Page 5 of 14

Find My iPhone implementation in LUA script

Posted: Friday 16 September 2016 19:23
by mvzut
Just checking, since I think there are a handful of people in the meantime that seem to have this running. What are your experiences? Does it drain the batteries? I personally feel there's no huge impact. Difficult to say of course, since one day you use your phone more intensive than the other. We should maybe check the percentage drop during one night after being fully charged, with and without the script running.

However, I am experiencing one annoying aspect. Once in a while, Apple suddenly thinks I am up to 1 km away from my house, usually only for one measurement interval, then I'm back home. Do others see this as well?

I could set a very large "home perimeter" but then it will think I'm still at home when I'm e.g. playing sports in the club nearby. I'm now thinking of combining it somehow with my previous presence awareness solution, which checked if the phones are seen by my router. Not really sure how to combine them exactly though.
Another solution could be to poll the phones more often and take the average position, or throw out "outliers".

Re: Find My iPhone implementation in LUA script

Posted: Friday 16 September 2016 20:10
by Egregius
Well, I removed after one day.
Nice toy, but nothing more than that in my opinion.
Even a one minute interval is way to slow to use it as home/away switch. I'll stick to my manual switch, at least I'm sure when it's pressed then.

Re: Find My iPhone implementation in LUA script

Posted: Saturday 17 September 2016 15:28
by deejc
I'm noticing pretty reduced battery life on my old 5s so I'll try using the home app and see its this or just the phone it maybe partly the ios10 upgrade as well ?


Sent from my iPhone using Tapatalk

Find My iPhone implementation in LUA script

Posted: Saturday 17 September 2016 18:57
by mvzut
lukev wrote:Great script, works like a charm!

What lines do I have to remove when I always want the text switch to be updated?
Great to hear it's working for you! Change

Code: Select all

if math.abs(prev_distance - distance) > radius then
  table.insert(commandArray,{['UpdateDevice'] = otherdevices_idx['Position ' .. user] .. '|0|' .. position_text})
end
into

Code: Select all

table.insert(commandArray,{['UpdateDevice'] = otherdevices_idx['Position ' .. user] .. '|0|' .. position_text})
Or just replace "radius" in the original three lines mentioned above with 0, or with a very small number (e.g. 0.05 = 50 meter) if you don't want to be flooded by small position changes.

Re: Find My iPhone implementation in LUA script

Posted: Monday 19 September 2016 23:57
by Maartenkr
Hello,

I have a question i have a problem whit the script i get the error:

2016-09-19 20:15:02.776 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_checkphones.lua: /home/pi/domoticz/scripts/lua/script_time_checkphones.lua:40: attempt to concatenate global 'stage2server' (a nil value)

Do you now what the problem is?

Re: Find My iPhone implementation in LUA script

Posted: Tuesday 20 September 2016 7:16
by mvzut
Maartenkr wrote:Hello,

I have a question i have a problem whit the script i get the error:

2016-09-19 20:15:02.776 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_checkphones.lua: /home/pi/domoticz/scripts/lua/script_time_checkphones.lua:40: attempt to concatenate global 'stage2server' (a nil value)

Do you now what the problem is?
Apparently the Apple server doesn't recognize your account in the first API call. Are you sure you have filled in your credentials right? No accidental spaces in them, exact same use of capitals, etc? Do you happen to have exotic characters in your password?

Re: Find My iPhone implementation in LUA script

Posted: Tuesday 20 September 2016 17:59
by Maartenkr
thanks
The message is now gone. Had the two others users there but use only 1.
Only now I have no details of where I am. and is also in the error log nothing

Find My iPhone implementation in LUA script

Posted: Wednesday 21 September 2016 8:59
by mvzut
Maartenkr wrote:thanks
The message is now gone. Had the two others users there but use only 1.
Only now I have no details of where I am. and is also in the error log nothing
Can you put some print commands in the script? You can start with removing the "--" before the print command that's already in the script. What do you see in the log? You can speed things up by temporarily changing the interval to 1 minute.

If you do see information on the iPhone's position in the log but not in the devices, this probably means that you didn't name the switch & text devices correctly.

Re: Find My iPhone implementation in LUA script

Posted: Wednesday 21 September 2016 12:43
by Maartenkr
I see nothing in the log

This is the code i use:

Code: Select all

-- Script to check the location of multiple iPhones every X minutes,
-- test if they are "home" and represent this using virtual switches

