Blockly ON / OFF equality behaving differently in OH4

One of my Blockly rules was not triggering after migrating to OH4 (was working fine in OH3.4.4).
The rule is triggered by a change in state to a virtual presence switch item, using the “contextual info” Block “new state of item”. The logic was IF / ELSE IF. I added an ELSE to log “Neither ON nor OFF” to the log if it didn’t match either, which is what happened.

Based on the troubleshooting of this issue Blocky In Text Block rejects contextual info Triggering item name in 4.0; worked in 3.4.4, I tried added a create text block, which fixes the problem.

I have always thought it curious that Blockly doesn’t provide an option (at least one I could find) to use ON and OFF states rather than “ON” and “OFF” strings. In DSL Rules, ON was not the same as “ON”. But using “ON” worked in Blocklies in OH 3.4, so I didn’t worry about it too much. Unless I’m missing something, I’m going to have to spend a lot of time going through my rules to fix this elsewhere.

Here are the Blocklies, where I have added the create text to the ON comparison but not the OFF so the code would show both:

Here is the code (which includes some logging I added that isn’t in the image)


if (String(event.itemState) == 'ON') {
4
  items.getItem('Presence_George').sendCommand('ON');
5
  items.getItem('Recent_Short_Term_Presence_George').sendCommand('ON');
6
  items.getItem('Recent_Short_Term_Presence_George_Timer').sendCommand('ON');
7
  items.getItem('George_Recently_Present_But_Now_Absent').sendCommand('OFF');
8
  items.getItem('OfficeDimmerSwitch_OnOff').sendCommand('ON');
9
  if (cache.private.exists('GeorgeArrivalTimer') === false || cache.private.get('GeorgeArrivalTimer').hasTerminated()) {
10
    cache.private.put('GeorgeArrivalTimer', actions.ScriptExecution.createTimer('GeorgeArrivalTimer', time.ZonedDateTime.now().plusMinutes(5), function () {
11
      if (items.getItem('ZoozSensorOffice_Alarmmotion').state == 'OFF' && items.getItem('iRobotRoombai7_State').state != 'ON') {
12
        items.getItem('OfficeDimmerSwitch_OnOff').sendCommand('OFF');
13
      } else {
14
        console.warn((['Office LIghts not turned off on arrival due to Motion or Vacuum state',items.getItem('ZoozSensorOffice_Alarmmotion').state,items.getItem('iRobotRoombai7_State').state].join('')));
15
      }
16
      cache.private.remove('GeorgeArrivalTimer');
17
    }));
18
  };
19
} else if (event.itemState == 'OFF') {
20
  items.getItem('Presence_George').sendCommand('OFF');
21
  items.getItem('OfficeFanTuya_switch_1').sendCommand('OFF');
22
  items.getItem('George_Recently_Present_But_Now_Absent').sendCommand('ON');
23
  if (items.getItem('iRobotRoombai7_State').state != 'ON' && items.getItem('ZoozSensorOffice_Alarmmotion').state != 'ON') {
24
    items.getItem('OfficeDimmerSwitch_OnOff').sendCommand('OFF');
25
  }
26
} else {
27
  console.info('Neither ON nor OFF');
28
}

(Looks like I got some line numbers above. I’m working from an iPad instead of my laptop and I’m less sure of how to get exactly what I want).

This seems similar to the previous issue that @stefan.hoehn and @rlkoshak helped resolve earlier. I created a new thread to avoid subject drift that can be confusing to others who stumble upon it while searching for solutions to similar problems. If that is not the preferred approach, please let me know. I have noticed some other Blockly behavior that is different (distance from block and a date time block that rejected the Now blocks, but worked fine when I re-added the Now blocks), and I’m happy to provide detailed information about my experience but want to do so in a manner that is helpful to those who volunteer their time to make all of this work so well for the rest of us.

I’ve answered this one a couple of times already. I opened an issue for it.

The “new item state”, “previous item state” and “received command” on the “context” block are not Strings. You need to convert these to a String before you can compare them to 'OFF'.

Sorry. I searched for it, but I guess I didn’t use terms that would help me find your previous answers.

For the record, this is the issue: [Blockly] Automatically convert `event.newItemState` et. al. to String · Issue #1991 · openhab/openhab-webui · GitHub

