diff --git a/homeassistant/components/switch/flux.py b/homeassistant/components/switch/flux.py new file mode 100644 index 00000000000..9a4580d6110 --- /dev/null +++ b/homeassistant/components/switch/flux.py @@ -0,0 +1,196 @@ +""" +Flux for Home-Assistant. + +The idea was taken from https://github.com/KpaBap/hue-flux/ + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/switch/flux/ +""" +from datetime import time +import logging +import voluptuous as vol + +from homeassistant.components.light import is_on, turn_on +from homeassistant.components.sun import next_setting, next_rising +from homeassistant.components.switch import DOMAIN, SwitchDevice +from homeassistant.const import CONF_NAME, CONF_PLATFORM, EVENT_TIME_CHANGED +from homeassistant.helpers.event import track_utc_time_change +from homeassistant.util.color import color_temperature_to_rgb as temp_to_rgb +from homeassistant.util.color import color_RGB_to_xy +from homeassistant.util.dt import now as dt_now +from homeassistant.util.dt import as_local +import homeassistant.helpers.config_validation as cv + +DEPENDENCIES = ['sun', 'light'] +SUN = "sun.sun" +_LOGGER = logging.getLogger(__name__) + +CONF_LIGHTS = 'lights' +CONF_START_TIME = 'start_time' +CONF_STOP_TIME = 'stop_time' +CONF_START_CT = 'start_colortemp' +CONF_SUNSET_CT = 'sunset_colortemp' +CONF_STOP_CT = 'stop_colortemp' +CONF_BRIGHTNESS = 'brightness' + +PLATFORM_SCHEMA = vol.Schema({ + vol.Required(CONF_PLATFORM): 'flux', + vol.Required(CONF_LIGHTS): cv.entity_ids, + vol.Optional(CONF_NAME, default="Flux"): cv.string, + vol.Optional(CONF_START_TIME): cv.time, + vol.Optional(CONF_STOP_TIME, default=time(22, 0)): cv.time, + vol.Optional(CONF_START_CT, default=4000): + vol.All(vol.Coerce(int), vol.Range(min=1000, max=40000)), + vol.Optional(CONF_SUNSET_CT, default=3000): + vol.All(vol.Coerce(int), vol.Range(min=1000, max=40000)), + vol.Optional(CONF_STOP_CT, default=1900): + vol.All(vol.Coerce(int), vol.Range(min=1000, max=40000)), + vol.Optional(CONF_BRIGHTNESS): + vol.All(vol.Coerce(int), vol.Range(min=0, max=255)) +}) + + +def set_lights_xy(hass, lights, x_val, y_val, brightness): + """Set color of array of lights.""" + for light in lights: + if is_on(hass, light): + turn_on(hass, light, + xy_color=[x_val, y_val], + brightness=brightness, + transition=30) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the demo switches.""" + name = config.get(CONF_NAME) + lights = config.get(CONF_LIGHTS) + start_time = config.get(CONF_START_TIME) + stop_time = config.get(CONF_STOP_TIME) + start_colortemp = config.get(CONF_START_CT) + sunset_colortemp = config.get(CONF_SUNSET_CT) + stop_colortemp = config.get(CONF_STOP_CT) + brightness = config.get(CONF_BRIGHTNESS) + flux = FluxSwitch(name, hass, False, lights, start_time, stop_time, + start_colortemp, sunset_colortemp, stop_colortemp, + brightness) + add_devices([flux]) + + def update(call=None): + """Update lights.""" + flux.flux_update() + + hass.services.register(DOMAIN, 'flux_update', update) + + +# pylint: disable=too-many-instance-attributes +class FluxSwitch(SwitchDevice): + """Flux switch.""" + + # pylint: disable=too-many-arguments + def __init__(self, name, hass, state, lights, start_time, stop_time, + start_colortemp, sunset_colortemp, stop_colortemp, + brightness): + """Initialize the Flux switch.""" + self._name = name + self.hass = hass + self._state = state + self._lights = lights + self._start_time = start_time + self._stop_time = stop_time + self._start_colortemp = start_colortemp + self._sunset_colortemp = sunset_colortemp + self._stop_colortemp = stop_colortemp + self._brightness = brightness + self.tracker = None + + @property + def name(self): + """Return the name of the device if any.""" + return self._name + + @property + def is_on(self): + """Return true if switch is on.""" + return self._state + + def turn_on(self, **kwargs): + """Turn on flux.""" + self._state = True + self.tracker = track_utc_time_change(self.hass, + self.flux_update, + second=[0, 30]) + self.update_ha_state() + + def turn_off(self, **kwargs): + """Turn off flux.""" + self._state = False + self.hass.bus.remove_listener(EVENT_TIME_CHANGED, self.tracker) + self.update_ha_state() + + # pylint: disable=too-many-locals + def flux_update(self, now=dt_now()): + """Update all the lights using flux.""" + sunset = next_setting(self.hass, SUN).replace(day=now.day, + month=now.month, + year=now.year) + start_time = self.find_start_time(now) + stop_time = now.replace(hour=self._stop_time.hour, + minute=self._stop_time.minute, + second=0) + + if start_time < now < sunset: + # Daytime + temp_range = abs(self._start_colortemp - self._sunset_colortemp) + day_length = int(sunset.timestamp() - start_time.timestamp()) + seconds_from_start = int(now.timestamp() - start_time.timestamp()) + percentage_of_day_complete = seconds_from_start / day_length + temp_offset = temp_range * percentage_of_day_complete + if self._start_colortemp > self._sunset_colortemp: + temp = self._start_colortemp - temp_offset + else: + temp = self._start_colortemp + temp_offset + x_val, y_val, b_val = color_RGB_to_xy(*temp_to_rgb(temp)) + brightness = self._brightness if self._brightness else b_val + set_lights_xy(self.hass, self._lights, x_val, + y_val, brightness) + _LOGGER.info("Lights updated to x:%s y:%s brightness:%s, %s%%" + " of day cycle complete at %s", x_val, y_val, + brightness, round(percentage_of_day_complete*100), + as_local(now)) + else: + # Nightime + if now < stop_time and now > start_time: + now_time = now + else: + now_time = stop_time + temp_range = abs(self._sunset_colortemp - self._stop_colortemp) + night_length = int(stop_time.timestamp() - sunset.timestamp()) + seconds_from_sunset = int(now_time.timestamp() - + sunset.timestamp()) + percentage_of_night_complete = seconds_from_sunset / night_length + temp_offset = temp_range * percentage_of_night_complete + if self._sunset_colortemp > self._stop_colortemp: + temp = self._sunset_colortemp - temp_offset + else: + temp = self._sunset_colortemp + temp_offset + x_val, y_val, b_val = color_RGB_to_xy(*temp_to_rgb(temp)) + brightness = self._brightness if self._brightness else b_val + set_lights_xy(self.hass, self._lights, x_val, + y_val, brightness) + _LOGGER.info("Lights updated to x:%s y:%s brightness:%s, %s%%" + " of night cycle complete at %s", x_val, y_val, + brightness, round(percentage_of_night_complete*100), + as_local(now)) + + def find_start_time(self, now): + """Return sunrise or start_time if given.""" + if self._start_time: + sunrise = now.replace(hour=self._start_time.hour, + minute=self._start_time.minute, + second=0) + else: + sunrise = next_rising(self.hass, SUN).replace(day=now.day, + month=now.month, + year=now.year) + return sunrise diff --git a/tests/components/switch/test_flux.py b/tests/components/switch/test_flux.py new file mode 100644 index 00000000000..ee20daf07ac --- /dev/null +++ b/tests/components/switch/test_flux.py @@ -0,0 +1,483 @@ +"""The tests for the Flux switch platform.""" +import unittest +from datetime import timedelta +from unittest.mock import patch + +from homeassistant.bootstrap import _setup_component, setup_component +from homeassistant.components import switch, light +from homeassistant.const import CONF_PLATFORM, STATE_ON, SERVICE_TURN_ON +import homeassistant.loader as loader +import homeassistant.util.dt as dt_util +from tests.common import get_test_home_assistant +from tests.common import fire_time_changed, mock_service + + +class TestSwitchFlux(unittest.TestCase): + """Test the Flux switch platform.""" + + def setUp(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + # self.hass.config.components = ['flux', 'sun', 'light'] + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + + def test_valid_config(self): + """Test configuration.""" + assert _setup_component(self.hass, 'switch', { + 'switch': { + 'platform': 'flux', + 'name': 'flux', + 'lights': ['light.desk', 'light.lamp'], + } + }) + + def test_valid_config_with_info(self): + """Test configuration.""" + assert _setup_component(self.hass, 'switch', { + 'switch': { + 'platform': 'flux', + 'name': 'flux', + 'lights': ['light.desk', 'light.lamp'], + 'stop_time': '22:59', + 'start_time': '7:22', + 'start_colortemp': '1000', + 'sunset_colortemp': '2000', + 'stop_colortemp': '4000' + } + }) + + def test_valid_config_no_name(self): + """Test configuration.""" + assert _setup_component(self.hass, 'switch', { + 'switch': { + 'platform': 'flux', + 'lights': ['light.desk', 'light.lamp'] + } + }) + + def test_invalid_config_no_lights(self): + """Test configuration.""" + assert not _setup_component(self.hass, 'switch', { + 'switch': { + 'platform': 'flux', + 'name': 'flux' + } + }) + + def test_flux_when_switch_is_off(self): + """Test the flux switch when it is off.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=10, minute=30, + second=0) + sunset_time = test_time.replace(hour=17, minute=0, + second=0) + sunrise_time = test_time.replace(hour=5, minute=0, + second=0) + timedelta(days=1) + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id] + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + self.assertEqual(0, len(turn_on_calls)) + + def test_flux_before_sunrise(self): + """Test the flux switch before sunrise.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=2, minute=30, + second=0) + sunset_time = test_time.replace(hour=17, minute=0, + second=0) + sunrise_time = test_time.replace(hour=5, minute=0, + second=0) + timedelta(days=1) + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id] + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 119) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.591, 0.395]) + + # pylint: disable=invalid-name + def test_flux_after_sunrise_before_sunset(self): + """Test the flux switch after sunrise and before sunset.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=8, minute=30, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, + minute=0, + second=0) + timedelta(days=1) + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id] + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 180) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.431, 0.38]) + + # pylint: disable=invalid-name + def test_flux_after_sunset_before_stop(self): + """Test the flux switch after sunset and before stop.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=17, minute=30, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, + minute=0, + second=0) + timedelta(days=1) + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id] + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 153) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.496, 0.397]) + + # pylint: disable=invalid-name + def test_flux_after_stop_before_sunrise(self): + """Test the flux switch after stop and before sunrise.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=23, minute=30, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, + minute=0, + second=0) + timedelta(days=1) + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id] + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 119) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.591, 0.395]) + + # pylint: disable=invalid-name + def test_flux_with_custom_start_stop_times(self): + """Test the flux with custom start and stop times.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=17, minute=30, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, + minute=0, + second=0) + timedelta(days=1) + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id], + 'start_time': '6:00', + 'stop_time': '23:30' + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 154) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.494, 0.397]) + + # pylint: disable=invalid-name + def test_flux_with_custom_colortemps(self): + """Test the flux with custom start and stop colortemps.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=17, minute=30, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, + minute=0, + second=0) + timedelta(days=1) + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id], + 'start_colortemp': '1000', + 'stop_colortemp': '6000' + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 167) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.461, 0.389]) + + # pylint: disable=invalid-name + def test_flux_with_custom_brightness(self): + """Test the flux with custom start and stop colortemps.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=17, minute=30, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, + minute=0, + second=0) + timedelta(days=1) + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id], + 'brightness': 255 + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 255) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.496, 0.397]) + + def test_flux_with_multiple_lights(self): + """Test the flux switch with multiple light entities.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + light.setup(self.hass, {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1, dev2, dev3 = platform.DEVICES + light.turn_on(self.hass, entity_id=dev2.entity_id) + self.hass.pool.block_till_done() + light.turn_on(self.hass, entity_id=dev3.entity_id) + self.hass.pool.block_till_done() + + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + state = self.hass.states.get(dev2.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + state = self.hass.states.get(dev3.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('xy_color')) + self.assertIsNone(state.attributes.get('brightness')) + + test_time = dt_util.now().replace(hour=12, minute=0, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, + minute=0, + second=0) + timedelta(days=1) + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.components.sun.next_rising', + return_value=sunrise_time): + with patch('homeassistant.components.sun.next_setting', + return_value=sunset_time): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id, + dev2.entity_id, + dev3.entity_id] + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.pool.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.pool.block_till_done() + call = turn_on_calls[-1] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 171) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.452, 0.386]) + call = turn_on_calls[-2] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 171) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.452, 0.386]) + call = turn_on_calls[-3] + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 171) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.452, 0.386])