Anwesenheitserkennung via Bluetooth (BLE) und G-Tags

Dieser Artikel beschreibt, wie eine Anwesenheitserkennung via Bluetooth realisiert werden kann.
Es handelt sich hier um eine von vielen möglichen Varianten.
Diese kommt ohne Bastelarbeiten aus. Ist bereits ein Linux System vorhanden - z.B. ein Raspberry Pi lassen sich die Kosten auf wenige Euro für die Leseeinheit drücken.
Als Tags können die Gigaset G-Tags aber auch andere BLE (Bluetooth Low Energy) Tags verwenden. Getestet habe ich es auch mit einfacheren Tags. 

 

 

Schritt-für-Schritt-Anleitung

  1. Zuerst muss der Bluetooth Dongle beschafft werden.
    Hat der Rechner bereits ein Bluetooth Modul sollte das genügen.
    Ich habe den LogiLink BT0015 verwendet. (Kostet unter 10 Euro)  
     

  2. Da ich bereits einen Linux Server hatte, kann ich ihn benutzen.
    Wer keinen hat, müsste sich einen aufsetzen - da gibt es diverse Anleitungen - das erspare ich uns hier. 
    Er sollte am Ende der Installation einen lauffähigen Webserver beinhalten.
     

  3. Auf dem Server muss dann das Paket bluez installiert sein.

    aptitude install bluez
     

  4. Mit den Kommandos hciconfig und hcitool kann man dann versuchen den Dongle zu aktivieren und die Tags zu scannen:

    Prompt> hciconfig hci0 up
    Prompt> /usr/bin/hcitool lescan

    LE Scan ...
    7C:2F:81:91:A1:B2 (unknown)
    7C:2F:81:91:A1:B2 Gigaset G-tag


    Wenn das nicht klappt, könnt ihr im Internet diverse Tutorials finden, wie das einzurichten ist
    oder wie die Fehlersuche anzugehen ist. Das würde hier den Rahmen sprengen. Ich setzte
    für die weitere Anleitung voraus, dass der Scan klappt. 
     

  5. Nun wird ein Shell Script erstellt, welches die Dongles scannt. Ich habe es scantag.sh genannt.

    scantag.sh

    hciconfig hci0 down hciconfig hci0 up (/bin/sleep 8;/usr/bin/killall --signal 2 /usr/bin/hcitool) |/usr/bin/hcitool lescan |grep -v "LE Scan" |cut -c1-17|sort -u

    Ich habe dem Script als Gruppe und Eigentümer root zugewiesen und die Rechte eingeschränkt:

    chmod 500 scantag.sh 
    chown root:root scantag.sh 
     

  6. Als nächstes müssen wir dem PHP-Script erlauben, das Scan-Script auszuführen.

    Dies erfolgt mit Hilfe des folgenden Kommandos und Hinzufügen des Eintrags für www-data:

    sudo visudo

    www-data ALL = NOPASSWD:/home/www/wo-auch-immer/scantag.sh
     

  7. Nun das PHP-Script, welches vom Miniserver bei einer Leseanforderung aufgerufen wird:

    index.php

    <?php // Bekannte G-Tags: $tags_known['1'] ="7C:2F:81:91:A1:B1"; // Tag rot $tags_known['2'] ="7C:2F:81:91:A1:B2"; // Tag grün $tags_known['4'] ="7C:2F:81:91:A1:B3"; // Tag schwarz $tags_known['8'] ="7C:2F:81:91:A1:B4"; // Tag orange $tags_known['16'] ="7C:2F:81:91:A1:B5"; // Tag weiß //31 = alle da //16 weiss //8 orange //4 schwarz //2 grün //1 rot function output($output) { echo $output." \n"; $socket = fsockopen('udp://miniserver:11111'); fputs($socket, "$output"); return; } // Ausführen des BLE-Scans exec('sudo /home/www/wo-auch-immer/scantag.sh',$tags_found); $tags_found = array_unique($tags_found,SORT_STRING); $bitmask=0; while(list($tag_user, $tag_mac) = each($tags_known)) { unset($found_tags); $found_tags = array_filter($tags_found, function($varu) use ($tag_mac) { return preg_match("/\b$tag_mac\b/i", $varu); }); if (count($found_tags) >= 1) { $bitmask=$bitmask + $tag_user; } } output($bitmask);

    Wenn man das Script im Browser aufruft, sollte eine Zahl welche in der Matrix den anwesenden Personen entspricht zurückgegeben werden.
    Parallel sendet das Script die Zahl auf den Port 11111 des Miniservers (virtueller Eingang).
     

  8. Zum Senden der Leseanforderung wird in der Loxone Config wird nun ein Virtueller Ausgang "G-Tag Leseanforderung" erstellt.

     

    Dahinter wird der Befehl erstellt:  (das ?read_G-Tags ist optional)

    Befehl bei EIN:  /bt/?read_G-Tags 

    HTTP Methode bei EIN:  GET 
     

  9. Zum Einlesen geht nun ein Merker auf Tr eines verzögerten Impuls Bausteins mit D: 0 und T; 90.
    Dieser verzögerte Impuls Baustein geht mit Q auf einen Impulsgeber mit TH: 0,5 und TL: 8,5.
    Dieser Impulsgeber geht mit Q direkt an den Virtuellen Ausgang.
    Wird der Merker nun getriggert, sendet der Miniserver für 90 Sekunden alle 9 Sekunden eine Leseanforderung.
    Der Merker wird durch diverse Ereignisse gesteuert - durch Bewegung vor und im Haus zum Beispiel.
     

  10. Nun der Empfangs-Teil. Dafür wird in der Loxone Config ein virtueller Eingang für die IP des Linux Rechners auf z.B. Port 11111 erstellt:

    Dahinter folgt wieder ein Befehl:

    Befehlserkennung: \v

    Als Digitaleingang verwenden nicht anhaken.

    Der Ausgang des Eingang-Befehls geht nun an AI1 eines Statusbausteins welcher auf der Favoriten-Seite visualisiert wird:

     

  11. Da mir das zu heftig war, das alles in die Loxone Config zu klickern, habe ich mir eine Excel Tabelle erstellt und diese
    dann über einen Editor direkt als XML in die .loxone Projektdatei eingefügt.
    Bei mir sieht das dann so aus:

    Status-Text-Block

    <StateTexts Num="32"> <StateText Valid="true" ValidV="true" Text="Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="1"/> <StateText Valid="true" ValidV="true" Text="Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="2"/> <StateText Valid="true" ValidV="true" Text="Chrissi &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="3"/> <StateText Valid="true" ValidV="true" Text="Moritz da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="4"/> <StateText Valid="true" ValidV="true" Text="Moritz &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="5"/> <StateText Valid="true" ValidV="true" Text="Moritz &amp; Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="6"/> <StateText Valid="true" ValidV="true" Text="Moritz, Chrissi &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="7"/> <StateText Valid="true" ValidV="true" Text="Oskar da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="8"/> <StateText Valid="true" ValidV="true" Text="Oskar &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="9"/> <StateText Valid="true" ValidV="true" Text="Oskar &amp; Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="10"/> <StateText Valid="true" ValidV="true" Text="Oskar, Chrissi &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="11"/> <StateText Valid="true" ValidV="true" Text="Oskar &amp; Moritz da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="12"/> <StateText Valid="true" ValidV="true" Text="Oskar, Moritz &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="13"/> <StateText Valid="true" ValidV="true" Text="Oskar, Moritz &amp; Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="14"/> <StateText Valid="true" ValidV="true" Text="Oskar, Moritz, Chrissi &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="15"/> <StateText Valid="true" ValidV="true" Text="Heinz da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="16"/> <StateText Valid="true" ValidV="true" Text="Heinz &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="17"/> <StateText Valid="true" ValidV="true" Text="Heinz &amp; Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="18"/> <StateText Valid="true" ValidV="true" Text="Heinz, Chrissi &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="19"/> <StateText Valid="true" ValidV="true" Text="Heinz &amp; Moritz da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="20"/> <StateText Valid="true" ValidV="true" Text="Heinz, Moritz &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="21"/> <StateText Valid="true" ValidV="true" Text="Heinz, Moritz &amp; Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="22"/> <StateText Valid="true" ValidV="true" Text="Heinz, Moritz, Chrissi &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="23"/> <StateText Valid="true" ValidV="true" Text="Heinz &amp; Oskar da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="24"/> <StateText Valid="true" ValidV="true" Text="Heinz, Oskar &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="25"/> <StateText Valid="true" ValidV="true" Text="Heinz, Oskar &amp; Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="26"/> <StateText Valid="true" ValidV="true" Text="Heinz, Oskar, Chrissi &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="27"/> <StateText Valid="true" ValidV="true" Text="Heinz, Oskar &amp; Moritz da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="28"/> <StateText Valid="true" ValidV="true" Text="Heinz, Oskar, Moritz &amp; Ulli da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="29"/> <StateText Valid="true" ValidV="true" Text="Heinz, Oskar, Moritz &amp; Chrissi da " TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="30"/> <StateText Valid="true" ValidV="true" Text="Heinz, Oskar, Moritz, Chrissi &amp; Ulli da" TextV="1" Icon="00000000-0000-0000-0000000000000000" Input0="1" CondV0="31" CondT0="31"/> <StateText Valid="true" ValidV="true" Text="Niemand anwesend" TextV="0" Icon="00000000-0000-0000-0000000000000000"/> </StateTexts>

    Der Ausgang TQ geht an einen visualisierten Logger-Baustein und der AQ über verzögerte Impuls-Bausteine an die Alarmanlage usw. 

  12. Viel Spaß bei der Umsetzung. 
     

Dieses Script ist sicher verbesserbar - über Anregungen freue ich mich immer. Verwendung auf eigene Gefahr!

Die Reichweite ist relativ gering und beträgt bei mir etwa 10 m. Der USB-Dongle sollte also schon nah am Schlüsselbrett/-körbchen oder der Garderobe positioniert sein wo sich die G-Tags befinden.

Ich habe ab und zu Aussetzer beim Einlesen welche dann im Logger-Baustein unschön als Niemand anwesend aufgelistet werden.
Das versuche ich noch irgendwie abzufangen. Da ich aber hauptsächlich den Statusbaustein auf der Favoriten-Seite nutze und die
Historie nur in einem Unterpunkt visualisiere stört es mich bisher nicht so sehr.

Verwandte Artikel