""" 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 logging import threading from datetime import timedelta from itertools import islice import voluptuous as vol import homeassistant.util.dt as date_util from homeassistant.const import ( ATTR_ENTITY_ID, EVENT_TIME_CHANGED, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_TOGGLE, STATE_ON) from homeassistant.helpers.entity import ToggleEntity, split_entity_id from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.event import track_point_in_utc_time from homeassistant.helpers.service import (call_from_config, validate_service_call) import homeassistant.helpers.config_validation as cv DOMAIN = "script" ENTITY_ID_FORMAT = DOMAIN + '.{}' DEPENDENCIES = ["group"] STATE_NOT_RUNNING = 'Not Running' CONF_ALIAS = "alias" CONF_SERVICE = "service" CONF_SERVICE_DATA = "data" CONF_SEQUENCE = "sequence" CONF_EVENT = "event" CONF_EVENT_DATA = "event_data" CONF_DELAY = "delay" ATTR_LAST_ACTION = 'last_action' ATTR_CAN_CANCEL = 'can_cancel' _LOGGER = logging.getLogger(__name__) _ALIAS_VALIDATOR = vol.Schema(cv.string) def _alias_stripper(validator): """Strip alias from object for validation.""" def validate(value): """Validate without alias value.""" value = value.copy() alias = value.pop(CONF_ALIAS, None) if alias is not None: alias = _ALIAS_VALIDATOR(alias) value = validator(value) if alias is not None: value[CONF_ALIAS] = alias return value return validate _DELAY_SCHEMA = { vol.Required(CONF_DELAY): vol.All({ CONF_ALIAS: cv.string, 'days': vol.All(vol.Coerce(int), vol.Range(min=0)), 'seconds': vol.All(vol.Coerce(int), vol.Range(min=0)), 'microseconds': vol.All(vol.Coerce(int), vol.Range(min=0)), 'milliseconds': vol.All(vol.Coerce(int), vol.Range(min=0)), 'minutes': vol.All(vol.Coerce(int), vol.Range(min=0)), 'hours': vol.All(vol.Coerce(int), vol.Range(min=0)), 'weeks': vol.All(vol.Coerce(int), vol.Range(min=0)), }, cv.has_at_least_one_key([ 'days', 'seconds', 'microseconds', 'milliseconds', 'minutes', 'hours', 'weeks'])) } _EVENT_SCHEMA = cv.EVENT_SCHEMA.extend({ CONF_ALIAS: cv.string, }) _SCRIPT_ENTRY_SCHEMA = vol.Schema({ CONF_ALIAS: cv.string, vol.Required(CONF_SEQUENCE): vol.All(vol.Length(min=1), [vol.Any( _EVENT_SCHEMA, _DELAY_SCHEMA, # Can't extend SERVICE_SCHEMA because it is an vol.All _alias_stripper(cv.SERVICE_SCHEMA), )]), }) CONFIG_SCHEMA = vol.Schema({ vol.Required(DOMAIN): cv.DictValidator(_SCRIPT_ENTRY_SCHEMA, cv.slug) }, extra=vol.ALLOW_EXTRA) def is_on(hass, entity_id): """Return if the switch is on based on the statemachine.""" return hass.states.is_state(entity_id, STATE_ON) def turn_on(hass, entity_id): """Turn script on.""" _, object_id = split_entity_id(entity_id) hass.services.call(DOMAIN, object_id) def turn_off(hass, entity_id): """Turn script on.""" hass.services.call(DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}) def toggle(hass, entity_id): """Toggle the script.""" hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id}) def setup(hass, config): """Load the scripts from the configuration.""" component = EntityComponent(_LOGGER, DOMAIN, hass) def service_handler(service): """Execute a service call to script.