mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-30 05:13:40 +00:00
Changed from centralized main+subentry coordinator pattern to independent
coordinators per home. Each config entry now manages its own home data
with its own API client and access token.
Architecture changes:
- API Client: async_get_price_info() changed from home_ids: set[str] to home_id: str
* Removed GraphQL alias pattern (home0, home1, ...)
* Single-home query structure without aliasing
* Simplified response parsing (viewer.home instead of viewer.home0)
- Coordinator: Removed main/subentry distinction
* Deleted is_main_entry() and _has_existing_main_coordinator()
* Each coordinator fetches its own data independently
* Removed _find_main_coordinator() and _get_configured_home_ids()
* Simplified _async_update_data() - no subentry logic
* Added _home_id instance variable from config_entry.data
- __init__.py: New _get_access_token() helper
* Handles token retrieval for both parent and subentries
* Subentries find parent entry to get shared access token
* Creates single API client instance per coordinator
- Data structures: Flat single-home format
* Old: {"homes": {home_id: {"price_info": [...]}}}
* New: {"home_id": str, "price_info": [...], "currency": str}
* Attribute name: "periods" → "pricePeriods" (consistent with priceInfo)
- helpers.py: Removed get_configured_home_ids() (no longer needed)
* parse_all_timestamps() updated for single-home structure
Impact: Each home operates independently with its own lifecycle tracking,
caching, and period calculations. Simpler architecture, easier debugging,
better isolation between homes.
80 lines
3.3 KiB
Python
80 lines
3.3 KiB
Python
"""
|
|
Diagnostics support for tibber_prices.
|
|
|
|
Learn more about diagnostics:
|
|
https://developers.home-assistant.io/docs/core/integration_diagnostics
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
if TYPE_CHECKING:
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from .data import TibberPricesConfigEntry
|
|
|
|
|
|
async def async_get_config_entry_diagnostics(
|
|
hass: HomeAssistant, # noqa: ARG001
|
|
entry: TibberPricesConfigEntry,
|
|
) -> dict[str, Any]:
|
|
"""Return diagnostics for a config entry."""
|
|
coordinator = entry.runtime_data.coordinator
|
|
|
|
# Get period metadata from coordinator data
|
|
price_periods = coordinator.data.get("pricePeriods", {}) if coordinator.data else {}
|
|
|
|
return {
|
|
"entry": {
|
|
"entry_id": entry.entry_id,
|
|
"version": entry.version,
|
|
"minor_version": entry.minor_version,
|
|
"domain": entry.domain,
|
|
"title": entry.title,
|
|
"state": str(entry.state),
|
|
"home_id": entry.data.get("home_id", ""),
|
|
},
|
|
"coordinator": {
|
|
"last_update_success": coordinator.last_update_success,
|
|
"update_interval": str(coordinator.update_interval),
|
|
"data": coordinator.data,
|
|
"update_timestamps": {
|
|
"price": coordinator._last_price_update.isoformat() if coordinator._last_price_update else None, # noqa: SLF001
|
|
"user": coordinator._last_user_update.isoformat() if coordinator._last_user_update else None, # noqa: SLF001
|
|
"last_coordinator_update": coordinator._last_coordinator_update.isoformat() # noqa: SLF001
|
|
if coordinator._last_coordinator_update # noqa: SLF001
|
|
else None,
|
|
},
|
|
"lifecycle": {
|
|
"state": coordinator._lifecycle_state, # noqa: SLF001
|
|
"is_fetching": coordinator._is_fetching, # noqa: SLF001
|
|
"api_calls_today": coordinator._api_calls_today, # noqa: SLF001
|
|
"last_api_call_date": coordinator._last_api_call_date.isoformat() # noqa: SLF001
|
|
if coordinator._last_api_call_date # noqa: SLF001
|
|
else None,
|
|
},
|
|
},
|
|
"periods": {
|
|
"best_price": {
|
|
"count": len(price_periods.get("best_price", {}).get("periods", [])),
|
|
"metadata": price_periods.get("best_price", {}).get("metadata", {}),
|
|
},
|
|
"peak_price": {
|
|
"count": len(price_periods.get("peak_price", {}).get("periods", [])),
|
|
"metadata": price_periods.get("peak_price", {}).get("metadata", {}),
|
|
},
|
|
},
|
|
"config": {
|
|
"options": dict(entry.options),
|
|
},
|
|
"cache_status": {
|
|
"user_data_cached": coordinator._cached_user_data is not None, # noqa: SLF001
|
|
"price_data_cached": coordinator._cached_price_data is not None, # noqa: SLF001
|
|
"transformer_cache_valid": coordinator._data_transformer._cached_transformed_data is not None, # noqa: SLF001
|
|
"period_calculator_cache_valid": coordinator._period_calculator._cached_periods is not None, # noqa: SLF001
|
|
},
|
|
"error": {
|
|
"last_exception": str(coordinator.last_exception) if coordinator.last_exception else None,
|
|
},
|
|
}
|