Make device sun light trigger async (#5823)

This commit is contained in:
Paulus Schoutsen 2017-02-09 00:10:53 -08:00 committed by GitHub
parent 4398b8b5c6
commit c550a316a4

View File

@ -4,6 +4,7 @@ Provides functionality to turn on lights based on the states.
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/device_sun_light_trigger/ https://home-assistant.io/components/device_sun_light_trigger/
""" """
import asyncio
import logging import logging
from datetime import timedelta from datetime import timedelta
@ -12,8 +13,8 @@ import voluptuous as vol
from homeassistant.core import callback from homeassistant.core import callback
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from homeassistant.const import STATE_HOME, STATE_NOT_HOME from homeassistant.const import STATE_HOME, STATE_NOT_HOME
from homeassistant.helpers.event import track_point_in_time from homeassistant.helpers.event import (
from homeassistant.helpers.event_decorators import track_state_change async_track_point_in_time, async_track_state_change)
from homeassistant.loader import get_component from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -42,20 +43,20 @@ CONFIG_SCHEMA = vol.Schema({
}, extra=vol.ALLOW_EXTRA) }, extra=vol.ALLOW_EXTRA)
def setup(hass, config): @asyncio.coroutine
def async_setup(hass, config):
"""The triggers to turn lights on or off based on device presence.""" """The triggers to turn lights on or off based on device presence."""
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
device_tracker = get_component('device_tracker') device_tracker = get_component('device_tracker')
group = get_component('group') group = get_component('group')
light = get_component('light') light = get_component('light')
sun = get_component('sun') sun = get_component('sun')
conf = config[DOMAIN]
disable_turn_off = config[DOMAIN].get(CONF_DISABLE_TURN_OFF) disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF)
light_group = config[DOMAIN].get(CONF_LIGHT_GROUP, light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS)
light.ENTITY_ID_ALL_LIGHTS) light_profile = conf.get(CONF_LIGHT_PROFILE)
light_profile = config[DOMAIN].get(CONF_LIGHT_PROFILE) device_group = conf.get(CONF_DEVICE_GROUP,
device_group = config[DOMAIN].get(CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES)
device_tracker.ENTITY_ID_ALL_DEVICES)
device_entity_ids = group.get_entity_ids(hass, device_group, device_entity_ids = group.get_entity_ids(hass, device_group,
device_tracker.DOMAIN) device_tracker.DOMAIN)
@ -74,6 +75,8 @@ def setup(hass, config):
"""Calculate the time when to start fading lights in when sun sets. """Calculate the time when to start fading lights in when sun sets.
Returns None if no next_setting data available. Returns None if no next_setting data available.
Async friendly.
""" """
next_setting = sun.next_setting(hass) next_setting = sun.next_setting(hass)
if not next_setting: if not next_setting:
@ -81,22 +84,26 @@ def setup(hass, config):
return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) return next_setting - LIGHT_TRANSITION_TIME * len(light_ids)
def async_turn_on_before_sunset(light_id): def async_turn_on_before_sunset(light_id):
"""Helper function to turn on lights. """Helper function to turn on lights."""
Speed is slow if there are devices home and the light is not on yet.
"""
if not device_tracker.is_on(hass) or light.is_on(hass, light_id): if not device_tracker.is_on(hass) or light.is_on(hass, light_id):
return return
light.async_turn_on(hass, light_id, light.async_turn_on(hass, light_id,
transition=LIGHT_TRANSITION_TIME.seconds, transition=LIGHT_TRANSITION_TIME.seconds,
profile=light_profile) profile=light_profile)
def async_turn_on_factory(light_id):
"""Factory to generate turn on callbacks."""
@callback
def async_turn_on_light(now):
"""Turn on specific light."""
async_turn_on_before_sunset(light_id)
return async_turn_on_light
# Track every time sun rises so we can schedule a time-based # Track every time sun rises so we can schedule a time-based
# pre-sun set event # pre-sun set event
@track_state_change(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON,
sun.STATE_ABOVE_HORIZON)
@callback @callback
def schedule_lights_at_sun_set(hass, entity, old_state, new_state): def schedule_light_turn_on(entity, old_state, new_state):
"""The moment sun sets we want to have all the lights on. """The moment sun sets we want to have all the lights on.
We will schedule to have each light start after one another We will schedule to have each light start after one another
@ -106,35 +113,23 @@ def setup(hass, config):
if not start_point: if not start_point:
return return
def async_turn_on_factory(light_id):
"""Lambda can keep track of function parameters.
No local parameters. If we put the lambda directly in the below
statement only the last light will be turned on.
"""
@callback
def async_turn_on_light(now):
"""Turn on specific light."""
async_turn_on_before_sunset(light_id)
return async_turn_on_light
for index, light_id in enumerate(light_ids): for index, light_id in enumerate(light_ids):
track_point_in_time(hass, async_turn_on_factory(light_id), async_track_point_in_time(
start_point + index * LIGHT_TRANSITION_TIME) hass, async_turn_on_factory(light_id),
start_point + index * LIGHT_TRANSITION_TIME)
async_track_state_change(hass, sun.ENTITY_ID, schedule_light_turn_on,
sun.STATE_BELOW_HORIZON, sun.STATE_ABOVE_HORIZON)
# If the sun is already above horizon schedule the time-based pre-sun set # If the sun is already above horizon schedule the time-based pre-sun set
# event. # event.
if sun.is_on(hass): if sun.is_on(hass):
schedule_lights_at_sun_set(hass, None, None, None) schedule_light_turn_on(None, None, None)
@track_state_change(device_entity_ids, STATE_NOT_HOME, STATE_HOME)
@callback @callback
def check_light_on_dev_state_change(hass, entity, old_state, new_state): def check_light_on_dev_state_change(entity, old_state, new_state):
"""Handle tracked device state changes.""" """Handle tracked device state changes."""
# pylint: disable=unused-variable
lights_are_on = group.is_on(hass, light_group) lights_are_on = group.is_on(hass, light_group)
light_needed = not (lights_are_on or sun.is_on(hass)) light_needed = not (lights_are_on or sun.is_on(hass))
# These variables are needed for the elif check # These variables are needed for the elif check
@ -164,17 +159,25 @@ def setup(hass, config):
# will all the following then, break. # will all the following then, break.
break break
if not disable_turn_off: async_track_state_change(
@track_state_change(device_group, STATE_HOME, STATE_NOT_HOME) hass, device_entity_ids, check_light_on_dev_state_change,
@callback STATE_NOT_HOME, STATE_HOME)
def turn_off_lights_when_all_leave(hass, entity, old_state, new_state):
"""Handle device group state change."""
# pylint: disable=unused-variable
if not group.is_on(hass, light_group):
return
logger.info( if disable_turn_off:
"Everyone has left but there are lights on. Turning them off") return True
light.async_turn_off(hass, light_ids)
@callback
def turn_off_lights_when_all_leave(entity, old_state, new_state):
"""Handle device group state change."""
if not group.is_on(hass, light_group):
return
logger.info(
"Everyone has left but there are lights on. Turning them off")
light.async_turn_off(hass, light_ids)
async_track_state_change(
hass, device_group, turn_off_lights_when_all_leave,
STATE_HOME, STATE_NOT_HOME)
return True return True