core/homeassistant/components/hue/v2/device.py

92 lines
3.5 KiB
Python

"""Handles Hue resource of type `device` mapping to Home Assistant device."""
from typing import TYPE_CHECKING
from aiohue.v2 import HueBridgeV2
from aiohue.v2.controllers.events import EventType
from aiohue.v2.models.device import Device, DeviceArchetypes
from homeassistant.const import (
ATTR_CONNECTIONS,
ATTR_IDENTIFIERS,
ATTR_MANUFACTURER,
ATTR_MODEL,
ATTR_NAME,
ATTR_SUGGESTED_AREA,
ATTR_SW_VERSION,
ATTR_VIA_DEVICE,
)
from homeassistant.core import callback
from homeassistant.helpers import device_registry
from ..const import DOMAIN
if TYPE_CHECKING:
from ..bridge import HueBridge
async def async_setup_devices(bridge: "HueBridge"):
"""Manage setup of devices from Hue devices."""
entry = bridge.config_entry
hass = bridge.hass
api: HueBridgeV2 = bridge.api # to satisfy typing
dev_reg = device_registry.async_get(hass)
dev_controller = api.devices
@callback
def add_device(hue_device: Device) -> device_registry.DeviceEntry:
"""Register a Hue device in device registry."""
model = f"{hue_device.product_data.product_name} ({hue_device.product_data.model_id})"
params = {
ATTR_IDENTIFIERS: {(DOMAIN, hue_device.id)},
ATTR_SW_VERSION: hue_device.product_data.software_version,
ATTR_NAME: hue_device.metadata.name,
ATTR_MODEL: model,
ATTR_MANUFACTURER: hue_device.product_data.manufacturer_name,
}
if room := dev_controller.get_room(hue_device.id):
params[ATTR_SUGGESTED_AREA] = room.metadata.name
if hue_device.metadata.archetype == DeviceArchetypes.BRIDGE_V2:
params[ATTR_IDENTIFIERS].add((DOMAIN, api.config.bridge_id))
else:
params[ATTR_VIA_DEVICE] = (DOMAIN, api.config.bridge_device.id)
zigbee = dev_controller.get_zigbee_connectivity(hue_device.id)
if zigbee and zigbee.mac_address:
params[ATTR_CONNECTIONS] = {
(device_registry.CONNECTION_NETWORK_MAC, zigbee.mac_address)
}
return dev_reg.async_get_or_create(config_entry_id=entry.entry_id, **params)
@callback
def remove_device(hue_device_id: str) -> None:
"""Remove device from registry."""
if device := dev_reg.async_get_device({(DOMAIN, hue_device_id)}):
# note: removal of any underlying entities is handled by core
dev_reg.async_remove_device(device.id)
@callback
def handle_device_event(evt_type: EventType, hue_device: Device) -> None:
"""Handle event from Hue devices controller."""
if evt_type == EventType.RESOURCE_DELETED:
remove_device(hue_device.id)
else:
# updates to existing device will also be handled by this call
add_device(hue_device)
# create/update all current devices found in controller
known_devices = [add_device(hue_device) for hue_device in dev_controller]
# Check for nodes that no longer exist and remove them
for device in device_registry.async_entries_for_config_entry(
dev_reg, entry.entry_id
):
if device not in known_devices:
# handle case where a virtual device was created for a Hue group
hue_dev_id = next(x[1] for x in device.identifiers if x[0] == DOMAIN)
if hue_dev_id in api.groups:
continue
dev_reg.async_remove_device(device.id)
# add listener for updates on Hue devices controller
entry.async_on_unload(dev_controller.subscribe(handle_device_event))