Interfacing Modbus industrial sensors with an open source IIoT gateway - Embedded.com

Interfacing Modbus industrial sensors with an open source IIoT gateway

Industrial internet of things (IIoT) applications typically require an edge gateway to integrate Modbus peripherals and other devices, but implementing a gateway can be costly and time consuming. This article offers a case study of interfacing an industrial sensor with an open source edge computing framework that can significantly simplify deployment.

Industrial Internet of Things (IIoT) technology is growing rapidly. IIoT applications in the field of remote monitoring and advanced analytics are revolutionizing businesses and are offering exemplary benefits to them. The edge computing usually occurs directly on the devices to which the sensors are attached or a gateway device that is physically close to the sensors.

In industrial use cases, where a number of sensors need to be interfaced with edge gateways, solution architects and developers need to decide on software design and development of an edge gateways and how to process data from various sensors and perform data analytics during design and development phase. In such situation, if there is no open source framework, the new software development, bug fixes may consume lot of efforts and cost.

The first article in this two-part series described industrial sensors with use cases and provides an overview of an edge gateway requirements along with a discussion about how edge gateway requirements can be met with EdgeX Foundry—an open source edge computing framework that serves as edge middleware between physical sensing and actuating “things” and an information technology (IT) system (Figure 1).


Figure 1. EdgeX Foundry (Source: www.edgexfoundry.org)

This article offers a case study of interfacing an industrial sensor with EdgeX for achieving edge computing functionality.

The objective of this case study is to evaluate one of the edge computing frameworks called EdgeX Foundry running on a Raspberry Pi gateway by interfacing an industrial temperature and humidity sensor. Here is the high level block and data flow diagram  with which the case study is explained:

click for full size image

Figure 2. High Level Block Diagram (Source: www.edgexfoundry.org)

Modbus

Modbus is an open protocol and transports are standard. It doesn’t require a specific physical layer, unlike many proprietary protocols, so Modbus networks are built on cheap and common infrastructure such as RS-485 links.

Modbus implements a very simple data representation and easy to understand. Its primary purpose is simply to move data between Modbus master and slave devices. There are only two kinds of data to move, registers and coils. Registers are 16-bit unsigned integers used to store the analog values such as temperature, humidity and pressure values. Coils are single bits used to store the digital values in Modbus memory map, usually status values such as switch status (ON or OFF), motor running status (UP or DOWN) and valve status (OPEN or CLOSE).

It required little code space, often as little as 1K. RAM varied with the size of your data space. Simple automation devices with little bits of data could be implemented with hardly any RAM space.

Modbus could be so readily understood by non-programmers. Engineers who built glue machines, meters, measuring devices, and such could easily understand the concept of coils/registers and the simple commands to read and write them.

Often multiple instruments are connected to the same Modbus network. No instrument supports all instrumentation network protocols, but almost all of them support Modbus. By choosing Modbus you have a good chance of avoiding compatibility problems and future upgrade problems.

Temperature Monitoring

An IoT temperature monitoring system allows an industry to track the environmental parameters on a secure web/mobile-based platform and offers instant notifications in real-time. These temperature sensor data can be accessed from remote end.

The data gathered from the temperature sensors can be used to create statistical insights. This will help the industries to improve the reliability of their warehouse and cold storage.

Many industrial use cases use this application:

  • Digital temperature monitoring in laboratories and clinics,
  • Food safety compliances,
  • Warehouse and Inventory Management,
  • Goods in transit,
  • Equipment monitoring.

For these kind of use cases temperature and humidity monitoring application is very much relevant. This application needs a gateway to monitor the temperature and humidity. The gateway requires an edge computing framework. Here, the Modbus sensor, gateway and edge computing framework used are SHT20 industrial temperature and humidity sensor, Raspberry Pi 4 and EdgeX Foundry respectively.

How Edgex is used?

Modbus Device Service Validation using Modbus Slave Simulator (ModbusPal)

ModbusPal is a Modbus slave simulator, free and open source, released under the GPL license. Its purpose is to offer an easy to use interface with the capabilities to reproduce complex and realistic Modbus environments. It supports TCP/IP natively, and supports serial communication if RxTx library is installed on the computer.

ModbusPal can simulate up to 247 Modbus slaves. Each slave can have holding registers and coils. Each register or coil can be animated by being associated to a dynamic value generator, called “automation”.

