OH4: Blockly with UoM Logic Comparison

Hi Stefan. Thanks, I did reply above with version.

Units of Measurement have been around for a long line (ON 2.0 or 2.1 IIRC). Units are not going anywhere and they have lots of uses inside and outside of rules. They are not mere decoration and they are not going anywhere. And since they are not going anywhere, Blockly should support them.

The great thing though is if you don’t want to use them, you don’t have to. Make all your
Items be just Number Items (it no longer matters what the Channel says it wants) and you never have to mess with units. Or if you keep your Items using units, use the “get numeric state of Item” block to get the numeric value without units. (Note: the state of the Item is a String so you’ll have to use that or “get quantity state of Item” to do math anyway.)

This isn’t new and changes made in OH 4 make it much less complicated and confusing.

I was actually concerned about the percent as that’s the Item/comparison that isn’t working, right?

Luckily you don’t have to use them if you see no value.

The units matter. What if I have one that only reports °C and another that only reports °F and I need to compare them? By using units it all just works (there are several different approaches). Without it’s my responsibility to

  1. know what units they have which is information kept outside the rule
  2. do the math to convert them to be compatible units before making the comparison

When you work with units, the units are taken into consideration. For a recent example I had someone who was wanting to convert Amperes to Watts (Volts was a known constant). The units library was smart enough to know that when you multiply amps with volts you get Watts and applied W as the unit as a result of the calculation automatically.

What if I decide to change my units from W to kW on an Item. Without using units I have to change all my rules.

But I think you will find that when you look at the code for QuantityType, this is exactly what has been done. It’s a class that has a separate value and unit data members.

It is often amazing to me how little faith people have in the intelligence, technical skills and capabilities of the developers and maintainers who contribute to openHAB. Do you really think they decided to implement it in this way if there were not logical, architectural, and technical reasons to do it in a more simple way?

As just one example, JavaScript does not support operator overloading. It is impossible to do 5 A * 120 V = 600 W. You cannot overload * to do anything except multiply JavaScript Numbers. So if you want to support doing math that actually takes the units into account, you have to use something else (functions in this case).

Blockly converts to JavaScript. So we have two choices:

  1. just don’t support QuantityTypes at all
  2. provide tools so that those users who want to use QuantityTypes can do so and tools for those who do not don’t have to.

To me, 2. sounds a whole lot better to me than 1 and I’m grateful that’s the direction that was followed because I personally find a ton of value working within units in my rules. I never throw away the units. But of course because of limitations in JavaScript, we can’t make using QuantityTypes in rules work the same working with plain old numbers so should we tell users who want to do so to go pound sand?

2 Likes

Sorry Rich. I am having issues with BOTH, so difficult to keep straight which one is being addressed. The Percentage type update looks like:

2023-07-23 18:35:11.018 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'SunSynk_Battery_SOC' changed from 91 % to 90 %

I have worked around to get the basic rule working with stipped off UoM. I have creted a 2nd item linked to the channel as a Number Item.

Once question that I have regarding a PERCENTAGE ite, with UoM. What is the correct and best way to define the Item:

  • Number with Unit Meta Data of % and State Description Meta Data of %.0f %%?
  • Number: Dimensionless with Unit Meta Data of % and State Description Meta Data of %.0f %%?

Need to investigate if the problem is the Percentage Item with Number:Dimensionless

I’m not sure that is necessary. Instead of using get quantity state of item you can use get numeric state of item which will be just a plain old number without units. Then you can compare it to 100 instead of Qty "100 %". You don’t need a whole new Item for this unless there is something else going on.

Note, I’m not sure what happens if you pull the quantity state from a Number Item. I think you’ll get null so you’ll definitely need to use “get numeric state” for that Item without units.

Never use unit metadata with a Number Item, only Number:X Items. At best it’ll be ignored but this is a pretty new feature so I can’t guarantee that. So if you want to go down this path, to avoid uncovering some other bug related to using unit with a non-unit bearing Item type avoid that.

Just need to make sure I follow 100%.

