Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions homeassistant/components/shelly/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,20 +682,20 @@ def async_remove_orphaned_entities(
):
return

device_id = devices[0].id
entities = er.async_entries_for_device(entity_reg, device_id, True)
for entity in entities:
if not entity.entity_id.startswith(platform):
continue
if key_suffix is not None and key_suffix not in entity.unique_id:
continue
# we are looking for the component ID, e.g. boolean:201, em1data:1
if not (match := COMPONENT_ID_PATTERN.search(entity.unique_id)):
continue

key = match.group()
if key not in keys:
orphaned_entities.append(entity.unique_id.split("-", 1)[1])
for device in devices:
entities = er.async_entries_for_device(entity_reg, device.id, True)
for entity in entities:
if not entity.entity_id.startswith(platform):
continue
if key_suffix is not None and key_suffix not in entity.unique_id:
continue
# we are looking for the component ID, e.g. boolean:201, em1data:1
if not (match := COMPONENT_ID_PATTERN.search(entity.unique_id)):
continue

key = match.group()
if key not in keys:
orphaned_entities.append(entity.unique_id.split("-", 1)[1])

if orphaned_entities:
async_remove_shelly_rpc_entities(hass, platform, mac, orphaned_entities)
Expand Down
11 changes: 11 additions & 0 deletions tests/components/shelly/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,17 @@ def register_device(
)


def register_sub_device(
device_registry: DeviceRegistry, config_entry: ConfigEntry, unique_id: str
) -> DeviceEntry:
"""Register Shelly sub-device."""
return device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
identifiers={(DOMAIN, f"{MOCK_MAC}-{unique_id}")},
via_device=(DOMAIN, format_mac(MOCK_MAC)),
)


async def snapshot_device_entities(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
Expand Down
26 changes: 24 additions & 2 deletions tests/components/shelly/test_binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
mutate_rpc_device_status,
register_device,
register_entity,
register_sub_device,
)

from tests.common import mock_restore_cache
Expand Down Expand Up @@ -475,8 +476,10 @@ async def test_rpc_remove_virtual_binary_sensor_when_orphaned(
) -> None:
"""Check whether the virtual binary sensor will be removed if it has been removed from the device configuration."""
config_entry = await init_integration(hass, 3, skip_setup=True)

# create orphaned entity on main device
device_entry = register_device(device_registry, config_entry)
entity_id = register_entity(
entity_id1 = register_entity(
hass,
BINARY_SENSOR_DOMAIN,
"test_name_boolean_200",
Expand All @@ -485,10 +488,29 @@ async def test_rpc_remove_virtual_binary_sensor_when_orphaned(
device_id=device_entry.id,
)

# create orphaned entity on sub device
sub_device_entry = register_sub_device(
device_registry,
config_entry,
"boolean:201-boolean",
)
entity_id2 = register_entity(
hass,
BINARY_SENSOR_DOMAIN,
"boolean_201",
"boolean:201-boolean",
config_entry,
device_id=sub_device_entry.id,
)

assert entity_registry.async_get(entity_id1) is not None
assert entity_registry.async_get(entity_id2) is not None

await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

assert entity_registry.async_get(entity_id) is None
assert entity_registry.async_get(entity_id1) is None
assert entity_registry.async_get(entity_id2) is None


async def test_blu_trv_binary_sensor_entity(
Expand Down
26 changes: 24 additions & 2 deletions tests/components/shelly/test_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
inject_rpc_device_event,
register_device,
register_entity,
register_sub_device,
)

from tests.common import async_fire_time_changed, mock_restore_cache
Expand Down Expand Up @@ -720,8 +721,10 @@ async def test_rpc_remove_virtual_switch_when_orphaned(
) -> None:
"""Check whether the virtual switch will be removed if it has been removed from the device configuration."""
config_entry = await init_integration(hass, 3, skip_setup=True)

# create orphaned entity on main device
device_entry = register_device(device_registry, config_entry)
entity_id = register_entity(
entity_id1 = register_entity(
hass,
SWITCH_DOMAIN,
"test_name_boolean_200",
Expand All @@ -730,10 +733,29 @@ async def test_rpc_remove_virtual_switch_when_orphaned(
device_id=device_entry.id,
)

# create orphaned entity on sub device
sub_device_entry = register_sub_device(
device_registry,
config_entry,
"boolean:201-boolean",
)
entity_id2 = register_entity(
hass,
SWITCH_DOMAIN,
"boolean_201",
"boolean:201-boolean",
config_entry,
device_id=sub_device_entry.id,
)

assert entity_registry.async_get(entity_id1) is not None
assert entity_registry.async_get(entity_id2) is not None

await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

assert entity_registry.async_get(entity_id) is None
assert entity_registry.async_get(entity_id1) is None
assert entity_registry.async_get(entity_id2) is None


@pytest.mark.usefixtures("entity_registry_enabled_by_default")
Expand Down
Loading