This is a very simple implementation of the ‘wasp in box’ algorithm for detecting overall presence. In home automation very often, we want the system to do certain things, but only if someone is home. Thus, this concept can almost be considered a foundation for lots of other decision making. This example is a very rudimentary implementation but I run this rule and it works in openHAB on my system and I hope others can learn from this simple example or use it for a starting point and improve it.
The Concept:
How it works is that if the wasp is in the box, sometimes we can hear him in there buzzing around. So long as the lid of the box is not opened, we can be assured the wasp is still in the box, even if he goes quiet for awhile. (he’s sleeping) But if the lid of the box is opened, we don’t know, the wasp could have flown away. But once the lid of the box is closed again, if we hear him in there buzzing around, we know the wasp is in the box again. If we don’t hear any buzzing, he must have flow away.
How does this work in helping us discern occupancy? Well, we need a door sensor on the lid of the box. Then we need a way of listen for buzzing, a motion sensor will work. When the lid of the box is opened, we listen for buzzing. If we hear buzzing (motion) once the lid is back on the box, we know the wasp is in the box. Then, until the next time the lid of the box is opened, whether we hear buzzing or not, we know the wasp is still in the box. If the lid of the box got opened and we haven’t hear any buzzing, we can only assume the wasp flew away.
Caveat:
I live in a 3rd floor flat with one entrance door. If there is more then one entry point in your home, obviously, we’ll need more sensors. I also live alone so more then one individual coming and going would also make things more complex. If you are attempting to track many people or a cat, you are on your own, try not to get hurt. (search cat flap for explanation… and laughs)
First we need some items created in an items files. If I’ve already lost you, go to the bottom of this post and dig into some of the docs and come back later. We need a contact sensor on the door (the lid of the box) and we need a motion sensor or some other way of listening for buzzing. Motion sensors can be flakey. In my case, I have a motion sensor pointed down the stairwell leading to the front door. You can neither exit or enter without tripping this motion sensor. (unless you are spiderman) There are also no windows in the direction the motion sensor is aimed or anything which could trigger a false alarm. I’ve also used persistence (with influx and grafana) to make sure things work as I hoped. But not good enough, I also use my phones presence on my wifi router, using the network binding to double check. Here we go… real physical items
Contact aeotecDoor "Aeotec Door Sensor" <door> (ghome) {channel="zwave:device:ffa81412:node4:sensor_door"}
Switch fibMoAlarm "Fibaro motion alarm" <alarm> (ghome) {channel="zwave:device:ffa81412:node2:alarm_motion"}
Switch foneIsHome "Daddys phone is home" <none> (ghome) {channel="network:pingdevice:5e529855:online"}
next we need some ‘dummy’ items (all the items can go in one file) A dummy item is an item which is not linked to any binding and simply holds information for us. (see further reading section below if you don’t get this)
we need a DateTime item to hold the last time the lid of the box (door) opened
we need a DateTime item to hold the last time we heard a buzzing sound (motion)
we need a Switch to indicate if the wasp is in the box or not
and we need a Switch item to use with the expire binding as a timer
DateTime lastBoxOpen "last time door opened" <none> (ghome)
DateTime lastBoxBuzz "last time motion deteted" <none> (ghome)
Switch WaspInBox "Wasp in Box switch" <none> (ghome)
Switch boxTimer "timer used for wasp in box" { expire="60s,command=OFF" }
We are also using a number to judge ‘confidence’ in our decision making. How ‘confident’ are we that the wasp really is in the box. We’ll get into it more in a minute but for now, understand confidence is judged by a number, zero (0) means we aren’t very sure and 100 means we are absolutely sure.
Number WaspConf "Wasp in Box confidence level" <none> (ghome)
OK… now for some rules.
first rule triggers when the lid of the box opens
// wasp in box
rule "boxOpened"
when
Item aeotecDoor changed from CLOSED to OPEN
then
var timex = new DateTimeType(now.toString)
lastBoxOpen.sendCommand(timex)
WaspConf.sendCommand(0)
boxTimer.sendCommand(ON)
WaspInBox.sendCommand(OFF)
end
A few things happen here. 1. we set the time the door opened. 2. we set the wasp confidence level to zero because the lid is open and we have no idea if the wasp is out or not. 3. we start the timer for 60 seconds. 4. we set the wasp in box switch ‘OFF’ (the wasp is out!)
next rule
rule "buzzInBox"
when
Item fibMoAlarm changed from OFF to ON
then
if (WaspInBox.state == ON) return;
var timey = new DateTimeType(now.toString)
lastBoxBuzz.sendCommand(timey)
boxTimer.sendCommand(OFF)
end
first thing we do here is check if we are wasting time. A good thing to do at the very begining of a rule is decide if we even need to run the rule. If we don’t, why waste a running thread right? So, if the wasp is in the box, abort execution of the rule and exit using the return statement. (don’t forget the semicolon) Next, record the time motion was triggered. Then, just for kicks, short circuit the timer by sending the ‘OFF’ command to the expire switch item. (why wait, we hear a buzzing)
Now a rule when the expire binding switch turns to ‘OFF’. 60 seconds have expired since the lid of the box opened (or the timer got restarted)
rule "boxTimerExpired"
when
Item boxTimer changed from ON to OFF
then
var tally = WaspConf.state as Number
if (tally > 74) return;
val openTime = new DateTime(lastBoxOpen.state.toString)
val motionTime = new DateTime(lastBoxBuzz.state.toString)
if (foneIsHome.state == ON) { tally = (tally + 20) }
if (foneIsHome.state == OFF) { tally = (tally - 20) }
if ( openTime.isBefore(motionTime) ) { tally = (tally + 60) }
if ( openTime.isAfter(motionTime) ) { tally = (tally - 5) }
if (tally >= 100){WaspConf.sendCommand(100)}
if (tally <= 0){WaspConf.sendCommand(0)}
if (tally > 0 && tally < 100){
WaspConf.sendCommand(tally)
boxTimer.sendCommand(ON)
}
end
OK… follow along and we’ll walk thru this one step at a time. First, we create a variable ‘tally’ to keep a running total of our ‘confidence’ level. We set the initial value of this running total of our confidence level to our dummy item WaspConf, which if the door just opened is set to zero. Next we check the last time the box opened and the last time we heard buzzing. We also check if the phone has logged on to the local wifi network. If my phone is on the network plus 20 or else if not minus 20. If motion has occurred since the door opened plus 60 if not minus 5. Write the value to our confidence level and restart the timer
Now a rule to react to confidence level changing
rule "waspConfChange"
when
Item WaspConf changed
then
if (WaspConf.state == 0) return;
if (WaspConf.state >= 75){ WaspInBox.sendCommand(ON)
} else { WaspInBox.sendCommand(OFF) }
end
simple, this is our threshold level. if confidence is over 75, the wasp is in the box.
One last thing, if the system restarts, things could be left in a funny state. This rule is not fully explained but it is just to set the ‘dummy’ or unbound items to something if the system restarts so the values aren’t null.
Since for instance, if the value of ‘WaspInBox’ is marked as out and motion is triggered, the system will self correct, we don’t have to worry to much about setting the values correctly, just that they are not set to null.
rule "initializeSys"
when
System started
then
// initialize wasp in box unbouund item values from null
WaspInBox.postUpdate(OFF)
WaspConf.postUpdate(0)
boxTimer.postUpdate(OFF)
lastBoxBuzz.sendCommand(new DateTimeType(now.toString))
lastBoxOpen.sendCommand(new DateTimeType(now.toString))
end
So, if everything goes to plan, when the door opens, the timers starts for 60 seconds. My phone logs on, motion short circuits the timer and… Alexa says welcome home
rule "waspCameHome"
when
Item WaspInBox changed from OFF to ON
then
alexaSpeak.sendCommand("Welcome home Andy")
end
/// end wasp in box code
or, the loop runs again. In my case, when I leave, sometime the wifi drops out at the bottom of the stairwell. Then, when I’m walking across the parking lot to the truck, it picks me up again. When I come home, sometimes it take a minute or two for the phone to log on. Obviously the ‘confidence’ levels can be adjusted. This simple example actually seems to work 100% accurately for me however. Once we have this working, we can check at the beginning of other rules like so…
// not running code... just snipe
if (WaspInBox.state == ON){
//do stuff
}
Also to consider, when your loop runs down, if there is motion but no phone, maybe an intruder? Obviously, you have to decide based on your set up, your confidence in the system reporting accurately, but this popular algorithmn works a treat even in it’s most simple form.
If you find mistakes please post or if you use this and it works or helps you do even cooler stuff, post it up!
Further reading:
Rich explains unbound items, which I call ‘dummy’ items
another rule example this one was based on
Items documentation
Expire binding documentation
extend syntax documentation