M5Stack – ESP32 en grafisch display in een compacte behuizing
De M5Stack-basismodule bevat een ESP32-kaart in een compacte behuizing; bijna de hele bovenkant wordt ingenomen door een kleurendisplay van 320 x 240 pixels met grafische mogelijkheden. Ik was heel benieuwd, hoe snel ik daarmee een kleine netwerktoepassing zou kunnen maken...
Ik heb bij mijn eerdere reviews al heel graag gewerkt met de ESP32-controller om kleine IoT-applicaties te ontwikkelen. De processor is uitgerust met WLAN, Bluetooth en ruim voldoende geheugen en hij is te programmeren met de Arduino-IDE. Bovendien zijn er heel voordelige en breadboard-vriendelijke ontwikkelkaarten verkrijgbaar. Met wat extra componenten (zoals een RGB -LED, een lichtsensor en Dupont-kabeltjes) en de juiste Arduino-library’s kunnen ook beginners snel kleine projecten realiseren, waarmee bijvoorbeeld sensorwaarden naar cloudplatforms kunnen worden gestuurd, om ze daar weer te geven.
Een goede uitbreiding is een klein display, dat statusmeldingen zoals bijvoorbeeld „No network“ kan weergeven. Een voorbeeld daarvan is de Lolin-kaart, die ik in een eerdere review aan de tand gevoeld heb. Een paar weken geleden wees mijn collega Mathias Claußen uit ons lab me op het M5Stack-systeem. De basismodule bevat een ESP32-kaart in een compacte behuizing; bijna de hele bovenkant wordt ingenomen door een kleurendisplay van 320 x 240 pixels met grafische mogelijkheden. Daaronder bevinden zich drie druktoetsen en verder zijn er diverse uitbreidingsconnectors aan alle kanten van de behuizing. Er zijn trouwens ook nog uitbreidingsmodules (bijvoorbeeld voor GPS), die gemakkelijk tussen de onder- en bovenkant van de basismodule kunnen worden ingeklikt, zodat we een eigen „stack“ kunnen samenstellen. Mijn collega Clemens Valens heeft al een review geschreven, waarin hij het M5Stack-systeem voorstelt.
Ik vond op Internet al snel een inleiding die laat zien, hoe we de benodigde bibliotheken in de Arduino-IDE kunnen inbouwen. En daar stond ook een kleine demo. Het bleek dat de ontwikkelaars de functies voor het aansturen van het display (en ook voor het afvragen van de toetsen) in een object met de naam M5 hadden ingekapseld. Na #includen van de library met
kunnen we in onze eigen sketch de methode
aanroepen en dan kunnen we met commando’s zoals
het display aansturen.
Op GitHub is ook een zogenaamde API Reference te vinden. Maar toch vond ik daar niet alles wat ik zocht. Ik moest bijvoorbeeld zelf uitzoeken, welke waarden ik als parameter voor de tekstgrootte (M5.Lcd.setTextSize) moest gebruiken (de waarden 2 tot 5 vind ik bruikbaar).
Uiteindelijk lukte het me toen heel snel om mijn kleine project dat ik voor de Lolin OLED-kaart heb ontwikkeld, naar de M5Stack porteren. In deze toepassing worden de waarden van een lichtsensor gesampeld en naar het cloudplatform OpenSenseMap gestuurd (zie Review). De spanning over de lichtgevoelige weerstand (schema) lees ik in via de uitbreidingsconnector aan de rechterkant van de M5Stack (zie foto).
U kunt mijn eerste M5Stack-app onderaan deze pagina downloaden. Overigens is er in de M5Stack een kleine accu ingebouwd (een extra accu is ook verkrijgbaar). Helaas werkt het geheel zonder externe voeding niet langer dan een uurtje op de geïntegreerde accu.
Het M5Stack-display had precies de juiste afmetingen om kleine tekstberichten op weer te geven. Even dacht ik nog aan de mogelijkheid om een kleine app voor de PC te schrijven, die dan via UDP of TCP /IP met de M5Stack zou kunnen communiceren. Het is veel eenvoudiger en flexibeler om tekstberichten in te voeren via een simpele webbrowser en ze naar het display te sturen. En dat werkt niet alleen vanaf de PC maar ook vanuit een mobiel apparaat.
Een ESP32-webserver had ik al geprogrammeerd voor mijn IoT-blog. Daarmee werd een klein formulier weergegeven om de SSID en het wachtwoord voor het WLAN-netwerk in te stellen. Om de waarden in een browser te kunnen invoeren, moesten we eerst inloggen in een door de ESP32 zelf opgezet „hulp“-netwerk, en dan via het adres 192.168.4.1 de ESP32 aanspreken (de ESP32 in de modus Access Point). Als de inloggegevens voor het LAN bij de ESP32 aangekomen waren, kon die inloggen op het netwerk, en kreeg dan een ander adres (bij mij was dat bijvoorbeeld 192.168.0.38).
Ik ging om mijn toepassing te realiseren aan de slag met mijn bestaande sketch. Ik breidde de webserver uit, zodat hij op zijn tweede adres een nieuwe webpagina presenteerde, met één enkel tekstveld (voor het bericht aan de DJ) en een Submit-button voor het verzenden. Nadat de ESP 32-webserver de tekst van de client-webbrowser had ontvangen, werd het bericht weergegeven op het display van de M5Stack.
Ten tweede vond ik mijn code niet netjes opgebouwd: er waren te veel functies om de beide verschillende webpagina’s samen te stellen en de requests te evalueren. Wat ik wilde was een library, die voor beide webpagina’s te gebruiken was, of er nu acht configuratiewaarden of alleen maar een berichttekst in te voeren waren.
Ten derde was ik er niet blij mee, dat de ESP32 dan weer als Access Point en dan weer als netwerk-client moest werken. Dat is niet alleen een potentieel beveiligingsrisico, maar het vergroot ook het stroomverbruik.
Na wat ontwikkeltijd kwam ik tot de oplossing, die u onderaan deze pagina kunt downloaden.
Tegen het flakkeren van het display gebruik ik een aantal kleine buffergeheugens, om precies te zijn maximaal vier, die we op vrij te kiezen cursor-posities kunnen inzetten. In mijn toepassing geeft de eerste buffer alleen de heartbeat weer (een teken, dat afwisselend 0 en 1 is). Een andere buffer bevat de statustekst (ingelogd of niet), en het adres waar de ESP32 te bereiken is. De derde buffer dient voor de weergave van de berichttekst. In de broncode zijn de functies voor het vullen van de DisplayBuffer-parameters (positie, grootte van de tekst, lengte van de tekst) en voor het schrijven van tekst natuurlijk voorzien van commentaar.
Om de webserver te abstraheren, heb ik om te beginnen een klasse Param geschreven. Die beheert een verzameling van maximaal acht parameters, die een naam, een waarde en een type hebben. Met de regels
instantieer ik in de toepassingssketch twee objecten van deze klasse. Het eerste object neemt de ontvangen berichttekst op (Messages.PValue[0]). Het tweede object dient voor het beheer van de instellingen (NetworkConfig.PValue[0] is de SSID, NetworkConfig.PValue[1] is het wachtwoord). Via zo’n object kunnen we in één keer een verzameling van strings doorgeven aan andere library’s. Bovendien kunnen we functies schrijven, die een Param-object (dus meerdere strings tegelijk) teruggeven als resultaat.
Mijn nieuwe webserver-library maakt daar gebruik van. De regels
maken de webserver-functies toegankelijk via het object myWebserver. De regel
pakt de GET -parameters uit, die binnenkomen als de gebruiker een webformulier heeft ingevuld (in de adresregel van de browser achter het „?“). De verkregen waarden worden dan in het object NetworkConfig geschreven en zijn toegankelijk met NetworkConfig.PValue[x]. Omgekeerd kunnen we met myWebserver.SerializeToHTMLInputTable(NetworkConfig) een HTML-tabel vullen met de benodigde invoervelden.
Als we de instellingen willen veranderen, dan moeten we de linker en de middelste druktoets van de M5Stack tegelijk indrukken (kijk maar eens in de broncode, hoe de druktoetsen worden afgevraagd). Dan verschijnt het adres 192.168.4.1, dat de ESP32 heeft in zijn zelf opgespannen netwerk. Als u (bijvoorbeeld met een smartphone) inlogt in dit netwerk, kunt u via dit adres de configuratiewebpagina oproepen. Bij dit project hoeft u alleen de SSID en het wachtwoord in te voeren. Na het verzenden van deze gegevens, probeert de ESP32 in te loggen in het WiFi-netwerk (dat duurt even). Als u de beide druktoetsen opnieuw tegelijk indrukt, dan verschijnt na een paar seconden het adres in dit netwerk.
U kunt de druktoetsen alleen gebruiken, als de heartbeat-weergave actief is; als die stilstaat, dan is de ESP32 bezig met andere taken. Zoiets is voor de gebruiker natuurlijk niet optimaal, we gaan in een van de volgende reviews kijken, hoe we dat kunnen oplossen!
Een goede uitbreiding is een klein display, dat statusmeldingen zoals bijvoorbeeld „No network“ kan weergeven. Een voorbeeld daarvan is de Lolin-kaart, die ik in een eerdere review aan de tand gevoeld heb. Een paar weken geleden wees mijn collega Mathias Claußen uit ons lab me op het M5Stack-systeem. De basismodule bevat een ESP32-kaart in een compacte behuizing; bijna de hele bovenkant wordt ingenomen door een kleurendisplay van 320 x 240 pixels met grafische mogelijkheden. Daaronder bevinden zich drie druktoetsen en verder zijn er diverse uitbreidingsconnectors aan alle kanten van de behuizing. Er zijn trouwens ook nog uitbreidingsmodules (bijvoorbeeld voor GPS), die gemakkelijk tussen de onder- en bovenkant van de basismodule kunnen worden ingeklikt, zodat we een eigen „stack“ kunnen samenstellen. Mijn collega Clemens Valens heeft al een review geschreven, waarin hij het M5Stack-systeem voorstelt.
Hoe stuur ik het display aan?
Bij mijn reviews ontwikkel ik graag een kleine applicatie, maar daar is altijd weinig tijd voor. Daarom begon ik met iets eenvoudigs: hoe snel zou het me lukken om een kleine sketch te maken, die een tekst op het display schrijft? De netwerkfuncties kon ik natuurlijk heel gemakkelijk uit mijn bestaande projecten overnemen, want de ESP32 is ook hier te programmeren met de Arduino-IDE.Ik vond op Internet al snel een inleiding die laat zien, hoe we de benodigde bibliotheken in de Arduino-IDE kunnen inbouwen. En daar stond ook een kleine demo. Het bleek dat de ontwikkelaars de functies voor het aansturen van het display (en ook voor het afvragen van de toetsen) in een object met de naam M5 hadden ingekapseld. Na #includen van de library met
#include <M5Stack.h>
kunnen we in onze eigen sketch de methode
M5.begin();
aanroepen en dan kunnen we met commando’s zoals
M5.Lcd.setCursor(x, y);
M5.Lcd.setTextSize(2);
M5.Lcd.print(“Hello World!”);
M5.Lcd.setTextSize(2);
M5.Lcd.print(“Hello World!”);
het display aansturen.
Op GitHub is ook een zogenaamde API Reference te vinden. Maar toch vond ik daar niet alles wat ik zocht. Ik moest bijvoorbeeld zelf uitzoeken, welke waarden ik als parameter voor de tekstgrootte (M5.Lcd.setTextSize) moest gebruiken (de waarden 2 tot 5 vind ik bruikbaar).
Uiteindelijk lukte het me toen heel snel om mijn kleine project dat ik voor de Lolin OLED-kaart heb ontwikkeld, naar de M5Stack porteren. In deze toepassing worden de waarden van een lichtsensor gesampeld en naar het cloudplatform OpenSenseMap gestuurd (zie Review). De spanning over de lichtgevoelige weerstand (schema) lees ik in via de uitbreidingsconnector aan de rechterkant van de M5Stack (zie foto).
U kunt mijn eerste M5Stack-app onderaan deze pagina downloaden. Overigens is er in de M5Stack een kleine accu ingebouwd (een extra accu is ook verkrijgbaar). Helaas werkt het geheel zonder externe voeding niet langer dan een uurtje op de geïntegreerde accu.
Berichten via een webserver
Met dit quick-and-dirty-porteren van een oud project had ik nog niet echt kunnen profiteren van het display en de compacte en gesloten behuizing. Gelukkig schoot me net een nieuw idee voor een toepassing te binnen. Ik heb thuis een kleine DJ-opstelling; waar soms vrienden en kennissen aan de decks staan. En dan nemen we het geheel op met verschillende camera’s. Soms wilde ik dan vanaf mijn regietafel iets aan de DJ daarboven melden, zonder dat ik met mijn armen zou hoeven zwaaien om de aandacht te trekken.Het M5Stack-display had precies de juiste afmetingen om kleine tekstberichten op weer te geven. Even dacht ik nog aan de mogelijkheid om een kleine app voor de PC te schrijven, die dan via UDP of TCP /IP met de M5Stack zou kunnen communiceren. Het is veel eenvoudiger en flexibeler om tekstberichten in te voeren via een simpele webbrowser en ze naar het display te sturen. En dat werkt niet alleen vanaf de PC maar ook vanuit een mobiel apparaat.
Een ESP32-webserver had ik al geprogrammeerd voor mijn IoT-blog. Daarmee werd een klein formulier weergegeven om de SSID en het wachtwoord voor het WLAN-netwerk in te stellen. Om de waarden in een browser te kunnen invoeren, moesten we eerst inloggen in een door de ESP32 zelf opgezet „hulp“-netwerk, en dan via het adres 192.168.4.1 de ESP32 aanspreken (de ESP32 in de modus Access Point). Als de inloggegevens voor het LAN bij de ESP32 aangekomen waren, kon die inloggen op het netwerk, en kreeg dan een ander adres (bij mij was dat bijvoorbeeld 192.168.0.38).
Ik ging om mijn toepassing te realiseren aan de slag met mijn bestaande sketch. Ik breidde de webserver uit, zodat hij op zijn tweede adres een nieuwe webpagina presenteerde, met één enkel tekstveld (voor het bericht aan de DJ) en een Submit-button voor het verzenden. Nadat de ESP 32-webserver de tekst van de client-webbrowser had ontvangen, werd het bericht weergegeven op het display van de M5Stack.
WiFiWebserver- en& DisplayBuffer-library
Toch waren er bij mijn eerste prototype nog drie dingen die me niet bevielen. Ten eerste flakkerde de weergave op het display. Er is in de M5Stack-API trouwens geen apart commando voor het wissen van het display. Om tekst te wissen, moeten we een reeks spaties sturen, en dan de nieuwe tekst er overheen schrijven.Ten tweede vond ik mijn code niet netjes opgebouwd: er waren te veel functies om de beide verschillende webpagina’s samen te stellen en de requests te evalueren. Wat ik wilde was een library, die voor beide webpagina’s te gebruiken was, of er nu acht configuratiewaarden of alleen maar een berichttekst in te voeren waren.
Ten derde was ik er niet blij mee, dat de ESP32 dan weer als Access Point en dan weer als netwerk-client moest werken. Dat is niet alleen een potentieel beveiligingsrisico, maar het vergroot ook het stroomverbruik.
Na wat ontwikkeltijd kwam ik tot de oplossing, die u onderaan deze pagina kunt downloaden.
Tegen het flakkeren van het display gebruik ik een aantal kleine buffergeheugens, om precies te zijn maximaal vier, die we op vrij te kiezen cursor-posities kunnen inzetten. In mijn toepassing geeft de eerste buffer alleen de heartbeat weer (een teken, dat afwisselend 0 en 1 is). Een andere buffer bevat de statustekst (ingelogd of niet), en het adres waar de ESP32 te bereiken is. De derde buffer dient voor de weergave van de berichttekst. In de broncode zijn de functies voor het vullen van de DisplayBuffer-parameters (positie, grootte van de tekst, lengte van de tekst) en voor het schrijven van tekst natuurlijk voorzien van commentaar.
Om de webserver te abstraheren, heb ik om te beginnen een klasse Param geschreven. Die beheert een verzameling van maximaal acht parameters, die een naam, een waarde en een type hebben. Met de regels
Param Messages = Param();
Param NetworkConfig = Param();
Param NetworkConfig = Param();
instantieer ik in de toepassingssketch twee objecten van deze klasse. Het eerste object neemt de ontvangen berichttekst op (Messages.PValue[0]). Het tweede object dient voor het beheer van de instellingen (NetworkConfig.PValue[0] is de SSID, NetworkConfig.PValue[1] is het wachtwoord). Via zo’n object kunnen we in één keer een verzameling van strings doorgeven aan andere library’s. Bovendien kunnen we functies schrijven, die een Param-object (dus meerdere strings tegelijk) teruggeven als resultaat.
Mijn nieuwe webserver-library maakt daar gebruik van. De regels
#include <WiFiWebserver.h>
WiFiWebserver myWebserver = WiFiWebserver();
WiFiWebserver myWebserver = WiFiWebserver();
maken de webserver-functies toegankelijk via het object myWebserver. De regel
NetworkConfig = myWebserver.DeSerializeFromGETParameter(GETParameter, NetworkConfig);
pakt de GET -parameters uit, die binnenkomen als de gebruiker een webformulier heeft ingevuld (in de adresregel van de browser achter het „?“). De verkregen waarden worden dan in het object NetworkConfig geschreven en zijn toegankelijk met NetworkConfig.PValue[x]. Omgekeerd kunnen we met myWebserver.SerializeToHTMLInputTable(NetworkConfig) een HTML-tabel vullen met de benodigde invoervelden.
Druktoetsen
Toen bleef alleen nog het derde probleem over: de ESP32 moet liefst niet de hele tijd zijn eigen netwerk opzetten als Access-Point. Bij mijn nieuwe toepassing gaat de ESP32 aan het begin van het programma in client-modus en probeert zich aan te melden bij het WiFi-netwerk. Als dat lukt, verschijnt het adres in dit netwerk en de tekst „Network“; de webserver wacht dan op een request van een webbrowser.Als we de instellingen willen veranderen, dan moeten we de linker en de middelste druktoets van de M5Stack tegelijk indrukken (kijk maar eens in de broncode, hoe de druktoetsen worden afgevraagd). Dan verschijnt het adres 192.168.4.1, dat de ESP32 heeft in zijn zelf opgespannen netwerk. Als u (bijvoorbeeld met een smartphone) inlogt in dit netwerk, kunt u via dit adres de configuratiewebpagina oproepen. Bij dit project hoeft u alleen de SSID en het wachtwoord in te voeren. Na het verzenden van deze gegevens, probeert de ESP32 in te loggen in het WiFi-netwerk (dat duurt even). Als u de beide druktoetsen opnieuw tegelijk indrukt, dan verschijnt na een paar seconden het adres in dit netwerk.
U kunt de druktoetsen alleen gebruiken, als de heartbeat-weergave actief is; als die stilstaat, dan is de ESP32 bezig met andere taken. Zoiets is voor de gebruiker natuurlijk niet optimaal, we gaan in een van de volgende reviews kijken, hoe we dat kunnen oplossen!