Softwareentwicklung

Allgemeines

MED greift zur Realisierung seiner Software-Komponenten auf einige bestehende Bibliotheken und Projekte zurück, basierend auf welchen er seine eigenen Komponenten aufbaut.

Auf dem verwendeten Raspberry Pi laufen (auf einem kopflosen Raspbian-Betriebssystem) zwei Projektrelevante Softwares:

  • NodeRED stellt mit seiner graphischen Programmieroberfläche und vielseitigen Integrationen die zentrale Steuereinheit MEDs dar. Zur Ergänzung der Standardfunktionen NodeREDs werden folgende Pakete verwendet:
    • node-red-contrib-speakerpi erlaubt das Abspielen von Tönen auf dem Raspberry Pi selbst
    • node-red-contrib-discord erlaubt das Empfangen und Senden von Nachrichten über den Anbieter Discord.
    • node-red-contrib-telegrambot erlaubt das Empfangen und Senden von Nachrichten über den Anbieter Telegram
    • node-red-dashboard erlaubt das Anlegen einer Website als Steuereinheit
  • Mosquitto ist ein einfacher MQTT-Broker, welche eine einfache, kabellose Kommunikation zwischen verschiedenen Geräten – hier Raspberry Pi und ESP8266 – ermöglicht.

Auf beiden verwendeten Microcontrollern kommen bestehende Softwarebibliotheken zum Einsatz, welche folgende Funktionalitäten bereitstellen:

  • WiFiManager (v0.15.0) von tzapu und tablatronix – Ermöglicht die dynamische Eingabe von WiFi-Verbindungsdaten sowie weiteren Parametern, anstatt diese fest im Quelltext zu hinterlegen
  • PubSubClient (v2.7.0) von Nick O’Leary– Implementiert MQTT-Kommunikation auf Seiten der Microcontroller
  • ArduinoJSON (v6.18.3) von Benoit Blanchon – Erlaubt das Erstellen und Auslesen von JSON-Strukturen, welche dann etwa über ein Netzwerk übertragen oder lokal gespeichert werden können.

Zusätzlich werden die Standard-Bibliotheken ESP8266WiFi und FS (Filesystem) verwendet.

Dazu kommt auf dem Klingel-Microcontroller die Bibliothek LiquidCrystal_I2C (v1.1.2) von Frank de Brabander, welche zur Steuerung des angeschlossenen LCD über einen I2C-Bus verwendet wird.

Systemaufbau und Schnittstellen

Gesamtsystem

Das System besteht, wie bereits in der Hardwaredokumentation beschrieben, aus einem Raspberry Pi und zwei ESP8266 Microcontrollern.
Aus der obenstehenden Grafik kann der Aufbau des Systems und die Verknüpfung der einzelnen Geräte entnommen werden: Die zentrale Steuereinheit des Systems befindet sich innerhalb von NodeRED und kommuniziert von dort aus auf zwei Arten mit anderen Geräten und Systemen:
Der direkt an den Raspberry Pi angeschlossene Reed-Switch für die Überwachung der Haustür wird über einen GPIO-Pin des Raspberry Pi angesteuert, die beiden Microcontroller jeweils per MQTT über einen lokalen Mosquitto-Server als Broker.
Die an die Microcontroller angeschlossenen Komponenten sind fest verlötet und werden über die zuvor genannten Bibliotheken angesprochen.

Entwicklungsablauf

Vor Beginn der eigentlichen Entwicklung wurden die oben genannten Bibliotheken und Packages gewählt und installiert.

Als erster eigentlicher Entwicklungsschritt werden die grundlegenden NodeRED-Flows angelegt, welche zu diesem Zeitpunkt bereits eine erste Version des Dashboards sowie einen Debug-Flow enthalten, welcher zur Simulation von MQTT-Eingaben genutzt werden kann.
Außerdem enthalten ist die grundlegende Version des Ablaufs, welcher beim Eintreten eines Events (Klingeln, Briefeinwurf, Tür geöffnet/geschlossen) aufgerufen wird:

Flow bei Klingel Event (finale Version)

