OH4 Blockly Calculations with items states

See Rules Blockly - Items & Things | openHAB. IIUC, the to unit block cannot convert a number to a quantity.

Workaround (untested): Convert your number to a string by appending ’ VA’ (mind the space) and use the to unit block to convert the string to a quantity (convert the string ‘123 VA’ to the quantity 123 VA).

Makes sense. Will test when I get power back (South Africa with Load Shedding). Weird there is no error though?

From logging, how can you differentiate between a string of 123.456 and a number of 123.456?

W and VA are both of type Power so there should be no problem converting between them using toUnit. However, looking at your second to last line we see the result of the division doesn’t have units, or probably it has the NONE unit used for ratios.

The behavior of toUnit is indeed to return null if it fails to convert between the units.

And this makes sense. When you divide a unit by something, you almost never get the same unit back. It’s almost always a new unit after dividing (e.g. kilometers divided by hours become KPH).

I’m not sure what you are attempting to calculate here (I’m not an electrician and it’s been decades since I’ve messed with electrical calculations). If you are certain that the new value is in fact a Power (W, VA, var, dBm) than I think @Mark_VG is on the right track. You will want to build a string with the quantity and " VA" (note there must be a space between the number and the units) and use the first block to convert it to a Quantity, or not if you are done and plan on posting this to an Item or something. If there are no more calculations to be done you can leave it as a String for logging and updating an Item with.

@stefan.hoehn
Would it make sense to add Blockly blocks for conversion from number to quantity and vice versa?

1 Like

@florian-h05 what do you think about that idea?

A block to convert from number to Quantity makes no sense, since a Quantity is relatively useless without a unit. You can possibly concatenate the number with a unit string to a new string and construct a Quantity with that string.

In the other direction: could make sense, however you can pass the Quantity to both the logger and the postUpdate/sendCommand method. If there is a need to get the number or other stuff from the Quantity, I’m not against having a block that allows access to the properties of the Quantity, see Quantity - Documentation.

