Skip to content

Modbus Device Service Example

This example shows how to use the Modbus Device Service. It is located in the device-modbus-c directory. It also demonstrates how XRT can be used to communicate with a Modbus-compliant slave device. A Java Modbus simulator, ModbusPal, has been used as an alternative to a physical Modbus TCP/IP device.

When the example is run, a container is instantiated and populated with components. The container uses component factories to manage components, which are specified in the config/main.json file. Each entry for a component in this file specifies the following:

  • The name of the component, for example: modbus_device_service
  • The name of the registered factory used to create the component, for example: XRT::ModbusDeviceService

The components used in this example are as follows:

Each component can be configured using the associated JSON file; for example, the Modbus Device Service component is configured using the modbus_device_service.json file. For further information on configuration of the Modbus Device Service component, see Modbus Device Service Component.

Example Configuration File

The modbus_device_service.json configuration file used for this example does the following:

  • Specifies a device instance, which is created at runtime based on the DENT.Mod.PS6037.profile.json device profile
  • Configures a schedule, which obtains a reading every two seconds from the Network Power Meter

The configuration file is as follows:

{
 "Library": "libxrt-modbus-device-service.so",
 "Factory": "xrt_modbus_device_service_factory",
 "Name":"modbus_device_service",
 "Topic":"modbus_device_service/data",
 "Devices":{
  "Network-Power-Meter-Simulation":{
   "profile":"Network Power Meter",
   "protocols":{
    "modbus-tcp":{
     "Address": "${MODBUS_DEVICE_ADDRESS}",
     "Port": "1502",
     "UnitID": "1"
    }
   }
  }
 },
 "Schedules":[
  {
   "device": "Network-Power-Meter-Simulation",
   "resource": "Current",
   "interval": 2000000
  }
 ],
 "ProfileDir":"config/profiles",
 "Scheduler":"sched",
 "Logger":"logger",
 "ThreadPool":"pool",
 "Bus":"bus"
}

Example Device Profile

In this example, the DENT.Mod.PS6037.profile.json device profile is used to represent the Network Power Meter IoT device that ModbusPal simulates. The device profile defines a device resource, named Current. The values of the primaryTable and startingAddress attributes for this device resource have been set to match the configuration of the Modbus slave.

The device profile is as follows:

{
 "name": "Network Power Meter",
 "manufacturer": "Dent Instruments",
 "model": "PS3037",
 "description": "Power Scout Meter",
 "labels": [
  "modbus",
  "powerscout"
 ],
 "deviceResources": [
  {
   "name": "Current",
   "description": "Average current of all phases",
   "attributes": {
    "primaryTable": "HOLDING_REGISTERS",
    "startingAddress": "9"
   },
   "properties": {
    "value": {
     "type": "UINT16",
     "scale": "1"
    },
    "units": {
     "type": "String",
     "readWrite": "R",
     "defaultValue": "min"
    }
   }
  }
 ]
}

Run ModbusPal

To replicate the slave configuration applied in the device profile using ModbusPal. ModbusPal must be run as follows:

  1. Download ModbusPal
  2. On a Debian-based system only, install java using the following command:
    sudo apt install librxtx-java
    
  3. Start ModbusPal using the following command:
    sudo java -jar ModbusPal.jar
    
  4. Create a file named NetworkPowerMeter.xmpp using the following command:
    touch NetworkPowerMeter.xmpp
    
  5. Copy the following to the created XMPP file:

    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE modbuspal_project SYSTEM "modbuspal.dtd">
    <modbuspal_project>
    <idgen value="1"/>
    <links selected="TCP/IP" >
    <tcpip port="1502" />
    <serial com="COM 1" baudrate="9600" parity="even" stops="1">
    <flowcontrol xonxoff="false" rtscts="false"/>
    </serial>
    </links>
    <automation name="Current" step="1.0" loop="false" init="0.0">
    <generator class="LinearGenerator" duration="30.0">
    <start value="0.0" relative="false"/>
    <end value="30.0" relative="false"/>
    </generator>
    </automation>
    <slave id="1" enabled="true" name="Network Power Meter" implementation="modbus">
    <holding_registers>
    <register address="8" value="0" name="Current">
    <binding automation="Current" class="Binding_SINT16" order="0"/>
    </register>
    </holding_registers>
    <coils>
    </coils>
    <tuning>
    <reply_delay min="0" max="0" />
    <error_rates no_reply="0.0" />
    </tuning>
    </slave>
    </modbuspal_project>
    

  6. Save the NetworkPowerMeter.xmpp file

  7. In ModbusPal, select the Load button, as illustrated below:

    ModbusPal

    The Open dialog box displays

  8. In the Open dialog box, locate the touch NetworkPowerMeter.xmpp file, and select the Open button, as illustrated below:

    ModbusPal Open dialog box

  9. Select the Start All button, as illustrated below:

    ModbusPal StartAll dialog box

  10. Select the Run button, as illustrated below:

    ModbusPal Run dialog box

Run the Example

To run the Modbus Device Service example, complete the following steps:

  1. Ensure that the modbus_device_service.json file, and any other required configuration files such as device profiles, are in the config directory

  2. Set the MODBUS_DEVICE_ADDRESS variable, which is used in the Address value of the modbus_device_service.json, to the address of your device.

    For example, if using ModbusPal to simulate a Modbus slave locally, you can use the following command to set Address to 127.0.0.1:

    export MODBUS_DEVICE_ADDRESS=127.0.0.1
    
  3. Run the simulation that has been loaded to ModbusPal

  4. Run the XRT executable for 10 seconds using the following commands:

    cd examples/modbus
    xrt config 10
    
    The output is similar to the following:
    [xrt:1610910789:console:Debug] modbus_init
    [iot-0-0:1610910789:console:Debug] get_connection: Network-Power-Meter-Simulation -> 0x7f4b54000b60
    [iot-0-0:1610910789:console:Debug] modbus get time = 3104 usec
    [iot-0-0:1610910789:console:Debug] publish: {"device":"Network-Power-MeterSimulation","resource":"Current","readings":{"Current":{"value":12,"type":"uint16"}}}
    [iot-0-1:1610910791:console:Debug] modbus get time = 1205 usec
    [iot-0-1:1610910791:console:Debug] publish: {"device":"Network-Power-MeterSimulation","resource":"Current","readings":{"Current":{"value":14,"type":"uint16"}}}
    [iot-0-0:1610910793:console:Debug] modbus get time = 1241 usec
    [iot-0-0:1610910793:console:Debug] publish: {"device":"Network-Power-MeterSimulation","resource":"Current","readings":{"Current":{"value":16,"type":"uint16"}}}
    [iot-0-1:1610910795:console:Debug] modbus get time = 1181 usec
    [iot-0-1:1610910795:console:Debug] publish: {"device":"Network-Power-MeterSimulation","resource":"Current","readings":{"Current":{"value":18,"type":"uint16"}}}
    [iot-0-0:1610910797:console:Debug] modbus get time = 1254 usec
    

Back to top