Die Welt der Dinge in deiner Hand

openHAB als Integrationsplattform im IoT

Thomas Eichstädt-Engelen

Die Idee des Internet of Things basiert darauf, dass die Dinge des Alltags vernetzt sind. Was aber, wenn das liebgewonnene „Ding“ keine IP- Schnittstelle aufweist oder das verwendete Protokoll für den IoT-Service der Wahl unverständlich ist? Was, wenn alle „Dinger“ mit einer einheitlichen Oberfläche bedient, ein gemeinsames Chart mit Daten bestücken, oder gemeinsamen Automatisierungsregeln folgen sollen? In diesem Fall können Integrationsplattformen helfen, die für diese Problemstellungen Lösungen anbieten.

Schenkt man Kevin Ashton glauben, erfand er im Jahre 1999 den Begriff “Internet of Things”, kurz IoT (Internet der Dinge) [1]. Er motivierte den Begriffs damit, dass immer noch die meisten der etwa 50 Petabyte (Stand 2009) an Informationen im Internet durch Menschen bzw. deren Interaktion gesammelt und bereitgestellt werden. Es wäre doch viel sinnvoller, so Ashton, wenn die Computer alles über die Dinge wüssten, was sie bräuchten, um ohne menschliches Zutun selbst aktiv zu werden. Auf diese Weise könnten sie für uns zählen, überwachen, melden, dass eine Wartung vollzogen werden muss, und erinnern, dass noch etwas einzukaufen ist.

Voraussetzung dafür ist schlicht, dass die Dinge vernetzt, also mit dem Internet verbunden sind. Hier sind wir zwar auf einem guten Weg, aber bei weitem noch nicht am Ziel angelangt. Smartphones und Smart-TVs stehen inzwischen für extrem gute Vernetzung. Auch immer mehr Haushaltsprodukte, wie Spül- und Waschmaschinen, Kühlschränke oder sogar Lampen werden mit LAN, Powerline oder WLAN-Anschluss ausgeliefert und können so potentiell am IoT teilnehmen. Für alle anderen Dinge, die (bisher) noch keine eigene IP-Schnittstelle besitzen, werden Adapter bzw. Gateways benötigt (und glücklicherweise inzwischen auch immer mehr angeboten). Darauf aufbauend sind Integrationsplattformen gefragt, welche diese Schnittstellen und deren unterschiedliche Protokolle adaptieren können. Die Plattformen sollten außerdem anliegende Daten in eine gemeinsame Datenstruktur transformieren können, um einen einheitlichen Zugriff, gemeinsame Mehrwertdienste wie Datenspeicherung und Datenexport, sowie Regeln und Visualisierung zu ermöglichen.

openHAB (open Home Automation Bus) [2] ist eine solche Integrationsplattform deren erstes Major-Release das Projekteam nach zweieinhalb Jahren Entwicklungsarbeit kürzlich vorstellte [3] [4]. Mit an Board waren neben vielen neuen Features, Erweiterungen und Fixes [5] vor allem auch zwei Funktionalitäten, die openHAB für das IoT rüsten: Der Persistence-Service, mit dem openHAB als Datenlieferant dienen kann, sowie die REST-API, mit der Kommandos aus dem IoT entgegen genommen und in echte Schaltbefehle gewandelt werden können. Dieser Artikel wird diese beiden Integrationsfeatures näher beleuchten.

Architektur-Recap

Die Grundidee der openHAB Runtime basiert auf einem Event Bus nach dem Publish-Subscribe-Pattern, der technisch durch den OSGi Event Admin Service umgesetzt worden ist. Jedes anzusteuernde Gerät bzw. jeder Sensor wird als abstraktes „Item“ definiert, wobei ein „Item“ beispielsweise einen Schalter, einen Temperaturmesswert oder auch den aktuellen Radiosender repräsentieren kann. Erst sogenannte Bindings koppeln Items an konkrete Hardware, Schnittstellen oder Protokolle. Technisch verbirgt sich hinter einem Item im Wesentlichen ein Konfigurationselement mit einem eindeutigen Namen und einem Typ (z. B. Switch, Dimmer, Number etc.). Eine besondere Stellung haben Items des Typs ‚Group’. Mit ihnen können mehrere Items entweder logisch (z.B. alle Items eines bestimmten Raums) oder nach Typ (alle Lichter) gruppiert werden. Eine genauere Beschreibung der wichtigsten Konzepte ist im einführenden EclipseMagazin-Artikel zu finden [2].

Persistence Support

