In der letzten Folge haben wir mit dem ESP32 DevKitC, einer RGB-LED und einem Fotowiderstand ein kleines Gerät realisiert, das periodisch Helligkeitswerte erfasst und zur Cloudplattform AllThingsTalk sendet. Dort werden sie auf einer vom Nutzer konfigurierbaren Webseite angezeigt. Damit das funktioniert, muss sich der ESP32 erst in ein WLAN einloggen, danach über TCP/IP und MQTT mit dem AllThingsTalk-MQTT-Broker verbinden. Wenn das geklappt hat, dann dimmt die RGB-LED periodisch von Grün herunter. Alle zwei Sekunden wird über den ADC ein Helligkeitswert gesampelt und per MQTT publiziert. Die nötigen Konfigurationsparameter (z. B. SSID des WLAN) können über eine Webseite eingestellt werden, die der ESP32 über ein selbst aufgespanntes WLAN und eine eigene kleine Webseite ausliefert.

So weit, so gut, allerdings hatte ich mich noch gar nicht darum gekümmert, dass es auch zu Verbindungsabbrüchen kommen kann. Bei den Tests für die letzte Folge habe ich das Gerät ja auch mal einen halben Tag laufen lassen, bis der Akku meiner Powerbank leer war (um das Stromsparen müssen wir uns in einer späteren Folge kümmern). Da konnte es passieren, dass die WLAN-Verbindung abbrach, was das Programm aber gar nicht mitbekam. Die grüne LED dimmte noch schön vor sich hin, Werte kamen aber natürlich nicht mehr bei AllThingsTalk an. Ein praktikables Datenloggen sieht anders aus.
 

ESP32 pingt

Beim Publizieren einer MQTT-Nachricht bekommt man vom Broker keine Bytes als Rückmeldung zurückgeschickt. Allerdings bietet MQTT ja den Ping-Mechanismus, um festzustellen, ob eine MQTT-Verbindung noch steht. Ich integrierte daher zuerst ein regelmäßiges Anpingen des AllThingsTalk-Brokers in meinen Arduino-Sketch. Um zu viel Traffic zu vermeiden, sollte nur nach jedem fünften Versenden eines Sensorwertes ein Ping erfolgen; das kann man über einen kleinen Zähler ja einfach realisieren. Implementiert habe ich den Zähler und das Pingen ganz zu Anfang in jenem Codeabschnitt der Loop-Schleife, in dem das Dimmen und die MQTT-Funktionen aufgerufen werden. Falls das Pingen negativ verläuft, wird MQTTClient_Connected wieder von true auf false zurückgesetzt, den Wert, den diese Variable auch beim Start hat. Danach folgt im Sketch gleich der Codeabschnitt, wo in diesem Fall das Verbinden mit dem Broker angestoßen wird. Hier musste ich nicht viel ändern. Ich habe nur ergänzt, dass im Falle eines Scheiterns
 
RouterNetworkDeviceState = NETWORKSTATE_NOTLOGGED;

werden soll. Ich nehme nämlich an, dass wir vermutlich aus dem WLAN herausgefallen sind, falls nach dem Pingen auch das Verbinden über MQTT nicht klappt.
Nun musste ich noch in die regelmäßig durchlaufene Loop-Schleife eine Prüfung auf
 
RouterNetworkDeviceState != NETWORKSTATE_LOGGED;

einbauen, gefolgt von einem (erneuten) Versuch des Einloggens.

Ein paar Funktiönchen

Ein solcher Versuch muss nun an drei verschiedenen Stellen im Code angestoßen werden: Beim Start des Programms in der Setup-Funktion, nach dem Empfang des ausgefüllten Konfigurationsformulars sowie nach einem gescheiterten Ping und einem nachfolgend gescheiterten Connect-Versuch. Da drängte sich natürlich das Schreiben einer eigenen Funktion auf, die ich LoginRouterNetworkAndSetRGB() genannt habe. Diese Funktion rief ich nun aber nicht direkt an den drei entsprechenden Stellen im Code auf. Stattdessen wird dort lediglich
 
RouterNetworkDeviceState = NETWORKSTATE_NOTLOGGED;

