mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Use device area id in intent matching (#86678)
* Use device area id when matching * Normalize whitespace in response * Add extra test entity
This commit is contained in:
parent
38203003d2
commit
adeaf746ec
@ -160,17 +160,19 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
).get(response_key)
|
||||
if response_str:
|
||||
response_template = template.Template(response_str, self.hass)
|
||||
intent_response.async_set_speech(
|
||||
response_template.async_render(
|
||||
{
|
||||
"slots": {
|
||||
entity_name: entity_value.text or entity_value.value
|
||||
for entity_name, entity_value in result.entities.items()
|
||||
}
|
||||
speech = response_template.async_render(
|
||||
{
|
||||
"slots": {
|
||||
entity_name: entity_value.text or entity_value.value
|
||||
for entity_name, entity_value in result.entities.items()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
# Normalize whitespace
|
||||
speech = " ".join(speech.strip().split())
|
||||
intent_response.async_set_speech(speech)
|
||||
|
||||
return ConversationResult(
|
||||
response=intent_response, conversation_id=conversation_id
|
||||
)
|
||||
|
@ -20,7 +20,7 @@ from homeassistant.core import Context, HomeAssistant, State, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.loader import bind_hass
|
||||
|
||||
from . import area_registry, config_validation as cv, entity_registry
|
||||
from . import area_registry, config_validation as cv, device_registry, entity_registry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_SlotsType = dict[str, Any]
|
||||
@ -159,6 +159,7 @@ def async_match_states(
|
||||
states: Iterable[State] | None = None,
|
||||
entities: entity_registry.EntityRegistry | None = None,
|
||||
areas: area_registry.AreaRegistry | None = None,
|
||||
devices: device_registry.DeviceRegistry | None = None,
|
||||
) -> Iterable[State]:
|
||||
"""Find states that match the constraints."""
|
||||
if states is None:
|
||||
@ -206,11 +207,28 @@ def async_match_states(
|
||||
assert area is not None, f"No area named {area_name}"
|
||||
|
||||
if area is not None:
|
||||
if devices is None:
|
||||
devices = device_registry.async_get(hass)
|
||||
|
||||
entity_area_ids: dict[str, str | None] = {}
|
||||
for _state, entity in states_and_entities:
|
||||
if entity is None:
|
||||
continue
|
||||
|
||||
if entity.area_id:
|
||||
# Use entity's area id first
|
||||
entity_area_ids[entity.id] = entity.area_id
|
||||
elif entity.device_id:
|
||||
# Fall back to device area if not set on entity
|
||||
device = devices.async_get(entity.device_id)
|
||||
if device is not None:
|
||||
entity_area_ids[entity.id] = device.area_id
|
||||
|
||||
# Filter by area
|
||||
states_and_entities = [
|
||||
(state, entity)
|
||||
for state, entity in states_and_entities
|
||||
if (entity is not None) and (entity.area_id == area.id)
|
||||
if (entity is not None) and (entity_area_ids.get(entity.id) == area.id)
|
||||
]
|
||||
|
||||
if name is not None:
|
||||
|
@ -9,6 +9,7 @@ from homeassistant.core import State
|
||||
from homeassistant.helpers import (
|
||||
area_registry,
|
||||
config_validation as cv,
|
||||
device_registry,
|
||||
entity_registry,
|
||||
intent,
|
||||
)
|
||||
@ -41,7 +42,7 @@ async def test_async_match_states(hass):
|
||||
entities.async_update_entity(state1.entity_id, area_id=area_kitchen.id)
|
||||
|
||||
entities.async_get_or_create(
|
||||
"switch", "demo", "1234", suggested_object_id="bedroom"
|
||||
"switch", "demo", "5678", suggested_object_id="bedroom"
|
||||
)
|
||||
entities.async_update_entity(
|
||||
state2.entity_id,
|
||||
@ -92,6 +93,45 @@ async def test_async_match_states(hass):
|
||||
)
|
||||
|
||||
|
||||
async def test_match_device_area(hass):
|
||||
"""Test async_match_state with a device in an area."""
|
||||
areas = area_registry.async_get(hass)
|
||||
area_kitchen = areas.async_get_or_create("kitchen")
|
||||
area_bedroom = areas.async_get_or_create("bedroom")
|
||||
|
||||
devices = device_registry.async_get(hass)
|
||||
kitchen_device = devices.async_get_or_create(
|
||||
config_entry_id="1234", connections=set(), identifiers={("demo", "id-1234")}
|
||||
)
|
||||
devices.async_update_device(kitchen_device.id, area_id=area_kitchen.id)
|
||||
|
||||
state1 = State(
|
||||
"light.kitchen", "on", attributes={ATTR_FRIENDLY_NAME: "kitchen light"}
|
||||
)
|
||||
state2 = State(
|
||||
"light.bedroom", "on", attributes={ATTR_FRIENDLY_NAME: "bedroom light"}
|
||||
)
|
||||
state3 = State(
|
||||
"light.living_room", "on", attributes={ATTR_FRIENDLY_NAME: "living room light"}
|
||||
)
|
||||
entities = entity_registry.async_get(hass)
|
||||
entities.async_get_or_create("light", "demo", "1234", suggested_object_id="kitchen")
|
||||
entities.async_update_entity(state1.entity_id, device_id=kitchen_device.id)
|
||||
|
||||
entities.async_get_or_create("light", "demo", "5678", suggested_object_id="bedroom")
|
||||
entities.async_update_entity(state2.entity_id, area_id=area_bedroom.id)
|
||||
|
||||
# Match on area/domain
|
||||
assert [state1] == list(
|
||||
intent.async_match_states(
|
||||
hass,
|
||||
domains={"light"},
|
||||
area_name="kitchen",
|
||||
states=[state1, state2, state3],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_async_validate_slots():
|
||||
"""Test async_validate_slots of IntentHandler."""
|
||||
handler1 = MockIntentHandler({vol.Required("name"): cv.string})
|
||||
|
Loading…
x
Reference in New Issue
Block a user