MODBUS binding, addressing reality vs. documentation

Hello everyone

I am having some confusion regarding the adresses used in the modbus binding. I am trying to read two holding registers from a modbus device over TCP. In the binding documentation it says:

Input as zero-based index number, e.g. in place of 400001 (first holding register), use the address "0"

I am quite sure there is a zero too much and it should be 40001 (or not?), but that’s not the problem. The first holding register I am trying to read is 41018 (with zero based addressing probably 41017) with a length of two, so my things file looked like this:

Bridge modbus:tcp:smartfoxtcp [ host="192.168.178.81", port=502, id=1 ] {

    // read-write for holding registers. Reading 4 registers, with index 1017, 1041
    // These correspond to holding register numbers 41017, 41041
    Bridge poller holding1 [ start=1017, length=2, refresh=120000, type="holding" ] {
        Thing data holdingPowerTotal [ readStart="1017", readValueType="int32" ]
    }

    Bridge poller holding2 [ start=1041, length=2, refresh=120000, type="holding" ] {
        Thing data holdingPowerAnalogout [ readStart="1041", readValueType="uint32" ]
    }
  }

However, that generates the following error:

2021-12-23 21:44:30.255 [INFO ] [ab.event.ThingStatusInfoChangedEvent] - Thing ‘modbus:poller:smartfoxtcp:holding2’ changed from ONLINE to OFFLINE (COMMUNICATION_ERROR): Error with read: org.openhab.core.io.transport.modbus.internal.ModbusSlaveErrorResponseExceptionImpl: Slave responsed with error=2

I read in a thread in this forum that this means, that I have a connection but the device tells me I can’t run this operation on this address. So I started playing around with the adresses in the modbus.things file in a way which is totally not according to the documentation by writing the full adresses and not only the offset to 40000:

Bridge modbus:tcp:smartfoxtcp [ host="192.168.178.81", port=502, id=1 ] {

    // read-write for holding registers. Reading 4 registers, with index 1017, 1041
    // These correspond to holding register numbers 41017, 41041
    Bridge poller holding1 [ start=41017, length=2, refresh=120000, type="holding" ] {
        Thing data holdingPowerTotal [ readStart="41017", readValueType="int32" ]
    }

    Bridge poller holding2 [ start=41041, length=2, refresh=120000, type="holding" ] {
        Thing data holdingPowerAnalogout [ readStart="41041", readValueType="uint32" ]
    }
  }

Now everything works and I get the correct values in my items, at least for positive values (negative have not yet occured). But I am unsure if this is only by change and it will stop working in some cases.

Is this just a problem of the documentation or am I missing something? It’s my first modbus project so maybe I just don’t know about this protocol…

I am running openhab 3.1.0 release build with the corresponding binding. The modbus device is a “Smartfox Pro”. If any information is missing I will of course add it to this thread.

Thank you very much in advance for everybody who will try to help me understand this.

regards, Ueli

Whose documentation?
The openHAB binding adopts the simplest unambiguous method - the address you put in the parameter is the address that goes out in the protocol on the wire.

There are however several different Modbus addressing conventions.
The holding register at x0000 can be referred to as “Holding 0” or “Holding 1” or “40001”, depending on the convention the author has chosen. They might start counting at 0 or 1, and use the 40000 prefix or not.
Because of the limitation of the 4xxxx prefix to 9999 registers, occasionally you will see 400001 to refer to the same target register as well.
Your puzzle then is to figure out which convention your device docs use, so that you know whether you need to adapt it to the protocol level the binding needs.

On top of that, some device designers really will mean x9C41 (40001 in hex) or perhaps x9C40 when they refer to “40001”. Looks like yours fall into that category.

It really helps if they give you a byte-by-byte example, but that’s up to your supplier.

Thank you very much, that explains it perfectly! So it seems to be mostly a problem of Modbus itself and the documentation of the supplier, because I didn’t get a lot of information from them considering these questions.

You write that the address I put in the parameter is the addres that goes out in the protocol, which should probably also be stated in the docs. If people like me (who have no previous experience with modbus) follow them, all they can read about the adressing of holding registers is:

Input as zero-based index number, e.g. in place of 400001 (first holding register), use the address "0" . Must be between (poller start) and (poller start + poller length - 1) (inclusive).

And the example leads in the same direction:

// read-write for holding registers. Reading 4 registers, with index 1500, 1501, 1502, 1503.
    // These correspond to holding register numbers 401501, 401502, 401503, 401504.
    Bridge poller holding [ start=1500, length=4, refresh=1000, type="holding" ] {
        Thing data holding1500 [ readStart="1500", readValueType="float32", writeStart="1500", writeValueType="float32", writeType="holding" ]
        Thing data holding1502 [ readStart="1502", readValueType="float32", writeStart="1502", writeValueType="float32", writeType="holding" ]
    }

If you agree I will add some information to the doc page on github.

You write that the address I put in the parameter is the addres that goes out in the protocol, which should probably also be stated in the docs

This is already mentioned under section discussing addressing.

Certainly welcome improvements to this topic, it is very common area where people get lost with the numbers.

The openHAB modbus binding uses data frame entity addresses when referring to modbus entities. That is, the entity address configured in modbus binding is passed to modbus protocol frame as-is. For example, Modbus poller thing with start=3, length=2 and type=holding will read modbus entities with the following numbers 40004 and 40005. The manufacturer of any modbus device may choose to use either notation, you may have to infer which, or use trial and error.

Modbus is difficult (because of stuff like the addressing), there is no easy way. Our binding docs should be about the binding, not be a Modbus tutorial - though of course we can point to some of those.