gesetzt. Der Einlog-Versuch erfolgt dann nicht unmittelbar, sondern erst beim Durchlaufen einer entsprechenden Abfrage in der Loop-Schleife. Damit ich die Anwendung durch ständig wiederholte Einlog-Versuch nicht lahmlegte, integrierte ich einen weiteren kleinen Zähler. Zwischen zwei Einlog-Versuchen gibt es nun immer etwas „Leerlauf“ von rund zwei Sekunden. Der asynchrone Aufruf der Funktion LoginRouterNetworkAndSetRGB() hat nun übrigens den Vorteil, dass nach dem Abschicken des Konfigurationsformulars zum ESP32-Webserver nicht gleich ein Einlog-Versuch unternommen wird, und die neue Webseite schneller ausgeliefert wird (Adresse 192.168.4.1, Näheres findet man in den letzten Folgen). Allerdings handeln wir uns damit einen kleinen Schönheitsfehler ein. Die Adresse des ESP32 im Routernetzwerk erhält man erst zurückgemeldet, wenn der Einlogversuch erfolgreich verläuft, die grüne LED dimmt und man danach nochmals den Submit-Button im Formular betätigt.
Anschließend lagerte ich auch das Veröffentlichen der Sensorwerte und den Webserver-Codeteil in eigene Funktionen aus. Das macht die Loop-Schleife übersichtlich und kompakt, wie man im Screenshot sieht.


 
Im Code erkennt man die drei Zähler und das Setzen der zwei Zustandsvariablen MQTTClient_Connected und RouterNetworkDeviceState. Auch die Setup-Funktion ist schlanker geworden (den neuen Sketch gibt es wie immer als Download, siehe unten). Schließlich habe ich noch meine kleine WLAN-Netzwerk-Library in eine Klassenbibliothek umgewandelt – ähnlich wie ich das in der letzten Folge für die TCP/IP- und MQTT-Funktionen gemacht habe. Die Files WiFiNetwork.h/.c sind in einem gleichnamigen Ordner untergebracht, der sich beim Kompilieren im Libraries-Ordner der Arduino-Umgebung befinden muss. Ich habe die seriellen Ausgaben aus den Funktionen herausgezogen und in das Hauptprogramm verlagert. Hierzu habe ich noch die Funktion GetOwnIPAddressInRouterNetwork() erstellt, welche die Adresse des ESP32 im Routernetzwerk zurückgibt. Die Aufrufe der WLAN-Netzwerk-Funktionen erfolgen jetzt in der objektorientierten Schreibweise, zum Beispiel wurde aus
WiFi_SetBothModesNetworkStationAndAccessPoint();
nun
myWiFiNetwork.SetBothModesNetworkStationAndAccessPoint();

Diese Umstellungen fügen dem Projekt keinerlei Funktionalität hinzu und mögen dem einen oder anderen vielleicht etwas dröge erscheinen – wir werden von der zunehmenden Modularität der Software aber noch profitieren, wenn wir andere Plattformen ausprobieren.
 

Kompakt und günstig: ESP32 Pico Kit

Die neue Software können Sie – falls Sie Besitzer eines ESP32DevKit C sind – gleich ausprobieren. Doch es gibt einen Ersatz, der noch kompakter ausfällt: Das ESP32 Pico Kit, das auch für den gerade laufenden Elektor ESP32-Entwickler-Wettbewerb verwendet wird. Das kleinere Board hat den Vorteil, dass es auf Steckbrettern mehr Platz lässt.



Der Sketch ließ sich 1:1 auf das neue Board laden, ich habe keine Unterschiede feststellen können. Es liegen lediglich die von mir benutzten Pins auf den Stiftleisten an anderer Stelle, was auf einem Steckbrett ja kein Problem darstellt. Die rote Test-LED habe ich statt an Pin 12 nun an Pin 15 angeschlossen (und den Code entsprechend geändert). Und noch eine Änderung gibt es: Nach einem vorübergehenden Abbruch der Stromversorgung muss man den EN-Button drücken, sonst läuft das Programm nicht los.

Im Betrieb erkennt man das regelmäßige Anpingen an einer kurzen Unterbrechung des periodischen Dimmens. Weitere Hinweise finden Sie am Ende der letzten Folge. Ich habe das kleine Gerätchen einen ganzen Tag laufen lassen, zwischendrin auch den Abbruch der WLAN-Verbindung simuliert. Auf meiner AllThingsTalk-Webseite habe ich mir die gesampelten und veröffentlichten Sensorwerte in einem Balkendiagramm anzeigen lassen. Im Screenshot am Anfang des Artikels erkennt man, wie es in meinem „Home Office“ nachmittags langsam dunkel wurde. Als ich gegen 18:00 Uhr das Zimmerlicht eingeschaltet habe, gab es einen kleinen Peak :-).

Weiter geht es in der nächsten Folge!