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

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 Driver Options

The Modbus Device Service can also make use of additional driver options. These can be added to the configuration file under the "Driver" field.

Parameter Type Description Default Value
LegacyStringOrdering Boolean Enable to use an older method of string ordering, where each string is byte-swapped by default. When this option is enabled string ordering cannot be otherwise configured. false
DefaultRequestTimeout UInt32 The default time in milliseconds to wait for a response from devices without a RequestTimeout property 500ms
DisableRequestRetries Boolean By default the Modbus Device Service will automatically retry any requests that fail. To disable this, this driver option can be set to true. false

Example usage:

{
  "Library": "libxrt-modbus-device-service.so",
  ...
  "Bus": "bus",
  "Driver": {
    "LegacyStringOrdering": true,
    "DefaultRequestTimeout": 300,
    "DisableRequestRetries": true
  }
}

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_INPUTS
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.

Note: Using a 32-bit rawType with a valueType of Float32 or using a 64-bit rawType with either valueType may result in a loss of precision due to the valueType not being able to perfectly represent all possible integer values.

Valid string values are as follows:
  • Int8
  • UInt8
  • Int16
  • UInt16
  • Int32
  • UInt32
  • Int64
  • UInt64

Valid valueType values when using a rawType attribute:
  • Float32
  • Float64
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.

Note: The default ordering for string resources is sequential character order. isByteSwap can be used to swap the byte order from this default configuration.
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

Note: The default ordering for string resources is sequential character order. isWordSwap can be used to swap the word order from this default configuration.
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_INPUTS, 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. Any numeric value.

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.

Note: Applying a scale to a large Int64/Uint64 value may result in a loss of accuracy.

Only one of "scale" or "scaleAddress" may be used.
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.
additive Value to be added to the result of a get request, or subtracted from the value within a put request. Any value for which the result of the addition/subtraction will remain within the limits of the valueType of the resource. An additive value producing a result outside these limits will cause a failure upon a get/put request.

Note: For resources with Int64/UInt64 valueTypes only, the lowest possible additive value is the minimum limit of an Int64.
additiveReadWrite Defines whether additive is applied to reads, writes, or both. Valid values are "R", "W", or "RW"

Default is "RW"
scaleAddress Address at which the scale factor for this resource can be found. The register must contain an Int16 value which determines how the decimal point should be shifted in the resource value. For example, a scaleAddress register containing the Int16 value -3 would equate to a scale factor on the resource of 0.001. Valid values are any valid register address within the same table as the resource.

Only one of "scale" or "scaleAddress" may be used.

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 Bool 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 Modbus RTU - 1 to 247.

Modbus TCP - 1 to 247 or 255. (A value of 255 is used to communicate directly with the device/gateway connected over TCP)
Modbus RTU - Yes.

Modbus TCP - No, Default 255.
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)
ReadMaxHoldingRegisters Maximum holding registers supported by the device per read operation. Any UInt16 value. No - Default: 125
ReadMaxInputRegisters Maximum input registers supported by the device per read operation. Any UInt16 value. No - Default: 125
ReadMaxBitsCoils Maximum bits supported by the device per read operation on coils. Any UInt16 value. No - Default: 2000
ReadMaxBitsDiscreteInputs Maximum bits supported by the device per read operation on discrete inputs. Any UInt16 value. No - Default: 2000
WriteMaxHoldingRegisters Maximum holding registers supported by the device per write operation. Any UInt16 value. No - Default: 123
WriteMaxBitsCoils Maximum bits supported by the device per write operation on coils. Any UInt16 value. No - Default: 1968
RequestTimeout Time in milliseconds to wait for a response from this modbus slave. Any UInt32 value. No - Default: 500ms or value supplied in the DefaultRequestTimeout driver option if set.
LinkRecovery Enables a connection error recovery mode. This will cause the connection to the device to be closed and reopened if a timeout occurs during communication with device. Timed out write requests will be re-attempted until successful. Timed out read requests will be re-attempted once. Boolean No - Default: false

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,
        "WriteMaxHoldingRegisters": 1
      }
    },
    "name": "modbus-sim"
  }
}

Note

WriteMaxHoldingRegisters is an optional field. In this example a value of 1 is used, meaning this device only supports writing to one holding register at a time.

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",
        "ReadMaxHoldingRegisters": 5
      }
    },
    "name": "modbus-sim"
  }
}

Note

ReadMaxHoldingRegisters is an optional field. In this example a value of 5 is used, meaning this device only supports reading up to five holding registers at a time.

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.