Moderne Mikrocontroller wie ein ESP32 sind so leistungsfähig, dass sie in MicroPython programmiert werden können - dank der mächtigen Bibliotheken kommt man hier schnell zu einem fertigen Projekt. Mit dem MakePython ESP32 Development Kit - es handelt sich dabei einerseits um ein Lehrbuch und andererseits um ein Hardware-Kit - schickt der bekannte Elektor-Autor Dogan Ibrahim nun ein Starterpaket ins Rennen, das die Arbeit mit MicroPython anhand realer Beispiele illustriert.

Dass MicroPython nicht der Weg zur „maximalen“ Programm- bzw. Software-Effizienz darstellt, muss man nicht wirklich diskutieren. Andererseits gilt, dass moderne Mikrocontroller wie ein ESP32 von der Leistungsfähigkeit her mit einem 486er mehr als mithalten - insbesondere in Kleinserien kann es deshalb vernünftiger sein, durch Nutzung von Hochsprachen einen Tausch von Programmier-Aufwand gegen Geschwindigkeit durchzuführen.
 

Das Buch

Beginnen wir mit dem - in Englisch vorliegenden - Lehrbuch: Interessant ist die (gelungene) Aufmachung, die eine Fake-Spiralbindung vortäuscht.

Der eigentliche didaktische Aufbau beginnt dann mit einer Kurz-Erklärung des ESP32 als Ganzes: Als Elektor-Leser, der mit Mikrocontrollern schon umfangreiche oder zumindest grundlegende Erfahrung mitbringt, bekommen Sie so „schnell“ einen Überblick über die verschiedenen von Espressif im Controller zur Verfügung gestellten Peripheriegeräte. Haben Sie mit Mikrocontrollern noch überhaupt keine Erfahrung, dürften die Ausführungen - zumindest stellenweise - zum bequemen Verständnis zu kurz sein.

Die Installation der IDEs – Ibrahim stellt uPyCraft und Thonny gleichermaßen vor, arbeitet später aber fast nur noch mit Thonny - wird unter Windows detailliert erklärt, Linux kommt nicht so sehr zu Sprache. Danach folgt noch ein Kapitel, das die Ausführung einiger „kleiner“ Python-Snippets unter Nutzung von Thonny illustriert - wer keine Kenntnisse der Python-Syntax mitbringt, kann sich an dieser Stelle nicht wirklich einarbeiten. Andererseits reichen die Ausführungen dicke aus, um die „Grundlagen“ der Arbeit mit MicroPython und der IDE zu verstehen.

Die eigentliche Vorstellung der im Werk enthaltenen 46 Projekte erfolgt dann im klassischen Dogan-Ibrahim-Stil: Im ersten Schritt präsentiert der Professor immer die „zu erledigende Gefechtsaufgabe“, um danach Code und Ausführungen zum Hardware-Aufbau zu präsentieren. Dass die Listings immer einen standardisierten Header mit gut zehn Zeilen Umfang mitbringen, „nervt“ insbesondere Freunde der kompakten Kodierung. Andererseits muss man Ibrahim in diesem Werk zugutekommen lassen, dass die Beispiele zwar nicht kompliziert sind, aber doch die wesentlichen Aspekte der Arbeit mit MicroPython treffend illustrieren.

Die verzweifelte Suche danach, wie man bestimmte Peripheriegeräte in Betrieb nimmt, haben sie nach der Lektüre mit Sicherheit nicht mehr zu befürchten. Sehr lobenswert ist nach Ansicht des Rezensenten, dass Ibrahim erklärt, wie man ein „zerschossenes“ Board mit einer neuen MicroPython-Firmware ausstattet.
 

220429-007-94-original-makepython-esp32-development-kit-sticker-afgesneden.png
Bild 1. Das Kit. Eine Plastikverpackung schützt die Komponenten zuverlässig vor Beschädigung.

Das Board im Blick

Apropos Evaluationsboard: Das Lehrbuch ist im Zusammenspiel mit dem in Bild 1 gezeigten Kit erhältlich, das ob der durchaus robusten Plastikverpackung auch zur „Mitnahme“ in Urlaub oder zur Verhütung der Langeweile bei einer Geschäftsreise taugt.