I have a ModBus value coming in, which is a percentage, there is no Number:Percentage available - should this be an option (I am sure there are many examples where a percentage is required)?

So in order to create an Item with the correct format for percentage I should use Number:Dimensionless and add Unit Metadata of %? -->this is what I have done, so that would take that out of the equation.

You need to separate in your mind these three things:

  1. the type of the Item
  2. the units of the state
  3. how the state of the Item is displayed

You have two choices for 1, Number or Number:Dimensionless (there is no such thing as Number:Percentage). If you choose Number as the Item type you are saying “I don’t want to use units. Period.” If you choose Number:Dimensionless you are saying “I want to use one of the Dimensionless units.” There are several Dimensionless units to choose from as Dimensionless is the unity type for all ratios (e.g. decibel, percent, etc.). When you choose Number, you don’t use the Qty blocks in your rules ever because your Item doesn’t have units.

If you chose just Number skip to 3. If you’ve chosen Number:Dimensionless you need to tell it which Dimensionless unit to use. If you don’t define the unit metadata, it will determine the unit from what the Channel uses in it’s updates and if there isn’t one there it will use the system default which is ONE for Dimensionless. By setting the unit to % you are saying, “no matter what, this Item will carry a percentage”.

The Item label and State Description metadata only impacts how the Item is shown on the UIs. It has nothing to do with how the Item’s state is used in rules or anywhere else (any more).

Forget about the formatting on the UI. You can worry about that once you get your rule working.

tl;dr: If you use Number as the Item type, there are no units and therefore it’s just a “numeric state” in your rules. If you use Number:Dimensionless you need to define the unit metadata to explicitly to set what units the Item carries and you need to use the “quantity state” in your rules if you want to consider the units in your rule.

1 Like

Thank you. I think that confirms that I was on the correct track as far as the percentage item goes. I will leave my item definition as is.

Stefan seems to have picked up an issue with the way my Blockly rules are generated. I will update to 4.0.0.RC1 and try again and see if anything changes.

Failing that I guess I will log a Bug Request to see why my rules are generated incorrectly?

Let’s wait until I have migrated my prod System to RC1 and doubled check there. Only then open an issue.

Maybe first, I have to apologize again for my tone. (And for somehow also high jacking this thread) I never meant to discredit anyone. I’m thankful for all developers making this great piece of software available. I was reading this topic on my mobile phone and maybe didn’t get any information correctly at first. I now took the time to go through it again.

I fully agree here. I never wanted to say something like that. English is not my native language and in such difficult cases, I might also have chosen the wrong words.

After going through this again, I can now tell you more clearly what kind of “shocked” me that much, that I wrote the posts above. In the end, it was only a single line of the Blockly code. This one:
grafik
Because this looks like the quantity of the item “ItemPower” is added with a STRING (the blockly block shows the two quotes) containing “10” and “W”. This was against all I ever learned as a computer scientist (which I am, but not working as a programmer any more). What happens if I write “10 w”, “10w”, “10 watts”, “10 watt” into this field? That’s looks very ambigous to me.
If the line had looked like this:
grafik
I never would have had any doubts about using quantities. Because in this case, the value and the unit are exactly defined and not an arbitrary string.

In the end, that’s all :slight_smile: I don’t know how the original field is handled, maybe it works like this already.

So again, apologies for starting this side-discussion.

Have a nice evening,
Melvin

That’s just one of the options. There is also a block to build the Qty with the number and the units as separate arguments.

The Qty block activates a builder. Its whole job is to parse what ever it’s passed into a Quantity Object.

image

You can use a String representation of the the number, a Java Number, and openHAB DecimalType, or a JavaScript Number for the first argument.

Sometimes it’s more convenient to provide it all as one String, sometimes as separate arguments

The units that are supported are documented at Units Of Measurement | openHAB and specific features unique to JS Scripting are documented at JavaScript Scripting - Automation | openHAB. Because Blockly converts to JS Sripting in OH 4 both links are relevant.

As long as the units are valid (I think the Ws need to be capitalized) all of those should work, following the old computer science Robustness principal. Be conservative in what you produce (internal to OH the value will always be 10 W) and be liberal in what you accept.

