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), and the ESP-NOW
mesh with an ESP32 emulator that bonded with that device; 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 complete is this?
The inventory is complete: all 94 frozen modules are identified and every one of them appears in these docs. The analysis is not. Of the 68 modules that are Totem’s own code (the other 26 are stock MicroPython and empty package inits), 28 have had their behaviour read out of the bytecode, 27 are partly decoded, and 13 are documented by name only and have never been read — includingf_lib/logger.py, which 41 of the other modules import. By volume of disassembly, that is
roughly 55% decoded, 35% partial, 10% untouched.
The module reference rates every module individually and ranks what
is left, so you can tell a verified claim from a plausible guess before relying on it.
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.