Skip to content

Modbus Device Service Component

The Modbus Device Service component provides communication and control with devices supporting the Modbus protocol. Modbus supports communication using either RS485 serial or Ethernet connections. These are referred to as RTU and TCP/IP respectively.

Using the device service with Modbus RTU differs subtly from using it for Modbus TCP connections, we will cover the differences on this page.

Key Features

The Modbus Device Service supports the following key features:

  • Read. Data can be read from each primary table using the appropriate function code:
Primary Table Modbus Function
Coils 1
Discrete Inputs 2
Holding Registers 3
Input Registers 4
  • Write. Data can be written to each writable primary table using the appropriate function code:
Primary Table Modbus Function
Coils (Single Coil) 5
Holding Registers (Single Register) 6
Coils (Multiple Coils) 15
Holding Registers (Multiple Registers) 16
  • Support for Modbus RTU connection types
  • Support for Modbus TCP/IP connection types
  • Batch read operation. Read multiple values in a single Modbus call from each primary table, using the function codes seen in the first table above
  • Batch write operation. Write multiple values in a single Modbus call to each writable primary table, using the function codes seen in the second table above

Note

XRT can be configured to automatically group schedules together creating larger batched readings, improving efficiency and throughput. For information on how to configure this feature please refer to the AutoBatchSize and AutoBatchTimeout settings described in Device Service Component Configuration.

Modbus Device Service Configuration

Note

Since there are no driver-specific configuration options for Modbus, please refer to Device Service Component Configuration for all the relevant core components that will need populated in order to run the Modbus Device Service.

A template of the Modbus Device Service configuration file is provided:

{
  "Library": "libxrt-modbus-device-service.so",
  "Factory": "xrt_modbus_device_service_factory",
  "Name": "modbus",
  "TelemetryTopic": "xrt/devices/modbus/telemetry",
  "RequestTopic": "xrt/devices/modbus/request",
  "ReplyTopic": "xrt/devices/modbus/reply",
  "StateDir": "./deployment/state",
  "ProfileDir": "./deployment/profiles",
  "Scheduler": "sched",
  "Logger": "logger",
  "ThreadPool": "pool",
  "Bus": "bus"
}

Modbus Device Profile

Details on general profile usage can be found on the Device Profiles page.

The following sections will cover how device resources are mapped to Modbus properties.

Required Resource Attributes

Ensure that the following attributes are defined for each resource in the device profile:

Attribute Description Valid Values
primaryTable Identifies the primary table. The primary table must be one of the following:
  • HOLDING_REGISTERS
  • INPUT_REGISTERS
  • COILS
  • DISCRETE_INPUT
startingAddress The address at which to start reading/writing in the Modbus device's representation of memory. This attribute defines the zero-based starting address. For example, to read data from the Modbus address 4004, the startingAddress attribute should be 4003. Any UInt16 value

Once we run a command, device-modbus will know its value type and register type, startingAddress, and register length. This allows it to read or write a value using the Modbus protocol.

Other Resource Attributes

The other (optional) attributes used in a Modbus device resource are described in the following table:

Attribute Description Valid Values
rawtype Defines the binary data read from the Modbus device and uses a value descriptor data type to identify the data type that the user wants to receive Valid string values are as follows:
  • INT16
  • UINT16
isByteSwap Defines whether to swap the byte on reading little-endian data to transform to big-endian format.

The Modbus Device Service uses big-endian format.

If the Modbus device uses little-endian format, set this attribute to true to correctly convert the data.
true, false
isWordSwap Defines whether to use 16-bit segments, also known as words, to re-order the byte sequence with big-endian or little-endian formats

To re-order the byte sequence, set this attribute to true
true, false
boolIndex Retrieves the bool value from the specified bit of a register The default is 0

For HOLDING_REGISTER and INPUT_REGISTERS, the valid range is 0 to 15, inclusive

For COILS and DISCRETE_INPUT, the value is 0
stringEncoding The supported string encoding Valid values are UTF8 or ASCII

Default is UTF8
stringRegisterSize Defines the capacity of the device resource for the string data Valid range is from 1 to 123 , inclusive

Default is 1

