Wer bisher mit der Arduino IDE die Firmware für den ESP programmiert hat kennt das. Code schreiben, kompilieren, linken und dann flashen. Wenn man im Programm in Ermangelung eines echten Debuggers Informationen haben wollte, hat man typischerweise Werte mit Serial.println() ausgegeben und sich diese im „Debugger“ Fenster der Arduino IDE angesehen. Deutlich komfortabler (aber im Grunde identisch) geht der mit PlattformIO in Visual Code von Microsoft. Möchte man einen weiteren Wert ansehen, dann muss man wieder den Code ändern und die ganze Prozedur geht von vorne los.
Wer Python bereits kennt, kennt auch die REPL Console von Python. REPL steht für Read – Evaluate – Print – Loop. In einer interaktiven Shell werden Befehle oder auch Blöcke eingegeben und direkt ausgeführt. Dies kann nützlich sein, wenn man kurz etwas testen möchte.
Wie schön wäre es, wenn man eine solche interaktive Shell auf dem Controller hätte. Genau hier kommt die Stärke von micropython zum Einsatz. Hast Du die micropython Firmware auf Deinem Controller geflashed, dann kannst Du in einen Linux Terminal einfach eine interaktive Pythonshell auf deinem Controller starten.
REPL auf dem Controller
Du benötigst ein Programm, dass eine serielle Kommunikation erlaubt. Unter Linux gibt es eine Vielzahl von Optionen. So kannst du screen, minicom oder picocom verwendet. Stelle sicher, das du der Linux Gruppe dialout
angehörst. Sonst hast du nicht die notwendigen Rechte, um mit dem Controller zu kommunizieren.
Nun gebe in einem Linux Terminal folgenden Befehl ein:
$ screen /dev/ttyUSB0 115200
Es kann sein, dass Du einmal Return drücken musst, um den Python Prompt zu sehen.
>>>
Den Port musst Du eventuell anpassen. Die Zahl gibt die Übertragungsgeschwindigkeit in baud an. Höhere Geschwindigkeiten sind möglich, aber auch fehleranfälliger. 115200 ist da ein guter Trade Off.
Und TaDa, Du befindest dich in einer Python Konsole, die Du genauso verwenden kannst, wie eine Python Konsole auf deinem Linux Rechner. Nur mit dem Unterschied, dass der Python Interpreter auf dem Controller läuft. Eingaben werden von Deinem Rechner an den Controller übertragen, dort evaluiert und mögliche Ausgaben wieder über das USB Kabel an Deinen Rechner zurück übertragen und in der Konsole ausgegeben.
Hello Klaas
Daher kannst du folgenden Befehl tippen und siehst sofort die Ausgabe in Deiner Konsole.
>>> print("Hello Klaas")
Hello Klaas
>>>
Ermitteln der installierten Version
Wenn man wissen möchte, welche Version auf dem Controller installiert ist, kann dies einfach über die REPL Shell ermitteln:
>>> from uos import uname
>>> uname()
(sysname='esp32', nodename='esp32', release='1.14.0', version='v1.14 on 2021-02-02', machine='ESP32 module with ESP32')
Dateitransfer mit ampy
Die interaktive Shell ist enorm hilfreich, um Dinge schnell einmal auszuprobieren. Aber bei längeren Tests, möchte man nicht immer jeden Befehl neu eintippen müssen. Hier kommt uns adafruit-ampy
zur Hilfe. adafruit-ampy
ist eine Open Source Python Library, die von Adafruit entwickelt wird und auf PyPi verfügbar ist.
Ampy installieren
Aktiviere Deine virtuelle Python Umgebung oder erstelle eine Neue. Dann installiere die Library.
(venv) $ pip install --upgrade adafruit-ampy
Nun steht Dir ampy zur Verfügung, um Dateien zu übertragen oder Python Skripte direkt auszuführen.
Ein Skript direkt ausführen
Wir nehmen noch einmal das "Hello Klaas"
Beispiel von oben. Lege mit Deinem Lieblingseditor eine Datei hello.py
an, die folgenden Inhalt hat.
print("Hello Klaas")
Nun kannst Du die Datei mit folgendem Befehl in Deiner virtuellen Umgebung ausführen:
ampy -p /dev/ttyUSB run hello.py
Auch hier musst Du den Port eventuell anpassen. Ampy verwendet eine Übertragungsgeschwindigkeit von 115.200 baud als Default. Du kannst dies über den Parameter -b
ändern. Ein Übersicht über die möglichen Unterkommandos und Optionen erhälst Du mit "ampy --help
„.
Das ist ziemlich cool, oder? Ampy eröffnet aber noch mehr Möglichkeiten, weil Du ampy nicht ausschließlich in der Kommandozeile benutzen musst, sondern auch programmatisch aus einem anderen Python Script heraus.
Für das folgende Beispiel nutze ich die interaktive Shell auf dem Rechner und nicht die auf dem Controller. Dazu einmal ein Beispiel, dass die Liste der Dateien auf dem Controller ausgibt.
$ python
>>> from ampy.files import Files
>>> from ampy.pyboard import Pyboard
>>> p = Pyboard("/dev/ttyUSB0")
>>> f = Files(p)
>>> f.ls()
['/boot.py - 139 bytes', '/main.py - 323 bytes']
>>>
Die Ausgabe kann natürlich bei Euch anders aussehen.
Ihr könnt auch Code ausführen, den Ihr in einem String haltet:
$ python
>>> from ampy.pyboard import Pyboard
>>> p = Pyboard("/dev/ttyUSB0")
>>> p.enter_raw_repl()
>>> p.exec('print("Hello Klaas")')
>>> p.exit_raw_repl()
Oder eine Datei, die auf dem Rechner liegt auf dem Controller ausführen und das Ausgaben lokal anzeigen lassen:
$ python
>>> from ampy.pyboard import Pyboard
>>> p = Pyboard("/dev/ttyUSB0")
>>> p.execfile('first_program.py')
Somit lässt sich der auszuführende Code auf dem Controller ohne einen zusätzlichen Flashvorgang austauschen. Nun will man aber sicher nicht immer den Controller immer in Verbindung mit einem Rechner nutzen können. In den meisten Fällen soll der Controller seinen Dienst ja alleine verrichten. Nach dem Startvorgang des Controllers wird, sofern vorhanden, die Datei main.py
ausgeführt. Wen Ihr Euch einmal die Liste mit den Dateien habt ausgeben lassen, dann findet Ihr auch noch eine boot.py
. Auf diese Datei gehe ich noch einmal gesondert ein. Für den Anfang lasst Ihr diese Datei, wie sie ist und speichert den Code, der nach einem Start ausgeführt werden soll in die Datei main.py
.
Dateien einfach kopieren
Um eine Datei auf den Controller zu kopieren, könnt Ihr einfach wieder auf ampy
zurückgreifen. Der Befehl zum Kopieren geht wie folgt:
(venv) $ ampy --port /dev/ttyUSB0 put main.py
Dann wird die lokale Datei main.py unter dem gleichen Namen in das Root Verzeichnis auf den Controller kopiert. Achtung! Eine eventuell vorhandene Datei mit dem gleichen Namen wird ohne Rückfrage überschrieben.
Wenn Ihr die Datei beim kopieren die Datei umbenennen wollt, dann gebt Ihr als zweiten Parameter den Zielnamen an.
(venv) $ ampy --port /dev/ttyUSB0 put main_one.py main.py