macchina.io EDGE

Datapoint Connectors

Introduction

Datapoint connectors provide an easy, configuration-only way to make the values stored in datapoints available to external systems via different protocols.

Generally, the configuration of datapoint connectors - specifying which datapoints are exposed via which protocols and protocol addresses - is done via service properties that are defined along with the datapoint.

The Modbus Datapoints Connector

The Modbus datapoints connector acts as a Modbus server (or slave device, in old terms) that makes the values of certain datapoints available via the Modbus TCP or RTU protocol.

Note: basic familiarity with the Modbus protocol and the Modbus data model (specifically holding registers and discrete inputs) is required to configure the Modbus connector.

Modbus clients (or master devices, in old terms) can read and update the value of datapoints exposed to the Modbus connector.

The following datapoint types are supported:

To expose a datapoint to the Modbus connector, a service property named io.macchina.modbus.mapping must be defined when the datapoint is created. When the datapoint is created in JavaScript, using the Datapoints module, this property is specified under the tags property. Similarly, when creating a Datapoint in C++ using the IoT::Datapoints::DatapointFactory service, this service property is specified in the tags member of IoT::Datapoints::BasicDatapointParams, which is the base class of all datapoint parameter types.

Modbus Mapping

Following is an example for such a datapoint definition in JavaScript:

const temperatureDatapoint = {
    type: 'scalar',
    params: {
        name: 'Temperature',
        physicalQuantity: 'temperature',
        physicalUnit: datapoints.physicalUnits.DEGREES_CELSIUS
    },
    tags: {
        'io.macchina.modbus.mapping': 'register=1000,type=int16,scale=10,offset=0,access=ro'
    }
};

Mapping Parameters

When defining the mapping to Modbus, different parameters controlling the mapping can be defined. The most important are the address (register or input), type of Modbus data, scaling of value and access mode. Parameters are delimited by a comma.

The available parameters are described in the following:

  • register: Address of the Modbus holding register the value is available under (all datapoints).
  • input: Address of the Modbus discrete input the value is available under (flags datapoint only).
  • type: Data type the datapoint's value is mapped to. See below for supported types. Defaults to int16.
  • access: Access permissions for Modbus clients. Read (r, ro), write (w, wo) or both (rw).
  • scale: Scaling factor for mapping a scalar value to the target type. Defaults to 1.0.
  • offset: Offset added to the scalar value for mapping to target type. Defaults to 0.0.
  • ttl: Optional time-to-live or time the value is considered valid, in milliseconds. If a datapoint's value has not been updated for the given time, the value is considered stale and no longer available via Modbus.
  • size: Number of holding registers the datapoint value spans over. Required for string and bitfield types.

Mapping Types

Datapoint values can be mapped to the following types by providing the corresponding type parameter value.

  • int16: 16-bit signed integer, occupies one holding register. Offset and scaling is applied.
  • int32: 32-bit signed integer, occupies two consecutive holding registers. Offset and scaling is applied for scalars.
  • int64: 64-bit signed integer, occupies four consecutive holding registers. Offset and scaling is applied for scalars.
  • float: 32-bit IEEE-754 floating-point number, occupies two consecutive holding registers.
  • double: 64-bit IEEE-754 floating-point number, occupies four consecutive holding registers.
  • string: ASCII or UTF-8 string. The number of consecutive holding registers holding the value (two bytes per register) must be given in the size parameter. String datapoint only.
  • bitfield: Multi-byte bitfield. The number of consecutive holding registers holding the value (two bytes per register) must be given in the size parameter. String datapoint only.

Generally, for all integer and floating-point values in Modbus, big-endian byte order is used.

There are certain restrictions as to which datapoint types can be mapped to which Modbus types.

  • A boolean datapoint must be mapped to an int16. Value will be 1 (true) or 0 (false). When writing, any non-zero value will be considered true.
  • A counter datapoint must be mapped to an int16, int32 or int64. Care must be taken that the counter's actual value does not exceed the Modbus type's range. If it does, the Modbus value will be trunctated. For example, for a 64-bit counter only the least significant 16 bits will be used if mapped to an int16.
  • An enum datapoint must be mapped to an int16 or int32. Like with a counter, truncation of the value may happen, but is less likely as enums usually don't have that many values for this to become an issue.
  • A flags datapoint must be mapped to a bitfield. A size (number of consecutive 16-bit holding registers) must be specified. The flag with bit number 0 will be mapped to the least significant bit of the first holding register.
  • For a scalar datapoint, value scaling will be applied, regardless of Modbus type. When read via Modbus, the datapoint's value will first be multipled by the scale, then the offset will be added. When writing a Modbus value to the datapoint, the offset will be subtracted from the Modbus value first, then the resulting value will be divided by the scale factor. Scalar datapoints can be mapped to int16, int32, int64, float and double.
  • A string datapoint must always be mapped to string. A size (number of consecutive 16-bit holding registers) must be specified. The string value will either be truncated, or extended with zero bytes to fit the number of registers. Each holding register contains two bytes of the string. The eight least significant bits of the first holding register contain the first byte of the string.

Supported Modbus Function Codes

The following Modbus function codes are supported:

  • Read Discrete Input (0x02): Only supported for flags datapoints (if access mode permits).
  • Read Holding Registers (0x03): Supported for all datapoints mapped to a holding register (if access mode permits).
  • Write Single Register (0x06): Supported for all datapoints mapped to a single holding register (if access mode permits).
  • Write Multiple Registers (0x10): Supported for all datapoints mapped to a holding register (if access mode permits).
  • Mask Write Register (0x16): Supported for all datapoints mapped to a single holding register (if access mode permits).

IMPORTANT: When reading or writing values that span multiple registers, the entire value must be read or written, by providing the appropriate number of registers to a Read Holding Registers or Write Multiple Registers request. It is possible to read multiple values, by specifying a number of registers that covers multiple mapped datapoints.

Modbus Exceptions Responses

An attempt to read a stale value will result in a Modbus exception response with a server device failure (0x04) exception code. An attempt to read an unmapped register, or a request that violates access permissions will result in a Modbus exception response with an illegal data address (0x02) exception code.

Enabling and Configuring the Modbus Connector

Modbus TCP

The following configuration properties are used to enable and configure the Modbus connector for TCP connections.

  • modbus.datapoints.tcp.enable: Enable (true) or disable (false, default) the Modbus TCP server.
  • modbus.datapoints.tcp.port: The TCP port number the Modbus server listens on. Defaults to 502.
  • modbus.datapoints.tcp.host: The IP address the Modbus server listens on. Defaults to 0.0.0.0 (all available TCP/IP network interfaces).
  • modbus.datapoints.tcp.maxConnections: Specifies the maximum number of simultaneous client connections allowed. Defaults to 8.
  • modbus.datapoints.tcp.unitAddress: The unit address used by the server. If set to a non-zero address, only requests for that specific address will be handled. If set to 0, all requests regardless of unit address will be handled.
  • modbus.datapoints.tcp.frameTimeout: Timeout in microseconds for receiving a protocol frame. Defaults to 10000 (10 ms).

Modbus RTU

The following configuration properties are used to enable and configure the Modbus connector for RTU connections.

  • modbus.datapoints.rtu.enable: Enable (true) or disable (false, default) the Modbus RTU server.
  • modbus.datapoints.rtu.device: Specify the device for the RS/TIA-485 interface, e.g. /dev/ttyUSB0.
  • modbus.datapoints.rtu.params: Specify the serial port parameters, including number of data bits, parity and number of stop bits, e.g. 8N1 (default). See Poco::Serial::SerialPort::open() for more information on this parameter.
  • modbus.datapoints.rtu.speed: Specify the baud rate, e.t. 9600 (default), 19200, 57600, etc.
  • modbus.datapoints.rtu.slaveAddress: The slave address used by the server. If set to a non-zero address, only requests for that specific address will be handled. If set to 0, all requests regardless of unit address will be handled.
  • modbus.datapoints.rtu.frameTimeout: Timeout in microseconds for receiving a protocol frame. Defaults to 10000 (10 ms).

The following RS/TIA-485 configuration parameters are supported:

  • modbus.datapoints.rtu.rs485.enable: Enable (true) or disable (false, default) RS-485 mode on the serial interface.
  • modbus.datapoints.rtu.rs485.rtsOnSend: Set (true) or don't set (false, default) the RTS signal to 1 when sending data, thereby enabling the RS-485 driver.
  • modbus.datapoints.rtu.rs485.rtsAfterSend: Set (true) or don't set (false, default) the RTS signal after sending data, thereby disabling the RS-485 driver.
  • modbus.datapoints.rtu.rs485.useGPIO: Use (true) a GPIO pin to enable the RS-485 driver rather than RTS. Used by some devices like Beaglebones. Defaults to false.
  • modbus.datapoints.rtu.rs485.gpioPin: If useGPIO is set, specify the number of the GPIO pin to use to enable the RS-485 driver.
  • modbus.datapoints.rtu.rs485.delayRTSBeforeSend: Specify the RTS delay in microseconds when sending data. Defaults to 0.
  • modbus.datapoints.rtu.rs485.delayRTSAfterSend: Specify the RTS delay in microseconds after sending data. Defaults to 0.
Securely control IoT edge devices from anywhere   Connect a Device