Kapitel 1. Erste Schritte

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Ein Weg liegt vor uns,

Brombeeren und Dornen, dann lichtet es sich.

Fast geschafft. Geduld.

Unter hast du wahrscheinlich schon mitbekommen, dass das Internet der Dinge riesig, unhandlich und sehr schwer zu bändigen ist. Um einen Weg nach vorne zu planen, müssen wir zunächst ein Problemfeld identifizieren und dann eine Architektur entwerfen, auf deren Grundlage wir unsere IoT-Lösung entwerfen und aufbauen können.

Beginnen wir mit ein paar wichtigen Fragen, um eine Grundlage zu schaffen: Welches Problem versuchst du zu lösen? Wo beginnt und endet es? Warum braucht es ein IoT-Ökosystem? Wie werden alle Teile zusammenarbeiten, um dieses Problem zu lösen? Welches Ergebnis kannst du erwarten, wenn alles wie geplant funktioniert? Wir werden jede dieser Fragen im Detail untersuchen und auf dem Weg dorthin eine durchgängige, integrierte IoT-Lösung entwickeln, die unsere Anforderungen erfüllt.

Was du in diesem Kapitel lernen wirst

Damit du wirklich verstehst, wie ein IoT-System aufgebaut werden kann und sollte, werde ich anhand der vorangegangenen Fragen einige grundlegende architektonische Konzepte erläutern und diese als Grundlage für jede Programmieraufgabe verwenden. Darauf aufbauend baust du eine Lösung, die das Problem Schicht für Schicht angeht, und fügst mit jedem weiteren Kapitel weitere Funktionen hinzu.

Es versteht sich von selbst, dass die richtigen Entwicklungstools dir Zeit und Frustration ersparen und dir beim Testen, Validieren und Bereitstellen helfen. Es gibt viele hervorragende Open-Source- und kommerzielle Entwicklungswerkzeuge und Frameworks, die dich dabei unterstützen.

Wenn du schon länger als Entwickler arbeitest, hast du sicher deine eigenen Vorlieben für die Entwicklungsumgebung, die am besten zu deinem Programmierstil und -ansatz passen. Die Beispiele, die ich dir zeige, basieren zwar auf meinen bevorzugten Werkzeugen, aber mein Ziel in diesem Kapitel ist es nicht, dir die Werkzeuge vorzuschreiben, die du verwenden musst, sondern dir dabei zu helfen, die IoT-Entwicklung so voranzutreiben, dass du schnell loslegen und schließlich deine eigenen Werkzeuge für zukünftige Entwicklungsprojekte auswählen kannst.

Die Konzepte, die ich vorstelle, werden das Wichtigste sein; die Programmiersprachen, Tools (und ihre jeweiligen Versionen) und Methoden können geändert werden. Diese Konzepte stellen einige der Grundlagen einer konsistenten Softwareentwicklung dar: Systemdesign, Kodierung und Tests.

Dein System definieren

Das Erstellen einer Problemstellung ist wahrscheinlich der wichtigste Teil dieses Puzzles. Beginnen wir damit, etwas zu formulieren, das einigermaßen einfach ist, aber ausreicht, um eine Vielzahl interessanter IoT-Herausforderungen zu erfassen:

Ich möchte die Umwelt in meinem Haus verstehen, wie sie sich im Laufe der Zeit verändert, und Anpassungen vornehmen, um den Komfort zu verbessern und gleichzeitig Geld zu sparen.

Das hört sich einfach an, aber das ist ein sehr weit gefasstes Ziel. Wir können es eingrenzen, indem wir die wichtigsten Aktionen und Objekte in unserer Problemstellung definieren. Unser Ziel ist es, das Was, das Warum und das Wie zu isolieren. Schauen wir uns zunächst das Was und das Warum an und ermitteln dann die Maßnahmen, die bei der Gestaltung berücksichtigt werden sollten.

Das Problem aufschlüsseln

Die Übungen in diesem Buch konzentrieren sich auf den Aufbau einer IoT-Lösung, die dir hilft, deine häusliche Umgebung zu verstehen und entsprechend zu reagieren. Wir gehen davon aus, dass du wissen willst, was in deinem Haus vor sich geht (in einem vernünftigen Rahmen) und dass du bei Bedarf Maßnahmen ergreifen kannst (z. B. die Klimaanlage einschalten, wenn die Temperatur zu hoch ist).

In diesem Teil von geht es um drei wichtige Aktivitäten:

Maßnahme: Daten sammeln

Definieren wir dies in Bezug auf das, was erfasst werden kann, wie Temperatur, Luftfeuchtigkeit und so weiter. Hier geht es um die Erfassung und Übertragung von Telemetriedaten(Messdaten ). Die Aktion - oder besser gesagt, die Aktionskategorie - heißt Datenerfassung und umfasst die folgenden Datenelemente (du kannst später weitere hinzufügen):

  • Temperatur

  • Relative Luftfeuchtigkeit

  • Barometrischer Druck

  • Systemleistung (Auslastungsmetriken für CPU, Speicher, Speicherung)

Modell: Ermitteln relevanter Veränderungen gegenüber einer gegebenen Ausgangssituation
Um zu entscheiden, welche Daten relevant sind und ob eine Veränderung des Wertes wichtig ist oder nicht, müssen wir nicht nur Daten sammeln, sondern auch Zeitreihendaten über die Elemente, die wir wahrnehmen können (wie Temperatur, Luftfeuchtigkeit usw., wie in der vorangegangenen Definition angegeben), speichern und trendmäßig darstellen. Dies wird in der Regel als Umwandlung von Daten in Informationen bezeichnet. Ich bezeichne diese Kategorie als Datenmanagement.
Verwalten: Maßnahmen ergreifen
Wir werden einige grundlegende Regeln aufstellen, um festzustellen, ob wir wichtige Schwellenwerte überschritten haben. Das bedeutet einfach, dass wir ein Signal an etwas senden, wenn ein Schwellenwert überschritten wird, der eine bestimmte Aktion erfordert (z. B. das Hoch- oder Herunterdrehen eines Thermostats). Dies wird in der Regel als Umwandlung von Informationen in Wissen bezeichnet. Ich bezeichne diese Kategorie als System-Trigger.

In meinem IoT-Kurs an der Universität spreche ich oft über Messen, Modellieren und Verwalten. Für mich sind das die Kernaspekte eines jeden IoT-Designs, die letztendlich dazu beitragen, die festgelegten Geschäftsziele oder Ergebnisse des Systems zu erreichen.

Relevante Ergebnisse definieren

Da wir nun wissen, welche Schritte wir unternehmen müssen, wollen wir uns mit dem Warum unserer Problemstellung befassen. Wir können dies mit den folgenden zwei Punkten zusammenfassen:

  • Mehr Komfort: Im Idealfall möchten wir eine gleichmäßige Temperatur und Luftfeuchtigkeit in unserem Wohnumfeld aufrechterhalten. Die Dinge werden ein bisschen komplizierter, wenn wir die Anzahl der Räume, ihre Nutzung und so weiter berücksichtigen. Ich bezeichne diese Aktionskategorie als Konfigurationsmanagement und sie geht Hand in Hand mit Datenmanagement und Systemauslösern.

  • Geld sparen: Das ist ein bisschen knifflig. Der offensichtlichste Weg, Geld zu sparen, ist, es nicht auszugeben! Da wir wahrscheinlich finanzielle Mittel für das Heizen, Kühlen oder Befeuchten eines bestimmten Bereichs aufwenden müssen, wollen wir das Optimum herausholen - nicht zu viel (Verschwendung) und nicht zu wenig (wir könnten im Winter mit gefrorenen Wasserleitungen enden). Da wir es hier mit einer gewissen Komplexität zu tun haben - z. B. Energiekosten, saisonale Schwankungen und alles, was mit dem Konfigurationsmanagement zu tun hat -, brauchen wir wahrscheinlich ein paar fortschrittlichere Analysen, um diese Probleme zu lösen. Ich nenne diese Aktionskategorie Analytik.

Du hast wahrscheinlich bemerkt, dass jeder Schritt in den Abschnitten "Was" und " Warum" einen Namen für eine Aktionskategorie hat, die bei der Entwicklung der Lösung helfen wird, wenn wir zum "Wie" übergehen. Zur Erinnerung: Diese Kategorien sind Datenerfassung, Datenmanagement, Systemauslöser, Konfigurationsmanagement und Analysen. Auf jede dieser Kategorien werden wir im Rahmen unseres Implementierungsansatzes näher eingehen.

Obwohl die Problemstellung auf den ersten Blick recht banal erscheint, stellt sich heraus, dass die Dinge, die du tun musst, um das Problem zu lösen, in vielen IoT-Systemen tatsächlich recht häufig vorkommen. Es ist notwendig, Daten an der Quelle zu sammeln, zu speichern und zu analysieren und Maßnahmen zu ergreifen, wenn ein Indikator darauf hindeutet, dass dies von Vorteil wäre. Sobald du deine IoT-Architektur definierst und mit dem Bau der Komponenten beginnst, die sie implementieren - auch wenn sie spezifisch für dieses Problem ist -, wirst du sehen, wie sie auf viele andere Problembereiche angewendet werden kann.

Werfen wir einen kurzen Blick auf einen einfachen Datenfluss, der diesen Entscheidungsprozess darstellt. In dem in Abbildung 1-1 dargestellten Datenflussdiagramm ist jede Aktionskategorie hervorgehoben.

Simple IoT data flow
Abbildung 1-1. Einfacher IoT-Datenfluss

Die meisten IoT-Systeme werden zumindest einige der fünf genannten Handlungskategorien benötigen. Das bedeutet, dass wir eine Architektur definieren können, die diese in einem Systemdiagramm abbildet, und dann mit der Erstellung von Softwarekomponenten beginnen, die einen Teil des Systems implementieren.

Hier fängt der Spaß für uns Ingenieure an, also lass uns mit einer Architekturdefinition loslegen, die unsere Problemstellung unterstützt (und die auch für andere wiederverwendbar ist).

Eine Lösung entwerfen

Organisation, Struktur und Klarheit sind die Markenzeichen einer guten Architektur, aber zu viel davon kann zu einem starren System führen, das sich nicht gut an zukünftige Bedürfnisse anpassen lässt. Und wenn wir versuchen, eine Architektur zu erstellen, die alle unsere denkbaren Anforderungen erfüllt, werden wir nie fertig (oder fangen vielleicht nicht einmal an)! Es geht um Ausgewogenheit, also lass uns die Architektur mit Blick auf zukünftige Flexibilität definieren, aber lass uns die Dinge auch relativ gut eingrenzen. So kannst du dich darauf konzentrieren, schnell zu einer Lösung zu kommen, während du in der Zukunft immer noch Aktualisierungen zulässt. Zunächst müssen jedoch einige Schlüsselbegriffe definiert werden, um ein architektonisches Grundgerüst zu schaffen, auf dem du deine Lösung aufbauen kannst.

Wie du dich vielleicht aus Abbildung P-1 im Vorwort erinnerst, werden IoT-Systeme in der Regel mit mindestens zwei (und manchmal drei oder mehr) architektonischen Ebenen im Hinterkopf entwickelt. Dies ermöglicht die Trennung der Funktionen sowohl physisch als auch logisch, was flexible Einsatzmöglichkeiten eröffnet. Das bedeutet, dass sich die Cloud-Dienste, die auf der Cloud-Ebene laufen, technisch gesehen überall auf der Welt befinden können, während sich die Geräte, die auf der Edge-Ebene laufen, am selben Ort befinden müssen wie die zu messenden physischen Systeme. Wie in Abbildung P-1 angedeutet, kann ein Beispiel für dieses Tiering darin bestehen, dass ein eingeschränktes Gerät mit Sensoren oder Aktoren mit einem Gateway-Gerät kommuniziert, das wiederum mit einem Cloud-basierten Dienst kommuniziert und umgekehrt.

Da wir einen Ort für die Implementierung dieser fünf Funktionskategorien brauchen, ist es wichtig, ihren Standort innerhalb der Architektur zu bestimmen, damit wir einige Dinge in der Nähe des Ortes der Handlung ausführen können und andere in der Cloud, wo du und ich leicht auf die Funktionen zugreifen (und sie sogar anpassen) können. Erinnern wir uns an die Edge Tier- und Cloud Tier-Architektur aus dem Vorwort und schauen wir uns an, wie wir die einzelnen Aktionskategorien aus dem Was und Warum den einzelnen Ebenen zuordnen:

  • Edge Tier (eingeschränkte Geräte und Gateway-Geräte): Datenerfassung, Datenmanagement, Gerätetrigger, Konfigurationsmanagement und Analysen

  • Cloud Tier (Cloud-Dienste): Datenmanagement, Konfigurationsmanagement und Analytik

Warum enthalten Edge Tier und Cloud Tier ähnliche Funktionen? Das liegt zum Teil an der Notwendigkeit, aber auch daran, dass wir es einfach können. Die technischen Grenzen und die Trennung der Zuständigkeiten zwischen Edge und Cloud werden immer unschärfer, da die Rechenleistung zunimmt und die geschäftlichen Anforderungen Rechen- und Analysefunktionen so nah wie möglich am Edge erfordern. Für einige autonome Entscheidungen ist es zum Beispiel nicht erforderlich, dass Nachrichten über das Internet in die Cloud und wieder zurück geschickt werden, da der Edge Tier sie direkt verwalten kann (und in einigen Fällen auch sollte). Es ist also wichtig, diese Fähigkeit zu berücksichtigen, wann immer und wo immer es sinnvoll ist.

