Imported from zdar/uwb-lokalizace (
AGENTS.md). Install upstream withnpx skills add zdar/uwb-lokalizace. Copyright stays with the author.
Agent Notes
Firmware modes
A single binary supports two WiFi modes, selected by provisioning the useHomeWifi flag.
- RTLS-NET / tunnel mode (
useHomeWifi = false): ANL createsRTLS-NET-<NNNN>AP; NODEs join it. - Home WiFi / development mode (
useHomeWifi = true): every module, including an ANL, joins the home WiFi as a station. No AP is created. Tags broadcastRPTand all modules broadcastHBto the LAN broadcast address.
Both modes can use either an ESP32 ANL or the PC ANL GUI (scripts/pc_anl.py).
Role switching
TAG / ANCHOR role switching (UWB role, not system role) must not reboot the ESP32. The UWB module is reconfigured through the existing AT command sequence (configureUWB()), which ends with AT+RESTART on the UWB chip only.
- UDP
ROLE,<0|1>handler and serialAT+ROLE=<0|1>handler both updatecurrentRole, save it to EEPROM, show the role screen, callconfigureUWB(), and then show the ready screen. - Do not add
ESP.restart()back into these paths — it reloads the old role from EEPROM and breaks remote switching.
EEPROM policy
Provisioning settings (UWB role, system role, network ID, UWB index, home-WiFi flag) are loaded from EEPROM on boot, but they are never written at runtime. The save* functions are intentionally no-ops.
This means:
- Values stored in EEPROM externally are respected on boot.
- Runtime changes made through the provisioning menu, UDP commands, or serial commands are not persisted across ESP32 reboots.
- TAG/ANCHOR role switching works without rebooting the ESP32; the UWB module is reconfigured on the fly via
configureUWB().
PC ANL GUI scope
scripts/pc_anl.py is an optional development GUI. It currently supports:
- Discovering nodes on the home WiFi.
- Switching TAG / ANCHOR roles remotely.
- Setting anchor positions manually.
- Calibrating anchors with a tag at known 3D points (Mode B).
- Viewing live solved tag positions.
It also supports fully automatic anchor calibration (Mode A), which temporarily switches each anchor to TAG, collects ranges, solves its position, and switches it back. The ESP32 ANL firmware has the same capability (autoCalibrateLoop() / CALAUTO,<id>), so you can use whichever ANL you prefer.
Two web listeners serve the same Flask app: HTTP on TCP 5000 (main PC; http://127.0.0.1:5000 counts as a browser secure context so the webcam works there) and HTTPS on TCP 50001 (https://<PC-IP>:50001 for remote devices, whose browsers block getUserMedia on plain-HTTP remote origins). The HTTPS listener serves a self-signed cert generated on first run into certs/ (SANs: localhost, hostname, 127.0.0.1, current LAN IPs); remote devices must accept the browser warning once. Cert generation needs the cryptography package (in requirements.txt); without it the app runs HTTP-only. Note TCP 50001 (HTTPS) and UDP 50001 (raw RPT forward to qr_scanner.py) are different protocols and do not conflict.
Common gotchas
- An ESP32 configured as ANL will ignore
ROLE,switch commands; only NODEs accept them. This is fine for PC-as-ANL development where every ESP is a NODE, but confusing if a mixed deployment is discovered by the GUI. - In home-WiFi mode, heartbeats are sent by all modules, not just NODEs, so the ANL is discoverable too.
