From Sonnet pre-release code review (3 real issues): - F1 (high): factory reset atomicity — save cleared creds BEFORE zeroing reset counter, so a power loss between commits still results in WiFiManager AP boot instead of inconsistent "counter=0 + stale creds" state - F2: isValidSSID now allows single-char SSIDs (per 802.11 spec) - F3: ntp_interval changes now trigger needsRestart (NTPClient constructed once in setup() with this value, doesn't pick up runtime changes) From internal backlog: - M2: setupWiFi Try-2 now supports open networks (no password) — fixed the &&-condition that required both ssid and password - M3: removed dead NTP_WAITING/NTP_SUCCESS/NTP_FAILED enum values - M4: randomSeed() with ESP.getChipId() ^ micros() — dissolve pattern varies Tested on hardware: 72/73 tests pass (single failure is expected — ntp_interval fuzz cases now trigger restart due to F3, second case lands in reboot window). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
10 KiB
10 KiB
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[1.9.9] - 2026-05-19
Fixed
- Factory reset atomicity: cleared WiFi credentials are now committed BEFORE the reset counter is zeroed. If power fails between the two writes, the device still boots into WiFiManager AP on next start (cleared creds win over stale counter) instead of being stuck in an inconsistent state
isValidSSIDrejected single-char SSIDs: length-1 networks like "A" were incorrectly flagged as all-same garbage. Now allowed (per 802.11 spec)ntp_intervalconfig changes ignored until reboot:NTPClientis constructed insetup()with this value and never re-initialized. Now triggersneedsRestartwhen the interval actually changes- Open WiFi (no password) failed to connect at setup (M2): Try-2 block in
setupWiFi()required both ssid and password; now falls back toWiFi.begin(ssid)when password is empty - Unseeded PRNG, identical dissolve pattern every boot (M4):
randomSeed()now called withESP.getChipId() ^ micros()— varies between devices and boots
Removed
- Dead
NTPStateenum values (M3):NTP_WAITING,NTP_SUCCESS,NTP_FAILEDwere defined but never assigned. Removed to reduce code surface area
[1.9.8] - 2026-05-19
Fixed
- handleConfigSave always rebooted device on save: only reboots now if WiFi/network
fields changed (
ssid,password,hostname,ntp_server). Other settings (brightness, timezone, intervals, coordinates, display options) apply live without restart. Eliminates reboot cascades during config tweaks and makes the test suite safe to run repeatedly.
[1.9.7] - 2026-05-19
Fixed
- Config endpoint accepted garbage values, bricking device (M1):
/configform handler now validates all inputs. SSID rejected if empty, >31 chars, non-printable, or all-same-char (fuzz garbage like "AAAA..."). Numeric fields areconstrain()-ed to safe ranges (ntp_interval/weather_interval: 60–86400,brightness: 0–7,timezone: ±12h,latitude/longitude: physical ranges,display_orientation: 0–3). Invalid input returns HTTP 400 instead of silently saving and rebooting.
[1.9.6] - 2026-05-18
Fixed
- Weather hangs permanently after TCP timeout (C1):
WEATHER_REQUESTINGstate now has a 15-second watchdog — if the HTTP callback never fires (NAT timeout, server half-close), state resets to IDLE and retry logic resumes - All retry timers freeze at ~49 days (C2): Replaced unsafe
millis() >= nextRetryTimewith subtraction-safe(millis() - nextRetryTime) < 0x80000000ULin RetryConfig and WiFiRetryConfig; fixed boot guard with static flag - DST switches on wrong day (H1): Last-Sunday formula was using year-only heuristic;
now computes weekday of the 31st from current
tm_wday: verified correct for 2026–2030 - Heap fragmentation from web API polling (H2): Replaced String+= concatenation with
snprintf+sendContentinhandleAPITime,handleAPIStatus,handleAPIDebug,handleAPIWeather— eliminates permanent heap fragmentation from 1s JS polling - Race condition on shared state (H3): Added
volatiletoweatherStateandntpState— prevents compiler from caching stale values across ESPAsyncTCP callback boundaries - Malformed JSON on long error messages:
lastErrorclamped to 79 chars before snprintf
Changed
- RAM usage: 37,268 bytes (46%) — down from 37,560 due to String elimination in API handlers
[1.9.5] - 2026-05-18
Fixed
- Temperature disappears permanently (#9): After 3 consecutive API failures,
the weather state machine was permanently locked —
weatherStatestayedWEATHER_FAILEDand no new requests were ever made even after the API recovered. Fix: reset retry counter and state after max retries so periodic refresh resumes after next interval (30 min).
[1.9.4] - 2026-05-14
Fixed
- Date timezone (#5): Date string now uses local time, so date rolls over at local midnight instead of UTC midnight
- Weather periodic refresh (#7): Removed
WEATHER_SUCCESSstate that permanently blocked periodic weather updates after first fetch; also fixed "Last update" counter showing raw timestamp instead of elapsed seconds - WiFi connects to wrong network (#3):
WiFi.begin()without params is now skipped when a saved SSID exists, preventing connection to SDK-cached open hotspots and config corruption
Changed
- WiFi startup: SDK-cached credentials only attempted on first boot (no saved SSID); subsequent boots go directly to saved credentials
- ArduinoJson:
StaticJsonDocument→JsonDocumentfor compatibility with ArduinoJson v7
Removed
- Unused
weekdayvariable in NTP DST calculation (compiler warning)
Internal
- Split
clock_ntp_ota_v1.9/directory renamed toweather_clock/— version no longer baked into path - Removed internal development documents from repository
[1.9.3] - 2026-01-06
Changed
- Refactored monolithic 2,100-line
.inointo modular structure:display.cpp,ntp_client.cpp,weather.cpp,web_server.cpp,wifi_manager.cpp
[1.9.2] - 2026-01-06
Fixed
- CRITICAL: WiFi credentials no longer cleared on connection failure
- Previous behavior erased SSID/password after failed connection attempts
- Now credentials persist indefinitely through WiFi outages
- OTA update credential loss issue (SDK credentials now tried first, then EEPROM)
Added
- WiFi Resilience: Infinite retry with exponential backoff (5s → 10s → 20s → ... → 5min max)
- Fallback AP: "TJ56654-Setup" enabled after ~5 min of failed attempts
- Device continues retry attempts while AP is active (dual STA+AP mode)
- AP automatically disabled when WiFi reconnects
- "No WiFi" display: Shows retry countdown instead of numeric counter
- "!" indicator: Shown in date line when WiFi is disconnected
- SDK credentials support: Tries WiFiManager-stored credentials first
Changed
- Clock continues running with last synced time during WiFi outages
- Improved user experience during network failures
- Removed aggressive credential clearing behavior
Network Activity
- NTP sync: 1 hour interval (pool.ntp.org:123 UDP)
- Weather fetch: 30 min interval (api.open-meteo.com HTTP)
- mDNS: continuous (224.0.0.251 UDP multicast)
- ~50 requests/day total
[1.9.1] - 2026-01-03
Fixed
- CRITICAL: WiFi startup sequence - synchronous connection in setup() to ensure proper initialization order
- Display blank screen for 10+ seconds on boot (now shows time after ~15 seconds)
- "DNS resolution failed" errors during startup
- Sunrise/sunset labels cut off on 128px screen (removed labels, arrows are self-explanatory)
Changed
- Hybrid WiFi model: synchronous in setup(), async reconnect in loop()
- Display formatting: superscript degree symbol and lowercase 'c' for temperature
- Sunrise/sunset screen now shows daylight duration (e.g., "Day 9h 41m") instead of static "Sun Times" text
Documentation
- Added detailed v1.9.1_HYBRID_FIX.md explaining startup sequence problem and solution
[1.9.0] - 2026-01-02
Added
- Fully async architecture (zero blocking operations in loop)
- Custom async NTP implementation (manual UDP packet handling)
- Async HTTP weather fetch (AsyncHTTPRequest library)
- Exponential backoff retry logic for network failures
- Independent epoch tracking for accurate time between NTP syncs
Changed
- Replaced blocking NTPClient with custom async UDP implementation
- Replaced blocking HTTP weather with AsyncHTTPRequest
- Removed all delay() calls from loop()
- WiFi connection now async (later fixed in v1.9.1)
Performance
- Loop time: 10ms → <1ms (10x improvement)
- Weather fetch: 1-10s blocking → 0ms
- NTP sync: 5-20s blocking → 0ms
- WiFi reconnect: 15s blocking → 0ms
- OTA updates now work during active weather fetching
Technical
- RAM usage: +536 bytes (36,980 → 37,516)
- Flash usage: +1040 bytes (407,500 → 408,540)
- IRAM: 61,987 bytes (94% - stable)
[1.8.0] - 2026-01-01
Security
- CRITICAL: Removed hardcoded WiFi credentials
- Integrated WiFiManager for secure captive portal setup
- Added config validation (magic number check)
- Input sanitization to prevent buffer overflows
Fixed
- IRAM overflow crisis (94% → 70% via ICACHE_FLASH_ATTR)
- NTP interval bug (config value was ignored, always used hardcoded 1 hour)
- Boolean parsing errors in JSON config import/export
- Infinite loop protection in display mode rotation
- Memory leaks from String concatenation in web handlers
Changed
- Web responses now use chunked transfer (eliminated 140+ String concatenations)
- Applied ICACHE_FLASH_ATTR to 26 functions (moved code from IRAM to Flash)
- Improved error handling throughout codebase
Performance
- Peak heap usage reduced by ~8KB
- EEPROM validation prevents loading corrupted config
[1.7.0] - 2025-12-31
Added
- Initial working firmware with correct display support
- NTP time synchronization
- Weather data from Open-Meteo API (free, no API key required)
- OTA update support (web-based and ArduinoOTA)
- Web interface (/, /config, /debug, /update)
- REST API (time, status, weather, config export/import)
- Display rotation (time, weather, sunrise/sunset modes)
- Timezone support with manual DST configuration
- EEPROM configuration persistence
Hardware Discovery
- Identified display as GM009605v4.3 (not TM1637 or TM1650)
- Discovered swapped I2C pins: SDA=GPIO0, SCL=GPIO2
- Switched to Adafruit_SSD1306 library
Replaced
- QWeather API → Open-Meteo (no registration required)
- Proprietary firmware → Open source custom firmware
- Insecure WiFi handling → WiFiManager with timeout
[1.6.0] - 2025-12-30 (unreleased)
Attempted
- TM1650 LED driver support (incorrect - device has OLED)
[1.5.0] - 2025-12-29 (unreleased)
Attempted
- TM1637 7-segment display support (incorrect - device has OLED)
Version Numbering
- Major version (X.0.0): Breaking changes, incompatible config format
- Minor version (1.X.0): New features, backward-compatible
- Patch version (1.9.X): Bug fixes, no new features
Status: v1.9.3 is production-ready and actively used 24/7.