Presence detection with location accuracy

I guess your locationAccuracy hasen’t been assigned a value.

One of my LocationAccuracy item:

Number KristofIPhone_LocationAccuracy "Location Accuracy [%.1f m]" <pin> { channel="icloud:device:e4648d7f:bd7e5916:locationAccuracy" }

And I can see the Accuracy on my sitemap…

This is wrong, a DecimalType cannot be the sum of a number and String

val DecimalType locationAccuracy = nameParts.get(0) + "_LocationAccuracy"

Put your location accuracy items in a group gAccuracy

Then do:

val locationAccuracyString = nameParts.get(0) + "_LocationAccuracy"
val locationAccuracy = gAccuracy.members.filter[ i | i.name == locationAccuracyString ].state as DecimalType
if(distance < 150 + locationAccuracy)

Thanks I’ll try that!

I get some errors like this:

2018-04-22 13:34:25.444 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'iPhone Home': 'state' is not a member of 'com.google.common.collect.Iterables$6'; line 12, column 25, length 70

I have never done this so lets ytry together:

val locationAccuracyString = nameParts.get(0) + "_LocationAccuracy"
val locationAccuracyItem = gAccuracy.members.filter[ i | i.name == locationAccuracyString ].head
val locationAccuracy = locationAccuracyItem.state as DecimalType
if(distance < 150 + locationAccuracy)

Thanks this seems to solve the issue :slight_smile: I haven’t found a better solution for this on the forum so it can be also good for anyone else. All phones sometimes loses location so comparing it with a constant number is not the best idea…
This is much better!

Thanks again!

That’s great, I wasn’t sure myself, I am going to consolidate my rules with grouping soon so this was good practice.

Below is how I ended up doing this… I am using the LastUpdate event to trigger the rule because Location gets updated before LocationAccuracy which can affect calculations of distance … I haven’t included the items or groups but I think the code is fairly readable without.

rule "Distance from home"

when
	Member of giDeviceLastUpdate received update
then
	Home_Location.state = new PointType(new DecimalType(44.925994), new DecimalType(-93.310812))
	val nameParts = triggeringItem.name.toString.split("_")
	val iDeviceName = nameParts.get(0) 

	val locationAccuracyName = nameParts.get(0) + "_LocationAccuracy"
	val locationAccuracyItem = giDeviceLocationAccuracy.members.findFirst[ i | i.name == locationAccuracyName ]
	val locationAccuracy = locationAccuracyItem.state as DecimalType

	val locationName = iDeviceName + "_Location"
	val locationItem = giDeviceLocation.members.findFirst[ i | i.name == locationName ]

	val int distance = Home_Location.distanceFrom(locationItem)

	val presenceiCloudName = iDeviceName + "_iCloud"
	val iCloudItem = gPresent.members.findFirst[ i | i.name == presenceiCloudName ]

	if (distance < 200 + locationAccuracy) {
		iCloudItem.postUpdate (ON)
 		logInfo("iCloud Testing : ","Present  "+iDeviceName)
	}
	else {
		iCloudItem.postUpdate (OFF)
		logInfo("iCloud Testing : ","Not present  "+iDeviceName)
	}
end

1 Like

Thanks, that’s good to know. I haven’t had time to dig into it, but I can clearly see that it takes some time to realize that I’m home…
I will try your method, thanks!

after experimenting over time, I have changed the rule such that if locationAccuracy < 50 I ignore the update and do not change presence.

I’m thinking about the opposite way. If the LocationAccuracy is big, it shouldn’t update the Home or Away. Because sometimes a 6km Accuracy will end in updating the switch as ‘Home’.

Why it shouldn’t update if the location accuracy is smaller than 50m? I usually get around 20m accuracy, which means it will never update the switch

Sorry, meant > rather than <… agree, only update when location is accurate :slight_smile:

Is there a way to use the location that is specified during configuration using the paperui rather than hard coding in the rules?

You mean the location which is specified in the PaperUI Regional settings?

Yes, that one!

Would you be able to share your items file? I tried copying / pasting your code in my rules but am getting errors:

2018-10-21 22:34:41.067 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'iPhone Home': An error occurred during the script execution: Couldn't invoke 'assignValueTo' for feature JvmVoid:  (eProxyURI: icloud.rules#|::0.2.0.2.0.0::0::/2)

I have groups created with the devices in there.

Group gPresent
Group giDeviceLocationAccuracy
Group giDeviceLocation

//Rich iPhone
Switch RichPhone_iCloud 			"Rich is at home"		(gPresent)
Number RichPhone_LocationAccuracy 	"Rich Location Accuracy"  	(giDeviceLocationAccuracy)	{ channel="icloud:device:3c1b5a15:4a5be5fe:locationAccuracy" }
Location RichPhone_Location 		"Rich Location"  		(giDeviceLocation)	{ channel="icloud:device:3c1b5a15:4a5be5fe:location" }

Not sure what I’m missing or doing wrong at this point.

Richard, I just in the middle of revising my items and rules around presence and the icloud. Will be a bit before I can post anything useful…

Old post, but could You share the Presence stuff? :slight_smile:

Which one? :slight_smile:

Here is my latest version, which tracks the phones location and updates the Presence Item:

val String filename = "Icloud.rules"

rule "Phones Home or Not"
when
	Member of gPhoneLastLocationUpdate changed
then
	// Get items
	val nameParts = triggeringItem.name.toString.split("_")
	val triggeringiPhoneName = nameParts.get(0) + "_Home"
	val locationAccuracyString = nameParts.get(0) + "_LocationAccuracy"
	val locationName = nameParts.get(0) + "_Location"

	val locationItem = gPhoneLocation.members.findFirst[ i | i.name == locationName ]

	// Calculate home address and phone address
	val PointType home_location = new PointType(new DecimalType(47.5274), new DecimalType(19.1126))
	val PointType phone_location = locationItem.state as PointType

	// Filter the Location Accuracy item corresponding to the phone	
	val locationAccuracyItem = gAccuracy.members.filter[ i | i.name == locationAccuracyString ].head

	// Convert it
	val locationAccuracy = locationAccuracyItem.state as DecimalType
	
	// If the location accuracy is not accurate, skip updating the switch
	if(locationAccuracy as Number > 450) {
		logInfo(filename, nameParts.get(0) + " -> " + "Location inaccurate ({} m), skipping update", locationAccuracy)
		return
	}

	// Calculate the distance from home to phone
	val int distance = phone_location.distanceFrom(home_location).intValue()
	
	// Update the triggering phone's Home item
	if(distance < 150 + locationAccuracy) {
		postUpdate(triggeringiPhoneName, "ON")
		logInfo(filename, nameParts.get(0) + " is at home." + " ->" + " Distance: " + distance + "m  " + "Location Accuracy: " + locationAccuracy + " m")
	}

	else {
		postUpdate(triggeringiPhoneName, "OFF")
		logInfo(filename, nameParts.get(0) +" is away." + " ->" + " Distance: " + distance + "m  " + "Location Accuracy: " + locationAccuracy + " m")
	}
end

1 Like