Da die Anwesenheitskontrolle mittels Handyerkennung per WLAN-Ping ab Andoid 6 nicht mehr zuverlässig funktionierte musste ich nach einer anderen Möglichkeit suchen die Anwesenheit unserer Mobiltelefone - vor allem zuverlässig und dauerhaft - zu realisieren.
Voraussetzung war, dass ich nicht noch weitere zusätzliche Mini-Rechner im Haus verteilen muss sondern meine vorhandenen AccessPoints mit installiertem openWRT verwenden kann - die sind nämlich sowieso schon vorhanden (insgesamt 5 Stück im eigenen Haus, Gartenhaus und benachbarten Elternhaus).
Nach vielen Versuchen und geopferten Nächten habe ich es endlich hinbekommen eine zentral verwaltete, über verteilte Clients laufende Anwesenheitskontrolle per Bluetooth auf openWRT zu realisieren.
Was wird benötigt?
- Access Points mit openWRT (z.B. GL.iNet GL-MT300N)
- USB-Bluetooth-Dongle (http://r.ebay.com/ESoHU0 (http://r.ebay.com/ESoHU0))
Folgende Schritte sind nötig:
1.) USB-Bluetooth-Unterstützung auf openWRT (anlehnend an https://wiki.openwrt.org/doc/howto/usb.bluetooth (https://wiki.openwrt.org/doc/howto/usb.bluetooth)):
Per SSH auf openWRT verbinden.
Anschliessend mit
opkg update
opkg install kmod-bluetooth bluez-libs bluez-utils kmod-usb-core kmod-usb-uhci kmod-usb2 usbutils
die USB-Bluetooth-Unterstützung installieren.
Für OpenWrt 18.06 wird noch zusätzlich das Paket uhttpd-mod-ubus benötigt:
opkg install uhttpd-mod-ubus
Danach muss der dbus noch gestartet werden:
/etc/init.d/dbus enable
/etc/init.d/dbus start
Laut Anleitung muss noch bluez-utils aktiviert werden - das ist aber scheinbar nicht mehr notwendig seit openWrt Chaos Calmer 15.05.
Nun muss nur noch mit hciconfig hci0 up
der Bluetooth-Dongle aktiviert werden.
Momentan ist bei einem Neustart immer das Bluetooth-Device wieder deaktiviert und es muss erneut durch diesen Befehl gestartet werden - ein Eintrag in der Crontab hat leider bisher noch nicht dazu geführt, dass dies automatisch beim Start des Routers / Access Points geschieht...
Damit das Bluetooth-Device bei jedem Neustart aktiviert ist muss in der Datei /etc/rc.local noch vor dem exit 0 der entsprechende Eintrag vorgenommen werden:
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.
hciconfig hci0 up
exit 0
Dies kann auch über die LuCI-Oberfläche vorgenommen werden:
Menü System -> Startup
...dort ganz nach unten scrollen und bei "Local Startup" den Eintrag anpassen.
2.) eigenes ubus-Plugin erstellen (anlehnend an https://wiki.openwrt.org/doc/techref/rpcd (https://wiki.openwrt.org/doc/techref/rpcd)):
Datei "bluetooth" erstellen im Verzeichnis /usr/libexec/rpcd/ und ausführbar machen.
Was mich einige Zeit gekostet hat war, dass bei mir das Verzeichnis nicht vorhanden war in dem die Datei erstellt werden muss.
Also musste ich zuerst die ganzen Verzeichnisse erstellen:
mkdir /usr/libexec
mkdir /usr/libexec/rpcd
Danach kann die Datei erstellt werden:
touch /usr/libexec/rpcd/bluetooth
Nun mit dem Editor der Wahl folgenden Inhalt in die Datei einfügen:
#!/bin/sh
case "$1" in
list)
echo '{ "check_client": { "bt_address": "str" } }'
;;
call)
case "$2" in
check_client)
# read the arguments
read input;
# optionally log the call
#logger -t "bluetooth" "call" "$2" "$input"
# return json object or an array
bt_address=$(echo $input | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | sed 's/\ //g' | sed 's/\"//g' | sed 's/bt_address://g' | awk -v k="text" '{n=split($0,a,","); print a[1]}')
name=$(hcitool name $bt_address)
echo '{ "clients": { "name": "'$name'" } }'
;;
esac
;;
esac
Die etwas längliche Zeile in der die Variable bt_address gesetzt wird ist aus dem Grund so lange weil ich auf manchen Systemen das Tool jq nicht zur Verfügung hatte und mit dem obigen Ausdruck auch mit Standardmitteln aus dem Input die zu prüfende Bluetooth-Adresse ermitteln kann.
Anschliessend die Datei ausführbar machen:
chmod +x /usr/libexec/rpcd/bluetooth
Nun muss noch der RPC-Dienst und uhttpd neu gestartet werden:
/etc/init.d/rpcd restart
/etc/init.d/uhttpd restart
Jetzt kann geprüft werden ob das Plugin gefunden und aktiviert wurde:
ubus -v list
dabei muss in der ganzen Ausgabe (bei mir an erster Stelle) eine ähnliche Ausgabe folgen:
'bluetooth' @4034634d
"check_client":{"bt_address":"String"}
Was macht nun das neu erstellte UBUS-Plugin?
Relativ leicht beschrieben: Es gibt den Namen für ein Gerät mit einer bestimmten Bluetooth-MAC-Adresse zurück.
Die Ein- und Ausgabe-Parameter sind dabei jeweils im JSON-Format zu formatieren / formatiert.
Beispiel:
root@OpenWrt:~# ubus call bluetooth check_client '{ "bt_address" : "AA:D3:D0:59:4C:68" }'
{
"clients": {
"name": "Samsung Galaxy S7"
}
}
Damit dieses UBUS-Plugin von einem anderen Rechner aus aufgerufen werden kann muss noch die entsprechende Berechtigung vergeben werden.Hierzu muss im Verzeichnis /usr/share/rpcd/acl.d eine Datei (in meinem Beispiel bluetoothtester.json) mit mindestens folgendem Inhalt angelegt werden:
{
"bluetoothtester": {
"description": "only for bluetooth-checks",
"read": {
"ubus": {
"bluetooth": [ "check_client" ],
},
}
}
}
dieses Plugin kann nun auch via HTTP von einem anderen Rechner aus mit JSON-RPC abgefragt werden:
3.) eigene Scripte auf dem FHEM-Rechner erstellen:
Es müssen zwei Scripte erstellt werden:
- ein Pyhon-Script welches den eigentlichen RPC-Aufruf macht
- ein Shell-Script welches das Python-Script verschalt und 0 oder 1 an FHEM zurück gibt.
Angelehnt habe ich mein Python-Script an das des Users JanLo der damit auch die WLAN-Sessions ausgelesen hat: https://forum.fhem.de/index.php/topic,33554.0.html (https://forum.fhem.de/index.php/topic,33554.0.html)
Ich habe das Script so angepasst dass dieses oben erstellte "bluetooth"-Plugin mit einer übergebenen Bluetooth-Adresse abgefragt wird.
Das Script findet ihr hier:
https://github.com/hatzlhoffer/OpenWRT-Bluetooth-Client-Check (https://github.com/hatzlhoffer/OpenWRT-Bluetooth-Client-Check)
Dieses Script könnt ihr nun z.B. in eurem home-Verzeichnis oder in einem anderen Verzeichnis für FHEM-Scripte auf eurem FHEM-Server ablegen.
Zusätzlich wird ein zweites Script erstellt (z.B. test_bluetooth.sh) mit folgendem Inhalt:
#!/bin/sh
var=$(python <Script-Verzeichnis>/check_bluetooth_clients.py $2 <openWRTUser> <openWRTPasswort> $1)
if [ -z "$var" ]
then
echo "0"
else
echo "1"
fi
Nun kann endlich in FHEM für jeden Access-Point auf dem eine Verbindung zum Mobiltelefon geprüft werden soll ein PRESENCE-Device angelegt werden in dem statt mit einem LAN-PING mit Hilfe des angelegten Shell-Scriptes auf Anwesenheit geprüft werden kann:
define <name> PRESENCE shellscript "<Script-Verzeichnis>/<Script-Name> <Bluetooth-Adresse> <Server-Name oder IP>"
Beispiel:
define handy_Michael_OG PRESENCE shellscript "/home/michael/jsontest/test_bluetooth.sh AA:D3:D0:59:4C:68 192.168.0.196"
bzw.
define handy_Michael_OG PRESENCE shellscript "/home/michael/jsontest/test_bluetooth.sh AA:D3:D0:59:4C:68 openWRTOG"
Ich habe für jeden User bisher drei solcher PRESENCE-Devices angelegt und das Ganze dann in einer "Anwesenheits-Struktur" zusammengefasst.
Somit habe ich endlich mein WLAN-Ping ablösen können, und musste keine weiteren Endgeräte aufstellen sondern konnte meine openWRT-Router weiterhin verwenden.
Ich hoffe, meine Anleitung kann dem ein oder anderen bei Problemen weiterhelfen - wenn jemand noch Verbesserungsvorschläge bezüglich der einzelnen Scripte hat: immer gerne her damit - das Ganze ist aktuell noch in der Anfangsphase - funktioniert aber in meinem internen Netz bisher wirklich absolut zuverlässig.
Ich möchte dabei Leute unterstützen die vor dem gleichen Problem stehen wie ich zu Beginn - ohne dass sie sich vielleicht so viele Nächte wie ich um die Ohren schlagen müssen... :-)
Eventuelle Verbesserungsvorschläge würde ich hier in diesem Eingangspost einarbeiten - dann hat jeder der das nachbauen möchte auch gleich die aktuelle Version...
Viele Grüße
Michael
Edit 17.07.2017: Automatisches Starten des Bluetooth-Device beschriebenEdit 25.06.2018: Berechtigung via ACL ergänzt
Edit 31.10.2018: Ergänzungen zu OpenWrt 18.06
Wer etwa 4mb auf seinem OpenWRT-Gerät frei hat, kann auch presenced verwenden:
Punkt 1) von oben ausühren
Anschliessen Perl am openWRT-Gerät installieren:
opkg install perl perlbase-cpan perlbase-perlio perlbase-getopt perlbase-threads perlbase-thread perlbase-attributes libustream-openssl ca-bundle ca-certificates
presenced entweder
wget https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/presenced
oder
aus dem fhem/contrib/PRESENCED/ Verzeichnis von FHEM
auf das OpenWRT-Gerät nach /usr/sbin/ kopieren.
cp presenced /usr/sbin/
presenced ausführbar machen:
chmod +x /usr/sbin/presenced
Das sollte dann etwa so aussehen:
root@r6220_Wohnzimmer:/usr/sbin# ./presenced -v
2020-01-03 15:31:19 - started with PID 17228
2020-01-03 15:31:19 - created socket on 0.0.0.0:5111
Mit CTRL + C kann man presenced wieder stoppen
2020-01-03 15:47:29 - caught SIGINT
2020-01-03 15:47:29 - removed PID-File /var/run/presenced.pid
2020-01-03 15:47:29 - exiting
Fehlt noch der automatische Start beim Booten:
Dazu eine Datei mit dem Namen presenced mit folgendem Inhalt in /etc/init.d/ erstellen:
#!/bin/sh /etc/rc.common
# Copyright (C) 2007-2011 OpenWrt.org
START=60
SERVICE_PID_FILE=/var/run/presenced.pid
start() {
service_start /usr/sbin/presenced -v -d
}
stop() {
service_stop /usr/sbin/presenced && rm $SERVICE_PID_FILE
}
Die Datei ausfürbar machen:
chmod +x /etc/init.d/presenced
und starten
/etc/init.d/presenced enable
/etc/init.d/presenced start