The validation of the modbus device service using ModbusPal simulator with a slave device as power meter is done by following below mentioned steps. In same way, we can simulate any kind of Modbus supported environment with slave devices such as temperature, humidity and pressure sensors.

  1. Setting ModbusPal environment,
  2. Adding slave devices and configuring their addressable, values and automations,
  3. Posting a Modbus device profile in EdgeX,
  4. Posting a Modbus device in EdgeX,
  5. Sending data to or actuating slave device (PUT),
  6. Receiving data from slave device (GET).
  7. Install any operating system that can install docker and docker-compose. In this example, we use Ubuntu 20.04.2 LTS to deploy EdgeX using docker.


Figure 3. Setting up an environment for ModbusPal Simulator

  1. Add slave devices, configure holding register(s), enter values and names and bind them to appropriate automation(s).


Figure 4. Adding and configuring slave devices in ModbusPal simulator (Source: www.edgexfoundry.org)

  1. Post device profile using POST command.
curl –X POST http://:48081/api/v1/deviceprofile/uploadfile -F file=@


Figure 5. Posting a device profile in EdgeX

  1. Post device using POST command. Use the below command to upload as a file or use the command which is screenshot to upload as a content.
curl –X POST http://:48081/api/v1/device/uploadfile -F “file=@


Figure 6. Posting a device in EdgeX

  1. Execute PUT command to send the data.
curl –X PUT http://:48082/api/v1/device//command/ -H “Content-Type:application/json” –d ‘{“”: “”,“”: “”}’


Figure 7. PUT command execution in EdgeX

  1. Execute GET command to receive the data.
curl –X GET http://:48082/api/v1/device/name//command/Configuration | json_pp

click for full size image

Figure 8. GET command execution in EdgeX

Device profile

The device profile describes a type of device within the EdgeX system. Each device managed by a device service has an association with a device profile, which defines that device type in terms of the operations which it supports. The device profile defines the device’s values and operation method, which can be Read or Write. A device profile consists of following tags:

  1. Identification: The profile contains various identification fields. The Name field is required and must be unique in an EdgeX deployment. Other fields are optional – they are not used by device services but may be populated for informational purposes,
  2. DeviceResources: A deviceResource specifies a sensor value within a device that may be read from or written to either individually or as part of a deviceCommand. It has a name for identification and a description for informational purposes,
  3. DeviceCommands: DeviceCommands define access to reads and writes for multiple simultaneous device resources. Each named deviceCommand should contain a number of get and/or set resourceOperations, describing the read or write respectively,
  4. CoreCommands: CoreCommands specify the commands which are available via the core-command micro service, for reading and writing to the device. Both deviceResources and deviceCommands may be represented by coreCommands (the name of the coreCommand refers to the name of the deviceCommand or deviceResource).

Device Profile of Modbus Temperature and Humidity Sensor (Scroll to view full listing)

name: "TemperatureHumiditySensor"
manufacturer: "ROBOKITS"
model: "RKI-4879"
labels:
 - "SHT20"
description: "Industrial Grade Temperature & Humidity Transmitter SHT20 Sensor High Precision Monitoring Modbus RS485"
deviceResources:
      -
        name: "TemperatureDegC"
        description: "Room Temperature in Degrees Celsius."
        attributes:
            { primaryTable: "INPUT_REGISTERS", startingAddress: "2", rawType: "INT16" }
        properties:
            value:
                { type: "Float32", readWrite: "R", scale: "0.1", floatEncoding: "eNotation" }
            units:
                { type: "String", readWrite: "R", defaultValue: "degrees celsius" }
      -
        name: "HumidityPercentRH"
        description: "Room Humidity in %RH."
        attributes:
            { primaryTable: "INPUT_REGISTERS", startingAddress: "3", rawType: "INT16" }
        properties:
            value:
                { type: "Float32", readWrite: "R", scale: "0.1", floatEncoding: "eNotation" }
            units:
                { type: "String", readWrite: "R", defaultValue: "%RH" }
deviceCommands:
      -
        name: "TemperatureDegC"
        get:
          - { index: "1", operation: "get", deviceResource: "TemperatureDegC" }
      -
        name: "HumidityPercentRH"
        get:
          - { index: "2", operation: "get", deviceResource: "HumidityPercentRH" }
coreCommands:
      -
        name: "TemperatureDegC"
        get:
            path: "/api/v1/device/{deviceId}/TemperatureDegC"
            responses:
              -
                code: "200"
                description: "Get the temperature in degrees C"
                expectedValues: ["TemperatureDegC"]
              -
                code: "503"
                description: "service unavailable"
                expectedValues: []
      -
        name: "HumidityPercentRH"
        get:
            path: "/api/v1/device/{deviceId}/HumidityPercentRH"
            responses:
              -
                code: "200"
                description: "Get the humidity in %RH"
                expectedValues: ["HumidityPercentRH"]
              -
                code: "503"
                description: "service unavailable"
                expectedValues: []

