FastAPI for the physical world.
A Python-native IoT framework for MicroPython · ESP32 · Raspberry Pi Pico W · Edge Devices
Writing MicroPython for ESP32 or Raspberry Pi Pico W today means bare metal — no routing, no middleware, no conventions. You wire up pins, call uasyncio.run(), and figure out the rest yourself.
VOLT fixes that. It brings the developer experience of FastAPI to constrained hardware in a footprint small enough to fit in an ESP32's flash.
from volt import App
from volt.sensors import DHT22
from volt.connectivity import WiFiConfig, MQTTConfig
app = App(device="esp32")
sensor = DHT22(pin=4)
app.config(
wifi=WiFiConfig(ssid="MyNetwork", password="secret"),
mqtt=MQTTConfig(broker="192.168.1.10"),
)
# HTTP endpoint
@app.get("/status")
def status():
return {"temp": sensor.temperature, "uptime": app.uptime()}
# MQTT subscription
@app.subscribe("home/lights/set")
def set_lights(payload):
lights.set(payload["state"])
# Periodic task
@app.every(seconds=30)
async def heartbeat():
await app.mqtt.publish("device/heartbeat", {"id": app.device_id})
app.run()Flash it:
volt flash main.py --port /dev/ttyUSB0- Captive Portal Provisioning: Touchless AP-fallback setup when WiFi drops.
- Over-The-Air (OTA) Updates: Atomic A/B dual-bank firmware flashing triggered via MQTT or HTTP.
- Fleet Telemetry: Continuous zero-config streaming of RAM, RSSI, and Uptime metrics.
- True Async Sensors: 100% non-blocking hardware interrupt (IRQ) driver architecture.
- Bounded Offline Queues: Configurable MQTT offline queue policies (
drop_oldest) to prevent memory leaks.
One decorator syntax across HTTP, MQTT, BLE, and WebSocket. Define your handler once — VOLT wires it to the right transport.
@app.get("/sensor") # HTTP GET
@app.subscribe("topic/in") # MQTT subscribe
@app.ble_characteristic("temp") # BLE GATT characteristicClean decorators for every embedded task pattern, built on uasyncio:
@app.every(seconds=10) # periodic
@app.on_pin(pin=4, trigger=RISING) # hardware interrupt
@app.when(lambda: temp.read() > 80) # threshold trigger
@app.on_connect # WiFi/MQTT connected
@app.on_disconnect # connection lostWiFi drops. MQTT brokers go down. VOLT handles it:
- Auto-reconnect with exponential backoff
- Offline queue — buffer messages to flash, flush on reconnect
- AP fallback mode — become a setup hotspot if WiFi is lost
- Heartbeat monitoring — detect silent failures
Swap hardware without rewriting application logic:
from volt.sensors import DHT22, SoilMoisture, Ultrasonic, BME280
temp = DHT22(pin=4)
soil = SoilMoisture(pin=34, adc_resolution=12)
dist = Ultrasonic(trigger=5, echo=18)
env = BME280(i2c_id=0, sda=21, scl=22)
# Unified interface across all sensors
print(temp.temperature, temp.humidity)
print(soil.percentage)
print(dist.cm)
print(env.pressure)Survives reboots. Optionally syncs to the cloud:
app.state.set("last_watered", time.time()) # written to flash
app.state.get("last_watered") # read back after reboot
app.state.sync_to("mqtt") # auto-publish on changeapp.watchdog(timeout=30) # auto-reboot if hung
app.crash_log(max_entries=10) # store crashes in flash
app.health_check(interval=60) # ping home server# Deploy code to device
volt flash main.py --port /dev/ttyUSB0
# Stream live logs
volt monitor --port /dev/ttyUSB0
# Open interactive REPL on device
volt shell --port /dev/ttyUSB0
# Discover VOLT devices on your network
volt scan
# Over-the-air update
volt ota push main.py --device 192.168.1.42
# Launch local web dashboard
volt dashboardvolt dashboard starts a local web UI that auto-discovers devices on your network:
- 📈 Live sensor readings with time-series graphs
- 💓 Device health — uptime, free RAM, WiFi RSSI
- 📨 MQTT message log (filterable by topic)
- 🔄 One-click OTA firmware push
- 🪲 Crash log viewer with full stack traces
| Device | WiFi | BLE | Flash | Status |
|---|---|---|---|---|
| ESP32 | ✅ | ✅ | 4MB | ✅ Supported |
| ESP32-S3 | ✅ | ✅ | 8MB | ✅ Supported |
| ESP8266 | ✅ | ❌ | 1MB | |
| Raspberry Pi Pico W | ✅ | ❌ | 2MB | ✅ Supported |
| Raspberry Pi Pico 2W | ✅ | ✅ | 4MB | 🚧 In Progress |
graph TD
classDef hardware fill:#f9f9f9,stroke:#333,stroke-width:2px;
classDef core fill:#e1f5fe,stroke:#0288d1,stroke-width:2px;
classDef protocol fill:#f3e5f5,stroke:#8e24aa,stroke-width:2px;
App["App Orchestrator<br/>(Router / Scheduler / State)"]:::core
subgraph "Edge Interfaces"
HTTP["HTTP / Captive Portal"]:::protocol
MQTT["MQTT + Bounded Queue"]:::protocol
BLE["BLE GATT"]:::protocol
end
subgraph "Hardware Abstraction"
OTA["OTA Manager (A/B Partition)"]:::core
Sensors["Async IRQ Sensors"]:::core
Tele["Fleet Telemetry"]:::core
end
HW["MicroPython / Hardware"]:::hardware
App --> HTTP
App --> MQTT
App --> BLE
App --> OTA
App --> Sensors
App --> Tele
OTA --> HW
Sensors --> HW
Tele --> HW
- Memory-first — the entire runtime fits under 40KB, leaving headroom for your app
- Fail gracefully — disconnections and crashes never permanently brick a device
- Convention over configuration — sensible defaults, zero-config for the 80% case
- No CPython assumptions — zero reliance on stdlib modules absent in MicroPython
- Protocol-agnostic handlers — one function can serve HTTP, MQTT, and BLE simultaneously
Upload via the CLI (recommended):
pip install volt-iot
volt flash main.py --port /dev/ttyUSB0Or copy manually using mpremote or ampy:
mpremote cp -r volt/ :volt/
mpremote cp main.py :main.pypip install volt-iotRequires Python 3.8+ on the host machine.
| Example | Description |
|---|---|
examples/temperature_logger |
Read DHT22, publish to MQTT every 30s |
examples/smart_switch |
HTTP + MQTT controlled relay |
examples/soil_monitor |
Soil sensor with threshold alerts |
examples/ble_beacon |
BLE GATT server with sensor characteristics |
examples/multi_protocol |
Same handler over HTTP, MQTT, and BLE |
examples/ota_update |
Self-updating firmware pattern |
v0.2 Enterprise shipped. All core routing and fleet administration features are active.
- Captive Portal AP fallback WiFi provisioning
- Over-The-Air (OTA) Updates with A/B partitioning via HTTP/MQTT
- Fleet Telemetry (RAM, Storage, RSSI, Uptime)
- Bounded Configurable MQTT Offline Queues
- Hardware Interrupt (IRQ) Async Sensor Drivers
- HTTP server (
@app.get,@app.post,@app.put,@app.delete) - MQTT pub/sub (
@app.subscribe,app.mqtt.publish, offline queue) - Periodic task scheduler (
@app.every) - Pin interrupt tasks (
@app.on_pin) - Threshold triggers (
@app.when) - Lifecycle hooks (
@app.on_connect,@app.on_disconnect) - Persistent state (flash-backed KV store, atomic writes)
- Watchdog + crash logging
- Health check (periodic HTTP ping)
- BLE GATT server (read + notify via
ubluetooth) - WebSocket server (RFC 6455, full frame parsing)
- Sensor library — DHT22, BME280, SoilMoisture, Ultrasonic
- CLI:
flash,monitor,shell,scan,ota,dashboard - Dashboard UI (Chart.js live graphs, OTA panel, crash log viewer)
- OTA updates (
/ota/uploadendpoint +volt ota push)
BLE write-characteristic support is deferred to v0.2.
Contributions are very welcome. VOLT is most useful when it supports a wide range of sensors and protocols.
git clone https://github.com/your-org/volt
cd volt
pip install -e ".[dev]"
pytestPlease open an issue before starting large features so we can align on direction.
MIT — see LICENSE for details.
Built for the makers, engineers, and hobbyists who believe Python belongs everywhere — including the physical world.