I haven’t had a chance to analyze it. Do you happen to know if this is a regression or has it always been that way?

Without having tried it myself, I’d think it is a regression. It could have worked in 3.x, because Nashorn did a type conversion to string when it was compared with string, but GraalJS is much more strict about types, so it wouldn’t do that conversion.

I’m generally not really happy that the event object differ in file-based and UI-based rules, however I haven’t found a automatic way to modify the event object in UI rules.
In 4.1, I want to improve that situation somehow.

In OH3 it worked without the need for the create text from block.

That wasn’t a ding against you. I’m probably going to create a tutorial post.

It’s just a slight bit of frustration that it’s become a much bigger issue than I expected.

Depends on what you mean. Has it always been that way for Blockly? No, in Nashorn there was some auto conversion between the states/commands and Strings so it worked. Yes, in GraalJS it has always been the case that for UI rules event is the raw Java Object, not something converted to a JS Object.

I raised an issue way back when the helper library was first getting developed and support for UI rules being added I think on the add-on repo or maybe it was the helper library repo IIRC. Or maybe it was a discussion on another issue. I can’t find it now.

IIRC the outcome was that the way that OH injects the event into UI script actions/conditions there wasn’t an opportunity for the add-on nor the helper library to capture that and convert it to a JS Object in a reasonable way. I was so happy to get other things like automatic injection of the library that I decided not to press my luck and push hard on this. I’ve simply lived with it. It’s not that big of a deal in text GraalJS actions/conditions. You just have to remember to call toSring().

But with Blockly the inconsistency really stands out and it’s only been a couple of days and it’s come up a lot.

Indeed, that was the case. Other cases of this are also happening like people with comparisons to string representations of numbers that worked because they were automatically converted which no longer work correctly because they are not in GraalJS. That one’s a bit more subtle I think because it will work some of the time.

This really would be most excellent if we can fix this for all users. However, failing that, even if we just fix it for Blockly users by having the block wrap the calls to event.X in String() or append .toString() for the state/command properties it would go a long way to helping those users.

It would be really really hackey but maybe in addition to injecting the require of the openhab library it could also inject the next line var event = utils.javaEventToJsEvent(event) (obviously such a function doesn’t exist yet) to convert the event to a JS Object (maybe add numeric and quantity equivalent values for the state and command properties to the Object as well).

It’s definitely not a satisfying approach but maybe that could work if all else fails?

Enjoy the fix with Support String/Number on eventcontext state/command by stefan-hoehn · Pull Request #1992 · openhab/openhab-webui · GitHub and I think in a pretty :sunglasses: and flexible way.

With a bit of luck we can deliver it with 4.0.1

What is the best way for us to share blocks that are behaving differently than they did in OH3?

For example, I use the GIS “distance from” block. In OH3, I could attach the “contextual info” block “new state of item”. In OH4, I saw that the “contextual info” block was rejected by the “distance from” block when I opened the rule to save it to convert it after converting. Adding a “create text from” block didn’t work in this case, as the “distance from” block would not accept it. I first solved this by extracting the lat and lon and using the GIS “position” block. I later found that if I assigned the “contextual info” block to a new variable, I could then directly attach that variable to the “distance from” block and it worked.

With the fix above the rejection should not happen anymore.

The place to inject this would be the already existing globals injection script, that takes care of console logging etc and is separate from the library injection.
The biggest problem is, that we first need to get the data used by the getTriggeredData function used for file-based rules. I have to check if that data is accessible, otherwise I need to find out how to make it accessible.

I do see that the changes on the Blockly side so have made it into 4.0.1 which is wonderful! @stefan.hoehn and @florian-h05, thank you for the quick fix!

1 Like

I upgraded to OH 4.0.1 and the new “contextual info” block eliminates the need for an additional “create text from block” as advertised. Thanks for the help.

The “distance from” GIS block still rejects the “contextual info” “new item state” block, even with “string” selected. In this case the item is a Location item, but I suppose Blockly has no way of know that. I have a work around, where I extract lat and lon and use them to populate the “position” GIS block. In OH3, this was not required as the “distance from” block accepted the “contextual info” block. I have a workaround and it is only a couple of lines of code and it may not be impacting as many users. But wanted to report back.

2 Likes