Beschäftigt man sich als Softwareentwickler mit dem Internet of Things (IoT), liegt das Hauptaugenmerk oft ausschließlich auf der Serverseite und der Auswahl von Cloud-Providern. Dabei ist ein Blick auf die Funktionsweise der eigentlichen „Things“, die die Basis der IoT-Pyramide ausmachen, mindestens genauso faszinierend. Mit ein wenig Programmieraufwand lässt sich sogar ein eigener IoT-Button erstellen.
Ob man dem Internet of Things und dem drum herum entstandenen Hype etwas abgewinnen kann oder nicht, liegt selbstverständlich im eigenen Ermessen und soll nicht Gegenstand dieses Artikels sein. Aus rein technischer Neugier jedoch lohnt sich ein Blick hinter die Kulissen und auf die eigentlichen Technologien, die dieses Ökosystem ausmachen. Das Hauptaugenmerk soll dabei aber zur Abwechslung einmal auf den Things liegen, also jenen Komponenten, die Daten erfassen und Aktionen in den Softwaresystemen im Hintergrund auslösen. Prominente Beispiele hierfür sind IoT-Buttons wie beispielsweise Amazons (heftig umstrittene und aktuell in Deutschland verbotene) Dash Buttons [1] oder zertifizierte IoT-Buttons für Microsoft Azure, wie sie beispielsweise von teXXmo [2] hergestellt werden.
Gemein ist diesen Geräten, dass sie per Knopfdruck Verbindung mit ihrem dahinterliegenden IoT-Serversystem aufnehmen und dort vordefinierte Aktionen auslösen. Eine solche Aktion kann vom Erfassen eines Datenpunkts über das Absetzen eines Tweets bis zum Herunterfahren eines Rollladens theoretisch alles beinhalten, sofern es sich serverseitig umsetzen lässt. Experimentierfreudige und kreative Geister haben vermutlich bereits beim Lesen dieser Zeilen ein Dutzend Szenarien im Kopf, die sich auf diese Weise verwirklichen ließen. Praktisch steht man allerdings vor dem Problem, dass fertige IoT-Buttons kaum bis gar nicht konfigurierbar sind und – wie im Fall von Amazons Dash Buttons – lediglich eine einzige voreingestellte Aktion auslösen können. Andere Geräte wie etwa teXXmo-IoT-Buttons bieten zwar diesbezüglich deutlich mehr Flexibilität, jedoch machen Mindestbestellmengen und Stückpreise zwischen 30 und 50 Euro einmalige Experimente zu einem wenig attraktiven Vergnügen. Vielmehr lohnt es sich, hier etwas Aufwand zu betreiben und ein solches Gerät im Eigenverfahren herzustellen.
Um tatsächlich einen physischen IoT-Button entwickeln zu können, ist allerdings ein Ausflug in die Welt der Mikrocontroller und Hardwareentwicklung Voraussetzung. Glücklicherweise existiert in diesem Bereich mit der Arduino Software- und Hardwareplattform quasi ein De-facto-Standard für Einsteiger und Hobbyisten [3]. Nahezu jedes Elektronikbastelprojekt setzt auf diese Plattform auf, was den Vorteil bietet, dass zu beinahe jedem Problem oder Anwendungsfall bereits ein Präzedenzfall in einem der unzähligen Internetforen zu finden ist. Anders als bei Einplatinencomputern wie dem Raspberry Pi [4] läuft auf einem Arduino-Mikrocontroller (Abb. 1) kein Betriebssystem, sondern lediglich ein Programm, das sofort nach dem Start ausgeführt wird.
Ein solches Arduino-Programm, das als „Sketch“ bezeichnet wird, entwickelt man in klassisch-hardwarenaher Manier in C oder C++, wobei gängige Arduino IDEs etwas Abstraktion bieten und man als Entwickler nur zwei Funktionen (setup und loop) implementieren muss. Der kürzestmögliche Arduino Sketch besteht somit lediglich aus diesen beiden leeren Methoden (Listing 1).
Listing 1
void setup()
{
}
void loop()
{
}
Typischerweise entwickelt man einen solchen Sketch mit der offiziellen und frei erhältlichen Arduino IDE (Abb. 2), die mittlerweile sogar über den Windows Store verfügbar ist; es stehen aber auch Add-ins für andere Entwicklungsumgebungen wie Visual Studio (Code) oder Eclipse zur Verfügung.
Der Arduino-Mikrocontroller wird (zumeist) über USB mit dem Rechner verbunden und der fertig kompilierte und gelinkte Sketch wird über ein serielles Protokoll an diesen übertragen. Über die serielle Schnittstelle erfolgt zumeist auch die Kommunikation mit dem Mikrocontroller zu Debugging- und Logging-Zwecken, da ein typisches Arduino Board in der Standardausführung über keine Anzeigemöglichkeiten verfügt und man auch einen Debugger vergebens sucht. Erfreulicherweise bietet die Arduino IDE zu diesem Zweck den sogenannten Serial Monitor (Abb. 2), der sich mit dem Eintrag Serial Monitor im Tools-Hauptmenü starten lässt und die serielle Kommunikation abwickelt. Der obligatorische „Hello World!“-Sketch ist in Listing 2 zu finden und zeigt zwei typische Muster der Arduino-Entwicklung. In der setup-Funktion finden diverse Initialisierungen statt (in dem Fall wird die Baudrate für die serielle Schnittstelle eingestellt) und in der loop-Funktion läuft zyklisch die Anwendungslogik, gedrosselt von einem delay-Aufruf (in Millisekunden).
Listing 2
void setup()
{
Serial.begin(115200);
}
void loop()
{
Serial.println("hello, world!");
delay(1000);
}
Um diesen ersten Arduino-Sketch gleich mit etwas Interaktivität anzureichern und dem Anspruch nach einem tatsächlichen IoT-Button Genüge zu tun, soll die Versuchsanordnung, wie sie in Abbildung 3 zu sehen ist, um einen solchen Druckknopf erweitert werden.
Zusätzlich zu Arduino und Druckknopf sind hierfür noch eine Experimentierplatine und zwei Steckverbinder nötig, wie sie in gängigen Arduino-Starterkits enthalten sind. Listing 3 zeigt die nötigen Änderungen am Sketch, die dafür sorgen, dass Pin 2 der Steckerleiste als Eingang initialisiert wird (pinMode) und in der Schleife mit digitalRead kontinuierlich abgefragt wird. Beim Drücken des Knopfs liefert der Aufruf von digitalRead den Wert LOW zurück und eine entsprechende Ausgabe erscheint wieder am Serial Monitor (Abb. 4).
Listing 3
void setup()
{
Serial.begin(115200);
pinMode(2, INPUT_PULLUP);
}
void loop()
{
int sensorVal = digitalRead(2);
if (sensorVal == LOW) {
Serial.println("Hello, from our IoT (?) Button!");
}
delay(50);
}
Wer sich angesichts dieser Tatsachen (C/C++, serielle Schnittstellen, Baudraten, fehlende Debugger, ...) in dunkle IT-Vorzeiten zurückversetzt fühlt oder diese Zeiten gar nur aus Erzählungen und Überlieferungen kennt, sollte dennoch nicht gleich die Flinte ins Korn werfen. Zum einen ist es eine durchaus spannende Erfahrung, nicht unzählige Abstraktionsschichten unter sich zu wissen, sondern möglichst nah an der eigentlichen Zielplattform zu arbeiten. Zum anderen sind Arduino-Sketche oft wenig komplex und lassen sich auch mit diesen bescheidenen Mitteln effizient umsetzen.
Angesichts der schon erwähnten Einschränkungen und der spartanischen Hardware, die ein typischer Arduino-Mikrocontroller mit sich bringt, bleibt auch die Hoffnung auf ein WLAN-Modul oder Internetfähigkeit vorerst nur ein frommer Wunsch. Zwar lassen sich verbreitete Arduino Boards wie der eingangs kennengelernte Arduino Uno (Abb. 1) nachträglich mit LAN- oder WLAN-Modulen bestücken, doch für diesen Anwendungsfall existiert eine sehr viel praktischere Abhilfe, die auf der Offenheit der Arduino-Spezifikation und ihrer Positionierung als Plattform beruht. Aus der Notwendigkeit der Netzwerkfähigkeit hat sich parallel zu den verschiedenen Ausprägungen und Klonen von (Atmel-Prozessor-basierten) Arduino Boards ein eigenes Ökosystem rund um den ESP8266-Mikrocontroller entwickelt. Ganz nach dem Arduino-Vorbild und -Prinzip stehen auch ESP8266-Mikrocontroller in verschiedensten Formen und Größen zur Verfügung (Abb. 5). Für die folgenden Versuchsanordnungen und Anwendungen wurde ein ESP8266 Board vom Typ NodeMcu (Abb. 5, oben rechts) verwendet [5], da es einen ausgezeichneten Kompromiss aus Formfaktor und Größe, Features (Micro-USB-Anschluss, nach außen geführte Pins etc.) sowie Preis (ab ca. 3 Euro im Chinaversand erhältlich) bietet.
Ebenso wie ihre Arduino-Vorbilder können ESP8266 Boards über die Arduino IDE programmiert werden. Voraussetzung dafür ist lediglich die Installation einer zusätzlichen Komponente, die die neue Hardware transparent in die Plattform integriert. Hierfür muss im Menü File der Eintrag Preferences ausgewählt werden, um den entsprechenden Einstellungsdialog zu öffnen. Dort wird im Feld Additional Boards Manager URLs: der Eintrag http://arduino.esp8266.com/stable/package_esp8266com_index.json hinzugefügt, um sämtliche unterstützte ESP8266 Boards für die Arduino IDE verfügbar zu machen (Abb. 6).
Der über das Menükommando Tools | Board: | Boards Manager zu öffnende Board-Manager-Dialog (Abb. 7) sorgt dann für die tatsächliche Installation in der IDE.
Jetzt gilt es lediglich noch, im Menü Tools | Board: den entsprechenden Mikrocontroller (NodeMCU 1.0) auszuwählen (Abb. 8), und die Versuchsanordnung mit dem Druckknopf sollte sich problemlos mit der neuen Hardware wiederholen lassen (Abb. 9).
Nachdem nun alle anfänglichen Hürden überwunden wurden, liegt das eigentliche Ziel der Kommunikation mit einem Netzwerk-Service endlich in greifbarer Nähe.
Voraussetzung für die erste erfolgreiche Netzwerkkommunikation ist die Registrierung des NodeMCU Boards im lokalen WLAN, was mit der Klasse WiFi aus der Bibliothek ESP8266WiFi.h in wenigen Schritten erledigt ist. Listing 4 zeigt die nötigen Änderungen in der Funktion setup, die für die erfolgreiche WLAN-Verbindung sorgen sollen.
Listing 4
#include <ESP8266WiFi.h>
void setup ()
{
Serial.begin(115200);
pinMode(2, INPUT_PULLUP);
WiFi.begin(<SSID>, <PASSWORD>);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print("Connecting ...");
}
}
Hier ist vor allem darauf zu achten, dass WLAN SSID und Passwort als Argumente an die Funktion WiFi.begin übergeben werden. Beabsichtigt man also, einen Sketch auf GitHub oder einer ähnlichen Plattform zu entwickeln und zu veröffentlichen, sollte man diese Argumente aus einer #include-Datei beziehen, die nicht Teil des veröffentlichten Codes ist.
Listing 5 enthält den eigentlichen Code, der zur Kommunikation über HTTP(S) und zum Absetzen einer einfachen GET-Anfrage an einen beliebigen URL notwendig ist. Der Klasse HTTPClient wird hierfür mit dem Aufruf von begin der entsprechende URL übergeben und zusätzlich sorgt der Parameter vom Typ WiFiClientSecure dafür, dass auch HTTPS-Kommunikation möglich ist. Der nachfolgende Aufruf der Funktion GET initiiert den tatsächlichen Datenaustausch über das Netzwerk. Im Erfolgsfall (HTTP-Antwortcode: 200) steht die Antwort über getString zum Abruf und zur Ausgabe am Serial Monitor bereit.
Listing 5
#include <ESP8266HTTPClient.h>
void loop()
{
if (WiFi.status() == WL_CONNECTED)
{
int sensorVal = digitalRead(2);
if (sensorVal == LOW) {
BearSSL::WiFiClientSecure client;
client.setInsecure();
HTTPClient https;
https.begin(client, <URL>);
int httpCode = https.GET();
if (httpCode == 200)
{
String payload = https.getString();
Serial.println(payload);
}
else
{
Serial.print("Fehler: ");
Serial.println(httpCode);
}
https.end();
}
}
}
Ein einfache Möglichkeit, um sicherzustellen, dass auch serverseitig die gewünschten Daten ankommen, ist die Verwendung des Dienstes Beeceptor [6], mit dem sich schnell und einfach Web-API-Endpunkte erstellen, Aufrufe in Echtzeit mitverfolgen und aufgrund von dynamisch definierten Regeln beantworten lassen. Abbildung 10 zeigt die Aktivitäten am Endpunkt https://beeceptor.com/console/windowsdeveloper, die von unserer Anwendung per Knopfdruck verursacht wurde.
An dieser Stelle lässt sich somit festhalten, dass die Basisanforderung an den selbst entwickelten IoT-Button erfolgreich umgesetzt wurde: Auf Knopfdruck besteht die Möglichkeit, einen beliebigen lokalen oder Internet-Service aufzurufen.
So zufriedenstellend der erste erfolgreiche Aufruf dieses simulierten Web-APIs auch war, soll nun dennoch ein tatsächlicher Anwendungsfall für den frisch geborenen IoT-Button folgen. Das neu erkorene Ziel besteht darin, per Knopfdruck einen Tweet abzusetzen. Das ließe sich vermutlich auch direkt über ein Aufrufen des Twitter-Web-APIs realisieren, doch birgt dies bereits eine gewisse Komplexität was Authentifizierung und Autorisierung betrifft, die nicht unbedingt am Mikrocontroller am besten aufgehoben ist. Zusätzlich stellt diese Entscheidung eine gewisse Einschränkung dar, sollte man zu einem späteren Zeitpunkt einen anderen Twitter-Account verwenden oder einen gänzlich anderen Service nutzen wollen. Aus diesem Grund bietet sich eine IoT-Plattform als Vermittlungsschicht zwischen IoT-Gerät und dem Ziel-Service (in diesem Fall Twitter) an. Eine solche Plattform, die speziell für IoT-Anwendungsfälle entworfen wurde, ist beispielsweise ThingSpeak [7]. Auf ThingSpeak können kostenfrei Endpunkte für IoT-Geräte angelegt und ihre Daten auf einfache Weise visualisiert werden. Der Fokus liegt dabei zwar auf IoT-Geräten, die kontinuierlich Daten wie Temperatur, Luftfeuchtigkeit usw. liefern, um diese dann in entsprechende Graphen zu verpacken, jedoch lässt sich mit Hilfe dieser Plattform auch der gewünschte Anwendungsfall einfach und problemlos umsetzen.
Nach erfolgreicher Registrierung können auf der ThingSpeak-Website eigene Channels definiert werden, die API-Endpunkten entsprechen (Abb. 11). Diese Channels werden über eindeutige URLs angesprochen und können bis zu acht Datenpunkte enthalten, die durch URL-Parameter (field1 - field8) identifiziert werden.
Das IoT-Button-Szenario würde grundsätzlich ganz ohne Datenpunkte auskommen, da keine variablen Werte transportiert werden, sondern der Aufruf an sich schon signalisiert, dass das gewünschte Ereignis eingetreten ist. Um jedoch später die Ereignissteuerung von ThingSpeak erfolgreich verwenden zu können, wird dennoch ein Datenpunkt bei der Erstellung des neuen Channels ausgewählt.
Wurde der Channel erfolgreich erstellt, findet man unter dem Reiter API Keys eine Reihe von URLs, die zur Aktualisierung sowie zur Datenabfrage des Channels verwendet werden können. Der URL, der für den Arduino-Sketch zur Anwendung kommt, findet sich unter Update a Channel Feed und hat die Form https://api.thingspeak.com/update?api_key=<SECRET_API_KEY>&field1=0. Ähnlich wie bei WLAN SSID und Passwort sollte man auch beim ThingSpeak API Key eine gewisse Sorgfalt walten lassen und ihn nach Möglichkeit aus dem Quellcode entfernen, falls man ihn veröffentlichen möchte.
Wieder lässt sich einfach verifizieren, ob der IoT-Button erfolgreich Daten an den neuen Endpunkt sendet, indem man die Visualisierung des Channels öffnet (Abb. 12).
Da der IoT-Button konstant den Wert 0 schickt, ist die Visualisierung an sich zwar wenig aussagekräftig, jedoch kann an dieser Stelle über den Menüeintrag React im Apps-Menü eine Ereignissteuerung hinzugefügt werden. An dieser Stelle kann die Verknüpfung des ThingSpeak-Kontos mit Twitter vorgenommen und eine Ereignisreaktion vom Typ ThingTweet erstellt werden. Diese neu erstellte Ereignisreaktion lässt sich anschließend so konfigurieren, dass unter der Bedingung, dass das Feld 1 den Wert 0 hat (also bei jedem Aufruf) ein Tweet abgesetzt wird (Abb. 13). Das Ergebnis ist in Abbildung 14 zu sehen.
Sofern man dem Themenkomplex IoT nicht fundamental ablehnend gegenübersteht und hardwarenahe Programmierung sowie ein wenig Elektronikbastelei nicht scheut, ist IoT auf der Clientseite ein äußerst spannendes Thema. Mit ein bisschen Kreativität und Erfindungsgeist lassen sich schon mit einem einfachen internetfähigen Druckknopf Projekte verwirklichen, die auch das alltägliche Leben bereichern und erleichtern können. Klassische Anwendungsszenarien im Bereich der Hausautomatisierung, beispielsweise Licht- oder Rollladensteuerungen, Klingeln und Türöffner, lassen sich mit dieser Technologie ebenso umsetzen wie spielerische Anwendungen in Form von Medientasten, die die aktuelle Lieblingsplaylist der Kinder auf dem netzwerkfähigen Soundsystem startet. Grenzen setzen dabei lediglich der eigene Erfindergeist und die Fantasie.
Wolfgang Ziegler ist Softwareentwickler, Blogger und Autor. Er ist .NET-Enthusiast der ersten Stunde und seine aktuellen Schwerpunkte liegen auf Webtechnologien und Cross-Plattform-Entwicklung mit .NET Core. Für Fragen, Trainings oder Vorträge steht er jederzeit gerne zur Verfügung.