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.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 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.pyandwebrepl_cfg.py, for 96 total.pyfiles; 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).
Firmware architecture
MicroPython app layout, the 94 frozen modules, and how they fit together.
2.4 GHz protocols
BLE, ESP-NOW mesh, WiFi OTA — message format, categories, and framing.
Navigation stack
u-blox GNSS, AssistNow, IMU fusion, and World Magnetic Model declination.
OTA & download URL
How updates are fetched and how the firmware URL is constructed.
Firmware at a glance
How to read this documentation
Findings are graded by how directly the binary supports them:Confirmed
Confirmed
Directly present in the image: version strings, module names, GATT UUIDs,
struct/format strings, log messages, and the observed
(cat_id, cmd_id) pairs.Inferred
Inferred
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).
Needs bytecode disassembly
Needs bytecode disassembly
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 for how to close these gaps.