[SOLVED] (create)Timer Loop Problem in a rule

Hello,

i would likу to make a notifications when Washingmachine finished. But it want it to repeat this notification till it will be turned off. First notification comes strait as if finished, then after 10 seconds, 20 seconds, 40 seconds, 80 seconds (this time intervals i will change later to bigger, it is just for testing) and on till it MODE_FINISHED changed to MODE_OFF or other one.

So here is the simple rule with timer

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3

var Timer timer = null 
var Number repeatTimer
var message = null 

rule "Washing Mashine State / Notifications / Tele Period Change"
when
	Item WashingmachineState changed
then 

	if (WashingmachineState.state == MODE_ACTIVE || WashingmachineState.state == MODE_STANDBY) {  
        if (WashingmachineState.state == MODE_ACTIVE) {
            //Resetting all values
            WashingmachineStartTime.postUpdate(now.toString)
            WashingmachineEndTime.postUpdate(NULL)
            WashingmachineTime.postUpdate(NULL) 
            WashingmachineEnergy.postUpdate(0)
            message = "Washing started (ACTIVE): " + String::format( "%1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS", new java.util.Date)
            logInfo("householdDevices.rules", message)
            sendTelegram("bot", messagePrefix + message)
        }
        TasmotaSocketDryerTelePeriod.sendCommand(TELEPERIOD_ACTIVE)
        message = "Tasmota Tele set to 30 (ACTIVE or STANDBY): " + String::format( "%1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS", new java.util.Date)
        logInfo("householdDevices.rules", message)
        sendTelegram("bot", messagePrefix + message)
    }   

	if (WashingmachineState.state == MODE_OFF) {  
        TasmotaSocketDryerTelePeriod.sendCommand(TELEPERIOD_OFF)
        message = "Tasmota Tele set to 300 (OFF): " + String::format( "%1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS", new java.util.Date)
        logInfo("householdDevices.rules", message)
        sendTelegram("bot", messagePrefix + message)
    }

    if (WashingmachineState.state == MODE_FINISHED) {
        repeatTimer = 10000
        timer = null
       //timer.cancel()

        timer = createTimer(now, [|   
            if (WashingmachineState.state == MODE_FINISHED) {
                WashingmachineEndTime.postUpdate(now.toString)

                repeatTimer = ((repeatTimer)* 2).intValue
                logInfo("householdDevices.rules", "Washingmachine finished. repeatTimer: " + repeatTimer + ". timer: " + timer)
                timer.reschedule(now.plusMillis(repeatTimer.intValue))

            } 
        ])

    }  
end

U need to look at the last section with timer starting with

 if (WashingmachineState.state == MODE_FINISHED) {

But i always get errors and i can not understand its meaning.

First one i explained on following screenshot https://prntscr.com/pr360t
Here i emulate washmashine and change MODE_FINISHED to MODE_ACTIVE and back to MODE_FINISHED and so on.

Second one comes unexpected and i do not understand its meaning

==> /var/log/openhab2/openhab.log <==

2019-11-01 12:53:54.178 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.2019-11-01T12:53:34.144+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@8918f8

} ] threw an unhandled Exception: 

java.lang.NullPointerException: null

	at org.eclipse.smarthome.model.script.engine.ScriptError.<init>(ScriptError.java:66) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:140) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:865) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:224) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:768) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:226) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy200.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]

	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]

==> /var/log/openhab2/events.log <==

2019-11-01 12:53:54.407 [me.event.ThingUpdatedEvent] - Thing 'yamahareceiver:zone:9ab0c000_f668_11de_9976_00a0de711e58:Zone_2' has been updated.

==> /var/log/openhab2/openhab.log <==

2019-11-01 12:53:54.397 [ERROR] [org.quartz.core.ErrorLogger         ] - Job (DEFAULT.2019-11-01T12:53:34.144+01:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {

  org.eclipse.xtext.xbase.impl.XIfExpressionImpl@8918f8

} ] threw an exception.

org.quartz.SchedulerException: Job threw an unhandled exception.

	at org.quartz.core.JobRunShell.run(JobRunShell.java:213) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]

	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [107:org.eclipse.smarthome.core.scheduler:0.10.0.oh240]

