ModBus Binding: convert raw 'Number' register to a 'Number:Energy' Item?

I am planning to use the ModBus binding to read some values from a power meter. The base ModBus binding has a data Thing with a Channel of type Number (raw number without any UoM) and I am wondering how to create UoM Items from it…

So in the example below, I have a data Thing that reads the total energy consumed from register 5 of the meter; this register is an unsigned swapped 32 bit integer that the manufacturer says represent Watt-hours (Wh), and so I would like to create an Item of type Number:Energy based on that value. My hypothesis is that I must apply a transform “JS(mult3600.js)” to convert the Wh denominated raw number to a Number:Energy in the default energy unit of Joules. => But my question is whether this is indeed correct?

Bridge modbus:tcp:g24 "Modbus Binding" @ "Under Stairs" [host="192.168.1.123", port=123] {
  Bridge poller poller "Electricity Meter Poller" @ "Under Stairs" [start=0, length=10, refresh=5000, type="input"] {
..
    Thing data energy "Electricity Meter Energy" @ "Under Stairs" [readStart="5", readValueType="uint32_swap", readTransform="JS(mult3600.js)"]
..
  }
}
(function(inputData) {
    return parseFloat(inputData) * 36000;
})(input)
Number:Energy Electricity_Meter_Energy "Electricity Meter Energy" channel="modbus:data:g24:poller:energy:number"}

Note: the same logic would apply to creating Number:ElectricPotential, Number:ElectricCurrent Items too…

This is not possible in OH2.

It looks like it should be possible in OH3 with the use of a transformation profile, to factor your number and add a units string.

Thanks @rossko57 I know about the use of scaling transforms. That was not my question though. The transform allows one to create a raw Number Item on it. My question was how to create a Number:Dimension Item from it.

This is not possible in OH2.

It looks like it should be possible in OH3, using a transform profile to (optionally) scale and then add a units string before passing the combined result to a Quantity Type Item.

@rossko57 if I understand it correctly you are saying that the transform should return a String in the form of “123.4 Wh” (say), and the OH3 core is able to read that String and populate a “Number:Energy” Item. Or?

Frankly I don’t understand what 's the problem here.
When you have defined the item as a Number:Energy type you can have the modbus binding write to it.
If the default units don’t match you should can apply a JS(mult3600.js). Works in both, OH2 and 3.

Thank you Markus. If I understand it correctly then for every Number:Dimension type there is a “default unit” that gets used if a unit is not explicitly mentioned. Or? So in my case of “Number:Energy” I suppose the default unit would be “Joule” (or “Calorie” ?). => Is this documented somewhere? (I did check and haven’t found anything so far)…

EDIT: I am pretty sure that there are no ‘default units’ for Energy, Power, etc. (or even Current, Voltage, Frequency…)

I think you need to have a play.

You certainly cannot use a channel profile of transform type to achieve units in OH2. It’s a OH2 restriction of the transform profile that it only works with String target Items. This is external to the binding/channel involved, so applies to all bindings.
The restriction has been lifted/fixed in OH3.

For Modbus Thing/channel definitions, this binding supports transfoms, so you can of course apply a readTransform at the data Thing definition. There is nothing to stop you adding units at that point, the in/out to the transform is always in string form, so “10.3 kW” is acceptable transform output here.
-but-
the Modbus binding supports porting data to/from various channel types, including number. It does not support channel types like number:energy. I expect this to cause you a problem.
EDIT - to clarify this part with the info from @AndrewFG experiments, it seems the plain number type channel will pass a Quantity Type value e.g. “40 W” from a transformation - so all you need to do next is link the number type channel to an Item type that expects the units e.g. Number:Power

If you try this, you can make temporary Modbus data Things using the same Modbus register etc. to port the result to various Items to see what’s going on and verify your transform. I’d use a String, plain Number, and Number:Energy (or whatever) target Items to experiment.

Thanks @rossko57. I did that, and it doesn’t. I will try again in a week or so with OH3.

@rossko57 just to confirm that it works perfectly in OH3. Many Thanks!

Things file…

Bridge modbus:tcp:g24 "Modbus Binding" @ "Under Stairs" [host="192.168.1.172", port=23, rtuEncoded=true] {
  Bridge poller poller "Electricity Meter Poller" @ "Under Stairs" [start=0, length=10, refresh=5000, type="input"] {
    Thing data voltage "Electricity Meter Voltage" @ "Under Stairs" [readStart="0", readValueType="uint16", readTransform="JS(24g-dV.js)"]
    Thing data current "Electricity Meter Current" @ "Under Stairs" [readStart="1", readValueType="uint32_swap", readTransform="JS(24g-mA.js)"]
    Thing data power "Electricity Meter Power" @ "Under Stairs" [readStart="3", readValueType="uint32_swap", readTransform="JS(24g-dW.js)"]
    Thing data energy "Electricity Meter Energy" @ "Under Stairs" [readStart="5", readValueType="uint32_swap", readTransform="JS(24g-Wh.js)"]
    Thing data frequency "Electricity Meter Frequency" @ "Under Stairs" [readStart="7", readValueType="uint16", readTransform="JS(24g-dHz.js)"]
    Thing data powerfactor "Electricity Meter PowerFactor" @ "Under Stairs" [readStart="8", readValueType="uint16", readTransform="JS(24g-percent.js)"]
    Thing data alarm "Electricity Meter Alarm" @ "Under Stairs" [readStart="9", readValueType="uint16"]
  }
}

