Skip to main content
v5.0.3 (release 339, built Sep 12 2026) is a hardening release on the same ESP-IDF v5.4 / MicroPython v1.25.0 base. The BLE and ESP-NOW wire formats are unchanged. Every record layout, TOTEM_MSG_MAP, EXTENDED and COMM_SPEED entry is identical. Clients written for v5.0.2 keep working, and the new BLE features are opt-in. The comparison reconstructs every frozen module from both images, disassembles them with MicroPython’s own mpy-tool.py, and diffs them function by function (see methodology). 73 modules are identical, 21 changed, 2 were removed.
The 73/21 split is CONFIRMED by two independent comparisons of the 94 modules common to both images: SHA-256 of the raw .mpy files, and a line diff of the disassembly with the source-path header stripped. Both agree exactly, and neither reports a module that the other does not.The methodology page says 74/20, and is not contradicting this: it compares decoded functions, which ignores the line-number table a .mpy carries. The next note is the one module that separates the two counts.The 21 changed modules are espnow_conn_v2, compass, ble_manager, ubx_gnss, project_data, f_ble/file_upload, compassing, peripherals, new_vibe, ota_ble, f_lib/file_mgr, nav_logger, f_ble/ble_lite, ble_controller, f_ble/chunking, ble_core, f_ble/ble_data, button, wdt_manager, peer_helpers, f_ota/system.
Twenty of those 21 changed their code. ble_controller.py did not.A .mpy differs whenever the module is recompiled, because source line numbers move and the line-number table is embedded in the file. Comparing the disassemblies with the source path, the raw bytecode blob and the line-info table stripped — leaving qstrs, object tables, preludes and decoded instructions — ble_controller is byte-for-byte identical between the two releases: the same 105-entry qstr table, the same 17-entry object table, the same instructions in all 14 code objects (confirmed). Every line-info entry moved by exactly +2 without compounding, which is two blank or comment lines inserted above class BleBlockers and nothing else.So a hash diff is the right tool for “what might have changed” and the wrong one for “what did”. The other twenty differ in instructions, not just in line numbers.
The diff is complete across all 94 modules — it compares bytecode, so it does not depend on anyone having understood the module. Knowing that a function changed is not the same as knowing what it does. Of the 21, 15 are rated DECODED and 6 PARTIAL on the module referenceble_controller.py was the last NAME-ONLY one and has since been read, which is how the recompile-only finding above came out. Where a change below is described in behavioural terms, that description comes from reading the bytecode; where it is described as “internal”, it does not.

At a glance

BLE

Unchanged: the command map, all gen_* record layouts, and both transmit loops. The legacy full-duplex loop that works on macOS behaves exactly as in v5.0.2; see transmit modes. A v5.0.3 device was tested end to end with totemctl.

ESP-NOW mesh

The module body of espnow_conn_v2 (imports, message maps, class construction) is opcode- identical. Changes are inside EspConn (details):
  • All-peer sends unicast to non-POI peers in a rotating order, limited by an estimate of free driver TX buffers.
  • Back-pressure: sends are dropped locally (tx_skipped) when no buffers are free.
  • ESP_ERR_ESPNOW_NO_MEM is treated as back-pressure. In v5.0.2 it set is_silent_reboot.
  • Relay shedding: mesh frames from non-peers are no longer relayed when the receiver drops frames or the TX pool is busy.
  • Supervisor: communicate_supervised restarts the comms task after a crash.
  • Bonding: an already-bonded requester gets five peer ACKs. A Smart Group cancel now also matches by UID.
The LR PHY rate is 250K (e.config(rate=41)) in both versions. Earlier docs said 500K.

Device behaviour

Removed modules