MicroPython on ESP32 with SiliconWit IO
In this tutorial, you will learn how to set up an ESP32 running MicroPython to publish sensor telemetry data to the SiliconWit IO IoT platform via MQTT over a secure TLS connection. MicroPython provides a Python-based development experience directly on the ESP32, making it fast to prototype and iterate without compiling firmware.
What You Will Learn
Section titled “What You Will Learn”- How to flash MicroPython firmware onto an ESP32
- How to connect the ESP32 to WiFi using MicroPython
- How to install and use the
umqtt.simplelibrary for MQTT - How to establish a TLS-encrypted connection to the SiliconWit IO MQTT broker
- How to publish JSON telemetry data from a
boot.pyandmain.pystructure
Prerequisites
Section titled “Prerequisites”Hardware
Section titled “Hardware”| Component | Description |
|---|---|
| ESP32 Development Board | Any ESP32, ESP32-S3, or ESP32-C3 board |
| USB Cable | For programming and powering the ESP32 |
| WiFi Network | 2.4 GHz WiFi with internet access |
Software
Section titled “Software”| Software | Purpose |
|---|---|
| esptool | Flash MicroPython firmware to the ESP32 |
| mpremote | Transfer files and interact with the ESP32 REPL |
| SiliconWit IO Account | Free IoT platform account |
SiliconWit IO Credentials
Section titled “SiliconWit IO Credentials”After registering a device on your SiliconWit IO dashboard, note down:
| Credential | Example | Description |
|---|---|---|
| Device ID | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | Unique device identifier (MQTT username and client ID) |
| Access Token | your_access_token_here | MQTT password |
| Publish Topic | d/{device_id}/t | Topic for sending sensor data (d = device, t = telemetry) |
Keep your access token secure. Never share it publicly or commit it to version control.
Step 1: Flash MicroPython onto the ESP32
Section titled “Step 1: Flash MicroPython onto the ESP32”1.1 Install esptool and mpremote
Section titled “1.1 Install esptool and mpremote”pip install esptool mpremote1.2 Download the MicroPython Firmware
Section titled “1.2 Download the MicroPython Firmware”Download the latest stable MicroPython firmware for your ESP32 variant from the official MicroPython downloads page:
| Board | Firmware Page |
|---|---|
| ESP32 (original) | micropython.org/download/ESP32_GENERIC |
| ESP32-S3 | micropython.org/download/ESP32_GENERIC_S3 |
| ESP32-C3 | micropython.org/download/ESP32_GENERIC_C3 |
Download the .bin file (e.g., ESP32_GENERIC-20241129-v1.24.1.bin).
1.3 Erase and Flash
Section titled “1.3 Erase and Flash”Find your ESP32 serial port:
ls /dev/ttyACM* /dev/ttyUSB*Erase the flash and write the new firmware:
esptool.py --chip esp32 --port /dev/ttyACM0 erase_flash
esptool.py --chip esp32 --port /dev/ttyACM0 \ --baud 460800 write_flash -z 0x1000 ESP32_GENERIC-20241129-v1.24.1.binNote: For ESP32-S3 or ESP32-C3, change
--chip esp32to--chip esp32s3or--chip esp32c3, and the flash offset may differ. Check the MicroPython download page for the exact command for your board.
1.4 Verify the Installation
Section titled “1.4 Verify the Installation”Connect to the REPL:
mpremote connect /dev/ttyACM0You should see the MicroPython prompt:
MicroPython v1.24.1 on 2024-11-29; Generic ESP32 module with ESP32Type "help()" for more information.>>>Press Ctrl+] to exit mpremote.
Step 2: Install umqtt.simple
Section titled “Step 2: Install umqtt.simple”The umqtt.simple library provides a lightweight MQTT client for MicroPython. Install it using mpremote:
mpremote connect /dev/ttyACM0 mip install umqtt.simpleThis downloads and installs the library directly onto the ESP32’s filesystem.
If
mip installfails due to network issues on the ESP32, you can install it after WiFi is configured inboot.pyby runningimport mip; mip.install("umqtt.simple")from the REPL.
Step 3: Create boot.py (WiFi Connection)
Section titled “Step 3: Create boot.py (WiFi Connection)”The boot.py file runs automatically when the ESP32 starts up. We use it to connect to WiFi so that main.py can immediately start MQTT communication.
Create a file called boot.py on your computer with the following content:
import networkimport time
# ========== WIFI CONFIGURATION ==========WIFI_SSID = "YOUR_WIFI_SSID"WIFI_PASSWORD = "YOUR_WIFI_PASSWORD"
# ========== CONNECT TO WIFI ==========def connect_wifi(): wlan = network.WLAN(network.STA_IF) wlan.active(True)
if wlan.isconnected(): print("[WIFI] Already connected") print(f"[WIFI] IP: {wlan.ifconfig()[0]}") return wlan
print(f"[WIFI] Connecting to {WIFI_SSID}...") wlan.connect(WIFI_SSID, WIFI_PASSWORD)
timeout = 20 while not wlan.isconnected() and timeout > 0: time.sleep(1) timeout -= 1 print(".", end="")
if wlan.isconnected(): print(f"\n[WIFI] Connected! IP: {wlan.ifconfig()[0]}") else: print("\n[WIFI] Connection failed!")
return wlan
wlan = connect_wifi()Upload it to the ESP32:
mpremote connect /dev/ttyACM0 cp boot.py :boot.pyStep 4: Create main.py (MQTT Telemetry)
Section titled “Step 4: Create main.py (MQTT Telemetry)”The main.py file runs after boot.py. It connects to the SiliconWit IO MQTT broker over TLS and publishes telemetry data in a loop.
Create a file called main.py on your computer:
import sslimport jsonimport timeimport machinefrom umqtt.simple import MQTTClient
# ========== SILICONWIT IO MQTT CONFIGURATION ==========MQTT_BROKER = "mqtt.siliconwit.io"MQTT_PORT = 8883DEVICE_ID = "YOUR_DEVICE_ID"ACCESS_TOKEN = "YOUR_ACCESS_TOKEN"PUBLISH_TOPIC = f"d/{DEVICE_ID}/t"
# ========== TIMING ==========TELEMETRY_INTERVAL = 30 # seconds
# ========== SENSOR READING ==========def read_sensors(): """ Read the ESP32 internal temperature sensor and uptime. Replace or extend this function with your own sensors. """ # Internal temperature sensor (available on most ESP32 variants) try: raw = machine.ADC(machine.ADC.BLOCK1, 0) # Simulated data — replace with real sensor readings import urandom temp = 20.0 + (urandom.getrandbits(8) / 255.0) * 15.0 hum = 30.0 + (urandom.getrandbits(8) / 255.0) * 50.0 except Exception: import urandom temp = 20.0 + (urandom.getrandbits(8) / 255.0) * 15.0 hum = 30.0 + (urandom.getrandbits(8) / 255.0) * 50.0
return { "temperature": round(temp, 1), "humidity": round(hum, 1), "uptime": time.ticks_ms() // 1000, "free_memory": machine.mem_free(), }
# ========== MQTT CONNECTION ==========def connect_mqtt(): """Create and connect the MQTT client with TLS.""" print(f"[MQTT] Connecting to {MQTT_BROKER}:{MQTT_PORT}...")
ssl_params = {"server_hostname": MQTT_BROKER}
client = MQTTClient( client_id=DEVICE_ID, server=MQTT_BROKER, port=MQTT_PORT, user=DEVICE_ID, password=ACCESS_TOKEN, keepalive=60, ssl=True, ssl_params=ssl_params, )
client.connect() print("[MQTT] Connected to SiliconWit IO") return client
# ========== MAIN LOOP ==========def main(): print("\n=== MicroPython ESP32 -> SiliconWit IO ===\n")
client = None try: client = connect_mqtt()
while True: try: # Read sensor data data = read_sensors() payload = json.dumps(data)
# Publish telemetry client.publish(PUBLISH_TOPIC, payload) print(f"[TELEMETRY] Sent: {payload}")
except OSError as e: print(f"[ERROR] Publish failed: {e}") print("[MQTT] Reconnecting...") try: client.disconnect() except Exception: pass time.sleep(5) client = connect_mqtt()
time.sleep(TELEMETRY_INTERVAL)
except KeyboardInterrupt: print("\n[INFO] Stopped by user") except Exception as e: print(f"[ERROR] Fatal: {e}") print("[INFO] Restarting in 10 seconds...") time.sleep(10) machine.reset() finally: if client: try: client.disconnect() except Exception: pass print("[INFO] Disconnected.")
main()Upload it to the ESP32:
mpremote connect /dev/ttyACM0 cp main.py :main.pyStep 5: Run and Test
Section titled “Step 5: Run and Test”Reset the ESP32 to start the scripts:
mpremote connect /dev/ttyACM0 resetOr press the RST button on the board. Then monitor the output:
mpremote connect /dev/ttyACM0Expected output:
[WIFI] Connecting to YOUR_WIFI_SSID........[WIFI] Connected! IP: 192.168.1.105
=== MicroPython ESP32 -> SiliconWit IO ===
[MQTT] Connecting to mqtt.siliconwit.io:8883...[MQTT] Connected to SiliconWit IO[TELEMETRY] Sent: {"temperature": 24.7, "humidity": 53.2, "uptime": 8, "free_memory": 112640}[TELEMETRY] Sent: {"temperature": 28.1, "humidity": 45.8, "uptime": 38, "free_memory": 112384}Step 6: Adding Real Sensors (Optional)
Section titled “Step 6: Adding Real Sensors (Optional)”DHT22 Temperature and Humidity
Section titled “DHT22 Temperature and Humidity”MicroPython includes a built-in dht module. Connect a DHT22 to GPIO 4 and update the read_sensors() function:
import dhtimport machine
dht_sensor = dht.DHT22(machine.Pin(4))
def read_sensors(): try: dht_sensor.measure() temp = dht_sensor.temperature() hum = dht_sensor.humidity() except OSError: temp = 0.0 hum = 0.0
return { "temperature": temp, "humidity": hum, "uptime": time.ticks_ms() // 1000, "free_memory": machine.mem_free(), }BME280 (Temperature, Humidity, Pressure)
Section titled “BME280 (Temperature, Humidity, Pressure)”For the BME280 sensor over I2C, install the driver and use:
from machine import I2C, Pinimport bme280
i2c = I2C(0, scl=Pin(22), sda=Pin(21))bme = bme280.BME280(i2c=i2c)
def read_sensors(): temp, pressure, hum = bme.values return { "temperature": float(temp.replace("C", "")), "humidity": float(hum.replace("%", "")), "pressure": float(pressure.replace("hPa", "")), }Step 7: View Data on SiliconWit IO
Section titled “Step 7: View Data on SiliconWit IO”- Log in to your SiliconWit IO dashboard.
- Navigate to your registered device.
- You should see telemetry data updating every 30 seconds.
- SiliconWit IO automatically detects and displays each data field.
Troubleshooting
Section titled “Troubleshooting”Flashing Issues
Section titled “Flashing Issues”| Symptom | Cause | Solution |
|---|---|---|
esptool cannot find the port | Wrong port or driver missing | Check ls /dev/ttyACM* /dev/ttyUSB*. Install CH340/CP210x drivers if needed. |
| Flash write fails | ESP32 not in bootloader mode | Hold BOOT, press RST, release BOOT, then run the flash command. |
mpremote shows no output | Wrong baud rate or port | Try mpremote connect /dev/ttyUSB0 or add --baud 115200. |
WiFi Issues
Section titled “WiFi Issues”| Symptom | Cause | Solution |
|---|---|---|
[WIFI] Connection failed! | Wrong SSID or password | Double-check credentials. ESP32 only supports 2.4 GHz WiFi. |
| WiFi connects then drops | Router compatibility | Try a different WiFi network. Some mesh routers cause issues. |
OSError: [Errno 118] | DNS resolution failed | Check your router’s DNS settings. Try restarting the router. |
MQTT Issues
Section titled “MQTT Issues”| Symptom | Cause | Solution |
|---|---|---|
OSError: [Errno -30592] | TLS handshake failed | Ensure ssl=True and ssl_params includes server_hostname. |
MQTTException: 5 | Authentication failed | Verify DEVICE_ID and ACCESS_TOKEN match your dashboard. |
MQTTException: 4 | Bad credentials format | Ensure username and password are strings, not bytes. |
OSError: [Errno 113] | Host unreachable | Check WiFi is connected. Verify broker address is correct. |
| Publishes stop after a while | Keepalive timeout | Reduce TELEMETRY_INTERVAL to less than keepalive value. |
Memory Issues
Section titled “Memory Issues”| Symptom | Cause | Solution |
|---|---|---|
MemoryError | ESP32 ran out of RAM | Reduce payload size. Use gc.collect() before allocations. |
ENOMEM during TLS | TLS buffer too large | Use a board with PSRAM (ESP32-S3 with 8MB). |
| Device resets randomly | Watchdog or stack overflow | Add gc.collect() in the main loop. Reduce JSON size. |
File Structure on ESP32
Section titled “File Structure on ESP32”After uploading both files, the ESP32 filesystem should contain:
/├── boot.py # WiFi connection (runs first on startup)├── main.py # MQTT telemetry (runs after boot.py)└── lib/ └── umqtt/ └── simple.py # MQTT library (installed via mip)The execution order on every boot or reset is:
boot.pyruns first and connects to WiFimain.pyruns next and starts the MQTT telemetry loop
Summary
Section titled “Summary”In this tutorial, you set up a complete MicroPython IoT telemetry system using:
- ESP32 as the microcontroller running MicroPython
- umqtt.simple for lightweight MQTT communication
- TLS encryption for secure data transmission on port 8883
- SiliconWit IO as the cloud platform for data visualization
- boot.py / main.py structure for clean startup sequencing
MicroPython makes it easy to rapidly prototype and test IoT applications without the compile-flash cycle of C/C++ firmware. You can edit files directly on the ESP32 via the REPL, making iteration fast. For production deployments with better performance, consider migrating to the Arduino/PlatformIO approach described in the ESP32 WiFi MQTT Relay tutorial.