Abbildung 1-2 zeigt, wie der einfache Datenfluss aus Abbildung 1-1 in eine mehrstufige Architektur passt.

Notional IoT data flow between the Edge and Cloud Tiers
Abbildung 1-2. Fiktiver IoT-Datenfluss zwischen der Edge- und der Cloud-Ebene

Beachte auch hier, dass wir uns die Verantwortung teilen, denn einige der Aktionskategorien werden in beiden Ebenen umgesetzt. Normalerweise ist doppelter Aufwand eine schlechte Sache - aber in diesem Fall kann er ein Vorteil sein! Mithilfe von Analysen kann anhand einiger Grundeinstellungen bestimmt werden, ob ein Auslöser an ein Gerät gesendet werden soll. Wenn die Temperatur in deiner Wohnung beispielsweise 30 °C übersteigt, möchtest du wahrscheinlich sofort die Klimaanlage einschalten und die Temperatur auf 22 °C senken. Es ist nicht nötig, sich dabei auf einen entfernten cloudbasierten Dienst in der Cloud Tier zu verlassen. Allerdings wäre es sinnvoll, die Cloud Tier darüber zu informieren, dass dies geschieht, und vielleicht einige historische Daten für spätere Analysen zu speichern.

Unsere Architektur nimmt langsam Form an. Jetzt brauchen wir nur noch eine Möglichkeit, sie in einem Systemdiagramm abzubilden, damit wir mit der physischen Welt interagieren können (mit Sensoren und Aktoren). Es wäre auch gut, die Dinge innerhalb der Edge Tier zu strukturieren, um zu vermeiden, dass Komponenten unnötigerweise dem Internet ausgesetzt werden. Diese Funktionalität kann als Anwendung implementiert werden, die entweder direkt auf dem Gerät oder auf einem Laptop oder einem anderen allgemeinen Computersystem mit Simulationslogik, die das Verhalten von Sensoren und Aktoren emulieren kann, ausgeführt werden kann. Dies wird als Grundlage für eine der beiden Anwendungen dienen, die du ab diesem Kapitel entwickeln wirst.

Da du irgendwann auf das Internet zugreifen willst, sollte dein Entwurf ein Gateway enthalten, das diese und andere Anforderungen erfüllt. Diese Funktion kann als Teil einer zweiten Anwendung implementiert werden, die du in diesem Kapitel entwickeln wirst. Diese Anwendung wird so konzipiert, dass sie auf einem Gateway-Gerät (oder auch auf einem Laptop oder einem anderen allgemeinen Computersystem) läuft. Deine Anwendung für das Gateway-Gerät und die Anwendung für das eingeschränkte Gerät bilden den "Rand" deines IoT-Designs, den ich in Zukunft als Edge Tier deiner Architektur bezeichnen werde.

Außerdem solltest du Analysedienste, Speicherungen und Ereignis-Manager so einsetzen, dass sie sicher sind, aber auch von deinem Gateway-Gerät und von Menschen genutzt werden können. Es gibt viele Möglichkeiten, dies zu tun, aber ich werde mich auf die Nutzung eines oder mehrerer Cloud-Dienste für einen Großteil dieser Funktionen konzentrieren.

Abbildung 1-3 bietet eine neue Ansicht, die dir einen weiteren Einblick in das gibt, was du bauen wirst und wie du die fünf erwähnten Aktionskategorien einbauen kannst. In grauen Kästen sind die Cloud-Dienste im Cloud Tier und die beiden Anwendungen im Edge Tier dargestellt, die die Funktionen deines eingeschränkten Geräts bzw. deines Gateway-Geräts enthalten.

Notional IoT simplified logical architecture with Edge and Cloud Tiers
Abbildung 1-3. Fiktive, vereinfachte logische IoT-Architektur mit Kanten- und Cloud-Ebenen

Schauen wir uns die einzelnen Punkte etwas genauer an:

Constrained Device Application (CDA)
Du erstellst diese Softwareanwendung, die als Teil eines simulierten Geräts ( ) in deiner Entwicklungsumgebung läuft und die Funktionen zur Datenerfassung und zum Auslösen von Systemen bereitstellt. Sie bildet die Schnittstelle zwischen den Sensoren des Geräts (die Daten aus der Umgebung ablesen) und den Aktoren (die Aktionen auslösen, z. B. das Ein- oder Ausschalten der Klimaanlage). Es wird auch eine Rolle dabei spielen, Maßnahmen zu ergreifen, wenn eine Auslösung erforderlich ist. Schließlich wird sie mit einer Kommunikationsbibliothek verbunden sein, um Nachrichten an die Gateway-App zu senden und von ihr zu empfangen.
Gateway Device Application (GDA)
Du erstellst diese Softwareanwendung, die als Teil eines simulierten Gateway-Geräts in deiner Entwicklungsumgebung läuft und Datenmanagement-, Analyse- und Konfigurationsmanagementfunktionen bietet. Ihre Hauptaufgabe besteht in der Verwaltung von Daten und den Verbindungen zwischen dem CDA und den Cloud-Diensten, die im Cloud Tier existieren. Sie verwaltet die Daten je nach Bedarf lokal und wird manchmal aktiv, indem sie einen Befehl an das eingeschränkte Gerät sendet, der eine Aktion auslöst. Sie verwaltet auch einige Konfigurationseinstellungen, d. h. diejenigen, die den Sollbereich für deine Umgebung darstellen, und führt erste Analysen durch, wenn neue Telemetriedaten empfangen werden.
Cloud-Dienste
Alle Anwendungen und Funktionen von Cloud-Diensten übernehmen oft einen Großteil der Datenverarbeitung und -speicherung, da sie theoretisch bis ins Unendliche skalieren können. Das bedeutet einfach, dass du, wenn sie gut konzipiert sind, so viele Geräte hinzufügen kannst, wie du willst, so viele Daten speichern kannst, wie du willst, und diese Daten eingehend analysieren kannst - Trends, Höchst- und Tiefstwerte, Konfigurationswerte und so weiter - und dabei alle relevanten Erkenntnisse an einen menschlichen Endnutzer weitergeben und vielleicht sogar Edge-Tier-Aktionen auf der Grundlage von definierten Schwellenwertüberschreitungen durchführen kannst. Technisch gesehen können Cloud-Dienste in einer IoT-Umgebung alle zuvor genannten Aktionskategorien ausführen, mit Ausnahme der Datenerfassung (d. h. sie führen keine direkten Erfassungs- oder Aktivierungsaktionen durch). Du wirst einige Cloud-Dienste entwickeln, die diese Funktionen übernehmen, aber in den meisten Fällen wirst du auf die allgemeinen Dienste zurückgreifen, die bereits von einigen Cloud-Providern angeboten werden.

Abbildung 1-4 zeigt, wie jede wichtige logische Komponente innerhalb unserer beiden Architekturebenen mit den anderen Komponenten zusammenwirkt.

Notional IoT detailed logical architecture with Edge and Cloud Tiers
Abbildung 1-4. Fiktive logische IoT-Detailarchitektur mit Kanten und Cloud-Ebenen

Wir werden die Abbildungen 1-3 und 1-4 als Basisarchitektur für alle Übungen in diesem Buch verwenden.

Jetzt, wo wir wissen, womit wir es zu tun haben, können wir unsere Entwicklungsumgebung einrichten, damit wir anfangen können, Code zu schreiben.

Einrichten deiner Entwicklungs- und Testumgebung

Die Entwicklung und Bereitstellung von Code für verschiedene Betriebssysteme, Hardwarekonfigurationen und Konfigurationssysteme ist kein Zuckerschlecken. Bei typischen IoT-Projekten müssen wir uns nicht nur mit verschiedenen Hardware-Komponenten auseinandersetzen, sondern auch mit den unzähligen Möglichkeiten, diese Plattformen zu entwickeln und bereitzustellen, ganz zu schweigen von den Eigenheiten der verschiedenen Cloud-Provider-Umgebungen, in denen wir oft arbeiten, was die kontinuierliche Integration und die kontinuierliche Bereitstellung (CI/CD) angeht.

Wie fangen wir bei all diesen Herausforderungen überhaupt an? Das Wichtigste zuerst: Welches Problem wollen wir lösen? Als Entwickler möchtest du deinen IoT-Entwurf in Code umsetzen, ihn testen, ihn so verpacken, dass er leicht auf ein oder mehrere Systeme verteilt werden kann, und ihn sicher einsetzen. Wir können unsere Entwicklungsherausforderungen in Form von Build-, Test- und Deployment-Phasen betrachten, die sich auch in zwei architektonische Ebenen einteilen lassen: Edge Tier (Telemetrie-Erzeugung und -Aktivierung) und Cloud Tier (Remote-Computing-Infrastruktur). Auf die Funktionen der Cloud Tier gehe ich später in Teil IV ein, während sich die Teile I, II und III auf die Edge Tier konzentrieren werden.

Obwohl der Edge Tier eines typischen IoT-Ökosystems mit spezieller Hardware zu tun haben könnte, kannst du für unsere Zwecke einen Großteil des erforderlichen Systemverhaltens simulieren und sogar einige Hardwarekomponenten in deiner lokalen Entwicklungsumgebung emulieren. Das macht den Einsatz viel einfacher und eignet sich hervorragend für alle Übungen in diesem Buch.

Es gibt viele Möglichkeiten, mit der IoT-Entwicklung zu beginnen. Die Übungen in diesem Buch konzentrieren sich auf den Aufbau eines integrierten, simulierten Implementierungsansatzes, der im Folgenden beschrieben wird. Die Integration von Hardware ist völlig optional und liegt außerhalb des Rahmens dieses Buches, wird aber in Kapitel 4 kurz als optionale Übung erwähnt.

Integrierter simulierter Einsatz
Dieser Ansatz erfordert kein spezielles Gerät und ermöglicht es dir, deine Entwicklungs-Workstation (Laptop) sowohl als Gateway als auch als eingeschränktes Gerät zu verwenden. Das heißt, du führst deine GDA und CDA in deiner lokalen Computerumgebung aus. Du wirst deine Sensor- und Antriebshardware emulieren, indem du einfache Softwaresimulatoren erstellst, um diese Funktionen in deinem CDA zu erfassen. Alle im Buch geforderten Übungen, mit Ausnahme der optionalen Übungen in Kapitel 4, die online zur Verfügung gestellt werden, sollten sich mit diesem Ansatz umsetzen lassen.
Getrennter physischer Einsatz

Dazu brauchst du ein Hardware-Gerät, wie z. B. einen Raspberry Pi, mit dem du dich mit echten Sensoren und Aktoren verbinden und mit ihnen interagieren kannst. Obwohl viele handelsübliche Single-Board-Computing-Geräte (SBC) als vollwertige Computer-Workstations verwendet werden können, bezeichne ich dieses Gerät als dein eingeschränktes Gerät, auf dem dein CDA direkt ausgeführt wird. Wie bei der integrierten simulierten Bereitstellung führst du den GDA in deiner lokalen Computerumgebung aus.

Hinweis

Wie bereits im Vorwort erwähnt, definiert das IETF RFC 7228 Dokument verschiedene Klassen von eingeschränkten Geräten (auch als eingeschränkte Knoten bezeichnet). Zu diesen Klassen gehören Klasse 0 (sehr eingeschränkt), Klasse 1 (eingeschränkt) und Klasse 2 (etwas eingeschränkt).1 Für unsere Zwecke gehen wir davon aus, dass unser CDA auf Geräten der Klasse 2 oder noch leistungsfähigeren Geräten laufen kann, die in der Regel vollständige IP-basierte Netzwerkstacks unterstützen. Obwohl es technisch möglich ist, Geräte der Klasse 2 direkt mit dem Internet zu verbinden, werden alle Beispiele und Übungen indirekt über den GDA mit dem Internet interagieren.

Blended Physical Deployment
Dieser Ansatz ist fast identisch mit dem Ansatz der getrennten Bereitstellung, allerdings werden sowohl dein CDA als auch dein GDA auf dem SBC-Gerät ausgeführt. Das bedeutet, dass du jede Anwendung auf einem anderen SBC bereitstellen kannst, obwohl das für keine der aufgeführten Übungen notwendig ist.

Die Übungen in diesem Buch konzentrieren sich zwar auf den integrierten, simulierten Einsatzansatz, aber wenn du dich für einen der beiden letzten Wege entscheidest, gibt es eine große Auswahl an preiswerten SBCs, die für dich in Frage kommen. Die einzigen Übungen in diesem Buch, die Hardware erfordern, sind die optionalen Übungen in Kapitel 4. Obwohl du sie auch auf anderen Hardware-Plattformen durchführen könntest, sind sie für die folgende Hardware konzipiert Raspberry Pi Modell 3 oder 4 und die Sense HAT-Platine (die an den GPIO (General-Purpose Input/Output) angeschlossen wird und den I2C (Inter-Integrated Circuit)-Bus für die Gerätekommunikation nutzt). Wenn du für diese Übungen ein anderes Gerät auswählst, solltest du eines in Betracht ziehen, das folgende Eigenschaften hat: GPIO-Funktionalität, I2C, TCP/IP- und UDP/IP-Netzwerke über WiFi oder Ethernet, Unterstützung für ein Linux-basiertes Betriebssystem (wie Debian oder ein Derivat) und Unterstützung für sowohl Python 3 als auch Java 11 (oder höher).

