Aller au contenu
kiwi

Tester Votre Présence 3 - The Utlimate Vengeance :)

Recommended Posts

Bonjour à  tous,

Cette solution, différente des autres, se base sur le fait que les objets wifi disposent d'un adresse "MAC" (ou ARP en anglais).

Cette adresse est obligatoire et a le grand avantage de ne nécessiter aucun port ouvert sur l'appareil a tester.

Prérequis :

  • Une machine *nix (Linux : Raspberry, Synology, FreeBSD, ...).
  • Une HC2 (une version spécifique HCL viendra plus tard).
  • Du Perl avec la bibliothèque CGI sur la machine hôte.
  • Avoir un baux DHCP fixe (aka configurer une IP fixe) pour les appareils a surveiller.
La solution se décompose en deux parties :
  • Un script CGI qui se met sur un serveur *nix.
  • Un virtual module qui s'occupe de faire des demandes toutes les 10 minutes sur ce script CGI.
Installation du CGI sur un serveur *nix.

Je prends pour référence mon Raspberry PI qui fait tourner mon domoticz. Ayant eu la flemme d'installer un PI "à  la main" j'avais déjà  pris la "Domoticz RaspberryPI SD Image", que vous pouvez trouver à  l'adresse suivante : http://www.domoticz.com/wiki/Domoticz_RaspberryPi_SD_Image.

Accessoirement j'ai installé avahi afin de le trouver via bonjour sur mon Mac.

Commandes a executer en root :

aptitude install avahi-daemon
Normalement l'image PI pour domoticz dispose déjà  d'un nginx préinstallé, il reste donc plus à  ajouter fcgiwrap pour que le CGI soit executable depuis nginx.

 

aptitude install fcgiwrap
Puis copier le fichier de configuration dans /etc/nginx :

cp /usr/share/doc/fcgiwrap/examples/nginx.conf /etc/nginx/fcgiwrap.conf
Il suffit de créer un répertoire cgi-bin et downloader le script arp.pl :

mkdir -p /usr/lib/cgi-bin
cd /usr/lib/cgi-bin
wget --no-check-certificate https://redmine.oav.net/projects/kiwi/repository/revisions/master/raw/fibaro/arp/arp.pl
chmod +x arp.pl
Il reste à  configurer le nginx pour qu'on puisse donc executer le CGI qui vas nous servir a trouver si le matériel fonctionne ou pas, créez le fichier /etc/nginx/sites-available/cgi avec le contenu suivant :

server {
        #listen   80; ## listen for ipv4; this line is default and implied
        #listen   [::]:80 default_server ipv6only=on; ## listen for ipv6
        listen 8000;

        root /usr/share/nginx/www;
        index index.html index.htm;

        # Make site accessible from http://localhost/
        server_name localhost;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ /index.html;
                # Uncomment to enable naxsi on this location
                # include /etc/nginx/naxsi.rules
        }

        include /etc/nginx/fcgiwrap.conf;

}
Puis activez le site :

cd /etc/nginx/sites-enabled && ln -s ../sites-available/cgi
nginx -t
Au "nginx -t" un test de syntaxe du fichier de conf vas être effectuée normalement si vous avez autre chose que :

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
C'est qu'il y a un erreur quelque part dans votre configuration.

Dans le cas où tout vas bien, relancez le service nginx :

service nginx restart
Puis nous pouvons passer au test CGI.

Exemple avec une ip en 192.168.0.50, mettez dans votre navigateur : http://ip.du.pi.lan:8000/cgi-bin/arp.pl?host=192.168.0.50, devrait vous donner le JSON suivant (si cette machine existe et que vous arrivez a pinger cette machine depuis le PI) :

 

{
hostname: "192.168.0.50",
ipv4: "192.168.0.50",
MAC: "aa:bb:cc:dd:ee:ff"
}
La partie *nix est donc finie.

Installation de la partie HC2.

Téléchargez le virtual module à  l'adresse : https://redmine.oav.net/projects/kiwi/repository/revisions/master/raw/fibaro/arp/presence.vfib (Si le certificat SSL fais la tronche c'est pas grave, je le mettrais à  jour bientôt).

Dans la configuration du modules, mettez l'ip correspondant au PI et le Port correspondant a celui que vous avez ouvert précédemment (dans mon exemple : 8000).

 

post-9-0-48830400-1418580189_thumb.png

Dans le code du bouton 1, complétez les lignes suivantes avec *vos* paramètres :

 

post-9-0-45919500-1418580234_thumb.png

local cgi = "/cgi-bin/arp.pl";
local what = "192.168.0.50";
Pour aller avec l'exemple ci dessus.

A noter que vous avez besoin de créer une variable locale qui s'appelle : Phone_<valeurdewhat>, par exemple : Phone_192.168.0.50 avec comme 2 valeurs 1 ou 0.

post-9-0-88358100-1418580252_thumb.png

Après laissez le reste se faire, normalement les icônes changent tout seul et la ligne de status affiche correctement les bonnes infos.

Enjoy et informez moi des pb ou evolutions.

Xavier

PS1: License du module : MPL1.1, URL de mon git : https://redmine.oav.net/projects/kiwi/repository/revisions/master/show/fibaro/arp

PS2: Si bug utilisez l'option "Nouvelle demande" afin que je corrige/adapte :)

Edits: 22/12 : corrections de carfnann

  • Upvote 3

Partager ce message


Lien à poster
Partager sur d’autres sites

Salut Kiwi!

Je vois que tu n'as pas chaumé, et ta soluce super bien pensée! Je l'installe dés que j'ai quelques minutes et j'ai hâte!

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonjour,

 

Super ce detecteur de présence, Question bete : QUID des smart à  la pomme qui se mettent en veille et perdent le WIFI ?

 

Merci, j'ai hate de l'installer

Partager ce message


Lien à poster
Partager sur d’autres sites

@pepite: Justement je n'ai que ça àla maison :) iPhone 5S et 4S... Donc tu peux considérer que ça marche :)

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonjour Kiwi,

 