Transform script 24g-dV.js (showing one example for the first Thing @ “deciVolts”)

(function(inputData) {
    return inputData + " dV";
})(input)

Items file

Number:ElectricCurrent Electricity_Meter_Current "Electricity Meter Current [%.1f A]" <24gamp> {channel="modbus:data:g24:poller:current:number"}
Number:Power Electricity_Meter_Power "Electricity Meter Power [%.1f kW]" <energy> {channel="modbus:data:g24:poller:power:number"}
Number:Energy Electricity_Meter_Energy "Electricity Meter Energy [%.1f kWh]" <energy> {channel="modbus:data:g24:poller:energy:number"}
Number:Frequency Electricity_Meter_Frequency "Electricity Meter Frequency [%.1f Hz]" <24ghertz> {channel="modbus:data:g24:poller:frequency:number"}
Number:Dimensionless Electricity_Meter_PowerFactor "Electricity Meter PowerFactor [%.0f %%]" <qualityofservice> {channel="modbus:data:g24:poller:powerfactor:number"}
Switch Electricity_Meter_Alarm "Electricity Meter Alarm [MAP(24g-alarm.map):%s]" <siren> {channel="modbus:data:g24:poller:alarm:switch"}


EDIT: I just want to point out the magic of this new solution: you can apply both a Unit-of-Measure and also Scaling in one go.

In the example above the register contains integer values in tenths of a volt…

  • In the old OH2.5 solution you would need to apply a value / 10 read transform on the Thing and then specifically apply a "[%.1f V]" formatting string on the Item/Sitemap.
  • In the new OH3 solution you apply a value + " dV" read transform on the Thing and then you can apply whatever formatting string you want on the Item/Sitemap (in my case also in Volts, and the conversion dV to V is done auto-magically).
2 Likes

Cool!

Please also check out my work on profiles implementing something similar [Modbus] Testing needed: scaling values to Quantity-aware Numbers and writing individual bits

The benefit of profile is that it works also the other way, from commands to modbus data, taking care of inverse scale and unit transformations.

@ssalonen after having received your great help with the RTU over TCP Encoding, I would love to help on your profile topic. But unfortunately my Modbus device is read only, so I don’t think I can help very much. ??

1 Like

Well it works with read only as well :slight_smile:

Ok. I will have a look at it.

1 Like

@ssalonen do you have a link for the jar? And do you confirm that all I need to do is add the following to my (deci)Volt Item definition?

[ profile="modbus:gainOffset", gain="0.1 V" ]

Also I wonder if the following would work? And if not, why? IMHO one should use the OH UoM Metric Prefixes for all order of ten scaling; it covers the range from 10^-24 (yocto) to 10^24 (yotta)… EDIT: UoM also has Binary Prefixes for scaling…)

[ profile="modbus:gainOffset", gain="1 dV" ]
1 Like

The jars are behind the link. All units of openHAB should be supported, even prefixes.b

You could do “1 V/10” or “0.1 V”, probably the deci-volt as well…

Currently the pre-gain offset parameter is mandatory, add that one as well, otherwise your example looks well. The profile configuration follows the channel name

Number:ElectricPotential MyItem "voltage [%.1f V]" { channel="modbus:data:localhostTCP3:holdingPoller:somedatathing:number"[ profile="modbus:gainOffset", gain="0.1 V", pre-offset="0" ] }

My first suggestions – therefore – are… :grin:

  • If offset argument is missing: default offset is 0
  • If gain argument is missing: default gain is 1
1 Like

@ssalonen Oops! I realised that there is a fundamental problem:

Your JARs are built based on the OH core prior to my PR for “RTU over TCP” having been merged. So I think that a) your binding version won’t work with the latest SNAPSHOT core, and b) my device needs “RTU over TCP” which is not yet in your jar. So basically it doesn’t work.

I think you need to rebase your PR based on the latest SNAPSHOTs of both ‘core’ and ‘addons’, and rebuild your jars. Otherwise I regret that I cannot test it.

1 Like

Thanks @AndrewFG! Indeed that is the case. Will have a look later, thanks!

@ssalonen looking at our respective PRs, it seems that the files that you and I ‘touched’ are mostly different ones. So there should not be too many merge conflicts if you have to do a git rebase. But I think that ‘ReadMe.md’ will probably need a manual merge…