Smart Things as Device Tracker

Moving over from a Smart Things system, I have struggled a little getting reliable presence tracking (about the only thing I regret so far!). All the various methods seem to have some fatal flaw:

  • iCloud is easy to set up and gives location info but is only polled every 5 minutes, and may or may not have an update for that poll. As such it is not usable to trigger actions like switching on lights when arriving home
  • NMAP just plain didn’t work for my iDevices
  • I don’t have a supported router (I may take a look at adding EdgeOS Support at some stage)
  • OwnTracks requires an MQTT server and I have struggled getting one setup and working (I’ll keep trying)
  • Locative looks promising but as the support is currently coded it doesn’t support location info, and it will only report when a geo fence is entered or exited, meaning that a user will show as away after a restart until they leave or enter a fence

I am hopeful that the pending iPhone app will have really good presence, but until then I needed something simple and reliable. I still have my Smart Things hub setup with the presence apps hooked in so I reverse engineered the Locative support in HA and wrote a ST SmartApp that would report presence back to HA.

  • Updates when leaving home
  • Updates when arriving home
  • Forces an update every 5 minutes to initialize a restarted HA system with correct location.

I suspect there are maybe a couple of other ST users out there that may be able to use this, so here is the SmartApp source (below). I have been testing it for several days, I hope it can help someone!

In addition, one thing I found useful was the ability to arbitrarily set people home and away when I was testing my automation. I wrote a simple shell command that would do this. Copy the command below into a script called “setpresence” or similar (as below this needs locative support setup):

wget -O /dev/null "<path to ha>?api_password=<password>&device=$1&id=$2&latitude=0&longitude=0&trigger=$3" > /dev/null 2>&1

Replace <path to ha> and <password> with appropriate values then you can force someone to leave with:

setpresence <tracker_id> Home exit

and to return with:

setpresence <tracker_id> Home enter

Here is the App, all you need to do is enable locative support.

definition(
    name: "HA Presence",
    namespace: "aimc",
    author: "[email protected]",
    description: "Report ST Presence Updates to Home Assistant",
    category: "My Apps",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
)

section ("URL (No parameters)") 
{
	input "url", "text", required: true
}
section ("API Key") 
{
 	input "apikey", "text", required: true
}

section ("People") 
 {
    input "people", "capability.presenceSensor", multiple: true
 }

def installed()
{
	subscribe(people, "presence", presence)
	runEvery5Minutes(forceUpdate)
    forceUpdate()
}

def updated()
{
	subscribe(people, "presence", presence)
    runEvery5Minutes(forceUpdate)
    forceUpdate()
}

private getPerson(evt)
{
	people.find{evt.deviceId == it.id}
}

def presence(evt)
{
	// log.debug "evt.name: $evt.value"

    def person = getPerson(evt)
    def value = evt.value
    updatePresence(person, value)
}

private updatePresence(person, value)
{
	def direction = ""

	if (value == "present")
    {
		direction = "enter"
	}
    else
    {
		direction = "exit"
	}
    
    def query=
    [
    	api_password: apikey,
        device: person.displayName.replaceAll("\\s","").replaceAll("'",""),
        id: "Home",
        latitude: 0,
        longitude: 0,
        trigger: direction
    ]
    
    def params = 
    [
    	uri: url,
    	path: "/api/locative",
    	query: query
	]	

	try 
    {
    	httpGet(params) 
        { 
        	//resp ->
        	//resp.headers.each 
            //{
        	//	log.debug "${it.name} : ${it.value}"
            //
           	//}
    		//log.debug "response contentType: ${resp.contentType}"
    		//log.debug "response data: ${resp.data}"
		}
    }
    catch (e) 
    {
    	// HA always closes the connection and ST doens't like it and logas a harmless exception - remove comments for testing!
    	//log.error "something went wrong: $e"
	}
}

def forceUpdate() 
{
    // iterate over our people variable that we defined
    // in the preferences method
    
    // log.debug "Forcing Update"
    for (person in people) 
    {
    	//log.debug person
    	updatePresence(person, person.currentPresence)
    }
}
1 Like

@aimc I managed to get the MQTT method working in under an hour, so if you want any pointers please let me know