Skip to main content

ModBus smartCORE module

Description​

The "modbus" module primarily reads the ModBus registers of ModBus devices. These devices can be

  • via a serial connection (ModBus/RTU)
  • via TCP (ModBus/TCP)

be connected.

Interfaces & protocols used​

  • ModBus

JSON configuration​

The following section describes the entire JSON configuration of the module and explains the individual parameters.

Example configuration​

An example ModBus/TCP configuration is shown below:

{
"module": "ModBus",
"comment": "ModBus/TCP config",
"factory": "modbus",
"config": {
"version": 1,
"type": "modbus",
"enable": true,
"pollCycleInMilliseconds": 1000,
"transport": {
"type": "tcp",
"ipAddress": "192.168.0.1",
"ipPortNumber": 502,
"timeoutInMilliseconds": 200
},
"devices": [
{
"enable": true,
"deviceName": "Device Name",
"deviceAddress": 1,
"readChannels": [
{
"name": "Channel Name",
"address": 49152,
"registerType": "HoldingReg",
"registerFormat": "REAL",
"byteOrder": "ABCD",
"bitOffset": 0,
"unit": "",
"scale": 1.0,
"offset": 0.0
}
]
}
]
}
}

Global module parameters​

Parameter nameRequiredData typeMeaningful value rangeDefaultDescription
versionYESINT1-ModBus protocol version
typeYESSTRING"modbus"-Serial interface for communication
enableYESBOOLtrue-Switch for production of data in smartCHANNELs
pollCycleInMillisecondsYESINT1 --polling interval [ms] of ModBus accesses
transportYESJSON object-configuration of the ModBus transport layer (see below)
devicesYESJSON array of JSON objects-List of ModBus participants
pollCycleInNanosecondsNoINT1 -100000000Polling interval [ns]. If the key is present it takes precedence over pollCycleInMilliseconds. If neither is given, 100 ms are used
enableInternalDataReductionNoBOOLtrue, falsefalseAttaches a data reduction filter to every channel the module creates (absTolerance 0.0, timeoutMs 60000): unchanged values are not written, but a value is written again after 60 s at the latest
autoGroupNoBOOLtrue, falsetrueGroups adjacent registers of a device into register blocks that are read in one transaction (see Register blocks)
autoGroupAllowGapsNoBOOLtrue, falsefalseAllows gaps inside a block: registers nobody asked for are read along instead of splitting the block
maxRegisterGroupNoINT1 - 125125Largest number of registers in one block. Larger values are capped at 125 with a warning - ModBus does not allow more in a single transaction
useF23withoutOutputsNoBOOLtrue, falsefalseUses function code 23 (Read/Write Multiple Registers) even when there is nothing to write (from smartCORE 2.12)
minimalChannelAlarmCountNoINT1 -2Number of immediately consecutive failed attempts after which a register block is switched off (see Timeout and switching off)
retryAfterBlockFailSNoINT0 -0Time [s] after which a register block that was switched off is tried again. 0 = no retry, the block stays off for this measurement (from smartCORE 2.12)
workloadAsChannelNoBOOLtrue, falsefalseCreates a diagnostic channel carrying the bus workload
workloadChannelBuffersizeNoINT1 -100Buffer size of the workload channel in elements
workloadChannelNoSTRING or JSON objectName or complete channel definition of the workload channel

ModBus/TCP specific transport parameters ("transport")​

Parameter NameRequiredData TypeMeaningful Value RangeDefaultDescription
typeYESSTRING"tcp"Selection ModBus/TCP
ipAddressYESSTRINGValid IP addressIP address of the ModBus device
ipPortNumberYESINTValid IP port numberIP port number of the ModBus device (should be set to 502 unless otherwise specified)
timeoutInMillisecondsYESINT1 -Timeout [ms] for TCP connection (should be set to 200 unless otherwise specified)

ModBus/RTU specific transport parameters ("transport")​

