Basic Motion Timer With Additional Force ON And Force OFF

rules
Tags: #<Tag:0x00007f014c5f07b8>

(John Schmitz) #1

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

(Rossko57) #2

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.


(Markus Storm) #3

Check out the expire binding, it’ll re-set timers if you set/update the item they’re attached to.


(Rossko57) #4

But expire binding
(a) does not allow for variable runtime
(b) does not allow to determine how long is yet to run, in order to take decisions about whether to leave alone or start over
© does not provide a means to disable it (unless having a another shorter timer to keep prodding the Item)