Skip to content

10.2 Industrial IoT Data Acquisition: Modbus and OPC UA

10.2.1 Industrial Data Acquisition: The Modbus Protocol and Driver Configuration

One of the biggest headaches in a factory is equipment that "does not speak." Siemens PLCs use S7, Rockwell's use CIP, Mitsubishi's use CC-Link, and some legacy instruments understand nothing more than a few bytes on an RS-485 serial line. Before data like this can be collected in a unified way, protocol interoperability must be solved first.

Modbus is the old soldier that solves this problem. It was introduced by Modicon in 1979 and later handed to the Modbus Organization for maintenance; the current stable version of the specification is v1.1b3. Nearly half a century on, newly installed devices still use Modbus, for one simple reason: reliability. A request frame is usually no more than a few dozen bytes; the master initiates and the slave answers; there is no negotiation and no session management, so any microcontroller can implement it. Many engineers call Modbus "the ASCII of the industrial world" — not the best performance, but accepted everywhere.

The Modbus Register Model: Four Data Objects

The Modbus protocol defines a register address space. Whether the physical substrate is a PLC's memory area or a sensor's memory, it is logically abstracted into four kinds of data objects (see Table 10-3). Understanding this model is the foundation of driver configuration.

Table 10-3: Common Modbus function codes

Data object typeWidthAccess typeFunction codes (read / write)Typical use
Coil1 bitRead/write01 (read coils) / 05 (write single coil) / 15 (write multiple coils)Relay status, on/off outputs
Discrete input1 bitRead-only02 (read discrete inputs)Push-button signals, limit switches
Input register16 bitRead-only04 (read input registers)Analog inputs: temperature, pressure, level
Holding register16 bitRead/write03 (read holding registers) / 06 (write single register) / 16 (write multiple registers)Device parameters, PID setpoints, accumulated totals

Each kind of data object is distinguished by its "function code," which expresses the operation intent. The master sends a function code + start address + quantity, and the slave returns the corresponding data or a write confirmation. The frame structure is extremely simple; taking Modbus RTU as an example:

  • Request frame: [slave address] [function code] [start address hi] [start address lo] [quantity hi] [quantity lo] [CRC lo] [CRC hi]
  • Response frame: [slave address] [function code] [byte count] [data 1]... [data N] [CRC lo] [CRC hi]

The CRC check uses CRC-16/MODBUS (generator polynomial 0x8005, commonly implemented in its bit-reversed form 0xA001), safeguarding data integrity on the serial link. Modbus TCP drops the CRC and adds a transaction identifier to the frame; the protocol's data structure itself is unchanged, and TCP mode runs over port 502.

One key engineering insight: Modbus has no subscribe/report mode. The master must periodically poll every register of every slave. This means the acquisition period, the number of slaves, and the number of bytes per read must be traded off against one another. When multiple slaves hang on one RS-485 network, the total time of one polling round depends on frame transmission time, slave response time, and the gaps between frames. Throughput falls linearly as the number of slaves grows — a hard constraint in high-speed fieldbus scenarios. If every point must be refreshed at 100-millisecond-level intervals, Modbus RTU is no longer realistic, and Profinet or EtherCAT must be considered.

Why Write Capability Is Needed

Modbus is not only about reading data; it also needs to write commands. The closed loop of the IoT DC3 platform depends on this capability: when AI analysis finds that a pump's current has drifted outside its normal window, the system can issue a command that writes a holding register to bring the pump speed down, instead of merely raising an alarm and waiting for manual action. How well write functions are supported must be confirmed at driver-selection time. In the IoT DC3 driver matrix, both ModbusTcpDriver and ModbusRtuDriver support reading and writing; this is expanded further in later chapters on the "command plane" and the "AI closed loop."

An IoT DC3 Driver Configuration Example: The Modbus TCP Driver

In IoT DC3, drivers connect to devices through a unified flow: driver registration → device registration → point configuration → acquisition start. Below is a JSON configuration snippet for a Modbus TCP driver, used to connect a temperature controller that supports Modbus TCP.

