Both Clyde North observers sat WL_CONNECTED on an AP that kept beaconing
after its bridge to the wired LAN died: association up, good RSSI, stale
DHCP lease, but ARP-invisible and both MQTT brokers stuck in backoff.
The firmware equated "associated" with "online", so neither node ever
re-scanned and the outage held until a manual reassociation.
Add a connectivity watchdog to NetworkService: while connected, ARP-probe
the gateway every 30s (posted to the lwIP tcpip thread, safe on both the
IDF4 and IDF5 cores). If the gateway stays silent for 3 minutes, clear
the channel hint and force a full disconnect/rescan so the node can roam
to a healthy AP, backing off exponentially (up to 48min) while the
outage persists. Nodes without a gateway skip the probe.
Add a `wifi reconnect` repeater command that triggers the same forced
reassociation on demand, and report `gw:ok|lost wd:<count>` in
`get wifi.status`. Teach the web panel parser the new fields (also fixes
the IP metric rendering as "x.x.x.x channel:n") and show Gateway and
Channel in the Wi-Fi card.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Integrates upstream v1.17.0. Key adaptations:
- companion + repeater NodePrefs moved to upstream's new ConfigSerializer
(prefs.json) format; EastMesh fields (companion wifi, repeater fan and
MQTT bridge peer) appended as serializer groups/keys
- legacy binary prefs loaders retain EastMesh tail fields, so existing
devices migrate their settings to the new format
- companion main.cpp adopts upstream InterfaceManager while keeping
runtime WiFi credentials from prefs
- kept EastMesh release-tag versioning in setup-build-environment action
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The `recv_pkt_region` is set when processing a flood packet in `filterRecvFloodPacket`
but direct/non-flood packets would never pass through that function, so the pointer was
not cleared for them.
`sendFloodReply` would then later use it blindly, which meant that the response would
either inherit the region from the last flood packet, or refer to a non-initialised pointer
if no region floods had been received yet.
MQTT status payload:
- Add packets_sent and packets_received (cumulative radio TX/RX totals)
to the status `stats` object, aligning with the Waev/MeshMapper schema.
Variants (variants/eastmesh_mqtt -> variants/eastmesh):
- Rename the variant folder to variants/eastmesh.
- Add the remaining *_repeater_observer_mqtt_bridge envs (2 -> 36), one
per observer board.
- Regroup envs by board (observer -> espnow -> mqtt_bridge) and add
per-vendor section banners.
Docs & release notes:
- Update folder path references in README, AGENTS, and boards docs.
- Add observer-eastmesh and observer-eastmesh-bridge-espnow 2026.6.6
release notes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Waev (mqtt.waev.app) as a curated MQTT broker, selectable from the
web-panel Primary/Secondary dropdowns and the CLI.
- Broker spec on bit 0x20, audience mqtt.waev.app, Google Trust Services
WE1 CA (matches Waev's cert chain); widen broker mask/count to 0x3F/6
- Per-broker JWT lifetime via BrokerSpec.token_ttl_secs: Waev enforces a
1-hour max token TTL and rejects the 6h default with MQTT CONNACK 5,
so it mints a 3600s token while other brokers keep the 6h default
- CLI get/set mqtt.waev, web-panel dropdown entry + hidden toggle, docs
- Log token TTL in the "token ready" line for broker auth debugging
fix(web): make Custom MQTT settings full width when Custom is selected
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Before this commit, there was no way to set a different max hop count
for unscoped messages.
Now with this change, by defaul it tracks the flood.max setting, until
a user provides a flood.max.unscoped value, which tax precidence for
packets if ROUTE_TYPE_FLOOD is true.