Skip to main content
Every module below is frozen into the firmware. Names are exact, taken from the frozen module registry. Roles are not all equally trustworthy, so each one carries a status marker saying how it was established.

How much of this firmware is actually decoded?

This page used to say roles were “inferred from symbols, string constants, and log lines” without saying which ones. That understated some modules and overstated others. The table below is the result of an explicit audit: every module was checked against its disassembly in re/v5.0.3/mpy/*.dis.
The 94 modules split into 68 Totem application modules, 23 stock MicroPython modules, and 3 empty package __init__.py files. Coverage of the Totem code — the only part worth decoding — is:
No module is documented by name alone any more. When this audit first ran the split was 28 / 27 / 13 — 55% of the bytecode decoded, and thirteen modules, 9,534 lines, never read at all. Those thirteen have since been read, and five modules moved from PARTIAL to DECODED with them.What remains is 22 PARTIAL modules, 23,865 lines: real internals documented and verified, main logic not. That is a different and smaller claim than “not decoded”, and the per-module tables below say which is which.
“Decoded” still does not mean “correct”. The same audit that produced these ratings found roughly sixty-five false claims across these pages, several of them stamped confirmed — a driver that is dead code, a deep-sleep mode that does not exist, a BLE central role the firmware does not compile, and an OTA hash that is never computed. Every rating here is a statement about how much was read, not a warranty on every sentence. Where a page marks a claim inferred or not recoverable, that is the honest state of it.
The counts above are module counts and raw disassembly line counts, which are a proxy for volume, not for importance. The ranked gap list below weights by how much other code depends on each module.

What is left to do, in priority order

Every module that was documented by name alone has now been read. What remains is PARTIAL: modules where a surface was decoded and the main body was not. Ranked by disassembly size × number of importing modules — how much of the rest of the firmware rests on code nobody has read through. Everything else is either DECODED or stock MicroPython. The per-module tables below carry the rating for each.
What closed, and where it went. Thirteen modules moved from NAME-ONLY to DECODED, and five from PARTIAL to DECODED:
  • f_lib/logger.py, f_lib/bitwise.py, f_lib/task_mgr.py, f_lib/file_mgr.py, f_lib/rtc_v2.py, f_lib/rtc_mem.py, f_lib/async_helpers.py, f_lib/tarfile.py, f_lib/gzip.py, f_lib/unpack.py, f_lib/firmware_helpers.pyf_lib
  • f_lib/requests.py, f_lib/wifi.pynetworking
  • f_ota/hotspot.pyhotspot server
  • ble_controller.pyBLE
  • imu_fusion_auto.pynavigation
  • debugger.py, peer_auto_bond.pytelemetry

Registry notes

The v5.0.3 frozen-module registry (mp_frozen_names) holds exactly 94 entries — the modules listed on this page. Two more .py files, boot.py and webrepl_cfg.py, exist only as on-flash VFS filesystem paths (./boot.py, ./webrepl_cfg.py), and are not frozen, which is why some tallies of the image reach 96.v5.0.2 had 96 frozen modules (98 with the two VFS files). v5.0.3 removed two that nothing imported: imu_fusion.py (an older, unused Madgwick Fusion/Cal implementation) and io_mgr.py (only import io).
Five more modules are imported but not present. project_main.start imports mpy_dev.dev_comms, mpy_dev.dev_imu, mpy_dev.dev_leds, mpy_dev.dev_rest, mpy_dev.dev_mem_release and web_bluetooth. None of them is frozen into the image and none is on the VFS, so those branches raise ImportError on a production device. They are developer bench paths — see boot flow. (CONFIRMED: the IMPORT_NAME opcodes are in project_main.dis; no matching module exists in the 94.)

Top-level application

Boot & filesystem

LEDs

apa106.py is not the LED driver. (CONFIRMED) leds.py opens with IMPORT_NAME f_lib.neopixel_v2 / IMPORT_FROM NeoPixel. apa106.py imports neopixel, and a search of all 94 disassemblies for IMPORT_NAME apa106 and IMPORT_NAME neopixel returns only apa106.dis itself. Both modules are unreachable in v5.0.3. Earlier revisions of these docs presented apa106.py as the driver; that was wrong.

Input & sensors

Bluetooth LE

ESP-NOW mesh & peers

Upload & OTA

Power & system

f_ble/ package

f_ota/ package

f_lib/ package

f_lib/rtc_mem.py — RTC-memory frame format (CONFIRMED)

RtcMem packs variable-length frames into machine.RTC().memory(). _rebuild_contents walks the buffer and builds contents, a dict mapping category id → list of byte offsets:
The walk is i += 5 + mem[i+4], stopping at mem_size or the end of the buffer. Three category ids are in use — not two:

f_lib/logger.py — what is actually in it (CONFIRMED from obj_table)

Not decoded as a module, but its constants are readable directly and are worth recording, because every log line quoted elsewhere on this site is produced here:
  • Levels, in order: ('NOT', 'DBG', 'INF', 'WAR', 'ERR', 'EXC') — index 0–5, selected by set_print_level.
  • ErrCode members: InvalidAuth, LimitReached, OperationFailed, ParamMissing, ParamInvalid, HardwareErr, InvalidLength, InvalidValue.
  • On-flash log file: errors.log. print_logs brackets its output with --- Logged Events --- / --- End Logged Events ---, and reports No log file on device when absent.
  • Record format: '{} | {} | {} | {} | {}' (five fields).
  • Public API: debug, info, warn, err, exc, print_logs, set_print_level, plus internal _log / _write.

f_lib/bitwise.py — the packing primitives (function list CONFIRMED)

Every wire format documented under protocols is built from these, but the functions themselves have not been decoded: bin_to_hex, bin_to_str, get_mac_addr, hex_to_bin, pack_2bit_value, pack_bits, pack_flags, pack_utf8_str, str_to_bin, unpack_2bit_value, unpack_bits, unpack_flags, unpack_utf8_str.

Standard / vendored MicroPython

Frozen library modules that ship with, or are vendored into, MicroPython. Not Totem code, and out of scope for decoding. Status STOCK is inferred from structure — the class and method sets match the documented upstream APIs and the modules import the corresponding C modules (_espnow, bdev) — rather than from a byte-for-byte diff against an upstream tree. asyncio/ (__init__, core, event, funcs, lock, stream), uasyncio.py, requests/__init__.py, urequests.py, mip/__init__.py, ssl.py, upysh.py, webrepl.py, webrepl_setup.py, onewire.py, ds18x20.py, neopixel.py, apa106.py, espnow.py, aioespnow.py, flashbdev.py, _boot.py, inisetup.py. Of these, inisetup.py carries a Totem modification (it writes main.py as well as boot.py), and neopixel.py / apa106.py are dead code.