Dieser Ablauf setzt maßgeblich auf eigenprogrammierte “Gate”-Functions. Diese haben zwei mögliche Inputs: Zum einen die kleinen, grauen Nodes, welche hier Eingänge aus den Dashboard-Einstellungen darstellen – hiermit kann der Status (An/Aus) des Gates verändert werden, wenn eine entsprechende Änderung im Dashboard vom Nutzer vorgenommen wird. Der zweite mögliche Input des Gates wird vom Gate selbst nicht weiter verarbeitet, sondern weitergeleitet, sofern der Status des Gates aktuell “An” ist – andernfalls wird die Nachricht ignoriert. Je nach Gate wird die Nachricht an eine entsprechende Node weitergeleitet – das Aktiv-Gate leitet jeweils an alle Funktionsgates weiter, das Audio-Gate an die Lautsprecherfunktion und so weiter.

Als nächstes werden die grundlegenden Versionen des Microcontroller-Codes angelegt. Diese basieren grob auf Beispielen aus Vorlesung und Übungen, werden jedoch angepasst, um gleichzeitig den WiFiManager und MQTT-Verbindungen benutzen zu können. Dabei werden die Verbindungsdaten zum MQTT-Broker nicht fest im Quelltext hinterlegt sondern dynamisch zum Systemstart als Custom Parameter über den WiFiManager abgefragt:

WiFiManager Custom Parameter

Diese Parameter werden nach einer erfolgreichen Verbindung in Variablen zwischengespeichert und vom System verwendet. Um die Daten nicht bei jedem Systemstart erneut eingeben zu müssen werden diese darüber hinaus noch im Dateisystem in einer .json Datei gespeichert (und vor dem Anlegen der Custom Parameter erneut geladen).

Als nächstes wird Unterstützung für die Messenger Telegram und Discord implementiert, sodass Benutzer des Systems von diesen Nachrichten erhalten und Nachrichten an diese Senden können. Hierfür werden die oben genannten Bibliotheken für die jeweiligen Messenger verwendet, welche jedoch jeweils vom Endbenutzer an zwei Stellen konfiguriert werden müssen: Zum einen muss jeder Benutzer einen eigenen API-Token angeben (erhalten für Telegram vom sog. BotFather, für Discord über die Discord Developer Seite), zum andern muss jeweils klargemacht werden, an welchen Chat oder Chatkanal der jeweilige Bot eine Nachricht senden soll. Diese haben jeweils eine dem jeweiligen System zugehörige ID, welche der Benutzer herausfinden muss. Um dies zu erleichtern, wird die Möglichkeit bereitgestellt, beim Empfang einer Nachricht, welche das Kommando /start oder /info enthält, dem jeweiligen Benutzer diese ID automatisch zuzuschicken:

Ablauf des ID-Findens (Telegram)
handleMessage Function Node

Die gefundene ID muss vom Benutzer selbst dann noch einmalig in eine Function-Node eingetragen werden. Diese könnte auch im Dashboard übergeben werden, dort ist sie jedoch nicht persistent, geht also bei Neustarts des Systems verloren – beim Eintragen in einer function-Node ist dies nicht der Fall, weshalb diese Variante ausgewählt wurde.

An dieser Stelle werden die NodeRED-Flows in drei Teile aufgeteilt (sowie den aktuell noch vorhandenen Debug-Flow):
> Configuration: Enthält, der Übersicht halber, beinahe ausschließlich Nodes, welche vom Endbenutzer einmalig konfiguriert werden müssen.
> MED-Logik: Enthält den Großteil der logischen Abläufe
> Dashboard: Enthält alle Komponenten welche direkt im Dashboard verwendet werden sowie die Reaktionen auf Dashboard-Aktionen, welche nicht ebenfalls in anderen Flows verwendet werden.
Die drei Flows werden dabei untereinander durch Link in/Link out Nodes verbunden, welche drahtlose Verbindungen zwischen Nodes (auch zwischen verschiedenen Flows) ermöglichen. [Genauere Übersicht über die einzelnen Flows weiter unten]

Zwischenzeitlich werden die tatsächlichen Detektions-Funktionen der Microcontroller programmiert: Ein Knopfdruck für die Klingel und ein IR-Sensor, welche jeweils beim Auslösen eine MQTT-Nachricht versenden, welche dann von NodeRED empfangen und verarbeitet werden.

Nun wird die Historienfunktion hinzugefügt. Diese speichert, sofern jeweils im Dashboard aktiviert, Events sowie die aktuelle Zeit in einer csv-Datei und gibt diese wenn gewünscht auf einer Extraseite im Dashboard wieder aus.