json
{
  "driver": {
    "code": "ModbusTcpDriver",
    "name": "Modbus TCP Driver"
  },
  "device": {
    "name": "Temperature Controller-01",
    "deviceCode": "TEMP_CTRL_001",
    "driverCode": "ModbusTcpDriver",
    "ip": "<device-ip>",
    "port": 502,
    "timeout": 3000,
    "retryCount": 3,
    "interval": "PT5S"
  },
  "points": [
    {
      "pointCode": "PV_TEMP",
      "name": "Process Temperature",
      "registerType": "HOLDING_REGISTER",
      "functionCode": 3,
      "address": 0,
      "dataType": "FLOAT32",
      "slaveId": 1,
      "unit": "℃"
    },
    {
      "pointCode": "SV_TEMP",
      "name": "Setpoint Temperature",
      "registerType": "HOLDING_REGISTER",
      "functionCode": 3,
      "address": 2,
      "dataType": "FLOAT32",
      "slaveId": 1,
      "unit": "℃"
    },
    {
      "pointCode": "ALARM_STATUS",
      "name": "Alarm Status",
      "registerType": "DISCRETE_INPUT",
      "functionCode": 2,
      "address": 0,
      "dataType": "BOOLEAN",
      "slaveId": 1
    }
  ]
}

Key parameter notes:

  • In this configuration example, interval: "PT5S" means the driver polls the device once every 5 seconds; the actual period should be calibrated against the device's response time and the fieldbus load.
  • registerType and functionCode appear as a pair: once the register type is chosen correctly, the function code is determined automatically, though some special cases allow manual specification.
  • dataType: "FLOAT32": a raw Modbus register is only a 16-bit integer, but in engineering practice two consecutive registers are commonly combined into a 32-bit floating-point number. The IoT DC3 driver implements byte-order and data-type conversion internally.
  • slaveId: in Modbus RTU mode this is the slave station address; in TCP mode it is usually set to 1 or 255 (because TCP itself already identifies the device), but some gateways or PLCs require it to be filled in.

Once this configuration is written into the IoT DC3 Manager Center, the temperature controller's values enter the Data Center in the structured PointValue format (with tenant, timestamp, and unit), ready for direct consumption by the upper-layer rule engine and AI models. This step is crucial — it turns "protocol convergence" from an abstract concept into a runnable rule. For the structure of PointValue and how raw data becomes semantically tagged point values, see Section 3.7 of Chapter 3 (the thing model) and Section 4.3 of Chapter 4 (device abstraction and data-model standardization).

Engineering Debugging Essentials

A few of the most common pitfalls when deploying a Modbus driver:

  1. Address offset. Modbus protocol addresses start at 0, but some devices' HMIs display them starting from 1. When configuring, always check the device manual to confirm "which register on the device 0x0000 corresponds to" — otherwise you will read wrong values.

  2. Byte order. For the same 32-bit floating-point value, different vendors may use different byte orders (Big Endian or Little Endian). In IoT DC3 driver configuration, if the data type is set to FLOAT32 but the values read back are garbage, check whether the driver supports a byte-order parameter. ModbusTcpDriver supports switching via the byteOrder parameter by default.

  3. Response timeout. In a multi-slave system on a serial link, one slave going offline can stretch the entire polling cycle. Leave ample margin when configuring timeout and retryCount, and give each slave its own acquisition interval, so that one slow slave does not drag down the whole bus.

  4. Write acknowledgment. For a request with write function code 06 or 16, a healthy slave echoes the request frame back unchanged as the confirmation. If what comes back is an exception response code (function code with the high bit set, such as 0x83), the write has failed. The driver should capture this exception in its logs and retry or report it.

These details determine the reliability of industrial data acquisition. Whether a driver is "good to use" usually depends not on the breadth of its protocol support but on how deeply it handles these boundary conditions. IoT DC3's engineering practice on this front will become clearer in the comparison with OPC UA.

10.2.2 The OPC UA Protocol: Similarities and Differences with Modbus

Modbus pins data locations directly to register addresses — fast, stable, and simple — but it has a fatal defect: it never tells you what is inside a register — current, temperature, or a status bit? Even when devices from different vendors use the same Modbus function codes, their register-address definitions go their own way, and integrators must grind through device manuals, confirming the mapping table bit by bit.

OPC UA (OPC Unified Architecture) solves exactly this problem. Its design goal is not to replace Modbus, but to add the two missing layers of "semantics" and "security" where Modbus only carries "raw data." Building OPC UA servers into PLCs, SCADA (Supervisory Control and Data Acquisition) systems, and edge gateways is already common practice, with field data exposed outward as a node tree.

The Core Difference: Register Addressing vs. Object-Model Addressing