Um IoT-Services in die Lage zu versetzen, automatische Aktionen (Meldungen, Warnungen, Erinnerungen) auszuführen, müssen sie von unterschiedlichsten Datenproduzenten mit Nutzdaten wie Temperatur-, Verbrauchs- oder Ertragsdaten versorgt werden. openHAB bietet hierfür den Persistence-Support an. Mit ihm können Item-Zustände über einen Zeitraum in Zeitreihen abgespeichert werden. openHAB ist dabei nicht auf einen Speicherort beschränkt. Es können vielmehr beliebig viele Speicherorte wie relationale, objektorientierte und Round-Robin-Datenbanken (RRD) sowie Cloud-basierte IoT-Services und einfache Logfiles unabhängig voneinander bedient werden. Während sich einige der genannten Optionen dazu anbieten, historische Zustände abzufragen und in Regeln zu verwenden, sind andere wie bspw. die IoT-Services eher für den Datenexport geeignet.

Jede dieser unterschiedlichen Optionen wird Persistence-Service genannt. Konzeptionell beschreibt ein Persistence-Service zu welcher Zeit welche Items abgespeichert bzw. exportiert werden sollen. Dafür werden sogenannte Strategies konfiguriert, die konzeptionell den Triggern in openHAB Rules entsprechen. Es ist also möglich, den Status eines Items bei jeder Änderung, jeder Aktualisierung (ohne dass eine Veränderung vorliegen muss) oder nach einem festen zeitlichen Muster, definierbar durch eine Cron-Expression, abzuspeichern.

Für jeden installierten Persistence-Service gibt es eine Konfigurationsdatei im Ordner <openhabhome>/configurations/persistence, deren Name dem zu konfigurierenden Persistence-Service enspricht. Nach bewährter Methode wurde dafür mit Xtext eine eigene DSL kreiert, um eine möglichst gute Adaption des Konzepts durch die Konfiguration zu ermöglichen. Generell ist eine solche Datei aus den Sektionen Strategies und Items aufgebaut, die wie folgt aussehen können:

Strategies {
    <strategyName1> : "<cronexpression1>"
    <strategyName2> : "<cronexpression2>"
    ...
    default = <strategyNameX>, <strategyNameY>
}

Aus Komfortgründen gibt es schon eine Reihe vorgefertigter Strategien, die nicht in der Strategies-Sektion aufgelistet werden müssen. Dies sind:

  • everyChange ~ speichert einen Status, wenn er sich ändert
  • everyUpdate ~ speichert einen Status, wenn er aktualisiert wird (unabhängig davon, ob sich der zugrunde liegende Status geändert hat)
  • restoreOnStartup ~ überschreibt den Item-Status mit dem zuletzt gespeicherten Wert, wenn der Status beim Systemstart undefiniert ist.Dies ist insbesondere bei virtuellen Items (wie „Anwesenheit“) sinnvoll, da deren Status nicht von anderer Stelle abgefragt werden kann.

Die Items-Sektion kann wie folgt ausgestaltet werden:

Items {
    <itemlist1> [-> "<alias1>"] [: strategy = <strategy1>, <strategy2>, ...]
    <itemlist2> [-> "<alias2>"] [: strategy = <strategyX>, <strategyY>, ...]
    ...
}

<itemlist> kann dabei eine kommaseparierte Liste sein, in der folgende Optionen erlaubt sind:

  • * ~ alle Items werden erfasst
  • <itemname> ~ ein einzelnes Item wird erfasst (GroupItems sind hier ebenfalls erlaubt, wobei tatsächlich der Status der Gruppe und nicht der seiner Mitglieder erfasst wird)
  • <groupname>* ~ alle Mitglieder dieser Gruppe werden erfasst, nicht aber die Gruppe selbst.

Zu jeder Item-Konfiguration kann ein (optionaler) Alias konfiguriert werden. Dieser dient bspw. zur Auswahl einer speziellen Tabelle oder der Feed-ID eines IoT-Service. Ebenfalls optional ist die Angabe der Speicherstrategie. Fehlt die Angabe, ziehen die als default markierten Strategien der Sektion Strategies. Eine gültige Konfiguration für den IoT-Service Open.Sen.Se [6] könnte so aussehen (siehe auch Abbildung 1):

// Strategien haben einen Namen und eine Definition. Sie werden in der Sektion   
// „Items“ referenziert
Strategies {
    everyHour : "0 0 * * * ?"
    everyDay  : "0 0 0 * * ?"

    // wenn für ein Item keine Strategie spezifiziert wurde, findet die
    // unten aufgeführte default-Strategie Anwendung
    default = everyChange
}

Items {
    // Speichere den aktuellen Wasserverbrauch unter dem Alias ‚4711’
    // bei jeder Änderung und zusätzlich jede Stunde. Stelle den Wert
    // beim Systemstart her.
    Wasserverbrauch -> 4711 : strategy = everyChange,everyHour,restoreOnStartup
}
Abbildung 1: Anzeige des Wasserverbrauchs in Open.Sen.Se

