""" Allow users to set and activate scenes. For more details about this component, please refer to the documentation at https://home-assistant.io/components/scene/ """ import asyncio import logging import voluptuous as vol from homeassistant.const import ( ATTR_ENTITY_ID, CONF_PLATFORM, SERVICE_TURN_ON) from homeassistant.loader import bind_hass import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.state import HASS_DOMAIN from homeassistant.loader import get_platform DOMAIN = 'scene' STATE = 'scening' STATES = 'states' def _hass_domain_validator(config): """Validate platform in config for homeassistant domain.""" if CONF_PLATFORM not in config: config = { CONF_PLATFORM: HASS_DOMAIN, STATES: config} return config def _platform_validator(config): """Validate it is a valid platform.""" p_name = config[CONF_PLATFORM] platform = get_platform(DOMAIN, p_name) if not hasattr(platform, 'PLATFORM_SCHEMA'): return config return getattr(platform, 'PLATFORM_SCHEMA')(config) PLATFORM_SCHEMA = vol.Schema( vol.All( _hass_domain_validator, vol.Schema({ vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN) }, extra=vol.ALLOW_EXTRA), _platform_validator ), extra=vol.ALLOW_EXTRA) SCENE_SERVICE_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, }) @bind_hass def activate(hass, entity_id=None): """Activate a scene.""" data = {} if entity_id: data[ATTR_ENTITY_ID] = entity_id hass.services.call(DOMAIN, SERVICE_TURN_ON, data) @asyncio.coroutine def async_setup(hass, config): """Set up the scenes.""" logger = logging.getLogger(__name__) component = EntityComponent(logger, DOMAIN, hass) yield from component.async_setup(config) @asyncio.coroutine def async_handle_scene_service(service): """Handle calls to the switch services.""" target_scenes = component.async_extract_from_service(service) tasks = [scene.async_activate() for scene in target_scenes] if tasks: yield from asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_TURN_ON, async_handle_scene_service, schema=SCENE_SERVICE_SCHEMA) return True class Scene(Entity): """A scene is a group of entities and the states we want them to be.""" @property def should_poll(self): """No polling needed.""" return False @property def state(self): """Return the state of the scene.""" return STATE def activate(self): """Activate scene. Try to get entities into requested state.""" raise NotImplementedError() def async_activate(self): """Activate scene. Try to get entities into requested state. This method must be run in the event loop and returns a coroutine. """ return self.hass.async_add_job(self.activate)