Blockly issue with contextual info triggering item name

Hello,

I’m running in an error when I use contextual info triggering item name in blockly.
What I’m trying to achieve is to kick off a scene of switching on and off a light a few times in a row that is connected to a Shelly1. The shelly has two channels, one for the power ON/OFF and one for the physical input switch ON/OFF. The scene is supposed to run on a timer, that I would like to cancel when the physical switch is pressed.

my rule in openhab 3.4 currently looks likes this:
image

and has two input triggers:

if I physically press the switch the rule runs as expected, as the log reports the timer cancellation.

however, when the rule is triggered by the cron condition, I have an error in the log:

2023-01-10 18:39:01.641 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'b0b32091e6' failed: ReferenceError: "event" is not defined in <eval> at line number 16

I expect that the problem is caused by the fact the the cron trigger is not seen as item. Is there a way to get around this problem?

thx

You may need to use a script block to see if this.event == undefined to tell the difference between the two triggers. There is no contextual info at all when the rule is run any way other than an Item event.

It might be easier to split this into two rules. As written, it doesn’t matter what Stoplicht_Input changes to. If it changes to anything it’s interpreted to mean that the scene should be cancelled.

  1. Create a new Item to cancel the scene.
  2. Create a Rule that all it does is send an OFF command to that new Item when Stoplicht_Input changes. You don’t even need Blockly.
  3. Create another rule triggered at 19:00. This rule will send an ON command to the new Item.
  4. Modify your existing rule to be triggered when the Item created in 1 receives a command. Inside the rule you just need to test the received command contextual info. If it’s OFF you know it was triggered by a change in Stoplicht_Input. It it’s ON you know it was triggered based on time.

This way, the contextual info will always exist in your rule because the only way it triggers is via an Item event.

thx. I failed to spot this easy approach!

not sure how to interact with the script block. I assume I need something like:

if (this.event == undefined)

but I don’t understand how it would fit into my blockly rule?

The script block is a way for you to arbitrarily add code not covered by the existing Blocks. It has to be ECMAScript 5.1 (i.e. an old version of JavaScript). Looking at the code tab of the Action shows you how the Blocks convert to that code.

The blocks would look something like

which generates

if(this.event !== undefined) {
events.sendCommand('TestSwitch', 'ON');
} else {
events.sendCommand('TestSwitch', 'OFF');
}

Notice how you have to reproduce all the parts of the if/else statement using script blocks because you can’t use the if/else blocks.

As you said Blockly currently just generates

event.itemName

for that block.

As in 4.0 I am trying to make Blockly more forgiving would it make sense and make it more forgiving and generate the following code

((this.event) ? event.itemName : ‘undefined’)

which would allow to test if “event.itemName” exists (indirectly)?

There’s a PR open (I think it’s still open) to add event.type for all the ways a rule can be triggered. When/if that gets merged, there will always be an event and you can tell how it was triggered based on event.type, eliminating the need to test for undefined.

So I wouldn’t change too much to handle this specific use case.

However, I don’t know if there are other cases where trying to test for undefined might be important. Sometime soon (I hope) event will always exist so that change won’t be necessary.

1 Like

as a non-programmer it took me a while to recognize a small mistake in the script. @rlkoshak you obviously intended to state:

if(this.event == undefined) {

because we are testing for an event that is equal to undefined, not unequal. But anyway, thanks for providing this solution. This is much more efficient compared to the quick fix.

@stefan.hoehn maybe this usecase and the solution approach provided by @rlkoshak qualifies for the documentation on “inline scripts”. A lot of the documentation is quite good, but this particular paragraph can use a less advanced entrypoint :wink: I read elsewhere that some feel blockly is the bridge to coding; I would argue that the Inline Script Block comes close to having that purpose on its own!

That was actually deliberate to match your original code. In your original code your “if true” is testing if triggering item name == Stoplicht_Input.

Testing for whether this.event is not undefined is the same test. this.event will only be “defined” in the case where the rule is triggered by an Item. This rule can only be triggered by Item Stoplicht_Input. Therefore, if this.event is not undefined means the same thing as if triggering item name == Stoplicht_Input because the only way this.event !== undefined evaluates to true is when triggering item name == Stoplicht_Input.

What documentation would you propose here? Just go ahead and bring up some ideas and I’ll may put something there.

These things happen when you are providing solutions to wannabe programmers…

I think you can even avoid the inline code and stay within blockly by using the get_context_attribute block and check against “undefined” like this: