Problems with Timer

Hi,
last week I updated my system from 3.2 to 3.3.
After that eyerything looks ok, but now I found a strange behaviour.
I did not see this directly after the update, because we have summer, and the heating is not needed.

So at every window I have a fibaro window Sensor that shows me the window state.
In case the windows ist openfor more that 20s the script should disable the heating.
So the Problem comes now with this 20 s timer.

Here you see the script, or parts of the script that were relevant for the timer.

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
logger.info(event);
logger.info("Start Window Rule");

this.myTimer = (this.myTimer===undefined) ? null : this.myTimer;
this.myHeatingOff = (this.myHeatingOff===undefined) ? 0 : this.myHeatingOff;


var ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
var ZonedDateTime   = Java.type("java.time.ZonedDateTime");

if(this.myTimer != undefined && this.myTimer != null){
  this.myTimer.cancel();
  this.myTimer = null;
  logger.info("timer canceld. do nothing");
      
}

if( event.itemState === CLOSED )
{
  logger.info("state close. timer running");
  if( this.myHeatingOff===1)
    {
      logger.info("Heating on");
      this.myHeatingOff=0;
    }
}
  
if( event.itemState === OPEN)
{
  logger.info("state open. Timer not set");
  this.myTimer = ScriptExecution.createTimer(ZonedDateTime.now().plusSeconds(20), function(){
        logger.info("Timer off");
        logger.info("itemState:"+event.itemState);
        logger.info("oldItemState:"+event.oldItemState);
        if(event.itemState===OPEN)
          {
            logger.info("still open after 20s -> Heizung aus");
            this.myHeatingOff = 1;
          }
         
 
       this.myTimer = null;

    
  }
  ) 
}


;

And here is the logging

2022-08-01 13:33:00.319 [INFO ] [org.openhab.rule.acb5ccd60b         ] - Item 'AZFI_SensorDoor' changed from CLOSED to OPEN
2022-08-01 13:33:00.322 [INFO ] [org.openhab.rule.acb5ccd60b         ] - Start Window Rule
2022-08-01 13:33:00.325 [INFO ] [org.openhab.rule.acb5ccd60b         ] - event:Item 'AZFI_SensorDoor' changed from CLOSED to OPEN
2022-08-01 13:33:00.328 [INFO ] [org.openhab.rule.acb5ccd60b         ] - itemName:AZFI_SensorDoor
2022-08-01 13:33:00.330 [INFO ] [org.openhab.rule.acb5ccd60b         ] - command:undefined
2022-08-01 13:33:00.333 [INFO ] [org.openhab.rule.acb5ccd60b         ] - items:OPEN
2022-08-01 13:33:00.338 [INFO ] [org.openhab.rule.acb5ccd60b         ] - state open. Timer not set
==> /var/log/openhab/events.log <==
2022-08-01 13:33:00.309 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'AZFI_SensorDoor' changed from CLOSED to OPEN
==> /var/log/openhab/openhab.log <==
2022-08-01 13:33:20.342 [INFO ] [org.openhab.rule.acb5ccd60b         ] - Timer off
2022-08-01 13:33:20.358 [WARN ] [ore.internal.scheduler.SchedulerImpl] - Scheduled job '<unknown>' failed and stopped
jdk.nashorn.internal.runtime.ECMAException: ReferenceError: "event" is not defined
	at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:319) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:291) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.objects.Global.__noSuchProperty__(Global.java:1616) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:677) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:527) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ScriptObject.invokeNoSuchProperty(ScriptObject.java:2445) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.runtime.ScriptObject.megamorphicGet(ScriptObject.java:2043) ~[jdk.scripting.nashorn:?]
	at jdk.nashorn.internal.scripts.Script$Recompilation$302$1105$\^eval\_.myTimer(<eval>:40) ~[?:?]
	at jdk.nashorn.javaadapters.org_eclipse_xtext_xbase_lib_Procedures$Procedure0.apply(Unknown Source) ~[?:?]
	at org.openhab.core.model.script.actions.ScriptExecution.lambda$0(ScriptExecution.java:97) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$12(SchedulerImpl.java:191) ~[?:?]
	at org.openhab.core.internal.scheduler.SchedulerImpl.lambda$1(SchedulerImpl.java:88) ~[?:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
	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:1128) [?:?]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
	at java.lang.Thread.run(Thread.java:834) [?:?]
