Owner presence tracking with openHAB2

If you use openHAB you will come to a point that you want to point that you control your devices at home dependant on the presence of your family, friends and yourself at home. Use cases can be:

  • Switch of the lights when nobody is at home
  • Get notification if a door or window opens or is open and your are not at home.
  • Cool down the heating when nobody is at home
  • and, and, and…

You can realize this in different ways. I did it for a longer time with the TR064 binding and my FritzBox by checking if my phone is in the WIFI or not. Over the time I must realize that the newer Android versions don’t keep the WIFI connection permanently to save battery. I started to implement time-out handling but it was not reliable for me any more.

So I decided to switch to GPS tracking. This allows also other interesting features, like creating of your own privately stored daily stored GPS Tracks to tag photos or privately stored and automatically created time sheets when you enter or leave your work to track your working hours. Python scripts for that you can find on my Github account.

Here now one example how you can realize Presence Tracking by using the GPSTracker binding the Android or iOS app OwnTracks. Note that your openHAB instance must be connected to myopenhab.org  with cloud connector to do to this.

Here the steps for setup presence tracking with GPS Tracker:

Install the GPSTracker binding over the Paper UI.

Install GPSTracker on your mobile device.

Create a new *. things file in your configuration and add a gps tracker thing:

Thing gpstracker:tracker:ol "oliver" [trackerId="ol"] {
Channels:

Type regionDistance : homeDistance "Distance from Home" [
    regionName="Home",
    regionCenterLocation="XX.XXXXXXXX,XX.XXXXXXXX", //your home location
    regionRadius=30,
    accuracyThreshold=30
    ]
Type regionDistance : workDistance "Distance from Work" [
    regionName="Work",
    regionCenterLocation="XX.XXXXXXXX,XX.XXXXXXXX", // work location
    regionRadius=200,
    accuracyThreshold=30
    ]
}

Adapt the regionCenterLocation to your home location and add optional other locations which you want to track. Like your working place.

In your OwnTracks app must be an HTTP connection configured to your
myopenhab.org account and the tracker id must be match to the two characters trackerId configured in the thing conifguration! All is decribed in the GPSTracker binding.

Now you need to add an *.items file with the items that you need for tracking and connect them to your just created GPS tracker:

Location	locationOliver	"Olivers Location [%2$s°N %3$s°E %1$sm]" {channel="gpstracker:tracker:ol:lastLocation"}
DateTime lastSeenOliver	"Last seen Oliver"	{channel="gpstracker:tracker:ol:lastReport"}
Number batteryOliver	"Battery level Oliver"	{channel="gpstracker:tracker:ol:batteryLevel"}
Number:Length accuracyOliver	"GPS Accuracy Oliver [%d m]" {channel="gpstracker:tracker:ol:gpsAccuracy"}
Number:Length distanceHomeOliver "Distance from Home Oliver [%d m]"	{channel="gpstracker:tracker:ol:homeDistance"}
Number:Length distanceWorkOliver "Distance from Work Oliver [%d m]"	{channel="gpstracker:tracker:ol:workDistance"}

Switch OliverAtHome "Oliver at home"
Switch OliverAtWork "Oliver at work"

Create virtual switches „PersonAtX“ which you will use in your rules to switch them ON and OFF based on your current location.

Now you should be able to create the following *.sitemap file:

sitemap gps label="GPS Tracker" {
    Frame label="Oliver" {
        Text item=batteryOliver icon="battery"
        Text item=distanceHomeOliver
        Text item=distanceWorkOliver
        Switch item=OliverAtHome
        Switch item=OliverAtWork
        Text item=lastSeenOliver icon="time"
        Text item=accuracyOliver
        Text item=locationOliver icon="motion"
        Mapview item=locationOliver height=10
    }
}

And see a sitemap on your device with your location:

sitemap in openHAB Android app

Now we need to write a rule which is triggered by any position change of your phone and checks it is close enough to the specific location to switch on your „PersonAtX“ switch. We can do a very simple variant for the work location, because you need only need to log when you are close and when you leave. The switch is set to ON when your position is closer than 20 meters from work and switched to OFF when you are more than 150 Meters away.

val Number DistanceArrived = 20
val Number DistanceLeft = 150
val Number AccuracyThreshold = 200

/* Oliver at work */
rule "Oliver at work"
when
Item distanceWorkOliver received update
then
	var Number distance = (distanceWorkOliver.state as QuantityType<Number>).doubleValue
	var Number accuracy = (accuracyOliver.state as QuantityType<Number>).doubleValue
	
if (accuracy < AccuracyThreshold) { // do only something if the accuracy is high enough
	if ((distance < DistanceArrived) && (OliverAtWork.state == OFF)) {
		sendCommand(OliverAtWork,ON)
	}
	else if ((OliverAtWork.state == ON) && (distance > DistanceLeft)) {
		sendCommand(OliverAtWork,OFF)

	}
}
end

Note that your phone position will loose accuracy when it goes to battery saving mode. That means it is recommended to consider a accuracy threshold and use only positions with higher accuracy in your script for evaluation.

For you presence at home you may want to implement a time-out handling that your lights are not switched off when you went shortly outside. You can do it with an extended rule.


//
// Define globa states based on rules

val Number DistanceArrived = 20
val Number DistanceLeft = 150
val DistanceArrivedTimeout = 60
val DistanceLeftTimeout = 240
val Number AccuracyThreshold = 200
var Boolean TimerRunning=false

/* Oliver home */
rule "Oliver Home"
when
Item distanceHomeOliver received update
then
	var Number distance = (distanceHomeOliver.state as QuantityType<Number>).doubleValue
	var Number accuracy = (accuracyOliver.state as QuantityType<Number>).doubleValue

	if (accuracy < AccuracyThreshold) { // do only something if the accuracy is high enough
		if ((distance < DistanceArrived) && (OliverAtHome.state == OFF)) {
			if( TimerRunning == false) {
				TimerRunning = true
				createTimer(now.plusSeconds(DistanceArrivedTimeout)) [|
					var Number distanceAfterTimeout = (distanceHomeOliver.state as QuantityType<Number>).doubleValue
					if((distanceAfterTimeout < DistanceArrived) && (OliverAtHome.state == OFF)) {
						sendCommand(OliverAtHome,ON)
					}
					TimerRunning=false
				]
			}
		}
		else if ((OliverAtHome.state == ON) && (distance > DistanceLeft)) {
			if( TimerRunning == false) {
				TimerRunning = true
				createTimer(now.plusSeconds(DistanceLeftTimeout)) [|
					var Number distanceAfterTimeout = (distanceHomeOliver.state as QuantityType<Number>).doubleValue
					if((distanceAfterTimeout > DistanceLeft) && (OliverAtHome.state == ON)) {
						sendCommand(OliverAtHome,OFF)
					}
					TimerRunning=false
				]
			}
		}
	}
end

Note that this script will be triggered with every position change even if a time-out is running. To prevent many timers running in parallel you can use a boolean like it is shown here.

Now you can write rules based on your switches to control devices at your home.