From 9ae6a3402c44ad8466a9ff9b75a611672615be0e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 6 Apr 2018 10:26:08 -0400 Subject: [PATCH 1/9] Version bump to 0.67.0b0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index d286aa85458..815562b68c5 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 67 -PATCH_VERSION = '0.dev0' +PATCH_VERSION = '0b0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From bd58a0de7dab6dc8119ddea5878f27ed1fb25c1e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 9 Apr 2018 21:21:26 -0400 Subject: [PATCH 2/9] Remove vendor lookup for mac addresses (#13788) * Remove vendor lookup for mac addresses * Fix tests --- .../components/device_tracker/__init__.py | 61 +-------- tests/components/device_tracker/test_init.py | 128 +----------------- tests/conftest.py | 4 +- 3 files changed, 6 insertions(+), 187 deletions(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 682496335a0..45f0e51a214 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -9,8 +9,6 @@ from datetime import timedelta import logging from typing import Any, List, Sequence, Callable -import aiohttp -import async_timeout import voluptuous as vol from homeassistant.setup import async_prepare_setup_platform @@ -19,7 +17,6 @@ from homeassistant.loader import bind_hass from homeassistant.components import group, zone from homeassistant.config import load_yaml_config_file, async_log_exception from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers import config_per_platform, discovery from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import async_track_time_interval @@ -76,7 +73,6 @@ ATTR_LOCATION_NAME = 'location_name' ATTR_MAC = 'mac' ATTR_NAME = 'name' ATTR_SOURCE_TYPE = 'source_type' -ATTR_VENDOR = 'vendor' ATTR_CONSIDER_HOME = 'consider_home' SOURCE_TYPE_GPS = 'gps' @@ -328,14 +324,10 @@ class DeviceTracker(object): self.hass, util.slugify(GROUP_NAME_ALL_DEVICES), visible=False, name=GROUP_NAME_ALL_DEVICES, add=[device.entity_id]) - # lookup mac vendor string to be stored in config - yield from device.set_vendor_for_mac() - self.hass.bus.async_fire(EVENT_NEW_DEVICE, { ATTR_ENTITY_ID: device.entity_id, ATTR_HOST_NAME: device.host_name, ATTR_MAC: device.mac, - ATTR_VENDOR: device.vendor, }) # update known_devices.yaml @@ -413,7 +405,6 @@ class Device(Entity): consider_home = None # type: dt_util.dt.timedelta battery = None # type: int attributes = None # type: dict - vendor = None # type: str icon = None # type: str # Track if the last update of this device was HOME. @@ -423,7 +414,7 @@ class Device(Entity): def __init__(self, hass: HomeAssistantType, consider_home: timedelta, track: bool, dev_id: str, mac: str, name: str = None, picture: str = None, gravatar: str = None, icon: str = None, - hide_if_away: bool = False, vendor: str = None) -> None: + hide_if_away: bool = False) -> None: """Initialize a device.""" self.hass = hass self.entity_id = ENTITY_ID_FORMAT.format(dev_id) @@ -451,7 +442,6 @@ class Device(Entity): self.icon = icon self.away_hide = hide_if_away - self.vendor = vendor self.source_type = None @@ -567,51 +557,6 @@ class Device(Entity): self._state = STATE_HOME self.last_update_home = True - @asyncio.coroutine - def set_vendor_for_mac(self): - """Set vendor string using api.macvendors.com.""" - self.vendor = yield from self.get_vendor_for_mac() - - @asyncio.coroutine - def get_vendor_for_mac(self): - """Try to find the vendor string for a given MAC address.""" - if not self.mac: - return None - - if '_' in self.mac: - _, mac = self.mac.split('_', 1) - else: - mac = self.mac - - if not len(mac.split(':')) == 6: - return 'unknown' - - # We only need the first 3 bytes of the MAC for a lookup - # this improves somewhat on privacy - oui_bytes = mac.split(':')[0:3] - # bytes like 00 get truncates to 0, API needs full bytes - oui = '{:02x}:{:02x}:{:02x}'.format(*[int(b, 16) for b in oui_bytes]) - url = 'http://api.macvendors.com/' + oui - try: - websession = async_get_clientsession(self.hass) - - with async_timeout.timeout(5, loop=self.hass.loop): - resp = yield from websession.get(url) - # mac vendor found, response is the string - if resp.status == 200: - vendor_string = yield from resp.text() - return vendor_string - # If vendor is not known to the API (404) or there - # was a failure during the lookup (500); set vendor - # to something other then None to prevent retry - # as the value is only relevant when it is to be stored - # in the 'known_devices.yaml' file which only happens - # the first time the device is seen. - return 'unknown' - except (asyncio.TimeoutError, aiohttp.ClientError): - # Same as above - return 'unknown' - @asyncio.coroutine def async_added_to_hass(self): """Add an entity.""" @@ -685,7 +630,6 @@ def async_load_config(path: str, hass: HomeAssistantType, vol.Optional('picture', default=None): vol.Any(None, cv.string), vol.Optional(CONF_CONSIDER_HOME, default=consider_home): vol.All( cv.time_period, cv.positive_timedelta), - vol.Optional('vendor', default=None): vol.Any(None, cv.string), }) try: result = [] @@ -697,6 +641,8 @@ def async_load_config(path: str, hass: HomeAssistantType, return [] for dev_id, device in devices.items(): + # Deprecated option. We just ignore it to avoid breaking change + device.pop('vendor', None) try: device = dev_schema(device) device['dev_id'] = cv.slugify(dev_id) @@ -772,7 +718,6 @@ def update_config(path: str, dev_id: str, device: Device): 'picture': device.config_picture, 'track': device.track, CONF_AWAY_HIDE: device.away_hide, - 'vendor': device.vendor, }} out.write('\n') out.write(dump(device)) diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index c051983d8fa..912bd315ecd 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -24,9 +24,7 @@ from homeassistant.remote import JSONEncoder from tests.common import ( get_test_home_assistant, fire_time_changed, - patch_yaml_files, assert_setup_component, mock_restore_cache, mock_coro) - -from ...test_util.aiohttp import mock_aiohttp_client + patch_yaml_files, assert_setup_component, mock_restore_cache) TEST_PLATFORM = {device_tracker.DOMAIN: {CONF_PLATFORM: 'test'}} @@ -111,7 +109,6 @@ class TestComponentsDeviceTracker(unittest.TestCase): self.assertEqual(device.config_picture, config.config_picture) self.assertEqual(device.away_hide, config.away_hide) self.assertEqual(device.consider_home, config.consider_home) - self.assertEqual(device.vendor, config.vendor) self.assertEqual(device.icon, config.icon) # pylint: disable=invalid-name @@ -173,124 +170,6 @@ class TestComponentsDeviceTracker(unittest.TestCase): "55502f40dc8b7c769880b10874abc9d0.jpg?s=80&d=wavatar") self.assertEqual(device.config_picture, gravatar_url) - def test_mac_vendor_lookup(self): - """Test if vendor string is lookup on macvendors API.""" - mac = 'B8:27:EB:00:00:00' - vendor_string = 'Raspberry Pi Foundation' - - device = device_tracker.Device( - self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name') - - with mock_aiohttp_client() as aioclient_mock: - aioclient_mock.get('http://api.macvendors.com/b8:27:eb', - text=vendor_string) - - run_coroutine_threadsafe(device.set_vendor_for_mac(), - self.hass.loop).result() - assert aioclient_mock.call_count == 1 - - self.assertEqual(device.vendor, vendor_string) - - def test_mac_vendor_mac_formats(self): - """Verify all variations of MAC addresses are handled correctly.""" - vendor_string = 'Raspberry Pi Foundation' - - with mock_aiohttp_client() as aioclient_mock: - aioclient_mock.get('http://api.macvendors.com/b8:27:eb', - text=vendor_string) - aioclient_mock.get('http://api.macvendors.com/00:27:eb', - text=vendor_string) - - mac = 'B8:27:EB:00:00:00' - device = device_tracker.Device( - self.hass, timedelta(seconds=180), - True, 'test', mac, 'Test name') - run_coroutine_threadsafe(device.set_vendor_for_mac(), - self.hass.loop).result() - self.assertEqual(device.vendor, vendor_string) - - mac = '0:27:EB:00:00:00' - device = device_tracker.Device( - self.hass, timedelta(seconds=180), - True, 'test', mac, 'Test name') - run_coroutine_threadsafe(device.set_vendor_for_mac(), - self.hass.loop).result() - self.assertEqual(device.vendor, vendor_string) - - mac = 'PREFIXED_B8:27:EB:00:00:00' - device = device_tracker.Device( - self.hass, timedelta(seconds=180), - True, 'test', mac, 'Test name') - run_coroutine_threadsafe(device.set_vendor_for_mac(), - self.hass.loop).result() - self.assertEqual(device.vendor, vendor_string) - - def test_mac_vendor_lookup_unknown(self): - """Prevent another mac vendor lookup if was not found first time.""" - mac = 'B8:27:EB:00:00:00' - - device = device_tracker.Device( - self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name') - - with mock_aiohttp_client() as aioclient_mock: - aioclient_mock.get('http://api.macvendors.com/b8:27:eb', - status=404) - - run_coroutine_threadsafe(device.set_vendor_for_mac(), - self.hass.loop).result() - - self.assertEqual(device.vendor, 'unknown') - - def test_mac_vendor_lookup_error(self): - """Prevent another lookup if failure during API call.""" - mac = 'B8:27:EB:00:00:00' - - device = device_tracker.Device( - self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name') - - with mock_aiohttp_client() as aioclient_mock: - aioclient_mock.get('http://api.macvendors.com/b8:27:eb', - status=500) - - run_coroutine_threadsafe(device.set_vendor_for_mac(), - self.hass.loop).result() - - self.assertEqual(device.vendor, 'unknown') - - def test_mac_vendor_lookup_exception(self): - """Prevent another lookup if exception during API call.""" - mac = 'B8:27:EB:00:00:00' - - device = device_tracker.Device( - self.hass, timedelta(seconds=180), True, 'test', mac, 'Test name') - - with mock_aiohttp_client() as aioclient_mock: - aioclient_mock.get('http://api.macvendors.com/b8:27:eb', - exc=asyncio.TimeoutError()) - - run_coroutine_threadsafe(device.set_vendor_for_mac(), - self.hass.loop).result() - - self.assertEqual(device.vendor, 'unknown') - - def test_mac_vendor_lookup_on_see(self): - """Test if macvendor is looked up when device is seen.""" - mac = 'B8:27:EB:00:00:00' - vendor_string = 'Raspberry Pi Foundation' - - tracker = device_tracker.DeviceTracker( - self.hass, timedelta(seconds=60), 0, {}, []) - - with mock_aiohttp_client() as aioclient_mock: - aioclient_mock.get('http://api.macvendors.com/b8:27:eb', - text=vendor_string) - - run_coroutine_threadsafe( - tracker.async_see(mac=mac), self.hass.loop).result() - assert aioclient_mock.call_count == 1, \ - 'No http request for macvendor made!' - self.assertEqual(tracker.devices['b827eb000000'].vendor, vendor_string) - @patch( 'homeassistant.components.device_tracker.DeviceTracker.see') @patch( @@ -463,7 +342,6 @@ class TestComponentsDeviceTracker(unittest.TestCase): 'entity_id': 'device_tracker.hello', 'host_name': 'hello', 'mac': 'MAC_1', - 'vendor': 'unknown', } # pylint: disable=invalid-name @@ -495,9 +373,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): timedelta(seconds=0)) assert len(config) == 0 - @patch('homeassistant.components.device_tracker.Device' - '.set_vendor_for_mac', return_value=mock_coro()) - def test_see_state(self, mock_set_vendor): + def test_see_state(self): """Test device tracker see records state correctly.""" self.assertTrue(setup_component(self.hass, device_tracker.DOMAIN, TEST_PLATFORM)) diff --git a/tests/conftest.py b/tests/conftest.py index 8f0ca787721..269d460ebb6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -123,7 +123,5 @@ def mock_device_tracker_conf(): ), patch( 'homeassistant.components.device_tracker.async_load_config', side_effect=lambda *args: mock_coro(devices) - ), patch('homeassistant.components.device_tracker' - '.Device.set_vendor_for_mac'): - + ): yield devices From 09dbd94467490e2d780181a70f00d709913400ee Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 10 Apr 2018 14:11:00 -0400 Subject: [PATCH 3/9] iglo hs color fix (#13808) --- homeassistant/components/light/iglo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/light/iglo.py b/homeassistant/components/light/iglo.py index 77e3972968c..f40dc2ce84e 100644 --- a/homeassistant/components/light/iglo.py +++ b/homeassistant/components/light/iglo.py @@ -79,7 +79,7 @@ class IGloLamp(Light): @property def hs_color(self): """Return the hs value.""" - return color_util.color_RGB_to_hsv(*self._lamp.state()['rgb']) + return color_util.color_RGB_to_hs(*self._lamp.state()['rgb']) @property def effect(self): From 234495ed0549cd33490ac41329fe26bf0099c645 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Thu, 12 Apr 2018 02:58:57 +0200 Subject: [PATCH 4/9] Fix too green color conversion (#13828) * Prepare test * Fix too green color conversion * Fix remaining tests --- homeassistant/util/color.py | 2 +- tests/components/light/test_demo.py | 8 ++-- tests/components/light/test_mqtt.py | 10 ++-- tests/components/light/test_mqtt_json.py | 2 +- tests/components/switch/test_flux.py | 58 ++++++++++++------------ tests/util/test_color.py | 20 ++++---- 6 files changed, 50 insertions(+), 50 deletions(-) diff --git a/homeassistant/util/color.py b/homeassistant/util/color.py index c2e4ac737e8..32e9df70a03 100644 --- a/homeassistant/util/color.py +++ b/homeassistant/util/color.py @@ -203,7 +203,7 @@ def color_RGB_to_xy_brightness( # Wide RGB D65 conversion formula X = R * 0.664511 + G * 0.154324 + B * 0.162028 - Y = R * 0.313881 + G * 0.668433 + B * 0.047685 + Y = R * 0.283881 + G * 0.668433 + B * 0.047685 Z = R * 0.000088 + G * 0.072310 + B * 0.986039 # Convert XYZ to xy diff --git a/tests/components/light/test_demo.py b/tests/components/light/test_demo.py index 963cda6abc4..8ba6385166b 100644 --- a/tests/components/light/test_demo.py +++ b/tests/components/light/test_demo.py @@ -29,15 +29,15 @@ class TestDemoLight(unittest.TestCase): def test_state_attributes(self): """Test light state attributes.""" light.turn_on( - self.hass, ENTITY_LIGHT, xy_color=(.4, .6), brightness=25) + self.hass, ENTITY_LIGHT, xy_color=(.4, .4), brightness=25) self.hass.block_till_done() state = self.hass.states.get(ENTITY_LIGHT) self.assertTrue(light.is_on(self.hass, ENTITY_LIGHT)) - self.assertEqual((0.378, 0.574), state.attributes.get( + self.assertEqual((0.4, 0.4), state.attributes.get( light.ATTR_XY_COLOR)) self.assertEqual(25, state.attributes.get(light.ATTR_BRIGHTNESS)) self.assertEqual( - (207, 255, 0), state.attributes.get(light.ATTR_RGB_COLOR)) + (255, 234, 164), state.attributes.get(light.ATTR_RGB_COLOR)) self.assertEqual('rainbow', state.attributes.get(light.ATTR_EFFECT)) light.turn_on( self.hass, ENTITY_LIGHT, rgb_color=(251, 253, 255), @@ -48,7 +48,7 @@ class TestDemoLight(unittest.TestCase): self.assertEqual( (250, 252, 255), state.attributes.get(light.ATTR_RGB_COLOR)) self.assertEqual( - (0.316, 0.333), state.attributes.get(light.ATTR_XY_COLOR)) + (0.319, 0.326), state.attributes.get(light.ATTR_XY_COLOR)) light.turn_on(self.hass, ENTITY_LIGHT, color_temp=400, effect='none') self.hass.block_till_done() state = self.hass.states.get(ENTITY_LIGHT) diff --git a/tests/components/light/test_mqtt.py b/tests/components/light/test_mqtt.py index 71fe77ef6be..7f7841b1a69 100644 --- a/tests/components/light/test_mqtt.py +++ b/tests/components/light/test_mqtt.py @@ -255,7 +255,7 @@ class TestLightMQTT(unittest.TestCase): self.assertEqual(150, state.attributes.get('color_temp')) self.assertEqual('none', state.attributes.get('effect')) self.assertEqual(255, state.attributes.get('white_value')) - self.assertEqual((0.32, 0.336), state.attributes.get('xy_color')) + self.assertEqual((0.323, 0.329), state.attributes.get('xy_color')) fire_mqtt_message(self.hass, 'test_light_rgb/status', '0') self.hass.block_till_done() @@ -311,7 +311,7 @@ class TestLightMQTT(unittest.TestCase): self.hass.block_till_done() light_state = self.hass.states.get('light.test') - self.assertEqual((0.652, 0.343), + self.assertEqual((0.672, 0.324), light_state.attributes.get('xy_color')) def test_brightness_controlling_scale(self): @@ -519,7 +519,7 @@ class TestLightMQTT(unittest.TestCase): mock.call('test_light_rgb/rgb/set', '50,50,50', 2, False), mock.call('test_light_rgb/brightness/set', 50, 2, False), mock.call('test_light_rgb/white_value/set', 80, 2, False), - mock.call('test_light_rgb/xy/set', '0.32,0.336', 2, False), + mock.call('test_light_rgb/xy/set', '0.323,0.329', 2, False), ], any_order=True) state = self.hass.states.get('light.test') @@ -527,7 +527,7 @@ class TestLightMQTT(unittest.TestCase): self.assertEqual((255, 255, 255), state.attributes['rgb_color']) self.assertEqual(50, state.attributes['brightness']) self.assertEqual(80, state.attributes['white_value']) - self.assertEqual((0.32, 0.336), state.attributes['xy_color']) + self.assertEqual((0.323, 0.329), state.attributes['xy_color']) def test_sending_mqtt_rgb_command_with_template(self): """Test the sending of RGB command with template.""" @@ -679,7 +679,7 @@ class TestLightMQTT(unittest.TestCase): state = self.hass.states.get('light.test') self.assertEqual(STATE_ON, state.state) - self.assertEqual((0.32, 0.336), state.attributes.get('xy_color')) + self.assertEqual((0.323, 0.329), state.attributes.get('xy_color')) def test_on_command_first(self): """Test on command being sent before brightness.""" diff --git a/tests/components/light/test_mqtt_json.py b/tests/components/light/test_mqtt_json.py index a183355fbb3..d6835b00be0 100644 --- a/tests/components/light/test_mqtt_json.py +++ b/tests/components/light/test_mqtt_json.py @@ -206,7 +206,7 @@ class TestLightMQTTJSON(unittest.TestCase): self.assertEqual(155, state.attributes.get('color_temp')) self.assertEqual('colorloop', state.attributes.get('effect')) self.assertEqual(150, state.attributes.get('white_value')) - self.assertEqual((0.32, 0.336), state.attributes.get('xy_color')) + self.assertEqual((0.323, 0.329), state.attributes.get('xy_color')) # Turn the light off fire_mqtt_message(self.hass, 'test_light_rgb', '{"state":"OFF"}') diff --git a/tests/components/switch/test_flux.py b/tests/components/switch/test_flux.py index a1e600860f9..c42061db958 100644 --- a/tests/components/switch/test_flux.py +++ b/tests/components/switch/test_flux.py @@ -154,8 +154,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 112) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.606, 0.379]) # pylint: disable=invalid-name def test_flux_after_sunrise_before_sunset(self): @@ -201,8 +201,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 173) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.439, 0.37]) # pylint: disable=invalid-name def test_flux_after_sunset_before_stop(self): @@ -249,8 +249,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 146) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.506, 0.385]) # pylint: disable=invalid-name def test_flux_after_stop_before_sunrise(self): @@ -296,8 +296,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 112) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.606, 0.379]) # pylint: disable=invalid-name def test_flux_with_custom_start_stop_times(self): @@ -345,8 +345,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 147) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.504, 0.385]) def test_flux_before_sunrise_stop_next_day(self): """Test the flux switch before sunrise. @@ -395,8 +395,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 112) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.606, 0.379]) # pylint: disable=invalid-name def test_flux_after_sunrise_before_sunset_stop_next_day(self): @@ -447,8 +447,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 173) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.439, 0.37]) # pylint: disable=invalid-name def test_flux_after_sunset_before_midnight_stop_next_day(self): @@ -498,8 +498,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.block_till_done() call = turn_on_calls[-1] - self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 126) - self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.574, 0.401]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 119) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.588, 0.386]) # pylint: disable=invalid-name def test_flux_after_sunset_after_midnight_stop_next_day(self): @@ -549,8 +549,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.block_till_done() call = turn_on_calls[-1] - self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 122) - self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.586, 0.397]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 114) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.601, 0.382]) # pylint: disable=invalid-name def test_flux_after_stop_before_sunrise_stop_next_day(self): @@ -600,8 +600,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 112) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.606, 0.379]) # pylint: disable=invalid-name def test_flux_with_custom_colortemps(self): @@ -650,8 +650,8 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 159) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.469, 0.378]) # pylint: disable=invalid-name def test_flux_with_custom_brightness(self): @@ -700,7 +700,7 @@ class TestSwitchFlux(unittest.TestCase): self.hass.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]) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.506, 0.385]) def test_flux_with_multiple_lights(self): """Test the flux switch with multiple light entities.""" @@ -762,14 +762,14 @@ class TestSwitchFlux(unittest.TestCase): fire_time_changed(self.hass, test_time) self.hass.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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 163) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.46, 0.376]) 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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 163) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.46, 0.376]) 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]) + self.assertEqual(call.data[light.ATTR_BRIGHTNESS], 163) + self.assertEqual(call.data[light.ATTR_XY_COLOR], [0.46, 0.376]) def test_flux_with_mired(self): """Test the flux switch´s mode mired.""" diff --git a/tests/util/test_color.py b/tests/util/test_color.py index b64cf0acf80..74ba72cd3d1 100644 --- a/tests/util/test_color.py +++ b/tests/util/test_color.py @@ -14,7 +14,7 @@ class TestColorUtil(unittest.TestCase): """Test color_RGB_to_xy_brightness.""" self.assertEqual((0, 0, 0), color_util.color_RGB_to_xy_brightness(0, 0, 0)) - self.assertEqual((0.32, 0.336, 255), + self.assertEqual((0.323, 0.329, 255), color_util.color_RGB_to_xy_brightness(255, 255, 255)) self.assertEqual((0.136, 0.04, 12), @@ -23,17 +23,17 @@ class TestColorUtil(unittest.TestCase): self.assertEqual((0.172, 0.747, 170), color_util.color_RGB_to_xy_brightness(0, 255, 0)) - self.assertEqual((0.679, 0.321, 80), + self.assertEqual((0.701, 0.299, 72), color_util.color_RGB_to_xy_brightness(255, 0, 0)) - self.assertEqual((0.679, 0.321, 17), + self.assertEqual((0.701, 0.299, 16), color_util.color_RGB_to_xy_brightness(128, 0, 0)) def test_color_RGB_to_xy(self): """Test color_RGB_to_xy.""" self.assertEqual((0, 0), color_util.color_RGB_to_xy(0, 0, 0)) - self.assertEqual((0.32, 0.336), + self.assertEqual((0.323, 0.329), color_util.color_RGB_to_xy(255, 255, 255)) self.assertEqual((0.136, 0.04), @@ -42,10 +42,10 @@ class TestColorUtil(unittest.TestCase): self.assertEqual((0.172, 0.747), color_util.color_RGB_to_xy(0, 255, 0)) - self.assertEqual((0.679, 0.321), + self.assertEqual((0.701, 0.299), color_util.color_RGB_to_xy(255, 0, 0)) - self.assertEqual((0.679, 0.321), + self.assertEqual((0.701, 0.299), color_util.color_RGB_to_xy(128, 0, 0)) def test_color_xy_brightness_to_RGB(self): @@ -155,16 +155,16 @@ class TestColorUtil(unittest.TestCase): self.assertEqual((0.151, 0.343), color_util.color_hs_to_xy(180, 100)) - self.assertEqual((0.352, 0.329), + self.assertEqual((0.356, 0.321), color_util.color_hs_to_xy(350, 12.5)) - self.assertEqual((0.228, 0.476), + self.assertEqual((0.229, 0.474), color_util.color_hs_to_xy(140, 50)) - self.assertEqual((0.465, 0.33), + self.assertEqual((0.474, 0.317), color_util.color_hs_to_xy(0, 40)) - self.assertEqual((0.32, 0.336), + self.assertEqual((0.323, 0.329), color_util.color_hs_to_xy(360, 0)) def test_rgb_hex_to_rgb_list(self): From f29904f1b56c2a486111374ee81d1898e1f04fd6 Mon Sep 17 00:00:00 2001 From: Marco Orovecchia Date: Thu, 12 Apr 2018 09:24:07 +0200 Subject: [PATCH 5/9] Rename from aurora light to nanoleaf_aurora (#13831) --- .coveragerc | 2 +- .../components/light/{aurora.py => nanoleaf_aurora.py} | 0 requirements_all.txt | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename homeassistant/components/light/{aurora.py => nanoleaf_aurora.py} (100%) diff --git a/.coveragerc b/.coveragerc index e9c69d137e2..48b45db347b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -407,7 +407,6 @@ omit = homeassistant/components/image_processing/seven_segments.py homeassistant/components/keyboard_remote.py homeassistant/components/keyboard.py - homeassistant/components/light/aurora.py homeassistant/components/light/avion.py homeassistant/components/light/blinksticklight.py homeassistant/components/light/blinkt.py @@ -422,6 +421,7 @@ omit = homeassistant/components/light/lifx.py homeassistant/components/light/limitlessled.py homeassistant/components/light/mystrom.py + homeassistant/components/light/nanoleaf_aurora.py homeassistant/components/light/osramlightify.py homeassistant/components/light/piglow.py homeassistant/components/light/rpi_gpio_pwm.py diff --git a/homeassistant/components/light/aurora.py b/homeassistant/components/light/nanoleaf_aurora.py similarity index 100% rename from homeassistant/components/light/aurora.py rename to homeassistant/components/light/nanoleaf_aurora.py diff --git a/requirements_all.txt b/requirements_all.txt index da2373443cb..8fe9c7e1c13 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -536,7 +536,7 @@ myusps==1.3.2 # homeassistant.components.media_player.nadtcp nad_receiver==0.0.9 -# homeassistant.components.light.aurora +# homeassistant.components.light.nanoleaf_aurora nanoleaf==0.4.1 # homeassistant.components.discovery From 9bd29589d50a7832a63378cdcaa5674d1fe4ef2c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 12 Apr 2018 08:22:07 -0400 Subject: [PATCH 6/9] Version bump to 0.67.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 815562b68c5..53c72a46c3f 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 67 -PATCH_VERSION = '0b0' +PATCH_VERSION = '0b1' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From b9306a5e521b855b6dddf4b92136a2c3c24b82e2 Mon Sep 17 00:00:00 2001 From: stephanerosi Date: Thu, 12 Apr 2018 15:44:56 +0200 Subject: [PATCH 7/9] Channel up/down for LiveTV and next/previous for other apps (#13829) --- homeassistant/components/media_player/webostv.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/webostv.py b/homeassistant/components/media_player/webostv.py index 860d69e22c3..ae9d259a47c 100644 --- a/homeassistant/components/media_player/webostv.py +++ b/homeassistant/components/media_player/webostv.py @@ -35,6 +35,7 @@ CONF_SOURCES = 'sources' CONF_ON_ACTION = 'turn_on_action' DEFAULT_NAME = 'LG webOS Smart TV' +LIVETV_APP_ID = 'com.webos.app.livetv' WEBOSTV_CONFIG_FILE = 'webostv.conf' @@ -357,8 +358,16 @@ class LgWebOSDevice(MediaPlayerDevice): def media_next_track(self): """Send next track command.""" - self._client.channel_up() + current_input = self._client.get_input() + if current_input == LIVETV_APP_ID: + self._client.channel_up() + else: + self._client.fast_forward() def media_previous_track(self): """Send the previous track command.""" - self._client.channel_down() + current_input = self._client.get_input() + if current_input == LIVETV_APP_ID: + self._client.channel_down() + else: + self._client.rewind() From 598f093bf0fecdefaa3d95d1ddae71317a05321e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 13 Apr 2018 07:32:05 -0400 Subject: [PATCH 8/9] Add authentication to error log endpoint (#13836) --- homeassistant/components/api.py | 16 +++++++++++++--- tests/components/test_api.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/api.py b/homeassistant/components/api.py index d272ebcb1c0..6fdf0c027a4 100644 --- a/homeassistant/components/api.py +++ b/homeassistant/components/api.py @@ -52,9 +52,8 @@ def setup(hass, config): hass.http.register_view(APIComponentsView) hass.http.register_view(APITemplateView) - log_path = hass.data.get(DATA_LOGGING, None) - if log_path: - hass.http.register_static_path(URL_API_ERROR_LOG, log_path, False) + if DATA_LOGGING in hass.data: + hass.http.register_view(APIErrorLog) return True @@ -356,6 +355,17 @@ class APITemplateView(HomeAssistantView): HTTP_BAD_REQUEST) +class APIErrorLog(HomeAssistantView): + """View to fetch the error log.""" + + url = URL_API_ERROR_LOG + name = "api:error_log" + + async def get(self, request): + """Retrieve API error log.""" + return await self.file(request, request.app['hass'].data[DATA_LOGGING]) + + @asyncio.coroutine def async_services_json(hass): """Generate services data to JSONify.""" diff --git a/tests/components/test_api.py b/tests/components/test_api.py index 6d5bec046f1..c9dae27d14c 100644 --- a/tests/components/test_api.py +++ b/tests/components/test_api.py @@ -2,13 +2,18 @@ # pylint: disable=protected-access import asyncio import json +from unittest.mock import patch +from aiohttp import web import pytest from homeassistant import const +from homeassistant.bootstrap import DATA_LOGGING import homeassistant.core as ha from homeassistant.setup import async_setup_component +from tests.common import mock_coro + @pytest.fixture def mock_api_client(hass, aiohttp_client): @@ -398,3 +403,31 @@ def _stream_next_event(stream): def _listen_count(hass): """Return number of event listeners.""" return sum(hass.bus.async_listeners().values()) + + +async def test_api_error_log(hass, aiohttp_client): + """Test if we can fetch the error log.""" + hass.data[DATA_LOGGING] = '/some/path' + await async_setup_component(hass, 'api', { + 'http': { + 'api_password': 'yolo' + } + }) + client = await aiohttp_client(hass.http.app) + + resp = await client.get(const.URL_API_ERROR_LOG) + # Verufy auth required + assert resp.status == 401 + + with patch( + 'homeassistant.components.http.view.HomeAssistantView.file', + return_value=mock_coro(web.Response(status=200, text='Hello')) + ) as mock_file: + resp = await client.get(const.URL_API_ERROR_LOG, headers={ + 'x-ha-access': 'yolo' + }) + + assert len(mock_file.mock_calls) == 1 + assert mock_file.mock_calls[0][1][1] == hass.data[DATA_LOGGING] + assert resp.status == 200 + assert await resp.text() == 'Hello' From c36c2be37218a1e97a6c4c1b9d3c5dd23e873c6b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 13 Apr 2018 16:52:50 -0400 Subject: [PATCH 9/9] Version bump to 0.67.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 53c72a46c3f..5364fe6951e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 67 -PATCH_VERSION = '0b1' +PATCH_VERSION = '0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3)