Die Übungen in diesem Buch konzentrieren sich auf den integrierten simulierten Einsatzpfad. Teil II führt in das Konzept der Integration mit der physischen Welt ein, und in Kapitel 4 werde ich einige Konzepte zur Hardware-Integration ansprechen, ohne dabei den Fokus auf simulierte Daten und emulierte Hardware zu verlieren.

Unabhängig vom gewählten Bereitstellungspfad gehen alle Übungen und Beispiele davon aus, dass du deine Entwicklung und Bereitstellung auf einer einzigen Workstation durchführst. Dazu gehört ein dreistufiger Prozess, der die Vorbereitung deiner Entwicklungsumgebung, die Definition deiner Teststrategie und die Festlegung eines Automatisierungsansatzes für die Erstellung und Bereitstellung umfasst. Ich werde in diesem Kapitel die Grundlagen dieser Schritte behandeln, um dir den Einstieg zu erleichtern. In späteren Übungen, die zusätzliche Abhängigkeiten sowie Test- und Automatisierungsanforderungen beinhalten, werde ich diese Schritte noch weiter ausführen.

Hinweis

Vielleicht hast du bereits Erfahrung mit der Entwicklung von Anwendungen in Java und Python in deiner eigenen Entwicklungsumgebung. Wenn das der Fall ist, solltest du den ersten Schritt - die Vorbereitung deiner Entwicklungsumgebung - noch einmal durchgehen, um sicherzustellen, dass deine Entwicklungsumgebung, einschließlich deines Betriebssystems, der Java-Laufzeitumgebung und des Python-Interpreters, mit den Anforderungen der Übung kompatibel ist.

Schritt I: Bereite deine Entwicklungsumgebung vor

Erinnere dich daran, dass dein CDA in Python und dein GDA in Java geschrieben wird. Technisch gesehen bedeutet dies, dass jedes Betriebssystem, das Python 3.7 oder höher und Java 11 oder höher unterstützt, für die meisten Übungen verwendet werden kann. Es gibt jedoch einige Linux-spezifische Abhängigkeiten , die du beachten solltest, bevor du deine Entwicklungsumgebung einrichtest:

  • Kapitel 4: Der Hardware-Emulator, den ich in diesem Kapitel bespreche, benötigt eine Unix-basierte Umgebung und einen X11 Server, um seine grafische Benutzeroberfläche (GUI) zu unterstützen. Linux und macOS sollten funktionieren, während für Windows das Windows Subsystem für Linux (WSL)2 und einen X11-Server.

  • Kapitel 8: Der Python-basierte CoAP3 Server ist eine optionale Übung und wurde teilweise mit dem Java-Client aus Kapitel 9 unter Windows 10, macOS und Linux getestet. Zum jetzigen Zeitpunkt wirst du diese Tests wahrscheinlich in einer Linux-basierten Umgebung durchführen müssen.

  • Kapitel 9: Einige der Python-basierten CoAP-Client-Übungen hängen derzeit von Linux-spezifischen Bindungen ab. Zum jetzigen Zeitpunkt musst du diese Tests wahrscheinlich in einer Linux-basierten Umgebung durchführen.

Obwohl ich die Einrichtung für Linux, macOS und Windows erläutern werde, empfehle ich dir, Linux als Entwicklungsumgebung zu verwenden, um einige der eben erwähnten Integrationsprobleme zu vermeiden. Lies dir unbedingt PIOT-CFG-01-001 durch, um mehr über die Einrichtung der Betriebsumgebung und die Kompatibilität der Bibliotheken zu erfahren. Viele der Open-Source-Bibliotheken, von denen die Übungen abhängen, werden aktiv gepflegt, aber das ist nicht immer der Fall. Bitte überprüfe jede Bibliothek auf die aktuellste getestete Version, ihre Lizenz und Nutzung sowie die Kompatibilitätseinschränkungen mit der Betriebsumgebung.

Hinweis

Die meisten meiner eigenen Entwicklungen finden unter Windows 10 statt, wobei ein Großteil der Anwendungen und Tests mit WSL und einem Ubuntu 20.04LTS-Kernel ausgeführt wird. Wenn du eine Nicht-Linux-Betriebsumgebung verwenden musst, kannst du deine End-to-End-IoT-Lösung trotzdem aufbauen, indem du die Übungen in Kapitel 4, Kapitel 8 und Kapitel 9 überspringst und dich stattdessen auf die in Kapitel 3 beschriebenen Datensimulatoren und das MQTT4 Protokoll für die Konnektivität. Lies dir aber auf jeden Fall alle Übungen durch, denn sie geben dir weitere Hinweise darauf, wie du deine Anwendungen in Zukunft weiterentwickeln kannst.

Mit den folgenden Schritten kannst du sicherstellen, dass auf deinem Arbeitsplatzrechner die richtigen Komponenten installiert sind, um diese Sprachen und ihre Abhängigkeiten zu unterstützen:

  1. Vergewissere dich, dass Python 3.7 oder höher auf deinem Rechner installiert ist (die aktuellste Version ist 3.10, obwohl ich für die Entwicklung und die Tests in der WSL hauptsächlich Python 3.8.5 verwendet habe). Um zu überprüfen, ob es bereits installiert ist, gehe wie folgt vor:

    1. Öffne ein Terminal- oder Konsolenfenster und gib Folgendes ein (achte darauf, dass zwei Bindestriche vor dem Parameter stehen)

      1. Linux/macOS:

        $ python3 –-version
      2. Fenster:

        C:\programmingtheiot> python –-version
    2. Er sollte eine ähnliche Ausgabe wie die folgende liefern:

      Python 3.8.5
    3. Wenn die zurückgegebene Version kleiner als 3.7 ist oder wenn du eine Fehlermeldung erhältst (z.B. "nicht gefunden"), musst du Python 3.7 oder höher installieren. Befolge die Anweisungen für dein Betriebssystem (Windows, macOS, Linux) unter https://www.python.org/downloads.

      Hinweis

      In manchen Fällen musst du den Quellcode für Python herunterladen und dann die ausführbaren Dateien erstellen und installieren. Schau dir die Anleitung auf https://devguide.python.org/setup/ an, wenn du diesen Weg gehen musst. Als Vorwarnung: Dieser Prozess kann eine Weile dauern.

  2. Stelle sicher, dass pip auf deinem Arbeitsplatzrechner installiert ist. Wenn nicht, kannst du pip installieren, indem du das Bootstrapping- und Installationsskript herunterlädst. Wenn du WSL oder Ubuntu verwendest, musst du pip möglicherweise mit dem apt-Paketmanager installieren.

    1. Öffne ein Terminal- oder Konsolenfenster und gib Folgendes ein (wieder mit zwei Bindestrichen vor dem Parameter):

      $ pip –-version
    2. Er sollte eine ähnliche Ausgabe wie die folgende liefern:

      pip 21.0.1
    3. Wenn pip nicht installiert ist oder deine Version veraltet ist, verwende Python, um das pip-Installationsskript auszuführen. Gib den folgenden Befehl ein:

      1. Linux/macOS:

        $ python3 get-pip.py
      2. Fenster:

        C:\programmingtheiot> python get-pip.py
  3. Vergewissere dich, dass Java 11 oder höher auf deinem Arbeitsplatzrechner installiert ist (die neueste Version von OpenJDK ist JDK 18). Du kannst mit den folgenden Schritten überprüfen, ob es bereits installiert ist, oder es installieren, falls nicht:

    1. Öffne ein Terminal- oder Konsolenfenster und gib Folgendes ein (es stehen zwei Bindestriche vor dem Parameter, obwohl es wahrscheinlich auch mit nur einem funktioniert):

      $ java –-version
    2. Es sollte etwas wie das Folgende zurückgeben (stelle sicher, dass du mindestens Java 11 hast):

      openjdk 14.0.2 2020-07-14
      OpenJDK Runtime Environment (build 14.0.2+12-Ubuntu-120.04)
      OpenJDK 64-Bit Server VM (build 14.0.2+12-Ubuntu-120.04, mixed mode,
      sharing)
    3. Wenn du eine Fehlermeldung erhältst (z.B. "nicht gefunden"), musst du Java 11 oder höher installieren. Befolge die Anweisungen für deine Plattform (Windows, macOS oder Linux) auf der OpenJDK-Website.

  4. Vergewissere dich, dass Git auf deinem Arbeitsplatzrechner installiert ist. Wenn nicht, kannst du Git ganz einfach installieren. Gehe zu "Git installieren" und sieh dir die Anweisungen für dein spezielles Betriebssystem an.

    Eine Voraussetzung für die Übungen in diesem Buch und für die Einrichtung deiner Entwicklungsumgebung ist ein grundlegendes Verständnis von Git, einem Tool zur Quellcodeverwaltung und Versionierung. Bei vielen IDEs ist die Quellcodeverwaltung bereits über einen integrierten Git-Client aktiviert. In einem früheren Schritt hast du Git über die Kommandozeile installiert, damit du Git-Befehle unabhängig von deiner IDE ausführen kannst. Weitere Informationen zur Verwendung von Git über die Kommandozeile findest du in der Git-Tutorial-Dokumentation.

    Tipp

    Du kannst Git als eigenständiges Quellcode-Verwaltungstool auf deinem lokalen Entwicklungsarbeitsplatz verwenden und deinen Quellcode in der Cloud mit einer Vielzahl kostenloser und kommerzieller Dienste verwalten. GitHub5 ist der Dienst, den ich verwende, um die Code-Repositories und die neuesten Übungsanleitungen (in die auch viele der Lösungen eingebettet sind) bereitzustellen. Achte darauf, dass du die Kanban-Tafel im Buch verfolgst, während du jede Übung in diesem Buch durchgehst, denn dort findest du die neuesten Informationen.

  5. Erstelle ein Arbeitsverzeichnis für die Entwicklung und lade den Quellcode und die Einheitstests für dieses Buch herunter:

    1. Öffne ein Terminal- oder Konsolenfenster, erstelle ein neues Arbeitsverzeichnis für die Entwicklung und wechsle dann in dieses Verzeichnis. Gib dann Folgendes ein:

      1. Linux/macOS:

        mkdir $HOME/programmingtheiot
        cd $HOME/programmingtheiot
      2. Fenster:

        mkdir C:\programmingtheiot
        cd C:\programmingtheiot
    2. Klone die folgenden zwei Quellcode-Repositories für dieses Buch, indem du Folgendes eingibst (du kannst die Repositories auch einfach aus der IDE heraus klonen):

      $ git clone https://github.com/programmingtheiot/python-components.git
      $ git clone https://github.com/programmingtheiot/java-components.git
  6. Richte deine Python-Umgebung ein. Am einfachsten, aber nicht zwingend erforderlich, ist es, eine virtuelle Umgebung zu verwenden, um deine Python-Abhängigkeiten und -Bibliotheken zu isolieren.

    Es gibt eine Handvoll Möglichkeiten, eine virtuelle Ausführungsumgebung für Python auf deinem System einzurichten, und ich möchte in diesem Schritt nicht auf alle eingehen. Ab Python 3.3 gibt es ein Modul für virtuelle Umgebungen, so dass du virtualenv nicht installieren musst, es sei denn, das ist deine bevorzugte Methode zur Virtualisierung von Python. Du kannst mehr über die Verwendung des venv-Moduls unter https://docs.python.org/3/library/venv.html lesen .

    1. Erstelle eine virtuelle Python-Umgebung. Öffne ein Terminal- oder Konsolenfenster, ändere dein Verzeichnis in den gewünschten Installationspfad für die virtuelle Umgebung (z.B. $HOME/programmingtheiot/piotvenv, du kannst aber auch ein beliebiges Verzeichnis wählen) und erstelle eine virtuelle Umgebung (venv) wie folgt:

      1. Linux/macOS:

        $ python3 -m venv $HOME/programmingtheiot/piotvenv
      2. Fenster:

        C:\programmingtheiot> python -m venv C:\programmingtheiot\piotvenv
    2. Installiere die erforderlichen Python-Module. Du kannst dies tun, indem du Folgendes eingibst:

      1. Linux/macOS:

        $ cd $HOME/programmingtheiot
        $ . piotvenv/bin/activate
        (piotvenv) $ pip install -r ./python-components/requirements.txt
      2. Fenster:

        cd C:\programmingtheiot
        C:\programmingtheiot> piotvenv\Scripts\activate.bat
        (piotvenv) C:\programmingtheiot>
        pip install -r .\python-components\requirements.txt
    3. Stelle sicher, dass deine Virtualenv aktiviert werden kann. Du kannst activate (mit dem activate-Skript) und dann deactivate virtualenv (mit dem deactivate-Befehl) ganz einfach über die Kommandozeile aktivieren:

      1. Linux/macOS:

        $ . piotvenv/bin/activate
        (piotvenv) $ deactivate
      2. Fenster:

        C:\programmingtheiot> piotvenv\Scripts\activate.bat
        (piotvenv) C:\programmingtheiot> deactivate

Zu diesem Zeitpunkt ist dein Entwicklungsarbeitsplatz weitgehend konfiguriert. Der nächste Schritt besteht darin, deine Entwicklungsumgebung zu konfigurieren und den Beispielquellcode für das Buch zu klonen.

