Boxes were updating from a dead GitHub repo and talking to the old broker
The program pointed its boot-time update check at a personal GitHub repo (husbananjum/m5core-s3-UIMETRIX-Z87) that now answers 404 for both version.txt and main.py, so every box on that build has been failing its check on every boot - harmlessly, but no release could ever reach them. It also had the broker at 192.168.87.11, while the boxes on the floor (and the UiMetrix server) are on 192.168.2.174. Updates now come from this repo on the company Gitea, through its anonymous raw-file URLs. For that the program is committed as main.py - the name the device downloads and runs - instead of "M5-Stack Code for Uimetrix.txt", and version.txt is added. The old broker stays as a commented line, the way the earlier networks are kept. - A push to main that also bumps version.txt IS a release now; every box that follows Gitea installs it at its next boot. Leave version.txt alone until main.py is ready for the floor. - No box follows Gitea yet: the ones with OTA code still point at the dead GitHub URL, and the ones on the floor run a build without OTA at all. Each needs one USB copy of this main.py; after that they update by themselves. - version.txt starts at 2.0. Nobody knows the highest number ever published on GitHub, and a box's NVS may hold a number it never actually ran; if any box shows a higher V... on its screen, bump version.txt above it. - A box freshly copied over USB still has its old NVS version (or the default 1.0), so on its first boot it downloads the identical main.py once and resets. Expected, not a loop. - The repo stores LF; the CRLF seen in a Windows checkout is core.autocrlf. Gitea serves the stored LF bytes, which is what the device compiles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>main
parent
4d487d3c58
commit
0d7c5781b0
|
|
@ -4,18 +4,20 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
|
||||
## What this repository is
|
||||
|
||||
Firmware for the UiMetrix shop-floor RFID tag-reader stations: an M5Stack CoreS3 with an RFID Unit and an RGB light bar, running MicroPython on the UIFlow 2.0 firmware (`M5`, `m5ui`, `unit`, `hardware`, `umqtt.simple`, `esp32.NVS` APIs). The whole program is the single file `M5-Stack Code for Uimetrix.txt`; on the device it is `/flash/main.py` (the `.txt` extension is just how it was exported; CRLF line endings).
|
||||
Firmware for the UiMetrix shop-floor RFID tag-reader stations: an M5Stack CoreS3 with an RFID Unit and an RGB light bar, running MicroPython on the UIFlow 2.0 firmware (`M5`, `m5ui`, `unit`, `hardware`, `umqtt.simple`, `esp32.NVS` APIs). The whole program is the single file `main.py`, served to the devices exactly as committed (the repo stores LF; the Windows checkout shows CRLF through `core.autocrlf`). It was `M5-Stack Code for Uimetrix.txt` until 2026-09-15; `git log --follow main.py` crosses the rename.
|
||||
|
||||
The repository is hosted on the company Gitea at `https://git.utopiadeals.com/UIND/UiMetrix-M5-Firmware` (branch `main`); pushing there does not reach any device, since devices pull from the GitHub repo described under "Releasing to devices". There is no PC-side toolchain: nothing to build, lint or run here, and there are no tests. Changes can only be verified on a device; debug output is `print()` over the USB serial port.
|
||||
The repository is hosted on the company Gitea at `https://git.utopiadeals.com/UIND/UiMetrix-M5-Firmware` (branch `main`), and **that is what the devices update from** (see "Releasing to devices"): a push to `main` that also bumps `version.txt` goes live on every box at its next boot, so keep unfinished work off `main` or leave `version.txt` alone until it is ready. There is no PC-side toolchain: nothing to build, lint or run here, and there are no tests. Changes can only be verified on a device; debug output is `print()` over the USB serial port.
|
||||
|
||||
The server that talks to this device is the UiMetrix ASP.NET Core app in `D:\Projects\UiMetrix` (`Services/MqttService.cs`; its own `CLAUDE.md` documents the server side). `D:\Projects\MqttWorkerService` is an older standalone worker that speaks the same protocol, and its `tools/rfid_enrol.py` numbers cards from this device's MQTT messages.
|
||||
|
||||
## Releasing to devices (OTA)
|
||||
|
||||
Devices update themselves at boot from the GitHub repo `husbananjum/m5core-s3-UIMETRIX-Z87` (`main` branch): `check_for_update()` fetches `version.txt`, compares it as a float against the `fw_version` string in NVS namespace `storage` (default `"1.0"`), and if newer downloads that repo's `main.py` and hands it to `install_update()`. The download must be HTTP 200, at least 1000 bytes, contain `def setup` and `def loop`, and compile; otherwise it is rejected. Installation writes it to `/flash/main_ota_temp.py`, renames the running program to `/flash/main_prev.py` (a rollback copy for manual recovery over USB), renames the download to `/flash/main.py`, and only then stores the new version in NVS and resets. A rejected download or a failed swap leaves the old program and the old version in place, so the next boot retries. A release is therefore: push the new `main.py` and bump `version.txt`. Things to keep in mind:
|
||||
Devices update themselves at boot from this repo's `main` branch on Gitea, over its anonymous raw-file URLs (`.../raw/branch/main/version.txt` and `.../raw/branch/main/main.py`; the host resolves to a public address, so any box with internet reaches it). `check_for_update()` fetches `version.txt`, compares it as a float against the `fw_version` string in NVS namespace `storage` (default `"1.0"`), and if newer downloads `main.py` and hands it to `install_update()`. The download must be HTTP 200, at least 1000 bytes, contain `def setup` and `def loop`, and compile; otherwise it is rejected. Installation writes it to `/flash/main_ota_temp.py`, renames the running program to `/flash/main_prev.py` (a rollback copy for manual recovery over USB), renames the download to `/flash/main.py`, and only then stores the new version in NVS and resets. A rejected download or a failed swap leaves the old program and the old version in place, so the next boot retries. A release is therefore: push the new `main.py` and bump `version.txt`. Things to keep in mind:
|
||||
|
||||
- Versions compare as floats, so `1.10` is older than `1.9`.
|
||||
- Builds before 2026-09-11 downloaded the file but never installed it, while still stamping the new version into NVS. Devices running such a build never pick up an OTA release: they need one manual USB copy of the fixed `main.py` first, and because their NVS may already claim a version they never ran, the next `version.txt` must be higher than any number published so far.
|
||||
- Until 2026-09-15 the update location was the personal GitHub repo `husbananjum/m5core-s3-UIMETRIX-Z87`, which now returns 404 for both files, so every box on that build has been failing its boot-time check (harmlessly) since. Those boxes, and any box running a build without OTA code at all (the ones with the broker at `192.168.2.174` hardcoded and no `V…` label on screen), need one manual USB copy of the current `main.py` to start following Gitea. `version.txt` was reset to `2.0` at the move; nobody knows the highest number ever published on GitHub, so if a box shows a higher `V…` on its screen, bump `version.txt` above it.
|
||||
- A box freshly copied over USB still carries its old NVS version (or the default `1.0`), so on its first boot it downloads and installs the identical `main.py` from Gitea once and resets; that is expected, not a loop.
|
||||
|
||||
## How the program works
|
||||
|
||||
|
|
|
|||
|
|
@ -149,15 +149,16 @@ def check_for_update():
|
|||
print("Update check failed:", e)
|
||||
|
||||
|
||||
UPDATE_VERSION_URL = "https://raw.githubusercontent.com/husbananjum/m5core-s3-UIMETRIX-Z87/refs/heads/main/version.txt"
|
||||
UPDATE_FILE_URL = "https://raw.githubusercontent.com/husbananjum/m5core-s3-UIMETRIX-Z87/refs/heads/main/main.py"
|
||||
UPDATE_VERSION_URL = "https://git.utopiadeals.com/UIND/UiMetrix-M5-Firmware/raw/branch/main/version.txt"
|
||||
UPDATE_FILE_URL = "https://git.utopiadeals.com/UIND/UiMetrix-M5-Firmware/raw/branch/main/main.py"
|
||||
OTA_MAIN_PATH = "/flash/main.py" # the program the device runs at boot
|
||||
OTA_TEMP_PATH = "/flash/main_ota_temp.py" # a download lands here first
|
||||
OTA_BACKUP_PATH = "/flash/main_prev.py" # the previous program, kept for manual rollback
|
||||
|
||||
|
||||
MQTT_CLIENT_ID = serial
|
||||
MQTT_BROKER = '192.168.87.11'
|
||||
MQTT_BROKER = '192.168.2.174'
|
||||
#MQTT_BROKER = '192.168.87.11'
|
||||
#MQTT_BROKER = 'scada.utopia.pk'
|
||||
MQTT_PORT = 1883
|
||||
MQTT_USER = 'utopia'
|
||||
|
|
@ -0,0 +1 @@
|
|||
2.0
|
||||
Loading…
Reference in New Issue