.. _user/protocols/modbus: ********** Modbus/TCP ********** Overview ======== Modbus/TCP is a communication protocol which is a variant of the Modbus family. It is based on a master/slave architecture and intended for use in industrial automation especially with PLCs or IO modules. Modbus/TCP is defined in IEC 61158. Modbus uses big-endian representation for addresses and data items. **Protocol structure:** +-------------------------+------------------------+--------------+-----------------+---------------+--------+ | transaction identifier | protocol identifier | length field | unit identifier | function code | data | +=========================+========================+==============+=================+===============+========+ | 2 byte | 2 byte (always 0x0000) | 2 byte (n+2) | 1 byte | 1 byte | n byte | +-------------------------+------------------------+--------------+-----------------+---------------+--------+ .. _user/protocols/modbus_connection: .. include:: ../protocolSchemas/ModbusConnection.rst .. _user/protocols/modbus_endpoint: .. include:: ../protocolSchemas/ModbusEndpoint.rst Supported function codes ======================== For reading or writing data over Modbus/TCP the protocol provides a set of functions. Which action should be performed on the other end of the connection is defined by the function code (fc). **Supported function codes are:** +---------------+-----------------------------------+-----------+ | Function code | Action | Operation | +===============+===================================+===========+ | 1 | Read coils | subscribe | +---------------+-----------------------------------+ | | 2 | Read discrete inputs | | +---------------+-----------------------------------+ | | 3 | Read holding registers | | +---------------+-----------------------------------+ | | 4 | Read input registers | | +---------------+-----------------------------------+-----------+ | 5 | Write single coil | write | +---------------+-----------------------------------+ | | 6 | Write single holding register | | +---------------+-----------------------------------+ | | 15 | Write multiple coils | | +---------------+-----------------------------------+ | | 16 | Write multiple holding registers | | +---------------+-----------------------------------+-----------+ .. _user/protocols/modbus/datatypes: Supported Data-types ==================== In Modbus/TCP there are no predefined data-types. The Connectware supports sending the raw payload over MQTT as binary. If the data-type is known and supported by the respective `fc`, the payload is converted to JSON format. The desired data type on read or on write is specified with the property ``dataType``. The possible values are as follows: +-------------+---+---+---+---+---------+ | DataType/FC | 1 | 2 | 3 | 4 | Size | +-------------+---+---+---+---+---------+ | raw | ✓ | ✓ | ✓ | ✓ | variable| +-------------+---+---+---+---+---------+ | bool | ✓ | ✓ | x | x | 1 bit | +-------------+---+---+---+---+---------+ | ascii | x | x | ✓ | ✓ | variable| +-------------+---+---+---+---+---------+ | base64 | x | x | ✓ | ✓ | variable| +-------------+---+---+---+---+---------+ | int16BE | x | x | ✓ | ✓ | 16 bit | +-------------+---+---+---+---+---------+ | int16LE | x | x | ✓ | ✓ | 16 bit | +-------------+---+---+---+---+---------+ | int32BE | x | x | ✓ | ✓ | 32 bit | +-------------+---+---+---+---+---------+ | int32LE | x | x | ✓ | ✓ | 32 bit | +-------------+---+---+---+---+---------+ | uint16BE | x | x | ✓ | ✓ | 16 bit | +-------------+---+---+---+---+---------+ | uint16LE | x | x | ✓ | ✓ | 16 bit | +-------------+---+---+---+---+---------+ | uint32BE | x | x | ✓ | ✓ | 32 bit | +-------------+---+---+---+---+---------+ | uint32LE | x | x | ✓ | ✓ | 32 bit | +-------------+---+---+---+---+---------+ | floatBE | x | x | ✓ | ✓ | 32 bit | +-------------+---+---+---+---+---------+ | floatLE | x | x | ✓ | ✓ | 32 bit | +-------------+---+---+---+---+---------+ | doubleBE | x | x | ✓ | ✓ | 64 bit | +-------------+---+---+---+---+---------+ | doubleLE | x | x | ✓ | ✓ | 64 bit | +-------------+---+---+---+---+---------+ | bigUInt64BE | x | x | ✓ | ✓ | 64 bit | +-------------+---+---+---+---+---------+ | bigUInt64LE | x | x | ✓ | ✓ | 64 bit | +-------------+---+---+---+---+---------+ If the payload is smaller than the required bits for the conversion (payload.length < dataType.length), an error is displayed in the logs and no message is sent over MQTT. If the payload has more bits (payload.length > dataType.length) than needed for the conversion, the "extra" bits are ignored and a message is sent over MQTT. As a comparison to other documentation, this is a list of other common names for the supported types: ================= ====== ============= ============= Common type name Size Minimum value Maximum value ================= ====== ============= ============= char 8 bit 0 255 byte 8 bit -128 127 short (int16) 16 bit -2^15 2^15-1 int (int32) 32 bit -2^31 2^31-1 uint (uint32) 32 bit 0 2^32-1 long64 64 bit -2^63 2^63-1 float 32 bit IEEE 754 IEEE 754 double 64 bit IEEE 754 IEEE 754 ================= ====== ============= ============= .. _user/protocols/modbus/input: Input Format ============= This Modbus implementation supports writing using the standard function calls 5, 6, 15 and 16. In most cases you can directly send a number in the message payload when you are trying to write to a coil or a single register (function call 5 or 6, respectively). When trying to write several coils at once (function call 15) your data message's ``value`` must consist of an array of boolean values, for example: ``[true, true, false, true]``. Alternatively, if your goal is to write several registers at once, the data type of the endpoint needs to be considered. The property ``dataType`` (see :ref:`Endpoint properties `) specifies how to properly serialize the data into an array of bytes suitable to write into the Modbus registers. For the available integer and float data types (see :ref:`user/protocols/modbus/datatypes` above) you can directly send the value in the message payload. A ``BigInt`` must be sent as a string value. You can also send ascii, base64, and utf8 encoded strings that will be parsed using Node.js Buffer class. Raw data in the form of an array of bytes is also supported. Input Format on Write --------------------- For writing data to modbus a message needs to be published to the `/set` topic of the Endpoint with the following properties: .. code:: json { "fc": "", "dataType": "", "data": "" } Output Format on Write ---------------------- Results are published to the `/res` topic of the Endpoint. The format depends on the modbus function being called and it is returned as a JSON object. Output Format ============= If data is read from Modbus and ``dataType`` is set to any of the potential values Output Format on Read --------------------- When data is read from the endpoint, results are published to the `/res` topic of the Endpoint. The output message is an object with two properties: .. code:: json { "timestamp": "", "value": "" } The value of the ``value`` property will be the JSON representation of the configured ``dataType``, i.e. a number, or a string, or for 'raw' the JSON representation of a Javascript buffer object. Alternatively, the property ``dataType`` can be left undefined, in which case the output is a Javascript buffer object directly. This is probably useful for further processing using suitable :ref:`mappings `. Example Configuration ===================== The following example demonstrates how to configure a simple Modbus connection and endpoint that `reads holding registers` (fc 3) from the device. Download: :download:`modbus-example.yml` .. literalinclude:: modbus-example.yml :language: yaml :linenos: References ========== 1. https://www.rtaautomation.com/technologies/modbus-tcpip/