Getting started with Python on Embedded - and Zerynth
Today we will focus on Python by using Zerynth IDE. Zerynth provides tools and services for programming professional microcontrollers in Python for embedded and IoT applications, which is known formerly as Viper. Some advantages of the Zerynth against other frameworks are smaller footprint, RTOS support and C/Python hybrid programming.
Tools and architecture
So what is needed to execute python code on a constrained device? Since MCUs run machine code, python code either has to be precompiled or just-in-time-compiled and executed. A running example needs a boot loader, an intermedia layer that carries python code in either form and contains the python runtime libraries. Typically one needs a specialized toolchain to compose all of these parts.
Zerynth offers different types of tools:
- Studio: Zerynth Studio is a powerful IDE/toolchain which provides a platform for developing Python or C/Python hybrid projects for your MCU. It is compatible with Windows/Linux/MacOS.
- Virtual Machine: Zerynth VM is a multithreaded RTOS with real hardware independence allowing code reuse on 32bit MCUs.
- ADM: "Advanced Device Manager" is an API based interface for easier cloud data forwarding, OTA updates and remote procedure calling.
- App: Mobile application interface for connected Zerynth objects can be used as a controller and display board for smart objects and IOT systems.
We’re fans of NodeMCU (v2, ESP8266-based and the ESP32 DevKit-C), so for this post, we’re using these as MCUs/Development Boards and Zerynth Studio. As we will see, Studio knows how to bring a VM onto the device.
Download and installation
First, download Zerynth Studio from https://www.zerynth.com/zerynth-studio/, and run the installer. Then, register at Zerynth Community Forum with an email address and a password, or with Facebook/Google accounts, which is later needed when running Studio. The forum is full of tips and discussions, so registration is really worth it.
Installation is straight forward, and automatically pulls library dependencies while installing - which takes some minutes.
Connect your board and move around the IDE
Zerynth Studio is a complete IDE for C/Python development. After starting it you see a typical view with code at the central text pane, menus to the left and on top. The middle entries in top menu say „Target: No Device“, so that’s a good point to start.
Connect your board. Here’s a list of supported devices so you can check if your hardware works with it. In Studio, click on „No device…“. A list pops up and shows the connected target (if it can be located). It tries to automatically recognize the device, but sometimes this can be tricky. In case of ESP8266/ESP32, a button „Disambiguate“ appears. After clicking on it a dialog opens where the correct board can be selected from a drop-down, see screenshot 1:
Great, so Studio knows what our device is. Click on the „Z“-ish button right next to the target drow down and register the device. After a short time, messages should appear in the lower console with claim success:
[info] Device NodeMcu v2 registered with uid: ioW2Qw0NSGGcQIaJkX4FkA Registration successful! Now you can virtualize your nodemcu2
Registration successful! Now you can virtualize your esp32_devkitc
Now the device should have a boot loader. Clicking on „z“ again to create a new Virtual Machine. A dialog appears, select the (free) Standard VM and continue:
VM created! You can now virtualize your esp32_devkitc.
Again, click on „Z“ and virtualise:
[info] Virtualization Ok Device Virtualized
After that, the board has been prepared with the basic parts to run Zerynth code: Bootloader and the Zerynth Virtual Machine.
Creating a project
Now it’s time to create a new project. On the left side there are two larger buttons to either open an existing project or create a new one. It’s also possible to browse through the extensive catalog of examples, but we’d like to start from scratch. Clicking on „Create“ opens the „New Project“ dialog, where Title, Description and a place to put the files is specified. As per default, the project is created within User’s home folders, so if you want to have it in a special place, specify this here.
Creating the project leaves us with a readme markdown document and a main.py, both rather empty. Let's fill in some code :)
For the ESP8266 let’s combine a simple Hello World with controlling the builtin LED:
import streams streams.serial() pinMode(LED0,OUTPUT) while True: print("Hello Zerynth!") digitalWrite(LED0, HIGH) sleep(1000) digitalWrite(LED0, LOW) sleep(1000)
When typing code or copy/pasting it, make sure to have the right indentation levels, because Python code and blocks are structured using indentation.
Zerynth assigns unified names for builtin GPIOs, such as
LED0 for the onboard LED. Please check if your board has these things as well. How do we know? Click on the „i“ / Info-Button in the top menu. This brings up the Device Info, which shows all Pins for the selected target alongside more information about peripherals and predefined names. Pretty much helpful!
The two buttons left of „Target“ are quite known from other embedded IDEs: Compile code and upload/flash to board.
After flashing the code, the build output tells us:
[info] Sending Bytecode: 4848 bytes ( available 593920 ) [info] Uplink done
And it should start to blink and to print out text on the serial console, which can be brought up by clicking on the right-most link, „terminal“.
Ok, compiling, flashing and inspecting works. Now let’s turn to some network interaction. We choose the MQTT example from the Zerynth example section, and simplify this a bit. If you already have a working MQTT broker installed somewhere that’s fine. Otherwise you could choose to install i.e. Mosquitto:
$ brew install mosquitto $ cd /usr/local/Cellar/mosquitto/1.4.14_2/sbin $ ./mosquitto
$ apt-get install mosquitto $ mosquitto
Mosquitto on Windows can require additional steps, but there are how-to’s around to google for.
Replace the code in the IDE with the following snippet (or create a new project).
import streams from mqtt import mqtt from wireless import wifi ## according to your board, choose the right wifi driver ## by commenting out as necessary from espressif.esp8266wifi import esp8266wifi as wifi_driver # from espressif.esp32net import esp32wifi as wifi_driver wifi_driver.auto_init() streams.serial() print("Establishing WiFi Link...") try: wifi.link("<YOURSID>",wifi.WIFI_WPA2,"<YOURPASSWORD>") print("Connected to WiFi") except Exception as e: print("ooops, something wrong while linking :(", e) while True: sleep(1000) def send_sample(obj): print("publishing: ", obj) client.publish("temp/random", str(obj)) try: print("connecting...") client = mqtt.Client("zerynth-mqtt",True) for retry in range(10): try: client.connect("<MQTT-BROKER-IP>“, 60) break except Exception as e: print(e) print("connected.") # publish a random value every three seconds while True: sleep(3000) x = random(0,50) send_sample(x) except Exception as e: print(e)
The are some things to be changed here. First, according to the type of board you use, select the right WiFi driver for it. The above code contains two settings for either ESP8266 or ESP32.
Then, add WiFi credentials at the places
The above snippet does a bunch of things. First it tries to connect to the WiFi, if successful, it uses mqtt class from mqtt package to connect to the broker. Code includes retries and timeouts. It then runs in a loop, waiting three seconds, then publishing a random number as a string to the topic
In case of Exceptions, these are printed out to serial. If all works well the serial monitor should look like so:
In another terminal window, use
mosquitto_sub to subscribe to the topic
temp/random. New messages are arriving there:
$ mosquitto_sub -v -t temp/random temp/random 26 temp/random 42 temp/random 18 (...)
Some tips for using ESP8266 with Zerynth:
- Rebooting the device can take some seconds, at least that is what we experienced. This is different compared to other platforms where application code is directly executed after releasing the reset button. So give it some time :)
- On ESP8266/ESP32 you can either look at the serial console or flash code - but not both. So before uploading code, close the serial monitor and open it again after the console says „Uplink done“.
- The Examples Section within Zerynth' Docs Area is well packed with code snippets - a look there is always worth it.
So much about Zerynth for now! There is no denying that the C/C++ is mainstream in embedded programming which provides various choices for Embedded OSes, libraries and documentation. On the other hand, IoT applications are expected to have higher demands for connectivity and data processing, which dynamic languages such as Python are good at. And Zerynth offers a powerful toolchain for this purpose.