Modern microcontrollers such as the ESP32 have enough computing resources to be programmed in a high-level language like MicroPython. Thanks to MicroPython's powerful libraries, this allows you to quickly prototype a project. With the MakePython ESP32 Development Kit that combines a textbook and a selection of electronic parts, well-known Elektor author Dogan Ibrahim presents a starter package for learning MicroPython based on real-world examples.

We don’t really need to discuss the fact that MicroPython is not the best way to achieve maximum software efficiency. On the other hand, it is true that modern microcontrollers like an ESP32 are more than able to keep up with an Intel 486 in terms of performance. Especially in one-offs or small product series, it can therefore be reasonable to trade off programming effort for speed by using high-level programming languages.

The Book

Let’s start with the textbook, which is available in English only. It has a quite fancy design with a (fake) spiral binding. The book begins with a brief introduction of the ESP32. For the (Elektor) reader who has already worked with microcontrollers, it provides a short overview of the various peripherals that Espressif put into the controller. If you have no experience at all with microcontrollers, the explanations – at least in places – might be too short for a good understanding.

The installation of the integrated programming environments (IDEs) is explained in detail for Windows, whereas Linux is hardly covered. Dogan Ibrahim introduces both uPyCraft and Thonny, but works almost exclusively with Thonny. This is followed by a chapter that illustrates the execution of some Python code snippets using Thonny. If you don’t know anything about Python, then you can’t really get into it at this point. On the other hand, the explanations are more than sufficient to understand the basics of working with MicroPython and the IDE.

The presentation of the 46 projects contained in the book is done in Dogan Ibrahim style: First, he presents the mission to complete and then gives code and explanations of the construction of the hardware. If you like compact coding, you may get annoyed somewhat by the fact that the listings always include the same header consisting of at least ten lines. On the other hand, to Ibrahim’s credit, the examples – while not complicated – do aptly illustrate the essential aspects of working with MicroPython. After reading the book, you won't have to search the internet for details on how to use certain peripherals.

Very commendable too, in the reviewer’s opinion, is the fact that Ibrahim explains how to restore a “bricked” board that no longer functions properly with fresh MicroPython firmware.

Figure 1: The kit contains a book and many electronic parts and modules to play with.

A Look at the Board

The kit combines the book with the kit shown in Figure 1. It comes with a robust plastic case, making it suitable for taking along on vacation or to prevent boredom on a business trip.

The author’s teaching experience has shown that especially developers not familiar with embedded systems will have a more comfortable learning experience if the development platform provides a display, graphical, if possible. Therefore, the kit contains the red board shown in Figure 2, the microcontroller board. The black area is not a black hole, but one of those widely used SSD1306-based OLED graphical displays with a resolution of 128 by 64 pixels.

The reviewer’s biggest point of criticism is found on this board: Its 2.54 mm headers are not mounted. This is a pity because it requires a soldering iron and not everybody has or knows how to use one. Otherwise, the board is fine. The ESP32 variant used is one of the larger models and has enough memory. The micro-USB-B interface allows using standard mobile phone data/charger cables, but the kit also includes a (very short) cable of decent quality.

Figure 2: This board allows for a quick start with MicroPython.

A Demo

While the textbook is primarily oriented towards the needs of developers working with Windows, the reviewer will (for his own convenience) refer to Ubuntu 20.04 LTS in what follows. The uPyCraft IDE is a rather bad choice because its execution in all Ubuntu versions later than 16.04 fails with an error message like:

ImportError: /tmp/_MEIOhQKhz/ version `ZLIB_1.2.9' not found (required by /usr/lib/x86_64-linux-gnu/

A better option is Thonny, which can be installed automatically by entering:

bash <(wget -O - 

It is launched by entering the command:


To uninstall it, we use the command:


All that remains to be done after the first start is confirming the language selection. 

The next step is to connect the evaluation board to a workstation. Fortunately, Elektor thoughtfully delivers the board with a preconfigured MicroPython runtime. Particularly convenient is that the board also switches on its display at the same time, which facilitates a function check. By the way, a Silicon Labs CP210x UART bridge chip is used as USB-to-serial converter.

At this point, you can switch to Thonny (Fig. 3). Make sure that you click on the Python version in the selection menu that appears at the bottom right, and then select the MicroPython (ESP32) version. Thonny will then search for ESP32 boards. In my case, the board used here was automatically detected.

The question whether you need to run Thonny with superuser privileges is debatable – since the reviewer’s user account is a member of the plugdev group, he was able to run Thonny in his normal user account and still interact with the ESP32. 

Figure 3: Screenshot of Thonny

A First Welcome 

As the next step, let’s put the device’s OLED display into operation. To do this, we open this URL and download the MakePython ESP32 Lessons Source Code archive (using RAR is a bit annoying in Linux). Extract the archive to a conveniently accessible location. For the following steps, we need the file, which provides the OLED driver code. 

First, click File -> Open, and then choose This Computer. Navigate to the file to load it into the editor. Then we choose File -> Save as and then the option MicroPython Board. If Thonny gets upset at this point about the backend being busy, click the red stop icon in the toolbar. Then save the file into the file system.

As is common with MicroPython, we first need to install some libraries and also define constants with additional information about the specifications of the display: 

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

For the actual communication with the display connected via I²C – which is uncommon, as you would usually expect SPI here – we then use an instance of the software I²C class: 

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)

Finally, we need to send a text to the display, like this: 

while True:
    oled.text('Hello World!',10,0)

Click the play icon in the IDE to see the text appearing on the display of the evaluation board. 

MQTT Setup 

As a next step, we want to go a little beyond the basic examples included in the kit and do something more advanced. This also proves that the kit is suitable for more complicated tasks. In this case, we wish to use the universally known MQTT protocol. To make things even more interesting, we will use a brand-new version of the Mosquitto MQTT broker (here is a list of issues that the parsers – which are configured more and more strictly for security reasons – can run into when working with MicroPython and its drivers). 

Speaking of MicroPython drivers: There are two competing implementations of MQTT for MicroPython. However, here we want to rely on the simpler variant available at Github -  download the file and save it under the name on the process computer.

In the next step, we need to set the Wi-Fi part of the board into station mode: 

. . .

For the actual connection setup, we then use the following method, largely inspired by the project template provided by MakerFabs. It implements a countdown timer including connection establishment. Of course, make sure to adapt the strings passed to wlan.connect to your wireless network:

def connectWiFi():
    oled.text('connecting WiFi',0,16)
  oled.text('MakePython ESP32',0,32)
    oled.text('WIFI connected',0,16)
    oled.text('NOT connected!',0,16)
  return True

Establishing the actual connection then couldn’t be easier:

while True:

In the next step, we want to provide ourselves with a Mosquitto server. Mosquitto may not be the fastest MQTT broker around, it is open source, free and very strict in its MQTT implementation. Due to its widespread use, it is also ensured that there is a more or less turnkey image in the Docker Hub that allows the deployment of the server without deep configurations of the host computer.

For a first attempt, enter the following command: 

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

Firstly, the parameters -p 1883:1883 and -p 9001:9001 - are important here – after all, each Docker container is provided with a full complement of TCP/IP ports by the runtime. Each of the parameters then connects one of these ports to the host computer’s network card. Via the parameter -v mosquitto.conf:/mosquitto/config/mosquitto.conf, we also integrate a configuration file.

At this point, it is a good idea to make an initial download attempt with an existing Internet connection. Docker will normally connect to the hub and download the required components, and then exit with the following error message: 

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

The cause of the error is that there is not yet a file named mosquitto.conf in the host workstation that we could make available to the container. 

To solve the problem, create a new file via the command line in the working directory with gedit:

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

The switch from Mosquitto version 1 to version 2 was accompanied by massive tightening of the security configuration. While a Mosquitto 1.X (started with default parameters) accepted server requests from any clients, Mosquitto 2 refuses this. However, if you place the following lines in the configuration file, everything will work as usual (and insecure) again: 

listener 1883
allow_anonymous true

The execution can then be commanded according to the following scheme – note that the -v parameter always requires a fully qualified path, which is why we call the pwd command and assemble the results by shell magic. pwd, by the way, stands for Print Working Directory, Figure 4 shows the behavior: 

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

If the Docker container acknowledges its successful start by returning 1658673183: mosquitto version 2.0.14 running, we are all set at this point. 

Figure 4: The pwd command returns the current working directory of the shell. 

Initializing the MQTT software on the ESP32

First of all, we need some constants for working with MQTT – make sure to adapt the IP address passed in the server string to your local operating situation: 

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

We also need a callback function that the MQTT driver will always call when a message is received: 

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

The actual setup of the MQTT connection is then comparatively simple: 

c = MQTTClient(CLIENT_ID, SERVER, keepalive=30)
print("Connected to %s, subscribed to %s topic" % (SERVER, TOPIC))

while True:

The call of c.subscribe ensures that the MQTT driver informs the server which message channels are currently of interest. It is also important to periodically call the method c.wait_msg() to provide the MQTT server with processing power for processing the information that is incoming or to be sent. In the command line or in the output window, you can then see the output Connected to, subscribed to b'led' topic.

In the next step, we want to connect one of the LEDs included in the kit, along with a resistor, to GPIO pin 12 – the author assumes that the reader has sufficient knowledge of electronics. The initialization of the GPIO port requires ordinary ESP32 code:

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

To process the incoming messages, we then need to extend the callback by combining the string supplied in the value topic with the constants provided for the various commands:

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

For testing, we want to use the command line utility mosquitto_pub: This is a tool available in Linux that allows commands to be sent directly to an MQTT server. The following commands are then used to switch the LED on and off: 

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

If the ESP32 and the server are in the same network, you can now switch the LED on and off. 

Conclusion and Outlook 

The MakePython ESP32 Development Kit is a fascinatingly compact toolbox that allows Python developers and/or electronics engineers to quickly unite the two worlds. Especially because everything is so nicely packaged in a turnkey manner, this is a box the reviewer is happy to recommend. 

Tag alert: Subscribe to the tag ESP32 and you will receive an e-mail as soon as a new item about it is published on our website!