OH4: Blockly with UoM Logic Comparison

Hi All

I am battling with UoM with Blockly again… I have a rule (based on a previousl working rule) as follows:

image

var Battery_Power, Battery_SOC;


//log:set DEBUG org.openhab.automation.script.ui.ZZ_Test_UOM
Battery_Power = items.getItem('SunSynk_Battery_Power').state;
Battery_SOC = items.getItem('SunSynk_Battery_SOC').state;
console.debug(('Battery Power is: ' + String(Battery_Power)));
console.debug(('Battery SOC is: ' + String(Battery_SOC)));
if (Battery_Power.quantityState.equal(Quantity('10 W'))) {
  console.debug(('QTY Battery Power is: ' + String(Quantity('10 W'))));
}

The two items are defined as:

SunSynk_Battery_Power - Number:Power with State Description of "%.0f W"
SunSynk_Battery_SOC - Number:Dimensionless with Unit Metadata of "%" an State Description of %.0f %%

When I run the “test” rule I get the following in log:

16:12:37.080 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery Power is: 325 W
16:12:37.081 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery SOC is: 99 %
16:12:37.081 [ERROR] [ab.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: undefined has no such function "equal"
        at <js>.:program(<eval>:9) ~[?:?]

So trying to work with UoM seems to not be working.

My working similar rule is as follows:

I cannot understand what I am doing wrong this time?

Any assistance would be appreciated
Mark

“get state of item” returns a String representation of the Item state. You need the Quantity version of the state.

In the menu that block reads “get [name] of item”.

Thanks Rich, tried as follows:

var Battery_Power, Battery_SOC;


//log:set DEBUG org.openhab.automation.script.ui.ZZ_Test_UOM
Battery_Power = items.getItem('SunSynk_Battery_Power').quantityState;
Battery_SOC = items.getItem('SunSynk_Battery_SOC').quantityState;
console.debug(('Battery Power is: ' + String(Battery_Power)));
console.debug(('Battery SOC is: ' + String(Battery_SOC)));
if (Battery_Power.quantityState.equal(Quantity('10 W'))) {
  console.debug(('QTY Battery Power is: ' + String(Quantity('10 W'))));
}

But I get the same error:

16:40:07.686 [INFO ] [openhab.event.RuleUpdatedEvent       ] - Rule 'ZZ_Test_UOM' has been updated.
16:40:08.688 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery Power is: 886 W
16:40:08.688 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery SOC is: 96 %
16:40:08.689 [ERROR] [ab.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: undefined has no such function "equal"
        at <js>.:program(<eval>:9) ~[?:?]
        at org.graalvm.polyglot.Context.eval(Context.java:399) ~[?:?]

The added wrinkle is that in my actual Rule I will be using the:

image

I could not get this to work in my “production” rule, so created a simplified rule to fault find.

Also, furthetr info - I am running on:

openHAB 4.0.0

Build #3528

EDIT:

So this works for the _Power, but not for the _SOC:

var Battery_Power, Battery_SOC;


//log:set DEBUG org.openhab.automation.script.ui.ZZ_Test_UOM
Battery_Power = items.getItem('SunSynk_Battery_Power').quantityState;
Battery_SOC = items.getItem('SunSynk_Battery_SOC').quantityState;
console.debug(('Battery Power is: ' + String(Battery_Power)));
console.debug(('Battery SOC is: ' + String(Battery_SOC)));
if (Battery_Power >= Quantity('1000 W')) {
  console.debug(('QTY Battery Power is: ' + String(Battery_Power)));
}
if (Battery_SOC <= Quantity('100 %')) {
  console.debug(('QTY Battery SOC is: ' + String(Battery_SOC)));
}
16:57:10.107 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'SunSynk_Inverter_Load_Power' changed from 1036 W to 1027 W
16:57:11.001 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery Power is: 1040 W
16:57:11.006 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery SOC is: 93 %
16:57:11.007 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - QTY Battery Power is: 1040 W

The SOC if doesn’t pass - even though it should

That gets tricky as the event data are the raw Java Objects, not the JS Scripting helper library equivalents. But you should be able to easily convert it by dropping that contextual info block to create the new quantity same as you do for “10 W”.

Note, that the Qyt Battery_Power is redundant. Battery_Power is already a Quantity. And that’s probably the problem. Because Battery_Power isn’t an Item, it has no quantityState method and apparently it’s trying to interpret Battery_Power as if it were an Item.

That does look like you can just drop a get item into a Qty block though or perhaps even into the Qty comparison block though without explicitly pulling the quantityState from the Item.

What does the event look like for this Item? I’ve seen cases where one has used a Numer:Dimensionless without defining the unit metadata come across as a number between 0 and 1. Maybe something weird like that is happening. Log out Qty "100 %1 too. Maybe that’s being set to 1?

image

Battery_Power = event.itemState.quantityState;

Produces the following in the logs:

08:24:27.176 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery Power is: undefined

and
image

Battery_Power = event.itemState;

Produces:

08:26:05.443 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - Battery Power is: 8 W

I have been able to FORCE the Battery_Power logic by stripping off the UoM, but based on previous advise would prefer to keep them as much as possible.

Not sure what you mean here?

image

Produces:

08:33:52.249 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - QTY 100% is: 100 %

That’s probably a bug. It shouldn’t be trying to call quantityState on the event.itemState. File an issue on the openhab-webuis repo for that.

In the mean time you can use the “create text with” block to convert the event.itemState to a String which you can pass to a Qty block.

events.log entries for this Item.

Just a side question (I’m more a newbie to Blockly etc.):
Why are you trying to use the quantity functions? Sounds complicated to me (but maybe I just don’t get the benefit). I use the comparison like this. The Plugwise_Circle01_Power item is of type Number:Power, but I just use the number representation:

Seems to work perfectly fine.

If the Items carry units you either need to strip the units off or you need to use the Qty blocks to do comparisons and math.

I couldn’t say what those blocks are doing without seeing the underlying code. Also, if you are on OH 3 whether or not and what units the item actually carries can be ambiguous.

I didn’t know that and never used them like this. I thought this was a kind of visual representation of the item and the object behind would just contain an integer. I always do directly math with any item, no matter which type it is (as long as it’s a number). From what I understand from the units description of OpenHAB, I think this is the case. It’s just a property of that number, but the number does not change. It tells OpenHAB to interpret this number in a certain way, but it’s still just digits.

This is the code behind it (Plugwise_Circle01_Power is of Type Number:Power and was created via GUI, I have no items file):

var current_power;


current_power = itemRegistry.getItem('Plugwise_Circle01_Power').getState();
if (current_power < 4) {
  events.sendCommand('WaschmaschineStatus', '0');
} else if (current_power > 4) {
  events.sendCommand('WaschmaschineStatus', '2');
}

Melvin, I recommend looking into the docs that I have wrote here: Blockly UOM. It also contains a cross-reference to the section that explains the concept behind units of measurement which is a major improvement of openHAB 4.

1 Like

Mark,

regarding your

image

Battery_Power = event.itemState.quantityState;

can you check which openHAB version you are on (I am on the latest snapshot) and try the following that I did to reproduce your problem (which I can’t):

which in my case produces the following code:

var ItemPower;

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

and produces the following output:


2023-07-23 11:19:17.226 [INFO ] [ript.ui.1_test_quantity_eventcontext] - 20.75 W
2023-07-23 11:19:17.230 [INFO ] [ript.ui.1_test_quantity_eventcontext] - 20.75 W
2023-07-23 11:19:17.235 [INFO ] [ript.ui.1_test_quantity_eventcontext] - 30.75 W
2023-07-23 11:19:17.241 [INFO ] [ript.ui.1_test_quantity_eventcontext] - 30.75 W

Hence, it is working well on my side. It seems one of my latest PR has fixed this:

I had a look (I already knew the units of measurement documentation) at the new Blockly functions. Though, to be honest, I don’t see much use in this. What I would expect is the following (speaking in pictures, not in ectual code):

A Number:Power item is an object containing a value field (e.g. 100.0) and a type property (‘Watt’). If you use it for calculations, you can just use the object’s value as it is (an integer/float). If you want to know how to present this to a user, you can use the type property and see that it is of type Watt and present it accordingly.

Using it as a combination and introducing the quantity method doesn’t make any sense to me except making everything much more complicated as it should be. Who would ever write an if-clause checking if a value is smaller than “10 W” instead of just checking if that value is smaller than “10”?? In either case, you know that you are talking about Watts.

Maybe I didn’t get the sense correctly, but in my opinion, I would remove this feature as fast as possible :slight_smile: This will cause so much confusion and makes things so much more complicated… And it doesn’t create any additional value…

Hi Stefan

I am on :

openHAB 4.0.0

Build #3528

As far as I know this is a later build that your fixes, which I recall.

I am happy to upgrade the RC1 release in the next day or two to check if that makes any difference to my case?

Do you think this has something to do with using a Variable? I need to do that to make sure I do not get the two item states in a transient state that messes up the result.

Thanks
Mark

EDIT:

Even without Variable I get:

image

console.debug(('***************UoM Battery Power is: ' + String(event.itemState.quantityState)));
13:38:12.472 [DEBUG] [nhab.automation.script.ui.ZZ_Test_UOM] - ***************UoM Battery Power is: undefined

I see:

2023-07-23 13:40:13.160 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'SunSynk_Battery_Power' changed from 0 W to 1 W

Will open a bug request shortly.
Thanks

Ok, maybe that sounded a little more harsh then it should :grinning: I can see some value in having items handled semantically correct, but still adding the quantities to every calculation doesn’t sounds like a good idea to me.

Using it as a combination and introducing the quantity method doesn’t make any sense to me except making everything much more complicated as it should be.

The reason is because a state should exactly not be a number only but a number with a unit. This is what the core team has put a lot of work into it in the last months. Lots of temperature items will give you a temperature directly with °C. With the support of quantities this lets you easily compare it without removing the unit before - note that this is part of the state not only the label that is shown (even though you can configure the state to be unitless and add the unit via the description pattern). Btw, you can even use units by multiplying them for example and V*W would become W then.

Ok, maybe that sounded a little more harsh then it should

Yes, it did :wink: :+1:

If you don’t like units, feel free to configure the state just to be a number and you are fine and you don’t need quantities but that is probably one’s taste… I do appreciate this a lot as an improvement and will change everything in my setup to become really unit-attached eventually.

Yes, the fix should exactly address that. I am about to install the RC version soon on my side and I will double check your block but it does look the similar to what I did. Do you mind creating exactly what I did in my example and see what the code is, so we can compare it?

Hi Stefan

Please see below: (Cahnged INFO to WARN)

var ItemPower;

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

And I get in the logs:

15:24:44.858 [INFO ] [openhab.event.ItemStateChangedEvent  ] - Item 'SunSynk_Battery_Power' changed from 0 W to 1 W
15:24:44.859 [WARN ] [ab.automation.script.ui.ZZ_StefanTest] - 1 W
15:24:44.859 [WARN ] [ab.automation.script.ui.ZZ_StefanTest] - undefined
15:24:44.860 [ERROR] [ab.automation.script.javascript.stack] - Failed to execute script:
org.graalvm.polyglot.PolyglotException: TypeError: undefined has no such function "add"
        at <js>.:program(<eval>:6) ~[?:?]
        at org.graalvm.polyglot.Context.eval(Context.java:399) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:458) ~[?:?]
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:426) ~[?:?]
        at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:262) ~[java.scripting:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocableAndAutocloseable.eval(DelegatingScriptEngineWithInvocableAndAutocloseable.java:53) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.eval(InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.java:78) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.DelegatingScriptEngineWithInvocableAndAutocloseable.eval(DelegatingScriptEngineWithInvocableAndAutocloseable.java:53) ~[?:?]
        at org.openhab.automation.jsscripting.internal.scriptengine.InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.eval(InvocationInterceptingScriptEngineWithInvocableAndAutoCloseable.java:78) ~[?:?]
        at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.lambda$0(ScriptActionHandler.java:71) ~[?:?]
        at java.util.Optional.ifPresent(Optional.java:178) ~[?:?]
        at org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler.execute(ScriptActionHandler.java:68) ~[?:?]
        at org.openhab.core.automation.internal.RuleEngineImpl.executeActions(RuleEngineImpl.java:1175) ~[?:?]
        at org.openhab.core.automation.internal.RuleEngineImpl.runRule(RuleEngineImpl.java:984) ~[?:?]
        at org.openhab.core.automation.internal.TriggerHandlerCallbackImpl$TriggerData.run(TriggerHandlerCallbackImpl.java:87) ~[?:?]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[?:?]
        at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
        at java.lang.Thread.run(Thread.java:833) ~[?:?]
15:24:44.862 [ERROR] [.internal.handler.ScriptActionHandler] - Script execution of rule with UID 'ZZ_StefanTest' failed: org.graalvm.polyglot.PolyglotException: TypeError: undefined has no such function "add"

That’s precisely what I don’t like and where I don’t see any additional value. Any sensor value should ONLY be a value, and the type should be a property. Then it’s much easier to do calculations, and you can still use units at any place you like because they are attached to the values. Separation of value and type. In my view, the basis of object-oriented programming. Never mix digits and characters in the same variable.

But maybe we are talking about the same thing, the quantity is maybe what I mean by “just value”. It’s just more complicated way of expressing it :slight_smile:

That’s weird, it generates a different code than on my side. What is the version you are running?

In the UI → Help & About