Smart Home openHAB Installation Teil 6 – Anwesenheitserkennung
Update 12.11.2020
Ab Dezember 2020 habe ich das Glück, ein Eigenheim zu besitzen. Mit dem Umzug werde ich mein Smart Home zukünftig mit Home Assistant steuern, sodass die Serie Smart Home openHAB Installation nicht länger fortgeführt und gepflegt wird.
Teil 6 meiner Beitragsreihe Smart Home openHAB Installation befasst sich mit dem Thema „Anwesenheitserkennung“. Aktuell nutze ich drei Apple Geräte, ein iPhone, ein iPad und eine Watch. Alle drei möchte ich in meine openHAB Installation einbinden und insbesondere die Werte des iPhones zur Anwesenheitserkennung nutzen. Darüberhinaus lassen sich natürlich weitere Werte in die Sitemap einbinden.
Der Anwesenheitsstatus kann später dazu dienen, um davon abhängie Aktionen auszuführen.
Binding: iCloud
Das iCloud Binding ist eins der komplizierteren Sorte. Grund dafür ist, dass Apple regelmäßig (jährlich) ein Zertifikat austauscht, welches für die Kommunikation benötigt wird. Daher funktioniert das Binding, das über die PaperUI installiert werden kann i.d.R. nur bis maximal zum nächsten Ablauf des Zertifikats.
Deshalb muss das Binding manuell installiert und angepasst werden, um es dauerhaft funktionsfähig zu halten.
- Download der Binding Snapshot JAR-Datei: https://openhab.jfrog.io/openhab/libs-pullrequest-local/org/openhab/binding/org.openhab.binding.icloud/
- Download des aktuellen Apple fmipmobile.crt Zertifikats: https://github.com/mauryquijada/openhab2-addons/tree/master/bundles/org.openhab.binding.icloud/src/main/resources
- Wichtig ist zu prüfen, dass das heruntergeladene Zertifikat auch aktuell und gültig ist!
- Danach muss das Zertifikat in der JAR-Datei ausgetauscht werden. Am Einfachsten geht dies, indem die Datei mit WinRAR oder 7Zip geöffnet wird. Jetzt lässt sich die neue Datei per Drag-and-Drop ins Archiv schieben und die bestehende Datei ersetzen.
- Abschließend ist die JAR-Datei ins openHAB AppOns Verzeichnis zu kopieren und ggf. die bestehende alte Datei zu ersetzen.
Der Vorgang ist entsprechend jährlich zu wiederholen.
$OPENHAB_CONF$/things/icloud.things
Nachdem nun das Binding eingerichtet ist, werden die Apple-ID und die Geräte in der Things-Datei angelegt.
Bridge icloud:account:appleId "Apple/iCloud: Apple ID" [ appleId="<AppleID>", password="<AppleID-Password>", refreshTimeInMinutes=5 ] { Thing device iphone "Apple/iCloud Device: iPhone" [ deviceId="<Device-ID aus der PaperUI Inbox>" ] Thing device ipad "Apple/iCloud Device: iPad" [ deviceId="<Device-ID aus der PaperUI Inbox>" ] Thing device iwatch "Apple/iCloud Device: Watch" [ deviceId="<Device-ID aus der PaperUI Inbox>" ] }
$OPENHAB_CONF$/items/icloud.items
Im Anschluss konfiguriere ich die Items für die Geräte. Für jedes Gerät lege ich eine Gruppe und die dazugehörigen Parameter an.
Group Apple_iCloud_iPhone "Apple/iCloud Group: iPhone" <icloud_iphone> Group Apple_iCloud_iPad "Apple/iCloud Group: iPad" <icloud_ipad> Group Apple_iCloud_Watch "Apple/iCloud Group: Watch" <icloud_iwatch> String Apple_iPhone_BatteryStatus "Apple/iCloud iPhone: Battery Status [%s]" <battery> (Apple_iCloud_iPhone) { channel="icloud:device:appleId:iphone:batteryStatus "} Number Apple_iPhone_BatteryLevel "Apple/iCloud iPhone: Battery Level [%d %%]" <battery> (Apple_iCloud_iPhone) { channel="icloud:device:appleId:iphone:batteryLevel" } Switch Apple_iPhone_FindMyPhone "Apple/iCloud iPhone: Trigger Find My iPhone" (Apple_iCloud_iPhone) { channel="icloud:device:appleId:iphone:findMyPhone", autoupdate="false" } Switch Apple_iPhone_Refresh "Apple/iCloud iPhone: Force iPhone Refresh" (Apple_iCloud_iPhone) { channel="icloud:device:appleId:iphone:location", autoupdate="false" } Location Apple_iPhone_Location "Apple/iCloud iPhone: Coordinates" (Apple_iCloud_iPhone) { channel="icloud:device:appleId:iphone:location" } Number Apple_iPhone_LocationAccuracy "Apple/iCloud iPhone: Coordinates Accuracy [%.0f m]" (Apple_iCloud_iPhone) { channel="icloud:device:appleId:iphone:locationAccuracy" } DateTime Apple_iPhone_LocationLastUpdate "Apple/iCloud iPhone: Last Update [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]" <time> (Apple_iCloud_iPhone) { channel="icloud:device:appleId:iphone:locationLastUpdate" } Switch Apple_iPhone_Home "Apple/iCloud iPhone: iPhone Home" <presence> (Apple_iCloud_iPhone) String Apple_iPad_BatteryStatus "Apple/iCloud iPad: Battery Status [%s]" <battery> (Apple_iCloud_iPad) { channel="icloud:device:appleId:ipad:batteryStatus" } Number Apple_iPad_BatteryLevel "Apple/iCloud iPad: Battery Level [%d %%]" <battery> (Apple_iCloud_iPad) { channel="icloud:device:appleId:ipad:batteryLevel" } Switch Apple_iPad_FindMyPhone "Apple/iCloud iPad: Trigger Find My iPad" (Apple_iCloud_iPad) { channel="icloud:device:appleId:ipad:findMyPhone", autoupdate="false" } Switch Apple_iPad_Refresh "Apple/iCloud iPad: Force iPad Refresh" (Apple_iCloud_iPad) { channel="icloud:device:appleId:ipad:location", autoupdate="false" } Location Apple_iPad_Location "Apple/iCloud iPad: Coordinates" (Apple_iCloud_iPad) { channel="icloud:device:appleId:ipad:location" } Number Apple_iPad_LocationAccuracy "Apple/iCloud iPad: Coordinates Accuracy [%.0f m]" (Apple_iCloud_iPad) { channel="icloud:device:appleId:ipad:locationAccuracy" } DateTime Apple_iPad_LocationLastUpdate "Apple/iCloud iPad: Last Update [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]" <time> (Apple_iCloud_iPad) { channel="icloud:device:appleId:ipad:locationLastUpdate" } Switch Apple_iPad_Home "Apple/iCloud iPad: iPad Home" <presence> (Apple_iCloud_iPad) String Apple_Watch_BatteryStatus "Apple/iCloud Watch: Battery Status [%s]" <battery> (Apple_iCloud_Watch) { channel="icloud:device:appleId:iwatch:batteryStatus" } Number Apple_Watch_BatteryLevel "Apple/iCloud Watch: Battery Level [%d %%]" <battery> (Apple_iCloud_Watch) { channel="icloud:device:appleId:iwatch:batteryLevel" } Switch Apple_Watch_FindMyPhone "Apple/iCloud Watch: Trigger Find My Watch" (Apple_iCloud_Watch) { channel="icloud:device:appleId:iwatch:findMyPhone", autoupdate="false" } Switch Apple_Watch_Refresh "Apple/iCloud Watch: Force Watch Refresh" (Apple_iCloud_Watch) { channel="icloud:device:appleId:iwatch:location", autoupdate="false" } Location Apple_Watch_Location "Apple/iCloud Watch: Coordinates" (Apple_iCloud_Watch) { channel="icloud:device:appleId:watch:location" } Number Apple_Watch_LocationAccuracy "Apple/iCloud Watch: Coordinates Accuracy [%.0f m]" (Apple_iCloud_Watch) { channel="icloud:device:appleId:iwatch:locationAccuracy" } DateTime Apple_Watch_LocationLastUpdate "Apple/iCloud Watch: Last Update [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]" <time> (Apple_iCloud_Watch) { channel="icloud:device:appleId:iwatch:locationLastUpdate" } Switch Apple_Watch_Home "Apple/iCloud Watch: Watch Home" <presence> (Apple_iCloud_Watch)
$OPENHAB_CONF$/rules/icloud.rules
Die Rules Datei dient dazu zu definieren, ob die Geräte zu Hause sind oder nicht. Hierzu werden bei einer Veränderung des Standorts die Koordinaten des Geräts mit den Koordinaten meines Wohnorts verglichen. Bei einer Abweichung von mehr als 100 Metern wird der Anwesenheitsstatus auf abwesend gesetzt.
Für die Berechnung der Dezimalkoordinaten für die Home Location habe ich folgende URL verwendet: https://www.gpskoordinaten.de/gps-koordinaten-konverter
rule "Apple iPhone Home/Away Status" when Item Apple_iPhone_Location changed then val PointType home_location = new PointType(new DecimalType(48.1502867), new DecimalType(11.8526639)) val PointType phone_location = Apple_iPhone_Location.state as PointType val int distance = phone_location.distanceFrom(home_location).intValue() if ( distance < 100) { Apple_iPhone_Home.postUpdate(ON) } else { Apple_iPhone_Home.postUpdate(OFF) } end rule "Apple iPad Home/Away Status" when Item Apple_iPad_Location changed then val PointType home_location = new PointType(new DecimalType(48.1502867), new DecimalType(11.8526639)) val PointType phone_location = Apple_iPad_Location.state as PointType val int distance = phone_location.distanceFrom(home_location).intValue() if ( distance < 100) { Apple_iPad_Home.postUpdate(ON) } else { Apple_iPad_Home.postUpdate(OFF) } end rule "Apple Watch Home/Away Status" when Item Apple_Watch_Location changed then val PointType home_location = new PointType(new DecimalType(48.1502867), new DecimalType(11.8526639)) val PointType phone_location = Apple_Watch_Location.state as PointType val int distance = phone_location.distanceFrom(home_location).intValue() if ( distance < 100) { Apple_Watch_Home.postUpdate(ON) } else { Apple_Watch_Home.postUpdate(OFF) } end
$OPENHAB_CONF$/transform/icloud.map
In der Sitemap möchte ich den Anwesenheitsstatus nicht als ON/OFF anzeigen lassen sondern als ✔/✘. Zudem soll der Batteriestatus in Deutscher Sprache angezeigt werden. Dazu verwende ich eine Mapping Datei.
// PRESENCESTATE / ANWESENHEITSSTATUS ON=✔ OFF=✘ // BATTERYSTATE / BATTERIESTATUS NotCharging=wird nicht geladen Charging=wird geladen Charged=vollständig geladen Unknown=unbekannt
$OPENHAB_CONF$/sitemaps/home.sitemap
In der Sitemap lege ich für jedes Gerät einen Eintrag im Frame Sonstiges unter Anwesenheitsstatus an, um anzuzeigen, ob das Gerät zu Hause ist oder nicht. Darunter zeige ich jeweils die zum Gerät gehörenden Item-Werte an, die ich sehen möchte. Die Standortkarte wird dabei nur eingeblendet, wenn das Gerät unterwegs ist.
Frame label="Sonstiges" { Text label="Anwesenheitsstatus" icon="presence" { Text item=Apple_iPhone_Home label="Apple iPhone [MAP(icloud.map):%s]" icon="icloud_iphone" { Text item=Apple_iPhone_BatteryLevel label="Batterieladung [%d %%]" icon="batterylevel" Text item=Apple_iPhone_BatteryStatus label="Ladezustand [MAP(icloud.map):%s]" icon="battery" Mapview item=Apple_iPhone_Location label="Standort" height=5 icon="icloud_map" visibility=[Apple_iPhone_Home == OFF] } Text item=Apple_iPad_Home label="Apple iPad [MAP(icloud.map):%s]" icon="icloud_ipad" { Text item=Apple_iPad_BatteryLevel label="Batterieladung [%d %%]" icon="batterylevel" Text item=Apple_iPad_BatteryStatus label="Ladezustand [MAP(icloud.map):%s]" icon="battery" Mapview item=Apple_iPad_Location label="Standort" height=5 icon="icloud_map" visibility=[Apple_iPad_Home == OFF] } Text item=Apple_Watch_Home label="Apple Watch [MAP(icloud.map):%s]" icon="icloud_iwatch" { Text item=Apple_Watch_BatteryLevel label="Batterieladung [%d %%]" icon="batterylevel" Text item=Apple_Watch_BatteryStatus label="Ladezustand [MAP(icloud.map):%s]" icon="battery" Mapview item=Apple_Watch_Location label="Standort" height=5 icon="icloud_map" visibility=[Apple_Watch_Home == OFF] } } }
Ein Hinweis noch zu o.g. Szenario:
Bitte beachten, dass die regelmäßige Abfrage der Geräte enormen Einfluss auf die Batterieladezeiten hat. Bei mir hat sich der Zyklus, wann ich z.B. das iPhone laden musste, halbiert. Somit muss man sich genau überlegen, ob diese Funktion der Anwesenheitserkennung wirklich genutzt wird. Ich habe die Funktion inzwischen auch wieder abgeschaltet und verwende das iCloud Binding nicht mehr.
Quellen:
https://www.openhab.org/