Please see Design Pattern: What is a Design Pattern and How Do I Use Them for an explanation of what a DP is and how to use them.
Problem Statement
There are often times where one has a number of sensors of different types which aggregate up to a single status value. The most common of these is presence detection, where one has multiple sensors (PIR, Bluetooth, Network, etc.) any one of which can indicate someone is home (or at least their device is home). Another use for this is rolling up the online status of a bunch of services.
Concept
This Design Pattern works best when one can represent the state of all relevant sensors as a Switch or a Number. These switches can be combined and aggregated into Groups and the state of the Group then represents the final state (e.g. whether someone is home).
Simple Example
In this example there are two people who are detected by the positions of their phone. Each phone has multiple ways to detect its presence. The specific bindings/sensors used is irrelevant for this approach so long as the state can be represented as a Switch.
Items
Group:Switch:AND(OFF,ON) gPresent "Presence [%s]"
Switch Sensor1 (gPresent )
Switch Sensor2 (gPresent )
Switch Sensor3 (gPresent )
There are no Rules.
Theory of Operation
The Group definition above means that if all members of the Group are OFF, set the Group’s state to OFF, otherwise set the Group’s state to ON. In other words, so long as one Switch is ON, gPresence will be ON. Therefore you can use gPresence in your Rules and Sitemap to determine if anyone is home.
Complicated Example
To continue this presence detection example, let’s add a anti-flapping (i.e. rapid changing of the state when one is on the edge of detection or taking a short trip to the mailbox or the like) and the ability to detect whether a specific person is home. Lets also add the ability to override the presence detection to always think someone is home even if all the sensors are OFF.
Items
Group:Number:SUM gPresent // counts the number of sensors reporting ON
Switch vPresent "Presence [MAP(en.map):%s]" <presence> // Item to represent presence
Switch tPresent { expire="5m,command=OFF" } // flapping timer
Switch aPresenceOverride "Override Presence Detection" <presence> (gPresent) // presence override
Group:Switch:AND(OFF,ON) gPersonOnePresent "Person One is Present [%s]" <present> // represents the presence of Person One
Group:Switch:AND(OFF,ON) gPersonTwoPresent "Person Two is Present [%s]" <present> // represents the presence of Person Two
Switch Override_Presence "Override Presence Detection" (gPresent) // Set to ON to make Presence alway be true
Switch PersonOneSensorOne (gPresent, gPersonOnePresent)
Switch PersonOneSensorTwo (gPresent, gPersonOnePresent)
Switch PersonOneSensorThree (gPresent, gPersonOnePresent)
Switch PersonTwoSensorOne (gPresent, gPersonTwoPresent)
Switch PersonTwoSensorTwo (gPresent, gPersonTwoPresent)
Switch PersonTwoSensorThree (gPresent, gPersonTwoPresent)
Rules
val logName = "presence"
rule "Reset vPresent to OFF on startup"
when
System started
then
vPresent.sendCommand(OFF)
gPresent.members.forEach[ SwitchItem s | s.sendCommand(OFF)]
end
rule "A presence sensor updated"
when
Item gPresent changed
then
logDebug(logName, "gPresent changed to " + gPresent.state.toString)
if(gPresent.state > 0 && (vPresent.state != ON || tPresent.state == ON)) {
logDebug(logName, "Someone came home")
if(tPresent.state != OFF) tPresent.postUpdate(OFF) // cancel the timer
if(vPresent.state != ON) vPresent.sendCommand(ON)
}
else if(gPresent.state == 0 && vPresent.state != OFF && tPresent.state != ON) {
logDebug(logName, "Everyone is away, setting timer")
tPresent.sendCommand(ON) // set timer to turn off vPresent
}
end
rule "Present timer expired, no one is home"
when
Item tPresent received command OFF
then
if(gPresent.state == 0) {
logInfo(logName, "Everyone is still away after the timer expired, setting house to away")
vPresent.sendCommand(OFF)
}
else {
logWarn(logName, "Presence Timer expired but gPresent is " + gPresent.state.toString)
}
end
Theory of Operation
- Override: By making the Override Switch a member of gPresent, one can simply turn off presence detection by setting the Override Switch to ON. This will force gPresentto always be ON regardless of what the rest of the sensors say.
- By adding sensors for specific people to a separate Group, one can detect when certain people (or at least their device) is present.
- The vPresent Switch represents the anti-flapped presence state. It will only turn OFF five minutes after all the other sensors turn OFF. Use this Switch to determine whether everyone is really gone. However, if you want a warning or to do something immediately when everyone leaves (e.g. reminder that a door is open) use the state of gPresent instead.
- Adding additional sensors or changing sensors used is a simple matter of adding them to the gPresent Group.
- These Rules use Design Pattern: Expire Binding Based Timers
Related Design Patterns
Design Pattern | How It’s Used |
---|---|
Design Pattern: Expire Binding Based Timers | Antiflapping Timer |
Design Pattern: Motion Sensor Timer | This is a specific implementation of Motion Sensor Timer |
Design Pattern: Proxy Item | vPresence is a Proxy Item |
Design Pattern: Separation of Behaviors | This DP is a specific implementation of Separation of Behaviors |