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

# Totem Compass Firmware

> Reverse-engineering documentation for the Totem Compass ESP32 firmware, version 5.0.3.

<Note>
  This is independent, unofficial reverse-engineering documentation produced by static
  analysis of publicly downloadable firmware images. It is not affiliated with or
  endorsed by Totem Labs. No services were attacked. Findings come from reading the firmware
  binaries and the companion mobile app. The BLE protocol was additionally exercised with the
  `totemctl` client against the author's own device (firmware 4.1.3 and 5.0.3); where that
  changed a conclusion, the page says so.
</Note>

## What this documents

The **Totem Compass** is a festival navigation and social device: a handheld puck with
a ring of addressable LEDs (called the "halo" in the companion app; `RING_PX_COUNT` in
firmware), a light-up capacitive touch crystal (the app's "Touch Crystal";
`CRYSTAL_PX_COUNT` plus the ESP32 `touch_pad` peripheral), a GNSS receiver, an IMU, and
three 2.4 GHz radios. Groups of Totems bond into a mesh so friends can find
each other, send taps and messages, and navigate to a shared point.

This site documents firmware **v5.0.3** at the level recoverable from the binary. It started
from v5.0.2; [What changed in 5.0.3](/firmware/changes-5.0.3) lists the differences.

* The firmware is an **ESP32** application built on **ESP-IDF v5.4**.
* The device runs **MicroPython v1.25.0**; all of Totem's own logic is **Python**,
  frozen into the image as compiled bytecode across **94 modules** (plus 2 on-flash VFS
  source files, `boot.py` and `webrepl_cfg.py`, for 96 total `.py` files; v5.0.2 had 96
  frozen modules).
* Three radios share the 2.4 GHz band: **BLE** (phone app), **ESP-NOW** (Totem-to-Totem
  mesh, called the "Unity Mesh" in the companion app; `MODE_ESP_NOW_*` / `MESH_*` in
  firmware), and **WiFi** (station-mode OTA updates; the device-hosted hotspot path is sunset).

<CardGroup cols={2}>
  <Card title="Firmware architecture" icon="microchip" href="/firmware/architecture">
    MicroPython app layout, the 94 frozen modules, and how they fit together.
  </Card>

  <Card title="2.4 GHz protocols" icon="tower-broadcast" href="/protocols/overview">
    BLE, ESP-NOW mesh, WiFi OTA — message format, categories, and framing.
  </Card>

  <Card title="Navigation stack" icon="location-crosshairs" href="/subsystems/navigation">
    u-blox GNSS, AssistNow, IMU fusion, and World Magnetic Model declination.
  </Card>

  <Card title="OTA & download URL" icon="download" href="/reference/download-url">
    How updates are fetched and how the firmware URL is constructed.
  </Card>
</CardGroup>

## Firmware at a glance

| Property             | Value                                                                                                                                                                      |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Product              | Totem Compass                                                                                                                                                              |
| Version              | 5.0.3 (S3 branch `totem`), release id 339: `f_ota/system.py` constants `release_code = '5.0.3'`, `release_id = 339`; the device reports the same in its BLE Static Data    |
| SoC                  | ESP32 (original), Xtensa dual-core (LX6, inferred), chip id 0 (inferred; `ESP_CHIP_ID_ESP32`)                                                                              |
| Framework            | ESP-IDF v5.4 (`-dirty`)                                                                                                                                                    |
| Runtime              | MicroPython v1.25.0 (`MicroPython v1.25.0-dirty on 2026-09-16`)                                                                                                            |
| Build date           | Sep 12 2026, 16:11:34                                                                                                                                                      |
| Image size           | 1,699,872 bytes                                                                                                                                                            |
| SHA-256 (image file) | `bfe1f5a4c39790d068ab4f041a6a56766f4b21f48289518d83d831b323450dc4` (of the flashable `.bin`; matches the release API and the download)                                     |
| App ELF SHA-256      | `97a29359fa06661ac57840a7d041650ed1fdb08aca8712ec2373d91ea37b5777` (`esp_app_desc_t.app_elf_sha256`, pins the source ELF; a distinct value from the image-file hash above) |
| Flash                | 4 MB, DIO @ 40 MHz (read from the image header via `esptool`)                                                                                                              |
| Segments             | 7 (see [memory map](/firmware/memory-map))                                                                                                                                 |

## How to read this documentation

Findings are graded by how directly the binary supports them:

<AccordionGroup>
  <Accordion title="Confirmed" icon="circle-check">
    Directly present in the image: version strings, module names, GATT UUIDs,
    struct/format strings, log messages, and the observed `(cat_id, cmd_id)` pairs.
  </Accordion>

  <Accordion title="Inferred" icon="circle-half-stroke">
    Strongly implied by symbol names and log text but assembled by the analyst
    (for example, the role of a module or the meaning of a command namespace).
  </Accordion>

  <Accordion title="Needs bytecode disassembly" icon="circle-question">
    Exact numeric values that live only inside frozen bytecode — the complete
    `cmd_id` enumeration and the precise binding of each `struct` format to a message.
    See [methodology](/reference/methodology) for how to close these gaps.
  </Accordion>
</AccordionGroup>