Doch damit zur eigentlichen Hardware: Die praktische Lehr-Erfahrung des Autors zeigt, dass insbesondere Embedded-fremde Entwickler „leichter“ lernen, wenn die Entwicklungs-Plattform ein (idealerweise vollgrafisches) Display zur Verfügung stellt.

Elektor umgeht dieses Problem insofern geschickt, als es die in Bild 2 gezeigte rote Platine ins Rennen geschickt - der schwarze Bereich ist kein schwarzes Loch, sondern eines der weit verbreiteten SSD1306-OLEDs mit einer Auflösung von 128 mal 64 Pixeln.

An dieser Stelle verbirgt sich der nach Ansicht des Autors größte Kritikpunkt: Die 2,54-mm-Header sind nicht eingelötet. Dies ist insofern schade, als eine Person, die das Kit „direkt“ in einem Store kauft und auf Urlaub mitnimmt, an dieser Stelle gelackmeiert ist – zumindest wenn man keinen Lötkolben zu ihrer Installation zur Hand hat, und der Handyshop nebenan nicht mithilft.

Sonst bietet das Board keinen Anlass zur Kritik: Die verwendete ESP32-Variante ist eines der größeren Modelle und hat ausreichend Speicher, das MicroUSB-Interface sorgt dafür, dass „Kommandogerät-Kabel“ schnell von jedem älteren Handy entlehnt werden können. Außerdem findet sich im Kit auch ein ganz kurzes Kabel brauchbarer Qualität.

Bild 2. Diese Platine ermöglicht das „schnelle Starten“ mit MicroPython.

Eine Demo

Während sich das Lehrbuch vor allem an den Bedürfnissen von unter Windows arbeitenden Entwicklern orientiert, wird der Autor in den folgenden Schritten - schon aus Gründen der Bequemlichkeit - auf Ubuntu 20.04 LTS setzen. Die unter uPyCraft bereitstehende IDE ist dabei eine eher schlechte Wahl, weil ihre Ausführung in allen Ubuntu-Versionen „neuer“ als 16.04 mit einer nach dem Schema

