1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00

Introduce better types in Yardian coordinator (#152641)

Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
James
2026-01-10 03:55:08 +11:00
committed by GitHub
parent 5f7dc49215
commit a0ec7bde33
3 changed files with 44 additions and 34 deletions

View File

@@ -32,8 +32,8 @@ def _zone_enabled_value(
) -> bool | None:
"""Return True if zone is enabled on controller."""
try:
return coordinator.data.zones[zone_id][1] == 1
except (IndexError, TypeError):
return coordinator.data.zones[zone_id].is_enabled
except IndexError:
return None

View File

@@ -3,6 +3,7 @@
from __future__ import annotations
import asyncio
from dataclasses import dataclass
import datetime
import logging
@@ -22,22 +23,24 @@ _LOGGER = logging.getLogger(__name__)
SCAN_INTERVAL = datetime.timedelta(seconds=30)
class YardianCombinedState:
@dataclass(slots=True)
class YardianZone:
"""Normalized metadata for a Yardian irrigation zone."""
name: str
is_enabled: bool
@dataclass
class YardianCoordinatorData:
"""Combined device state for Yardian."""
def __init__(
self,
zones: list[list],
active_zones: set[int],
oper_info: OperationInfo,
) -> None:
"""Initialize combined state with zones, active_zones and oper_info."""
self.zones = zones
self.active_zones = active_zones
self.oper_info = oper_info
zones: list[YardianZone]
active_zones: set[int]
oper_info: OperationInfo
class YardianUpdateCoordinator(DataUpdateCoordinator[YardianCombinedState]):
class YardianUpdateCoordinator(DataUpdateCoordinator[YardianCoordinatorData]):
"""Coordinator for Yardian API calls."""
config_entry: ConfigEntry
@@ -75,31 +78,19 @@ class YardianUpdateCoordinator(DataUpdateCoordinator[YardianCombinedState]):
serial_number=self._serial,
)
async def _async_update_data(self) -> YardianCombinedState:
async def _async_update_data(self) -> YardianCoordinatorData:
"""Fetch data from Yardian device."""
_LOGGER.debug(
"Fetching Yardian device state for %s (controller=%s)",
self._name,
type(self.controller).__name__,
)
try:
async with asyncio.timeout(10):
_LOGGER.debug(
"Fetching Yardian device state for %s (controller=%s)",
self._name,
type(self.controller).__name__,
)
# Fetch device state and operation info; specific exceptions are
# handled by the outer block to avoid double-logging.
dev_state = await self.controller.fetch_device_state()
oper_info = await self.controller.fetch_oper_info()
oper_keys = list(oper_info.keys()) if hasattr(oper_info, "keys") else []
_LOGGER.debug(
"Fetched Yardian data: zones=%s active=%s oper_keys=%s",
len(getattr(dev_state, "zones", [])),
len(getattr(dev_state, "active_zones", [])),
oper_keys,
)
return YardianCombinedState(
zones=dev_state.zones,
active_zones=dev_state.active_zones,
oper_info=oper_info,
)
except TimeoutError as e:
raise UpdateFailed("Timeout communicating with device") from e
@@ -110,3 +101,22 @@ class YardianUpdateCoordinator(DataUpdateCoordinator[YardianCombinedState]):
except Exception as e: # safety net for tests to surface failure reason
_LOGGER.exception("Unexpected error while fetching Yardian data")
raise UpdateFailed(f"Unexpected error: {type(e).__name__}: {e}") from e
_LOGGER.debug(
"Fetched Yardian data: zones=%s active=%s oper_keys=%s",
len(dev_state.zones),
len(dev_state.active_zones),
list(oper_info.keys()),
)
return YardianCoordinatorData(
zones=[
YardianZone(
name=str(zone_info[0]),
is_enabled=zone_info[1] == 1,
)
for zone_info in dev_state.zones
],
active_zones=set(dev_state.active_zones),
oper_info=oper_info,
)

View File

@@ -62,7 +62,7 @@ class YardianSwitch(CoordinatorEntity[YardianUpdateCoordinator], SwitchEntity):
@property
def name(self) -> str:
"""Return the zone name."""
return self.coordinator.data.zones[self._zone_id][0]
return self.coordinator.data.zones[self._zone_id].name
@property
def is_on(self) -> bool:
@@ -72,7 +72,7 @@ class YardianSwitch(CoordinatorEntity[YardianUpdateCoordinator], SwitchEntity):
@property
def available(self) -> bool:
"""Return the switch is available or not."""
return self.coordinator.data.zones[self._zone_id][1] == 1
return self.coordinator.data.zones[self._zone_id].is_enabled
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""