fix: C1 C2 H1 H2 H3 — stability fixes for long-running operation

C1 (critical): Add 15s watchdog for WEATHER_REQUESTING state — resets to
IDLE if TCP connection hangs silently, preventing permanent weather death

C2 (critical): Fix millis() rollover in all retry timers — replace unsafe
`millis() >= nextRetryTime` with subtraction-safe `(millis() - nextRetryTime)
< 0x80000000UL` in RetryConfig and WiFiRetryConfig; fix boot guard with
static flag instead of raw millis() comparison

H1 (high): Fix DST last-Sunday formula — was using incorrect year-only
heuristic; now derives weekday of the 31st from current day's tm_wday:
`weekdayOf31 = (tm_wday + (31 - day)) % 7`. Verified: March 2026 = 29th ✓

H2 (high): Replace String+= with snprintf+sendContent in handleAPITime,
handleAPIStatus, handleAPIDebug, handleAPIWeather — eliminates permanent
heap fragmentation from JS polling every second

H3 (high): Add volatile to weatherState and ntpState — shared between
ESPAsyncTCP callbacks and main loop; prevents stale register-cached reads

RAM: 37,268 bytes (46%) — reduced from 37,560 due to String elimination

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alex Petrochenko
2026-05-18 15:53:39 +01:00
co-authored by Claude Sonnet 4.6
parent eeec0155c3
commit 78bbd96f45
6 changed files with 108 additions and 61 deletions
+4 -2
View File
@@ -70,7 +70,8 @@ struct RetryConfig {
}
bool isRetryTime() {
return nextRetryTime > 0 && millis() >= nextRetryTime;
// Subtraction-safe: works correctly across millis() rollover at ~49.7 days
return nextRetryTime > 0 && (millis() - nextRetryTime) < 0x80000000UL;
}
void reset() {
@@ -101,7 +102,8 @@ struct WiFiRetryConfig {
}
bool isRetryTime() {
return nextRetryTime > 0 && millis() >= nextRetryTime;
// Subtraction-safe: works correctly across millis() rollover at ~49.7 days
return nextRetryTime > 0 && (millis() - nextRetryTime) < 0x80000000UL;
}
void reset() {