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.
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
- Linux-Server (raspberry pi ist ausreichend)
- eingerichter Webserver (Apache oder lighthttp)
- Fritzbox
- 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.
Einrichten des Linux-Servers
Falls ein Webserver noch nicht eingerichtet sein sollte, lässt sich das relativ schnell nachholen mit folgendem Befehl:
sudo apt-get install apache2
Anschließende muss für die Funktionalität des Perl-Skriptes noch etwas nachinstalliert werden.
sudo apt-get install libxml-simple-perl libio-all-lwp-perl libgetopt-long-descriptive-perl
Test des Webservers
Ein erster Test sollte der Ereichbarkeit des Webservers gelten, dazu die IP-ADRESSE des Servers eingeben und über folgenden Text freuen
It works! This is the default web page for this server. The web server software is running but no content has been added, yet.
Einrichten des Perl-Skriptes
Anschließend folgendes Perl-Skript in einem beliebigen Verzeichnis unter etwa folgendem Namen speichern, /home/pi/fritzbox-bewohner1.pl.
Es sind folgende Anpassungen notwendig und zwar im oberen Bereich, beim dem Block und ziemlich weit unten im Bereich der Pfad-Angaben:
# ---------------- Konfig ---------------- my $ip = "xxx.xxx.xxx.xxx"; my $port = "49443"; my @macs_to_check = ("11:22:33:44:55:66", "22:33:44:55:66:77"); # ----------------/Konfig ---------------- if ($arg_any){ if ($any_online){ #print "Anwesend"; my $datei = '/var/www/on-Bewohner1'; open (my $fh, ">>", $datei) or die "Kann Datei $datei nicht oeffnen: $!"; print $fh strftime("%Y-%m-%d %H-%M-%S", localtime), " Anwesend\n"; close $fh; my $dateianwesend = '/var/www/anwesend-Bewohner1'; open (my $fhanwesend, ">", $dateianwesend) or die "Kann Datei $datei nicht oeffnen: $!"; print $fhanwesend strftime("%Y-%m-%d %H-%M-%S", localtime), " Wert = 1\n"; close $fhanwesend; } else{ #print "Abwesend"; my $datei = '/var/www/off-Bewohner1'; open (my $fh, ">>", $datei) or die "Kann Datei $datei nicht oeffnen: $!"; print $fh strftime("%Y-%m-%d %H-%M-%S", localtime), " Abwesend\n"; close $fh; my $dateianwesend = '/var/www/anwesend-Bewohner1'; open (my $fhanwesend, ">", $dateianwesend) or die "Kann Datei $datei nicht oeffnen: $!"; print $fhanwesend strftime("%Y-%m-%d %H-%M-%S", localtime), " Wert = 0\n"; close $fhanwesend; exit 0; } }
Hier nun das Perl-Skript
#!/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 POSIX qw/ strftime /; # ---------------- Konfig ---------------- my $ip = "xxx.xxx.xxx.xxx"; my $port = "49443"; my @macs_to_check = ("11:22:33:44:55:66", "22:33:44:55:66:77"); # ----------------/Konfig ---------------- # Arguments # "any" checks if at least one/any MAC is online my $arg_any = ''; GetOptions('any' => \$arg_any); # disable SSL checks. No signed certificate! $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0; $ENV{HTTPS_DEBUG} = 1; # Discover Service Parameters my $ua = new LWP::UserAgent; $ua->default_headers; $ua->ssl_opts( verify_hostname => 0 ,SSL_verify_mode => 0x00); # Read all available services 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} detected...\n" unless $arg_any; # Parse XML service response, get needed parameters for LAN host service my $control_url = "not set"; my $service_type = "not set"; my $service_command = "GetSpecificHostEntry"; # fixed command for requesting info of specific MAC 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!"; } # Prepare request for query LAN host $ua->default_header( 'SOAPACTION' => "$service_type#$service_command" ); my $xml_mac_resp; my $any_online = 0; # if arg any specified 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 not found in FritzBox Database!\n" unless $arg_any; } } 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) is online with IP $ip on $iftype\n" unless $arg_any; $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) is offline\n" unless $arg_any; } } } # If "any" arg was passed, only print summary status if ($arg_any){ if ($any_online){ #print "Anwesend"; my $datei = '/var/www/on-Bewohner1'; open (my $fh, ">>", $datei) or die "Kann Datei $datei nicht oeffnen: $!"; print $fh strftime("%Y-%m-%d %H-%M-%S", localtime), " Anwesend\n"; close $fh; my $dateianwesend = '/var/www/anwesend-Bewohner1'; open (my $fhanwesend, ">", $dateianwesend) or die "Kann Datei $datei nicht oeffnen: $!"; print $fhanwesend strftime("%Y-%m-%d %H-%M-%S", localtime), " Wert = 1\n"; close $fhanwesend; } else{ #print "Abwesend"; my $datei = '/var/www/off-Bewohner1'; open (my $fh, ">>", $datei) or die "Kann Datei $datei nicht oeffnen: $!"; print $fh strftime("%Y-%m-%d %H-%M-%S", localtime), " Abwesend\n"; close $fh; my $dateianwesend = '/var/www/anwesend-Bewohner1'; open (my $fhanwesend, ">", $dateianwesend) or die "Kann Datei $datei nicht oeffnen: $!"; print $fhanwesend strftime("%Y-%m-%d %H-%M-%S", localtime), " Wert = 0\n"; close $fhanwesend; exit 0; } }
Funktionsweise des Skripts
Das Skript fragt die Fritzbox nach ob die im Konfig-Block angegeben MAC-Adressen anwesend sind und schreibt dann je nach Zustand in folgende Dateien:
- Bei Anwesenheit
- /var/www/anwesend-Bewohner1
- das aktuelle Datum und die Uhrzeit und Wert = 1
- /var/www/on-Bewohner1
- fortlaufend das Datum und die Uhrzeit und den Status Anwesend
- /var/www/anwesend-Bewohner1
- Bei Abwesenheit
- /var/www/anwesend-Bewohner1
- das aktuelle Datum und die Uhrzeit und Wert = 0
- /var/www/on-Bewohner1
- fortlaufend das Datum und die Uhrzeit und den Status Abwesend
- /var/www/anwesend-Bewohner1
Je nach An- oder Abwesenheit werden unter der Datei /var/www/anwesend-Bewohner1 nun zwei Werte gepeichert. Wobei 1 für An- und 0 für Abwesenheit steht. Diese Werte können nun zur Auswertung für den Miniserver verwendet werden.
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
sudo crontab -e
Folgende Zeilen am Ende einfügen:
* * * * * /usr/bin/perl /home/pi/fritzbox-Bewohner1.pl -any >/dev/null 2>&1
Nun fragt der raspberry pi jede Minute den Status der anwesenden WLAN-Geräte bei der Fritzbox ab.
Einrichtung Loxone
In Loxone muss als Erstes folgendes erstellt werden:
Einen virtuellen HTTP-Eingang mit folgenden Einstellungen:
Anschließend ein Virtueller HTTP Eingang Befehl mit folgenden Einstellungen:
Anschließend noch eine leicht abgewandelte Config-Version von dott:
Der Statusbaustein sieht folgendermaßen aus: