Files
HaloKeymind/tools/mota

tools/mota/ - OTA Python reference library & build/test tooling

The Python side of MeshCore's .mota OTA system. It is the reference implementation of the wire spec (docs/ota_protocol.md) and the build + test infrastructure - it is no longer a user-facing CLI.

Want to build / verify / inspect / serve .mota from the command line? Use the standalone motatool Rust CLI (its own repository). It supersedes the old mota.py / mota_seeder.py (now removed) and produces byte-identical containers. The files here are the spec oracle and the firmware build/test glue.

Setup

Uses the repo's Python venv (meshcore/). Dependencies: detools (delta), cryptography (Ed25519), intelhex (nRF52 .hex handling).

./meshcore/bin/pip install detools cryptography intelhex

Files

File What
motalib.py Core logic: multihash, EndF, merkle tree+proofs, manifest/container build/parse/verify. The reference implementation of the spec and the unit-test oracle. Imported by everything below.
pio_endf.py PlatformIO post-build hook (wired in platformio.ini) that injects the EndF self-identity trailer into the flashed firmware (-D ENABLE_OTA).
gen_vectors.py Generates test/test_ota/mota_vectors.h - the cross-check vectors the native C++ tests run against.
gen_targets.py Generates src/helpers/ota/OtaTargets.h - the target_id -> env-name table (every ENABLE_OTA env, resolved from pio project config). Shared by the firmware and motatool so a node can name a target seen over the air without sending the string. Regenerate when the OTA env set changes.
test_mota.py Unit tests for motalib (run directly or via pytest).

Tests

./meshcore/bin/python tools/mota/test_mota.py      # EndF, merkle+proofs, full/delta, signing,
                                                   # tamper detection, approval enforcement
./meshcore/bin/python tools/mota/gen_vectors.py    # regenerate the native-test cross-check vectors
./meshcore/bin/python tools/mota/gen_targets.py    # regenerate src/helpers/ota/OtaTargets.h (needs `pio`)

EndF build integration

EndF must live in the flashed firmware (not just inside the .mota), because a node serves its own firmware and matches a delta's base_hash against its own EndF. Wiring (handled by pio_endf.py):

  • ESP32 / RP2040 (emit firmware.bin): post:tools/mota/pio_endf.py in the env's extra_scripts plus -D ENABLE_OTA=1. The hook appends the 56-byte EndF (with target_id/fw_version/hw_id) to the app .bin before merge.
  • nRF52 / STM32 (emit .hex -> .uf2): the same hook rewrites the .hex with the trailer at the image end. The byte logic is motalib.ensure_endf, used everywhere.

target_id = sha2-256:4(pio_env_name), hw_id = explicit -D MOTA_HW_ID or a role-stripped hardware family derived from the environment name, and fw_version = parsed from FIRMWARE_VERSION. A node (and motatool, reading the firmware's EndF) therefore auto-discovers identity without relying on filenames.