ImportError: /tmp/_MEIOhQKhz/libz.so.1: version `ZLIB_1.2.9' not found (required by /usr/lib/x86_64-linux-gnu/libpng16.so.16)

aufgebauten Fehlermeldung scheitert.

„Schöner“ ist Thonny, das sich durch Eingabe von

bash <(wget -O - https://thonny.org/installer-for-linux) 

automatisiert installieren lässt - der Start erfolgt danach durch die Eingabe des Kommandos

/home/tamhan/apps/thonny/bin/thonny

für die Deinstallation greifen wir auf

/home/tamhan/apps/thonny/bin/uninstall

zurück. Im Rahmen des ersten Starts ist dann „nur“ noch ein Sprachauswahl-Assistent abzunicken. 

Im nächsten Schritt bietet es sich auch schon an, das Evaluationsboard mit einer Workstation zu verbinden. An dieser Stelle denkt Elektor mit, und liefert das Board mit einer vorkonfigurierten MicroPython-Runtime aus. Besonders empfehlenswert ist in diesem Zusammenhang, dass die Platine auch gleich das Display einschaltet, was eine „Funktionskontrolle“ erleichtert. Als Konverter kommt dabei übrigens ein Chip vom Typ Silicon Labs CP210x UART-Bridge zum Einsatz.  

An dieser Stelle können Sie in Thonny (Bild 3) wechseln und müssen darauf achten, im unten rechts eingeblendeten Auswahl-Menü die Python-Version anzuklicken und sich danach für die Version MicroPython (ESP32) entscheiden. Thonny geht daraufhin automatisiert auf die Suche nach ESP32-Boards; im Fall der hier verwendeten Platine wurde das Board automatisch erkannt. 

Über die Frage, ob Sie Thonny mit Superuser-Rechten ausführen müssen, lässt sich diskutieren - da das Benutzerkonto des Autors Mitglied der plugdev-Gruppe ist, konnte er Thonny auch in seinem normalen User-Account ausführen und trotzdem mit dem ESP32 interagieren. 

Bild 3. Screenshot von Thonny.

Ein erster Willkommensgruß!

ls nächste Amtshandlung wollen wir dazu übergehen, das OLED-Display des Geräts in Betrieb zu nehmen. Hierzu öffnen wir die URL, und laden das Archiv MakePython ESP32 Lessons Source Code herunter - die Nutzung von rar ist unter Linux ein wenig ärgerlich. 

Extrahieren Sie das Archiv jedenfalls in einen bequem zugänglichen Ort. Wir benötigen für die folgenden Schritte vor allem die Datei ssd1306.py, die den OLED-Treibercode zur Verfügung stellt. 

Klicken Sie im ersten Schritt auf File -> Open, und entscheiden Sie sich danach für die Option This Computer. Im nächsten Schritt navigieren Sie zur Datei, um sie im Editor zu laden. 

Sodann entscheiden wir uns für File -> Save as, und dann für die Option MicroPython Board. 

Sofern Thonny sich an dieser Stelle über das „Beschäftigtsein“ des Backends aufregt, können Sie in der Toolbar auf das rote Stopp-Symbol klicken, um einen Halt zu befehligen. Im nächsten Schritt speichern Sie die Datei unter dem bekannten Namen ins Dateisystem - zumindest dann, wenn Sie nicht die Original-Firmware „unverändert“ belassen haben. In diesem Fall ist die Datei nämlich schon am Platz. 

Als erste Amtshandlung importieren wir - unter MicroPython ist dies üblich - einige Bibliotheken, und legen auch Konstanten mit zusätzlichen Informationen über die Topologie des Displays fest: 

import machine
import ssd1306
import time
WIDTH = const(128)
HEIGHT = const(64)

Für die eigentliche Kommunikation mit dem per I2C angeschlossenen Display - dies ist unüblich, meist trifft man hier auf SPI - setzen wir dann auf eine Instanz der Software-I2C-Klasse: 

pscl = machine.Pin(5, machine.Pin.OUT)
psda = machine.Pin(4, machine.Pin.OUT)
i2c = machine.I2C(scl=pscl, sda=psda)
oled = ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c)

Zu guter Letzt müssen wir dann nur noch nach folgendem Schema einen Text in Richtung des Displays schreiben: 

while True:
    oled.fill(0)
    oled.text('Hello World!',10,0)
    oled.show()
    time.sleep(1)

An dieser Stelle können Sie in der IDE auch schon auf das Play-Symbol klicken, um sich am Aufscheinen des Texts auf dem Display des Evaluationsboards zu erfreuen. 
 

Einrichtung von MQTT

Als nächste Aufgabe wollen wir ein wenig über den „gewöhnlichen“ im Kit enthaltenen Projekt-Schatz hinausgehen, und eine fortgeschrittene Aufgabe realisieren - dies zeigt unter anderem auch, dass das Kit für höhere Aufgaben geeignet ist. Spezifischerweise wollen wir das universell bekannte MQTT-Protokoll verwenden. Besonders interessant wird die Aufgabe dadurch, dass wir hier mit einer brandaktuellen Version des MQTT-Brokers Mosquitto arbeiten wollen - unter der URL findet sich eine (lesenswerte) Beschreibung der „Probleme“, die die aus Sicherheitsgründen immer strikter eingestellten Parser im Zusammenspiel mit den MicroPython-Treibern bekommen.. 

Apropos MikroPython-Treiber: Es gibt für MicroPython mittlerweile sogar zwei konkurrierende Implementierungen von MQTT. Wir wollen hier allerdings auf die unter Github -  stehende einfachere Variante setzen - laden Sie die Datei https://github.com/micropython/micropython-lib/blob/master/micropython/umqtt.simple/umqtt/simple.py herunter, und speichern diese danach unter dem Namen simple.py auf dem Prozessrechner. 

Im nächsten Schritt müssen wir nach folgendem Schema die WLAN-Transmitter des Boards in den Station-Modus versetzen:

. . .
wlan=network.WLAN(network.STA_IF)

Für den eigentlichen Verbindungsaufbau setzen wir dann auf eine nach dem folgenden Schema aufgebaute Methode - sie stammt im Großen und Ganzen aus dem von MakerFabs zur Verfügung gestellten Projektskelett, und realisiert einen Countdown-Timer samt Verbindungsaufbau. Achten Sie natürlich darauf, die an wlan.connect übergebenen Strings an ihre Drahtlosnetzwerk-Situation anzupassen:

def connectWiFi():
  i=0
  wlan.active(True)
  wlan.disconnect()
  wlan.connect("ssid","pass")
  while(wlan.ifconfig()[0]=='0.0.0.0'):
    i=i+1
    oled.fill(0)
    oled.text('connecting WiFi',0,16)
    oled.text('Countdown:'+str(20-i)+'s',0,48)
    oled.show()
    time.sleep(1)
    if(i>20):
      break
  oled.fill(0)
  oled.text('Makerfabs',25,0)
  oled.text('MakePython ESP32',0,32)
  if(i<20):
    oled.text('WIFI connected',0,16)
  else:
    oled.text('NOT connected!',0,16)
  oled.show()
  time.sleep(3)
  return True

Der eigentliche Test-Verbindungsaufbau könnte dann einfacher nicht sein:

connectWiFi()
while True:
    time.sleep(1)

Im nächsten Schritt wollen wir uns einen Mosquitto-Server zur Verfügung stellen: Mosquitto ist zwar nicht der „schnellste“ MQTT-Broker, ist aber quelloffen, kostenlos und im Bereich der MQTT-Implementierung sehr streng. 

Ob seiner hohen Verbreitung ist außerdem sichergestellt, dass es im Docker-Hub ein mehr oder weniger schlüsselfertiges Image gibt, dass die Bereitstellung des Servers ohne tiefergehende Konfigurationen des Host-Computers ermöglicht. 

Für einen ersten Anlauf reicht es aus, folgenden Befehl einzugeben: 

docker run -it -p 1883:1883 -p 9001:9001 -v mosquitto.conf:/mosquitto/config/mosquitto.conf eclipse-mosquitto

Wichtig sind hier erstens die Parameter -p 1883:1883 und -p 9001:9001 - jeder Docker-Container wird von der Runtime ja mit einem „vollen“ Komplement an TCP/IP-Ports ausgestattet. Jeder der Parameter verbindet dann einen dieser Ports mit der Netzwerkkarte des Host-Computers. Über den Parameter -v mosquitto.conf:/mosquitto/config/mosquitto.conf  „integrieren“ wir außerdem eine Konfigurationsdatei.

An dieser Stelle bietet es sich an, bei bestehender Internetverbindung einen ersten Download-Versuch durchzuführen. Docker wird normalerweise Verbindung zum Hub aufnehmen und die benötigten Komponenten herunterladen, um danach mit der folgenden Fehlermeldung zu verenden:

docker: Error response from daemon: source /var/lib/docker/aufs/mnt/a22b9e557c37d99eb71f17e7bc6d38df6e7677d09225376d416612adf0977ccd/mosquitto/config/mosquitto.conf is not directory

Ursache des Fehlers ist, dass es in der Host-Workstation noch keine Datei mit dem Namen mosquitto.conf gibt, die wir dem Container zur Verfügung stellen könnten.

Zur Lösung reicht es aus, auf der Kommandozeile im Arbeitsverzeichnis mit gedit ein neues File anzulegen:

(base) tamhan@tamhan-thinkpad:~$ gedit mosquitto.conf

Der Umstieg von Mosquitto Version 1 auf Mosquitto Version 2 ging mit „massiven“ Verschärfungen im Bereich der Sicherheits-Konfiguration einher. Während ein „mit Default-Parameter“ gestarteter Mosquitto 1.X-Serveranfragen von beliebigen Clients entgegennahm, verweigert Mosquitto 2 dies. Wenn Sie allerdings die folgenden Passagen in der Konfigurationsdatei platzieren, funktioniert alles wieder wie gewohnt (und unsicher): 

listener 1883
allow_anonymous true

Die eigentliche Ausführung lässt sich dann nach folgendem Schema befehligen - beachten Sie, dass der Parameter -v immer einen voll qualifizierten Pfad verlangt, weshalb wir das Kommando pwd aufrufen und die Ergebnisse durch Shell-Magie „verwursteln“. pwdsteht dabei übrigens für Print Working Directory, Bild 4 zeigt das Verhalten:

(base) tamhan@tamhan-thinkpad:~$ docker run -it -p 1883:1883 -p 9001:9001 -v $(pwd)/mosquitto.conf:/mosquitto/config/mosquitto.conf eclipse-mosquitto
. . .

Sofern der Docker-Container seinen erfolgreichen Start durch Rückgabe von 1658673183: mosquitto version 2.0.14 running, quittiert, sind wir an dieser Stelle gefechtsbereit.
 

220429-001-94-original-3.png
Bild 4. Der pwd-Befehl liefert das aktuelle Arbeitsverzeichnis der Shell.

Inbetriebnahme der MQTT-Software am ESP32

Als Erstes benötigen wir auch für die Arbeit mit MQTT einige Konstanten - achten Sie darauf, die im Server-String übergebene IP-Adresse an Ihre lokale Betriebssituation anzupassen:

SERVER = "192.168.178.146"
CLIENT_ID = ubinascii.hexlify(machine.unique_id())
TOPIC = b"led"
state = 0

Außerdem benötigen wir eine Callback-Funktion, die der MQTT-Treiber immer beim Eingehen einer Nachricht aufrufen wird:

def sub_cb(topic, msg):
    global state
    print((topic, msg))
    . . .

Die eigentliche Einrichtung der MQTT-Verbindung ist dann vergleichsweise simpel:

connectWiFi()
c = MQTTClient(CLIENT_ID, SERVER, keepalive=30)
c.set_callback(sub_cb)
c.connect()
c.subscribe(TOPIC)
print("Connected to %s, subscribed to %s topic" % (SERVER, TOPIC))


while True:
    c.wait_msg()

Der Aufruf von c.sorgt dafür, dass der MQTT-Treiber dem Server mitteilt, an welchen Nachrichten-Kanälen aktuell Interesse besteht. Wichtig ist außerdem noch das periodische Aufrufen der Methode c.wait_msg(), um dem MQTT-Server Rechenleistung zur „Abarbeitung“ der eingehenden und der zu sendenden Informationen zur Verfügung zu stellen. In der Kommandozeile bzw. im Ausgabefenster dürfen Sie sich dann an der Ausgabe Connected to 192.168.178.146, subscribed to b'led' topic erfreuen.

Im nächsten Schritt möchten wir noch eine der mitgelieferten Leuchtdioden samt dem beigelegten Widerstand mit dem GPIO-Pin 12 verbinden - der Autor geht davon aus, dass ausreichend Elektronik-Kenntnisse beim Leser verfügbar sind. Die Initialisierung des GPIO-Ports ist dann ebenfalls gewöhnlicher ESP32-Code:

led = Pin(12, Pin.OUT, value=1)

Für die „Verarbeitung“ der eingehenden Nachrichten müssen wir den Callback dann insofern erweitern, als wir den im Wert topic angelieferten String mit den für die verschiedenen Befehle vorgesehenen Konstanten verdrahten:

def sub_cb(topic, msg):
    global state
    print((topic, msg))
    if msg == b"on":
        led.value(1)
        state = 1
    elif msg == b"off":
        led.value(0)
        state = 0
    elif msg == b"toggle":
        led.value(state)

Für das eigentliche Testen wollen wir dann auf die Kommandozeilen-Utility mosquitto_pub setzen: Es handelt sich dabei um ein unter Linux zur Verfügung stehendes Werkzeug, dass das „direkte“ Absetzen von Kommandos in Richtung eines MQTT-Servers erlaubt. Zum Ein- und Ausschalten der LED dienen dann die folgenden Kommandos:

(base) tamhan@tamhan-thinkpad:~$ mosquitto_pub -t led -m 'on'
(base) tamhan@tamhan-thinkpad:~$ mosquitto_pub -t led -m 'off'

Sofern ESP 32 und Server im gleichen Netzwerk sind, können Sie ab sofort die Leuchtdiode ein und ausschalten.
 

Fazit und Ausblick!

Das MakePython ESP32 Development Kit ist ein faszinierend-kompakter Werkzeugkasten, der Python-Entwicklern und/oder Elektronikern schnell die Vereinigung der beiden Welten ermöglicht. Insbesondere weil alles so schön „schlüsselfertig“ verpackt ist, ist dies eine Box, dem der Rezensent gerne eine Empfehlung ausspricht.