Caused by: java.lang.NullPointerException

	at org.eclipse.smarthome.model.script.engine.ScriptError.<init>(ScriptError.java:66) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:140) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:865) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:224) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:768) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:220) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluateArgumentExpressions(XbaseInterpreter.java:1116) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1046) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:992) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:151) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:902) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:226) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:458) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:244) ~[?:?]

	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:447) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:228) ~[?:?]

	at aorg.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.doEvaluate(ScriptInterpreter.java:226) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:204) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:190) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46) ~[?:?]

	at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29) ~[?:?]

	at com.sun.proxy.$Proxy200.apply(Unknown Source) ~[?:?]

	at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:49) ~[?:?]

	at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[?:?]

	... 1 more

Maybe there is fault in rule, but where. I’m trying to made this rule for about 4 days without success!
Please help!

Thanks a lot!

If you search, you will find the fault in the rule is the use of timers which bog down OH rule threads. There are usually other ways to accomplish your goal. @rlkoshak is the master of design patterns here.

1 Like

Havr you tried this:

            if (WashingmachineState.state == 3) {
1 Like

If that works try changed this

val Number MODE_FINISHED = 3

to

var Number MODE_FINISHED = 3

And do:

if (WashingmachineState.state == MODE_FINISHED) {

again

1 Like

But what fault? Please aim it.

Thanks!
Will try now.
But how can it be associated with timer probmels?)))

Again the same Screenshot by Lightshot
and the second error also(((

Many people misuse timers causing many issues. .I looking closer, it appears you are only using your timer to repeat a log message? I believe that will still consume one of the 5 threads available for active rules. You may be able to accomplish the same thing using cron for example.

It looks like the old timer if i change the state of MODE_FINISHED to new one sill working and give this results like this http://prntscr.com/pr4fxd
despite of that ID of times changes http://prntscr.com/pr4gpq
Looks like a bug ((((

Ok it can be, i can understand if timer fires LATER as it must, But how can be explained that it fires ERLIER that is must?

I found it, look here http://prntscr.com/pr4l1j
This second timer is like the continuation of first one again despite of their IDs

Maybe timer must be cancelled someway, not like this timer = null
I tried timer.cancel() but i get error on it.

It is fine using timers in rules, but of course you need to manage them with thought.

This may be helpful. Remember your variable ‘timer’ is just a handle.

Personally, I would change the variable name from ‘timer’ to something more helpful like ‘modetimer’ before you write some other rule with timers and get mixed up.

1 Like

I will change it of course after testing.
But now i can certanly say that “I found it, look here Screenshot by Lightshot
This second timer is like the continuation of first one again despite of their IDs” and the " timer is still running in the background … and stores a handle"

But reading your example i did not understood how to solve it (((
Could u give me a tip?

Thanks!

Timers are not usually an issue unless:

  • you have a bunch that expire at the same time which usually isn’t possible unless you are using cron triggered Rules
  • your Timer bodies are long running which isn’t the case here.

The timers as used in the OP shouldn’t be causing any problems. Don’t confuse Timers with Thread::sleep. Thread::sleep blocks a Rule for the given time and that can and does cause a lot of problems.

Why fight with milliseconds. It’s so much more intuitive to use higher level units. Want the thread to go off in 20 seconds? Use now.plusSeconds(20). What it to go off in an hour? Use now.plusHours(1).

You should indeed cancel the timer and not just set it to null. If there was an old Timer running, it will continue to run. There is a shortcut to check for null and only call cancel if the timer is not null in Rules DSL.

timer?.cancel

I suspect that you are seeing odd times because you have a bunch of these orphaned timers floating around because you don’t cancel them before creating a new one.

When you reload your .rules file, all the stuff in the file get’s reset. We call that “stuff” the context. But, any scheduled Timers you created in that Timer do not go away. When those Timers finally expire, they cannot run because their context no longer exists.

This error is benign and can be ignored.

In Scripted Automation, there is a special unload function you can define to clean up the timers and prevent them from becoming orphaned.

You probably got an error because sometimes timer is null and you can’t call cancel on something that is null. The line I have above with the ? will check that timer is not null first before calling cancel.

This is a good point. I don’t know if it is still true but it used to be the case that all your global vars and vals must be unique even if defined in different .rules files. But even if that has been fixed, it’s good practice to use more meaningful names anyway.

4 Likes

Thanks a lot.
Will try to check it and give you a feedback!

Rich, thanks a lot!
I would mark your advice as Solution, because it really works!
Now rule works excellent!

Only the question are the var’s and val’s defined at the top of the rule file are visible (or having conflicts/problems) in another rules files?
I need to make more same rules for dishwasher and dryer and now need to understand if i need to rename all the definitions.

No, they belong to this rules file only

1 Like