For example, to store the "Hello World" string in ASCII encoding, we need 96 bits (12 characters multiplied by 8 bits), so the required stringRegisterSize would be 6 (96 bits divided by 16 bits)

For the read command, the Modbus device reads the data types from the specified startingAddress for the length specified in the stringRegisterSize and parses the binary data to a sting with the encoding specified in stringEncoding

For the write command, the Modbus device checks that the parameter is a valid string in the specified encoding, converts the string to data bytes and writes it back to the register
scale The scaling factor applied to values during processing of requests. The type of scaling (on writes only, reads only, or both) can be assigned using the `scaleType` attribute, as described below. Valid range is from 0 to 1

The value assigned will be the factor that is multiplied by the stored value on reads, and will be used to divide the value on writes. For example, a scaling factor of 0.1 will transform a value of 10 to instead be 100 as represented in internal memory.

The value used for the scaling factor should be assigned with respect to the maximum values allowed for the valueType assigned. A value scaled to beyond the maximum available value may be truncated by the datatype used. For example, writing a value to a resource with valueType "UINT16" should not result in the scaled value exceeding 65,535, the maximum value of UINT16. Any value scaled beyond this could lead the value to be truncated in memory.

Default is 1
scaleType Defines whether scaling is applied on reads, writes, or both. Valid values are 'R', 'W', and 'RW'.

Default is 'RW'

A 'R' value will allow for scaling to be applied only when values are read into the device service.

A 'W' value will allow for scaling to be applied only when values are written to device memory.

A 'RW' value will allow for scaling to be applied on both reads and writes. This will effectively appear as the same value on both sides of the operations, but inspecting the internal memory of the device will show that the scaling factor has been applied. This allows for precision to be maintained in integer-based memory registers.

Data Types

When the device receives a request, it returns a value with a Modbus type. The following table lists the supported Modbus data types, their equivalent Xrt data types, the supported read / write abilities, and how many 16-bit registers are used to store the data:

Modbus Data Type Xrt Data Type Read/Write Ability Number of 16-bit Registers Used
Bit Boolean RW 1
String String RW Dependant on string encoding
Signed 8-bit Int Int8 RW 1
Unsigned 8-bit Int UInt8 RW 1
Signed 16-bit Int Int16 RW 1
Unsigned 16-bit Int UInt16 RW 1
Signed 32-bit Int Int32 RW 2
Unsigned 32-bit Int UInt32 RW 2
32-bit Float Float32 RW 2
Signed 64-bit Int Int64 RW 4
Unsigned 64-bit Int UInt64 RW 4
64-bit Double Float64 RW 4

Example Device Resources

The following section provides examples of some device resources mapped to Modbus properties.

  • The extract from a device profile shown below reads the 'Current' property, whose unsigned 16-bit int value is found at address 9 of the holding table registers.
Location Description
Primary Table Holding Registers
Starting Address 9
Property Current
Modbus Data Type Unsigned 16-bit Int
Xrt Data Type UInt16
Read/Write Access RW
{
  "name": "Current",
  "description": "Average current of all phases",
  "attributes": {
    "primaryTable": "HOLDING_REGISTERS",
    "startingAddress": 9
  },
  "properties": {
    "valueType": "UInt16",
    "readWrite": "RW"
  }
}
  • The extract from a device profile shown below reads the 'Energy' property, whose 32-bit float value is found at address 4001 of the holding registers.
Location Description
Primary Table Holding Registers
Starting Address 4001
Property Energy
Modbus Data Type 32-bit Float
Xrt Data Type Float 32
Read/Write Access RW
{
  "name": "Energy",
  "description": "System Total True Energy",
  "attributes": {
    "primaryTable": "HOLDING_REGISTERS",
    "startingAddress": 4001
  },
  "properties": {
    "valueType": "Float32",
    "readWrite": "RW"
  }
}
  • The extract from a device profile shown below reads the 'IsRunning' property, whose boolean value is found at address 1 of the coils.
