diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 4bfcb98e9d4..8f0c93f5c9f 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -929,8 +929,10 @@ SERVICE_SCHEMA = vol.All( vol.Exclusive(CONF_SERVICE_TEMPLATE, "service name"): vol.Any( service, dynamic_template ), - vol.Optional("data"): vol.All(dict, template_complex), - vol.Optional("data_template"): vol.All(dict, template_complex), + vol.Optional("data"): vol.Any(template, vol.All(dict, template_complex)), + vol.Optional("data_template"): vol.Any( + template, vol.All(dict, template_complex) + ), vol.Optional(CONF_ENTITY_ID): comp_entity_ids, vol.Optional(CONF_TARGET): vol.Any(ENTITY_SERVICE_FIELDS, dynamic_template), } diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 57bcefe56e3..c2720c02f47 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -234,7 +234,12 @@ def async_prepare_call_from_config( continue try: template.attach(hass, config[conf]) - service_data.update(template.render_complex(config[conf], variables)) + render = template.render_complex(config[conf], variables) + if not isinstance(render, dict): + raise HomeAssistantError( + "Error rendering data template: Result is not a Dictionary" + ) + service_data.update(render) except TemplateError as ex: raise HomeAssistantError(f"Error rendering data template: {ex}") from ex diff --git a/tests/components/automation/test_init.py b/tests/components/automation/test_init.py index 214b2ea20e8..b90c6a90819 100644 --- a/tests/components/automation/test_init.py +++ b/tests/components/automation/test_init.py @@ -45,9 +45,9 @@ def calls(hass): return async_mock_service(hass, "test", "automation") -async def test_service_data_not_a_dict(hass, calls): +async def test_service_data_not_a_dict(hass, caplog, calls): """Test service data not dict.""" - with assert_setup_component(0, automation.DOMAIN): + with assert_setup_component(1, automation.DOMAIN): assert await async_setup_component( hass, automation.DOMAIN, @@ -59,6 +59,34 @@ async def test_service_data_not_a_dict(hass, calls): }, ) + hass.bus.async_fire("test_event") + await hass.async_block_till_done() + assert len(calls) == 0 + assert "Result is not a Dictionary" in caplog.text + + +async def test_service_data_single_template(hass, calls): + """Test service data not dict.""" + with assert_setup_component(1, automation.DOMAIN): + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: { + "trigger": {"platform": "event", "event_type": "test_event"}, + "action": { + "service": "test.automation", + "data": "{{ { 'foo': 'bar' } }}", + }, + } + }, + ) + + hass.bus.async_fire("test_event") + await hass.async_block_till_done() + assert len(calls) == 1 + assert calls[0].data["foo"] == "bar" + async def test_service_specify_data(hass, calls): """Test service data."""