mirror of https://github.com/home-assistant/core
327 lines
9.9 KiB
Python
327 lines
9.9 KiB
Python
"""Test intent_script component."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from homeassistant import config as hass_config
|
|
from homeassistant.components.intent_script import DOMAIN
|
|
from homeassistant.const import SERVICE_RELOAD
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers import (
|
|
area_registry as ar,
|
|
entity_registry as er,
|
|
floor_registry as fr,
|
|
intent,
|
|
)
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
from tests.common import async_mock_service, get_fixture_path
|
|
|
|
|
|
async def test_intent_script(hass: HomeAssistant) -> None:
|
|
"""Test intent scripts work."""
|
|
calls = async_mock_service(hass, "test", "service")
|
|
|
|
await async_setup_component(
|
|
hass,
|
|
"intent_script",
|
|
{
|
|
"intent_script": {
|
|
"HelloWorld": {
|
|
"description": "Intent to control a test service.",
|
|
"platforms": ["switch"],
|
|
"action": {
|
|
"service": "test.service",
|
|
"data_template": {"hello": "{{ name }}"},
|
|
},
|
|
"card": {
|
|
"title": "Hello {{ name }}",
|
|
"content": "Content for {{ name }}",
|
|
},
|
|
"speech": {"text": "Good morning {{ name }}"},
|
|
}
|
|
}
|
|
},
|
|
)
|
|
|
|
handlers = [
|
|
intent_handler
|
|
for intent_handler in intent.async_get(hass)
|
|
if intent_handler.intent_type == "HelloWorld"
|
|
]
|
|
|
|
assert len(handlers) == 1
|
|
handler = handlers[0]
|
|
assert handler.description == "Intent to control a test service."
|
|
assert handler.platforms == {"switch"}
|
|
|
|
response = await intent.async_handle(
|
|
hass, "test", "HelloWorld", {"name": {"value": "Paulus"}}
|
|
)
|
|
|
|
assert len(calls) == 1
|
|
assert calls[0].data["hello"] == "Paulus"
|
|
|
|
assert response.speech["plain"]["speech"] == "Good morning Paulus"
|
|
|
|
assert not (response.reprompt)
|
|
|
|
assert response.card["simple"]["title"] == "Hello Paulus"
|
|
assert response.card["simple"]["content"] == "Content for Paulus"
|
|
|
|
|
|
async def test_intent_script_wait_response(hass: HomeAssistant) -> None:
|
|
"""Test intent scripts work."""
|
|
calls = async_mock_service(hass, "test", "service")
|
|
|
|
await async_setup_component(
|
|
hass,
|
|
"intent_script",
|
|
{
|
|
"intent_script": {
|
|
"HelloWorldWaitResponse": {
|
|
"action": {
|
|
"service": "test.service",
|
|
"data_template": {"hello": "{{ name }}"},
|
|
},
|
|
"card": {
|
|
"title": "Hello {{ name }}",
|
|
"content": "Content for {{ name }}",
|
|
},
|
|
"speech": {"text": "Good morning {{ name }}"},
|
|
"reprompt": {
|
|
"text": "I didn't hear you, {{ name }}... I said good morning!"
|
|
},
|
|
}
|
|
}
|
|
},
|
|
)
|
|
|
|
handlers = [
|
|
intent_handler
|
|
for intent_handler in intent.async_get(hass)
|
|
if intent_handler.intent_type == "HelloWorldWaitResponse"
|
|
]
|
|
|
|
assert len(handlers) == 1
|
|
handler = handlers[0]
|
|
assert handler.platforms is None
|
|
|
|
response = await intent.async_handle(
|
|
hass, "test", "HelloWorldWaitResponse", {"name": {"value": "Paulus"}}
|
|
)
|
|
|
|
assert len(calls) == 1
|
|
assert calls[0].data["hello"] == "Paulus"
|
|
|
|
assert response.speech["plain"]["speech"] == "Good morning Paulus"
|
|
|
|
assert (
|
|
response.reprompt["plain"]["reprompt"]
|
|
== "I didn't hear you, Paulus... I said good morning!"
|
|
)
|
|
|
|
assert response.card["simple"]["title"] == "Hello Paulus"
|
|
assert response.card["simple"]["content"] == "Content for Paulus"
|
|
|
|
|
|
async def test_intent_script_service_response(hass: HomeAssistant) -> None:
|
|
"""Test intent scripts work."""
|
|
calls = async_mock_service(
|
|
hass, "test", "service", response={"some_key": "some value"}
|
|
)
|
|
|
|
await async_setup_component(
|
|
hass,
|
|
"intent_script",
|
|
{
|
|
"intent_script": {
|
|
"HelloWorldServiceResponse": {
|
|
"action": [
|
|
{"service": "test.service", "response_variable": "result"},
|
|
{"stop": "", "response_variable": "result"},
|
|
],
|
|
"speech": {
|
|
"text": "The service returned {{ action_response.some_key }}"
|
|
},
|
|
}
|
|
}
|
|
},
|
|
)
|
|
|
|
response = await intent.async_handle(hass, "test", "HelloWorldServiceResponse")
|
|
|
|
assert len(calls) == 1
|
|
assert calls[0].return_response
|
|
|
|
assert response.speech["plain"]["speech"] == "The service returned some value"
|
|
|
|
|
|
async def test_intent_script_falsy_reprompt(hass: HomeAssistant) -> None:
|
|
"""Test intent scripts work."""
|
|
calls = async_mock_service(hass, "test", "service")
|
|
|
|
await async_setup_component(
|
|
hass,
|
|
"intent_script",
|
|
{
|
|
"intent_script": {
|
|
"HelloWorld": {
|
|
"action": {
|
|
"service": "test.service",
|
|
"data_template": {"hello": "{{ name }}"},
|
|
},
|
|
"card": {
|
|
"title": "Hello {{ name }}",
|
|
"content": "Content for {{ name }}",
|
|
},
|
|
"speech": {
|
|
"type": "ssml",
|
|
"text": '<speak><amazon:effect name="whispered">Good morning {{ name }}</amazon:effect></speak>',
|
|
},
|
|
"reprompt": {"text": "{{ null }}"},
|
|
}
|
|
}
|
|
},
|
|
)
|
|
|
|
response = await intent.async_handle(
|
|
hass, "test", "HelloWorld", {"name": {"value": "Paulus"}}
|
|
)
|
|
|
|
assert len(calls) == 1
|
|
assert calls[0].data["hello"] == "Paulus"
|
|
|
|
assert (
|
|
response.speech["ssml"]["speech"]
|
|
== '<speak><amazon:effect name="whispered">Good morning Paulus</amazon:effect></speak>'
|
|
)
|
|
|
|
assert not (response.reprompt)
|
|
|
|
assert response.card["simple"]["title"] == "Hello Paulus"
|
|
assert response.card["simple"]["content"] == "Content for Paulus"
|
|
|
|
|
|
async def test_intent_script_targets(
|
|
hass: HomeAssistant,
|
|
area_registry: ar.AreaRegistry,
|
|
entity_registry: er.EntityRegistry,
|
|
floor_registry: fr.FloorRegistry,
|
|
) -> None:
|
|
"""Test intent scripts work."""
|
|
calls = async_mock_service(hass, "test", "service")
|
|
|
|
await async_setup_component(
|
|
hass,
|
|
"intent_script",
|
|
{
|
|
"intent_script": {
|
|
"Targets": {
|
|
"description": "Intent to control a test service.",
|
|
"action": {
|
|
"service": "test.service",
|
|
"data_template": {
|
|
"targets": "{{ targets if targets is defined }}",
|
|
},
|
|
},
|
|
"speech": {
|
|
"text": "{{ targets.entities[0] if targets is defined }}"
|
|
},
|
|
}
|
|
}
|
|
},
|
|
)
|
|
|
|
floor_1 = floor_registry.async_create("first floor")
|
|
kitchen = area_registry.async_get_or_create("kitchen")
|
|
area_registry.async_update(kitchen.id, floor_id=floor_1.floor_id)
|
|
entity_registry.async_get_or_create(
|
|
"light", "demo", "1234", suggested_object_id="kitchen"
|
|
)
|
|
entity_registry.async_update_entity("light.kitchen", area_id=kitchen.id)
|
|
hass.states.async_set("light.kitchen", "off")
|
|
|
|
response = await intent.async_handle(
|
|
hass,
|
|
"test",
|
|
"Targets",
|
|
{"name": {"value": "kitchen"}, "domain": {"value": "light"}},
|
|
)
|
|
assert len(calls) == 1
|
|
assert calls[0].data["targets"] == {"entities": ["light.kitchen"]}
|
|
assert response.speech["plain"]["speech"] == "light.kitchen"
|
|
calls.clear()
|
|
|
|
response = await intent.async_handle(
|
|
hass,
|
|
"test",
|
|
"Targets",
|
|
{
|
|
"area": {"value": "kitchen"},
|
|
"floor": {"value": "first floor"},
|
|
},
|
|
)
|
|
assert len(calls) == 1
|
|
assert calls[0].data["targets"] == {
|
|
"entities": ["light.kitchen"],
|
|
"areas": ["kitchen"],
|
|
"floors": ["first_floor"],
|
|
}
|
|
calls.clear()
|
|
|
|
response = await intent.async_handle(
|
|
hass,
|
|
"test",
|
|
"Targets",
|
|
{"device_class": {"value": "door"}},
|
|
)
|
|
assert len(calls) == 1
|
|
assert calls[0].data["targets"] == ""
|
|
calls.clear()
|
|
|
|
|
|
async def test_reload(hass: HomeAssistant) -> None:
|
|
"""Verify we can reload intent config."""
|
|
|
|
config = {"intent_script": {"NewIntent1": {"speech": {"text": "HelloWorld123"}}}}
|
|
|
|
await async_setup_component(hass, "intent_script", config)
|
|
await hass.async_block_till_done()
|
|
|
|
intents = hass.data.get(intent.DATA_KEY)
|
|
|
|
assert len(intents) == 1
|
|
assert intents.get("NewIntent1")
|
|
|
|
yaml_path = get_fixture_path("configuration.yaml", "intent_script")
|
|
|
|
with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_RELOAD,
|
|
{},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(intents) == 1
|
|
|
|
assert intents.get("NewIntent1") is None
|
|
assert intents.get("NewIntent2")
|
|
|
|
yaml_path = get_fixture_path("configuration_no_entry.yaml", "intent_script")
|
|
|
|
with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
|
|
await hass.services.async_call(
|
|
DOMAIN,
|
|
SERVICE_RELOAD,
|
|
{},
|
|
blocking=True,
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
# absence of intent_script from the configuration.yaml should delete all intents.
|
|
assert len(intents) == 0
|
|
assert intents.get("NewIntent1") is None
|
|
assert intents.get("NewIntent2") is None
|