Source: https://mokxi.com/learn/esp32-micropython-simulator
Updated: 2026-10-26

Learn

# ESP32 MicroPython simulator: the official firmware, online

Beginner

Written by the Mokxi team, updated October 26, 2026

Start building free Open the editor

Or see every lesson.

- 455 parts on the bench
- 43 boards running now
- 1.00x real time, on every board

Click to open it in the editor

Press Run. The official MicroPython firmware boots, main.py is copied onto the board, and GPIO 2 blinks both LEDs.

Mokxi runs MicroPython on its classic ESP32 boards: the DOIT DevKit V1, the DevKitC and the LOLIN32 Lite. Put one on the canvas, choose MicroPython (main.py) in its Firmware panel, write main.py and press Run. What runs is the official MicroPython v1.29.0 firmware for the ESP32, the same file micropython.org publishes, on Mokxi’s model of the whole chip, booted from Espressif’s own mask ROM. Nothing in the page interprets your Python.

When you press Run, the computer on the end of the board’s simulated USB cable copies your .py files onto the board’s flash the way Thonny and mpremote do, then soft-reboots it. MicroPython prints MPY: soft reboot and runs main.py. Everything print() says shows in the Serial Monitor, and when main.py ends, or you stop it with Ctrl-C, the REPL answers there.

The circuit above is the first of six starters below: GPIO 2 blinks the DevKit’s own blue LED and a red LED wired to D2, and the Serial Monitor says on and off.

## Blink with machine.Pin

Pin(2, Pin.OUT) is GPIO 2, which on a DevKit V1 is wired to the board’s blue LED and to the header pin D2. The red LED on D2 goes through 220 ohms to ground, so the two light together and go dark together.

main.py: blink an LED

## A button with Pin.irq()

A button from D15 to ground, with the pin’s own pull-up: the pin reads 1 until the button is pressed, and Pin.IRQ_FALLING calls the handler when it goes to 0. A real button bounces, and so does this one, so the handler only sets a flag. The main loop waits 20 ms for the contacts to settle and counts a press only if the pin is still 0. Pressed three times, it prints presses 1, presses 2 and presses 3, once each, and toggles the board’s LED with each press.

main.py: count presses with an interrupt

## Fade an LED with PWM

PWM(Pin(4), freq=1000) is one of the ESP32’s LEDC channels on D4, and duty_u16() takes 0 to 65535. The loop steps the duty up and back down, so the LED brightens and dims in small steps: it breathes, rather than blinks.

main.py: an LED that breathes

## A DHT22 with the dht module

MicroPython’s own dht module reads a DHT22 on D4, bit by bit through the pin, as on a real board. With the part set to 23.5 C and 41% it prints Temperature: 23.5 C Humidity: 41.0 %, and when you change the temperature on the part the next reading follows it.

main.py: a DHT22

## An SSD1306 OLED on I2C

I2C(0, scl=Pin(22), sda=Pin(21)) is the ESP32’s first I2C block on the pins most ESP32 tutorials use. scan() finds the OLED and prints I2C: ['0x3c']. Add micropython-lib’s ssd1306.py as a tab beside main.py and it is copied onto the board with it, as Thonny would copy it; the program then draws two lines of text and a counter that goes up once a second.

main.py: text on an SSD1306 OLED

## WiFi and an HTTP GET with urequests

network.WLAN joins Mokxi’s simulated access point. Its name and password are the board’s WiFi properties, which start as Mokxi-Lab and breadboard. The board gets its address over DHCP and prints Connected, IP address 192.168.4.2.

urequests.get() then fetches http://weather.mokxi/, one of the made-up sites of the simulated network, and the program prints Mokxi: 21.5 C, 48 % humidity. The Cloud panel shows the requests the board makes. The network is simulated: names outside .mokxi are not found, and https:// has nowhere to go.

main.py: join WiFi and fetch the weather

## What works, and what does not

Working: machine.Pin with interrupts, PWM on the LEDC, ADC on ADC1’s eight channels with the four attenuations, I2C and SoftI2C, SPI and SoftSPI, UART(1) and UART(2), neopixel, dht, onewire and ds18x20, machine.freq() at 80, 160 or 240 MHz, and network.WLAN with socket and urequests on the simulated network. Drivers such as ssd1306.py talk to the parts on the canvas.

Not simulated: light and deep sleep; ADC2; PSRAM; the I2C and SPI slave modes; UART flow control; receiving with the RMT; the watchdogs resetting the board; and on the network, the access point mode’s clients (WLAN(AP_IF) starts and reports no stations), ESP-NOW, power save, TLS, and any network but the simulated one. The firmware is the single-core build. Code in flash runs as fast as code in RAM, as the caches’ timing is not modeled.

## Importing from Wokwi

A Wokwi project for an ESP32 with a main.py imports as a MicroPython project, with its board set to MicroPython. Its board joins Wokwi-GUEST with no password, as on Wokwi, so the usual wlan.connect("Wokwi-GUEST", "") works as written.

## The same code on a real ESP32

A MicroPython board needs no build. Put MicroPython on the ESP32 with esptool (esptool.py --chip esp32 erase_flash, then esptool.py --chip esp32 write_flash -z 0x1000 ESP32_GENERIC-UNICORE-20260824-v1.29.0.bin, from micropython.org/download/ESP32_GENERIC), then copy main.py onto it with Thonny or mpremote.

On a real board, change the SSID and password in the WiFi starter to your own network’s. The .mokxi sites exist only in Mokxi.

## Questions

Is this real MicroPython?

Yes. The board runs the official MicroPython v1.29.0 firmware for the ESP32, the single-core build micropython.org publishes, on a model of the whole chip booted from Espressif’s mask ROM. Nothing in the web page interprets your Python.

Which boards run MicroPython?

The classic ESP32 boards: the DOIT DevKit V1, the DevKitC and the LOLIN32 Lite, and the Raspberry Pi Pico. Choose MicroPython (main.py) in the board’s Firmware panel. An Arduino sketch on the same board runs as before.

How does main.py get onto the board?

The way mpremote does it. At Run, the simulated computer on the board’s USB port enters the raw REPL over UART0, writes each .py file into the board’s filesystem, and soft-reboots the board, which then runs boot.py and main.py.

Does it download anything?

The first Run of a MicroPython project on an ESP32 downloads the firmware and the chip’s ROM, 1.4 MB, and the browser keeps them for every later Run. An Arduino sketch never downloads them.

Related

## Keep going

Raspberry Pi Pico MicroPython in Your Browser ESP32 DevKit V1 Pinout: Every Pin and Which to Avoid The MicroPython simulator MicroPython blink on an ESP32 Beginner MicroPython button interrupt on an ESP32 Beginner MicroPython PWM fade on an ESP32 Beginner DHT22 on an ESP32 with MicroPython Beginner SSD1306 OLED on an ESP32 with MicroPython Beginner MicroPython WiFi weather on an ESP32 Intermediate Help: MicroPython on the ESP32 The project page, with the full sketch Beginner

Sources

## Where the facts on this page come from

- micropython.org: firmware for the ESP32 (v1.29.0, 2026-08-24)
- MicroPython documentation: quick reference for the ESP32

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building free Open the editor
