WIP: Migrate scene to async + homeassistant scene async (#4665)

* Migrate scene to async + homeassistant scene async

* fix lint

* Update state.py

* Fix tests
This commit is contained in:
Pascal Vizeli 2016-12-02 06:38:12 +01:00 committed by Paulus Schoutsen
parent 49cfe38cca
commit 2e6a48ff5f
5 changed files with 51 additions and 20 deletions

View File

@ -4,6 +4,7 @@ Allow users to set and activate scenes.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/scene/ https://home-assistant.io/components/scene/
""" """
import asyncio
import logging import logging
from collections import namedtuple from collections import namedtuple
@ -39,7 +40,8 @@ def activate(hass, entity_id=None):
hass.services.call(DOMAIN, SERVICE_TURN_ON, data) hass.services.call(DOMAIN, SERVICE_TURN_ON, data)
def setup(hass, config): @asyncio.coroutine
def async_setup(hass, config):
"""Setup scenes.""" """Setup scenes."""
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -59,17 +61,21 @@ def setup(hass, config):
component = EntityComponent(logger, DOMAIN, hass) component = EntityComponent(logger, DOMAIN, hass)
component.setup(config) yield from component.async_setup(config)
def handle_scene_service(service): @asyncio.coroutine
def async_handle_scene_service(service):
"""Handle calls to the switch services.""" """Handle calls to the switch services."""
target_scenes = component.extract_from_service(service) target_scenes = component.async_extract_from_service(service)
print(target_scenes)
print(component.entities)
tasks = [scene.async_activate() for scene in target_scenes]
if tasks:
yield from asyncio.wait(tasks, loop=hass.loop)
for scene in target_scenes: hass.services.async_register(
scene.activate() DOMAIN, SERVICE_TURN_ON, async_handle_scene_service,
schema=SCENE_SERVICE_SCHEMA)
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_scene_service,
schema=SCENE_SERVICE_SCHEMA)
return True return True
@ -89,4 +95,12 @@ class Scene(Entity):
def activate(self): def activate(self):
"""Activate scene. Try to get entities into requested state.""" """Activate scene. Try to get entities into requested state."""
raise NotImplementedError raise NotImplementedError()
@asyncio.coroutine
def async_activate(self):
"""Activate scene. Try to get entities into requested state.
This method is a coroutine.
"""
yield from self.hass.loop.run_in_executor(None, self.activate)

View File

@ -4,13 +4,14 @@ Allow users to set and activate scenes.
For more details about this component, please refer to the documentation at For more details about this component, please refer to the documentation at
https://home-assistant.io/components/scene/ https://home-assistant.io/components/scene/
""" """
import asyncio
from collections import namedtuple from collections import namedtuple
from homeassistant.components.scene import Scene from homeassistant.components.scene import Scene
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, STATE_OFF, STATE_ON) ATTR_ENTITY_ID, STATE_OFF, STATE_ON)
from homeassistant.core import State from homeassistant.core import State
from homeassistant.helpers.state import reproduce_state from homeassistant.helpers.state import async_reproduce_state
DEPENDENCIES = ['group'] DEPENDENCIES = ['group']
STATE = 'scening' STATE = 'scening'
@ -20,21 +21,24 @@ CONF_ENTITIES = "entities"
SceneConfig = namedtuple('SceneConfig', ['name', 'states']) SceneConfig = namedtuple('SceneConfig', ['name', 'states'])
def setup_platform(hass, config, add_devices, discovery_info=None): @asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Setup home assistant scene entries.""" """Setup home assistant scene entries."""
scene_config = config.get("states") scene_config = config.get("states")
if not isinstance(scene_config, list): if not isinstance(scene_config, list):
scene_config = [scene_config] scene_config = [scene_config]
add_devices(HomeAssistantScene(hass, _process_config(scene)) yield from async_add_devices(HomeAssistantScene(
for scene in scene_config) hass, _process_config(scene)) for scene in scene_config)
return True return True
def _process_config(scene_config): def _process_config(scene_config):
"""Process passed in config into a format to work with.""" """Process passed in config into a format to work with.
Async friendly.
"""
name = scene_config.get('name') name = scene_config.get('name')
states = {} states = {}
@ -81,6 +85,8 @@ class HomeAssistantScene(Scene):
ATTR_ENTITY_ID: list(self.scene_config.states.keys()), ATTR_ENTITY_ID: list(self.scene_config.states.keys()),
} }
def activate(self): @asyncio.coroutine
def async_activate(self):
"""Activate scene. Try to get entities into requested state.""" """Activate scene. Try to get entities into requested state."""
reproduce_state(self.hass, self.scene_config.states.values(), True) yield from async_reproduce_state(
self.hass, self.scene_config.states.values(), True)

View File

@ -1,4 +1,5 @@
"""Helpers that help with state related things.""" """Helpers that help with state related things."""
import asyncio
import json import json
import logging import logging
from collections import defaultdict from collections import defaultdict
@ -33,6 +34,7 @@ from homeassistant.const import (
STATE_OFF, STATE_ON, STATE_OPEN, STATE_PAUSED, STATE_PLAYING, STATE_OFF, STATE_ON, STATE_OPEN, STATE_PAUSED, STATE_PLAYING,
STATE_UNKNOWN, STATE_UNLOCKED) STATE_UNKNOWN, STATE_UNLOCKED)
from homeassistant.core import State from homeassistant.core import State
from homeassistant.util.async import run_coroutine_threadsafe
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -111,6 +113,13 @@ def get_changed_since(states, utc_point_in_time):
def reproduce_state(hass, states, blocking=False): def reproduce_state(hass, states, blocking=False):
"""Reproduce given state."""
return run_coroutine_threadsafe(
async_reproduce_state(hass, states, blocking), hass.loop).result()
@asyncio.coroutine
def async_reproduce_state(hass, states, blocking=False):
"""Reproduce given state.""" """Reproduce given state."""
if isinstance(states, State): if isinstance(states, State):
states = [states] states = [states]
@ -129,7 +138,7 @@ def reproduce_state(hass, states, blocking=False):
else: else:
service_domain = state.domain service_domain = state.domain
domain_services = hass.services.services[service_domain] domain_services = hass.services.async_services()[service_domain]
service = None service = None
for _service in domain_services.keys(): for _service in domain_services.keys():
@ -157,7 +166,8 @@ def reproduce_state(hass, states, blocking=False):
for (service_domain, service, service_data), entity_ids in to_call.items(): for (service_domain, service, service_data), entity_ids in to_call.items():
data = json.loads(service_data) data = json.loads(service_data)
data[ATTR_ENTITY_ID] = entity_ids data[ATTR_ENTITY_ID] = entity_ids
hass.services.call(service_domain, service, data, blocking) yield from hass.services.async_call(
service_domain, service, data, blocking)
def state_as_number(state): def state_as_number(state):

View File

@ -0,0 +1 @@
"""Tests for scene component."""