Boot sequence
- The bootloader validates the appended image SHA-256 and the OTA-data partition, then jumps into the selected app slot. Failed or rolled-back updates land on the previous good slot (see OTA).
_boot.pymounts the filesystem throughflashbdev.py(the flash block device).inisetup.pyperforms first-boot filesystem setup.boot.py(a VFS file on flash, distinct from the frozen_boot.py) runs on every boot, including wake from deep sleep, immediately beforemain.py.main.py/project_main.pybring up the application: event bus, task manager, LEDs, radios, GNSS, and the compass state machine. In v5.0.3compass.startlaunches the ESP-NOW comms task viaenow_v2.communicate_supervised, which restarts it on a crash (v5.0.2:communicate_v2directly).
Power / boot modes
device_power.py tracks an application-level boot_mode and a battery-health state. Observed
states and transitions (from log strings and symbols):
Reset cause vs. boot-loop protection
The appboot_mode above is separate from the hardware reset cause the ESP reports
(Reset Cause: {} — e.g. WDT_RESET, DEEPSLEEP_RESET). A boot-failure / crash-counter
mechanism guards against boot loops: it tracks boot_count, boots_failed
(with boots_failed_max / boots_failed_min) and boots_wdt, and on a bad boot runs a WDT
recovery path (check_bootsec, calc_recovery_risk, check_recovery_cache,
Performing immediate WDT Recovery) before rebooting (Rebooting from: {} in 3sec,
Is Reboot a Continued Session: {}).
Remote power control (demigod)
Power state can be commanded remotely over the mesh. A peer can send a demigod power-control command (Power control demigod command received, demigod_gen_pwr_control) that changes the
power mode or triggers power-down (Sending demigod command to power down), subject to a
qualification gate (Device disqualified from demigod command).
Sleep
The device uses both light and deep sleep aggressively to save power.Light sleep
Periodic wake with duty tracking:
Awoke from lightsleep | Slept for: {} of {} | Total Sleep: {} | sleep duty: {:.3f}.
GNSS RTC sync can block sleep (Block sleep for GNSS RTC Sync).Deep sleep
State is preserved in RTC memory (
f_lib/rtc_mem.py, rtc_v2.py) — notably BLE pairing
secrets (BLE secrets found in RTC memory, saving to VFS, later flushed to VFS) and a
device snapshot (is_rtc_snapshot, snapshot_coords / snapshot_ticks / snapshot_travel)
so navigation state survives sleep. On wake:
Awake from Deep Sleep | {} | Free mem: {}.[touch] Low battery mode ON/OFF adjusts
the capacitive baseline so the Touch Crystal still works as the battery drains. This
low-battery touch state (constant BATT_POOR_TOUCH) is part of the touch subsystem, not a
value of the battery-health enum above.
Watchdog
wdt_manager.py is not a plain task-WDT wrapper but a condition/blocker engine
(WdtManager / WdtConditions / WdtBlockers): an async feed loop (Starting WDT feed loop)
feeds the native task watchdog (mpy_machine_wdt / task_wdt), and is disabled while any
condition or blocker is active — _should_enable returns False ([WDT {}] cond=[{}] blk=[{}]).
The v5.0.3 blockers are ('log rotate', 'vfs write', 'wlan kick'); WLAN_KICK = 2 is new,
set and cleared by ble_manager around its WiFi-driver “kick” (v5.0.2 had only the first
two). It supports dynamic threshold changes
(Updating WDT threshold from: {} to {}) and drives a recovery/reboot path
(Performing immediate WDT Recovery, restore_wdt_reboot) that ties into the boot-failure
counters above.
A separate BLE handoff watchdog (ble_handoff_watchdog, [BLE Watchdog] Handoff stall detected)
arbitrates BLE TX-priority ownership between the phone app and the ESP
(last_handoff_to_app / last_handoff_to_esp); when a handoff stalls it reclaims TX priority.