Konfigurieren einer integrierten Entwicklungsumgebung (IDE)

Es gibt viele hervorragende Tools und IDEs, die dir als Entwickler helfen, in Java und Python geschriebene Anwendungen zu schreiben, zu testen und einzusetzen. Es gibt Tools, mit denen ich sehr vertraut bin und die für meine Entwicklungsanforderungen gut funktionieren. Ich gehe davon aus, dass es dir ähnlich geht und du deine eigenen Vorlieben für Tools hast. Es ist eigentlich egal, welches Toolset du verwendest, solange die Tools einige grundlegende Anforderungen erfüllen. Dazu gehören für mich Codehervorhebung und -vervollständigung, Codeformatierung und Refactoring, Debugging, Kompilierung und Paketierung, Unit- und andere Tests sowie Quellcodekontrolle.

Ich habe die Beispiele in diesem Buch mit der Eclipse IDE mit installiertem PyDev entwickelt, da sie die von mir angegebenen Anforderungen erfüllt und eine Reihe anderer praktischer Funktionen bietet, die ich regelmäßig in meinen Entwicklungsprojekten verwende. Vielleicht kennst du auch andere IDEs wie Visual Studio Code und IntelliJ IDEA, die beide ebenfalls Java und Python unterstützen. Die Wahl der IDE für die Übungen in diesem Buch ist natürlich ganz dir überlassen.

Wenn du bereits mit dem Schreiben, Testen und Verwalten von Softwareanwendungen mit einer anderen IDE vertraut bist, wird das meiste in diesem Abschnitt ein alter Hut sein. Ich empfehle dir jedoch, ihn durchzulesen, da dieser Abschnitt den Grundstein für die Entwicklung deines GDA und CDA legt.

Richte dein Gateway Device Application Projekt ein

Der erste Schritt in diesem Prozess besteht darin, die neueste Eclipse IDE für die Java-Entwicklung zu installieren. Die neuesten Download-Links für Eclipse findest du unter https://www.eclipse.org/downloads. Du wirst feststellen, dass es viele verschiedene IDE-Varianten gibt. Für unsere Zwecke kannst du einfach "Eclipse IDE for Java Developers" wählen. Folge dann den Anweisungen, um die IDE auf deinem lokalen System zu installieren.

Nach der Installation startest du Eclipse, wählst Datei → Importieren, suchst Git → "Projekte aus Git" und klickst auf Weiter.

Wähle "Vorhandenes lokales Repository" und klicke auf Weiter. Wenn du bereits einige Git-Repositories in deinem Home-Pfad hast, wird Eclipse sie wahrscheinlich erkennen und sie im nächsten Dialog als Optionen zum Importieren anbieten (nicht abgebildet). Um das neu geklonte Repository zu importieren, klickst du auf Hinzufügen, was dich zum nächsten Dialog führt (siehe Abbildung 1-5). Von hier aus kannst du dein neues Git-Repository hinzufügen.

Auf meinem Arbeitsplatzrechner befindet sich das Repository, das ich importieren möchte, unter E:\aking\programmingtheiot\java-components. Bei dir wird der Name wahrscheinlich anders lauten, also achte darauf, dass du ihn richtig eingibst! Für Windows-Beispiele bleibe ich meist bei dem Pfad C:\programmingtheiot.

Import java-components from your local Git repository
Abbildung 1-5. Importiere java-components aus deinem lokalen Git-Repository

Klicke auf Fertig stellen und dein neues Projektarchiv wird der Liste der Projektarchive hinzugefügt, die du importieren kannst. Markiere dieses neue Repository und klicke auf Weiter. Eclipse zeigt dir dann einen weiteren Dialog an und fordert dich auf, das Projekt mit einer von mehreren Optionen zu importieren, wie in Abbildung 1-6 dargestellt.

Import java-components as an existing Eclipse project
Abbildung 1-6. java-components als bestehendes Eclipse-Projekt importieren

Du hast nun die Wahl: Du kannst java-components als bestehendes Eclipse-Projekt mit dem Assistenten für neue Projekte oder als allgemeines Projekt importieren. Wenn du deine Projektumgebung nicht vollständig anpassen willst, empfehle ich dir die erste Option - ein bestehendes Eclipse-Projekt zu importieren. Bei diesem Vorgang wird im Arbeitsverzeichnis (das ich in jedes der bereits geklonten Repositories eingefügt habe) nach einer .project Datei gesucht, aus der ein neues Java-Projekt namens java-components entsteht. Wenn du lieber dein eigenes Projekt erstellen möchtest, kannst du diese Datei entfernen und mit dem entsprechenden Assistenten als neues Projekt importieren.

Klicke auf Fertigstellen und dein neues Projekt wird der Liste der Projekte im Eclipse Package Explorer hinzugefügt, der sich standardmäßig auf der linken Seite deines IDE-Bildschirms befindet. Wenn du dein Projekt nicht sofort im Package Explorer siehst, ändere einfach die Perspektive der IDE auf "Java" (oder "Python" für den CDA).

Dein GDA-Projekt ist jetzt in Eclipse eingerichtet, also lass uns die Dateien darin erkunden. Navigiere zu diesem Projekt in Eclipse und klicke auf das Caret-Symbol (>), um es zu erweitern, wie in Abbildung 1-7 gezeigt.

GDA project now set up and ready for use
Abbildung 1-7. Das GDA-Projekt ist nun eingerichtet und einsatzbereit
Hinweis

Was, wenn dir der Projektname nicht gefällt? Kein Problem - du kannst mit der rechten Maustaste auf den Namen java-components klicken, Umbenennen wählen, den neuen Namen eingeben und auf OK klicken. Du sollst nur wissen, dass ich das Projekt im gesamten Buch weiterhin mit dem ursprünglichen Namen bezeichnen werde :).

Du wirst feststellen, dass bereits einige Dateien im Projekt enthalten sind - eine ist GatewayDeviceApp im Paket programmingtheiot.gda.app und die andere, auf oberster Ebene, heißt pom.xml. Die Datei GatewayDeviceApp ist ein Platzhalter für den Anfang, du kannst sie aber auch durch deine eigene Datei ersetzen. Ich empfehle dir jedoch, die Namenskonvention beizubehalten, da die pom.xml davon abhängt, um den Code zu kompilieren, zu testen und zu verpacken. Wenn du dich bereits mit Maven auskennst, kannst du alle Änderungen vornehmen, die du möchtest.

Wenn du deinen GDA von der Kommandozeile aus erstellen willst, musst du Maven installieren, falls es nicht bereits in deiner Umgebung installiert ist.

Tipp

Für diejenigen unter euch, die mit Maven weniger vertraut sind: Die pom.xml ist die wichtigste Konfigurationsdatei von Maven und enthält Anweisungen zum Laden von Abhängigkeiten, ihre jeweiligen Versionen, Namenskonventionen für deine Anwendung, Build-Anweisungen und natürlich Anweisungen zum Verpacken. Die meisten dieser Abhängigkeiten sind bereits enthalten, du kannst aber auch deine eigenen hinzufügen, wenn du andere für nützlich hältst. Du wirst außerdem feststellen, dass Maven seine eigene Standardverzeichnisstruktur hat, die ich für das Java-Repository beibehalten habe. Um mehr über diese und andere Funktionen von Maven zu erfahren, empfehle ich dir, das fünfminütige Maven-Tutorial durchzuarbeiten.

Um sicherzugehen, dass deine GDA-Entwicklungsumgebung richtig eingerichtet ist, kannst du den GDA in der IDE erstellen und ausführen (wir haben das in Eclipse getestet). Gehe einfach wie folgt vor:

  1. Stelle sicher, dass dein Arbeitsplatz mit dem Internet verbunden ist.

  2. Führe deine GDA-Anwendung in Eclipse aus.

    1. Klicke erneut mit der rechten Maustaste auf das Projekt java-components und scrolle nach unten zu "Ausführen als" und klicke dieses Mal auf "Java-Anwendung".

    2. Überprüfe die Ausgabe in der Konsole am unteren Rand des Eclipse IDE-Bildschirms. Die Ausgabe sieht ähnlich aus wie die folgende:

      Jul 04, 2020 3:10:49 PM programmingtheiot.gda.app.GatewayDeviceApp
      initConfig INFO: Attempting to load configuration.
      Jul 04, 2020 3:10:49 PM programmingtheiot.gda.app.GatewayDeviceApp
      startApp INFO: Starting GDA...
      Jul 04, 2020 3:10:49 PM programmingtheiot.gda.app.GatewayDeviceApp
      startApp INFO: GDA ran successfully.

Wenn du dich dafür entscheidest, den GDA zu bauen und ihn von der Kommandozeile aus zu starten, musst du Maven sagen, dass es die Tests überspringen soll, da sie fehlschlagen werden (da es noch keine Implementierung zum Testen gibt). In einer Linux-Shell kannst du den folgenden Befehl aus dem obersten Quellverzeichnis deines GDAs verwenden:

$ mvn install -DskipTests

Jetzt bist du bereit, deinen eigenen Code für den GDA zu schreiben. Jetzt müssen wir deinen Entwicklungsarbeitsplatz für den CDA einrichten.

Richte dein Projekt für die eingeschränkte Geräteanwendung ein

Dieser Prozess ähnelt dem GDA-Einrichtungsprozess, erfordert aber das Hinzufügen von PyDev zu Eclipse. Hier ist eine Zusammenfassung der Aktivitäten, damit du loslegen kannst.

Wenn sie nicht bereits läuft, starte die Eclipse IDE. Öffne in einem separaten Fenster oder Bildschirm deinen Webbrowser und navigiere zur PyDev Python IDE for Eclipse Download-Seite; ziehe das PyDev "Install"-Symbol von der Webseite und lege es in der Nähe des oberen Randes der Eclipse IDE ab (du wirst ein grünes "Plus"-Symbol sehen, das anzeigt, dass du es in die IDE ablegen kannst). Eclipse wird dann automatisch PyDev und seine Abhängigkeiten für dich installieren.

Sobald PyDev installiert ist, kannst du den Python-Interpreter so einstellen, dass er die venv- (oder virtualenv-) Umgebung verwendet, wenn du sie im vorherigen Abschnitt erstellt hast. Wähle Voreinstellungen → PyDev → Interpreter → "Python-Interpreter". Eclipse zeigt einen Dialog an, der dem in Abbildung 1-8 gezeigten ähnelt.

Add a new Python interpreter
Abbildung 1-8. Einen neuen Python-Interpreter hinzufügen

Füge dann einen neuen Interpreter hinzu, indem du "Nach python/pypy.exe suchen" auswählst und die entsprechenden Informationen im nächsten Pop-up-Fenster eingibst. Wenn du fertig bist, wählst du den Interpreter venv (oder virtualenv) aus und klickst auf Nach oben, bis er ganz oben in der Liste steht. Jetzt ist venv (oder virtualenv) dein Standard-Python-Interpreter, wie in Abbildung 1-9 dargestellt.

Klicke auf "Anwenden und schließen".

Virtualenv Python interpreter now set as default
Abbildung 1-9. Virtualenv Python-Interpreter jetzt als Standard eingestellt

Sobald diese Schritte abgeschlossen sind, wähle Datei → Importieren und importiere das python-components Git-Repository, das du bereits von GitHub geklont hast. Auch dieser Schritt ist fast identisch mit den vorherigen Schritten in den Abbildungen 1-5, 1-6 und 1-7, nur dass du das python-components Git-Repository importierst, das du von GitHub geklont hast.

Auf meinem Arbeitsplatzrechner befindet sich das Repository, das ich importieren möchte, unter:

C:\programmingtheiot\python-components

Wie beim GDA wird der Name deines Repositorys wahrscheinlich anders lauten, also achte darauf, dass du den richtigen Pfad verwendest. Ich habe auch die Eclipse .project Datei in dieses Repository aufgenommen, damit du sie als Eclipse-Projekt importieren kannst. Dieses Projekt ist standardmäßig auf Python eingestellt und verwendet daher PyDev als Projektvorlage. Auch hier kannst du importieren, wie du willst, aber ich empfehle dir, es so zu importieren, wie du es mit dem GDA gemacht hast.

Sobald du den Importvorgang abgeschlossen hast, siehst du in deinem Package Explorer ein neues Projekt namens python-components. Du hast jetzt die CDA-Komponenten in deiner Eclipse IDE eingerichtet.

Um die Dateien darin zu sehen, navigiere zu python-components und klicke auf das Caret (>), um es weiter zu erweitern, wie in Abbildung 1-10 gezeigt.

CDA project now set up and ready for use
Abbildung 1-10. Das CDA-Projekt ist jetzt eingerichtet und einsatzbereit

Du wirst feststellen, dass bereits viele Python-Dateien im Projekt enthalten sind. Eine davon ist ConstrainedDeviceApp.py im Paket programmingtheiot.cda.app, das der Anwendungs-Wrapper für den CDA ist. Es gibt auch __init__.py Dateien in jedem Paket; das sind leere Dateien, die der Python-Interpreter benutzt, um zu bestimmen, in welchen Verzeichnissen er nach Python-Dateien suchen soll (du kannst sie vorerst ignorieren). Ähnlich wie beim GDA-Beispiel (das in Java geschrieben wurde) ist die ConstrainedDeviceApp nur ein Platzhalter, um dir den Einstieg zu erleichtern.

