Remove individual lcn devices for each entity (#136450)
parent
15ca2fe489
commit
800fe1b01e
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue