Anwesenheitserkennung mit WLAN über eine Fritzbox

Hiermit soll beschrieben werden, wie mit einem Linux-Server (raspberry pi oder ähnlich), einer Fritzbox und einem iPhone oder Android-Handy die Anwesenheit eines oder mehrere Bewohner geprüft werden kann um verschiedene Stadien im Haus zu aktivieren.
Und vor allem kommt diese Lösung ohne Zugriffe auf Cloud-Dienste aus.

 

Im Forum wurde angekündigt, dass es Probleme geben könnte mit iPhone-Geräten.

 

Ich habe nun seit dem 09. Januar 2016 die Anwesenheitsdaten immer mitgeschrieben um nachzuvollziehen, wann das Gerät aus der Fritzbox verschwindet.

Es gab nur einmal in der Nacht einen Aussetzer von ca. 1 1/2 Std. Das ist aber aus meiner Sicht vernachlässigbar, da

  • Die Nachtabsenkung aktiv war

  • Und noch zwei weitere Handys für die Fritzbox sichtbar waren

 

Aktualisierung am 17.02.2016:

Ich habe durch einen Tipp aus dem Forum (direktes schreiben des Status auf dem Server) die Datei angepasst.

Was mir jedoch nicht gefiel, dass die Daten (u.a. das Loxone-Kennwort) unverschlüsselt durch das heimische Netz geschickt werden. Das soll mit der neuen Methode meines Erachtens besser sein. Denn der Miniserver empfängt nur noch einen Status den der raspberry sendet.

 

 

 

Als Inspiration diente mir folgender Forumeintrag:

Anwesenheit per WLAN feststellen

Dort habe ich die Grunddatei vom User Dott verwendet.

Das Perlskript zur Fritzbox-Abfrage kommt von Bock-Systems. Bitte auch von dort bitte die notwendigen Einstellungen für die Fritzbox nachschauen.

Benötigte Hard- und Software

  1. Linux-Server (raspberry pi ist ausreichend)

  2. Fritzbox

  3. iPhone oder Android mit aktiviertem WLAN

Fritzbox MAC-Adressen

Es gilt über die Fritzbox die MAC-Adressen der betroffenen Mobilfunkgeräte herauszufinden.

Die Übersicht für alle Netzwerkgeräte befindet sich bei FRITZ!OS 6.50 unter folgendem Pfad, wobei Android meistens mit "android-" beginnen und einer alphanumerischen Kombination enden.

  • Bei aktuell eingebuchten Geräten

    • Heimnetz -> Heimnetzübersicht -> Details beim jeweiligen Netzgerät

  • Bei vergangenen eingebuchten Geräten

    • Heimnetz -> Heimnetzübersicht -> Netzwerkverbindungen -> Details beim jeweiligen Netzgerät

Als Beispiel haben wir nun die MAC-Adressen erhalten

11:22:33:44:55:66 und 22:33:44:55:66:77, wobei eins davon ein iPhone und das andere ein Android-Handy ist.

Installieren der Perl-Umgebung auf dem Linux-Server

 

Installieren der Perl-Umgebung auf dem Linux-Server
sudo apt-get install libxml-simple-perl libio-all-lwp-perl libgetopt-long-descriptive-perl

 

Einrichten des Perl-Skriptes

Anschließend folgendes Perl-Skript in einem beliebigen Verzeichnis unter etwa folgendem Namen speichern, /home/pi/fritzbox-bewohner1.pl.

Funktionsweise des Skripts

Das Perl-Skript fragt die Fritzbox die MAC-Adressen ab und sendet per UDP "xxx-1" für online und "xxx"-0 für offline.

Die Information kann dann wie auf der Seite UDP Eingang definieren ausgewertet werden.

 

