- New driver: app/drivers/olimex_esp32_c6_evb_pn532/
- Full relay/input control (inherits base behaviour)
- get_nfc_status(), get_nfc_config(), set_nfc_config() methods
- manifest.json with NFC hardware metadata (UEXT1 pins, card standard)
- NFC management routes (boards.py):
- GET /boards/<id>/nfc — management page
- GET /boards/<id>/nfc/status_json — live JSON (polled every 3 s)
- POST /boards/<id>/nfc/config — save auth UID / relay / timeout
- POST /boards/<id>/nfc/enroll — enrol last-seen card with one click
- New template: templates/boards/nfc.html
- Live reader status (PN532 ready, access state, last UID)
- Quick Enroll: present card → Refresh → Enrol in one click
- Manual Settings: type/paste UID, pick relay, set absence timeout
- detail.html: NFC Access Control button shown for pn532 board type
All three hardware drivers (Olimex, generic_esp32, generic_esp8266) now
probe with the first request and bail immediately on failure.
Before: offline board with 4 relays + 3 inputs = 7 requests × 3 s timeout
= up to 21 s of blocking + 7 log lines per recheck cycle.
After: exactly 1 request × 3 s timeout regardless of I/O count.
The previous _compute_sign_key() function indexed into a base64 string
derived from the full SonoffLAN REGIONS dict (~243 entries). Our partial
dict only produced a 7876-char a string but needed index 7872+, so the
function must use the full dict.
Solution: pre-compute the key once from the full dict and hardcode the
resulting 32-byte ASCII key. This is deterministic — the SonoffLAN
algorithm always produces the same output regardless of when it runs.
The sonoff_ewelink driver now loads cleanly alongside all other drivers.