Files
2026-07-08 10:43:39 -04:00

90 lines
3.4 KiB
Python

"""Base entity for the Maintenance Supporter integration."""
from __future__ import annotations
from typing import Any
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from ..const import CONF_OBJECT, DOMAIN, GLOBAL_UNIQUE_ID
from ..coordinator import MaintenanceCoordinator
class MaintenanceEntity(CoordinatorEntity[MaintenanceCoordinator]):
"""Base class for Maintenance Supporter entities."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: MaintenanceCoordinator,
task_id: str,
) -> None:
"""Initialize the base entity."""
super().__init__(coordinator)
self._task_id = task_id
self._object_data = coordinator.entry.data.get(CONF_OBJECT, {})
@property
def device_info(self) -> DeviceInfo:
"""Return device info for this maintenance object.
Three shapes (2.19, device attachment):
* ``ha_device_id`` set → attach to that EXISTING device: return only
its identifiers/connections so the registry merges us onto it — no
name/manufacturer, which would overwrite the owning integration's
metadata (the obj→device forward-sync skips linked objects too).
* ``parent_entry_id`` set → our own device, nested under the parent
object's device via ``via_device``.
* neither → our own stand-alone device (the historical shape).
"""
obj = self._object_data
hass = self.coordinator.hass
if device_id := obj.get("ha_device_id"):
device = dr.async_get(hass).async_get(device_id)
if device is not None and (device.identifiers or device.connections):
info = DeviceInfo()
if device.identifiers:
info["identifiers"] = device.identifiers
if device.connections:
info["connections"] = device.connections
return info
# Linked device vanished → fall through to an own device so the
# entities never end up device-less.
identifiers = {(DOMAIN, self.coordinator.entry.unique_id or "")}
device_info = DeviceInfo(
identifiers=identifiers,
name=obj.get("name", "Unknown"),
)
if obj.get("manufacturer"):
device_info["manufacturer"] = obj["manufacturer"]
if obj.get("model"):
device_info["model"] = obj["model"]
if obj.get("serial_number"):
device_info["serial_number"] = obj["serial_number"]
if obj.get("area_id"):
device_info["suggested_area"] = obj["area_id"]
if parent_entry_id := obj.get("parent_entry_id"):
parent = hass.config_entries.async_get_entry(parent_entry_id)
if parent is not None and parent.domain == DOMAIN and parent.unique_id and parent.unique_id != GLOBAL_UNIQUE_ID:
device_info["via_device"] = (DOMAIN, parent.unique_id)
return device_info
@property
def _task_data(self) -> dict[str, Any]:
"""Return the current task data from coordinator."""
if self.coordinator.data is None:
return {}
tasks: dict[str, Any] = self.coordinator.data.get("tasks", {})
result: dict[str, Any] = tasks.get(self._task_id, {})
return result