A lot (but not all) of the problems experienced above go away if we had a way to get the numeric and quantity state straight from the Item (hence the Issue I opened, link above, to add those as well as “raw state” to the get property from Item block.

But this last problem where the division either returned a raw number or, more likely I think, it returned a ratio meaning it’s using the Dimensionless units (NONE?). In cases like those and in cases where one needs to do calculations that are a mix of numbers and quantities the problem still remains.

I’ve found that to be a bit awkward. I couldn’t find any way to do that without the three line set of blocks shown above (post #15), though maybe I missed the correct block to do that better?

One thing that could ease that problem is if the string to quantity block had a version that took two arguments so the value and the unit could be passed in separately. The Java QuantityType class has a constructor that supports that but I’m not sure the Quantity builder in openhab-js supports that. That might be less disruptive than adding a whole new set of Quantity blocks and it would encourage users to remain in Quantity space instead of stripping the units off of everything as a matter of habit.

I think the Units of Measurement blocks were just added in OH 4, correct? In that case you could even replace that one block I think without needing to create a new block if adding the new block is a problem. As far as I’m concerned (I do not speak for the maintainers) those blocks haven’t been released yet so it wouldn’t be a breaking change, besides the fact that OH 4 is for breaking changes in the first place.

When/if the changes to how core manages units gets merged :crossed_fingers: this will also become less of an issue because those who don’t want to use units can simply define their Items to not use them and then there’s no need to have to strip them in the rules.

This option works too:

Full code:

var upsWatt, upsWattNoUoM, upsPF, upsVA, upsVA_UoM, Temp, Temp1;


upsWatt = items.getItem('ShellyEM_UPS_Watt').state;
console.error(('Raw Value of ShellyEM_UPS_Watt: ' + String(upsWatt)));
upsWattNoUoM = actions.Transformation.transform('REGEX', '([0-9.]*) (\\D)', items.getItem('ShellyEM_UPS_Watt').state);
console.error(('No UoM  Value of ShellyEM_UPS_Watt: ' + String(upsWattNoUoM)));
upsPF = items.getItem('ShellyEM_UPS_PowerFactor').state;
console.error(('Raw Value of ShellyEM_UPS_PowerFactor: ' + String(upsPF)));
upsPF = upsPF * 1;
console.error(('Updated Value of ShellyEM_UPS_PowerFactor: ' + String(upsPF)));
upsVA = upsWatt / upsPF;
console.error(('Calculated VA value is: ' + String(upsVA)));
upsVA_UoM = (Quantity(upsWatt).divide(upsPF).toUnit('VA'));
console.error(('Calculated VA with UoM value is: ' + String(upsVA_UoM)));
upsPF = items.getItem('ShellyEM_UPS_PowerFactor').state;
console.error(('New upsPF for last test' + String(upsPF)));
upsPF += 'W';
console.error(('New upsPF after W append ' + String(upsPF)));
upsPF = Quantity(upsPF);
console.error(('New upsPF after IOM block ' + String(upsPF)));
Temp = (Quantity(upsWatt).divide(upsPF));
console.error(('New Temp after / ' + String(Temp)));
Temp += ' VA';
console.error(('Appended VA Result ' + String(Temp)));
Temp1 = (Quantity(Temp).toUnit('VA'));
console.error(('***********NEWCalculated VA with UoM value is Temp1 : ' + String(Temp1)));

Log output:

19:11:34.694 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - Raw Value of ShellyEM_UPS_Watt: 732.18 W
19:11:34.695 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - No UoM  Value of ShellyEM_UPS_Watt: 732.18 W
19:11:34.695 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - Raw Value of ShellyEM_UPS_PowerFactor: 0.9
19:11:34.696 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - Updated Value of ShellyEM_UPS_PowerFactor: 0.9
19:11:34.696 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - Calculated VA value is: NaN
19:11:34.697 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - Calculated VA with UoM value is: 813.53333333333333333333333333333325198 VA
19:11:34.697 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - New upsPF for last test0.9
19:11:34.698 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - New upsPF after W append 0.9W
19:11:34.698 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - New upsPF after IOM block 0.9 W
19:11:34.699 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - New Temp after / 813.53333333333333333333333333333325198
19:11:34.699 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - Appended VA Result 813.53333333333333333333333333333325198 VA
19:11:34.700 [ERROR] [nhab.automation.script.ui.Watts_to_VA] - ***********NEWCalculated VA with UoM value is Temp1 : 813.5333333333333 VA

I am really not sure which is better or easier. They all take a fair bit of “background” coding knowledge from what I can see.

This has been an interesting learning experience for me and hopefully helps someone else in the future.

Like so? (see the second block)

image

I wouldn’t like to get rid of the first block though because often you compare against a constant in the code and therefore the second block would be unnecessary complex.

This block

image

would generate the following code

console.info(Quantity(‘10’+‘W’));

or this one

would generate

console.info(Quantity(items.getItem(‘WZ_Temperatur’).state+‘W’));

Note that the latter would fail if the item already has a Unit.

I already implemented that. If you are happy with that, I can do a PR.

I cannot imagine how that block would look like and what it would be used for. Can you provide an idea?

What about the following additional idea: would it make sense to provide the following “convenience” getter for an item that would return the quantity directly instead of the state which then would return a Quantity (provided that the state does include the unit! of course, this wouldn’t work in the above case where the unit is missing)?

it would be basically the getState-Block encapsulated by a UOM-Block

looks great except there needs to be a spot space between the number and the unit.

I’ve already opened an issue for this one. However I include rawState and numericState too.

Sure, will do, though it even works without it :wink:

Can you forward that link to the issue? And maybe even the code that you expect to be generated?

These are all just accessing what’s already on the Item Object already. Instead of calling .name on the Item, call .numericState, .quantityState, or .rawState. I think it’s going to be as simple as adding these to the list of options.

1 Like

I created a comprehensive PR today that also fixes these requirements. Just look up your issue and see the related PR.

1 Like