1.1.1.1      Device Profile of GPIO Device – 1 (Red LED) (Scroll to view full listing)

name: "device-gpio12"
manufacturer: "Jiangxing Intelligence"
model: "SP-01"
labels:
  - "gpio12"
description: "automatically export gpio12 by command"
deviceResources:
  -
    name: "value"
    description: "set or get system gpio value"
    properties:
      value:
        { type: "Int8", readWrite: "RW", minimum: "0", maximum: "1", defaultValue: "0" }
      units:
        { type: "String", readWrite: "R", defaultValue: "high:1; low:0" }
deviceCommands:
  -
    name: "value"
    get:
      - { operation: "get", deviceResource: "value" }
    set:
      - { operation: "set", deviceResource: "value", parameter: "0" }
coreCommands:
  -
    name: "value"
    put:
      path: "/api/v1/device/{deviceId}/value"
      parameterNames: ["value"]
      responses:
        -
          code: "200"
          description: ""
        -
          code: "500"
          description: "service unavailable"
          expectedValues: []
    get:
      path: "/api/v1/device/{deviceId}/value"
      responses:
        -
          code: "200"
          description: ""
          expectedValues: ["value"]
        -
          code: "500"
          description: "service unavailable"
          expectedValues: []

Device Profile of GPIO Device – 2 (Blue LED) (Scroll to view full listing)

name: "device-gpio14"
manufacturer: "Jiangxing Intelligence"
model: "SP-01"
labels:
  - "gpio14"
description: "automatically export gpio14 by command"
deviceResources:
  -
    name: "value"
    description: "set or get system gpio value"
    properties:
      value:
        { type: "Int8", readWrite: "RW", minimum: "0", maximum: "1", defaultValue: "0" }
      units:
        { type: "String", readWrite: "R", defaultValue: "high:1; low:0" }
deviceCommands:
  -
    name: "value"
    get:
      - { operation: "get", deviceResource: "value" }
    set:
      - { operation: "set", deviceResource: "value", parameter: "0" }
coreCommands:
  -
    name: "value"
    put:
      path: "/api/v1/device/{deviceId}/value"
      parameterNames: ["value"]
      responses:
        -
          code: "200"
          description: ""
        -
          code: "500"
          description: "service unavailable"
          expectedValues: []
    get:
      path: "/api/v1/device/{deviceId}/value"
      responses:
        -
          code: "200"
          description: ""
          expectedValues: ["value"]
        -
          code: "500"
          description: "service unavailable"
          expectedValues: []

Configurations

The configuration file to define devices and schedule jobs. The micro services (i.e., device-modbus) generates a relative instance on startup. It has details such as type of protocol, gateway name, protocol, address, port and path (unit ID).

Configuration File of Temperature and Humidity Sensor (Scroll to view full listing)

[Writable]
LogLevel = 'DEBUG'

[Service]
BootTimeout = 30000
CheckInterval = '10s'
Host = 'localhost'
ServerBindAddr = ''  # blank value defaults to Service.Host value
Port = 49991
Protocol = 'http'
StartupMsg = 'device modbus started'
Timeout = 5000
ConnectRetries = 10
Labels = []
EnableAsyncReadings = true
AsyncBufferSize = 16

[Registry]
Host = 'localhost'
Port = 8500
Type = 'consul'

[Logging]
EnableRemote = false
File = './GPIO.LOG'

[Clients]
  [Clients.Data]
  Protocol = 'http'
  Host = 'localhost'
  Port = 48080

  [Clients.Metadata]
  Protocol = 'http'
  Host = 'localhost'
  Port = 48081

  [Clients.Logging]
  Protocol = 'http'
  Host = 'localhost'
  Port = 48061

[Device]
  DataTransform = true
  InitCmd = ''
  InitCmdArgs = ''
  MaxCmdOps = 128
  MaxCmdValueLen = 256
  RemoveCmd = ''
  RemoveCmdArgs = ''
  ProfilesDir = './res'
  UpdateLastConnected = false

# Pre-define Devices
[[DeviceList]]
  Name = 'TemperatureHumiditySensor'
  # device profile file name
  Profile = 'TemperatureHumiditySensor'
  Description = 'Industrial Grade Temperature & Humidity Transmitter SHT20 Sensor High Precision Monitoring Modbus RS485'
  labels = [ 'TemperatureHumiditySensor','modbusRTU' ]
  [DeviceList.Protocols]
    [DeviceList.Protocols.modbus-rtu]
       Address = '/dev/ttyUSB0'
       BaudRate = '9600'
       DataBits = '8'
       StopBits = '1'
       Parity = 'N'
       UnitID = '1'
  [[DeviceList.AutoEvents]]
    Frequency = '5s'
    OnChange = false
    Resource = 'TemperatureDegC'
  [[DeviceList.AutoEvents]]
    Frequency = '5s'
    OnChange = false
    Resource = 'HumidityPercentRH'

