Modbus Binding V1 -> V2 Config Update Howto

With the Update from openHAB 2.3 (or earlier) to openHAB 2.4 a new, oh2-compliant version of the modbus binding is introduced. The new version is not backward compatible, so the old modbus config will not work. I describe here how I created the new config based on my old config.

My old modbus configuration defined 4 slaves:

poll=500

tcp.slave1.connection=192.168.2.9:502
tcp.slave1.type=coil
tcp.slave1.id=1
tcp.slave1.start=12288
tcp.slave1.length=128
tcp.slave1.updateunchangeditems=false

tcp.slave2.connection=192.168.2.9:502
tcp.slave2.type=holding
tcp.slave2.id=2
tcp.slave2.start=12338
tcp.slave2.length=100
tcp.slave2.updateunchangeditems=false

tcp.slave3.connection=192.168.2.9:502
tcp.slave3.type=holding
tcp.slave3.id=3
tcp.slave3.start=12438
tcp.slave3.length=100
tcp.slave3.updateunchangeditems=false

tcp.slave4.connection=192.168.2.9:502
tcp.slave4.type=holding
tcp.slave4.id=4
tcp.slave4.start=12538
tcp.slave4.length=100
tcp.slave4.updateunchangeditems=false

As you can see, all the slaves poll the same modbus device, in my case a Wago 750-841 controller. Now, how to create a thing file for this pollers.

The new modbus binding uses a three-level definition.

Level one defines a Bridgefor every modbus slave. As I only have one, my new config will only contain one top-level bridge:

Bridge modbus:tcp:wago [ host="192.168.2.9", port=502, id=1 ] {

}

Host and Port are from my old modbus config.

Within the top level Bridge there are one or more second level bridges that replace the former slave configurations. The poll frequency can now be set per slave, so you may want to define different poll cycles up to your needs. The slave Bridge configs go inside the top level config. For me it now looks like this:

Bridge modbus:tcp:wago [ host="192.168.2.9", port=502, id=1 ] {

    Bridge poller wago_slave1 [ start=12288, length=128, refresh=500, type="coil" ] {
    }

    Bridge poller wago_slave2 [ start=12338, length=100, refresh=4000, type="holding" ] {
    }

    Bridge poller wago_slave3 [ start=12438, length=100, refresh=5000, type="holding" ] {
    }

    Bridge poller wago_slave4 [ start=12538, length=100, refresh=10000, type="holding" ] {
    }
}

The third (and most complex) part is now the definition of Thing objects for every Item bound to modbus. This definitions go into the corresponding 2nd level Bridge definitions. Here it is especially important that the modbus binding now uses absolute addresses all over the place, while the addresses in the item definition were relative to the start address of the slave definition before.

One example:

My old Item definition contained a line like this:

Switch FooSwitch  "Foo Switch"  {modbus="slave1:0"} 

I now have to define a Thing that can later be bound to that Item.

My slave1 poller used 12288 as start address. So I define a data Thing within my poller wago_slave2 with this address:

Thing data wago_s1_000 [ readStart="12288", readValueType="bit", writeStart="12288", writeValueType="bit", writeType="coil" ]

The Item

Switch BarSwitch  "Bar Switch" {modbus="slave1:1"}

with relative address 1 leads to the thing definition

Thing data wago_s1_001 [ readStart="12289", readValueType="bit", writeStart="12289", writeValueType="bit", writeType="coil" ]

Note the absolute address used here.

The Thing file now looks like this:

Bridge modbus:tcp:wago [ host="192.168.2.9", port=502, id=1 ] {

    Bridge poller wago_slave1 [ start=12288, length=128, refresh=500, type="coil" ] {
        Thing data wago_s1_000 [ readStart="12288", readValueType="bit", writeStart="12288", writeValueType="bit", writeType="coil" ]
        Thing data wago_s1_001 [ readStart="12289", readValueType="bit", writeStart="12289", writeValueType="bit", writeType="coil" ]
    }

    Bridge poller wago_slave2 [ start=12338, length=100, refresh=4000, type="holding" ] {
    }

    Bridge poller wago_slave3 [ start=12438, length=100, refresh=5000, type="holding" ] {
    }

    Bridge poller wago_slave4 [ start=12538, length=100, refresh=10000, type="holding" ] {
    }
}

Save this in the ā€œthingsā€ subdirectory of your openHAB 2 config. Watch the file events.log as it lists your new added data Things. Given that there are no config errors, they quickly change from INITIALIZING to ONLINE.

Finally the Item definition has to be changed to refer to the new created data Thing. you can copy the names you need for this directly from the events.log file:

Switch FooSwitch  "Foo Switch" {modbus="slave1:0"} 
Switch BarSwitch  "Bar Switch" {modbus="slave1:1"}

turn into

Switch FooSwitch  "Foo Switch" {channel="modbus:data:wago:wago_slave1:wago_s1_000:switch", autopudate="false"} 
Switch BarSwitch  "Bar Switch" {channel="modbus:data:wago:wago_slave1:wago_s1_001:switch", autoupdate="false"}

Notice that the names I have chosen for my data Things end with the numbers of the relative addresses in the former item definition. That made it possible to change my Item file with only a few ā€œsearch and replaceā€ commands.

The definition of autoupdate is optional; please refer to the modbus binding documentation to check whether you need it or not.

Continue to add data Things for all your other Items the same way and link them to your Items.

Save your updated item file and check whether updates come in as expected.

