Bluetooth LE Presence Awareness mit iOS und Raspberry Pi
Von Ewald Wieser am 17.02.2014
Aus der mehrfachen Beschäftigung mit Bluetooth Low Energy und iOS im Laufe dieses Semesters gepaart mit meinem Interesse für Intelligente Hausautomation entstand die Idee das Smartphone und die BLE-Technologie zur Anwesenheitserkennung zu verwenden. Das Smartphone hat man ja meistens mit eingesteckt, eignet sich daher ja bestens für diese Aufgabe. Seit iOS7 ist es ja möglich, dass Apps auch im Hintergrund BLE-Komunikation betreiben.
Einige Fragen, die ich mir anfangs stellte, waren:
- Wie groß ist die Reichweite von den eingebauten Bluetooth-LE Chips?
- Wie zuverlässig funktioniert es, die App im Hintergrund laufen zu lassen, also nichts weiter tun zu müssen?
- Wie genau und stabil funktioniert das Ganze?
Erste Überlegungen
Meine erste Idee bestand darin, das von Apple spezifizierte iBeacon-Protokoll zu verwenden, da es ja eine Art Positionserkennung innerhalb von Gebäuden ermöglicht. Apple baut dabei auf dem Bluetooth-LE Protokoll auf, verwendet aber nicht, wie sonst üblich, die darin spezifizierten Services und Characteristics, sondern nur die Advertisement-Nachricht. Für genauere Infos siehe http://stackoverflow.com/questions/18906988/what-is-the-ibeacon-bluetooth-profile.
Spezifiziert ist das iBeacon-Protokoll für die Annäherungserkennug, die sog. Proximity. Anstatt einer genauen Position erhält man nur den ungefähren Abstand zu iBeacon. Dies wird dadurch ermöglicht, dass das iBeacon diejenige Signalstärke mitsendet, mit der es in 1m Abstand empfangen wird. Kombiniert mit der tatsächlichen Signalstärke des empfangenen Signal lässt sich so der Abstand näherungsweise ermitteln.
In iOS7 ist das iBeacon-Protokoll als CoreLocation implementiert und wird über CLLocationManager und CLBeaconRegion verwendet. Es sind sogenannte Regions definierbar mit einer eindeutigen UUID, die das Beacon aussendet. Weiters sind zusätzlich zum ungefähren Abstand die States Inside/Outside bzw. Near/Far vorgesehen.
Tests:
- Eine Variante ist, das iPhone als iBeacon einzusetzen und der Raspberry erkennt die Annäherung desselben.
- Die zweite Variante wäre, den Raspberry als iBeacon aufzusetzen und das iPhone erkennt, wenn es in der Nähe ist.
Erkenntnisse:
Die erste Möglichkeit fällt leider weg, da das iPhone ständig advertisen müsste, das Advertisen im Background aber leider vom System nicht erlaubt wird. Die App müsste also immer im Vordergrund sein und das iPhone nicht gelockt.
Die zweite Möglichkeit habe ich mit der NodeJS-Library node-bleacon umzusetzen versucht, bin dabei aber auf folgende Restriktionen gestoßen:
- Zum einen erfolgt die Erkennung, dass das iPhone in Reichweite eines iBeacons ist, wenn das iPhone gelockt ist, teilweise sehr spät (bis zu 15 min.),
- zum anderen weiß zwar dann das iPhone, dass es in der Nähe des Beacons ist, aber wie erfährt das der Raspberry? Dazu müsste ein zweiter Kommunikationsweg (3G, WLAN) verwendet werden, was das Ganze wieder umständlich macht.
Ergebnis:
Die iBeacon-Variante ist also nicht brauchbar!
Zweite Idee
Die zweite Idee bestand darin, das System als Kombination von Bluetooth LE Central und Peripheral umzusetzen, so wie das Protokoll eigentlich gedacht ist. Dabei verbindet sich ein Gerät zu einem zweiten und kann so von ihm Daten abfragen bzw. zu ihm senden. Realisiert wird das über sogenannte Services und Characteristics.
Diese Funktion ist in iOS7 in CoreBluetooth umgesetzt und als CBCentralManager bzw. CBPeripheralManager verwendet (siehe http://www.raywenderlich.com/52080/introduction-core-bluetooth-building-heart-rate-monitor).
Es gibt wieder 2 Varianten für die Umsetzung:
- Das iPhone wird als Peripheral eingesetzt, welches seine UUID advertised, der Raspberry Pi scannt danach und loggt dessen Anwesenheit.
- Der Raspberry Pi wird als Peripheral aufgesetzt und advertised seine UUID, das iPhone scannt danach und connected. Anschließend folgt ein zyklisches Schreiben eines Wertes (1 sec), um seine Anwesenheit kundzutun.
Erkenntnisse:
In der ersten Variante muss das iPhone seine UUID ständig advertisen, was zwar mittels CoreBluetooth im Background möglich ist (siehe: Apple Developer Guidelines), aber dauerhaft Strom benötigt und somit den Akku des iPhones innerhalb kürzester Zeit entleert. Die Raspberry Pi-Tests habe ich mit der NodeJS-Library noble gemacht.
Die zweite Variante habe ich als die Beste angesehen. Das iPhone muss zwar ständig nach der UUID des Raspberry scannen, was aber ein passiver Vorgang ist, also nicht sonderlich viel Strom braucht. Zudem wird es im Background-Modus vom Betriebssystem übernommen. Für den Peripheral-Modus auf dem Raspberry habe ich die NodeJS-Library bleno verwendet. Zum loggen der Anwesenheit habe ich das Projekt eines anderen Entwicklers genommen und etwas abgeändert (PiThermServer). Meine Sourcecodes habe ich auf GitHub zur Verfügung gestellt:
- PiPresenceServer für das Raspberry Pi Peripheral, das die Anwesenheit loggt.
- iOSBLEPresence, die zugehörige App, die sich zum Peripheral verbindet und zyklisch einen Wert schreibt (1 Sekunde).
Beobachtungen/Probleme:
- Ein Problem, das mir sehr viel Kopfweh verursacht und viel Zeit gekostet hat, war: iOS cached UUIDs und Namen von Peripherals anhand der Bluetooth-ID. Wenn man sich also schon mal mit einem iPhone zu einem Peripheral verbunden hat und das Peripheral dann seine UUID oder seinen Namen ändert, wird es unter iOS immer noch unter dem alten Namen und mit der alten UUID angezeigt. Da hilft leider nur ein Zurücksetzen auf Werkseinstellungen des iPhones.
- Ein Manko des Systems ist die sehr geringe Reichweite von Bluetooth LE. Das ganze funktioniert nur, wenn Raspberry Pi und das iPhone im selben Zimmer sind. Sobald man sich aus dem Zimmer hinausbewegt, wird die Verbindung verloren. Ich habe dabei aber leider noch nicht herausgefunden, ob es an einer geringen Signalstärke des Bluetooth-USB Dongles am Raspberry liegt oder an der geringen Signalstärke des iPhones, das den Update-Wert nicht mehr schreiben kann.
- Ein weiterer Nachteil des Testsetups ist, dass der Akku des iPhones, selbst wenn es nur gelockt herumliegt, nicht länger als 24 Stunden hält. Das liegt wohl an der relativ kurzen Update-Zeit, in der das iPhone einen Wert an den Raspberry schickt.
Mögliche Verbesserungen:
- Die geringe Reichweite von Bluetooth LE ließe sich durch Zusammenschalten mehrerer Raspberry Pi überbrücken, die miteinander über LAN kommunizieren und die Anwesenheit von Centrals austauschen.
- Um die Akkuzeit zu verbessern, wäre die einfachste Möglichkeit, die Update-Zeit zu vergrößern. Dadurch würde sich aber gleichzeitig die Zeit wie schnell erkannt wird, dass das Smartphone sich aus der Reichweite bewegt hat, verschlechtern.
Offene Fragen:
- Eine Frage, die bisher ungelöst blieb ist: Wie verhält sich das System nach einer App-Termination durch zu wenig freien Speicher am iPhone? Wird die App automatisch neu gestartet und die Verbindung wieder hergestellt, oder muss ich die App manuell neu starten?
- Ein ähnliches Problem entsteht, wenn der Akku des iPhones leer ist und das Gerät neu startet. Die App wird leider nicht automatisch gestartet und man muss dies manuell tun. Irgendwo hab ich zwar mal gelesen, dass das funktionieren sollte, zusammengebracht hab ich’s allerdings noch nicht.
1 Kommentar
Was hast du für BLE HW am Raspi angeschlossen?
The comments are closed.