Es gibt auch zwei .txt-Dateien: requirements.txt und basic_imports.txt. Diese sollten identisch sein - ich habe die zweite erstellt, um sie von anderen Anforderungsdateien zu unterscheiden, die für diese Version des Buches nicht verwendet werden. Die Datei requirements.txt wird verwendet, um Bibliotheksabhängigkeiten zu installieren, die zur Unterstützung der kommenden CDA-Programmierübungen benötigt werden.

Warnung

Wenn du viel mit Python gearbeitet hast, bist du wahrscheinlich mit der Umgebungsvariablen PYTHONPATH vertraut. Da ich versucht habe, das GDA- und das CDA-Paketierungsschema ähnlich zu halten, musst du PyDev (und deiner Virtualenv-Umgebung) möglicherweise mitteilen, wie sie in dieser Verzeichnisstruktur navigieren sollen, um deine Anwendung auszuführen. Vergewissere dich, dass die Pfade src/main/python und src/test/python beide in PYTHONPATH gesetzt sind, indem du Folgendes tust: Klicke mit der rechten Maustaste auf "python-components", wähle "PyDev - PYTHONPATH" und klicke dann auf "Add source folder" (Quellordner hinzufügen), wie in Abbildung 1-11 gezeigt. Wähle den Ordner " python" unter "main" aus und klicke auf "Übernehmen". Mache dasselbe für den Python-Ordner unter test. Klicke zum Abschluss auf "Übernehmen und schließen".

Updating the PYTHONPATH environment variable within PyDev and Eclipse
Abbildung 1-11. Aktualisieren der Umgebungsvariablen PYTHONPATH in PyDev und Eclipse

Führe deine CDA-Anwendung in Eclipse aus.

  1. Klicke erneut mit der rechten Maustaste auf auf das Projekt "python-components", scrolle nach unten zu "Ausführen als" und klicke dieses Mal auf "Python Run".

  2. Überprüfe die Ausgabe in der Konsole am unteren Rand des Eclipse IDE-Bildschirms. Wie bei deinem GDA-Testlauf sollten keine Fehler auftreten, und die Ausgabe sollte in etwa so aussehen wie die folgende:

    2020-07-06 17:15:39,654:INFO:Attempting to load configuration...
    2020-07-06 17:15:39,655:INFO:Starting CDA...
    2020-07-06 17:15:39,655:INFO:CDA ran successfully.

Anwendungskonfiguration

Nachdem du den CDA und den GDA ausgeführt hast, hast du wahrscheinlich die Protokollmeldungen zur Konfiguration bemerkt und erinnerst dich natürlich an die Diskussion über das Konfigurationsmanagement weiter oben in diesem Kapitel. Da du für jede Anwendung eine Reihe von verschiedenen Konfigurationsparametern brauchst, habe ich in jedem Code-Repository eine einfache Hilfsklasse mit dem Namen ConfigUtil bereitgestellt.

In Python delegiert ConfigUtil an sein eingebautes configparser Modul und in Java delegiert ConfigUtil an die Commons-Konfigurationsbibliothek von Apache. In beiden Fällen kannst du die Standardkonfigurationsdatei (./config/PiotConfig.props) oder eine angepasste Version laden.

Der einfachste Weg, um sicherzustellen, dass die Standardkonfigurationsdatei jedes Repositorys vom CDA und GDA korrekt geladen wird, ist die Aktualisierung der Eigenschaft DEFAULT_CONFIG_FILE_NAME config/PiotConfig.props' , um den voll qualifizierten (absoluten) Dateinamen für PiotConfig.props in der Klasse ConfigConst jedes Repositorys zu referenzieren (zu finden im Verzeichnis ./programmingtheiot/common in jedem Repository).

Hier ist ein Windows-spezifisches Beispiel für die aktualisierte DEFAULT_CONFIG_FILE_NAME-Eigenschaft des CDA nach der Änderung (du musst natürlich die Zuordnung zu deiner eigenen Datei ändern und eine andere Pfadbenennungskonvention verwenden, wenn du WSL oder Linux verwendest):

DEFAULT_CONFIG_FILE_NAME = "C:\programmingtheiot\python-components\config\
  PiotConfig.props"

Für die Übungen in diesem Buch sind viele der "Konstanten", die du brauchst, bereits in der ConfigConst Klasse des jeweiligen Repositorys definiert, obwohl du deine eigenen hinzufügen kannst (und wahrscheinlich auch musst).

Das Format der Konfigurationsdatei ist für die CDA und die GDA identisch. Hier ist ein kurzes Beispiel aus der PiotConfig.props des CDA:

[ConstrainedDevice]
deviceLocationID = constraineddevice001
enableEmulator   = False
enableSenseHAT   = False
enableMqttClient = True
enableCoapClient = False
enableLogging    = True
pollCycleSecs    = 60
testGdaDataPath  = /tmp/gda-data
testCdaDataPath  = /tmp/cda-data

Und hier ist ein Ausschnitt aus der PiotConfig.props der GDA:

[GatewayDevice]
deviceLocationID        = gatewaydevice001
enableLogging           = True
pollCycleSecs           = 60
enableMqttClient        = True
enableCoapServer        = False
enableCloudClient       = False
enableSmtpClient        = False
enablePersistenceClient = False
testGdaDataPath         = /tmp/gda-data
testCdaDataPath         = /tmp/cda-data

Beachte, dass die Abschnitte durch ein Schlüsselwort in Klammern gekennzeichnet sind und die Eigenschaften im Format Schlüssel = Wert vorliegen. Das macht es einfach, neue Abschnitte und Schlüssel/Wert-Paare hinzuzufügen.

Ein Sonderfall, der in jeder Implementierung von ConfigUtil behandelt wird, ist die Möglichkeit, eine separate Konfigurationsdatei zu definieren und zu laden, die Anmeldeinformationen oder andere sensible Daten enthält, die nicht Teil der Konfiguration deines Repositorys sein sollten. In jedem Abschnitt kannst du einen Wert für credFile angeben, einen Schlüssel, der auf eine lokale Datei verweist, die sich außerhalb deines Projektarchivs befinden kann und sollte.

Warnung

Wenn du dir die PiotConfig.props für die CDA und GDA ansiehst, wirst du feststellen, dass sie für einige Abschnitte einen credFile Eintrag enthält. Der Grund dafür ist, dass Kennwortreferenzen, Benutzerauthentifizierungs-Tokens, API-Schlüssel und so weiter aus der Hauptkonfigurationsdatei herausgenommen werden, damit sie separat referenziert werden können. Es ist sehr wichtig, solche Geheimnisse aus deinen Repos herauszuhalten - du solltest NIEMALS Benutzernamen, Passwörter, private Schlüssel oder andere sensible Daten an dein Git-Repository übergeben. Wenn du eine Möglichkeit brauchst, diese Art von Informationen zu speichern, solltest du dir den Artikel "Verschlüsselte Geheimnisse" genau durchlesen, um mehr über diesen Prozess in GitHub zu erfahren. Die sichere Speicherung von Anmeldeinformationen ist ein wichtiges Thema, das aber nicht in den Rahmen dieses Buches passt.

Der Konfigurationsansatz, den ich hier beschrieben habe, ist eher einfach und nur für Test- und Prototyping-Zwecke gedacht. Wenn du schon eine Weile programmierst, hast du vielleicht schon eine Strategie und Lösung für die Anwendungskonfiguration entwickelt. Du kannst die Konfigurationsfunktionen, die ich hier vorgestellt habe, gerne an deine Bedürfnisse anpassen.

Zu diesem Zeitpunkt sollten sowohl dein GDA als auch dein CDA in deiner IDE eingerichtet sein und funktionieren und du solltest mit der Funktionsweise der Konfigurationslogik vertraut sein. Jetzt kannst du anfangen, deinen eigenen Code für beide Anwendungen zu schreiben!

Bevor wir uns in die Übungen in Kapitel 2 stürzen, sollten wir jedoch noch zwei weitere Themen besprechen: Testen und Automatisierung.

Schritt II: Definiere deine Teststrategie

Jetzt, da deine Entwicklungsumgebung für deinen GDA und CDA eingerichtet ist, können wir besprechen, wie du den Code, den du entwickeln wirst, testen wirst. Es ist klar, dass gute Tests ein wichtiger Bestandteil jeder technischen Arbeit sind, und das gilt auch für die Programmierung. Jede Anwendung, die du entwickelst, sollte gründlich getestet werden, egal ob sie völlig unabhängig von anderen Anwendungen funktioniert oder eng mit anderen Systemen verbunden ist. Außerdem sollte jede Codeeinheit, die du schreibst, getestet werden, um sicherzustellen, dass sie sich wie erwartet verhält. Was genau ist eine Unit? Für unsere Zwecke wird eine Unit immer als eine Funktion oder Methode dargestellt, die du testen möchtest.

Tipp

Was ist der Unterschied zwischen einer Funktion und einer Methode? Grob vereinfacht ist eine Funktion eine benannte Gruppierung von Code, die eine Aufgabe ausführt (z. B. zwei Zahlen addiert) und ein Ergebnis zurückgibt. Wenn die Funktion eine Eingabe akzeptiert, wird sie als ein oder mehrere Parameter übergeben. Eine Methode ist fast identisch mit einer Funktion, ist aber mit einem Objekt verbunden. Im objektorientierten Sprachgebrauch ist ein Objekt einfach eine Klasse, die instanziiert wurde, und eine Klasse ist die formale Definition einer Komponente - ihre Methoden, Parameter, Aufbau- und Abbaulogik. Alle Java-Beispiele in diesem Buch werden in Klassenform dargestellt, wobei die Methoden als Teil jeder Klasse definiert sind. Python kann in Skriptform mit Funktionen oder als Klassen mit Methoden geschrieben werden, aber ich ziehe es vor, Python-Klassen mit Methoden zu schreiben und werde das auch für jedes Python-Beispiel in diesem Buch tun, mit nur wenigen Ausnahmen.

Unit-, Integrations- und Leistungstests

Es gibt viele Möglichkeiten, Softwareanwendungen und Systeme zu testen, und es gibt einige hervorragende Bücher, Artikel und Blogs zu diesem Thema. Die Entwicklung einer funktionierenden IoT-Lösung erfordert eine sorgfältige Prüfung - innerhalb einer Anwendung und zwischen verschiedenen Anwendungen und Systemen. Für die Lösung, die du entwickeln wirst, konzentriere ich mich auf drei Tests: Einheitstests, Integrationstests und Leistungstests.

Unit-Tests sind Code Module, die geschrieben werden, um die kleinstmögliche Codeeinheit zu testen, die für den Test zugänglich ist, z. B. eine Funktion oder Methode. Diese Tests werden geschrieben, um zu überprüfen, ob eine Reihe von Eingaben für eine bestimmte Funktion oder Methode das erwartete Ergebnis liefert. Häufig werden auch Randbedingungen getestet, um sicherzustellen, dass die Funktion oder Methode mit diesen Bedingungen angemessen umgehen kann.

Tipp

Eine Codeeinheit kann technisch gesehen eine einzelne Codezeile, mehrere Codezeilen oder sogar eine ganze Codebibliothek sein. Für unsere Zwecke bezieht sich eine Unit auf eine oder mehrere Codezeilen oder eine ganze Codebibliothek, auf die über eine einzige Schnittstelle zugegriffen werden kann, die auf dem lokalen System verfügbar ist, d. h. eine Funktion oder eine Methode, die die Funktionalität der Unit kapselt und von deiner Testanwendung aus aufgerufen werden kann. Bei dieser Funktionalität kann es sich zum Beispiel um einen Sortieralgorithmus, eine Berechnung oder sogar um einen Einstiegspunkt für eine oder mehrere zusätzliche Funktionen oder Methoden handeln.

Ich verwende JUnit für Unit-Tests von Java-Code (in Eclipse enthalten) und das Python-Framework Unittest6 für Unit-Tests von Python-Code (Teil des Standard-Python-Interpreters und verfügbar in PyDev). Wenn du Eclipse und PyDev verwendest, musst du unter keine zusätzlichen Komponenten installieren, um Unit-Tests in deiner IDE zu schreiben und auszuführen.

Hinweis

In deinem GDA-Projekt hast du wahrscheinlich zwei Verzeichnisstrukturen für deinen Quellcode entdeckt: eine für den Java-Quellcode unter ./src/main/java und eine für den Java-Unit-Testcode unter ./src/test/java. Das ist die Standardkonvention für Maven-Projekte, und deshalb habe ich mich entschieden, die gleiche Verzeichniskonvention auch für den CDA zu verwenden (wobei ich natürlich "java" mit "python" vertauscht habe).

Du hast vielleicht bemerkt, dass die CDA- und GDA-Projekte ein ./src/test/python-Verzeichnis bzw. ein ./src/test/java-Verzeichnis enthalten. Ich stelle dir die meisten Unit-Tests und viele Integrationstests zur Verfügung, mit denen du überprüfen kannst, ob deine Implementierung funktioniert, aufgeschlüsselt nach den einzelnen Kapiteln. Diese Tests eignen sich für die Hauptübungen, obwohl sie nicht alle möglichen Kanten abdecken sollen. Für eine zusätzliche Testabdeckung und für alle optionalen Übungen musst du deine eigenen Unit- und/oder Integrationstests erstellen.

Hier ist ein einfaches Beispiel für einen Unit-Test in Java mit JUnit, der überprüft, ob sich die Methode addTwoIntegers() wie erwartet verhält:

