Montag, 11. Januar 2016

Anwesenheitserkennung

Da gibt es viele Artikel die sich mit der Lösung beschäftigen - aber was ist eigentlich das Problem?

Ich will nicht einfach ein Code Beispiel liefern, ich will vor allem beschreiben, warum es so komplex scheint. Der hier beschriebene Code funktioniert fast vollständig als Trockenübung. In der realen Umgebung müssen einige Definitionen angepasst werden.

Erkennung von Geräten

Heute hat praktisch jeder ein Smartphone. Das WLAN und Bluetooth Modul bieten eine gute Möglichkeit der Erkennung. Wlan durch Anmeldung beim Router, Bluetooth durch einen "Ping" auf die MAC Adresse. Die MAC Adresse ist eine eindeutige Hardware Adresse des Gerätemoduls. Sicher bzw. Fälschungssicher ist diese nicht! Für die Erkennung muss die WLAN und Bluetooth MAC bekannt sein!

Die Anwesenheit der Geräte (Komponenten) wird durch ein PRESENCE Device oder dummy Devices erzeugt. Die Anzahl der Komponenten, die eine Person als vorhanden ermitteln können, kann fast beliebig sein. Dabei gilt:

  • ist ein Gerät vorhanden, ist die Person da. 
  • Sind alle Geräte abwesend ist die Person abwesend.

Alle Geräte (PRESENCE Definitionen) werden dafür einfach in eine structure gepackt. Damit die erwartungsgemäß funktioniert, muss festgelegt werden wie die Komponenten die structure beeinflussen soll. Dies wird durch drei Attribute erreicht: clientstate_behavior, clientstate_priority, event-on-change-reading.

Erkennung von Personen

Die Person selbst wird durch einen dummy device erzeugt. Diese zusätzliche Geräteinstanz ist nötig um einen gewisse Toleranz bei Abwesenheit zu erzeugen (Neustart Gerät, mal kurz im Keller oder vorm Haus usw.) D.h. die Gerätegruppe (structure) wird abgefragt und entsprechend ein dummy gesetzt. Wird die structure als present erkannt, ist jemand gekommen und der Status des dummy wird sofort gesetzt. Wird die structure als absent erkannt, wird eine gewisse Zeit gewartet. Sollte die structure nicht zurück auf present gesetzt werden, wird der Status auf absent gesetzt. Typischerweise nimmt man dafür eine watchdog Funktion. Diese lässt sich ziemlich einfach mit einem DOIF realisieren.

Der Code

Die Definition für FHEM sieht Beispielhaft so aus:
 define Dev11 dummy  
 attr Dev11 event-on-change-reading state  
 attr Dev11 eventMap 0:absent 1:present  
 attr Dev11 room Status  
 attr Dev11 webCmd present:absent  
 define Dev12 dummy  
 attr Dev12 event-on-change-reading state  
 attr Dev12 eventMap 0:absent 1:present  
 attr Dev12 room Status  
 attr Dev12 webCmd present:absent  
 define st_Dev1 structure bewohner Dev11 Dev12  
 attr st_Dev1 clientstate_behavior relative  
 attr st_Dev1 clientstate_priority present|1 absent|0  
 attr st_Dev1 event-on-change-reading state  
 attr st_Dev1 room Status  
 define PersonD1 dummy  
 attr PersonD1 room Status  
 define di_st_Dev1 DOIF ([st_Dev1] eq "absent")(set PersonD1 absent) DOELSEIF ([st_Dev1] eq "present")(set PersonD1 present)  
 attr di_st_Dev1 room Status  
 attr di_st_Dev1 wait 10  

Der Trick mit Telnet

Mittlerweile ist der "Trick" mit Telnet überholt. Aktuell arbeitet man besser mit der Raw Definition.
So landet das Codebeispiel direkt über die Commandzeile in der fhem.cfg

Mit putty (oder einem anderen Terminalprogramm) auf den Host (RaspberryPi) verbinden. Im Terminal folgendes eingeben:

 telnet localhost 7072  

Wenn ein Telnet Passwort vergeben wurde, wird dies abgefragt. Anschließen sooft enter drücken bis der fhem> Prompt erscheint. Jetzt einfach die Codezeilen in die Zeile kopieren.

Die Abfrage der Fritzbox

Um die Fritzbox abzufragen, verwende ich die checkAllFritzMACpresent Funktion aus dem Wiki . Die Fritzbox wird durch ein FRITZBOX Device in FHEM abgebildet.
Ich habe ein DOIF gebaut, das mehrere Geräte abfragen kann. Dazu werden die Geräte Stati in userReadings geschrieben. Bitte die userReadings und dummy's nicht gleich benennen, das führt zu Eigenheiten wenn man etwas loggen will.
 define di_FBAbfrage DOIF ([FB7490:?lastReadout.*]) (set Dev11 [di_FBAbfrage:D11], set Dev21 [di_FBAbfrage:D21])  
 attr di_FBAbfrage do always  
 attr di_FBAbfrage room Status  
 attr di_FBAbfrage userReadings D11 {checkAllFritzMACpresent("AA:BB:CC:DD:EE:FF")}, D21 {checkAllFritzMACpresent("11:22:33:44:55:66")}
 attr di_FBAbfrage wait 2

Das DOIF wird immer getriggert wenn die Fritzbox abgefragt wird. Es pollt also nicht zusätzlich wie die meisten anderen Lösungen. Um sicherzustellen, dass die Abfrage der Fritzbox abgeschlossen und die userReadings gesetzt sind wird mit der commando Ausführung 2 sec gewartet.
Diese Lösung erklärt auch die eventMap Attribute in dem Geräte dummy. Diese übersetzen die Resultate der Subroutine (0|1) in Presenceinformationen (absent|present).

Die Bewohner

Mehrere Personen können jetzt noch in eine structure zusammengefasst werden. Dabei gehen wir analog der Dev1 structure vor. Der zusätzliche dummy und das Watchdog werden nicht benötigt.

define st_Bewohner structure bewohner PersonD1 PersonD2

Damit ist es möglich sowohl Personen als auch Bewohner bezogene Aktionen auszulösen. Hierfür definiert man notify's oder DOIF's die dem Personen dummy oder der Bewohner structur getriggert werden.

Die Skalierung

Steht einmal die gesamte Struktur der Anwesenheitserkennung, gibt es zwei Ansatzpunkte um leicht etwas zu ändern:
Zusätzliches Kriterium der Anwesenheit der Person: einfach zusätzliche definieren und anschließend die Structure der Geräte mit addstruct bzw. delstruct.
addstruct st_Dev1 Dev13
Zusätzliche Person: einfach die Person definieren und mit addstruct bzw. delstruct zur Structure der Bewohner hinzufügen
addstruct st_Bewohner PersonNeu

Keine Kommentare:

Kommentar veröffentlichen