lib modbus

OverviewSupported ProtocolsRegister MapCurrent PointsWritable PointsHistoryBlock Reads


The ModbusExt implements connector support for Modbus protocol.

Supported Protocols

ModbusExt supports two protocols for accessing Modbus slave devices:


To setup a connector to access a Modbus slave over TCP/IP, we use the modbus-tcp URI scheme:

dis: "Modbus TCP/IP Connector"
uri: `modbus-tcp://host/`
modbusSlave: 1
modbusRegMapUri: `data/modbus/xxx.csv`


To access the slave using serial RTU over a TCP connection, use the modbus-rtutcp scheme:

dis: "Modbus RTU over TCP/IP Connector"
uri: `modbus-rtutcp://host/`
modbusSlave: 1
modbusRegMapUri: `data/modbus/xxx.csv`

Register Map

Modbus connectors are required to define a register map using the modbusRegMapUri tag. The register map specifies which points get read/written out of a Modbus slave. The register map URI must be a path relative to the project's home directory or can be a fan:// URI to a CSV file bundled in a pod.

Register maps are simple CSV files:

name, addr,  data, rw, scale, dis,  unit, tags
ping, 40001, u2,   r,  ,      Ping, ,
do0,  00017, bit,  rw, ,      DO-0, ,
do1,  00017, bit,  rw, ,      DO-1, ,
ai0,  40001, u2,   r,  ,      AI-0, ,
ai1,  40002, u2,   r,  *10,   AI-1, kW,   power


Register address are defined with addr column and specified using Modbus convention:

0xxxx  Coil              00001-065536
1xxxx  Discrete Input    10001-165536
3xxxx  Input Register    30001-365536
4xxxx  Holding Register  40001-465536


A valid ping register is required in order to test connectivity to slave.

Data Type

The data column specifies how register data is modeled.

bit  Bool
u1   Unsigned  8-bit Int
u2   Unsigned 16-bit Int
u4   Unsigned 32-bit Int
s1   Signed  8-bit Int
s2   Signed 16-bit Int
s4   Signed 32-bit Int
s8   Signed 64-bit Int
f4   32-bit Float
f8   64-bit Float

Bit Mask

The bit data type supports a position notation for cases where bits are packed into input or holding registers:

name, addr,  data,  rw
do0,  40101, bit:0, rw
do1,  40101, bit:1, rw
do2,  40101, bit:2, rw

Word and Byte Order

If register data is not stored in network byte order, you can specify the order using a suffix:

u2le   Unsigned 16-bit Int  Little endian byte and word order
u2leb  Unsigned 16-bit Int  Little endian byte order only
u2lew  Unsigned 16-bit Int  Little endian word order only


Read and write permissions are configured using rw column:

rw  Register may be read and written
r   Register is read-only
w   Register is write-only

Scale Factor

An optional scale factor can be applied to registers using the scale column. The scale format is [op] [num] where the factor is a numeric constant.

add:    +1.5
minus:  -0.25
mult:   *10
div:    /1000

Dis, Unit, Tags

The dis, unit, and tags column allow optional pre-configuration for the point during the learn process:

name, addr,  data, rw, dis,  unit, tags
ai1,  40002, u2,   r,  AI-1, kW,   power foo bar

Current Points

Modbus proxy points are configured with modbusCur tag, which maps to a valid register map name:

modbusConnRef: @conn
modbusCur: ai0

Writable Points

Modbus proxy points are configured to write to remote system points via the modbusWrite tag:

modbusConnRef: @conn
modbusWrite: ao5


History synchronization is not supported by Modbus. You will need to use collection to store history.

Block Reads

Modbus connectors will attempt to optimize consecutive registers into a single block read when possible. This behavior can be tuned by adding the modbusBlockGap and modbusBlockMax tags to your modbusConn rec.


By default, blocks require all points to be in truly consecutive registers:

// block 1
40001 u2
40002 u2
40003 u2

// block 2
40005 u2

If you have a small gap in an otherwise sequential run of registers, you can tune to maintain a single read by adding the modbusBlockGap tag to your conn rec. This tag specifies the maximum number of registers that can be skipped for a single block:

modbusBlockGap: 1

// block 1
40001 u2
40002 u2
40003 u2
40005 u2  // 400004 will be read but discarded


By default, blocks are limited to 100 total registers (which includes skipped registers from modbusBlockGap). To force a connector to split blocks into smaller or larger chunks, add the modbusBlockMax tag to your conn rec:

modbusBlockMax: 2

// block 1
40001 u2
40002 u2

// block 2
40003 u2
40004 u2

Be aware a block read failure will result in the entire block's points being marked as fault.