Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add targeted entities to sentence debug API #95480

Merged
merged 4 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions homeassistant/components/conversation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import re
from typing import Any, Literal

from hassil.recognize import RecognizeResult
import voluptuous as vol

from homeassistant import core
Expand Down Expand Up @@ -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
Expand All @@ -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."""

Expand Down
59 changes: 59 additions & 0 deletions tests/components/conversation/snapshots/test_init.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,11 @@
'intent': dict({
'name': 'HassTurnOn',
}),
'targets': dict({
'light.kitchen': dict({
'matched': True,
}),
}),
}),
dict({
'entities': dict({
Expand All @@ -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,
]),
Expand Down
10 changes: 9 additions & 1 deletion tests/components/conversation/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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
],
}
Expand Down
Loading