Files
core/homeassistant/components/overkiz/entity.py
T
2026-08-13 13:53:15 +02:00

146 lines
5.3 KiB
Python

"""Parent class for every Overkiz device."""
from typing import cast, override
from pyoverkiz.enums import APIType, OverkizAttribute, OverkizCommandParam, OverkizState
from pyoverkiz.models import Device
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN
from .coordinator import OverkizDataUpdateCoordinator
from .executor import OverkizExecutor
class OverkizEntity(CoordinatorEntity[OverkizDataUpdateCoordinator]):
"""Representation of an Overkiz device entity."""
_attr_has_entity_name = True
_attr_name: str | None = None
_attr_device_info: DeviceInfo | None = None
def __init__(
self, device_url: str, coordinator: OverkizDataUpdateCoordinator
) -> None:
"""Initialize the device."""
super().__init__(coordinator)
self.device_url = device_url
self.executor = OverkizExecutor(device_url, coordinator)
self._attr_assumed_state = not self.device.states
self._attr_unique_id = self.device.device_url
if self.device.identifier.is_sub_device:
# In case of sub entity, use the provided label as name
self._attr_name = self.device.label
self._attr_device_info = self.generate_device_info()
@property
@override
def available(self) -> bool:
"""Return True if entity is available."""
if self.device.available:
return super().available
# Workaround: local API may incorrectly report
# available=False (Somfy-TaHoma-Developer-Mode#217)
if self.coordinator.client.server_config.api_type != APIType.LOCAL:
return False
if status_state := self.device.states.get(OverkizState.CORE_STATUS):
return (
status_state.value == OverkizCommandParam.AVAILABLE
and super().available
)
return False
@property
def device(self) -> Device:
"""Return Overkiz device linked to this entity."""
return self.coordinator.data[self.device_url]
def generate_device_info(self) -> DeviceInfo:
"""Return device registry information for this entity."""
# Some devices, such as the Smart Thermostat have several devices
# in one physical device, with same device url, terminated by '#' and a number.
# In this case, we use the base device url as the device identifier.
if self.device.identifier.is_sub_device:
# Only return the url of the base device, to inherit device name
# and model from parent device.
return DeviceInfo(
identifiers={(DOMAIN, self.device.identifier.base_device_url)},
)
manufacturer = (
self.device.attributes.get_value(OverkizAttribute.CORE_MANUFACTURER)
or self.device.states.get_value(OverkizState.CORE_MANUFACTURER_NAME)
or self.coordinator.client.server_config.manufacturer
)
model = (
self.device.states.first_value(
[
OverkizState.CORE_MODEL,
OverkizState.CORE_PRODUCT_MODEL_NAME,
OverkizState.IO_MODEL,
]
)
or self.device.ui_class.value
)
suggested_area = (
self.coordinator.areas[self.device.place_oid]
if self.coordinator.areas and self.device.place_oid
else None
)
return DeviceInfo(
identifiers={(DOMAIN, self.device.identifier.base_device_url)},
name=self.device.label,
manufacturer=str(manufacturer),
model=str(model),
sw_version=cast(
str,
self.device.attributes.get_value(
OverkizAttribute.CORE_FIRMWARE_REVISION
),
),
model_id=self.device.widget,
hw_version=self.device.controllable_name,
suggested_area=suggested_area,
via_device_id=dr.async_get_device_id_by_identifier(
self.coordinator.hass,
(DOMAIN, self.device.identifier.gateway_id),
config_entry_id=self.coordinator.config_entry.entry_id,
),
configuration_url=self.coordinator.client.server_config.configuration_url,
)
class OverkizDescriptiveEntity(OverkizEntity):
"""Representation of a Overkiz device entity based on a description."""
def __init__(
self,
device_url: str,
coordinator: OverkizDataUpdateCoordinator,
description: EntityDescription,
) -> None:
"""Initialize the device."""
super().__init__(device_url, coordinator)
self.entity_description = description
self._attr_unique_id = f"{super().unique_id}-{self.entity_description.key}"
if self.device.identifier.is_sub_device:
if isinstance(description.name, str):
self._attr_name = f"{self.device.label} {description.name}"
else:
self._attr_name = self.device.label
elif isinstance(description.name, str):
self._attr_name = description.name