Ein weiteres Beispiel für einen Persistence-Service ist die Anwesenheitssimulation, die unter Verwendung des Google Kalenders implementiert wurde. Bei der Anwesenheitssimulation geht es darum, durch Nachahmung des „normalen“ Nutzer-Verhaltens (Licht, Rolläden, Bewässerung, etc.) ein Haus bewohnt wirken zu lassen um Einbrecher abzuschrecken. Der  Persistence-Service lädt dafür Status-Änderungen in einen Kalender hoch und legt darin Ereignisse für die Zukunft an. Eine Schaltbefehl der jetzt ausgeführt wird, führt damit zu einem Ereignis welches zum aktuellen Zeitpunkt zuzüglich eines Offsets von (standardmäßig) zwei Wochen angelegt wird. Aktiviert der Nutzer zu gegebener Zeit die Anwesenheitssimulation, werden nun die damals exportierten, tatsächlich aufgetretenen Ereignisse abgespielt. Damit ist für die Anwesenheitssimulation kein spezielles Training des Systems mehr nötig. Über die gewohnten Oberflächen des Google Kalenders (Web, Smartphone, Desktop) kann man natürlich jederzeit auf einzelne Ereignisse zugreifen, sie administrieren und optimieren.

REST-API

openHAB kann im Systemverbund des IoT von dort aus auch Aktionen entgegen nehmen und diese in „echte“ Schaltbefehle umsetzen. Es wäre z.B. ein Szenario denkbar, in dem mehrere openHAB-Installationen an unterschiedlichen Standorten über einen IoT-Service koordiniert werden sollen. Würde man in der ersten Lokation den Status „anwesend“ setzen, soll der Status in der zweiten Lokation auf „abwesend“ geschaltet werden.

Für die automatische Aktivierung des jeweils anderen Status stellt openHAB eine REST-Schnittstelle zur Verfügung, die im Wesentlichen zwei Aufgaben erfüllt: Zum Einen bietet sie lesenden Zugriff auf die deklarierten Items und Sitemaps und zum Anderen können Status-Updates und Kommandos an einzelne Items geschickt werden [7]. Die Einstiegs-URI der REST-API lautet http://&lt;host&gt;:&lt;port&gt;/rest (z.B. http://demo.openhab.org:8080/rest) und führt zu folgender Antwort:

<openhab>
    <link type="items">http://demo.openhab.org:8080/rest/items</link>
    <link type="sitemaps">http://demo.openhab.org:8080/rest/sitemaps</link>
</openhab>

Lesender Zugriff

Für den lesenden Zugriff auf Items können folgende URIs mit HTTP-GET aufgerufen werden

  • http://<host>:<port>/rest/items ~ ruft die Liste aller Items ab (media-type: application/xml, application/json, application/x-javascript)
  • http://<host>:<port>/rest/items/Anwesenheit ~ ruft ein einzelnes Item ab (media-type: application/xml, application/json, application/x-javascript)
  • http://<host>:<port>/rest/items/Anwesenheit/state ~ ruft den konkreten Status eines Items ab (media-type: plain text)

Damit Nutzer der REST-API möglichst ressourcenschonend über Status Änderungen informiert werden, wurde das Server-Push Verfahren unter Zuhilfenahme des Atmosphere-Frameworks implementiert [8]. Clients können sich für Änderungen folgender Ressourcen registrieren.

  • ein einzelnes Item (oder eine Item-Gruppe)
  • ein Item-Status
  • eine Seite der Sitemap

Wann immer sich der Status eines Items, welches Teil einer subskribierten Ressource ist, ändert, wird die fragliche Ressource in exakt der gleichen Syntax zurückgegeben, als wäre sie durch einen „normalen“ Request angefragt worden. Dieses Verhalten ist insbesondere für Clients sinnvoll, die sich auf die Seiten einer Sitemap subskribieren, weil sie so einen Refresh durchführen können, sobald sich der Status eines Items auf der aktuell angezeigten Seite geändert hat. Ebenfalls relevant ist das Verfahren bei der Integration von openHAB mit anderen z.B. IoT-Services, da diese aktiv über Änderungen informiert werden anstatt selbständig pollen zu müssen. Die Nutzung der Server-Push Technologien ist dabei übrigens denkbar einfach: Clients müssen lediglich in ihren Requests den HTTP-Header X-Atmosphere-Transport setzen.

Schreibender Zugriff

openHAB unterscheidet zwischen der Aktualisierung eines Status und dem Verarbeiten eines Kommandos [9]. Aus diesem Grund gibt es auch unterschiedliche Wege, um ein Update bzw. ein Kommando auszuführen.

Ein Status-Update wird mit dem HTTP-Verb PUT an die URI http://<host>:<port>/rest/items/Anwesenheit/state geschickt. Der neue Status kann für Testzwecke mit cURL mit folgender Kommandozeile aktualisiert werden:

