In this example, I will show a way of how to detect a particular sequence of events (other solutions can be possible). I created two simple rules to detect when I arrive or leave home. More complex rules can be created, if more than one person lives in the house and if you consider other conditions.
Automation #7: Detect a particular sequence of events
In summary, the pattern to detect when I arrive home is represented by the following sequence of events:
(1) Front_Door_Motion --> (2) Front_Door_Contact --> (3) Entrance_Hall_Motion
and the pattern to detect that I’m leaving home is:
(1) Entrance_Hall_Motion --> (2) Front_Door_Contact --> (3) Front_Door_Motion
Note: I’m only considering that all three events occur within a time window of 60 seconds.
// Initialize variables to avoid null checks
// These variable will save the last time in which they changed to the desired state
var lastDoorOpen = now().minusHours(24)
var lastEHallMotion = now().minusHours(24)
var lastFDoorMotion = now().minusHours(24)
rule "(DSL) Front Door Opened"
when
Item Front_Door_Contact changed to OPEN
then
lastDoorOpen = now()
end
rule "(DSL) Motion Detected - Entrance Hall"
when
Item Entrance_Hall_Motion changed to ON
then
lastEHallMotion = now()
// discard events older than 60 secs
if( lastFDoorMotion.isBefore(lastEHallMotion.minusSeconds(60))) return;
if(lastEHallMotion.isAfter(lastDoorOpen) && lastDoorOpen.isAfter(lastFDoorMotion)) {
// code logic for arriving home
}
end
rule "(DSL) Motion Detected - Front Door "
when
Item Front_Door_Motion changed to ON
then
lastFDoorMotion = now()
// discard events older than 60 secs
if( lastEHallMotion.isBefore(lastFDoorMotion.minusSeconds(60))) return;
if(lastFDoorMotion.isAfter(lastDoorOpen) && lastDoorOpen.isAfter(lastEHallMotion)) {
// code logic for leaving home
}
end
Jython Implementation
from core.rules import rule
from core.triggers import when
from java.time import ZonedDateTime as ZDateTime
lastDoorOpen = ZDateTime.now().minusHours(24)
lastEHallMotion = ZDateTime.now().minusHours(24)
lastFDoorMotion = ZDateTime.now().minusHours(24)
@rule("(Py) Front Door Opened")
@when("Item Front_Door_Contact changed to OPEN")
def front_door_opened(event):
global lastDoorOpen
lastDoorOpen = ZDateTime.now()
@rule("(Py) Motion Detected - Entrance Hall")
@when("Item Entrance_Hall_Motion changed to ON")
def entrance_hall_motion(event):
global lastEHallMotion, lastFDoorMotion
lastEHallMotion = ZDateTime.now()
if lastFDoorMotion.isBefore(lastEHallMotion.minusSeconds(60)):
return
if lastEHallMotion.isAfter(lastDoorOpen) and lastDoorOpen.isAfter(lastFDoorMotion):
# code logic for arriving home
@rule("(Py) Motion Detected - Front Door")
@when("Item Front_Door_Motion changed to ON")
def front_door_motion(event):
global lastEHallMotion, lastFDoorMotion
lastFDoorMotion = ZDateTime.now()
if lastEHallMotion.isBefore(lastFDoorMotion.minusSeconds(60)):
return
if lastFDoorMotion.isAfter(lastDoorOpen) and lastDoorOpen.isAfter(lastEHallMotion):
# code logic for leaving Home
Happy coding!
Humberto
Note :
Suggestions or recommendations to improve the implementation are welcome!
Do you have more complex automations that shares the same logic of this example? Please share it
I´ve rebuild my welcome rule with your example.
It´s working pretty good but there´s still something that´s a little bit unclear.
I´m using two Homematic sensors for the door and the lock and one Fibaro motion sensor in the hallway.
I would like to check for the sequence: Lock opened -> door opened -> motion detected
That´s already working fine, but the rule fires again when there´s another motion detected 60 seconds after the door was opened.
For my understanding, i just need to reduce the for // discard events older than 60 secs
Or is there any other way?
var lastDoorOpen = now().minusHours(24)
var lastLockOpen = now().minusHours(24)
var lastMotionHall = now().minusHours(24)
val String ruleIdentifier = "WelcomeHome"
rule "Schloss geöffnet"
when
Item itmTuerschloss changed from CLOSED to OPEN
then
lastLockOpen = now()
logInfo(ruleIdentifier, "Schloss geöffnet " + lastLockOpen)
end
rule "Tür geöffnet"
when
Item itmTuer_Flur changed from CLOSED to OPEN
then
lastDoorOpen = now()
logInfo(ruleIdentifier, "Tür geöffnet " + lastDoorOpen)
end
rule "Begrüßung"
when
Item itmFIBmotion2 changed to 1
then
lastMotionHall = now()
logInfo(ruleIdentifier, "Bewegung erkannt " + lastMotionHall)
if(lastMotionHall.isBefore(lastDoorOpen.minusSeconds(60)))
{
return;
}
val CurrentHour = now.getHourOfDay
val Night = (CurrentHour >22 || CurrentHour <8)
if(lastMotionHall.isAfter(lastDoorOpen) && lastDoorOpen.isAfter(lastLockOpen))
{
// complex rule to check if someones home and let an Echo Dot say something
}
end
If your motion sensor checks for movement more frequently (< 60 secs), indeed you should consider reducing the time window. In my case after a movement is detected the motion sensor goes to sleep for 60 secs.
Maybe there is a better solution than mine. I’m not an experienced OpenHab user
I haven’t tested this solution but should be something like that… I used the same approach to avoid multiple notifications from the doorbell Automation #1: Doorbell notification
If that doesn’t work let me know and I will look it later
Just for my understanding.
When does oH use the initial var = parameters?
Everytime the rule fires or just when the rule is loaded into the runtime? 2019-09-15 02:05:37.613 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'FlurWelcome.rules'
Because my check to ensure the rule only fires once made the rule stop before even firing.
I changed the initial parameter for my lastWelcome to var lastWelcome = now().plusHours(24) to ensure the check lastMotionHall.isAfter(lastWelcome) fires correctly.