@Test
public int testAddTwoIntegers(int a, int b)
{
  // TODO: be sure to implement MyClass and the addTwoIntegers() method!
  MyClass mc = new MyClass();
  
  // baseline assertions
  assertTrue(mc.addTwoIntegers(0, 0) == 0);
  assertTrue(mc.addTwoIntegers(1, 2) == 3);
  assertTrue(mc.addTwoIntegers(-1, 1) == 0);
  assertTrue(mc.addTwoIntegers(-1, -2) == -3);
  assertFalse(mc.addTwoIntegers(1, 2) == 4);
  assertFalse(mc.addTwoIntegers(-1, -2) == -4);
}

Was ist, wenn du eine einzelne Testklasse mit zwei einzelnen Unit-Tests hast, aber nur einen ausführen möchtest? Füge einfach @Ignore vor der Annotation @Test hinzu, und JUnit überspringt den betreffenden Test. Entferne die Annotation, um den Test wieder zu aktivieren.

Schauen wir uns das gleiche Beispiel in Python an, indem wir das in Python 3 integrierte Unittest-Framework verwenden:

def testAddTwoIntegers(self, a, b):
  // TODO: be sure to implement MyClass and the addTwoIntegers() method!
  MyClass mc = MyClass()
  
  # baseline assertions
  self.assertTrue(mc.addTwoIntegers(0, 0) == 0)
  self.assertTrue(mc.addTwoIntegers(1, 2) == 3)
  self.assertTrue(mc.addTwoIntegers(-1, 1) == 0)
  self.assertTrue(mc.addTwoIntegers(-1, -2) == -3)
  self.assertFalse(mc.addTwoIntegers(1, 2) == 4)
  self.assertFalse(mc.addTwoIntegers(-1, -2) == -4)

Das Unittest-Framework ermöglicht es dir, ähnlich wie JUnit, bestimmte Tests zu deaktivieren, wenn du das möchtest. Füge @unittest.skip("Put your reason here.") oder @unittest.skip als Annotation vor der Methodendeklaration hinzu, und das Framework überspringt diesen speziellen Test.

Hinweis

Die Unit-Tests in den Repositories python-components und java-components können als automatisierte Tests entweder über die Kommandozeile oder innerhalb der IDE ausgeführt werden. Das heißt, du kannst sie so skripten, dass sie automatisch als Teil deines Builds ausgeführt werden und je nach Implementierung der zu testenden Einheit entweder bestehen oder fehlschlagen.

Integrationstests sind für das IoT sehr wichtig, da mit ihnen überprüft werden kann, ob die Verbindungen und Interaktionen zwischen Systemen und Anwendungen wie erwartet funktionieren. Angenommen, du willst einen Sortieralgorithmus mit einem in die Testklasse eingebetteten Basisdatensatz testen - dann schreibst du in der Regel einen oder mehrere Unit-Tests, führst jeden einzelnen aus und überprüfst, ob alles in Ordnung ist.

Was aber, wenn der Sortieralgorithmus Daten aus einem Datenspeicher beziehen muss, auf den du über dein lokales Netzwerk oder sogar das Internet zugreifen kannst? Was dann, fragst du dich vielleicht? Nun, jetzt hast du eine weitere Abhängigkeit, nur um deinen Sortiertest durchzuführen. Du brauchst einen Integrationstest, um zu überprüfen, ob die Verbindung zur Datenablage verfügbar ist und ordnungsgemäß funktioniert, bevor du den Sortier-Unit-Test durchführst.

Diese Art von Abhängigkeiten kann Integrationstests in jeder Umgebung zu einer Herausforderung machen, vor allem aber im IoT, da es manchmal notwendig ist, Server einzurichten, auf denen spezielle Protokolle laufen, um unsere Sachen zu testen. Aus diesem Grund und um deine Testumgebung so unkompliziert wie möglich zu halten, werden alle Integrationstests manuell durchgeführt und überprüft.

Hinweis

Manuelle Ausführung und Überprüfung bedeutet, dass die Integrationstests in den Repositories python-components und java-components so konzipiert sind, dass sie von dir über die Kommandozeile ausgeführt werden und du sie beobachten musst, um Erfolg oder Misserfolg festzustellen. Während einige Tests technisch gesehen von deiner IDE aus ausgeführt werden können und sogar in eine automatisierte Testausführungsumgebung integriert werden können, müssen andere vor der Ausführung eingerichtet werden (beschrieben in den Testkommentaren selbst oder in der Anforderungskarte für das zu testende Modul). Ich würde vorschlagen, dass du sie nur über die Kommandozeile ausführst.

Leistungstests schließlich sind nützlich, um zu testen, wie schnell oder effizient ein System eine Vielzahl von Bedingungen bewältigt. Sie können sowohl bei Unit- als auch bei Integrationstests eingesetzt werden, wenn z. B. die Reaktionszeit oder die Anzahl der unterstützten gleichzeitigen Verbindungen gemessen werden muss.

Nehmen wir an, es gibt viele verschiedene Systeme, die eine Liste von Daten aus deinem Datenbestand abrufen müssen, und jedes von ihnen möchte diese Liste von Daten sortiert haben, bevor deine Anwendung sie an sie zurückgibt. Wenn du das Systemdesign und die Optimierung des Datenbankschemas einen Moment lang ignorierst, kannst du mit einer Reihe von Leistungstests herausfinden, wie schnell die einzelnen Systeme auf die Anfrage reagieren (von der ersten Anfrage bis zur Antwort) und wie viele Systeme gleichzeitig auf deine Anwendung zugreifen können, bevor sie nicht mehr angemessen reagiert.

Ein weiterer Aspekt der Leistungstests ist die Überprüfung der Belastung des Systems, auf dem deine Anwendung läuft, was für IoT-Anwendungen sehr nützlich sein kann. IoT-Geräte sind in der Regel in gewisser Weise eingeschränkt - Arbeitsspeicher, CPU, Speicherung usw. -, während Cloud-Dienste beliebig skaliert werden können. Es liegt also auf der Hand, dass unsere ersten IoT-Anwendungen - die wir in Kapitel 2 vorstellen -die Voraussetzungen dafür schaffen, die Leistung jedes einzelnen Geräts zu überwachen.

Da Leistungstests oft Hand in Hand mit Integrations- und Unit-Tests gehen, werden wir auch hier Maven und spezialisierte Unit-Tests sowie bei Bedarf Open-Source-Tools verwenden.

Hinweis

Die Leistungstests in den Repositories python-components und java-components sind alle als manuelle Tests konzipiert und müssen beobachtet werden, um Erfolg oder Misserfolg festzustellen, ähnlich wie bei den zuvor beschriebenen Integrationstests. Auch hier ist eine Automatisierung technisch machbar, liegt aber außerhalb des Rahmens dieses Buches. Sie werden in der Übung beschrieben oder sind in der Anforderungskarte für das jeweilige Modul enthalten.

Es gibt viele Tools für Leistungstests, und du kannst auch deine eigenen schreiben. System-zu-System- und Kommunikationsprotokoll-Leistungstests sind für die Zwecke dieses Buches völlig optional, und ich werde dieses Thema in Kapitel 10 nur kurz anschneiden. Wenn du mehr über benutzerdefinierte Leistungstests erfahren möchtest, solltest du dir Tools ansehen, die speziell für diesen Zweck entwickelt wurden, wie z. B. Locust, mit dem du deine eigenen Leistungstests schreiben kannst und das eine webbasierte Benutzeroberfläche (UI) enthält.

Testtipps für die Übungen in diesem Buch

Der Beispielcode für jede Übung in diesem Buch enthält Unit-Tests, mit denen du den von dir geschriebenen Code testen kannst. Diese Unit-Tests, die in den Repositories java-components und python-components enthalten sind, die du bereits in dein GDA- bzw. CDA-Projekt eingebunden hast, sind wichtig, um sicherzustellen, dass deine Implementierung richtig funktioniert.

Für einige Übungen gibt es auch Integrationstests, die du unverändert verwenden oder an deine speziellen Bedürfnisse anpassen kannst. Ich habe auch einige Beispielleistungstests beigefügt, mit denen du testen kannst, wie gut dein Code unter Last funktioniert.

Deine Implementierung jeder Übung sollte jeden der vorgegebenen Einheitstests zu 100 % erfolgreich bestehen. Du kannst gerne weitere Unit-Tests hinzufügen, wenn du meinst, dass sie hilfreich sind, um die von dir entwickelten Funktionen zu überprüfen. Die mitgelieferten Integrationstests und Leistungstests sind ebenfalls hilfreich, um die Umsetzung der einzelnen Übungen zu überprüfen.

Erinnere dich: Prüfungen sind dein Freund - und wie ein Freund sollten sie nicht ignoriert werden. Sie zu schreiben und zu pflegen kann sicherlich zeitaufwändig sein, aber in jede gute Freundschaft muss investiert werden. Diese Tests - ob Unit-, Integrations- oder Leistungstests - helfen dir dabei, dein Design zu validieren und zu überprüfen, ob deine Funktionen richtig funktionieren.

Schritt III: Verwalte deinen Design- und Entwicklungsworkflow

Du hast also herausgefunden, wie du deinen Code schreiben und testen willst - großartig! Aber wäre es nicht toll, wenn du alle deine Anforderungen, deinen Quellcode und deine CI/CD-Pipelines verwalten könntest? In unserem letzten Schritt geht es um die Verwaltung deines gesamten Entwicklungsworkflows. Dazu gehören die Verfolgung der Anforderungen, die Verwaltung des Quellcodes und die CI/CD-Automatisierung.

Du hast es wahrscheinlich satt, dass ich immer wieder sage, dass die Entwicklung von IoT-Systemen schwierig ist. Das liegt vor allem an der Natur des Edge Tier (da wir oft mit verschiedenen Gerätetypen, Kommunikationsparadigmen, Betriebsumgebungen, Sicherheitseinschränkungen und so weiter zu tun haben). Zum Glück gibt es viele moderne CI/CD-Tools, die dabei helfen können, in diesen schwierigen Gewässern zu navigieren. Schauen wir uns einige Auswahlkriterien für diese Tools an und untersuchen dann, wie wir eine CI/CD-Pipeline aufbauen können, die für unsere Bedürfnisse geeignet ist.

Deine IoT-CI/CD-Pipeline sollte eine sichere Authentifizierung und Autorisierung, Skriptfähigkeit über eine Linux-ähnliche Kommandozeile, Integration mit Git und Container-Infrastruktur sowie die Möglichkeit, Pipelines sowohl in deiner lokalen als auch in einer Cloud-gehosteten Umgebung auszuführen, unterstützen.

Es gibt viele Online-Dienste, die diese Funktionen anbieten, einige davon sowohl kostenlos als auch kostenpflichtig. Als du den Quellcode für dieses Buch heruntergeladen hast, hast du ihn mit der Klon-Funktion von Git aus meinen GitHub-Repositories gezogen. GitHub ist ein Online-Dienst, der die Verwaltung des gesamten Entwickler-Workflows unterstützt, einschließlich Quellcodekontrolle (mit Git), CI/CD-Automatisierung und Planung.

Bei jeder Übung wird der Code lokal erstellt, getestet und bereitgestellt, aber es wird auch davon ausgegangen, dass dein Code in ein Online-Repository mit Git für die Quellcodeverwaltung übertragen wird. Du kannst natürlich auch den Online-Dienst deiner Wahl verwenden. In diesem Buch gehen alle Beispiele und Übungen davon aus, dass GitHub verwendet wird.7

Hinweis

Es gibt viele großartige Ressourcen, Tools und Online-Dienste, mit denen du deine Entwicklungsarbeit verwalten und automatisierte CI/CD-Pipelines einrichten kannst. Lies dir diesen Abschnitt durch, probiere einiges aus und wähle dann mit zunehmender Erfahrung die Tools und Dienste aus, die für dich am besten geeignet sind.

Anforderungen verwalten

Ah ja - Anforderungen. Was bauen wir, wen interessiert das, und wie wollen wir es bauen? Pläne sind gut, nicht wahr? Und da sie gut sind, sollten wir ein Tool haben, das das Gute einschließt, mit Funktionen wie Aufgabenpriorisierung, Aufgabenverfolgung, Teamzusammenarbeit und (vielleicht) Integration mit anderen Tools.

Die CDA- und GDA-Repositories enthalten Shell-Implementierungen (und einige vollständige Implementierungen) der Klassen und Schnittstellen, die du in den Programmierübungen der einzelnen Kapitel erstellen wirst. Alle Anforderungen - einschließlich einiger informativer Hinweise - findest du in einem anderen GitHub-Repository, das ich im Projekt Programming the IoT zur Verfügung gestellt habe. Das ist der beste Ort, um anzufangen, denn es bietet eine geordnete Liste von Aktivitäten in Spalten und Zeilen, wie sie für ein Kanban-Board typisch ist.

Hinweis

Von Zeit zu Zeit aktualisiere ich die Übungen auf der Kanban-Tafel und die Anleitungskarten sowie die unterstützenden Python- und Java-Quellcode-Repositories. Auf der Kanban-Tafel findest du daher die aktuellsten Informationen zu allen Übungen, die im Buch behandelt werden. Solltest du Unstimmigkeiten zwischen dem Buch und dem Online-Inhalt auf GitHub feststellen, beziehe dich auf letzteren, da er am genauesten sein sollte.

