[RELEASE] Life360 with States - Track all attributes with app and driver. Also supports RM4 and Dashboards!

Say what? What headaches!!!!! :rofl: :man_shrugging: :scream:

back in the day I used the webcore presence app and it was the ONLY one that was reliable for me.... but oh my is presence a constant problem it seems with all platforms.

1 Like

yes and then name your "home" location whatever shows up in "address1" and at least it's a temporary fix.... you don't need the custom code to do that though. Just go into the Life360 device for the user you want and look at events. You'll see it in there too.

Thanks for the suggestion. Sure enough, every few minutes the address1 value changes from "Home" to the name of our street without a street number (huh?), while the name value remains "Home". About one second later, address1 reverts. Guess I could add a delay in my presence combiner to debounce, but I sure would like to figure out a way to solve this, rather than bandaid it. Is the only way waiting and hoping Life360 sorts it out?

Edit: Just for giggles, I opened a support ticket with Life360. Not expecting much.

Maybe if more do it would help!

1 Like

Apart from the suggested quick fix in the app (which should work given you have confirmed the symptoms), I was wondering if the app could change to using the location name instead of address1 for everything. Not sure of the implications.

And then theres my more radical alternative of not using either of those fields - and doing all location detection in the hubitat app (using GPS coordinates) - which I have got working nicely, but I'm not in a finished state.

Weird, I tried the quick fix and it didn’t seem to change anything. Perhaps I should try again.

I did a change to the location tracker driver that only looks at address1 if your distance is outside of the geofence radius. It has been solid as well.

That seems like a solid idea...care to share?

replace these 2 functions in the location tracker driver

private extraInfo
def generatePresenceEvent

code
def generatePresenceEvent(boolean present, homeDistance) {
if(logEnable) log.debug "In generatePresenceEvent - present: $present - homeDistance: $homeDistance"
def linkText = getLinkText(device)
def descriptionText = formatDescriptionText(linkText, present)
def handlerName = getState(present)

CurrentAddress = device.currentValue('address1')

if(!present){
    if(CurrentAddress == "home" || CurrentAddress == "Home") {
        present = true
    }
}

def presence = formatValue(present)
def results = [
	name: "presence",
	value: presence,
	linkText: linkText,
	descriptionText: descriptionText,
	handlerName: handlerName,
]
if(logEnable) log.debug "In generatePresenceEvent - Generating Event: ${results}"
sendEvent (results)

if(units == "Kilometers" || units == null || units == ""){
    def statusDistance = homeDistance / 1000
    def status = sprintf("%.2f", statusDistance.toDouble().round(2)) + " km from: Home"
    if(status != device.currentValue('status')){
        sendEvent( name: "status", value: status )
        state.update = true
    }
} else {
    def statusDistance = (homeDistance / 1000) / 1.609344 
    def status = sprintf("%.2f", statusDistance.toDouble().round(2)) + " Miles from: Home"
    if(status != device.currentValue('status')){
        sendEvent( name: "status", value: status )
        state.update = true
    }
    state.status = status
}

def km = sprintf("%.2f", homeDistance / 1000)
if(km.toDouble().round(2) != device.currentValue('distanceKm')){
    sendEvent( name: "distanceKm", value: km.toDouble().round(2) )
    state.update = true
}

def miles = sprintf("%.2f", (homeDistance / 1000) / 1.609344)
if(miles.toDouble().round(2) != device.currentValue('distanceMiles')){    
    sendEvent( name: "distanceMiles", value: miles.toDouble().round(2) )
    state.update = true
}

if(homeDistance.toDouble().round(2) != device.currentValue('distanceMetric')){
    sendEvent( name: "distanceMetric", value: homeDistance.toDouble().round(2) )
    state.update = true
}

if(state.update == true){
    sendEvent( name: "lastLocationUpdate", value: "Last location update on:\r\n${formatLocalTime("MM/dd/yyyy @ h:mm:ss a")}" )
    state.update = false
}

sendStatusTile1()

}

