Auch ohne Saft nicht kraftlos (Linux-Magazin, Januar 2017)

Bei einem Stromausfall sackt die Intelligenz eines Smart Homes schlagartig ab. Mittels einer Notstromversorgung und einem Groovy-Script auf der Smartthings-Plattform schickt es aber wenigstens dem Hausherrn eine Nachricht über das Malheur aufs Mobiltelefon.

In Deutschland eher selten, aber in den USA selbst in Großstädten eine Normalität: Der Strom ist mal wieder weg. Sei es, dass die Stadt San Francisco Stromoberleitungen immer noch als wilden Kabelverhau zwischen Häusern spannt (Abbildung 1) oder dass die elektrische Infrastruktur der Umspannwerke veraltet und bröselig ist, jedenfalls muss ein Smart Home hier stets mit dem Schlimmsten rechnen und Strategien für den Fall bereithalten, dass der Saft mal ein paar Stunden ausbleibt. Auch wer in Ländern mit stabiler Stromversorgung lebt, wird die heute vorgestellte Ausfallsicherheit zu schätzen wissen, wenn ein gewitzter Einbrecher vorsichtshalber vor dem Einstieg die Haussicherung rausfliegen lässt, aber einen gehörigen Schreck bekommt, falls trotzdem die Sirene losgeht!

Dabei sollten sowohl Herzstücke der Automatisierung wie der Controller ohne Netzstrom weiter laufen, als auch dessen Verbindung ins Internet funktionieren, einschließlich des Signalwegs dorthin, auf dem Router, Kabel- oder DSL-Modems liegen, die ebenfalls ohne Strom nichts tun. Beschränkt sich der Hausherr darauf, nur lebenswichtige Komponenten bei einem Stromausfall am Laufen zu halten, summiert sich der Verbrauch auf nur wenige Watt und selbst eine billige batteriegepufferte Notstromversorgung für weniger als 50 Euro kann diese Minimal-Infrastruktur eine Weile am Leben halten.

Abbildung 1: San Francisco: Stromversorgung mittels Kabelverhau führt zu Ausfällen.

Qual der Hardwarewahl

Diese Uninterruptible Power Supplies (UPS) genannten Geräte geben ihre Kenndaten meist in Volt-Ampere (VA) an, was leider nicht für die Beantwortung der elementarsten Frage reicht, wie lange sie nämlich einen Verbraucher mit bekanntem Stromverbrauch am Laufen halten. Hierzu muss der User die Eckdaten der intern verwendeten Batterien kennen und in eine auf [2] erklärte Formel einsetzen, aus der dann die Minuten bis zum Stillstand herauskommen.

Zunächst erwarb ich ein Billig-UPS für 30 Dollar, das allerdings mit sinnlosem, nicht abstellbarem Gepiepse im stromlosen Betrieb nervte, sodass ich schließlich $120 für ein sehr solide gearbeitetes UPS von Tripp-Lite auf den Ladentisch legte, das nicht nur digital anzeigt, für wieviele Minuten Betrieb der Saft noch reicht, sondern sogar eine Quiet-Taste hat, die dafür sorgt, dass der Apparat auch während eines Stromausfalls ohne Piepsen seinen Dienst tut. Wunder der Technik!

Abbildung 2: Der Smartthings-Hub (oben) und die Notstromversorgung für die Internetverbindung (unten).

Schlaues Heim trotz Ausfall

Wie in [6] am Ende kurz erwähnt, war das von mir eingesetzte Starter-Kit der Firma Smartthings mit Controller und einem Set von vier verschiedenen Sensoren und Aktuatoren bis vor kurzem nur in den USA erhältlich. Seit September 2015 ist der Smartthings-Hub allerdings auch in einer angepassten UK-Version für den europäischen Markt zu haben und auf amazon.de zum Preis von 239 Euro zu bestellen. Passende Sensoren und Aktoren, die das Z-Wave oder ZigBee-Protokoll beherrschen gibt es ebenfalls auf diesem Weg, zum Preis von etwa 40 Euro.

Abbildung 3: Der Hub zeigt an, ob er auf Netzspannung oder wegen eines Ausfalls auf Batterie läuft.

