Update: This feature is now part of modbus binding 1.10.0.
Hello everyone!
Originally discussed in here, there has been a need for having transformation support for opnehab. Some of the more complicated use cases (e.g. rollershutter items) could be implemented simply using transformations.
I have been implementing this support for a while now, and feel confident sharing the first test version with the community. Along this update comes support for
- writing to different address based on the command received
- declaring/overriding value type in the items
- read-only and write-only items (use case with some slave manufacturers)
- support for all item types, as long as necessary transformations are used (see rollershutter example below)
The item configuration syntax was extended to support these new use cases. You can notice that MQTT and HTTP bindings have been the inspiration.
All feedback is most welcome!
Extended item configuration
Now the item configuration string can consist of one or more “IO-definitions”, describing how the data is read from modbus, or data written to modbus.
Read definition:
<[slaveName:readIndex:trigger=TRIGGER,transformation=TRANSFORMATION,valueType=VALUETYPE]
Write definition:
>[slaveName:writeIndex:trigger=TRIGGER,transformation=TRANSFORMATION,valueType=VALUETYPE]
All the keyword arguments after index are optional. Defaults are such that they correspond to binding behaviour currently. Multiple read/write definitions can be specified with commas. Old item syntax is still supported for backwards compatibility.
Explanation of different arguments
-
trigger
: a string matching command (write definitions) or state (read definitions). If the command/state does not match the trigger value, the command/state is not processed by this write/read definition. Use*
to process all (overrides slave’supdateunchangeditems
). UseCHANGED
with read entries to handle only changed values (similar toupdateunchangeditems=false
). Usedefault
to handle all or just the changed values, depending on slaveupdateunchangeditems
parameter (this might be buggy at the moment – will fix it later). If omitted, usesdefault
. -
transformation
: transformation to use interpreting the result. Can be eitherdefault
(no transformation, i.e. pass value as is), orSERVICE(ARG)
to refer to transformation service. Any other value than the above types will be interpreted as static text, in which case the actual content of the message is ignored. Can If omitted, usesdefault
. The transformations can convert to string representing command and state types of the item. You can also always use numbers (DecimalType), ON/OFF and OPEN/CLOSED. -
valueType
: valueType to use when interpreting the register. UseDEFAULT
to refer to slave definition’s valueType. If omitted, usesdefault
.
Examples
JS transformation (scaling)
This example multiplies the DecimalType commands by 10 when writing to modbus, and divides the values by 10 when reading from modbus.
default.items:
//
Number NumberItem "Number [%.1f]" <temperature> {modbus=">[slave1:0:transformation=JS(multiply10.js)],<[slave1:0:transformation=JS(divide10.js)]"}
transform/multiply10.js:
// Wrap everything in a function
(function(i) {
return Math.round(parseFloat(i, 10) * 10);
})(input)
// input variable contains data passed by openhab
transform/divide10.js:
// Wrap everything in a function
(function(i) {
return parseFloat(i) / 10;
})(input)
// input variable contains data passed by openhab
Rollershutter example
(inspired by [modbus] enhance modbus binding for rollershutter items #4654)
This is an example how different Rollershutter commands can be written to MODBUS.
Roller shutter position is read from register 0, UP(=1)/DOWN(=-1) commands are written to register 1, and MOVE(=1)/STOP(=0) commands are written to register 2.
default.items:
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]"}
default.sitemap:
sitemap demo label="Main Menu" {
Switch item=RollershutterItem label="Roller shutter [(%d)]" mappings=[UP="up", STOP="X", DOWN="down"]
}
Read-only items
Number NumberItem "Number [%.1f]" <temperature> {modbus="<[slave1:0]"}
Write-only items
Number NumberItem "Number [%.1f]" <temperature> {modbus=">[slave1:0]"}
Set coil to true on any command
(inspired by [Modbus] Coil reset only after item update to ON (OFF excepted) #4745)
Reads from index 0, writes to index 1. All writes (no matter what command) are converted to 1.
Number NumberItem "Number [%.1f]" <temperature> {modbus="<[slave1:0],>[slave1:1:transformation=ON]"}
Related github issues
- Transform support for Modbus Binding #4204
- [Modbus] Coil reset only after item update to ON (OFF excepted) #4745
- [modbus] enhance modbus binding for rollershutter items #4654
- [request] Modbus Binding write and read not contiguous addresses #4407
Best,
Sami