Location Description
Primary Table Coils
Starting Address 1
boolIndex 0
Property FanSpeedAvg
Modbus Data Type Bit value
Xrt Data Type Bool
Read/Write Access RW
{
  "name": "IsRunning",
  "description": "Boolean value indicating whether system is running.",
  "attributes": {
    "primaryTable": "COILS",
    "startingAddress": 1,
    "boolIndex": 0
  },
  "properties": {
    "valueType": "Bool",
    "readWrite": "RW"
  }
}
  • The extract from a device profile shown below reads the 'FanSpeedAvg' property, whose 16-bit signed int value is found at address 1000 of the holding registers. This example utilises scaling via the raw type identified. In this case, the value stored in the register will be multiplied by 0.01 to obtain the float 32 value.

    For example, a read value of 2250 would become 22.50. See the Device Profiles page for more information on scaling factors in Edge Xrt.

Location Description
Primary Table Holding Registers
Starting Address 1000
Raw Type INT16
Scaling Factor 0.01
Scaling Type RW
Property FanSpeedAvg
Modbus Data Type 32-bit Float
Xrt Data Type Float 32
Read/Write Access RW
{
  "name": "FanSpeedAvg",
  "description": "Average fan speed for the system.",
  "attributes": {
    "primaryTable": "HOLDING_REGISTERS",
    "startingAddress": 1000,
    "rawType": "INT16",
    "scale": 0.01,
    "scaleType": "RW"
  },
  "properties": {
    "valueType": "Float32",
    "readWrite": "RW"
  }
}

Device Commands

See the Device Profiles page for details on how to define device commands for grouping device resources for fewer requests

Modbus Device Provisioning

The following sections will explain how devices can be statically configured for both Modbus-TCP and Modbus-RTU device services.

Note

For information on dynamic device additions, removals and updates please see the MQTT API Guide.

Modbus Protocol Properties

The available Modbus protocol properties are described in the following table:

Protocol Property Description Valid Values Required
UnitID The station identifier Values up to 247 Yes
Address For Modbus TCP/IP, the IP address or host name

For Modbus RTU, the path to the serial device
When using TCP, a valid IP address

When using RTU, a valid serial address
Yes
Port Used for Modbus TCP/IP only

The TCP port of the Modbus device
Any valid port number Yes (for Modbus TCP/IP)
BaudRate Used for Modbus RTU only

The baud rate for a serial device

The provided baud rate must match for devices using the same address
Unsigned integer Yes (for Modbus RTU)
DataBits Used for Modbus RTU only

The number of bits of data
Valid values are as follows:
  • 7
  • 8
Yes (for Modbus RTU)
StopBits Used for Modbus RTU only

The number of stop bits
Valid values are as follows:
  • 1
  • 2
Yes (for Modbus RTU)
Parity Used for Modbus RTU only

The parity value

Specify N for no parity

Specify E for even parity

Specify O for odd parity
Valid values are as follows:
  • N
  • E
  • O
Yes (for Modbus RTU)

Modbus-TCP Device Provisioning Example

To provision a Modbus-TCP device, the modbus-tcp protocol must be used along with the relevant protocol properties provided in the table above.

An example of a Modbus-TCP device provision within the devices.json file is provided below:

{
  "modbus-sim": {
    "profileName": "modbus-sim-profile",
    "protocols": {
      "modbus-tcp": {
        "Address": "127.0.0.1",
        "Port": 502,
        "UnitID": 1
      }
    },
    "name": "modbus-sim"
  }
}

Modbus-RTU Device Provisioning Example

To provision a Modbus-RTU device, the modbus-rtu protocol must be used along with some protocol properties:

An example of a Modbus-RTU device is provided below:

{
  "modbus-sim": {
    "profileName": "modbus-sim-profile",
    "protocols": {
      "modbus-rtu": {
        "Address": "/tmp/slave",
        "UnitID": 1,
        "BaudRate": 9600,
        "DataBits": 8,
        "StopBits": 1,
        "Parity": "N"
      }
    },
    "name": "modbus-sim"
  }
}

Modbus Device Service Interaction

For information on how to dynamically execute reads, writes, setting up schedules, and much more, please refer to the MQTT API Guide.

For interactive examples of the Modbus-TCP and Modbus-RTU Device Services refer to the Modbus-TCP Xrt Example and Modbus-RTU Xrt Example projects. Follow the instructions in that example to demonstrate many features of Edge Xrt with the device service running against a Modbus simulator.

Run the Modbus Device Service

Find details on how to run the Modbus Device Service on the Run Device Services page.