Modbus Server

Purpose

Purpose of this plugin is to instantiate a Modbus Server on the Ardexa edge device.

Description

This plugin will read a configuration file, read Modbus registers from a local network, and then publish Modbus data locally. Data can be sourced either via RTU (local serial device) or from local IP addresses. The source Modbus registers can then be remapped to other registers. No data will be sent to the Ardexa cloud. This plugin is just to assist some plant owners that require Modbus data to be shared locally, via a Modbus Server.

Configuration File

The configuration file is required to manage various aspects of the data collection and conversion. The file must be defined as shown below. There are a few rules to note:

  1. The IP/Serial device address MUST be at the end of ALL the mbpoll commands

  2. Mbpoll commands MUST start with _cmd, , followed by the mbpoll command which sources the data

  3. All the other lines in the configuration file define registers and how they are to be treated.

  4. All lines that start with an # character are treated as comments and will be ignored.

  5. Each of the columns listed below MUST not be empty.

  6. For Type, only the valid strings can be used: INT16, INT32, FLOAT.

  7. If a INT32 or FLOAT type is used, be sure to leave 2 sequential output registers free.

  8. Scale can be any floating point number. It can only be used on FLOAT, but NOT INT16 or INT32 - which must be set to 1.0.

  9. _cmd is the commands to run. Only modpoll or the mbpoll commands can be used to read Modbus registers. mbpoll is preferred. The registers being collected MUST MATCH the registers listed in the configuration items. If not, you will have empty fields when running a discover. The IP address or serial device MUST appear as the last entry in the command.

  10. Each Output Register must be unique. If there are any duplicates, then the script will report an error and not run.

#
_cmd, mbpoll -m tcp -a 1 -r 120 -c 50 -t 3 -1 -0 -p 502 192.168.1.10
_cmd, mbpoll -m rtu -a 2 -r 1 -c 2 -t 3 -1 -0 /dev/ttyACM3
#
# Output Register    Type,      Description,    Units,      Scale,  Source Endpoint        Input Register
1,                   INT16,     Pressure,       hPa,        150,    192.168.1.10,            123
2,                   INT32,     Direction,      degs,       1.1,    192.168.1.10,            130
8,                   INT16,     Flow Rate,      L/min,      3.5,    192.168.1.10,            145
9,                   FLOAT,     Radiation,      W/m^2,      1.0,    192.168.1.10,            155
105,                 INT16,     Temp,           C,          0.1,    /dev/ttyACM3,            2
206,                 INT16,     Humidity,       %,          0.01,   /dev/ttyACM3,            3

Usage

This plugin uses a configuration file. The file must be named as modbus_server.txt in the directory: /opt/ardexa/config/modbus-server, and configured as discussed above. Once a single scenario has been defined, a service will be activated that waits for Modbus requests. The task element of the scenario will not do anything. The scenario must be activated as a service. Due to a technical limitation, in order to save some config data when initially setting up the server, such as a custom port, once the service is created you may have to turn on the Test Mode then SAVE, then turn it off and SAVE again. DO NOT create multiple scenarios for this service, it is not designed for this and will lead to undefined behaviour.

Also, you need to open a firewall port manually once the scenario has been activated. This is a design feature, to warrant that the user is aware of the risks of activating a service (server) on the local device. To open a firewall port on the Ardexa device run the following command: sudo ufw allow 502, where 502 should be the port number required. To close all ports, run the command: sudo ufw default deny incoming. The Modbus Server port is defined when setting up the server.

If a Modbus request is received, the data defined in the configuration file will be queried and served via the service. The plugin will make a maximum of 3 attempts to read the data, and will cache the results for a maximum of 10 seconds. This cache is to prevent the source endpoints from being overloaded with modbus queries. Queries may take a little longer, so a timeout of a few seconds may be required. If using the mbpoll client, this is achieved using the -o argument, such as the query: mbpoll -m tcp -a 1 -r 11 -c 8 -t 4:float -1 -0 -o 8 -p 502 127.0.0.1 - which specifies a timeout of 8 seconds. DO NOT connect to this server with multiple clients, it can only handle one connection at a time. If one client has been connected for more than 30 seconds it will be automatically disconnected, this is to prevent dead connections blocking the server.

Clients querying the Modbus server must use address 1. It will respond to either Input or Holding registers requests. When the service is started, or when running a discover command (see below), a PDF file will be written to /opt/ardexa/config/modbus-server/modbus_server_mapping.pdf, which will show the parameters of the configuration file, IP address, port and cache settings. It can be downloaded from the edit scenario page by selecting in the drop down.

Please note that for this service to be reliable a static IP address must be defined on the Ardexa device. In order to test the plugin is working ok, the service can be checked as follows: systemctl status modbus-server-plugin.service

Test Mode

There is also a test mode, used to serve known values for debugging. this is activated by the switch in the scenario page. These registers and their value can then be checked with a script that is run with the discover button. The script and its configuration files, found in /opt/ardexa/config/modbus-server, can be downloaded and configured locally to test a remote server. There should be a test_client.py script, a test_server.txt configuration and some .dict lookups. There is also a multiple option in the config interface, this will add duplicate test registers in multiples of 100, for example if multiple is 2 then registers 1 and 101 will store the current hour.

Some of the test mode registers values are dynamic and others are fixed, as per the list below:

register, value

1,           hour
2,           minute
3,           second
4,           True
5,           32 bit unix time int
7,           32 bit uptime float
9,10,11      day of week character, eg. Thu
12,          0x1234
13,          0xabcd
14,          cpu usage 32 bit float
16,          ram usage 32 bit float
18,19,20,21  timezone characters, eg. AEST
22,23,24,25  ip addr numbers as 16 bit ints
26,          32 bit uptime int
30001,       0xff00
30002,       1.2345 32 bit float little endian
30004,       1.2345 32 bit float big endian
30006,       123456 32 bit int little endian
30008,       123456 32 bit int big endian
30010,       2 
30011,       4
30012,       8
30013,       16
30014,       0010000000000000
30015,       308
30016,       51

Last updated