_have_time_sync is reset to false whenever WiFi disconnects, even
though the ESP32 RTC continues to hold accurate time after a
successful SNTP sync. This caused hasTimeSync() to return false
during transient WiFi outages, unnecessarily tearing down MQTT
broker connections and suppressing packet publishing.
Introduce _last_time_sync to record the wall-clock time of the
most recent confirmed sync. Move hasTimeSync() out of the header
into NetworkService.cpp and extend its logic: in addition to the
existing _have_time_sync flag, return true if the system clock is
still sane (>= kMinSaneEpoch) and no more than kMaxOutOfSync (24h)
has elapsed since the last confirmed sync.
This makes the MQTT uplink resilient to brief WiFi dropouts without
requiring any changes to callers of hasTimeSync().
Also bump kMinSaneEpoch from 2025-01-01 to 2026-01-01.
There's no known reason why additional firmware build of this board
with serial logging enabled was needed.
So, removing it for now to optimize building process and cleanup
firmware list.
When the MQTT WebSocket handshake fails before a connection is fully
established (e.g. "Sec-WebSocket-Accept not found"), the IDF v4
transport teardown path writes only 3 of the 4 bytes of the heap block
tail canary (expected 0xbaad5678, actual 0xbaad5600). The subsequent
esp_mqtt_client_destroy() call frees that block, causing multi_heap_free
to detect the broken canary and abort:
CORRUPT HEAP: Bad tail at 0x3fcb42a4. Expected 0xbaad5678 got 0xbaad5600
assert failed: multi_heap_free multi_heap_poisoning.c:259 (head != NULL)
The fix is to check heap integrity with heap_caps_check_integrity_all(false)
between esp_mqtt_client_stop() and esp_mqtt_client_destroy(). If corruption
is detected, scan internal SRAM (0x3FC00000–0x3FD00000) for the truncated
canary pattern and restore it to the correct value before
destroy() runs.
The scan is a no-op when the heap is clean and is compiled out entirely
on IDF v5+, where the underlying bug does not exist.
This fixes crash-on-reconnect observed with ESP32-S3 + IDF v4 + WSS transport.