Historientabelle mit Beispieleinträgen

Als letztes Feature wird nun noch das LCD integriert, auf welchem Nachrichten des Benutzers angezeigt werden können. Hierbei kann der Benutzer entweder mit dem Kommando /send Nachricht seine gewünschte Nachricht an NodeRED senden, oder diese direkt im Dashboard in das zuständige Textfeld eingeben. Darüber hinaus kann er im Dashboard auswählen, wie lange die jeweilige Nachricht angezeigt werden soll, wodurch ggf. Akkuleistung gespart werden kann.
Wird eine Nachricht von einem Messenger erhalten, so prüft NodeRED zunächst, ob die Nachricht auf das Display passt (Dieses unterstützt mit 2 Reihen a 16 Zeichen insgesamt 32 maximal Zeichen) – ist dies nicht der Fall so wird dem Nutzer eine entsprechende Fehlermeldung angezeigt, andernfalls wird das Display mit der Nachricht für die im Dashboard gewählte Zeit aktiviert. Eine Beispiel-Ausgabe (auf einem 4×20 Display) sieht wie folgt aus:

Ausgabe eines Beispiel-Textes auf einem (größeren) LCD

Nachdem die Softwareentwicklung an sich nun abgeschlossen ist, bleiben nur noch einige Aufräumarbeiten, wie etwa den bisherigen working-title in allen Instanzen durch den neu gewählten Projekttitel MED zu ersetzen oder den Debug-Tab des Dashboards und diverse Serial.println()s aus dem Quelltext der Microcontroller zu entfernen.

Erstellte Oberflächen

An dieser Stelle werden die entworfenen Oberflächen gezeigt, welche entwickelt wurden, bisher aber noch nicht direkt vorgestellt wurden.

Dashboard

Das Dashboard bietet, wie bereits erwähnt, genaue Kontrolle darüber, welche Aktion ausgehend von einem Event getroffen werden soll. Darüber hinaus kann pro Event festgelegt werden, wieviel Zeit zwischen zweimaligem Auslösen des Events vergehen muss.
Zusätzlich kann der Nutzer Nachrichten an das LCD im Klingelgehäuse versenden und die Dauer der Nachrichtenanzeige auf dem LCD bestimmen.
Zuletzt kann noch ausgewählt werden, ob Nachrichten via Telegram, Discord oder Beidem empfangen werden sollen.

WiFiManager mit MQTT-Custom-Parametern

Diese Oberfläche wird vom WiFiManager automatisch generiert – aus den Standard-Daten, die für einen WiFi-Login benötigt werden, und den übergebenen Custom Parametern (s. Quelltext oben).

Erstellte Flows

An dieser Stelle werden die drei Flows gezeigt, welche entwickelt wurden, bisher aber noch nicht direkt in Gänze vorgestellt wurden.

Configuration-Flow

Der Configuration-Flow enthält Nodes, welche der Benutzer einmalig beim Aufsetzen des Systems konfigurieren muss. Diese sind jeweils mit einem [!] gekennzeichnet und beziehen sich hauptsächlich auf das Empfangen und Senden von Nachrichten über die verschiedenen Messenger.

Dashboard

Der Dashboard-Flow enthält alle Nodes, welche direkt im Dashboard angezeigt werden (türkis/hellblau), oder direkt durch diese Nodes aber keine anderen beeinflusst werden – dies sind teils MQTT-Nodes, die Intervalle oder Texte an Microcontroller versenden, aber auch die Nodes, welche sich mit der Historientabelle befassen (unten) – entweder um Daten zu laden oder um die Tabelle zu leeren.

MED-Logik

Der MED-Logik Flow stellt die grundsätzliche Logik MEDs bereit – einen Eingang für MQTT-Nachrichten, welche dann nach Thema zugeordnet werden und anschließend den bereits beschriebenen Teilflow mit verschiedenen Gates und Ausgängen durchlaufen, sowie einen Eingang für Nachrichten des am Raspberry Pi angeschlossenen Reed-Switches, welche dann ebenfalls einen ähnlichen Ablauf durchlaufen.
Außerdem werden wieder verwendbare Teilflows zum schreiben in die Historie und zum Senden von Nachrichten über die jeweils im Dashboard aktivierten Messenger-Dienste definiert (oben).