Parameter nameRequiredData typeMeaningful value rangeDefaultDescription
typeYESSTRING"rtu"Selection ModBus/RTU
baudRateYESINTValid ModBus baud rateBaud rate of the serial interface
dataBitsYESINT5 - 8Data bits of the serial interface
parityYESSTRING"no", "even", "odd"Parity of the serial interface
stopBitsYESDOUBLE1.0, 1.5, 2.0Stop bits of the serial interface
portNameYESSTRINGValid device fileDevice file of the serial interface
timeoutInMillisecondsYESINT1 -Response timeout [ms] of the serial connection. It bounds how long the answer of a participant is waited for and is passed to libmodbus as modbus_set_response_timeout()
deviceTimeoutInMillisecondsNoINT0 -0Pause [ms] between two devices of a sweep, inserted after all register blocks of one device have been polled
readDelayMsNoINT0 -Overrides the frame silence t3.5 [ms] that is kept before every request. Without the key it is derived from the baud rate (see Frame silence)

ModBus device parameters ("devices")​

Parameter NameRequiredData TypeMeaningful Value RangeDefaultDescription
enableYESBOOLtrueSwitch for activating the ModBus device
deviceNameYESSTRINGName of the ModBus device
deviceAddressYESINT1 -Address of the ModBus device
readChannelsYESJSON Array of JSON objectssee below

The keys autoGroup, autoGroupAllowGaps, maxRegisterGroup and useF23withoutOutputs may also be given per device, where they override the global value.

ModBus channel configuration ("readChannels")​

Parameter nameRequiredData typeMeaningful value rangeDefaultDescription
nameYESSTRINGname of the smartCHANNEL
addressYESINTAddress of the ModBus register
registerTypeYESSTRINGValid ModBus register typeType of ModBus register ("InputReg", "HoldingReg", "Coil", "Status", "0x17" (read access only))
registerFormatYESSTRINGValid ModBus register formatFormat of the ModBus register ("I8", "I16", "I32", "I64", "UI8", "UI16", "UI32", "UI64", "REAL", "BOOL")
byteOrderYESSTRINGsee belowOrder of the bytes of the value, see Byte order
bitOffsetYESUINTBit offset of the value to be interpreted
unitYESSTRINGUnit of the smartCHANNEL
scaleYESDOUBLEScaling of the smartCHANNEL
offsetYESDOUBLEOffset of the smartCHANNEL
enableNoBOOLtrue, falsetrueA channel set to false is neither created nor read
pollingIntervalMultiplicatorNoINT1 -1The register block of this channel is only read in every n-th polling cycle
registerGroupNoINT0 -Assigns the channel to a register block by hand. Channels carrying the same number form one block and are excluded from automatic grouping

ModBus channel configuration ("readChannelGroups")​

Alternatively, several channel configurations can be combined into a JSON array, so that the ModBus registers on which this group is based can be read in a single step can be read in a single step (if the register type is identical). This readChannelGroup array combined in this way can then be listed in the JSON array of the "readChannelGroups", e.g.

"readChannelGroups": [
[
{
"name": "Channel 1",
"address": 49152,
"registerType": "HoldingReg",
"registerFormat": "REAL",
"byteOrder": "ABCD",
"bitOffset": 0,
"unit": "",
"scale": 1.0,
"offset": 0.0
},
{
"name": "Channel 2",
"address": 49158,
"registerType": "HoldingReg",
"registerFormat": "REAL",
"byteOrder": "ABCD",
"bitOffset": 0,
"unit": "",
"scale": 1.0,
"offset": 0.0
}
]
]

Alternatively, "readChannels" or "readChannelGroups" can be specified.

Register blocks​

The channels of a device are not read one by one. smartCORE groups them into register blocks: a block is one contiguous address range of one register type and is read in exactly one ModBus transaction. Every channel is fed by exactly one block.

Grouping is done by register type and address. The four ModBus address spaces (coil, discrete input, input register, holding register) are independent of each other - coil 4 and input register 4 are different things and never share a block. A new block begins as soon as

  • the range would span more than maxRegisterGroup registers, or
  • the next register does not immediately follow the previous one and autoGroupAllowGaps is false.

With autoGroupAllowGaps: true gaps are bridged: the block reads registers no channel needs and saves a transaction in return. That pays off for small gaps and expensive accesses, not for addresses far apart.

To decide the layout yourself, give registerGroup per channel: channels carrying the same number form one block and are excluded from automatic grouping.

Byte order​