// **** Life360 ****
private extraInfo(address1,address2,battery,charge,endTimestamp,inTransit,isDriving,latitude,longitude,since,speedMetric,speedMiles,speedKm,wifiState,xplaces,avatar,avatarHtml,lastUpdated) {
if(logEnable) log.debug "extrainfo = Address 1 = $address1 | Address 2 = $address2 | Battery = $battery | Charging = $charge | Last Checkin = $endTimestamp | Moving = $inTransit | Driving = $isDriving | Latitude = $latitude | Longitude = $longitude | Since = $since | Speedmeters = $speedMetric | SpeedMPH = $speedMiles | SpeedKPH = $speedKm | Wifi = $wifiState"

newAddress = address1
oldAddress = device.currentValue('address1')
log.debug "oldAddress = $oldAddress | newAddress = $newAddress" 
if(newAddress != oldAddress) {
    sendEvent(name: "address1prev", value: oldAddress)
    sendEvent(name: "address1", value: newAddress)
    sendEvent(name: "since", value: since)

// if(newAddress == "home" || newAddress == "Home") {
// log.debug "-------------------THIS ONE 5"
// sendEvent(name: "presence", value: "present", isStateChange: true)
// } else {
// log.debug "-------------------THIS ONE 6"
// sendEvent(name: "presence", value: "not present", isStateChange: true)
// }
}

prevAddress = device.currentValue('address1prev')
if(prevAddress == null) {
    sendEvent(name: "address1prev", value: "Lost")
}

if(battery != device.currentValue('battery')) { sendEvent(name: "battery", value: battery) }    
if(charge != device.currentValue('charge')) { sendEvent(name: "charge", value: charge) }

if(inTransit != device.currentValue('inTransit')) { sendEvent(name: "inTransit", value: inTransit) }

def curDriving = device.currentValue('isDriving') 
if(isDriving != device.currentValue('isDriving')) { sendEvent(name: "isDriving", value: isDriving) }

def curlat = device.currentValue('latitude').toString()
latitude = latitude.toString()
if(latitude != curlat) { sendEvent(name: "latitude", value: latitude) }

def curlong = device.currentValue('longitude').toString()
longitude = longitude.toString()
if(longitude != curlong) { sendEvent(name: "longitude", value: longitude) }

if(speedMetric != device.currentValue('speedMetric')) { sendEvent(name: "speedMetric", value: speedMetric) }

if(speedMiles != device.currentValue('speedMiles')) { sendEvent(name: "speedMiles", value: speedMiles) }

if(speedKm != device.currentValue('speedKm')) { sendEvent(name: "speedKm", value: speedKm) }

if(wifiState != device.currentValue('wifiState')) { sendEvent(name: "wifiState", value: wifiState) }

setBattery(battery.toInteger(), charge.toBoolean(), charge.toString())

sendEvent(name: "savedPlaces", value: xplaces)

sendEvent(name: "avatar", value: avatar)

sendEvent(name: "avatarHtml", value: avatarHtml)

sendEvent(name: "lastUpdated", value: lastUpdated.format("MM-dd - h:mm:ss a"))

sendStatusTile1()

}

Thanks @napalmcsr. No luck here I guess, still spouting off every few minutes. Nobody is moving around, but it keeps saying we are. Crazy.

Thanks.

Spouting constantly over here too

I tried... is it showing your distance being outside of your radius?

address change

but within distance so I didn't get the presence change

I don't think I had to change anything in the app code...

Make sure you are using Brian's latest app and driver code with my additional code fix. Mine works great.. Remember, the problem is address1 changes to an address when it should continue to take the place name value when inside the geofence. My code fix overrides this problem by making use of the name attribute coming from life360 api.. The name attribute keeps the place name value when address1 changes.. Its a work around...

Although the changes didn't make a difference for me, I felt it might for others and also wanted to keep one code base. So I uploaded the changes.

app:
2.0.8 - 09/26/20 - Testing Fix by @jpoeppelman1

driver:
1.0.7 - 10/01/20 - Added code adjustments from @napalmcsr

Thanks

2 Likes

New version on GitHub. With this version I took a different approach and looked straight at the GPS Lat/Long to see if someone has moved or not. Regardless of what address1 was saying. There is a new input in each device, Max GPS Jump. This will give you a cushion to determine if the person has actually moved or not.

app:
2.0.9 - 10/08/20 - Attempting fix for jumping GPS

driver:
1.0.8 - 10/08/20 - Add new input, Max GPS Jump - If you are getting a lot of false readings, raise this value

1 Like

I can't get the built in life360 app to work, it sees my circles (2) and allows me to choose users from one of the them, but not the right one. The person dropdown simply does nothing. So I figured I'd try your app, when I click the correct circle, it displays an error and this in the log:

groovyx.net.http.HttpResponseException: Bad Request on line 237 (listCircles)

Thoughts on why this would happen? Thanks!

Edit: Looks like the built in app throws this error: getMembers Error:[errorMessage:Unknown issue type: lp, url:/v3/circles/aab9b006-82ed-44f5-a398-ea4473bef2aa/members.json, status:400]

Looks like something is wrong with your Life360 account. :man_shrugging:

I recreated the entire circle and it's working now, thank you!

1 Like

How is this working for everyone?? I haven't had a bad reading in 3 days! Great to be able to use this again. :grin:

1 Like

I have had it up for about nine hours now. We have only had one person leave, but no false departures/arrivals so far. Great Job. Thanks.

1 Like