WolkGateway Module Modbus
WolkGateway module for connecting Modbus devices to WolkAbout IoT Platform by communicating with WolkGateway.
Supported protocol(s):
- Wolkabout Protocol
Installing from source
This repository must be cloned from the command line using:
git clone --recurse-submodules https://github.com/Wolkabout/WolkGatewayModule-Modbus.git
Prerequisite
Following tools/libraries are required in order to build WolkGateway Module Modbus
- cmake - version 3.5 or later
- autotools
- automake
- autoconf
- g++
- m4
- zlib1g-dev
- libtool
- openssl
Former can be installed on Debian based system from terminal by invoking:
sudo apt-get install automake g++ autotools-dev autoconf m4 zlib1g-dev cmake libtool libssl-dev
Afterwards dependencies are built, and Makefile build system is generated by invoking:
./configure
Generated build system is located inside out
directory To build the module, invoke:
cd out
make -j$(nproc)
sudo make install
Installing will place the application in PATH, and create a systemctl unit, which you can use with:
sudo service modbus_module status/start/stop/restart
The configuration files used are placed in /etc/modbusModule/
, which you should configure before you start your
service. If you don't know how to configure the module, continue on to the next part.
Configuring Module
Module configuration consists of 2 configurations files
- moduleConfiguration.json
- devicesConfiguration.json
Below are sections describing each of these configuration files that need to be edited with the parameters of your
modbus devices before running the application. These files are located in out
directory, and are passed to Modbus
module executable in following manner:
./modbusModule moduleConfiguration.json devicesConfiguration.json
moduleConfiguration.json
Module configuration file contains settings that relate to communication with WolkGateway, and outgoing Modbus connection, reading period time and response timeout.
{
"mqttHost": "tcp://localhost:1883",
// Address of local MQTT broker (connection with WolkGateway)
"connectionType": "SERIAL/RTU",
// Modbus connection type, choice between "SERIAL/RTU" and "TCP/IP"
"tcp/ip": {
// TCP/IP connection properties (ignored if connectionType is "SERIAL/RTU")
"host": "192.168.x.x",
// IP address of Modbus server (mandatory if connectionType is "TCP/IP")
"port": 502
// Port of Modbus server (default is 502, if not stated)
},
"serial/rtu": {
// Serial/RTU connection properties (ignored if connectionType is "TCP/IP")
"serialPort": "SERIAL_PORT",
// Serial port location such as /dev/ttyS0 (mandatory if connection type is "SERIAL/RTU")
"baudRate": 115200,
// Baud rate for serial connection (default is 115200, if not stated)
"dataBits": 8,
// DataBits for Modbus RTU (default is 8, if not stated)
"stopBits": 1,
// StopBits for Modbus RTU (default is 1, if not stated)
"bitParity": "NONE"
// BitParity for Modbus RTU, can be "NONE", "EVEN", "ODD" (default is "NONE", if not stated)
},
"responseTimeoutMs": 200,
// Wait time for respond from slaves/servers (default is 200, if not stated)
"registerReadPeriodMs": 500
// Period of reading all registers/devices (default is 500, if not stated)
}
devicesConfiguration.json
Devices configuration file contains information necessary to define templates, which include registers that bind to Wolkabout IoT Platform sensors/actuators/alarms/configurations, and then devices, with their information, and a template. This is the guide by which the module will register devices, and then send data for.
You define templates, that are described by their name, and mappings.
{
"templates": [
{
"name": "<TEMPLATE_NAME>",
"mappings": [
// define mappings
]
}
]
}
After doing so, you define all the mappings inside a template.
Single mapping includes one or more Modbus registers that produce a single sensor/actuator/alarm/configuration on a device, on the platform. They're characterized by a name, and a reference key, used to identify them, by their register type (necessary), data type (necessary), operation type (necessary for some output types), and mapping type.
Register types:
-
Read & Write:
COIL
HOLDING_REGISTER
-
Read Only:
INPUT_REGISTER
INPUT_CONTACT
-
Data types:
- UINT16/INT16
- BOOL
- UINT32/INT32 (with merge operations)
- FLOAT (with merge operation)
- STRING (with stringify operations)
-
Operation types:
MERGE_BIG_ENDIAN
orMERGE_LITTLE_ENDIAN
(in combination with"dataType": "UINT32/INT32"
)MERGE_FLOAT
(in combination with"dataType": "FLOAT"
)TAKE_BIT
(in combination with"dataType": "BOOL"
)STRINGIFY_ASCII
orSTRINGIFY_UNICODE
(in combination with"dataType": "STRING"
)
Mappings are by default registered as:
- Sensors for read only types
- Actuator for read & write types
You can override this behaviour by adding a field to the mapping, stating one of the next types ("mappingType"
):
SENSOR
ACTUATOR
ALARM
- only forINPUT_CONTACT
CONFIGURATION
- only forCOIL
andHOLDING_REGISTER_ACTUATOR
{
// Inside of a template
"name": "<TEMPLATE_NAME>",
"mappings": [
{
"name": "mappingName",
// Register name
"reference": "mappingReference",
// Unique reference used to differ register on WolkAbout IoT Platform
"minimum": -32768,
// Minimum value that can be held in register. Required for visualization on WolkAbout IoT Platform
"maximum": 32767,
// Maximum value that can be held in register. Required for visualization on WolkAbout IoT Platform
"address": 0,
// Register address
"registerType": "INPUT_REGISTER",
// Register type - "INPUT_REGISTER" or "HOLDING_REGISTER_ACTUATOR" or "HOLDING_REGISTER_SENSOR" or "INPUT_CONTACT" or "COIL"
"dataType": "INT16"
// Data type stored in register - "INT16" or "UINT16" or "REAL32" for "INPUT_REGISTER"/"HOLDING_REGISTER_ACTUATOR"/"HOLDING_REGISTER_SENSOR" register type, and "BOOL" for "COIL"/"INPUT_CONTACT"
},
{
"name": "mappingName2",
"reference": "mappingReference2",
"minimum": -4000,
"maximum": 4000,
"address": 1,
"registerType": "HOLDING_REGISTER",
"dataType": "FLOAT",
"deadbandValue": 4.0,
// Optional - Indicates a change in value of the mapping that is insignificant data. Applicable to numeric mappings.
"frequencyFilterValue": 250
// Optional - When register changes value often, disregard changes until X milliseconds pass since last accepted value.
},
{
"name": "mappingName3",
"reference": "mappingReference3",
"address": 1,
"registerType": "INPUT_CONTACT",
"dataType": "BOOL",
"mappingType": "ALARM"
// This is where for the first time, we override the default Mapping type
},
{
"name": "mappingName4",
"reference": "mappingReference4",
"address": 2,
"registerType": "HOLDING_REGISTER",
"operationType": "MERGE_BIG_ENDIAN",
"dataType": "UINT32",
"mappingType": "CONFIGURATION"
},
{
"name": "mappingReference5",
"reference": "mappingReference5",
"address": 3,
"registerType": "COIL",
"dataType": "BOOL",
"writeOnly": true
// If the mapping needs to be Write-Only, you put this attribute.
},
{
"name": "mappingReference6",
"reference": "mappingReference6",
"address": 10,
"addressCount": 10,
"registerType": "HOLDING_REGISTER",
"dataType": "STRING",
"operationType": "STRINGIFY_ASCII"
},
{
"name": "mappingReference7",
"reference": "mappingReference7",
"address": 8,
"bitIndex": 0,
"registerType": "INPUT_REGISTER",
"operationType": "TAKE_BIT",
"dataType": "BOOL"
}
]
}
After you completely defined a template, you can list a device.
{
"devices": [
{
"name": "<DEVICE_NAME>",
// User readable device name, necessary to register a device
"key": "<DEVICE_KEY>",
// Unique device key
"slaveAddress": 1,
// Slave address (obligatory if connection type is "SERIAL/RTU"), must be unique in this list
"template": "<TEMPLATE_NAME>"
// Name of defined template
}
// other devices
]
// templates
}
In "TCP/IP" mode, device count is maxed at 1, and you don't need to state a slaveAddress for the device.
If the user happens to enter an invalid template name, the device won't be created. Module will function if at least one device is valid. If there are no devices that have been inputted correctly, the module will exit out, and used will be notified.