I’d like to have a simple motion detector timer pattern except I would like to add a “force on” and a “force off” based on switches to have a forced on or off for a longer duration. The best I’ve come up with so far is three timers where each rule checks for the existence of the other timers (essentially using the existence of them as state information), and behave appropriately. This is a little complex. Sample rules (untested) below.
Is there a better way to achieve this? Thanks for any advice.
val int longTimeout = 30
val int shortTimeout = 5
var offTimer = null
var shortOnTimer = null
var longOnTimer = null
rule "Force off triggered"
when
Item ForceOff received update ON
then
lamp.sendCommand(OFF)
if(offTimer === null) {
offtimer = createTimer(now.plusMinutes(longTimeout), [|
offTimer = null
])
}
else {
offtimer.reschedule(now.plusMinutes(longTimeout), [|
}
if (shortOnTimer !== null) {
shortOnTimer.cancel
shortOnTimer = null
}
if (longOnTimer !== null) {
longOnTimer.cancel
longOnTimer = null
}
end
rule "Force on triggered"
when
Item ForceOn received update ON
then
lamp.sendCommand(ON)
if(longOnTimer === null) {
longOnTimer = createTimer(now.plusMinutes(longTimeout), [|
longOnTimer = null
])
}
else {
onTimer.reschedule(now.plusMinutes(longTimeout), [|
}
if (offTimer !== null) {
offTimer.cancel
offTimer = null
}
if (shortOnTimer !== null) {
shortOnTimer.cancel
shortOnTimer = null
}
end
rule "Motion triggered"
when
Item Motion received update ON
then
if(longOnTimer === null) && (offTimer === null) {
lamp.sendCommand(ON)
shortOnTimer = createTimer(now.plusMinutes(longTimeout), [|
shortOnTimer = null
lamp.sendCommand(ON)
])
}
else {
shortOnTimer.reschedule(now.plusMinutes(longTimeout), [|
}
end
Logically, your forced-on and motion timers are doing the same thing - setting an OFF directive in the future. So at first glance, they could be the same timer, just set up with different initial time of run.
But the problem arises when you get a motion trigger while a timer is already running. You’d probably want to extend the time (wouldn’t you?) - but you cannot discover what the remaining time is. You might replace an existing long time with a shorter one, which I imagine is unwanted.
There are ways round that by using an additional variable with the target datestamp, so you can see if the proposed new time is later than the existing one. Quite a bit of work though, it’s probably easier to maintain two separate timers I think.
The third timer has a different function, and you need to “know” from outside that it is there to block motion triggers. The only way to do that is by giving it a different name.
So I think your three timer solution is reasonable.
I’ve wrestled with this sort of problem myself, and ended up with a different approach. Putting the ON time into an accessible minute counter, with rules to decrement it and turn something OFF at zero.
That allows rules to compare a proposed runtime with actual, and if required overload the counter.
That still doesn’t solve the forced-off / blocking task though.
In my case I can detect when people use wall switches, and wanted to lockout any motion triggers for a period after they’d used wall switches (on the assumption that live user knows best).
So associated with each Lighting Item is (yet another) Item to act as manual flag. That locks out motion triggers when set, and I use the expire binding to time them out after a fixed period, restoring auto control.