check_for_update() wrote the download to main_ota_temp.py, stamped the new
version in NVS and reset, but never replaced main.py. Devices therefore kept
running the old program while reporting the newest version, so no OTA release
ever reached the field.
The routine now validates the download (HTTP 200, minimum size, setup/loop
present, compiles), keeps the running program as main_prev.py for manual
rollback, renames the download to main.py, and records the version only after
the swap succeeds. A rejected download or failed swap leaves the old program
and version in place so the next boot retries.
CLAUDE.md describes the new flow and the field caveat: devices on the old
build need one manual USB copy first, and the next version.txt must exceed any
number already published because their NVS may claim a version they never ran.
.gitignore drops the __pycache__ left by PC-side syntax checks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Import the UiMetrix tag-reader firmware (UIFlow 2.0 MicroPython script) as
exported from the device, plus a CLAUDE.md describing the OTA release path,
the MQTT contract with the UiMetrix server and the scan/ACK lifecycle.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>