curl -X put -H "Content-Type: text/plain" -v -d "ON" http://<host>:<port>/rest/items/Anwesenheit/state

Durch Nutzung des HTTP-Verbs POST lassen sich Commands über die URI http://<host>:<port>/rest/items/Anwesenheit an ein Item schicken. Die passende Kommandozeile sieht wie folgt aus:

curl -H "Content-Type: text/plain" -v -d "ON" http://<host>:<port>/rest/items/Light_FF_Bath_Ceiling

Was gibt es sonst Neues?

Eine ganze Menge! Neben neuen Bindings für Asterisk (VoIP PBX), MPD (Music Player Daemon), NTP (Network Time Protocol), Novelan (Wärmepumpe), SNMP (Simple Network Management Protocol), VDR (Video Disc Recorder), weiteren Features wie TTS (Text to Speech), die Dropbox-Anbindung und vielen neuen Actions sind vor allem weitere UI Implementierung dazu gekommen.

Zu der bereits bekannten Webapplikation „Classic UI“, die per CSS und Javascript eine iPhone-Applikation nachbildet, haben sich eine Reihe neuer UIs gesellt. Zunächst sei das GreenT UI genannt, welches auf Sencha-Touch, einem auf mobile Anwendungen spezialisierten HTML5-Framework, basiert. Das GreenT-UI erkennt unterschiedliche Endgeräte (auf Wunsch automatisch) und passt daraufhin sein Layout an. Außerdem wurde ein Theme-Mechanismus implementiert, um sogar die Farbgestaltung individuell vornehmen zu können. Neben den genannten Webapplikationen wurden erstmals auch native Clients für Android [10] sowie iOS [11] ausgeliefert. Alle drei neuen UIs kommunizieren über die REST-Schnittstelle mit der openHAB-Runtime.

Überdies wurde die bisherige Implementierung der Rule-Engine (JBoss Drools) durch eine wesentlich schlankere Eigenimplementierung ausgetauscht. Auch bei dieser Eigenimplementierung wurde auf bewährte Technologien wie Xtext und Xbase aus dem Eclipse-Modelling Umfeld zurück gegriffen. Einen detaillierten Einblick gibt [12].

Ausblick

Es bleibt spannend, was die Zukunft im IoT-Umfeld bringen wird. Für openHAB sind bereits viele zusätzliche Bindings am Horizont zu sehen, die weiteren „Dingen“ die Teilnahme am IoT ermöglichen werden. Ganz konkret sind hier Bindings für TCP/UDP, Sonos, Plugwise, Homematic, PLC, Modbus, IHC/ELKO und IRTrans zu nennen. Auch der Aufbau und der Support der stetig wachsenden Community werden weiter im Fokus des Projektteams stehen.

Fazit

Integrationsplattformen sind wichtige Komponenten im IoT-Umfeld. openHAB bietet als solche Plattform die richtigen APIs, um sowohl als Datenlieferant wie auch als Datenempfänger einen echten Mehrwert im IoT zu leisten.

Referenzen

  1. http://www.rfidjournal.com/article/view/4986  ↩

  2. http://it-republik.de/jaxenter/artikel/Home-Smart-Home-Heimautomatisierung-mit-OSGi-3833.html  ↩

  3. http://www.heise.de/newsticker/meldung/Quelloffene-Heimautomatisierung-mit-openHAB-1-0-1670540.html  ↩

  4. http://kaikreuzer.blogspot.com/2012/08/openhab-1.html  ↩

  5. http://code.google.com/p/openhab/wiki/ReleaseNotes10  ↩

  6. http://open.sen.se  ↩

  7. http://code.google.com/p/openhab/wiki/REST  ↩

  8. https://github.com/Atmosphere/atmosphere  ↩

  9. http://code.google.com/p/openhab/wiki/Architecture  ↩

  10. http://code.google.com/p/openhab/downloads/detail?name=HABDroid.apk  ↩

  11. https://itunes.apple.com/us/app/openhab/id492054521?mt=8  ↩

  12. http://kaikreuzer.blogspot.de/2012/05/xtext-xbase-quartz-joda-time-perfect.html  ↩

Thumb dsc02125 2

Thomas Eichstädt-Engelen is a Smart Living enthusiast, and contributor to the Eclipse SmartHome project, as well as project lead for openHAB. Until March 2016, he worked as Principal Consultant at innoQ. He has a strong focus on developing individual custom software with Eclipse technologies (Java, RCP, OSGi) primarily in the Smart Home sector.

More content

Eclipse magazin
Dieser Artikel ist ursprünglich in Ausgabe 01/2013 der Zeitschrift EclipseMagazin erschienen. Die Veröffentlichung auf innoq.com erfolgt mit freundlicher Genehmigung des S&S Media-Verlags.

Comments

Please accept our cookie agreement to see full comments functionality. Read more