OH 4.0.1 JavaScript (ECMAScript-2021) always defines event object in an rule

Hi folks,

I just moved to OH 4.0.1 and I have a rule which is triggered by a timer and by item events.

Like documented here: JavaScript Scripting - Automation | openHAB in OH 3.4 I was able to differentiate, if the rule was triggered by an

  • item event → event was defined, or by a
  • timer → event was not defined.

In OH 4.0.1 event is always defined. It contains a string like “Timer 6 triggered”, when the rule isn’t triggered by an item but by a timer.

Is this a new feature which is not mentionend in the docs and in the breaking changes? I have to rewrite some of my rules, because I cannot rely on a not defined event object when I want to react to a timer trigger.

Cheers,
kuczerek

Yes. All rule triggers except manually have an event Object telling how the rule was triggered to differentiate between all trigger types, not just Item and Thing triggers.

I don’t know if this made it into the docs. I’m not entirely certain where in the docs it would go.

All you have to change is what you compare to. Instead of if(this.event === undefined) use if(event.type == 'TimerEvent') (I think, log out event.type to verify it’s called “TimerEvent”).

As previously implemented, you couldn’t tell the difference from a timer trigger, a system started trigger, manual trigger, time of day trigger, nor could you tell the difference between timer triggers (the 6 is the ID of the trigger which is shown in the UI under the code tab for UI rules).

OH 4.3.2

What would the event.type when a rule calls another rule?
It seems as if there is no event.type defined in such case…

See the following example:


error message:

ReferenceError: "event" is not defined

Full log:

2025-03-01 21:14:00.815 [INFO ] [ion.script.ui.test_blockly_something] - Rule fired ... (something...)
2025-03-01 21:14:00.815 [INFO ] [ion.script.ui.test_blockly_something] - ExecutionEvent
2025-03-01 21:14:00.816 [INFO ] [cript.ui.test_blockly_something_else] - Rule fired ... (something else...)
2025-03-01 21:14:00.817 [ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'test_blockly_something_else' failed: org.graalvm.polyglot.PolyglotException: ReferenceError: "event" is not defined
2025-03-01 21:14:00.817 [INFO ] [ion.script.ui.test_blockly_something] - Rule finished ... (something...)

Why is there no event defined?
Do you know?

Correct, there is no event Object at all when a rule is called from another rule.

Because the rule wasn’t triggered by an event. No event, no event Object. But you can test to see if the event exists.

I had expected this would return “false” when called from a rule. Surprisingly the same error message as in my previous post is returned.

Anyway, I successfully used THIS approach to be able to know when a rule has been triggered by another rule.

That’s a bug then. It should return false if the event is Object is not available. What’s the code generated? It should resolve to (event !== undefined) which will generate false if the event isn’t defined. It shouldn’t throw an error and in my experiements it works as expected.

There might be some strange edge case happening here to generate an error or the error is occuring elsewhere in your rule.

I don’t know how jsscripting does it, but it should be an ExecutionEvent, not null.

ExecutionEvent when run manually but for some time and I thought it was still the case that when one rule calls another there is no event. At least there isn’t one in a managed Script Action or Script Condition. The event is still there for file based JS rules.

Rules calling other rules are not caused by an event so it seems odd that there would be an event Object. For file based rules though, that’s the only way to get the arguments passed from the other rule unto the action.

But if a rule calling another rule does cause an event now, then there really is no use for the “contextual info event available” block and it should be removed. There will always be an event.

But that still does not explain why it’s throwing an error. It should just always return true.

I guess it’s a matter of perspective or opinion. Rules calling other rules can be considered an execution event. But perhaps it was meant only for when UI rule is executing another script through its rule action?

In any case in JRuby, calling rule["uid"].run, by default will insert an ExecutionEvent (in openhab 4+).

The context is a separate thing outside the event, and it is still needed because ExecutionEvent itself doesn’t carry any context.

This depends on the implementation in the jsscripting library perhaps?

In plain JS, simply calling console.log(test) will generate an exception because test is undefined.

You can only test for undefined when referring to an object’s member.

i.e.:

test => raises an exception (ReferenceError)
var x = 0
x.test => doesn’t raise an exception, instead, it would return undefined

The test for event in this case needs to use typeof i.e. if (typeof(event) === undefined). Due to how js does things, this isn’t entirely accurate because one can define var event = undefined but it’s a good enough check.

That’s what is different in JS. For file based rules the action is isolated so all it gets is what’s passed into it. Since JS wraps the event Object anyway to convert it to JS, I added a PR awhile back to include the context as part of that.

For managed rules, the context just gets injected directly and the event Object remains the Java Event and is not wrapped and converted to JS. I very much dislike this difference but it’s technically challenging to overcome so it remains.

Correct. And the “contextual info event available” block turns into (event !== undefined). So no error should be thrown. It doesn’t try to access anything, just see if it exists. That shouldn’t throw an error under any circumstances, just return true or false.

It throws an error when the rule is called from a rule - see below:

Rule 1:

console.info('Rule fired ... (something...)');
console.info((event !== undefined));
console.info(event.type);
rules.runRule('test_blockly_something_else', {});
console.info('Rule finished ... (something...)');

… runs Rule 2:

console.info('Rule fired ... (something else...)');
console.info((event !== undefined));
console.info('Rule finished ... (something else...)');

Log:

2025-03-07 22:29:13.066 [INFO ] [ion.script.ui.test_blockly_something] - Rule fired ... (something...)
2025-03-07 22:29:13.067 [INFO ] [ion.script.ui.test_blockly_something] - true
2025-03-07 22:29:13.068 [INFO ] [ion.script.ui.test_blockly_something] - ExecutionEvent
2025-03-07 22:29:13.069 [INFO ] [cript.ui.test_blockly_something_else] - Rule fired ... (something else...)
2025-03-07 22:29:13.071 [ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'test_blockly_something_else' failed: org.graalvm.polyglot.PolyglotException: ReferenceError: "event" is not defined
2025-03-07 22:29:13.071 [INFO ] [ion.script.ui.test_blockly_something] - Rule finished ... (something...)

Well of course it’s going to throw an error on that line.

event doesn’t exist, so event.type isn’t going to exist. The whole reason to test if it exists is to not try to use it later because that will throw an error.

That’s because you don’t try to use it after discovering it doesn’t exist like in the first rule.

If exists returns false, you can not do anything with event. If you try it will throw an error.

As far as I can see it, there is no error on that line.

Rule 1 is the one that I triggered manually via MainUI.
event availabletrue
event typeExecutionEvent

2025-03-07 22:29:13.067 [INFO ] [ion.script.ui.test_blockly_something] - true
2025-03-07 22:29:13.068 [INFO ] [ion.script.ui.test_blockly_something] - ExecutionEvent

Rule 2 is triggered by Rule 1 and throws the error…
event availableerror instead of false (as I would expect)

2025-03-07 22:29:13.071 [ERROR] [.handler.AbstractScriptModuleHandler] - Script execution of rule with UID 'test_blockly_something_else' failed: org.graalvm.polyglot.PolyglotException: ReferenceError: "event" is not defined

I had it backwards then.

It should not throw an error. There is nothing wrong with that code as far as I can tell. event is undefined when it “is not defined”. Maybe the extra pair of parens is causing problems? I can’t imagine why that would be the case.

It’s definitely something strange. All I can offer is to file an issue on Blockly (openhab-webui repo).

This would be very helpful.
Thank you.

Since I cannot reproduce the error, you would be a better person to file the issue.