A workshop about MicroPython on ESP32.
Since not everyone has access to physical hardware, we can simulate esp32 microcontrollers using wokwi. This allows us to focus on programming before moving to real hardware. Everything done here can be transferred directly to physical ESP32 devices.
Start a new project here: wokwi-esp32, you can save it if you create an account, but it is not needed for this workshop You will mainly work with:
main.py→ your programdiagram.json→ hardware wiring
When you press Start simulation, Wokwi automatically transfer all files what is on the left and executes main.py.
Let’s start with a simple LED test.
Replace diagram.json with led.json from the ./diagrams folder inside wokwi.
Press the play button in Wokwi, the REPL will show the Serial Monitor with:
>>>, Type something pythonic.
To test the led you can type this in the REPL:
from machine import Pin
led_pin = Pin(2, Pin.OUT)
led_pin.value(1) # LED on
led_pin.value(0) # LED offIf everything works, you should see the LED toggle.
- CTRL-C → Stop current program
- CTRL-D → Restart (boot.py + main.py)
- CTRL-A → Raw REPL (used for uploading files)
The REPL is useful for debugging, but real programs are written in:
boot.py → system setup (WiFi, MQTT, drivers)
main.py → application logic
MicroPython runs in this order: boot.py → main.py → REPL
- boot.py runs once on startup
- main.py runs your program
- when main.py finishes → you return to REPL
- CTRL + D → restarts everything
for assignments below we use the lib machine
Turn on or off some output, output is always 3.3v on esp32
replace diagram.json with led.json
Make an LED blink:
- start slow (1s delay)
- gradually speed up (0.05s delay)
- create a “charging effect”
PWM simulates analog voltage by switching fast ON/OFF.
This is mostly used in leds and motors.
replace diagram.json with led.json
Make the Led Breath:
- Update
Assigment_1to make the LED “breathe” like a tiny robot heart.
The same as the output the esp32 can check if a signal is high or low (3.3V or ground)
replace diagram.json with button.json
Blink led when button is pressed:
- When button is pressed the light should start blinking.
- Blinking stops or restarts when button is pressed again.
ADC converts voltage (0–3.3V) into digital values and returns as signal in range between 0-3.3 volts.
replace diagram.json with potential_meter.json
Map value of potentiometer to led brightness
Deep-sleep is one of the reasons you could choose for a microcontroller. Deep-sleep is like turning everything off except the rtc (for counting). by this we can put the device (off) to save battery and turn it on in the morning to update some sensors.
Put the ESP32 to deepsleep to save power.
- sleep for 10 seconds
- wake up
- print "hello world"
- repeat
For more information deepsleep
After putting the device to deepsleep we can "wake" them again by shorting a pin.
replace diagram.json with button.json
Put the esp32 to deepsleep
- let it sleep forever
- wake up by pressing the button.
for more information deepsleep interrupt esp32
Most sensors etc need some delays or waits before you get response, you give them a signal to do (like turning a motor) and want to wait 5 sec.
the normal python sleep(5) will block the whole micropython loop. Try to keep the loop non-blocking(ish)
replace diagram.json with stepper_motor.json
turn the motor clockwise or counterclockwise depending on the potential meter, while not blocking the loop. for more information visit timers and delays
Even though Wokwi runs main.py, you can structure like this:
main.py
led.py
let's structure the stepper motor of asssignment 6 in its own module.
like normal you can import it as
# main.py
from led import blink
blink()For connecting the device to wifi wokwi is serving a network with real network access. You can connect to the network with
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASS = ""and use the lib import network for more documentation network.
So let's make a sender and listener/subcriber with mqtt, a protocol to send or subscribe to topics. heavily used in IoT for sending sensor data. mqtt is standard included in micropython together with wifi. and thus all diagrams.json will work just fine for this assigment. To listen or send messages to the simulated device go to hivemq and send a message to the topic or subscribe to topics. Use this for communication with mqtt after you connected to wifi.
from umqtt.simple import MQTTClient
MQTT_CLIENT_ID = f"micropython-sender_{NAME}"
MQTT_BROKER = "broker.mqttdashboard.com"
MQTT_USER = ""
MQTT_PASSWORD = ""
MQTT_TOPIC = "QSTARS_MQTT"For more documentation check mqtt
When a sender is made and sends a message to a topic you can see ith with the hivemq and subscribe to the topic to see incomming messages when the listener is made you can send via hivemq also messages to a certain topic.
Here are the most used protocols in IoT devices, most of the time you would not interact directly with it, but with a lib written for the sensor. Only when you make your own sensor or using a sensor not frequently used you need to interact directly with these protocols. Therefore it is written here as demo, but no assignments are made.
from machine import UART
uart = UART(1, baudrate=9600, tx=17, rx=16)
uart.write("Hello UART\n")
while True:
if uart.any():
print(uart.read())from machine import I2C, Pin
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
devices = i2c.scan()
print("I2C devices found:", devices)from machine import SPI, Pin
spi = SPI(
1,
baudrate=1000000,
polarity=0,
phase=0,
sck=Pin(18),
mosi=Pin(23),
miso=Pin(19)
)
print("SPI initialized:", spi)We have 50 rgb led ring ws2812 you can send a message to the led ring and let them make a full circle.
You can use the lib neopixel from Adafruit. In essence this lib will create the message you send through the pipeline,
what every led is doing, it takes the first tuple (r,g,b) and execute it, after that it passes the rest of the message to the next pixel.
This led is getting a message with 1 tuple less in the message until it is empty. Therefore you can couple more ledstrips to 1.
When the led ring is working, you can use the 1 empty pin on the led ring(DOut) to couple it to any other ws2812 input of ring 1.
This way, you can make longer and more complicated designs.
import neopixel
NUM_LEDS = 50For more documentation check neopixel.
- add more rings / individual
ws2812or strips to the simulation. - add mqtt to device and control the led-ring colors via mqtt.
We're going to make 2 devices, device 1 with a dht22 sensor for reading out temp and humidity
and device 2 for displaying the temp on a display.
For device 1 (tab 1) we use lcd_display.json for device 2 (tab 2) we use dht22.json
One device will read out the dht22 sensor with help of dhtt lib
the lcd display can be set with:
from i2c_lcd import I2cLcd
# ---------- LCD ----------
I2C_ADDR = 0x27
totalRows = 2
totalColumns = 16
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=10000)
lcd = I2cLcd(i2c, I2C_ADDR, totalRows, totalColumns)
lcd.putstr("Waiting data...")and we need to include the 2 files lcd_api.py and i2c_lcd.py sometimes you can download them via mip a micropython package manager,
But due to low memory most of the time a stripped down version is saved inside the project.
- More used MQTT library, but bigger MQTT lib github
- Importing Mip Packages MicroPython pip library