DEVLOG #8 - MQTT AUTH, POWER-FAILURE RECOVERY, DASHBOARD REDESIGNED FROM SCRATCH
Website: https://spottr.brunogg.in
Work Done:
- Added MQTT username and password support across the whole stack. The captive portal now has optional auth fields, the credentials save to NVS with the rest of the config, and the
pi-bridgeauthenticates the same way. Leaving them blank keeps the old anonymous behaviour, so nothing broke for existing setups - Fixed a bug where every scanner broadcast the same setup network name. The AP name is built from the last two bytes of the device MAC, but it was being read from the WiFi driver before the interface existed, so every board came up as
Spottr-Scanner-0000. Reading the MAC directly from efuse fixed it, and each scanner now shows its real suffix, unique per device and stable across reboots - Fixed a power-failure recovery bug that only showed up in the real deployment. When the power came back, the scanners booted in about two seconds but the router took closer to a minute, so the scanners found no network, assumed they were unconfigured, and dropped into the config portal. Every node had to be manually restarted. The logic was treating “can’t connect right now” as “isn’t set up”. Now a scanner with credentials in NVS retries WiFi indefinitely and only ever opens the portal if there are genuinely no credentials or the command is given over serial
- Added a WiFi watchdog to the main loop, so a dropout during normal operation reconnects on its own instead of leaving the scanner stuck retrying MQTT over a dead network
- Fixed the OTA status LED never actually animating.
ledSet()only records the state, and the pin write happens inledUpdate(), which runs from the main loop, but the OTA download blocks that loop entirely. So the LED just froze at whatever brightness it had. Driving it fromhttpUpdate’s progress callback fixed it, and the pattern is twice as fast now so a quick update is still visible - Redesigned the dashboard from scratch. Went for a design language closer to Nothing and Apple’s dark mode, so the whole thing is monochrome with mono uppercase labels, thin tabular numerals and a lot of empty space. Stripped out the animated gradient orbs, the dot-grid background and the glassmorphism, since that look is everywhere now and reads as generic. Cards are visible because they’re lighter than the page rather than because they have a border, and colour only appears where it means something, so a room lighting up when someone walks in is the only saturated thing on screen
- Rebuilt the Overview page as three columns, with stats and occupied rooms on the left, the floor map in the middle, and a badge rail on the right where every badge can be searched, edited, disabled or deleted without leaving the page. Added pan and zoom to the map
- Fixed a bug where any badge added through the dashboard would never show a location. New badges were saved with an uppercase MAC while the
pi-bridgewrites location keys in lowercase, so the two never matched. Pulled the MAC handling into a shared module so both pages normalise the same way - Replaced the component-library sidebar with a custom animated one, and moved the shared liveness and badge logic into
lib/status.jsandlib/badges.js. The duplicated copies of that logic are exactly what let the floor map and the overview page drift apart and disagree about which scanners were online
Future Work
- Build the Scanners Management page to assign rooms to auto-registered scanners and a Logs Page to view the history of every action performed
- Add offline buffering to the scanner firmware so badge detections aren’t lost if WiFi drops, and flush them once reconnected
- Add checksum verification to the OTA process so a corrupted download can’t be flashed to a scanner
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.