Perl-Skript zur Fritzbox-Abfrage
#!/usr/bin/perl -w use strict; use warnings; use LWP::Simple; use LWP::UserAgent; use XML::Simple; use Getopt::Long; use open qw(:std :utf8); use HTTP::Request::Common; use IO::Socket::INET; # ------------- Konfiguration ------------- my $ip = "192.168.xxx.xxx"; # IP Fritzbox my $port = "49443"; # Port Fritzbox my @macs_to_check = ("AA:BB:CC:DD:EE:FF"); # MAC Adresse der Geraete, es können mehrere eingetragen werden my $LOXIP = "192.168.xxx.xxx"; # IP Miniserver my $udpport = "34435"; # UDP-Port my $online = "xxx-1"; # Person Online my $offline = "xxx-0"; # Person Offline # ---------------- Programm ---------------- $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0; $ENV{HTTPS_DEBUG} = 1; my $ua = new LWP::UserAgent; $ua->default_headers; $ua->ssl_opts( verify_hostname => 0 ,SSL_verify_mode => 0x00); my $resp_discover = $ua->get("https://$ip:$port/tr64desc.xml"); my $xml_discover; if ( $resp_discover->is_success ) { $xml_discover = $resp_discover->decoded_content; } else { die $resp_discover->status_line; } my $discover = XMLin($xml_discover); print "$discover->{device}->{modelName} gefunden...\n"; my $control_url = "not set"; my $service_type = "not set"; my $service_command = "GetSpecificHostEntry"; foreach(@{$discover->{device}->{deviceList}->{device}->[0]->{serviceList}->{service}}){ if("urn:LanDeviceHosts-com:serviceId:Hosts1" =~ m/.*$_->{serviceId}.*/){ $control_url = $_->{controlURL}; $service_type = $_->{serviceType}; } } if ($control_url eq "not set" or $service_type eq "not set"){ die "control URL/service type not found. Cannot request host info!"; } $ua->default_header( 'SOAPACTION' => "$service_type#$service_command" ); my $xml_mac_resp; my $any_online = 0; foreach my $mac (@macs_to_check){ my $init_request = <<EOD; <?xml version="1.0" encoding="utf-8"?> <s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" > <s:Header> </s:Header> <s:Body> <u:$service_command xmlns:u="$service_type"> <NewMACAddress>$mac</NewMACAddress> </u:$service_command> </s:Body> </s:Envelope> EOD my $init_url = "https://$ip:$port$control_url"; my $resp_init = $ua->post($init_url, Content_Type => 'text/xml; charset=utf-8', Content => $init_request); $xml_mac_resp = XMLin($resp_init->decoded_content); if(exists $xml_mac_resp->{'s:Body'}->{'s:Fault'}){ if($xml_mac_resp->{'s:Body'}->{'s:Fault'}->{detail}->{UPnPError}->{errorCode} eq "714"){ print "MAC $mac nicht in der FritzBox gefunden!\n"; } } if(exists $xml_mac_resp->{'s:Body'}->{'u:GetSpecificHostEntryResponse'}){ if($xml_mac_resp->{'s:Body'}->{'u:GetSpecificHostEntryResponse'}->{NewActive} eq "1"){ my $name = $xml_mac_resp->{'s:Body'}->{'u:GetSpecificHostEntryResponse'}->{NewHostName}; my $ip = $xml_mac_resp->{'s:Body'}->{'u:GetSpecificHostEntryResponse'}->{NewIPAddress}; my $iftype = $xml_mac_resp->{'s:Body'}->{'u:GetSpecificHostEntryResponse'}->{NewInterfaceType}; print "MAC $mac ($name) ist online mit der IP $ip mit $iftype\n"; $any_online = 1; } if($xml_mac_resp->{'s:Body'}->{'u:GetSpecificHostEntryResponse'}->{NewActive} eq "0"){ my $name = $xml_mac_resp->{'s:Body'}->{'u:GetSpecificHostEntryResponse'}->{NewHostName}; print "MAC $mac ($name) ist offline\n"; } } } if ($any_online){ my $sock = new IO::Socket::INET(PeerAddr => $LOXIP, PeerPort => $udpport, Proto => 'udp', Timeout => 1) or die('Error opening socket.'); print $sock $online; exit 1; } else{ my $sock = new IO::Socket::INET(PeerAddr => $LOXIP, PeerPort => $udpport, Proto => 'udp', Timeout => 1) or die('Error opening socket.'); print $sock $offline; exit 0; }

Trennung des Skriptes

Um eine getrennte Abfrage für jeden Bewohner zu machen sind mehrere Skripte erforderlich. Also fritzbox-Bewohner1.pl, fritzbox-Bewohner2.pl, usw.

Automatisierung der Abfrage

Um das ganze automatisiert abfragen zu können ist wieder ein cronjob und die Ausführberechtigung für das Skript notwendig.

chmod +x /home/pi/fritzbox-Bewohner1.pl
cronjob anlegen

Folgende Zeilen am Ende einfügen:

Nun fragt der raspberry pi jede Minute den Status der anwesenden WLAN-Geräte bei der Fritzbox ab.

 

Den Empfang der UDP - Telegramme und die Verwertung im Miniserver ist unter UDP Eingang definieren beschrieben.