Files
core/homeassistant/components/nexia/entity.py
T

176 lines
5.9 KiB
Python

"""The nexia integration base entity."""
from typing import TYPE_CHECKING, override
from nexia.sensor import NexiaSensor
from nexia.thermostat import NexiaThermostat
from nexia.zone import NexiaThermostatZone
from homeassistant.const import ATTR_IDENTIFIERS, ATTR_NAME
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
ATTRIBUTION,
DOMAIN,
MANUFACTURER,
SIGNAL_THERMOSTAT_UPDATE,
SIGNAL_ZONE_UPDATE,
)
from .coordinator import NexiaDataUpdateCoordinator
class NexiaEntity(CoordinatorEntity[NexiaDataUpdateCoordinator]):
"""Base class for nexia entities."""
_attr_attribution = ATTRIBUTION
_attr_device_info: DeviceInfo | None = None
def __init__(self, coordinator: NexiaDataUpdateCoordinator, unique_id: str) -> None:
"""Initialize the entity."""
super().__init__(coordinator)
self._attr_unique_id = unique_id
class NexiaThermostatEntity(NexiaEntity):
"""Base class for nexia devices attached to a thermostat."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: NexiaDataUpdateCoordinator,
thermostat: NexiaThermostat,
unique_id: str,
) -> None:
"""Initialize the entity."""
super().__init__(coordinator, unique_id)
self._thermostat = thermostat
thermostat_id = thermostat.thermostat_id
self._attr_device_info = DeviceInfo(
configuration_url=self.coordinator.nexia_home.root_url,
identifiers={(DOMAIN, thermostat_id)}, # type: ignore[arg-type] # until fix issue #139773
manufacturer=MANUFACTURER,
model=thermostat.get_model(),
name=thermostat.get_name(),
sw_version=thermostat.get_firmware(),
)
self._thermostat_signal = f"{SIGNAL_THERMOSTAT_UPDATE}-{thermostat_id}"
@override
async def async_added_to_hass(self) -> None:
"""Listen for signals for services."""
await super().async_added_to_hass()
self.async_on_remove(
async_dispatcher_connect(
self.hass,
self._thermostat_signal,
self.async_write_ha_state,
)
)
def _signal_thermostat_update(self) -> None:
"""Signal a thermostat update.
Whenever the underlying library does an action against
a thermostat, the data for the thermostat and all
connected zone is updated.
Update all the zones on the thermostat.
"""
async_dispatcher_send(self.hass, self._thermostat_signal)
@property
@override
def available(self) -> bool:
"""Return True if thermostat is available and data is available."""
return super().available and self._thermostat.is_online
class NexiaThermostatZoneEntity(NexiaThermostatEntity):
"""Base class for nexia devices attached to a thermostat."""
def __init__(
self,
coordinator: NexiaDataUpdateCoordinator,
zone: NexiaThermostatZone,
unique_id: str,
dev_info: DeviceInfo | None = None,
) -> None:
"""Initialize the entity."""
super().__init__(coordinator, zone.thermostat, unique_id)
self._zone = zone
if TYPE_CHECKING:
assert self._attr_device_info is not None
if dev_info is not None:
self._attr_device_info |= dev_info
else:
self._attr_device_info |= {
ATTR_IDENTIFIERS: {(DOMAIN, zone.zone_id)}, # type: ignore[arg-type] # until fix issue #139773
ATTR_NAME: zone.get_name(),
"via_device_id": dr.async_get_device_id_by_identifier(
self.coordinator.hass,
(DOMAIN, zone.thermostat.thermostat_id), # type: ignore[arg-type] # until fix issue #139773
config_entry_id=self.coordinator.config_entry.entry_id,
),
}
self._zone_signal = f"{SIGNAL_ZONE_UPDATE}-{zone.zone_id}"
@override
async def async_added_to_hass(self) -> None:
"""Listen for signals for services."""
await super().async_added_to_hass()
self.async_on_remove(
async_dispatcher_connect(
self.hass,
self._zone_signal,
self.async_write_ha_state,
)
)
def _signal_zone_update(self) -> None:
"""Signal a zone update.
Whenever the underlying library does an action against
a zone, the data for the zone is updated.
Update a single zone.
"""
async_dispatcher_send(self.hass, self._zone_signal)
class NexiaRoomIQEntity(NexiaThermostatZoneEntity):
"""Base class for RoomIQ sensor entities."""
def __init__(
self,
coordinator: NexiaDataUpdateCoordinator,
zone: NexiaThermostatZone,
sensor: NexiaSensor,
key: str,
) -> None:
"""Initialize the entity."""
dev_info: DeviceInfo | None = None
if sensor.has_online:
# has_online indicates the RoomIQ sensor connects remotely
dev_info = DeviceInfo(
identifiers={(DOMAIN, str(sensor.id))},
model=None, # not reported
name=sensor.name,
suggested_area=sensor.name,
sw_version=None, # not reported
via_device_id=dr.async_get_device_id_by_identifier(
coordinator.hass,
(DOMAIN, zone.zone_id), # type: ignore[arg-type] # until fix issue #139773
config_entry_id=coordinator.config_entry.entry_id,
),
)
super().__init__(coordinator, zone, f"{sensor.id}-{key}", dev_info)
self._attr_translation_key = key
self._sensor_id = sensor.id