Unfortunately there is no way for Blockly to know all the Units to generate a list to choose from. It gets even more complicated when you apply quantity qualifiers. For example, MW (megawatt) and kW (kilowatt) are also valid units. That list of units will become huge to list them all. And we still probably wouldn’t get it right as some units can be combined on the fly. For example Bq/m³ uses four different modifiers. The Becquerel unit for radioactivity. The / to indicate “per”. m to represent Meters and the 3 to indicate volume. But these are all combined to represent the radioactivity density reading (it’s a radon sensor).

From an end user perspective, accepting the units as a String is probably the best we can offer short of creating a whole new UI “unit builder” which would be cool but I wonder if effort were not better spent elsewhere.

As for being off topic, I don’t think it is drastically so. Confusion about what UoM and Quantity is I think is relevant to this discussion.

1 Like

I have upgraded to 4.0.0 RELEASE and now my generated rule looks like:

var ItemPower;


console.warn(event.itemState);
console.warn(Quantity(event.itemState));
console.warn((Quantity(event.itemState).add(Quantity('10 W'))));
ItemPower = Quantity(event.itemState);
console.warn((Quantity(ItemPower).add(Quantity('10 W'))));

Logs:

11:02:21.464 [WARN ] [ab.automation.script.ui.ZZ_StefanTest] - 4 W
11:02:21.465 [WARN ] [ab.automation.script.ui.ZZ_StefanTest] - 4 W
11:02:21.468 [WARN ] [ab.automation.script.ui.ZZ_StefanTest] - 14 W
11:02:21.469 [WARN ] [ab.automation.script.ui.ZZ_StefanTest] - 14 W

The percentage rule also work now.

Thanks Rich and Stefan for the help.

2 Likes

Can i convert this without QT to a normal number with blockly?

Convert what to a normal number?

Ultimately you should either use Quantities or not. If you don’t want to use units make your Items be just Number Items and there will be no units. If you want units, you should keep the units where possible and work with the units. This will give you more flexibility and more robust code.

There are only a few cases where you should move outside of Quantities if you have them to begin with:

  • you want to do an operation that results in something that cannot be represented by the current set of units
  • you want to use something from Math (e.g. round, though round has been added to QT recently but after 4.0.1 was released) that simply cannot be done with a Quantity.

Thanks for this hint. But at the moment my openhab isn’t working with many scripts, 'cause before update to 4.0 UoM Items where not really easy to handle. Now my trick isn’t working and i must rebuild the code. At the moment Openhab 4.0.1 runs with many issues very bad and i try at first to fix scripts easy as possible. And that helped me at the moment:

To get the numeric state of item.

Why are you working with the normal comparison block instead the the blockly Quantity Comparison when comparing the Leistung (Power) here?

How does it work with 3.4? The same?

Blockly doesn’t support UOM in 3.4 - this was a major improvement for 4.0. I thought you were on 4.0.1 already?

Yes exactly and openhab isn’t running well after 4.0 upgrade. It’s all bad i must fix all my script and then if i have more time i can improve it. But at this point, it doesn’t help me to recreate a complete rule! So step by step! I sit here since 7h with a system that crash every time with many errors and I do my best. But optimizing is very low in my agenda.

If you are on OH 4.0.1 I see nothing wrong with the blockly code you’ve posted here. Whether OfficeScreensLeistung has a unit or not, screenPower will be just the number without units.

I think our point is this isn’t about optimizing the code. It’s about reducing the amount of work you need to do. Once again, if you don’t care about the units, get rid of the units by changing the types of your Items to just be Numbers. If you do care about units, it’s no more work to modify your rules to use the units than it is to modify your rules to strip off the units. In fact, it’s more work for you to strip off the units in many cases and exactly double the work if you want to go back and add in the use of units later.

All you’d need to change to the blocks you show above is “get quantity state of itme” and use the Quantity Comparison block in your if statements. Same amount of work, just a different selection of blocks.

Yes I know it. I post a possible solution. That’s all.