M5Stack – ESP32 und Grafikdisplay im kompakten Gehäuse
Das M5Stack-Basismodul integriert ein ESP32-Board in ein kompaktes Gehäuse; fast die gesamte Oberseite wird von einem grafikfähigen Farbdisplay mit 320 x 240 Pixeln eingenommen. Ich war gespannt, wie schnell ich damit zu einer kleinen Netzwerk-Anwendung gelangen konnte...
Für meine letzten Reviews habe ich bereits sehr gerne mit dem ESP32-Controller gearbeitet, um kleine IoT-Applikationen zu entwickeln. Der Prozessor ist mit WLAN, Bluetooth und reichlich Speicher ausgestattet und per Arduino-IDE programmierbar. Darüber hinaus gibt es sehr günstige und steckbrettfreundliche Entwicklungsboards. Mit ein paar zusätzlichen Bauteilen (wie RGB-LED, Fotosensor und Steckbrücken) sowie den entsprechenden Arduino-Librarys gelangen auch Einsteiger schnell zu kleineren Projekten, bei denen etwa Sensorwerte zu Cloud-Plattformen geschickt und dort angezeigt werden.
Eine gute Ergänzung ist ein kleines Display, das Statusmeldungen wie zum Beispiel „No Network“ anzeigen kann. So zum Beispiel beim Lolin Board, das ich mir in einem früheren Review angesehen habe. Vor ein paar Wochen machte mich mein Kollege Mathias Claußen aus unserem Labor auf das M5Stack-System aufmerksam. Das Basismodul integriert ein kleines ESP32-Board in ein formschönes, kompaktes Gehäuse; fast die gesamte Oberseite wird von einem grafikfähigen Farbdisplay mit 320 x 240 Pixeln eingenommen. Darunter befinden sich drei taktile Taster; darüber hinaus gibt es diverse Erweiterungssteckverbinder auf allen Seiten des Gehäuses. Es existieren außerdem Zusatzmodule (zum Beispiel für GPS), die einfach zwischen Ober- und Unterseite des Basismoduls eingeklickt werden können, so dass man sich seinen persönlichen „Stapel“ zusammenstellen kann. Mein Kollege Clemens Valens hat bereits ein Review verfasst, in dem er das M5Stack-System vorstellt.
Ich stieß im Netz sehr schnell auf eine Anleitung, die zeigt, wie man die nötigen Bibliotheken in die Arduino-IDE einbindet. Hier war auch eine kleine Demo zu finden. Es stellte sich schnell heraus, dass die Entwickler die Funktionen zum Ansteuern des Displays (und auch zum Abfragen der Taster) in einem Objekt namens M5 gekapselt hatten. Nach Einbinden der Lib mit
ruft man im eigenen Sketch die Methode
auf und kann dann über Befehle wie
das Display ansteuern.
Auf GitHub steht auch eine sogenannte API Reference zur Verfügung. Ich habe dort allerdings nicht alles gefunden, was ich gesucht habe. Zum Beispiel musste ich eigene Versuche machen, um herauszufinden, welche Werte ich als Parameter für die Schriftgröße (M5.Lcd.setTextSize) verwenden kann (die Werte 2 bis 5 finde ich sinnvoll).
Schließlich konnte ich dann aber sehr schnell mein kleines Projekt, das ich für das Lolin OLED-Board entwickelt hatte, auf den M5Stack portieren. In dieser Anwendung werden die Werte eines Fotosensors gesampelt und zur Cloud-Plattform OpenSenseMap geschickt (siehe Review). Die Spannung über dem Fotowiderstand (Schaltung) lese ich am Erweiterungssteckverbinder auf der rechten Seite des M5Stacks ein (siehe Foto).
Meine erste M5Stack-App können Sie unten downloaden. Übrigens ist im M5Stack ein kleiner Akku eingebaut (ein Extra-Akku ist ebenfalls erhältlich). Mit dem integrierten Akku läuft das Ganze leider nur etwa ein Stündchen ohne externe Stromversorgung.
Das M5Stack-Display hatte genau die richtige Größe, um auf der Bühne kleine Textnachrichten anzuzeigen. Schnell verworfen habe ich die Idee, eine kleine App für den PC zu schreiben, die mit dem M5Stack über UDP oder rudimentäres TCP/IP kommuniziert. Einfacher und flexibler ist es, Textnachrichten über einen simplen Webbrowser einzugeben und zum Display zu schicken – das geht ja dann vom PC aus genauso wie von einem Mobilgerät.
Einen ESP32-Webserver hatte ich ja schon für meinen IoT-Blog programmiert; damit wurde ein kleines Formular ausgeliefert, über das man die SSID und das Passwort für das eigene WLAN-Netzwerk einstellen konnte. Um die Werte in einem Browser eingeben zu können, musste man sich zuerst in ein vom ESP32 selbst aufgespanntes „Hilfs“-Netzwerk einloggen, und dann über die Adresse 192.168.4.1 an den ESP32 wenden (ESP32 im Modus Access Point). Nachdem die Login-Daten für das Routernetzwerk beim ESP32 angekommen waren, konnte sich dieser einloggen, und bekam dann eine andere Adresse (bei mir war das zum Beispiel 192.168.0.38).
Um meine Anwendung zu realisieren, nahm ich einen meiner bisherigen Sketche als Grundlage. Ich erweiterte den Webserver so, dass er nach einem Aufruf unter dieser zweiten Adresse eine neue kleine Webseite auslieferte, mit einem einzigen Textfeld (für die Nachricht an den DJ) sowie einen Submit-Button zum Abschicken. Nachdem der ESP32-Webserver den Text vom Client-Webbrowser empfangen hatte, wurde die Nachricht auf dem M5Stack-Display dargestellt.
Zweitens fand ich meinen Code nicht schön, es waren zu viele eigene Funktionen damit beschäftigt, die beiden verschiedenen Webseiten zusammenzustellen und die Requests auszuwerten. Hier sollte eine Library her, die für beide Webseiten brauchbar war – egal ob bis zu acht Konfigurationswerte oder nur ein kleiner Nachrichtentext einzugeben waren.
Drittens wollte ich davon weg, den ESP32 die ganze Zeit sowohl im Access-Point- als auch im Station-Modus zu betreiben. Das war nicht nur potentiell unsicher, sondern erhöhte auch den Stromverbrauch.
Nach etwas Entwicklungszeit kam ich auf die Lösung, die Sie unten downloaden können.
Gegen das Flackern des Displays verwende ich einen kleinen Zeichen-Puffer ein – genau genommen sind es bis zu vier, die man wahlfrei an verschiedenen Cursor-Positionen einsetzen kann. In meiner Anwendung ist der erste Buffer nur für die Heartbeat-Anzeige (ein Zeichen, das zwischen 0 und 1 wechselt) zuständig. Ein weiterer Puffer nimmt den Statustext auf (eingeloggt oder nicht), darüber hinaus wird hier die Adresse angezeigt, unter der der ESP32 zu erreichen ist. Der dritte Buffer ist für die Anzeige des Nachrichtentexts verantwortlich. Im Quellcode sind die Funktionen zum Setzen der DisplayBuffer-Parameter (Position, Schriftgröße, Länge des Textes) und zum Schreiben von Text natürlich dokumentiert.
Um den Webserver zu abstrahieren, habe ich zuerst eine kleine Klasse Param geschrieben – sie verwaltet einen Satz von bis zu acht Parametern, die einen Namen, einen Wert und einen Typ haben. Mit den Zeilen
„ziehe“ ich mir im Anwendungssketch zwei Objekte dieser Klasse. Das erste Objekt nimmt den empfangenen Nachrichtentext auf (Messages.PValue[0]). Das zweite Objekt dient zur Verwaltung der Einstellungen (NetworkConfig.PValue[0] ist die SSID, NetworkConfig.PValue[1] ist das Passwort). Über ein solches Objekt können wir an andere Librarys gleichzeitig einen Satz von Strings übergeben. Darüber hinaus können wir Funktionen schreiben, die ein Param-Objekt (also mehrere Strings gleichzeitig) zurückgeben.
Meine neue Webserver-Library macht davon Gebrauch. Die Zeilen
machen die Webserver-Funktionen über das Objekt myWebserver zugänglich. Die Zeile
nimmt den GET-Parameter auseinander, der bei einem übermittelten Webformular die vom Nutzer eingetragenen Werte codiert (in der Browseraddresszeile hinter dem „?“). Die erhaltenen Werte werden dann in das Objekt NetworkConfig geschrieben und sind mit NetworkConfig.PValue[x] zugänglich. Umgekehrt kann man mit myWebserver.SerializeToHTMLInputTable(NetworkConfig) eine HTML-Tabelle mit den nötigen Eingabefeldern erhalten, in die der User die Werte von NetworkConfig (SSID, Passwort) eingeben kann.
Eine gute Ergänzung ist ein kleines Display, das Statusmeldungen wie zum Beispiel „No Network“ anzeigen kann. So zum Beispiel beim Lolin Board, das ich mir in einem früheren Review angesehen habe. Vor ein paar Wochen machte mich mein Kollege Mathias Claußen aus unserem Labor auf das M5Stack-System aufmerksam. Das Basismodul integriert ein kleines ESP32-Board in ein formschönes, kompaktes Gehäuse; fast die gesamte Oberseite wird von einem grafikfähigen Farbdisplay mit 320 x 240 Pixeln eingenommen. Darunter befinden sich drei taktile Taster; darüber hinaus gibt es diverse Erweiterungssteckverbinder auf allen Seiten des Gehäuses. Es existieren außerdem Zusatzmodule (zum Beispiel für GPS), die einfach zwischen Ober- und Unterseite des Basismoduls eingeklickt werden können, so dass man sich seinen persönlichen „Stapel“ zusammenstellen kann. Mein Kollege Clemens Valens hat bereits ein Review verfasst, in dem er das M5Stack-System vorstellt.
Wie steuere ich das Display an?
Bei meinen Reviews entwickle ich ja gerne eine kleine Applikation, aber die Zeit dafür ist immer knapp. Daher stellte sich für mich als Erstes die Frage, wie schnell ich zu einem kleinen Sketch kommen würde, der einen Text auf das Display schreibt. Die Netzwerkfunktionen konnte ich ja ganz einfach aus meinen bisherigen Projekten übernehmen – denn der ESP32 ist auch hier per Arduino-IDE programmierbar.Ich stieß im Netz sehr schnell auf eine Anleitung, die zeigt, wie man die nötigen Bibliotheken in die Arduino-IDE einbindet. Hier war auch eine kleine Demo zu finden. Es stellte sich schnell heraus, dass die Entwickler die Funktionen zum Ansteuern des Displays (und auch zum Abfragen der Taster) in einem Objekt namens M5 gekapselt hatten. Nach Einbinden der Lib mit
#include <M5Stack.h>
ruft man im eigenen Sketch die Methode
M5.begin();
auf und kann dann über Befehle wie
M5.Lcd.setCursor(x, y);
M5.Lcd.setTextSize(2);
M5.Lcd.print(“Hello World!”);
M5.Lcd.setTextSize(2);
M5.Lcd.print(“Hello World!”);
das Display ansteuern.
Auf GitHub steht auch eine sogenannte API Reference zur Verfügung. Ich habe dort allerdings nicht alles gefunden, was ich gesucht habe. Zum Beispiel musste ich eigene Versuche machen, um herauszufinden, welche Werte ich als Parameter für die Schriftgröße (M5.Lcd.setTextSize) verwenden kann (die Werte 2 bis 5 finde ich sinnvoll).
Schließlich konnte ich dann aber sehr schnell mein kleines Projekt, das ich für das Lolin OLED-Board entwickelt hatte, auf den M5Stack portieren. In dieser Anwendung werden die Werte eines Fotosensors gesampelt und zur Cloud-Plattform OpenSenseMap geschickt (siehe Review). Die Spannung über dem Fotowiderstand (Schaltung) lese ich am Erweiterungssteckverbinder auf der rechten Seite des M5Stacks ein (siehe Foto).
Meine erste M5Stack-App können Sie unten downloaden. Übrigens ist im M5Stack ein kleiner Akku eingebaut (ein Extra-Akku ist ebenfalls erhältlich). Mit dem integrierten Akku läuft das Ganze leider nur etwa ein Stündchen ohne externe Stromversorgung.
Nachrichten über Webserver
Bei dieser Quick-and-Dirty-Portierung eines alten Projekts war das Display und die Kompakt- und Geschlossenheit des Gehäuses aber noch nicht richtig zur Geltung gekommen. Da fügte es sich gut, dass mir eine weitere Anwendungsidee geradewegs zufiel. Ich habe zuhause ja eine kleine DJ-Bühne; von Zeit zu Zeit stehen Freunde und Bekannte dort an den Decks, und wir nehmen das Ganze mit verschiedenen Kameras auf. Mitunter hatte ich mir vom Regieplatz aus eine Möglichkeit gewünscht, dem DJ dort oben etwas zu signalisieren, ohne mit meinen Händen vor ihm herumwedeln zu müssen.Das M5Stack-Display hatte genau die richtige Größe, um auf der Bühne kleine Textnachrichten anzuzeigen. Schnell verworfen habe ich die Idee, eine kleine App für den PC zu schreiben, die mit dem M5Stack über UDP oder rudimentäres TCP/IP kommuniziert. Einfacher und flexibler ist es, Textnachrichten über einen simplen Webbrowser einzugeben und zum Display zu schicken – das geht ja dann vom PC aus genauso wie von einem Mobilgerät.
Einen ESP32-Webserver hatte ich ja schon für meinen IoT-Blog programmiert; damit wurde ein kleines Formular ausgeliefert, über das man die SSID und das Passwort für das eigene WLAN-Netzwerk einstellen konnte. Um die Werte in einem Browser eingeben zu können, musste man sich zuerst in ein vom ESP32 selbst aufgespanntes „Hilfs“-Netzwerk einloggen, und dann über die Adresse 192.168.4.1 an den ESP32 wenden (ESP32 im Modus Access Point). Nachdem die Login-Daten für das Routernetzwerk beim ESP32 angekommen waren, konnte sich dieser einloggen, und bekam dann eine andere Adresse (bei mir war das zum Beispiel 192.168.0.38).
Um meine Anwendung zu realisieren, nahm ich einen meiner bisherigen Sketche als Grundlage. Ich erweiterte den Webserver so, dass er nach einem Aufruf unter dieser zweiten Adresse eine neue kleine Webseite auslieferte, mit einem einzigen Textfeld (für die Nachricht an den DJ) sowie einen Submit-Button zum Abschicken. Nachdem der ESP32-Webserver den Text vom Client-Webbrowser empfangen hatte, wurde die Nachricht auf dem M5Stack-Display dargestellt.
WiFiWebserver- und DisplayBuffer-Library
Allerdings störten mich bei meinem ersten Prototyp noch drei Dinge. Erstens flackerte die Anzeige des Displays. Es gibt in der M5Stack-API übrigens keinen dezidierten Befehl zum Löschen des Displays, man muss, um Text zu löschen, eine Kette von Leerzeichen ausgeben, und dann den neuen Text darüber schreiben.Zweitens fand ich meinen Code nicht schön, es waren zu viele eigene Funktionen damit beschäftigt, die beiden verschiedenen Webseiten zusammenzustellen und die Requests auszuwerten. Hier sollte eine Library her, die für beide Webseiten brauchbar war – egal ob bis zu acht Konfigurationswerte oder nur ein kleiner Nachrichtentext einzugeben waren.
Drittens wollte ich davon weg, den ESP32 die ganze Zeit sowohl im Access-Point- als auch im Station-Modus zu betreiben. Das war nicht nur potentiell unsicher, sondern erhöhte auch den Stromverbrauch.
Nach etwas Entwicklungszeit kam ich auf die Lösung, die Sie unten downloaden können.
Gegen das Flackern des Displays verwende ich einen kleinen Zeichen-Puffer ein – genau genommen sind es bis zu vier, die man wahlfrei an verschiedenen Cursor-Positionen einsetzen kann. In meiner Anwendung ist der erste Buffer nur für die Heartbeat-Anzeige (ein Zeichen, das zwischen 0 und 1 wechselt) zuständig. Ein weiterer Puffer nimmt den Statustext auf (eingeloggt oder nicht), darüber hinaus wird hier die Adresse angezeigt, unter der der ESP32 zu erreichen ist. Der dritte Buffer ist für die Anzeige des Nachrichtentexts verantwortlich. Im Quellcode sind die Funktionen zum Setzen der DisplayBuffer-Parameter (Position, Schriftgröße, Länge des Textes) und zum Schreiben von Text natürlich dokumentiert.
Um den Webserver zu abstrahieren, habe ich zuerst eine kleine Klasse Param geschrieben – sie verwaltet einen Satz von bis zu acht Parametern, die einen Namen, einen Wert und einen Typ haben. Mit den Zeilen
Param Messages = Param();
Param NetworkConfig = Param();
Param NetworkConfig = Param();
„ziehe“ ich mir im Anwendungssketch zwei Objekte dieser Klasse. Das erste Objekt nimmt den empfangenen Nachrichtentext auf (Messages.PValue[0]). Das zweite Objekt dient zur Verwaltung der Einstellungen (NetworkConfig.PValue[0] ist die SSID, NetworkConfig.PValue[1] ist das Passwort). Über ein solches Objekt können wir an andere Librarys gleichzeitig einen Satz von Strings übergeben. Darüber hinaus können wir Funktionen schreiben, die ein Param-Objekt (also mehrere Strings gleichzeitig) zurückgeben.
Meine neue Webserver-Library macht davon Gebrauch. Die Zeilen
#include <WiFiWebserver.h>
WiFiWebserver myWebserver = WiFiWebserver();
WiFiWebserver myWebserver = WiFiWebserver();
machen die Webserver-Funktionen über das Objekt myWebserver zugänglich. Die Zeile
NetworkConfig = myWebserver.DeSerializeFromGETParameter(GETParameter, NetworkConfig);
nimmt den GET-Parameter auseinander, der bei einem übermittelten Webformular die vom Nutzer eingetragenen Werte codiert (in der Browseraddresszeile hinter dem „?“). Die erhaltenen Werte werden dann in das Objekt NetworkConfig geschrieben und sind mit NetworkConfig.PValue[x] zugänglich. Umgekehrt kann man mit myWebserver.SerializeToHTMLInputTable(NetworkConfig) eine HTML-Tabelle mit den nötigen Eingabefeldern erhalten, in die der User die Werte von NetworkConfig (SSID, Passwort) eingeben kann.