Have a rule that after execution pauses for some hours

Hi all

I have been struggling to generate a rule that, after triggering, pauses for, lets say 12 hours in order not to send multiple commands while the triggering status is still valid.

Specifically, I want a rule that opens all blinds above a wind speed threshold but once they’re retracted the rule should pause.

rule "Vertical blinds up at wind"
when Item OWM_Wind_Speed changed
        then
            if (wRun === null){
                if (OWM_Wind_Speed.state > 20 && gVertStoren.state > 0 ) {
                    gVertStoren.members.forEach[i|i.sendCommand(0)]
                    wRun = createTimer(now.plusHours(20), [|logWarn(ruleName1, "Timer Off")])
                }
            }
        
end

This rule is faulty. Anyone to the rescue?

rule "Vertical blinds up at wind"
when Item OWM_Wind_Speed changed
        then
            if (wRun === null){
                if (OWM_Wind_Speed.state > 20 && gVertStoren.state > 0 ) {
                    gVertStoren.members.forEach[ i|i.sendCommand(0)]
                    wRun = createTimer(now.plusHours(20), [ |
                        logWarn(ruleName1, "Timer Off")
                        wRun = null // reset the timer
                    ])
                }
            }
end

If you are running snapshot you need to insert a space after the [
However running a timer for 20 hours is not recommended as you are creating a thread for the timer and that thread is then unavailable for the next 20 hours leaving you with only 4 threads available to run OH.
Use the expire binding instead:

Install the expire binding
Create a switch item as follow:

Switch BlindsWindTimer { expire="20h, command=OFF" }

Your rules:

rule "Vertical blinds up at wind"
when Item OWM_Wind_Speed changed
        then
            if (BlindsSwitchTimer.state == OFF) {
                if (OWM_Wind_Speed.state > 20 && gVertStoren.state > 0 ) {
                    gVertStoren.members.forEach[i|i.sendCommand(0)]
                    BlindsWindTimer.sendCommand(ON)
                }
            }
end

Not quite. If OP were using Thread::sleep that would be a concern. But Timer threads come from a separate thread pool, and the Timer only consumes a runtime thread when it had triggered and is running the lambda.

A long timing timer may take up a miniscule extra amount of memory but it won’t use a rules execution thread. That has why we recommend using timers instead of sleeps for anything more than half a second.

Expire binding has lots of other benefits though, including much simpler code to manage it.

There might be a little bug in the expire example. I think you need

if (BlindsSwitchTimer.state != ON) {

To cover the car where BlindsSwitchTimer is NULL. On a restart of OH, unless something else sets it to OFF the timer will never get started.

1 Like

My bad, I was under the impression the the OH timer were taking up a thread and that’s why the expire binding was so powerful. I will still recommend it’s use whenever possible as it is much easier to use than timers (Syntax, check if null, cancel the timer…)
Thanks

Thank you both. I implemented your codes and now I wait for wind :wink: