I found some inspiration in comments of the tutorial.
Contact PIR_GPIO "PIR GPIO" { gpio="pin:27 activelow:yes force:yes" }
Switch PIR "PIR [MAP(pir.map):%s]" {expire="10s,command=OFF"} // Send OFF command after time x
Group:Number:SUM MotionEventTimers "Number of active timers [%d]"
Switch MotionEvent1Timer (MotionEventTimers) { expire="1m,command=OFF" }
Switch MotionEvent2Timer (MotionEventTimers) { expire="1m,command=OFF" }
var lastRun = now
val numTimers = MotionEventTimers.members.size
rule "Handle PIR_GPIO Events"
when
Item PIR_GPIO changed from OPEN to CLOSED
then
logInfo("PIR_GPIO Event", "changed from OPEN to CLOSED")
// ignore the event if it has been less
// then n seconds since the last time or PIR state is on already
if(PIR.state == OFF && lastRun.isAfter(now.minusSeconds(20))) {
logInfo("PIR_GPIO Event", "Ignoring event")
return;
}
logInfo("PIR_GPIO Event", "MotionEventTimers == " + MotionEventTimers)
logInfo("PIR_GPIO Event", "MotionEventTimers.state == " + MotionEventTimers.state)
// if there are less than numTimers ON timers, find the one that is OFF and set it to ON
if(MotionEventTimers.state < numTimers) {
logInfo("PIR_GPIO Event", "MotionEventTimers.members: " + MotionEventTimers.members)
MotionEventTimers.members.filter[ t | t.state != ON ].head.sendCommand(ON)
logInfo("PIR_GPIO Event", "Setting " + MotionEventTimers.state + "/" + numTimers + " Timer ON")
}
logInfo("PIR_GPIO Event", "MotionEventTimers.state == " + MotionEventTimers.state)
// if timers.size == numTimers then this event is the numTimers + 1 ON event in a minute
if(MotionEventTimers.state == numTimers) {
lastRun = now
PIR.sendCommand(ON)
logInfo("PIR_GPIO Event", numTimers + " timers ON")
}
end
Log:
[script.PIR_GPIO Event] - changed from OPEN to CLOSED
[script.PIR_GPIO Event] - MotionEventTimers == MotionEventTimers (Type=GroupItem, BaseType=NumberItem, Members=2, State=0, Label=Number of active timers, Category=null)
[script.PIR_GPIO Event] - MotionEventTimers.state == 0
[script.PIR_GPIO Event] - MotionEventTimers.members: [MotionEvent2Timer (Type=SwitchItem, State=OFF, Label=null, Category=null, Groups=[MotionEventTimers]), MotionEvent1Timer (Type=SwitchItem, State=OFF, Label=null, Category=null, Groups=[MotionEventTimers])]
[script.PIR_GPIO Event] - Setting 1/2 Timer ON
[script.PIR_GPIO Event] - MotionEventTimers.state == 1
[script.PIR_GPIO Event] - changed from OPEN to CLOSED
[script.PIR_GPIO Event] - MotionEventTimers == MotionEventTimers (Type=GroupItem, BaseType=NumberItem, Members=2, State=1, Label=Number of active timers, Category=null)
[script.PIR_GPIO Event] - MotionEventTimers.state == 1
[script.PIR_GPIO Event] - MotionEventTimers.members: [MotionEvent2Timer (Type=SwitchItem, State=ON, Label=null, Category=null, Groups=[MotionEventTimers]), MotionEvent1Timer (Type=SwitchItem, State=OFF, Label=null, Category=null, Groups=[MotionEventTimers])]
[script.PIR_GPIO Event] - Setting 2/2 Timer ON
[script.PIR_GPIO Event] - MotionEventTimers.state == 2
[script.PIR_GPIO Event] - 2 timers ON
[script.Motion] - update ON
[script.Motion] - detected motion, but resident is present
[script.Motion] - Stopping PIR actions. TODO
Note: I have used t.state != ON
instead of t.state == OFF
because the state was UNDEFINED
and therefore not matched in the filter.
I have to tweak the timing because it doesn’t meets my requirement yet and test it in production.