Teach search about blueprints (#78535)

This commit is contained in:
Erik Montnemery 2023-05-30 15:04:35 +02:00 committed by GitHub
parent 24e1243da7
commit d05d67414a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 167 additions and 1 deletions

View file

@ -228,6 +228,20 @@ def automations_with_blueprint(hass: HomeAssistant, blueprint_path: str) -> list
]
@callback
def blueprint_in_automation(hass: HomeAssistant, entity_id: str) -> str | None:
"""Return the blueprint the automation is based on or None."""
if DOMAIN not in hass.data:
return None
component: EntityComponent[AutomationEntity] = hass.data[DOMAIN]
if (automation_entity := component.get_entity(entity_id)) is None:
return None
return automation_entity.referenced_blueprint
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up all automations."""
hass.data[DOMAIN] = component = EntityComponent[AutomationEntity](

View file

@ -160,6 +160,20 @@ def scripts_with_blueprint(hass: HomeAssistant, blueprint_path: str) -> list[str
]
@callback
def blueprint_in_script(hass: HomeAssistant, entity_id: str) -> str | None:
"""Return the blueprint the script is based on or None."""
if DOMAIN not in hass.data:
return None
component: EntityComponent[ScriptEntity] = hass.data[DOMAIN]
if (script_entity := component.get_entity(entity_id)) is None:
return None
return script_entity.referenced_blueprint
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Load the scripts from the configuration."""
hass.data[DOMAIN] = component = EntityComponent[ScriptEntity](LOGGER, DOMAIN, hass)

View file

@ -37,7 +37,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
(
"area",
"automation",
"blueprint",
"automation_blueprint",
"config_entry",
"device",
"entity",
@ -45,6 +45,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"person",
"scene",
"script",
"script_blueprint",
)
),
vol.Required("item_id"): str,
@ -81,10 +82,12 @@ class Searcher:
DONT_RESOLVE = {
"area",
"automation",
"automation_blueprint",
"config_entry",
"group",
"scene",
"script",
"script_blueprint",
}
# These types exist as an entity and so need cleanup in results
EXIST_AS_ENTITY = {"automation", "group", "person", "scene", "script"}
@ -176,6 +179,22 @@ class Searcher:
for area in automation.areas_in_automation(self.hass, automation_entity_id):
self._add_or_resolve("area", area)
if blueprint := automation.blueprint_in_automation(
self.hass, automation_entity_id
):
self._add_or_resolve("automation_blueprint", blueprint)
@callback
def _resolve_automation_blueprint(self, blueprint_path) -> None:
"""Resolve an automation blueprint.
Will only be called if blueprint is an entry point.
"""
for entity_id in automation.automations_with_blueprint(
self.hass, blueprint_path
):
self._add_or_resolve("automation", entity_id)
@callback
def _resolve_config_entry(self, config_entry_id) -> None:
"""Resolve a config entry.
@ -295,3 +314,15 @@ class Searcher:
for area in script.areas_in_script(self.hass, script_entity_id):
self._add_or_resolve("area", area)
if blueprint := script.blueprint_in_script(self.hass, script_entity_id):
self._add_or_resolve("script_blueprint", blueprint)
@callback
def _resolve_script_blueprint(self, blueprint_path) -> None:
"""Resolve a script blueprint.
Will only be called if blueprint is an entry point.
"""
for entity_id in script.scripts_with_blueprint(self.hass, blueprint_path):
self._add_or_resolve("script", entity_id)

View file

@ -449,6 +449,113 @@ async def test_person_lookup(hass: HomeAssistant) -> None:
}
async def test_automation_blueprint(hass):
"""Test searching for automation blueprints."""
assert await async_setup_component(
hass,
"automation",
{
"automation": [
{
"alias": "blueprint_automation_1",
"trigger": {"platform": "template", "value_template": "true"},
"use_blueprint": {
"path": "test_event_service.yaml",
"input": {
"trigger_event": "blueprint_event_1",
"service_to_call": "test.automation_1",
"a_number": 5,
},
},
},
{
"alias": "blueprint_automation_2",
"trigger": {"platform": "template", "value_template": "true"},
"use_blueprint": {
"path": "test_event_service.yaml",
"input": {
"trigger_event": "blueprint_event_2",
"service_to_call": "test.automation_2",
"a_number": 5,
},
},
},
]
},
)
# Ensure automations set up correctly.
assert hass.states.get("automation.blueprint_automation_1") is not None
assert hass.states.get("automation.blueprint_automation_1") is not None
device_reg = dr.async_get(hass)
entity_reg = er.async_get(hass)
searcher = search.Searcher(hass, device_reg, entity_reg, MOCK_ENTITY_SOURCES)
assert searcher.async_search("automation", "automation.blueprint_automation_1") == {
"automation": {"automation.blueprint_automation_2"},
"automation_blueprint": {"test_event_service.yaml"},
"entity": {"light.kitchen"},
}
searcher = search.Searcher(hass, device_reg, entity_reg, MOCK_ENTITY_SOURCES)
assert searcher.async_search("automation_blueprint", "test_event_service.yaml") == {
"automation": {
"automation.blueprint_automation_1",
"automation.blueprint_automation_2",
},
}
async def test_script_blueprint(hass):
"""Test searching for script blueprints."""
assert await async_setup_component(
hass,
"script",
{
"script": {
"blueprint_script_1": {
"use_blueprint": {
"path": "test_service.yaml",
"input": {
"service_to_call": "test.automation",
},
}
},
"blueprint_script_2": {
"use_blueprint": {
"path": "test_service.yaml",
"input": {
"service_to_call": "test.automation",
},
}
},
}
},
)
# Ensure automations set up correctly.
assert hass.states.get("script.blueprint_script_1") is not None
assert hass.states.get("script.blueprint_script_1") is not None
device_reg = dr.async_get(hass)
entity_reg = er.async_get(hass)
searcher = search.Searcher(hass, device_reg, entity_reg, MOCK_ENTITY_SOURCES)
assert searcher.async_search("script", "script.blueprint_script_1") == {
"entity": {"light.kitchen"},
"script": {"script.blueprint_script_2"},
"script_blueprint": {"test_service.yaml"},
}
searcher = search.Searcher(hass, device_reg, entity_reg, MOCK_ENTITY_SOURCES)
assert searcher.async_search("script_blueprint", "test_service.yaml") == {
"script": {"script.blueprint_script_1", "script.blueprint_script_2"},
}
async def test_ws_api(hass: HomeAssistant, hass_ws_client: WebSocketGenerator) -> None:
"""Test WS API."""
assert await async_setup_component(hass, "search", {})