Fine tuning of wifi presence detection

Here is my presence detection. It is based on Network Health and some BT sensors which report presence of a device via MQTT. Like you I have presence for me and my wife along with a general presence. It waits five minutes before it switches the general presence after all of the other presence detection Items go OFF. I also provide an override in case I have house guests.

NOTES:

  • I redacted IP addresses
  • The phone’s IP addresses are statically assigned by the router
  • The BT detection script I use is located here: https://github.com/rkoshak/sensorReporter
  • Pay attention to the group membership because most of the Items get rolled up into a Group and rules only deal with the Groups.
  • The g<Hostname>Sensors groups are defined in another file and are used to help me detect when one of my remote sensor devices (really Raspberry Pis with stuff wired to their GPIO and a BT dongle plugged in) come back online.

#Items:

Switch Present "Someone is Present" <present> // turns off 5 minutes after everyone leaves

Group:Switch:AND(OFF,ON) gPresent     "Present group" <present>
Group:Switch:AND(OFF,ON) gRichPresent "Rich Present" <present>
Group:Switch:AND(OFF,ON) gJennPresent "Jenn Present" <present>

Switch   S_V_RichPhoneIP   "Moto X PE Network [%s]"     <network>   (gRichPresent, gPresent)                  { nh="<IP>" }
Switch   S_V_RichChimeraBT "Moto X PE BT Chimera [%s]"  <bluetooth> (gRichPresent, gPresent, gChimeraSensors) { mqtt="<[mosquitto:presence_sensors/bluetooth/chimeraRich:state:default]" }
Switch   S_V_RichGarageaBT "Moto X PE Garage [%s]"      <bluetooth> (gRichPresent, gPresent, gCerberosSensors){ mqtt="<[mosquitto:presence_sensors/bluetooth/garageRich:state:default]" }
Switch   S_V_RichHydraBT   "Moto X PE Hydra [%s]"       <bluetooth> (gRichPresent, gPresent, gHydraSensors)   { mqtt="<[mosquitto:presence_sensors/bluetooth/hydraRich:state:default]" }

Switch  S_V_JennPhoneIP    "iPhone 6p Network [%s]"     <network>   (gJennPresent, gPresent)                  { nh="<IP>" }
Switch  S_V_JennChimeraBT  "iPhone 6p BT Chimera [%s]"  <bluetooth> (gJennPresent, gPresent, gChimeraSensors) { mqtt="<[mosquitto:presence_sensors/bluetooth/chimeraJenn:state:default]" }
Switch  S_V_JennGarageBT   "iPhone 6p BT Garage [%s]"   <bluetooth> (gJennPresent, gPresent, gCerberosSensors){ mqtt="<[mosquitto:presence_sensors/bluetooth/garageJenn:state:default]" }
Switch  S_V_JennHydraBT    "iPhone 6p BT Hydra [%s]"    <bluetooth> (gJennPresent, gPresent, gHydraSensors)   { mqtt="<[mosquitto:presence_sensors/bluetooth/hydraJenn:state:default]" }

Switch S_V_PresenceOverride "Override Presence Detection [%s]" <network>

#Rules:

import org.openhab.model.script.actions.*

val String logNamePresence = "presence"
var Timer presenceTimer = null

rule "gPresent changed"
when
    Item gPresent changed
then

        if(S_V_PresenceOverride.state != ON) {
                // Someone came home
                if(gPresent.state == ON && Present.state != ON) {
                        logInfo(logNamePresence, "Someone is home")
                        if(presenceTimer != null && !presenceTimer.hasTerminated) {
                                presenceTimer.cancel
                        }
                        presenceTimer = null
                        Present.sendCommand(ON)
                }

                // everyone left
                else if(gPresent.state == OFF && Present.state != OFF) {
                        logInfo(logNamePresence, "No one is home, setting timer")
                        if(presenceTimer == null) {
                                presenceTimer = createTimer(now.plusMinutes(5), [|
                                        if(gPresent.state == OFF) {
                                                logInfo(logNamePresence, "No one is home after five minutes, setting Present to OFF")
                                                if(Present.state != OFF) Present.sendCommand(OFF)
                                        }
                                        else {
                                                logInfo(logNamePresence, "Someone came home before the five minutes were up")
                                                if(Present.state != ON) Present.sendCommand(ON)
                                        }
                                        presenceTimer = null
                                ])
                        }
                }
        }
        else {
                logInfo(logNamePresence, "Presence detection is overridden")
                Present.sendCommand(ON)
        }
end

rule "Update Present to ON when Override is turned ON"
when
        Item S_V_PresenceOverride received command ON
then
        logInfo(logNamePresence, "Overriding presence detection")
        Present.sendCommand(ON)
end

#Theory of Operation:
There is one Switch for each of the sensors that can detect the presence of me or my wife. The states of these Switches are rolled up into a Group. Similarly the states for all these Switches are rolled up into a gPresent group. If any switch reports as ON then the groups it is a member of will also report as ON. Only if all the switches go OFF will gPresent go OFF.

The main thing the rules do is add a delay of five minutes before setting the Present switch to OFF after gPresent switches to OFF. If it goes back to ON before the five minutes are up Present remains ON.

Of course, if the override switch is ON, Present remains ON and is never allowed to go OFF. (It just occurred to me that I could simplify things a lot if I add the Override switch to the gPresent Group which would eliminate the “Update Present to ON when Override is turned ON” rule and simplify the other one but then I would lose the logging statements, need to decide how much I care about that.).

In rules that care about whether or not someone is home (e.g. setting Nest to Away) it only checks the Present state. However, for things like getting an alert when everyone leaves but the door was left open the rules check the gPresent state (it does me no good to find out I left the backdoor open five minutes after I left).

2 Likes