Ta raquette concerne la table ARP ? si c'est le cas, pourquoi ne pas faire référence à  l'adresse MAC directement ( quelque soit l'adresse IP ) ?

Partager ce message


Lien à poster
Partager sur d’autres sites

@kiwi

Yes, je mets ca en place sur le RPI dès que possible hihihi

Partager ce message


Lien à poster
Partager sur d’autres sites

@yassinex: le perl cgi est capable de manger des adresses MAC, donc normalement ça doit marcher. 

 

Pourquoi des ip / nom d'hosts? parce que c'est plus facile de se souvenir de ça que d'une adresse MAC :)

 

(Ok je parles pas d'IPv6 encore)

Partager ce message


Lien à poster
Partager sur d’autres sites

Oui mais du coup ton script ne fonctionnera pas en mode DHCP car l'IP change ( et non l'adresse MAC ).

 

Il y'a des cas ou l'on souhaite pas forcement  réserver une IP (Invités, voisins...) mais on souhaite quand même activer des scénarios/action en leur présence. 

 

Example avec GEA :

GEA.add(id["Sonnerie_Porte"], -1 , "Les Lutins Arrivent", {{"Repeat"}, {"Time", "08:00", "18:00"}, {"Global", "LesRelous", "Oui"}, {"VirtualDevice", id["Cage-Pitbull"],"1"}, {"Value", id["Portail_Jardin"], 0} })

...

  • Upvote 1

Partager ce message


Lien à poster
Partager sur d’autres sites

Sisi il fonctionne en mettant une adresse MAC (grep power !) : http://ip.du.ras.pi:8080/cgi-bin/arp.pl?host=aa:af:bb:cf:de:ad me retourne :

{
hostname: "aa:af:bb:cf:de:ad",
ipv4: "192.168.0.40",
MAC: "aa:af:bb:cf:de:ad"
}
Donc l'effet kiss cool, c'est que tu peux retrouver comme ça quelle adresse IP appartient l'adresse MAC que tu précises... :)

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonsoir @kiwi

 

Alors je teste et voila mes premiers retours (c'est peut-etre moi le boulet)

1- Impossible de créer une variable globale avec le contenu de "what" si what est numerique comme dans le tuto

   --> Si what = 192.168.0.50 (adresse du smartphone si j'ai bien compris ???) alors impossible de creer la variable en "Phone_192.168.0.50"

 

 
2- Variable globale crée en mettant en "what" : le nom recup du DHCP fixe de la box : OK donc pour moi par exemple :
  -->
local what = "iphonepepite";

donc variable globale : Phone_iphonepepite sans mettre de valeurs

 

3- Test de la verif presence en cliquant sur le bouton : message : iphonepepite is not at home alors que je suis bien wifi

 

Me suis-je trompé quelque part ?

 

 

J'oubliais :

Pour tester une autre smartphone, on rajoute bien un bouton en changeant "what" et en rajoutant une variable globale correspondante ?

 

4- Test avec variable predefinie avec valeur 0 et 1, pas mieux, meme message "...is not at home"

5- dans le main loop il reste cela  que j'ai modifié aussi avec le nom de la variable predefinie

local status = fibaro:getGlobal("Phone_ikiwi")

6- idem avec Variable globale sans valeur : idem : meme message ..is not at home

 

Quelquechose me dit que c'est moi qui fait une erreur quelquepart ;-)

 

 

 AU fait ..heu...what is it ? ;)

"PS2: Si bug utilisez l'option "Nouvelle demande" afin que je corrige/adapte"

 

 

Modifié par pepite

Partager ce message


Lien à poster
Partager sur d’autres sites

@pepite: sur ton pi si peux tu me donner ce que fait la commande :

arp -a 
en MP ?

J'ai une configuration particulière chez moi (avec des DNS / reverse DNS / plutôt proche de l'état de l'art dans un datacenter que des "choses" normales chez mr tout le monde).

Sur le point 1, je vais modifier le virtual module pour qu'il prenne autre chose de le contenu de la variable what.

Sur le point 5, j'ai oublié de dire cette partie, doc àmettre a jour (ca sera fait bientôt)

Sur le dernier point, j'ai un bug tracker sur le redmine ou est hébergé le GIT... :) Mais c'est pas grave :)

Partager ce message


Lien à poster
Partager sur d’autres sites

Bonjour,

 
Désolé mais je ne suis pas sur de comprendre en quoi cette méthode différe…
Est ce l’équivalent d’un ping?
Si oui pourquoi avoir besoin de l’adresse mac?
 
Sinon ta méthode fonctionne même si l’iPhone est en veille?
 
 
 
Merci en tout cas :D

Partager ce message


Lien à poster
Partager sur d’autres sites

@carfman: le concept d'adresse MAC est que toute carte ethernet (y compris wifi) en as une et est obligée de l'annoncer. Le ping quand a lui n'est même pas obligatoire et des fois même certains matériels ne répondent pas au ping alors que l'adresse MAC réponds (je ne vais pas décrire comment ca marche, mais la carte wifi du téléphone réponds directement aux requêtes MAC alors que le ping dois passer dans le CPU du smartphone, donc on est plus bas niveau dans les couches OSI : niveau 1 : câbles / wifi, niveau 2 : MAC, niveau 3: ping / tcp...en gros).

Sur les machines *nix (linux, ...) la table MAC -> IP est gardée en cache un certain nombre de temps (sur FreeBSD j'arrive a tuner ça sur linux, je recherche encore la bonne commande a mettre), donc partant de ce fait que les iBidules ne se présente que une fois très courte sur le réseau, en utilisant ca cache on peux savoir, sans encombrer le réseau wifi (qui est partagé par tous les clients wifi, donc limité en bande passante) si un téléphone est la depuis peu de temps (peu = dans mes versions de tests environ 30 minutes), de façon "passive".

Mon code n'est pas encore parfait, mais je vais corriger le virtual module pour qu'on puisse mettre ip / mac / nom (si, comme moi, on a mis un DNS propre a la maison).

Partager ce message


Lien à poster
Partager sur d’autres sites

Je vais suivre ça, et attendre de voir une version qui tourne sur HCL.

J'utilise la version de Tony depuis un peu moins d'une semaine et j'avoue n'avoir aucun raté.

 

Par contre je rencontre une défaut à  utiliser ce système pour par exemple allumer mes Hue quand j'arrives chez moi.

 

Explication:

Je contrôle les Hue avec un Virtual Device qui balance une requête en PUT et donc avec un paramètre définie.

A coté de ça j'ai une scène qui regarde la valeur de la variable Présence,

 

Si Présent = Allume Hue (avec le parcmètre du Virtual Device)

 

Dans une autre scène

Si absent = Stop Hue

 

donc à  chaque cycle de scène ca me remet les paramètres de l'ampoule du Virtual Device. Donc si j'avais changé par exemple la couleur ou luminosité, ca reset :/

 

Je ne peut par exemple donc pas faire d'annonce vocal par exemple quand un tél entre sous le wifi, car ça le ferait à  chaque cycle de vérification de la variable et non seulement à  son changement d'état ce qui serait l'idéal.

 

Rappel: Je suis sur une HCL  :15:

Partager ce message


Lien à poster
Partager sur d’autres sites

je viens de mettre ton pgm en place, c'est au poil! 

 

juste quelques remarques :

* il y a des erreurs de typo dans le tuto, quand on fait un copier coller bêtement comme moi...

 

 

créez le fichier /etc/nginx/site-available/cgi avec le contenu suivant :

 

il y a un s à  site  => 

créez le fichier /etc/nginx/site-available/cgi avec le contenu suivant :

 

 

 

 

 

  1. cd /etc/nginx/site-enabled && ln -s ../sites-available/cgi

 

idem

 

 

  1. cd /etc/nginx/sites-enabled && ln -s ../sites-available/cgi

 

 

 

et juste une chose, j'ai rajouter une gestion du what local pour y mettre mon prénom car je n'ai pas mis de dns chez moi...

juste avant 

if(response.MAC == "unknown")

 

le 1er local what lui je l'ai gardé pour l'@ mac

 

 

merci encore

Partager ce message


Lien à poster
Partager sur d’autres sites

@carfnann

 

ah zut, kiwi le pauvre essaie de me debugger par MP. Pour moi cela ne fonctionne pas, cela t'embeterait de partager ton code qui tourne stp ? en MP ?

ca peut aussi aider kiwi a ne pas s'arracher les cheveux avec moi ;-)

merci....

 

pepite

Partager ce message


Lien à poster
Partager sur d’autres sites

voila le contenu de mon bouton action

local thismodule = fibaro:getSelfId();
local ip = fibaro:get(thismodule, 'IPAddress');
local port = fibaro:get(thismodule, 'TCPPort');
local cgi = "/cgi-bin/arp.pl";
local what = "80:be:xx:xx:xx:xx";
-- DON'T FORGET to create global variable Phone_ with "what" content
-- ie if what="ikiwi", then the GV will be : Phone_ikiwi

fibaro:debug("ARP : http://"..ip..":"..port..cgi);

local arpstuff = pcall(function()
    
    local ARP = Net.FHttp(ip,port);

    local response, status, errorCode = ARP:GET(cgi.."?host="..what);
    --fibaro:debug("Debug : r : "..response.."\n");
    --fibaro:debug("Debug : s : "..status.."\n");
    --fibaro:debug("Debug : e : "..errorCode.."\n");
    if(tonumber(status)==200)
    then
	-- enregistrement du retour de l API dans une table
	response = json.decode(response);
	fibaro:debug(response.hostname);
	fibaro:debug(response.MAC);
      what = "Julien";
	if(response.MAC == "unknown")
	then
		fibaro:debug(what.." is not at home");
		if (fibaro:getGlobalValue("Phone_"..what)=="1")
		then
			fibaro:setGlobal("Phone_"..what,"0");
		end;	
		fibaro:log(what.." is not at home");
	else
		fibaro:debug(what.." is at home");
		if (fibaro:getGlobalValue("Phone_"..what)=="0")
		then
			fibaro:setGlobal("Phone_"..what,"1");
		end
		fibaro:log(what.." is at home");
	end;
			
    else
       fibaro:debug("status: " .. tostring(status or "")); 
       fibaro:debug("error code: " .. tostring(errorCode or "")); 
    end;
end);
    

if (not arpstuff) then
	fibaro:debug("ARP polling failed");
end;

d'abord j'affecte mon adresse mac à  la variable locale what (ligne 5), pour faire la requête

puis ensuite j'affecte mon nom (ligne 25), pour mettre à  jour ma variable globale "phone_Julien"

 

c'est tout ce que j'ai fait (plus la variable global dans le main loop pour avoir phone_Julien)

Partager ce message


Lien à poster
Partager sur d’autres sites

bizarrement, je fais maintenant la meme requête http pour l'iPhone de ma femme et cela ne passe plus... :(

Partager ce message


Lien à poster
Partager sur d’autres sites

j'espere que je ne t'ai pas porté la poisse..

Kiwi vient de me demander de faire d'autres manips.mais toujours pas ;-)

 

merki

Partager ce message


Lien à poster
Partager sur d’autres sites

Hello,

Attention j'ai modifié le code du bouton (et pas encore mis àjour le code du virtual module), le voici :

local thismodule = fibaro:getSelfId();
local ip = fibaro:get(thismodule, 'IPAddress');
local port = fibaro:get(thismodule, 'TCPPort');
local cgi = "/kiwi/arp.pl";
local what = "ikiwi";
-- DON'T FORGET to create global variable Phone_ with "what" content
-- ie if what="ikiwi", then the GV will be : Phone_ikiwi or change the 
-- following
local gbname = "Phone_"..what;

fibaro:debug("ARP : http://"..ip..":"..port..cgi);

local arpstuff = pcall(function()

    -- Create the global variable name
    local gbname = "Phone_"..what;
    
    local ARP = Net.FHttp(ip,port);

    local response, status, errorCode = ARP:GET(cgi.."?host="..what);
    --fibaro:debug("Debug : r : "..response.."\n");
    --fibaro:debug("Debug : s : "..status.."\n");
    --fibaro:debug("Debug : e : "..errorCode.."\n");
    if(tonumber(status)==200)
    then
	-- enregistrement du retour de l API dans une table
	response = json.decode(response);
	fibaro:debug(response.hostname);
	fibaro:debug(response.MAC);
	if(response.MAC == "unknown")
	then
		fibaro:debug(what.." is not at home");
		if (fibaro:getGlobalValue(gbname)=="1")
		then
			fibaro:setGlobal(gbname,"0");
		end;	
		fibaro:log(what.." is not at home");
	else
		fibaro:debug(what.." is at home");
		if (fibaro:getGlobalValue(gbname)=="0")
		then
			fibaro:setGlobal(gbname,"1");
		end
		fibaro:log(what.." is at home");
	end;
			
    else
       fibaro:debug("status: " .. tostring(status or "")); 
       fibaro:debug("error code: " .. tostring(errorCode or "")); 
    end;
end);
    

if (not arpstuff) then
	fibaro:debug("ARP polling failed");
end;

D'autre part, le problèmes viennent du fait chez certains que la machine qui héberge le CGI ne vois pas assez souvent les iDevices.

De mon coté, sur mon PI j'ai deux choses :

- un resolveur dns (serveur dns) qui remplace celui de mon FAI (comme ça je n'ai pas accès a la censure d'état), qui peux être installé a avec "aptitude install unbound". Le serveur DHCP alors annonce ce serveur comme serveur DNS de la maison.

- j'ai aussi installé avahi... Ce qui me permet d'avoir accès via bonjour a mes matériels.

D'autre part d'après les échanges que j'ai eu avec pepite, un sysctl -w net.ipv4.neigh.default.base_reachable_time_ms=1800000 en root permet de garder le cache ARP de facon plus longue.

Il est vrai que mon code est très "unix" centric, et donc dépend aussi un peu de ma configuration personnelle qui peux ne pas être la même partout.

Partager ce message


Lien à poster
Partager sur d’autres sites

Salut Kiwi, 

Merci pour ce module virtuel et tout le boulot qui va avec !

Une question, j'ai installé le tout et je me demandais combien de temps faut-il pour être notifié absent ?

Si j'ai bien suivit , c'est le temps que l'on ne soit plus dans la table arp ? Par contre, impossible de savoir quelle est sa durée de vie.

Partager ce message


Lien à poster
Partager sur d’autres sites

@Ez3kiel: le TTL de la table ARP dépends de pas mal de choses mais beaucoup de la variable kernel "net.ipv4.neigh.default.base_reachable_time_ms", d'ailleurs dans le post précédent au tiens, j'ai donné une méthode pour le mettre plus haut.
 
Il est vrai que par contre Linux n'est pas "ultra" cool sur cette méthode car il y a d'autres paramètres (a la con) qui rentrent en compte.
 
Sur FreeBSD (que je préfère de loin à  Linux) la command arp -a montre bien le TTL de la table ARP :

$ arp -a
ikiwi.home.oav.net (192.2.0.40) at aa:af:ee:ff:de:ad on em0 expires in 2331 seconds [ethernet]
(...)

A noter et j'insiste la dessus, que mon PI ou Serveur FreeBSD est LE serveur sur lequel tous les appareils se connectent, en effet, il fait :

 

  • Serveur DNS (ipv4 et ipv6)
  • Serveur Proxy (configuré sur tous les idevices)
  • Serveur web qui réponds aux requêtes wpad (pour l'auto conf des proxy).

Rien que ces paramètres permettent une demande régulière de data a ce serveur et garantis que l'expiration de la table ARP corresponds bien au fait que l'utilisateur n'est plus dans les parages depuis "quelques temps".

  • Upvote 1

Partager ce message


Lien à poster
Partager sur d’autres sites

@Kiwi,

 OK, je comprends mieux pourquoi ça marche chez toi et pas chez moi.

En fin de compte, tous tes devices passent par le pi chez toi. du coup, ta table arp est cohérente avec la présence des devices.

chez moi la table est complètement désynchronisée de la présence.

je vois des périphériques connectés qui ne le sont pas et d'autres qui devraient l’être mais qui sont invisibles.

 

par exemple mon tel android est éteint depuis 2h du mat et mon pc fixe depuis 6h et je les vois toujours present chez moi.

 

Une question, est ce que la mise en place du pi en tant que passerelle pour tous les devices est compliquée a faire ?

Partager ce message


Lien à poster
Partager sur d’autres sites

×