""" Support for scripts. Scripts are a sequence of actions that can be triggered manually by the user or automatically based upon automation events, etc. For more details about this component, please refer to the documentation at https://home-assistant.io/components/script/ """ import asyncio import logging import voluptuous as vol from homeassistant.const import ( ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_TOGGLE, SERVICE_RELOAD, STATE_ON, CONF_ALIAS) from homeassistant.core import split_entity_id from homeassistant.loader import bind_hass from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent import homeassistant.helpers.config_validation as cv from homeassistant.helpers.script import Script _LOGGER = logging.getLogger(__name__) DOMAIN = 'script' DEPENDENCIES = ['group'] ATTR_CAN_CANCEL = 'can_cancel' ATTR_LAST_ACTION = 'last_action' ATTR_LAST_TRIGGERED = 'last_triggered' ATTR_VARIABLES = 'variables' CONF_SEQUENCE = 'sequence' ENTITY_ID_FORMAT = DOMAIN + '.{}' GROUP_NAME_ALL_SCRIPTS = 'all scripts' SCRIPT_ENTRY_SCHEMA = vol.Schema({ CONF_ALIAS: cv.string, vol.Required(CONF_SEQUENCE): cv.SCRIPT_SCHEMA, }) CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({cv.slug: SCRIPT_ENTRY_SCHEMA}) }, extra=vol.ALLOW_EXTRA) SCRIPT_SERVICE_SCHEMA = vol.Schema(dict) SCRIPT_TURN_ONOFF_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, vol.Optional(ATTR_VARIABLES): dict, }) RELOAD_SERVICE_SCHEMA = vol.Schema({}) @bind_hass def is_on(hass, entity_id): """Return if the script is on based on the statemachine.""" return hass.states.is_state(entity_id, STATE_ON) @bind_hass def turn_on(hass, entity_id, variables=None, context=None): """Turn script on.""" _, object_id = split_entity_id(entity_id) hass.services.call(DOMAIN, object_id, variables, context=context) @bind_hass def turn_off(hass, entity_id): """Turn script on.""" hass.services.call(DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}) @bind_hass def toggle(hass, entity_id): """Toggle the script.""" hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id}) @bind_hass def reload(hass): """Reload script component.""" hass.services.call(DOMAIN, SERVICE_RELOAD) @bind_hass def async_reload(hass): """Reload the scripts from config. Returns a coroutine object. """ return hass.services.async_call(DOMAIN, SERVICE_RELOAD) async def async_setup(hass, config): """Load the scripts from the configuration.""" component = EntityComponent( _LOGGER, DOMAIN, hass, group_name=GROUP_NAME_ALL_SCRIPTS) await _async_process_config(hass, config, component) async def reload_service(service): """Call a service to reload scripts.""" conf = await component.async_prepare_reload() if conf is None: return await _async_process_config(hass, conf, component) async def turn_on_service(service): """Call a service to turn script on.""" # We could turn on script directly here, but we only want to offer # one way to do it. Otherwise no easy way to detect invocations. var = service.data.get(ATTR_VARIABLES) for script in component.async_extract_from_service(service): await hass.services.async_call(DOMAIN, script.object_id, var, context=service.context) async def turn_off_service(service): """Cancel a script.""" # Stopping a script is ok to be done in parallel await asyncio.wait( [script.async_turn_off() for script in component.async_extract_from_service(service)], loop=hass.loop) async def toggle_service(service): """Toggle a script.""" for script in component.async_extract_from_service(service): await script.async_toggle(context=service.context) hass.services.async_register(DOMAIN, SERVICE_RELOAD, reload_service, schema=RELOAD_SERVICE_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TURN_ON, turn_on_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TURN_OFF, turn_off_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) hass.services.async_register(DOMAIN, SERVICE_TOGGLE, toggle_service, schema=SCRIPT_TURN_ONOFF_SCHEMA) return True async def _async_process_config(hass, config, component): """Process script configuration.""" async def service_handler(service): """Execute a service call to script.