Add targeted entities to sentence debug API (#95480)

* Return targets with debug sentence API

* Update test

* Update homeassistant/components/conversation/__init__.py

* Include area/domain in test sentences

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
pull/95509/head
Michael Hansen 2023-06-28 17:34:43 -05:00 committed by GitHub
parent 0b81550092
commit 487dd3f956
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 1 deletions

View File

@ -8,6 +8,7 @@ import logging
import re
from typing import Any, Literal
from hassil.recognize import RecognizeResult
import voluptuous as vol
from homeassistant import core
@ -353,6 +354,10 @@ async def websocket_hass_agent_debug(
}
for entity_key, entity in result.entities.items()
},
"targets": {
state.entity_id: {"matched": is_matched}
for state, is_matched in _get_debug_targets(hass, result)
},
}
if result is not None
else None
@ -362,6 +367,49 @@ async def websocket_hass_agent_debug(
)
def _get_debug_targets(
hass: HomeAssistant,
result: RecognizeResult,
) -> Iterable[tuple[core.State, bool]]:
"""Yield state/is_matched pairs for a hassil recognition."""
entities = result.entities
name: str | None = None
area_name: str | None = None
domains: set[str] | None = None
device_classes: set[str] | None = None
state_names: set[str] | None = None
if "name" in entities:
name = str(entities["name"].value)
if "area" in entities:
area_name = str(entities["area"].value)
if "domain" in entities:
domains = set(cv.ensure_list(entities["domain"].value))
if "device_class" in entities:
device_classes = set(cv.ensure_list(entities["device_class"].value))
if "state" in entities:
# HassGetState only
state_names = set(cv.ensure_list(entities["state"].value))
states = intent.async_match_states(
hass,
name=name,
area_name=area_name,
domains=domains,
device_classes=device_classes,
)
for state in states:
# For queries, a target is "matched" based on its state
is_matched = (state_names is None) or (state.state in state_names)
yield state, is_matched
class ConversationProcessView(http.HomeAssistantView):
"""View to process text."""

View File

@ -382,6 +382,11 @@
'intent': dict({
'name': 'HassTurnOn',
}),
'targets': dict({
'light.kitchen': dict({
'matched': True,
}),
}),
}),
dict({
'entities': dict({
@ -394,6 +399,60 @@
'intent': dict({
'name': 'HassTurnOff',
}),
'targets': dict({
'light.kitchen': dict({
'matched': True,
}),
}),
}),
dict({
'entities': dict({
'area': dict({
'name': 'area',
'text': 'kitchen',
'value': 'kitchen',
}),
'domain': dict({
'name': 'domain',
'text': '',
'value': 'light',
}),
}),
'intent': dict({
'name': 'HassTurnOn',
}),
'targets': dict({
'light.kitchen': dict({
'matched': True,
}),
}),
}),
dict({
'entities': dict({
'area': dict({
'name': 'area',
'text': 'kitchen',
'value': 'kitchen',
}),
'domain': dict({
'name': 'domain',
'text': 'lights',
'value': 'light',
}),
'state': dict({
'name': 'state',
'text': 'on',
'value': 'on',
}),
}),
'intent': dict({
'name': 'HassGetState',
}),
'targets': dict({
'light.kitchen': dict({
'matched': False,
}),
}),
}),
None,
]),

View File

@ -1652,16 +1652,22 @@ async def test_ws_hass_agent_debug(
hass: HomeAssistant,
init_components,
hass_ws_client: WebSocketGenerator,
area_registry: ar.AreaRegistry,
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test homeassistant agent debug websocket command."""
client = await hass_ws_client(hass)
kitchen_area = area_registry.async_create("kitchen")
entity_registry.async_get_or_create(
"light", "demo", "1234", suggested_object_id="kitchen"
)
entity_registry.async_update_entity("light.kitchen", aliases={"my cool light"})
entity_registry.async_update_entity(
"light.kitchen",
aliases={"my cool light"},
area_id=kitchen_area.id,
)
hass.states.async_set("light.kitchen", "off")
on_calls = async_mock_service(hass, LIGHT_DOMAIN, "turn_on")
@ -1673,6 +1679,8 @@ async def test_ws_hass_agent_debug(
"sentences": [
"turn on my cool light",
"turn my cool light off",
"turn on all lights in the kitchen",
"how many lights are on in the kitchen?",
"this will not match anything", # null in results
],
}