[SOLVED] Timer rule - but more elegant

Hi All,

I have a switch that i like to switch on with a timer. I created a massive rule, which works but is far from elegant. What i did is as soon as my timer receives a new input, it waits for 1 minutes and then inputs the value minus 1.

So i have my regular on/off switch an item with mappings for the timer and an item that shows how many minutes are left on the timer.

Items are as follows:

Switch	item=TestSwitch				label="Test Switch"		icon="ostairlights"
						Switch	item=TestSwitch_Timer 		label="Timer Select"	icon="timer" 	mappings=[0="5 min", 1="15 min", 2="30 min", 3="1 hr", 4="2 hrs"]
						Text	item=TestSwitch_TimerDur	label="Remaining timer [%.0f]"		icon="timer"

Now the rules i have created is as follows (the countdown rule i made for every minutes from 120 down to 0). So how can I simplify this rule to just one instead of 120 rules.

rule "Test Lights 30 min"
when
	Item TestSwitch_Timer received command "2"
then
	TestSwitch.sendCommand(ON)
	TestSwitch_TimerDur.sendCommand(30)
	logInfo("info","Test light 30 min timer activated")
end

rule "Switch Timer to 0"
when 
	Item TestSwitch_TimerDur received command "0"
then
	F1_HW_Stairlight.sendCommand(OFF)
	logInfo("info","Test light switches off")
end

rule "Timer from 30 to 29"
when
    Item TestSwitch_TimerDur received command "30"
then
    logInfo("info","30 min left on timer")
    createTimer(now.plusMinutes(1), [ | TestSwitch_TimerDur.sendCommand(29)] )
end
rule "Timer from 29 to 28"
when
    Item TestSwitch_TimerDur received command "29"
then
    logInfo("info","29 min left on timer")
    createTimer(now.plusMinutes(1), [ | TestSwitch_TimerDur.sendCommand(28)] )
end
rule "Timer from 28 to 27"
when
    Item TestSwitch_TimerDur received command "28"
then
    logInfo("info","28 min left on timer")
    createTimer(now.plusMinutes(1), [ | TestSwitch_TimerDur.sendCommand(27)] )
end

That’s really simple :wink:

Switch item=TestSwitch label="Test Switch" icon="ostairlights"
Switch item=TestSwitch_Timer label="timer [%.0f mins]" icon="timer" mappings=[0="OFF",5="5 min", 15="15 min", 30="30 min", 60="1 hr", 120="2 hrs"]
var Timer tTimer = null                                                      // pointer to timer

rule "Timer"
when
    Item TestSwitch_Timer received command
then
    if(receivedCommand instanceof Number) {                                   // just to be sure
        val Number mins = (receivedCommand as Number).intValue                // duration to set
        if(mins == 0) {                                                       // deactivate timer if set to 0
            if(tTimer !== null)                                               // if there is an active timer
                logInfo("timer","Timer deactivated!")
                tTimer.cancel                                                 // cancel
                tTimer = null                                                 // deinitialize
                TestSwitch.sendCommand(OFF)                                   // switch light off
        } else {                                                              // set timer
            logInfo("timer","Timer set to {} Minutes!",mins)
            TestSwitch.sendCommand(ON)                                        // switch light on
            tTimer?.cancel                                                    // cancel existing timer
            TestSwitch_Timer.postUpdate(mins)                                 // set display to duration
            tTimer = createTimer(now.plusMinutes(1), [                        // initialize timer
                val Number nDuration = (TestSwitch_Timer.state as Number) - 1 // get new duration
                TestSwitch_Timer.postUpdate(nDuration)                        // set display to duration
                if(nDuration > 0) {                                           // already reached end?
                    logInfo("timer","Timer end pending {} Minutes",nDuration)
                    tTimer.reschedule(now.plusMinutes(1))                     // repeat
                } else {
                    logInfo("timer","Timer ended.")
                    TestSwitch.sendCommand(OFF)                               // switch light off
                    tTimer = null                                             // deinitialize timer
                }
            ])
        }
    }
end

Timer is created once and is repeated until reached end. Display is updated once a Minute (Display is the same Item as timer control).

You can deactivate the timer. You can simply add other duration by setting the Item state accordingly.

3 Likes

Similar

Awesome. Works perfectly. Just needed to change the , to . in the line

tTimer,reschedule(now.plusMinutes(1))

Ups, sorry, Typo…

For reference, I did the correction above :slight_smile:

Hello,

Line 18: tTimer?.cancel // cancel existing timer

“?” is correct? or typo?

Ed

The use of ? here is a bit of magic. If timer is null the cancel will not be attempted, avoiding what would otherwise be an error.

1 Like

Yes, that’s correct.

tMyTimer?.cancel

is the same as

if(tMyTimer !== null) tMyTimer.cancel
1 Like

Hello,

I have even more elegant requirement for rule, but struggling.
I have several Items, and want them work together.
Garage_gate (Open/close)
Garage_door (Open/close)
Light_switch (on/off)
Several move detection items with (open/close)
and I have also event for sunset/sunrise.

I wan something very elegant.
when I open garage door or garage gate, and it’s also after sunset event (possible with delta), then I turn on light. Later I want to keep light on for 2 minutes, for example. but when I receive move detection, I want this timer back reset to 2 minutes. and turn off when a timer get 0 or it’s sunrise (sunrise it’s optional, but preferred).

Maybe I can get help with this?

Edward

Take a look at Area Triggers and Actions. The example code fits most people’s lighting needs…

Hi, I was trying this example as is,same items, same sitemap, but I get a warning and it doesn’t work.
I’m doing a clean install of oh 2.5.10-1.
The warning is:2020-11-13 18:39:24.943 [WARN ] [rest.core.internal.item.ItemResource] - Received HTTP POST request at 'items/TestSwitch_Timer' with an invalid status value '5'.

what am I doing wrong?
thank you in advance

You probably created TestSwitch_Timer as a Switch type Item, which willnot like being sent numeric commands. Make it a Number type Item.

Perfect…thanks…that was the problem