commandArray = {}
-- polling interval in minutes (1-59), setting this too low may drain the phones' batteries
interval = 1
local m = os.date('%M')
if (m % interval == 0) then

  json = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")()

  -- Array of users to be checked
  users = {
            Maarten = {username = 'info@kromhout-*****' ; password = '*****' ; devicename = 'Maarten'};
                      }
  -- The latitude and longitude of your house (use Google Maps or similar to find this)
  homelongitude = 51.873552
  homelatitude = 4.149446
  -- Radius (in km) which will be used to determine if a device is at home
  radius = 0.5

  function address(longitude, latitude)
    command = "curl -s https://maps.googleapis.com/maps/api/geocode/json?latlng=" .. latitude .. "," .. longitude .. "&sensor=false"
    local handle = io.popen(command)
    local result = handle:read("*a")
    handle:close()
    output = json:decode(result)
    return output.results[1].formatted_address
  end

  for user,credentials in pairs(users) do
    stage1command = "curl -s -X POST -D - -o /dev/null -L -u '" .. credentials.username .. ":" .. credentials.password .. "' -H 'Content-Type: application/json; charset=utf-8' -H 'X-Apple-Find-Api-Ver: 2.0' -H 'X-Apple-Authscheme: UserIdGuest' -H 'X-Apple-Realm-Support: 1.0' -H 'User-agent: Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)' -H 'X-Client-Name: iPad' -H 'X-Client-UUID: 0cf3dc501ff812adb0b202baed4f37274b210853' -H 'Accept-Language: en-us' -H 'Connection: keep-alive' https://fmipmobile.icloud.com/fmipservice/device/" .. credentials.username .."/initClient"
    local handle = io.popen(stage1command)
    local result = handle:read("*a")
    handle:close()

    stage2server = string.match(result, "X%-Apple%-MMe%-Host%:%s(.*%.icloud%.com)")
    stage2command = "curl -s -X POST -L -u '" .. credentials.username .. ":" .. credentials.password .. "' -H 'Content-Type: application/json; charset=utf-8' -H 'X-Apple-Find-Api-Ver: 2.0' -H 'X-Apple-Authscheme: UserIdGuest' -H 'X-Apple-Realm-Support: 1.0' -H 'User-agent: Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)' -H 'X-Client-Name: iPad' -H 'X-Client-UUID: 0cf3dc501ff812adb0b202baed4f37274b210853' -H 'Accept-Language: en-us' -H 'Connection: keep-alive' https://" .. stage2server .. "/fmipservice/device/" .. credentials.username .."/initClient"
    local handle = io.popen(stage2command)
    local result = handle:read("*a")
    handle:close()

    output = json:decode(result)
    for key,value in pairs(output.content) do
      if value.name == credentials.devicename then
        lon = value.location.longitude
        lat = value.location.latitude
        distance = math.sqrt(((lon - homelongitude) * 111.320 * math.cos(math.rad(lat)))^2 + ((lat - homelatitude) * 110.547)^2)  -- approximation
        position = address(lon,lat)
        position_text = string.gsub(position, ', Netherlands', '') .. ' (' .. (math.floor(distance*10+0.5)/10) .. ' km)'
        prev_distance_str = string.match(otherdevices['Position ' .. user], '%(.*%)') or '(1000 km)'
		prev_distance = tonumber(string.sub(prev_distance_str, 2,-5))
        -- update text device, but only if postion has changed more than defined in "radius" to reduce log size
        if math.abs(prev_distance - distance) > radius then  
          table.insert(commandArray,{['UpdateDevice'] = otherdevices_idx['Position ' .. user] .. '|0|' .. position_text})
        end
        print('iPhone ' .. user .. ': ' .. math.floor(distance*100+0.5)/100 .. ' km from home')
        if distance < radius  then
          if otherdevices['iPhone ' .. user] == 'Off' then
            commandArray['iPhone ' .. user] = 'On'
            table.insert(commandArray, {['SendNotification'] = 'Presence update#' .. user .. ' came home'})
          end
        else
          if otherdevices['iPhone ' .. user] == 'On' then
            commandArray['iPhone ' .. user] = 'Off'
            table.insert(commandArray, {['SendNotification'] = 'Presence update#' .. user .. ' left home'})
          end
        end
      end
    end
  end

end

return commandArray

Re: Find My iPhone implementation in LUA script

Posted: Wednesday 21 September 2016 14:23
by mvzut
Since apparently it doesn't execute the print command at all, this must mean that "if value.name == credentials.devicename" is never true. Is your iPhone really called 'Maarten", not "iPhone van Maarten" or something? You can check this in the iPhone's configuration screen under General > Info.

Re: Find My iPhone implementation in LUA script

Posted: Wednesday 21 September 2016 19:34
by Nautilus
Hmm, first strange issue with this approach of presence detection. On two occasions today, my location has been identified as my wife's location. I assume the phone (nor the "find my iPhone" service) cannot "accidentally" do this so can it be the script in some way - has anyone seen this before? Credentials and other info is different between these two users so that shouldn't cause any issues. I'm the first user in the table and for some reason the second user's location is applied to my switch.

edit: I think this is solved. I messed up a bit with my conditions so that there was possibility that "position_text" variable did not update. I guess it used then the value from the other user...:)

Re: Find My iPhone implementation in LUA script

Posted: Friday 23 September 2016 17:53
by pepijn
lukev wrote:Oke, now I have something very strange.... I'm monitoring 2 iPhones with this script. Both used to work fine. Now one of the phones keeps on switching: coming home - leaving home - coming home - etc.... The 'leave' address is my work address. Of course I'm not there every other five minutes. It also updates the text device with the address in Boxtel. 5 minutes later it updates back to the address in Goirle.

The printout seems ok, it reads my geo-location. But in the last sentence, it switches back to the old adress... How is this possible?
I've added the printout. Made some adjustments for privacy reasons ;-)

Code: Select all

PHONE WIFE
2016-09-23 14:00:03.171 LUA: 4.xxxxxxxx
2016-09-23 14:00:03.171 LUA: 51.xxxxxxx
2016-09-23 14:00:03.171 LUA: 38.555599388868
2016-09-23 14:00:03.562 LUA: xxxxxweg 7, XXXX XX Roosendaal, Netherlands
2016-09-23 14:00:03.563 LUA: iPhone Wife: 38.56 km from home

MY PHONE
2016-09-23 14:00:05.420 LUA: 5.xxxxxx
2016-09-23 14:00:05.420 LUA: 51.xxxxxxxxx
2016-09-23 14:00:05.420 LUA: 0.015057582198338
2016-09-23 14:00:05.764 LUA: xxxxxstraat 135, XXXX XX Goirle, Netherlands
2016-09-23 14:00:05.765 LUA: iPhone Luke: 0.02 km from home		===== so here it says I'm home, which is correct!	

MY PHONE AGAIN?!?
2016-09-23 14:00:05.765 LUA: 5.xxxxxx
2016-09-23 14:00:05.765 LUA: 51.xxxxx
2016-09-23 14:00:05.765 LUA: 20.065109746031
2016-09-23 14:00:06.212 LUA:xxxx straat, XXXX Boxtel, Netherlands
2016-09-23 14:00:06.212 LUA: iPhone Luke: 20.07 km from home      ======= so here it says I'm at work, which is not!
I think this is location based, my phone has the same behavior when I am at home in Goirle. My wifes phone works fine.

Find My iPhone implementation in LUA script

Posted: Saturday 24 September 2016 0:36
by mvzut
I think I have something similar, although not as extreme. My phone is regularly thought to be at the highway about 1 km away from my house, just for the duration of one polling cycle.
Could it be that this is caused by the way the iPhone checks its location? Here's my theory:

I know a combination of technologies is used to it determine a phone's position, not only GPS but also the WiFi access points in the neighborhood. GPS can take a minute or so to get a good fix, so WiFi triangulation is often used to get a decent enough first estimation. I think Find My iPhone probably limits the time the phones can take to determine their positions. Sometimes this time may be too short to get a (good) GPS fix, so it will use the WiFi localisation technique.
WiFi localisation can be surprisingly accurate (try locate yourself in Google Maps on a tablet or laptop without GPS, it usually knows your location pretty well). But it can sometimes also be way off. The strangest thing I ever experienced in this respect was when I got an old router from a friend, which I installed as an extra access point. In the first weeks, my telephone sometimes thought it was in the town where my friend lives, which is 150 km away!

So: my estimation is that the weird behavior you are seeing is not caused by my script (don't know how it could), but an effect of the phone's localisation which can be inaccurate at times, especially when the service demands a quick answer from the phone. In normal use this is not a big problem, when you see a strange/old address you just hit refresh and the location is usually ok the second time. But the script doesn't do that, it assumes every reading is correct. What we could do is that we change the script in such a way that it polls twice directly after each other (with one minute in between) and then doesn't poll for the next 10 minutes or so to limit battery drain. I need to think about an elegant way to implement that.

What do you think?

Re: Find My iPhone implementation in LUA script

Posted: Saturday 24 September 2016 1:09
by Nautilus
Maybe something like storing the distance to a variable and in case the "at home" switch - based on the location - would need to turn "off" then in this case the location would be checked again and if it is still giving the "off" location, only then really turn the switch "off". Just polling twice in one minute and then taking a 10 minute break would not make much difference as either of the polls could be giving the "false negative". As the most important aspect is probably to know whether someone is at home or not - and I guess very seldom it goes the other way around (one is located at somewhere else but iPhone thinks you are at home) - I'd stick to checking whether the user has really left home. And this is maybe then something to be verified with the double check.

In my case I put the main script behind a switch ("Update Location") and then I control how often it is switched on with a time based script and additionally with certain PIR sensors and ping calls (to quickly notice if someone arrives home). But this is all only for detecting the arrival...

Re: Find My iPhone implementation in LUA script

Posted: Monday 26 September 2016 22:54
by Nautilus
lukev wrote:Pilot is pretty flawless when it comes to geonfencing.
I guess this depends on certain things (e.g. how Domoticz is opened up for remote connections?)... For me Pilot was very unreliable, but then again using "find my iPhone" has not failed yet (except for the few mistakes I made myself when modifying the script). Although it is not as fast to react (depends on polling frequency) but something I'll try to improve (so far using PIR's and ping to trigger the update - maybe I'll try the Pilot geofence once more but this time also just to trigger the "find my iPhone" -update)...

Re: Find My iPhone implementation in LUA script

Posted: Wednesday 28 September 2016 8:44
by MarceldeJongNL
I implemented this script, and I store my coordinates in a custom Text sensor.
In my Waze script (viewtopic.php?f=23&t=7777) I use these coordinates to calculate the travel time from my current location to home and work. Now I can easely see how long my expected travel time will be.
Screen Shot 2016-09-28 at 08.43.24.png
Screen Shot 2016-09-28 at 08.43.24.png (98.59 KiB) Viewed 3705 times

Re: Find My iPhone implementation in LUA script

Posted: Sunday 09 October 2016 16:05
by patoo77
Nice work mate, always love to see what is being done using location positioning :)
The only downside I would see is huge battery drain, since polling for FindMyiPhone every 5 minute has to be huge in terms of battery ressources. Have you monitored how much battery it costs/hour?

I am always looking to improve the location on my own app, I have alrdy given a try to the "find my iphone" API a few years ago.
I wonder if your solution could be improved by coupling it with my own Pilot app: for example, trigger the "poll" only when the users enters a much wide radius (maybe a km around home). That way, less battery usage, and much better positioning.

Happy to speak with you all on that matter,
P

Re: Find My iPhone implementation in LUA script

Posted: Monday 10 October 2016 15:38
by BluesBro
Hi!

I get two types of errors
2016-10-10 15:33:02.316 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_checkphones.lua: /home/pi/domoticz/scripts/lua/script_time_checkphones.lua:48: attempt to index field 'location' (a nil value)

And

2016-10-10 15:34:01.389 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_checkphones.lua: /home/pi/domoticz/scripts/lua/script_time_checkphones.lua:40: attempt to concatenate global 'stage2server' (a nil value)

This is my script:

Code: Select all

-- Script to check the location of multiple iPhones every X minutes,
-- test if they are "home" and represent this using virtual switches

commandArray = {}
-- polling interval in minutes (1-59), setting this too low may drain the phones' batteries
interval = 3
local m = os.date('%M')
if (m % interval == 0) then

  json = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")()

  -- Array of users to be checked
  users = {
            User1 = {username = '[email protected]' ; password = 'MyPassword' ; devicename = 'My Name iPhone'};
          }
  -- The latitude and longitude of your house (use Google Maps or similar to find this)
  homelongitude = 63.3363705
  homelatitude = 10.3109684
  -- Radius (in km) which will be used to determine if a device is at home
  radius = 0.5

  function address(longitude, latitude)
    command = "curl -s https://maps.googleapis.com/maps/api/geocode/json?latlng=" .. latitude .. "," .. longitude .. "&sensor=false"
    local handle = io.popen(command)
    local result = handle:read("*a")
    handle:close()
    output = json:decode(result)
    return output.results[1].formatted_address
  end

  for user,credentials in pairs(users) do
    stage1command = "curl -s -X POST -D - -o /dev/null -L -u '" .. credentials.username .. ":" .. credentials.password .. "' -H 'Content-Type: application/json; charset=utf-8' -H 'X-Apple-Find-Api-Ver: 2.0' -H 'X-Apple-Authscheme: UserIdGuest' -H 'X-Apple-Realm-Support: 1.0' -H 'User-agent: Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)' -H 'X-Client-Name: iPad' -H 'X-Client-UUID: 0cf3dc501ff812adb0b202baed4f37274b210853' -H 'Accept-Language: en-us' -H 'Connection: keep-alive' https://fmipmobile.icloud.com/fmipservice/device/" .. credentials.username .."/initClient"
    local handle = io.popen(stage1command)
    local result = handle:read("*a")
    handle:close()

    stage2server = string.match(result, "X%-Apple%-MMe%-Host%:%s(.*%.icloud%.com)")
    stage2command = "curl -s -X POST -L -u '" .. credentials.username .. ":" .. credentials.password .. "' -H 'Content-Type: application/json; charset=utf-8' -H 'X-Apple-Find-Api-Ver: 2.0' -H 'X-Apple-Authscheme: UserIdGuest' -H 'X-Apple-Realm-Support: 1.0' -H 'User-agent: Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)' -H 'X-Client-Name: iPad' -H 'X-Client-UUID: 0cf3dc501ff812adb0b202baed4f37274b210853' -H 'Accept-Language: en-us' -H 'Connection: keep-alive' https://" .. stage2server .. "/fmipservice/device/" .. credentials.username .."/initClient"
    local handle = io.popen(stage2command)
    local result = handle:read("*a")
    handle:close()

    output = json:decode(result)
    for key,value in pairs(output.content) do
      if value.name == credentials.devicename then
        lon = value.location.longitude
        lat = value.location.latitude
        distance = math.sqrt(((lon - homelongitude) * 111.320 * math.cos(math.rad(lat)))^2 + ((lat - homelatitude) * 110.547)^2)  -- approximation
        position = address(lon,lat)
        position_text = string.gsub(position, ', Netherlands', '') .. ' (' .. (math.floor(distance*10+0.5)/10) .. ' km)'
        prev_distance_str = string.match(otherdevices['Position ' .. user], '%(.*%)') or '(1000 km)'
      prev_distance = tonumber(string.sub(prev_distance_str, 2,-5))
        -- update text device, but only if postion has changed more than defined in "radius" to reduce log size
        if math.abs(prev_distance - distance) > radius then  
          table.insert(commandArray,{['UpdateDevice'] = otherdevices_idx['Position ' .. user] .. '|0|' .. position_text})
        end
        print('iPhone ' .. user .. ': ' .. math.floor(distance*100+0.5)/100 .. ' km from home')
        if distance < radius  then
          if otherdevices['iPhone ' .. user] == 'Off' then
            commandArray['iPhone ' .. user] = 'On'
            table.insert(commandArray, {['SendNotification'] = 'Presence update#' .. user .. ' came home'})
          end
        else
          if otherdevices['iPhone ' .. user] == 'On' then
            commandArray['iPhone ' .. user] = 'Off'
            table.insert(commandArray, {['SendNotification'] = 'Presence update#' .. user .. ' left home'})
          end
        end
      end
    end
  end

end

return commandArray
Does anyone see the error?

Edit:

The error is now reduced to only:

2016-10-10 16:34:02.816 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_checkphones.lua: /home/pi/domoticz/scripts/lua/script_time_checkphones.lua:46: attempt to index field 'location' (a nil value)

Re: Find My iPhone implementation in LUA script

Posted: Monday 10 October 2016 16:46
by bobross
BluesBro wrote:Hi!

The error is now reduced to only:

2016-10-10 16:34:02.816 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_checkphones.lua: /home/pi/domoticz/scripts/lua/script_time_checkphones.lua:46: attempt to index field 'location' (a nil value)
Is the name of your phone exactlly correct ? (as seen in iCloud)

Re: Find My iPhone implementation in LUA script

Posted: Monday 10 October 2016 21:24
by BluesBro
bobross wrote:
BluesBro wrote:Hi!

The error is now reduced to only:

2016-10-10 16:34:02.816 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_checkphones.lua: /home/pi/domoticz/scripts/lua/script_time_checkphones.lua:46: attempt to index field 'location' (a nil value)
Is the name of your phone exactlly correct ? (as seen in iCloud)
Jupp