Skip to main content
The firmware image analysed here is publicly downloadable. Two different URL constructions reach the same bytes: the phone app’s direct S3 download, recovered by decompiling the Android app’s Hermes bytecode, and the device’s own OTA fetch, recovered from the frozen MicroPython bytecode in re/v5.0.3/mpy/*.dis. They do not share a single string.
App-side facts below come from decompiled Hermes bytecode and from observing the live API — they cannot be verified against the firmware image. Device-side facts carry file.dis:line citations into the disassembly.

Device-side: how the firmware builds its own URLs

Everything the device fetches hangs off cfg.ota_url and cfg.version.

Where cfg.ota_url comes from

  1. project_main.perform_ota() sets it from the branch named in perform.ota (project_main.dis:446):
  2. Failing that, f_ota.main.start_ota assembles the same default by concatenation (f_ota_main.dis:1221):
  3. If the release poll succeeds, the API overwrites it with its body.endpoint string and cfg.version with body.release_code (get_release_from_api, f_ota_install_ota.dis:672). The server therefore chooses the download host; the on-device S3 URL is only the fallback.
All three host literals are in the image at re/v5.0.3/rodata_strings.txt:1816, :1837 and :2123http://datapeak-developer.s3.us-east-1.amazonaws.com, the …/{} template of it, and http://api.totemportal.com. No https:// Totem host appears anywhere; the only https:// literals in the image are upstream MicroPython defaults (micropython.org, raw.githubusercontent.com, gitlab.com).

The fetches

_get_endpoints(file_path, s3_dir_url, dest_dir) is the whole of the URL builder (f_ota_install_ota.dis:1214):
with s3_dir_url = cfg.ota_url + '/' + cfg.version and dest_dir = cfg.save_to (default 'next'). So:
The ?uid= cache-buster is rand_key(length=8), 8 characters from A–Za–z0–9 seeded by os.urandom (f_lib_helpers.dis). The name is not a template — it is whichever entry of the contents.json array satisfies entry[-4:] == '.bin' (or '.tgz'). The device then reverse-engineers the version from the resulting URL (f_ota_install_ota.dis:1017):
which is the only place the firmware ever assumes a …_v<code>.<ext> naming convention — and it assumes it about a string the server supplied, with no validation.
The literal firmware_v appears nowhere in the image: zero matches across all seven segments seg0seg6 and zero across the 94 frozen modules. The filename is a server-side/app-side convention that the device only parses, never constructs.

App-side: the releases API

The phone app fetches release metadata from an endpoint the firmware never mentions:
No releases literal exists in the firmware (grep -l releases *.dis → no matches). The device’s only API endpoints are {API_ENDPOINT}/devices/{mac}/ota and …/devices/{mac}/ota?updated, plus {API_ENDPOINT}/events/{mac} and {API_ENDPOINT}/debug/{mac} for log upload after an update (ota_callback.dis:497).
Response (abridged) at time of analysis. The API lists one current release per branch; after the 5.0.3 rollout, release 335 (v5.0.2) was no longer listed:

URL construction (app)

For release 339 (v5.0.3):
Release 335 (v5.0.2) followed the same pattern (…/totem/5.0.2/firmware_v5.0.2.bin). The construction order was confirmed from the raw Hermes opcodes (a HermesInternal.concat call of exactly ten operands ending in the filename), not only from decompiler output.
The https:// scheme above is the app’s. The firmware embeds only the plaintext http:// variants of both hosts. Whether the app rewrites http:// to https:// before use is not verifiable from the firmware.

Which release fields the firmware actually knows about

Earlier revisions of this page listed s3_dir_url and package_json_url among the “release fields referenced by the firmware.” Both were wrong: The product/branch directory names are on-device, as plain strings: totem_compass and totem in f_ota/main.py and f_ota/system.py, totem_compass/totem as perform_ota()’s ota_branch default, and totem_compass/pre_alpha as the default first argument of the REPL helper project_main.force_ota() (project_main.dis:386).

On-device OTA vs app download

Firmware: {} found in repo is a log line about the remote contents.json listing, not a local repository. Earlier revisions of this page read it as an on-device artifact store; there is no such store for firmware images.

Verification

The object at the app-constructed URL matched the API’s own integrity fields exactly: The v5.0.2 download (release 335) matched its record the same way (1,692,352 B, a6d05597…c7bf8896). The image begins with 0xE9 and carries the ESP-IDF app-descriptor magic 0xABCD5432, confirming a genuine ESP32 application image. Since the device never sees sha256_hash, this check confirms that the app’s download is intact — it says nothing about what the device flashes. See OTA integrity.
The path is scoped by release_code (the /5.0.3/ segment), but the object is a plain static S3 key with no content hash or immutable prefix — that fixed per-version URL keeps serving whatever bytes currently sit at the key until the object is replaced. Release metadata, including the pre_alpha branch, is served openly by the app’s releases API.