Remove individual lcn devices for each entity (#136450)

echo
Andre Lengwenus 2025-02-23 14:42:54 +01:00 committed by GitHub
parent 15ca2fe489
commit 800fe1b01e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 23 additions and 76 deletions

View File

@ -49,6 +49,7 @@ from .helpers import (
InputType, InputType,
async_update_config_entry, async_update_config_entry,
generate_unique_id, generate_unique_id,
purge_device_registry,
register_lcn_address_devices, register_lcn_address_devices,
register_lcn_host_device, register_lcn_host_device,
) )
@ -120,6 +121,9 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
register_lcn_host_device(hass, config_entry) register_lcn_host_device(hass, config_entry)
register_lcn_address_devices(hass, config_entry) register_lcn_address_devices(hass, config_entry)
# clean up orphaned devices
purge_device_registry(hass, config_entry.entry_id, {**config_entry.data})
# forward config_entry to components # forward config_entry to components
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)

View File

@ -3,19 +3,18 @@
from collections.abc import Callable from collections.abc import Callable
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ADDRESS, CONF_DOMAIN, CONF_NAME, CONF_RESOURCE from homeassistant.const import CONF_ADDRESS, CONF_NAME, CONF_RESOURCE
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from .const import CONF_DOMAIN_DATA, DOMAIN from .const import DOMAIN
from .helpers import ( from .helpers import (
AddressType, AddressType,
DeviceConnectionType, DeviceConnectionType,
InputType, InputType,
generate_unique_id, generate_unique_id,
get_device_connection, get_device_connection,
get_device_model,
) )
@ -36,6 +35,14 @@ class LcnEntity(Entity):
self.address: AddressType = config[CONF_ADDRESS] self.address: AddressType = config[CONF_ADDRESS]
self._unregister_for_inputs: Callable | None = None self._unregister_for_inputs: Callable | None = None
self._name: str = config[CONF_NAME] self._name: str = config[CONF_NAME]
self._attr_device_info = DeviceInfo(
identifiers={
(
DOMAIN,
generate_unique_id(self.config_entry.entry_id, self.address),
)
},
)
@property @property
def unique_id(self) -> str: def unique_id(self) -> str:
@ -44,28 +51,6 @@ class LcnEntity(Entity):
self.config_entry.entry_id, self.address, self.config[CONF_RESOURCE] self.config_entry.entry_id, self.address, self.config[CONF_RESOURCE]
) )
@property
def device_info(self) -> DeviceInfo | None:
"""Return device specific attributes."""
address = f"{'g' if self.address[2] else 'm'}{self.address[0]:03d}{self.address[1]:03d}"
model = (
"LCN resource"
f" ({get_device_model(self.config[CONF_DOMAIN], self.config[CONF_DOMAIN_DATA])})"
)
return DeviceInfo(
identifiers={(DOMAIN, self.unique_id)},
name=f"{address}.{self.config[CONF_RESOURCE]}",
model=model,
manufacturer="Issendorff",
via_device=(
DOMAIN,
generate_unique_id(
self.config_entry.entry_id, self.config[CONF_ADDRESS]
),
),
)
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass.""" """Run when entity about to be added to hass."""
self.device_connection = get_device_connection( self.device_connection = get_device_connection(

View File

@ -4,7 +4,6 @@ from __future__ import annotations
import asyncio import asyncio
from copy import deepcopy from copy import deepcopy
from itertools import chain
import re import re
from typing import cast from typing import cast
@ -22,7 +21,6 @@ from homeassistant.const import (
CONF_NAME, CONF_NAME,
CONF_RESOURCE, CONF_RESOURCE,
CONF_SENSORS, CONF_SENSORS,
CONF_SOURCE,
CONF_SWITCHES, CONF_SWITCHES,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -30,23 +28,14 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from .const import ( from .const import (
BINSENSOR_PORTS,
CONF_CLIMATES, CONF_CLIMATES,
CONF_HARDWARE_SERIAL, CONF_HARDWARE_SERIAL,
CONF_HARDWARE_TYPE, CONF_HARDWARE_TYPE,
CONF_OUTPUT,
CONF_SCENES, CONF_SCENES,
CONF_SOFTWARE_SERIAL, CONF_SOFTWARE_SERIAL,
CONNECTION, CONNECTION,
DEVICE_CONNECTIONS, DEVICE_CONNECTIONS,
DOMAIN, DOMAIN,
LED_PORTS,
LOGICOP_PORTS,
OUTPUT_PORTS,
S0_INPUTS,
SETPOINTS,
THRESHOLDS,
VARIABLES,
) )
# typing # typing
@ -96,31 +85,6 @@ def get_resource(domain_name: str, domain_data: ConfigType) -> str:
raise ValueError("Unknown domain") raise ValueError("Unknown domain")
def get_device_model(domain_name: str, domain_data: ConfigType) -> str:
"""Return the model for the specified domain_data."""
if domain_name in ("switch", "light"):
return "Output" if domain_data[CONF_OUTPUT] in OUTPUT_PORTS else "Relay"
if domain_name in ("binary_sensor", "sensor"):
if domain_data[CONF_SOURCE] in BINSENSOR_PORTS:
return "Binary Sensor"
if domain_data[CONF_SOURCE] in chain(
VARIABLES, SETPOINTS, THRESHOLDS, S0_INPUTS
):
return "Variable"
if domain_data[CONF_SOURCE] in LED_PORTS:
return "Led"
if domain_data[CONF_SOURCE] in LOGICOP_PORTS:
return "Logical Operation"
return "Key"
if domain_name == "cover":
return "Motor"
if domain_name == "climate":
return "Regulator"
if domain_name == "scene":
return "Scene"
raise ValueError("Unknown domain")
def generate_unique_id( def generate_unique_id(
entry_id: str, entry_id: str,
address: AddressType, address: AddressType,
@ -169,13 +133,6 @@ def purge_device_registry(
) -> None: ) -> None:
"""Remove orphans from device registry which are not in entry data.""" """Remove orphans from device registry which are not in entry data."""
device_registry = dr.async_get(hass) device_registry = dr.async_get(hass)
entity_registry = er.async_get(hass)
# Find all devices that are referenced in the entity registry.
references_entities = {
entry.device_id
for entry in entity_registry.entities.get_entries_for_config_entry_id(entry_id)
}
# Find device that references the host. # Find device that references the host.
references_host = set() references_host = set()
@ -198,7 +155,6 @@ def purge_device_registry(
entry.id entry.id
for entry in dr.async_entries_for_config_entry(device_registry, entry_id) for entry in dr.async_entries_for_config_entry(device_registry, entry_id)
} }
- references_entities
- references_host - references_host
- references_entry_data - references_entry_data
) )

View File

@ -45,9 +45,14 @@ async def test_get_triggers_module_device(
) )
] ]
triggers = await async_get_device_automations( triggers = [
hass, DeviceAutomationType.TRIGGER, device.id trigger
) for trigger in await async_get_device_automations(
hass, DeviceAutomationType.TRIGGER, device.id
)
if trigger[CONF_DOMAIN] == DOMAIN
]
assert triggers == unordered(expected_triggers) assert triggers == unordered(expected_triggers)
@ -63,11 +68,8 @@ async def test_get_triggers_non_module_device(
identifiers={(DOMAIN, entry.entry_id)} identifiers={(DOMAIN, entry.entry_id)}
) )
group_device = get_device(hass, entry, (0, 5, True)) group_device = get_device(hass, entry, (0, 5, True))
resource_device = device_registry.async_get_device(
identifiers={(DOMAIN, f"{entry.entry_id}-m000007-output1")}
)
for device in (host_device, group_device, resource_device): for device in (host_device, group_device):
triggers = await async_get_device_automations( triggers = await async_get_device_automations(
hass, DeviceAutomationType.TRIGGER, device.id hass, DeviceAutomationType.TRIGGER, device.id
) )