Devices¶
A device is a single physical ESP32 unit in the field.
Identity¶
A device is identified by (project, device_id). The device_id is
opaque to SimpleOTA; pick whatever is stable on your hardware:
- MAC address (
AA:BB:CC:DD:EE:FF): common for Wi-Fi-only fleets. - Serial number / chip ID: useful if you provision IDs at the factory.
- A UUID burned into NVS during first-boot: flexible, vendor-agnostic.
Warning
device_id participates in cohort hashing. Changing it on a unit
moves it to a different bucket and can flip its exposure to an
in-flight rollout.
Compatibility metadata¶
Devices declare their hardware so SimpleOTA can refuse to install
incompatible firmware. Reported by the device on every /check/ call:
| Field | Example | Notes |
|---|---|---|
framework |
arduino, esp-idf |
Required. |
chip_family |
esp32, esp32s3 |
Required. |
board_id |
esp32dev |
Free-form, must match artifact. |
hardware_revision |
rev-a |
Optional. |
partition_profile |
default_4mb |
Required for Arduino, must match. |
nvs_schema_version |
1 |
Bumped when NVS layout changes. |
security_mode |
basic, secure_boot_v2 |
Optional. |
A device only receives an artifact whose manifest matches all required dimensions. See Compatibility.
Lifecycle¶
stateDiagram-v2
[*] --> active: auto-register
active --> inactive: plan downgrade<br/>or admin action
inactive --> active: upgrade plan<br/>or re-activate
active --> [*]: delete
inactive --> [*]: delete
active = false devices keep their history but receive no updates.
This is how plan downgrades work without losing audit trail.
Auto-registration¶
Most fleets never manually create a device. The first call to
/api/v1/ota/check/ with a project token will create the device row,
provided:
- The plan's device limit hasn't been reached.
- The token belongs to the same project.
If the cap is hit, the response is 200 with
{"update_available": false, "status": "over_limit"} so the device doesn't
hammer-retry.