<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Phil Yeh</title>
    <description>The latest articles on Forem by Phil Yeh (@philyeh).</description>
    <link>https://forem.com/philyeh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3617170%2Fe807fbe4-882c-42ae-a879-bb10f1193c08.jpeg</url>
      <title>Forem: Phil Yeh</title>
      <link>https://forem.com/philyeh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/philyeh"/>
    <language>en</language>
    <item>
      <title>From Theory to Practice: Digital Twin Core Concepts and Implementation Ideas for Engineers</title>
      <dc:creator>Phil Yeh</dc:creator>
      <pubDate>Fri, 12 Dec 2025 07:19:31 +0000</pubDate>
      <link>https://forem.com/philyeh/from-theory-to-practice-digital-twin-core-concepts-and-implementation-ideas-for-engineers-3f0l</link>
      <guid>https://forem.com/philyeh/from-theory-to-practice-digital-twin-core-concepts-and-implementation-ideas-for-engineers-3f0l</guid>
      <description>&lt;p&gt;🌐 The Bridge: Why Digital Twins Matter Now&lt;br&gt;
Have you ever wished you could predict a machine failure before it happens, or simulate the impact of a change in your supply chain without risking real-world downtime? That's the power of the Digital Twin.&lt;/p&gt;

&lt;p&gt;A Digital Twin is more than just a fancy 3D model. It's a live, virtual replica of a physical asset, system, or process that is constantly synchronized with real-world data. It serves as a testing ground, a crystal ball, and a diagnostic tool all rolled into one.&lt;/p&gt;

&lt;p&gt;For engineers, understanding Digital Twins is crucial for mastering the next phase of IoT and predictive analytics in fields like manufacturing, smart cities, and energy management.&lt;/p&gt;

&lt;p&gt;🔬 Step 1: Deconstructing the Digital Twin (The Three Core Layers)&lt;br&gt;
To build a Twin, we must first understand its three fundamental components.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Physical Asset Layer (The Source)
This layer includes the real-world equipment and the infrastructure used to gather data:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Key Technologies: IoT sensors, PLCs, and Edge Computing devices.&lt;/p&gt;

&lt;p&gt;Data Types: Real-time metrics like temperature, pressure, vibration, and energy consumption.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Virtual Model Layer (The Brain)
This is where the magic happens—the calculations, simulations, and predictions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Behavioral Models:&lt;/p&gt;

&lt;p&gt;Physics-Based: Uses known equations (thermodynamics, fluid dynamics) to predict behavior.&lt;/p&gt;

&lt;p&gt;Data-Driven (ML/AI): Uses historical data to train models that predict failures or optimal settings.&lt;/p&gt;

&lt;p&gt;Data Structure: Requires robust databases, often Time Series Databases (e.g., InfluxDB), to efficiently handle high-velocity, timestamped sensor data.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Connection &amp;amp; Services Layer (The Data Flow)
This is the communication pipeline that ensures the Twin is alive. It requires bi-directional data flow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Inbound Flow (Physical to Virtual): Sensors push data to the cloud/edge (often via MQTT).&lt;/p&gt;

&lt;p&gt;Outbound Flow (Virtual to Physical): The Twin sends control commands or optimization suggestions back to the physical asset (e.g., throttling a motor speed).&lt;/p&gt;

&lt;p&gt;🛠️ Step 2: The Engineer's Starting Guide (A POC Blueprint)&lt;br&gt;
Ready to start building your first Twin? Here is a practical, two-phase approach focusing on open-source tools.&lt;/p&gt;

&lt;p&gt;Phase A: Data Ingestion and Basic Shadowing&lt;br&gt;
Your goal here is to create a "Shadow Twin"—a basic model that mirrors the live state.&lt;/p&gt;

&lt;p&gt;Set up MQTT Broker: Start a lightweight message broker (e.g., Mosquitto or a cloud service like AWS IoT Core).&lt;/p&gt;

&lt;p&gt;The Python Data Emitter: Use Python to simulate or collect sensor readings and publish them to the broker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Python

# python_emitter.py - Simulating sensor data publishing
import paho.mqtt.client as mqtt
import time
import random

broker_url = "your_mqtt_broker"
topic = "asset/motor/temperature"

client = mqtt.Client()
client.connect(broker_url, 1883, 60)

while True:
    temp = 70 + random.uniform(-2, 2)  # Simulate temp fluctuation
    client.publish(topic, f"{time.time()},{temp:.2f}")
    print(f"Published: {temp:.2f}")
    time.sleep(5)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visualization: Use Grafana to subscribe to the MQTT topic and display the data on a dashboard. This is your first visual Twin!&lt;/p&gt;

&lt;p&gt;Phase B: Integrating Predictive Intelligence&lt;br&gt;
Now, let's add the "intelligence" to the Twin using a simple Machine Learning model.&lt;/p&gt;

