Skip to content

Commit f307464

Browse files
committed
feat(examples/micropython_esp32): add example
1 parent f186c8f commit f307464

File tree

5 files changed

+167
-0
lines changed

5 files changed

+167
-0
lines changed

examples/micropython_esp32/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.bin

examples/micropython_esp32/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# MicroPython on ESP32
2+
3+
This example shows how to run MicroPython on an ESP32 board. It creates a firmware image with a littlefs filesystem and injects a MicroPython script into it. The firmware image is uploaded to the Wokwi ESP32 simulator and the MicroPython script is executed. The script prints some information about the ESP32 chip and the filesystem.
4+
5+
## Running the example
6+
7+
Run the following command in the root directory of the project:
8+
9+
```bash
10+
pip install -e .[dev]
11+
python -m examples.micropython_esp32.main
12+
```
13+
14+
## Program output
15+
16+
The program output is printed to the console. The output is similar to the following:
17+
18+
```
19+
Wokwi client library version: 0.0.2
20+
Connected to Wokwi Simulator, server version: 1.0.0-20250701-g79c3ac34
21+
Simulation started, waiting for 3 seconds…
22+
--------------------------------
23+
Hello, MicroPython! I'm running on a Wokwi ESP32 simulator.
24+
--------------------------------
25+
CPU Frequency: 160000000
26+
MAC Address: 24:0a:c4:00:01:10
27+
Flash Size: 4096 kB
28+
Total Heap: 166592 bytes
29+
Free Heap: 163040 bytes
30+
Filesystem:
31+
Root path : /
32+
Block size: 4096 bytes
33+
Free space: 2084864 bytes
34+
--------------------------------
35+
MicroPython v1.25.0 on 2025-04-15; Generic ESP32 module with ESP32
36+
Type "help()" for more information.
37+
>>>
38+
```
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": 1,
3+
"author": "Uri Shaked",
4+
"editor": "wokwi",
5+
"parts": [
6+
{
7+
"type": "board-esp32-devkit-c-v4",
8+
"id": "esp",
9+
"top": 0,
10+
"left": 0
11+
}
12+
],
13+
"connections": [
14+
["esp:TX", "$serialMonitor:RX", "", []],
15+
["esp:RX", "$serialMonitor:TX", "", []]
16+
],
17+
"dependencies": {}
18+
}

examples/micropython_esp32/main.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# SPDX-License-Identifier: MIT
2+
# Copyright (C) 2025, CodeMagic LTD
3+
4+
import asyncio
5+
import os
6+
from pathlib import Path
7+
8+
import requests
9+
from littlefs import LittleFS
10+
11+
from wokwi_client import GET_TOKEN_URL, WokwiClient
12+
13+
EXAMPLE_DIR = Path(__file__).parent
14+
FIRMWARE_NAME = "ESP32_GENERIC-20250415-v1.25.0.bin"
15+
FIRMWARE_FILE = EXAMPLE_DIR / FIRMWARE_NAME
16+
FIRMWARE_URL = f"https://micropython.org/resources/firmware/{FIRMWARE_NAME}"
17+
FIRMWARE_OFFSET = 0x1000
18+
FLASH_SIZE = 0x400000
19+
FS_OFFSET = 0x200000
20+
FS_SIZE = 0x200000
21+
SLEEP_TIME = int(os.getenv("WOKWI_SLEEP_TIME", "3"))
22+
23+
MICROPYTHON_CODE = """
24+
# This is a MicroPython script that runs on the simulated ESP32 chip.
25+
# It prints some information about the ESP32 chip and the filesystem.
26+
27+
import esp
28+
import esp32
29+
import gc
30+
import machine
31+
import os
32+
33+
print("--------------------------------")
34+
print("Hello, MicroPython! I'm running on a Wokwi ESP32 simulator.")
35+
print("--------------------------------")
36+
37+
# Chip information
38+
print(f"CPU Frequency: {machine.freq()}")
39+
mac_address = ':'.join(['{:02x}'.format(x) for x in machine.unique_id()])
40+
print(f"MAC Address: {mac_address}")
41+
42+
# Memory information
43+
print(f"Flash Size: {esp.flash_size() // 1024} kB")
44+
print(f"Total Heap: {gc.mem_alloc() + gc.mem_free()} bytes")
45+
print(f"Free Heap: {gc.mem_free()} bytes")
46+
47+
# Filesystem information
48+
statvfs = os.statvfs("/")
49+
block_size, free_blocks = statvfs[0], statvfs[3]
50+
print("Filesystem:")
51+
print(f" Root path : /")
52+
print(f" Block size: {block_size} bytes")
53+
print(f" Free space: {block_size * free_blocks} bytes")
54+
print("--------------------------------")
55+
"""
56+
57+
58+
async def main() -> None:
59+
token = os.getenv("WOKWI_CLI_TOKEN")
60+
if not token:
61+
raise SystemExit(
62+
f"Set WOKWI_CLI_TOKEN in your environment. You can get it from {GET_TOKEN_URL}."
63+
)
64+
65+
if not FIRMWARE_FILE.exists():
66+
print(f"Downloading {FIRMWARE_NAME} from {FIRMWARE_URL}")
67+
response = requests.get(FIRMWARE_URL)
68+
response.raise_for_status()
69+
with open(FIRMWARE_FILE, "wb") as f:
70+
f.write(response.content)
71+
72+
firmware_data = bytearray(FLASH_SIZE)
73+
with open(FIRMWARE_FILE, "rb") as f:
74+
firmware_data[FIRMWARE_OFFSET : FIRMWARE_OFFSET + f.tell()] = f.read()
75+
76+
# Inject some micropython code into a littlefs filesystem inside the firmware image
77+
lfs = LittleFS(block_size=4096, block_count=512, prog_size=256)
78+
with lfs.open("main.py", "w") as lfs_file:
79+
lfs_file.write(MICROPYTHON_CODE)
80+
firmware_data[FS_OFFSET : FS_OFFSET + FS_SIZE] = lfs.context.buffer
81+
82+
with open(EXAMPLE_DIR / "firmware.bin", "wb") as f:
83+
f.write(bytes(firmware_data))
84+
85+
client = WokwiClient(token)
86+
print(f"Wokwi client library version: {client.version}")
87+
88+
hello = await client.connect()
89+
print("Connected to Wokwi Simulator, server version:", hello["version"])
90+
91+
# Upload the diagram and firmware files
92+
await client.upload_file("diagram.json", EXAMPLE_DIR / "diagram.json")
93+
await client.upload(FIRMWARE_NAME, bytes(firmware_data))
94+
95+
# Start the simulation
96+
await client.start_simulation(firmware=FIRMWARE_NAME, elf=FIRMWARE_NAME)
97+
98+
# Stream serial output for a few seconds
99+
serial_task = asyncio.create_task(client.serial_monitor_cat())
100+
print(f"Simulation started, waiting for {SLEEP_TIME} seconds…")
101+
await client.wait_until_simulation_time(SLEEP_TIME)
102+
serial_task.cancel()
103+
104+
# Disconnect from the simulator
105+
await client.disconnect()
106+
107+
108+
if __name__ == "__main__":
109+
asyncio.run(main())

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ dependencies = [
9595
"mkdocs-material[extensions]",
9696
"mkdocstrings[python]",
9797
"types-requests",
98+
"littlefs-python>=0.14.0",
9899
]
99100

100101
[tool.hatch.envs.dev]

0 commit comments

Comments
 (0)