mirror of
https://github.com/home-assistant/core.git
synced 2026-08-24 02:24:51 -05:00
Extract entities from device triggers and device actions (#175454)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
parent
750850f0ba
commit
2395296739
@@ -1829,6 +1829,15 @@ class Script:
|
||||
for trigger in step[CONF_WAIT_FOR_TRIGGER]:
|
||||
referenced |= set(trigger_helper.async_extract_entities(trigger))
|
||||
|
||||
elif action == cv.SCRIPT_ACTION_DEVICE_AUTOMATION:
|
||||
# Only extract the entity if it has been resolved to an entity
|
||||
# id during validation; unvalidated configs hold an entity
|
||||
# registry id.
|
||||
if isinstance(
|
||||
entity_id := step.get(ATTR_ENTITY_ID), str
|
||||
) and valid_entity_id(entity_id):
|
||||
referenced.add(entity_id)
|
||||
|
||||
elif action == cv.SCRIPT_ACTION_ACTIVATE_SCENE:
|
||||
referenced.add(step[CONF_SCENE])
|
||||
|
||||
|
||||
@@ -2067,6 +2067,15 @@ def async_extract_entities(trigger_conf: dict) -> list[str]:
|
||||
entity_ids.append(at_time[CONF_ENTITY_ID])
|
||||
return entity_ids
|
||||
|
||||
if trigger_conf[CONF_PLATFORM] == "device":
|
||||
# Only extract the entity if it has been resolved to an entity id
|
||||
# during validation; unvalidated configs hold an entity registry id.
|
||||
if isinstance(
|
||||
entity_id := trigger_conf.get(CONF_ENTITY_ID), str
|
||||
) and valid_entity_id(entity_id):
|
||||
return [entity_id]
|
||||
return []
|
||||
|
||||
if trigger_conf[CONF_PLATFORM] == "calendar":
|
||||
return [trigger_conf[CONF_OPTIONS][CONF_ENTITY_ID]]
|
||||
|
||||
|
||||
@@ -2481,6 +2481,7 @@ async def test_extraction_functions(
|
||||
"sensor.trigger_state",
|
||||
"sensor.trigger_numeric_state",
|
||||
"sensor.trigger_event",
|
||||
"light.bla",
|
||||
"light.condition_state",
|
||||
"light.in_both",
|
||||
"light.in_first",
|
||||
|
||||
@@ -919,6 +919,7 @@ async def test_extraction_functions(
|
||||
"script.test3",
|
||||
}
|
||||
assert set(script.entities_in_script(hass, "script.test1")) == {
|
||||
"light.device_in_both",
|
||||
"light.in_both",
|
||||
"light.in_first",
|
||||
}
|
||||
|
||||
@@ -568,6 +568,7 @@ async def test_search(
|
||||
ItemType.AREA: {living_room_area.id},
|
||||
ItemType.CONFIG_ENTRY: {wled_config_entry.entry_id},
|
||||
ItemType.DEVICE: {wled_device.id},
|
||||
ItemType.ENTITY: {wled_segment_1_entity.entity_id},
|
||||
ItemType.FLOOR: {first_floor.floor_id},
|
||||
ItemType.INTEGRATION: {"wled"},
|
||||
}
|
||||
@@ -711,7 +712,7 @@ async def test_search(
|
||||
assert not search(ItemType.ENTITY, "sensor.unknown")
|
||||
assert search(ItemType.ENTITY, wled_segment_1_entity.entity_id) == {
|
||||
ItemType.AREA: {living_room_area.id},
|
||||
ItemType.AUTOMATION: {"automation.wled_entity"},
|
||||
ItemType.AUTOMATION: {"automation.wled_entity", "automation.wled_device"},
|
||||
ItemType.CONFIG_ENTRY: {wled_config_entry.entry_id},
|
||||
ItemType.DEVICE: {wled_device.id},
|
||||
ItemType.FLOOR: {first_floor.floor_id},
|
||||
|
||||
@@ -4833,6 +4833,18 @@ async def test_referenced_entities(hass: HomeAssistant) -> None:
|
||||
},
|
||||
{"action": "test.script", "data": {"without": "entity_id"}},
|
||||
{"scene": "scene.hello"},
|
||||
{
|
||||
"domain": "light",
|
||||
"device_id": "abcdefgh",
|
||||
"entity_id": "light.device_action",
|
||||
"type": "turn_on",
|
||||
},
|
||||
{
|
||||
"domain": "light",
|
||||
"device_id": "abcdefgh",
|
||||
"entity_id": "1234567890abcdef1234567890abcdef",
|
||||
"type": "turn_on",
|
||||
},
|
||||
{
|
||||
"choose": [
|
||||
{
|
||||
@@ -4989,6 +5001,7 @@ async def test_referenced_entities(hass: HomeAssistant) -> None:
|
||||
"light.condition_list_2",
|
||||
"light.condition_target",
|
||||
"light.default_seq",
|
||||
"light.device_action",
|
||||
"light.direct_entity_referenced",
|
||||
"light.entity_in_data_template",
|
||||
"light.entity_in_target",
|
||||
|
||||
@@ -6020,6 +6020,54 @@ async def test_async_extract_entities(
|
||||
assert trigger.async_extract_entities(trigger_conf) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trigger_conf", "expected"),
|
||||
[
|
||||
pytest.param(
|
||||
{
|
||||
"platform": "device",
|
||||
"device_id": "abcdefgh",
|
||||
"domain": "light",
|
||||
"entity_id": "light.kitchen",
|
||||
"type": "turned_on",
|
||||
},
|
||||
["light.kitchen"],
|
||||
id="resolved-entity-id",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
"platform": "device",
|
||||
"device_id": "abcdefgh",
|
||||
"domain": "light",
|
||||
"entity_id": "1234567890abcdef1234567890abcdef",
|
||||
"type": "turned_on",
|
||||
},
|
||||
[],
|
||||
id="unresolved-registry-id",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
"platform": "device",
|
||||
"device_id": "abcdefgh",
|
||||
"domain": "sensor",
|
||||
"type": "battery_level",
|
||||
},
|
||||
[],
|
||||
id="no-entity-id",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_async_extract_entities_device_trigger(
|
||||
trigger_conf: dict[str, Any], expected: list[str]
|
||||
) -> None:
|
||||
"""Test extracting entities from device trigger configs.
|
||||
|
||||
Validation resolves the entity registry id to an entity id; extraction
|
||||
ignores unresolved registry ids.
|
||||
"""
|
||||
assert trigger.async_extract_entities(trigger_conf) == expected
|
||||
|
||||
|
||||
_MOCK_DEVICE_ID = "_mock_device_id_"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user