Thanks @rossko57, @AndrewZ and @mbs38 on comments regarding the configuration complexity.
Indeed that is a valid concern. As we are discussing a low level protocol with no “thing” discovery, I tend to agree with @rossko57 that ultimately user should be able to decide what kind of modbus requests the software is executing. Otherwise the binding developer has made the decision for the user, and in the worst case ending up with non-working config.
For example, we have seen so many “exotic” modbus devices (as @rossko57 said) in these forums, that any automatic “combination” of requests is error prone I think.
One of the other design criterias was not to reduce functionality compared to older binding (I think we have managed with this pretty well – although some limitations are there, as discussed in this thread). For example, with the openhab1 binding, one can configure Rollershutter “device” without any rules, ultimately represented by a single thing. Yes, there are additional “helper” things to make it happen but I think that’s a necessary compromise (see more discussion below).
If we would decide to leave the modbus binding with simple IO functionality (just supporting number items for example with no transformations), much of the binding complexity could be reduced. Naturally, the complexity would be introduced in the form of “proxy items” and rules.
For example of more complex example, rollershutter example from openhab1
modbus.things
Bridge modbus:tcp:endpointTCP [ host="127.0.0.1", port=502, id=2 ] {
Bridge poller holding [ start=0, length=4, refresh=500, type="holding" ] {
Bridge readwrite LivingRoomRollershutter {
// Roller shutter position is read from register 0
Thing read readPosition [ start=0, valueType="int16" ]
// UP(=1)/DOWN(=-1) commands are written to register 1
Thing write writeUp [ start=1, trigger="UP", transform="1", valueType="int16", type="holding" ]
Thing write writeDown [ start=1, trigger="DOWN", transform="-1", valueType="int16", type="holding" ]
// MOVE(=1)/STOP(=0) commands are written to register 2
Thing write writeMove [ start=2, trigger="MOVE", transform="1", valueType="int16", type="holding" ]
Thing write writeStop [ start=2, trigger="STOP", transform="0", valueType="int16", type="holding" ]
}
}
Here the item would be
Rollershutter RollershutterLivingRoomPosition "Roller shutter position [%.1f]" <temperature> {channel="modbus:readwrite:endpointTCP:holding:LivingRoomRollershutter:rollershutter"}
and sitemap same as in old version (see the link).
You can compare this to the openhab1 version (rows added for clarity) and see the analogy.
Rollershutter RollershutterItem "Roller shutter position [%.1f]"
<temperature> {modbus="<[slave1:0],
>[slave1:1:trigger=UP,transformation=1],
>[slave1:1:trigger=DOWN,transformation=-1],
>[slave1:2:trigger=MOVE,transformation=1],
>[slave1:2:trigger=STOP,transformation=0]"}
A bit unfortunately, we have had quite many cases requiring this kind of functionality (see the thread and linked threads).
We could support the “cryptical” item configuration pattern above and thus there would be no need for read
and write
things, just the readwrite
. However, we then would lose the UI configuration possibilities and it’s easy to make typoes.
We could combine some things though: Say we would combine poller and endpoint things. Since we have different parameters for serial and tcp endpoints, we would have to introduce “tcp-poller” and “serial-poller”. In case of many “pollers” (e.g. user wants to poll coils and holding registers), one would have to carefully copy-paste the endpoint information (e.g. ip address and other relevant settings). The current design tries to be “orthogonal” and as such no information is repeated.
One thing that I would like to mention is that I do have a concern that we are inventing something here that is quite different from the other bindings. As said in this thread, I found no other as low level protocols supports as openHAB2 addons yet to take example from. For example, there has been quite long discussions with KNX and MQTT bindings – there are no easy/natural thing hierachy there.
Nevertheless, if the outcome feels like super-complex and hard to understand we have work to do. I hope that with clear examples and proper documentation this can be remedied…
What do you think? Does this make sense at all?
EDIT: managed to get rid of the mapping in the example by using rolleshutter channel instead of number channel.