diff --git a/homeassistant/const.py b/homeassistant/const.py index 6e9954578b2..4bc5e189cf2 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -224,7 +224,6 @@ CONF_RESOURCE: Final = "resource" CONF_RESOURCE_TEMPLATE: Final = "resource_template" CONF_RESOURCES: Final = "resources" CONF_RESPONSE_VARIABLE: Final = "response_variable" -CONF_RESPONSE: Final = "response" CONF_RGB: Final = "rgb" CONF_ROOM: Final = "room" CONF_SCAN_INTERVAL: Final = "scan_interval" diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 393e11d9bbd..2f2f3cdf0a9 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -59,7 +59,6 @@ from homeassistant.const import ( CONF_PARALLEL, CONF_PLATFORM, CONF_REPEAT, - CONF_RESPONSE, CONF_RESPONSE_VARIABLE, CONF_SCAN_INTERVAL, CONF_SCENE, @@ -1691,10 +1690,7 @@ _SCRIPT_STOP_SCHEMA = vol.Schema( **SCRIPT_ACTION_BASE_SCHEMA, vol.Required(CONF_STOP): vol.Any(None, string), vol.Exclusive(CONF_ERROR, "error_or_response"): boolean, - vol.Exclusive(CONF_RESPONSE, "error_or_response"): vol.Any( - vol.All(dict, template_complex), - vol.All(str, template), - ), + vol.Exclusive(CONF_RESPONSE_VARIABLE, "error_or_response"): str, } ) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 13f29a96f78..e871c5120cd 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -46,7 +46,6 @@ from homeassistant.const import ( CONF_MODE, CONF_PARALLEL, CONF_REPEAT, - CONF_RESPONSE, CONF_RESPONSE_VARIABLE, CONF_SCENE, CONF_SEQUENCE, @@ -1031,10 +1030,14 @@ class _ScriptRun: raise _AbortScript(stop) self._log("Stop script sequence: %s", stop) - if CONF_RESPONSE in self._action: - response = template.render_complex( - self._action[CONF_RESPONSE], self._variables - ) + if CONF_RESPONSE_VARIABLE in self._action: + try: + response = self._variables[self._action[CONF_RESPONSE_VARIABLE]] + except KeyError as ex: + raise _AbortScript( + f"Response variable '{self._action[CONF_RESPONSE_VARIABLE]}' " + "is not defined" + ) from ex else: response = None raise _StopScript(stop, response) diff --git a/tests/components/script/test_init.py b/tests/components/script/test_init.py index 456eddbdaa7..7441e734848 100644 --- a/tests/components/script/test_init.py +++ b/tests/components/script/test_init.py @@ -25,7 +25,7 @@ from homeassistant.core import ( callback, split_entity_id, ) -from homeassistant.exceptions import ServiceNotFound +from homeassistant.exceptions import HomeAssistantError, ServiceNotFound from homeassistant.helpers import entity_registry as er, template from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.script import ( @@ -1515,10 +1515,15 @@ async def test_responses(hass: HomeAssistant, response: Any) -> None: { "script": { "test": { - "sequence": { - "stop": "done", - "response": response, - } + "sequence": [ + { + "variables": {"test_var": {"response": response}}, + }, + { + "stop": "done", + "response_variable": "test_var", + }, + ] } } }, @@ -1526,7 +1531,40 @@ async def test_responses(hass: HomeAssistant, response: Any) -> None: assert await hass.services.async_call( DOMAIN, "test", {"greeting": "world"}, blocking=True, return_response=True - ) == {"value": 5} + ) == {"response": response} + # Validate we can also call it without return_response + assert ( + await hass.services.async_call( + DOMAIN, "test", {"greeting": "world"}, blocking=True, return_response=False + ) + is None + ) + + +async def test_responses_error(hass: HomeAssistant) -> None: + """Test response variable not set.""" + mock_restore_cache(hass, ()) + assert await async_setup_component( + hass, + "script", + { + "script": { + "test": { + "sequence": [ + { + "stop": "done", + "response_variable": "test_var", + }, + ] + } + } + }, + ) + + with pytest.raises(HomeAssistantError): + assert await hass.services.async_call( + DOMAIN, "test", {"greeting": "world"}, blocking=True, return_response=True + ) # Validate we can also call it without return_response assert ( await hass.services.async_call( diff --git a/tests/components/websocket_api/test_commands.py b/tests/components/websocket_api/test_commands.py index 012199b5e5c..0916aaf46e4 100644 --- a/tests/components/websocket_api/test_commands.py +++ b/tests/components/websocket_api/test_commands.py @@ -24,7 +24,10 @@ from homeassistant.setup import DATA_SETUP_TIME, async_setup_component from homeassistant.util.json import json_loads from tests.common import MockEntity, MockEntityPlatform, MockUser, async_mock_service -from tests.typing import ClientSessionGenerator, WebSocketGenerator +from tests.typing import ( + ClientSessionGenerator, + WebSocketGenerator, +) STATE_KEY_SHORT_NAMES = { "entity_id": "e", @@ -1686,7 +1689,7 @@ async def test_execute_script(hass: HomeAssistant, websocket_client) -> None: "data": {"hello": "world"}, "response_variable": "service_result", }, - {"stop": "done", "response": "{{ service_result }}"}, + {"stop": "done", "response_variable": "service_result"}, ], } ) @@ -1732,6 +1735,48 @@ async def test_execute_script(hass: HomeAssistant, websocket_client) -> None: assert call.context.as_dict() == msg_var["result"]["context"] +async def test_execute_script_complex_response( + hass: HomeAssistant, hass_ws_client: WebSocketGenerator +) -> None: + """Test testing a condition.""" + await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}}) + await hass.async_block_till_done() + ws_client = await hass_ws_client(hass) + + await ws_client.send_json_auto_id( + { + "type": "execute_script", + "sequence": [ + { + "service": "calendar.list_events", + "data": {"duration": {"hours": 24, "minutes": 0, "seconds": 0}}, + "target": {"entity_id": "calendar.calendar_1"}, + "response_variable": "service_result", + }, + {"stop": "done", "response_variable": "service_result"}, + ], + } + ) + + msg_no_var = await ws_client.receive_json() + assert msg_no_var["type"] == const.TYPE_RESULT + assert msg_no_var["success"] + assert msg_no_var["result"]["response"] == { + "events": [ + { + "start": ANY, + "end": ANY, + "summary": "Future Event", + "description": "Future Description", + "location": "Future Location", + "uid": None, + "recurrence_id": None, + "rrule": None, + } + ] + } + + async def test_subscribe_unsubscribe_bootstrap_integrations( hass: HomeAssistant, websocket_client, hass_admin_user: MockUser ) -> None: