Re: Find My iPhone implementation in LUA script
Posted: Tuesday 13 September 2016 21:06
Add some prints to the script and watch the logfile.
Open source Home Automation System
https://forum.domoticz.com/
That explains a lot .joto wrote:Hi again
my bad guys, I'm running on Windows and that's probably why it doesn't work...
Never used lua or curl before so it will probably take a while for me to find the OS-dependent parts.
Problems is a good way to learn new things
Thanks for this script!mvzut wrote:I guess you could be right! At first, I didn't have the check that it was only updated when the difference with the previous position was large enough. I get the previous distance from the contents of the text field, so when that doesn't contain "(x.x km)" it will never be updated. I have added a line in the scriptEgregius wrote:Could it be that you need to manually update the text sensor once it a text like "Westlaan 401-407, 8800 Roeselare (6.7 km)"?See original post where it needs to be placed. Can you let me know if this helps?Code: Select all
if prev_distance == nil then prev_distance = 1000 end
Code: Select all
prev_dist = tonumber(string.sub(string.match(otherdevices['Position ' .. user], '%(.*%)'), 2,-5))
Code: Select all
prev_dist = tonumber(string.sub(string.match(otherdevices_svalues['Position ' .. user], '%(.*%)'), 2,-5))
Nice, do you have some more information available on this?Egregius wrote:Do you know you can (ab)use the same service to sent text messages to ios? They even make sound when the phone is in do not disturb mode or silent.
Strange, here it (also) works without using svalues. Makes you wonder how two Domoticz systems can behave so differently? Are you perhaps on a stable (older) version?G3rard wrote:Thanks for this script!mvzut wrote:I guess you could be right! At first, I didn't have the check that it was only updated when the difference with the previous position was large enough. I get the previous distance from the contents of the text field, so when that doesn't contain "(x.x km)" it will never be updated. I have added a line in the scriptEgregius wrote:Could it be that you need to manually update the text sensor once it a text like "Westlaan 401-407, 8800 Roeselare (6.7 km)"?See original post where it needs to be placed. Can you let me know if this helps?Code: Select all
if prev_distance == nil then prev_distance = 1000 end
I had to change the linetoCode: Select all
prev_dist = tonumber(string.sub(string.match(otherdevices['Position ' .. user], '%(.*%)'), 2,-5))
to get this working.Code: Select all
prev_dist = tonumber(string.sub(string.match(otherdevices_svalues['Position ' .. user], '%(.*%)'), 2,-5))
Only in PHPG3rard wrote:Nice, do you have some more information available on this?Egregius wrote:Do you know you can (ab)use the same service to sent text messages to ios? They even make sound when the phone is in do not disturb mode or silent.
Code: Select all
ios('test message with high priority');
I think I see what the problem is. I was looking at the wrong line all the time, line 56 in your script seems to be the line with the UpdateDevice command, right? In that line there is a space missing after 'iPhone'. I had that typo for a brief moment in my original post, but corrected it as soon as I saw it. Apparently you copied the code before that. Let me know if it works now! If so, please remove the "position_text = position" if you want distance info in your text devices.cattoo wrote:Well its not the JSON file thats the issue. Check this post and see the rest of the posts
http://www.domoticz.com/forum/viewtopic ... 318#p96326
Well, i copied the script again and got new errorsmvzut wrote:I think I see what the problem is. I was looking at the wrong line all the time, line 56 in your script seems to be the line with the UpdateDevice command, right? In that line there is a space missing after 'iPhone'. I had that typo for a brief moment in my original post, but corrected it as soon as I saw it. Apparently you copied the code before that. Let me know if it works now! If so, please remove the "position_text = position" if you want distance info in your text devices.cattoo wrote:Well its not the JSON file thats the issue. Check this post and see the rest of the posts
http://www.domoticz.com/forum/viewtopic ... 318#p96326
Code: Select all
Error: EventSystem: in Iphone: [string "-- Script to check the location of multiple i..."]:75: 'end' expected (to close 'if' at line 8) near
Code: Select all
2016-09-14 09:17:00.304 LUA: User check
2016-09-14 09:17:00.305 LUA: end User check
2016-09-14 09:17:00.305 LUA: funct adres
2016-09-14 09:17:00.305 LUA: end funct adres
2016-09-14 09:17:00.305 LUA: start stage1command
2016-09-14 09:17:01.255 LUA: end stage1command
2016-09-14 09:17:01.262 LUA: start stage2command
2016-09-14 09:17:01.847 LUA: end stage2command
2016-09-14 09:17:01.847 LUA: start json decode
2016-09-14 09:17:02.809 LUA: end stage1command
2016-09-14 09:17:02.809 LUA: start stage2command
2016-09-14 09:17:03.395 LUA: end stage2command
2016-09-14 09:17:03.396 LUA: start json decode
2016-09-14 09:17:03.414 LUA: end json decode
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")()
print('User check')
-- Array of users to be checked
users = {
Mike = {username = 'me' ; password = 'me' ; devicename = 'iPhone Mike'};
Cez = {username = 'her' ; password = 'her' ; devicename = 'iPhone Cez'}
-- Person3 = {username = '[email protected]' ; password = 'password3' ; devicename = 'iPhone Person3'}
}
print('end User check')
-- The latitude and longitude of your house (use Google Maps or similar to find this)
homelongitude = 14.938646
homelatitude = 50.504517
-- Radius (in km) which will be used to determine if a device is at home
radius = 0.5
print('funct adres')
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
print('end funct adres')
print('start stage1command')
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()
print('end stage1command')
print('start stage2command')
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()
print('end stage2command')
print('start json decode')
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_dist = tonumber(string.sub(string.match(otherdevices['Position ' .. user], '%(.*%)'), 2,-5))
if prev_distance == nil then prev_distance = 1000 end
if math.abs(prev_dist - distance) > radius then -- only update text device if postion has changed more than defined in "radius" to reduce log size
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
print('end json decode')
end
return commandArray
Code: Select all
print('start json decode')
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
print(distance)
position = address(lon,lat)
print(lon)
print(lat)
position_text = string.gsub(position, ', Netherlands', '') .. ' (' .. (math.floor(distance*10+0.5)/10) .. ' km)'
prev_dist = tonumber(string.sub(string.match(otherdevices['Position ' .. user], '%(.*%)'), 2,-5))
if prev_distance == nil then prev_distance = 1000 end
if math.abs(prev_dist - distance) > radius then -- only update text device if postion has changed more than defined in "radius" to reduce log size
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
Ok, sorry, missed an "end" in line 54, see updated original post again.cattoo wrote:Well, i copied the script again and got new errorsmvzut wrote:I think I see what the problem is. I was looking at the wrong line all the time, line 56 in your script seems to be the line with the UpdateDevice command, right? In that line there is a space missing after 'iPhone'. I had that typo for a brief moment in my original post, but corrected it as soon as I saw it. Apparently you copied the code before that. Let me know if it works now! If so, please remove the "position_text = position" if you want distance info in your text devices.cattoo wrote:Well its not the JSON file thats the issue. Check this post and see the rest of the posts
http://www.domoticz.com/forum/viewtopic ... 318#p96326Its getting closer....Code: Select all
Error: EventSystem: in Iphone: [string "-- Script to check the location of multiple i..."]:75: 'end' expected (to close 'if' at line 8) near
From your debugging output I conclude that getting the info from Apple using curl and json-decoding works fine. But if the "print(lon)" and "print(lat)" do not show up in the log, that must mean that the "if value.name == credentials.devicename" is never true. Are you sure you typed the name of your iPhone correctly in the "users" array? Are there any special characters in it maybe? You could adda a print(result) after "local result = handle:read("*a")". That should print a very long string in the log with all your device info. Try to look for your device name in it. Does it show up, and how is it exactly spelled?mcmikev wrote:I have added some more print lines none of these are shown in the log
Maybe some extra information : I run on RPI2B with domoticz image.Code: Select all
print('start json decode') 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 print(distance) position = address(lon,lat) print(lon) print(lat) position_text = string.gsub(position, ', Netherlands', '') .. ' (' .. (math.floor(distance*10+0.5)/10) .. ' km)' prev_dist = tonumber(string.sub(string.match(otherdevices['Position ' .. user], '%(.*%)'), 2,-5)) if prev_distance == nil then prev_distance = 1000 end if math.abs(prev_dist - distance) > radius then -- only update text device if postion has changed more than defined in "radius" to reduce log size 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
Code: Select all
Error: EventSystem: in Check_iphone: [string "-- Script to check the location of multiple i..."]:54: bad argument #1 to 'match' (string expected, got nil)