Presence detection with location accuracy

Dear Community!

I have been using this rule for detecting phones state:

rule "iPhone Home"
	Item KristofIPhone_Location changed or
	Item EdinaIPhone_Location changed or
	Item ReKaIPhone_Location changed
	val PointType home_location = new PointType(new DecimalType(47.5274), new DecimalType(19.1126))
	val PointType phone_location = triggeringItem.state as PointType
	val nameParts ="_")
	val triggeringiPhoneName = nameParts.get(0) + "_Home"
	val int distance = phone_location.distanceFrom(home_location).intValue()
	if(distance < 150) {
		postUpdate(triggeringiPhoneName, "ON")
		logInfo(nameParts.get(0), "iPhone is at home.")
	} else {
		postUpdate(triggeringiPhoneName, "OFF")
		logInfo(nameParts.get(0),  "iPhone is away.")

However it is not working well at all times. Sometimes phones loses precise location thus the rule says that the phone is not at home. (Because the precision is bigger than that constant number) I want to solve this something like including the Location Accuracy to make a dynamic radius for “Home”. Like:

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

and in the head of the if:

if(distance < 150 + locationAccuracy)

But I get some errors like this:

	2018-04-21 11:47:07.416 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'iPhone Home': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.lib.NumberExtensions.operator_plus(java.lang.Number,java.lang.Number) on instance: null

What I’m missing?


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 | == 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 '$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 | == 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"

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

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

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

	val int distance = Home_Location.distanceFrom(locationItem)

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

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

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#|::

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: