OTA Update Mechanism¶
Why a State Machine¶
OTA updates are long-running, multi-step operations that can fail at any
stage. A finite state machine (FSM) makes the allowed transitions explicit,
prevents illegal state combinations, and provides a clear recovery path from
every failure mode. The current state is always observable via GetOTAStatus.
State Persistence and Power-Loss Recovery¶
When entering one of six checkpointable states (update_available,
downloading, paused, update_ready, download_failed, update_failed),
OTAStateMachine writes an OTASnapshot to a YAML checkpoint file at
DEFAULT_CHECKPOINT_FILE (/data/tolomeo/ota-service.yml). The snapshot
records the current state, installed firmware info, and pending update info.
Entering updated or update_successful instead deletes the checkpoint.
Note
If /data does not exist at runtime (development machines, CI
environments), the checkpoint falls back to
<tempdir>/tolomeo/ota-service.yml (e.g. /tmp/tolomeo/ota-service.yml
on Linux). Production edge devices are expected to have /data mounted.
That path is the default, not a fixture. A deployment relocates it, and the downloaded package, through the plugin's configuration table:
[plugins.swupdate]
download_dir = "/data/firmware"
download_filename = "image.swu"
checkpoint_file = "/data/firmware/ota-state.yml"
OTAPlugin applies checkpoint_file in before_setup, which is the first point
where both the plugin id — the table is keyed by it — and the configuration are
known. Entering bootstrapping both reads a snapshot and, if one is found,
writes another, so the state machine is constructed with bootstrapping deferred
and stays in that state until the location is assigned. See the
Configuration Reference.
Once its location is known, the FSM enters the bootstrapping state and reads
the checkpoint file. It selects one of the six detect_* transitions to move to
the correct runtime state:
bootstrapping → updated (no pending update)
bootstrapping → update_available (update was announced)
bootstrapping → paused (download was in progress but paused)
bootstrapping → update_ready (download completed, not yet installed)
bootstrapping → download_failed (download was in progress and failed)
bootstrapping → update_failed (install was in progress and failed)
This means the service survives a power cut at any point in the update lifecycle and resumes from exactly where it left off.
Download Task Synchronisation¶
OTAPlugin does not drive the FSM directly during a download. Instead, it
registers callbacks on TaskManager via _on_download_state_change and
_on_download_error. When the download task completes, the callback fires
fsm.download_success(); on failure it fires fsm.download_fail(). This
decouples the FSM from the asyncio task scheduler.
Error Recovery¶
Every failure state has exactly one recovery path:
| State | Recovery command | Resulting state |
|---|---|---|
download_failed |
AbortOTAUpdate |
update_available |
update_failed |
AbortOTAUpdate |
update_available |
| Any state | ResetOTAState |
Returns the FSM to a clean baseline (bootstrapping → re-detect → updated), discarding any pending update |
CancelOTAUpdate applies to in-progress states (downloading, paused,
update_ready) and returns to update_available without clearing the
pending update info, allowing an immediate retry.