From cd30f2de0d17f3ce574b7dabf51e50035b95d36b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 5 Mar 2016 19:56:50 -0800 Subject: [PATCH] Device Sun Light Trigger: Clean up --- .../components/device_sun_light_trigger.py | 154 ++++++++---------- tests/components/device_tracker/test_init.py | 10 +- .../test_device_sun_light_trigger.py | 4 +- tests/helpers/test_event_decorators.py | 1 + 4 files changed, 72 insertions(+), 97 deletions(-) diff --git a/homeassistant/components/device_sun_light_trigger.py b/homeassistant/components/device_sun_light_trigger.py index a8cf5b5d417..c96c013275b 100644 --- a/homeassistant/components/device_sun_light_trigger.py +++ b/homeassistant/components/device_sun_light_trigger.py @@ -1,8 +1,6 @@ """ -homeassistant.components.device_sun_light_trigger -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Provides functionality to turn on lights based on the state of the sun and -devices. +devices home. For more details about this component, please refer to the documentation at https://home-assistant.io/components/device_sun_light_trigger/ @@ -12,9 +10,9 @@ from datetime import timedelta import homeassistant.util.dt as dt_util from homeassistant.const import STATE_HOME, STATE_NOT_HOME -from homeassistant.helpers.event import track_point_in_time, track_state_change - -from . import device_tracker, group, light, sun +from homeassistant.helpers.event import track_point_in_time +from homeassistant.helpers.event_decorators import track_state_change +from homeassistant.loader import get_component DOMAIN = "device_sun_light_trigger" DEPENDENCIES = ['light', 'device_tracker', 'group', 'sun'] @@ -29,28 +27,26 @@ CONF_LIGHT_GROUP = 'light_group' CONF_DEVICE_GROUP = 'device_group' -# pylint: disable=too-many-branches +# pylint: disable=too-many-locals def setup(hass, config): """ Triggers to turn lights on or off based on device precense. """ + logger = logging.getLogger(__name__) + device_tracker = get_component('device_tracker') + group = get_component('group') + light = get_component('light') + sun = get_component('sun') disable_turn_off = 'disable_turn_off' in config[DOMAIN] - light_group = config[DOMAIN].get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS) - light_profile = config[DOMAIN].get(CONF_LIGHT_PROFILE, LIGHT_PROFILE) - device_group = config[DOMAIN].get(CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES) - - logger = logging.getLogger(__name__) - device_entity_ids = group.get_entity_ids(hass, device_group, device_tracker.DOMAIN) if not device_entity_ids: logger.error("No devices found to track") - return False # Get the light IDs from the specified group @@ -58,32 +54,37 @@ def setup(hass, config): if not light_ids: logger.error("No lights found to turn on ") - return False def calc_time_for_light_when_sunset(): """ Calculates the time when to start fading lights in when sun sets. Returns None if no next_setting data available. """ next_setting = sun.next_setting(hass) - - if next_setting: - return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) - else: + if not next_setting: return None + return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) - def schedule_light_on_sun_rise(entity, old_state, new_state): + def turn_light_on_before_sunset(light_id): + """ Helper function to turn on lights slowly 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): + return + light.turn_on(hass, light_id, + transition=LIGHT_TRANSITION_TIME.seconds, + profile=light_profile) + + # Track every time sun rises so we can schedule a time-based + # pre-sun set event + @track_state_change(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON, + sun.STATE_ABOVE_HORIZON) + def schedule_lights_at_sun_set(hass, entity, old_state, new_state): """The moment sun sets we want to have all the lights on. We will schedule to have each light start after one another and slowly transition in.""" - def turn_light_on_before_sunset(light_id): - """ Helper function to turn on lights slowly if there - are devices home and the light is not on yet. """ - if device_tracker.is_on(hass) and not light.is_on(hass, light_id): - - light.turn_on(hass, light_id, - transition=LIGHT_TRANSITION_TIME.seconds, - profile=light_profile) + start_point = calc_time_for_light_when_sunset() + if not start_point: + return def turn_on(light_id): """ Lambda can keep track of function parameters but not local @@ -91,83 +92,60 @@ def setup(hass, config): only the last light will be turned on.. """ return lambda now: turn_light_on_before_sunset(light_id) - start_point = calc_time_for_light_when_sunset() - - if start_point: - for index, light_id in enumerate(light_ids): - track_point_in_time( - hass, turn_on(light_id), - (start_point + index * LIGHT_TRANSITION_TIME)) - - # Track every time sun rises so we can schedule a time-based - # pre-sun set event - track_state_change(hass, sun.ENTITY_ID, schedule_light_on_sun_rise, - sun.STATE_BELOW_HORIZON, sun.STATE_ABOVE_HORIZON) + for index, light_id in enumerate(light_ids): + track_point_in_time(hass, turn_on(light_id), + start_point + index * LIGHT_TRANSITION_TIME) # If the sun is already above horizon # schedule the time-based pre-sun set event if sun.is_on(hass): - schedule_light_on_sun_rise(None, None, None) + schedule_lights_at_sun_set(hass, None, None, None) - def check_light_on_dev_state_change(entity, old_state, new_state): - """ Function to handle tracked device state changes. """ + @track_state_change(device_entity_ids, STATE_NOT_HOME, STATE_HOME) + def check_light_on_dev_state_change(hass, entity, old_state, new_state): + """Handle tracked device state changes.""" + # pylint: disable=unused-variable lights_are_on = group.is_on(hass, light_group) light_needed = not (lights_are_on or sun.is_on(hass)) - # Specific device came home ? - if entity != device_tracker.ENTITY_ID_ALL_DEVICES and \ - new_state.state == STATE_HOME: + # These variables are needed for the elif check + now = dt_util.now() + start_point = calc_time_for_light_when_sunset() - # These variables are needed for the elif check - now = dt_util.now() - start_point = calc_time_for_light_when_sunset() + # Do we need lights? + if light_needed: + logger.info("Home coming event for %s. Turning lights on", entity) + light.turn_on(hass, light_ids, profile=light_profile) - # Do we need lights? - if light_needed: + # Are we in the time span were we would turn on the lights + # if someone would be home? + # Check this by seeing if current time is later then the point + # in time when we would start putting the lights on. + elif (start_point and + start_point < now < sun.next_setting(hass)): - logger.info( - "Home coming event for %s. Turning lights on", entity) + # Check for every light if it would be on if someone was home + # when the fading in started and turn it on if so + for index, light_id in enumerate(light_ids): + if now > start_point + index * LIGHT_TRANSITION_TIME: + light.turn_on(hass, light_id) - light.turn_on(hass, light_ids, profile=light_profile) + else: + # If this light didn't happen to be turned on yet so + # will all the following then, break. + break - # Are we in the time span were we would turn on the lights - # if someone would be home? - # Check this by seeing if current time is later then the point - # in time when we would start putting the lights on. - elif (start_point and - start_point < now < sun.next_setting(hass)): - - # Check for every light if it would be on if someone was home - # when the fading in started and turn it on if so - for index, light_id in enumerate(light_ids): - - if now > start_point + index * LIGHT_TRANSITION_TIME: - light.turn_on(hass, light_id) - - else: - # If this light didn't happen to be turned on yet so - # will all the following then, break. - break - - # Did all devices leave the house? - elif (entity == device_group and - new_state.state == STATE_NOT_HOME and lights_are_on and - not disable_turn_off): + if not disable_turn_off: + @track_state_change(device_group, STATE_HOME, STATE_NOT_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( "Everyone has left but there are lights on. Turning them off") - light.turn_off(hass, light_ids) - # Track home coming of each device - track_state_change( - hass, device_entity_ids, check_light_on_dev_state_change, - STATE_NOT_HOME, STATE_HOME) - - # Track when all devices are gone to shut down lights - track_state_change( - hass, device_group, check_light_on_dev_state_change, - STATE_HOME, STATE_NOT_HOME) - return True diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index a11979b2758..c106163d0d1 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -1,21 +1,15 @@ -""" -tests.components.device_tracker.test_init -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Tests the device tracker compoments. -""" +"""Tests for the device tracker compoment.""" # pylint: disable=protected-access,too-many-public-methods import unittest from unittest.mock import patch from datetime import datetime, timedelta import os -from homeassistant.config import load_yaml_config_file from homeassistant.loader import get_component import homeassistant.util.dt as dt_util from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, - STATE_HOME, STATE_NOT_HOME, CONF_PLATFORM, DEVICE_DEFAULT_NAME) + STATE_HOME, STATE_NOT_HOME, CONF_PLATFORM) import homeassistant.components.device_tracker as device_tracker from tests.common import ( diff --git a/tests/components/test_device_sun_light_trigger.py b/tests/components/test_device_sun_light_trigger.py index 2421577f312..0309ac1fb75 100644 --- a/tests/components/test_device_sun_light_trigger.py +++ b/tests/components/test_device_sun_light_trigger.py @@ -7,7 +7,7 @@ import homeassistant.loader as loader from homeassistant.const import CONF_PLATFORM, STATE_HOME, STATE_NOT_HOME from homeassistant.components import ( device_tracker, light, sun, device_sun_light_trigger) - +from homeassistant.helpers import event_decorators from tests.common import ( get_test_config_dir, get_test_home_assistant, ensure_sun_risen, @@ -41,6 +41,7 @@ class TestDeviceSunLightTrigger(unittest.TestCase): def setUp(self): # pylint: disable=invalid-name self.hass = get_test_home_assistant() + event_decorators.HASS = self.hass self.scanner = loader.get_component( 'device_tracker.test').get_scanner(None, None) @@ -64,6 +65,7 @@ class TestDeviceSunLightTrigger(unittest.TestCase): def tearDown(self): # pylint: disable=invalid-name """ Stop down stuff we started. """ self.hass.stop() + event_decorators.HASS = None def test_lights_on_when_sun_sets(self): """ Test lights go on when there is someone home and the sun sets. """ diff --git a/tests/helpers/test_event_decorators.py b/tests/helpers/test_event_decorators.py index 0d87be43740..99fcf8c5d0f 100644 --- a/tests/helpers/test_event_decorators.py +++ b/tests/helpers/test_event_decorators.py @@ -38,6 +38,7 @@ class TestEventDecoratorHelpers(unittest.TestCase): def tearDown(self): # pylint: disable=invalid-name """ Stop down stuff we started. """ self.hass.stop() + event_decorators.HASS = None def test_track_sunrise(self): """ Test track sunrise decorator """