If you have many modbus items (>50) and made use of the updateunchangeditems feature of the old modbus binding, be sure to read this discussion and use the snapshot version of the modbus binding linked there. Otherwise you might see high CPU load due to the way the new binding works.

If you make use of other features of the old modbus binding this article doesnā€™t cover feel free to describe how to update them in a comment.

@ssalonen: If you think this article is helpful, maybe you might refer to it from your binding documentation.

Yours

Wolfgang

6 Likes

This is a really good and clear explanation how to migrate from the old binding to 2.x. And I think some users will find this very useful. Thanks!

One question though. Wouldnā€™t this be better placed in Tutorials&Examples / Solutions category?

1 Like

Really great post, I like the way you have outlined a systematic approach for migrating the configuration.

Indeed that would be a good documentation addition. I encourage you to submit PR to github, I always like to say itā€™s community project, after all :slight_smile:

Perhaps it is worth pointing out that old binding is still there, but it is recommended to migrate to new binding eventuallyā€¦

Dear @ssalonen,

I will create a PR within the next few days ā€¦ maybe on Wednesday, but I canā€˜t promise. Stay tuned.

Yours

Wolfgang

1 Like

PR Created:

2 Likes

Dear @Wolfgang1966,

thank you veru much for this very clear tutorial for the migration (and btw thanks also @ssalonen for this very promising new binding for modbus)

Iā€™m considering the migration myself and iā€™m on one of these cases with over 50 modbus items to migrate (i could count 83ā€¦)
There is one thing that is not clear to me after having studied the tutorial which is relative to the behaviour of the new binding wrt what was before managed through the updateunchangeditems parameter of the former modbus.cfg.

In short, do you know if the new binding is acting as updateunchangeditems=true or false?

I would suppose it acts as with the ā€˜trueā€™ mode however iā€™m trying to anticipate what iā€™ll get as i use both modes in my application. hence i would need as well to work out a way to mimic the other ā€˜falseā€™ mode (whereby update events are triggered only upon an effective change of value). On this point, would you may be have a suggestion for a workaround for mimicking as seamlessly as possible the other ā€˜falseā€™ mode (or the ā€˜trueā€™ mode in case i guess wrong and the binding indeed acts as with the former ā€˜falseā€™ mode)

thanks in advance!

The nearest equivalent of this in v2 is the data Thing parameter updateUnchangedValuesEveryMillis, but it does work in a slightly different way. I think you need a 2.5+ version to get this recent feature.

By default, every read poll updates an Item linked by channel.
This parameter will ā€œmiss outā€ Item updates where the polled value does not change - for a fixed length of time. You might set this for some minutes, for example.
As with v1, this reduces overhead on openHAB event bus, persistence services, etc.

thanks @rossko57! thatā€™s great help, i had totally missed that parameter and corresponding clarif from the doc, sorry for that. this param is indeed what i could have dreamt of to make the transition straightforward.
thanks again for such a quick and clear answer and warning for the 2.5+ iā€™ll take care, much appreciated
good luck to you and to all

Dear @oliviercommelarbre,

the 2.4 version of the binding acts equal to updateunchangeditems=true. The 2.5 snapshot version introduces the parameter updateUnchangedValuesEveryMillis as @rossko57 mentioned already. If you choose a very high value for milliseconds (e.g.1000000), you basically get the same behaviour you had using updateunchangeditems=false.

I have this configuration running for some weeks now already and it works fine. CPU load is acceptable in this config, while it was clearly too high for my 200+ modbus items when using the 2.4 version of the binding.

Dear @Wolfgang1966,

thank you for this extra clarification. Indeed i had followed @rossko57ā€™s hint and got to the 2.5.0-SNAPSHOT (build #1540) to be on the safe side with the new parameter (note: iā€™ve tried first the 2.5.0.M1 but the parameter was not effective, probably it was introduced later in the 2.5 consolidation work). Now Iā€™ve already completed the migration (thanks to your tutorial + the clear and exhaustive manual for the binding i must say), and sofar so good, all works like a charm under 2.5 and the new binding, including on performance.

I actually found a single hickup in migrating that is maybe worth mentioning here in case others get it on the way, which is related to the value types:

In my load of registers, i had under the V1 binding configuration declared some 8-bits type integers (int8 or uint8) for holding registers that i knew would not use the 16-bits range. The V1 binding is permissive on this, in that it will transparently cast the 16-bit integers out of modbus into 8-bits equivalents to match your defined sink type. However the V2 binding requires (rightly in fact) that one chooses which of the two bytes to extract (using the notation readStart=ā€œX.Yā€) to get back to the desired one-byte sink integer. If you donā€™t use this notation, then the read does not work at all. Indeed, you get an error logged but not in openhab.log so it took me a bit of time to find-out.

You will get an error in events.log like:

ā€˜modbus:data:slave:holding:MyItemā€™ changed from INITIALIZING to OFFLINE (CONFIGURATION_ERROR): readStart=X.Y must be used with value types less than 16bit!

Rather than using the notation with the byte offset, i have preferred to solve the issue by changing all the 8-bits type i had in my V1 config into 16-bits types (i.e. uint16 or int16). Indeed, since the integer values are anyway coming out of modbus in 16-bits integers (holding registers), it does not make much sense in my case to attempt to change that into 8-bits integers to finally use them as a Number type or DecimalType down the chain in openhab.

hopefully my mistake will not be repeated by others thanks to the post

here we go, thanks again for your reply and for the great help already ahead of it!

1 Like