The value of a channel is cut out of the buffer that was read by the same component the fmProducer module uses, the SimpleBufferPicker. byteOrder therefore accepts two notations:

  • By name - bigEndian (also big, be, motorola, msb, network) or littleEndian (also little, le, intel, lsb). Without a value, big endian applies.
  • As a mapping - a sequence of letters that puts the bytes of the value into the order in which they sit on the bus. The length of the sequence says how many bytes the value spans, the order of the letters how they are to be swapped.

This also answers the difference between "AB" and "BA": both describe a value made of two bytes. "AB" takes them in the order they were read, "BA" swaps them. The same for four bytes: "ABCD" unchanged, "CDAB" word-swapped, "DCBA" fully reversed - the four variants ModBus devices use to store 32 bit values.

"BIT" is a special case for access to a single bit. A sequence that is neither a known name nor a valid mapping disables the channel; the message names it.

Timing and error handling​

Polling cycle​

The bus is served by a thread of its own that reads all due register blocks one after another in every polling cycle (pollCycleInMilliseconds or pollCycleInNanoseconds). A block with pollingIntervalMultiplicator: n is only due in every n-th cycle; blocks sharing a multiplicator are spread over different cycles so that they do not all fall into the same one.

Changed behaviour from smartCORE 2.12

A block that is not due in a cycle produces nothing. Up to smartCORE 2.11 the unchanged contents of the block were written out again under the current time instead - a channel with pollingIntervalMultiplicator: 5 delivered five times as many values as there were measurements.

Timestamps of the measured values​

Every channel carries the timestamp of the transaction its value came from: the moment the answer of the device arrived. All channels of one register block therefore carry the same timestamp. The moment the device formed the value or put it on the wire is not observable over ModBus - the arrival of the answer is the closest instant the protocol offers.

Changed behaviour from smartCORE 2.12

Up to smartCORE 2.11 the values carried the moment they were written into the smartCHANNEL, not the moment of the measurement - that is, the moment after all devices on the bus had been polled, possibly delayed by several seconds.

Frame silence on ModBus/RTU​

Before every request the line is kept quiet for the duration of the frame silence t3.5 - the pause that separates one RTU message from the next. Its length follows from:

ConditionSilence
readDelayMs is setthe given value
Baud rate above 19200 (or unknown)1.75 ms - the fixed value of the MODBUS over Serial Line Specification V1.02; the computed one would shrink to 0.33 ms at 115200 baud and separate nothing
otherwise3.5 characters of 11 bits, that is 38500000 / baud rate microseconds - 4.01 ms at 9600 baud
Changed behaviour from smartCORE 2.12

The pause sits in front of the request. Up to smartCORE 2.11 it followed a successful answer - and therefore did not happen after a timeout, which is the one case in which the line needs the silence most.

Two things are logged along the way, because they point to a system configured to run faster than its line: bytes of the previous request still sitting in the output queue when the next one starts ("the line is slower than the polling cycle assumes"), and data found unexpectedly in the input buffer. The latter is read and reported with its first bytes rather than discarded silently.

Timeout and switching off a register block​

If a request receives no answer within timeoutInMilliseconds, the access counts as failed. The register block counts such failures, and after minimalChannelAlarmCount failures in a row it is switched off: it is no longer polled and its channels produce nothing. The message names the device, the register address, the function code, the length of the streak and whether another attempt is planned.

Not every fault counts towards that threshold:

Answer of the deviceEffect
No answer (timeout), Illegal Function (01), Illegal Data Address (02), Illegal Data Value (03), Server Failure (04), Negative Acknowledge (07), Memory Parity (08), Gateway Target Failed To Respond (0B)counts towards switching off - the device or the configuration is permanently not in order
Acknowledge (05), Server Busy (06), Gateway Path Unavailable (0A)does not count - the device is asking for patience
A damaged frame, e.g. a CRC errordoes not count - an event, not a state; repeating the request is the right answer to it

retryAfterBlockFailS decides whether a block that was switched off comes back: with 0 it stays off for the duration of the measurement, with a value greater than zero it is tried again after that time. If the attempt succeeds the block is in service again and the counter is back at zero; if it fails, the waiting time starts over.

tip

A device that occasionally disappears and comes back in the field needs retryAfterBlockFailS. Without the key it is over after minimalChannelAlarmCount failed attempts, even if the device is back on the bus two minutes later.

Module information​

InformationValue
AuthorsoptiMEAS GmbH
since smartCORE0.1
Module typeProducer
DependenciesNONE