Die spezifischen Anforderungen in jeder Spalte sind als Karten erfasst und verweisen auf "Issues" aus dem book-exercise-tasks Repository, das ich erstellt habe, um das zentrale Anforderungsmanagement zu erleichtern. Du kannst jede dieser Anforderungen ganz einfach durch einen Klick auf den Namen oder durch das Öffnen einer neuen Registerkarte genauer betrachten.

Die Namenskonvention für jede Karte sollte relativ einfach zu verstehen sein: {book}-{app type}-{chapter}-{number}. Zum Beispiel: PIOT-CDA-01-001, was sich auf Programming the Internet of Things (PIOT), Constrained Device App (CDA), Kapitel 1 (01), Anforderung Nr. 1 (001) bezieht.

Die letzte Zahl ist wichtig, denn sie gibt die Reihenfolge an, die du einhalten solltest. Zum Beispiel folgt Anforderung Nr. 2 (002) auf Anforderung Nr. 1 (001) und so weiter. Der Inhalt jeder Anforderung enthält die Anweisungen zur Umsetzung, die du als Programmierer befolgen sollst, gefolgt von den Tests, die du durchführen sollst, um zu überprüfen, ob der Code richtig funktioniert.

Es gibt zwei besondere Nummern, die du beachten musst, obwohl auch sie der Reihenfolge folgen. Alle Aufgaben, die mit "000" enden, sind einrichtungsbezogene Aufgaben, wie z.B. die Erstellung deines Zweigs. Alle Aufgaben, die mit "100" enden, sind Aufgaben im Zusammenhang mit der Zusammenführung und Validierung, z. B. die Zusammenführung deines Kapitelzweigs mit deinem Hauptzweig und die Überprüfung, ob alle Funktionen wie erwartet funktionieren.

Alle diese Karten und Notizen sind in der Kanban-Tafel des Buches organisiert, mit einer einzigen Spalte für jedes Kapitel, damit du alle Dinge sehen kannst, die für die Übungen in jedem Kapitel umgesetzt werden müssen. Du hast wahrscheinlich schon von agilen8 Projektmanagementverfahren wie Scrum und Kanban gehört. Bei einer Kanban-Tafel wählst du eine Karte aus, beginnst mit der Arbeit daran und schließt sie ab, sobald sie getestet, verifiziert, überprüft und bestätigt wurde.

Auch wenn du die Karten, die ich dir zur Verfügung stelle, nicht abrufen und schließen kannst, stehen sie dir zur Verfügung, um sie zu überprüfen und zu verfolgen, während du die Übungen in den einzelnen Kapiteln durcharbeitest. Wie du deine CDA- und GDA-Anforderungen in deinen eigenen Repositories verwaltest, erkläre ich dir in Kapitel 2, wenn du anfängst, Code zu schreiben. Jetzt gebe ich dir erst einmal einen kurzen Überblick darüber, wie ich Anforderungskarten (die nur auf ein oder mehrere Repositories verweisen) im Kanban-Board von Programming the IoT eingerichtet habe.

Hinweis

Ich verwalte die Aktivitäten für dieses Buch auch mit einem Kanban-Board. Jede Karte auf der Tafel steht für eine Aufgabe, die ich oder eines meiner Teammitglieder erledigen muss. Eine Karte wird erst dann auf "Erledigt" gesetzt, wenn das Team zustimmt, dass sie erledigt ist.

GitHub bietet einen "Issues"-Reiter, um Anforderungen und andere Notizen zu deinem Repository zu verfolgen. Abbildung 1-12 zeigt die Aufgabenvorlage, die ich in diesem Buch für jede Anforderung verwendet habe. Das ist das Material, das in jede Aufgabe hineingehört und kann Text, Links usw. enthalten. Beachte, dass jede der von mir erstellten Anforderungskarten fünf Elemente enthält: Titel, Beschreibung, Aktionen, Schätzung und Tests.

Task template
Abbildung 1-12. Aufgabenvorlage

Die meisten dieser Kategorien sind selbsterklärend. Aber warum nur drei Aufwandsstufen für Estimate? In diesem Buch sollten die meisten Aktivitäten in eine der folgenden "Aufwandsstufen" fallen: 2 Stunden oder weniger (Small), etwa einen halben Tag (Medium) oder etwa einen Tag (Large). Beachte, dass es sich hierbei nur um Richtwerte handelt, die je nach den verschiedenen Faktoren stark variieren können.

Eine "Aufgabe" mit dem Namen "IoT-Lösung mit drei Cloud-Diensten integrieren" stellt sicherlich eine Arbeit dar, die erledigt werden muss, aber allein dem Namen nach zu urteilen, ist sie viel zu groß und kompliziert, um eine einzige Arbeitsaktivität zu sein. In diesem Fall kann ich mehrere Aufgaben erstellen, für die ich jeweils eine Reihe von Tests durchführe. In anderen Fällen kann es sein, dass ich mehrere Module habe, die alle sehr grundlegend sind und ähnliche Implementierungen haben - und die alle im selben Issue enthalten sind. Ich versuche, jedes Issue so weit wie möglich in sich geschlossen zu halten.

Abbildung 1-13 zeigt ein Beispiel für ein Templating, das mit den Highlights aus der ersten Programmieraufgabe ausgefüllt ist, die du haben wirst: die Erstellung der Constrained Device Application (CDA).

Example of a typical development task
Abbildung 1-13. Beispiel für eine typische Entwicklungsaufgabe

Und Abbildung 1-14 zeigt das Ergebnis des Hinzufügens der Aufgabe als Kanban-Karte. Diese Karte wurde automatisch erstellt, nachdem die Aufgabe einem Projekt zugeordnet wurde. Beachte, dass sie der Spalte "Zu erledigen" auf der Tafel hinzugefügt wurde, da sie neu ist und noch keinen Status hat. Sobald du mit der Arbeit an der Aufgabe beginnst und ihren Status änderst, wird sie in die Spalte "In Bearbeitung" verschoben.

Auch hier sind die Anforderungen bereits für dich geschrieben und im Kanban-Board Programmierung des IoT enthalten, aber jetzt solltest du eine bessere Vorstellung davon haben, wie diese Anforderungen definiert sind, und sogar eine Vorlage für die Erstellung deiner eigenen, falls du dich dafür entscheidest.

The new example task added into the Kanban board
Abbildung 1-14. Die neue Beispielaufgabe, die der Kanban-Tafel hinzugefügt wurde

Als Nächstes richten wir deine entfernten Git-Repositories ein.

Einrichten deiner Remote-Repositories

Es gibt viele hervorragende cloudbasierte Git-Repository-Dienste. Wie ich bereits erwähnt habe, verwende ich GitHub. Deshalb habe ich hier einige optionale Anleitungen bereitgestellt, um dir den Einstieg zu erleichtern:

  1. Erstelle ein GitHub-Konto. (Falls gewünscht, erstelle eine Organisation, die mit dem GitHub-Konto verbunden ist).

  2. Erstelle innerhalb deines Kontos (oder deiner Organisation) die folgenden Daten:

    1. Ein neues privates Projekt namens "Programming the IoT - Exercises"

    2. Ein neues privates Git-Repository namens "java-components"

    3. Ein neues privates Git-Repository namens "python-components"

  3. Aktualisiere das Remote-Repository sowohl für "java-components" als auch für "python-components".

    1. Führe in der Befehlszeile die folgenden Befehle aus:

      git remote set-url origin {your new URL}
      git commit -m “Initial commit.”
      git push
    2. WICHTIG: Vergewissere dich, dass du dies sowohl für "java-components" als auch für "python-components" tust und die entsprechende Git-Repository-URL für beide verwendest!

Sobald du diese Aufgaben erledigt hast, sind deine Git-Repositories eingerichtet und du kannst deinen Code lokal verwalten und mit deiner Remote-Instanz synchronisieren.

Codeverwaltung und Verzweigung

Einer der wichtigsten Vorteile von Git ist die Möglichkeit, mit anderen zusammenzuarbeiten und dein lokales Code-Repository mit einem Remote-Repository in der Cloud zu synchronisieren. Wenn du schon einmal mit Git gearbeitet hast, bist du bereits mit Remotes und Branching vertraut. Ich werde hier nicht weiter ins Detail gehen, aber es sind wichtige Konzepte, die du als Teil deiner Automatisierungsumgebung verstehen solltest.

Mit Hilfe von Verzweigungen kann jeder Entwickler oder jedes Team seine Arbeit aufteilen, ohne die Hauptcodebasis negativ zu beeinflussen. In Git wird dieser Standard-Hauptzweig derzeit "master" genannt und enthält in der Regel den Code, der fertiggestellt, getestet, verifiziert und (normalerweise) in Produktion gegeben wurde. Dies ist der Standardzweig für "java-components" und "python-components". Du kannst ihn zwar so belassen und einfach mit diesem Standardzweig arbeiten, aber das ist aus den genannten Gründen in der Regel nicht zu empfehlen.

Die Verzweigungsstrategien können sich von Unternehmen zu Unternehmen und von Team zu Team unterscheiden. Bei der von mir bevorzugten Strategie wird jedes Kapitel in einem neuen Zweig erstellt und sobald alles korrekt funktioniert und getestet wurde, wird der Kapitelzweig mit dem Master zusammengeführt. Von dort aus wird ein neuer Zweig für das nächste Kapitel aus dem zusammengeführten Master erstellt und so weiter.

Auf diese Weise kannst du Änderungen zwischen den Kapiteln leicht nachverfolgen und sogar zu den historischen Aufzeichnungen eines früheren Kapitels zurückgehen, wenn du sehen willst, was sich zwischen, sagen wir, Kapitel 2 und Kapitel 5 geändert hat. In Eclipse kannst du mit der rechten Maustaste auf das Projekt (entweder "java-components" oder "python-components") klicken und Team → "Switch To" → "New Branch" wählen, um einen neuen Zweig für deinen Code zu erstellen.

Ich schlage vor, dass du die Namenskonvention "kapiteln" für jeden Zweignamen verwendest, wobei nn die zweistellige Kapitelnummer ist. Der Zweig für Kapitel 1 heißt zum Beispiel "Kapitel01", der Zweig für Kapitel 2 heißt "Kapitel02" und so weiter. Es ist nützlich, eine Verzweigungsstrategie zu haben, die es dir ermöglicht, zu einem früheren, "letzten bekannten guten" Zweig zurückzukehren oder zumindest zu sehen, was sich zwischen einem Kapitel und dem nächsten geändert hat. Zur Erinnerung habe ich die kapitelbezogene Verzweigungsstrategie in den Anforderungen für jedes Kapitel dokumentiert.

Hinweis

Die Details zum Verzweigen und Zusammenführen von Git liegen außerhalb des Rahmens dieses Buches, daher empfehle ich dir, den Leitfaden "Git Branching-Basic Branching and Merging" zu lesen, wenn du dich damit befassen möchtest.

Überlegungen zur Automatisierung

Die Automatisierung von Software-Builds, -Tests, -Integration und -Deployment ist ein wichtiger Bestandteil vieler Entwicklungsumgebungen, auch wenn sie den Rahmen dieses Buches sprengen würde. Ich werde in diesem Abschnitt einige Konzepte erörtern, aber in dieser Ausgabe des Buches nicht darauf eingehen.

Automatisiertes CI/CD in der Cloud

In Eclipse kannst du deinen CDA- und GDA-Code schreiben, Unit-Tests durchführen und beide Anwendungen bauen und verpacken. Das ist nicht wirklich automatisiert, denn du musst den Prozess selbst starten, indem du einen Befehl wie mvn install von der Kommandozeile aus ausführst oder den Maven-Installationsprozess in der IDE aufrufst. Das ist gut, um beide Anwendungen so weit zu bringen, dass du sie ausführen kannst, aber es führt sie nicht wirklich aus - du musst die Anwendungen immer noch manuell starten und dann deine Integrations- und/oder Leistungstests durchführen.

Als Entwickler/in besteht ein Teil deiner Arbeit darin, Code zu schreiben und zu testen, um die festgehaltenen Anforderungen zu erfüllen (z.B. in Form von Karten auf einer Kanban-Tafel). Sobald du weißt, dass deine Code-Einheiten richtig funktionieren, kann alles andere automatisch ablaufen - zum Beispiel, nachdem du deinen Code in den entfernten Entwicklungszweig (z. B. "chapter02") gepackt hast - das wäre ziemlich clever.

GitHub unterstützt diese Automatisierung durch GitHub-Aktionen.9 In Kapitel 2 werde ich mehr darüber erzählen und dir helfen, deine eigene Automatisierung für die Anwendungen, die du bauen willst, einzurichten.

Automatisiertes CI/CD in deiner lokalen Entwicklungsumgebung

Es gibt viele Möglichkeiten, CI/CD in deiner lokalen Umgebung zu verwalten. GitHub-Aktionen können z.B. mit selbst gehosteten Runnern lokal ausgeführt werden.10 Es gibt auch ein Tool zur Workflow-Automatisierung namens Jenkins, das lokal ausgeführt werden kann, sich gut mit lokalen und entfernten Git-Repositories integrieren lässt und über eine Plug-in-Architektur verfügt, mit der du seine Möglichkeiten scheinbar endlos erweitern kannst.

Warnung

Es gibt viele großartige Jenkins-Plug-ins und andere Hilfsprogramme von Drittanbietern, die ich für meine eigene Build-, Test- und Deployment-Umgebung als nützlich empfunden habe, aber du solltest selbst recherchieren, welche davon aktiv gepflegt werden und einen Mehrwert für deine spezielle Umgebung bieten. Es kann leicht zu Problemen mit der Systemkompatibilität und sogar zu Sicherheitslücken kommen, wenn du nicht genau weißt, was ein Produkt kann und was es nicht kann. Diese Entscheidung liegt letztendlich in deiner Verantwortung.

Sobald es installiert und gesichert ist, kannst du Jenkins so konfigurieren, dass es automatisch dein Git-Repository lokal oder aus der Ferne überwacht und einen Build/Test/Deploy/Run-Workflow auf deinem lokalen System ausführt und den Erfolg bei jedem Schritt überprüft. Wenn der Build zum Beispiel wegen eines Kompilierfehlers in deinem Code fehlschlägt, meldet Jenkins dies und hält den Prozess an. Das Gleiche gilt, wenn der Build erfolgreich ist, aber die Tests fehlschlagen - der Prozess wird beim ersten Fehler angehalten. So wird sichergestellt, dass dein lokales Deployment nicht mit einem Update überschrieben wird, das nicht kompiliert wird oder bei dem die konfigurierten Tests fehlschlagen.

Die Einrichtung eines lokalen Automatisierungstools kann ein kompliziertes und zeitaufwändiges Unterfangen sein. Es ist jedoch sehr hilfreich, denn es automatisiert im Grunde alles, was du zum Erstellen, Testen und Verteilen deiner Software tun musst. Allerdings ist es für die Übungen in diesem Buch nicht erforderlich, deshalb gehe ich hier nicht näher darauf ein.

Containerisierung

Du hast wahrscheinlich schon von der Containerisierung gehört. Dabei handelt es sich um eine Möglichkeit, deine Anwendung und alle ihre Abhängigkeiten in ein einziges Image oder einen Container zu packen, der in vielen verschiedenen Betriebsumgebungen eingesetzt werden kann. Dieser Ansatz ist sehr praktisch, denn er ermöglicht es dir, deine Software so zu erstellen und einzusetzen, dass die Hosting-Umgebung keine Rolle mehr spielt, vorausgesetzt, die Zielumgebung unterstützt die von dir verwendete Container-Infrastruktur.

Docker11 ist im Wesentlichen eine Anwendungsengine, die auf einer Vielzahl von Betriebssystemen wie Windows, macOS und Linux läuft und als Host für deine Container-Instanz(en) dient. Dein GDA und dein CDA können zum Beispiel in Containern untergebracht und dann auf jedem Gerät eingesetzt werden, das die zugrunde liegende Container-Infrastruktur und -Laufzeit unterstützt.

Es sei darauf hingewiesen, dass die Containerisierung von Anwendungen mit hardwarespezifischem Code problematisch sein kann, da sie nicht auf eine andere Hardwareplattform übertragen werden kann (selbst wenn die Container-Engine unterstützt wird). Wenn du willst, dass deine hardwarespezifische Anwendung auf jeder Plattform läuft, die Docker unterstützt, brauchst du für diese Plattform einen hardwarespezifischen Emulator, der mit dem für die Anwendung entwickelten Code kompatibel ist.

Wenn dein CDA zum Beispiel Code enthält, der von Raspberry Pi-spezifischer Hardware abhängt, ist das für uns im Moment weniger wichtig, da du Sensoren und Aktoren emulierst und dir erst in Kapitel 4 (das wiederum optional ist) Gedanken über hardwarespezifischen Code machen musst. In Kapitel 4 gehe ich näher darauf ein und zeige dir Strategien, wie du die Hardwarespezifität in deinem CDA überwinden kannst.

Wenn du CI/CD-Pipelines in einer Remote- oder Cloud-Umgebung verwendest, wirst du feststellen, dass diese Dienste wahrscheinlich auf virtuellen Maschinen eingesetzt werden und deinen Code in einem Container ausführen, der die erforderlichen Abhängigkeiten enthält, die alle als Teil der Pipeline konfiguriert sind. In vielen Fällen ist das absolut sinnvoll und kann eine effektive Strategie sein, um Konsistenz und eine einfache Bereitstellung zu gewährleisten. Der Nachteil ist, dass die Zielplattform die Container-Laufzeitumgebung unterstützen muss, die du einsetzen willst. Plattformübergreifende Sprachen können dies vereinfachen, aber ich glaube nicht, dass dieses Problem in absehbarer Zeit verschwinden wird.

Um die Dinge einfacher zu halten, werde ich nicht auf die Verwendung von Containern in deiner Entwicklungsumgebung und als Teil deiner Workstation eingehen, obwohl dies viele Vorteile mit sich bringt. Der Hauptgrund dafür ist, dass es anfangs eine weitere Ebene der Komplexität darstellt, die es zu verwalten gilt, und ich möchte, dass du so schnell wie möglich mit deinen eigenen Anwendungen loslegen kannst.

Programmierübungen

All die Arbeit, die du bis zu diesem Punkt geleistet hast, diente dazu, dich auf die Erstellung deiner CDA und GDA vorzubereiten. Du kennst dich mit dem IoT aus, hast eine Entwicklungsumgebung eingerichtet und bist bereit zu programmieren. So weit, so gut, oder?

Wenn du dir deine Codebasis ansiehst, wirst du feststellen, dass du bereits eine ganze Reihe von Komponenten eingesetzt hast. Die meisten sind sogar nur Shell-Implementierungen der Komponenten, die sowohl für den CDA als auch für den GDA erforderlich sind. Aber wie sollen sie letztendlich alle zusammenarbeiten?

In den verbleibenden Kapiteln des Buches wirst du die Anforderungen, die im Kanban-Board Programmierung des IoT dokumentiert sind, durchgehen, um diesen Endzustand zu erreichen. Die Abbildungen 1-15 und 1-16 zeigen den allgemeinen Entwurfsansatz, den wir für den CDA und den GDA verfolgen, um dieses Ziel zu erreichen.

CDA end-state design
Abbildung 1-15. CDA Endzustandsentwurf
GDA end-state design
Abbildung 1-16. GDA Endstadium Design

Sieht nach einer Menge Arbeit aus! Aber keine Sorge - wir werden Schritt für Schritt vorgehen. Jedes Kapitel fügt den Diagrammen weitere Funktionen hinzu, indem es die Farbkodierung in der Legende (für bestehende, neue und geänderte Komponenten) verwendet und die einzelnen Bereiche, die im Kapitel behandelt werden, näher erläutert.

Werfen wir einen Blick auf die spezifischen Designs von CDA und GDA, die für dieses Kapitel relevant sind, und gehen wir die Übungen durch (es gibt nur eine für jede Anwendung). Du kannst die Details für jede Anwendung online nachlesen: PIOT-CDA-01-001 für den CDA und PIOT-GDA-01-001 für den GDA.

CDA design for Chapter 1: GDA design for Chapter 1
Abbildung 1-17. CDA-Design für Kapitel 1 (links) und GDA-Design für Kapitel 1 (rechts)

Das sieht schon etwas überschaubarer aus! Die erste - und vielleicht wichtigste - hast du bereits abgeschlossen und alle Anforderungen aus Kapitel 1 umgesetzt! Jetzt musst du sie nur noch testen. Im Abschnitt Test auf jeder Anforderungskarte siehst du, dass du jede Anwendung als manuellen Integrationstest ausführen musst.

Testen der App für eingeschränkte Geräte

Für die CDA navigierst du zum Pfad ./src/main/python/programmingtheiot/part01/integration/app. Du wirst den ConstrainedDeviceAppTest sehen. Nachdem du diesen Test ausgeführt hast, sollte deine Ausgabe ähnlich wie die folgende aussehen:

Finding files... done.
.
2020-12-30 13:54:32,915 - MainThread - root - INFO - Testing ConstrainedDeviceApp
class...
2020-12-30 13:54:32,915 - MainThread - root - INFO - Initializing CDA...
2020-12-30 13:54:32,915 - MainThread - root - INFO - Starting CDA...
2020-12-30 13:54:32,916 - MainThread - root - INFO - Loading config:
../../../../../../../config/PiotConfig.props
2020-12-30 13:54:32,917 - MainThread - root - DEBUG - Config:
['Mqtt.GatewayService', 'Coap.GatewayService', 'ConstrainedDevice']
2020-12-30 13:54:32,917 - MainThread - root - INFO - Created instance of
ConfigUtil: <programmingtheiot.common.ConfigUtil.ConfigUtil object at
0x0000026B463E0E48>
2020-12-30 13:54:32,917 - MainThread - root - INFO - CDA started.
2020-12-30 13:54:32,917 - MainThread - root - INFO - CDA stopping...
2020-12-30 13:54:32,917 - MainThread - root - INFO - CDA stopped with exit code 0.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK

Vielleicht bemerkst du zahlreiche Log-Ausgaben zum Laden von Modulen (die ich ausgeschlossen habe) - das ist in Ordnung. Wenn deine Ausgabe im Allgemeinen dem hier gezeigten Muster entspricht, kannst du mit dem Testen des GDA fortfahren.

Testen der Gateway-Geräte-App

Um den GDA zu testen, navigiere zum Pfad ./src/main/java/programmingtheiot/part01/integration/app. Du wirst den GatewayDeviceAppTest sehen. Deine Ausgabe sieht in etwa so aus wie die folgende:

Dec 30, 2020 1:45:50 PM programmingtheiot.gda.app.GatewayDeviceApp <init>
INFO: Initializing GDA...
Dec 30, 2020 1:45:50 PM programmingtheiot.gda.app.GatewayDeviceApp parseArgs
INFO: No command line args to parse.
Dec 30, 2020 1:45:50 PM programmingtheiot.gda.app.GatewayDeviceApp startApp
INFO: Starting GDA...
Dec 30, 2020 1:45:50 PM programmingtheiot.gda.app.GatewayDeviceApp startApp
INFO: GDA started successfully.
Dec 30, 2020 1:45:51 PM programmingtheiot.gda.app.GatewayDeviceApp stopApp
INFO: Stopping GDA...
Dec 30, 2020 1:45:51 PM programmingtheiot.gda.app.GatewayDeviceApp stopApp
INFO: GDA stopped successfully with exit code 0.

Wenn deine Ausgabe ähnlich aussieht, kannst du anfangen, Code zu schreiben.

Fazit

Herzlichen Glückwunsch - du hast soeben das erste Kapitel von Programming the Internet of Things abgeschlossen! Du hast einige grundlegende IoT-Prinzipien kennengelernt, eine Problemstellung für deine IoT-Lösung erstellt und eine grundlegende IoT-Systemarchitektur mit Cloud Tier und Edge Tier aufgebaut.

Am wichtigsten ist vielleicht, dass du jetzt die Basis für zwei Anwendungen hast - den GDA und den CDA -, die im Laufe dieses Buchs als Grundlage für einen Großteil deiner IoT-Softwareentwicklung dienen werden. Schließlich hast du deine Entwicklungsumgebung und deinen Entwicklungsworkflow eingerichtet, etwas über Anforderungsmanagement gelernt, dich mit Unit-, Integrations- und Leistungstests beschäftigt und einige grundlegende CI/CD-Konzepte zur Automatisierung von Builds und Deployment betrachtet.

Jetzt bist du bereit, mit Python und Java echte IoT-Funktionen in deinen CDA und GDA einzubauen. Wenn du bereit bist, weiterzumachen, würde ich vorschlagen, dass du dir ein Wasser oder eine gute Tasse Kaffee oder Tee holst und wir dann loslegen.

1 Carsten Bormann, Mehmet Ersue, and Ari Keränen, "Terminology for Constrained-Node Networks", IETF Informational RFC 7228, May 2014, 8-10.

2 Erfahre mehr über WSL und wie du sie auf deiner Plattform installierst unter https://oreil.ly/YK9Rb.

3 CoAP (Constrained Application Protocol) ist ein Nachrichtenprotokoll, das ich in Teil III (insbesondere in den Kapiteln 8 und 9) besprechen werde.

4 MQTT (Message Queuing Telemetry Transport) ist ein Messaging-Protokoll, auf das ich in Teil III (insbesondere in den Kapiteln 6 und 7) eingehen werde.

5 Weitere Informationen findest du auf der GitHub-Website.

6 Ausführliche Informationen über die Unittest-Bibliothek von Python 3 findest du in der Unittest-Dokumentation.

7 Auf der GitHub-Website kannst du mehr über GitHub und seine Hosting-Funktionen erfahren und einen kostenlosen Account erstellen.

8 Mehr darüber erfährst du, wenn du das Agile Manifest liest.

9 GitHub-Aktionen sind eine Funktion auf GitHub, mit der individuelle Workflows für diejenigen erstellt werden können, die ein Konto auf GitHub haben.

10 Selbst gehostete Runner, die Teil von GitHub Actions sind, ermöglichen es dir, deine Action-Workflows lokal auszuführen. Dabei gibt es natürlich einige Einschränkungen und Sicherheitsbedenken. Mehr über selbst gehostete Runner erfährst du in der GitHub Actions Dokumentation.

11 Mehr über die Konzepte der Containerisierung und die Produkte von Docker erfährst du auf der Docker-Website.

Get Programmierung des Internets der Dinge now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.