Update sensor.py

This commit is contained in:
balgerion
2025-04-30 10:06:14 +02:00
committed by GitHub
parent e6d49f1483
commit f2afb213b4

View File

@ -1,5 +1,6 @@
"""Sensor platform for Pstryk Energy integration.""" """Sensor platform for Pstryk Energy integration."""
import logging import logging
import asyncio
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.components.sensor import SensorEntity, SensorStateClass from homeassistant.components.sensor import SensorEntity, SensorStateClass
@ -20,11 +21,14 @@ async def async_setup_entry(
buy_top = entry.options.get("buy_top", entry.data.get("buy_top", 5)) buy_top = entry.options.get("buy_top", entry.data.get("buy_top", 5))
sell_top = entry.options.get("sell_top", entry.data.get("sell_top", 5)) sell_top = entry.options.get("sell_top", entry.data.get("sell_top", 5))
_LOGGER.debug("Setting up Pstryk sensors with buy_top=%d, sell_top=%d", buy_top, sell_top)
# Cleanup old coordinators if they exist # Cleanup old coordinators if they exist
for price_type in ("buy", "sell"): for price_type in ("buy", "sell"):
key = f"{entry.entry_id}_{price_type}" key = f"{entry.entry_id}_{price_type}"
coordinator = hass.data[DOMAIN].get(key) coordinator = hass.data[DOMAIN].get(key)
if coordinator: if coordinator:
_LOGGER.debug("Cleaning up existing %s coordinator", price_type)
# Cancel scheduled updates # Cancel scheduled updates
if hasattr(coordinator, '_unsub_hourly') and coordinator._unsub_hourly: if hasattr(coordinator, '_unsub_hourly') and coordinator._unsub_hourly:
coordinator._unsub_hourly() coordinator._unsub_hourly()
@ -34,10 +38,45 @@ async def async_setup_entry(
hass.data[DOMAIN].pop(key, None) hass.data[DOMAIN].pop(key, None)
entities = [] entities = []
coordinators = []
# Create coordinators first
for price_type in ("buy", "sell"): for price_type in ("buy", "sell"):
key = f"{entry.entry_id}_{price_type}" key = f"{entry.entry_id}_{price_type}"
coordinator = PstrykDataUpdateCoordinator(hass, api_key, price_type) coordinator = PstrykDataUpdateCoordinator(hass, api_key, price_type)
await coordinator.async_config_entry_first_refresh() coordinators.append((coordinator, price_type, key))
# Initialize coordinators in parallel to save time
initial_refresh_tasks = []
for coordinator, _, _ in coordinators:
# Check if we're in the setup process or reloading
try:
# Newer Home Assistant versions
from homeassistant.config_entries import ConfigEntryState
is_setup = entry.state == ConfigEntryState.SETUP_IN_PROGRESS
except ImportError:
# Older Home Assistant versions - try another approach
is_setup = not hass.data[DOMAIN].get(f"{entry.entry_id}_initialized", False)
if is_setup:
initial_refresh_tasks.append(coordinator.async_config_entry_first_refresh())
else:
initial_refresh_tasks.append(coordinator.async_refresh())
refresh_results = await asyncio.gather(*initial_refresh_tasks, return_exceptions=True)
# Mark as initialized after first setup
hass.data[DOMAIN][f"{entry.entry_id}_initialized"] = True
# Process coordinators and set up sensors
for i, (coordinator, price_type, key) in enumerate(coordinators):
# Check if initial refresh succeeded
if isinstance(refresh_results[i], Exception):
_LOGGER.error("Failed to initialize %s coordinator: %s",
price_type, str(refresh_results[i]))
# Still add coordinator and set up sensors even if initial load failed
# Schedule updates
coordinator.schedule_hourly_update() coordinator.schedule_hourly_update()
coordinator.schedule_midnight_update() coordinator.schedule_midnight_update()
hass.data[DOMAIN][key] = coordinator hass.data[DOMAIN][key] = coordinator
@ -56,6 +95,7 @@ class PstrykCurrentPriceSensor(CoordinatorEntity, SensorEntity):
def __init__(self, coordinator: PstrykDataUpdateCoordinator, price_type: str): def __init__(self, coordinator: PstrykDataUpdateCoordinator, price_type: str):
super().__init__(coordinator) super().__init__(coordinator)
self.price_type = price_type self.price_type = price_type
self._attr_device_class = "monetary"
@property @property
def name(self) -> str: def name(self) -> str:
@ -67,12 +107,19 @@ class PstrykCurrentPriceSensor(CoordinatorEntity, SensorEntity):
@property @property
def native_value(self): def native_value(self):
if self.coordinator.data is None:
return None
return self.coordinator.data.get("current") return self.coordinator.data.get("current")
@property @property
def native_unit_of_measurement(self) -> str: def native_unit_of_measurement(self) -> str:
return "PLN/kWh" return "PLN/kWh"
@property
def available(self) -> bool:
"""Return if entity is available."""
return self.coordinator.last_update_success and self.coordinator.data is not None
class PstrykPriceTableSensor(CoordinatorEntity, SensorEntity): class PstrykPriceTableSensor(CoordinatorEntity, SensorEntity):
"""Today's price table sensor.""" """Today's price table sensor."""
@ -94,10 +141,21 @@ class PstrykPriceTableSensor(CoordinatorEntity, SensorEntity):
@property @property
def native_value(self) -> int: def native_value(self) -> int:
# number of price slots today # number of price slots today
if self.coordinator.data is None:
return 0
return len(self.coordinator.data.get("prices_today", [])) return len(self.coordinator.data.get("prices_today", []))
@property @property
def extra_state_attributes(self) -> dict: def extra_state_attributes(self) -> dict:
if self.coordinator.data is None:
return {
"all_prices": [],
"best_prices": [],
"top_count": self.top_count,
"last_updated": dt_util.as_local(dt_util.utcnow()).isoformat(),
"data_available": False
}
today = self.coordinator.data.get("prices_today", []) today = self.coordinator.data.get("prices_today", [])
sorted_prices = sorted( sorted_prices = sorted(
today, today,
@ -109,4 +167,10 @@ class PstrykPriceTableSensor(CoordinatorEntity, SensorEntity):
"best_prices": sorted_prices[: self.top_count], "best_prices": sorted_prices[: self.top_count],
"top_count": self.top_count, "top_count": self.top_count,
"last_updated": dt_util.as_local(dt_util.utcnow()).isoformat(), "last_updated": dt_util.as_local(dt_util.utcnow()).isoformat(),
"data_available": True
} }
@property
def available(self) -> bool:
"""Return if entity is available."""
return self.coordinator.last_update_success and self.coordinator.data is not None