Nachdem wir uns in Teil 1 mit den allgemeinen Grundprinzipien von IoT Hardware und Software vertraut gemacht haben, sehen wir uns dieses Mal einen etwas spezielleren Anwendungsfall am Beispiel von Azure IoT Hub an. Erneut steht der Do it yourself-Faktor im Vordergrund, indem der Sensor, welcher die Daten übermittelt, selbst gebastelt und programmiert wird. Ebenso wird eine Webanwendung entwickelt, um die Visualisierung der Daten vorzunehmen, die vom Sensor an einen Azure IoT Hub versendet wurden.
Im ersten Teil dieser Artikelserie haben wir einen IoT-Button entwickelt, der bei Betätigung ein Ereignis ausgelöst hat, das sich mit verschiedenen Web-API-basierten Aktionen verknüpfen ließ. Erste Erfahrungen mit der Visualisierung von IoT-Daten haben wir durch die Verwendung der Plattform ThingSpeak ebenfalls schon gesammelt. Da die Visualisierung diskreter Ereignisse im Sinne von „Knopf wurde gedrückt“ jedoch nur bedingt sinnvoll und optisch ansprechend ist, bedienen wir uns in diesem Artikel echter Sensordaten in Form von Temperatur und Luftfeuchtigkeitsmessungen.
Als Hardwareplattform wird uns wieder das Arduino-Ökosystem dienen, jedoch gehen wir einen Schritt weiter in Richtung Plattformabstraktion und versenden die Daten mit Hilfe des Microsoft Azure IoT Arduino SDKs an einen Azure IoT Hub. Die Sensordaten, die in diesem IoT Hub landen, werden anschließend in einer ebenfalls selbst entwickelten ASP.NET-Core-MVC-Anwendung konsumiert und in ansprechenden Graphen visualisiert.
Ehe wir beginnen können, IoT-Daten zu generieren, zu versenden, auszuwerten und zu visualisieren, müssen noch ein paar Vorbereitungen getroffen werden. Die Daten, die unser Sensor produzieren wird, sollen mit Hilfe von Azure IoT entgegengenommen und verarbeitet werden, dazu müssen im Azure-Portal entsprechende Ressourcen angelegt werden.
Zuallererst wird ein sogenannter IoT Hub benötigt, der als zentrale Sammelstelle für eine oder mehrere IoT-Datenquellen dient. Ein solcher IoT Hub lässt sich über die Kommandos Create a resource | Internet of Things | IoT Hub erstellen (Abb. 1). Im nächsten Schritt müssen dann noch ein paar Einstellungen getroffen werden (Abb. 2), bevor der IoT Hub tatsächlich erzeugt wird.
Im letzten Schritt muss man sich noch zu Skalierbarkeit und Größe des zu erstellenden IoT Hubs Gedanken machen (Abb. 3). Hier gilt natürlich, wie nahezu überall, je größer, desto teurer; jedoch sollte für unsere Demozwecke die kostenlose Variante (Free Tier) völlig ausreichend sein.
Nachdem der IoT Hub nun erfolgreich erstellt wurde, können wir im nachfolgenden Schritt schon darangehen, eine Ressource für den eigentlichen IoT-Sensor zu erzeugen. Hierfür registrieren wir im Abschnitt IoT Devices über die Schaltfläche Add ein neues Azure-IoT-Device, das den physischen Sensor repräsentiert (Abb. 4). Im folgenden Schritt (Abb. 5) muss noch ein Name für das IoT-Device vergeben werden (in unserem Beispiel: DIY_IoT_Sensor) und nach einem Klick auf die Schaltfläche Save steht dieses zur Verfügung.
Selektiert man das neu erzeugte IoT-Device nun per Mausklick im IoT Hub, werden in der Detailansicht einige Eigenschaften angezeigt. Für uns am wichtigsten ist die Eigenschaft Connection string, die wir später benötigen, um den physischen Sensor damit zu assoziieren (Abb. 6). Es empfiehlt sich daher, diese Zeichenfolge zu kopieren, um sie dann griffbereit zu haben.
Als abschließenden Schritt unserer Vorbereitungen klonen wir lediglich noch ein GitHub Repository, das den Code für die Beispielanwendung enthält, die wir nachfolgend verwenden werden. Dieses Repository ist anhand von zwei Verzeichnissen in ein Arduino-Projekt und ein ASP.NET-Core-Projekt unterteilt:
Nachdem alle Vorbereitungsarbeiten hiermit abgeschlossen sind, können wir uns der Entwicklung der eigentlichen Sensorhardware widmen. Abbildung 7 zeigt den Versuchsaufbau dieses Sensors und wie er sich mit relativ wenig Aufwand und Hardware-Komponenten bereits umsetzen lässt. Im Wesentlichen besteht der Sensor aus zwei Elektronikkomponenten, die auf einer Steckplatine fliegend verkabelt sind.
Abbildung 8 zeigt den Aufbau unseres IoT-Sensors noch einmal schematisch.
Die Programmierung unseres selbst entwickelten IoT-Sensors erfolgt wie im vorhergehenden Teil dieser Artikelserie mit der Arduino IDE (Abb. 9). Der erste Versuch, den Arduino Sketch Azure_IoT_Sensor.ino aus dem GitHub Repository zu kompilieren, wird vermutlich mit einer Unzahl von Fehlermeldungen quittiert werden, was daran liegt, dass eine Reihe von Vorbedingungen erfüllt sein muss.
Zuerst sollten wir überprüfen, ob der D1-Mikrocontroller in der Arduino IDE auch korrekt eingebunden und ausgewählt wurde. Da dieser Mikrocontroller (ebenso wie der NodeMCU im letzten Artikel) zur Familie der ESP8266-Boards gehört, die als externe Erweiterung in der Arduino IDE konfiguriert werden müssen, stellen wir sicher, dass die ESP8266-Erweiterung korrekt installiert wurde. Hierfür muss im Menü File der Eintrag Preferences ausgewählt werden, um den entsprechenden Einstellungsdialog zu öffnen. Dort sollte im Feld Additional Boards Manager URLs: der Eintrag http://arduino.esp8266.com/stable/package_esp8266com_index.json stehen, um sämtliche unterstützten ESP8266-Boards für die Arduino IDE verfügbar zu machen (Abb. 10). Über das Menükommando Tools | Board: | Board Manager und den sich daraufhin öffnenden Board-Manager-Dialog stellen wir dann sicher, dass die ESP8266-Erweiterung installiert ist. Hier ist ausschlaggebend, dass die Version 2.4.2 ausgewählt wird (Abb. 11) und gegebenenfalls muss ein Downgrade dieses Pakets erfolgen (siehe Kasten „Kompatibilitätsprobleme“). Wenn das geschehen ist, gilt es lediglich noch im Menü Tools | Board: unseren entsprechenden Mikrocontroller (D1 mini Pro) auszuwählen (Abb. 12).
Aktuell gibt es einen Konflikt zwischen der letzten Version 2.5.0 der Arduino-ESP8266-Erweiterung sowie den Azure-IoT-Bibliotheken, der sich in einer Reihe unangenehmer und kryptischer Compilerfehlermeldungen äußert. Das Problem lässt sich auf mehrere Arten lösen, in unserem Fall ist die schnellste und einfachste Variante jedoch die, auf Version 2.4.2 der ESP8266-Erweiterung zurückzugehen, da diese für unsere Zwecke völlig ausreichend ist.
Damit sich der Arduino Sketch Azure_IoT_Sensor.ino nun tatsächlich kompilieren lässt, ist es noch notwendig, eine Reihe von Softwarebibliotheken zu installieren, die zum einen die Kommunikation mit dem DHT11-Sensor erlauben und zum anderen die Integration in das Azure-IoT-Ökosystem ermöglichen. Die zusätzlichen Bibliotheken lassen sich bequem über den Libarary-Manager nachinstallieren, der über die Menükommandos Sketch | Include Library | Manage Libraries … geöffnet werden kann (Abb. 13). Um den DHT11-Temperatur- und -Luftfeuchtigkeitssensor verwenden zu können, müssen folgende zwei Bibliotheken installiert werden:
Die Verwendung des Micosoft Azure IoT Arduino SDKs setzt in unserem Fall folgende Pakete voraus:
Wenn wir nun, nach erfolgreicher Installation dieser Bibliotheken, versuchen, den Arduino Sketch zu kompilieren, sollte dies ohne Fehlermeldungen möglich sein. Zur Ausführung des Programms und zur Inbetriebnahme des Sensors müssen wir uns lediglich noch auf die Suche nach den drei #define-Konstanten aus Listing 1 machen, um ein erfolgreiches Funktionieren des Sensors zu ermöglichen. Da der Sensor über keine Eingabe- oder nachträgliche Konfigurationsmöglichkeiten verfügt, müssen elementare Konfigurationsdaten wie WLAN SSID und Passwort sowie der Azure IoT Connection String (siehe oben) fix im Code hinterlegt werden. Hier ist Vorsicht geboten, sollte man vorhaben, den Code wieder öffentlich zur Verfügung zu stellen. Allzu schnell landen Passwörter und Connection-Strings auf Plattformen wie GitHub und können für dubiose Zwecke missbraucht werden. Abhilfe kann hier eine zusätzliche Include-Datei schaffen, die die sensiblen Daten enthält und über Mechanismen wie .gitignore vor unbeabsichtigter Veröffentlichung geschützt wird.
Listing 1
//
// TODO: set these values before uploading the sketch
//
#define IOT_CONFIG_WIFI_SSID ""
#define IOT_CONFIG_WIFI_PASSWORD ""
#define IOT_CONFIG_CONNECTION_STRING ""
Wurden diese Konfigurationseinstellungen erfolgreich hinterlegt, der Sketch kompiliert und auf den Mikrocontroller übertragen, sollte dieser nun bereits kontinuierlich Sensordaten an unseren Azure IoT Hub schicken; Listing 2 zeigt den wesentlichen Teil des Codes, der dafür verantwortlich ist. Zuerst werden mit den Aufrufen von dht.readHumidity() und dht.readTemperature() die Temperatur- und Luftfeuchtigkeitswerte vom DHT11-Sensor ausgelesen und händisch über den Aufruf von sprintf in eine JSON-Datenstruktur verpackt. Diese JSON-Zeichenkette wird im nächsten Schritt mittels IoTHubMessage_CreateFromByteArray in ein IOTHUB_MESSAGE_HANDLE verpackt, das mit dem Aufruf von IoTHubClient_LL_SendEventAsync verschickt wird.
Listing 2
void loop()
{
sprintf(msg, "{ 'humidity': %.2f,'temperature':%.2f }", dht.readHumidity(), dht.readTemperature());
IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray((const unsigned char *)msg, strlen(msg));
if (messageHandle == NULL)
{
Serial.println("unable to create a new IoTHubMessage");
}
else
{
if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, nullptr, nullptr) != IOTHUB_CLIENT_OK)
{
Serial.println("failed to hand over the message to IoTHubClient");
}
else
{
Serial.println("IoTHubClient accepted the message for delivery");
}
IoTHubMessage_Destroy(messageHandle);
}
IOTHUB_CLIENT_STATUS status;
while ((IoTHubClient_LL_GetSendStatus(iotHubClientHandle, &status) == IOTHUB_CLIENT_OK) && (status == IOTHUB_CLIENT_SEND_STATUS_BUSY))
{
IoTHubClient_LL_DoWork(iotHubClientHandle);
ThreadAPI_Sleep(100);
}
Serial.println("wait...");
delay(5000);
}
Bevor wir die Daten unseres IoT-Sensors in einer eigenen Anwendung konsumieren und visualisieren, sollten wir zunächst überprüfen, ob diese Daten tatsächlich in unserem Azure IoT Hub ankommen.
Am einfachsten lässt sich das mit dem Azure IoT Device Explorer bewerkstelligen. Dabei handelt es sich um eine Windows-Applikation, die auf GitHub zur Verfügung steht und für schnelle Diagnosen und Fehlerbehebungszwecke entwickelt wurde. Wenn uns bis zu diesem Zeitpunkt keine Fehler unterlaufen sind, sollten die Daten, die der Sensor liefert, bereits im Azure Device Explorer auftauchen (Abb. 14).
Eine andere Möglichkeit, den Eingang der Sensordaten zu verifizieren, die auch auf Betriebssystemen wie Mac OS oder Linux zur Verfügung steht, ist die Verwendung der Azure CLI. Bei dieser handelt es sich um ein plattformübergreifendes Python-Kommandozeilenwerkzeug, das von der Dokumenatation heruntergeladen und installiert werden kann. Danach stehen mit dem Kommandozeilenbefehl az eine Vielzahl von Azure Konfigurations- und Diagnosemöglichkeiten zur Verfügung.
Vor der ersten Verwendung dieses Werkzeugs ist ein Log-in erforderlich, das über folgenden Befehl und einem sich anschließend öffnendem Browserfenster erfolgt.: az login.
Dann können die eingehenden Sensordaten über folgendes Kommando abgefragt werden:
az iot hub monitor-events --hub-name <IOT_HUB_NAME>
Die anschließende Ausgabe sollte jener in Listing 3 entsprechen.
Listing 3
Starting event monitor, use ctrl-c to stop...
{
"event": {
"origin": "DIY_IoT_Sensor",
"payload": "{ 'humidity': 24.00,'temperature':22.00 }"
}
}
{
"event": {
"origin": "DIY_IoT_Sensor",
"payload": "{ 'humidity': 32.00,'temperature':22.00 }"
}
}
Nachdem wir nun erfolgreich verifiziert haben, dass die Daten tatsächlich in unserem Azure IoT Hub landen, können wir uns ihrer Visualisierung widmen. Das Beispielprojekt im Ordner webapp, das diese Visualisierung übernimmt, ist eine ASP.NET-Core-MVC-Anwendung, die den Verlauf der Sensordaten in Echtzeit mit zwei Graphen für Temperatur und Luftfeuchtigkeit darstellt.
Zur Verbindung mit dem Azure IoT Hub wird das NuGet-Paket Microsoft.AzureEventHubs verwendet, das den Zugriff auf die eigentlichen Sensordaten ermöglicht. Mit Hilfe von ASP.NET Core SignalR werden diese Daten in Echtzeit zur Verfügung gestellt, um vom Webbrowser visualisiert werden zu können. Die Darstellung in den Graphen wird dabei von der JavaScript-Bibliothek Chart.js übernommen.
Die Applikation ist grundsätzlich bereit zur Ausführung, jedoch müssen auch in dieser – ähnlich wie in der Arduino-Anwendung – einige Konstanten angepasst werden, um eine erfolgreiche Verbindung zum IoT Hub zu ermöglichen. Auch hier gilt es wieder, eine gewisse Vorsicht mit Verbindungsdaten walten zu lassen, um diese nicht unbeabsichtigt für andere zugänglich zu machen. ASP.NET Core bietet hierfür sogar einen Mechanismus in Form von Application Secrets, deren Verwendung eine sinnvolle Erweiterung dieser Applikation darstellen würde.
Im Augenblick bedienen wir uns jedoch besagter Konstanten im Code und passen die Werte in Listing 4 der Klasse IoTHubEventsReader an.
Am einfachsten erhalten wir diese Werte, indem wir sie mit dem bereits erwähnten Kommandozeilenwerk az abfragen:
az iot hub show --query properties.eventHubEndpoints.events.endpoint --name
<IOT_HUB_NAME>
az iot hub show --query properties.eventHubEndpoints.events.path --name
<IOT_HUB_NAME>
az iot hub policy show --name iothubowner --query primaryKey --hub-name
<IOT_HUB_NAME>
Wenn wir die Applikation nun ausführen und der Sensor im Hintergrund Daten an den IoT-Sensor schickt, sollten diese Daten in Echtzeit eintreffen und wie in Abbildung 15 zu sehen visualisiert werden.
Listing 4
// Event Hub-compatible endpoint
private const string EventHubsCompatibleEndpoint = "";
// Event Hub-compatible name
private const string EventHubsCompatiblePath = "";
// SharedAccessKeyName
private const string IotHubSasKey = "";
Mit überschaubarem Aufwand haben wir ein Szenario entwickelt, in dem ein selbst gebauter Sensor mit dem Arduino Azure IoT SDK Daten an einen IoT Hub sendet, die anschließend in einer eigenen Applikation visualisiert werden. Dieses Szenario zeigt eindrucksvoll, wie man unter geschickter Verwendung von günstigen bis frei verfügbaren Hardware- und Softwarekomponenten Systeme entwickeln kann, die bis vor Kurzem einen immensen finanziellen oder zumindest zeitlichen Aufwand bedeutet hätten. Diese Art von Technologiedemokratisierung ist es, die es jedem von uns möglich macht, eigene Ideen und Visionen umzusetzen – sei es auch nur aus Interesse und Neugier an den Technologien an sich.