Start with the addressing scheme and the essential difference between the two becomes clear. Modbus's unit of communication is the register address — a 16-bit integer (e.g., 40001) denoting the starting offset of a holding register. You tell the other side "read 40001-40010," and it returns ten 16-bit values, but the meaning of those values is agreed in advance between the two parties; the protocol itself imposes no constraint.

OPC UA instead models each data point as a node, uniquely identified by a NodeId. A NodeId has two parts: a namespace index and an identifier (which can be an integer, a string, and so on). Namespaces keep identifiers from different sources apart — two vendors may define identifiers with the same numeric value in their respective namespaces without any conflict. This is the real foundation of OPC UA's cross-vendor interoperability: instead of requiring all devices to adopt one address mapping table, you decouple them through namespaces and the node tree.

In the four-layer IoT architecture, OPC UA is an application-layer protocol running on top of TCP/IP, connecting downward to PLCs/controllers and handing data upward to the data platform. Unlike Modbus TCP, which is fixed to TCP port 502 (Modbus RTU runs over serial links such as RS-485 and has no notion of a port), OPC UA uses the opc.tcp:// protocol (port 4840 by default) and builds in session management, secure channels, and data encryption.

Security Mechanisms

Modbus's security shortcomings are an industry consensus. The original Modbus TCP had no authentication and no encryption — not even the simplest username and password. Practitioners have since patched it in various ways: restricting IP access, deploying VPNs, doing protocol conversion at gateways. But at the protocol level, Modbus security remains an afterthought.

OPC UA built security into the specification from day one. Every OPC UA connection goes through a complete handshake: the client and the server establish a secure channel, negotiate a security policy (such as Basic256Sha256), exchange certificates, and use signing and encryption to guarantee message integrity and confidentiality. One of the administrator's routine tasks is managing the certificate trust chain — the server certificate, the client certificate, and the CA (Certificate Authority) certificate; none can be missing. This often creates extra work for integrators during line commissioning, but once the line is running, the security payoff is real.

The Information Model and the Address Space

OPC UA's core innovation is the information model. It does not merely transmit a value; it packages the value together with its type, unit, description, and metadata, and exposes all of it to the upper layers. This means that once an OPC UA client (for example, IoT DC3's OPC UA driver) connects to a server, it does not determine addresses by consulting manuals — it traverses the node tree directly, reads each node's metadata, and discovers the device's data structure automatically.

The OPC UA address space is a tree-structured object model: the root node is Objects, with concrete device objects attached below it; each object contains variable nodes (VariableNode), method nodes (MethodNode), and reference relationships.

Figure 10-5 OPC UA Address Space TreeOPC UA organizes devices with Organizes and contains variables and methods with HasComponent; NodeId, DataType, and Description are variable attributes; only extra properties like EngineeringUnits are referenced via HasProperty.Figure 10-5 OPC UA Address Space TreeNodeId, DataType, and Description are Variable Attributes; only extra properties like EngineeringUnits use HasPropertyObjectsContainer of all objectsOrganizesMain pathMotor 1Device objectTemperature · speed · statusDevice 2Device objectFlow · pressureHasComponentTemperatureVariable · FloatSpeedVariable · IntStatusVariable · BoolFlowVariable · FloatResetMethod · remotely callableVariable AttributesNodeId: ns=2;i=1234 · DataType: DoubleDescription: temperature readingProperty NodeEngineeringUnits: °CHasProperty → extra propertiesBlue box = object nodeGreen box = variable nodeOrange box = method nodeSolid = HasComponentDashed = HasPropertyBlue solid = OrganizesFigure 10-5 The OPC UA address space organizes nodes via references; a variable's own attributes must be distinguished from extra properties linked through HasProperty.
Figure 10-5 OPC UA Address Space Tree

This self-describing capability is impossible with Modbus. A Modbus client must already know which register address to read and what the returned value means — this information does not travel inside the protocol; it lives in manuals and configuration files. OPC UA places this metadata in the protocol's address space, so client programs discover it automatically on connect, eliminating a great deal of manual configuration.

Nor has the picture of the information model stopped at the "node tree." For field-level controller-to-controller communication, the OPC Foundation has introduced the OPC UA FX (Field eXchange) companion specification, extending OPC UA from "controller to upper-level systems" to "controller to controller (C2C)"; together with TSN (Time-Sensitive Networking) and single-pair Ethernet, OPC UA is sinking from the information layer down into the domain of deterministic real-time control. On the semantic-interoperability side, the Asset Administration Shell (AAS, IEC 63278) standardizes the description of equipment assets across their full life cycle, forming two sides of the same coin with the OPC UA information model. As of this book's writing (2026), "OPC UA carries the data, AAS governs the semantics" has become the mainstream picture of industrial semantic interoperability, and technology selection should factor in how well a driver keeps up with the FX- and AAS-related specifications.

