Add entity deduplication by assist device ID in conversation agent (#123957)
* Add entities deduplication by assist device ID in default conversation agent * Updated test.pull/124254/head
parent
b4afca3e7e
commit
254aa8c9ea
homeassistant/components/conversation
tests/components/conversation
|
@ -349,6 +349,9 @@ class DefaultAgent(ConversationEntity):
|
|||
}
|
||||
for entity in result.entities_list
|
||||
}
|
||||
device_area = self._get_device_area(user_input.device_id)
|
||||
if device_area:
|
||||
slots["preferred_area_id"] = {"value": device_area.id}
|
||||
async_conversation_trace_append(
|
||||
ConversationTraceEventType.TOOL_CALL,
|
||||
{
|
||||
|
@ -917,18 +920,26 @@ class DefaultAgent(ConversationEntity):
|
|||
if not user_input.device_id:
|
||||
return None
|
||||
|
||||
devices = dr.async_get(self.hass)
|
||||
device = devices.async_get(user_input.device_id)
|
||||
if (device is None) or (device.area_id is None):
|
||||
return None
|
||||
|
||||
areas = ar.async_get(self.hass)
|
||||
device_area = areas.async_get_area(device.area_id)
|
||||
device_area = self._get_device_area(user_input.device_id)
|
||||
if device_area is None:
|
||||
return None
|
||||
|
||||
return {"area": {"value": device_area.name, "text": device_area.name}}
|
||||
|
||||
def _get_device_area(self, device_id: str | None) -> ar.AreaEntry | None:
|
||||
"""Return area object for given device identifier."""
|
||||
if device_id is None:
|
||||
return None
|
||||
|
||||
devices = dr.async_get(self.hass)
|
||||
device = devices.async_get(device_id)
|
||||
if (device is None) or (device.area_id is None):
|
||||
return None
|
||||
|
||||
areas = ar.async_get(self.hass)
|
||||
|
||||
return areas.async_get_area(device.area_id)
|
||||
|
||||
def _get_error_text(
|
||||
self,
|
||||
error_key: ErrorKey | str,
|
||||
|
|
|
@ -308,6 +308,72 @@ async def test_unexposed_entities_skipped(
|
|||
assert result.response.matched_states[0].entity_id == exposed_light.entity_id
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_components")
|
||||
async def test_duplicated_names_resolved_with_device_area(
|
||||
hass: HomeAssistant,
|
||||
area_registry: ar.AreaRegistry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test entities deduplication with device ID context."""
|
||||
area_kitchen = area_registry.async_get_or_create("kitchen_id")
|
||||
area_bedroom = area_registry.async_get_or_create("bedroom_id")
|
||||
|
||||
kitchen_light = entity_registry.async_get_or_create("light", "demo", "1234")
|
||||
bedroom_light = entity_registry.async_get_or_create("light", "demo", "5678")
|
||||
|
||||
# Same name and alias
|
||||
for light in (kitchen_light, bedroom_light):
|
||||
light = entity_registry.async_update_entity(
|
||||
light.entity_id,
|
||||
name="top light",
|
||||
aliases={"overhead light"},
|
||||
)
|
||||
hass.states.async_set(
|
||||
light.entity_id,
|
||||
"off",
|
||||
attributes={ATTR_FRIENDLY_NAME: light.name},
|
||||
)
|
||||
# Different areas
|
||||
kitchen_light = entity_registry.async_update_entity(
|
||||
kitchen_light.entity_id,
|
||||
area_id=area_kitchen.id,
|
||||
)
|
||||
bedroom_light = entity_registry.async_update_entity(
|
||||
bedroom_light.entity_id,
|
||||
area_id=area_bedroom.id,
|
||||
)
|
||||
|
||||
# Pipeline device in bedroom area
|
||||
entry = MockConfigEntry()
|
||||
entry.add_to_hass(hass)
|
||||
assist_device = device_registry.async_get_or_create(
|
||||
config_entry_id=entry.entry_id,
|
||||
connections=set(),
|
||||
identifiers={("demo", "id-1234")},
|
||||
)
|
||||
assist_device = device_registry.async_update_device(
|
||||
assist_device.id,
|
||||
area_id=area_bedroom.id,
|
||||
)
|
||||
|
||||
# Check name and alias
|
||||
for name in ("top light", "overhead light"):
|
||||
# Only one light should be turned on
|
||||
calls = async_mock_service(hass, "light", "turn_on")
|
||||
result = await conversation.async_converse(
|
||||
hass, f"turn on {name}", None, Context(), device_id=assist_device.id
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["entity_id"][0] == bedroom_light.entity_id
|
||||
|
||||
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
|
||||
assert result.response.intent is not None
|
||||
assert result.response.intent.slots.get("name", {}).get("value") == name
|
||||
assert result.response.intent.slots.get("name", {}).get("text") == name
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_components")
|
||||
async def test_trigger_sentences(hass: HomeAssistant) -> None:
|
||||
"""Test registering/unregistering/matching a few trigger sentences."""
|
||||
|
|
Loading…
Reference in New Issue