Die meisten Komponenten dieser Smart-Home-Lösung arbeiten batteriebetrieben und sogar der Controller ist batteriegestützt und schaltet bei fehlender Netzspannung übergangslos um, so dass es damit keinerlei Vorkehrungen bedarf. Auch meine Arlo-Überwachungskameras ([3]) laufen drahtlos mit Batterie, also kümmert sich das UPS nur um die Arlo-Basestation, sowie Router und ISP-Modem. Praktisch alles läuft mit dieser einfachen Lösung bis zu drei Stunden lang weiter wenn der mal Strom ausfällt. Längere Auszeiten als eine Stunde sind gottlob selten, auch hier bei uns im wilden Westen.

Doch wie stellt ein Sensor überhaupt fest, dass der Strom ausgefallen und das Notstromaggregat angesprungen ist? Es wäre naheliegend, den Controller selbst zu fragen und in der Tat zeigt sein Webinterface (Abbildung 3) an, ob er auf Notbatterie läuft oder Netzspannung anliegt. Leider bietet Smartthings diese Information nicht über die Developer-API an, also kam mir als erstes eine an den Meister umständlicher technischer Lösungen, Rube Goldberg, erinnernde Konstruktion in den Sinn.

Abbildung 4: Manchmal erfordern widrige Umstände die Konstruktion von Rube-Goldberg-Maschinen (https://en.wikipedia.org/wiki/Rube_Goldberg_machine).

Wie wäre es mit einer lichtdichten Verputzdose vom Baumarkt, in die ein Netzkabel hineinführt, ein LED-Nachtlicht mit nur 0,3 Watt betreibt und einem batteriebetriebenen Lichtsensor, der kontrolliert, ob das Licht und damit der Netzstrom an ist (Abbildung 5)? Als Sensor bot sich ein Gerät namens Zooz (Abbildung 6) an, das als Bewegungsmelder fungiert, aber auch nebenbei Raumtemperatur und Lichteinfall in Lux misst.

Abbildung 5: Ein LED-Nachtlicht brennt solange Strom da ist und signalisiert damit dem Sensor, dass die Versorgung funktioniert.

Abbildung 6: Der batteriebetriebene Licht/Bewegungs/Temperatur-Sensor von Zooz spricht Z-Wave mit dem Controller.

Der Smartthings-Hub integriert so ziemlich jedes Gerät, das das drahtlose Z-Wave oder ZigBee-Protokoll spricht, und so war auch das Einbinden des Sensors in den Z-Wave-Verbund des Hubs über die Mobiltelefon-App kein Thema (Abbildung 7).

Abbildung 7: Neue Z-Wave-Komponenten findet der Hub im Inclusion-Modus oft automatisch.

Schlaue Apps

Smartthings App fürs Mobiltelefon (iOS und Android) liest dann die Sensor-Daten in regelmäßigen Abständen ein, oder einfach per Subscription immer dann, wenn vordefinierte Ereignisse eintreten. Den aktuellen Zustand aller Geräte zeigt die Dashboard genannte Übersicht an (Abbildung 8). Schalter lassen sich so per App umlegen und die App visualiert den Endzustand.

Abbildung 8: Die Smartthings-App zeigt den Zustand aller Geräte an und steuert sie einzeln an.

Abbildung 9: User können ihre eigenen Applikationen für den Smartthings-Hub in einer IDE in Groovy schreiben und mittels "Publish" installieren.

Was darüber hinausgeht, kann der User selbst programmieren. In sogenannten "SmartApps" können registrierte Entwickler Groovy-Code zusammenklopfen, der Sensoren abfrägt, Aktionen mit Z-Wave-Aktoren einleitet oder externe Web-Requests abzufeuert. Smartthings gibt sich schmallippig, wenn man wissen will, wo die SmartApps tatsächlich laufen, auf dem Hub oder in der Cloud, und je nach Last behält es sich die Firma vor, die notwendigen Rechenschritte hier oder da auszuführen.

Ein Simulator in der IDE hilft, letzte Kinderkrankheiten auszumerzen, und drückt der User "Publish for me" (Abbildung 8), installiert die Telefon-App den auf dem Desktop im Browser editierten Code. Zauberei!

Listing 1: zooz.groovy

    01 definition(
    02   name: "PowerPoll",
    03   namespace: "mschilli",
    04   author: "Mike Schilli",
    05   description: "Power outage sensor",
    06   category: "Convenience")
    07 
    08 preferences {
    09   section("Device") {
    10     input "sensor", 
    11       "capability.motionSensor", 
    12       required: true
    13   }
    14 }
    15 
    16 def installed() {
    17   initialize()
    18 }
    19 
    20 def updated() {
    21   initialize()
    22 }
    23 
    24 def initialize() {
    25   unschedule()
    26   schedule("42 * * * * ?", handler)
    27 }
    28 
    29 def handler() {
    30   log.debug "Light Check: " + 
    31     sensor.currentIlluminance
    32 }

Der Code in Listing 1 definiert im Abschnitt "preferences" die Sensoren, die der User auswählen muss, nachdem er die neu installierte SmartApp unter dem Punkt "Marketplace->My Apps" ausgewählt und gestartet hat. Vorgegeben ist nur "capability.motionSensor" und die SmartApp befrägt hierzu den Hub nach allen Geräten mit dieser Eigenschaft und präsentiert dann dem User eine Auswahlliste (Abbildung 10). Wählt dieser dann den neu hinzugekommenen "Z-Wave Plus Motion/Temp Sensor" aus, startet die SmartApp und der verblüffte Entwickler kann die Log-Ausgaben der irgendwo in der Cloud laufenden App in einem beliebigen Browserfenster verfolgen (Abbildung 11).

Abbildung 10: Der User, der die SmartApp installiert hat, wählt selbst die Geräte aus, die er zu steuern beabsichtigt.

Fixe Events

Der Code selbst ist Event-gesteuert, die Funktionen installed und updated sind notwendige Einsprungpunkte, die der Hub nach der Neuinstallation oder dem Auffrischen der SmartApp anspringt. Beide kanalisiert Listing 1 in die Funktion initialize ab Zeile 24, die einen Cron-Eintrag anlegt, der in der 42. Sekunde jeder Minute die ab Zeile 29 definierte Funktion handler anspringt. Vor dem Anlegen des neuen Cron-Eintrags löscht unschedule vorsichtshalber alle bislang angelegten, damit es zu keiner Explosion von neuen Einträgen kommt. Die Methode currentIlluminance des Sensor-Objektes in Zeile 31 liest den Lichtwert des Sensors aus, dessen Namen Zeile 10 vorher vom User in der App eingeholt hat. Dass ein String in Zeile 10 mir nichts dir nichts ein Objekt in Zeile 31 erzeugt nennt man, das sei am Rande bemerkt, in Fachkreisen "Spooky Action at a Distance". Erfahrene Programmierer scheuen den Effekt wie der Teufel das Weihwasser, aber die Smartthings-Developer-API ist leider voll von derartigen Narreteien.

Abbildung 11: Den Lichtsensor liest der Hub nur alle vier Minuten aus, während Ereignisse am Kontaktsensor sofort erscheinen.

Wie die Log-Ausgabe in Abbildung 11 zeigt, stellte sich leider heraus, dass der Hub den Zooz-Sensor nur alle paar Minuten ausliest. Außerdem unterstützte das Zooz-Gerät den sonst angebotenen Subscription-Modus anscheinend nicht, bei dem der Hub bei jeder Wertänderung an einem Sensor sofort einen Callback anspringt. Fällt der Strom aus, dauert es also unter Umständen fünf Minuten, bis der Code den Ausfall bemerkt und Aktionen wie die Benachrichtigung des Users über SMS einleiten kann. Nicht das Ende der Welt, aber es geht schon noch besser.

Noch ein Sensor

Auf Amazon fand ich noch einen Z-Wave-Sensor vom Hersteller Seven7express (Abbildung 12), der Stromausfälle sehr effizient meldet. Er ist als Türkontakt implementiert und meldet "closed" falls der Strom angeschaltet ist und "open" falls nicht. Über einen Ladegerätadapter steckt er in der Steckdose, während im Sensor selbst eine Batterie steckt, die es ihm erlaubt, per Z-Wave Signale an den Hub zu schicken, falls kein Strom mehr in der Steckdose ist.

Abbildung 12: Der batteriegestützte Power Outage Sensor von Seven7express zeigt wie ein Türkontakt an, ob Strom da ist oder nicht.

Das Gerät funktionierte auf Anhieb, und das Groovy-Skript in Listing 2 implementiert die Logik zur Steuerung. Im Preference-Abschnitt sucht der Hub nach Sensoren mit der Eigenschaft "capability.contactSensor" und bietet dem User unter anderem den neu installierten Power-Sensor an wenn dieser die App aktiviert.

Zeile 26 meldet eine Subscription auf den Event "contact" an, den der Hub jedes Mal auslöst, wenn der Sensor von "open" auf "closed" und umgekehrt springt. So bekommt das Skript Stromausfälle mit nur ein, zwei Sekunden Verzögerung mit und loggt sie in den Zeilen 31 und 33 mit.

Listing 2: power-sensor.groovy

    01 definition(
    02   name: "PowerSensor",
    03   namespace: "mschilli",
    04   author: "Mike Schilli",
    05   description: "Subscribe and detect",
    06   category: "Convenience")
    07 
    08 preferences {
    09   section("Device") {
    10     input "power", 
    11       "capability.contactSensor", 
    12       required: true
    13   }
    14 }
    15 
    16 def installed() {
    17   initialize()
    18 }
    19 
    20 def updated() {
    21   initialize()
    22 }
    23 
    24 def initialize() {
    25   unsubscribe()
    26   subscribe(power, "contact", evthandler)
    27 }
    28 
    29 def evthandler(evt) {
    30   if(power.currentContact == "closed") {
    31     log.debug "Power back!"
    32   } else {
    33     log.debug "Power outage!"
    34   }
    35 }

Hallo User

Stellt die SmartApp fest, dass der Strom weg ist, kann sie mit der in [7] schon einmal vorgestellten Prowl-Web-API den User auf seinem Handy wachrütteln. Listing 3 pflanzt den von Prowl verlangten API-Key ein, den registrierte Nutzer nach dem Kauf der App für $2.99 auf der Webseite abholen (https://www.prowlapp.com/).

Abbildung 13: Durch diese Textnachricht weiß der User Bescheid, dass zuhause der Strom ausgefallen ist.

Die Funktion prowl nimmt eine Nachricht entgegen ("Power out!" bzw. "Power back!"), setzt das Event-Feld damit und fügt noch den Namen der sendenden App und eine kleine Erklärung dazu, damit der Empfänger weiß, woher die Nachricht kommt. Im try-Block setzt dann httpGet den Request ab und sowohl im Gut- als auch im Fehlerfall loggt log.debug eine entsprechende Nachricht für etwaige später folgende Fehleranalysen. Ein sehr einfacher und effizient zu nutzender Service, der sowohl auf iOS also auch Android funktioniert (Abbildung 13).

Listing 3: prowl.groovy

    01 def prowl(message) {
    02   def params = [
    03     uri: "https://api.prowlapp.com",
    04     path: "/publicapi/add",
    05     query: [
    06       event: message,
    07       application: "Smartthings",
    08       url: "",
    09       description: "Power Outage Notification",
    10       apikey: "xxxxxxxxxxxxxxxxxxxxxxx"
    11     ]
    12   ]
    13 
    14   try {
    15     httpGet(params) { resp ->
    16       log.debug "Prowl message sent";
    17     }
    18   } catch(e) {
    19     log.error "Can't send Prowl message: $e"
    20   }
    21 }

Webzugriff

Abbildung 14: Der User erlaubt den Web-Zugriff auf ausgewählte Z-Wave-Geräte.

Wer auch den etwas versteckten OAuth-Abschnitt beim Einrichten der SmartApp aktiviert, erhält nach einem OAuth-Token-Dance (zum Beispiel über das CPAN-Modul OAuth::Cmdline, Abbildung 14) einen Access-Token, der den Zugriff auf die laufende SmartApp aus dem offenen Internet erlaubt. Der SmartApp-Code in Listing 4 definiert im Abschnitt mappings die Einstiegspunkte der Web-API und die ihnen zugewiesenen Aktionen. Die ab Zeile 9 definierte Funktion checkPower liest dann auf Zuruf den aktuellen Zustand des Sensors aus und gibt das Ergebnis als Array zurück, den die Web-API im JSON-Format an den Web-Client zurückgibt.

Listing 4: webapi.groovy

    01 mappings {
    02   path("/power") {
    03     action: [
    04       GET: "checkPower"
    05     ]
    06   }
    07 }
    08 
    09 def checkPower() {
    10   return [power: 
    11     power.currentContact == "closed" ? 
    12       "ok" : "not ok"]
    13 }

Abbildung 15 zeigt die Abfrage mit einem curl-Client von der Kommandozeile. Zuerst erfragt dieser die Lage des "Endpoints", also die vollständige URL, unter der ein registrierter User all seine SmartApps findet. Mit dieser URL kann der Client dann auf die im Code definierten Einstiegspunkte zugreifen (im Beispiel: /power) und erhält JSON-formatierte Ausgaben zurück, wie die dass das "power"-Feld den Wert "ok" oder "not ok" führt.

Abbildung 15: Curl auf der Kommandozeile greift über die Web-API auf den Stromausfallfühler zu.

Schlimmer Zustand

Die Programmierung der Smartthings-API ist allerdings nur für Bastler mit Eselsgeduld zu empfehlen. Samsungs Smartthings-Abteilung scheint das Stiefkind der Organisation zu sein. Nicht nur ist die Dokumentation völlig unzureichend und widersprüchlich, auch der Source-Code des Hub-Kerns ist nicht zugänglich und sogar die Groovy-eigenen Self-Inspection-Mechanismen wurden ausgehebelt, damit der User ja die wahren Namen der falsch dokumentierten Attribute nicht finden kann. Im vorliegenden Fall wäre es zum Beispiel nicht zu kompliziert, den Hub zu fragen, ob der Strom noch aus der Leitung oder den Reservebatterien kommt, statt Rube-Goldberg-Lösungen wie die heute beschriebene zu produzieren. Läge der Hub-Code offen, könnten engagierte Hobbyisten sogar etwaige Lücken in der API füllen.

Die App stürzt ständig ab, die Webseite zur Entwicklung von Smartapps ist lieblos hingeschustert und weist gravierende funktionale Mängel auf, wie die, dass der "Update"-Knopf zum Ändern der Metadaten nicht funktioniert. Wer denkt, der Developerzugriff erfolgte über graph.api.smartthings.com, wird über das Forum darüber belehrt, dass es in den USA nicht graph sondern graph-na02-useast1 heißen muss und im UK graph-eu01-euwest1, sonst findet die API die Geräte des Users nicht, der sich darüber die Haare rauft. Das eigentlich standardmäßig übliche Sharding über den Usernamen funktioniert nicht. Dem steht eine engagierte Community gegenüber, die selbst aus den lieblos hingeworfenen Brocken noch laufende Applikationen stampft. Die einzig richtige Strategie für Samsung dürfte die Offenlegung des gesamten Projekts einschließlich der verwendeten Kommunikationsprotokolle sein, und es der Community zu überlassen, es in eine wartbare Plattform mit Zukunft zu verwandeln. Potential wäre da.

Infos

[1]

Listings zu diesem Artikel: http://www.linux-magazin.de/pub/listings/magazin/2017/01/perl-snapshot

[2]

"How-to Geek: How to Select a Battery Backup for Your Computer", http://www.howtogeek.com/161479/how-to-select-a-battery-backup-for-your-computer/

[3]

Michael Schilli, "Schaut auf diese Stadt", Linux-Magazin 12/2016, http://www.linux-magazin.de/Ausgaben/2016/12/Perl-Snapshot

[4]

Smartthings Hub der Firma Samsung: https://www.smartthings.com

[5]

"Writing Your First SmartApp", Smarthings API Tutorial, http://docs.smartthings.com/en/latest/getting-started/first-smartapp.html

[6]

Michael Schilli, "Fernschalter smart", Linux-Magazin 07/2016, http://www.linux-magazin.de/Ausgaben/2016/07/Perl-Snapshot

[7]

Michael Schilli, "Private Rezeption", Linux-Magazin 04/2016, http://www.linux-magazin.de/Ausgaben/2016/04/Perl-Snapshot

Michael Schilli

arbeitet als Software-Engineer in der San Francisco Bay Area in Kalifornien. In seiner seit 1997 laufenden Kolumne forscht er jeden Monat nach praktischen Anwendungen verschiedener Programmiersprachen. Unter mschilli@perlmeister.com beantwortet er gerne Ihre Fragen.