Edit: A rewrite to take advantage of the Debounce rule template on the marketplace.
This is a tutorial to show a generic and sensor independent way to do presence detection with multiple sensors and implementing anti-flapping (i.e. all sensors must be OFF for a certain amount of time before the home goes to away).
Requirements
- One or more Switches determines whether someone is present.
- If one or more of these Switches is ON then someone is presumed to be present (more complex algorithms are possible but implementing them is an exercise left to the student)
- All Switches must be off for a certain amount of time (5 minutes in this case) before turning off presence. If one returns before that amount of time then presence never turns OFF.
The Code
Items
In this example we will have two people. Each person will have two sensors and when any one of those sensors is ON the person is determined to be present. When both go to off for five minutes the person is determined to be absent.
Finally, there is one Item that represents the overall presence.
Because we are using the Debounce rule template we will also need some Proxy Items also.
Item Name | Type | Purpose | Member of | Debounce metadata |
---|---|---|---|---|
Presence |
Group:Switch using the “if one ON then ON” function |
Represents overall presence | ||
Person1Presence |
Switch |
Represents the debounced presence for Person 1 | Presence |
|
Person1Presence_Raw |
Group:Switch using “if one ON then ON” function |
Represents the raw presence status of Person 1 | Debounce |
debounce=Person1Presence[timeout="5m", states="OFF", command=true] |
Person1Sensor1 |
Switch |
One of Person 1’s sensors | Person1Presence_Raw |
|
Person1Sensor2 |
Switch |
One of Person 1’s sensors | Person1Presence_Raw |
|
Person2Presence |
Switch |
Represents the debounced presence for Person 2 | Presence |
|
Person2Presence_Raw |
Group:Switch using “if one ON then ON” function |
Represents the raw presence status of Person 2 | Debounce |
debounce=Person2Presence[timeout="5m", states="OFF", command=true] |
Person2Sensor1 |
Switch |
One of Person 2’s sensors | Person1Presence_Raw |
|
Person2Sensor2 |
Switch |
One of Person 2’s sensors | Person1Presence_Raw |
|
PresenceOverride |
Switch |
If one wants to turn off presence detection flip to ON. | Presence |
Create these Items in MainUI with these parameters. To add the metadata click on “Add metadata” and “enter custom namespace”. Enter “debounce” as the namespace. Then create the debounce metadata to look like:
value: Person1Presence
config:
states: OFF
timeout: 2m
command: "True"
In a text based .items file:
Group Debounce
Group:Switch:OR(ON,OFF) Presence "Presence"
Switch PresenceOverride (Presence) "Override Presence Detection"
Switch Person1Presence "Person1 Presence" (Presence)
Group:Switch:OR(ON,OFF) Person1Presence_Raw (Debounce) { debounce="Person1Presence[timeout='5m', states=OFF, command=true]" }
Switch Person1Sensor1 (Person1Presence_Raw)
Switch Person1Sensor2 (Person1Presence_Raw)
Switch Person2Presence "Person1 Presence" (Presence)
Group:Switch:OR(ON,OFF) Person2Presence_Raw (Debounce) { debounce="Person2Presence[timeout='5m', states=OFF, command=true]" }
Switch Person2Sensor1 (Person2Presence_Raw)
Switch Person2Sensor2 (Person2Presence_Raw)
Rule
In MainUI navigate to Settings->Automation and browse through the list of rule templates to find Debounce. You many need to click “show all”. Add it.
Navigate to Rules and click the + icon to create a new rule. Enter reasonable information for the Unique ID, Name, and Description. Select “Debounce” from the list of templates. For the “Debounce Group” configuration parameter select “Debounce” from the list of Items. Click save.
This will create the Debounce rule that drives the five minute delay when someone leaves. No coding on your part is required.
Theory of Operation
Each sensor is a member of a Group. If any one of the sensors is ON the Group’s state will be ON. When the Group changes state to ON that state is immediately passed to the proxy Item by the Debounce rule. When the Group changes to OFF that state is held for five minutes before being passed to the proxy Item.
The two proxy Items, one for each person, is in turn made a member of the overall presence group along with an overrride switch.
Any time a sensor changes to ON, that ripples through the Groups immediately and applies. Only when all the sensors for a person turn OFF and remain OFF for five minutes will that person be marked as OFF. Only if all people (and the override) are OFF will the overall presence be marked as OFF. So five minutes after the last person leaves will Presence go to OFF.
The code after this point is deprecated and will be removed at some point after OH 3.2 is released.
Python
See [Deprecated] Design Pattern: Debounce which uses presence detection as an example and uses the debounce Python library to implement this such that the user need only add metadata to the Sensor Group Items.
Rules DSL
rule "Reset Presence and sensors to OFF on startup"
when
System started
then
Presence.sendCommand(OFF)
Presence_Sensors.sendCommand(OFF)
end
rule "A presence sensor updated"
when
Item Presence_Sensors changed
then
if(Presence_Timer.state == ON && Presence_Sensors.state == Presence.state) {
logInfo(logName, "Timer is running but group and proxy are the same, cancelling timer")
Presence_Timer.postUpdate(OFF)
}
else if(Presence_Sensors.state == Presence.state) {
logInfo(logName, "No timer and both group and proxy are the same, nothing to do")
return;
}
if(Presence_Sensors.state == OFF) {
logInfo(logName, "Everyone is away, setting anti-flapping timer")
Presence_Timer.sendCommand(ON)
}
else if(Presence_Sensors.state == ON) {
logInfo(logName, "Someone came home, setting presence to ON")
Presence.sendCommand(ON)
}
end
rule "Presence timer expired, no one is home"
when
Item Presence_Timer received command OFF
then
logInfo(logName, "Everyone is still away, setting presence to OFF")
Presence.sendCommand(OFF)
end
Theory of Operation
There are three Items that work together to make this work.
-
Presence_Sensors: A Group of Switches configured so if all the Switches are OFF the Group’s state is OFF and if one or more is ON the Group’s state is ON.
-
Presence_Timer: A Switch that will receive a command OFF 5 minutes after changing to ON. If it gets updated to OFF, nothing happens, effectively cancelling the timer.
-
Presence: A proxy Switch that gets set to ON immediately when Presence_Sensors changes to ON and set to OFF only if Presence_Sensors remains OFF for 5 minutes or longer.
These three Items drive two Rules. The first Rule triggers on any change to Presence_Sensors.
First we check to see if there is a Timer running (i.e. Presence_Timer.state == ON
) and whether Presence_Sensors and Presence have the same state. If they are the same (i.e. both OFF or both ON) then there is no longer a need for the Timer so we can cancel it. And since they are already the same state there is nothing else to do.
If there is no Timer and both are the same state then there is nothing at all to do so just return.
If we get to this point in the Rule we know that there is no Timer and that Presence_Sensors and Presence have are different states.
If Presence_Sensors is OFF then we know that Presence is not OFF so we need to create a Timer to turn it OFF in 5 minutes.
If Presence_Sensors is ON then we know we need to send a command ON to Presence immediately.
If there is a Timer but Presence_Sensors and Presence are different, do nothing and let the Timer take care of bringing them to the same state.