Repository navigation
ESP32 decision firmware 0.1.0 — all ESP32 chips, safe serial OTA (preview)
Pre-releasePreview firmware from PR #1018, which is not merged yet. It runs RuVector decision models on the ESP32 itself, with no cloud or Wi-Fi needed. You can update it over the USB serial port, and it rolls back automatically if an update fails its self-test.
Plain-language guide: https://gist.github.com/ruvnet/c994f474e94ce2efbf088b9b1406488d
Which file do I need?
| Your chip | First install (flash at 0x0) |
Later updates (OTA) |
|---|---|---|
| ESP32 (original) | ruvector-decision-esp32-full-factory.bin |
ruvector-decision-esp32-full-ota.bin |
| ESP32-S2 | …-esp32s2-full-factory.bin |
…-esp32s2-full-ota.bin |
| ESP32-S3 | …-esp32s3-full-factory.bin |
…-esp32s3-full-ota.bin |
| ESP32-C2 (2 MB flash) | …-esp32c2-full-factory.bin |
…-esp32c2-full-ota.bin |
| ESP32-C3 | …-esp32c3-full-factory.bin |
…-esp32c3-full-ota.bin |
| ESP32-C6 | …-esp32c6-full-factory.bin |
…-esp32c6-full-ota.bin |
| ESP32-H2 | …-esp32h2-full-factory.bin |
…-esp32h2-full-ota.bin |
| ESP32-P4 | …-esp32p4-full-factory.bin |
…-esp32p4-full-ota.bin |
Each chip also has a production variant. It removes the profiling buffers, which frees 16 KB of RAM; inference, selftest, bench and energy all still work.
Install
pip install esptool
esptool.py --chip auto write_flash 0x0 ruvector-decision-esp32c6-full-factory.binYou can also use the browser flasher at https://espressif.github.io/esptool-js/: pick the factory file and set the address to 0x0. Then open a serial terminal at 115200 baud and send meta. The reply should include "selftest_pass":true.
Update over serial (OTA)
python3 examples/esp32-decision/tools/ota.py --port /dev/ttyUSB0 ruvector-decision-esp32c6-production-ota.binThis works on every chip, including the H2 and P4, which have no Wi-Fi. The board has two app slots. A new image is only kept if its model self-test passes after reboot; otherwise the board switches back to the previous image. The board rejects an image with the wrong SHA-256, an image built for another chip, and a transfer that stops partway.
What was verified (measured)
On a physical ESP32-C6 (CP210x, 160 MHz), using these exact images:
- factory boot, self-test and
bench: 174.5 µs per decision - OTA to the production image: committed, 21.6 s transfer
- OTA of a deliberately broken image: rolled back automatically
Earlier on the same board, with images built from identical sources:
- 1000/1000 decisions matched the Rust reference (INT16); INT8 matched 99.8%
- An 11-round paired rig with the real occupancy model gave exact decisions in every round, and the PR kernel was 1.056× faster than baseline. That is below the ADR's 1.10× bar for claiming a speedup.
- Six OTA rejection cases were each refused, with the board still running its previous image.
- The production image has 16,384 more bytes of free heap.
All 16 images were built with espressif/idf:v5.4.4 from commit 88e5b13. The C6 is the only chip that has run on silicon. The ESP32, S2, S3, C2, C3, H2 and P4 images are cross-compiled only and have not been run on hardware. Evidence is in examples/esp32-decision/tests/evidence/ (ota-esp32c6-physical.json, rig-esp32c6-physical.json, release-builds.json) and in the ADR-007 follow-up section.
Limits
- The bundled default model is the synthetic demo model. The occupancy model was trained on one office and is a benchmark, not a deployable occupancy detector.
- Boards need a USB-UART bridge on UART0; most DevKitC boards have one. Boards that only have the chip's built-in USB-Serial/JTAG port are not supported yet.
- OTA runs over the serial port only: there is no network OTA and no image signing. Anyone who can reach the port can already reflash the board through the ESP32's built-in serial bootloader.
- Not measured yet: energy, S3 physical rounds, and real sensor capture.
Verify downloads with sha256sum -c SHA256SUMS.