embedblocks/espnow-mqtt

0.2.0

Latest
uploaded 23 hours ago
Lightweight MQTT-like publish/subscribe over ESP-NOW. Stateless publishers, central WiFi-connected broker, no fragmentation, 250-byte frame discipline. Requires ESP-IDF >= 5.5.0.

Changelog

# Changelog

All notable changes to espnow_mqtt will be documented here.
Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

---

## [Unreleased]

## [0.1.0] — Initial release

### Added

**Wire protocol**
- 5-message protocol: REGISTER, REGISTER_ACK, PUBLISH, ID_UNKNOWN, BROKER_ANNOUNCE
- 250-byte frame discipline — no fragmentation
- 1-byte `topic_id` negotiation: string overhead on first frame only
- Little-endian 16-bit sequence counter in PUBLISH header

**Publisher role**
- CONTINUOUS mode: persistent publisher_task, channel scan, keepalive timer,
  no-reply timeout, exponential/slow-interval backoff, rediscovery
- SLEEP mode: blocking `register_sync()` / `publish_sync()` API, RTC state
  persistence across deep-sleep wakes
- Boot jitter: configurable random delay to spread simultaneous registrations
- Permanent-rejection detection: `perm_rejected` flag after N consecutive
  `REGISTER_ACK{topic_id=0}` responses; clearable via `espnow_mqtt_clear_perm_rejected()`

**Broker role**
- Static topic registry: `(publisher_mac, topic_string) → topic_id` mapping
- Subscriber dispatch task with `+` wildcard pattern matching
- Per-publisher sequence gap and duplicate detection (always-dispatch contract)
- Three-phase boot: `broker_prepare()` pre-announces on last NVS channel before
  WiFi connect; `broker_start()` goes fully online after IP assignment
- NVS channel persistence (`espnow_mqtt` namespace, `last_ch` key)
- Publisher radio-silence timeout callback
- Publisher lifecycle events: REGISTERED, REREGISTERED, TIMEOUT
- `espnow_mqtt_purge_mac()` for OTA publisher replacement
- Peer wrapper API: `espnow_mqtt_add_peer()` / `del_peer()` for runtime changes

**Security**
- MAC-based trust filter: frames from non-peer MACs dropped before any parsing
- Optional HMAC-SHA256 payload integrity (`PAYLOAD_HMAC=y`):
  16-byte truncated tag prepended to every PUBLISH payload; constant-time
  XOR-accumulate verify; mbedTLS software path only (not hardware HMAC peripheral)

**Build system**
- Role-split builds: `ROLE_PUBLISHER` and `ROLE_BROKER` strip the irrelevant
  `.c` file entirely from the link (not just `#if` guards)
- IDF ≥ 5.5.0 required (recv_cb struct form since 5.0; send_cb struct form since 5.5)
- Targets: esp32, esp32s3, esp32c3, esp32c6, esp32s2 (publisher role only on S2)

### Known Limitations

- No LMK/ESP-NOW encryption (requires key distribution infrastructure)
- No `#` wildcard in subscriptions (requires wire protocol extension)
- `REGISTER_ACK` carries no `rejection_reason` field — broker logs are the only
  way to distinguish `"registry full"` from `"malformed topic"`
- `REGISTER_ACK` and `ID_UNKNOWN` replies are sent inline in `recv_cb` (WiFi task)
  rather than deferred to a dispatch queue; a slow `esp_now_send()` stalls recv_cb
- Stale topic GC on REGISTER is not automatic — call `espnow_mqtt_purge_mac()`
  before an OTA reboot that changes topic strings
- `topic_id` counter does not reset within a broker boot session; wraps at 254
  (broker reboot required after 254 unique `(mac, topic)` pairs)
- HMAC secret is compiled into firmware; no per-device derivation in this version

### Future Candidates

- Dual-queue architecture: separate control queue (REGISTER_ACK, ID_UNKNOWN)
  from the PUBLISH dispatch queue to prevent control starvation under high load
- `rejection_reason` field in `REGISTER_ACK` wire format (breaks wire compatibility)
- Per-device HMAC secret derivation from MAC + master secret via eFuse
- `#` multi-level wildcard (requires wire protocol version bump)

Links

To add this component to your project, run:

idf.py add-dependency "embedblocks/espnow-mqtt^0.2.0"

download archive

Stats

  • Archive size
    Archive size ~ 88.84 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

embedblocks/espnow-mqtt version: 0.2.0
|