Configuration File of GPIO Devices (Red LED and Blue LED) (Scroll to view full listing)

[Writable]
LogLevel = 'DEBUG'

[Service]
BootTimeout = 30000
CheckInterval = '10s'
Host = 'localhost'
ServerBindAddr = ''  # blank value defaults to Service.Host value
Port = 49950
Protocol = 'http'
StartupMsg = 'device gpio started'
Timeout = 5000
ConnectRetries = 10
Labels = []
EnableAsyncReadings = false
AsyncBufferSize = 16

[Registry]
Host = 'localhost'
Port = 8500
Type = 'consul'

[Logging]
EnableRemote = false
File = './GPIO.LOG'

[Clients]
  [Clients.Data]
  Protocol = 'http'
  Host = 'localhost'
  Port = 48080

  [Clients.Metadata]
  Protocol = 'http'
  Host = 'localhost'
  Port = 48081

  [Clients.Logging]
  Protocol = 'http'
  Host = 'localhost'
  Port = 48061

[Device]
  DataTransform = true
  InitCmd = ''
  InitCmdArgs = ''
  MaxCmdOps = 128
  MaxCmdValueLen = 256
  RemoveCmd = ''
  RemoveCmdArgs = ''
  ProfilesDir = './res'
  UpdateLastConnected = false

# Pre-define Devices
[[DeviceList]]
  Name = "gpio12"
  Profile = "device-gpio12"
  Description = "use gpio12"
  Labels = ['gpio12']
  [DeviceList.Protocols]
    [DeviceList.Protocols.other]
      Address = "device-gpio12"

[[DeviceList]]
  Name = "gpio14"
  Profile = "device-gpio14"
  Description = "use gpio14"
  Labels = ['gpio14']
  [DeviceList.Protocols]
    [DeviceList.Protocols.other]
      Address = "device-gpio14"

Setup and Execution with Results

  1. Connect the SHT20 Industrial Grade Temperature and Humidity Transmitter to the Raspberry Pi (in which the EdgeX Foundry is installed) through RS485 interface to USB converter and LEDs using jumpers and resisters as shown in below picture.

click for full size image

Figure 9. Hardware Connectivity Details

    1. Upload the device profile above to metadata with a POST to http://localhost:48081/api/v1/deviceprofile/uploadfile and add the file as key “file” to the body in form-data format, and the created ID will be returned. The following example command uses curl to send the request:
      curl –X POST http://:48081/api/v1/deviceprofile/uploadfile -F file=@
    2. Ensure all the mandatory device services are up and running.


Figure 10. Verifying active device services

c. Add the device with a POST to http://localhost:48081/api/v1/device, the body will look something like: (Scroll to view full listing)

curl -X POST http://localhost:48081/api/v1/device -H "Content-Type:application/json" -d '{
   "name" :"TemperatureHumiditySensor",
   "description":"Industrial Grade Temperature & Humidity Transmitter SHT20 Sensor High Precision Monitoring Modbus RS485",
   "adminState":"UNLOCKED",
   "operatingState":"ENABLED",
   "protocols":{
      "modbus-rtu":{
         "Address" : "/dev/ttyUSB0",
         "BaudRate" : "9600",
         "DataBits" : "8",
         "StopBits" : "1",
         "Parity" : "N",
         "UnitID" : "1"
      }
   },
   "labels":[
      "TemperatureHumiditySensor",
      "modbusRTU"
   ],
   "service":{"name":"edgex-device-modbus"},
   "profile":{"name":"TemperatureHumiditySensor"},
   "autoEvents":[
      {
         "frequency":"5s",
         "onChange":false,
         "resource":"TemperatureDegC"
      },
      {
         "frequency":"5s",
         "onChange":false,
         "resource":"HumidityPercentRH"
      }
   ]
}'

The device can be added using POST command or as a part of configuration.toml file.

  1. The device service will be pulling the temperature and humidity data from the sensor for every 5 seconds. The received data will be sent to core service and stored in Redis server.
2021/03/02 05:03:33 modbus: sending 01 04 00 01 00 01 60 0a
2021/03/02 05:03:33 modbus: received 01 04 02 01 4d 78 95

Table 1. Decoding Modbus Request and Response

