Skip to main content
Version: 1.20.0

Modbus

The Modbus TCP and RTU agents allow integration of Modbus devices into OpenRemote, enabling communication via Ethernet (TCP) or Serial (RTU).

How It Works

In OpenRemote, Modbus agents act as Modbus masters, communicating directly with Modbus slave devices. The agent manages the connection parameters (TCP or Serial) and facilitates reading and writing data to specified registers or coils of the connected Modbus devices. The agents can optimize their read requests by batching multiple registers in one call. This is disabled by default (see batched requests).

Configuring a Modbus Agent

You can configure either Modbus TCP or Modbus RTU agents:

Modbus TCP Agent

ParameterDescriptionRequiredDefault
hostIP address or hostname of the Modbus deviceYes-
portTCP port number of the Modbus deviceYes-
deviceConfigDevice (unitID) specific settings, applies "default" setting unless a specific UnitID config is addedNoauto-populated with defaults

Modbus RTU Agent

ParameterDescriptionRequiredDefault
serialPortSerial port identifier (e.g., /dev/ttyUSB0)Yes-
serialBaudrateBaud rate for serial communicationNo9600
dataBitsNumber of data bits per frameNo8
parityParity bit setting (NONE, ODD, EVEN)NoEVEN
stopbitsNumber of stop bits (STOPBITS_1, STOPBITS_2)NoSTOPBITS_1
deviceConfigDevice (unitID) specific settings, applies "default" setting unless a specific UnitID config is addedNoauto-populated with defaults

Device Config

While the above settings are applicable for all devices on the bus port, some settings can vary per device (unitId / modbus device address). The "default" setting is applied to all unitID's unless specified otherwise. If you have a unitID on the bus requiring a different config, add an extra property to the config with that unitID as name. For example, a specific config for unitID 1 would be:

Device Config Example:

{
"default": {
"endianFormat": "BIG_ENDIAN",
"illegalRegisters": "",
"maxRegisterLength": 1
},
"1": {
"endianFormat": "LITTLE_ENDIAN",
"illegalRegisters": "23,24,100-200",
"maxRegisterLength": 40
}
}

Valid parameters are:

ParameterDescription
endianFormatByte endianness: BIG_ENDIAN (ABCD), LITTLE_ENDIAN (DCBA), BIG_ENDIAN_BYTE_SWAP (BADC), LITTLE_ENDIAN_BYTE_SWAP (CDAB)
illegalRegistersRegisters not supported by the device (e.g. "23,24,100-200")
maxRegisterLengthMaximum amount of registers in one request (default: 1)

Batched requests

The settings illegalRegisters and maxRegisterLength are used to setup combined registers read into a single request. This can significantly reduce traffic on the bus and reduce response times. By default, maxRegisterlength is set to 1, resulting in no batching. When raising maxRegisterLength, illegalRegister must be used to take into account register ranges that are invalid for that specific device. For example, when agentlinks are setup to register 1 and 20, this will be combined in one call if maxRegisterLength > 20. However, if a call to register 19 results in an exception response by the device, this will fail, so you would then need to add 19 to illegalRegisters. The agent forms groups of batches based on identical requestInterval, unitID, and readMemoryArea.

Each asset attribute can link to the Modbus agent via an Agent Link. Below are the parameters required:

ParameterDescriptionRequired
Read AddressRegister or coil addressYes (for read)
Read Memory AreaRegister type (COIL, DISCRETE, HOLDING, INPUT)Yes (for read)
Read Value TypeData type (BOOL, INT, UINT, DINT, REAL, etc.). Also used for multi-register write conversions.Yes (for read)
Write AddressRegister or coil address for writeYes (for write)
Write Memory AreaRegister type for write (COIL, HOLDING)Yes (for write)
Unit IdModbus device address (1–255). Required for reading. Writes default to 1 if omitted. For TCP, this is typically 1 unless connecting through a Modbus gateway.Yes (for read)
Request IntervalInterval between reads/writes in milliseconds (minimum: 1000). If not set, reads execute once on connection and writes execute on demand only.Optional
Registers AmountAmount of registers to read/write (automatically determined from data type if not set)Optional

Important: Modbus addressing in OpenRemote is 1-based. Address 1 maps to PDU address 0x0000.

Example Attribute Link:

{
"readAddress": 24,
"readMemoryArea": "HOLDING",
"readValueType": "UINT",
"writeAddress": 24,
"writeMemoryArea": "HOLDING",
"unitId": 1,
"requestInterval": 5000
}