IoT DC3 OPC UA Driver Configuration

IoT DC3's OPC UA driver (dc3-driver-opc-ua) is already marked as fully implemented in the official documentation and supports both read and write operations. At the configuration level, it needs the endpoint URL, the security policy, and the list of nodes to subscribe to. A typical JSON configuration looks like this (not from a real project — shown only to illustrate the structure):

json
{
  "driver": "opc-ua",
  "endpoint": "opc.tcp://<plc-ip>:4840",
  "security": {
    "mode": "SignAndEncrypt",
    "policy": "Basic256Sha256",
    "clientCert": "cert/iot-dc3-client.der",
    "clientKey": "cert/iot-dc3-client.pem"
  },
  "namespaceIndex": 2,
  "points": [
    {
      "name": "motor-1-temperature",
      "nodeId": "ns=2;i=1001",
      "dataType": "float",
      "unit": "°C",
      "pollInterval": 1000
    },
    {
      "name": "motor-1-speed",
      "nodeId": "ns=2;i=1002",
      "dataType": "int16",
      "unit": "rpm",
      "pollInterval": 500
    }
  ]
}

The nodeId in the configuration can be a numeric identifier (ns=2;i=1001) or a string identifier (ns=2;s="Temperature"), depending on how the server's address space is defined. Choosing the security policy is the difficult part of this configuration: during line commissioning you can first downgrade to None or Sign mode, then switch to SignAndEncrypt once the mutual certificate trust relationship is established.

Selection Criteria

The relationship between Modbus and OPC UA is not one of replacement. A mature industrial IoT system usually runs both:

  • Modbus for simple sensors, legacy instruments, and cost-sensitive slave devices. Register addresses are fixed and the protocol stack is lightweight; a single RS-485 bus can carry dozens of Modbus RTU slaves.
  • OPC UA for complex devices that need semantic interoperability, system-level integration, and cross-vendor interaction. If the device itself supports OPC UA (many Siemens and Rockwell controllers have it built in at the firmware level), using the OPC UA driver directly saves a great deal of address-mapping maintenance.

Many gateway products in the field support both Modbus and OPC UA, converting protocols between Modbus devices and OPC UA servers. A three-tier network pattern is common: sensors and instruments hang on the Modbus bus, a PLC acts as a concentrator exposing an OPC UA server to the upper layer, and IoT DC3 connects to the PLC through its OPC UA driver. This keeps the simple devices at the bottom compatible while gaining semantic integration and security control at the top.

10.2.3 Edge Gateways and Data Preprocessing

From Modbus's RS-485 serial lines to OPC UA's Ethernet, and on to the 4-20mA analog interfaces still used by large numbers of legacy devices, the field's communication protocols, electrical interfaces, baud rates, and byte orders are wildly uneven. If every link chooses raw pass-through — letting devices hold long connections directly to the cloud platform — what you face is not just peak pressure on network bandwidth but also the risk of field control cycles being disrupted by polling delays. That is why a layer of edge gateways must sit between the production line and the cloud platform. It is not a simple relay; it is the core node of the "device-edge-cloud" three-tier architecture that carries protocol conversion, data preprocessing, and local caching. These three responsibilities determine the quality and robustness of the acquisition chain — the engineering dividing line between "able to connect" and "connecting well."

Protocol Conversion: Unifying the Fragments

The most immediate need is to unify heterogeneous protocols into a single data model the platform layer can understand. An industrial edge gateway typically ships with dozens of device drivers and can simultaneously host Modbus RTU slaves at different addresses on an RS-485 bus, OPC UA servers on Ethernet, and even devices with proprietary TCP protocols. Conversion is not simple byte shuffling: which OPC UA NodeId does Modbus register address 40001 map to? By what scaling factor is a 4-20mA analog channel converted into engineering values (for example, 4mA corresponding to 0 °C and 20mA to 150 °C)? These mappings must be predefined in the gateway's configuration tool, forming a version-manageable "point mapping table."

