Missbehaviour if blockly rules triggering one blockly master script?

I have a strange behaviour when I call one blockly master script with different (blocky) rules.

My rules are based on the so-called “room mode”, which should trigger different scenarios depending on the room mode (automatic, manual, alarm, …).

For this I have created rules for the individual rooms, these rules then pass attributes to the same Maststerscript and should trigger the actions with timer there.

Rules:


are triggering this Master-Script:

Timer detail:

Unfortunately, something strange happens… Timers with individual names per room that are supposed to affect the triggering individual rooms seem to trigger actions in the other rooms.

My questions:

Is this a intentional behaviour?

Does it have something to do with the fact that Blockly creates unique IDs like

<variable id="Ln_=7P!L{7fYF/6]j`D%">to_pushover < /variable>

for all attributes in the background code and these are then overwritten again and again by the triggering rules?

Am I not allowed to trigger one script with running timers from different rules - does the timer refer to the clear name (in my case the room name) or the unique id?

Maybe it is an easy one to answer for @rlkoshak or @stefan.hoehn

…fun fact: I also know how to solve the problem… either multiple scripts or multiple individual rules that contain the script. But originally I wanted to avoid this and only update one script if I do have changes.

Sorry for answering late…

I can’t reproduce the problem with the following simplified idea:

var room;


room = 'Arbeitszimmer';
if (cache.private.exists(room) === false || cache.private.get(room).hasTerminated()) {
  cache.private.put(room, actions.ScriptExecution.createTimer(room, time.ZonedDateTime.now().plusSeconds(2), function () {
    console.info('Arbeitszimmer');
    }));
};
room = 'Wohnzimmer';
if (cache.private.exists(room) === false || cache.private.get(room).hasTerminated()) {
  cache.private.put(room, actions.ScriptExecution.createTimer(room, time.ZonedDateTime.now().plusSeconds(3), function () {
    console.info('Wohnzimmer');
    }));
};

results into the expected

2023-12-02 18:00:25.709 [INFO ] [enhab.automation.script.ui.timer_var] - Arbeitszimmer
2023-12-02 18:00:27.082 [INFO ] [enhab.automation.script.ui.timer_var] - Wohnzimmer

but I can see the problem here:

var room, light, rulename;


room = 'Arbeitszimmer';
light = 'AZ-Main';
if (cache.private.exists(room) === false || cache.private.get(room).hasTerminated()) {
  cache.private.put(room, actions.ScriptExecution.createTimer(room, time.ZonedDateTime.now().plusSeconds(2), function () {
    console.info('Timer Arbeitszimmer');
    console.info(('light -> ' + String(light)));
    }));
};
room = 'Wohnzimmer';
light = 'WZ-Main';
if (cache.private.exists(room) === false || cache.private.get(room).hasTerminated()) {
  cache.private.put(room, actions.ScriptExecution.createTimer(room, time.ZonedDateTime.now().plusSeconds(3), function () {
    console.info('Timer Wohnzimmer');
    console.info(('light -> ' + String(light)));
    }));
};

which results into

2023-12-02 18:17:27.495 [INFO ] [enhab.automation.script.ui.timer_var] - Timer Arbeitszimmer
2023-12-02 18:17:27.497 [INFO ] [enhab.automation.script.ui.timer_var] - light -> WZ-Main
2023-12-02 18:17:28.516 [INFO ] [enhab.automation.script.ui.timer_var] - Timer Wohnzimmer
2023-12-02 18:17:28.517 [INFO ] [enhab.automation.script.ui.timer_var] - light -> WZ-Main

Normally I would say that a closure like function() {}would have to be done with function(light) { } where javascript would use the “saved” light-value for the closure.
I am not totally sure what the specified behaviour for this is, ie. where the value is coming from when just using the outer context. It might be specified as the value of the outer context at the time when the closure is run.

maybe Florian can share some light here.

1 Like

However that’s not the case.

Looking at the Blockly generated code, the timer callback function it is accessing the variable by directly referencing it and reading it from the global context. When the timer expires, the callback function is therefore using the current value of the variable. If it has been mutated meanwhile, the new value will be accessed.

To avoid mutation here, function generators should be used. I could also imagine adding support for passing parameters as supported by setTimeout/setInterval to createTimer.

BTW we have a whole section about that in the JS Scripting docs: JavaScript Scripting - Automation | openHAB and an improved version of this section is already pushed to the source repo.

2 Likes