From 3977d5e329523afa2cded61c24a116dec2f6a3d9 Mon Sep 17 00:00:00 2001 From: Julian Pawlowski <75446+jpawlowski@users.noreply.github.com> Date: Tue, 2 Dec 2025 19:00:20 +0000 Subject: [PATCH] fix(coordinator): add _is_fetching flag and fix tomorrow data detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement _is_fetching flag to show "refreshing" status during API calls, and fix needs_tomorrow_data() to recognize single-home cache format. Changes: - Set _is_fetching flag before API call, reset after completion (core.py) - Fix needs_tomorrow_data() to check for "price_info" key instead of "homes" - Remove redundant "homes" check in should_update_price_data() - Improve logging: change debug to info for tomorrow data checks Lifecycle status now correctly transitions after 13:00 when tomorrow data is missing: cached → searching_tomorrow → refreshing → fresh → cached Impact: Users will see accurate lifecycle status and tomorrow's electricity prices will automatically load when available after 13:00, fixing issue since v0.14.0 where prices weren't fetched without manual HA restart. --- .../tibber_prices/coordinator/core.py | 16 ++++++++++ .../coordinator/data_fetching.py | 10 ++----- .../tibber_prices/coordinator/helpers.py | 29 ++++++++++--------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/custom_components/tibber_prices/coordinator/core.py b/custom_components/tibber_prices/coordinator/core.py index e8c8686..6cefbf7 100644 --- a/custom_components/tibber_prices/coordinator/core.py +++ b/custom_components/tibber_prices/coordinator/core.py @@ -587,12 +587,28 @@ class TibberPricesDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]): # Track last_price_update timestamp before fetch to detect if data actually changed old_price_update = self._last_price_update + # CRITICAL: Check if we need to fetch data BEFORE starting the fetch + # This allows the lifecycle sensor to show "searching_tomorrow" status + # when we're actively looking for tomorrow's data after 13:00 + should_update = self._data_fetcher.should_update_price_data(current_time) + + # Set _is_fetching flag if we're about to fetch data + # This makes the lifecycle sensor show "refreshing" status during the API call + if should_update: + self._is_fetching = True + # Immediately notify lifecycle sensor about state change + # This ensures "refreshing" or "searching_tomorrow" appears DURING the fetch + self.async_update_listeners() + result = await self._data_fetcher.handle_main_entry_update( current_time, self._home_id, self._transform_data, ) + # CRITICAL: Reset fetching flag AFTER data fetch completes + self._is_fetching = False + # CRITICAL: Sync cached data after API call # handle_main_entry_update() updates data_fetcher's cache, we need to sync: # 1. cached_user_data (for new integrations, may be fetched via update_user_data_if_needed()) diff --git a/custom_components/tibber_prices/coordinator/data_fetching.py b/custom_components/tibber_prices/coordinator/data_fetching.py index c8c2a10..9bbf5c6 100644 --- a/custom_components/tibber_prices/coordinator/data_fetching.py +++ b/custom_components/tibber_prices/coordinator/data_fetching.py @@ -149,14 +149,9 @@ class TibberPricesDataFetcher: # Check if after 13:00 and tomorrow data is missing or invalid now_local = self.time.as_local(current_time) - if ( - now_local.hour >= TOMORROW_DATA_CHECK_HOUR - and self._cached_price_data - and "homes" in self._cached_price_data - and self.needs_tomorrow_data() - ): + if now_local.hour >= TOMORROW_DATA_CHECK_HOUR and self._cached_price_data and self.needs_tomorrow_data(): self._log( - "debug", + "info", "API update needed: After %s:00 and tomorrow's data missing/invalid", TOMORROW_DATA_CHECK_HOUR, ) @@ -165,6 +160,7 @@ class TibberPricesDataFetcher: return "tomorrow_check" # No update needed - cache is valid and complete + self._log("debug", "No API update needed: Cache is valid and complete") return False def needs_tomorrow_data(self) -> bool: diff --git a/custom_components/tibber_prices/coordinator/helpers.py b/custom_components/tibber_prices/coordinator/helpers.py index 15acbcc..bd8ce97 100644 --- a/custom_components/tibber_prices/coordinator/helpers.py +++ b/custom_components/tibber_prices/coordinator/helpers.py @@ -109,32 +109,33 @@ def needs_tomorrow_data( cached_price_data: dict[str, Any] | None, ) -> bool: """ - Check if tomorrow data is missing or invalid in flat interval list. + Check if tomorrow data is missing or invalid in cached price data. + + Expects single-home cache format: {"price_info": [...], "home_id": "xxx"} + + Old multi-home format (v0.14.0) is automatically invalidated by is_cache_valid() + in cache.py, so we only need to handle the current format here. Uses get_intervals_for_day_offsets() to automatically determine tomorrow based on current date. No explicit date parameter needed. Args: - cached_price_data: Cached price data with homes structure + cached_price_data: Cached price data in single-home structure Returns: - True if any home is missing tomorrow's data, False otherwise + True if tomorrow's data is missing, False otherwise """ - if not cached_price_data or "homes" not in cached_price_data: + if not cached_price_data or "price_info" not in cached_price_data: return False - # Check each home's intervals for tomorrow's date - for home_data in cached_price_data["homes"].values(): - # Use helper to get tomorrow's intervals (offset +1 from current date) - coordinator_data = {"priceInfo": home_data.get("price_info", [])} - tomorrow_intervals = get_intervals_for_day_offsets(coordinator_data, [1]) + # Single-home format: {"price_info": [...], "home_id": "xxx"} + # Use helper to get tomorrow's intervals (offset +1 from current date) + coordinator_data = {"priceInfo": cached_price_data.get("price_info", [])} + tomorrow_intervals = get_intervals_for_day_offsets(coordinator_data, [1]) - # If no intervals for tomorrow found, we need tomorrow data - if not tomorrow_intervals: - return True - - return False + # If no intervals for tomorrow found, we need tomorrow data + return len(tomorrow_intervals) == 0 def parse_all_timestamps(price_data: dict[str, Any], *, time: TibberPricesTimeService) -> dict[str, Any]: