Re: Geolocalisation et info Iphone
Publié : 07 oct. 2019, 22:21
Génial!
Reprenez le contrôle de votre domotique
https://easydomoticz.com/forum/
je ne sais pas faire ça
Pourquoi tu ne fais pas comme moi ? Une table, avec les utilisateurs dedans, et tu boucle sur la lecture de la table pour developper le code, ou mettre a jour les variables...FredWst a écrit : 07 oct. 2019, 20:39 Bonjour,
J'ai ajouté la création automatique des objets, la position domicile est maintenant celle renseignée dans domoticz.
Pour la gestion des utilisateurs, c'est un peu plus compliqué à gérer de façon automatique …
Le seul moyen existant est de configurer dans le script. J'ai donc ajouté une option simple pour enable/disable un user.
Je mettrai à disposition dans les jours qui vienne.
Cdl
Fred
Code : Tout sélectionner
-- *************************************************************************************************
-- Précision (en km) de detection de position au domicile ou de changement de position
local Precision=0.2
-- Trace
local debug=true
-- Déclaration des utilisateurs.
-- Par défaut 3 utilisateurs possible.
-- name = "" -> utilisateur non utilisé.
-- Les devices nécéssaires sont créés automatiquement.
-- En cas de suppression d'un utilisateur, il faut supprimer les devices manuellement.
local users = {
user1 = {name = "nom"; username = "adresse mail"; password = "mot de passe"};
user2 = {name = ""; username = "adresse mail"; password = "mot de passe"};
user3 = {name = ""; username = "adresse mail"; password = "mot de passe"};
}
-- *************************************************************************************************
-- Fonction de calcul de distance
-- Renvoi la distance en kilometre a une decimale entre deux coordonées GPS
local function distancekm(latitude1, longitude1, latitude2, longitude2)
rayonTerre = 6378137; -- Rayon équatorial de la terre en metre
radlatx = math.rad(latitude1);
radlonx = math.rad(longitude1);
radlaty = math.rad(latitude2);
radlony = math.rad(longitude2);
calculLatitude = (radlaty - radlatx) / 2;
calculLongitude = (radlony - radlonx) / 2;
detail = (math.sin(calculLatitude))^2 + math.cos(radlatx) * math.cos(radlaty) * (math.sin(calculLongitude))^2;
calcul = 2 * math.atan(math.sqrt(detail), math.sqrt(1 - detail));
output = math.floor((rayonTerre * calcul)/100)/10
return output
end
-- Fonction de recuperation des informations icloud
-- Renvoi les informations du telephone (Position GPS, Batterie, Status...)
local function iCloud(triggered)
--On recherche le device associé au devicename de l'utilisateur
for key,value in pairs(triggered.json.content) do
if value.deviceClass == 'iPhone' then
--On verifie que le device est localisé depuis peu pour recuperer les valeurs importantes
if value.isLocating == true and value.location ~= nil and value.location.isInaccurate ~= true and value.location.isOld ~= true then
result = {
batlvl = math.floor(value.batteryLevel * 100 / 1);
batstat = value.batteryStatus;
accuracy = value.location.isInaccurate;
latitudeiPhone = value.location.latitude;
longitudeiPhone = value.location.longitude;
positionType = value.location.positionType;
timestampupdate = value.location.timeStamp;
horizontalAccuracy = value.location.horizontalAccuracy
}
return result
elseif value.isLocating == false or value.location == nil or value.location.isInaccurate == true or value.location.isOld == true or value.location.locationFinished == false then
return nil
else
return nil
end
end
end
end
-- Fonction de calcule d'itineraire
-- Renvoi dans une table le temps en minute et la distance en metre de trajet entre deux coordonées GPS
local function waze(dz, triggered)
convert = dz.utils.fromJSON(triggered.data)
routeTotalDistm = 0
for key,value in pairs(convert.response.results) do
routeTotalDistm = routeTotalDistm + value.length
end
if routeTotalDistm ~= nil and convert.response.totalRouteTime ~= nil then
trajet = { temps = convert.response.totalRouteTime ; distance = routeTotalDistm }
return trajet
else
return nil
end
end
-- Recherche le user ayant déclenché httpResponses callback
local function findUser(dz,triggered)
for usr,cpt in pairs(dz.data.users) do
if string.find(triggered.callback,usr) then
return usr
end
end
end
--Codage base64
local function encodeb64(data)
local bb='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
return ((data:gsub('.', function(x)
r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return bb:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end
local function jsonAPI(dz, apiCall)
url = 'curl -s "'..dz.settings['Domoticz url']..'/json.htm?'..apiCall..'"'
handle = assert(io.popen(url))
result = handle:read("*a")
handle:close()
return dz.utils.fromJSON(result)
end
--Crée virtual harware
local function createVirtualHardware(dz)
jsonAPI(dz,"type=command¶m=addhardware&htype=15&port=1&name=GeolocalisationDummy&enabled=true")
end
--Retourne idx du virtual harware s'il existe
local function isVirtualHardwareExist(dz)
output = jsonAPI(dz,"type=hardware&filter=all&used=true&order=Name")
if output ~= nil then
for index,result in pairs(output.result) do
if result.Type == 15 then
return result.idx
end
end
end
return -1
end
--Retourne idx du device s'il existe
local function isVirtualDeviceExist(dz,device)
output = jsonAPI(dz,"type=devices&filter=all&used=true&order=Name")
if output ~= nil then
for index,result in pairs(output.result) do
if result.Name == device then
return result.idx
end
end
end
return -1
end
local function createObject(dz,nom)
--Teste l'existance d'un virtual hardware
index = isVirtualHardwareExist(dz)
--Crée virtual harware s'il n'existe pas
if index == -1 then
createVirtualHardware(dz)
index = isVirtualHardwareExist(dz)
end
if index then
if isVirtualDeviceExist(dz,'Presence '..nom) == -1 then
jsonAPI(dz, "type=createvirtualsensor&idx="..index.."&sensorname=Presence%20"..nom.."&sensortype=6")
id = isVirtualDeviceExist(dz, 'Presence '..nom)
if id then
jsonAPI(dz, "type=setused&idx="..id.."&name=Presence%20"..nom.."&description=&strparam1&strparam2&protected=false&switchtype=0&customimage=18&used=true&addjvalue=0&addjvalue2=0&option")
end
end
if isVirtualDeviceExist(dz,'Adresse '..nom) == -1 then
jsonAPI(dz, "type=createvirtualsensor&idx="..index.."&sensorname=Adresse%20"..nom.."&sensortype=5")
--id = isVirtualDeviceExist(dz, 'Adresse%20'..nom)
--if id then
-- jsonAPI(dz, "type=setused&idx="..id.."&name=Adresse%20"..nom.."&description=&strparam1&strparam2&protected=false&switchtype=0&customimage=18&used=true&addjvalue=0&addjvalue2=0&option")
--end
end
if isVirtualDeviceExist(dz,'Trajet '..nom) == -1 then
jsonAPI(dz, "type=createvirtualsensor&idx="..index.."&sensorname=Trajet%20"..nom.."&sensortype=5")
--id = isVirtualDeviceExist(dz, 'Trajet%20'..nom)
--if id then
-- jsonAPI(dz, "type=setused&idx="..id.."&name=Trajet%20"..nom.."&description=&strparam1&strparam2&protected=false&switchtype=0&customimage=18&used=true&addjvalue=0&addjvalue2=0&option")
--end
end
if isVirtualDeviceExist(dz,'Batterie '..nom) == -1 then
jsonAPI(dz, "type=createvirtualsensor&idx="..index.."&sensorname=Batterie%20"..nom.."&sensortype=5")
--id = isVirtualDeviceExist(dz, 'Batterie%20'..nom)
--if id then
-- jsonAPI(dz, "type=setused&idx="..id.."&name=Batterie%20"..nom.."&description=&strparam1&strparam2&protected=false&switchtype=0&customimage=18&used=true&addjvalue=0&addjvalue2=0&option")
--end
end
end
end
return {
active = true,
on = {
timer = {'every 1 minutes'},
httpResponses = { 'iClouduser1', 'wazeuser1', 'Adresseuser1',
'iClouduser2', 'wazeuser2', 'Adresseuser2',
'iClouduser3', 'wazeuser3', 'Adresseuser3'
}
},
--Variables persistantes initialisées au premier lancement du script par le système
--Après les données sont mémorisées : obligation liée au principe du callback, les données doivent être non volatile entre appel
--Le fichier de configuration ce trouve là -> domoticz/scripts/dzVents/data/ et se nomme __data_Geolocalisation.lua
data = {
users = { initial = {
user1 = {
latitudeiPhone = 0;
longitudeiPhone = 0;
DistanceDomicile = 0;
deplacement = false;
position = '';
delai = 1;
},
user2 = {
latitudeiPhone = 0;
longitudeiPhone = 0;
DistanceDomicile = 0;
deplacement = false;
position = '';
delai = 6;
},
user3 = {
latitudeiPhone = 0;
longitudeiPhone = 0;
DistanceDomicile = 0;
deplacement = false;
position = '';
delai = 12;
},
}
}
},
execute = function(domoticz, triggeredItem)
-- Latitude et Longitude du domicile:
latitudeDomicile=domoticz.settings.location.latitude
longitudeDomicile=domoticz.settings.location.longitude
--Déclenchement toutes les minutes aucun impact sur la durée batterie de l'iPhone
if (triggeredItem.isTimer) then
--for user,compte in pairs(domoticz.data.users) do
for user,compte1 in pairs(users) do
compte = domoticz.data.users[user]
if compte1.name ~= '' then
createObject(domoticz, compte1.name)
if debug then
print('Lancement demande de localisation '..compte1.name..' dans '..compte.delai..' seconde(s)')
end
domoticz.openURL({
url = 'https://fmipmobile.icloud.com/fmipservice/device/'..compte1.username..'/initClient',
headers = {
["Authorization"] = "Basic "..encodeb64(compte1.username..':'..compte1.password), --Type authentification basic fonctionne avec authentification deux facteurs
["Content-Type"] = "application/json",
["charset"] = "utf-8",
["X-Apple-Find-Api-Ver"] = "2.0",
["X-Apple-Authscheme"] = "UserIdGuest",
["X-Apple-Realm-Support"] = "1.0",
["User-agent"] = "Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)",
["X-Client-Name"] = "iPad",
["Accept-Language"] = "en-us",
["Connection"] = "keep-alive",
["Origin"] = "https://www.icloud.com"
},
method = 'POST',
callback = 'iCloud'..user
}).afterSec(compte.delai) --compte.delai : Astuce pour décaler les demandes sinon waze n'aime pas !
end
end
elseif triggeredItem.isHTTPResponse and triggeredItem.ok then
if (triggeredItem.isJSON) then
--Test type de callback
if string.find(triggeredItem.callback,'iCloud') then
--Récupère le user qui génère le callback
user = findUser(domoticz,triggeredItem)
compte = domoticz.data.users[user]
compte1 = users[user]
--Fonction de recherche données uniquement deviceClass:iPhone voir filtre dans la fonction elle même en début de code
device = iCloud(triggeredItem)
if device ~= nil then
-- Ancienne position:
latitudePrecente = compte.latitudeiPhone
longitudePrecedente = compte.longitudeiPhone
-- Ancienne distance [position-domicile]:
DistanceDomicilePrecedente = distancekm(latitudePrecente, longitudePrecedente, latitudeDomicile, longitudeDomicile)
-- Distance [nouvelle position-ancienne position]:
EcartDistance = distancekm(device.latitudeiPhone, device.longitudeiPhone,latitudePrecente, longitudePrecedente)
-- Distance [nouvelle position-domicile]:
compte.DistanceDomicile = distancekm(device.latitudeiPhone, device.longitudeiPhone, latitudeDomicile, longitudeDomicile)
--Presence: si la distance avec le domicile est inferieure à la précision souhaitée alors le smartphone est present au domicile
if compte.DistanceDomicile < Precision then --Presence
if domoticz.devices('Presence ' .. compte1.name).state == 'Off' then --Arrivée
domoticz.devices('Presence ' .. compte1.name).switchOn().silent()
end
compte.DistanceDomicile = 0
else
if domoticz.devices('Presence ' .. compte1.name).state == 'On' then
domoticz.devices('Presence ' .. compte1.name).switchOff().silent()
end
end
if debug then
print('Callback iCloud : '..compte1.name..': '..compte.DistanceDomicile..' km du domicile, '..device.batlvl..'% de batterie restante. Statut: "'..device.batstat..'". Precision: '..device.horizontalAccuracy)
end
--Deplacement: si la distance avec l'ancienne position est superieure à la précision souhaitée alors le smartphone n'est plus au meme endroit et se deplace
if EcartDistance > Precision then
compte.deplacement = true
if DistanceDomicilePrecedente > compte.DistanceDomicile then
compte.position='En rapprochement du domicile'
else
compte.position='En éloignement du domicile'
end
if debug then
print('iPhone de '..compte1.name.. ': '..compte.position)
end
domoticz.devices('Adresse '..compte1.name).updateText(compte.position)
if debug then
print('Lancement demande de trajet '..compte1.name)
end
domoticz.openURL({
url = 'https://www.waze.com/row-RoutingManager/routingRequest?from=x:'..longitudeDomicile..'+y:'..latitudeDomicile..'&to=x:'..device.longitudeiPhone..'+y:'..device.latitudeiPhone..'&at=0&returnJSON=true&returnGeometries=false&returnInstructions=false&timeout=30000&nPaths=1&clientVersion=1.0.0&options=AVOID_TRAILS:t,ALLOW_UTURNS:t',
headers={["Content-Type"] = "application/json",["referer"]="https://www.waze.com"},
method = 'POST',
callback = 'waze'..user
})
else
if compte.deplacement == true and ( domoticz.devices('Adresse '..compte1.name).state=='En éloignement du domicile' or domoticz.devices('Adresse '..compte1.name).state=='En rapprochement du domicile') then
if debug then
print("Lancement demande de l'adresse de "..compte1.name)
end
domoticz.openURL({
url = 'https://api-adresse.data.gouv.fr/reverse/?lon='.. device.longitudeiPhone .. '&lat=' .. device.latitudeiPhone,
method = 'GET',
callback = 'Adresse'..user
})
end
compte.deplacement = false
end
domoticz.devices('Batterie '..compte1.name).updateText('Niveau : '..device.batlvl..'%.\13\10 Statut : '..device.batstat)
--Mémorisation nouvelle coordonnée iPhone
--Mise a jour des informations
compte.latitudeiPhone = device.latitudeiPhone
compte.longitudeiPhone = device.longitudeiPhone
else
print('Retour iCloud problème : '..compte1.name)
end
end
--Test type de callback
if string.find(triggeredItem.callback,'Adresse') then
--Récupère le user qui génère le callback
user = findUser(domoticz,triggeredItem)
compte = domoticz.data.users[user]
compte1 = users[user]
adresse = triggeredItem.json.features[1].properties.label
if adresse ~=nil then
compte.position=adresse..' ('..compte.DistanceDomicile..' km)'
if debug then
print('Callback Adresse : '..compte1.name..': '..compte.position)
end
domoticz.devices('Adresse '..compte1.name).updateText(compte.position)
else
print('Retour Adresse problème : '..compte1.name)
compte.position=domoticz.devices('Adresse '..compte1.name).state
end
end
else
--C'est bien un format JSON mais domoticz ne le detecte pas !
--Test type de callback
if string.find(triggeredItem.callback,'waze') then
--Récupère le user qui génère le callback
user = findUser(domoticz,triggeredItem)
compte = domoticz.data.users[user]
compte1 = users[user]
trajet = waze(domoticz,triggeredItem)
if trajet ~= nil then
--Fonction waze retourne pour le trajet entre deux coordonées une table avec le temps en seconde et la distance en metre
heures=math.floor(trajet.temps / 3600)
minutes=math.floor((trajet.temps % 3600) / 60)
secondes=math.floor((trajet.temps % 3600) % 60)
ETA=os.date("%Hh%M",os.time()+trajet.temps)
duree=heures..'h'..minutes..'min'
trafic='Heure d\'arrivée: '..ETA..' - '..tostring(((math.floor(trajet.distance/100))/10))..'Km, '..duree
if debug then
print('Callback waze : ' .. compte1.name .. ': '..trafic)
end
domoticz.devices('Trajet '..compte1.name).updateText(trafic)
else
print('Retour Waze problème : '..compte1.name)
end
end
end
end
end
}