Understanding Timers in Rules

Hello

I am using the latest snapshot of OH 4 and i have a question regarding Timers.
In my understanding Thread:sleep(1000) Waits in the rule and this is not recommendet for larger amounts of time since “only” a few instances of rules can trigger at the same time.

I have a rule that triggers when the level of my cistern is updated and for safety reasons i want the valve that refills the cistern when it is under a cetrain level to be active for at most 4 hours - so i created a timer.

In the first if condition i check the level to stop the valve once the desired level is reached but this does not ever seem to be triggered.

I thought using a timer escapes the rule so the trigger condition can fire again. but that does not seem to be the case.

Does the rule keep running at the point of the square brackets of the timer once the timer is finished? SO in other words it works exactly like thread::sleep but in a better way as i mentioned before?

I will try using 2 rules for achieving my goal but i want to understand timers better.

Thank you.

PS: Here’s the rule:

ule "Bewässerung: Nachspeisung Zisterne"
when
    Item Aussen_Zisterne_Fuellstand received update
then
    // Case 1 Füllstand ausreichend
    if(Aussen_Zisterne_Fuellstand.state > 35 && Aussen_Zisterne_Nachspeisung_Merker.state == ON)
    {
        sendNotification("com","Nachspeisung Zisterne: Füllstand erreicht.")
        SprinklerZone6Run.sendCommand(OFF)
        Aussen_Zisterne_Nachspeisung_Merker.sendCommand(OFF)
        createTimer(now.plusMinutes(1),
            [ |  
            if(Aussen_Zisterne_Nachspeisung_Durchflussschalter.state == CLOSED)
            {
                sendNotification("","Nachspeisung Zisterne: Durchfluss inaktiv.")
            }
            else if(Aussen_Zisterne_Nachspeisung_Durchflussschalter.state == OPEN) 
            {
                sendNotification("m","Nachspeisung Zisterne: ACHTUNG! Durchfluss noch aktiv!")
            }
            ])
    }
    else if(Aussen_Zisterne_Fuellstand.state < 15 && Aussen_Zisterne_Nachspeisung_Merker.state != ON && Aussen_Zisterne_Drucksensor_Alarm_Drahtbruch.state == CLOSED && gSprinklerOhneSpeisung.state == OFF)
    {
        sendNotification("om","Nachspeisung Zisterne: Gestartet.")
        SprinklerZone6Run.sendCommand(ON)
        SprinklerZone6RunCustom.sendCommand('7200s')
        Aussen_Zisterne_Nachspeisung_Merker.sendCommand(ON)
        createTimer(now.plusSeconds(7200),
            [ |  
            sendNotification("com","Nachspeisung Zisterne: Gestoppt - Zeit abgelaufen.")
            SprinklerZone6Run.sendCommand(OFF)
            Aussen_Zisterne_Nachspeisung_Merker.sendCommand(OFF)            
            ])   
    }
end```

That’s correct :slight_smile:

That’s true for openHAB up to 2.x, but not longer for openHAB >= 3.0.0
Nowadays there is one dedicated thread per rule, so a rule will never be executed more than once at the same time.

I don’t see any obvious issues with your rule, but as a first guess, please don’t use received update but changed as trigger. You want the rule to operate if the level has changed.

1 Like

Ok. The info that a rule wont trigger again when the timer runs explains what i am experiencing.
I want to stop the flow once the desired level is reached so i split it up into 2 separate rules.
Should i use a global timer and cancel it once the level is reached? I think this would be the cleanest approach.

That was the case for Thread:sleep, not for timers. A rule will run, independent if a timer is present. So worst case is that you create a zillion running timers.

If a rule runs that creates a timer, have it check for an existing running timer and do nothing (end) until the timer has expired, update that timer (thought that is possible) or kill it and create it again with the new info required for the timer.

In that case you can create a global for your timer, where you can give your timer a name. When the rule runs you can check if that timer name already runs and proceed accordingly.

1 Like

thank you! I will test that soon. for now i use flags that get set when the timer gets started.
your approach seems more elegant!

You could also add an expiration timer at the metadata of the item which is controling the valve.
So you will not need an timer in a rule.

And keep the 2 rules.

  1. Rule will enable the Valve (and start the expiration timer) if the lower level is reached
  2. Rule will disable the Valve if higher level is reached (expiration timer should be killed/ignored afaik)

And if the higher level is not reached in 4 hours, the expiration timer will disable the valve.

How you are controlling your valves? Cause i’m controlling my valves with an arduino+relay, and the max-on-time is handled directly on them, so even if my openhab dies (or my rule or sensor is faulty) the valves gets closed.

mytimer.reschedule

Note, you need to save the timer in a global variable (I called it mytimer above) or the cache to reference it in subsequent trigger of the rule or from another rule.

Thank you all so mich for your input! I will certainly dig deeper into timers tomorrow.

I am using a hunter hydrawise 6 valve controller.
I know i can schedule it directly in the hunter app but at the moment the lawn is growing for the first time and there is much tweaking needed :wink:
Also the valve to refill will permanently be controlled via Openhab but i am only passing the time to the hunter controller so it should be kinda safe as well. I also added a flow meter that sends me a push if the valve received a stop request and there is still flow after a short delay.