> ## Documentation Index
> Fetch the complete documentation index at: https://totem-cb8b3887.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Application architecture

> The MicroPython application: 94 frozen modules (v5.0.3) and how they are layered.

## 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 unused `imu_fusion.py` and `io_mgr.py` were removed). From the bottom up:

```text theme={null}
┌─────────────────────────────────────────────────────────────┐
│  Application    compass.py · compassing.py · main.py          │
│                 project_main.py · new_vibe.py · chat_msg.py    │
├─────────────────────────────────────────────────────────────┤
│  Comms          f_ble/ (BLE)   espnow*/peer* (ESP-NOW mesh)    │
│                 data_upload_v2 · svc_ble_transfer · ota_ble    │
├─────────────────────────────────────────────────────────────┤
│  Sense & act    ubx_gnss · imu_fusion_auto · mag_wmm_data      │
│                 leds · animations · touch_button_v2             │
│                 button · device_power · ds18x20                 │
├─────────────────────────────────────────────────────────────┤
│  Platform lib   f_lib/ (wifi, requests, task_mgr, rtc, gzip,   │
│                 tarfile, logger, file_mgr, firmware_ota…)       │
├─────────────────────────────────────────────────────────────┤
│  Runtime        MicroPython v1.25.0 · asyncio · espnow · ble    │
│                 (native, on ESP-IDF v5.4)                       │
└─────────────────────────────────────────────────────────────┘
```

## Packages

### `f_lib/` — platform library

Reusable infrastructure used by everything above it.

| Module                                                           | Role                                                                                  |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `wifi.py`, `wifi_v2.py`                                          | station/AP control, connect, scan                                                     |
| `requests.py`                                                    | HTTP client (used by OTA and cloud sync)                                              |
| `task_mgr.py`, `async_helpers.py`, `generators.py`               | asyncio task orchestration                                                            |
| `event_manager.py` (top-level)                                   | pub/sub event bus (`evt_*` events)                                                    |
| `rtc_mem.py`                                                     | the RTC-memory allocator — frames retained in `machine.RTC().memory()` across a reset |
| `rtc_v2.py`                                                      | *not* RTC storage: `class RTCv2(machine.RTC)` adding calendar/timestamp maths         |
| `file_mgr.py`, `gzip.py`, `tarfile.py`, `unpack.py`              | file + archive handling for `.tgz` OTA packages                                       |
| `firmware_ota.py`, `firmware_rollback.py`, `firmware_helpers.py` | OTA slot write + rollback                                                             |
| `neopixel_v2.py`                                                 | the addressable-LED driver — `leds.py` imports `NeoPixel` from here                   |
| `bitwise.py`, `helpers.py`, `logger.py`                          | utilities and structured logging                                                      |

### `f_ble/` — Bluetooth LE

| Module           | Role                                                                                                                                                                   |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `peripheral.py`  | builds the BLE advertising payload (`gen_advertise_payload`)                                                                                                           |
| `ble_lite.py`    | `BleLite` GATT peripheral: `advertise`/`advertise_burst`, `enable`/`disable`, `register_services`, `add_characteristic`, connection lifecycle (`irq_cb`, `disconnect`) |
| `ble_data.py`    | GATT data types: `Characteristic` (flag bits), `Service`, `Conn` (connection status), `BleErr`                                                                         |
| `chunking.py`    | fragmenting large payloads into chunks (`FileTransfer`, `gen_transfer_buff`, `download_ota`/`download_vfs`)                                                            |
| `file_upload.py` | chunked file transfer with resume/ACK (`FileUploader`: `request`, `_send_header`, `_stream`, pause gates)                                                              |

### `f_ota/` — update engine

| Module                                  | Role                                                                                                                                        |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `main.py`                               | OTA orchestration                                                                                                                           |
| `hotspot.py`                            | phone-hotspot update flow (`totemupdate` SSID) — now **sunset**; WiFi OTA (`Performing Firmware update via WiFi`) is the active update path |
| `install_ota.py`                        | write + activate the new slot                                                                                                               |
| `config.py`, `system.py`, `f_assets.py` | update config, system helpers, asset fetch                                                                                                  |

## Top-level modules by subsystem

<Tabs>
  <Tab title="Compass & nav">
    `compass.py`, `compassing.py`, `ubx_gnss.py`, `nav_helpers.py`, `nav_logger.py`,
    `imu_fusion_auto.py`, `mag_wmm_data.py`, `task_mag_declination.py`
  </Tab>

  <Tab title="LEDs">
    `leds.py`, `animations.py`, `f_lib/neopixel_v2.py`.
    (`neopixel.py` and `apa106.py` are also frozen but are
    [dead code](/reference/modules) — nothing imports them.)
  </Tab>

  <Tab title="Input & sensors">
    `button.py`, `touch_button_v2.py`, `peripherals.py`, `ds18x20.py`, `onewire.py`,
    `new_vibe.py`
  </Tab>

  <Tab title="Mesh & peers">
    `espnow.py`, `espnow_conn_v2.py`, `espnow_msg.py`, `aioespnow.py`,
    `peer_auto_bond.py`, `peer_helpers.py`, `peer_management.py`
  </Tab>

  <Tab title="Comms & upload">
    `ble_controller.py`, `ble_core.py`, `ble_manager.py`, `svc_ble_transfer.py`,
    `data_upload_v2.py`, `ota_ble.py`, `ota_block_writer.py`, `ota_callback.py`,
    `ota_daemon.py`, `chat_msg.py`
  </Tab>

  <Tab title="Power & system">
    `device_power.py`, `wdt_manager.py`, `stats.py`, `debugger.py`,
    `demi_god.py`, `flashbdev.py`, `inisetup.py`, `webrepl.py`, `mip/`
  </Tab>
</Tabs>

The full list with one-line descriptions is on the [module reference](/reference/modules),
which also rates each module **DECODED / PARTIAL / NAME-ONLY** so you can tell which of
the roles above were read out of the bytecode and which are still guesses. Of the 68 Totem
application modules, 28 are decoded, 27 are partial, and 13 have never been read.

## 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.