Sent Decoding   Received Decoding
01 Slave ID   01 Slave ID
04 Function Code   04 Function Code
00 01 Register Address   02 Bytes Count
00 01 Number of Registers   01 4d Data (0x014d = 333)
60 0a CRC   78 95 CRC
  1. Core service will be sending the data to application service. The below figure shows the data in core service.


Figure 11. Temperature and Humidity Data Stored in Core Service

  1. The application service sends the data to the cloud. Here we use the IBM cloud. The below figure shows the data in IBM cloud.

click for full size image

Figure 12. Temperature and Humidity Data in IBM Cloud sent from Application Service

  1. In other side from north bound to south bound, application service will send the data to rules engine (here we use Kuiper rules engine). The following rules are set.

Table 2. Rules

Rules No. Rules LED Status
Rule #1 TemperatureDegC > 30°C Red 1 (ON)
Rule #2 TemperatureDegC < 30°C Red 0 (OFF)
Rule #3 TemperatureDegC > 28°C Blue 0 (OFF)
Rule #4 TemperatureDegC < 28°C Blue 1 (ON)


Figure 13. Rule #1


Figure 14. Script to apply the rules

  1. Whenever threshold temperatures are met, the rules engine sends a command to core command.
  2. The core command actuates the GPIO device service to turn on or turn off the LEDs based threshold temperature. Once we run the rules the rules will be applied. Here gpio12 meant for red LED and gpio14 meant for blue LED.

a. Glow the red LED whenever the temperature goes higher than 30 °C.

Rules Engine Logs:

level=info msg="sink result for rule red_led_on:
[{\"TemperatureDegC\":32.3}] file="sinks/log_sink.go:16"
rule=red_led_on
level=info msg="sink result for rule blue_led_off:
[{\"TemperatureDegC\":32.3}] file="sinks/log_sink.go:16"
rule=blue_led_off

GPIO:

root@ubuntu:~# cat /sys/class/gpio/gpio12/value
1
root@ubuntu:~# cat /sys/class/gpio/gpio14/value
0

b. Glow a blue LED whenever the temperature goes less than 28 °C.

Rules Engine:

level=info msg="sink result for rule red_led_off:
[{\"TemperatureDegC\":27.2}] file="sinks/log_sink.go:16"
rule=red_led_off
level=info msg="sink result for rule blue_led_on:
[{\"TemperatureDegC\":27.2}] file="sinks/log_sink.go:16"
rule=blue_led_on

GPIO:

root@ubuntu:~# cat /sys/class/gpio/gpio12/value
0
root@ubuntu:~# cat /sys/class/gpio/gpio14/value
1
  1. Finally, the GPIO service will make the LED(s) to turn on or turn off.

Conclusion

Industries are in the need of interfacing sensors and actuators and monitoring and controlling the environmental parameters for long term. The EdgeX framework enables the temperature and humidity monitoring application versatile, has enabled the controlled environment in industries, datacenters and laboratories. Interfacing any other industrial sensors with EdgeX Foundry will also work similar to industrial grade temperature and humidity sensor. This will save a huge amount of developer effort, development cost and latency as the EdgeX framework handles data storage, analytics, device management and cloud connectivity and gateway is very near to the sensors.

Acronyms

Acronym Expansion
AOF Append Only File
API Application Program Interface 
AWS Amazon Web Services
BACnet Building Automation and Control Network
BLE Bluetooth Low Energy
CURL Client Uniform Resource Locator
GPIO General Purpose Input Output
HTTP Hypertext Transfer Protocol
IBM International Business Machines
IIoT Industrial Internet of Things
IoT Internet of Things
IT Information Technology
LED Light Emitting Diode
LTS Long Term Support
M2M Man to Machine
MQTT Message Queuing Telemetry Transport
RDB Redis Database
Redis REmote DIctionary Server
REST Representational State Transfer
RS-485 Recommended Standard – 485
SCADA Supervisory Control and Data Acquisition
SQL Structured Query Language
TCP/IP Transmission Control Protocol/Internet Protocol

Vediyappan Villali is a Lead Engineer with HCL Technologies. He is working in developing and testing embedded software products. He is a part of the Embedded Platform Lab COE.
Vijay Annamalaisamy is a Senior Technical Specialist with HCL technologies. He has extensive experience in developing embedded software for products from multiple domains. He is a part of the Embedded Platform Lab COE and has contributed for various projects.
Sathya Durai is a Senior Solutions Architect with HCL technologies. He has extensive experience in playing the architect role for embedded software development for products from multiple domains. He is a part of the Embedded Platform Lab COE and has contributed for various projects.

Related Contents:

For more Embedded, subscribe to Embedded’s weekly email newsletter.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.