From d16edb3ef016e8515410a84206e6bbc695a23cd2 Mon Sep 17 00:00:00 2001 From: Matthew Donoughe Date: Sat, 5 Oct 2019 16:30:43 -0400 Subject: [PATCH] add script shortcut for activating scenes (#27223) * add script shortcut for activating scenes use `- scene: scene.` in a script to activate a scene * Update validation --- homeassistant/helpers/config_validation.py | 3 +++ homeassistant/helpers/script.py | 24 +++++++++++++++++++ tests/helpers/test_script.py | 27 ++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 4d5df8785e2..8598b50f140 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -885,6 +885,8 @@ DEVICE_ACTION_BASE_SCHEMA = vol.Schema( DEVICE_ACTION_SCHEMA = DEVICE_ACTION_BASE_SCHEMA.extend({}, extra=vol.ALLOW_EXTRA) +_SCRIPT_SCENE_SCHEMA = vol.Schema({vol.Required("scene"): entity_domain("scene")}) + SCRIPT_SCHEMA = vol.All( ensure_list, [ @@ -895,6 +897,7 @@ SCRIPT_SCHEMA = vol.All( EVENT_SCHEMA, CONDITION_SCHEMA, DEVICE_ACTION_SCHEMA, + _SCRIPT_SCENE_SCHEMA, ) ], ) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 05b28102726..1e65c24eaaf 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -9,12 +9,15 @@ from typing import Optional, Sequence, Callable, Dict, List, Set, Tuple, Any import voluptuous as vol import homeassistant.components.device_automation as device_automation +import homeassistant.components.scene as scene from homeassistant.core import HomeAssistant, Context, callback, CALLBACK_TYPE from homeassistant.const import ( + ATTR_ENTITY_ID, CONF_CONDITION, CONF_DEVICE_ID, CONF_DOMAIN, CONF_TIMEOUT, + SERVICE_TURN_ON, ) from homeassistant import exceptions from homeassistant.helpers import ( @@ -46,6 +49,7 @@ CONF_EVENT_DATA_TEMPLATE = "event_data_template" CONF_DELAY = "delay" CONF_WAIT_TEMPLATE = "wait_template" CONF_CONTINUE = "continue_on_timeout" +CONF_SCENE = "scene" ACTION_DELAY = "delay" @@ -54,6 +58,7 @@ ACTION_CHECK_CONDITION = "condition" ACTION_FIRE_EVENT = "event" ACTION_CALL_SERVICE = "call_service" ACTION_DEVICE_AUTOMATION = "device" +ACTION_ACTIVATE_SCENE = "scene" def _determine_action(action): @@ -73,6 +78,9 @@ def _determine_action(action): if CONF_DEVICE_ID in action: return ACTION_DEVICE_AUTOMATION + if CONF_SCENE in action: + return ACTION_ACTIVATE_SCENE + return ACTION_CALL_SERVICE @@ -147,6 +155,7 @@ class Script: ACTION_FIRE_EVENT: self._async_fire_event, ACTION_CALL_SERVICE: self._async_call_service, ACTION_DEVICE_AUTOMATION: self._async_device_automation, + ACTION_ACTIVATE_SCENE: self._async_activate_scene, } @property @@ -362,6 +371,21 @@ class Script: self.hass, action, variables, context ) + async def _async_activate_scene(self, action, variables, context): + """Activate the scene specified in the action. + + This method is a coroutine. + """ + self.last_action = action.get(CONF_ALIAS, "activate scene") + self._log("Executing step %s" % self.last_action) + await self.hass.services.async_call( + scene.DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: action[CONF_SCENE]}, + blocking=True, + context=context, + ) + async def _async_fire_event(self, action, variables, context): """Fire an event.""" self.last_action = action.get(CONF_ALIAS, action[CONF_EVENT]) diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index ebc56c111ee..4b8be715f37 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -9,7 +9,9 @@ import jinja2 import voluptuous as vol import pytest +import homeassistant.components.scene as scene from homeassistant import exceptions +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON from homeassistant.core import Context, callback # Otherwise can't test just this file (import order issue) @@ -120,6 +122,31 @@ async def test_calling_service(hass): assert calls[0].data.get("hello") == "world" +async def test_activating_scene(hass): + """Test the activation of a scene.""" + calls = [] + context = Context() + + @callback + def record_call(service): + """Add recorded event to set.""" + calls.append(service) + + hass.services.async_register(scene.DOMAIN, SERVICE_TURN_ON, record_call) + + hass.async_add_job( + ft.partial( + script.call_from_config, hass, {"scene": "scene.hello"}, context=context + ) + ) + + await hass.async_block_till_done() + + assert len(calls) == 1 + assert calls[0].context is context + assert calls[0].data.get(ATTR_ENTITY_ID) == "scene.hello" + + async def test_calling_service_template(hass): """Test the calling of a service.""" calls = []