==> /var/log/openhab/events.log <==
2022-08-01 13:34:31.816 [INFO ] [openhab.event.RuleUpdatedEvent      ] - Rule 'acb5ccd60b' has been updated.

Has anyone an idea whats going wrong?
Before the update everything works fine.
Thanks
Thorsten

It seems like it should work but clearly the event Object isn’t making it into the function passed to createTimer. So you can do one of two things:

  1. Use createTimerWithArgument(ZonedDateTime.now().plusSeconds(20), event, function(event) {

  2. Use a function generator.

var timerBody = function(event) {
    return function() {
        logger.info("Timer off");
        ...
    }
}
this.myTimer = ScriptExecution.createTimer(ZonedDateTime.now().plusSeconds(20), timerBody(event));

Thanks, I used the 2nd advice from you. Now it works.
But it means:

  • my original solution was syntactically not correct, even if it works and produces no error messages,
    or
    -something changed with the update.

But …now the error has gone. So thank you

There are not changes being made that are specific to the ECMAScript 5.1 rules engine. All the new development and changes are being made to the JS Scripting add-on which brings ECMAScript 11. So I couldn’t say why it worked before but not now.

Hi Rich,
as you mentioned the new Version of JavaScripting ( Version 11), I start reading about that.

Some of my scripts could be easily translated, and some of this things were going easier now.

But this script with the timer…
Do you have an idea what I have to change?

I found some posts of you, also you’re github repro.
Also in the openhab doc there is an example.

var timer = setTimeout(() => { console.log('Timer expired.'); }, 10000); // Would log 'Timer expired.' in 10s.
if (timer.isActive()) console.log('Timer is waiting to execute.');
timer.cancel();
if (timer.isCancelled()) console.log('Timer has been cancelled.');
timer.reschedule(time.ZonedDateTime.now().plusSeconds(2)); // Logs 'Timer expired.' in 2s.

In the setTimeout there should be the function call.
But I can not get it to work.
Is it not possible to put the timeBody fctn that you stated above inside the setTimeout?

Did I still need the createTimer? Or is anything done with the setTimeout?

best regards

JS Scripting uses setTimeout instead of createTimer because setTimeout is a JavaScript construct and createTimer is an openHAB/Java construct. The library for JS Scripting seeks to present only JavaScript to you.

You could still use createTimer if you wanted to but the library is going to push you more towards using the JavaScript instead.

Right, in that doc that’s () => { console.log('Timer expired.'); }.

I’m not sure what you mean. Either of these should work:

var timerBody = function(event) {
    return function() {
        logger.info("Timer off");
        ...
    }
}
this.myTimer = setTimeout(timerBody(event), 20000);

or

this.myTimer = setTimeout((event) => {
    logger.info("Timer off");
    ...    
}, 20000, event);

setTimeout replaces createTimer in JS Scripting. You can still use createTimer if you want to.

Hi Rich,
thanks for your comment.
I exactly uses the first suggestion from you. But it will not work.
Crazy think I struggeld before some month ago :frowning:
I did the edit think from my android tablet, usinf chrome as the browser.

After I read you’re commetn yesterday evening, I copied the code to my laptop and add it again
to the rule. SAME CODE!!!
Now it works…

I had nearly a same issue with custom widgets. If I edit the yaml code from the tablet, something goes
wrong.
So from now on I will only use the PC.

One last question:
I used an instance variable inside the rule:
this.myHeatingOff = (this.myHeatingOff===undefined) ? 0 : this.myHeatingOff;

With this I want to control something in my heating rules.
What must I change to use this instance variable inside the timer body.
Or correctly I want to use the same variable as in the body of the rule.

If I put just this.myHeatingOff inside the timer body, the logging says ‘undefined’. So it is a diffrent variable.
Could I pass the this… to the timerBody?

You’d need to pass it to the timer body same way that event is passed. If using a function generator that would be

var timerBody = function(event, myHeatingOff) {
    // do stuff
}

this.myTimer = setTimeout(timerBody(event, this.myHeatingOff), 20000);

Note, instance variables like that are not guaranteed to remain supported long term. In JS Scripting cache is better to be used for this purpose. At some point even that might become replaced with a more generic mechanism that is supports all the rules languages.

Hi Rich,
thanks again. It works. But I will change now to use cache, as you’ve mentioned it.
BR
Thorsten