All notable changes to the Zebrabox ESP32 Control firmware are documented in this file.
This project follows Semantic Versioning and the format is based on Keep a Changelog.
Version 1.3.2 (single-mode AWS IoT / mutual-TLS) is the base release.
Author: Thomas Joss, keynexis AG
Major rework. The Control device (relays + RFID/Wiegand keypad + magnetic door sensor) moves from a single-mode AWS IoT MQTT client to a dual-mode communication stack that mirrors the Zebrabox Locker:
The same application handlers (relay control, door sensor, RFID/keypad,
heartbeat) run in both modes via a channel argument that is either an
ESPNowTransport (Primary) or an MQTTClient (Secondary); globals.espnow_mode
selects the send path.
lib/crypto.py — AES-128-CBC + HMAC-SHA256 (encrypt-then-MAC) and key
derivation, using ucryptolib hardware AES.lib/espnow_transport.py — framed transport with per-send sequence
numbers, application-level ACK/retry, and a 16-entry replay-dedup ring.handler/espnow_discovery.py — Primary-mode bootstrap: channel sweep,
CONFIG_REQUEST broadcast, best-RSSI gateway selection.config/espnow_config.py — persistence of the discovered gateway in
config.tmp (zone_id, channel, gateway_mac, pmk).handler/espnow_listener.py — Primary-mode inbound command dispatch
(relay open/close, restart, sensor/RFID toggles) plus routing of
MSG_OTA_* frames to the OTA receiver.handler/ota_receiver.py — Primary-mode OTA: reassembles streamed
firmware into the inactive partition, set_boot() + reset on commit.handler/event_sender.py — mode-agnostic send_event() (encrypted
ESP-NOW unicast in Primary, MQTT publish in Secondary).pm=PM_NONE) in boot._activate_wlan_for_espnow().
An active-but-unassociated STA otherwise enters modem-sleep and silently drops
inbound ESP-NOW frames; on ESP32/WROVER-E this prevented the device from ever
receiving the gateway's CONFIG_RESPONSE. Required for reliable LR reception.handler/mqtt_listener.py — inbound
MQTT commands must carry a valid hmac + recent timestamp (HMAC_MAX_AGE).
RTC is NTP-synced at startup in Secondary mode for timestamp checks.mqtt_ping keep-alive task.build/run_build.py — ESP32 classic (Xtensa) OTA build,
output to C:\\\\E\\\\m\\\\ports\\\\esp32\\\\build-ZEBRABOX_ESP32-OTA (its own directory,
separate from any C3 variant). Built OTA artifacts collected in
firmware_files/ (bootloader.bin, partition-table.bin,
ota_data_initial.bin, micropython.bin, merged firmware.bin).boot.py — Primary/Secondary decision tree: try ESP-NOW discovery first
(cached-gateway probe or full channel sweep), fall back to the WiFi chain
(wifi.cfg → keynexis_SETUP provisioning AP → open networks); OTA-pending
forces Secondary.program.py — dual-mode orchestrator; branches on globals.espnow_mode
and spawns the matching task set.globals.py — populated with Primary (espnow, transport, gateway_mac,
pmk, crypto_keys, espnow_mode, ota_in_progress) and Secondary
(wlan, bssid) state, plus Wiegand accumulation state.-ats.iot.eu-central-1.amazonaws.com,
mutual-TLS client certificates) to the Keynexis broker
(mqtt.keynexis.app:8883, username/password over TLS). Topic namespace
changed from intellilock/storage/thing/{mac}/… to keynexis/storage/thing/{mac}/….