In the context of the Web of Things (WoT), a Binding Template is a blueprint that gives guidance on how to implement a specific IoT protocol, data format or IoT platform. The Core Binding Templates specification explains the overall mechanism and requirements for any binding to follow. This document gives implementation guidelines regarding the Modbus protocol, which is a well-known cost-effective IoT protocol for communication between industrial control and automation devices.
More specifically, this document defines a set of vocabulary terms that can be used inside a Thing Description document, and associated rules which allow to describe WoT operations using the Modbus protocol over the network. Additionally, relevant examples are provided to showcase different vocabulary terms and the associated behavior.
This document is a work in progress
The Modbus is a data communication protocol originally developed by Modicon which is now a part of Schneider Electric. The protocol was specifically designed for the remote management of the hardware devices in the industrial environment. For this reason, it has low level of abstraction and it has built in bit handling capabilities oriented to the direct control of the relays and generic contact statuses. The physical layer it is mainly an RS485 differential bus which has less susceptibility to the EMC interference. This Limit the usability of the protocol in short distance networks, typically within a kilometer. Due to its age the protocol does not implement any safety system, so usually when wide internet access is needed it is encapsulated in a TCP/IP protocol and with Ethernet as a physical layer. Thanks to this encapsulation strategy, the Modbus protocol can reach remote nodes deployed in distant facilities over the internet. Moreover, in the years due to its simplicity and cost-effectiveness the Modbus protocol becomes a standard all over the world. This fame together with the advancement of the microcontroller/microprocessor led to a shift on how applications pack the information. Today it is usual to store and read any type of data in the Holdings Registers like bit, bytes, words, float etc.
This document describes how the Web of Things specification can be use to present devices that use the Modbus protocol in a Thing Description. In particular, the document explain how to create valid URLs and Forms for the different operations that the Modbus protocol can perform. Developers are encouraged to use this document as an implementation guidelines and as a reference for the creation of their own binding implementations. The following sections will cover the URL format, the Vocabulary and a list of Form examples.
Forms of a Thing Description instance with Modbus Binding complies with this specification if it follows the normative statements in and .
A JSON Schema [[?JSON-SCHEMA]] to validate Thing Description instances containing Modbus Binding is provided in the GitHub repository.
modbus+tpc://
, modbus+ascii://
and modbus+rtu://
.
Considering that in Web of Things context all protocol binding templates are required to at least support the Internet Protocol, for the Modbus protocol modbus+tcp://
was selected as the only valid URL scheme. The following shows the typical structure of an URL of the Modbus protocol:
modbus+tcp://{address}:{port}/{unitID}/{address}?quantity={?quantity}
Where:
{address}
is the IP address of the Modbus device{port}
is the port of the Modbus device{unitID}
is the unit ID of the Modbus device. See vocabulary{address}
is the address of the register/coil referenced in this URL. See vocabulary{quantity}
the amount of registers/coils referenced in this URL. See vocabularyVocabulary term | Description | Assignment | Type |
---|---|---|---|
modbus:address |
Specifies the starting address of the Modbus operations | required | integer |
modbus:unitID |
The Unit ID is usually not needed for ModbusTCP, since the IP-address works as unique identifier, but for compability reasons still often included | required | integer |
modbus:quantity |
Specifies the amount of either registers or coils to be read or written to | optional | integer |
Vocabulary term | Description | Assignment | Type |
---|---|---|---|
modbus:pollingTime |
Modbus TCP maximum polling rate. The Modbus specification does not define a maximum or minimum allowed polling rate, however specific implementations might introduce such limits. Defined as integer of milliseconds. | optional | integer |
modbus:timeout |
Modbus response maximum waiting time. Defines how much time the runtime should wait until it receives a reply from the device. | optional | integer |
modbus:zeroBasedAddressing |
Modbus implementations can differ in the way addressing works, as the first coil/register can be either referred to as True or False. | optional | boolean |
modbus:entity |
A registry type to let the runtime automatically detect the right function code | optional | Entity |
modbus:function |
Function Code sent by the master in every request. Specifying the desired interaction. | optional | Function |
modbus:function
cannot (See the
[[[#example-read-coil-entity]]])
Value | Description |
---|---|
Coil |
Represent a modbus coil register. These entities can be read or written |
DiscreteInput |
Represent a modbus discrete input. These entities can only be read |
HoldingRegister |
Represent a modbus holding register. These entities can be read or written |
InputRegister |
Represent a modbus input register. These entities can only be read |
modbus:function
, the value of modbus:function
property should be ignored.
Value | Label | Code | Description |
---|---|---|---|
readCoil |
Read Single Coil | 1 | Read a single coil (i.e. boolean/bit access) value. Usually in the address range 00001-09999 |
readDeviceIdentification |
Read Device Identification | 43 | Read Device Identification for diagnostic purposes. Avaiable in the majority of Modbus implementations. |
readDiscreteInput |
Read Discrete Inputs | 2 | Read Physical Discrete Inputs (bit access). Address range 10001-19999 |
readHoldingRegisters |
Read Multiple Holding Registers | 3 | Read Multiple Holding Registers (16 bit access). Address range 40001-49999 |
readInputRegisters |
Read Multiple Input Registers | 4 | Read Multiple Physical Input Registers (16 bits). Address range 30001-39999 |
writeMultipleCoils |
Write Multiple Coils | 15 | Write Multiple Physical Coils (internal bits). Address range 00001-09999 |
writeMultipleHoldingRegisters |
Write Multiple Holding Registers | 16 | Write Multiple Holding Registers (output registers, 16 bit). Address range 40001-49999 |
writeSingleCoil |
Write Single Coil | 5 | Write Single Physical Coil (internal bit). Address range 00001-09999 |
writeSingleHoldingRegister |
Write Single Holding Register | 6 | Write Single HoldingRegister (internal bits). Address range 40001-49999 |
This section describes strategies and default values to employ protocol specific concepts within the WoT Interaction model.
The following table lists the default mappings between the protocol specific concepts and the WoT concepts. Please note that operations that are not
listed in the table are not supported by this binding template. For example, since the Modbus protocol is a request-response based protocol, the
subscribeevent
operation is not supported.
Operation | Default Binding |
---|---|
writeproperty |
"modbus:function": "writeSingleCoil" |
invokeaction |
"modbus:function": "writeSingleCoil" |
readallproperties |
"modbus:function": "readHoldingRegisters" |
readmultipleproperties |
"modbus:function": "readHoldingRegisters" |
writeallproperties |
"modbus:function": "writeMultipleHoldingRegisters" |
writemultipleproperties |
"modbus:function": "writeMultipleHoldingRegisters" |
Operation | Default | Comments |
---|---|---|
modbus:quantity |
1
|
|
modbus:zeroBaseAddressing |
false
|
|
modbus:timeout |
infinite
|
Additional to the default mappings, users may decide to use other [[[#function]]]s for a specific operation. The following table lists examples of possible mappings for some operation types.
Operation | Possible Binding |
---|---|
writeproperty |
"modbus:function":"writeMultipleCoils"
|
writeproperty |
"modbus:function":"writeSingleHoldingRegister"
|
readproperty |
"modbus:function":"readDeviceIdentification"
|
readproperty |
"modbus:function":"readDiscreteInput"
|
observeproperty |
"modbus:function":"readCoil" ;
"modbus:pollingTime": 1000
|
{ "href": "modbus+tcp://127.0.0.1:60000/1", "op": [ "readproperty" ], "modbus:function": "readCoil", "modbus:address": 1 }To describe forms with multiple operations types, the [[[#entity]]] keyword can be used to create a short description of the modbus endpoint.
{ "href": "modbus+tcp://127.0.0.1:60000/1/1", "op": [ "readproperty", "writeproperty" ], "modbus:entity": "Coil", }A TD processor will intepred [[[#example-read-coil-entity]]] configuration as the following:
{ "href": "modbus+tcp://127.0.0.1:60000/1/1", "op": [ "readproperty", ], "modbus:function": "readCoil", }, { "href": "modbus+tcp://127.0.0.1:60000/1/1", "op": [ "writeproperty", ], "modbus:function": "writeCoil", },Reducing effectively the verbosity of a TD. Thanks to the expressiveness of the Modbus ontology users can describe also the total number of registries read or wrote in a WoT operation. [[[#example-read-holding]]] shows how to read or write 8 HoldingRegisters.
{ "href": "modbus+tcp://127.0.0.1:60000/1/40001?quantity=8", "op": [ "readproperty", "writeproperty" ], "modbus:entity": "HoldingRegister" }When possible WoT consumers will use Modbus features to read the desired amount of data with a single protocol request. However, it may be possible to still specify a total length for Modbus operations that do not support reading or writing on a range of registers (see [[[#example-read-coil-range]]]). In these circumstances consumers will perform different requests to satisfy the configuration requirements.
{ "href": "modbus+tcp://127.0.0.1:60000/1/1?quantity=8", "op": [ "readproperty", "writeproperty" ], "modbus:entity": "Coil" }Another notable configuration of a form using the Modbus vocabulary is the polling mechanism. Thanks to the keyword
pollingTime
the user can indicate the intervals for observing a particular
set of registers. Supposing that the device knows that the value of coil register 1 does change every
1000 ms, in [[[#example-polling]]], it suggest that the polling time should not be faster than 10 ms. WoT
consumers may still create requests faster than the specified time but it should be taken as a reasonable
default for observing a property.
{ "href": "modbus+tcp://127.0.0.1:60000/1/1", "op": [ "observeproperty" ], "modbus:entity": "Coil", "modbus:pollingTime": 1000, }Finally, [[[#full-td]]] shows a complete device described using Modbus ontology.
{ "@context": [ "https://www.w3.org/2019/wot/td/v1", { "modbus": "https://www.example.com/ns/modbustcp" } ], "title": "ModbusPLC", "description": "An industrial machine, retrofitted to be IoT capable.", "id": "uri:dev:ModbusTCPThing", "securityDefinitions": { "nosec_sc": { "scheme": "nosec" } }, "security": "nosec_sc", "base": "modbus+tcp://192.168.178.32:502/1/", "properties": { "limitSwitch1": { "title": "downLimitSwitch", "type": "boolean", "description": "Limit switch moving downwards", "forms": [ { "op": "readproperty", "href": "10003", "modbus:function": "readDiscreteInput", "contentType": "application/octet-stream" } ] }, "limitSwitch2": { "title": "forwardLimitSwitch", "type": "boolean", "description": "Limit Switch moving forward", "forms": [ { "op": "readproperty", "href": "10002", "modbus:function": "readDiscreteInput", "contentType": "application/octet-stream" } ] }, "moveDown": { "title": "moveDown", "type": "boolean", "description": "Down Motor Status (single coil). PLC output, can be written to control the motor.", "forms": [ { "op": [ "writeproperty", "observeproperty", "readproperty" ], "href": "6", "modbus:entity": "Coil", "modbus:pollingTime": 100, "contentType": "application/octet-stream" } ] }, "moveForward": { "title": "moveForward", "type": "boolean", "description": "Forward Motor Status (single coil). PLC output, can be written to control the motor.", "forms": [ { "op": [ "writeproperty", "observeproperty", "readproperty" ], "href": "3", "modbus:entity": "Coil", "modbus:pollingRate": 100, "contentType": "application/octet-stream" } ] } } }
The following describe the [[[#url]]] using [[[RFC2234]]] with the reference to [[[uri]]] specification.
MODBUS-URI = "modbus+tcp://" authority path-modbus [ "?quantity=" quantity ] path-modbus = "/" unitID "/" address unitID=1*DIGIT address=1*DIGIT quantity=1*DIGIT