I’ve developed two new features with the OH3 modbus binding:
1) QuantityType-aware numbers
Modbus binding currently supports only plain Number channels. This makes it incompatible with excellent UoM system of openHAB.
Typically decimal numbers are scaled to integers with Modbus. Having support for scaling the integers and attaching the unit with a convenience profile would streamline configuration UoM aware numbers.
This allows you scale bare Number like 58 (from Modbus) to be converted to QuantityType 5.8 Celsius (item). Also command works when writing data to Modbus.
Command individual bits of modbus registers is currently hard, and additional rules are required. See e.g. @Rossko57 's post in the forum Bitwise operations in a modbus register
We can use the new profile to command individual bits.
Bit of a late thought, but writeable modbus bit values are most likely to be wanted to be used with Switch type openHAB Items.
That would in turn raise the spectre of whether “0” means ON or OFF
Could have a selection by profile="modbus:bitinvert" ,,,
or maybe profile="modbus:bit", bit-index="1-invert"
Question: what happens if we use modbus:bit profile with a write-only uint16 data Thing?
Is the “register image cache” still maintained according to command/write activity, and so will affect the data written to modbus e.g we might write a pattern like 00100011 depending on history?
I’m looking at a PLC use case, where it might work better if the “register image cache” was always zero, e.g. we only wrote a single bit 000100 style. I’m still working out whether it would really be better or not!
I don’t think that’s very common, and can easily be achieved if needed by other means, but it led me to think about the cache workings.
A device having a write-only register that we just cannot read may be more common, some PLCs are weird like that, so it would be good to understand.
I’m sure maintaining the cache image would be the correct way to do it, in general.
Related - does the profile update the state of the linked Item according to the cache? I think it should not - autoupdate does that job, if wanted. Only real read poll data should get passed to Item state?
Currently commands are ignored if there is no value read
So having write-only items with this bit profile is not supported atm. I think it’s ok, perhaps a rare case in the end?
The commands do update the internal cache as well. Actually, this does not matter since the same bit is always overwritten with commands, and the cache is not shared with other instances of the profile (other items). Real reads the clear the whole cache and extract the bit from the 16bits
Write only items with always-zero-cache could be implemented with simple MAP transformations, wouldn’t they? ON mapping to 2^n and OFF mapping to 0
Related - does the profile update the state of the linked Item according to the cache? I think it should not - autoupdate does that job, if wanted. Only real read poll data should get passed to Item state?
Profile only 1) passes state updates from binding, towards the item; 2) passes commands from item towards the binding. Indeed it does not update item state based on commands received by the item.
So your understanding is correct, only real poll data gets passed to item state.
In general, I am not sure if auto-update is working with profiles in general… I have not tried.
It strikes me that this “scale and add units” profile is generally useful throughout openHAB. A great many bindings still supply number-only channels because they cannot “know” much about the target device e.g. an HTTP fetch. While the user often knows exactly what he’s getting, and fiddles about with state presentations or scripted transforms to get it looking right.
I think it should be promoted to be one of the default system profiles, not a part of Modbus particularly. Well done Sami
Yes correct on the bit profile. The precompiled jars are slightly outdated, UI part was fixed later.
There are certain problems with the bit profile due to constraints imposed by the openHAB profile mechanism. Actually I will probably remove the bit profile in the end in its current form.
Thank you @rossko57 . Indeed it is very general in that sense and it crossed my mind as well. It can be also used with gain of one but simply “attaching” the unit. This would be convenient with temperature values for example.
Only part that is not general there is the limitation that it only works with bindings that output raw values. I initially tried to cover the fully general use case as well, accepting quantitype as input, (with the thinking of bringing it to core/outside modbus) but there are quite many surprising edges and troubles with the unit conversions. In the end I think it is much more rare use case but could be used in some cases, e.g. to fix units.
That’s reasonable.
If the binding is already sending Quantity type channel that is because it thinks has it all correct already, it needs no further massaging.
I have now reimplemented the way one can command individual bits of a holding register: now it is part of a data thing, not a profile.
This has a benefit that many commands play nice together as they all share the same internal cache. It is possible to fire many commands in succession each referring to different bits of the same register.
Links in the first post have been updated, precompiled jar is behind the link. The gainOffset profile should work the same way as before, no major changes.
I would like to test. I am on OH3.1.0 Bulid 2175. Followed the instructions on the github page and got this error when installing openhab-transport-serial:
openhab> feature:install openhab-transport-serial
org.apache.felix.resolver.reason.ReasonException: Unable to resolve org.openhab.binding.modbus.sunspec/3.1.0.202102020413: missing requirement [org.openhab.binding.modbus.sunspec/3.1.0.202102020413] osgi.wiring.package; filter:="(osgi.wiring.package=org.openhab.binding.modbus.discovery)"
at org.apache.felix.resolver.Candidates$MissingRequirementError.toException(Candidates.java:1343)
at org.apache.felix.resolver.ResolverImpl.doResolve(ResolverImpl.java:420)
at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:378)
at org.apache.felix.resolver.ResolverImpl.resolve(ResolverImpl.java:332)
at org.apache.karaf.features.internal.region.SubsystemResolver.resolve(SubsystemResolver.java:257)
at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:393)
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1062)
at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:998)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Error executing command: Unable to resolve org.openhab.binding.modbus.sunspec/3.1.0.202102020413: missing requirement [org.openhab.binding.modbus.sunspec/3.1.0.202102020413] osgi.wiring.package; filter:="(osgi.wiring.package=org.openhab.binding.modbus.discovery)"
I have installed SunSpec Bundle in this version:
230 x Active x 80 x 3.1.0.202101310352 x openHAB Add-ons :: Bundles :: SunSpec Bundle
I am not sure what that error means… What if you just skip the installation of the serial?
Does the modbus bundle install and start?
Since you already have sunspec installed, you must have some version of modbus binding installed. You might need to call bundle:update Xx to make sure the jar from the addons folder is used.
The first testing results are very positive. I was able to read and write data with following thing configuration: Thing data EG_Bad [ readStart="0.0", readValueType="bit", writeStart="0.0", writeValueType="bit", writeType="holding" ]
The part to write at the end is new: writeStart=“0.0”, writeValueType=“bit”, writeType=“holding”
For this part, I am now using a separate thing configuration which looks like this: Thing data EG_Bad [ writeStart="0", writeValueType="bit", writeType="coil" ]
This I now don’t need any more… awesome! The item is only linked to one channel.
Thank you very much!