2 Commits
Author SHA1 Message Date
Alex PetrochenkoandClaude Sonnet 4.6 d5d2b23129 chore: bump version to 1.9.5, update CHANGELOG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 14:53:15 +01:00
Alex PetrochenkoandClaude Sonnet 4.6 2f3814c225 fix(weather): recover from permanent lockup after max retries (closes #9)
After 3 consecutive API failures, weatherRetry.reset() was never called
and weatherState stayed WEATHER_FAILED permanently. Both the retry path
and periodic refresh path require WEATHER_IDLE, so no new requests were
ever made — even after the API recovered.

Fix: when maxRetriesReached(), reset weatherRetry and set weatherState
back to WEATHER_IDLE so the next periodic refresh interval (default 30min)
triggers a fresh attempt automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 14:52:42 +01:00
3 changed files with 18 additions and 3 deletions
+9
View File
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.9.5] - 2026-05-18
### Fixed
- **Temperature disappears permanently** (#9): After 3 consecutive API failures,
the weather state machine was permanently locked — `weatherState` stayed `WEATHER_FAILED`
and 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 ## [1.9.4] - 2026-05-14
### Fixed ### Fixed
+1 -1
View File
@@ -9,7 +9,7 @@
#include <Arduino.h> #include <Arduino.h>
// Firmware version // Firmware version
#define FIRMWARE_VERSION "1.9.4" #define FIRMWARE_VERSION "1.9.5"
// OLED I2C Configuration // OLED I2C Configuration
#define I2C_SDA 0 // GPIO0 (I2C Data) - SWAPPED! #define I2C_SDA 0 // GPIO0 (I2C Data) - SWAPPED!
+8 -2
View File
@@ -96,7 +96,10 @@ void ICACHE_FLASH_ATTR onWeatherResponse(void* optParm, AsyncHTTPRequest* reques
weatherRetry.scheduleRetry(); weatherRetry.scheduleRetry();
if (weatherRetry.maxRetriesReached()) { if (weatherRetry.maxRetriesReached()) {
Serial.println("Weather max retries reached"); // Reset so periodic refresh can retry after weatherInterval — prevents permanent lockup
Serial.println("Weather max retries reached, resetting for next interval");
weatherRetry.reset();
weatherState = WEATHER_IDLE;
} else { } else {
unsigned long backoff = weatherRetry.getBackoffDelay() / 1000; unsigned long backoff = weatherRetry.getBackoffDelay() / 1000;
Serial.printf(" Retry scheduled in %lu seconds\n", backoff); Serial.printf(" Retry scheduled in %lu seconds\n", backoff);
@@ -113,7 +116,10 @@ void ICACHE_FLASH_ATTR onWeatherResponse(void* optParm, AsyncHTTPRequest* reques
weatherRetry.scheduleRetry(); weatherRetry.scheduleRetry();
if (weatherRetry.maxRetriesReached()) { if (weatherRetry.maxRetriesReached()) {
Serial.println("Weather max retries reached"); // Reset so periodic refresh can retry after weatherInterval — prevents permanent lockup
Serial.println("Weather max retries reached, resetting for next interval");
weatherRetry.reset();
weatherState = WEATHER_IDLE;
} else { } else {
unsigned long backoff = weatherRetry.getBackoffDelay() / 1000; unsigned long backoff = weatherRetry.getBackoffDelay() / 1000;
Serial.printf(" Retry scheduled in %lu seconds\n", backoff); Serial.printf(" Retry scheduled in %lu seconds\n", backoff);