&lt;p&gt;Model Training (Hypothetical RUL Model): Assume you've trained a classification model (using Scikit-learn or similar) to predict the Remaining Useful Life (RUL) of your motor based on its temperature and vibration history.&lt;/p&gt;

&lt;p&gt;The Prediction Service: A dedicated Python service reads the latest data and feeds it into the trained model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Python
# prediction_service.py - The Twin's intelligence
import pandas as pd
from joblib import load
# Assume 'rul_predictor.joblib' is a trained ML model

model = load('rul_predictor.joblib')

def predict_rul(latest_data):
    # Process latest_data (e.g., features for the last 1 hour)
    features_df = pd.DataFrame([latest_data]) 
    prediction = model.predict(features_df)

    # 0 = Normal, 1 = Caution, 2 = Failure imminent
    return prediction[0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  (This service would run continuously, reading from the Time Series DB)
&lt;/h1&gt;

&lt;p&gt;By connecting this prediction service to your live data stream, your Twin starts providing actionable insights (e.g., sending an alert when the RUL drops below 10 days).&lt;/p&gt;

&lt;p&gt;🚀 Step 3: Challenges and The Future&lt;br&gt;
Key Challenges in Implementation&lt;br&gt;
Data Quality: Twins are only as good as the data they receive. Dealing with sensor drift, gaps, and noise is a massive engineering challenge.&lt;/p&gt;

&lt;p&gt;Synchronization Latency: For real-time control applications (like self-driving cars), the delay between the physical event and the virtual update must be minimal.&lt;/p&gt;

&lt;p&gt;Scalability: Managing the data synchronization and simulation load for millions of individual Twins (e.g., every turbine in a wind farm).&lt;/p&gt;

&lt;p&gt;Looking Ahead&lt;br&gt;
The future of Digital Twins is exciting:&lt;/p&gt;

&lt;p&gt;XR Integration: Using AR/VR headsets to overlay live Twin data onto the physical asset during maintenance (e.g., seeing a projected temperature reading overlaid on the actual motor).&lt;/p&gt;

&lt;p&gt;Edge Twins: Shifting more simulation and predictive processing to Edge devices to reduce latency and cloud costs.&lt;/p&gt;

&lt;p&gt;📢 What’s Your Twin?&lt;br&gt;
Digital Twin technology transforms maintenance from reactive to predictive.&lt;/p&gt;

&lt;p&gt;What process or asset in your current engineering domain do you think is ripest for Digital Twin development? Share your ideas and challenges in the comments below!&lt;/p&gt;

</description>
      <category>iot</category>
      <category>python</category>
      <category>machinelearning</category>
      <category>devops</category>
    </item>
    <item>
      <title>The Architecture of Implicit Messaging: Implementing Raw CIP I/O in Python</title>
      <dc:creator>Phil Yeh</dc:creator>
      <pubDate>Wed, 03 Dec 2025 03:26:51 +0000</pubDate>
      <link>https://forem.com/philyeh/the-architecture-of-implicit-messaging-implementing-raw-cip-io-in-python-1o0c</link>
      <guid>https://forem.com/philyeh/the-architecture-of-implicit-messaging-implementing-raw-cip-io-in-python-1o0c</guid>
      <description>&lt;p&gt;The Challenge of Class 1 I/O&lt;br&gt;
Ethernet/IP (EIP) is based on the Common Industrial Protocol (CIP), which defines two primary messaging types:&lt;/p&gt;

&lt;p&gt;Explicit Messaging (TCP 44818): Request/Response—used for configuration and diagnostics.&lt;/p&gt;

&lt;p&gt;Implicit Messaging (UDP 2222): Cyclic I/O—used for high-speed, repetitive data exchange (Class 1 Connections).&lt;/p&gt;

&lt;p&gt;The architectural challenge lies in managing resource contention and time determinism when setting up these complex connections using raw sockets, rather than relying on commercial drivers.&lt;/p&gt;

&lt;p&gt;🏗️ The 4-Step Connection Sequence&lt;br&gt;
A robust implementation requires careful management of the TCP setup and the subsequent UDP I/O lifecycle. Our architecture follows these four steps within a cyclic process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Register Session (TCP)&lt;br&gt;
The process begins with an Explicit Message to the target device's Encapsulation Layer (TCP 44818). This step establishes a Session Handle, which identifies the connection for subsequent requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Forward Open (TCP)&lt;br&gt;
This is the most critical step. The client sends a Forward Open command containing all parameters necessary for the Class 1 I/O connection, including:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Requested Packet Interval (RPI).&lt;/p&gt;

&lt;p&gt;Connection Path (Assembly Instance IDs for the I/O data).&lt;/p&gt;

&lt;p&gt;Connection Timeout parameters. The device returns the O2T (Originator to Target) and T2O (Target to Origin) Connection IDs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Cyclic I/O Exchange (UDP)&lt;br&gt;
Once the connection is established via TCP, the system shifts to high-speed UDP 2222. The client sends periodic data using the established O2T connection ID, and the device responds with the T2O data. This ensures minimal latency for cyclic data updates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Forward Close &amp;amp; Teardown (TCP)&lt;br&gt;
To prevent the target device from eventually timing out and reporting a fault, the client must explicitly send a Forward Close command (TCP). This gracefully releases the resources allocated by the device before the socket is closed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💻 Architecture for Deterministic Testing&lt;br&gt;
To reliably test this intricate sequence, our study kit employs a dual-application structure:&lt;/p&gt;

&lt;p&gt;Raw Socket Client: Implements the full TCP and UDP state machine, managing the cyclic Open/Close sequence.&lt;/p&gt;

&lt;p&gt;Mock PLC Server: A separate Python application running on localhost that listens on TCP 44818 and UDP 2222. The mock server is essential for deterministic testing, as it guarantees correct, instantaneous responses during the handshake, allowing developers to isolate logic errors from physical layer noise.&lt;/p&gt;

&lt;p&gt;Python I/O Loop Structure&lt;br&gt;
The raw socket implementation requires precise packet assembly. Below is the conceptual structure used to manage the cyclic UDP exchange:&lt;/p&gt;

&lt;p&gt;Python&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Conceptual Structure for I/O Loop

while running:
    # 1. Open Session (TCP) &amp;amp; Forward Open (TCP) is performed here...

    # 2. UDP Exchange Phase:
    try:
        # Construct and send O2T packet using raw bytes
        udp_socket.sendto(o2t_packet, (target_ip, 2222))

        # Receive T2O packet (Target to Origin)
        received_data, addr = udp_socket.recvfrom(1024)

        # Log and parse the raw data...

    except socket.timeout:
        log("Warning: UDP I/O Timeout occurred.")

    # 3. Forward Close (TCP) &amp;amp; TCP Disconnect is performed here...

    time.sleep(RPI_WAIT_TIME)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔒 Conclusion&lt;br&gt;
Understanding the raw socket implementation of CIP is critical for developers working in industrial cybersecurity, custom SCADA integration, or embedded systems where external libraries are too large or unavailable.&lt;/p&gt;

&lt;p&gt;We have documented the complete architecture and technical insights for this project on GitHub. If you are interested in acquiring the full, ready-to-deploy Python source code for this framework and diving into the raw packet structure for your own custom industrial solutions:&lt;/p&gt;

&lt;p&gt;View the complete project and detailed architecture: &lt;a href="https://github.com/PhilYeh1212/Python-EthernetIP-Raw-Socket-Client" rel="noopener noreferrer"&gt;Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By Phil Yeh | Senior Automation Engineer&lt;/p&gt;

</description>
      <category>ethernetip</category>
      <category>cip</category>
      <category>python</category>
      <category>sockets</category>
    </item>
    <item>
      <title>How I Fixed Python's Serial Freezing Issue: A Multi-threaded Tkinter Solution</title>
      <dc:creator>Phil Yeh</dc:creator>
      <pubDate>Fri, 28 Nov 2025 01:51:40 +0000</pubDate>
      <link>https://forem.com/philyeh/how-i-fixed-pythons-serial-freezing-issue-a-multi-threaded-tkinter-solution-2n21</link>
      <guid>https://forem.com/philyeh/how-i-fixed-pythons-serial-freezing-issue-a-multi-threaded-tkinter-solution-2n21</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzgyjojvogikz5lpjf9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxzgyjojvogikz5lpjf9i.png" alt="FlowChart" width="634" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As automation engineers, we hit a frustrating wall: writing a simple Modbus GUI tool with Tkinter, only to have the entire application freeze ("Not Responding") while waiting for the slow RS485 sensor to reply.&lt;/p&gt;

&lt;p&gt;If you are dealing with &lt;strong&gt;serial I/O&lt;/strong&gt; and &lt;strong&gt;real-time UI updates&lt;/strong&gt;, the solution lies in proper threading.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ The Fix: Multi-threading for Stability
&lt;/h2&gt;

&lt;p&gt;The core issue is &lt;strong&gt;blocking I/O&lt;/strong&gt;. Since the main Tkinter loop handles the UI, waiting for the serial port stops the entire window from updating.&lt;/p&gt;

&lt;p&gt;The professional solution is to use the &lt;code&gt;threading&lt;/code&gt; module to separate the UI rendering thread from the I/O polling thread.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Threading Logic
&lt;/h3&gt;

&lt;p&gt;We implemented a daemon thread dedicated solely to reading the Modbus device. This ensures the UI is responsive, even if the polling takes several seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The UI remains responsive because the heavy lifting runs in a separate thread.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;thread_helper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;daemon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Tkinter mainloop continues to run smoothly
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📘 Modbus Protocol Primer: Deciphering the Hex (Tutorial Value)&lt;br&gt;
To effectively debug Modbus, you need to understand the structure of the command frame. The tool guides users through this structure directly on the screen:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0yfkujf72fztwzz95xx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0yfkujf72fztwzz95xx1.png" alt="Sheet" width="523" height="170"&gt;&lt;/a&gt;&lt;br&gt;
(The default command in the tool is 01 03 00 00 00 03)&lt;/p&gt;

&lt;p&gt;✨ Production Features (The True Value)&lt;br&gt;
This project provides a robust, reusable template that is ready for industrial deployment. The source code handles all the time-consuming integration headaches:&lt;/p&gt;

&lt;p&gt;Universal Serial Setup: Supports custom Data Bits (5-8), Parity (N, E, O), and Stop Bits (1, 1.5, 2).&lt;/p&gt;

&lt;p&gt;Auto CRC-16: Automatically calculates and appends the Modbus checksum.&lt;/p&gt;

&lt;p&gt;Raw Hex Logging: Logs both the raw response and parsed data to a CSV file.&lt;/p&gt;

&lt;p&gt;📥 Get the Fully Integrated Solution&lt;br&gt;
This article shares the architectural solution. If you want the complete, multi-threaded GUI source code—including the full UI logic, auto-CRC calculation, and CSV logging feature—you can acquire the packaged files &lt;a href="https://pokhts.gumroad.com/l/python-modbus-logger" rel="noopener noreferrer"&gt;here-$9.9&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By Phil Yeh | Senior Automation Engineer&lt;/p&gt;

</description>
      <category>python</category>
      <category>modbus</category>
      <category>tkinter</category>
      <category>threading</category>
    </item>
    <item>
      <title>Stop decoding Hex manually. I built a Python J1939 Sniffer with a GUI (No Hardware Needed)</title>
      <dc:creator>Phil Yeh</dc:creator>
      <pubDate>Tue, 25 Nov 2025 00:57:06 +0000</pubDate>
      <link>https://forem.com/philyeh/stop-decoding-hex-manually-i-built-a-python-j1939-sniffer-with-a-gui-no-hardware-needed-1p8o</link>
      <guid>https://forem.com/philyeh/stop-decoding-hex-manually-i-built-a-python-j1939-sniffer-with-a-gui-no-hardware-needed-1p8o</guid>
      <description>&lt;p&gt;After receiving the &lt;strong&gt;Top Docker Author badge&lt;/strong&gt; last week for my &lt;a href="https://dev.to/philyeh/how-i-built-a-100-offline-second-brain-for-engineering-docs-using-docker-llama-3-no-openai-4gcj"&gt;Offline AI post&lt;/a&gt; (thanks everyone! 🙏), many of you asked about my workflow for hardware and vehicle networks.&lt;/p&gt;

&lt;p&gt;So today, I'm switching gears from &lt;strong&gt;AI&lt;/strong&gt; to &lt;strong&gt;Heavy Duty Vehicles&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you work with &lt;strong&gt;CAN Bus&lt;/strong&gt; or &lt;strong&gt;SAE J1939&lt;/strong&gt; (Trucks, Buses, Machinery), you know the pain:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Professional tools are expensive:&lt;/strong&gt; A Vector CANalyzer license costs thousands of dollars.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Hex dumps are unreadable:&lt;/strong&gt; Seeing &lt;code&gt;18FEF100&lt;/code&gt; means nothing unless you memorize the J1939 spec.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Hardware dependency:&lt;/strong&gt; You usually need a physical adapter (PCAN, Kvaser) just to test your code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To solve this, I built a &lt;strong&gt;Python-based J1939 Sniffer&lt;/strong&gt; that decodes PGNs automatically and includes a &lt;strong&gt;Simulation Mode&lt;/strong&gt; for hardware-free development.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbitq434bkdb78dwro1d.png" alt=" " width="800" height="642"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  🏗️ The Challenge: Parsing 29-bit IDs
&lt;/h2&gt;

&lt;p&gt;Standard CAN (11-bit) is simple. But J1939 uses &lt;strong&gt;29-bit Extended Identifiers&lt;/strong&gt;, which pack a lot of data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Priority (3 bits)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PGN (Parameter Group Number) (18 bits)&lt;/strong&gt; &amp;lt;--- &lt;em&gt;The most important part&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source Address (8 bits)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you get a raw ID like &lt;code&gt;0x18FEF100&lt;/code&gt;, you need to extract the &lt;strong&gt;PGN&lt;/strong&gt; to know what the message actually is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Python Logic
&lt;/h3&gt;

&lt;p&gt;Here is the core logic I used to extract the PGN and Source Address from a raw integer ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_j1939_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;can_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Extract PGN and Source Address from a 29-bit CAN ID.
    Format: [Priority(3)] [Reserved(1)] [Data Page(1)] [PDU Format(8)] [PDU Specific(8)] [Source Address(8)]
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Shift right by 8 bits to drop Source Address
&lt;/span&gt;    &lt;span class="c1"&gt;# Mask with 0x3FFFF to keep only the 18-bit PGN
&lt;/span&gt;    &lt;span class="n"&gt;pgn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;can_id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x3FFFF&lt;/span&gt;

    &lt;span class="c1"&gt;# Mask with 0xFF to get the last 8 bits
&lt;/span&gt;    &lt;span class="n"&gt;source_address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;can_id&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0xFF&lt;/span&gt;

    &lt;span class="c1"&gt;# Shift right by 26 bits to get Priority
&lt;/span&gt;    &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;can_id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pgn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🛠️ The Solution: A GUI Sniffer&lt;br&gt;
I wrapped this logic into a Tkinter GUI using the python-can library. It listens to the bus, parses the ID, and looks up the PGN in a built-in dictionary.&lt;/p&gt;

&lt;p&gt;The Result&lt;br&gt;
Instead of staring at 18FEF100, the tool tells you: 👉 CCVS - Vehicle Speed&lt;/p&gt;

&lt;p&gt;Instead of 0CF00400, it shows: 👉 EEC1 - Engine Speed (RPM)&lt;/p&gt;

&lt;p&gt;Features&lt;br&gt;
🚛 Auto-Decode: Built-in dictionary for common PGNs (RPM, Temp, Speed, Battery).&lt;/p&gt;

&lt;p&gt;🎮 Simulation Mode: Click "Start Demo" to generate fake J1939 traffic. Perfect for testing UI logic without sitting in a truck.&lt;/p&gt;

&lt;p&gt;🔌 Universal Support: Works with Vector, Peak-System (PCAN), Kvaser, and slcan via python-can.&lt;/p&gt;

&lt;p&gt;📥 Try it yourself&lt;br&gt;
I have open-sourced the project structure and the J1939 parsing logic on GitHub. You can use it as a template for your own ECU tools.&lt;/p&gt;

&lt;p&gt;🔗 GitHub Repository: &lt;a href="https://github.com/PhilYeh1212/Python-CAN-Bus-J1939-Sniffer-GUI" rel="noopener noreferrer"&gt;Python-CAN-Bus-J1939-Sniffer-GUI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎁 For those who want the full package: If you want the complete, production-ready source code (including the GUI, Simulation Mode, and Multi-threading), I've made it available on Gumroad.&lt;/p&gt;

&lt;p&gt;🔥 Black Friday Deal: Use code BLACKFRIDAY for 15% OFF all my engineering tools.&lt;/p&gt;

&lt;p&gt;👉 Get the Full Source Code&lt;a href="https://pokhts.gumroad.com/l/python-can-j1939-tool?_gl=1*hjiu20*_ga*OTI5NDQ0OTEuMTc2MzM2MzI3OQ..*_ga_6LJN6D94N6*czE3NjQwMzIxNDIkbzE2JGcxJHQxNzY0MDMyMTUxJGo1MSRsMCRoMA.." rel="noopener noreferrer"&gt;(link)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy Hacking! 🚛&lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>engineering</category>
      <category>opensource</category>
    </item>
    <item>
      <title>5 Python Tools I Built to Automate My Industrial IoT Workflow (Open Source)</title>
      <dc:creator>Phil Yeh</dc:creator>
      <pubDate>Thu, 20 Nov 2025 10:00:43 +0000</pubDate>
      <link>https://forem.com/philyeh/5-python-tools-i-built-to-automate-my-industrial-iot-workflow-open-source-h3p</link>
      <guid>https://forem.com/philyeh/5-python-tools-i-built-to-automate-my-industrial-iot-workflow-open-source-h3p</guid>
      <description>&lt;p&gt;Update: 🏷️ Black Friday Sale is ON! Use code BLACKFRIDAY for 15% OFF on the Ultimate Toolkit.&lt;/p&gt;

&lt;p&gt;As a Senior Automation Engineer, I spend half my life debugging communication protocols. Modbus, MQTT, CAN Bus, Ethernet/IP... you name it.&lt;/p&gt;

&lt;p&gt;The problem is, most professional tools (like Vector CANalyzer or proprietary PLC software) are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Expensive&lt;/strong&gt; (Thousands of dollars).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Windows-only&lt;/strong&gt; (I love Docker/Linux).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Closed Source&lt;/strong&gt; (I can't customize them).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, over the past few weekends, I decided to build my own &lt;strong&gt;"Survival Toolkit"&lt;/strong&gt; using Python.&lt;/p&gt;

&lt;p&gt;Here are the 5 open-source tools I created to replace expensive software, all available on my GitHub.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The "Privacy-First" AI Datasheet Reader
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; I have hundreds of PDF datasheets to read, but I can't upload them to ChatGPT due to NDA/Privacy concerns.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; A 100% offline RAG system using Docker + Llama 3.&lt;/p&gt;

&lt;p&gt;It runs entirely on my local machine (RTX 3060). No data leaves the building.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaaa2mlsbhaduk3tpsfa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaaa2mlsbhaduk3tpsfa.png" alt="AI Architecture" width="772" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; &lt;code&gt;Docker&lt;/code&gt;, &lt;code&gt;Ollama&lt;/code&gt;, &lt;code&gt;ChromaDB&lt;/code&gt;, &lt;code&gt;Streamlit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/PhilYeh1212/Local-AI-Knowledge-Base-Docker-Llama3" rel="noopener noreferrer"&gt;Local-AI-Knowledge-Base-Docker-Llama3&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. The J1939 &amp;amp; CAN Bus Sniffer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Debugging vehicle ECUs usually requires a $300+ hardware adapter just to see the data.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; A Python GUI that works with cheap USB-CAN adapters (slcan) and automatically decodes J1939 PGNs.&lt;/p&gt;

&lt;p&gt;It even has a &lt;strong&gt;"Demo Mode"&lt;/strong&gt; to simulate traffic if you don't have hardware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjflhvnizjafrpmxtdx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjflhvnizjafrpmxtdx1.png" alt="CAN Bus Demo" width="800" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;tkinter&lt;/code&gt;, &lt;code&gt;python-can&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature:&lt;/strong&gt; Decodes Engine Speed, Temp, and other PGNs instantly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/PhilYeh1212/Python-CAN-Bus-J1939-Sniffer-GUI" rel="noopener noreferrer"&gt;Python-CAN-Bus-J1939-Sniffer-GUI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. The "Anti-Freezing" Modbus Logger
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Writing a simple Python script to read RS485 is easy, but the GUI always freezes (blocks) while waiting for the sensor to reply.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; A multi-threaded Modbus RTU Master.&lt;/p&gt;

&lt;p&gt;It separates the UI thread from the Serial polling thread, so the app remains responsive 100% of the time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2k7zzbpwh9r6mu6dje4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2k7zzbpwh9r6mu6dje4t.png" alt="Modbus Logger" width="744" height="910"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;tkinter&lt;/code&gt;, &lt;code&gt;pyserial&lt;/code&gt;, &lt;code&gt;threading&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/PhilYeh1212/Python-Modbus-Serial-Logger-GUI" rel="noopener noreferrer"&gt;Python-Modbus-Serial-Logger-GUI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. The MQTT Data Recorder
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Sometimes I just want to save MQTT sensor data to an Excel file for analysis, without setting up a database.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; A lightweight MQTT Client that logs everything to CSV automatically.&lt;/p&gt;

&lt;p&gt;Updated to support the latest &lt;strong&gt;Paho-MQTT v2.0&lt;/strong&gt; standard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fongdkkdp6yhn7lqf2oxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fongdkkdp6yhn7lqf2oxs.png" alt="MQTT Logger" width="598" height="780"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;paho-mqtt&lt;/code&gt;, &lt;code&gt;csv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/PhilYeh1212/Python-MQTT-Data-Logger-GUI" rel="noopener noreferrer"&gt;Python-MQTT-Data-Logger-GUI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. The Virtual Ethernet/IP Lab
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Learning the CIP protocol (used by Rockwell/Omron PLCs) is hard without physical hardware.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; A Mock PLC Server + Raw Socket Client.&lt;/p&gt;

&lt;p&gt;It simulates the full &lt;code&gt;Forward Open&lt;/code&gt; handshake and Implicit Messaging on your localhost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqr5ytggqjnu1pqpe0kj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqr5ytggqjnu1pqpe0kj.png" alt="Ethernet IP Demo" width="800" height="769"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; &lt;code&gt;Pure Python&lt;/code&gt;, &lt;code&gt;socket&lt;/code&gt;, &lt;code&gt;struct&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/PhilYeh1212/Python-EthernetIP-Raw-Socket-Client" rel="noopener noreferrer"&gt;Python-EthernetIP-Raw-Socket-Client&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎁 Conclusion
&lt;/h2&gt;

&lt;p&gt;Building your own tools is the best way to learn. Not only do you save money on licenses, but you also get full control over the source code.&lt;/p&gt;

&lt;p&gt;I have open-sourced the documentation and basic architecture for all these projects on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want the complete, production-ready source code for ALL these tools (5-in-1), I've bundled them together here:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://pokhts.gumroad.com/l/senior-engineer-toolkit" rel="noopener noreferrer"&gt;The Ultimate Senior Engineer Toolkit (Gumroad)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>python</category>
      <category>automation</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Local RAG with Llama 3 &amp; Docker: Build an Offline Second Brain (No OpenAI)</title>
      <dc:creator>Phil Yeh</dc:creator>
      <pubDate>Tue, 18 Nov 2025 09:03:19 +0000</pubDate>
      <link>https://forem.com/philyeh/how-i-built-a-100-offline-second-brain-for-engineering-docs-using-docker-llama-3-no-openai-4gcj</link>
      <guid>https://forem.com/philyeh/how-i-built-a-100-offline-second-brain-for-engineering-docs-using-docker-llama-3-no-openai-4gcj</guid>
      <description>&lt;p&gt;[UPDATE: Dec 2025] 🚀 Due to the overwhelming interest in this Local RAG setup, I’ve officially released the production-ready toolkit on Gumroad to help you save hours of configuration time!&lt;/p&gt;

&lt;p&gt;Based on your feedback, I’ve created two versions to suit your needs:&lt;/p&gt;

&lt;p&gt;Option 1: The "Lite" Edition ($59) – Perfect for developers! Get the full Dockerized source code, Streamlit UI, and PDF pipeline. Ideal if you want to deploy it yourself and own the code.&lt;/p&gt;

&lt;p&gt;Option 2: The "Pro" Solution ($299) – For enterprises and busy professionals. Includes the full suite PLUS a 1-on-1 Remote Setup Service. I will personally ensure the system is perfectly tuned and running on your hardware.&lt;/p&gt;

&lt;p&gt;Why use this?&lt;/p&gt;

&lt;p&gt;100% Private: No data ever leaves your machine (No OpenAI/Cloud APIs).&lt;/p&gt;

&lt;p&gt;One-Click Setup: Move from "dependency hell" to a functional RAG system in minutes using Docker.&lt;/p&gt;

&lt;p&gt;Proven Results: Check out the new Demo Video on the product page to see it in action!&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://pokhts.gumroad.com/l/ai-knowledge-docker" rel="noopener noreferrer"&gt;Get the Local RAG Toolkit here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎉 Update: Wow! This post was awarded the Top Docker Author Badge of the week! Thanks to everyone for the amazing support and feedback. 🙏&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ipfyzqtu7guohbozp83.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ipfyzqtu7guohbozp83.png" alt=" " width="776" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nx3aaczxx2oiplkup4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4nx3aaczxx2oiplkup4y.png" alt="Offline AI System Architecture Docker Llama 3" width="772" height="598"&gt;&lt;/a&gt;&lt;br&gt;
Stop sending your sensitive datasheets to the cloud. Here is how I deployed a private, enterprise-grade RAG system.&lt;/p&gt;

&lt;p&gt;As a Senior Automation Engineer, I deal with hundreds of technical documents every month — datasheets, schematics, internal protocols, and legacy codebases.&lt;/p&gt;

&lt;p&gt;We all know the power of LLMs like GPT-4. Being able to ask, “What is the maximum voltage for the RS485 module on page 42?” and getting an instant answer is a game-changer.&lt;/p&gt;

&lt;p&gt;But there is a problem: Privacy.&lt;/p&gt;

&lt;p&gt;I cannot paste proprietary schematics or NDA-protected specs into ChatGPT. The risk of data leakage is simply too high.&lt;/p&gt;

&lt;p&gt;So, I set out to build a solution. I wanted a “Second Brain” that was:&lt;/p&gt;

&lt;p&gt;100% Offline: No data leaves my local network.&lt;/p&gt;

&lt;p&gt;Free to run: No monthly API subscriptions (bye-bye, OpenAI bills).&lt;/p&gt;

&lt;p&gt;Dockerized: Easy to deploy without “dependency hell.”&lt;/p&gt;

&lt;p&gt;Here is the architecture I built using Llama 3, Ollama, and Docker.&lt;/p&gt;

&lt;p&gt;The Architecture: Why this Tech Stack?&lt;br&gt;
Building a RAG (Retrieval-Augmented Generation) system locally used to be a nightmare of Python dependencies and CUDA driver issues. To solve this, I designed a containerized microservices architecture.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The Brain: Ollama + Llama 3&lt;br&gt;
I chose Ollama as the inference engine because it’s lightweight and efficient. For the model, Meta’s Llama 3 (8B) is the current sweet spot — it’s surprisingly capable of reasoning through technical documentation and runs smoothly on consumer GPUs (like an RTX 3060).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Memory: ChromaDB&lt;br&gt;
For the vector database, I used ChromaDB. It runs locally, requires zero setup, and handles vector retrieval incredibly fast.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Glue: Python &amp;amp; Streamlit&lt;br&gt;
The backend is written in Python, handling the “Ingestion Pipeline”:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Parsing: Extracting text from PDFs.&lt;/p&gt;

&lt;p&gt;Chunking: Breaking text into manageable pieces.&lt;/p&gt;

&lt;p&gt;Embedding: Converting text into vectors using the mxbai-embed-large model.&lt;/p&gt;

&lt;p&gt;UI: A clean Streamlit interface for chatting with the data.&lt;/p&gt;

&lt;p&gt;How It Works (The “Happy Path”)&lt;br&gt;
The beauty of this system is the Docker implementation. Instead of installing Python libraries manually, the entire system spins up with a single command.&lt;/p&gt;

&lt;p&gt;The docker-compose.yml orchestrates the communication between the AI engine, the database, and the UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YAML

# Simplified concept of the setup
services:
  ollama:
    image: ollama/ollama:latest
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

  backend:
    build: ./app
    depends_on:
      - ollama
      - chromadb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once running, the workflow is simple:&lt;/p&gt;

&lt;p&gt;Drop your PDF files into the knowledge_base folder.&lt;/p&gt;

&lt;p&gt;Click “Update Knowledge Base” in the UI.&lt;/p&gt;

&lt;p&gt;Start chatting.&lt;/p&gt;

&lt;p&gt;The system automatically vectorizes your documents. When you ask a question, it retrieves the most relevant paragraphs and feeds them to Llama 3 as context.&lt;/p&gt;

&lt;p&gt;The Challenge: It’s Not Just About “Running” the Model&lt;br&gt;
While the concept sounds simple, getting it to production-grade stability took me weeks of debugging.&lt;/p&gt;

&lt;p&gt;Here is what most “Hello World” tutorials don’t tell you:&lt;/p&gt;

&lt;p&gt;PDF Parsing is messy: Tables in engineering datasheets often break standard parsers.&lt;/p&gt;

&lt;p&gt;Context Window limits: Llama 3 has a limit. You need a smart “Sliding Window” strategy for chunking large documents.&lt;/p&gt;

&lt;p&gt;Docker Networking: Getting the Python container to talk to the Ollama container on the host GPU requires specific networking configurations.&lt;/p&gt;

&lt;p&gt;I spent countless nights fixing connection timeouts, optimizing embedding models, and ensuring the UI doesn’t freeze during large file ingestions.&lt;/p&gt;

&lt;p&gt;Want to Build Your Own?&lt;br&gt;
If you are an engineer or developer who wants to own your data, I highly recommend building a local RAG system. It’s a great way to learn about GenAI architecture.&lt;/p&gt;

&lt;p&gt;However, if you value your time and want to skip the configuration headaches, I have packaged my entire setup into a ready-to-deploy solution.&lt;/p&gt;

&lt;p&gt;It includes:&lt;/p&gt;

&lt;p&gt;✅ The Complete Source Code (Python/Streamlit).&lt;/p&gt;

&lt;p&gt;✅ Production-Ready Docker Compose file.&lt;/p&gt;

&lt;p&gt;✅ Optimized Ingestion Logic for technical docs.&lt;/p&gt;

&lt;p&gt;✅ Setup Guide for Windows/Linux.&lt;/p&gt;

&lt;p&gt;You can download the full package and view the detailed documentation on my GitHub.&lt;/p&gt;

&lt;p&gt;👉 View the Project &amp;amp; Download Source Code on GitHub &lt;a href="https://github.com/PhilYeh1212/Local-AI-Knowledge-Base-Docker-Llama3/blob/main/README.md" rel="noopener noreferrer"&gt;link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By Phil Yeh Senior Automation Engineer specializing in Industrial IoT and Local AI solutions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://pokhts.gumroad.com/l/python-mqtt-logger" rel="noopener noreferrer"&gt;Python MQTT Data Logger&lt;/a&gt;&lt;/strong&gt; - A clean GUI to debug brokers &amp;amp; auto-save data to CSV.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://pokhts.gumroad.com/l/python-can-j1939-tool" rel="noopener noreferrer"&gt;Python CAN Bus &amp;amp; J1939 Sniffer&lt;/a&gt;&lt;/strong&gt; - Decode vehicle data without expensive hardware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://pokhts.gumroad.com/l/python-modbus-logger" rel="noopener noreferrer"&gt;Python Modbus Data Logger&lt;/a&gt;&lt;/strong&gt; - Debug RS485 devices with a multi-threaded GUI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://pokhts.gumroad.com/l/ethernet-ip-study-kit" rel="noopener noreferrer"&gt;Ethernet/IP Study Kit&lt;/a&gt;&lt;/strong&gt; - Learn CIP protocol with a Python-based mock PLC.
****
👉 &lt;strong&gt;Get the Source Code for all these tools:&lt;/strong&gt; &lt;a href="https://gumroad.com/products" rel="noopener noreferrer"&gt;Visit my Gumroad Store&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>docker</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
