Over-the-air updates for your home-made ESP32 fleet
Otter keeps track of your ESP32 and ESP8266 devices and updates their firmware from a single dashboard, with live progress, staged rollouts, release channels and automatic rollback.
A staged rollout to three weather stations: a canary first, with a look at its details page while it updates, then the rest. Real time, recorded with the device simulator.
Everything a small fleet needs
Built for the dozen devices on your shelf, ready for the hundred it may become.
๐ก Live inventory
Every device checks in with its firmware, signal and uptime, and tells what it's made of: exact chip, flash, PSRAM, radios. See who is online, search, filter and tag them.
โก Updates start in a second
Devices long-poll the server: a deployment reaches them within a second or two, and progress streams live to your browser.
๐ Safe by default
SHA-256 checks, bootloader rollback on ESP-IDF, downloads that resume after a stall, automatic retries, and images too big for a device's slot refused up front.
๐ช Staged rollouts
Release to 10 %, then 50 %, then everyone. Too many failures and the rollout halts before touching the rest of the fleet.
๐ค๏ธ Release channels
Publish on beta or stable and let devices follow a channel: they update themselves, and never downgrade.
๐ Notifications
Failed update, halted rollout, crash, device offline or brand new: get told on ntfy, Discord or any webhook.
๐๏ธ Commands and configuration
Reboot a device or blink its LED from the dashboard, and change its settings per tag or per device, applied within a second, no reboot.
๐ฅ Crash reports
A device that crashes sends its core dump summary: read the call stack with function names and source lines, per firmware version.
๐ชถ Tiny updates
Devices download a patch from the firmware they run, often a few tens of KB instead of a megabyte, or a compressed image. Stalled downloads resume where they stopped.
๐ถ Wi-Fi without recompiling
One image for every network: set the Wi-Fi over USB right after flashing (Improv, from a browser or a terminal), move a device to a new network from the dashboard.
๐ Battery devices
Deep-sleeping devices check in once per wake-up, stay "online" while asleep, and still get updates, commands and settings.
๐ Home Assistant & metrics
Devices show up in Home Assistant with a firmware update entity, and a Prometheus endpoint feeds your Grafana dashboards.
๐ณ Runs anywhere
One Docker image for amd64 and arm64 (Raspberry Pi), SQLite inside. HTTPS with Caddy, accounts and API tokens included.
๐ท๏ธ CI releases
Push a tag like weather/v1.6.0: CI builds every hardware variant with that version and uploads it to Otter.
How it works
Devices always call the server, never the other way around: no open port, no NAT trouble, sleepy devices welcome.
Add the agent
Drop the ESP-IDF component or the Arduino library into your firmware and point it at your Otter server.
Devices check in
Each device reports its state and waits for orders. It shows up on the dashboard within seconds.
Upload and deploy
Upload a .bin, deploy it to a device, a tag, a channel or the whole fleet, and watch the progress bars fill.
Hardware support
The protocol is small JSON requests over HTTP(S), documented: other boards and languages can speak it too.
| Chip | Framework | OTA + rollback | Long polling |
|---|---|---|---|
| ESP32 family (tested on ESP32-C6, builds for ESP32) | ESP-IDF component: HTTPS, device tokens, signatures, crash reports, mDNS | โ bootloader rollback | โ |
| ESP32 (tested on ESP32-C6, Arduino core 3) | Arduino library: device tokens, signatures, deep sleep | โ image validation | โ |
| ESP8266 | Arduino library | โ image validation | periodic check-ins |
Quick start
From nothing to a first over-the-air update in a few minutes.
Start the server
git clone https://github.com/XNinety9/otter cd otter && docker compose up -d docker compose exec otter \ python -m otter.cli create-user admin
Open http://<host>:8000 and log in.
Flash a device
export WIFI_SSID=โฆ WIFI_PASS=โฆ export OTTER_SERVER=http://<host>:8000 cd firmware/examples/esp32-idf pio run -e esp32c6 -t upload
It appears on the dashboard a few seconds later.
Ship an update
# token: python -m otter.cli create-token โฆ export OTTER_TOKEN=otk_โฆ tools/release.sh otter-demo 1.1.0
It builds and uploads every hardware variant. Click Roll out and watch it update.
No hardware yet? tools/simulate.py spins up a fleet of fake devices that speak the real protocol.
Security, honestly
HTTPS with Caddy, accounts and API tokens, a token per device that can be revoked alone, and signed firmware: devices refuse any image you didn't sign, even from a compromised server.
Over plain HTTP, anyone on your network could read passwords and serve a malicious firmware. Put Otter behind HTTPS before it leaves your desk: the guide shows how, and the protocol's security section says exactly what is protected.