The engineering difficulty of protocol conversion lies not in "being able to convert" but in "being configurable and traceable." A well-designed gateway lets operations staff update mappings dynamically without restarting devices, and writes both the raw value and the result of every conversion into logs. This is not mere redundant logging — it is the starting point of the data lineage that digital twins require. When an abnormal temperature appears on the line, an engineer should be able to trace back to "this 135 °C originally corresponded to bytes 3-4 of Modbus holding register 40100." Without that capability, troubleshooting means re-checking the entire link from scratch — extremely inefficient.

Data Preprocessing: Less Volume, No Loss of Quality

The cloud platform does not need every millisecond-level raw waveform; what it cares about are trends and events. The edge gateway can perform three operations locally: filtering to remove sensor glitches and power-supply noise; downsampling to compress 1 kHz vibration data into 1 Hz means or extremes; and threshold evaluation to produce event-based reporting — for example, transmitting once only when "temperature above 85 °C persists for 10 seconds," rather than pushing the raw over-limit status on every acquisition cycle.

The value of these preprocessing steps is not computational "savings" but semantic "concentration." The gateway can tag each collected point — device number, workstation, measurement range, unit — so that by the time data reaches the platform it is already a contextualized PointValue (value + semantics + timestamp + tenant), not meaningless raw bytes. The normalization pipeline between IoT DC3's driver layer and its Data Center is realized precisely through such preprocessing. What preprocessing produces determines which logic the downstream rule engine can trigger and what the AI model can "make sense of" — an engineering judgment.

Offline Caching and Resumable Transfer

Network reliability on the factory floor is far lower than in the office. Fiber cut by a forklift, switches rebooting at random, Wi-Fi signals blocked by metal shelving — disconnection is the norm, not the exception. The edge gateway must keep collecting during network outages, buffering to local flash or an SD card; once the network recovers, it re-transmits the missing data in timestamp windows without overwriting newly collected values. The core of resumable transfer is an ordered timestamp queue: every data record carries a globally increasing timestamp; the platform side uses the stamps to detect missing intervals and requests exactly the back-fill it needs from the gateway.

Cache capacity calls for engineering judgment. An example: a workshop with 200 acquisition points, one snapshot per second, about 17 million records a day. Field gateways are typically configured with tens to a hundred-plus GB of flash and a circular overwrite policy — keep the most recent N days, and drop older data or archive it weekly. The key trade-off in this policy: the longer the history retained, the more complete the resumable transfer, but the greater the local storage pressure; engineering practice usually takes "one long weekend plus one working day" as the baseline, covering a window of roughly 72-120 hours. If longer retention is needed for local offline analysis, the usual choice is tiered storage — metadata stays on flash, while raw waveforms are offloaded to external storage nodes.

Deployment: An Electronics Assembly Line

An example: an electronics assembly line deploys 4 reflow ovens, 6 pick-and-place machines, and 2 AOI (Automated Optical Inspection) units. The reflow ovens output their temperature profiles over Modbus RTU (6 measurement points); the pick-and-place machines expose nozzle pressure and rotation speed via OPC UA; the AOI units output defect coordinates over a proprietary TCP protocol. One edge gateway, installed in an IP54 cabinet beside the line, connects to all three device classes at once. Inside the gateway run three driver stacks: a Modbus RTU master polling the 4 ovens, an OPC UA client subscribing to the 6 pick-and-place machines, and a TCP socket parser receiving the AOI data streams. It polls all points once per second; oven temperatures are downsampled to max-min-average and reported over MQTT; AOI defects are reported only as detection events (raw coordinates stay local). The gateway is configured with about 64 GB of storage, retains 72 hours of history, keeps collecting normally when the network is down, and automatically back-fills the unacknowledged time intervals once the network recovers.

Under this configuration, what the cloud platform receives is not 200 raw values per second but aggregated, event-based data — traffic drops markedly, while the oven-temperature extremes needed for diagnosing line anomalies are not lost. Here the edge gateway acts as the first gatekeeper of data quality.

The edge gateway is not an accessory; it is the engineering backbone of industrial IoT's "last mile." Protocol conversion solves connectivity, data preprocessing solves consumability, and offline caching solves survivability — miss any one of the three and the acquisition chain is unreliable. And one of the core values of IoT DC3's driver architecture is precisely to peel these responsibilities out of business code and hand them to dedicated driver modules, freeing developers to focus on higher-level business logic. The discussion that follows covers time-series storage and rule-engine design after data reaches the platform — and the clean, semantically tagged data the edge gateway delivers is the foundation of all intelligence above it.

From Industrial Software to AI Agents · Building a multi-protocol, cloud-native, open-source industrial IoT platform ready to evolve toward AI agents