Präsenz / Anwesenheitserkennung Smart Mirror – Geofence

Eigentlich wollte ich die Anwesenheitserkennung meines Smart Mirrors über einen Bluetooth Ping regeln, was sich aber leider aufgrund von Problemen mit dem Bluetooth Stack bluez als nicht machbar herausgestellt hat. Ich habe hier darüber geschreiben.

Das schöne am l2ping wäre die sehr einfache Implementierung gewesen und man wäre nicht auf das Smartphone als Partnergerät angewiesen gewesen. Auch Geräte wie z.B. Wearables hätte man einbinden können.

Geofence

Mit Apps wie z.B. Geofency (iPhone) oder EgiGeoZone (Android) kann man einen virtuellen Zaun um den eigenen Wohnort ziehen und bei dessen Betreten und Verlassen Events triggern.

Ich habe meine App Geofency so eingerichtet, dass mein Smartphone beim Betreten des Grundstücks eine URL mit Parametern auf meinem Smart Mirror aufruft und dort ein Flag setzt, das für meine Anwesenheit steht.

Damit der Smart Mirror nicht nur auf meine Anwesenheit sondern auch auf die meiner Freundin reagiert, ist der HDMI Port nur dann aus, wenn wir beide nicht anwesend sind.
Auf dem Smart Mirror läuft ein Webserver mit einem .php Script, das die Befehle unserer Geofence Apps entgegennimmt und verarbeitet. Es werden die Befehle unterteilt in die Zugehörigkeit von „Silvan“ und „Sabine“ sowie „Ist anwesend – 1“ und „Ist abwesend – 0“.

Die beiden Werte werden in zwei Textdateien festgehalten auf die im weiteren Schritt ein Code Snippet zugreift, das den Innhalt auswertet und den HDMI Port abschaltet, sobald beide Werte auf „Ist abwesend – 0“ stehen.

Geofency arbeitet mit POST und EgiGeoZone mit GET. Deshalb muss ich beide Varianten auswerten.

In dem Code Snippet sind noch Log- und Diagnosefunktionen auskommentiert, die bei der Einrichtung helfen und euch z.B. die ID zeigen mit der sich das iPhone meldet.

Zu beachten ist, dass die Logfiles auf dem Apache die entsprechenden Zugriffsrechte besitzen und der Gruppe www-data gehören.

Bildschirmfoto 2016-03-21 um 00.00.10

geofence.php

<?php
        //print_r($_POST);
if(isset($_GET['entry'])){
$entry=$_GET["entry"];
$device=$_GET["device"];
$name=$_GET["name"];
$id=$_GET["id"];
}
 
else if(isset($_POST['entry'])){
$entry=$_POST["entry"];
$device=$_POST["device"];
$name=$_POST["name"];
$id=$_POST["id"];
}else{
$entry="";
$device="";
$name="";
$id="";
}
 
if ($device == "D07D3xxx-Bxxx-4xxx-Bxxx-4BE759DE9xxx"){
        if($entry == 1)
                file_put_contents("silvan.log", "1");
        else
                file_put_contents("silvan.log", "0");
        }
 
if ($device == "sabine"){
        if($entry == 1)
                file_put_contents("sabine.log", "1");
        else
                file_put_contents("sabine.log", "0");
        }
 
$t_sabine = file_get_contents('sabine.log');
$t_silvan = file_get_contents('silvan.log');
 
if ($t_sabine == "1" || $t_silvan == "1")
        exec("sudo /var/www/html/modules/geofence/onoff.sh 1");
else
        exec("sudo /var/www/html/modules/geofence/onoff.sh 0");
 
//    $filename = "geofence.log";
//    file_put_contents($filename, $_POST, FILE_APPEND);
?>

onoff.sh

Das Script „onoff.sh“ wird entweder mit den Parametern „1“ (on) und „0“ (off) aufgerufen und steuert den HDMI Port.

#!/bin/bash
if [ $1 == "0" ]
 then
 vcgencmd display_power 0
 else
 vcgencmd display_power 1
fi

[twoclick_buttons]


l2ping lässt Raspberry einfrieren

Zur Präsenzerkennung für meinen Smart Mirror hätte ich gerne mit den Bordmitteln meines Raspberrys einen Bluetooth Ping via l2ping genutzt um darüber die Anwesenheit meines Smartphones oder das meiner Freundin zu erkennen und damit den HDMI Port des Bildschirms an oder aus zu schalten.

Das Prinzip ist eigentlich einfach. Man ermittelt die Bluetooth MAC-Adresse des zu erkennenden Bluetoothgeräts und fragt in regelmäßigen Abständen dieses Gerät via l2ping an. Meldet es sich zurück, ist diejenige Person anwesend und der HDMI Port kann angeschaltet bleiben.

Das schöne an l2Ping ist, dass das Smartphone/Wearable o.ä. nicht mit dem Smart Mirror connected sein muss. Das Bluetooth der Geräte muss lediglich aktiviert sein. Ein großer Komfortgewinn gegenüber einer permanenten Koppelung.

Leider scheint mit dem Raspberryeigenen Bluetooth Stack „bluez“ etwas nicht zu stimmen. Einzelne Anfragen via l2ping werden zwar ordentlich verarbeitet nach einer Vielzahl von Anfragen friert der Raspberry Pi irgendwann komplett ein, sodass nur noch die Stromquelle getrennt werden kann.

Der einfache l2ping mit Parameter -f (Floodping) reicht bei mir aus um das System nach einiger Zeit einzufrieren.

sudo l2ping -f 12:23:34:45:56:67

Es dauert bei mir ca. 350 Anfragen bis der Raspberry komplett einfriert.

Leider bin ich nicht der einzige, der dieses Problem hat. Es gibt in Foren zur Heimautomation bereits einige Berichte darüber dass Leute über den l2ping Befehl gerne die Anwesenheitserkennung steuern würden, ihnen aber leider je nach Häufigkeit der Pings die Geräte irgendwann einfrieren.

Ich bin kein C-programmierer und kann deshalb leider nur mutmaßen was hier falsch läuft aber ein Punkt in dem source code von bluez-l2ping kommt mir verdächtig vor.

Und zwar wird bei jeder Anfrage ein neuer Socket erstellt, der aber nur im Fehlerfall wieder geschlossen wird:

error:
	close(sk);
	free(send_buf);
	free(recv_buf);
	exit(1);

Ist das Bluetoothgerät also in Reichweite, läuft irgendwann der Sockethandler voll (so meine Vermutung). Ich habe die Entwickler des l2ping zwar angeschrieben und habe das Problem beschrieben aber wie und ob das Problem behoben werden kann, steht noch in den Sternen. l2ping taugt also leider (noch) nicht für eine Präsenzerkennung zur Heimautomation.

Update

Ich dachte ich hätte mit Python einen weiteren Ansatz gefunden ein Bluetooth Gerät zu detektieren. Und zwar mit Hilfe von:

#!/usr/bin/python
import bluetooth

while True:
    result = bluetooth.lookup_name('12:23:34:45:56:67', timeout=5) 
    if (result != None): 
        print "Gerät da" 
    else: 
        print "Gerät nicht da"

Leider führt aber auch dieses Script zum Einfrieren des Raspberrys. Im Hintergrund wird dabei vermutlich auch der Stack von bluez verwendet.
[twoclick_buttons]