Skip to content

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.

  • How to flash MicroPython firmware onto an ESP32
  • How to connect the ESP32 to WiFi using MicroPython
  • How to install and use the umqtt.simple library for MQTT
  • How to establish a TLS-encrypted connection to the SiliconWit IO MQTT broker
  • How to publish JSON telemetry data from a boot.py and main.py structure
ComponentDescription
ESP32 Development BoardAny ESP32, ESP32-S3, or ESP32-C3 board
USB CableFor programming and powering the ESP32
WiFi Network2.4 GHz WiFi with internet access
SoftwarePurpose
esptoolFlash MicroPython firmware to the ESP32
mpremoteTransfer files and interact with the ESP32 REPL
SiliconWit IO AccountFree IoT platform account

After registering a device on your SiliconWit IO dashboard, note down:

CredentialExampleDescription
Device IDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxUnique device identifier (MQTT username and client ID)
Access Tokenyour_access_token_hereMQTT password
Publish Topicd/{device_id}/tTopic for sending sensor data (d = device, t = telemetry)

Keep your access token secure. Never share it publicly or commit it to version control.

Terminal window
pip install esptool mpremote

Download the latest stable MicroPython firmware for your ESP32 variant from the official MicroPython downloads page:

BoardFirmware Page
ESP32 (original)micropython.org/download/ESP32_GENERIC
ESP32-S3micropython.org/download/ESP32_GENERIC_S3
ESP32-C3micropython.org/download/ESP32_GENERIC_C3

Download the .bin file (e.g., ESP32_GENERIC-20241129-v1.24.1.bin).

Find your ESP32 serial port:

Terminal window
ls /dev/ttyACM* /dev/ttyUSB*

Erase the flash and write the new firmware:

Terminal window
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.bin

Note: For ESP32-S3 or ESP32-C3, change --chip esp32 to --chip esp32s3 or --chip esp32c3, and the flash offset may differ. Check the MicroPython download page for the exact command for your board.

Connect to the REPL:

Terminal window
mpremote connect /dev/ttyACM0

You should see the MicroPython prompt:

MicroPython v1.24.1 on 2024-11-29; Generic ESP32 module with ESP32
Type "help()" for more information.
>>>

Press Ctrl+] to exit mpremote.

The umqtt.simple library provides a lightweight MQTT client for MicroPython. Install it using mpremote:

Terminal window
mpremote connect /dev/ttyACM0 mip install umqtt.simple

This downloads and installs the library directly onto the ESP32’s filesystem.

If mip install fails due to network issues on the ESP32, you can install it after WiFi is configured in boot.py by running import mip; mip.install("umqtt.simple") from the REPL.

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 network
import 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:

Terminal window
mpremote connect /dev/ttyACM0 cp boot.py :boot.py

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 ssl
import json
import time
import machine
from umqtt.simple import MQTTClient
# ========== SILICONWIT IO MQTT CONFIGURATION ==========
MQTT_BROKER = "mqtt.siliconwit.io"
MQTT_PORT = 8883
DEVICE_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:

Terminal window
mpremote connect /dev/ttyACM0 cp main.py :main.py

Reset the ESP32 to start the scripts:

Terminal window
mpremote connect /dev/ttyACM0 reset

Or press the RST button on the board. Then monitor the output:

Terminal window
mpremote connect /dev/ttyACM0

Expected 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}

MicroPython includes a built-in dht module. Connect a DHT22 to GPIO 4 and update the read_sensors() function:

import dht
import 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(),
}

For the BME280 sensor over I2C, install the driver and use:

from machine import I2C, Pin
import 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", "")),
}
  1. Log in to your SiliconWit IO dashboard.
  2. Navigate to your registered device.
  3. You should see telemetry data updating every 30 seconds.
  4. SiliconWit IO automatically detects and displays each data field.
SymptomCauseSolution
esptool cannot find the portWrong port or driver missingCheck ls /dev/ttyACM* /dev/ttyUSB*. Install CH340/CP210x drivers if needed.
Flash write failsESP32 not in bootloader modeHold BOOT, press RST, release BOOT, then run the flash command.
mpremote shows no outputWrong baud rate or portTry mpremote connect /dev/ttyUSB0 or add --baud 115200.
SymptomCauseSolution
[WIFI] Connection failed!Wrong SSID or passwordDouble-check credentials. ESP32 only supports 2.4 GHz WiFi.
WiFi connects then dropsRouter compatibilityTry a different WiFi network. Some mesh routers cause issues.
OSError: [Errno 118]DNS resolution failedCheck your router’s DNS settings. Try restarting the router.
SymptomCauseSolution
OSError: [Errno -30592]TLS handshake failedEnsure ssl=True and ssl_params includes server_hostname.
MQTTException: 5Authentication failedVerify DEVICE_ID and ACCESS_TOKEN match your dashboard.
MQTTException: 4Bad credentials formatEnsure username and password are strings, not bytes.
OSError: [Errno 113]Host unreachableCheck WiFi is connected. Verify broker address is correct.
Publishes stop after a whileKeepalive timeoutReduce TELEMETRY_INTERVAL to less than keepalive value.
SymptomCauseSolution
MemoryErrorESP32 ran out of RAMReduce payload size. Use gc.collect() before allocations.
ENOMEM during TLSTLS buffer too largeUse a board with PSRAM (ESP32-S3 with 8MB).
Device resets randomlyWatchdog or stack overflowAdd gc.collect() in the main loop. Reduce JSON size.

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:

  1. boot.py runs first and connects to WiFi
  2. main.py runs next and starts the MQTT telemetry loop

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.