Zum Ende der Metadaten springen
Zum Anfang der Metadaten

Diese Anleitung beschreibt, wie man mit einer Fritz!Box 7490 eine Smartphone-Anwesenheitserkennung via WLAN-Erkennung bauen kann.

Voraussetzung

Die Voraussetzung zur Nutzung des Scripts ist eine Server mit einer laufenden Perl-Installation und einem Cron-Daemon.

Schritt-für-Schritt-Anleitung

  1. Zuerst wird das Perl Script fritzbox-bewohner.pl mit folgendem Inhalt erstellt:

    fritzbox-bewohner.pl
    #!/usr/bin/perl -w
    #####################################################
    # Script zur Anwesenheitserkennung von WLAN-Geräten #
    # an einer Fritz!Box 7490 in Verbindung mit einem   #
    # Loxone Miniserver                                 #
    # Version: 2016.02.27.15.09.14                      #
    #####################################################
    # Miniserver UDP Information
    my $mshost        = 'miniserver';         # Miniserver-IP oder Hostname
    my $msport        = 7007;                 # Miniserver UDP-Empfangsport
    my $msprotocol    = 'udp';
    
    # Fritz!Box Information
    my $ip = 'fritz.box'; # Fritz!Box-IP oder Hostname
    my $port = 49443;     # Fritz!Box Port
    # Flushing to STDOUT after each write
    $| = 1;
    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 /;
    use IO::Socket;
    # Check Command Line parameters
    # Minumum 2 - Resident and at least one Phone-MAC address
    my $num_args = $#ARGV + 1;
    if ($num_args < 2) 
    {
        print "Missing command line argument!";
        print "\nUsage: fritzbox-bewohner.pl <BewohnerN> <Handy-MAC1> [<Handy-MACn>]";
        print "\nExample: fritzbox-bewohner.pl Bewohner1 00:00:00:00:00:00\n";
        exit;
    }
    # Alle MACs sammeln und im Array macs_to_check speichern 
    my @macs_to_check =($ARGV[1]);
    my $bewohner = $ARGV[0];
    print "Checking presence for User ".$bewohner." with MAC ".$ARGV[1];
    for (my $mac=1; $mac <= $num_args-2; $mac++) 
     { 
      push @macs_to_check, $ARGV[$mac+1];
      print " or MAC ".$ARGV[($mac+1)];
     }
    print " at " . $ip ." on port " . $port . "...\n";
    # 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"; 
    
    # 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";
                    }
             }
            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";
                            $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"; 
                    }
           }
    }
    # Creating UDP socket to Miniserver
    my $client = IO::Socket::INET->new (
        PeerAddr    => $mshost,
        PeerPort    => $msport,
        Proto       => $msprotocol,
        Type        => SOCK_DGRAM
    ) or die "Socket could not be created, failed with error: $!\n";
    print "Sending Data '".$bewohner.":".$any_online."' to $mshost on port $msport ...\n";
    $client->send($bewohner.":".$any_online);
    $client->close();
  2. Danach wird die Konfiguration dieses Scripts angepasst. Es ist die Adresse der Fritzbox und des Miniservers anzupassen. Auf Wunsch auch der UDP-Port des Miniservers welcher die Info empfängt.
  3. Nun wird ein Eintrag in der Crontab des Servers angelegt. Ich rufe das Script jede Minute auf. Die Fritz!Box liefert die Daten sowieso bis zu 15 Minuten verzögert aus.

    crontab
    * * * * * /usr/bin/perl /home/pfad/zum/script/fritzbox-bewohner.pl Bewohner1 54:4E:90:11:22:33 >/dev/null 2>&1
    * * * * * /usr/bin/perl /home/pfad/zum/script/fritzbox-bewohner.pl Bewohner2 14:A3:64:44:55:66 >/dev/null 2>&1 
  4. In der Loxone Config muss nun ein Virtueller UDP Eingang ersellt werden:
    Die Senderadresse ist optional aber beim UDP Empfangsport muss die Port-Nummer vom $msport eingetragen werden. Hier im Beispiel ist es die 7007
  5. Ausserdem wird nun für jeden Bewohner in der In der Loxone Config ein Virtueller UDP Eingang Befehl angelegt.
    Als Befehlserkennung ist \iBewohner1:\i\v zu verwenden wobei Bewohner1 für jeden Bewohner anzupassen ist und dem ersten Parameter des Scripts in der Crontab entspricht.
  6. Ich gehe dann mit den Daten durch einen Status-Baustein auf einen Tracker.


Dank an jdlwguard-loxone und svethi welche mich motiviert haben, das umzusetzen und von wo ich Teile des Codes übernommen habe. 
 

Erfolgreich getestet mit einer Fritz!Box 7490 mit Fritz!OS 06.51 an einem Miniserver Version 7.3.2.24 und Iphone 6 sowie Samsung S3 Neo.

Verwandte Artikel

3 Kommentare

  1. Marco Grasso sagt:

    Hallo, ich habe das ganze einmal übernommen! Leider mag es mein iPhone nicht! Das von meiner Frau wird richtig dargestellt. Ich bin nie anwesend.

     

    1. Hast Du dafür eine Lösung gefunden ?
      Hab bei meiner Frau genau dasselbe Problem (Zwinkern)

  2. Marco Grasso sagt:

    Hi, sorry für die Späte Antwort, ich habe das iPhone umbenannt in Bananen Handy, seit dem geht es!

    Es scheint das die FB meinen Namen nicht zu mag.