Layered view
Totem’s firmware is a MicroPython application organized into a small number of packages plus a set of top-level modules — 94 frozen modules in v5.0.3 (v5.0.2: 96; the unusedimu_fusion.py and io_mgr.py were removed). From the bottom up:
Packages
f_lib/ — platform library
Reusable infrastructure used by everything above it.
f_ble/ — Bluetooth LE
f_ota/ — update engine
Top-level modules by subsystem
- LEDs
- Input & sensors
- Mesh & peers
- Comms & upload
- Power & system
Concurrency model
The application is asyncio-based.f_lib/task_mgr.py and the frozen asyncio
package schedule long-running coroutines (BLE service loop, mesh outbox drain, GNSS
polling, LED animation ticks, background checks). Many tasks wait on evt_* events from
the event_manager bus before doing work, so subsystems can be paused and resumed — for
example, evt_ble_active and evt_battery_usable gate BLE and battery-dependent tasks,
and Vibe Mode (new_vibe) waits on events such as evt_non_eco_mode and
evt_led_override_off. (The v5.0.2 log lines task started, waiting on enable events /
task cancelled came from Vibe Mode’s _DBG telemetry and no longer exist in v5.0.3.)
In v5.0.3 compass.start launches the ESP-NOW comms task through
enow_v2.communicate_supervised, which restarts it if it crashes (v5.0.2 launched
communicate_v2 directly).
A separate async watchdog-feed loop (wdt_manager.py / WdtManager) runs alongside
task_mgr and asyncio: it feeds the hardware WDT via wdt_feed_loop / feed_now, but
is disabled while any WdtConditions condition or WdtBlockers blocker is active
(_should_enable returns False). v5.0.3’s blockers are log rotate, vfs write, and the
new wlan kick (WLAN_KICK = 2, set by ble_manager around its WiFi-driver kick). When
the loop is running, a stalled event loop stops the feed and lets the watchdog fire.