Data Types

OpenRemote Modbus integration supports various data types:

  • BOOL: Boolean (single-bit)
  • SINT/USINT/BYTE: 8-bit integer (signed/unsigned)
  • INT/UINT/WORD: 16-bit integer (signed/unsigned)
  • DINT/UDINT/DWORD: 32-bit integer (signed/unsigned)
  • LINT/ULINT/LWORD: 64-bit integer (signed/unsigned, terms as long or BigInteger may be used for very large values)
  • REAL: 32-bit floating-point
  • LREAL: 64-bit floating-point
  • CHAR/WCHAR: Character (single or wide, represented as char or String)

Example Configuration

Here’s a full example configuration for a Modbus TCP temperature sensor:

Agent Configuration:

{
"host": "192.168.1.50",
"port": 502,
"deviceConfig": {
"default": {
"endianFormat": "BIG_ENDIAN",
"illegalRegisters": "",
"maxRegisterLength": 1
}
}
}

Agent Link Configuration:

{
"readAddress": 23,
"readMemoryArea": "INPUT",
"readValueType": "REAL",
"registersAmount": 2,
"requestInterval": 60000,
"unitId": 1
}

Under the Hood

The Modbus agent is written for openremote natively. This enables thorough integration into the openremote attribute event model. When you configure a linked attribute with a Read setting along with a request interval, the agent schedules periodic read requests to the device (using the specified function code based on Read Type, e.g. function 0x03 for holding registers or 0x01 for coils, etc.). The response is parsed according to the Read Value Type (e.g. UINT, BOOL, etc.) and then the attribute's value is updated in OpenRemote. With only writing active, the request acknowledgement will be used to determine whether the write was successful, and the attribute value is updated locally. However, it may be the case that you write a setpoint register but want to update the value from another register which holds the actual value (the device may have limits for example). In that case, enable both reading and writing. You can do that either on the same or a different register, depending how the device works. When both reading and writing are active, instead of using the request acknowledgement, the value is immediately read back with a read request after the write request.

Read/Write Interval & Combinations

Read ConfiguredWrite ConfiguredRequest Interval SetResulting Behavior
yesnonoone time read after agent connects
noyesnoonly writes after attribute is manipulated
yesyesnoone time read after agent connects, only writes after attribute is manipulated, then reads back.
yesnoyescyclic reads
noyesyescyclic writes (re-sends the current attribute value each interval)
yesyesyescyclic reads; writes are on-demand when the attribute value changes, followed by a verification read

Note on addressing: Remember that OpenRemote uses 1-based addressing for Modbus. This is a common source of confusion. Always confirm whether your device documentation lists register addresses starting at 1 or 0, and adjust accordingly. For instance, if a device documentation refers to "Register 100" (but is zero-based), you might actually need to use 101. However, if it refers to "Register 40001" (Modbus convention for first holding register), you should use 1. The OpenRemote Modbus agent ultimately converts your given address into the proper Modbus PDU address (e.g. address 1 will be sent as 0x0000 in the request).

Note on data types: Most standard types are available. For example, if you need to read a 32-bit integer split across two registers (as many devices use), you can choose DINT or UDINT. If you need a 32-bit float, choose REAL. The agent will automatically read the necessary number of registers (two for 32-bit, four for 64-bit, etc.) in one request. If you select a 64-bit type (LINT, ULINT, LREAL), note that it will read four consecutive 16-bit registers (since Modbus registers are 16-bit each) to assemble the 64-bit value. Ensure that adjacent registers are free or belong to the same value in your device, otherwise you might get incorrect data. Booleans (BOOL) correspond to single bits when used with coils or discrete inputs. If you use BOOL on a register type (holding/input), any non-zero register value is interpreted as true. Note that there is no separate write value type; multi-register writes use the read value type for data conversion.

In summary, the Modbus agent allows you to bring data from PLCs, power meters, sensors, and other Modbus-based devices into OpenRemote, and to control those devices, using the Modbus protocol. By setting up the agent with the correct connection parameters and linking attributes with the proper register type, address, and data type, you can integrate Modbus data seamlessly into your OpenRemote project. The flexible configuration (separating read and write settings) accommodates devices that use distinct registers for status and control, and the use of standard data type definitions makes it easier to handle multi-register values. The ongoing documentation efforts and community feedback (see OpenRemote forums) are refining this feature, but with the information above, you should be able to get started with Modbus integration in OpenRemote. Modbus requests have a 3-second timeout.