mirror of
https://github.com/home-assistant/core.git
synced 2026-08-24 10:13:52 -05:00
Allow linking template helpers to child devices (#179590)
This commit is contained in:
@@ -88,12 +88,13 @@ class AbstractTemplateEntity(Entity):
|
||||
)
|
||||
|
||||
device_registry = dr.async_get(hass)
|
||||
# Allow linking to a main or child device, but not to a composite device.
|
||||
if (
|
||||
device_id := config.get(CONF_DEVICE_ID)
|
||||
) is not None and device_registry.async_is_composite_device_id(
|
||||
device_id
|
||||
) is False:
|
||||
self.device_entry = device_registry.async_get(device_id)
|
||||
(device_id := config.get(CONF_DEVICE_ID)) is not None
|
||||
and (device_entry := device_registry.async_get(device_id)) is not None
|
||||
and not device_registry.async_is_composite_device_id(device_id)
|
||||
):
|
||||
self.device_entry = device_entry
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
|
||||
@@ -41,9 +41,9 @@ class CompositeDeviceIdRepairFlow(RepairsFlow):
|
||||
errors: dict[str, str] = {}
|
||||
if user_input is not None:
|
||||
device_id = user_input.get(CONF_DEVICE_ID)
|
||||
if (
|
||||
device_id is None
|
||||
or device_registry.async_is_composite_device_id(device_id) is False
|
||||
if device_id is None or (
|
||||
device_registry.async_get(device_id) is not None
|
||||
and not device_registry.async_is_composite_device_id(device_id)
|
||||
):
|
||||
options = {**entry.options}
|
||||
if device_id:
|
||||
|
||||
@@ -492,6 +492,56 @@ async def test_change_device(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"linked_device",
|
||||
[
|
||||
pytest.param("main", id="main_device"),
|
||||
pytest.param("child", id="child_device"),
|
||||
],
|
||||
)
|
||||
async def test_link_to_main_or_child_device(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
linked_device: str,
|
||||
) -> None:
|
||||
"""Test a template entity links to a selected main or child device."""
|
||||
source_entry = MockConfigEntry()
|
||||
source_entry.add_to_hass(hass)
|
||||
main_device = device_registry.async_get_or_create(
|
||||
config_entry_id=source_entry.entry_id,
|
||||
identifiers={("test", "main")},
|
||||
)
|
||||
child_device = device_registry.async_get_or_create_child(
|
||||
config_entry_id=source_entry.entry_id,
|
||||
identifiers={("test", "child")},
|
||||
parent_device_id=main_device.id,
|
||||
)
|
||||
selected_device_id = {"main": main_device, "child": child_device}[linked_device].id
|
||||
|
||||
template_config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
options={
|
||||
"name": "My template",
|
||||
"state": "{{10}}",
|
||||
"template_type": "sensor",
|
||||
"device_id": selected_device_id,
|
||||
},
|
||||
title="Template",
|
||||
)
|
||||
template_config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(template_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
template_entities = list(
|
||||
entity_registry.entities.get_entries_for_config_entry_id(
|
||||
template_config_entry.entry_id
|
||||
)
|
||||
)
|
||||
assert len(template_entities) == 1
|
||||
assert template_entities[0].device_id == selected_device_id
|
||||
|
||||
|
||||
async def test_setup_removes_stale_helper_device(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
|
||||
@@ -176,6 +176,53 @@ async def test_composite_device_id_repair_flow(
|
||||
assert entity_entry.device_id == picked_device_id
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("split_devices")
|
||||
async def test_composite_device_id_repair_flow_links_child_device(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
) -> None:
|
||||
"""Test the repair flow accepts a child device and links the entity to it."""
|
||||
source_entry = MockConfigEntry(domain="itg3")
|
||||
source_entry.add_to_hass(hass)
|
||||
parent_device = device_registry.async_get_or_create(
|
||||
config_entry_id=source_entry.entry_id,
|
||||
identifiers={("itg3", "parent")},
|
||||
)
|
||||
child_device = device_registry.async_get_or_create_child(
|
||||
config_entry_id=source_entry.entry_id,
|
||||
identifiers={("itg3", "child")},
|
||||
parent_device_id=parent_device.id,
|
||||
)
|
||||
|
||||
entry = await _setup_template_entry(hass, COMPOSITE_ID)
|
||||
issue_id = f"composite_device_id_{entry.entry_id}"
|
||||
assert issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
|
||||
assert await async_setup_component(hass, "repairs", {})
|
||||
await hass.async_block_till_done()
|
||||
client = await hass_client()
|
||||
|
||||
result = await start_repair_fix_flow(client, DOMAIN, issue_id)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "select_device"
|
||||
|
||||
result = await process_repair_fix_flow(
|
||||
client, result["flow_id"], json={CONF_DEVICE_ID: child_device.id}
|
||||
)
|
||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.options[CONF_DEVICE_ID] == child_device.id
|
||||
assert not issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
|
||||
entity_entry = entity_registry.async_get(TEMPLATE_ENTITY_ID)
|
||||
assert entity_entry is not None
|
||||
assert entity_entry.device_id == child_device.id
|
||||
|
||||
|
||||
async def test_composite_device_id_repair_flow_ambiguity_not_resolved(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
|
||||
Reference in New Issue
Block a user