Compare commits

...

2 Commits

Author SHA1 Message Date
David Bonnes 87b1b17015 Merge branch 'dev' into evo_refactor_ids 2026-04-18 08:41:03 +01:00
David Bonnes 20b186c8f3 Refactor: extract unique_zone_id(), consolidate _evo_id init
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 07:04:09 +00:00
4 changed files with 40 additions and 34 deletions
+26 -24
View File
@@ -12,7 +12,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import EVOHOME_DATA
from .coordinator import EvoDataUpdateCoordinator
from .entity import EvoEntity, is_valid_zone
from .entity import EvoEntity, is_valid_zone, unique_zone_id
async def async_setup_platform(
@@ -45,28 +45,11 @@ async def async_setup_platform(
class EvoResetButtonBase(EvoEntity, ButtonEntity):
"""Button entity for system reset."""
"""Base for reset button entities."""
_attr_entity_category = EntityCategory.CONFIG
_evo_state_attr_names = ()
def __init__(
self,
coordinator: EvoDataUpdateCoordinator,
evo_device: evo.ControlSystem | evo.HotWater | evo.Zone,
) -> None:
"""Initialize the system reset button."""
super().__init__(coordinator, evo_device)
# zones can be renamed, so set name in their property method
if isinstance(evo_device, evo.ControlSystem):
self._attr_name = f"Reset {evo_device.location.name}"
elif not isinstance(evo_device, evo.Zone):
self._attr_name = f"Reset {evo_device.name}"
self._attr_unique_id = f"{evo_device.id}_reset"
async def async_press(self) -> None:
"""Reset the Evohome entity to its base operating mode."""
await self.coordinator.call_client_api(self._evo_device.reset())
@@ -80,6 +63,17 @@ class EvoResetSystemButton(EvoResetButtonBase):
_evo_device: evo.ControlSystem
_evo_id_attr = "system_id"
def __init__(
self,
coordinator: EvoDataUpdateCoordinator,
evo_device: evo.ControlSystem,
) -> None:
"""Initialize the system reset button."""
super().__init__(coordinator, evo_device)
self._attr_unique_id = f"{evo_device.id}_reset"
self._attr_name = f"Reset {evo_device.location.name}"
class EvoResetDhwButton(EvoResetButtonBase):
"""Button entity for DHW override reset."""
@@ -89,6 +83,17 @@ class EvoResetDhwButton(EvoResetButtonBase):
_evo_device: evo.HotWater
_evo_id_attr = "dhw_id"
def __init__(
self,
coordinator: EvoDataUpdateCoordinator,
evo_device: evo.HotWater,
) -> None:
"""Initialize the DHW reset button."""
super().__init__(coordinator, evo_device)
self._attr_unique_id = f"{evo_device.id}_reset"
self._attr_name = f"Reset {evo_device.name}"
class EvoResetZoneButton(EvoResetButtonBase):
"""Button entity for zone override reset."""
@@ -105,12 +110,9 @@ class EvoResetZoneButton(EvoResetButtonBase):
) -> None:
"""Initialize the zone reset button."""
super().__init__(coordinator, evo_device)
if evo_device.id == evo_device.tcs.id:
# this system does not have a distinct ID for the zone
self._attr_unique_id = f"{evo_device.id}z_reset"
self._attr_unique_id = f"{unique_zone_id(evo_device)}_reset"
@property
def name(self) -> str:
"""Return the name of the evohome entity."""
"""Return the name, dynamically following any zone rename."""
return f"Reset {self._evo_device.name}"
+2 -8
View File
@@ -49,7 +49,7 @@ from .const import (
EvoService,
)
from .coordinator import EvoDataUpdateCoordinator
from .entity import EvoChild, EvoEntity, is_valid_zone
from .entity import EvoChild, EvoEntity, is_valid_zone, unique_zone_id
from .helpers import async_create_deprecation_issue_once
_LOGGER = logging.getLogger(__name__)
@@ -170,13 +170,8 @@ class EvoZone(EvoChild, EvoClimateEntity):
"""Initialize an evohome-compatible heating zone."""
super().__init__(coordinator, evo_device)
self._evo_id = evo_device.id
if evo_device.id == evo_device.tcs.id:
# this system does not have a distinct ID for the zone
self._attr_unique_id = f"{evo_device.id}z"
else:
self._attr_unique_id = evo_device.id
self._attr_unique_id = unique_zone_id(evo_device)
if coordinator.client_v1:
self._attr_precision = PRECISION_TENTHS
@@ -352,7 +347,6 @@ class EvoController(EvoClimateEntity):
"""Initialize an evohome-compatible controller."""
super().__init__(coordinator, evo_device)
self._evo_id = evo_device.id
self._attr_unique_id = evo_device.id
self._attr_name = evo_device.location.name
@@ -28,6 +28,17 @@ def is_valid_zone(zone: evo.Zone) -> bool:
)
def unique_zone_id(evo_device: evo.Zone) -> str:
"""Return a unique identifier for a zone-based entity.
Some systems assign the zone the same ID as its parent TCS; in that case
we append 'z' so the zone entity doesn't collide with the controller entity.
"""
if evo_device.id == evo_device.tcs.id:
return f"{evo_device.id}z"
return evo_device.id
class EvoEntity(CoordinatorEntity[EvoDataUpdateCoordinator]):
"""Base for any evohome-compatible entity (controller, DHW, zone).
@@ -86,6 +97,7 @@ class EvoChild(EvoEntity):
"""Initialize an evohome-compatible child entity (DHW, zone)."""
super().__init__(coordinator, evo_device)
self._evo_id = evo_device.id
self._evo_tcs = evo_device.tcs
self._schedule: list[DayOfWeekDhwT] | None = None
@@ -70,7 +70,6 @@ async def async_setup_platform(
class EvoDHW(EvoChild, WaterHeaterEntity):
"""Base for any evohome-compatible DHW controller."""
_attr_name = "DHW controller"
_attr_operation_list = list(HA_STATE_TO_EVO)
_attr_supported_features = (
WaterHeaterEntityFeature.AWAY_MODE
@@ -89,7 +88,6 @@ class EvoDHW(EvoChild, WaterHeaterEntity):
"""Initialize an evohome-compatible DHW controller."""
super().__init__(coordinator, evo_device)
self._evo_id = evo_device.id
self._attr_unique_id = evo_device.id
self._attr_name = evo_device.name # is static