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:
|
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:
|
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:
|
Yes (for Modbus RTU) |
StopBits |
Used for Modbus RTU only
The number of stop bits |
Valid values are as follows:
|
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:
|
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.