mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 17:31:15 -04:00
Include child devices when targeting a labelled parent device (#182664)
This commit is contained in:
@@ -155,6 +155,18 @@ class SelectedEntities:
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def _add_referenced_device(
|
||||
dev_reg: dr.DeviceRegistry, device_id: str, selected: SelectedEntities
|
||||
) -> None:
|
||||
"""Add a device and its child devices."""
|
||||
selected.referenced_devices.add(device_id)
|
||||
selected.referenced_devices.update(
|
||||
child_device.id
|
||||
for child_device in dr.async_entries_for_parent_device(dev_reg, device_id)
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def _resolve_referenced_devices(
|
||||
dev_reg: dr.DeviceRegistry, device_ids: set[str], selected: SelectedEntities
|
||||
@@ -165,8 +177,6 @@ def _resolve_referenced_devices(
|
||||
if device is None:
|
||||
selected.missing_devices.add(device_id)
|
||||
selected.referenced_devices.add(device_id)
|
||||
elif isinstance(device, dr.ChildDeviceEntry):
|
||||
selected.referenced_devices.add(device_id)
|
||||
elif split_devices := dev_reg.async_get_devices_for_composite_device_id(
|
||||
device_id
|
||||
):
|
||||
@@ -174,23 +184,10 @@ def _resolve_referenced_devices(
|
||||
# it resolves to the devices it was split into so actions targeting it
|
||||
# still trickle down. Only the splits are referenced, not the composite id,
|
||||
# so a device-id consumer does not act on the same underlying device twice.
|
||||
# Each split's children are included too, matching the direct-device branch.
|
||||
for split_device in split_devices:
|
||||
selected.referenced_devices.add(split_device.id)
|
||||
selected.referenced_devices.update(
|
||||
child_device.id
|
||||
for child_device in dr.async_entries_for_parent_device(
|
||||
dev_reg, split_device.id
|
||||
)
|
||||
)
|
||||
_add_referenced_device(dev_reg, split_device.id, selected)
|
||||
else:
|
||||
selected.referenced_devices.add(device_id)
|
||||
selected.referenced_devices.update(
|
||||
child_device.id
|
||||
for child_device in dr.async_entries_for_parent_device(
|
||||
dev_reg, device_id
|
||||
)
|
||||
)
|
||||
_add_referenced_device(dev_reg, device_id, selected)
|
||||
|
||||
|
||||
def async_extract_referenced_entity_ids(
|
||||
@@ -255,12 +252,9 @@ def async_extract_referenced_entity_ids(
|
||||
if entity_entry.hidden_by is None:
|
||||
selected.indirectly_referenced.add(entity_entry.entity_id)
|
||||
|
||||
# Labels are never inherited by child devices (see
|
||||
# dr.async_entries_for_label): a labeled parent is not expanded into its
|
||||
# children. Only devices that carry the label themselves are targeted,
|
||||
# which is consistent with template label_devices() and search.
|
||||
# Labeled devices expand like directly targeted devices, children included.
|
||||
for device_entry in dr.async_entries_for_label(dev_reg, label_id):
|
||||
selected.referenced_devices.add(device_entry.id)
|
||||
_add_referenced_device(dev_reg, device_entry.id, selected)
|
||||
|
||||
for area_entry in area_reg.areas.get_areas_for_label(label_id):
|
||||
selected.referenced_areas.add(area_entry.id)
|
||||
|
||||
@@ -1262,21 +1262,28 @@ async def test_extract_label_with_child_devices(
|
||||
hass: HomeAssistant,
|
||||
child_device_setup: dict[str, str],
|
||||
) -> None:
|
||||
"""Test labels are not inherited by child devices when targeting.
|
||||
"""Test a labeled parent device expands to its child devices when targeting.
|
||||
|
||||
A labeled parent targets only the parent and its own entities; a labeled child
|
||||
targets only that child. This mirrors dr.async_entries_for_label, which
|
||||
documents that labels are never inherited from the parent.
|
||||
Labels are not inherited by child devices, but a labeled parent is targeted like
|
||||
a directly targeted device, so its children are included. A labeled child
|
||||
targets only that child.
|
||||
"""
|
||||
ids = child_device_setup
|
||||
|
||||
# The label is on the parent; it does not expand to the child devices, and only
|
||||
# the parent's own entities are indirectly referenced.
|
||||
selected = target.async_extract_referenced_entity_ids(
|
||||
hass, target.TargetSelection({"label_id": "strip-label"})
|
||||
)
|
||||
assert selected.referenced_devices == {ids["parent"]}
|
||||
assert selected.indirectly_referenced == {ids["strip_switch"]}
|
||||
assert selected.referenced_devices == {
|
||||
ids["parent"],
|
||||
ids["outlet_1"],
|
||||
ids["outlet_2"],
|
||||
}
|
||||
assert selected.indirectly_referenced == {
|
||||
ids["strip_switch"],
|
||||
ids["outlet_1_switch"],
|
||||
ids["outlet_2_switch"],
|
||||
ids["outlet_1_energy"],
|
||||
}
|
||||
|
||||
# A label on a child device targets only the child device
|
||||
selected = target.async_extract_referenced_entity_ids(
|
||||
|
||||
Reference in New Issue
Block a user