From e32f933cb685381cb48dc381db781725498ac421 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Jan 2017 15:13:59 -0800 Subject: [PATCH 001/157] Version bump to 0.38.0.dev0 --- homeassistant/const.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 2bde15106d2..9769649f008 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,8 +1,8 @@ # coding: utf-8 """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 -MINOR_VERSION = 37 -PATCH_VERSION = '0' +MINOR_VERSION = 38 +PATCH_VERSION = '0.dev0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 4, 2) From 5ae5d9b576eb1c769392ef7e47ff4c974c380ccb Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 29 Jan 2017 02:05:24 +0100 Subject: [PATCH 002/157] Upgrade rpi-rf to 0.9.6 (#5611) --- homeassistant/components/switch/rpi_rf.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/rpi_rf.py b/homeassistant/components/switch/rpi_rf.py index 361f4e0e934..866fea0df0b 100644 --- a/homeassistant/components/switch/rpi_rf.py +++ b/homeassistant/components/switch/rpi_rf.py @@ -12,7 +12,7 @@ from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) from homeassistant.const import (CONF_NAME, CONF_SWITCHES) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['rpi-rf==0.9.5'] +REQUIREMENTS = ['rpi-rf==0.9.6'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 2e983ea0f54..ab2c6b036ae 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -564,7 +564,7 @@ pyzabbix==0.7.4 radiotherm==1.2 # homeassistant.components.switch.rpi_rf -# rpi-rf==0.9.5 +# rpi-rf==0.9.6 # homeassistant.components.media_player.yamaha rxv==0.4.0 From a9325ea66395209f4c8dd402a27ebcf7d856b6be Mon Sep 17 00:00:00 2001 From: David-Leon Pohl Date: Sun, 29 Jan 2017 02:49:16 +0100 Subject: [PATCH 003/157] Fixes: Pilight Switch rejects alphanumeric IDs #5119 (#5601) --- homeassistant/components/switch/pilight.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/switch/pilight.py b/homeassistant/components/switch/pilight.py index 40c459dc189..b56367e80be 100644 --- a/homeassistant/components/switch/pilight.py +++ b/homeassistant/components/switch/pilight.py @@ -33,7 +33,7 @@ COMMAND_SCHEMA = vol.Schema({ vol.Optional('off'): cv.positive_int, vol.Optional(CONF_UNIT): cv.positive_int, vol.Optional(CONF_UNITCODE): cv.positive_int, - vol.Optional(CONF_ID): cv.positive_int, + vol.Optional(CONF_ID): vol.Any(cv.positive_int, cv.string), vol.Optional(CONF_STATE): cv.string, vol.Optional(CONF_SYSTEMCODE): cv.positive_int, }, extra=vol.ALLOW_EXTRA) From fddab7f2b44e4c0c7b39f2de7ca9ebff15c53765 Mon Sep 17 00:00:00 2001 From: Kyle Hendricks Date: Sun, 29 Jan 2017 03:37:59 -0500 Subject: [PATCH 004/157] Fixes the AsusWRT `ip neigh` regex to handle the possible IPv6 "router" flag (#5605) See the last line here: http://linux-ip.net/gl/ip-cref/ip-cref-node62.html --- homeassistant/components/device_tracker/asuswrt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/device_tracker/asuswrt.py b/homeassistant/components/device_tracker/asuswrt.py index 512ccba0b74..e18d560e653 100644 --- a/homeassistant/components/device_tracker/asuswrt.py +++ b/homeassistant/components/device_tracker/asuswrt.py @@ -76,6 +76,7 @@ _IP_NEIGH_REGEX = re.compile( r'\w+\s' r'\w+\s' r'(\w+\s(?P(([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))))?\s' + r'\s?(router)?' r'(?P(\w+))') _NVRAM_CMD = 'nvram get client_info_tmp' From 24f828d7eb12a8ab96d3c7d22f19fd33dbdbc1b2 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sun, 29 Jan 2017 12:59:13 +0100 Subject: [PATCH 005/157] Fix mysensors RGB and W light turn on (#5608) * RGBW light needs a white value defined. * Log error if V_RGB is not 6 characters and V_RGBW not 8 characters. --- homeassistant/components/light/mysensors.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/mysensors.py b/homeassistant/components/light/mysensors.py index 9a018192f63..7cb978bc10c 100644 --- a/homeassistant/components/light/mysensors.py +++ b/homeassistant/components/light/mysensors.py @@ -151,8 +151,14 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light): rgb = list(new_rgb) if rgb is None: return - if new_white is not None and hex_template == '%02x%02x%02x%02x': - rgb.append(new_white) + if hex_template == '%02x%02x%02x%02x': + if new_white is not None: + rgb.append(new_white) + elif white is not None: + rgb.append(white) + else: + _LOGGER.error('White value is not updated for RGBW light') + return hex_color = hex_template % tuple(rgb) if len(rgb) > 3: white = rgb.pop() @@ -236,11 +242,20 @@ class MySensorsLight(mysensors.MySensorsDeviceEntity, Light): """Update the controller with values from RGB or RGBW child.""" set_req = self.gateway.const.SetReq value = self._values[self.value_type] + if len(value) != 6 and len(value) != 8: + _LOGGER.error( + 'Wrong value %s for %s', value, set_req(self.value_type).name) + return color_list = rgb_hex_to_rgb_list(value) if set_req.V_LIGHT not in self._values and \ set_req.V_DIMMER not in self._values: self._state = max(color_list) > 0 if len(color_list) > 3: + if set_req.V_RGBW != self.value_type: + _LOGGER.error( + 'Wrong value %s for %s', + value, set_req(self.value_type).name) + return self._white = color_list.pop() self._rgb = color_list From 261ffbbfeaa0462c1abdbfffb3323b2588346004 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 29 Jan 2017 23:40:37 +0100 Subject: [PATCH 006/157] Move part of image_processing tests (#5634) * Move part of image_processing tests * fix lint --- .../components/image_processing/demo.py | 31 ------------ .../components/image_processing/test_init.py | 30 +++++------- .../image_processing/test.py | 49 +++++++++++++++++++ 3 files changed, 62 insertions(+), 48 deletions(-) create mode 100644 tests/testing_config/custom_components/image_processing/test.py diff --git a/homeassistant/components/image_processing/demo.py b/homeassistant/components/image_processing/demo.py index 62b1f8bee9b..97f0eace41d 100644 --- a/homeassistant/components/image_processing/demo.py +++ b/homeassistant/components/image_processing/demo.py @@ -5,7 +5,6 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/demo/ """ -from homeassistant.components.image_processing import ImageProcessingEntity from homeassistant.components.image_processing.openalpr_local import ( ImageProcessingAlprEntity) from homeassistant.components.image_processing.microsoft_face_identify import ( @@ -15,42 +14,12 @@ from homeassistant.components.image_processing.microsoft_face_identify import ( def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the demo image_processing platform.""" add_devices([ - DemoImageProcessing('camera.demo_camera', "Demo"), DemoImageProcessingAlpr('camera.demo_camera', "Demo Alpr"), DemoImageProcessingFaceIdentify( 'camera.demo_camera', "Demo Face Identify") ]) -class DemoImageProcessing(ImageProcessingEntity): - """Demo alpr image processing entity.""" - - def __init__(self, camera_entity, name): - """Initialize demo alpr.""" - self._name = name - self._camera = camera_entity - self._count = 0 - - @property - def camera_entity(self): - """Return camera entity id from process pictures.""" - return self._camera - - @property - def name(self): - """Return the name of the entity.""" - return self._name - - @property - def state(self): - """Return the state of the entity.""" - return self._count - - def process_image(self, image): - """Process image.""" - self._count += 1 - - class DemoImageProcessingAlpr(ImageProcessingAlprEntity): """Demo alpr image processing entity.""" diff --git a/tests/components/image_processing/test_init.py b/tests/components/image_processing/test_init.py index 77cfd19bf92..b13dcf48a72 100644 --- a/tests/components/image_processing/test_init.py +++ b/tests/components/image_processing/test_init.py @@ -61,17 +61,14 @@ class TestImageProcessing(object): config = { ip.DOMAIN: { - 'platform': 'demo' + 'platform': 'test' }, 'camera': { 'platform': 'demo' }, } - with patch('homeassistant.components.image_processing.demo.' - 'DemoImageProcessing.should_poll', - new_callable=PropertyMock(return_value=False)): - setup_component(self.hass, ip.DOMAIN, config) + setup_component(self.hass, ip.DOMAIN, config) state = self.hass.states.get('camera.demo_camera') self.url = "{0}{1}".format( @@ -84,33 +81,32 @@ class TestImageProcessing(object): @patch('homeassistant.components.camera.demo.DemoCamera.camera_image', autospec=True, return_value=b'Test') - @patch('homeassistant.components.image_processing.demo.' - 'DemoImageProcessing.process_image', autospec=True) - def test_get_image_from_camera(self, mock_process, mock_camera): + def test_get_image_from_camera(self, mock_camera): """Grab a image from camera entity.""" self.hass.start() - ip.scan(self.hass, entity_id='image_processing.demo') + ip.scan(self.hass, entity_id='image_processing.test') self.hass.block_till_done() - assert mock_camera.called - assert mock_process.called + state = self.hass.states.get('image_processing.test') - assert mock_process.call_args[0][1] == b'Test' + assert mock_camera.called + assert state.state == '1' + assert state.attributes['image'] == b'Test' @patch('homeassistant.components.camera.async_get_image', side_effect=HomeAssistantError()) - @patch('homeassistant.components.image_processing.demo.' - 'DemoImageProcessing.process_image', autospec=True) - def test_get_image_without_exists_camera(self, mock_process, mock_image): + def test_get_image_without_exists_camera(self, mock_image): """Try to get image without exists camera.""" self.hass.states.remove('camera.demo_camera') - ip.scan(self.hass, entity_id='image_processing.demo') + ip.scan(self.hass, entity_id='image_processing.test') self.hass.block_till_done() + state = self.hass.states.get('image_processing.test') + assert mock_image.called - assert not mock_process.called + assert state.state == '0' class TestImageProcessingAlpr(object): diff --git a/tests/testing_config/custom_components/image_processing/test.py b/tests/testing_config/custom_components/image_processing/test.py new file mode 100644 index 00000000000..0c538bc6781 --- /dev/null +++ b/tests/testing_config/custom_components/image_processing/test.py @@ -0,0 +1,49 @@ +"""Provide a mock image processing.""" + +from homeassistant.components.image_processing import ImageProcessingEntity + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the test image_processing platform.""" + add_devices([TestImageProcessing('camera.demo_camera', "Test")]) + + +class TestImageProcessing(ImageProcessingEntity): + """Test image processing entity.""" + + def __init__(self, camera_entity, name): + """Initialize test image processing.""" + self._name = name + self._camera = camera_entity + self._count = 0 + self._image = "" + + @property + def should_poll(self): + """Return True if entity has to be polled for state.""" + return False + + @property + def camera_entity(self): + """Return camera entity id from process pictures.""" + return self._camera + + @property + def name(self): + """Return the name of the entity.""" + return self._name + + @property + def state(self): + """Return the state of the entity.""" + return self._count + + @property + def device_state_attributes(self): + """Return device specific state attributes.""" + return {'image': self._image} + + def process_image(self, image): + """Process image.""" + self._image = image + self._count += 1 From 847a5a064d8a79b4e0d45b9e46b3a5482624a17f Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 30 Jan 2017 01:15:40 +0100 Subject: [PATCH 007/157] Aiohttp client unittest (#5635) * add test for cleanup * add test for mjpeg stream --- tests/helpers/test_aiohttp_client.py | 83 +++++++++++++++++++++++++++- tests/test_util/aiohttp.py | 25 ++++++++- 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/tests/helpers/test_aiohttp_client.py b/tests/helpers/test_aiohttp_client.py index 83e1275819b..4bca671059f 100644 --- a/tests/helpers/test_aiohttp_client.py +++ b/tests/helpers/test_aiohttp_client.py @@ -1,10 +1,13 @@ """Test the aiohttp client helper.""" +import asyncio import unittest import aiohttp +from homeassistant.bootstrap import setup_component import homeassistant.helpers.aiohttp_client as client -from homeassistant.util.async import run_callback_threadsafe +from homeassistant.util.async import ( + run_callback_threadsafe, run_coroutine_threadsafe) from tests.common import get_test_home_assistant @@ -79,3 +82,81 @@ class TestHelpersAiohttpClient(unittest.TestCase): assert isinstance( self.hass.data[client.DATA_CONNECTOR_NOTVERIFY], aiohttp.TCPConnector) + + def test_get_clientsession_cleanup(self): + """Test init clientsession with ssl.""" + run_callback_threadsafe(self.hass.loop, client.async_get_clientsession, + self.hass).result() + + assert isinstance( + self.hass.data[client.DATA_CLIENTSESSION], aiohttp.ClientSession) + assert isinstance( + self.hass.data[client.DATA_CONNECTOR], aiohttp.TCPConnector) + + run_coroutine_threadsafe( + client.async_cleanup_websession(self.hass), self.hass.loop + ).result() + + assert self.hass.data[client.DATA_CLIENTSESSION].closed + assert self.hass.data[client.DATA_CONNECTOR].closed + + +@asyncio.coroutine +def test_fetching_url(aioclient_mock, hass, test_client): + """Test that it fetches the given url.""" + aioclient_mock.get('http://example.com/mjpeg_stream', content=[ + b'Frame1', b'Frame2', b'Frame3' + ]) + + def setup_platform(): + """Setup the platform.""" + assert setup_component(hass, 'camera', { + 'camera': { + 'name': 'config_test', + 'platform': 'mjpeg', + 'mjpeg_url': 'http://example.com/mjpeg_stream', + }}) + + yield from hass.loop.run_in_executor(None, setup_platform) + + client = yield from test_client(hass.http.app) + + resp = yield from client.get('/api/camera_proxy_stream/camera.config_test') + + assert resp.status == 200 + assert aioclient_mock.call_count == 1 + body = yield from resp.text() + assert body == 'Frame3Frame2Frame1' + + aioclient_mock.clear_requests() + aioclient_mock.get( + 'http://example.com/mjpeg_stream', exc=asyncio.TimeoutError(), + content=[b'Frame1', b'Frame2', b'Frame3']) + + resp = yield from client.get('/api/camera_proxy_stream/camera.config_test') + + assert resp.status == 200 + body = yield from resp.text() + assert body == '' + + aioclient_mock.clear_requests() + aioclient_mock.get( + 'http://example.com/mjpeg_stream', exc=asyncio.CancelledError(), + content=[b'Frame1', b'Frame2', b'Frame3']) + + resp = yield from client.get('/api/camera_proxy_stream/camera.config_test') + + assert resp.status == 200 + body = yield from resp.text() + assert body == '' + + aioclient_mock.clear_requests() + aioclient_mock.get( + 'http://example.com/mjpeg_stream', exc=aiohttp.errors.ClientError(), + content=[b'Frame1', b'Frame2', b'Frame3']) + + resp = yield from client.get('/api/camera_proxy_stream/camera.config_test') + + assert resp.status == 200 + body = yield from resp.text() + assert body == '' diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index afe2f626de7..220eccca699 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -25,7 +25,7 @@ class AiohttpClientMocker: content=None, json=None, params=None, - headers=None, + headers={}, exc=None, cookies=None): """Mock a request.""" @@ -39,7 +39,7 @@ class AiohttpClientMocker: url = str(yarl.URL(url).with_query(params)) self._mocks.append(AiohttpClientMockResponse( - method, url, status, content, cookies, exc)) + method, url, status, content, cookies, exc, headers)) def get(self, *args, **kwargs): """Register a mock get request.""" @@ -91,7 +91,8 @@ class AiohttpClientMocker: class AiohttpClientMockResponse: """Mock Aiohttp client response.""" - def __init__(self, method, url, status, response, cookies=None, exc=None): + def __init__(self, method, url, status, response, cookies=None, exc=None, + headers={}): """Initialize a fake response.""" self.method = method self._url = url @@ -101,6 +102,7 @@ class AiohttpClientMockResponse: self.response = response self.exc = exc + self._headers = headers self._cookies = {} if cookies: @@ -109,6 +111,18 @@ class AiohttpClientMockResponse: cookie.value = data self._cookies[name] = cookie + if isinstance(response, list): + self.content = mock.MagicMock() + + @asyncio.coroutine + def read(*argc, **kwargs): + """Read content stream mock.""" + if self.response: + return self.response.pop() + return None + + self.content.read = read + def match_request(self, method, url, params=None): """Test if response answers request.""" if method.lower() != self.method.lower(): @@ -142,6 +156,11 @@ class AiohttpClientMockResponse: return True + @property + def headers(self): + """Return content_type.""" + return self._headers + @property def cookies(self): """Return dict of cookies.""" From b5047bbaad5b8cef3bcfe7d3be24faaeb995f355 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Jan 2017 18:36:48 -0800 Subject: [PATCH 008/157] Prioritize core.js (#5636) * Prioritize loading app core script * change app skeleton to be small --- .../components/frontend/templates/index.html | 51 +++++++------------ 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/frontend/templates/index.html b/homeassistant/components/frontend/templates/index.html index a13d640a579..4b1aa2033ea 100644 --- a/homeassistant/components/frontend/templates/index.html +++ b/homeassistant/components/frontend/templates/index.html @@ -9,6 +9,7 @@ + {% for panel in panels.values() -%} {% endfor -%} @@ -27,32 +28,25 @@ font-weight: 300; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; + margin: 0; + padding: 0; } - #ha-init-skeleton { - display: -webkit-flex; - display: flex; - -webkit-flex-direction: column; - -webkit-justify-content: center; - -webkit-align-items: center; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin-bottom: 83px; - font-family: Roboto, sans-serif; - font-size: 0pt; + #ha-init-skeleton::before { + display: block; + content: ""; + height: 48px; + background-color: #03A9F4; + } + + #ha-init-skeleton .message { transition: font-size 2s; + font-size: 0; + padding: 24px; } - #ha-init-skeleton paper-spinner { - height: 28px; - margin-top: 16px; + #ha-init-skeleton.error .message { + font-size: 16px; } #ha-init-skeleton a { @@ -60,15 +54,6 @@ text-decoration: none; font-weight: bold; } - - #ha-init-skeleton.error { - font-size: 16px; - } - - #ha-init-skeleton.error img, - #ha-init-skeleton.error paper-spinner { - display: none; - } #} From da4f402ebe852d5c5df347532ff4aa8182e6d5f2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Jan 2017 18:43:39 -0800 Subject: [PATCH 009/157] Update frontend (#5637) --- homeassistant/components/frontend/version.py | 20 +- .../components/frontend/www_static/core.js | 5 +- .../components/frontend/www_static/core.js.gz | Bin 33501 -> 2366 bytes .../frontend/www_static/frontend.html | 596 +++++++++++++++++- .../frontend/www_static/frontend.html.gz | Bin 132201 -> 137113 bytes .../www_static/home-assistant-polymer | 2 +- .../www_static/panels/ha-panel-dev-event.html | 2 +- .../panels/ha-panel-dev-event.html.gz | Bin 2719 -> 2733 bytes .../www_static/panels/ha-panel-dev-info.html | 2 +- .../panels/ha-panel-dev-info.html.gz | Bin 1341 -> 1239 bytes .../panels/ha-panel-dev-service.html | 2 +- .../panels/ha-panel-dev-service.html.gz | Bin 17910 -> 17861 bytes .../www_static/panels/ha-panel-dev-state.html | 2 +- .../panels/ha-panel-dev-state.html.gz | Bin 2880 -> 2890 bytes .../panels/ha-panel-dev-template.html | 2 +- .../panels/ha-panel-dev-template.html.gz | Bin 7366 -> 7368 bytes .../www_static/panels/ha-panel-history.html | 2 +- .../panels/ha-panel-history.html.gz | Bin 7373 -> 7297 bytes .../www_static/panels/ha-panel-iframe.html.gz | Bin 403 -> 403 bytes .../www_static/panels/ha-panel-logbook.html | 2 +- .../panels/ha-panel-logbook.html.gz | Bin 7904 -> 8010 bytes .../www_static/panels/ha-panel-map.html | 70 +- .../www_static/panels/ha-panel-map.html.gz | Bin 43843 -> 43798 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2329 -> 2338 bytes 25 files changed, 639 insertions(+), 70 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 12566881be8..40c89a9739d 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -1,18 +1,18 @@ """DO NOT MODIFY. Auto-generated by script/fingerprint_frontend.""" FINGERPRINTS = { - "core.js": "769f3fdd4e04b34bd66c7415743cf7b5", - "frontend.html": "d48d9a13f7d677e59b1d22c6db051207", + "core.js": "ff2b54b939ec12826a671d7630579724", + "frontend.html": "216d2fb1c6dc67ce85f2eefbdef0e9af", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", - "panels/ha-panel-dev-event.html": "f19840b9a6a46f57cb064b384e1353f5", - "panels/ha-panel-dev-info.html": "3765a371478cc66d677cf6dcc35267c6", - "panels/ha-panel-dev-service.html": "1d223225c1c75083738033895ea3e4b5", - "panels/ha-panel-dev-state.html": "8257d99a38358a150eafdb23fa6727e0", - "panels/ha-panel-dev-template.html": "cbb251acabd5e7431058ed507b70522b", - "panels/ha-panel-history.html": "9f2c72574fb6135beb1b381a4b8b7703", + "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", + "panels/ha-panel-dev-info.html": "27ea4123b8a5e0b789c903e22f119e52", + "panels/ha-panel-dev-service.html": "9f749635e518a4ca7991975bdefdb10a", + "panels/ha-panel-dev-state.html": "89731c71777c0b54bdc5e883ff8e70db", + "panels/ha-panel-dev-template.html": "97f77b69faef8c5975c09431912831cc", + "panels/ha-panel-history.html": "44e463708a54cb6243dea42d0e173c4a", "panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab", - "panels/ha-panel-logbook.html": "313f2ac57aaa5ad55933c9bbf8d8a1e5", - "panels/ha-panel-map.html": "13f120066c0b5faa2ce1db2c3f3cc486", + "panels/ha-panel-logbook.html": "0e8ea21b5f515a315b7952e396c84280", + "panels/ha-panel-map.html": "9c8c7924ba8f731560c9f4093835cc26", "websocket_test.html": "575de64b431fe11c3785bf96d7813450" } diff --git a/homeassistant/components/frontend/www_static/core.js b/homeassistant/components/frontend/www_static/core.js index f3679c981d7..2e8d6635872 100644 --- a/homeassistant/components/frontend/www_static/core.js +++ b/homeassistant/components/frontend/www_static/core.js @@ -1,4 +1 @@ -!(function(){"use strict";function t(t){return t&&t.__esModule?t.default:t}function e(t,e){return e={exports:{}},t(e,e.exports),e.exports}function n(t,e){var n=e.authToken,r=e.host;return xe({authToken:n,host:r,isValidating:!0,isInvalid:!1,errorMessage:""})}function r(){return Ve.getInitialState()}function i(t,e){var n=e.errorMessage;return t.withMutations((function(t){return t.set("isValidating",!1).set("isInvalid",!0).set("errorMessage",n)}))}function o(t,e){var n=e.authToken,r=e.host;return Fe({authToken:n,host:r})}function u(){return Ge.getInitialState()}function a(t,e){var n=e.rememberAuth;return n}function s(t){return t.withMutations((function(t){t.set("isStreaming",!0).set("hasError",!1)}))}function c(t){return t.withMutations((function(t){t.set("isStreaming",!1).set("hasError",!0)}))}function f(){return Xe.getInitialState()}function h(t){return{type:"auth",api_password:t}}function l(){return{type:"get_states"}}function p(){return{type:"get_config"}}function _(){return{type:"get_services"}}function d(){return{type:"get_panels"}}function v(t,e,n){var r={type:"call_service",domain:t,service:e};return n&&(r.service_data=n),r}function y(t){var e={type:"subscribe_events"};return t&&(e.event_type=t),e}function g(t){return{type:"unsubscribe_events",subscription:t}}function m(){return{type:"ping"}}function S(t,e){return{type:"result",success:!1,error:{code:t,message:e}}}function E(t){return t.result}function b(t,e){var n=new tn(t,e);return n.connect()}function I(t,e,n,r){void 0===r&&(r=null);var i=t.evaluate(Lo.authInfo),o=i.host+"/api/"+n;return new Promise(function(t,n){var u=new XMLHttpRequest;u.open(e,o,!0),u.setRequestHeader("X-HA-access",i.authToken),u.onload=function(){var e;try{e="application/json"===u.getResponseHeader("content-type")?JSON.parse(u.responseText):u.responseText}catch(t){e=u.responseText}u.status>199&&u.status<300?t(e):n(e)},u.onerror=function(){return n({})},r?(u.setRequestHeader("Content-Type","application/json;charset=UTF-8"),u.send(JSON.stringify(r))):u.send()})}function O(t,e){var n=e.model,r=e.result,i=e.params,o=n.entity;if(!r)return t;var u=i.replace?sn({}):t.get(o),a=Array.isArray(r)?r:[r],s=n.fromJSON||sn;return t.set(o,u.withMutations((function(t){for(var e=0;e6e4}function gt(t,e){var n=e.date;return n.toISOString()}function mt(){return Zr.getInitialState()}function St(t,e){var n=e.date,r=e.stateHistory;return 0===r.length?t.set(n,ti({})):t.withMutations((function(t){r.forEach((function(e){return t.setIn([n,e[0].entity_id],ti(e.map(On.fromJSON)))}))}))}function Et(){return ei.getInitialState()}function bt(t,e){var n=e.stateHistory;return t.withMutations((function(t){n.forEach((function(e){return t.set(e[0].entity_id,oi(e.map(On.fromJSON)))}))}))}function It(){return ui.getInitialState()}function Ot(t,e){var n=e.stateHistory,r=(new Date).getTime();return t.withMutations((function(t){n.forEach((function(e){return t.set(e[0].entity_id,r)})),history.length>1&&t.set(ci,r)}))}function wt(){return fi.getInitialState()}function Tt(t,e){t.dispatch(Xr.ENTITY_HISTORY_DATE_SELECTED,{date:e})}function At(t,e){void 0===e&&(e=null),t.dispatch(Xr.RECENT_ENTITY_HISTORY_FETCH_START,{});var n="history/period";return null!==e&&(n+="?filter_entity_id="+e),on(t,"GET",n).then((function(e){return t.dispatch(Xr.RECENT_ENTITY_HISTORY_FETCH_SUCCESS,{stateHistory:e})}),(function(){return t.dispatch(Xr.RECENT_ENTITY_HISTORY_FETCH_ERROR,{})}))}function Ct(t,e){return t.dispatch(Xr.ENTITY_HISTORY_FETCH_START,{date:e}),on(t,"GET","history/period/"+e).then((function(n){return t.dispatch(Xr.ENTITY_HISTORY_FETCH_SUCCESS,{date:e,stateHistory:n})}),(function(){return t.dispatch(Xr.ENTITY_HISTORY_FETCH_ERROR,{})}))}function Dt(t){var e=t.evaluate(pi);return Ct(t,e)}function zt(t){t.registerStores({currentEntityHistoryDate:Zr,entityHistory:ei,isLoadingEntityHistory:ri,recentEntityHistory:ui,recentEntityHistoryUpdated:fi})}function Rt(t){t.registerStores({moreInfoEntityId:Jr})}function Mt(t,e){var n=e.model,r=e.result,i=e.params;if(null===t||"entity"!==n.entity||!i.replace)return t;for(var o=0;o0?i=setTimeout(r,e-c):(i=null,n||(s=t.apply(u,o),i||(u=o=null)))}var i,o,u,a,s;null==e&&(e=100);var c=function(){u=this,o=arguments,a=(new Date).getTime();var c=n&&!i;return i||(i=setTimeout(r,e)),c&&(s=t.apply(u,o),u=o=null),s};return c.clear=function(){i&&(clearTimeout(i),i=null)},c}function Yt(t){var e=ho[t.hassId];e&&(e.scheduleHealthCheck.clear(),e.conn.close(),ho[t.hassId]=!1)}function Jt(t,e){void 0===e&&(e={});var n=e.syncOnInitialConnect;void 0===n&&(n=!0),Yt(t);var r=t.evaluate(Lo.authToken),i="https:"===document.location.protocol?"wss://":"ws://";i+=document.location.hostname,document.location.port&&(i+=":"+document.location.port),i+="/api/websocket",b(i,{authToken:r}).then((function(e){var r=Bt((function(){return e.ping()}),co);r(),e.socket.addEventListener("message",r),ho[t.hassId]={conn:e,scheduleHealthCheck:r},fo.forEach((function(n){return e.subscribeEvents(so.bind(null,t),n)})),t.batch((function(){t.dispatch(Ye.STREAM_START),n&&oo.fetchAll(t)})),e.addEventListener("disconnected",(function(){t.dispatch(Ye.STREAM_ERROR)})),e.addEventListener("ready",(function(){t.batch((function(){t.dispatch(Ye.STREAM_START),oo.fetchAll(t)}))}))}))}function Wt(t){t.registerStores({streamStatus:Xe})}function Xt(t,e,n){void 0===n&&(n={});var r=n.rememberAuth;void 0===r&&(r=!1);var i=n.host;void 0===i&&(i=""),t.dispatch(Ue.VALIDATING_AUTH_TOKEN,{authToken:e,host:i}),oo.fetchAll(t).then((function(){t.dispatch(Ue.VALID_AUTH_TOKEN,{authToken:e,host:i,rememberAuth:r}),yo.start(t,{syncOnInitialConnect:!1})}),(function(e){void 0===e&&(e={});var n=e.message;void 0===n&&(n=So),t.dispatch(Ue.INVALID_AUTH_TOKEN,{errorMessage:n})}))}function Qt(t){t.dispatch(Ue.LOG_OUT,{})}function Zt(t){t.registerStores({authAttempt:Ve,authCurrent:Ge,rememberAuth:Be})}function $t(){if(!("localStorage"in window))return{};var t=window.localStorage,e="___test";try{return t.setItem(e,e),t.removeItem(e),t}catch(t){return{}}}function te(){var t=new Ho({debug:!1});return t.hassId=xo++,t}function ee(t,e,n){Object.keys(n).forEach((function(r){var i=n[r];if("register"in i&&i.register(e),"getters"in i&&Object.defineProperty(t,r+"Getters",{value:i.getters,enumerable:!0}),"actions"in i){var o={};Object.getOwnPropertyNames(i.actions).forEach((function(t){"function"==typeof i.actions[t]&&Object.defineProperty(o,t,{value:i.actions[t].bind(null,e),enumerable:!0})})),Object.defineProperty(t,r+"Actions",{value:o,enumerable:!0})}}))}function ne(t,e){return Vo(t.attributes.entity_id.map((function(t){return e.get(t)})).filter((function(t){return!!t})))}function re(t){return on(t,"GET","error_log")}function ie(t,e){var n=e.date;return n.toISOString()}function oe(){return Wo.getInitialState()}function ue(t,e){var n=e.date,r=e.entries;return t.set(n,nu(r.map(tu.fromJSON)))}function ae(){return ru.getInitialState()}function se(t,e){var n=e.date;return t.set(n,(new Date).getTime())}function ce(){return uu.getInitialState()}function fe(t,e){t.dispatch(Yo.LOGBOOK_DATE_SELECTED,{date:e})}function he(t,e){t.dispatch(Yo.LOGBOOK_ENTRIES_FETCH_START,{date:e}),on(t,"GET","logbook/"+e).then((function(n){return t.dispatch(Yo.LOGBOOK_ENTRIES_FETCH_SUCCESS,{date:e,entries:n})}),(function(){return t.dispatch(Yo.LOGBOOK_ENTRIES_FETCH_ERROR,{})}))}function le(t){return!t||(new Date).getTime()-t>cu}function pe(t){t.registerStores({currentLogbookDate:Wo,isLoadingLogbookEntries:Qo,logbookEntries:ru,logbookEntriesUpdated:uu})}function _e(t){return t.set("active",!0)}function de(t){return t.set("active",!1)}function ve(){return Eu.getInitialState()}function ye(t){return navigator.serviceWorker.getRegistration().then((function(t){if(!t)throw new Error("No service worker registered.");return t.pushManager.subscribe({userVisibleOnly:!0})})).then((function(e){var n;return n=navigator.userAgent.toLowerCase().indexOf("firefox")>-1?"firefox":"chrome",on(t,"POST","notify.html5",{subscription:e,browser:n}).then((function(){return t.dispatch(gu.PUSH_NOTIFICATIONS_SUBSCRIBE,{})})).then((function(){return!0}))})).catch((function(e){var n;return n=e.message&&e.message.indexOf("gcm_sender_id")!==-1?"Please setup the notify.html5 platform.":"Notification registration failed.",console.error(e),qn.createNotification(t,n),!1}))}function ge(t){return navigator.serviceWorker.getRegistration().then((function(t){if(!t)throw new Error("No service worker registered");return t.pushManager.subscribe({userVisibleOnly:!0})})).then((function(e){return on(t,"DELETE","notify.html5",{subscription:e}).then((function(){return e.unsubscribe()})).then((function(){return t.dispatch(gu.PUSH_NOTIFICATIONS_UNSUBSCRIBE,{})})).then((function(){return!0}))})).catch((function(e){var n="Failed unsubscribing for push notifications.";return console.error(e),qn.createNotification(t,n),!1}))}function me(t){t.registerStores({pushNotifications:Eu})}function Se(t,e){return on(t,"POST","template",{template:e})}function Ee(t){return t.set("isListening",!0)}function be(t,e){var n=e.interimTranscript,r=e.finalTranscript;return t.withMutations((function(t){return t.set("isListening",!0).set("isTransmitting",!1).set("interimTranscript",n).set("finalTranscript",r)}))}function Ie(t,e){var n=e.finalTranscript;return t.withMutations((function(t){return t.set("isListening",!1).set("isTransmitting",!0).set("interimTranscript","").set("finalTranscript",n)}))}function Oe(){return Pu.getInitialState()}function we(){return Pu.getInitialState()}function Te(){return Pu.getInitialState()}function Ae(t){return Uu[t.hassId]}function Ce(t){var e=Ae(t);if(e){var n=e.finalTranscript||e.interimTranscript;t.dispatch(ju.VOICE_TRANSMITTING,{finalTranscript:n}),er.callService(t,"conversation","process",{text:n}).then((function(){t.dispatch(ju.VOICE_DONE)}),(function(){t.dispatch(ju.VOICE_ERROR)}))}}function De(t){var e=Ae(t);e&&(e.recognition.stop(),Uu[t.hassId]=!1)}function ze(t){Ce(t),De(t)}function Re(t){var e=ze.bind(null,t);e();var n=new webkitSpeechRecognition;Uu[t.hassId]={recognition:n,interimTranscript:"",finalTranscript:""},n.interimResults=!0,n.onstart=function(){return t.dispatch(ju.VOICE_START)},n.onerror=function(){return t.dispatch(ju.VOICE_ERROR)},n.onend=e,n.onresult=function(e){var n=Ae(t);if(n){for(var r="",i="",o=e.resultIndex;o>>0;if(""+n!==e||4294967295===n)return NaN;e=n}return e<0?_(t)+e:e}function v(){return!0}function y(t,e,n){return(0===t||void 0!==n&&t<=-n)&&(void 0===e||void 0!==n&&e>=n)}function g(t,e){return S(t,e,0)}function m(t,e){return S(t,e,e)}function S(t,e,n){return void 0===t?n:t<0?Math.max(0,e+t):void 0===e?t:Math.min(e,t)}function E(t){this.next=t}function b(t,e,n,r){var i=0===t?e:1===t?n:[e,n];return r?r.value=i:r={value:i,done:!1},r}function I(){return{value:void 0,done:!0}}function O(t){return!!A(t)}function w(t){return t&&"function"==typeof t.next}function T(t){var e=A(t);return e&&e.call(t)}function A(t){var e=t&&(In&&t[In]||t[On]);if("function"==typeof e)return e}function C(t){return t&&"number"==typeof t.length}function D(t){return null===t||void 0===t?U():o(t)?t.toSeq():V(t)}function z(t){return null===t||void 0===t?U().toKeyedSeq():o(t)?u(t)?t.toSeq():t.fromEntrySeq():H(t)}function R(t){return null===t||void 0===t?U():o(t)?u(t)?t.entrySeq():t.toIndexedSeq():x(t)}function M(t){return(null===t||void 0===t?U():o(t)?u(t)?t.entrySeq():t:x(t)).toSetSeq()}function L(t){this._array=t,this.size=t.length}function j(t){var e=Object.keys(t);this._object=t,this._keys=e,this.size=e.length}function k(t){this._iterable=t,this.size=t.length||t.size}function N(t){this._iterator=t,this._iteratorCache=[]}function P(t){return!(!t||!t[Tn])}function U(){return An||(An=new L([]))}function H(t){var e=Array.isArray(t)?new L(t).fromEntrySeq():w(t)?new N(t).fromEntrySeq():O(t)?new k(t).fromEntrySeq():"object"==typeof t?new j(t):void 0;if(!e)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+t);return e}function x(t){var e=q(t);if(!e)throw new TypeError("Expected Array or iterable object of values: "+t);return e}function V(t){var e=q(t)||"object"==typeof t&&new j(t);if(!e)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+t);return e}function q(t){return C(t)?new L(t):w(t)?new N(t):O(t)?new k(t):void 0}function F(t,e,n,r){var i=t._cache;if(i){for(var o=i.length-1,u=0;u<=o;u++){var a=i[n?o-u:u];if(e(a[1],r?a[0]:u,t)===!1)return u+1}return u}return t.__iterateUncached(e,n)}function G(t,e,n,r){var i=t._cache;if(i){var o=i.length-1,u=0;return new E(function(){var t=i[n?o-u:u];return u++>o?I():b(e,r?t[0]:u-1,t[1])})}return t.__iteratorUncached(e,n)}function K(t,e){return e?B(e,t,"",{"":t}):Y(t)}function B(t,e,n,r){return Array.isArray(e)?t.call(r,n,R(e).map((function(n,r){return B(t,n,r,e)}))):J(e)?t.call(r,n,z(e).map((function(n,r){return B(t,n,r,e)}))):e}function Y(t){return Array.isArray(t)?R(t).map(Y).toList():J(t)?z(t).map(Y).toMap():t}function J(t){return t&&(t.constructor===Object||void 0===t.constructor)}function W(t,e){if(t===e||t!==t&&e!==e)return!0;if(!t||!e)return!1;if("function"==typeof t.valueOf&&"function"==typeof e.valueOf){if(t=t.valueOf(),e=e.valueOf(),t===e||t!==t&&e!==e)return!0;if(!t||!e)return!1}return!("function"!=typeof t.equals||"function"!=typeof e.equals||!t.equals(e))}function X(t,e){if(t===e)return!0;if(!o(e)||void 0!==t.size&&void 0!==e.size&&t.size!==e.size||void 0!==t.__hash&&void 0!==e.__hash&&t.__hash!==e.__hash||u(t)!==u(e)||a(t)!==a(e)||c(t)!==c(e))return!1;if(0===t.size&&0===e.size)return!0;var n=!s(t);if(c(t)){var r=t.entries();return e.every((function(t,e){var i=r.next().value;return i&&W(i[1],t)&&(n||W(i[0],e))}))&&r.next().done}var i=!1;if(void 0===t.size)if(void 0===e.size)"function"==typeof t.cacheResult&&t.cacheResult();else{i=!0;var f=t;t=e,e=f}var h=!0,l=e.__iterate((function(e,r){if(n?!t.has(e):i?!W(e,t.get(r,yn)):!W(t.get(r,yn),e))return h=!1,!1}));return h&&t.size===l}function Q(t,e){if(!(this instanceof Q))return new Q(t,e);if(this._value=t,this.size=void 0===e?1/0:Math.max(0,e),0===this.size){if(Cn)return Cn;Cn=this}}function Z(t,e){if(!t)throw new Error(e)}function $(t,e,n){if(!(this instanceof $))return new $(t,e,n);if(Z(0!==n,"Cannot step a Range by 0"),t=t||0,void 0===e&&(e=1/0),n=void 0===n?1:Math.abs(n),e>>1&1073741824|3221225471&t}function ot(t){if(t===!1||null===t||void 0===t)return 0;if("function"==typeof t.valueOf&&(t=t.valueOf(),t===!1||null===t||void 0===t))return 0;if(t===!0)return 1;var e=typeof t;if("number"===e){if(t!==t||t===1/0)return 0;var n=0|t;for(n!==t&&(n^=4294967295*t);t>4294967295;)t/=4294967295,n^=t;return it(n)}if("string"===e)return t.length>Pn?ut(t):at(t);if("function"==typeof t.hashCode)return t.hashCode();if("object"===e)return st(t);if("function"==typeof t.toString)return at(t.toString());throw new Error("Value type "+e+" cannot be hashed.")}function ut(t){var e=xn[t];return void 0===e&&(e=at(t),Hn===Un&&(Hn=0,xn={}),Hn++,xn[t]=e),e}function at(t){for(var e=0,n=0;n0)switch(t.nodeType){case 1:return t.uniqueID;case 9:return t.documentElement&&t.documentElement.uniqueID}}function ft(t){Z(t!==1/0,"Cannot perform this action with an infinite size.")}function ht(t){return null===t||void 0===t?bt():lt(t)&&!c(t)?t:bt().withMutations((function(e){var r=n(t);ft(r.size),r.forEach((function(t,n){return e.set(n,t)}))}))}function lt(t){return!(!t||!t[Vn])}function pt(t,e){this.ownerID=t,this.entries=e}function _t(t,e,n){this.ownerID=t,this.bitmap=e,this.nodes=n}function dt(t,e,n){this.ownerID=t,this.count=e,this.nodes=n}function vt(t,e,n){this.ownerID=t,this.keyHash=e,this.entries=n}function yt(t,e,n){this.ownerID=t,this.keyHash=e,this.entry=n}function gt(t,e,n){this._type=e,this._reverse=n,this._stack=t._root&&St(t._root)}function mt(t,e){return b(t,e[0],e[1])}function St(t,e){return{node:t,index:0,__prev:e}}function Et(t,e,n,r){var i=Object.create(qn);return i.size=t,i._root=e,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function bt(){return Fn||(Fn=Et(0))}function It(t,e,n){var r,i;if(t._root){var o=f(gn),u=f(mn);if(r=Ot(t._root,t.__ownerID,0,void 0,e,n,o,u),!u.value)return t;i=t.size+(o.value?n===yn?-1:1:0)}else{if(n===yn)return t;i=1,r=new pt(t.__ownerID,[[e,n]])}return t.__ownerID?(t.size=i,t._root=r,t.__hash=void 0,t.__altered=!0,t):r?Et(i,r):bt()}function Ot(t,e,n,r,i,o,u,a){return t?t.update(e,n,r,i,o,u,a):o===yn?t:(h(a),h(u),new yt(e,r,[i,o]))}function wt(t){return t.constructor===yt||t.constructor===vt}function Tt(t,e,n,r,i){if(t.keyHash===r)return new vt(e,r,[t.entry,i]);var o,u=(0===n?t.keyHash:t.keyHash>>>n)&vn,a=(0===n?r:r>>>n)&vn,s=u===a?[Tt(t,e,n+_n,r,i)]:(o=new yt(e,r,i),u>>=1)u[a]=1&n?e[o++]:void 0;return u[r]=i,new dt(t,o+1,u)}function zt(t,e,r){for(var i=[],u=0;u>1&1431655765,t=(858993459&t)+(t>>2&858993459),t=t+(t>>4)&252645135,t+=t>>8,t+=t>>16,127&t}function Nt(t,e,n,r){var i=r?t:p(t);return i[e]=n,i}function Pt(t,e,n,r){var i=t.length+1;if(r&&e+1===i)return t[e]=n,t;for(var o=new Array(i),u=0,a=0;a0&&io?0:o-n,c=u-n;return c>dn&&(c=dn),function(){if(i===c)return Xn;var t=e?--c:i++;return r&&r[t]}}function i(t,r,i){var a,s=t&&t.array,c=i>o?0:o-i>>r,f=(u-i>>r)+1;return f>dn&&(f=dn),function(){for(;;){if(a){var t=a();if(t!==Xn)return t;a=null}if(c===f)return Xn;var o=e?--f:c++;a=n(s&&s[o],r-_n,i+(o<=t.size||e<0)return t.withMutations((function(t){e<0?Wt(t,e).set(0,n):Wt(t,0,e+1).set(e,n)}));e+=t._origin;var r=t._tail,i=t._root,o=f(mn);return e>=Qt(t._capacity)?r=Bt(r,t.__ownerID,0,e,n,o):i=Bt(i,t.__ownerID,t._level,e,n,o),o.value?t.__ownerID?(t._root=i,t._tail=r,t.__hash=void 0,t.__altered=!0,t):Ft(t._origin,t._capacity,t._level,i,r):t}function Bt(t,e,n,r,i,o){var u=r>>>n&vn,a=t&&u0){var c=t&&t.array[u],f=Bt(c,e,n-_n,r,i,o);return f===c?t:(s=Yt(t,e),s.array[u]=f,s)}return a&&t.array[u]===i?t:(h(o),s=Yt(t,e),void 0===i&&u===s.array.length-1?s.array.pop():s.array[u]=i,s)}function Yt(t,e){return e&&t&&e===t.ownerID?t:new Vt(t?t.array.slice():[],e)}function Jt(t,e){if(e>=Qt(t._capacity))return t._tail;if(e<1<0;)n=n.array[e>>>r&vn],r-=_n;return n}}function Wt(t,e,n){void 0!==e&&(e|=0),void 0!==n&&(n|=0);var r=t.__ownerID||new l,i=t._origin,o=t._capacity,u=i+e,a=void 0===n?o:n<0?o+n:i+n;if(u===i&&a===o)return t;if(u>=a)return t.clear();for(var s=t._level,c=t._root,f=0;u+f<0;)c=new Vt(c&&c.array.length?[void 0,c]:[],r),s+=_n,f+=1<=1<h?new Vt([],r):_;if(_&&p>h&&u_n;y-=_n){var g=h>>>y&vn;v=v.array[g]=Yt(v.array[g],r)}v.array[h>>>_n&vn]=_}if(a=p)u-=p,a-=p,s=_n,c=null,d=d&&d.removeBefore(r,0,u);else if(u>i||p>>s&vn;if(m!==p>>>s&vn)break;m&&(f+=(1<i&&(c=c.removeBefore(r,s,u-f)),c&&pu&&(u=c.size),o(s)||(c=c.map((function(t){return K(t)}))),i.push(c)}return u>t.size&&(t=t.setSize(u)),Lt(t,e,i)}function Qt(t){return t>>_n<<_n}function Zt(t){return null===t||void 0===t?ee():$t(t)?t:ee().withMutations((function(e){var r=n(t);ft(r.size),r.forEach((function(t,n){return e.set(n,t)}))}))}function $t(t){return lt(t)&&c(t)}function te(t,e,n,r){var i=Object.create(Zt.prototype);return i.size=t?t.size:0,i._map=t,i._list=e,i.__ownerID=n,i.__hash=r,i}function ee(){return Qn||(Qn=te(bt(),Gt()))}function ne(t,e,n){var r,i,o=t._map,u=t._list,a=o.get(e),s=void 0!==a;if(n===yn){if(!s)return t;u.size>=dn&&u.size>=2*o.size?(i=u.filter((function(t,e){return void 0!==t&&a!==e})),r=i.toKeyedSeq().map((function(t){return t[0]})).flip().toMap(),t.__ownerID&&(r.__ownerID=i.__ownerID=t.__ownerID)):(r=o.remove(e),i=a===u.size-1?u.pop():u.set(a,void 0))}else if(s){if(n===u.get(a)[1])return t;r=o,i=u.set(a,[e,n])}else r=o.set(e,u.size),i=u.set(u.size,[e,n]);return t.__ownerID?(t.size=r.size,t._map=r,t._list=i,t.__hash=void 0,t):te(r,i)}function re(t,e){this._iter=t,this._useKeys=e,this.size=t.size}function ie(t){this._iter=t,this.size=t.size}function oe(t){this._iter=t,this.size=t.size}function ue(t){this._iter=t,this.size=t.size}function ae(t){var e=Ce(t);return e._iter=t,e.size=t.size,e.flip=function(){return t},e.reverse=function(){var e=t.reverse.apply(this);return e.flip=function(){return t.reverse()},e},e.has=function(e){return t.includes(e)},e.includes=function(e){return t.has(e)},e.cacheResult=De,e.__iterateUncached=function(e,n){var r=this;return t.__iterate((function(t,n){return e(n,t,r)!==!1}),n)},e.__iteratorUncached=function(e,n){if(e===bn){var r=t.__iterator(e,n);return new E(function(){var t=r.next();if(!t.done){var e=t.value[0];t.value[0]=t.value[1],t.value[1]=e}return t})}return t.__iterator(e===En?Sn:En,n)},e}function se(t,e,n){var r=Ce(t);return r.size=t.size,r.has=function(e){return t.has(e)},r.get=function(r,i){var o=t.get(r,yn);return o===yn?i:e.call(n,o,r,t)},r.__iterateUncached=function(r,i){var o=this;return t.__iterate((function(t,i,u){return r(e.call(n,t,i,u),i,o)!==!1}),i)},r.__iteratorUncached=function(r,i){var o=t.__iterator(bn,i);return new E(function(){var i=o.next();if(i.done)return i;var u=i.value,a=u[0];return b(r,a,e.call(n,u[1],a,t),i)})},r}function ce(t,e){var n=Ce(t);return n._iter=t,n.size=t.size,n.reverse=function(){return t},t.flip&&(n.flip=function(){var e=ae(t);return e.reverse=function(){return t.flip()},e}),n.get=function(n,r){return t.get(e?n:-1-n,r)},n.has=function(n){return t.has(e?n:-1-n)},n.includes=function(e){return t.includes(e)},n.cacheResult=De,n.__iterate=function(e,n){var r=this;return t.__iterate((function(t,n){return e(t,n,r)}),!n)},n.__iterator=function(e,n){return t.__iterator(e,!n)},n}function fe(t,e,n,r){var i=Ce(t);return r&&(i.has=function(r){var i=t.get(r,yn);return i!==yn&&!!e.call(n,i,r,t)},i.get=function(r,i){var o=t.get(r,yn);return o!==yn&&e.call(n,o,r,t)?o:i}),i.__iterateUncached=function(i,o){var u=this,a=0;return t.__iterate((function(t,o,s){if(e.call(n,t,o,s))return a++,i(t,r?o:a-1,u)}),o),a},i.__iteratorUncached=function(i,o){var u=t.__iterator(bn,o),a=0;return new E(function(){for(;;){var o=u.next();if(o.done)return o;var s=o.value,c=s[0],f=s[1];if(e.call(n,f,c,t))return b(i,r?c:a++,f,o)}})},i}function he(t,e,n){var r=ht().asMutable();return t.__iterate((function(i,o){r.update(e.call(n,i,o,t),0,(function(t){return t+1}))})),r.asImmutable()}function le(t,e,n){var r=u(t),i=(c(t)?Zt():ht()).asMutable();t.__iterate((function(o,u){i.update(e.call(n,o,u,t),(function(t){return t=t||[],t.push(r?[u,o]:o),t}))}));var o=Ae(t);return i.map((function(e){return Oe(t,o(e))}))}function pe(t,e,n,r){var i=t.size;if(void 0!==e&&(e|=0),void 0!==n&&(n===1/0?n=i:n|=0),y(e,n,i))return t;var o=g(e,i),u=m(n,i);if(o!==o||u!==u)return pe(t.toSeq().cacheResult(),e,n,r);var a,s=u-o;s===s&&(a=s<0?0:s);var c=Ce(t);return c.size=0===a?a:t.size&&a||void 0,!r&&P(t)&&a>=0&&(c.get=function(e,n){return e=d(this,e),e>=0&&ea)return I();var t=i.next();return r||e===En?t:e===Sn?b(e,s-1,void 0,t):b(e,s-1,t.value[1],t)})},c}function _e(t,e,n){var r=Ce(t);return r.__iterateUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterate(r,i);var u=0;return t.__iterate((function(t,i,a){return e.call(n,t,i,a)&&++u&&r(t,i,o)})),u},r.__iteratorUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterator(r,i);var u=t.__iterator(bn,i),a=!0;return new E(function(){if(!a)return I();var t=u.next();if(t.done)return t;var i=t.value,s=i[0],c=i[1];return e.call(n,c,s,o)?r===bn?t:b(r,s,c,t):(a=!1,I())})},r}function de(t,e,n,r){var i=Ce(t);return i.__iterateUncached=function(i,o){var u=this;if(o)return this.cacheResult().__iterate(i,o);var a=!0,s=0;return t.__iterate((function(t,o,c){if(!a||!(a=e.call(n,t,o,c)))return s++,i(t,r?o:s-1,u)})),s},i.__iteratorUncached=function(i,o){var u=this;if(o)return this.cacheResult().__iterator(i,o);var a=t.__iterator(bn,o),s=!0,c=0;return new E(function(){var t,o,f;do{if(t=a.next(),t.done)return r||i===En?t:i===Sn?b(i,c++,void 0,t):b(i,c++,t.value[1],t);var h=t.value;o=h[0],f=h[1],s&&(s=e.call(n,f,o,u))}while(s);return i===bn?t:b(i,o,f,t)})},i}function ve(t,e){var r=u(t),i=[t].concat(e).map((function(t){return o(t)?r&&(t=n(t)):t=r?H(t):x(Array.isArray(t)?t:[t]),t})).filter((function(t){return 0!==t.size}));if(0===i.length)return t;if(1===i.length){var s=i[0];if(s===t||r&&u(s)||a(t)&&a(s))return s}var c=new L(i);return r?c=c.toKeyedSeq():a(t)||(c=c.toSetSeq()),c=c.flatten(!0),c.size=i.reduce((function(t,e){if(void 0!==t){var n=e.size;if(void 0!==n)return t+n}}),0),c}function ye(t,e,n){var r=Ce(t);return r.__iterateUncached=function(r,i){function u(t,c){var f=this;t.__iterate((function(t,i){return(!e||c0}function Ie(t,n,r){var i=Ce(t);return i.size=new L(r).map((function(t){return t.size})).min(),i.__iterate=function(t,e){for(var n,r=this,i=this.__iterator(En,e),o=0;!(n=i.next()).done&&t(n.value,o++,r)!==!1;);return o},i.__iteratorUncached=function(t,i){var o=r.map((function(t){return t=e(t),T(i?t.reverse():t)})),u=0,a=!1;return new E(function(){var e;return a||(e=o.map((function(t){return t.next()})),a=e.some((function(t){return t.done}))),a?I():b(t,u++,n.apply(null,e.map((function(t){return t.value}))))})},i}function Oe(t,e){return P(t)?e:t.constructor(e)}function we(t){if(t!==Object(t))throw new TypeError("Expected [K, V] tuple: "+t)}function Te(t){return ft(t.size),_(t)}function Ae(t){return u(t)?n:a(t)?r:i}function Ce(t){return Object.create((u(t)?z:a(t)?R:M).prototype)}function De(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):D.prototype.cacheResult.call(this)}function ze(t,e){return t>e?1:te?-1:0}function on(t){if(t.size===1/0)return 0;var e=c(t),n=u(t),r=e?1:0,i=t.__iterate(n?e?function(t,e){r=31*r+an(ot(t),ot(e))|0}:function(t,e){r=r+an(ot(t),ot(e))|0}:e?function(t){r=31*r+ot(t)|0}:function(t){r=r+ot(t)|0});return un(i,r)}function un(t,e){return e=Rn(e,3432918353),e=Rn(e<<15|e>>>-15,461845907),e=Rn(e<<13|e>>>-13,5),e=(e+3864292196|0)^t,e=Rn(e^e>>>16,2246822507),e=Rn(e^e>>>13,3266489909),e=it(e^e>>>16)}function an(t,e){return t^e+2654435769+(t<<6)+(t>>2)|0}var sn=Array.prototype.slice;t(n,e),t(r,e),t(i,e),e.isIterable=o,e.isKeyed=u,e.isIndexed=a,e.isAssociative=s,e.isOrdered=c,e.Keyed=n,e.Indexed=r,e.Set=i;var cn="@@__IMMUTABLE_ITERABLE__@@",fn="@@__IMMUTABLE_KEYED__@@",hn="@@__IMMUTABLE_INDEXED__@@",ln="@@__IMMUTABLE_ORDERED__@@",pn="delete",_n=5,dn=1<<_n,vn=dn-1,yn={},gn={value:!1},mn={value:!1},Sn=0,En=1,bn=2,In="function"==typeof Symbol&&Symbol.iterator,On="@@iterator",wn=In||On;E.prototype.toString=function(){return"[Iterator]"},E.KEYS=Sn,E.VALUES=En,E.ENTRIES=bn,E.prototype.inspect=E.prototype.toSource=function(){return this.toString()},E.prototype[wn]=function(){return this},t(D,e),D.of=function(){return D(arguments)},D.prototype.toSeq=function(){return this},D.prototype.toString=function(){return this.__toString("Seq {","}")},D.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},D.prototype.__iterate=function(t,e){return F(this,t,e,!0)},D.prototype.__iterator=function(t,e){return G(this,t,e,!0)},t(z,D),z.prototype.toKeyedSeq=function(){return this},t(R,D),R.of=function(){return R(arguments)},R.prototype.toIndexedSeq=function(){return this},R.prototype.toString=function(){return this.__toString("Seq [","]")},R.prototype.__iterate=function(t,e){return F(this,t,e,!1)},R.prototype.__iterator=function(t,e){return G(this,t,e,!1)},t(M,D),M.of=function(){return M(arguments)},M.prototype.toSetSeq=function(){return this},D.isSeq=P,D.Keyed=z,D.Set=M,D.Indexed=R;var Tn="@@__IMMUTABLE_SEQ__@@";D.prototype[Tn]=!0,t(L,R),L.prototype.get=function(t,e){return this.has(t)?this._array[d(this,t)]:e},L.prototype.__iterate=function(t,e){for(var n=this,r=this._array,i=r.length-1,o=0;o<=i;o++)if(t(r[e?i-o:o],o,n)===!1)return o+1;return o},L.prototype.__iterator=function(t,e){var n=this._array,r=n.length-1,i=0;return new E(function(){return i>r?I():b(t,i,n[e?r-i++:i++])})},t(j,z),j.prototype.get=function(t,e){return void 0===e||this.has(t)?this._object[t]:e},j.prototype.has=function(t){return this._object.hasOwnProperty(t)},j.prototype.__iterate=function(t,e){for(var n=this,r=this._object,i=this._keys,o=i.length-1,u=0;u<=o;u++){var a=i[e?o-u:u];if(t(r[a],a,n)===!1)return u+1}return u},j.prototype.__iterator=function(t,e){var n=this._object,r=this._keys,i=r.length-1,o=0;return new E(function(){var u=r[e?i-o:o];return o++>i?I():b(t,u,n[u])})},j.prototype[ln]=!0,t(k,R),k.prototype.__iterateUncached=function(t,e){var n=this;if(e)return this.cacheResult().__iterate(t,e);var r=this._iterable,i=T(r),o=0;if(w(i))for(var u;!(u=i.next()).done&&t(u.value,o++,n)!==!1;);return o},k.prototype.__iteratorUncached=function(t,e){if(e)return this.cacheResult().__iterator(t,e);var n=this._iterable,r=T(n);if(!w(r))return new E(I);var i=0;return new E(function(){var e=r.next();return e.done?e:b(t,i++,e.value)})},t(N,R),N.prototype.__iterateUncached=function(t,e){var n=this;if(e)return this.cacheResult().__iterate(t,e);for(var r=this._iterator,i=this._iteratorCache,o=0;o=r.length){var e=n.next();if(e.done)return e;r[i]=e.value}return b(t,i,r[i++])})};var An;t(Q,R),Q.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},Q.prototype.get=function(t,e){return this.has(t)?this._value:e},Q.prototype.includes=function(t){return W(this._value,t)},Q.prototype.slice=function(t,e){var n=this.size;return y(t,e,n)?this:new Q(this._value,m(e,n)-g(t,n))},Q.prototype.reverse=function(){return this},Q.prototype.indexOf=function(t){return W(this._value,t)?0:-1},Q.prototype.lastIndexOf=function(t){return W(this._value,t)?this.size:-1},Q.prototype.__iterate=function(t,e){for(var n=this,r=0;r=0&&e=0&&nn?I():b(t,o++,u)})},$.prototype.equals=function(t){return t instanceof $?this._start===t._start&&this._end===t._end&&this._step===t._step:X(this,t)};var Dn;t(tt,e),t(et,tt),t(nt,tt),t(rt,tt),tt.Keyed=et,tt.Indexed=nt,tt.Set=rt;var zn,Rn="function"==typeof Math.imul&&Math.imul(4294967295,2)===-2?Math.imul:function(t,e){t|=0,e|=0;var n=65535&t,r=65535&e;return n*r+((t>>>16)*r+n*(e>>>16)<<16>>>0)|0},Mn=Object.isExtensible,Ln=(function(){try{return Object.defineProperty({},"@",{}),!0}catch(t){return!1}})(),jn="function"==typeof WeakMap;jn&&(zn=new WeakMap);var kn=0,Nn="__immutablehash__";"function"==typeof Symbol&&(Nn=Symbol(Nn));var Pn=16,Un=255,Hn=0,xn={};t(ht,et),ht.of=function(){var t=sn.call(arguments,0);return bt().withMutations((function(e){for(var n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}}))},ht.prototype.toString=function(){return this.__toString("Map {","}")},ht.prototype.get=function(t,e){return this._root?this._root.get(0,void 0,t,e):e},ht.prototype.set=function(t,e){return It(this,t,e)},ht.prototype.setIn=function(t,e){return this.updateIn(t,yn,(function(){return e}))},ht.prototype.remove=function(t){return It(this,t,yn)},ht.prototype.deleteIn=function(t){return this.updateIn(t,(function(){return yn}))},ht.prototype.update=function(t,e,n){return 1===arguments.length?t(this):this.updateIn([t],e,n)},ht.prototype.updateIn=function(t,e,n){n||(n=e,e=void 0);var r=jt(this,Re(t),e,n);return r===yn?void 0:r},ht.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):bt()},ht.prototype.merge=function(){return zt(this,void 0,arguments)},ht.prototype.mergeWith=function(t){var e=sn.call(arguments,1);return zt(this,t,e)},ht.prototype.mergeIn=function(t){var e=sn.call(arguments,1);return this.updateIn(t,bt(),(function(t){return"function"==typeof t.merge?t.merge.apply(t,e):e[e.length-1]}))},ht.prototype.mergeDeep=function(){return zt(this,Rt,arguments)},ht.prototype.mergeDeepWith=function(t){var e=sn.call(arguments,1);return zt(this,Mt(t),e)},ht.prototype.mergeDeepIn=function(t){var e=sn.call(arguments,1);return this.updateIn(t,bt(),(function(t){return"function"==typeof t.mergeDeep?t.mergeDeep.apply(t,e):e[e.length-1]}))},ht.prototype.sort=function(t){return Zt(Se(this,t))},ht.prototype.sortBy=function(t,e){return Zt(Se(this,e,t))},ht.prototype.withMutations=function(t){var e=this.asMutable();return t(e),e.wasAltered()?e.__ensureOwner(this.__ownerID):this},ht.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new l)},ht.prototype.asImmutable=function(){return this.__ensureOwner()},ht.prototype.wasAltered=function(){return this.__altered},ht.prototype.__iterator=function(t,e){return new gt(this,t,e)},ht.prototype.__iterate=function(t,e){var n=this,r=0;return this._root&&this._root.iterate((function(e){return r++,t(e[1],e[0],n)}),e),r},ht.prototype.__ensureOwner=function(t){return t===this.__ownerID?this:t?Et(this.size,this._root,t,this.__hash):(this.__ownerID=t,this.__altered=!1,this)},ht.isMap=lt;var Vn="@@__IMMUTABLE_MAP__@@",qn=ht.prototype;qn[Vn]=!0,qn[pn]=qn.remove,qn.removeIn=qn.deleteIn,pt.prototype.get=function(t,e,n,r){for(var i=this.entries,o=0,u=i.length;o=Gn)return At(t,s,r,i);var _=t&&t===this.ownerID,d=_?s:p(s);return l?a?c===f-1?d.pop():d[c]=d.pop():d[c]=[r,i]:d.push([r,i]),_?(this.entries=d,this):new pt(t,d)}},_t.prototype.get=function(t,e,n,r){void 0===e&&(e=ot(n));var i=1<<((0===t?e:e>>>t)&vn),o=this.bitmap;return 0===(o&i)?r:this.nodes[kt(o&i-1)].get(t+_n,e,n,r)},_t.prototype.update=function(t,e,n,r,i,o,u){void 0===n&&(n=ot(r));var a=(0===e?n:n>>>e)&vn,s=1<=Kn)return Dt(t,l,c,a,_);if(f&&!_&&2===l.length&&wt(l[1^h]))return l[1^h];if(f&&_&&1===l.length&&wt(_))return _;var d=t&&t===this.ownerID,v=f?_?c:c^s:c|s,y=f?_?Nt(l,h,_,d):Ut(l,h,d):Pt(l,h,_,d);return d?(this.bitmap=v,this.nodes=y,this):new _t(t,v,y)},dt.prototype.get=function(t,e,n,r){void 0===e&&(e=ot(n));var i=(0===t?e:e>>>t)&vn,o=this.nodes[i];return o?o.get(t+_n,e,n,r):r},dt.prototype.update=function(t,e,n,r,i,o,u){void 0===n&&(n=ot(r));var a=(0===e?n:n>>>e)&vn,s=i===yn,c=this.nodes,f=c[a];if(s&&!f)return this;var h=Ot(f,t,e+_n,n,r,i,o,u);if(h===f)return this;var l=this.count;if(f){if(!h&&(l--,l=0&&t>>e&vn;if(r>=this.array.length)return new Vt([],t);var i,o=0===r;if(e>0){var u=this.array[r];if(i=u&&u.removeBefore(t,e-_n,n),i===u&&o)return this}if(o&&!i)return this;var a=Yt(this,t);if(!o)for(var s=0;s>>e&vn;if(r>=this.array.length)return this;var i;if(e>0){var o=this.array[r];if(i=o&&o.removeAfter(t,e-_n,n),i===o&&r===this.array.length-1)return this}var u=Yt(this,t);return u.array.splice(r+1),i&&(u.array[r]=i),u};var Wn,Xn={};t(Zt,ht),Zt.of=function(){return this(arguments)},Zt.prototype.toString=function(){return this.__toString("OrderedMap {","}")},Zt.prototype.get=function(t,e){var n=this._map.get(t);return void 0!==n?this._list.get(n)[1]:e},Zt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):ee()},Zt.prototype.set=function(t,e){return ne(this,t,e)},Zt.prototype.remove=function(t){return ne(this,t,yn)},Zt.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},Zt.prototype.__iterate=function(t,e){var n=this;return this._list.__iterate((function(e){return e&&t(e[1],e[0],n)}),e)},Zt.prototype.__iterator=function(t,e){return this._list.fromEntrySeq().__iterator(t,e)},Zt.prototype.__ensureOwner=function(t){if(t===this.__ownerID)return this;var e=this._map.__ensureOwner(t),n=this._list.__ensureOwner(t);return t?te(e,n,t,this.__hash):(this.__ownerID=t,this._map=e,this._list=n,this)},Zt.isOrderedMap=$t,Zt.prototype[ln]=!0,Zt.prototype[pn]=Zt.prototype.remove;var Qn;t(re,z),re.prototype.get=function(t,e){return this._iter.get(t,e)},re.prototype.has=function(t){return this._iter.has(t)},re.prototype.valueSeq=function(){return this._iter.valueSeq()},re.prototype.reverse=function(){var t=this,e=ce(this,!0);return this._useKeys||(e.valueSeq=function(){return t._iter.toSeq().reverse()}),e},re.prototype.map=function(t,e){var n=this,r=se(this,t,e);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(t,e)}),r},re.prototype.__iterate=function(t,e){var n,r=this;return this._iter.__iterate(this._useKeys?function(e,n){return t(e,n,r)}:(n=e?Te(this):0,function(i){return t(i,e?--n:n++,r)}),e)},re.prototype.__iterator=function(t,e){if(this._useKeys)return this._iter.__iterator(t,e);var n=this._iter.__iterator(En,e),r=e?Te(this):0;return new E(function(){var i=n.next();return i.done?i:b(t,e?--r:r++,i.value,i)})},re.prototype[ln]=!0,t(ie,R),ie.prototype.includes=function(t){return this._iter.includes(t)},ie.prototype.__iterate=function(t,e){var n=this,r=0;return this._iter.__iterate((function(e){return t(e,r++,n)}),e)},ie.prototype.__iterator=function(t,e){var n=this._iter.__iterator(En,e),r=0;return new E(function(){var e=n.next();return e.done?e:b(t,r++,e.value,e)})},t(oe,M),oe.prototype.has=function(t){return this._iter.includes(t)},oe.prototype.__iterate=function(t,e){var n=this;return this._iter.__iterate((function(e){return t(e,e,n)}),e)},oe.prototype.__iterator=function(t,e){var n=this._iter.__iterator(En,e);return new E(function(){var e=n.next();return e.done?e:b(t,e.value,e.value,e)})},t(ue,z),ue.prototype.entrySeq=function(){return this._iter.toSeq()},ue.prototype.__iterate=function(t,e){var n=this;return this._iter.__iterate((function(e){if(e){we(e);var r=o(e);return t(r?e.get(1):e[1],r?e.get(0):e[0],n)}}),e)},ue.prototype.__iterator=function(t,e){var n=this._iter.__iterator(En,e);return new E(function(){for(;;){var e=n.next();if(e.done)return e;var r=e.value;if(r){we(r);var i=o(r);return b(t,i?r.get(0):r[0],i?r.get(1):r[1],e)}}})},ie.prototype.cacheResult=re.prototype.cacheResult=oe.prototype.cacheResult=ue.prototype.cacheResult=De,t(Me,et),Me.prototype.toString=function(){return this.__toString(je(this)+" {","}")},Me.prototype.has=function(t){return this._defaultValues.hasOwnProperty(t)},Me.prototype.get=function(t,e){if(!this.has(t))return e;var n=this._defaultValues[t];return this._map?this._map.get(t,n):n},Me.prototype.clear=function(){if(this.__ownerID)return this._map&&this._map.clear(),this;var t=this.constructor;return t._empty||(t._empty=Le(this,bt()))},Me.prototype.set=function(t,e){if(!this.has(t))throw new Error('Cannot set unknown key "'+t+'" on '+je(this));if(this._map&&!this._map.has(t)){var n=this._defaultValues[t];if(e===n)return this}var r=this._map&&this._map.set(t,e);return this.__ownerID||r===this._map?this:Le(this,r)},Me.prototype.remove=function(t){if(!this.has(t))return this;var e=this._map&&this._map.remove(t);return this.__ownerID||e===this._map?this:Le(this,e)},Me.prototype.wasAltered=function(){return this._map.wasAltered()},Me.prototype.__iterator=function(t,e){var r=this;return n(this._defaultValues).map((function(t,e){return r.get(e)})).__iterator(t,e)},Me.prototype.__iterate=function(t,e){var r=this;return n(this._defaultValues).map((function(t,e){return r.get(e)})).__iterate(t,e)},Me.prototype.__ensureOwner=function(t){if(t===this.__ownerID)return this;var e=this._map&&this._map.__ensureOwner(t);return t?Le(this,e,t):(this.__ownerID=t,this._map=e,this)};var Zn=Me.prototype;Zn[pn]=Zn.remove,Zn.deleteIn=Zn.removeIn=qn.removeIn,Zn.merge=qn.merge,Zn.mergeWith=qn.mergeWith,Zn.mergeIn=qn.mergeIn,Zn.mergeDeep=qn.mergeDeep,Zn.mergeDeepWith=qn.mergeDeepWith,Zn.mergeDeepIn=qn.mergeDeepIn,Zn.setIn=qn.setIn,Zn.update=qn.update,Zn.updateIn=qn.updateIn,Zn.withMutations=qn.withMutations,Zn.asMutable=qn.asMutable,Zn.asImmutable=qn.asImmutable,t(Pe,rt),Pe.of=function(){return this(arguments)},Pe.fromKeys=function(t){return this(n(t).keySeq())},Pe.prototype.toString=function(){return this.__toString("Set {","}")},Pe.prototype.has=function(t){return this._map.has(t)},Pe.prototype.add=function(t){return He(this,this._map.set(t,!0))},Pe.prototype.remove=function(t){return He(this,this._map.remove(t)); -},Pe.prototype.clear=function(){return He(this,this._map.clear())},Pe.prototype.union=function(){var t=sn.call(arguments,0);return t=t.filter((function(t){return 0!==t.size})),0===t.length?this:0!==this.size||this.__ownerID||1!==t.length?this.withMutations((function(e){for(var n=0;n=0;r--)n={value:t[r],next:n};return this.__ownerID?(this.size=e,this._head=n,this.__hash=void 0,this.__altered=!0,this):Je(e,n)},Be.prototype.pushAll=function(t){if(t=r(t),0===t.size)return this;ft(t.size);var e=this.size,n=this._head;return t.reverse().forEach((function(t){e++,n={value:t,next:n}})),this.__ownerID?(this.size=e,this._head=n,this.__hash=void 0,this.__altered=!0,this):Je(e,n)},Be.prototype.pop=function(){return this.slice(1)},Be.prototype.unshift=function(){return this.push.apply(this,arguments)},Be.prototype.unshiftAll=function(t){return this.pushAll(t)},Be.prototype.shift=function(){return this.pop.apply(this,arguments)},Be.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):We()},Be.prototype.slice=function(t,e){if(y(t,e,this.size))return this;var n=g(t,this.size),r=m(e,this.size);if(r!==this.size)return nt.prototype.slice.call(this,t,e);for(var i=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=i,this._head=o,this.__hash=void 0,this.__altered=!0,this):Je(i,o)},Be.prototype.__ensureOwner=function(t){return t===this.__ownerID?this:t?Je(this.size,this._head,t,this.__hash):(this.__ownerID=t,this.__altered=!1,this)},Be.prototype.__iterate=function(t,e){var n=this;if(e)return this.reverse().__iterate(t);for(var r=0,i=this._head;i&&t(i.value,r++,n)!==!1;)i=i.next;return r},Be.prototype.__iterator=function(t,e){if(e)return this.reverse().__iterator(t);var n=0,r=this._head;return new E(function(){if(r){var e=r.value;return r=r.next,b(t,n++,e)}return I()})},Be.isStack=Ye;var ir="@@__IMMUTABLE_STACK__@@",or=Be.prototype;or[ir]=!0,or.withMutations=qn.withMutations,or.asMutable=qn.asMutable,or.asImmutable=qn.asImmutable,or.wasAltered=qn.wasAltered;var ur;e.Iterator=E,Xe(e,{toArray:function(){ft(this.size);var t=new Array(this.size||0);return this.valueSeq().__iterate((function(e,n){t[n]=e})),t},toIndexedSeq:function(){return new ie(this)},toJS:function(){return this.toSeq().map((function(t){return t&&"function"==typeof t.toJS?t.toJS():t})).__toJS()},toJSON:function(){return this.toSeq().map((function(t){return t&&"function"==typeof t.toJSON?t.toJSON():t})).__toJS()},toKeyedSeq:function(){return new re(this,!0)},toMap:function(){return ht(this.toKeyedSeq())},toObject:function(){ft(this.size);var t={};return this.__iterate((function(e,n){t[n]=e})),t},toOrderedMap:function(){return Zt(this.toKeyedSeq())},toOrderedSet:function(){return qe(u(this)?this.valueSeq():this)},toSet:function(){return Pe(u(this)?this.valueSeq():this)},toSetSeq:function(){return new oe(this)},toSeq:function(){return a(this)?this.toIndexedSeq():u(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Be(u(this)?this.valueSeq():this)},toList:function(){return Ht(u(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(t,e){return 0===this.size?t+e:t+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+e},concat:function(){var t=sn.call(arguments,0);return Oe(this,ve(this,t))},includes:function(t){return this.some((function(e){return W(e,t)}))},entries:function(){return this.__iterator(bn)},every:function(t,e){ft(this.size);var n=!0;return this.__iterate((function(r,i,o){if(!t.call(e,r,i,o))return n=!1,!1})),n},filter:function(t,e){return Oe(this,fe(this,t,e,!0))},find:function(t,e,n){var r=this.findEntry(t,e);return r?r[1]:n},forEach:function(t,e){return ft(this.size),this.__iterate(e?t.bind(e):t)},join:function(t){ft(this.size),t=void 0!==t?""+t:",";var e="",n=!0;return this.__iterate((function(r){n?n=!1:e+=t,e+=null!==r&&void 0!==r?r.toString():""})),e},keys:function(){return this.__iterator(Sn)},map:function(t,e){return Oe(this,se(this,t,e))},reduce:function(t,e,n){ft(this.size);var r,i;return arguments.length<2?i=!0:r=e,this.__iterate((function(e,o,u){i?(i=!1,r=e):r=t.call(n,r,e,o,u)})),r},reduceRight:function(t,e,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Oe(this,ce(this,!0))},slice:function(t,e){return Oe(this,pe(this,t,e,!0))},some:function(t,e){return!this.every($e(t),e)},sort:function(t){return Oe(this,Se(this,t))},values:function(){return this.__iterator(En)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some((function(){return!0}))},count:function(t,e){return _(t?this.toSeq().filter(t,e):this)},countBy:function(t,e){return he(this,t,e)},equals:function(t){return X(this,t)},entrySeq:function(){var t=this;if(t._cache)return new L(t._cache);var e=t.toSeq().map(Ze).toIndexedSeq();return e.fromEntrySeq=function(){return t.toSeq()},e},filterNot:function(t,e){return this.filter($e(t),e)},findEntry:function(t,e,n){var r=n;return this.__iterate((function(n,i,o){if(t.call(e,n,i,o))return r=[i,n],!1})),r},findKey:function(t,e){var n=this.findEntry(t,e);return n&&n[0]},findLast:function(t,e,n){return this.toKeyedSeq().reverse().find(t,e,n)},findLastEntry:function(t,e,n){return this.toKeyedSeq().reverse().findEntry(t,e,n)},findLastKey:function(t,e){return this.toKeyedSeq().reverse().findKey(t,e)},first:function(){return this.find(v)},flatMap:function(t,e){return Oe(this,ge(this,t,e))},flatten:function(t){return Oe(this,ye(this,t,!0))},fromEntrySeq:function(){return new ue(this)},get:function(t,e){return this.find((function(e,n){return W(n,t)}),void 0,e)},getIn:function(t,e){for(var n,r=this,i=Re(t);!(n=i.next()).done;){var o=n.value;if(r=r&&r.get?r.get(o,yn):yn,r===yn)return e}return r},groupBy:function(t,e){return le(this,t,e)},has:function(t){return this.get(t,yn)!==yn},hasIn:function(t){return this.getIn(t,yn)!==yn},isSubset:function(t){return t="function"==typeof t.includes?t:e(t),this.every((function(e){return t.includes(e)}))},isSuperset:function(t){return t="function"==typeof t.isSubset?t:e(t),t.isSubset(this)},keyOf:function(t){return this.findKey((function(e){return W(e,t)}))},keySeq:function(){return this.toSeq().map(Qe).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(t){return this.toKeyedSeq().reverse().keyOf(t)},max:function(t){return Ee(this,t)},maxBy:function(t,e){return Ee(this,e,t)},min:function(t){return Ee(this,t?tn(t):rn)},minBy:function(t,e){return Ee(this,e?tn(e):rn,t)},rest:function(){return this.slice(1)},skip:function(t){return this.slice(Math.max(0,t))},skipLast:function(t){return Oe(this,this.toSeq().reverse().skip(t).reverse())},skipWhile:function(t,e){return Oe(this,de(this,t,e,!0))},skipUntil:function(t,e){return this.skipWhile($e(t),e)},sortBy:function(t,e){return Oe(this,Se(this,e,t))},take:function(t){return this.slice(0,Math.max(0,t))},takeLast:function(t){return Oe(this,this.toSeq().reverse().take(t).reverse())},takeWhile:function(t,e){return Oe(this,_e(this,t,e))},takeUntil:function(t,e){return this.takeWhile($e(t),e)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=on(this))}});var ar=e.prototype;ar[cn]=!0,ar[wn]=ar.values,ar.__toJS=ar.toArray,ar.__toStringMapper=en,ar.inspect=ar.toSource=function(){return this.toString()},ar.chain=ar.flatMap,ar.contains=ar.includes,Xe(n,{flip:function(){return Oe(this,ae(this))},mapEntries:function(t,e){var n=this,r=0;return Oe(this,this.toSeq().map((function(i,o){return t.call(e,[o,i],r++,n)})).fromEntrySeq())},mapKeys:function(t,e){var n=this;return Oe(this,this.toSeq().flip().map((function(r,i){return t.call(e,r,i,n)})).flip())}});var sr=n.prototype;sr[fn]=!0,sr[wn]=ar.entries,sr.__toJS=ar.toObject,sr.__toStringMapper=function(t,e){return JSON.stringify(e)+": "+en(t)},Xe(r,{toKeyedSeq:function(){return new re(this,!1)},filter:function(t,e){return Oe(this,fe(this,t,e,!1))},findIndex:function(t,e){var n=this.findEntry(t,e);return n?n[0]:-1},indexOf:function(t){var e=this.keyOf(t);return void 0===e?-1:e},lastIndexOf:function(t){var e=this.lastKeyOf(t);return void 0===e?-1:e},reverse:function(){return Oe(this,ce(this,!1))},slice:function(t,e){return Oe(this,pe(this,t,e,!1))},splice:function(t,e){var n=arguments.length;if(e=Math.max(0|e,0),0===n||2===n&&!e)return this;t=g(t,t<0?this.count():this.size);var r=this.slice(0,t);return Oe(this,1===n?r:r.concat(p(arguments,2),this.slice(t+e)))},findLastIndex:function(t,e){var n=this.findLastEntry(t,e);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(t){return Oe(this,ye(this,t,!1))},get:function(t,e){return t=d(this,t),t<0||this.size===1/0||void 0!==this.size&&t>this.size?e:this.find((function(e,n){return n===t}),void 0,e)},has:function(t){return t=d(this,t),t>=0&&(void 0!==this.size?this.size===1/0||t-1&&t%1===0&&t<=Number.MAX_VALUE}var i=Function.prototype.bind;e.isString=function(t){return"string"==typeof t||"[object String]"===n(t)},e.isArray=Array.isArray||function(t){return"[object Array]"===n(t)},"function"!=typeof/./&&"object"!=typeof Int8Array?e.isFunction=function(t){return"function"==typeof t||!1}:e.isFunction=function(t){return"[object Function]"===toString.call(t)},e.isObject=function(t){var e=typeof t;return"function"===e||"object"===e&&!!t},e.extend=function(t){var e=arguments,n=arguments.length;if(!t||n<2)return t||{};for(var r=1;r0)){var e=this.reactorState.get("dirtyStores");if(0!==e.size){var n=c.default.Set().withMutations((function(n){n.union(t.observerState.get("any")),e.forEach((function(e){var r=t.observerState.getIn(["stores",e]);r&&n.union(r)}))}));n.forEach((function(e){var n=t.observerState.getIn(["observersMap",e]);if(n){var r=n.get("getter"),i=n.get("handler"),o=p.evaluate(t.prevReactorState,r),u=p.evaluate(t.reactorState,r);t.prevReactorState=o.reactorState,t.reactorState=u.reactorState;var a=o.result,s=u.result;c.default.is(a,s)||i.call(null,s)}}));var r=p.resetDirtyStores(this.reactorState);this.prevReactorState=r,this.reactorState=r}}}},{key:"batchStart",value:function(){this.__batchDepth++}},{key:"batchEnd",value:function(){if(this.__batchDepth--,this.__batchDepth<=0){this.__isDispatching=!0;try{this.__notify()}catch(t){throw this.__isDispatching=!1,t}this.__isDispatching=!1}}}]),t})();e.default=(0,m.toFactory)(E),t.exports=e.default}),(function(t,e,n){function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n={};return(0,o.each)(e,(function(e,r){n[r]=t.evaluate(e)})),n}Object.defineProperty(e,"__esModule",{value:!0});var o=n(4);e.default=function(t){return{getInitialState:function(){return i(t,this.getDataBindings())},componentDidMount:function(){var e=this;this.__unwatchFns=[],(0,o.each)(this.getDataBindings(),(function(n,i){var o=t.observe(n,(function(t){e.setState(r({},i,t))}));e.__unwatchFns.push(o)}))},componentWillUnmount:function(){for(var t=this;this.__unwatchFns.length;)t.__unwatchFns.shift()()}}},t.exports=e.default}),(function(t,e,n){function r(t){return t&&t.__esModule?t:{default:t}}function i(t,e){return new C({result:t,reactorState:e})}function o(t,e){return t.withMutations((function(t){(0,A.each)(e,(function(e,n){t.getIn(["stores",n])&&console.warn("Store already defined for id = "+n);var r=e.getInitialState();if(void 0===r&&f(t,"throwOnUndefinedStoreReturnValue"))throw new Error("Store getInitialState() must return a value, did you forget a return statement");if(f(t,"throwOnNonImmutableStore")&&!(0,O.isImmutableValue)(r))throw new Error("Store getInitialState() must return an immutable value, did you forget to call toImmutable");t.update("stores",(function(t){return t.set(n,e)})).update("state",(function(t){return t.set(n,r)})).update("dirtyStores",(function(t){return t.add(n)})).update("storeStates",(function(t){return S(t,[n])}))})),m(t)}))}function u(t,e){return t.withMutations((function(t){(0,A.each)(e,(function(e,n){t.update("stores",(function(t){return t.set(n,e)}))}))}))}function a(t,e,n){var r=t.get("logger");if(void 0===e&&f(t,"throwOnUndefinedActionType"))throw new Error("`dispatch` cannot be called with an `undefined` action type.");var i=t.get("state"),o=t.get("dirtyStores"),u=i.withMutations((function(u){r.dispatchStart(t,e,n),t.get("stores").forEach((function(i,a){var s=u.get(a),c=void 0;try{c=i.handle(s,e,n)}catch(e){throw r.dispatchError(t,e.message),e}if(void 0===c&&f(t,"throwOnUndefinedStoreReturnValue")){var h="Store handler must return a value, did you forget a return statement";throw r.dispatchError(t,h),new Error(h)}u.set(a,c),s!==c&&(o=o.add(a))})),r.dispatchEnd(t,u,o,i)})),a=t.set("state",u).set("dirtyStores",o).update("storeStates",(function(t){return S(t,o)}));return m(a)}function s(t,e){var n=[],r=(0,O.toImmutable)({}).withMutations((function(r){(0,A.each)(e,(function(e,i){var o=t.getIn(["stores",i]);if(o){var u=o.deserialize(e);void 0!==u&&(r.set(i,u),n.push(i))}}))})),i=b.default.Set(n);return t.update("state",(function(t){return t.merge(r)})).update("dirtyStores",(function(t){return t.union(i)})).update("storeStates",(function(t){return S(t,n)}))}function c(t,e,n){var r=e;(0,T.isKeyPath)(e)&&(e=(0,w.fromKeyPath)(e));var i=t.get("nextId"),o=(0,w.getStoreDeps)(e),u=b.default.Map({id:i,storeDeps:o,getterKey:r,getter:e,handler:n}),a=void 0;return a=0===o.size?t.update("any",(function(t){return t.add(i)})):t.withMutations((function(t){o.forEach((function(e){var n=["stores",e];t.hasIn(n)||t.setIn(n,b.default.Set()),t.updateIn(["stores",e],(function(t){return t.add(i)}))}))})),a=a.set("nextId",i+1).setIn(["observersMap",i],u),{observerState:a,entry:u}}function f(t,e){var n=t.getIn(["options",e]);if(void 0===n)throw new Error("Invalid option: "+e);return n}function h(t,e,n){var r=t.get("observersMap").filter((function(t){var r=t.get("getterKey"),i=!n||t.get("handler")===n;return!!i&&((0,T.isKeyPath)(e)&&(0,T.isKeyPath)(r)?(0,T.isEqual)(e,r):e===r)}));return t.withMutations((function(t){r.forEach((function(e){return l(t,e)}))}))}function l(t,e){return t.withMutations((function(t){var n=e.get("id"),r=e.get("storeDeps");0===r.size?t.update("any",(function(t){return t.remove(n)})):r.forEach((function(e){t.updateIn(["stores",e],(function(t){return t?t.remove(n):t}))})),t.removeIn(["observersMap",n])}))}function p(t){var e=t.get("state");return t.withMutations((function(t){var n=t.get("stores"),r=n.keySeq().toJS();n.forEach((function(n,r){var i=e.get(r),o=n.handleReset(i);if(void 0===o&&f(t,"throwOnUndefinedStoreReturnValue"))throw new Error("Store handleReset() must return a value, did you forget a return statement");if(f(t,"throwOnNonImmutableStore")&&!(0,O.isImmutableValue)(o))throw new Error("Store reset state must be an immutable value, did you forget to call toImmutable");t.setIn(["state",r],o)})),t.update("storeStates",(function(t){return S(t,r)})),v(t)}))}function _(t,e){var n=t.get("state");if((0,T.isKeyPath)(e))return i(n.getIn(e),t);if(!(0,w.isGetter)(e))throw new Error("evaluate must be passed a keyPath or Getter");var r=t.get("cache"),o=r.lookup(e),u=!o||y(t,o);return u&&(o=g(t,e)),i(o.get("value"),t.update("cache",(function(t){return u?t.miss(e,o):t.hit(e)})))}function d(t){var e={};return t.get("stores").forEach((function(n,r){var i=t.getIn(["state",r]),o=n.serialize(i);void 0!==o&&(e[r]=o)})),e}function v(t){return t.set("dirtyStores",b.default.Set())}function y(t,e){var n=e.get("storeStates");return!n.size||n.some((function(e,n){return t.getIn(["storeStates",n])!==e}))}function g(t,e){var n=(0,w.getDeps)(e).map((function(e){return _(t,e).result})),r=(0,w.getComputeFn)(e).apply(null,n),i=(0,w.getStoreDeps)(e),o=(0,O.toImmutable)({}).withMutations((function(e){i.forEach((function(n){var r=t.getIn(["storeStates",n]);e.set(n,r)}))}));return(0,I.CacheEntry)({value:r,storeStates:o,dispatchId:t.get("dispatchId")})}function m(t){return t.update("dispatchId",(function(t){return t+1}))}function S(t,e){return t.withMutations((function(t){e.forEach((function(e){var n=t.has(e)?t.get(e)+1:1;t.set(e,n)}))}))}Object.defineProperty(e,"__esModule",{value:!0}),e.registerStores=o,e.replaceStores=u,e.dispatch=a,e.loadState=s,e.addObserver=c,e.getOption=f,e.removeObserver=h,e.removeObserverByEntry=l,e.reset=p,e.evaluate=_,e.serialize=d,e.resetDirtyStores=v;var E=n(3),b=r(E),I=n(9),O=n(5),w=n(10),T=n(11),A=n(4),C=b.default.Record({result:null,reactorState:null})}),(function(t,e,n){function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(){return new s}Object.defineProperty(e,"__esModule",{value:!0});var o=(function(){function t(t,e){for(var n=0;nn.dispatchId)throw new Error("Refusing to cache older value");return n})))}},{key:"evict",value:function(e){return new t(this.cache.remove(e))}}]),t})();e.BasicCache=s;var c=1e3,f=1,h=(function(){function t(){var e=arguments.length<=0||void 0===arguments[0]?c:arguments[0],n=arguments.length<=1||void 0===arguments[1]?f:arguments[1],i=arguments.length<=2||void 0===arguments[2]?new s:arguments[2],o=arguments.length<=3||void 0===arguments[3]?(0,u.OrderedSet)():arguments[3];r(this,t),console.log("using LRU"),this.limit=e,this.evictCount=n,this.cache=i,this.lru=o}return o(t,[{key:"lookup",value:function(t,e){return this.cache.lookup(t,e)}},{key:"has",value:function(t){return this.cache.has(t)}},{key:"asMap",value:function(){return this.cache.asMap()}},{key:"hit",value:function(e){return this.cache.has(e)?new t(this.limit,this.evictCount,this.cache,this.lru.remove(e).add(e)):this}},{key:"miss",value:function(e,n){var r;if(this.lru.size>=this.limit){if(this.has(e))return new t(this.limit,this.evictCount,this.cache.miss(e,n),this.lru.remove(e).add(e));var i=this.lru.take(this.evictCount).reduce((function(t,e){return t.evict(e)}),this.cache).miss(e,n);r=new t(this.limit,this.evictCount,i,this.lru.skip(this.evictCount).add(e))}else r=new t(this.limit,this.evictCount,this.cache.miss(e,n),this.lru.add(e));return r}},{key:"evict",value:function(e){return this.cache.has(e)?new t(this.limit,this.evictCount,this.cache.evict(e),this.lru.remove(e)):this}}]),t})();e.LRUCache=h}),(function(t,e,n){function r(t){return t&&t.__esModule?t:{default:t}}function i(t){return(0,l.isArray)(t)&&(0,l.isFunction)(t[t.length-1])}function o(t){return t[t.length-1]}function u(t){return t.slice(0,t.length-1)}function a(t,e){e||(e=h.default.Set());var n=h.default.Set().withMutations((function(e){if(!i(t))throw new Error("getFlattenedDeps must be passed a Getter");u(t).forEach((function(t){if((0,p.isKeyPath)(t))e.add((0,f.List)(t));else{if(!i(t))throw new Error("Invalid getter, each dependency must be a KeyPath or Getter");e.union(a(t))}}))}));return e.union(n)}function s(t){if(!(0,p.isKeyPath)(t))throw new Error("Cannot create Getter from KeyPath: "+t);return[t,_]}function c(t){if(t.hasOwnProperty("__storeDeps"))return t.__storeDeps;var e=a(t).map((function(t){return t.first()})).filter((function(t){return!!t}));return Object.defineProperty(t,"__storeDeps",{enumerable:!1,configurable:!1,writable:!1,value:e}),e}Object.defineProperty(e,"__esModule",{value:!0});var f=n(3),h=r(f),l=n(4),p=n(11),_=function(t){return t};e.default={isGetter:i,getComputeFn:o,getFlattenedDeps:a,getStoreDeps:c,getDeps:u,fromKeyPath:s},t.exports=e.default}),(function(t,e,n){function r(t){return t&&t.__esModule?t:{default:t}}function i(t){return(0,s.isArray)(t)&&!(0,s.isFunction)(t[t.length-1])}function o(t,e){var n=a.default.List(t),r=a.default.List(e);return a.default.is(n,r)}Object.defineProperty(e,"__esModule",{value:!0}),e.isKeyPath=i,e.isEqual=o;var u=n(3),a=r(u),s=n(4)}),(function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var r=n(8),i={dispatchStart:function(t,e,n){(0,r.getOption)(t,"logDispatches")&&console.group&&(console.groupCollapsed("Dispatch: %s",e),console.group("payload"),console.debug(n),console.groupEnd())},dispatchError:function(t,e){(0,r.getOption)(t,"logDispatches")&&console.group&&(console.debug("Dispatch error: "+e),console.groupEnd())},dispatchEnd:function(t,e,n,i){(0,r.getOption)(t,"logDispatches")&&console.group&&((0,r.getOption)(t,"logDirtyStores")&&console.log("Stores updated:",n.toList().toJS()),(0,r.getOption)(t,"logAppState")&&console.debug("Dispatch done, new state: ",e.toJS()),console.groupEnd())}};e.ConsoleGroupLogger=i;var o={dispatchStart:function(t,e,n){},dispatchError:function(t,e){},dispatchEnd:function(t,e,n){}};e.NoopLogger=o}),(function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var r=n(3),i=n(9),o=n(12),u=(0,r.Map)({logDispatches:!1,logAppState:!1,logDirtyStores:!1,throwOnUndefinedActionType:!1,throwOnUndefinedStoreReturnValue:!1,throwOnNonImmutableStore:!1,throwOnDispatchInDispatch:!1});e.PROD_OPTIONS=u;var a=(0,r.Map)({logDispatches:!0,logAppState:!0,logDirtyStores:!0,throwOnUndefinedActionType:!0,throwOnUndefinedStoreReturnValue:!0,throwOnNonImmutableStore:!0,throwOnDispatchInDispatch:!0});e.DEBUG_OPTIONS=a;var s=(0,r.Record)({dispatchId:0,state:(0,r.Map)(),stores:(0,r.Map)(),cache:(0,i.DefaultCache)(),logger:o.NoopLogger,storeStates:(0,r.Map)(),dirtyStores:(0,r.Set)(),debug:!1,options:u});e.ReactorState=s;var c=(0,r.Record)({any:(0,r.Set)(),stores:(0,r.Map)({}),observersMap:(0,r.Map)({}),nextId:1});e.ObserverState=c})])}))})),ke=t(je),Ne=function(t){var e,n={};if(!(t instanceof Object)||Array.isArray(t))throw new Error("keyMirror(...): Argument must be an object.");for(e in t)t.hasOwnProperty(e)&&(n[e]=e);return n},Pe=Ne,Ue=Pe({VALIDATING_AUTH_TOKEN:null,VALID_AUTH_TOKEN:null,INVALID_AUTH_TOKEN:null,LOG_OUT:null}),He=ke.Store,xe=ke.toImmutable,Ve=new He({getInitialState:function(){return xe({isValidating:!1,authToken:!1,host:null,isInvalid:!1,errorMessage:""})},initialize:function(){this.on(Ue.VALIDATING_AUTH_TOKEN,n),this.on(Ue.VALID_AUTH_TOKEN,r),this.on(Ue.INVALID_AUTH_TOKEN,i)}}),qe=ke.Store,Fe=ke.toImmutable,Ge=new qe({getInitialState:function(){return Fe({authToken:null,host:""})},initialize:function(){this.on(Ue.VALID_AUTH_TOKEN,o),this.on(Ue.LOG_OUT,u)}}),Ke=ke.Store,Be=new Ke({getInitialState:function(){return!0},initialize:function(){this.on(Ue.VALID_AUTH_TOKEN,a)}}),Ye=Pe({STREAM_START:null,STREAM_STOP:null,STREAM_ERROR:null}),Je=ke.Store,We=ke.toImmutable,Xe=new Je({getInitialState:function(){return We({isStreaming:!1,hasError:!1})},initialize:function(){this.on(Ye.STREAM_START,s),this.on(Ye.STREAM_ERROR,c),this.on(Ye.LOG_OUT,f)}}),Qe=1,Ze=2,$e=3,tn=function(t,e){this.url=t,this.options=e||{},this.commandId=1,this.commands={},this.connectionTries=0,this.eventListeners={},this.closeRequested=!1};tn.prototype.addEventListener=function(t,e){var n=this.eventListeners[t];n||(n=this.eventListeners[t]=[]),n.push(e)},tn.prototype.fireEvent=function(t){var e=this;(this.eventListeners[t]||[]).forEach((function(t){return t(e)}))},tn.prototype.connect=function(){var t=this;return new Promise(function(e,n){var r=t.commands;Object.keys(r).forEach((function(t){var e=r[t];e.reject&&e.reject(S($e,"Connection lost"))}));var i=!1;t.connectionTries+=1,t.socket=new WebSocket(t.url),t.socket.addEventListener("open",(function(){t.connectionTries=0})),t.socket.addEventListener("message",(function(o){var u=JSON.parse(o.data);switch(u.type){case"event":t.commands[u.id].eventCallback(u.event);break;case"result":u.success?t.commands[u.id].resolve(u):t.commands[u.id].reject(u.error),delete t.commands[u.id];break;case"pong":break; -case"auth_required":t.sendMessage(h(t.options.authToken));break;case"auth_invalid":n(Ze),i=!0;break;case"auth_ok":e(t),t.fireEvent("ready"),t.commandId=1,t.commands={},Object.keys(r).forEach((function(e){var n=r[e];n.eventType&&t.subscribeEvents(n.eventCallback,n.eventType).then((function(t){n.unsubscribe=t}))}))}})),t.socket.addEventListener("close",(function(){if(!i&&!t.closeRequested){0===t.connectionTries?t.fireEvent("disconnected"):n(Qe);var e=1e3*Math.min(t.connectionTries,5);setTimeout((function(){return t.connect()}),e)}}))})},tn.prototype.close=function(){this.closeRequested=!0,this.socket.close()},tn.prototype.getStates=function(){return this.sendMessagePromise(l()).then(E)},tn.prototype.getServices=function(){return this.sendMessagePromise(_()).then(E)},tn.prototype.getPanels=function(){return this.sendMessagePromise(d()).then(E)},tn.prototype.getConfig=function(){return this.sendMessagePromise(p()).then(E)},tn.prototype.callService=function(t,e,n){return this.sendMessagePromise(v(t,e,n))},tn.prototype.subscribeEvents=function(t,e){var n=this;return this.sendMessagePromise(y(e)).then((function(r){var i={eventCallback:t,eventType:e,unsubscribe:function(){return n.sendMessagePromise(g(r.id)).then((function(){delete n.commands[r.id]}))}};return n.commands[r.id]=i,function(){return i.unsubscribe()}}))},tn.prototype.ping=function(){return this.sendMessagePromise(m())},tn.prototype.sendMessage=function(t){this.socket.send(JSON.stringify(t))},tn.prototype.sendMessagePromise=function(t){var e=this;return new Promise(function(n,r){e.commandId+=1;var i=e.commandId;t.id=i,e.commands[i]={resolve:n,reject:r},e.sendMessage(t)})};var en=Pe({API_FETCH_ALL_START:null,API_FETCH_ALL_SUCCESS:null,API_FETCH_ALL_FAIL:null,SYNC_SCHEDULED:null,SYNC_SCHEDULE_CANCELLED:null}),nn=ke.Store,rn=new nn({getInitialState:function(){return!0},initialize:function(){this.on(en.API_FETCH_ALL_START,(function(){return!0})),this.on(en.API_FETCH_ALL_SUCCESS,(function(){return!1})),this.on(en.API_FETCH_ALL_FAIL,(function(){return!1})),this.on(en.LOG_OUT,(function(){return!1}))}}),on=I,un=Pe({API_FETCH_SUCCESS:null,API_FETCH_START:null,API_FETCH_FAIL:null,API_SAVE_SUCCESS:null,API_SAVE_START:null,API_SAVE_FAIL:null,API_DELETE_SUCCESS:null,API_DELETE_START:null,API_DELETE_FAIL:null,LOG_OUT:null}),an=ke.Store,sn=ke.toImmutable,cn=new an({getInitialState:function(){return sn({})},initialize:function(){var t=this;this.on(un.API_FETCH_SUCCESS,O),this.on(un.API_SAVE_SUCCESS,O),this.on(un.API_DELETE_SUCCESS,w),this.on(un.LOG_OUT,(function(){return t.getInitialState()}))}}),fn=Object.getOwnPropertySymbols,hn=Object.prototype.hasOwnProperty,ln=Object.prototype.propertyIsEnumerable,pn=A()?Object.assign:function(t,e){for(var n,r,i=arguments,o=T(t),u=1;u5m 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 diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index b0b33404525..8d721687e6a 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -1,5 +1,597 @@ \ No newline at end of file +n&&e.updateNativeStyleProperties(document.documentElement,this.customStyle)}};return r}(),function(){"use strict";var e=Polymer.Base.serializeValueToAttribute,t=Polymer.StyleProperties,n=Polymer.StyleTransformer,r=Polymer.StyleDefaults,s=Polymer.Settings.useNativeShadow,i=Polymer.Settings.useNativeCSSProperties;Polymer.Base._addFeature({_prepStyleProperties:function(){i||(this._ownStylePropertyNames=this._styles&&this._styles.length?t.decorateStyles(this._styles,this):null)},customStyle:null,getComputedStyleValue:function(e){return i||this._styleProperties||this._computeStyleProperties(),!i&&this._styleProperties&&this._styleProperties[e]||getComputedStyle(this).getPropertyValue(e)},_setupStyleProperties:function(){this.customStyle={},this._styleCache=null,this._styleProperties=null,this._scopeSelector=null,this._ownStyleProperties=null,this._customStyle=null},_needsStyleProperties:function(){return Boolean(!i&&this._ownStylePropertyNames&&this._ownStylePropertyNames.length)},_validateApplyShim:function(){if(this.__applyShimInvalid){Polymer.ApplyShim.transform(this._styles,this.__proto__);var e=n.elementStyles(this);if(s){var t=this._template.content.querySelector("style");t&&(t.textContent=e)}else{var r=this._scopeStyle&&this._scopeStyle.nextSibling;r&&(r.textContent=e)}}},_beforeAttached:function(){this._scopeSelector&&!this.__stylePropertiesInvalid||!this._needsStyleProperties()||(this.__stylePropertiesInvalid=!1,this._updateStyleProperties())},_findStyleHost:function(){for(var e,t=this;e=Polymer.dom(t).getOwnerRoot();){if(Polymer.isInstance(e.host))return e.host;t=e.host}return r},_updateStyleProperties:function(){var e,n=this._findStyleHost();n._styleProperties||n._computeStyleProperties(),n._styleCache||(n._styleCache=new Polymer.StyleCache);var r=t.propertyDataFromStyles(n._styles,this),i=!this.__notStyleScopeCacheable;i&&(r.key.customStyle=this.customStyle,e=n._styleCache.retrieve(this.is,r.key,this._styles));var a=Boolean(e);a?this._styleProperties=e._styleProperties:this._computeStyleProperties(r.properties),this._computeOwnStyleProperties(),a||(e=o.retrieve(this.is,this._ownStyleProperties,this._styles));var l=Boolean(e)&&!a,c=this._applyStyleProperties(e);a||(c=c&&s?c.cloneNode(!0):c,e={style:c,_scopeSelector:this._scopeSelector,_styleProperties:this._styleProperties},i&&(r.key.customStyle={},this.mixin(r.key.customStyle,this.customStyle),n._styleCache.store(this.is,e,r.key,this._styles)),l||o.store(this.is,Object.create(e),this._ownStyleProperties,this._styles))},_computeStyleProperties:function(e){var n=this._findStyleHost();n._styleProperties||n._computeStyleProperties();var r=Object.create(n._styleProperties),s=t.hostAndRootPropertiesForScope(this);this.mixin(r,s.hostProps),e=e||t.propertyDataFromStyles(n._styles,this).properties,this.mixin(r,e),this.mixin(r,s.rootProps),t.mixinCustomStyle(r,this.customStyle),t.reify(r),this._styleProperties=r},_computeOwnStyleProperties:function(){for(var e,t={},n=0;n0&&l.push(t);return[{removed:a,added:l}]}},Polymer.Collection.get=function(e){return Polymer._collections.get(e)||new Polymer.Collection(e)},Polymer.Collection.applySplices=function(e,t){var n=Polymer._collections.get(e);return n?n._applySplices(t):null},Polymer({is:"dom-repeat",extends:"template",_template:null,properties:{items:{type:Array},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},sort:{type:Function,observer:"_sortChanged"},filter:{type:Function,observer:"_filterChanged"},observe:{type:String,observer:"_observeChanged"},delay:Number,renderedItemCount:{type:Number,notify:!0,readOnly:!0},initialCount:{type:Number,observer:"_initializeChunking"},targetFramerate:{type:Number,value:20},_targetFrameTime:{type:Number,computed:"_computeFrameTime(targetFramerate)"}},behaviors:[Polymer.Templatizer],observers:["_itemsChanged(items.*)"],created:function(){this._instances=[],this._pool=[],this._limit=1/0;var e=this;this._boundRenderChunk=function(){e._renderChunk()}},detached:function(){this.__isDetached=!0;for(var e=0;e=0;t--){var n=this._instances[t];n.isPlaceholder&&t=this._limit&&(n=this._downgradeInstance(t,n.__key__)),e[n.__key__]=t,n.isPlaceholder||n.__setProperty(this.indexAs,t,!0)}this._pool.length=0,this._setRenderedItemCount(this._instances.length),this.fire("dom-change"),this._tryRenderChunk()},_applyFullRefresh:function(){var e,t=this.collection;if(this._sortFn)e=t?t.getKeys():[];else{e=[];var n=this.items;if(n)for(var r=0;r=r;a--)this._detachAndRemoveInstance(a)},_numericSort:function(e,t){return e-t},_applySplicesUserSort:function(e){for(var t,n,r=this.collection,s={},i=0;i=0;i--){var c=a[i];void 0!==c&&this._detachAndRemoveInstance(c)}var h=this;if(l.length){this._filterFn&&(l=l.filter(function(e){return h._filterFn(r.getItem(e))})),l.sort(function(e,t){return h._sortFn(r.getItem(e),r.getItem(t))});var u=0;for(i=0;i>1,a=this._instances[o].__key__,l=this._sortFn(n.getItem(a),r);if(l<0)e=o+1;else{if(!(l>0)){i=o;break}s=o-1}}return i<0&&(i=s+1),this._insertPlaceholder(i,t),i},_applySplicesArrayOrder:function(e){for(var t,n=0;n=0?(e=this.as+"."+e.substring(n+1),i._notifyPath(e,t,!0)):i.__setProperty(this.as,t,!0))}},itemForElement:function(e){var t=this.modelForElement(e);return t&&t[this.as]},keyForElement:function(e){var t=this.modelForElement(e);return t&&t.__key__},indexForElement:function(e){var t=this.modelForElement(e);return t&&t[this.indexAs]}}),Polymer({is:"array-selector",_template:null,properties:{items:{type:Array,observer:"clearSelection"},multi:{type:Boolean,value:!1,observer:"clearSelection"},selected:{type:Object,notify:!0},selectedItem:{type:Object,notify:!0},toggle:{type:Boolean,value:!1}},clearSelection:function(){if(Array.isArray(this.selected))for(var e=0;e \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 6c318038174a7c47cb63d232d556075fa9a132bd..32bc37123a6bd4249e49200cdc42c70f81a2bcf5 100644 GIT binary patch delta 110663 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

#Emgq#sF1#OdKcF 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 delta 105712 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

_EQnc}#YsF#PNIG7Fn_r& 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 5159326a7b3..a1057681f1a 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 5159326a7b3d1ba29ae17a7861fa2eaa8c2c95f6 +Subproject commit a1057681f1a33cffc79708085c1646d786712a87 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html index 531167d98a8..bbe752c7018 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html @@ -1 +1 @@ -

\ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html.gz index 22fde6f1a5f3e6636e49768837b19d6081bac803..c4be6a82b4d2ff6cdaabafcc27e23033b0713ef7 100644 GIT binary patch delta 2724 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 delta 2710 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 QXYKz0YB~n|!QCDJ07tz%2LJ#7 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html index 0ecddfec1f3..040284939d0 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html @@ -1,2 +1,2 @@ \ No newline at end of file + clear: both;white-space:pre-wrap}
About
\ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html.gz index 8c840c85985b1c1ac0056f7060ebd0e1e3256dee..91027a35abbfdc84fd79ded63990ae447091e155 100644 GIT binary patch literal 1239 zcmV;|1StC-iwFq1r;b2KFRvG3_3jfc%li}fNEx@NT&tpXy&oK~C} z-hg5PmP|HFMCReS1Ih9s7%xEXQ)QxOPg4R8RE|N++zsY!hUs~NZ zg5_Fin|xCg#W|}TYaLkTKtb*k*`Nci&e;mGd+AT_)%uT98(oy^#zW&bh6{l?Bxm25 zhc4ooZvDo?gJ)dHvPp8pfIU~T0ak%5E1$fCx{H=z9cI7zksG7d6Ncp*j8dRi7Wxzn zrd@>X0Hw`Im}|3uoQ_cm-weerxkaGh_MRClYi`#=7Z3>6YRi-^vB%!(4Q`gQVP2a) z|MN^+f$sZv^FW+dQjo!)3b`LRJRggHbkGgyNo)?wTJN#ILTT<38?2wiKUq+&1)NR4 zBI94KfZK#*+E?eRN_t?<@Ej6jfvqezT^jdOU!>@(ZyGvMd>wjGamQS4wNfEH3nlh? zPU%x9DdYo)$3?HT%D6=eb5=vsj`@>@W6rBNy}22lZf_}Zm0tCrupC}4@fkM)$M>v} z=WJs!$TCEEIUK zyf-e1<4V`S5F?%EjgMqFV6rZWv-zB2AGw!#9OmZYf-n04p8fFh0e_KcN=gRq&M7X0 zGC7`OyZ9NMl8dd=uyS*Qop<4I6tcvB7Pd^ky-j0-sV=U#uZY)Vz_gZ!Qyi^%trBv= ze0aVS(r!I$iyhC#zbQ5zv6xDnTM*K_m=cfd4+3?UDc;=E#p@9yNVX=NWNnjIL>Gjw zz=cW;XrmzNs~>A=GbLSx7N|8yDPIA(e0NQh#B=W;bmW6>Es~ZTC0R;ewHek|ALM)R zdYmW95jHiXLB4$c^S^sW4OQzJ>~Vy`_LLK>mH$JSkM18Lgdsoa=&M#LPg)mb{V3vU zwTjHzSI8G_OS-t~pUJnue)bG}C=rEAe?tkY{^v%$=7GyY^(pz0`@sI!ajJ5 zogYzSf?KKVX4~3Nfhp~}8TX#&s5?o4A{7L5GTnq}MF)MKOuN~^(#`~?8+h>oBK)8( z@%!=`3f?L|na+Ao+Z^Wfz2@SPCV?AYKL14r&>+`bsS6_~^zEB#Ivb{V7p6FkP!OBR z(}4S~;nOGji$3O`1*5G85z#KnWFscQY&z|_DSq>Zp{DV0k&OF`=ieEDFu#8a005%E BUkv~N literal 1341 zcmV-D1;Y9tiwFp$)pA$@1889_aA9s`Y%OGEb}eacW^XQNbZu+^tyceT+cpsXe^0@2 zKw$%xv~E;*A>u**fZ?G`XoC_vSY{2Fl-AD zKqkNY?gzg+a#~`g=F<{HHlJ32f~BRf4sgbQy?z;d%jeUm-%ND2nol!b1(nVk1x#i$ zUW&ko8dQ+MB9L{i36D@2B@pIQhbxb(Q`KZJqMk? zh1E@+1*ulr#$V)lei~FRXdKwUfr1ocSrdU!r@<1EJBi2lD*gW0MjNKOMyPRZM3zwu z@yR#lz70j98(bsYV<40)>Nq6~*i$8I2uhGeiScu&+He8ZQS|HYg)wS13MhR;UUFg$ ze4V_(xDBZsptLy(b4}urpt0qumsG6y$g($m9VS63IqgewGEUmsK#jZnl=kr z2dGUK|7oIaM)cipbI+VsGGjfT^07Z6JROqX6107Il8O@~4I(9&D=jd#-g?LX(S%Z+ z!O8eDHvFXugpFCEu{>Rt5+QI#q!1em!O{xTPNVMB=TqY9ibh0Atb8p>;R2Uht&|VX zLP52jalQ*>xx9yLyNFt=L|Brr2r8(XA%0d1ig`KXH#hy)?JZ}n)XNU!m;H|m`lb!9 z@jYwOxm>VH_!>)8;Juys!(VXB04Gd@U-0!F^K(VaUjna#qWDxVT7 zE#%Z#h{nZHRO$)>!bpdr#!&hOlU2c-O=q0yC{U)6KQ|ZUV$mJo$#>81=|41e!C9}} z8K(uGrl3By^Ph;6ooz_{%FPW`-u>2xaeF(B3`IA;6j(CUj97D7G*z zVVpE`=rny8?9<0T{yj4dO0}xM9(u@ar>iVzzS&pae)0soPm!jRen&&PvpWdpvImji2KbIjk1}h6vXbvXt-_%S zq_Mi`#uBA_L|bqB&7ZHx$pGAQ;-&K1_n6n-(M$@h3sRpicLt6wkfA3JeZA_C-NA`E zJ7l|{o72)wb>7i*UOnw0(Gx(=9Cqi`kE(4)KDtBr{F?e9r%9`q{ye*FM+0~PECHw) zAq(mqETv-(oUcYaJ-8>B|DN$GlQE@X!IhlRCJHm-!@`fA`He38{5i1irL{8~w_$P` zN-&uEW9SF(!}#61IB4zR*%3WFQs@nmT4`{jqS0Eq_{ghek^p5csRHp0l_S&3(2utl z!|LsXBubH^1Q)OUPQ1pIf%uoi3%8y0cg(Q(f-VLS^<*Jb1M%l4?PPP;JPFvDz60h8 zEgj1wpSfytaUit(gt`+58HS)ZoH?`V35M&%2$`|A{%>un_BhBkt4o zISu9BJeR0Idu?^hgr9_8hhOq`vN`mlAWrTDqDX13KZHGAdzprh1UDMDlSfPYnLc}F zLwc1g=#oB%Tr>(t<4MP~iDAayXpwFE!#BmJkALzWd~&( zeSZ7l1AnUzyU&8r79k6H8~T$Pd9(4jZO8O_>Lopm`X_nRJ>mZXaAQ_v$qN7g@vxgX diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html index c3068300cd2..bd9b5163382 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html.gz index 5bfed6cbac9226d9519fee89e1129e884e383e35..e9b1d4676fc3285106ca5f6a4a0c1dd68940cc0d 100644 GIT binary patch literal 17861 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

+Zr@q!XF0WHqz}>-+w)76s(Z6rfsN;Q>*BUFL z!aZV|x(7jcOO!~rr~yM85l6}d+@W6iI0$0>-P<)NRM)JcNnK!io44&zF+M&DXDAcj z^gEQ8%z5YiBpEBO>y_>=WtwEr)6`P5EHc1cCE%|)yG>9%md}`L4(&83P@YnxuB7v^ z7J@c;;-f%>&tVDI+eu!+bhARayLVI-&#d@uwca!N-R ze6Dx+VKl;`$i(6rz(PG}YJ+E}eb7DB;gBcj#{rE4)Pt<2E+BC7bX6haleYzn*27HV ztOj=LK~rMjH3Kudeo)Aq7lGcb5|grBBr|Tc07Mgc78YIDjY@N^()ZDWZzj__kT?^1 z0cb-1CYZ2>Y_SlNQ710KWD`DdplSCN2q`Fnsv8MO&93n#C9-^7(E(lfQ;99$hsz8o zH*60avz6pNN@8m`gNwh2Rb2q1gN2A)g^xGzn;42ivo`k;zsYdlaP_gbQx2<*bf7jm zKkUZGhec7S@X9~nQFX@;x!E*uz#jk{86`L<&>{D&M|OgL0}~;d_cr;(y~(4ex)TZi zWXr_Y!0xwT)-YhRpCWCV}#P0v9#5G@U^>gonQm6mo0oSsovoZ`S`^#($N@KWr9 zx_lsTE>CYlIcWY#teX;h^*yuO@9*(c?uFf@ggL9vc)n2LORMVv zZowe@_tST8;{o?#&5FovyxS?WIoZ58d{TLVvF_C5>MU>g!KFPD>9Qpy5YXw`APnsB zxzn*-jE_0_ge~XE10Yih7}^ScViy`8?`Zxm7{~RE`W*~N| z9CWWBxwEF7oKqn^Ut3Hp=PAMXU}Y{1*8mT`0Ee_heUM{_Wr|W6WcF#Yo0ntL@w*nuSNQNa zCYtU`aohPawAH_#hMIQ}vL-O6HQw#uiylqR&es@b(WLJF#iUI>Wq%KQU8X2fDw6(a z*i>~(7jJL~s(neydnC2~nZwX|&)vuo+6>5c9m#loAhxmo{gU{u4zjjXSH(3t?s(Kp z@d};{PuJBuL0)1=9^j#!7fl}4_C-8?ktQnuXM_QTt|s?!IAQ~AX)*{7n21e>=S4R6 loW{}&wGr~}#BtKQ#+QK&`Bb3OMSD{m|38Gguj$DU0RZxB`(*$C diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html index da96f77d3d4..5e1c76cd5cf 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html @@ -1 +1 @@ -

\ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz index ee640b9c7cbe4c04892a5f5479e32d91c82a31c2..7afd9e352b6c07ab75a53fd651ad51516b2a1d4f 100644 GIT binary patch literal 2890 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 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html index e122c075f9d..97704f2eb40 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html @@ -1,2 +1,2 @@ \ No newline at end of file + clear: both;white-space:pre-wrap}.rendered.error{color:red}
Templates

Templates are rendered using the Jinja2 template engine with some Home Assistant specific extensions.

[[processed]]
\ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html.gz index fcfef9681b55ab6c060e4912e2b203e324ba8b66..c1d37f78c05be8f807b3053deecfc1aadc4f652f 100644 GIT binary patch delta 7315 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 F0086wWlI16 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-history.html b/homeassistant/components/frontend/www_static/panels/ha-panel-history.html index ac1979c3cb1..f1fe31fb6a5 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-history.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-history.html @@ -1,4 +1,4 @@ \ No newline at end of file + */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:after,.pika-single:before{content:" ";display:table}.pika-single:after{clear:both}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-inrange .pika-button{background:#D5E9F7}.is-startrange .pika-button{color:#fff;background:#6CB31D;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button,.is-outside-current-month .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help}} \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-history.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-history.html.gz index 589cf52692ce4accbe313b45d80b180badab17ac..1644f0ab51cb70fe72a5c452934a53c26361d7b9 100644 GIT binary patch literal 7297 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 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html.gz index 974200ba1f7cd466eb528561fcae0109777158da..95751cabbf8e95e5a511ee0d37806059beb47039 100644 GIT binary patch delta 17 YcmbQtJeiq8zMF$%*YduIjU3&K04|sXdjJ3c delta 17 YcmbQtJeiq8zMF$XSL1T{MviVq04Pudvj6}9 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html b/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html index c3fd949967a..0941409efa9 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html @@ -1,4 +1,4 @@ \ No newline at end of file + */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:after,.pika-single:before{content:" ";display:table}.pika-single:after{clear:both}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-inrange .pika-button{background:#D5E9F7}.is-startrange .pika-button{color:#fff;background:#6CB31D;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button,.is-outside-current-month .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help}} \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html.gz index 2844f1ce8e084fbfb3ab615bd4fe2e20f1210d2e..0d6da7658ce0b3207952ed51841445ae57ad9b2a 100644 GIT binary patch literal 8010 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 M2f;#|D+pHr0J^xjKL7v# literal 7904 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 KnF{+1RsaB?TWW9s diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-map.html b/homeassistant/components/frontend/www_static/panels/ha-panel-map.html index 42097a123a2..6af9a28c48b 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-map.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-map.html @@ -2,46 +2,14 @@ },_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,"leaflet-zoom-hide"),o.DomUtil.addClass(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e){o.DomUtil.setPosition(this._mapPane,new o.Point(0,0));var i=!this._loaded;this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset");var n=this._zoom!==e;this._moveStart(n)._move(t,e)._moveEnd(n),this.fire("viewreset"),i&&this.fire("load")},_moveStart:function(t){return t&&this.fire("zoomstart"),this.fire("movestart")},_move:function(t,e,n){e===i&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(o||n&&n.pinch)&&this.fire("zoom",n),this.fire("move",n)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return o.Util.cancelAnimFrame(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(e){if(o.DomEvent){this._targets={},this._targets[o.stamp(this._container)]=this;var i=e?"off":"on";o.DomEvent[i](this._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress",this._handleDOMEvent,this),this.options.trackResize&&o.DomEvent[i](t,"resize",this._onResize,this),o.Browser.any3d&&this.options.transform3DLimit&&this[i]("moveend",this._onMoveEnd)}},_onResize:function(){o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],s="mouseout"===e||"mouseover"===e,r=t.target||t.srcElement,a=!1;r;){if(i=this._targets[o.stamp(r)],i&&("click"===e||"preclick"===e)&&!t._simulated&&this._draggableMoved(i)){a=!0;break}if(i&&i.listens(e,!0)){if(s&&!o.DomEvent._isExternalTarget(r,t))break;if(n.push(i),s)break}if(r===this._container)break;r=r.parentNode}return n.length||a||s||!o.DomEvent._isExternalTarget(r,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!o.DomEvent._skipped(t)){var e="keypress"===t.type&&13===t.keyCode?"click":t.type;"mousedown"===e&&o.DomUtil.preventOutline(t.target||t.srcElement),this._fireDOMEvent(t,e)}},_fireDOMEvent:function(t,e,i){if("click"===t.type){var n=o.Util.extend({},t);n.type="preclick",this._fireDOMEvent(n,n.type,i)}if(!t._stopped&&(i=(i||[]).concat(this._findEventTargets(t,e)),i.length)){var s=i[0];"contextmenu"===e&&s.listens(e,!0)&&o.DomEvent.preventDefault(t);var r={originalEvent:t};if("keypress"!==t.type){var a=s instanceof o.Marker;r.containerPoint=a?this.latLngToContainerPoint(s.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=a?s.getLatLng():this.layerPointToLatLng(r.layerPoint)}for(var h=0;h0?Math.round(t-e)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(e))},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom(),n=o.Browser.any3d?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(e,Math.min(i,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){o.DomUtil.removeClass(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,e){var i=this._getCenterOffset(t)._floor();return!((e&&e.animate)!==!0&&!this.getSize().contains(i)||(this.panBy(i,e),0))},_createAnimProxy:function(){var t=this._proxy=o.DomUtil.create("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(e){var i=o.DomUtil.TRANSFORM,n=t.style[i];o.DomUtil.setTransform(t,this.project(e.center,e.zoom),this.getZoomScale(e.zoom,1)),n===t.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",function(){var e=this.getCenter(),i=this.getZoom();o.DomUtil.setTransform(t,this.project(e,i),this.getZoomScale(i,1))},this)},_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,e,i){if(this._animatingZoom)return!0;if(i=i||{},!this._zoomAnimated||i.animate===!1||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),s=this._getCenterOffset(t)._divideBy(1-1/n);return!(i.animate!==!0&&!this.getSize().contains(s)||(o.Util.requestAnimFrame(function(){this._moveStart(!0)._animateZoom(t,e,!0)},this),0))},_animateZoom:function(t,e,i,n){i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,o.DomUtil.addClass(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),setTimeout(o.bind(this._onZoomTransitionEnd,this),250)},_onZoomTransitionEnd:function(){this._animatingZoom&&(o.DomUtil.removeClass(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),o.Util.requestAnimFrame(function(){this._moveEnd(!0)},this))}}),o.map=function(t,e){return new o.Map(t,e)},o.Layer=o.Evented.extend({options:{pane:"overlayPane",nonBubblingEvents:[],attribution:null},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[o.stamp(t)]=this,this},removeInteractiveTarget:function(t){return delete this._map._targets[o.stamp(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var e=t.target;if(e.hasLayer(this)){if(this._map=e,this._zoomAnimated=e._zoomAnimated,this.getEvents){var i=this.getEvents();e.on(i,this),this.once("remove",function(){e.off(i,this)},this)}this.onAdd(e),this.getAttribution&&this._map.attributionControl&&this._map.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),e.fire("layeradd",{layer:this})}}}),o.Map.include({addLayer:function(t){var e=o.stamp(t);return this._layers[e]?this:(this._layers[e]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this)},removeLayer:function(t){var e=o.stamp(t);return this._layers[e]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[e],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null,this):this},hasLayer:function(t){return!!t&&o.stamp(t)in this._layers},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},_addLayers:function(t){t=t?o.Util.isArray(t)?t:[t]:[];for(var e=0,i=t.length;ethis._layersMaxZoom&&this.setZoom(this._layersMaxZoom),this.options.minZoom===i&&this._layersMinZoom&&this.getZoom()100&&n<500||t.target._simulatedClick&&!t._simulated?void o.DomEvent.stop(t):(o.DomEvent._lastClick=i,void e(t))}},o.DomEvent.addListener=o.DomEvent.on,o.DomEvent.removeListener=o.DomEvent.off,o.PosAnimation=o.Evented.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=o.Util.requestAnimFrame(this._animate,this),this._step()},_step:function(t){var e=+new Date-this._startTime,i=1e3*this._duration;e1e-7;l++)e=r*Math.sin(h),e=Math.pow((1-e)/(1+e),r/2),u=Math.PI/2-2*Math.atan(a*e)-h,h+=u;return new o.LatLng(h*i,t.x*i/n)}},o.CRS.EPSG3395=o.extend({},o.CRS.Earth,{code:"EPSG:3395",projection:o.Projection.Mercator,transformation:function(){var t=.5/(Math.PI*o.Projection.Mercator.R);return new o.Transformation(t,.5,-t,.5)}()}),o.GridLayer=o.Layer.extend({options:{tileSize:256,opacity:1,updateWhenIdle:o.Browser.mobile,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:i,noWrap:!1,pane:"tilePane",className:"",keepBuffer:2},initialize:function(t){o.setOptions(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView(),this._update()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),o.DomUtil.remove(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=null},bringToFront:function(){return this._map&&(o.DomUtil.toFront(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(o.DomUtil.toBack(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){return this._map&&(this._removeAllTiles(),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=o.Util.throttle(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return e.createElement("div")},getTileSize:function(){var t=this.options.tileSize;return t instanceof o.Point?t:new o.Point(t,t)},_updateZIndex:function(){this._container&&this.options.zIndex!==i&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var e,i=this.getPane().children,n=-t(-(1/0),1/0),o=0,s=i.length;othis.options.maxZoom||in&&this._retainParent(s,r,a,n))},_retainChildren:function(t,e,i,n){for(var s=2*t;s<2*t+2;s++)for(var r=2*e;r<2*e+2;r++){var a=new o.Point(s,r);a.z=i+1;var h=this._tileCoordsToKey(a),l=this._tiles[h];l&&l.active?l.retain=!0:(l&&l.loaded&&(l.retain=!0),i+1this.options.maxZoom||this.options.minZoom!==i&&s1)return void this._setView(t,s);for(var m=a.min.y;m<=a.max.y;m++)for(var p=a.min.x;p<=a.max.x;p++){var f=new o.Point(p,m);if(f.z=this._tileZoom,this._isValidTile(f)){var g=this._tiles[this._tileCoordsToKey(f)];g?g.current=!0:l.push(f)}}if(l.sort(function(t,e){return t.distanceTo(h)-e.distanceTo(h)}),0!==l.length){this._loading||(this._loading=!0,this.fire("loading"));var v=e.createDocumentFragment();for(p=0;pi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return o.latLngBounds(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToBounds:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),s=n.add(i),r=e.unproject(n,t.z),a=e.unproject(s,t.z);return this.options.noWrap||(r=e.wrapLatLng(r),a=e.wrapLatLng(a)),new o.LatLngBounds(r,a)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var e=t.split(":"),i=new o.Point(+e[0],+e[1]);return i.z=+e[2],i},_removeTile:function(t){var e=this._tiles[t];e&&(o.DomUtil.remove(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){o.DomUtil.addClass(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity<1&&o.DomUtil.setOpacity(t,this.options.opacity),o.Browser.android&&!o.Browser.android23&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),o.bind(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&o.Util.requestAnimFrame(o.bind(this._tileReady,this,t,null,s)),o.DomUtil.setPosition(s,i),this._tiles[n]={el:s,coords:t,current:!0},e.appendChild(s),this.fire("tileloadstart",{tile:s,coords:t})},_tileReady:function(t,e,i){if(this._map){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);i=this._tiles[n],i&&(i.loaded=+new Date,this._map._fadeAnimated?(o.DomUtil.setOpacity(i.el,0),o.Util.cancelAnimFrame(this._fadeFrame),this._fadeFrame=o.Util.requestAnimFrame(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(o.DomUtil.addClass(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),o.Browser.ielt9||!this._map._fadeAnimated?o.Util.requestAnimFrame(this._pruneTiles,this):setTimeout(o.bind(this._pruneTiles,this),250)))}},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new o.Point(this._wrapX?o.Util.wrapNum(t.x,this._wrapX):t.x,this._wrapY?o.Util.wrapNum(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new o.Bounds(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}}),o.gridLayer=function(t){return new o.GridLayer(t)},o.TileLayer=o.GridLayer.extend({options:{minZoom:0,maxZoom:18,maxNativeZoom:null,minNativeZoom:null,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,e){this._url=t,e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomReverse?(e.zoomOffset--,e.minZoom++):(e.zoomOffset++,e.maxZoom--),e.minZoom=Math.max(0,e.minZoom)),"string"==typeof e.subdomains&&(e.subdomains=e.subdomains.split("")),o.Browser.android||this.on("tileunload",this._onTileRemove)},setUrl:function(t,e){return this._url=t,e||this.redraw(),this},createTile:function(t,i){var n=e.createElement("img");return o.DomEvent.on(n,"load",o.bind(this._tileOnLoad,this,i,n)),o.DomEvent.on(n,"error",o.bind(this._tileOnError,this,i,n)),this.options.crossOrigin&&(n.crossOrigin=""),n.alt="",n.setAttribute("role","presentation"),n.src=this.getTileUrl(t),n},getTileUrl:function(t){var e={r:o.Browser.retina?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var i=this._globalTileRange.max.y-t.y;this.options.tms&&(e.y=i),e["-y"]=i}return o.Util.template(this._url,o.extend(e,this.options))},_tileOnLoad:function(t,e){o.Browser.ielt9?setTimeout(o.bind(t,this,null,e),0):t(null,e)},_tileOnError:function(t,e,i){var n=this.options.errorTileUrl;n&&(e.src=n),t(i,e)},getTileSize:function(){var t=this._map,e=o.GridLayer.prototype.getTileSize.call(this),i=this._tileZoom+this.options.zoomOffset,n=this.options.minNativeZoom,s=this.options.maxNativeZoom;return null!==n&&is?e.divideBy(t.getZoomScale(s,i)).round():e},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,e=this.options.maxZoom,i=this.options.zoomReverse,n=this.options.zoomOffset,o=this.options.minNativeZoom,s=this.options.maxNativeZoom;return i&&(t=e-t),t+=n,null!==o&&ts?s:t},_getSubdomain:function(t){var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e]},_abortLoading:function(){var t,e;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&(e=this._tiles[t].el,e.onload=o.Util.falseFn,e.onerror=o.Util.falseFn,e.complete||(e.src=o.Util.emptyImageUrl,o.DomUtil.remove(e)))}}),o.tileLayer=function(t,e){return new o.TileLayer(t,e)},o.TileLayer.WMS=o.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var i=o.extend({},this.defaultWmsParams);for(var n in e)n in this.options||(i[n]=e[n]);e=o.setOptions(this,e),i.width=i.height=e.tileSize*(e.detectRetina&&o.Browser.retina?2:1),this.wmsParams=i},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var e=this._wmsVersion>=1.3?"crs":"srs";this.wmsParams[e]=this._crs.code,o.TileLayer.prototype.onAdd.call(this,t)},getTileUrl:function(t){var e=this._tileCoordsToBounds(t),i=this._crs.project(e.getNorthWest()),n=this._crs.project(e.getSouthEast()),s=(this._wmsVersion>=1.3&&this._crs===o.CRS.EPSG4326?[n.y,i.x,i.y,n.x]:[i.x,n.y,n.x,i.y]).join(","),r=o.TileLayer.prototype.getTileUrl.call(this,t);return r+o.Util.getParamString(this.wmsParams,r,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+s},setParams:function(t,e){return o.extend(this.wmsParams,t),e||this.redraw(),this}}),o.tileLayer.wms=function(t,e){return new o.TileLayer.WMS(t,e)},o.ImageOverlay=o.Layer.extend({options:{opacity:1,alt:"",interactive:!1,crossOrigin:!1},initialize:function(t,e,i){this._url=t,this._bounds=o.latLngBounds(e),o.setOptions(this,i)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(o.DomUtil.addClass(this._image,"leaflet-interactive"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){o.DomUtil.remove(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._image),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=t,this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t=this._image=o.DomUtil.create("img","leaflet-image-layer "+(this._zoomAnimated?"leaflet-zoom-animated":""));t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,t.onload=o.bind(this.fire,this,"load"),this.options.crossOrigin&&(t.crossOrigin=""),t.src=this._url,t.alt=this.options.alt},_animateZoom:function(t){var e=this._map.getZoomScale(t.zoom),i=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min;o.DomUtil.setTransform(this._image,i,e)},_reset:function(){var t=this._image,e=new o.Bounds(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),i=e.getSize();o.DomUtil.setPosition(t,e.min),t.style.width=i.x+"px",t.style.height=i.y+"px"},_updateOpacity:function(){o.DomUtil.setOpacity(this._image,this.options.opacity); }}),o.imageOverlay=function(t,e,i){return new o.ImageOverlay(t,e,i)},o.Icon=o.Class.extend({initialize:function(t){o.setOptions(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(!i){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n=this._createImg(i,e&&"IMG"===e.tagName?e:null);return this._setIconStyles(n,t),n},_setIconStyles:function(t,e){var i=this.options,n=i[e+"Size"];"number"==typeof n&&(n=[n,n]);var s=o.point(n),r=o.point("shadow"===e&&i.shadowAnchor||i.iconAnchor||s&&s.divideBy(2,!0));t.className="leaflet-marker-"+e+" "+(i.className||""),r&&(t.style.marginLeft=-r.x+"px",t.style.marginTop=-r.y+"px"),s&&(t.style.width=s.x+"px",t.style.height=s.y+"px")},_createImg:function(t,i){return i=i||e.createElement("img"),i.src=t,i},_getIconUrl:function(t){return o.Browser.retina&&this.options[t+"RetinaUrl"]||this.options[t+"Url"]}}),o.icon=function(t){return new o.Icon(t)},o.Icon.Default=o.Icon.extend({options:{iconUrl:"marker-icon.png",iconRetinaUrl:"marker-icon-2x.png",shadowUrl:"marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return o.Icon.Default.imagePath||(o.Icon.Default.imagePath=this._detectIconPath()),(this.options.imagePath||o.Icon.Default.imagePath)+o.Icon.prototype._getIconUrl.call(this,t)},_detectIconPath:function(){var t=o.DomUtil.create("div","leaflet-default-icon-path",e.body),i=o.DomUtil.getStyle(t,"background-image")||o.DomUtil.getStyle(t,"backgroundImage");return e.body.removeChild(t),0===i.indexOf("url")?i.replace(/^url\([\"\']?/,"").replace(/marker-icon\.png[\"\']?\)$/,""):""}}),o.Marker=o.Layer.extend({options:{icon:new o.Icon.Default,interactive:!0,draggable:!1,keyboard:!0,title:"",alt:"",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:"markerPane",nonBubblingEvents:["click","dblclick","mouseover","mouseout","contextmenu"]},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on("zoomanim",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),this._zoomAnimated&&t.off("zoomanim",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var e=this._latlng;return this._latlng=o.latLng(t),this.update(),this.fire("move",{oldLatLng:e,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){if(this._icon){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,e="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),i=t.icon.createIcon(this._icon),n=!1;i!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(i.title=t.title),t.alt&&(i.alt=t.alt)),o.DomUtil.addClass(i,e),t.keyboard&&(i.tabIndex="0"),this._icon=i,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex});var s=t.icon.createShadow(this._shadow),r=!1;s!==this._shadow&&(this._removeShadow(),r=!0),s&&o.DomUtil.addClass(s,e),this._shadow=s,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),s&&r&&this.getPane("shadowPane").appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),o.DomUtil.remove(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&o.DomUtil.remove(this._shadow),this._shadow=null},_setPos:function(t){o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(e)},_initInteraction:function(){if(this.options.interactive&&(o.DomUtil.addClass(this._icon,"leaflet-interactive"),this.addInteractiveTarget(this._icon),o.Handler.MarkerDrag)){var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new o.Handler.MarkerDrag(this),t&&this.dragging.enable()}},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;o.DomUtil.setOpacity(this._icon,t),this._shadow&&o.DomUtil.setOpacity(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor||[0,0]},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor||[0,0]}}),o.marker=function(t,e){return new o.Marker(t,e)},o.DivIcon=o.Icon.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:"leaflet-div-icon"},createIcon:function(t){var i=t&&"DIV"===t.tagName?t:e.createElement("div"),n=this.options;if(i.innerHTML=n.html!==!1?n.html:"",n.bgPos){var s=o.point(n.bgPos);i.style.backgroundPosition=-s.x+"px "+-s.y+"px"}return this._setIconStyles(i,"icon"),i},createShadow:function(){return null}}),o.divIcon=function(t){return new o.DivIcon(t)},o.DivOverlay=o.Layer.extend({options:{offset:[0,7],className:"",pane:"popupPane"},initialize:function(t,e){o.setOptions(this,t),this._source=e},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,1),this.bringToFront()},onRemove:function(t){t._fadeAnimated?(o.DomUtil.setOpacity(this._container,0),this._removeTimeout=setTimeout(o.bind(o.DomUtil.remove,o.DomUtil,this._container),200)):o.DomUtil.remove(this._container)},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._container),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._container),this},_updateContent:function(){if(this._content){var t=this._contentNode,e="function"==typeof this._content?this._content(this._source||this):this._content;if("string"==typeof e)t.innerHTML=e;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(e)}this.fire("contentupdate")}},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),e=o.point(this.options.offset),i=this._getAnchor();this._zoomAnimated?o.DomUtil.setPosition(this._container,t.add(i)):e=e.add(t).add(i);var n=this._containerBottom=-e.y,s=this._containerLeft=-Math.round(this._containerWidth/2)+e.x;this._container.style.bottom=n+"px",this._container.style.left=s+"px"}},_getAnchor:function(){return[0,0]}}),o.Popup=o.DivOverlay.extend({options:{maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,className:""},openOn:function(t){return t.openPopup(this),this},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),t.fire("popupopen",{popup:this}),this._source&&(this._source.fire("popupopen",{popup:this},!0),this._source instanceof o.Path||this._source.on("preclick",o.DomEvent.stopPropagation))},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("popupclose",{popup:this}),this._source&&(this._source.fire("popupclose",{popup:this},!0),this._source instanceof o.Path||this._source.off("preclick",o.DomEvent.stopPropagation))},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return("closeOnClick"in this.options?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t="leaflet-popup",e=this._container=o.DomUtil.create("div",t+" "+(this.options.className||"")+" leaflet-zoom-animated");if(this.options.closeButton){var i=this._closeButton=o.DomUtil.create("a",t+"-close-button",e);i.href="#close",i.innerHTML="×",o.DomEvent.on(i,"click",this._onCloseButtonClick,this)}var n=this._wrapper=o.DomUtil.create("div",t+"-content-wrapper",e);this._contentNode=o.DomUtil.create("div",t+"-content",n),o.DomEvent.disableClickPropagation(n).disableScrollPropagation(this._contentNode).on(n,"contextmenu",o.DomEvent.stopPropagation),this._tipContainer=o.DomUtil.create("div",t+"-tip-container",e),this._tip=o.DomUtil.create("div",t+"-tip",this._tipContainer)},_updateLayout:function(){var t=this._contentNode,e=t.style;e.width="",e.whiteSpace="nowrap";var i=t.offsetWidth;i=Math.min(i,this.options.maxWidth),i=Math.max(i,this.options.minWidth),e.width=i+1+"px",e.whiteSpace="",e.height="";var n=t.offsetHeight,s=this.options.maxHeight,r="leaflet-popup-scrolled";s&&n>s?(e.height=s+"px",o.DomUtil.addClass(t,r)):o.DomUtil.removeClass(t,r),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),i=this._getAnchor();o.DomUtil.setPosition(this._container,e.add(i))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,e=parseInt(o.DomUtil.getStyle(this._container,"marginBottom"),10)||0,i=this._container.offsetHeight+e,n=this._containerWidth,s=new o.Point(this._containerLeft,-i-this._containerBottom);s._add(o.DomUtil.getPosition(this._container));var r=t.layerPointToContainerPoint(s),a=o.point(this.options.autoPanPadding),h=o.point(this.options.autoPanPaddingTopLeft||a),l=o.point(this.options.autoPanPaddingBottomRight||a),u=t.getSize(),c=0,d=0;r.x+n+l.x>u.x&&(c=r.x+n-u.x+l.x),r.x-c-h.x<0&&(c=r.x-h.x),r.y+i+l.y>u.y&&(d=r.y+i-u.y+l.y),r.y-d-h.y<0&&(d=r.y-h.y),(c||d)&&t.fire("autopanstart").panBy([c,d])}},_onCloseButtonClick:function(t){this._close(),o.DomEvent.stop(t)},_getAnchor:function(){return o.point(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}}),o.popup=function(t,e){return new o.Popup(t,e)},o.Map.mergeOptions({closePopupOnClick:!0}),o.Map.include({openPopup:function(t,e,i){return t instanceof o.Popup||(t=new o.Popup(i).setContent(t)),e&&t.setLatLng(e),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),o.Layer.include({bindPopup:function(t,e){return t instanceof o.Popup?(o.setOptions(t,e),this._popup=t,t._source=this):(this._popup&&!e||(this._popup=new o.Popup(e,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,e){if(t instanceof o.Layer||(e=t,t=this),t instanceof o.FeatureGroup)for(var i in this._layers){t=this._layers[i];break}return e||(e=t.getCenter?t.getCenter():t.getLatLng()),this._popup&&this._map&&(this._popup._source=t,this._popup.update(),this._map.openPopup(this._popup,e)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e=t.layer||t.target;if(this._popup&&this._map)return o.DomEvent.stop(t),e instanceof o.Path?void this.openPopup(t.layer||t.target,t.latlng):void(this._map.hasLayer(this._popup)&&this._popup._source===e?this.closePopup():this.openPopup(e,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)}}),o.Tooltip=o.DivOverlay.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return o.Browser.touch&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip",e=t+" "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=o.DomUtil.create("div",e)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e=this._map,i=this._container,n=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=i.offsetWidth,h=i.offsetHeight,l=o.point(this.options.offset),u=this._getAnchor();"top"===r?t=t.add(o.point(-a/2+l.x,-h+l.y+u.y,!0)):"bottom"===r?t=t.subtract(o.point(a/2-l.x,-l.y,!0)):"center"===r?t=t.subtract(o.point(a/2+l.x,h/2-u.y+l.y,!0)):"right"===r||"auto"===r&&s.xh&&(s=r,h=a);h>i&&(e[s]=1,this._simplifyDPStep(t,e,i,n,s),this._simplifyDPStep(t,e,i,s,o))},_reducePoints:function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;ne&&(i.push(t[n]),o=n);return oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n},_sqClosestPointOnSegment:function(t,e,i,n){var s,r=e.x,a=e.y,h=i.x-r,l=i.y-a,u=h*h+l*l;return u>0&&(s=((t.x-r)*h+(t.y-a)*l)/u,s>1?(r=i.x,a=i.y):s>0&&(r+=h*s,a+=l*s)),h=t.x-r,l=t.y-a,n?h*h+l*l:new o.Point(r,a)}},o.Polyline=o.Path.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,e){o.setOptions(this,e),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var e,i,n=1/0,s=null,r=o.LineUtil._sqClosestPointOnSegment,a=0,h=this._parts.length;ae)return r=(n-e)/i,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,e){return e=e||this._defaultShape(),t=o.latLng(t),e.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new o.LatLngBounds,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return o.Polyline._flat(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var e=[],i=o.Polyline._flat(t),n=0,s=t.length;n=2&&e[0]instanceof o.LatLng&&e[0].equals(e[i-1])&&e.pop(),e},_setLatLngs:function(t){o.Polyline.prototype._setLatLngs.call(this,t),o.Polyline._flat(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return o.Polyline._flat(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,e=this.options.weight,i=new o.Point(e,e);if(t=new o.Bounds(t.min.subtract(i),t.max.add(i)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t)){if(this.options.noClip)return void(this._parts=this._rings);for(var n,s=0,r=this._rings.length;s';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}(),o.SVG.include(o.Browser.vml?{_initContainer:function(){this._container=o.DomUtil.create("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(o.Renderer.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=o.SVG.create("shape");o.DomUtil.addClass(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=o.SVG.create("path"),e.appendChild(t._path),this._updateStyle(t)},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;o.DomUtil.remove(e),t.removeInteractiveTarget(e)},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,s=t._container;s.stroked=!!n.stroke,s.filled=!!n.fill,n.stroke?(e||(e=t._stroke=o.SVG.create("stroke")),s.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=o.Util.isArray(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(s.removeChild(e),t._stroke=null),n.fill?(i||(i=t._fill=o.SVG.create("fill")),s.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(s.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){o.DomUtil.toFront(t._container)},_bringToBack:function(t){o.DomUtil.toBack(t._container)}}:{}),o.Browser.vml&&(o.SVG.create=function(){try{return e.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return e.createElement("')}}catch(t){return function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}()),o.Canvas=o.Renderer.extend({onAdd:function(){o.Renderer.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=e.createElement("canvas");o.DomEvent.on(t,"mousemove",o.Util.throttle(this._onMouseMove,32,this),this).on(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this).on(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_updatePaths:function(){var t;this._redrawBounds=null;for(var e in this._layers)t=this._layers[e],t._update();this._redraw()},_update:function(){if(!this._map._animatingZoom||!this._bounds){this._drawnLayers={},o.Renderer.prototype._update.call(this);var t=this._bounds,e=this._container,i=t.getSize(),n=o.Browser.retina?2:1;o.DomUtil.setPosition(e,t.min),e.width=n*i.x,e.height=n*i.y,e.style.width=i.x+"px",e.style.height=i.y+"px",o.Browser.retina&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_initPath:function(t){this._updateDashArray(t),this._layers[o.stamp(t)]=t;var e=t._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=e),this._drawLast=e,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var e=t._order,i=e.next,n=e.prev;i?i.prev=n:this._drawLast=n,n?n.next=i:this._drawFirst=i,delete t._order,delete this._layers[o.stamp(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if(t.options.dashArray){var e,i=t.options.dashArray.split(","),n=[];for(e=0;et.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(u=!u);return u||o.Polyline.prototype._containsPoint.call(this,t,!0)},o.CircleMarker.prototype._containsPoint=function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()},o.GeoJSON=o.FeatureGroup.extend({initialize:function(t,e){o.setOptions(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,s=o.Util.isArray(t)?t:t.features;if(s){for(e=0,i=s.length;e1)return void(this._moved=!0);var n=i.touches&&1===i.touches.length?i.touches[0]:i,s=new o.Point(n.clientX,n.clientY),r=s.subtract(this._startPoint);(r.x||r.y)&&(Math.abs(r.x)+Math.abs(r.y)50&&(this._positions.shift(),this._times.shift())}this._map.fire("move",t).fire("drag",t)},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,e){return t-(t-e)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),e=this._offsetLimit;t.xe.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,r=Math.abs(o+i)0?s:-s))-e;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(e+r):t.setZoomAround(this._lastMousePos,e+r))}}),o.Map.addInitHook("addHandler","scrollWheelZoom",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart:o.Browser.msPointer?"MSPointerDown":o.Browser.pointer?"pointerdown":"touchstart",_touchend:o.Browser.msPointer?"MSPointerUp":o.Browser.pointer?"pointerup":"touchend",addDoubleTapListener:function(t,e,i){function n(t){var e;if(e=o.Browser.pointer?o.DomEvent._pointersCount:t.touches.length,!(e>1)){var i=Date.now(),n=i-(r||i);a=t.touches?t.touches[0]:t,h=n>0&&n<=l,r=i}}function s(){if(h&&!a.cancelBubble){if(o.Browser.pointer){var t,i,n={};for(i in a)t=a[i],n[i]=t&&t.bind?t.bind(a):t;a=n}a.type="dblclick",e(a),r=null}}var r,a,h=!1,l=250,u="_leaflet_",c=this._touchstart,d=this._touchend;return t[u+c+i]=n,t[u+d+i]=s,t[u+"dblclick"+i]=e,t.addEventListener(c,n,!1),t.addEventListener(d,s,!1),o.Browser.edge||t.addEventListener("dblclick",e,!1),this},removeDoubleTapListener:function(t,e){var i="_leaflet_",n=t[i+this._touchstart+e],s=t[i+this._touchend+e],r=t[i+"dblclick"+e];return t.removeEventListener(this._touchstart,n,!1),t.removeEventListener(this._touchend,s,!1),o.Browser.edge||t.removeEventListener("dblclick",r,!1),this}}),o.extend(o.DomEvent,{POINTER_DOWN:o.Browser.msPointer?"MSPointerDown":"pointerdown",POINTER_MOVE:o.Browser.msPointer?"MSPointerMove":"pointermove",POINTER_UP:o.Browser.msPointer?"MSPointerUp":"pointerup",POINTER_CANCEL:o.Browser.msPointer?"MSPointerCancel":"pointercancel",TAG_WHITE_LIST:["INPUT","SELECT","OPTION"],_pointers:{},_pointersCount:0,addPointerListener:function(t,e,i,n){return"touchstart"===e?this._addPointerStart(t,i,n):"touchmove"===e?this._addPointerMove(t,i,n):"touchend"===e&&this._addPointerEnd(t,i,n),this},removePointerListener:function(t,e,i){var n=t["_leaflet_"+e+i];return"touchstart"===e?t.removeEventListener(this.POINTER_DOWN,n,!1):"touchmove"===e?t.removeEventListener(this.POINTER_MOVE,n,!1):"touchend"===e&&(t.removeEventListener(this.POINTER_UP,n,!1),t.removeEventListener(this.POINTER_CANCEL,n,!1)),this},_addPointerStart:function(t,i,n){var s=o.bind(function(t){if("mouse"!==t.pointerType&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(this.TAG_WHITE_LIST.indexOf(t.target.tagName)<0))return;o.DomEvent.preventDefault(t)}this._handlePointer(t,i)},this);if(t["_leaflet_touchstart"+n]=s,t.addEventListener(this.POINTER_DOWN,s,!1),!this._pointerDocListener){var r=o.bind(this._globalPointerUp,this);e.documentElement.addEventListener(this.POINTER_DOWN,o.bind(this._globalPointerDown,this),!0),e.documentElement.addEventListener(this.POINTER_MOVE,o.bind(this._globalPointerMove,this),!0),e.documentElement.addEventListener(this.POINTER_UP,r,!0),e.documentElement.addEventListener(this.POINTER_CANCEL,r,!0),this._pointerDocListener=!0}},_globalPointerDown:function(t){this._pointers[t.pointerId]=t,this._pointersCount++},_globalPointerMove:function(t){this._pointers[t.pointerId]&&(this._pointers[t.pointerId]=t)},_globalPointerUp:function(t){delete this._pointers[t.pointerId],this._pointersCount--},_handlePointer:function(t,e){t.touches=[];for(var i in this._pointers)t.touches.push(this._pointers[i]);t.changedTouches=[t],e(t)},_addPointerMove:function(t,e,i){var n=o.bind(function(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&this._handlePointer(t,e)},this);t["_leaflet_touchmove"+i]=n,t.addEventListener(this.POINTER_MOVE,n,!1)},_addPointerEnd:function(t,e,i){var n=o.bind(function(t){this._handlePointer(t,e)},this);t["_leaflet_touchend"+i]=n,t.addEventListener(this.POINTER_UP,n,!1),t.addEventListener(this.POINTER_CANCEL,n,!1)}}),o.Map.mergeOptions({touchZoom:o.Browser.touch&&!o.Browser.android23,bounceAtZoomLimits:!0}),o.Map.TouchZoom=o.Handler.extend({addHooks:function(){o.DomUtil.addClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){o.DomUtil.removeClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var n=i.mouseEventToContainerPoint(t.touches[0]),s=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(n.add(s)._divideBy(2))),this._startDist=n.distanceTo(s),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),o.DomEvent.on(e,"touchmove",this._onTouchMove,this).on(e,"touchend",this._onTouchEnd,this),o.DomEvent.preventDefault(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var e=this._map,i=e.mouseEventToContainerPoint(t.touches[0]),n=e.mouseEventToContainerPoint(t.touches[1]),s=i.distanceTo(n)/this._startDist;if(this._zoom=e.getScaleZoom(s,this._startZoom),!e.options.bounceAtZoomLimits&&(this._zoome.getMaxZoom()&&s>1)&&(this._zoom=e._limitZoom(this._zoom)),"center"===e.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=i._add(n)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=e.unproject(e.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(e._moveStart(!0),this._moved=!0),o.Util.cancelAnimFrame(this._animRequest);var a=o.bind(e._move,e,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=o.Util.requestAnimFrame(a,this,!0),o.DomEvent.preventDefault(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,o.Util.cancelAnimFrame(this._animRequest),o.DomEvent.off(e,"touchmove",this._onTouchMove).off(e,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}}),o.Map.addInitHook("addHandler","touchZoom",o.Map.TouchZoom),o.Map.mergeOptions({tap:!0,tapTolerance:15}),o.Map.Tap=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){o.DomEvent.off(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if(o.DomEvent.preventDefault(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new o.Point(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,"leaflet-active"),this._holdTimeout=setTimeout(o.bind(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),o.DomEvent.on(e,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),o.DomEvent.off(e,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],n=i.target;n&&n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var e=t.touches[0];this._newPos=new o.Point(e.clientX,e.clientY),this._simulateEvent("mousemove",e)},_simulateEvent:function(i,n){var o=e.createEvent("MouseEvents");o._simulated=!0,n.target._simulatedClick=!0,o.initMouseEvent(i,!0,!0,t,1,n.screenX,n.screenY,n.clientX,n.clientY,!1,!1,!1,!1,0,null),n.target.dispatchEvent(o)}}),o.Browser.touch&&!o.Browser.pointer&&o.Map.addInitHook("addHandler","tap",o.Map.Tap),o.Map.mergeOptions({boxZoom:!0}),o.Map.BoxZoom=o.Handler.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane},addHooks:function(){o.DomEvent.on(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){o.DomEvent.off(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_resetState:function(){this._moved=!1},_onMouseDown:function(t){ -return!(!t.shiftKey||1!==t.which&&1!==t.button)&&(this._resetState(),o.DomUtil.disableTextSelection(),o.DomUtil.disableImageDrag(),this._startPoint=this._map.mouseEventToContainerPoint(t),void o.DomEvent.on(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this))},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=o.DomUtil.create("div","leaflet-zoom-box",this._container),o.DomUtil.addClass(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var e=new o.Bounds(this._point,this._startPoint),i=e.getSize();o.DomUtil.setPosition(this._box,e.min),this._box.style.width=i.x+"px",this._box.style.height=i.y+"px"},_finish:function(){this._moved&&(o.DomUtil.remove(this._box),o.DomUtil.removeClass(this._container,"leaflet-crosshair")),o.DomUtil.enableTextSelection(),o.DomUtil.enableImageDrag(),o.DomEvent.off(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){setTimeout(o.bind(this._resetState,this),0);var e=new o.LatLngBounds(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(e).fire("boxzoomend",{boxZoomBounds:e})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}}),o.Map.addInitHook("addHandler","boxZoom",o.Map.BoxZoom),o.Map.mergeOptions({keyboard:!0,keyboardPanDelta:80}),o.Map.Keyboard=o.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex="0"),o.DomEvent.on(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),o.DomEvent.off(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){if(!this._focused){var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollLeft||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanDelta:function(t){var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;e0&&t.screenY>0&&this._map.getContainer().focus()}}),o.control=function(t){return new o.Control(t)},o.Map.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){function t(t,s){var r=i+t+" "+i+s;e[t+s]=o.DomUtil.create("div",r,n)}var e=this._controlCorners={},i="leaflet-",n=this._controlContainer=o.DomUtil.create("div",i+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){o.DomUtil.remove(this._controlContainer)}}),o.Control.Zoom=o.Control.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"-",zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=o.DomUtil.create("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,s){var r=o.DomUtil.create("a",i,n);return r.innerHTML=t,r.href="#",r.title=e,r.setAttribute("role","button"),r.setAttribute("aria-label",e),o.DomEvent.on(r,"mousedown dblclick",o.DomEvent.stopPropagation).on(r,"click",o.DomEvent.stop).on(r,"click",s,this).on(r,"click",this._refocusOnMap,this),r},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMinZoom())&&o.DomUtil.addClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMaxZoom())&&o.DomUtil.addClass(this._zoomInButton,e)}}),o.Map.mergeOptions({zoomControl:!0}),o.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl))}),o.control.zoom=function(t){return new o.Control.Zoom(t)},o.Control.Attribution=o.Control.extend({options:{position:"bottomright",prefix:'Leaflet'},initialize:function(t){o.setOptions(this,t),this._attributions={}},onAdd:function(t){t.attributionControl=this,this._container=o.DomUtil.create("div","leaflet-control-attribution"),o.DomEvent&&o.DomEvent.disableClickPropagation(this._container);for(var e in t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this},_update:function(){if(this._map){var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(", ")),this._container.innerHTML=i.join(" | ")}}}),o.Map.mergeOptions({attributionControl:!0}),o.Map.addInitHook(function(){this.options.attributionControl&&(new o.Control.Attribution).addTo(this)}),o.control.attribution=function(t){return new o.Control.Attribution(t)},o.Control.Scale=o.Control.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=o.DomUtil.create("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=o.DomUtil.create("div",e,i)),t.imperial&&(this._iScale=o.DomUtil.create("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,i=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(i)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t),i=e<1e3?e+" m":e/1e3+" km";this._updateScale(this._mScale,i,e/t)},_updateImperial:function(t){var e,i,n,o=3.2808399*t;o>5280?(e=o/5280,i=this._getRoundNum(e),this._updateScale(this._iScale,i+" mi",i/e)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,e,i){t.style.width=Math.round(this.options.maxWidth*i)+"px",t.innerHTML=e},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+"").length-1),i=t/e;return i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1,e*i}}),o.control.scale=function(t){return new o.Control.Scale(t)},o.Control.Layers=o.Control.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,e,i,n){return i1,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=e&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var e=this._getLayer(o.stamp(t.target)),i=e.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;i&&this._map.fire(i,e)},_createRadioElement:function(t,i){var n='",o=e.createElement("div");return o.innerHTML=n,o.firstChild},_addItem:function(t){var i,n=e.createElement("label"),s=this._map.hasLayer(t.layer);t.overlay?(i=e.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=s):i=this._createRadioElement("leaflet-base-layers",s),i.layerId=o.stamp(t.layer),o.DomEvent.on(i,"click",this._onInputClick,this);var r=e.createElement("span");r.innerHTML=" "+t.name;var a=e.createElement("div");n.appendChild(a),a.appendChild(i),a.appendChild(r);var h=t.overlay?this._overlaysList:this._baseLayersList;return h.appendChild(n),this._checkDisabledLayers(),n},_onInputClick:function(){var t,e,i,n=this._form.getElementsByTagName("input"),o=[],s=[];this._handlingClick=!0;for(var r=n.length-1;r>=0;r--)t=n[r],e=this._getLayer(t.layerId).layer,i=this._map.hasLayer(e),t.checked&&!i?o.push(e):!t.checked&&i&&s.push(e);for(r=0;r=0;s--)t=n[s],e=this._getLayer(t.layerId).layer,t.disabled=e.options.minZoom!==i&&oe.options.maxZoom},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),o.control.layers=function(t,e,i){return new o.Control.Layers(t,e,i)}}(window,document) \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-map.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-map.html.gz index f542d52730d373d1ac0f41b2ec48a07c830b33a1..1a7bc76bc0da87e26944a2cdd7bdc0e39d7cec21 100644 GIT binary patch delta 14549 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 delta 14658 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 E0AMtz^Z)<= diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index 3c0d0ab8b0d..4a39f9d0276 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","23137dada0d5b1e147f988eb63607368"],["/frontend/panels/dev-event-f19840b9a6a46f57cb064b384e1353f5.html","21cf247351b95fdd451c304e308a726c"],["/frontend/panels/dev-info-3765a371478cc66d677cf6dcc35267c6.html","dd614f2ee5e09a9dfd7f98822a55893d"],["/frontend/panels/dev-service-1d223225c1c75083738033895ea3e4b5.html","3c6d75bd5b2e38bb73391f71ea338496"],["/frontend/panels/dev-state-8257d99a38358a150eafdb23fa6727e0.html","3cf24bb7e92c759b35a74cf641ed80cb"],["/frontend/panels/dev-template-cbb251acabd5e7431058ed507b70522b.html","edd6ef67f4ab763f9d3dd7d3aa6f4007"],["/frontend/panels/map-13f120066c0b5faa2ce1db2c3f3cc486.html","e14d872bfdc0372b5f04cefe1ed3b7a6"],["/static/core-769f3fdd4e04b34bd66c7415743cf7b5.js","08e08915eed6697b16c07725fd9b43cb"],["/static/frontend-d48d9a13f7d677e59b1d22c6db051207.html","2d297277e12f77a102ad2694dff4adfd"],["/static/mdi-5bb2f1717206bad0d187c2633062c575.html","fd915b78a66e34026eb1eebfe58157d8"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","89313f9f2126ddea722150f8154aca03"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},createCacheKey=function(e,t,n,a){var c=new URL(e);return a&&c.toString().match(a)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,t){var n=new URL(e);return n.search=n.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),n.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],a=new URL(t,self.location),c=createCacheKey(a,hashParamName,n,!1);return[a.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(n){if(!t.has(n))return e.add(new Request(n,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(n){return Promise.all(n.map(function(n){if(!t.has(n.url))return e.delete(n)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,n=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(n);var a="index.html";!t&&a&&(n=addDirectoryIndex(n,a),t=urlsToCacheKeys.has(n));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(n=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(n)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var n,a;for(n=0;nn!PY&O%T%{4hDKe%2Gjt7YeMXDrZ$F=>x_komT$+D8&=}ZzaAn}gx9p3|-RSSdG zG=((IM6W7oinYN`PQ-{87+y}-<&ayJ|HK3MSO<1bcC zdFS07-&(=d;3F7Z!Oym~RJAE|A-Vm}%S))t3tpCj%Wp3D#=Fr)1MgSue7kzXyM3o7 z=pTH=4afiO$_eb6Z}{xtIxhLii14fo9;Gm^;rGwYon2=f`(%1DiS346W#ccFCK;vH@u`2Q}zoHa$CY#*Xjk zgi-=5<5?1GNL5I~C`%*<9>yuzhq~#^QsX7BplrtqE=OQvK8j^VSr`f?bsRCC zQ>i1Gr*W7-6o-&@D4-r9M3PCSbSz24!j#iE4tXdgXSs-2d|Xda>3T#{;1QurWITpY zq**TWkO8HdkQ`#VQA2r@CX9(tB)Ef1AVTF)q;!go<(wQ>(?WAuNEqchjq-%W5R;5Y zlBao2&>x{dD?vhj?~qIhh%}+0OhroaOshzwd77w1NWy-g$#4UsEKeCh5owyrP{ff? zGKMT;T4#`kN^JB*p=4>2D3PWK#0)W@5ka6OV=UHTdR&iz#j>=j@>Hj(NOH|VXEH`_ zWSB>cE1o7^QKn1#lhaG*fBLI560gyK!JdNusD0L?%imse~-n z6hPZhhmdow6TGn+jc&(HEoxJbKXgB%U+Yo@#%L6! z7|o^31dEa+#iEFK9!HdN&J_`1!hR;|bupWpwX9Sif?1{s6(BP#R~?2xG2t1-WD8rt>Q`8F9Exc%FR(1Hp}7#VwKbeYG$V>g zg7u;pcH<)LM|rMy=gS7L?R8_)zubpYz_`Xc zai-2=Z@B0Aa?jkNeUH9;nPVtRL>bfrd=3Gp5;Z^e zp$Ty0Xs+*Hna!&w*twv^0rf0A_qtK`sIISdQEgQ9&uH3%{F(E1-eJ&}$;D2cI6e-` z?WcN^Ty2NO8`QQxUL6==uDejOkUFWd)c2A8~C0Ul!>M38q?fMG@$Yz1w@i9Wg( z#t-nHmCXR|-yn1fy)Jm!o;oesKf-Z&R^aH2FSgc*G>njJL>i!&@eRe!VAlq-n z@(W_rr-$9(9|72&Y%Vcy`v~{3-<+b3x;*(mB5~yS#~;O?{|H=r8r%W6Kjq*ze*`F5 z7M7LpmlunlK-C?X_HjZhoWH;Py80)(Mfrp;O@$F|!G>?<11LaCpE2 z?wRwu>ppwp_SAoiXUkjLB+A?MVddhgZoWZ-3DP7 zbmW7kv)e?DdgL2>C~lxdGE-j)Gyn5>+Vjps`7`L4@o*pJ1Z=Z$V&+YKHF()HHD=JK zISe|LYS3HM!obYA8C>yp0N(Dixw|{A!f$d9lmk@TsRQF{c!v+5cqW$hdXcbKSOD@ IH>VT;0Beka-2eap literal 2329 zcmV+!3Fh`6iwFpI?}}Ig19N3^c4=c}Uw3bEYh`jSYI6XkSZkA;$QAu7GL@AfgAh#v z4Wp=BUau>0;#c`m{xI>n`f*#rMxa1z#*>-(@3{?Zl%h$aMRq!xsP+ZomC5i z)-;7Q&P1;&X^OfUv|!%oXI#!feQe6s1@EQ-vudgV1mEDgb-lpMp>j7L>}^=^eB<5dqJg)ocD`M`;oW!V zCg>l0#SO>*?aB%4ns4~*;W{q)=6VU|aOWTSB=~w|c1%0a-C3ld1Ow>r<_kZZPN#3g zSCFPhuYctQB~&vr9}d@BWnEz;R?^hX_JiSYPn@s8$hqr``LY;y=3NJKvnZ3XT-)II zHw!THTAe#@-@O0e_;cV2n)ckH`;Y$Fy>Xt^l|d{=AJAFn+~Lb*xps8?wXG}1f4V{; zP4VAu?cDhlcmvJAIWu>jFKTst{?GSsUI#XFsu^0*2knwKgJlEKW)5o5#cXyO9Y}80nLP9l;%V;g4@vhJpF+t!wrnGC}AqkIn8L2agv0< zwGt84JY^As@Lmt%hTi zDdTJ#9?UP5u}EkoLyEtN4r2)#&=)EgUxQ`=D&$z!4UAZtYijcaLQJbzDAd7XlAs$> zGYrSq7UhN+gjr4!0DPY_LC_G!B22Vg;6|}0cjLfF#hJ=E+Rkh~0fK9Tk8u@Yg6^SZPEGQ*2NALKUL~0oQ~P7KN$cDpVw6GD;~8(?}+4n?qSKN+9p1Yaw#)}D8&F0 z67xKXG3_~51WS_sOw`L_HaBZo2&)!Zh9MOoGZIrBh7b`Uu`VJK#Xpnv3RJOLtc784 zv2F+p8Odd&Ws;>yNPsaW6sE&Z4SNT(Rmq#RG>$37@*Jy9aGj7m)m)H-i%da=i7j`f z6}E4WHNUhEBa%no@o%uKW+*2nc^*=cAw*~pXAor}dMF?d2_Y;wDJQ^xY{JD6#p34- zwSsjEBPRt!LZ*2t^&UjUg3q8uB52f?1wzBWU|C*6^F_?o)^Hj}8Bs(MYz7MZ2T$V& zP048pDdBuq+7$>{FP3$M-M1Z;g+XF3s=f@c!(le(8iSN71=v_4Y%Cg+DaPs#5$n%> z#{sYT0;W!THQJEE=rS6OoHMtDQU?vp3M7z@VV)eU1g)%*h#klCi&=#=ij&A&-k?N- z6!wZE4*hC}y$`D|)D9|wf`eMfn&cjwCnu`mo) zzT7jnXy2kQpXM0K5>W>A0G~p;c2I%!SmO1@J_;xMz!`6g$z(g)we65}sq1T9R2x8fbuMP~b(3z<<(68`^U|HNp&hLt>touO^^JBW7!Y<#p3A6YS*`R;HcZ~Pt=R41v zbn>w7y1D$NO{xkpbqbtgaU6C0UCSW2;)VHGnWA(%5843hyK=XU;`G7b@Hp~d>o!7z zw@tk$S_n|R`?P8Jb$~Rya37!R z4ML~T>w=f80o!bxn0ZrQ4W2hmjT!V|4uejm8uS*m zFfem&23Nct!1pBv3SSlN029AO#{#F%VA)x4q(|8~uP$vBHkJGMS-mP%_3y`KV9|zq z9lFNz_Ajk7upO+o;C%4Qo5%ZTBVVpB1-8pwL7c9L<*J<@X&jUOh5>_z{IR~fXl?2F zyZz$Gm^QDkUhiC#xJZ(PDJ_v7!hCpJ)7`c>nC(zpf^ycEGWH&3eQ#rb>}AaT{fqab zdf&aX!9HOxL=Ig&eW&Df-&jMyI=*)UB+I%5_h7k4?Z~1H&l=97@A@p?>BZ}|)}`)K zY@lm!uCPsXEOLlvH!1mig1Le<7f!0bZN|4rb#~@qR&$&JDx3nWLTm=85?M*ETI@Xo zzR7qVbZf3R!7nyu*joG4sorcmeB=JPa3FsB;rL-7aCaAnJ8$wo Date: Sun, 29 Jan 2017 23:26:35 -0800 Subject: [PATCH 010/157] Update frontend (#5638) * Ensure fonts get loaded quicker * Update frontend --- .../components/frontend/templates/index.html | 3 +++ homeassistant/components/frontend/version.py | 4 ++-- .../components/frontend/www_static/core.js | 2 +- .../components/frontend/www_static/core.js.gz | Bin 2366 -> 2414 bytes .../frontend/www_static/frontend.html | 4 ++-- .../frontend/www_static/frontend.html.gz | Bin 137113 -> 137242 bytes .../www_static/home-assistant-polymer | 2 +- .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2338 -> 2339 bytes 9 files changed, 10 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/frontend/templates/index.html b/homeassistant/components/frontend/templates/index.html index 4b1aa2033ea..05e33dc5dcc 100644 --- a/homeassistant/components/frontend/templates/index.html +++ b/homeassistant/components/frontend/templates/index.html @@ -10,6 +10,9 @@ href='/static/icons/favicon-apple-180x180.png'> + + + {% for panel in panels.values() -%} {% endfor -%} diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 40c89a9739d..9289ace07fa 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -1,8 +1,8 @@ """DO NOT MODIFY. Auto-generated by script/fingerprint_frontend.""" FINGERPRINTS = { - "core.js": "ff2b54b939ec12826a671d7630579724", - "frontend.html": "216d2fb1c6dc67ce85f2eefbdef0e9af", + "core.js": "40a73d7be324cb52fbba55d993db126c", + "frontend.html": "ee127d284ce3d29b2162d499ca45ef88", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", diff --git a/homeassistant/components/frontend/www_static/core.js b/homeassistant/components/frontend/www_static/core.js index 2e8d6635872..e6fe289666a 100644 --- a/homeassistant/components/frontend/www_static/core.js +++ b/homeassistant/components/frontend/www_static/core.js @@ -1 +1 @@ -!(function(){"use strict";function e(e){return{type:"auth",api_password:e}}function n(){return{type:"get_states"}}function t(){return{type:"get_config"}}function r(){return{type:"get_services"}}function i(){return{type:"get_panels"}}function s(e,n,t){var r={type:"call_service",domain:e,service:n};return t&&(r.service_data=t),r}function o(e){var n={type:"subscribe_events"};return e&&(n.event_type=e),n}function c(e){return{type:"unsubscribe_events",subscription:e}}function u(){return{type:"ping"}}function a(e,n){return{type:"result",success:!1,error:{code:e,message:n}}}function f(e){return e.result}function d(e,n){var t=new P(e,n);return t.connect()}function v(e,n){return e._subscribeConfig?e._subscribeConfig(n):new Promise(function(t,r){function i(e){a=Object.assign({},a,e);for(var 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 literal 2366 zcmV-E3BmRsiwFq1r;b5m zV3aM4yM%+hRVfmK3H)b#loMtq3g1C^6}8t+ry#FyvM zh2ZNn5BCRnPt4+~$>9sY)K3sG0R?eJ6N3A~^(F^5-fM@KJ`5l&{Rs~sl}jHJYM#EC zysn<^N+mv-l0dJx^c&~b*~lm7Q#8(GJO$J6$uHB!u+;KIsA;_y1;!@C%_cyCgiV8d zy9NnA4TMbj-?te1bWG@Z9LH6_j7AFxX4K1K^bcLwuQZ-a>CXI)Bw}rgdlYC#^h*w3<7u>rTT9(!JB$7W;Urf+@Dod)JP05Pd{4pS z2UrSA)1zW~$RGvS9CuIXz)Pq&=3V3aHTs~T28d$~{GdPZiXSxaLs?MxL{B3*Q30$+ z=%<-Tr?EPe&Q0{@<=AUfD0qG`H24;t zZTKmv^U$&rRDxz-kdQI}Oxq?zNvtlmegbge3chs1%L42!KCsH}0_@HvV(KTPRpOmZ zAw8Jh!ylrCBu3wMXrH;X&ye<$HWy@If<5FftGIyGTp(*MU^N%`g(0e!;yG_qKxJyf z6qZO5%OHjQVn`&5nn>6nk<=(hsDyQ?Bta?xZl;SjP)Sx($>KFC5kL{>i&?T_a%tGX zaCTo`iyfjO7B6Laek9AYw`KXV)x_Z1wertFaphYt@Z2ca49T~p&&H1Ylbfykx(Sp4 z)6jFz3y9GsBLWD?YnH5>eaVJmx8$v!?n@u=X`dOR{+2PuRr_D61X7 zp<+kgQf0-~gQ#A@n+s_JN03lsJr}4}26?7jH?+CM*(016xOyjhLl&jK6g~{|lBr-y z&3Sxk{7mTHY$AthUr6(lr=fOee}W!>f#8I9VUt|^9)BBbl* zYuC>|?PA?3S*^A11b-ZjN;liEdd0u>s$myDF5Znp*%=y#KOY2!@E+nZy^VjNSMjg( zTijNwS0WDzwT?M8KQq&v0$rNs)eJ$;vSBj)oC1tHkjIULId#Cqdxb1{Zil(cF^=>) z%lUWySHa;;8lRS^3!!rCO-rQs^!yNg3$`lL86K#5q}ADo4YmQj5Vnzie)f;O1V=*% zRJ4DfuFio%^A@#Gv+K~%PGO4_l!$lZ(MVTiPeH9av~`0$tme4ifup|2AJ+Q(3>$hm z`Aar$sVjZxwvCRiDua(UE0*G99UGCGG~&p5tO9|il3;6`fVpCS`OLqfUK0=}5H{K~ z8EeivIYdq*yRml$L5c~MJaBtL{*%w|%#$xM&Pn}tpbBPNF1=QXll`zn{9eFUd3^-9 zJnFmHncaR8|9*FS6Kt6RlV+x&BT@b+G}tN$&@<3lv7CFx&tBMAc#;G_de;9}&?d}T z@&HrJGl}L<(H|l+v%H81lc2ncxafg^NVeW##}W>_Gu{AXyuBc_EC*dVS0fy8mR{%# z;5`?dW&SDzo@78r&Sm=58pVfjtY{}d!Taoi<9WC{U&tL>3z)9_TWEKHAbKL%gBNOS z-eillWQ($XHZrx1Ol?hi53a!A>~>~O3-J#<5vlu5nIL<&vZ1BtNN?gck)+F4yH@=^f1PLqi|9`j%S`IYHa zun|zby9o4O5Yk-Viw)0;!TwS@7gx}E+b+0EP`D+Ro(79aS$ayVnYVris6NNU{e{@c zO>kCZ2O_067XxVJO~)JX)Ju5wO6Cn{;w7~1CCIC2`Y0OS?UtKul|j4&eg(9;Ebbt7 zvgv4Xjb4Gr0}45M^x3ykG~~2SQPaZKiwFmdG^8zo<`TL}(m&f(y>dg2C~5lUgL_Ns zzJw!LU$1a^!Y_}7uI2Cw`VCHngLBvPjZmw@aPtRcd{dzC&kVT~3+S6)04lW|>sVgx zA{^R=LLPORiqB~Thr$%>GIFJ_@35JcXzXo*I#e3i9)k{iOV;3KcC>B \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 32bc37123a6bd4249e49200cdc42c70f81a2bcf5..5e0bfda85c5ec69d2b55df35d8a7c5cb33e705fe 100644 GIT binary patch delta 78826 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

3?H8 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 Y7xEAJ{0?t&AbTDBe|+@OgA|Gg0EwvLzyJUM delta 78736 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index a1057681f1a..e4b2ec1710d 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit a1057681f1a33cffc79708085c1646d786712a87 +Subproject commit e4b2ec1710da8d6e134f9846813833e6d7ce2929 diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index 4a39f9d0276..c090fa12098 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","f6221e38a865fe7d020486caea554d30"],["/frontend/panels/dev-event-5c82300b3cf543a92cf4297506e450e7.html","1bb68c3df5c14307a2550a0cca39b435"],["/frontend/panels/dev-info-27ea4123b8a5e0b789c903e22f119e52.html","2a47633b0b67eaace1bd944df70209a1"],["/frontend/panels/dev-service-9f749635e518a4ca7991975bdefdb10a.html","1bc71eb7620c7b7198fd4b7976d6bc13"],["/frontend/panels/dev-state-89731c71777c0b54bdc5e883ff8e70db.html","40c3766db776e531232413a9c3335f07"],["/frontend/panels/dev-template-97f77b69faef8c5975c09431912831cc.html","5a4848a193ba4aed4359bb3e0e05bac6"],["/frontend/panels/map-9c8c7924ba8f731560c9f4093835cc26.html","8ae4874622d23d995ddf2a8b0ffa8d80"],["/static/core-ff2b54b939ec12826a671d7630579724.js","92db0b7b4404755fbeaf0928d793ae3e"],["/static/frontend-216d2fb1c6dc67ce85f2eefbdef0e9af.html","018592a2337e9f2a2e4306cec7ef0aea"],["/static/mdi-7a0f14bbf3822449f9060b9c53bd7376.html","8d60ec43a3f8a77b21c312783ae5b892"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","89313f9f2126ddea722150f8154aca03"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.toString().match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a))return e.add(new Request(a,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);var n="index.html";!t&&n&&(a=addDirectoryIndex(a,n),t=urlsToCacheKeys.has(a));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,n;for(a=0;a%Lkws{5NOF5i*=YD*JEI@EUl_Mf7NL!l3a7p znT*jJ8RiiqIiVTaAUCRF9%WI+NzMe1I4BHDE(C)R!WdIHIjjoX$|#qaOmi9uo@sO| zPC}XMD9l;LVkv2|(U5V7vNTF4Rg|ebkCoDtXCl;^XDSPO4Hlq6j%D4zC<=MXR4M@7 zmLjHF2p-3{m0>h!B7?83f6ZbHbIS5K%pgl?%o$+zrg0SUIMZa4U2C};2Sxydrix~f z1g2;%C`qV_@?7#LMx?Th)l7#ni>M??jQJ1I<8BdZO=?hhiQXXm&387g= zX%yu;50g;jGG^Ay^Z^c)gdnkOn9ewch!TkbPBX>tZ%HYgws?wa5@SDnMpft~v|> zot2DIN@(;mS#LlUtHoNF2ErgBX^15vvCqU=5{CpZ?Xjd#_RoZUfZ3|#%~~3lOk+i= z7}G$Gz-x~ z0eMIWN#mn(0{jQ}hY@Ai6L^YR!MX*4NC8yHBu}sf?(ARi8MH_Qjk;JMH2ea~@*0{8 zF1Swu6Uh$L7qirJ)!D4LS95E8=qwzMk{vR*9f3cGJRe<}-u#9mZ=8Du#lOy`)G zG*Jq8is6bwosl@=l81=(x!-ZXTfTs)(_W1>q%gXqqmgsswovMzfmwkB(lN}ly_KMq zH4?Gocz!XfutsqbdCwb^Xpq9*aO6Rxp6S{6_mx>(jL&_p)Ne@0mOigvRSLdOA7%{8 z%a)w@)Y9PRRu8X{uO|K2f%JrI%Y!91^9rR0EixgvBjOE*?!)rQ)ObD*O#QK=JlDJP zWdqpux-scraJ{3==YG{|l=~V7)o>`cB;mwlNxkxJZ(SL*$h2~PGQEG3VFedKp*P&~ ze7R$8(Y{AtzRWR{C87-K5k7@>?VtkdvBc|*eG*P~fivDcCX@TouB{hvXr$w7-@56* zx6{J%RToUP6O*|GB7YzH&;&SgG}jNW%;wb->|D^|fO;05d)+8|RM*$Ks5YwlXEg0m z{>*th?=a}gY zm><*K6n3j!n=p%?kPZ50)t2$TJiqh2Nhc5MuA9qW+oY-xQ-7zxITpuJ$KSRLf-7E_ z&y^`kxAUM4u)ZtzzEK=M80;TM9({Trp~3s6UKA|^sNQ|vH2gY18eX`M&ejf zh(G@kxb`%-1#o}L!EgQuP_is6E8#CM7C(WiJ236ygjP6zfBDJjnqAXJH0TdaYY?$^ zj`k||VGp|SBX060X8Je^ePVSjwVGm~AWijC+T;nI^?xc$InzBNb1j?r$AtCL>W)o!BMtHH~rsWF2-&0)}~RD<5476xX{&ESf+1NgqgK;f&R9bn?O=vd(N z87w;s4)iEH=hdaH!lrVczNlBFs{Z}d3@qC4phMSq-u|U^2DXFs7Mu=#dG~Y|ZRE@K zrNI4iR}jZ5V!3MP2O7tuzhS`OA%CpzE?Qf9{(pAAI54Ko>#Mh07bPx|WMN86Wo6qlf!^`(rxhgsj-*dKct^Kk#-{ixoz?`*J7*b9+;SC8K*Io%#>2w2B= zZh&N2x8UwA_oy9MwBcF9dGKAId_%`7uCmv>Xg;M~>DZnbkW`HV@mE@|$-ZQ8+8D9n6n(Iw)$Hoj>YhOCmo6q*& exPLAjh~I8Fei#V+x{Je|H~Akfb6wM?6aWBg2se!Y delta 2170 zcmV-=2!;2f5~30YABzYGyQh%`MgwHYvXM_cVD>&(@a5w#R!w>5-5uXr!PVd+7+k^6 zwzgEYDRd#Z{m;uwsLTsqmV(P~F8Ic~(M1FASM7Yedc(VYrzYqhe8mmN|Lw{N?3!=* z?BO~t`Q~~Fr*P*#vL*O>Wp+$E(2?vYe|E!gxF^onVC39&#(Y_fJM*rCxmlF)Sgvhw z{F?=sd96;J_wPP_a{M`P1xdGLNqfh9pbL#NrvRpel{@T`+<3C@a zkf!)=w|46M3cP`4;GCE{&lk12KK-!= zj_>G%QUWaFSrThVRY=1qOC$##$B|;8bME7Zy6MbP<0Y@4Y{v>NM_^+(?WAuNEqchjq-%W z5R;5YlBao2&>x{dD?vhj?~qIhh%}+0OhroaOshzwd77w1NWy-g$#4UsEKeCh5owyr zP{ff?GKMT;T4#`kN^JB*p=4>2D3PWK#0)W@5ka6OV=UHTdR&iz#j>=jfAUnPsYr6o zL1!{XZ)BK9jO2u7XoK9Sig}bp87DatJmR1*EV&R2LI`6_;pA~u*j7fl%w(F=NbpRf zTX7P~Tt{KfG8RiolZ}RqLzJZv=A5ET<$0`>raTj&);v?$I@>Hjg&fPefsxkKf|Iix zB$`VTo}@%!jKdhQrcv;*ps_)U_?oxs1`&f zN+zj`7m!VwCbwlSl~7GD@Q; z*Lj$PB9}1}D#d7S;ZR8k63d3^jAMu>kr?1KLz`of<+KyLu^NqTf5%NNYEzFtbU&kC z>rw^AXcVOw&85r)i;^V8qKJ4NN0f5T6%k>=ekSU5F`JvUtW+R^S*8gUATumi9fm+L z;TgqdL8G6^dIPFhE!M&`5C#!RLo5+VwT!XRgak0{5oeVBGhrWKwkmnEmc}L1Sdl6g zg6o*%iROaDTx1F|f6QpPE3L47d#w4TeHf9Pe#gJTvYOedB02UCks(BA5Kn<-A$lkv z4+$Y@d{j<=|Jam>D8rt>Q`8F9Exc%FR(1Hp}7#V zwKbeYG$V>gg7u;pcH<#5pZi>?-;j_keO|w+6nvlF&lr}M zEjjV2rNPf1e_kVBP5Q9|=?U4E2TN||6-p0UWI}L9#2XIX`{k3V@q8Yb`eR3Vu6O6l z2C(gQW75CidQY3r{i@d}4>b;|;ZW{K!imX}dga~Tx-w{yY32N6x_x}+3>^!@2~@IH z@cF~57n{Ji#yfGQ&SP)5=lOEa+@gJtzI>TuC`&{cF4O~j3hmlK1=eGU*BkpJoa_T< zye%e^?P%B53wUg#<7?l#>A<(s!tzxYOtlx2x&eG-Aan}7E_m6V zIxX5i!f|<4;OLAmx;}L3=(;THD+i(K{v4cteRe!VAlq-n@(W_rr-$9(9|72&Y%Vcy z`v~{3-<+b3x;*(mB5~yS#~;O?{|H=r8r%W6Kjq*ze*`F57M7LpmlunlK-C?X_HjZh zoWH;Pki)YJQ z+a$`{^+jQiErnB2bj(X%9dnj(8 zMKV)g3N!!ndD`>NL-{l4nDKBQ<^*hivvFePO?@?Z*)%m~(5E>JI+beBThzk9%()p{ z@pb^;ml!B~RkQ<4{1zPxoIZnPXTc*q%FcOpX{)fQ+@~+${8AmY%9$B>ES;P70yFSZzdhxogb*cLt8|WIG zD{K=TiyY$FO-g<>!Cb+b3n%9lmk@TsRQF{c!v+5cqW$hdXcbKSOD@H>VT;04;DXL;wH) From c8ff1094f8694060019d8e24fcd02266c7d57b8d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 30 Jan 2017 00:20:51 -0800 Subject: [PATCH 011/157] Update frontend (#5640) --- homeassistant/components/frontend/version.py | 4 ++-- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 137242 -> 137258 bytes .../www_static/home-assistant-polymer | 2 +- .../www_static/panels/ha-panel-dev-state.html | 2 +- .../panels/ha-panel-dev-state.html.gz | Bin 2890 -> 2904 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2339 -> 2342 bytes 8 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 9289ace07fa..7a236857038 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,13 +2,13 @@ FINGERPRINTS = { "core.js": "40a73d7be324cb52fbba55d993db126c", - "frontend.html": "ee127d284ce3d29b2162d499ca45ef88", + "frontend.html": "80d2d9b949edc68fcfc62b361ebe2f7e", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", "panels/ha-panel-dev-info.html": "27ea4123b8a5e0b789c903e22f119e52", "panels/ha-panel-dev-service.html": "9f749635e518a4ca7991975bdefdb10a", - "panels/ha-panel-dev-state.html": "89731c71777c0b54bdc5e883ff8e70db", + "panels/ha-panel-dev-state.html": "041f5b660f7a1fa748e47fc46c0bdb3c", "panels/ha-panel-dev-template.html": "97f77b69faef8c5975c09431912831cc", "panels/ha-panel-history.html": "44e463708a54cb6243dea42d0e173c4a", "panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 26bef4764bc..11bfc631674 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -594,4 +594,4 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th this.hass.callService('media_player', service, serviceData); }, }); -}()); \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 5e0bfda85c5ec69d2b55df35d8a7c5cb33e705fe..f93ee1a7752784a22a192b5baf13f7c205ba4f3b 100644 GIT binary patch delta 18328 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

3J#RW`LC}Y0O;SA4*~OU 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 delta 18261 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 Y7xEAJ{0?t&AbTDBe|+@OgA|Gg0O_lg8~^|S diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index e4b2ec1710d..94cde37aaa1 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit e4b2ec1710da8d6e134f9846813833e6d7ce2929 +Subproject commit 94cde37aaa110111aba8d5b292f4ea2a39fd9687 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html index 5e1c76cd5cf..d271289788f 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html @@ -1 +1 @@ -

\ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz index 7afd9e352b6c07ab75a53fd651ad51516b2a1d4f..17d4f3d76ae04d09d412fcc9b7c99dbb07536042 100644 GIT binary patch delta 2838 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 delta 2824 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 aAyqq^D~DyUO;h;42>t_&C(~j~AOHYbF>zA> diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index c090fa12098..c20bf9bab2c 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","75e4d32fcb7895e4351d4698bd7db369"],["/frontend/panels/dev-event-5c82300b3cf543a92cf4297506e450e7.html","1bb68c3df5c14307a2550a0cca39b435"],["/frontend/panels/dev-info-27ea4123b8a5e0b789c903e22f119e52.html","2a47633b0b67eaace1bd944df70209a1"],["/frontend/panels/dev-service-9f749635e518a4ca7991975bdefdb10a.html","1bc71eb7620c7b7198fd4b7976d6bc13"],["/frontend/panels/dev-state-89731c71777c0b54bdc5e883ff8e70db.html","40c3766db776e531232413a9c3335f07"],["/frontend/panels/dev-template-97f77b69faef8c5975c09431912831cc.html","5a4848a193ba4aed4359bb3e0e05bac6"],["/frontend/panels/map-9c8c7924ba8f731560c9f4093835cc26.html","8ae4874622d23d995ddf2a8b0ffa8d80"],["/static/core-40a73d7be324cb52fbba55d993db126c.js","71bd739508e8725a3e7db7544a58f135"],["/static/frontend-ee127d284ce3d29b2162d499ca45ef88.html","3f0c842c165b8ac507e5146f21b38a66"],["/static/mdi-7a0f14bbf3822449f9060b9c53bd7376.html","8d60ec43a3f8a77b21c312783ae5b892"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","89313f9f2126ddea722150f8154aca03"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.toString().match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a))return e.add(new Request(a,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);var n="index.html";!t&&n&&(a=addDirectoryIndex(a,n),t=urlsToCacheKeys.has(a));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,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 JUDKx&008TPmQnx! From f1d1f7d032460334e86b5a6ccd59ef6f8c937860 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 30 Jan 2017 00:57:13 -0800 Subject: [PATCH 012/157] Update frontend (#5642) --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 137258 -> 137256 bytes .../www_static/home-assistant-polymer | 2 +- .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2342 -> 2340 bytes 6 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 7a236857038..e6ca070baa8 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,7 +2,7 @@ FINGERPRINTS = { "core.js": "40a73d7be324cb52fbba55d993db126c", - "frontend.html": "80d2d9b949edc68fcfc62b361ebe2f7e", + "frontend.html": "e530d966406fcb2fddb692842dc83c1b", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 11bfc631674..63907d1f912 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -594,4 +594,4 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th this.hass.callService('media_player', service, serviceData); }, }); -}()); \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index f93ee1a7752784a22a192b5baf13f7c205ba4f3b..9c6a246df4b4f24fcaf7b7d1613290c09f56e519 100644 GIT binary patch delta 16736 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 H{)q?xg7LEk delta 16738 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 F0095J+AshB delta 517 zcmV+g0{Z==5~dOcABzYG0Qa#5k^vWvlu4|lj1sA`NJ7G6!4(UWOmHos$efd}0geKw zm6JaL6@Mxfl0{$9WWeAgjG0bEnua<9rXh=Sj596cRE9zkoI5=_3?<%Y?jnvhP8p=Y)VSf?jlvt9dI}JHtoM&;$x#E#3ibN^R zAs3<6kgGf#G+2O2Ih9R|lQ@JdQklSr$5JF*3js+&TO*1FPi642Be@xcIg5%U%rVb+ z0ug3PWJw%Dl54ihuC3gi1Cu;dTos~-3seNEmRhDjlY)Swa0n Date: Mon, 30 Jan 2017 13:09:36 +0100 Subject: [PATCH 013/157] Add unittest for cleanup not validate ssl stuff. (#5643) --- tests/helpers/test_aiohttp_client.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/helpers/test_aiohttp_client.py b/tests/helpers/test_aiohttp_client.py index 4bca671059f..c54770268d0 100644 --- a/tests/helpers/test_aiohttp_client.py +++ b/tests/helpers/test_aiohttp_client.py @@ -100,6 +100,25 @@ class TestHelpersAiohttpClient(unittest.TestCase): assert self.hass.data[client.DATA_CLIENTSESSION].closed assert self.hass.data[client.DATA_CONNECTOR].closed + def test_get_clientsession_cleanup_without_ssl(self): + """Test init clientsession with ssl.""" + run_callback_threadsafe(self.hass.loop, client.async_get_clientsession, + self.hass, False).result() + + assert isinstance( + self.hass.data[client.DATA_CLIENTSESSION_NOTVERIFY], + aiohttp.ClientSession) + assert isinstance( + self.hass.data[client.DATA_CONNECTOR_NOTVERIFY], + aiohttp.TCPConnector) + + run_coroutine_threadsafe( + client.async_cleanup_websession(self.hass), self.hass.loop + ).result() + + assert self.hass.data[client.DATA_CLIENTSESSION_NOTVERIFY].closed + assert self.hass.data[client.DATA_CONNECTOR_NOTVERIFY].closed + @asyncio.coroutine def test_fetching_url(aioclient_mock, hass, test_client): From 87764a51baa437f02b3941e240576260880f475b Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 30 Jan 2017 16:16:49 +0100 Subject: [PATCH 014/157] Use device_state_attributes() for platforms (#5649) * Use device_state_attributes() for platforms * Update test * Fix lint issue --- .../components/sensor/deutsche_bahn.py | 2 +- homeassistant/components/sensor/gpsd.py | 2 +- homeassistant/components/sensor/hddtemp.py | 2 +- homeassistant/components/sensor/hp_ilo.py | 2 +- .../components/sensor/imap_email_content.py | 2 +- .../components/sensor/linux_battery.py | 2 +- .../components/sensor/mold_indicator.py | 2 +- homeassistant/components/sensor/statistics.py | 2 +- homeassistant/components/sensor/zamg.py | 2 +- .../sensor/test_imap_email_content.py | 86 ++++++++----------- 10 files changed, 45 insertions(+), 59 deletions(-) diff --git a/homeassistant/components/sensor/deutsche_bahn.py b/homeassistant/components/sensor/deutsche_bahn.py index 51394e0f3ac..34be6ba078c 100644 --- a/homeassistant/components/sensor/deutsche_bahn.py +++ b/homeassistant/components/sensor/deutsche_bahn.py @@ -65,7 +65,7 @@ class DeutscheBahnSensor(Entity): return self._state @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes.""" connections = self.data.connections[0] connections['next'] = self.data.connections[1]['departure'] diff --git a/homeassistant/components/sensor/gpsd.py b/homeassistant/components/sensor/gpsd.py index 0fb24c96283..f6f9e75df31 100644 --- a/homeassistant/components/sensor/gpsd.py +++ b/homeassistant/components/sensor/gpsd.py @@ -98,7 +98,7 @@ class GpsdSensor(Entity): return STATE_UNKNOWN @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes of the GPS.""" return { ATTR_LATITUDE: self.agps_thread.data_stream.lat, diff --git a/homeassistant/components/sensor/hddtemp.py b/homeassistant/components/sensor/hddtemp.py index 1a964a458e2..c0e3dc32d4d 100644 --- a/homeassistant/components/sensor/hddtemp.py +++ b/homeassistant/components/sensor/hddtemp.py @@ -83,7 +83,7 @@ class HddTempSensor(Entity): return TEMP_FAHRENHEIT @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes of the sensor.""" return { ATTR_DEVICE: self.details[1], diff --git a/homeassistant/components/sensor/hp_ilo.py b/homeassistant/components/sensor/hp_ilo.py index 17a58dd9862..675db6400a0 100644 --- a/homeassistant/components/sensor/hp_ilo.py +++ b/homeassistant/components/sensor/hp_ilo.py @@ -110,7 +110,7 @@ class HpIloSensor(Entity): return self._state @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes.""" return self._data diff --git a/homeassistant/components/sensor/imap_email_content.py b/homeassistant/components/sensor/imap_email_content.py index b5845ab78ed..5f9a7e7f8e7 100644 --- a/homeassistant/components/sensor/imap_email_content.py +++ b/homeassistant/components/sensor/imap_email_content.py @@ -159,7 +159,7 @@ class EmailContentSensor(Entity): return self._message @property - def state_attributes(self): + def device_state_attributes(self): """Return other state attributes for the message.""" return self._state_attributes diff --git a/homeassistant/components/sensor/linux_battery.py b/homeassistant/components/sensor/linux_battery.py index 79f485d80dd..ddfb12f008b 100644 --- a/homeassistant/components/sensor/linux_battery.py +++ b/homeassistant/components/sensor/linux_battery.py @@ -98,7 +98,7 @@ class LinuxBatterySensor(Entity): return ICON @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes of the sensor.""" return { ATTR_NAME: self._battery_stat.name, diff --git a/homeassistant/components/sensor/mold_indicator.py b/homeassistant/components/sensor/mold_indicator.py index 61cdae5fb36..102b4620410 100644 --- a/homeassistant/components/sensor/mold_indicator.py +++ b/homeassistant/components/sensor/mold_indicator.py @@ -238,7 +238,7 @@ class MoldIndicator(Entity): return self._state @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes.""" if self._is_metric: return { diff --git a/homeassistant/components/sensor/statistics.py b/homeassistant/components/sensor/statistics.py index 15184fbbc11..ff2df5ef893 100644 --- a/homeassistant/components/sensor/statistics.py +++ b/homeassistant/components/sensor/statistics.py @@ -116,7 +116,7 @@ class StatisticsSensor(Entity): return False @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes of the sensor.""" if not self.is_binary: return { diff --git a/homeassistant/components/sensor/zamg.py b/homeassistant/components/sensor/zamg.py index 6f621b683b6..6b500460d7b 100644 --- a/homeassistant/components/sensor/zamg.py +++ b/homeassistant/components/sensor/zamg.py @@ -112,7 +112,7 @@ class ZamgSensor(Entity): return SENSOR_TYPES[self.variable][1] @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes.""" return { ATTR_WEATHER_ATTRIBUTION: ATTRIBUTION, diff --git a/tests/components/sensor/test_imap_email_content.py b/tests/components/sensor/test_imap_email_content.py index 17619f1efa6..f8e5caf0dd2 100644 --- a/tests/components/sensor/test_imap_email_content.py +++ b/tests/components/sensor/test_imap_email_content.py @@ -46,8 +46,8 @@ class EmailContentSensor(unittest.TestCase): def test_allowed_sender(self): """Test emails from allowed sender.""" test_message = email.message.Message() - test_message['From'] = "sender@test.com" - test_message['Subject'] = "Test" + test_message['From'] = 'sender@test.com' + test_message['Subject'] = 'Test' test_message['Date'] = datetime.datetime(2016, 1, 1, 12, 44, 57) test_message.set_payload("Test Message") @@ -58,19 +58,20 @@ class EmailContentSensor(unittest.TestCase): ["sender@test.com"], None) - sensor.entity_id = "sensor.emailtest" + sensor.entity_id = 'sensor.emailtest' sensor.update() self.assertEqual("Test Message", sensor.state) - self.assertEqual("sender@test.com", sensor.state_attributes["from"]) - self.assertEqual("Test", sensor.state_attributes["subject"]) + self.assertEqual('sender@test.com', + sensor.device_state_attributes['from']) + self.assertEqual('Test', sensor.device_state_attributes['subject']) self.assertEqual(datetime.datetime(2016, 1, 1, 12, 44, 57), - sensor.state_attributes["date"]) + sensor.device_state_attributes['date']) def test_multi_part_with_text(self): """Test multi part emails.""" msg = MIMEMultipart('alternative') - msg['Subject'] = "Link" - msg['From'] = "sender@test.com" + msg['Subject'] = 'Link' + msg['From'] = 'sender@test.com' text = "Test Message" html = "Test Message" @@ -82,11 +83,8 @@ class EmailContentSensor(unittest.TestCase): msg.attach(htmlPart) sensor = imap_email_content.EmailContentSensor( - self.hass, - FakeEMailReader(deque([msg])), - "test_emails_sensor", - ["sender@test.com"], - None) + self.hass, FakeEMailReader(deque([msg])), 'test_emails_sensor', + ['sender@test.com'], None) sensor.entity_id = "sensor.emailtest" sensor.update() @@ -107,11 +105,11 @@ class EmailContentSensor(unittest.TestCase): sensor = imap_email_content.EmailContentSensor( self.hass, FakeEMailReader(deque([msg])), - "test_emails_sensor", - ["sender@test.com"], + 'test_emails_sensor', + ['sender@test.com'], None) - sensor.entity_id = "sensor.emailtest" + sensor.entity_id = 'sensor.emailtest' sensor.update() self.assertEqual( "Test Message", @@ -120,8 +118,8 @@ class EmailContentSensor(unittest.TestCase): def test_multi_part_only_other_text(self): """Test multi part emails with only other text.""" msg = MIMEMultipart('alternative') - msg['Subject'] = "Link" - msg['From'] = "sender@test.com" + msg['Subject'] = 'Link' + msg['From'] = 'sender@test.com' other = "Test Message" @@ -130,13 +128,10 @@ class EmailContentSensor(unittest.TestCase): msg.attach(htmlPart) sensor = imap_email_content.EmailContentSensor( - self.hass, - FakeEMailReader(deque([msg])), - "test_emails_sensor", - ["sender@test.com"], - None) + self.hass, FakeEMailReader(deque([msg])), 'test_emails_sensor', + ['sender@test.com'], None) - sensor.entity_id = "sensor.emailtest" + sensor.entity_id = 'sensor.emailtest' sensor.update() self.assertEqual("Test Message", sensor.state) @@ -145,14 +140,14 @@ class EmailContentSensor(unittest.TestCase): states = [] test_message1 = email.message.Message() - test_message1['From'] = "sender@test.com" - test_message1['Subject'] = "Test" + test_message1['From'] = 'sender@test.com' + test_message1['Subject'] = 'Test' test_message1['Date'] = datetime.datetime(2016, 1, 1, 12, 44, 57) test_message1.set_payload("Test Message") test_message2 = email.message.Message() - test_message2['From'] = "sender@test.com" - test_message2['Subject'] = "Test 2" + test_message2['From'] = 'sender@test.com' + test_message2['Subject'] = 'Test 2' test_message2['Date'] = datetime.datetime(2016, 1, 1, 12, 44, 57) test_message2.set_payload("Test Message 2") @@ -164,18 +159,14 @@ class EmailContentSensor(unittest.TestCase): states_received.set() track_state_change( - self.hass, - ["sensor.emailtest"], - state_changed_listener) + self.hass, ['sensor.emailtest'], state_changed_listener) sensor = imap_email_content.EmailContentSensor( self.hass, FakeEMailReader(deque([test_message1, test_message2])), - "test_emails_sensor", - ["sender@test.com"], - None) + 'test_emails_sensor', ['sender@test.com'], None) - sensor.entity_id = "sensor.emailtest" + sensor.entity_id = 'sensor.emailtest' sensor.update() self.hass.block_till_done() @@ -189,39 +180,34 @@ class EmailContentSensor(unittest.TestCase): def test_sender_not_allowed(self): """Test not whitelisted emails.""" test_message = email.message.Message() - test_message['From'] = "sender@test.com" - test_message['Subject'] = "Test" + test_message['From'] = 'sender@test.com' + test_message['Subject'] = 'Test' test_message['Date'] = datetime.datetime(2016, 1, 1, 12, 44, 57) test_message.set_payload("Test Message") sensor = imap_email_content.EmailContentSensor( - self.hass, - FakeEMailReader(deque([test_message])), - "test_emails_sensor", - ["other@test.com"], - None) + self.hass, FakeEMailReader(deque([test_message])), + 'test_emails_sensor', ['other@test.com'], None) - sensor.entity_id = "sensor.emailtest" + sensor.entity_id = 'sensor.emailtest' sensor.update() self.assertEqual(None, sensor.state) def test_template(self): """Test value template.""" test_message = email.message.Message() - test_message['From'] = "sender@test.com" - test_message['Subject'] = "Test" + test_message['From'] = 'sender@test.com' + test_message['Subject'] = 'Test' test_message['Date'] = datetime.datetime(2016, 1, 1, 12, 44, 57) test_message.set_payload("Test Message") sensor = imap_email_content.EmailContentSensor( - self.hass, - FakeEMailReader(deque([test_message])), - "test_emails_sensor", - ["sender@test.com"], + self.hass, FakeEMailReader(deque([test_message])), + 'test_emails_sensor', ['sender@test.com'], Template("{{ subject }} from {{ from }} with message {{ body }}", self.hass)) - sensor.entity_id = "sensor.emailtest" + sensor.entity_id = 'sensor.emailtest' sensor.update() self.assertEqual( "Test from sender@test.com with message Test Message", From 55992468b04017fb4b72ad5816913432f73b14e1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 30 Jan 2017 09:12:07 -0800 Subject: [PATCH 015/157] Update frontend (#5652) * Return empty result when history date is in future * Update frontend --- homeassistant/components/frontend/version.py | 6 +++--- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 137256 -> 137251 bytes .../www_static/home-assistant-polymer | 2 +- .../www_static/panels/ha-panel-history.html | 2 +- .../panels/ha-panel-history.html.gz | Bin 7297 -> 7288 bytes .../www_static/panels/ha-panel-logbook.html | 2 +- .../panels/ha-panel-logbook.html.gz | Bin 8010 -> 8001 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2340 -> 2339 bytes homeassistant/components/history.py | 7 ++++++- 11 files changed, 14 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index e6ca070baa8..8496b59be4c 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,7 +2,7 @@ FINGERPRINTS = { "core.js": "40a73d7be324cb52fbba55d993db126c", - "frontend.html": "e530d966406fcb2fddb692842dc83c1b", + "frontend.html": "d3e11787b7487dfe95a957ff029ae2a2", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", @@ -10,9 +10,9 @@ FINGERPRINTS = { "panels/ha-panel-dev-service.html": "9f749635e518a4ca7991975bdefdb10a", "panels/ha-panel-dev-state.html": "041f5b660f7a1fa748e47fc46c0bdb3c", "panels/ha-panel-dev-template.html": "97f77b69faef8c5975c09431912831cc", - "panels/ha-panel-history.html": "44e463708a54cb6243dea42d0e173c4a", + "panels/ha-panel-history.html": "8955c1d093a2c417c89ed90dd627c7d3", "panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab", - "panels/ha-panel-logbook.html": "0e8ea21b5f515a315b7952e396c84280", + "panels/ha-panel-logbook.html": "f36297a894524518fa70883f264492b0", "panels/ha-panel-map.html": "9c8c7924ba8f731560c9f4093835cc26", "websocket_test.html": "575de64b431fe11c3785bf96d7813450" } diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 63907d1f912..6e43f6f5fc0 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -594,4 +594,4 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th this.hass.callService('media_player', service, serviceData); }, }); -}()); \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 9c6a246df4b4f24fcaf7b7d1613290c09f56e519..dd18d7556642edd17dfbcc2a7fb9e0bdd20693aa 100644 GIT binary patch delta 5655 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 delta 5696 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 0a45e0e95ba..06edb226510 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 0a45e0e95babf568cfcf7de228990550a86421e5 +Subproject commit 06edb22651024bef45c3b7630ae85a422d8cb710 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-history.html b/homeassistant/components/frontend/www_static/panels/ha-panel-history.html index f1fe31fb6a5..71b823295a6 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-history.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-history.html @@ -1,4 +1,4 @@ \ No newline at end of file + */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:after,.pika-single:before{content:" ";display:table}.pika-single:after{clear:both}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-inrange .pika-button{background:#D5E9F7}.is-startrange .pika-button{color:#fff;background:#6CB31D;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button,.is-outside-current-month .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help}} \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-history.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-history.html.gz index 1644f0ab51cb70fe72a5c452934a53c26361d7b9..0c3d57acb4197e2b448c63fae63350df99ccf87c 100644 GIT binary patch delta 7261 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 delta 7287 zcmV--9EjuiIDt8TABzYGx~Gm<0t0AaEpTCOWo#{IX>)XMa(OOjbZu+^wLJS?+c>lT zpQkY1v((-=A>mS32PYr5wzLIWpxy21>Bmn=l*Glcv$g_cLmue7#(AmM3AFpi z*$e108jWT~bCG2Bhhh}9_J^GHTKgj|nAIJ!G~*($KV83ns_xmX{SDdKNqW=PelNVU zhGDPAJFm%s?%WZ>F!M~zON$5AE>p?9I9OY|593~PUt_)A$sM43A7+Bb zJoQ+hdU{EBf)jb6ZUIqUha;X$gqH;-+dbxm?ksM9^Cff+_N}djxCSN!>kg?K1QOd7 z=yT^@@&u}skCHq7B(@%3i7hQ-izU0mCaZN*&Vfik zkMP#&-dY11gBvFVgdWTtW@8kUga}>NFJZeNWm{igoJF=fB~*P-yV4>6+uR!lrdX9S z@ES;ecGQ-?9OOaD#}VstXXD@homC#;|Nq<=cs6LS7X{^QAyGKCWmkBu8?h`qXCq#L zx(jRV@rR2(bqZ=)3xaB6?)4UsMD*+N(J@fKRt$o`XlM(6VTKCmsyA7{Wuh25s|nM~ z%L((a8IW~XuxH~SP1$s#CU_u#c)VeH!WgwFNDkR4stDnZP zzP=U$x#z%-f!rDnA|3^cyIlkXam=QU+f>r51KY&o<4gQC_XaBk{_8gM*4NkhuZ?;g zgi?Qegtj^kt~E5P zNt!uzkN$;)9j~0wGFFd^DQa`?X60^#E#B-Wsl%)gOq?4AcS+c@aDn_Q`{sq~>r3`p zK*#!eJc%NJk`*~9kkwk8^f;+s-@&@uj$!{Hx*+EF7K)YH4MDkncM+5zvM2KqjZGqfyp?D{WsZ%uwT1_O)-6M| z_cewqa!%Ma3gcqrh&>b)T;e5*2i$Mey=<7=|H1j~`DE1LsT%kNAOIzdqSEj14>q6S zlJ&BnvsBLnONB&Bv+%fQ)WYoY`aNRD$*(5;e)!$l~KO39ad|M;8 zsBU{P%&EF?dfhydGkvw+vUtMMDHzLFypyWp8B4nWWFL&vFrqrPzMaIJennV2m<%Qv zkY!)-vEWEQlrOp>k)?C+#;Wm{cV+RLcMr0Gzyv400;M9fK#?q5Pk1JOOMmcQtjpI! zFe|e7Dh*}fiotHdVuA5$2=SIgD{)GM5}8CJG05RISTZr>BPGxzzTy#>5M8?%^H`UU zq9n_~j#G9|<+*piWUbIjiAq3jniRPyTETA96;=4Db~wf=D7adQaImcYLOU7TvlY(a zE7%qY)EEYp7_Gv%>|`{57E^ZywKcHC&nuiODS5FkdKS6Rzz(x2M+_KKi(czR6CBwj z8#>ql@mm)5c(pr8QwTh&q&W~YC*~BHmkHH^%i;qmAYz%&rqyR0%*}i|Uo! zM+}Yuk*QVyf)$Gt#3{i~W7>=*bYYxgn?{)L-x3gQYZLB7?duYM6l^;ULtN@H!KxTf z+b?3i=PU!|py$eLQbkW}5kkd$k+jH-BweKzbVGM4a;@ZL=IgZgQ zJnmMRyRr9jo9|SUbOtsT45u^^mmv_9cNOaMfg# zmGQL%>rfgN*wqH&8 zYJep(F?lE`5K@Y)EL4Lemb41pSzmuren}y&_&ISQ%abyXmHX*E$7W5hjL?3X$vEU6 z@_0~z^)82h?Or8+@}o-619fvS`CyNah0?VG2Dy_1+7EUW^v`KDauB74`x0bIAe6m8 z4JLcB%Aa5)2;3aEZQHl4k_*QDS@JH05|-je!!eLS3&X9xp%$fp>m&s6IfjyMPt@OQxn*Ao9fw^b@RG^X`gU}wod~HE46V#)d6BV z)7*2vs6fW7Tffw(6bKThuBl9PdG z4SMg~84vj5qdGO?c)HWn#{dwnfFFfCzLurklZfL98^(N)2KSxF5negcf?RWrT8;Pu zTQ#H%@?=AQZOky9JBLho0ZY3;fyx05DQO7_2)sXM6Je$UN z;6Ok=2UKy#E(bTLYfl2Gfb$s$iX&YxNHt1TA?YqoP(e#-Lx^7;?53m^?GY7fooJHc zxkIB~$Kl1g+%}&bMZIe2;cKv160e;r|KFOqB z+1aFj193da2x8LG*ggL#z}+(7?+bunITn#^*H^*px>|~-@pvK@`J*G}W=yBGy~F8R z5Tuycv>g_3N3WY0jXFsu9eF_>dAJ@6*!ns{p0X(HIc}TPL_$=!lz+Ou5u4)=+|Stp zdQj@V!$`z>M>6E(&E4Z;O8&~pMNNx&m2@Y6#$i2f9tl-iaTIoMe*|<0Vl`oqCp=&^ z5CueiT8n#$MTU%P%>-i&hS^oys(C*QL7hO^3~NO;wF{;WeszMCTYc{Bz>fCh?rrEj zS0?)(Z#fW&vb{4r*ju(1l)NT!mlOi%6UcPKVCgQ~v(@szs%3~qw;Q$r3{uV=w!oc# z$43U9d59SXQ5DcU znUIjzPeo+QNE@cXbCxz9%d0YWz`_xoXOGY~f&^l<{M=V!DwIQsWYQf%Uj8i5DmFqV zun(+|F-30G44(jW<_BzTqg-R-G0b~^1ibChG_J4Q4D3iu9#;a$Jy?jL7RH$G9CFy? zTvDrn&~sja)dV&ov8s7tF@~i2CZedW$1AfM=3~S}%TX2$~ zu(*ACK?z&4@ATaEB6zznNIevxFMW_~DAhDExp!~VMW*)YWtD_*5tWbNY+|N=QgL7> z?tXjGin(Q=KAJy!(H<@Up~JElES>B6M3u6GIy?DN+y@0S858=Z0irQC3Cd8GX=Pm z#jEbG%Mk5ym6j$i{sU6tn!TA7T{# z3b;n`qFZg$o1%1_VDhna%s^aZo+zC)tcGrAXnHzf8C^ksfwgKNj)Gwwqs8cLL7Y!a zEU;nZuQ#ihd-~4SH={Y#-B|S z2r8qZlUhoUbVj7c2hwTrXu{ZRy3%qAkPS zvf7hjWaZ(twN&jm&{L{?f?=L+k$VDM7_ye{$8A9A%ZQq{7)`-{6fL+?J)3#K?@e>w zO2FK+m79OS9BR|*iGJ_rIraEhSjDy6Dyq@?;;YbJ-6G#D(20hmTPc-`QKDXizkEFf z*)j-3GB{L<)m2xSndW&}%kpk86SO(KRvW8PJ_(#p6b6PI zn~cmQWz=-Hp$RLVX4z8M z-T602BErECA3YfQTHG2h;m(;@2^v*BqU_D|zLF`g#*|TBP^7^NHi#Zfd09|a5-$lh zw|~oRG;@D@S;zkxe5*-mG#&Ydg)B3v=ofw9X#z$v&)X4ykRC^^0<9)UGjy9c0m8+n zWf=J5O{#4~x-0M!xNcrCMsr0AIdnBQat@g$b&2c2-LfR)9f8b=8%=QXE9KGTm5RGC zmLoo;B~J;MOO;u@x8@K+7RFOv$`4ecW)hE&DgR!4qE#1}r>|%>Jtuz6*AYBwJ?xLlpbjg`I zyl@mc^y6j=k{K*m3A3NL5txR>^_@kGo!kp9V(#QuflD|$c`@%Rp3gvUQ7QRtxqS7M z=N~O!#lYNbd4BooI_1gbD~ugoTEg7PZ$6iBcJg9>-lty+L7y%zFTHr8uqr1sSttW8 z{ZwHkbUq`%;vD|Md98%Idweu5w{>0#9yJ$khGn(VM7GPNrLsd-h7hbtD{?d4$Ae0R ze;P1PJ#tKRFnTlEPjY}!kZ5yyGi?Q#F*4I5(_&;RHAbd5(!5`;+7-$MQWp1;k>eKe z(bmg<;yLKX*MGC>-`^_ott%ROh!vf>w^`WWD5y6h@YD;|H^Qsu%Bl-S+QN7>bR+|$ zXfe8oRtFuC4lkYxd)x~3q|nY&=bs{_3o5!TlfvOqEsSHH;%nt#=*9Ya#Fp>mAsP%~ z6=h;rxNvV0=UF-(i_k@h>#fSL^T-ijM`_`I={l{#Ehg79md{3u+c(>@KVi-{>)v!X5}BTxfm6F;auQrOuj3CrwdBJn&uM$MDzL1Q-HUoMCQ97Ly;SvO6h=sFp%LX&r{5;NJ(Llh!x zu_K!B67mGM7d+8}S8hSChOZYZ21S2Lio6K=`ueaEx3VH3(jCRicNuuQExZUHR^tjcrQfRK zMZhpv>Ttc4vqhD#l~mH_<`cu6je}N?Df>rvkte_~rs3vKz(6Cvev{8drVu_u!lWNaw(vlICaDHR ziQ2_%Y}7SoDQWO=fT=qad5J} ze(YR&c}{;6U=`N-CFtxYkB^;y7R`PVsNvpKAiVEjK~7=qnekZh*fHzgrR!Y)1kax- zV!y6o@2iFJCal@Bf4RPXxo?a;fPwj`A@-;W+J*d_@UoRx$X=9BU)R@1&ZTQ~(3vXE zYt{jz`2|D@d}uo-!Ju*ii;rOO6Ntc0s^Ivqf*w@6>d5gdByWn|G-l(Vf`2U~UljX#JUEPf(1vSPctL8%a z3e|uuu3CQxst+A=&JK-K$2ieUo;t16155Xti>g+PUcAjK50_$H0j;j}O3>J^#{qO%+oAt&vc%?hgr$ewGJc_JG>+tH>TDQ(luPyv6 zDTWa0(HaUd_BS?q9SH@I?`Q+CZPbkG``O=BiZ^Z!O=+GmRonV!i}J+B(abr85Uu`$IJwGT3~6-P!@Z zH1J0if24zd4pSe@)plHkQKogXev~lbqt$8NWAx~6Zr8^T%@IonVeIdX9~3xc!n0)= z3Gh`_7KMY@2StGOY4n(5%$JkU~;_v#$H^Wy5a0Zs?F!4bUWWdFo+*@T@yYGw2>CAug!7%xi<*y@Ebu zBK!h7jU+bvVFaUn7LA9@N$`QFn1Z8is-j<4Q{zdb(keVnoRxRQQ?%r~OC|zW4il?A zQ822mMT*=|oY}%M2@RJJD^}ePL&2-~ij{-b-KT84B!(sK;rA_>v_@uUPN7r>Oa3w; zAS>a2pmTAeN@gF4b9d)g3;xeJRogLGGkRH$>B+SHaPpZcePhJ`0MaAdU^Y9@Fx88uaAEn@V9(?m~8yL zwfA=8Q+;yqCSr%Thtcn++pq6&_QSWApLR~t+qZ+kAPC$AjvyPnf;oyKWbprASyC^5 zSaNZn9Go2tPU^k;{y}{H{nO^l&X?Q6qgSu*`{DcFKY#usxu_hz-G1HQ8i?%V-Mi$~ z;raDZ0ysb4vxD&U`N!91pWd9^et+E=e81fsonD+z{!Hre(cYi&QNQu_&%r_Z`SiaI zJ`Q)T-w_=LSD!v#T)x{m`f_?2xQ0T1)r?2UhN76w+9Ig;MulQ-YV#}&$0~ED4Gbch z$^F=<*MHT%3ieXO#u@i@L3gMp<;K1?Fs;Wbcd%L!|x3k;W)<0kVTG)g6!VqN! z(drt;baT;|?yNATPuYF>7<|!$mTeljs_<_lDfie9&FU!mySln-g^kOtuEA1&!$IiS z;pNMh&n*poq`8#EO#m)p2me)z!>`C@2D(Nu5%7?<8GUVNm3g7U7}j6pB8|}BpsXB( zvCh+eOd>TrKR*8xR^4hy7is;{*xl>%9j#L->xGld-$Jime9Bm!*u;LkbMpJET}fsB zMdOonnj>Ex9d0#_P0}!!d4djq{T<{_VP07AGidehEur;lPkn1zo?U5fmEP-Sa+(Dz zVC5;5 z^c~$03>=Gj1mR{Tk`%wj6?_EyQ*f0pSYh0aCOsb5VVcC%e#9Rv7)5=5cB`hs-I?BR zjh8^=n2mv?5Yw31h&@zw=mFtHK@TB;dGyp(bS;1yuROkf#oyn)*_Mo)s`4A2uU~Iu z{Tix9uX@Y_-H>R&r2G}N)A`wr-cxj&jDv8Vz@E)$_BV3!`5a$yg7cG~^2}yo_Fh(C z7=vE?%Rj3KZtb)2xQd^D8v-3*)$5lA)_mw@l`h1dm_7=9_1u z*lGD+g8Gm|(-BV{&@O*@>v`ie8RHkKJo9I$|Nacs-j{#oW$sB8P>qKmHO^vr>V_In zZuf}WK7NQ`uDpbQQNhUPex=1fiK`?g1w|+F5@h*sFn_)WV~ee;M#`I0HI~GTmjMgn zUOH(ibZY6qZ|=#z;KX~+jH07;b^D_ZIvn+Ef2>sDU z{+As}FAVa>JiK_agipD6OEanTeo&uDnH&%JyoO(h%G0<~xxU{o$k0O#LeoSR2j8}bjY RZO|WT`#+qo-DR&$003qXG{67= diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html b/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html index 0941409efa9..7b5c0f6d33c 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html @@ -1,4 +1,4 @@ \ No newline at end of file + */.pika-single{z-index:9999;display:block;position:relative;color:#333;background:#fff;border:1px solid #ccc;border-bottom-color:#bbb;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.pika-single:after,.pika-single:before{content:" ";display:table}.pika-single:after{clear:both}.pika-single.is-hidden{display:none}.pika-single.is-bound{position:absolute;box-shadow:0 5px 15px -5px rgba(0,0,0,.5)}.pika-lendar{float:left;width:240px;margin:8px}.pika-title{position:relative;text-align:center}.pika-label{display:inline-block;position:relative;z-index:9999;overflow:hidden;margin:0;padding:5px 3px;font-size:14px;line-height:20px;font-weight:700;background-color:#fff}.pika-title select{cursor:pointer;position:absolute;z-index:9998;margin:0;left:0;top:5px;filter:alpha(opacity=0);opacity:0}.pika-next,.pika-prev{display:block;cursor:pointer;position:relative;outline:0;border:0;padding:0;width:20px;height:30px;text-indent:20px;white-space:nowrap;overflow:hidden;background-color:transparent;background-position:center center;background-repeat:no-repeat;background-size:75% 75%;opacity:.5}.pika-next:hover,.pika-prev:hover{opacity:1}.is-rtl .pika-next,.pika-prev{float:left;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==)}.is-rtl .pika-prev,.pika-next{float:right;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=)}.pika-next.is-disabled,.pika-prev.is-disabled{cursor:default;opacity:.2}.pika-select{display:inline-block}.pika-table{width:100%;border-collapse:collapse;border-spacing:0;border:0}.pika-table td,.pika-table th{width:14.285714285714286%;padding:0}.pika-table th{color:#999;font-size:12px;line-height:25px;font-weight:700;text-align:center}.pika-button{cursor:pointer;display:block;box-sizing:border-box;-moz-box-sizing:border-box;outline:0;border:0;margin:0;width:100%;padding:5px;color:#666;font-size:12px;line-height:15px;text-align:right;background:#f5f5f5}.pika-week{font-size:11px;color:#999}.is-today .pika-button{color:#3af;font-weight:700}.is-selected .pika-button{color:#fff;font-weight:700;background:#3af;box-shadow:inset 0 1px 3px #178fe5;border-radius:3px}.is-inrange .pika-button{background:#D5E9F7}.is-startrange .pika-button{color:#fff;background:#6CB31D;box-shadow:none;border-radius:3px}.is-endrange .pika-button{color:#fff;background:#3af;box-shadow:none;border-radius:3px}.is-disabled .pika-button,.is-outside-current-month .pika-button{pointer-events:none;cursor:default;color:#999;opacity:.3}.pika-button:hover{color:#fff;background:#ff8000;box-shadow:none;border-radius:3px}.pika-table abbr{border-bottom:none;cursor:help}} \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-logbook.html.gz index 0d6da7658ce0b3207952ed51841445ae57ad9b2a..c81ae0bc4545bec3ebb536adf50165d822f0ac1d 100644 GIT binary patch delta 181 zcmV;m080PLKEXZ*ABzYG;c}0$2bUgyx@6QoJpX#z^5^b6zIfDutqd*}UZHK}3Cb2j zg_iF3ik?f?tP4+mH`8=FOTB19DrQmFOOE>Bo6ZQTz5q(fi&vTYEiJ_OFOw32(67qo z-_u&oRW!LDaMM36bdF?!ROei)1ni%)DZ{7YM>i0oA@>T!x-UD>SM+3E5(($YcxW15a-sTU1Bb#^^L@ zUL=EKl05HdCYIjJDEw9-lYpCEYoRkI3o`T&DlNO{iT9IuE&5&VG}P58eRXgxd4d0U sj93230mXRB=G$NWdCuhc;!MBLQ3}^K=nJ_22f;#|D+pHr056$aK>z>% diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index 51bcfcf8e37..acbc367861c 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","4efd59ca836bcdd17f6188481a6d8f4e"],["/frontend/panels/dev-event-5c82300b3cf543a92cf4297506e450e7.html","1bb68c3df5c14307a2550a0cca39b435"],["/frontend/panels/dev-info-27ea4123b8a5e0b789c903e22f119e52.html","2a47633b0b67eaace1bd944df70209a1"],["/frontend/panels/dev-service-9f749635e518a4ca7991975bdefdb10a.html","1bc71eb7620c7b7198fd4b7976d6bc13"],["/frontend/panels/dev-state-041f5b660f7a1fa748e47fc46c0bdb3c.html","f00c0e74a916e44d61c680e23f5aa34d"],["/frontend/panels/dev-template-97f77b69faef8c5975c09431912831cc.html","5a4848a193ba4aed4359bb3e0e05bac6"],["/frontend/panels/map-9c8c7924ba8f731560c9f4093835cc26.html","8ae4874622d23d995ddf2a8b0ffa8d80"],["/static/core-40a73d7be324cb52fbba55d993db126c.js","71bd739508e8725a3e7db7544a58f135"],["/static/frontend-e530d966406fcb2fddb692842dc83c1b.html","fd82f5caada2a3c247ef460841c36bb2"],["/static/mdi-7a0f14bbf3822449f9060b9c53bd7376.html","8d60ec43a3f8a77b21c312783ae5b892"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","89313f9f2126ddea722150f8154aca03"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.toString().match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a))return e.add(new Request(a,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);var n="index.html";!t&&n&&(a=addDirectoryIndex(a,n),t=urlsToCacheKeys.has(a));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,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 scI?cswf44Gz5DF+jr-@qLHHdNhvTb(ps)Kl+ now: + return self.json([]) end_time = start_time + one_day entity_id = request.GET.get('filter_entity_id') From ab019b9747f601f5fde4f5d33998e39f6a14c4b5 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 30 Jan 2017 18:14:00 +0100 Subject: [PATCH 016/157] Upgrade slacker to 0.9.40 (#5650) --- homeassistant/components/notify/slack.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/slack.py b/homeassistant/components/notify/slack.py index 90944cbd308..ea21d2b2afc 100644 --- a/homeassistant/components/notify/slack.py +++ b/homeassistant/components/notify/slack.py @@ -14,7 +14,7 @@ from homeassistant.const import ( CONF_API_KEY, CONF_USERNAME, CONF_ICON) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['slacker==0.9.30'] +REQUIREMENTS = ['slacker==0.9.40'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index ab2c6b036ae..abe9fdf730e 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -588,7 +588,7 @@ sense-hat==2.2.0 sharp_aquos_rc==0.3.2 # homeassistant.components.notify.slack -slacker==0.9.30 +slacker==0.9.40 # homeassistant.components.notify.xmpp sleekxmpp==1.3.1 From 1bf3eba6038a1b9aabb34b809b7e84d483018b51 Mon Sep 17 00:00:00 2001 From: Matt N Date: Mon, 30 Jan 2017 09:15:26 -0800 Subject: [PATCH 017/157] `yarn setup_js_dev` was deleted (#5639) --- script/bootstrap_frontend | 1 - 1 file changed, 1 deletion(-) diff --git a/script/bootstrap_frontend b/script/bootstrap_frontend index ed3321b1d93..e1d4ef887be 100755 --- a/script/bootstrap_frontend +++ b/script/bootstrap_frontend @@ -17,5 +17,4 @@ yarn install # Install bower web components. Allow to download the components as root since the user in docker is root. ./node_modules/.bin/bower install --allow-root -yarn run setup_js_dev cd ../../../../.. From 3a1607500efaade0dd630293bac3a493b2eeb842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 30 Jan 2017 18:17:57 +0100 Subject: [PATCH 018/157] Add set_options_service for input select (#5630) --- homeassistant/components/input_select.py | 38 ++++++++++++++++++++++++ tests/components/test_input_select.py | 38 +++++++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/input_select.py b/homeassistant/components/input_select.py index bd25a74ae3f..a099e6eb8c3 100644 --- a/homeassistant/components/input_select.py +++ b/homeassistant/components/input_select.py @@ -45,6 +45,15 @@ SERVICE_SELECT_PREVIOUS_SCHEMA = vol.Schema({ }) +SERVICE_SET_OPTIONS = 'set_options' + +SERVICE_SET_OPTIONS_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_ids, + vol.Required(ATTR_OPTIONS): + vol.All(cv.ensure_list, vol.Length(min=1), [cv.string]), +}) + + def _cv_input_select(cfg): """Config validation helper for input select (Voluptuous).""" options = cfg[CONF_OPTIONS] @@ -89,6 +98,14 @@ def select_previous(hass, entity_id): }) +def set_options(hass, entity_id, options): + """Set options of input_select.""" + hass.services.call(DOMAIN, SERVICE_SET_OPTIONS, { + ATTR_ENTITY_ID: entity_id, + ATTR_OPTIONS: options, + }) + + @asyncio.coroutine def async_setup(hass, config): """Setup input select.""" @@ -148,6 +165,20 @@ def async_setup(hass, config): DOMAIN, SERVICE_SELECT_PREVIOUS, async_select_previous_service, schema=SERVICE_SELECT_PREVIOUS_SCHEMA) + @asyncio.coroutine + def async_set_options_service(call): + """Handle a calls to the set options service.""" + target_inputs = component.async_extract_from_service(call) + + tasks = [input_select.async_set_options(call.data[ATTR_OPTIONS]) + for input_select in target_inputs] + if tasks: + yield from asyncio.wait(tasks, loop=hass.loop) + + hass.services.async_register( + DOMAIN, SERVICE_SET_OPTIONS, async_set_options_service, + schema=SERVICE_SET_OPTIONS_SCHEMA) + yield from component.async_add_entities(entities) return True @@ -207,3 +238,10 @@ class InputSelect(Entity): new_index = (current_index + offset) % len(self._options) self._current_option = self._options[new_index] yield from self.async_update_ha_state() + + @asyncio.coroutine + def async_set_options(self, options): + """Set options.""" + self._current_option = options[0] + self._options = options + yield from self.async_update_ha_state() diff --git a/tests/components/test_input_select.py b/tests/components/test_input_select.py index 04ab4ceed58..7fb832ddc22 100644 --- a/tests/components/test_input_select.py +++ b/tests/components/test_input_select.py @@ -6,7 +6,8 @@ from tests.common import get_test_home_assistant from homeassistant.bootstrap import setup_component from homeassistant.components.input_select import ( - ATTR_OPTIONS, DOMAIN, select_option, select_next, select_previous) + ATTR_OPTIONS, DOMAIN, SERVICE_SET_OPTIONS, + select_option, select_next, select_previous) from homeassistant.const import ( ATTR_ICON, ATTR_FRIENDLY_NAME) @@ -175,3 +176,38 @@ class TestInputSelect(unittest.TestCase): self.assertEqual('Hello World', state_2.attributes.get(ATTR_FRIENDLY_NAME)) self.assertEqual('mdi:work', state_2.attributes.get(ATTR_ICON)) + + def test_set_options_service(self): + """Test set_options service.""" + self.assertTrue( + setup_component(self.hass, DOMAIN, {DOMAIN: { + 'test_1': { + 'options': [ + 'first option', + 'middle option', + 'last option', + ], + 'initial': 'middle option', + }, + }})) + entity_id = 'input_select.test_1' + + state = self.hass.states.get(entity_id) + self.assertEqual('middle option', state.state) + + data = {ATTR_OPTIONS: ["test1", "test2"], "entity_id": entity_id} + self.hass.services.call(DOMAIN, SERVICE_SET_OPTIONS, data) + self.hass.block_till_done() + + state = self.hass.states.get(entity_id) + self.assertEqual('test1', state.state) + + select_option(self.hass, entity_id, 'first option') + self.hass.block_till_done() + state = self.hass.states.get(entity_id) + self.assertEqual('test1', state.state) + + select_option(self.hass, entity_id, 'test2') + self.hass.block_till_done() + state = self.hass.states.get(entity_id) + self.assertEqual('test2', state.state) From 3b32afda01571df67645bcea8f0227dbe98dcad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 30 Jan 2017 18:20:35 +0100 Subject: [PATCH 019/157] bug fix in hue (#5623) --- homeassistant/components/light/hue.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 3e1e81b05ea..a934788f36b 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -59,11 +59,9 @@ DEFAULT_ALLOW_HUE_GROUPS = True PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST): cv.string, - vol.Optional(CONF_ALLOW_UNREACHABLE, - default=DEFAULT_ALLOW_UNREACHABLE): cv.boolean, - vol.Optional(CONF_FILENAME, default=PHUE_CONFIG_FILE): cv.string, - vol.Optional(CONF_ALLOW_IN_EMULATED_HUE, - default=DEFAULT_ALLOW_IN_EMULATED_HUE): cv.boolean, + vol.Optional(CONF_ALLOW_UNREACHABLE): cv.boolean, + vol.Optional(CONF_FILENAME): cv.string, + vol.Optional(CONF_ALLOW_IN_EMULATED_HUE): cv.boolean, vol.Optional(CONF_ALLOW_HUE_GROUPS, default=DEFAULT_ALLOW_HUE_GROUPS): cv.boolean, }) @@ -98,9 +96,11 @@ def _find_host_from_config(hass, filename=PHUE_CONFIG_FILE): def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Hue lights.""" # Default needed in case of discovery - filename = config.get(CONF_FILENAME) - allow_unreachable = config.get(CONF_ALLOW_UNREACHABLE) - allow_in_emulated_hue = config.get(CONF_ALLOW_IN_EMULATED_HUE) + filename = config.get(CONF_FILENAME, PHUE_CONFIG_FILE) + allow_unreachable = config.get(CONF_ALLOW_UNREACHABLE, + DEFAULT_ALLOW_UNREACHABLE) + allow_in_emulated_hue = config.get(CONF_ALLOW_IN_EMULATED_HUE, + DEFAULT_ALLOW_IN_EMULATED_HUE) allow_hue_groups = config.get(CONF_ALLOW_HUE_GROUPS) if discovery_info is not None: From 495b0667e958e082260b3242e281d5a8fc5a0b4f Mon Sep 17 00:00:00 2001 From: miniconfig Date: Mon, 30 Jan 2017 15:29:56 -0500 Subject: [PATCH 020/157] Added new sensor component to monitor OpenEVSE chargers equipped with the WiFi Kit. --- .coveragerc | 1 + homeassistant/components/sensor/openevse.py | 102 ++++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 106 insertions(+) create mode 100644 homeassistant/components/sensor/openevse.py diff --git a/.coveragerc b/.coveragerc index b4f05ee01a3..910622573f8 100644 --- a/.coveragerc +++ b/.coveragerc @@ -325,6 +325,7 @@ omit = homeassistant/components/sensor/nzbget.py homeassistant/components/sensor/ohmconnect.py homeassistant/components/sensor/onewire.py + homeassistant/components/sensor/openevse.py homeassistant/components/sensor/openexchangerates.py homeassistant/components/sensor/openweathermap.py homeassistant/components/sensor/pi_hole.py diff --git a/homeassistant/components/sensor/openevse.py b/homeassistant/components/sensor/openevse.py new file mode 100644 index 00000000000..25b068be5ad --- /dev/null +++ b/homeassistant/components/sensor/openevse.py @@ -0,0 +1,102 @@ +""" +Support for monitoring an OpenEVSE Charger. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.openevse/ +""" + +import logging + +from requests import RequestException + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import TEMP_CELSIUS, CONF_HOST +from homeassistant.const import CONF_MONITORED_VARIABLES +from homeassistant.helpers.entity import Entity + +_LOGGER = logging.getLogger(__name__) +REQUIREMENTS = ['openevsewifi==0.2'] +SENSOR_TYPES = { + 'status': ['Charging Status', None], + 'charge_time': ['Charge Time Elapsed', 'minutes'], + 'ambient_temp': ['Ambient Termperature', TEMP_CELSIUS], + 'ir_temp': ['IR Temperature', TEMP_CELSIUS], + 'rtc_temp': ['RTC Temperature', TEMP_CELSIUS], + 'usage_session': ['Usage this Session', 'kWh'], + 'usage_total': ['Total Usage', 'kWh'] +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_MONITORED_VARIABLES, default=['status']): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the OpenEVSE sensor.""" + from openevsewifi import openevsewifi + + host = config.get(CONF_HOST) + monitored_variables = config.get(CONF_MONITORED_VARIABLES) + + charger = openevsewifi.Charger(host) + + dev = [] + for variable in monitored_variables: + dev.append(OpenEVSESensor(variable, charger)) + + add_devices(dev) + + +class OpenEVSESensor(Entity): + """Implementation of an OpenEVSE sensor.""" + + # pylint: disable=too-many-arguments + def __init__(self, sensor_type, charger): + """Initialize the sensor.""" + self._name = SENSOR_TYPES[sensor_type][0] + self.type = sensor_type + self._state = None + self.charger = charger + self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this sensor.""" + return self._unit_of_measurement + + def update(self): + """Get the monitored data from the charger.""" + try: + if self.type == 'status': + self._state = self.charger.getStatus() + elif self.type == 'charge_time': + self._state = self.charger.getChargeTimeElapsed()/60 + elif self.type == 'ambient_temp': + self._state = self.charger.getAmbientTemperature() + elif self.type == 'ir_temp': + self._state = self.charger.getIRTemperature() + elif self.type == 'rtc_temp': + self._state = self.charger.getRTCTemperature() + elif self.type == 'usage_session': + self._state = float(self.charger.getUsageSession())/1000 + elif self.type == 'usage_total': + self._state = float(self.charger.getUsageTotal())/1000 + else: + self._state = 'Unknown' + except (RequestException, ValueError, KeyError): + _LOGGER.warning('Could not update status for %s', self.name) diff --git a/requirements_all.txt b/requirements_all.txt index ab2c6b036ae..5a82a3e383f 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -333,6 +333,9 @@ neurio==0.3.1 # homeassistant.components.google oauth2client==3.0.0 +# homeassistant.components.sensor.openevse +openevsewifi==0.2 + # homeassistant.components.switch.orvibo orvibo==1.1.1 From 7f3ee8a83cf2a694307cd8ef188b9af2de73f864 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Mon, 30 Jan 2017 21:27:20 -0500 Subject: [PATCH 021/157] [docker] cec install path fixed upstream (#5651) --- script/build_libcec | 8 -------- 1 file changed, 8 deletions(-) diff --git a/script/build_libcec b/script/build_libcec index 1c30d634437..fcac8e6f22c 100755 --- a/script/build_libcec +++ b/script/build_libcec @@ -11,7 +11,6 @@ PYTHON_LIBDIR=$(python -c 'from distutils import sysconfig; print(sysconfig.get_ PYTHON_LDLIBRARY=$(python -c 'from distutils import sysconfig; print(sysconfig.get_config_var("LDLIBRARY"))') PYTHON_LIBRARY="${PYTHON_LIBDIR}/${PYTHON_LDLIBRARY}" PYTHON_INCLUDE_DIR=$(python -c 'from distutils import sysconfig; print(sysconfig.get_python_inc())') -PYTHON_SITE_DIR=$(python -c 'from distutils import sysconfig; print(sysconfig.get_python_lib(prefix=""))') cd "$(dirname "$0")/.." mkdir -p build && cd build @@ -34,12 +33,6 @@ git submodule update --init src/platform make install ) -# Fix upstream install hardcoded Debian path. -# See: https://github.com/Pulse-Eight/libcec/issues/288 -sed -i \ - -e '/DESTINATION/s:lib/python${PYTHON_VERSION}/dist-packages:${PYTHON_SITE_DIR}:' \ - src/libcec/cmake/CheckPlatformSupport.cmake - # Build libcec ( mkdir -p build && cd build @@ -47,7 +40,6 @@ sed -i \ cmake \ -DPYTHON_LIBRARY="${PYTHON_LIBRARY}" \ -DPYTHON_INCLUDE_DIR="${PYTHON_INCLUDE_DIR}" \ - -DPYTHON_SITE_DIR="${PYTHON_SITE_DIR}" \ .. make make install From 976cd545feab767a7de070ab08832f40958a96a5 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Tue, 31 Jan 2017 03:19:49 -0500 Subject: [PATCH 022/157] Fixes issue #5627 by bumping external Amcrest module to version 1.1.4 (#5662) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/camera/amcrest.py | 2 +- homeassistant/components/sensor/amcrest.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/camera/amcrest.py b/homeassistant/components/camera/amcrest.py index ecc93dfaaeb..f272dda4bb3 100644 --- a/homeassistant/components/camera/amcrest.py +++ b/homeassistant/components/camera/amcrest.py @@ -18,7 +18,7 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import ( async_get_clientsession, async_aiohttp_proxy_stream) -REQUIREMENTS = ['amcrest==1.1.3'] +REQUIREMENTS = ['amcrest==1.1.4'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/amcrest.py b/homeassistant/components/sensor/amcrest.py index 44fdeca54f1..08d551b8fde 100644 --- a/homeassistant/components/sensor/amcrest.py +++ b/homeassistant/components/sensor/amcrest.py @@ -20,7 +20,7 @@ import homeassistant.loader as loader from requests.exceptions import HTTPError, ConnectTimeout -REQUIREMENTS = ['amcrest==1.1.3'] +REQUIREMENTS = ['amcrest==1.1.4'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index abe9fdf730e..762013c5524 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -39,7 +39,7 @@ aiohttp_cors==0.5.0 # homeassistant.components.camera.amcrest # homeassistant.components.sensor.amcrest -amcrest==1.1.3 +amcrest==1.1.4 # homeassistant.components.media_player.anthemav anthemav==1.1.8 From 2c31e3ea8c0fe74a69c21a01110685ef2b2cb932 Mon Sep 17 00:00:00 2001 From: Teemu R Date: Tue, 31 Jan 2017 09:23:05 +0100 Subject: [PATCH 023/157] Cleanup modes & available, bump version requirement (#5606) * Cleanup modes & available, bump version requirement * check for Noneness on available --- .../components/climate/eq3btsmart.py | 19 +++++++++---------- requirements_all.txt | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/climate/eq3btsmart.py b/homeassistant/components/climate/eq3btsmart.py index 6587ad86300..7e0712647ea 100644 --- a/homeassistant/components/climate/eq3btsmart.py +++ b/homeassistant/components/climate/eq3btsmart.py @@ -10,14 +10,14 @@ import voluptuous as vol from homeassistant.components.climate import ( ClimateDevice, PLATFORM_SCHEMA, PRECISION_HALVES, - STATE_UNKNOWN, STATE_AUTO, STATE_ON, STATE_OFF, + STATE_AUTO, STATE_ON, STATE_OFF, ) from homeassistant.const import ( CONF_MAC, TEMP_CELSIUS, CONF_DEVICES, ATTR_TEMPERATURE) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['python-eq3bt==0.1.4'] +REQUIREMENTS = ['python-eq3bt==0.1.5'] _LOGGER = logging.getLogger(__name__) @@ -61,15 +61,12 @@ class EQ3BTSmartThermostat(ClimateDevice): # we want to avoid name clash with this module.. import eq3bt as eq3 - self.modes = {None: STATE_UNKNOWN, # When not yet connected. - eq3.Mode.Unknown: STATE_UNKNOWN, - eq3.Mode.Auto: STATE_AUTO, - # away handled separately, here just for reverse mapping - eq3.Mode.Away: STATE_AWAY, + self.modes = {eq3.Mode.Open: STATE_ON, eq3.Mode.Closed: STATE_OFF, - eq3.Mode.Open: STATE_ON, + eq3.Mode.Auto: STATE_AUTO, eq3.Mode.Manual: STATE_MANUAL, - eq3.Mode.Boost: STATE_BOOST} + eq3.Mode.Boost: STATE_BOOST, + eq3.Mode.Away: STATE_AWAY} self.reverse_modes = {v: k for k, v in self.modes.items()} @@ -79,7 +76,7 @@ class EQ3BTSmartThermostat(ClimateDevice): @property def available(self) -> bool: """Return if thermostat is available.""" - return self.current_operation != STATE_UNKNOWN + return self.current_operation is not None @property def name(self): @@ -116,6 +113,8 @@ class EQ3BTSmartThermostat(ClimateDevice): @property def current_operation(self): """Current mode.""" + if self._thermostat.mode < 0: + return None return self.modes[self._thermostat.mode] @property diff --git a/requirements_all.txt b/requirements_all.txt index 762013c5524..08fdac11a60 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -498,7 +498,7 @@ pysnmp==4.3.2 python-digitalocean==1.10.1 # homeassistant.components.climate.eq3btsmart -# python-eq3bt==0.1.4 +# python-eq3bt==0.1.5 # homeassistant.components.sensor.darksky python-forecastio==1.3.5 From 5f0138f8e465859ec98a7a5dea63b63a315648c9 Mon Sep 17 00:00:00 2001 From: Teemu R Date: Tue, 31 Jan 2017 10:01:11 +0100 Subject: [PATCH 024/157] new yeelight backend lib, new features (#5296) * initial yeelight based on python-yeelight * adapt yeelight's discovery code & suppress exceptions on set_default * Support flash & code cleanups Adds simple pulse for flashing, needs to be refined. This commit also includes changing transition from seconds to milliseconds, and cleans up the code quite a bit. * cleanup code, adjust default transition to 350 * bump required version to 0.0.13 * Cleaning up and marking todos, ready to be reviewed * Renamed back to yeelight. * Removed effect support for now until we have some sane effects available. * Add "breath" notification for flash, currently hidden behind a False check due to unknown issue not accepting it. * TODO/open points are marked as such. * Fix a typo in rgb calculation * yeelight__ for autodetected bulbs hostname from mdns seems to vary * Lint fixes, add music mode, fix flash * Flash transforms now to red and back * Fix lint warnings * Add initial music mode. * remove unused mode logging, move set_mode to turn_on * Add save_on_change configuration variable * yeelight: check if music mode is on before enabling it. * Fix linting, bump required python-yeelight version * More linting fixes, use import when needed instead of saving the module handle * Use OR instead of + for features assignment * Fix color temperature support, convert non-rgb values to rgb values in rgb() * Fix typo on duration, thanks @qzapwy for noticing * yeelight: fix issues from review, behave when not available * Implement available() * Fix transition to take seconds instead of milliseconds * Fix default configuration for detected bulbs * Cache values fetched in update() * Add return values for methods * yeelight: kwarg-given transition overrides config, slight cleanups * change settings back to optional, request update when calling add_devices * As future version of python-yeelight will wrap exceptions, we can handle broken connections more nicely. * bump yeelight library version * Remove unused import * set the default only when settings are changed and not, e.g., when turned on by automation * update comment & fix linting --- homeassistant/components/light/yeelight.py | 341 +++++++++++++++------ requirements_all.txt | 6 +- 2 files changed, 249 insertions(+), 98 deletions(-) diff --git a/homeassistant/components/light/yeelight.py b/homeassistant/components/light/yeelight.py index a8a2ec9b3fc..616bae94a91 100644 --- a/homeassistant/components/light/yeelight.py +++ b/homeassistant/components/light/yeelight.py @@ -5,158 +5,309 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.yeelight/ """ import logging -import socket +import colorsys import voluptuous as vol +from homeassistant.util.color import ( + color_temperature_mired_to_kelvin as mired_to_kelvin, + color_temperature_kelvin_to_mired as kelvin_to_mired, + color_temperature_to_rgb) from homeassistant.const import CONF_DEVICES, CONF_NAME -from homeassistant.components.light import (ATTR_BRIGHTNESS, ATTR_RGB_COLOR, - ATTR_COLOR_TEMP, - SUPPORT_BRIGHTNESS, - SUPPORT_RGB_COLOR, - SUPPORT_COLOR_TEMP, - Light, PLATFORM_SCHEMA) +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_TRANSITION, ATTR_COLOR_TEMP, + ATTR_FLASH, FLASH_SHORT, FLASH_LONG, + SUPPORT_BRIGHTNESS, SUPPORT_RGB_COLOR, SUPPORT_TRANSITION, + SUPPORT_COLOR_TEMP, SUPPORT_FLASH, + Light, PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv -from homeassistant.util import color as color_util -from homeassistant.util.color import \ - color_temperature_mired_to_kelvin as mired_to_kelvin -REQUIREMENTS = ['pyyeelight==1.0-beta'] +REQUIREMENTS = ['yeelight==0.2.1'] _LOGGER = logging.getLogger(__name__) +CONF_TRANSITION = "transition" +DEFAULT_TRANSITION = 350 + +CONF_SAVE_ON_CHANGE = "save_on_change" +CONF_MODE_MUSIC = "use_music_mode" + DOMAIN = 'yeelight' -SUPPORT_YEELIGHT = (SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR | - SUPPORT_COLOR_TEMP) - -DEVICE_SCHEMA = vol.Schema({vol.Optional(CONF_NAME): cv.string, }) +DEVICE_SCHEMA = vol.Schema({ + vol.Optional(CONF_NAME): cv.string, + vol.Optional(CONF_TRANSITION, default=DEFAULT_TRANSITION): cv.positive_int, + vol.Optional(CONF_MODE_MUSIC, default=False): cv.boolean, + vol.Optional(CONF_SAVE_ON_CHANGE, default=True): cv.boolean, +}) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( {vol.Optional(CONF_DEVICES, default={}): {cv.string: DEVICE_SCHEMA}, }) +SUPPORT_YEELIGHT_RGB = (SUPPORT_RGB_COLOR | + SUPPORT_COLOR_TEMP) + +SUPPORT_YEELIGHT = (SUPPORT_BRIGHTNESS | + SUPPORT_TRANSITION | + SUPPORT_FLASH) + + +def _cmd(func): + """A wrapper to catch exceptions from the bulb.""" + def _wrap(self, *args, **kwargs): + import yeelight + try: + _LOGGER.debug("Calling %s with %s %s", func, args, kwargs) + return func(self, *args, **kwargs) + except yeelight.BulbException as ex: + _LOGGER.error("Error when calling %s: %s", func, ex) + + return _wrap + def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Yeelight bulbs.""" lights = [] if discovery_info is not None: - device = {'name': discovery_info['hostname'], - 'ipaddr': discovery_info['host']} - lights.append(YeelightLight(device)) + _LOGGER.debug("Adding autodetected %s", discovery_info['hostname']) + + # not using hostname, as it seems to vary. + name = "yeelight_%s_%s" % (discovery_info["device_type"], + discovery_info["properties"]["mac"]) + device = {'name': name, 'ipaddr': discovery_info['host']} + + lights.append(YeelightLight(device, DEVICE_SCHEMA({}))) else: for ipaddr, device_config in config[CONF_DEVICES].items(): - device = {'name': device_config[CONF_NAME], 'ipaddr': ipaddr} - lights.append(YeelightLight(device)) + _LOGGER.debug("Adding configured %s", device_config[CONF_NAME]) - add_devices(lights) + device = {'name': device_config[CONF_NAME], 'ipaddr': ipaddr} + lights.append(YeelightLight(device, device_config)) + + add_devices(lights, True) # true to request an update before adding. class YeelightLight(Light): """Representation of a Yeelight light.""" - def __init__(self, device): + def __init__(self, device, config): """Initialize the light.""" - import pyyeelight - + self.config = config self._name = device['name'] self._ipaddr = device['ipaddr'] - self.is_valid = True - self._bulb = None - self._state = None - self._bright = None + + self._supported_features = SUPPORT_YEELIGHT + self._available = False + self._bulb_device = None + + self._brightness = None + self._color_temp = None + self._is_on = None self._rgb = None - self._ct = None - try: - self._bulb = pyyeelight.YeelightBulb(self._ipaddr) - except socket.error: - self.is_valid = False - _LOGGER.error("Failed to connect to bulb %s, %s", self._ipaddr, - self._name) @property - def unique_id(self): + def available(self) -> bool: + """Return if bulb is available.""" + return self._available + + @property + def supported_features(self) -> int: + """Flag supported features.""" + return self._supported_features + + @property + def unique_id(self) -> str: """Return the ID of this light.""" return "{}.{}".format(self.__class__, self._ipaddr) @property - def name(self): + def color_temp(self) -> int: + """Return the color temperature.""" + return self._color_temp + + @property + def name(self) -> str: """Return the name of the device if any.""" return self._name @property - def is_on(self): + def is_on(self) -> bool: """Return true if device is on.""" - return self._state == self._bulb.POWER_ON + return self._is_on @property - def brightness(self): + def brightness(self) -> int: """Return the brightness of this light between 1..255.""" - return self._bright + return self._brightness + + def _get_rgb_from_properties(self): + rgb = self._properties.get("rgb", None) + color_mode = self._properties.get("color_mode", None) + if not rgb or not color_mode: + return rgb + + color_mode = int(color_mode) + if color_mode == 2: # color temperature + return color_temperature_to_rgb(self.color_temp) + if color_mode == 3: # hsv + hue = self._properties.get("hue") + sat = self._properties.get("sat") + val = self._properties.get("bright") + return colorsys.hsv_to_rgb(hue, sat, val) + + rgb = int(rgb) + blue = rgb & 0xff + green = (rgb >> 8) & 0xff + red = (rgb >> 16) & 0xff + + return red, green, blue @property - def rgb_color(self): + def rgb_color(self) -> tuple: """Return the color property.""" return self._rgb @property - def color_temp(self): - """Return the color temperature.""" - return color_util.color_temperature_kelvin_to_mired(self._ct) + def _properties(self) -> dict: + return self._bulb.last_properties @property - def supported_features(self): - """Flag supported features.""" - return SUPPORT_YEELIGHT + def _bulb(self) -> object: + import yeelight + if self._bulb_device is None: + try: + self._bulb_device = yeelight.Bulb(self._ipaddr) + self._bulb_device.get_properties() # force init for type - def turn_on(self, **kwargs): - """Turn the specified or all lights on.""" - if not self.is_on: - self._bulb.turn_on() + btype = self._bulb_device.bulb_type + if btype == yeelight.BulbType.Color: + self._supported_features |= SUPPORT_YEELIGHT_RGB + self._available = True + except yeelight.BulbException as ex: + self._available = False + _LOGGER.error("Failed to connect to bulb %s, %s: %s", + self._ipaddr, self._name, ex) - if ATTR_RGB_COLOR in kwargs: - rgb = kwargs[ATTR_RGB_COLOR] - self._bulb.set_rgb_color(rgb[0], rgb[1], rgb[2]) - self._rgb = [rgb[0], rgb[1], rgb[2]] + return self._bulb_device - if ATTR_COLOR_TEMP in kwargs: - kelvin = int(mired_to_kelvin(kwargs[ATTR_COLOR_TEMP])) - self._bulb.set_color_temperature(kelvin) - self._ct = kelvin - - if ATTR_BRIGHTNESS in kwargs: - bright = int(kwargs[ATTR_BRIGHTNESS] * 100 / 255) - self._bulb.set_brightness(bright) - self._bright = kwargs[ATTR_BRIGHTNESS] - - def turn_off(self, **kwargs): - """Turn the specified or all lights off.""" - self._bulb.turn_off() - - def update(self): - """Synchronize state with bulb.""" - self._bulb.refresh_property() - - # Update power state - self._state = self._bulb.get_property(self._bulb.PROPERTY_NAME_POWER) - - # Update Brightness value - bright_percent = self._bulb.get_property( - self._bulb.PROPERTY_NAME_BRIGHTNESS) - bright = int(bright_percent) * 255 / 100 - # Handle 0 - if int(bright) == 0: - self._bright = 1 + def set_music_mode(self, mode) -> None: + """Set the music mode on or off.""" + if mode: + self._bulb.start_music() else: - self._bright = int(bright) + self._bulb.stop_music() - # Update RGB Value - raw_rgb = int( - self._bulb.get_property(self._bulb.PROPERTY_NAME_RGB_COLOR)) - red = int(raw_rgb / 65536) - green = int((raw_rgb - (red * 65536)) / 256) - blue = raw_rgb - (red * 65536) - (green * 256) - self._rgb = [red, green, blue] + def update(self) -> None: + """Update properties from the bulb.""" + import yeelight + try: + self._bulb.get_properties() - # Update CT value - self._ct = int(self._bulb.get_property( - self._bulb.PROPERTY_NAME_COLOR_TEMPERATURE)) + self._is_on = self._properties.get("power") == "on" + + bright = self._properties.get("bright", None) + if bright: + self._brightness = 255 * (int(bright) / 100) + + temp_in_k = self._properties.get("ct", None) + if temp_in_k: + self._color_temp = kelvin_to_mired(int(temp_in_k)) + + self._rgb = self._get_rgb_from_properties() + + self._available = True + except yeelight.BulbException as ex: + if self._available: # just inform once + _LOGGER.error("Unable to update bulb status: %s", ex) + self._available = False + + @_cmd + def set_brightness(self, brightness, duration) -> None: + """Set bulb brightness.""" + if brightness: + _LOGGER.debug("Setting brightness: %s", brightness) + self._bulb.set_brightness(brightness / 255 * 100, + duration=duration) + + @_cmd + def set_rgb(self, rgb, duration) -> None: + """Set bulb's color.""" + if rgb and self.supported_features & SUPPORT_RGB_COLOR: + _LOGGER.debug("Setting RGB: %s", rgb) + self._bulb.set_rgb(rgb[0], rgb[1], rgb[2], duration=duration) + + @_cmd + def set_colortemp(self, colortemp, duration) -> None: + """Set bulb's color temperature.""" + if colortemp and self.supported_features & SUPPORT_COLOR_TEMP: + temp_in_k = mired_to_kelvin(colortemp) + _LOGGER.debug("Setting color temp: %s K", temp_in_k) + + self._bulb.set_color_temp(temp_in_k, duration=duration) + + @_cmd + def set_default(self) -> None: + """Set current options as default.""" + self._bulb.set_default() + + @_cmd + def set_flash(self, flash) -> None: + """Activate flash.""" + if flash: + from yeelight import RGBTransition, SleepTransition, Flow + if self._bulb.last_properties["color_mode"] != 1: + _LOGGER.error("Flash supported currently only in RGB mode.") + return + + transition = self.config[CONF_TRANSITION] + if flash == FLASH_LONG: + count = 1 + duration = transition * 5 + if flash == FLASH_SHORT: + count = 1 + duration = transition * 2 + + red, green, blue = self.rgb_color + + transitions = list() + transitions.append( + RGBTransition(255, 0, 0, brightness=10, duration=duration)) + transitions.append(SleepTransition( + duration=transition)) + transitions.append( + RGBTransition(red, green, blue, brightness=self.brightness, + duration=duration)) + + flow = Flow(count=count, transitions=transitions) + self._bulb.start_flow(flow) + + def turn_on(self, **kwargs) -> None: + """Turn the bulb on.""" + brightness = kwargs.get(ATTR_BRIGHTNESS) + colortemp = kwargs.get(ATTR_COLOR_TEMP) + rgb = kwargs.get(ATTR_RGB_COLOR) + flash = kwargs.get(ATTR_FLASH) + + duration = self.config[CONF_TRANSITION] # in ms + if ATTR_TRANSITION in kwargs: # passed kwarg overrides config + duration = kwargs.get(ATTR_TRANSITION) * 1000 # kwarg in s + + self._bulb.turn_on(duration=duration) + + if self.config[CONF_MODE_MUSIC] and not self._bulb.music_mode: + self.set_music_mode(self.config[CONF_MODE_MUSIC]) + + # values checked for none in methods + self.set_rgb(rgb, duration) + self.set_colortemp(colortemp, duration) + self.set_brightness(brightness, duration) + self.set_flash(flash) + + # save the current state if we had a manual change. + if self.config[CONF_SAVE_ON_CHANGE]: + if brightness or colortemp or rgb: + self.set_default() + + def turn_off(self, **kwargs) -> None: + """Turn off.""" + self._bulb.turn_off() diff --git a/requirements_all.txt b/requirements_all.txt index 08fdac11a60..7a85b87efbb 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -554,9 +554,6 @@ pywebpush==0.6.1 # homeassistant.components.wemo pywemo==0.4.11 -# homeassistant.components.light.yeelight -pyyeelight==1.0-beta - # homeassistant.components.zabbix pyzabbix==0.7.4 @@ -685,6 +682,9 @@ yahoo-finance==1.4.0 # homeassistant.components.sensor.yweather yahooweather==0.8 +# homeassistant.components.light.yeelight +yeelight==0.2.1 + # homeassistant.components.light.zengge zengge==0.2 From 29816f304107b668aca924cb6401ff421012dade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Tue, 31 Jan 2017 13:51:02 +0100 Subject: [PATCH 025/157] Vlc (#5665) * vlc default name --- homeassistant/components/media_player/vlc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/media_player/vlc.py b/homeassistant/components/media_player/vlc.py index 711c8c74422..c961811f168 100644 --- a/homeassistant/components/media_player/vlc.py +++ b/homeassistant/components/media_player/vlc.py @@ -21,6 +21,7 @@ REQUIREMENTS = ['python-vlc==1.1.2'] _LOGGER = logging.getLogger(__name__) CONF_ARGUMENTS = 'arguments' +DEFAULT_NAME = 'Vlc' SUPPORT_VLC = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ SUPPORT_PLAY_MEDIA | SUPPORT_PLAY @@ -34,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the vlc platform.""" - add_devices([VlcDevice(config.get(CONF_NAME), + add_devices([VlcDevice(config.get(CONF_NAME, DEFAULT_NAME), config.get(CONF_ARGUMENTS))]) From 9ae574c7d9578dc038c828f422b6076eb2c211fe Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 31 Jan 2017 07:39:01 -0800 Subject: [PATCH 026/157] Update frontend (#5669) --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 8 +++++++- .../frontend/www_static/frontend.html.gz | Bin 137251 -> 137289 bytes .../www_static/home-assistant-polymer | 2 +- .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2339 -> 2341 bytes 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 8496b59be4c..d66832c8d6a 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,7 +2,7 @@ FINGERPRINTS = { "core.js": "40a73d7be324cb52fbba55d993db126c", - "frontend.html": "d3e11787b7487dfe95a957ff029ae2a2", + "frontend.html": "237887f9419d044774ea6c35bad82e40", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 6e43f6f5fc0..e428597871e 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -224,6 +224,9 @@ window.hassUtil.domainIcon = function (domain, state) { case 'binary_sensor': return state && state === 'off' ? 'mdi:radiobox-blank' : 'mdi:checkbox-marked-circle'; + case 'calendar': + return 'mdi:calendar'; + case 'camera': return 'mdi:video'; @@ -251,6 +254,9 @@ window.hassUtil.domainIcon = function (domain, state) { case 'homeassistant': return 'mdi:home'; + case 'image_processing': + return 'mdi:image-filter-frames'; + case 'input_boolean': return 'mdi:drawing'; @@ -401,7 +407,7 @@ window.hassUtil.isComponentLoaded = function (hass, component) { window.hassUtil.computeLocationName = function (hass) { return hass.config.core.location_name; -}; \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 58a5826255a6d05df9213920a071dbab932673b7..f0cbc9b47867988c8f06e2082fce6687ece33722 100644 GIT binary patch delta 76550 zcmV(tKocAkr3OJF$CN4_Cy6@oLuA0)y*V;73E1soX&)kaoHE#k^>=|!PI~qL0ETmWy zT0;l-N~~m5i^tecr;ON&**FouKIo!-qv@m24J};8_H!^1gV~wwBa6~mJF5#M{qu#StPd2eWi2Go zkqeKs6p9fhv`Tu)OamO1Y64BRf9Miw3mM*xvnOJLflEnFQ$^>sk5MjmmpLxKL3{e7 zDJ_XV4K0i*{S6Aftk>qSy(kyv@&mXq!e&GdxfmpiVp8orX;fwe0Po6#ffBpBjhbPb8 z{{H)mXNL!+v#)i54ref{eB$5xjotk~rvh=)Vf2#~${zKNK(10BRTo#!Nx;al!C0gQknLn7$0wHj!M3w5`Z$K&*Z;kDYRtfS-1NO=Y?RW$8EW^1r1xCWN(k_hXY^RkV>>m^(f)q&j= zMqQqkGK82)hLweT6HZ59@?Kp(z+s!-^mmAnqyy>G2-FoC z#-xIQsClY|(g6ckfsM7w%S0OU3g<-bYP@YQc9Xp#_GLUgic$;nQ-{V|a8)W(nt^Va z5*18wSE%g}6nNzW>)8n^vH*_Rehx(L6nYk+ zeCU%_sJE$Nq;D-jpjks-IE|X4tS`sHYDhsPe7q@Tu|$u)(M}QIR(=(M|QuFdckhmK~TR|)>Wg93})2Q24 zf{0NGCvtsq>l4S)SmWRY;dC`N3c>k@u~g8q)OUAQ(6}S*o85x$PHIFB)s9ohI{nuR zk&Dryo4#E^h5ri>7H;2f@`*66xoPH#XKmhRFT$n* z{o(QzcHFnxPt(EvUYY*6oY>t;6j$9Mi&~8> zT0dAdMcbx&T7H1{@dX?JSV@G(KdxM1KmcNeG&u;dnwsHT+?s`ygvj$AP=^n-Dal#) z6fh+%e?icnzY#V(D>IGz1;vp$$8eX9p4vcX+x4_2x+FyUlSkNQr zQ?oRUDb-`>=$vwF!b+V!bna~B2OkoOMl_F~GL5cfz6fs}il2}m~2`R*yoS836@@@@N|~JvB7dzl=N$;~19+H9FX5up%NXi@ph=DvSOV zaBDht_X}mM@@MXm!d3&$@VvrCL;5r@R_&*rs5jZ`w+9KAOU4OMEc`RgZg8Wh+ zQ_|q$Yy-xJU0L8t#smfzVjL)&1Ckwk^uM_totHHgRLYOrldHG4fkYme#SBvG!Z-TH zRFSbpn-NH2RXj2XnkugPu~$|He?dj>0Hz?Bc<4uN{2g3IegKcVc|*hSq$0i zWvCDxs?cg^N4A>~dDM)1^E;|)bOalwfRM_axNt=*SHx}-JI;YBnLlpj%WVz>iBC8> z+`XguF*5Iz_U&f0;!f~d64??1N2pVuW}Gw;2s;W_I0n>5O26S1S#!^te@br71SWx9 zx2|K{hjBlW1z5s(oLILw0l0%~0u)&2FzYjt&GYs#>@W|F7|n@Y7{l5KM8!;GFTX{u za%RKUTJpN=KG)_Bmx?!UiytDFksU0?&(Aiz(2h3{CN{!WHflT)Y5#bQkmf!5r;4+s zPncX#rEHF;!4h`L8O9-ee?3-<^XFwVEf=#Q?zP2s5<>G9b`S&hqcxz$swsKeZnQg) z_gsp)2P)Alvx>7mNu3O;l`}Q&MhT=?zDI3+<#rjs7e)T& zC5q%6We#ur1QHLe{y+o=4~q1mxh?Kn!@EW-ndGn6rLoHJ z?yJrh@0_FNQ)TWL}- zN9p}^tpkHuU3`W=SH+^7Z|K3mtg>}DCda9_@620jspD^0?D}lJ{471wS_I6KpLifQ zYuYv&^a2KBY;O*e6AlCvPIWvam1WI zQqkQZwiMYr(T%atQclQ=DRmLoPR8VsZ3*za=t^%g6*+k?4&7kp-DBbA(f8ZRAZ5tkRwj69Mw7tU9^~gH!;p!aB z+!|2o`wgFTIP3p=e}HflbkQ&KHd&S6NHj{>a!egV5+gE~2L7C%!!hd`OJ>!$D$9>+ zD_E1>f2oCU1LRCXU6y*aWRVc%BcI2Pt zfhdNIolvJw{(2*0_)&B}lPa*MvNbti-$pz;YXoV}^lWZUfLUS3R$wY^O6Mwn6WMn8 zkE935lrRt)v{Js5BjIc+*-Gw7kBXa~jY+?ke~R`=^W=9LFb3RifZA)SPvyTOvB3U~ z@3(ITxBc%*0L6^vPH)y`a;Nh5}05-xGB$RwX&XobsSVr zN|Dq*jzK@RNZ{;JJmJZ+mis9l~gL(t$6klEq#_E;#%2*E1u{GVRo-c0fl3iLo<1 zzNGC5M@SdD)MXiNR+(_%@nUvfe)wEnf5kmqi-Kzk2@v1XZo}C5;8^cIczE>%jql_r zKa_N;J|PO_3arT?D%=|h)iXu_(c!}W9jc2mRLE0TP1MDjR8k2Yfp4<%^(rg~QS=s8WE-uS(o=S*J_DJB|7qg1wDmfYths*v2g=G49w26!ZZWoea9HN3f z)SZ6hPyCf+Yxs5}VoTH%r$RjvBzq}tuBl#R6EblIh>O=rDTR%Z)z zx-1na`!|aIsI$a+tt8_%e@o2gUou`~iSe#Y#yblGU5qPrYZfcR3$#J62E;1~vwX=2 zagyj-iWaw&$g+wT20cYcIrNDq{9LSiOfv1+UQO_ zgB+zbxlmXy>Fc0jy=1RNvq{|qQCV*RFT(QuMqGzrQ)t`Q$`fHKf7?raR|Z!EiBx!T zE2Te8^ob%}xxw!m_ei3~>BkS4g7UUgK%gHdREjdJQh#?!0G7A%;dGKR9V+2VYR1(X zF>N^+(f3^)Qz6@?Ova=xg-!A+X%F{dS}*7G=T&Xl`!u+uPuaN|AmrpL>_IV~+rHjJ zd~!8d@d!?`8$k~mehxIFJzhPG{a-pH3fe9)9~^iL(`I* z6nBgjh}ov{)T9=Y`RE`gYUZsLpr;94y9fw-Mrgt}&O12N-mK^lHl?SV)9;Kxtoe8UkS{ zS({l~#eFblfiO$=nL$EXkR$d$;8ZETcS#GKjw3r)X0NH>GCozP@>34QO#J9kV?KhfL|u2 z`Gor*m&cFb3B#}fx?RxsIFAD$)9L~Xhft+Am|S~ML%@43fTphk+C<^T zEN#NE3dCc{E5jKhL{WO&?68j9tboaaoOia9GZUmsbiy_>ueV{H6^zin| zahZ-evszGQIndeTQZ4)6gKiP!oIL=VeNif&l9`B=f2gP8v_YHuj=kntOhPzgwGHM= z>7JF>?glfc%o#ixO#;B9(3bOD%JqHgVYJLY7?5yO9axOYaiZTk$+372VId=VY}GjK z%Ly{24O2f<>k!wo%!%5PUJ5mb=pZp9Gej|7eMzB9m3nU`le69k{!iqYo~(Z=)yT|U z@{@AfAj;|N15_;MTezoL}Pf4X3-~vTwqkp zS^-%bbtNB)EdiaE&1NAbsOW~;JskAI5Hbgakfw}lr-I(q~es&&$afAbTOfrm77 zV$>0y@c2cSpe{?|Wh!sUPA)w#ND!r;4pgh2<`OKk2q2jOZ!{ov+)N?6+;VXpH^vo_ zp4s)3VI5?oD^IXqFlg!2R#@6&;lrw(JGd3j+=mxW-#`29i`(yo^Iwb|c_rAJ6e5Kt<9bs2A6l5b=6~(7 zbUW$+3=u$o$|t45du0Uasgh~7&Z~pt5ixk<$ZfR9C3nntBgSq6x&yM30`f%5jIfC2 zWMu);#J(paej$~NVkZV()O(>&uvK#rF(8urLK#P?;=r|mA*Ro&1wbk!0ZF|)>tWdW zQ}QY%p4CSvB9r@p7)yHA!_)b7-B-cKX6}Kb@>W+uaRCZ9 zXt;fS)tiy4`(~ObE=!ntLlH}WH@?OX)>`an*EQl+MY>yUefXjk@=cs+cmZ#5>B8PV zoUt5te>=N^(x*jjzpLXfSt#m08(E_YcK$W|pogK*p@O9M_zTmz;N1kIDG-n!e-y}n zSHt9Us%qXJzSbHrbvsXVoChfJOoW1A8w+;CG?S`HG&r#+f%8ahA9!bT{QWpUuKFgO z>Mq9LhbF%3+>>3bFjd_M1q9BY0maUVG7dzxe+KrC*BHMOr=JzTH?(~>YM8PTGKaYu zP{22e_XbalZ9=ar>4>zzdvx_>vb=7wELx-qD@K5SX<|iUG&WTWq&9w{moUAqn`J$| zT9TWF$v+3o(i%-@fYLrrNKo#NU_c^`ek;Su;%aaK$#YT|WlLO=rZYc!<8ndEIxQx2 zf6aM~eMnjS*!!tke7xa?O;bUmB+T%mkPbmEynBoK>wse23AvIqH5@+VHcg9wHBHNc z)E+c%earU6TC>SoV{HT3uf`{-+7q+w!@ubM`=+A`mslyT^^GS2WAjH}?8QdkwjCm7 zvsjTNiWIEx=m`FxF&?JjC;lblym?Eue{1m9Fd)R-wem9mWJXxAGS_Ct2IRo+u*Fx4 zk6($h3rl)^Ia@$L2eau2X|CfJP-tP_@ih8TH90ru{#%iv0K$8v-rX&C@>;pNj1;73 z7u&~@7ZQx-)445^TojJ{(VQS=8g4JqSxvy4?C$+l2KVZl3Zoo#1Z3MXx({98f3Jju zr-=#GSjr*;CX?g@>%1vY49G$OyuTV#M3Z(pb;C*TC8(vYSfNVzU0isVi}MqYOI)iVz39ES46UuDKY345`64eno@`#R` z5WXm)p*J=>UXTJfflbGr^To7w-w#iIfBXCe1+y)Oh%Tg%z-%HXTaj*} zuQVvWP#fsXM;`U(eUBZ`7>(dF>$iPgVK(*X0)^iIY)p#Kt7}Z`J@! zYEuV2A`g0!aO^S3*b`mhWE2kM#t7&R2`Uktqxzue)tO` zr>GVvpbDBku@*zUx*m13H@IGC|Iyak_kxY>PiPxI^FseT8i_FJfE=#oW#BP~jliB| z^80IvHXDNifA%P~HqX#=Ep9s2Cis*x!a^HOCSmPYH{f&pxrB!~rUHwSV0bZoKpR4f zVZt$o?R0u8y{9z_Ka>!z+ycH@s@KsRu5p zCFvlF>&4kwNs>sq0ih*$`6Vo;mqAoWs3}}^<~p{@q?G*8)yBHQ=C%0aFNOGRAX!St z@1g@s56k`g@>87O2cwaP+PC0+MfqpZl0S;A$4=RlPmr#EpVJwPUH z4R_J%e0dXW@exK{&%3H>*uzO?rMpPqlZ#3E&Y6q@QKvKlp z!i{m$-0xV2bf1{r4I8o>Mvhp(DWN~>SY>!xwR%dKS&A<%U9@X=(#_hxLC0g7@wQnd zK0F?HSp^{4sn*wO$XjiD8AGFje}V9^cB9=g3W7<__YW*YZa|vJ=cGv@+;~3dUP)CW}x~2aH=(r*SpClu_w>S zfA54!4`9!6Y9!)dBsN)}8S(TQblMs`1lIIYdr5~x%MN($ZrCBGSV-D^yKwpCs#wf! ze@veh*ENYj$HV;xrXSfsTLHYD59F0K4pWv+`v|LbF>NC~Jlebm@@aXOdN9t3Yh`5h zp56qBE)R$WzgjQw*m~{-{MNCb0;ZVQ?Z*igWq%J@Paoc_2Zzln-jKUGX#4t#{PUT4 ze_T-xQa-s9x|;c~{{WOrdceqS+nk`1)1JX`H_ThdP@V zz??H+EY)jj`P?(NC%CXizHkV*gr8ZDp!!#WW4VBqiy~StC~12sl2o(nqVKOEuXptC z7Qn%8_RXM!%Km8ZAW`r)!N;brh;Ox|bA+$of99~1 zaUW`G&7(z3s9opG4-Kv3&hgwmjg~Z^dX4utW8@)+ZTxyd1TV}jz=hFqm?t7$=t?Ls0JgCr#B{wP@d=p(BfgMhe(`=h{Xo)X zWi=8ttcVp=F%5-=BV#U^s{$RWfBfe%#nG@~r$vx-eZ@)={F^I2MVBuBM&BLrW^h0L zzvZcE+K;?aXkUcjt5^Xu=U9}nB8Syw352X&3Q-B|bve@|g(8*ou@=epLVWwS->6z9 zRlEUx!`HLo3LdRy1ROTu4m*PjxC~0ZCeljZy8SwX&ajQZJ9kC;9IZj4e<9EEFdFXH zl91>#node3C~38lA#nvXo5T!9Y-e#4FSmS`HOGQECy5bIxwE#%Smy=|PhQ^jX34bC zHd104vf=){m>a%JxTEwfci&Ri(@@%r>O17a}+< zH`9so+V%GE*!x*`V)4B)DlI#6WWzn_geU0L$t4SJD zv~Lj2T+d70v;%2fSh`(@pk03eok%((oDsv(t}s{{K?O%P`Ehp(e+#jBBBoab5zZ(c zp$rdmc=N2Oh@i`P_i*B7hOrvy54&Iayyy$wKP{S6Qx2azu<}f5GN&qm1@~oKuMW;v zJmZeZ$uV?XmBePpvnx?A-xMFn)22kOri-V*H7yulh7T^cfZ?2qj~bSDj+f-6oBTTA zIB9oxP!4CaFSobSe{WJjtaTo1zasU0TiLa>TyS{EJ zsox}qmh|RBpyFGMfy%EPg#C6mdnfBer)|-zI|$)v$(+4Ee-8_U2h!zVd6gP9Y0PV? z+BNkx>>sb4HZ_%Y{xr1Nen?y)nJ>u6e!`5#M0wC!Q(W>5p@I>4Tyl${4)Oz8jjnQm z8`{v8d-s{a@ts$J1<<8^#V3jE{Gb?_8wW#X)RV_8#GU_QX~V3i^ay8Pu6Z zfzn!{yD6@_SBR#TUQ_PQ?Q>ShJD*V%9{KF|f3lnb`72?nF;B8vDxgyg7u{eT z&aWPi4%S{E)wo~5HL~_9&Z;LPdGB?$mof>bmL~iJ+aHbo+TOw2#MlIvhR$2K#IrIl z@eePg@MdXjro6?pk3Y|S;GfeTiFoj{y#rmNN9WMd5_FWqWezX}Izbx+^1L>UhVX-a z>7VYBe@}sNe78QiXkM&)(=DO$tdAZxRuF)P&)}jg&@e-|316otfHk=29k24%VI!4v zTbZeNPUmzdzE)241uZd_SE;JMFBP>eie|v@ilV5xJg3O&mLRFKWOxLgm~%}dKZ!Q9 zVBenuU}Y)1AAB8K(qEOXnjW|41y=TY26ql%e;=}AaT}I8aREiIN~v*~Eo?B@jyC7z zmvrT~(6!U9i$DTMUT7WONH2ac5R=>Ccc@(XN8uY|4*@KEko)zXAYoh0st%qv|5D*S z%u$npz4G>-u)+On`jq8uuSQ0JzINZ1_52B-k0X2)a!;KuQMpK$FI1!3n8p`(k3D&g ze?^SiiRIHxkc{sH#A)|7PDaE%506`sh-Tzo!(lbwl)n)cQDp<`RSL~#y19}hlixLa z?Mf!)yeUmD88L!vsdd%m523A&+FxgI`P0xnN?ZZ? z+=ym(cX!Yu*?bQ9@P0&3F@osvXMfONe+*ey^g!D@ZOUtubv(zRF!H)i z*u;Gc-)tX@HBeT#mVY*Ll`KJBEPhwdVtbe!tUL#*My7HtX{32BBpZtR{#)^>e^fq+ zcSc#L9h0D(OH2aqZgV`!M+N&j<}4+_l9659T4^|$xjNY#2n_wi75d zP8yQ<8s0Tx#bG0VgZufw{22b}s68Hg7}o+z*Y|Vs6Hvm+kz@0>0^X|TJhU5q_PNY? zwph^5kaj$cndoy-+%=Qbd~gFqe~aFhXF&SuH&ftj33g=w0zDvIPG#Zc)XD5T+@h9z zwq1GliJ^rJY;CS#;Xqibp_}9XcuSYc*sCy9J)$h%7z1LTaq)fLl7xtDT#e|w{ykf>C7b+Iu z<@NqwvIo@v{{v#HSIkKprzbltXG6oOT1VsgJiZ*pnA4kOzQna7f41*D`jW}Yd?{p? zx3}}G&IRmA8WkhMiuVh$yErow%mKlGXsS7ylS!aO&Ogw~$WWXLApriaNbWUv5$)Js z=hDQX%d9kU<_ceZNprbewiih8Er*gxfZjdpR2GKW>o?va-wb%NB7Y8Vo#A5n8OZ%B zd$1;{U<@g{_KW@9e<_9&$-d^z;3_-Ir-SS4GQT$(Wv|s<^_Jo>JU0gbm}XE+%Ey-n z{i=_a)z{fsc9~}Q^D6tAq2I@FV8vycj;sC@+1&zrto*}3tHN>O$jBH5n7YeJk@-=f3VaC^Bjf!Acfv&ne|5F zbKE#iOhhWYS@N6g}MphF#- zZoXsuFzX#DXDXhM;xp@6E8smQO)di2M%r(Ps(Fh`UzQ7hp>V>Llt}(sqLEdwj2zkf z>&43j$3v7!fBZ%C4FKEaRVir-^D*ISRA@50Q|GaT6M|B40anOc5MB)^As|#*tiM27 zcGS8su95fU8Ehm_HGH3_U^#zCuaR$>b94qt$o|ZHJaVJ`MONZvpnOuCp@!oh=m6qO zFJ4Gcjs6@WbIlS8nX|i#-b-2;Hli1CV?mRj$SVE*e?|)-NJ}|Dj%y#B9TrYeY|t#x zeSc9e;;ST`aBG*Oe_V-{=)KF=+N-nYRo#A#5uFD83{{NLIGawQHE|6u@~fh5%9rzH z(Ng@PqHf`+!0ib8VCR*K8RhJwB>ijvXd$-_&62cB7UWVpKRW>Qd2KlaIU_yP>xJQ{ z(SY%Oe>qsBcVGq1(v<*-8(M~O%Ybnp{^}b9<}$7`?1kDrSQ?iLWJu_MT>0}r|Fp`k zSpQb8xp%5e_OG@5ieF+L_WVc&kCH$V_0Nv*4&b-5@3c$p2-w28N%$cB4IAox6rjeo z$slBF=;JioU@nk=+{$aedqV@#Y#}%^Z!B=8f4PNKCwqrfRE(&QGh4sW#ikQqia^-D zFFASYW&YxlY$;GBsQ ztoDQ_OCEnu6YgG1!`}01)&oq@gZ0JhrCs*exn9qa)A9lj#Gc%df2qykMSD5#9VDyO zfARV^mh(jEC!b+?>obhwo84FlKyo`S3ZP4c{)oC}mH5EESsjjcR9gLQV(Pej+Lu$> z66+4@MsyHTm=>V}8GF3bG*p*Txh#|&kBhT5Bx}}ovutQIcyRSan$#M8|AdGeGld{y zoFqZFBKMo1>q2ccOx_!5`^M;ltnH0@f6#32A^bPE2mjRPrv({wjjLL<9y*RkE zXhaK&4M8P0sbtXnd7R3LD_%j3+*!nezR|^1%sxnf@zc?LAb8&-0=%L8+O z13S-=agFVEM$X_#z#3}XX^x>hz{yYnI06qc3JBegX0zh2d60~Su(%@_pxIv0Dl;6c z#x&&crLpQ{3`!dbZGd)RKoT6CtbzZQ(vAj3Sm(ik%iYrmAk8kMe=@dHc9E;7^%rSY zaCK?%eL~;xW*8$eWvs)v>VclY66)JSr}-hD|E8 zI*Wz1m9)`nET7Z#e_<710o9@hst?)}I=;PKJlP+mHw8Rgq1Hi@*W(@j*lq=FJTI(Y zPV$R8YR=Y$A|l{Mm(|?nelu96cTQk$VWHB!1QwhGF17+6+ofySI`($*m5BQ+D zV{dDz!Y5krXNYgFav7@C-H^P<0@J}&@1sSzw(1l&@a^pqf6^L(cJ)@ue0i)5UR1xz z6bn_o>-doM8;;;3&P0rbs`f~R?WH|hWu~fQT5ld z+@Ytp5-J~r@3tor&$}4|A2B`2QSrf9OJAg~OfT-u;D#Cq?M;QB<^3QgW|wx)hB`pT zwIk3>rF^N&f3;2rURmmUj7$hSE8SWplh!BV1)--#RB0|YI-|ylFq7-L{PkQt8Ujq( zQ=O|0m5~+=4h(M#WiVotAL3&~ztNPQ#yP&$Hf#)wI_;>pUJ~fi4-m|4=oaavxnb{A z*6CiqR5$IPYNWA{#+K`RufZ&$@SCPlR&VpUYSHIMe|j@5nle1{v4tdj*yuZJFmamF zd$2`ISjlZ@oBAq|8$q5L1s+vxtZ|UiPfR{sl5#VOX|`=!F1Ia7?Z^h_(qoJ#%oU;} z^{%rokqn=G3Sq9cGL#amh;4b#qT1%Zw%0px4!O)0PvD354Y!S>-u^@U46q2bTUPeE zXpD5AfAX@sqpL6J%Jfy~v_-xMb-wRdQui}5%60H_pIH3d(9pxiM@9q8ASW+S$Lsm% z(l4di0>DPJI{RXjjretmfm|Qouq6Ze9;99I44y0&(t75R1iwu|_M#YIG`LVCECW~r zPzhL5dJv_*)g0Nof_1&t{o>`U8dE%V!=s+?f7?TjSPXZ1ivrzdWWDBM`5E(+N5JAL zPgpY$lh-@HTN@$ASqmpV4vwOO>BWPK$Gi#8&Xj~Nv@a!i;v6Juf!Ps}o~jd5)wB07 zAGR0J$pEIYps6LDk~5e;N%{w$mesV}1|&MSxdIe?b%CLLdJG=4+dI=@!MdF0eqIm} zf5z$0(2@0z+19|cTx+~0qz}c{h#IN0yJAac<3#*=CJXkl!8Fm^u5to#ZxWV9eYh&i z>BakUx;$SHGC_?-*4NwJ6?%Kv>>n-qX==t7@o`NTSTy{i&=Huj312tEKne~SMLIrsJ)CI57Gb`}=$nSx#(U2k}=>6Ji?e_@yy zxGt^b><#HO7`OBR2<8-o$cP8(Z`wZE5(`3bu#ysk`@i=n;QpSLR=cRa zh8Iqal=FsrU~RWE8GqxQQ`#F6e~~2#6{KsN_5B4tc?s2d5M#d=aNQpnqPc$ym}D^* z!3!@7IM3dpS{-q7$ChLBn8Z#*-Ed}>SeX`1$rR>q2f31BVQxbJf zb&ifig58GK58Tbl3WfL~m`roE_*RxY&~&o)Ny27|<9 zja4*U7*jbT4x|k!p?G&>sK7$CC-)B$YPAQr5$HYoov216yjbKSS|MoXn~U4qxmEse zwnn!_UqW#)F;A7YRF1}Ie+L9hS)+|tSSv3NlIwcT9#vAJPrE6GS$VnKnqc6EZy3{# zf0`B3Uq&;1(CtzN0SaBW9JrM7^W-_CBt2utDPr#(yMe92)|ld28XNBJ4QMF%2i{ci zm9Ya{t?co~)~!B2?ccq7FYEpMFzemJ_(rFAx5rj_bnlnb^1*6&e~w)0c&X=4NB6kY z*H|GlZUdGZJizEmvF(duTv|PP1JW5WN-#3i`4SC_Y{IujF2S*pjo(JTfEAVh8o!Nv z3w%_m=Q>rF{eIZ;L8klp0uNH+cv(*xjjAZqKvjkk1qEHAE;#Ix{JHg;^Kw}uO>wqN zvKt2ES2JNwiM&}lN!z}PP0{1IcAm7m~YbwU9dN^fBF)m$&cuVP-*mnTz>-E{(&FI?4Q zgR#k6Q`x>Vk?Y0B1x5xymyW#D2gx8Ai{E;dUc6T{S-V~of1iqqT`ubeQnPQ?k65=9 z6Nd%fF{MO!Ahkw}czcS}_u#B(&`}LkFJ~vk=i;kZZc(6@Q&r|-d0Bd8Fmdn+!zVAW zwN`3ydj*R*9IC;zs;9_zai=+>`HAqoa&;!(xa(q7-9D&M89G=)hFGlP6lmuY!TdEx z-!;^9OmjP>f5+0IgwuJ?JpdwzW@ci;Ak8u?lplV1hOeqA?f|ZS4(f)LZLm3EGr2~FvxZvy-1sPgvU1$fBGc@_BCs z_&+@Duyk*<$|C4UAf8QJIMTZdXMKqJE3>YEx2^P3pj;k=uV-tLef{*ptzLPaxSX|) zSd#~QnbUCa4W|a*C1zUlEQGPyFT=o8e=L#)ttwmcx~NH{tjPOljE>r`q|=Uig?*tS zX>E1hIyCHFvWxS{lfA;&d2t|p17HmrIf8+8O1n$%D`HI@#BU|l)?H8Tz0}2X+wOAm zuOCCwP|W9AxUjr#!vd<+(DmDETqc<1M3nchn(_+}qxX4$!rq%fYW1#sG$s_S+Tb$`p zo~)7Sc>nk&B(;`0Wxa%uwm?S&X|s+AhCMVsxf+molcbx(nhiOLwnTK_q8!x$Ql|w* zTlUQGLV8AaJo+2x0EdONm7HT&f8bjV)T{|F`#?R4Xk|(89^UVi?6J*pZ#a6?tcjv) z?#2L+&_xLk>6sBu_oorY&vm2I#;c`z`mEp;R**vbU`Y^4q524tgg}0z2|r7muI!CR zy?r>hXl*>Q%#0tVow0Y#mB~7nEfl18^V+7Vv$pR3wyod2RU)R<-rim9#bq{*EDL(3>MpNQzex4dZH(YW!{rmW5!g{(_>+s;c#P_Zg&e9p{t!@C_N z>9AMnH|-ENv%$_(i%;mDbKRkj_aqvyP!YY#*LSq_aaDcU$91#re>QW|+x9-RSwwB-L#$0E#du7%=^cZ~^2X-v0W=Jj! zeh2vHRCa~6SqNSBf376@3JDoGwCYDBiF zpt($6gx&X-T$`rp!DgQGK679PM#;T$TuOsw(=JZ5E)40ie^F@s(pu-bDQgk3QCc;9 zd1CZ&=dPNN8`r3NRb(U~y)a(Tr6f2oG@c_{ulE(u8>MgkR#UpRb_+BjYQ<>uu1 z99o_9l_x>ABBS`oZrEfv3-l;#D0Fhxx*#CL!C9g)Ef!mCVPwHQyx)1h^Rp~F$-ivGG`-o2PEuf(ip2 zw4xZ!8)!|`grQ%6O)*ldHKa_&Ub0sdCwHTyLvg9mu)Qc3rcf;G)7z@gK5An}$ds1d zE$>+g8<^AqB4-8U&98mmn!r{6<5|8-}tnbV|`;4KbjS7 zF^-n}W}1@peqDaorw)5+5{9T*A3FNI_ED)_)^5waW!!G|yE}kM2(vL8%F)J68AG z9X=D}*B?Dkg8>iKGh7TqahWHv$+>i{10`oytp+cvxa#LY-*7+V+KLEEk&fyVf)|5T zONVs0oT4>xit_~7f=Md9fknDf56@5wj0i+e2^|c)%GNE;?ry@Wwyok-m{Y0GPfrLe zV}I%JV4hvW^<}t>S?WdITduNE`uOL2Dn7F@bgG{xXtUugplX~wxt@?9{i1KABSLBc zr_0&b{gjj`g|PksiK%^djDgi}&M-m(IgVZpaYUA{j|XJ4z9=rsP1GpY@pL@0gMV5+ zg3e}DF<+h^-<0R01JmP@FHf?Y}9}EsHB{G35rhplTVSS1~CWt6~bYWTPK*ao9j!2{h;C+YPnuFs2)rS ziB@H!=Mnn<>8W2#%U=o~&AzgG7aFh>goh7SOchwCTdR`sn}LMaE5T-2$Dv&fr`L52 zL%Ugj?1s4M#1g`_6fPQsGV{;A=YWtpo2jU#)TVm>1xs0-RpqQFJfX@%jepPB7LRcIqP#arB zjON9*NDKLA{5k(Rc6$kpOjJH;b*HMU-eb|D`4w&^VEq#|(f?L#Vx2$>tAw$`TCAe5 zhqvefR%DV)Laz;m2wJ<7Ie+@YiRNAa=pP_UGhTZy=?!`gIqfz9Wt@qW1bvnj^>UvdR^Nh!(w-QfC43o4h3w^t>Jta{3) zy1}MyUc$@tD;9CN)mzF(QS@c@`T@SN*X>*4In2;H-e~U`3M|%4gUZY{n8=T~ds(Kk zMvVErm$9)wAzmM{$bZ-ab%=(My!M0r5xJJ`Dl=xmkY=B`L*TXjjzMfN1QJTktU)O7 z^|(Kt+)0YLXeKA(V-rCX_9DS+i*9JN+x8=l#TMP*!P=^q&Cs)8xBiO|v_Qoj&$o5F zl(p|TpWE`k43XQ+kmtM~0e;ALp((k|KlF)U4tNVW233tDIXwnthjKE3s5JI`pxX8;QhhD5$W0 zZzNwwR7M?CQn!A^6=! zDVxT1y#|nSQGe9Wme?urfmFyljI`{iaQ^n>)`OE|r9 zcL+*4DNS2mIZ4Qrb@zJ?v@Qlhb*vBNY!lX7T4F5kD1VMXak@P~T1CaX3bst*LAl;F zYB#T0?xy%udT`mmbG30hpH9mw7qBm(V1-Jo&Y3wu?QizKa$3%Q{Tf>ZDo1cP?M3uPsi;kWPdzRr-L*hs7xdV1YWW zKD()^j(<_f2+U-B20OaRpN5pl~y7Rhxteh%gU9CJvxg!}da)pR-kb6I|bKW7!t6UQCmJ`vvOskI~0rI|TsrKRo; zPpfLVRfbp=gEN@<_xUYx`tj3jIRx{pFg{~v zQh!8}483YbsPj@f&ch-Y+GMe}tr?FS4_f)!g81jy|XE&x=VJYnbMPtCj6ZQQ(=#R{3* z#iyFQ`8{3CumikGpB1pzwj8|vYA%tr{eKMw8>#SlRn+Z7_HnHw~%h<|#_U#bJd7?f};0pZ^Wb{&%%IxNQC#mO|Rx`#xpd z@JV*Fy~R@8q=X%iJ7_XIkbiZ^PYli>s~618M`QGZgFVQ;bJl~DFCuP^~wT$F%6X!81G@B-*>UIb=tiACTKawlIk zEhXX)>Z?;NkWNDa{N=K~bR1W7(BQ`%G81a8 z(hmSjgaN<{gcfUdg#xIBSu8;PomHq)zYNu3ArEr#-+n6Vd2!|PSfyOo>Q?a;wczb3 z$?P2Yitt?%%72@Eg;QQl%`DZYZuKoWm<`KDN@KVF5fk8x$Wd7&it&H`%Ln{QWv zRuRz5?{EuFv=wnXL>|T=fCP*L^M=pgKKtX%i{B4VUcP_&f9S{WZ=b(F9yGk1@G*c6 zEO-ROJ}-Z>&yB&tIH{WVhp*Xxe=V)1Sh>KiBi;Dp;w8vB;$Le@bCWBR1?!aT;@#8O z@&umCiGMQXf>}KiX8Gi!UaZ_qI=$hin~g^DK$>Kg1h*(t>>cCW!uql#DqlYsdVn2t z*d_xE*|x{&Sf{6iL%sEo6OiHy@{e1iA)8Df^HpLQ!w^XQgYb#Xx)N+?fovo&cFriP zI`fC-RU!G!qW%1a88B2DFq@3N%m!@miO>FwG=DOTbo{0arRQU0$}}v%B1M>{(FYKG z2Cg&5CK`|hs0a8k@l&`sm!R^e%P$|OOticz!2^`TWm%xSJLX@<2?AI`I#93<2MH>} znThNR?;zp73EP9|<72mgD|WzV(oCiUcp%Q9h=+zNMq?3rE)3OBywX$6SeenzqD4cA zGJh{G*>C|S>{mmXmhF$y+uISA5sPXU5{+{y6h)Kw7lH~^upM$TAZFQIZ8s%Lyf+%l zgy%r7(65v(OA(-XW$==bgIe)fvhR2)-;+=+>fyfS!3-Wv9%w4F%NwUd&pS7uT_qCq zt*iX2(Qo6W>n56Y9sU}f0C}hq7{?`@Vt?y|%N|}R+S)wW*xJdyR;@Np>PBnzUU%KN z$>Eg>clbU&1zxKasUMW>OB<;hf+;!5+uNJfn z+hFCjrK?wVO&gUn`aot*Y##Qg$Q>P>tty%gz{kDF71Hs>)Xzw(QV17rHLo=44Sxx5 z96ChM1J)Zt(jn$$s>WnpMR@{`-*T2@Ywv_SQSmOmSP(`>BpF@Vsfb`Gabin)LxiVX z<&zUA@H+)sMNChb0SYM1$~EN$p{snjIA=G5%bl-@mR}5ee9-sAsm{dx(h8z}kMQN5 zM2_(AGWwSUn7|)Fx;68+C|hO~N`Km${6hAPf3kUgAv%M9vs(M?D|u`KImTvB3_i^Y zvy=!&A_tqz_vAFv?A%!naiQv4@GM?{Z@@|Omp}DQoD%B6d75VP$259K znddx@VlaPvM&HHYEKRd@1P(ORutUMMv<mxWp#VoUw=mJAx^hM1vJB|^L$TQ z1xOcy9u?;Ylb^#&W6|J>S6OsrG9ofFNm6DBZ$3?5w*8q&vh7GaYJQpK|2j23a;e{ACVzB{E;=@e}WV;B;BrOsXQSb;5R9YwwlIt?&tn9!~23#?PE_u75T-C>vjF-nb!6*e%j@mjbEc z@$n}T^x~7pl|$e_Yep75xWr>5_6Mb>?KxO{SzXmdMRprdNfrDBd;A3kH_pMHAIjvPwIETA!1XI+r zl`}n~`ApQ^V1J4~JL}ILk8W?# zm~ghcdxaW7FpD(91gk7&^4uiL`h2yDYW$G0!IIYS>wf^x{DIDMl)O7>?c$%?kH zBVB+AVb|`iDGIYRUeh7l06e>>=E}L-(z0x}8mCx&WMmsHAj0#J)mFHSc>L%Ax_Y>` zx1Of8E}RN4`qq%$EwR*^VF9GghLER8ughYbY<~q{uDBa~TX6Ek%J&T`jWwd3Niu4L z3_^|X`87M*+1(xOK!!MjVpWVW3Gd3%HbpUiHB3R0=$+N8pHh@wX!>PcNLO%1ajAIe z0Hu6OE7qR<=~ohcqNY;Wv`(k%j)3Jy8jWxJ2^SDAeF^5K@D43gSN(293%+f?z9|;P zd4E|`%eglefkK-6=vYh(h}7!x`tm>X{n5TilK4fC_B?9Y)&GGRU)SjTeKu2P3Eut1 zmE?#o7te|-ECXct^rJbAOe?C-W~4*^S|FKzLV8TE^Ys=4j_Tlp1j zTb!0w*_s6efM2#t#GN^Z3$3rw#$mjs8h^>gomF%!h1^A!?@@2@)npmP%GM$`g3>K^ znqhJMtSqmdnkE8$P1we)2ySmJ)HEr{=)*>-r7#4sDo#?{U?f~fnxz2(Iz?3)v6@fe z0X-|f94=qNG~1X-k^<+Wl8JUnhugV=d>!m(gV&04SaTZe#(%A`nyWdw?5MMmvJ`aI z5JhbH;5eNCJ+!_ycC0EgnzQa^BMt)4o?a2ajJCS3}CfpmBvAuMjAbl667XCnTtD* z6-4``wVk)OG3p%N5nKdT5MBi}srS{X(xpS8iaiFj8Z8}QVdHa+ik#vCX%aAH?H+{< z6Z3qvcn9amzKU`H-6O3}z%WyqV1g4y;5fNta!b5t58+RHMXn$-Oy@RNX^sOQG zEg~i*GkCPhC)G)(D~>&9Q?FZf?~=YwgMy6RrpbPnZRHT?<}?~xVd&@d8^IDb(+70~V$?gyIr?XCJL4Wub)`Oi0j)FzO)45YD%os%)Kb@+va zZX>-Fq5st4^c2&Oix2`!K+}?>n!?i;nMh_0+5(AgYY}s>S=Q~ZU!fc!1fbc_t3=hP z{zLAbTlQiA06~TbnXvN6dT8QSz%wW7u~WRPwjIV7Q=Q*y$=VKX~IO%1XT_C(iz;c>|>a`bO-oc<-1 zIHhX-Ry7q@1883;X`5U-m*o=ZPP^oYIb*oJ9myRM_dzRBI$dp{eRa+lqFAL8z9Uq^ zU%Y;y6v0tA>wis2VBnp7L7A6|3ioH)uTht%cruz4@E*W56fzO2y8wzf5xaw8iF!!N zI_L-dz(mD$imULvYQ!?k7)UjGqC)iOyuF3OQ{B-RbvXsJ&rt1tW zj+V!G3@VgBH1f8rU}@EA1bwK`wJEkHVdFz)i+#dM)qlKdzwYiTb=X$wc+;&MzrwRE znj#!)oz~z$#cCh`KEA8&Rk5o?`cBJg-f!>RP1P1VNC0L_uYgeoPi3Vw7AaI~L8u^Z z%KE(gU>7d33Wp!aa)4LvZ4Jn5A}8~NU`+m&PwI=Jd5yvoXz4Ag$pB$7f~|#r(t}!1 zn?v$30)KSjSfrFHMIl1elb;qX^-s=6>}H(-8taHp2;|H1M6!|A5W}~HnIZc^fl|$a zrsAM@QjhB=1w8QsjKOtM1@rQYdzq6Wg{YVyTk9*1`La$UGEp^y=8kXCu~$q|vC2%s z*=o$p2#yQQ!O$7Z%Yc(K)A8Fg8r9ncP&q)bY=2Pj?RDE!GeKm=ileZgTAaTxi)OiS zJh9eg0~a?_dT-g?=Ng}LMB;dk!vrxLvWSZlJJKmp$-)oUD$MjAM!ZHCEFf|A0*0-< z=kL`f%uX@DVUR1y!$9=vRx`)v%S1fKGlu;y-h^Z>=y(?scZBSwi)0$Q6qA&-grjGk zz<&iGBms-_d`I%q1zF4dH;J^2?6azF+Lz|=q&ynKf!G;ZdT?@5ThavhHbBWO%&d(M zFlFNUe76KnvYNyh3>cb;EWK<<@zWQ#7m0b~H*~!SH6=Rs2I4HxX40YBkPFqeL`cD{ z%>xy1z#<$U5a7A{OdvRnroi^6-`1L13{{Fs%_UgAxo%tuny9?}QJt?3Vv}j!F z7m^pGOib9YmVtx0sG5sFF@wz7-G2>B6Qw<`zVo$7mrNO+&adl!8oSw~voTzcx^p3T zpyp!rbtTt#e5jJ}-B11-y|%onO!YEZq=z4(3IfPhr~tTKMMfFILnek2>{)4J_FW?r z4)6mf+ki*|8X|+$>K~?s8*{R>>PlcPDg;%e9%XeP=|nB*`auR)v{Nl)yMM`j!^9$! z>K>b9%R3Bc%~ukXoO^672Y=>aV||~_gK84%1|=4F<48Q`9qnj_97ZR#J27Qr64`~M zZCGL_&jWI|ZrOoYtK)WA&I{9U z-G*R(RiJ0*NJpo?a}m_EHG~$GJnX30zlZ8L|~&7 z6WZThTS#s{{U`Cq1+)KRFO2f2RH_JcbYe8WwPb=K4bg3V_l;?&-mrq24-O)!wwjS) zt-Btp>)Mip4sA{dTmt$K{KDSwfo+(8O^mnp#)_0C$DJ?_%P{C~Y%E_fbhlQvtmkn?;-VbC0=AmEAmt6B<+)oEwh%ueZvs{B&5 zk=kZXurfWN16}y;v+Wt=p+x;0bTWq2M}BleK_IAv-D{?tDz8wQ9~$?M9uah556JA( z8P9Zi_4S?JPBoG$TWA3UhCb*m((0%^&KIne0JQU>6kDz`&(mLokeFOu zm&FW=FPSvMpMO<5Oj5=_OT5^Zd36w)!clcR4y9*L>$>=guXOy|U#7RW(8kg7IL(%+ zQU%HiR0hhIXyR1}Jr&Us;(^rs7R{zIKr>vNqx}&|G9hj z{Ar zvlx9jYLD3k#Bjdwh> zf9?69{#MS!W6xS$;Cfo%|C01LJt~H2mJqg2xXDwb} z92>46upk#otYf*jp`8Gukx(?UGXV)}WPkAn45`RtH_;mHh-Ig{q312M@KJt&a=Bd` z!Cud~0U3sXj(~o^ivDbMlFxc4+3$H)1%v*#kvD+dM2pb{>yzZcWd1)^W> zKLp6yY9u~jmX+J;(Q$Vx)s!?kVR&wagu@*F$?zY>=Z*F>2M2)Z#Fv-zcn^L-8g3e8 zDix}^D6r-1EM#uT(Dj&98<*`WG=BjIAiYWk^7(xJ+(8x#DG2V@%B$EGxbM4k>rJ%Q>Cd?z~%frTSCKV zsT=s**Sp7{letT;0U!a&xN47 zfs#OzI@xs@WPlJWK{27`Z6Q`Y2fSPM**emhjLN=T8Rn1x$RWPJk{Cj&xPG0!hRbFw z1N;J$!mtHilW#s3;^?5hAYMy-fPfb%5J%Q&7EUY?A}FB^PbFmC-1uT(kdcSvrPUr6 zmE%Lh=7cunh!HCb^e+oj{(r12Xs{GYarJ_7(^=`G&82m?VHJkB8c-CK-OR0)Xzs=7 zDQYy*j`xigXy3o>4TrtMNAU3rPqI@T*I}$}WEPbQ98%>-rhRZp z&50^;;;P4aQs5yu}Z@}C95lIKDgi94~D%wN%o%afbo6TX(T((KLLwFmsA+Nv#(rwCe9gb<&wq13cCT$gb>4*E?>;XbkWSFYbM~2V?lRIB0YX zf2LXxuBg%kH9m$1gK_rtFmAqtW!V=QL5TMX=81u z@ciDrjDPn5{~;bs@-c15>7s;qdld5fAJU5C^*TC|h{A&NC8VHlc85K`I?)dz8o; z5*XasmdI4i$>LUvBAqpgr_I?Q(fP75Dt~6Hv*+XIV6-6bOu>S7fLS@+tEel^uC-)-w2>#~AdPk^a^ZAGIc97Esf&25wEz%;mc& z;mu&X@O11vU(tq~sWDHC zGK`)k{fE(8;97o5uJOGvUIqQbhf#kR;UBngaY?dXUig^v?O`;ChAO#SHJCnt)c(Uq zdU27(s)$UC;MOC8*N9|C{>^*(Uo_P-xKgm7nlOb)Q~`a^)- zP>c2b2!GSKZ`eq0U~HK2Av}oQ!|FYQrF@E)FC<_PK7aDGq>MUP zYK*GxyrfWvsq4N;&h@;PVwc}m|nlzu=!Fr`1@qXSxa- zU@NfJ<#RHA^u&(gfUj(O0sfvyWFve|M?Ss7!<;gIDqSIwOx1iUFYu|nNa*=U+GR#% zQYb$?gHigpqz7~KohrM)A&jd&`$7+KED+id{btMLVJv^92SM56$5k4~np0q_pz3pR zX~Tbn`q*V5nS{iW_zmPWO0^1H-c0&z6|7(%jadT|)})w~4XT&%AL}s6bTOC-mO|}Q zJ{U5>y_ht;;gq+4EQ9`y97gkGc<-K)=_-;R)%~ltLhB1M4%bw+)zj^gSJOlJ!zd1U7|I6FAZ{8ifcz*oi-Mfg?r~KDt z^M19&sLedURkif3aGW_t&(3bMpZyzKIG|UPYW26N**fllN$%B608F%VLi=+QNBjr zd2ayBa4#4h43PUBj8;lFU?oo83{Kvvee!0sGqcC_=B=;M*#)iRqAcrdapl#tf0*9M z6^Dwxheq>ADA&tumY<4r0lH~)ZN_w`) zmu3QbB=)Bfi<5x^q#sA+lI27ye}OzM=m{*8gGitlO=cxZGOJONS&_xTGHbFlvnoq7 z>tc{1vnHmP^)Q9i64PWY$;rAJ?jC@-V)WI$Y>q{7O;=4rw2LXSSv7;rvoxD{m(KH5 zt&a`MuvC2;X^d7f8)SEm){^Xw++$C=_qhui%u%Cp|D+4XTu^9MXL0i;e;a|+wbSk8 z6(DoE$S$El{PQ;v@g~0q`C!#3?%Jgre~0$Mhm!pr#pq@H0$5`S9`g z-_gL8&MbcYBjYh$5PR~VF;fx04}+EPKypw*3yLPceh~3yR2(&^&MkPMKK~`)j(>{b z@J})4CEQY|Q8MxQFV-*re-It>PuVm7W?ioV)w|!MUcV3g^QKwG2M3=&f9`*N&@ZdA zgW+HQ`qzWY^X6g!EzzS@G)qt@P{jTa!y;W|0B#qt|A5CxnthD@hZM2p6mYD)mGLaH zwo;}j7?4QeCVhNZs0e+b|75&Mt+fBLl=9lD42qXl}J zhL1yDjlQAU@F7c3DTi2o9Vq~auh}IX``-=*7z=YThwk9#I?^`@MvAVY-k+yHL}DG- zWQ^Y8iT{Y{VlK0xDn>-=EZQo*M%K72FyO#ZNi-w|#Ae*EpdjSco1`tiQ!rK6*pU7X zpBMo<^mmrA4}HUWf515ciUF_r=THIY2JthC>e=bTOcZ##DQq&_G%^G$@ z+Yh3lx}w(bC*4fER&6U6Os43k=LF5dm|NK31Z`(Y8{>xC8e&Y|n`OGHvm5agp$oZh znC9LMQyRP>c@3)~bXWD)iMIL*0vM-1lN1)7jbRY3f%Vxt;VjnLP@ckf3RAwJ*g{~t znaXOTtE`&(e~74mqOm@E=!aI&*6c$u6njY_qoHuV9qS9OlWXfy68p`y{4fPrto4Z0 z$?zZa1sUNF$$lH!;&RinNlBd9U=P+q^0zlPL;Oya)fUhAq72Pj*t|SlcpqD|xW?10 z+YkGd(wWzUFBK^ihDy^l2ZmgTNt7qtRCy{(;i5_Re}@qYf@-2DiD;3`qVwc* z1OSs#a6itCz&E-`StaP1Jq1=z^l%8N=lEzD4U=R>3MDHjQg97%W<>_vcD#t__fZ+2 zM+C<_V!b|=3`lX2y0XAPNbh2&OfR5jgyd!^R3fX0!gMUl1yc(`>q?gOQcn-6i0Tt` zMbtMle^OaXMz7c?#?dC!%k-}`vNxHyBbZ7R6MxzU5oO}KGtjp)V0jc0)JYYn2T=Wf z&}0jFSa0CP@+Z)V+>(3u@F4SDSv#9zY<9-Ue~ew_a$ggEAat zLfIrLp- zf0|01ObHFz579+uju;L$pn?riU#OuWKbimFDp^g^sa6Mo2K7Z)vXZ{dk_y3TGL35{ zy&jAJ%bY%*iG?{83j?TYaykX1jwVd!@`FXzlPaK#d-vq;b5`+!l^srlMRZQ3FIdJr z$@&JK;IK>2HW!YgsH-3~;|hh)&A5!`e`tTYR;b-4s?czEV> zWr+0?&|izJO3D#a)VsE%6|t`qt5I8i0@Ur-9unFuh8tDni9q3Okej8AS&ZNgPS}yl zD00S`Slqa~N5z!rl@vGZuB9<9dbRf$JOoglE(cou7}6k;*C=*F8RA@v?&V}BgHcd zu1n{N`8*V7Y$Pzjg`R>k2=RR>nq|uFBJQvJ7V(Bf1skK`Ex5sL^I{suZKmjRe^M+wPpI_8MJ^Iw>IzX@V=FruN{S^Y8jvO!z8_g3 z38_KllQs4~G5@eWkBG^e02XWB+EV7ghZjL4;iPdG_qpv3ly4i|xtdoD^jZ3~nwf6T_M3{{3G zAaT)Pcu}0{hF>#iwpOD&?H{j}=%&J@^aXS-+J7;!E2-DfDcaEj#bGx{&j6Htp4RVS zDlE3Ht4(wy(oj(zfh(uq#!9WM1T2xyfw(_iM_KoFIeS-J^Ck6x#4&90rvy45;!j#xfw+d368V2Ru7oH}`NirVDhC=|Qan(&y z4fTcfCySKA>_4SLe>LSdQzh}njUH`pnzA%~Gkq8esnCCVbbR#m-QQjusd2q;(u-w+ zqB%g9pMh(E3qy+fl9uZh3@++N%>7j^ok-?L8XxC#rEg}ep1qv=`@)fcwpPNZO$xPi zm#icbQxkJrzU63KK?|+?SPFCR9~Y_eZYhm?wH{asC!w_%e|Jo4RqQ16!O^Ly)5?%! zAUu}BQY^GVXw!U~QIu)&s;Vutp)Slk904WpsqIclpZMd!y?X=U6;bPByvtD0@Mo8D zcH?1dv6WAM-jGoE)z@BnO*JQ0497@ zGUbYzoM!HIe-v#2*^>cZRpYXY<%Vl}CRLZU7F(K%s9|^01syz?vYpG+G4)na`!m^Z zBBhXtq4KhtDcBlk=jMhf(pZN~dES-Bj?YumHj0RfT+QJY+ zFQfp1e-_k*fyQj@V<%>iF8kQdv4FcaRBpgw{*wLhW4)QN0EE~^#$)B0CHAXTfv#44 za=D8%xyuo$x%{wJ4x)m2U?i1P$4)%P#|-VEP=C`2{9g*By}YLM*cd!%HXu6oDzs{r z7ng?~D}i`DCFMO&*$fD!GujFE4kVP_+t-e{e~Zl1OWW75qKE=}C3XCyyp*sx$XmfY zpJDW;oHiId4zoS__F&tnb?i8B)+G4A!npei+KH?j0FzDQag0<$@^>Qmmy1Vi;S@!YW%K$715cWifutDVBD>~ycsz{wjT{fx zlHb!87gv^c$K@-}j6f=>6)G>iSqOJossTj1?NngRQL5HTr&vbSMf0V8fBL|3 zILMZ9<@hajyejU}c7$djM(d+&PqfdEZbnCU$M!n+J1h8a5z06M0-@K(yI(@g> zVl^(LU1k+NpWtP8@1FL7f~>Lie;tJJKz|nxujg)DgYWjyTnIS_y3d$~$)PFO%SEEX z6-pV#s4_`}=vXEQ;ksV^pP*rY}84{c#D#r2xj92n1#1+Kf{DFLqf9CsEN*YGz z_wH@=-V9AG5s^*mXf<84ckNA{pCdXNs1~rPl{g2u`+wA?NUpc;=c$sU$MolBMP{e(q zL=%a2@7q#2RN2%-OkI>(e}Rfl%m`QD2s#by;K&vn&r0Wj_7N7NU0~yaBt#eMu5lz5 z8ML<~hv51_7>Nf?*X584q{&yZ4m63SP7=Y)a_%Z83}I78gZt| zsALLGF(yTm9GwKMPU@x#gnCjqUEAifS&}I&s(*c`?;k|IFBjkHdqORv`yfZ1sbO!+ zG=rNYXZ|u7XQ4RxrHH#g{| z2~&-Vtl+wJ`)Lkcf1?6$Q6VFd!NP*rbKa38e+dfvf|9FUSU zybF0MT8#C2sDhc_y9ZUG9OXnIxvS+@5_%KnTQbm}+Jy3N#eLw#lS*w~p|5OdPXrb^ z$wt`YD9oP}Ne2e5AnTes&P#`?{AL&2yXAHkhPsf7jgl;jVLJfhKU~-Rt%M z#x00-lr}D6K-9UuEvvxLr7Kvt>cOZ|5#lvdR?^|GR~Ok)m0w(-N;#_1<_vO51_~tt z3in|r7056V7Kniol|VCAgb?oLOP;O5@@^JcJ~~ZO0abLRhv}#ihm5Yd)5kMi=M6mz zpMEXM!YtuSe^i*V87#!OIVG{6f!5*!U3RU+$Kh0HyiU@nj_fUL*~04Ew3=j$Qtba$ z=K7`6j2i&9xL8jOhis8+kLW>}XeYFV9E@tE0$B@>&Mme*pVU(}z*U03gN978C+Yq^ ztO4Jj6+7zU1E*bz51clhyFDFu@_HDFtx`XEo%TJ3fA0I?G7oAo?+H4$GLW%Ur1yQ7 zB7L@>pnJrCbm*0bx9M5|X!$WiUx_xvk~;>T#LONctx#!iNgL@rt8*0ZRFOdR^zndUlwSkp%I31+nTC3~Fp-t}M+KL1Hn)q5Y-;q>(s(fLC{z1E zS4Pt2e-BqfUesB002h&YgP|TVTHXRNk&mpZKhrwDsorMQjNGr=RoO=HW0AANY&Sv* zX*v=c2k7G)5)*cVg)!%kM4$#74~9ABt;cw{Nvn-%(^N@o--0|k_}2lSS_LFC-ou8U zYy>QTU*pbIsIk>v2JJ-$9G{`4G}<_;o6SQ*e}DaomB&&B#jg3^$673EGbhTegm4sQ z=8|47FJp`bN-gJqsO8+AJ0S*ZX~K(4=;SVr|XH)T+v@du3ouYcQ$rxq$z+@dpig`P?y5huE&`KG8> z$j#Yw>>2ryhfhOJ#csd^WrP;Gm%WDH9x!zb|1{Hqqv6#73j?BNfrdcIP6y^s-IHEd1HGF1!n&b|pzqY$4q%4Kf zHFm`1U*7{m;_kQ(B`R=sul(xK-G}PlWur!rggR7Io`lN)2>tAiJPI(E`QWq@*<2n zN(%e%Qy>WqC(}1T#7T0(PnIe4iu?g!fD<5_mzRFO2AH0m2Wg1vC!As-(qlw7;N)My z^!`^j|3XU$e(jxv;Wf4`{2`1?aZUmu{{G&+OBclP*HkYwTM zB?n5gW2SK3RjHSr1jc#BCbUpp!Xyr>_ujHYbI8NHkDb@3pM&8 zREcmCN%?URq7s=ZBpqE>Eq`Sqi#!+((94`%NWmF8Xkdj}#1oG*Wi_v<-w#zxC*WGh z;hJLXq5;~D+gLLT_kSz2<>yi(-`n?;dwbE?li}FMbAzZ9!8^`43O!BWSl(n8H`(RQ z?EI#JU!OkTd^*4R1PCAgNg?^-=HlW8zLw3+a^?f<81f6X-KVtOWINhXVBfz%uOw6| zH%cAMv$LBjo!^|{KREV-Gh!8xR$-!tSx25l10wz7p;}XE?O%QFItgA)c6T`TVhU=*ytkvTz8(- zlV5O9%n#9!xT(cA`@3nDS!`a`BvleEws&KDLSb_ea;cKsEW|Gp+ zQ}4v|`_$vb`B!E5h{AsG1AeJhfe(9Cq?=Q2I;uJm34gp7@mZN3p?E*AhUjb$;SRn; z8OD>b0SOu@Cj(UcqKd+bw3nh8DQ*uelbky76B{`nU2&sRPI`0GlE0#<>4Cv@Yfl7* z5IL9#S#w~vq9f0Lp*{2gdavH0EYMD2*cNx|L?A;xyR{ZVYf~<5E$-d>mitIG0~4Ae z(n@DXn19(V3!=e)=HtoU0AGmPo-_*J5A%`qZLWeYu=l@y*90< zu|o=JgfG%WYs~7LOzMCI;SZ!61ozrHl~E-nRdm_>P+pRxf@;GDdbjFg;R})#pyB%t z5V`63P(?!OqFpe^$LTnmEmiCXUVAIB{BP)M80m~G@8e!=#xkJ-PY_{rG2XN_-I1Z?<^r| zTaKCrB6<*7wo5m*Wq~xs9zG0TJ2H}dB!5sS`c?!ol(35Z;cA|yK+&4iLb zXQRrWt@08r?8or=X*`+i0UQEWo4Wm!5a7<^jQ#*tVxFaG)d%PuTYR9@(RdZrp7{Rv zDs8CVmr^P=-q2BAwx_r+=oD z*yZkLa(Oj9Ft>8$E*V_jT;2SB^I#s1zk(VM=6ao(ZY|!q?)UDY))VSS;nB|I3&oyP ztGQN*LB)a`=MjdW4y_QkS<6q*jC`H-(ZLt}m;=r3*FY;EGMg!Fk%!@U7z3V?XJm$F zq=jHN#?V}Bj-k0wZ`r8sMpw^y;(yX1Feo7wRLM+1(+r@|a4ETzmVG>!lY%`)T$H() znTx21Yf!;I$2^X=Sh&4JEjoGG*AeYm!p`#u>YoARQ5$FY1dHuVM3)hy9ZunYYr}O_ z=MF_DVvjzNQz!UwB{u6bOPNPUfc#IU(F^$ViAH=LoJ60(j!{mqI_hZQAAcAx+to9A zZd{5Fd}}=B8jkkZnH~fah$WxGS#ly3l8&Ijy?Za{-#R!6lcWw{AaLiv2aFu^gR2mR zj%9++p|Zs~f<6JRU(lZw6yHl$LFXiHv(!9l_bge7K@8;}hByfMB6x}0{uKXti~sxv zyYk!PE3qrTiCuY@wBY<|@_*ZOY`!zJ=`Oe`-vwAQ`V9Ysqf7WV!5KtP*)PCVZ^aJa z125m3OSv&m)vnB35)SsJmSuyr4t!D6m$fNwQ`hf>Uff&11wTL zkqSH-@>GY4N}|@&@H>2DSG0%HcjHA8b@*UnEN$Nh`ZFi`Q_6e%P=CsDh}K*r{7v^f zxt?cd`0FCMW^Kh2|26#&0N^w_rMF@6m%TEGZ+!Dcr@(9kvYz^%kNH)Jh7XYY)E6I@ z#@Chc^}F#Un#B|iOF`n#kV2>y3jkY|2Q*qdcLmR(sqma3<*=XAkQca;1%|vT`zZ_j zt`*SJ#jt3C^~dZp4u3lJBPPvaNoX36~=A5&J$#v0!E!9yYC$wM_lDXLI z5zk#vF8gUTaU}~acoXcWQRsJCMV4dd(FBi99>~`O_ve=WW=1j-sxTqkRal_rKtbuLXGwpXJg}yoZs&bth_HiFj+nyWU;MKQ- z9Z1M5blU29E&Gr)yV$zQ>mE`p_eo#K7Yv);PQGCN>;IH97$7dUc|;oR?lMVp;+!*^ zJ~A}Gy_OEFPxG{DF5x>fvbpQV6dhMyHkm zBg>QqjO=rh0b{YrfH4;aj5#-8WRO(DglyB)Q9CKw$y${I5jvW5&QI9t)Y|%!z6_Tj zlzoR4tCTdkGLyE6s~Uu9;%beh!^G7prJK0Y30>JkkAE;yP~h^T-i4PjoDp4r$ZR#$ z6_>`*3;D%z1;>W89WVquq=~Tbe@7p{fz*=07X=b_RAYbW$MAE63UdNyT?-e6lQJr& z>qrG7$5Z5s zn0RQ~jDO-XxqR(YJq-sCYF;zH?t9yfD|6kNFSo4uaty)j65lrk8ZESDBp1j zz!kfVn2L}qd~7mO+uedq2&w{I7fE-m#Ek3Jr~#-h@;bxOqv=GnTUkU}ni-k20&Mvi z*kZoPRia&O>4tBe#>7@w%=V77EZ4YU78>$)%zsXAKU2}#>wo0UxhRu#Wo!(0#JeZ0!ak^t^+uchNA<|KehN3!s6PhKvTp{SAj55o$mx&^P?VDfm_5dRG zm|ZlR8C>*Z>G%ha#yhRB9K7CwupW%1_bEjQ!@({WpE9!zy`b)9sNJOPZe-Un|9@zf z4?5aWBbNvon=*#pYRV|ww0x#@%)o#lb8j3=DqNIUjgn`sE{N;8%oKzXYUHtufR5hV zvmkU-l0S=<&lBl*hMhIR#z{9RXhG$6rPK-hT0HvC^zL2h2hKdQVZ@#0WZXG|_CawF zuxVh$IC?cb{VHEvs!?FHv(Jtd1b7R+&SQ5{Fc(N;lbwdz2}JS#ZI#!WOk>i zP|a;KP=!L{4&Z#Da2o?CGQC(X==!jmc($sW@W!91^hPjj>T%0Sp&tAK(NPaV=9BI3hpzldHZ|xE_q|P}Tw_HFGdf0%qo!KT znrCLUO&e=YWXJtvG_KW4V1I0snz?JUg<-elw>%F!07ke4DXg>ALfxi2$wHg~gSt1T zCzB&L1QuTs0v(`d^=J7F zOe%IPLKp{Ts7J*^iG}o#!Og48`(Np&^!=>LmyO8tBvwO@rXsWj?mbbE+cw@LGykMr zH)#1Cw_N8Dw(fUV;eS8A*@89M+p^gvOXHgOpS8`xsbeRqkZvED$7xxUNIm^Zk~4#}eG=r&G~ zN%!!#c<|;gxFff2M35)ufb?59)0GO0TNwSM3b|n3-hUx`NTf%(i!bo@O15fXL3$Yf6f8(x4rlk9q%g8(hrC2W z+E%$$Lqvh5Dw5w?R*>(bZ%j7M)ChYRc9QBYDO}-_+BihjBO!C7h`1XgD0T;AEW)Tl zr;ic$UVjc?!{XRfVW=1fC*D}ErEA-#np{`@?tBn5?fy6_porD(FxHvjFi08eVNWtx`WhihwX?;od-cT;fiZZ1JEjVdAE~JITYhNWm@HqEn(+28JY& z0<5v+f3;dPCQefAO{Ol7fC88%IXajAEpK7pN!^)AP zTnnIsAX$LDkCgbv9T(ctqEJu6X#5Emqi+X=^Hy^eM;6_B%%JYj?YmK4zK`0?%Z&Ex zjahEvlPOJ)tOeLcWQJ=-4BRd1v-i@j$fW3=M)MNo>1v`%CaRXTVxDBODxWc*&POHF z3x7b@?UH^JzMc_DEXu-g|7?}(@)9kI$x>*R#0mse#3^2*jEsgy2-W3ya~z=hf{G~4 z9%QWjWYNSQ_6FanXyRsxzIfzOvBkxl8A0xVS~(h6~?F}cJDU2_?C=6`h0U*KUOz+metOt?Bam*Wk>wwA^FtZ85g zWLq8@xUqfaH>m_C&&if+TB=yJX4JG;{&>x0qGZ}Tm3L-F2hi*Ih~ zh+NFe#dh&1XS zZ`7=T6L)H=B=+%&I+eo>EnSD*OiRPCZ^c;Hpgb$21nNOtfFGxy2!&a%wtqXYCcq4ZQ^UfI*Ku@pm!wxm+lAzvE~eJRWbQn=FlmX(UpqKWfp!5>4<(Eu^@ zCVZ2$1QroS>oGtmN)wl~NPiU4=zvk4q+?e`oV9e5`2C~$VhsO^SuxdJ6nQQD|5<94 z1srv4hi4rxETokrL=zQuOJ~E=V;IsiAjbrev7Xt zYb$X;WmtjrXl7`QMKcTDFu_v6E%*14bdd_Nv#1DWQoou!JCp9VLw{#gHQu&UPz!;8wprI;u%YSyTzBs1Yh`Sq-eysNfBSiRuZQ+SSrEhCXdX=Pp)Qm#4kbTD@ zI#$qLz6c?K_dfcgT$zN;*c8j^JcSmm$071+NYcU&0^_ug0p=`;v=yu-8~e}F0=Y4i zn-_C01+tiLiUe2*Lw578qu^TbXE4S$B~VXUG<>*J@FFWx!vR z22&nT1KU8~PJg#=!d0X<6z#Tz3EJ`AiI72o0u4ik(MB_;t_IagOPKK zU9KA%3`#-K3bj}U0LzLi(iZLuOwHNapE0jQn-8YYtA997YnzIG($WKtxG_Z8CZ-c* zFhQYn3`Qc?mDQwjx8YSRV?oIB&ey1TK*}Atq4|M6j)RK)Uv)-5G^p;7g<-uD9bAP` zZ-^1#7$K}IkkJ=)zVWqNf6?xt#rKxU%1A*`y5R{VlCdB0mnI2JrN}%fBZu~O>J$T6 zo6h)Rhkrdx6E&JO+rXiZLQLYOH`@)m@h)}jM7=elANCa*CI;8*$ZZC^hV^@VP?OT) zlgIq;+j4OQ#BXq&*D>17177LLx%tsacAkF9%c_niyk!4%Ru*z-Kk$4E(8NSNnd1c< z9c9cd6}s++tUQ`Xw*daoUq{B*R40#rtjddL)PFIVwCBu~OrMuW#{)(Hb-0mA-2KKJ zBpaSx*9TnCS}xr~i@&Nf54JL&HNNoWwghVApYb5VzrUgvrbhT@noLJx1z%QW@f^?| zpu6JztST3aS7`wiDtZGEN`ya`vyU)E;q1k_{uf4WJ#nV03mM>trM;|KkJx(F)>bf; zS%1tSjC7YYk`QO16NI-qVWM`P*3aO~XLHt%m;~YmyTmWW!YTu}Yk|gYKu9yqwLPKj zK;8`JM^%<#kcJd)b0TV^#aPW>wnWWKUmjdrrsysbp}sEuRx4zzk9&!ge~u@~05I-A zvS;qi5ZnRgvW{LBh-_!3;)Y#WjInE;%6}l%HAR${3%aFacDe>^_Z&wJ555|>OY&Fp z24BMOJk)5{HDvW&tB72cRTrbkIYvXIYUCUW&vL_Z>pCD>lM$D?VhF7=szy9onm9OJ5Q)Np^gSOh-SMSsuQ zA&+*p5On$eeo1N{h0(?WgPx&K@Oh4C^8{ZCUIXSusAqvj3)MiSI7sKYFEHGwK4wh@ zP}>l}{p7R^;xvy@0;cNoacmj`rpk_7%8j>M zdS?r_UwvmYciRAGQ@7uP?q+t{2KS+k+mU)LlvkA{_Z&y==T(P$g>Q-4OIkk~LO zfXrh9feNe_#4HTOSuHPt`2>n}Z(;h;-W#Zn*a9V@CzIeR?Ves1r=<$Ax@YCWY;hO? z@Te$!Z_Ky8 zRV}5Ld2KZ@Br!i`jBzYLJuHAhlPw*(vSowL`@L}8@3KFB(f0~|(aWCrjn6ZF6>zm6 zzkG_*1O(B$DCaBG>wlXkeh$oHZ_c?z-%IN{YY=%Pe!qWkf}s}}eN-Tgdtj74@Si+x zGGKVqCIb!@kHM4pysVpR;Y>X~Mc4f6zi>j1MYO2AIOYjY?q7=&5#u4TOA7na;>=y= zJfF|AVhxj{&L7Y7Pc$jB6&NN@&@+8}TR;(k-xm|=iL57&4}U~&j}M?x_*a|g7FOL5 zd6>)Vl6N4tj#MYWKJ)&fXFMGaul^^ys)ZcH$b19Kut=|3d4>e#-Kv1gOvzD}(kpL# zeO^}i??~`2o?@t)m_3^CIG9X(h6nJevQu2Eqw;CPDeHJ|u#QBio9^lq5~rg!3`C8S ziCK6XOoB@S{(m~#T;vq4@S5GBR!&iBh8ZmDhq7E`X~74Fw0yb%IC`^c>U_>AkItg( z`hQbAOP6r4%+fz{SZM1U8C+IrR@SIvRQg|V$^%C07qEv)P}XDCPJZkkV>B#ndzp#3 z4~uzHXBFD^#1o(E8*%t}DP zYn>>e75J*p&s7JXM&ZP;&0}p}tyR==IQwA_07Vh$++klRFE!~cOx;v637|D^-f+p; zyQe=U?6E0r8e*wit=9SP_^eL@;#{7d#O=mWy~)l>oTF!x!oUbwM~{rF)b->y6S8%i zq_)5~j7GK!5Bs)wN0{Ls<2lae&(6_HM|-d=moLmbuaN|tkF|LOVH|W!%jtuW3uHxZ zor*z8K<8Pk=W(!s)7oWa7_Hkz6!-3Jmji_XTMBJvbZvd1sZm?EmuQ6nF@N8?$9Xgh zpD_JLcb%{c_iu9l%i5wUy7sG>XhljXE!>3Sf)>hh%4=%D3i69VOjzAwokbP<*1qSq zRl-67C2M`j=j`q{3$jmH%CwCvP6mV3u_-C-RQYdxY}mNBvC ztK`hb?rfSYXtiac944xeOM4-9lM;{gl&;{GKSvCO^G;mtojfLIi}R ze?)rL)-~blx1H8SADsrBC2uLW_2$(jjvxI@%{I&P44Xb2Mylz%kA{p5d|&a+-# ze6ctGTqySEw|eu>^f&*(u5bRibmPR|_t#q#9B8)Xs`(FAaTsh?ak$lVmnqN&J%Ef= z@2o06^RT>s*5m@-n<5qO;`V z+Qyu$nx@_|fum#G{qw} zgzJ{1T~({kQ^@FLi|i8Xp8=h>diUchx=&xfeD(C`<(t>X&wlyg<+I}-Ui`l=U%ZR` z+3Ey9?>Iz=~U)u@|HEd`qP<*SS_(P3eg*of%)%{b@(k%eNYl8$?UX#^7xEs z#k9iv11t215qa_$=jlPttM9$xVDZp{|LZ;c9Vtf4fj?(B6l&stnme$^(jiJPMulu| z1Or{wy!QYfpr8TKwk6&jyrAc*Zp@CzL}FE3_`)jZqf zm_L!j1~@M~q*fB2^K+O7iHLx#eWD3mNVK?<#A8R<$$wVCh(q2%O9WI4BI>^zY*J8^ zKO=Deh_D?}`+R$;X>quA5mE>VfnecHx=UsQ*<==Y&J)}cB_>VLD89tMrL4m(hfp#v z{p8Y>p?_*e#v@+_K0>_@5Cjx&PK(5UGO0>BFN+0Q40o<0QOcOeW}VGn0(8)ESUr>FTPEQx;a%7vz-6%w64A`)ty!MiJhyD(3e?1mliwl;XD znm7hs=cKJu-t%_^rnEtLachFN;KmfYD7gp#Fcz>5UN??bXtw6C5+0%_ys9G1qbIV&mbSIVpjb6P!FgVF^DA&<>JS z-G5BJp%$;hE8pHgPeX-vmzuX8OUK|NM-&-CZ$g^+X3cvoIWS9we}=@s$@zcPR}{lm zW?w71E4%NQC}T7GIh&_-A@9%vk8H*O$jM6oEvr#e6xs4(&fc5T1-BK*LT=ozvCT~B zvc35Z2L--AYLaZ6^$7vp+%Qk60wx2Wl0^LwGw{;pG6v+AFEA3cFQbu zilDphc*d4Y66Hs3u4zjzF+I**x5WUP^$MugjuT;B#OWz8+=?Xx1`|c#r+E`+{t&agCfAG6IGM=~KH+N(+H*=Q`X^_d}KU!XT1ARZ* zx)YXK#72#Y4#2f5Zc#M}O$`LjWwkdU4$38XC~b&(hRe|^dT zG8&o6i@pW04wWFw8-BOETx-4Af-1u0_3GptIFOKQ7%_CBu%dQG{&ISHI?^PMmIPJr zX~LwM(}>Ic_-AMc1^4m`3|5gAMpg5^;SHFHp>YefRzzMutUz=EtW)d286`tw?D9g2 z9O`7PlTHoobVWIbpk%4q5E%O9f8Dc>@HTfBwan4Kqv7}@I|Vdvw$Br9cXMgC(k_?S z4mX!R^d1}1UB#W))E_&l_O0VU1@2qNUPQ%~YEZ!QW*M$Y3p&ih=~yLgSzOma>mqO< ze_A0I@^2x^>3T;RwMK;7o2Av9iKC8%KvLTWR;FHE;H|j*A&0QynpHYUf9Ge}HObl7 zvyGVkl-$-zGpcNBBO`|`lE?C2; zP**rTV;TjXK^O~};j@jko1Yi&GO{K;g3f2PyN+7UAkuo}GlFxIjAxVs>_ z3-Ce|RbO<$G8JbX(|~ z8^RamSP*{K>_^;00IzUQ9Ov`cY+a_WahT?*icJr)RxUlrcUkigq4*A`DQU}V9a?m; zZI|*}msk_XvaM=!7wM&|3@SBgrRpYII*aLrNJGipp(bC}YB)V-1XL&TVDRuydKr1x zIf@4{IK}K8b9OshI0K{JY{_Be>a{KPTgs;tx#5j#Q9X!B4NOv4aJc|06v z2fWqG#9dXRn9doUOX1(H4~&gAG;A@o|a zag}LJ@LKBS@M1uOaa?{C8+m9pHFA|wxsJA^5~y>gj)GBt@Td+)U!V!cXqakhPaNB= zEn4MKi#0RG_GKD$tsCj-Zk;ifiU!tt-LC2`$H2|qf40D*SJLAOaTp%s&qf=;A6g4__z)KA!R_nZdI7#Y zj0Ug-QU6i6{_Ab}V?*4$UhX>U|K0*lyMxhg;IkcU{t&qA0w%kF$8Er3S8%v17~E$2 zcir}u0d$KI@Ks*x681gDKz&78vgfEYW)}%$C1M$w)R8@0sxFP&LFTufH@6A|Ek?8J ze~r_S|Jd4r*7%(Q78IQ6v)U?!L7Ag|<#p)GX_|S=DC(tN3-!|Yt$HhkJH1)U5XZNL zLUQ}1&X~12`u8e&~-xv?AF;ev_}pev&i;TcJ7ONZ(pmEl;srql+H?RD&B z5J6vCZ6%q=XsJ^X3>M{QAA_ZBEOdbmTIy|uQgpDg&AhFv2~h_i)KU_|7M)npf2GHU zp?b3I{#oh;KCtd6L}P_@5gMs%FMDKrM5afiS-#;Rv;BJc+p2Ez(>$AZKWys4IBu6T zXXbK}7+TdhKBg&2ufj0Z-(9J7JF#8rmKIu0cG}=0*~*!$swY{;69Agt_X8wuw=mPL zMs1GNYWIP&T_^YKYTeCdd!iI^f4$#s?qY{Ibh6jZj%2{Yx!H=nQGQEAyl5HMc7#i=#RDJkx_v#1Up=_a2Be-o7t;urz z#_rYVXY-u2$gcGl^TU?Q986mG;g(j?TeXnsNnI`g*O9XxX^J-xrg_31f6tb$_wiBm ziPflDzuPXK68xIO|k*#SZf z_P^B@)OGCf)YHb_W&|cofA)sxFw1EvyHO{pt-fQ;tSwMpWS4d!F4T&wMRCZwx;0g3 z2K*+4U$1@7tz|nWc z?rZIt>4`C08|yq8TnMbA6>H&PJyW8jHV&$bbXh;yTDT?1QNz&Df1)GX7)US2;3)hi zV2;zYrACAV+eFR;jg>Sqb^#&k%M!FJYKbeH0yujBKl$9dV+%T96W!=O=n-i>y!#Yw&2??< zy!)&LzGYIS-n^|Gf6yHZh1Ok$3TxR3WoumNZ3`lM(~x-=*~Byt0a#7^{y-u4?-Yio z-z_-z#D4?F(_>Yl-c->0_TfA`3q7{Cy2#UfmE5JcbA8QA&9N365tpReTE|3XxpCSq zHEGj!0_9u7i4M^YK*WC8G2OZ69k);yiU-5*mzPlw|J}Nme_i!<1ZHPPMU1VJtuloRWK>TeslC4oEvNf7+ z@7jh^^58K~BW(E|;yi5!GF$x3v{ty~6Grc-&0tES%4-L~yq39NOx1mpI%8I)Zv zklkA9*tZ9Be|#v3@V{YeyNpaV|NlF0Ps8EP-Ke?tw$Fd(7CL&RfESyErPW1b?vnMS4kJ=_P)l$|uvBf6tbNyApG1R8$Ji#Gsg46H8Rg zeZ!!NeBvL&thoE&qPK#cFcwVK{10psb6H#gn2~FkBmCt{Eql?0cvWlZ{pY7J^-~%F z?uEUYCWE+>;Q%kYu_fR6%4a2*(8cCzHuh1>pRW>r-)5P38mBw5V$Rz*l4&oBxpNxo zg!8@rf6BSp)|2M8Ef7Gh8(5GJ9SUQLzkKdar=TatHr#E3QF8{oxz6*j0fN!*F};(( zam5l}oyBIX__mDd|2j1jNhS@_EA6bkTXZ20* z$asjh`W9YC%e>g3)NZfRZlA@iy2{&&0JCm4f4#<*-^SJe4IN%_nb$U(2+rYlK51*O z=;998sj#{xb}D{h4EJeOrB}w}x?JB**KW%S#5NA=3U<>mBa6sCrUK%%oe|lXY_7b> zH&dw~>x(aSpjN%rXZJh3I6=}Hdtke=A?X+Su*Z1I^y9p|An&pBY*x_$f+)DAG)(gAR9VXGX@jNuV;e-ky&J1;0Z*c=#MKo`+&2XG1I2K+Ag`$k2n7B#{9%Q8j zLUPD`|7-5bN9_5%d%PDUZitz(6;JI}aR2fRTtn&y5|gXK9`JG#x*dDk`&&?=dAn{tA%&#}SpH45QRP ztrCRSw0xis(e5zP+H?TI=fqeYU@-d3%j7?h$>&?$z1YY4W*lEe?p@-gcrGm6WzutH zq?e+?XGgvPJXRoA0Vw);c+S)KfB9mI)?NZpmHTC~wm>t+lZJpaP|FmMW~DZGei;fS zCUXt;vk{8~wc~kXO&su52{p|q>-^?ytaY->alCJ?vf8gv>j>2>)|2}jiDd;?>o6W{ zpZL+H%@hG{H}B_AMU3S*Qy2$!qWq}Q)aja*BAxIZ#;z6ZZW4T(1QHA{dkn#b0)V1gJIV@{jwD@*hsAZ<3qoPeZz1Cn zitGi6zJpe3?hB4}rupX6dlOrk)>p+Wa1#u2J9b&-7L#n5X7iXkNgF&nM<}T=!9Lgo z86bUuJ)p9nd?!<({ixgWf9Ac+Fyc+0G;q76iSDaTw15%Yi0Thgy0U=FJ7b!tS?#h{ z)?L0gA*|k_0dm3Rpl*^)*J1y+5>T4&5uh8wur^P@BlPJb2(G2>ui@~HI7k*v8|Zz; zcCrZ*qk*!?*l|K1C(@>xvtRVhWo?qpGH|xeP$|sCD-D8tw165TxV2 zfG$;p6>*?oX~#CAK?8a=AJMFYN&|cyz)Sj_*{*{j250MN#Nx|#Z#5cCXwn`G?}nct z_Su0qbrH)}=Lpa(&@oN+j%2@`z{feSl`|IOdRG2$&=37Pgn}gMb9Fq-gqkNJ}9Iu%(e-8AGV@o%eSlf_43P&b7 zQ|otn<&iQ+Hk!MbnsjaZpW}N*cQ3>9AyrB8x?GQJaya5}Gh(`}=4on3s>?2H#i~dL zGn|@|shUq3WbdNXot0j~O|5RIvGo5TECLW-(l8FxN2H1fAq&Ect9dT-aY2k*jI@`? zcG?bb!fhUKe>hkO4>;7KA8|)Bs*^w85l%PWBEsMpvEsiCZ!yyYir&JN1cv>GYqknb zABMB?;sTmwaZ}u$)K1Fz)zDPl9$K0QB(7Zd(W-~s_U+P@@mT6`^GUze)A1}_0x`76 zf6ugjCQbTL%yeo@`&;yArsP|98kJdFc+35_B7gnme+-k&$27SvzNak=Jw@#?u%z=Q zrga1*u?q_Dz%%(yuq@5MP`Xsrm&B}Uwd;7Q+x232`}5OZU%vj^@%y8vM=##T6CXQ4 z#yawsDN;NBG_o!agQ(`~@K~D!3y~s%IIHXa7zjiiZp`V)roOT^@UW;&s=g4+l&c`hik+dhoq6 zx!}6#{fFOY7yk+57>~Cj2qh6E<~^7xNozg&FEXrd;B@Ctq!Fj`!~IE-1>7Ll6>)ZP?^~ zx3z-8W%Zv%4(f_oB#{xiRE)zB?drVFe>6JI>z~VXZppdW^U}PWQM}?l6K#u#R*iJg znqo|#x~W#PrmSEQe>!^gGcQFBM6OOUZ2TGB1Ha^sE|^SOj3Mxeo$Nh(`tEtp--qof ze_6s>JxeicRX9rdYZ&ud`V$wR5&r&W33ZR+Ifn)lFU5L+K!+O!?;fD^F$S& zLA@h@E_{g$BfAKX8OP&f{X%b;e@tW;nLAjUI~Xx|Zxje;3f$9mxRD?cwdTELZ7>q6jm}2$1#d+I_Fy0_+Sj9-AYimK|5<^?Ke_I;4_Lb(m z|0r*SQzWz@Su$}-$aS!Z%x5D3{JzXAO?4tF=}vrNHpp&4K!RqQJ6H&um!JQJb&hD> z`j|K#twT4XWRZI&eV{e71FzH;@lnUS$24eLCXisVYen0aR%qy%W`&!lE$k5Qx!uM^ZNwP5RDD#|7V9-nk)36WQ zhv86zgX4pR_Z_t;Sx{hb_+*_wF%A_S*K`f801#AW?mQs*L$x z3RT&+m|(3Pm8EMM;O=PaBDm<6^EkunDYEc^1rPaYu-Cxovzr^A8B#H|3jKm+k-MM( z%oOQPdEb|(r&ieRfA48s!zoIOCi1FP5kEeu zFig@s6Fu<4{*z_Cd?2f$o=+-jVjb+m>-CV&>8)~%uQWGqo}aQR^HTV)#!joOE?3no ztG%Z5Fw!llc4qVbm7jXG(Y1GI1XA8geT88p9f(~&i>J`;c=k8r>f zV`lxU^kTtJwwD%jVf_eAWxTwO*+ogYS^Y0arnRq-t)yCeLEK`I!P+H?kt(WQ08>D$ zzYu!Y|K)W)*LsPkidqlCRMGR~O$uf4&q$?;qL3qgV(xnMU+}MN7w)0IW$0`aoHM4r7~o@d4a(xqS?kT%{oK(%~BErz33n=j{!>`sm5Sh1_sSNM*_65_i#ABXot-wJntPn!kMFEz(e0|>Ubg-E0S9RzgES^qWoNZGnLWd`^_ZCo%%m~xZC<8rljlT zi;v*p@bDJrfCYT7zx+N74!_-bA^wCz@Zgc7dxb2sVk@rHv|j%J(b1q774AcwUfv|U z)efX+k|F3=KwY)gIl}x@mrZl@hu z!LrPF+inHhN8fOqg8xG!TI!efE-mr$?vd45!_aTQDDqA1ahkm*g6Z1RN%)w5aVA@} z&t62{V&DpGtlHs)tIs$`e`In>H*ydPNaaxIDs_6Q6*GGl*&AlWR0iSlwMWedu(fJo z*JR6p=7qryONrL&?iP?L43Jkh7mWuuZV`~?5?1ABqVGwgBlrdiAS=Xos3;pxURd8) zi??B{7mQB5_AFUK?BSo*#7EbqDu2L~iUL@UCqIWOldRj*yMf4`9jd`W6zf1U;W zO$wI)<|89`y%v+z^3`Kl>$;FRBYgrb4b*RR>ke2UIWDaiH93ad)~M67>CH)R^ENsk zLc@c-HeH~0N}evfjf$r%O)z?B$>NN?+zz{;JhTohSH_2JN2VBjqHu@rXt~Wq2e6{W zrd-mCm)^9NMGEO!f1c<@_~13?pm}lDf;5PSHGJ%P_}$mKcVaEe>p!YR>%dOKP(PV2 zKjp;C2$fn1pyST6cvUR|QVz&x2b5AD;D#RSdwzU!)?XH9hC6nq;SfXD>{q9&cJmQY z44Kcphc{)9BwS*R^!ek0v}Wll_~?;Z>?eJ;7#kf2t2iPuf4<1wws>@_H7EF_;pzKY zF4GxGzhO^D{C7N*^UmuY+zMh=B7dMwH(g>gZha$`=W?UmxeoS5R%a(EceSLw4lDaM zKBQ2oMLiPQSeo19Z^fr(+o2sWZ8_Qww;$H+)!>tEjTU2;0+wklkJl&4dKXn@ZPfik z`TR_?8hGC#Dx?YLrq|lR-6hgfIzyNcT4Y;;s{G~0AAej6U4`0#tTrfJYkM)0p$Kr7 zV5|WZf2$q*y>1s2!0b>u5J1(grF@0D>Pu(L-3N1GXzv`eHu)XTX=_2k^&~Go<#mqkUa#p#zQ9#vSEHJ=!=gi15&VJ9mv9y% z4L)0LkqK`x?RfUnp-IQj=vK{ntqPsytroePf2?j#D%0lH^4H8=M0B&TBCLktvsQ3d z!o?SvoT!kce0KPlDx(w{ODCqc)MAs`4wWq(7CMDo(adFVqdfX5c=GUf;$O`3c!~Uw zQbIgWi}@luQmhiH>T+;tO#$Da@JZiYeGBMyWO|ymN2|TOnm$Hg)e4Dl`CZWVifgnH8^qfP9IXg?9ne z+gpb@d8nQAWB&}xdd;PEdI+{0-B!P2??3hP*J-BQ2X zAZlDH-i)h|irfvuU#MKo6m7=YegcS*xD-#YtgyE`fXvt@Mwsa;@20Q;i%tEt*=awF zDMt<=%H$+<>ce5$w+Fpznhs_)e|6)#i~{*`jIjyhMKiWjfQ8uL-$PgH-{{|?p_ta) zh^T9j;smKtk$8U0C?fpn$LzKPrXROY=xnf^Hn&`B1e)b-z%M^WV2=GSX;G zRX$9D;$zPmf20R`_+NEdEPu{VDj-9If5YTjrx+G2lUt2$i|Akm9^iFJB>xJII0^!d zJDxQ_sMy_v6@P#?_)E1A#;z)b%v)Op)UsB>Pi|hngC4H9doxu-IBrF2P`)JOR8m`k zXX#>bVtDGVq8tv^I1qNFf1lH;2z*|h3`@P!G)L#AepCTi(IRL*T7PaYQJ~5RPjFo& zapl^LaqC*?f|o7r3v|-S=SauP&V!lIbk+0?7n=Pl``;^BPc0ko-myv=y%WiI5X?X< z16|=pU$s5j^ZiNoxU1-GJG3Ted;qrTGJlmW<7;f0hN^E8lvjuy zq9^(VEv#b?K^*+)PqN29{V7<+E0`=^Xwo7Oh@YcbpkB8Se*=zBRxqChk!A=JN)-xR z5Ye;RA(%-i9FtF-PiGVHL^zwl#&F0kp3gblN+<2E$EkihpWIu+jzV){VZ^{9e^WhJ zi^&n#Yux5#jFv78Sgd9fShs$jF_y)f8lC`zYy;vk2R&Dv0%5K0jw!+-E{g2*^Ji59 z^|0fz&&kw&f6nI#x;p{){+^yMI;qOL!EGlgZVz-XsLn`cs-R+{Ke6kaauH?y)n&R6 zG{jZx;gChiQB}iT+2p6rsh=UM?2$P{eyccD+PqEl9wb6fdP>DIjlN zFUkpdgKBcX5Wq7L%r{rjYJi58L>GQ}a zlRy4@e*xV8P|j##@usykD_^J3mH@}&1HJd)w+@8Oqik>i)i*->9p3Q&`W*v7_0fU> zUA=)1a3I-x%%CEY3J)llsDv=BgnaXc33a2R`XWgQ{kBr-wQ;(auHF3VuG3JdCxs~B z82SY<98#vn&{84Te#kH;E}+pdt+d|VZu2p@f5SHl4CD|SDVWp)>j@auq<4hnL zcuz0hREDBkV^yp-38`s*slS_#F2SEzP=-fBW&!^~1d(DyXp)|R=UXW+NCB{6qe#-Wjaa??ir@}E@{gz+ztK`EfonItI ze+^wGYH1_eb09ewzJNj#zmY#~%-OiA7dAGtozBm%{e`Wvihp3D^|F@`!`Nw>wsOlk zn%f_YnjN!iGyJMqY2-^bvD--w;f!7`Qjo5qusb?E(>fVv^ZAuL<)M|_!gN+~@?2<* zNutH+?qo9Q4c9n0V8GrtekG76$b)ace^ub+D~$=@X>umDfh@PA0->w!;Y#G-h@ktC z@G;J2Nq#QONe} z=9R|G{HzUKAB&E*T2JiLNr?A>SzMGN0*&rrYggY*x+TSSthIm8OO)}7G`mb@AK&v0 zlVtO-K3_K+6qj2T4O4bRXK$#Pdvo{W$B!RDYR~^@F|h4DoXGkE>sLY-MUBbh-f40ZfOICDZoWWgSG8mUHVi87UT<-36t6g>C)A9^O zuB1$_l5RvltzJ|}89-Zg9o##lfJw#H<834J?-5qt04vH8scA8aCWaI&8qb|X)C^Fsc-I2JBR`!wY)u9p)&R6jbcZS+8^~=pewh1aEe~J@)cm^7{ z2mX*?=2vA(6{3D0BgMg1T;{m5eg+O)puUqVOwZ8riC`P8$W%L_g%f%iqhP*GXR92u zL{kFfo46o{304U8L0}!bVK{{;_m$bQ_jer|(|9fw$nyxeDHf2i%wk`;y{o#eIe3L259v(uzod3f_D22>6Zz`r`->o-5WIeCNk zGm0(uINYsykK7zFR&0;n>@v@bYN8DMg8a2sAQIn|RSn?WF4B{WyZ5m=j$4KH{PATk z+>QG)5gXKw?YSFL(9bZ6H%0Lz#`ybbkj`V&j2AU|cPic-f2JwF5nPOI(}it6T)&HZ zZJPaj|4-%}f^D~uXX80(sHFB$C8hj7dbi30e;jtBX|pb?F2rKbw0do!Atay}^@UXb@z3go5X%Ch>|smgBeqa| z;^}Dhs7NGKvVmka6k4i>>P87;EyB!Z^#MJdf-ln4DVOTfJV)_mF+a@VenP3i8$IHzCPpxN$s9eqlZ8}BD`NSr}aGa0zMhN82($CSrnM? zM1cVT%C$yccD~{)D$w+$c=RY055zjBv(d0w7awU*uJdUuk-(A`ldH_CP~yET_;x&a}7WI2>XoLfIni-!=aYMs0MH175AD(Enc8%ygI`R9c5DVKI(w1O5~}fq zn(M3^E%?ttcbuCDh&%h;S{#@W3`1{p!mN)%BI0yMu%RDc9v@F%zj^y^&9)qu6ZPS@ zV}8B({*GcX3Kz(V&nNfm=nDUJ2mcy-GH_q^uQS3tTr^!|t5eLV24n$;(+avrEn^s? zrEg(b{Fghs0a$+}J%M0VyW~L6MZ+dC*We;4|Dq@vD7*u`b;sDZjuCAxKvFq-jdvlC zLNJ>=!+O^SRz-OeO{4V>Po>(l*mQ%oYKakJ;)UnJ#iDDo^L*uQWq8JeL?~`z;!@SS zDtaKOt$LjKb%YwrF{X_9n3kRoSNT7j(lxAlPsAl>=v;q4!#}*)$A5$htc*Vtb{+zB z8kPDq{3`lKCDDi2bZxC>|GCC%>S7=PP9T2>G zu$(8dYW*F2NhZTN7=)hmfWw5sDV^z0x7Qec_Jf5~#m59!` z7#f)L7V9@kz30S~miQ!4OAm2xfiU@|X{kS4! zcZ`2QF*lR`!rEGvyN^|d5ksM&Kaj(#I6dIQ)X*nX6Lyf0EoVTEkcQN4-Rg_&NY_P0 z4c-2i!H!9en%*oz6lX^JH;&hDet7xUpH8N~9=-W(`sU}8qmzG|9=#rgB**kc#?mQ~ zZuIh}-(LRP@$~q|cfUT9@UpcOkFLG_u* z#8FhKp!L(tbAKb*ixtvg)AiTrdfITW9?~;vg+wYnIVMO)P7Cr^MYmCtsrzl6-0prd z+Nh2UD&FAA`byVSt!a-n+fiZt!fJ5rDj59DxT3w$L`U^5uI~CxYRVm(`>X$0z!iV@ z$zTvYga3aA{~zuR24{{WZHebsaXGsr=ethWxdJJMHPitmc3a+dLv4kC@6bPqw1S-) zpt^7=H;tm#(L5>Pe&CrYf?K0IV=MQKV`WfF6NjYq^;NU_th!T|xk$9NQ6ee0x#)BxER8&8y z2K4bHje6NP7x192NzV5bXrOIZ0Rp6HOw5vH+|a4nZpzX3UaC9mrL zfZi>gYm<)f$sTw9!maT1z`k9_}TThC5am6@gRNR~@F7I}C(B_xAzyTV6 z$ZEcnU86q?_MSg~J;aYplFs)hFTeZY>9|*0zMx=Wm9O7Fd9(k+EBH$4o65&?`rp_N zb%xrW@173^#z@|%V%*YAxH1K(CwG#zS9D%W6Toefs2E{ow;#8TiZ7 zz32PqPxY6JRgz@k7CeE+%rbeAm9XoS9>JjRu6dHMF*3B}D)HUJ5*#Y6KxC*x z@7o3TGp#zGT7fIqMrVPo_1!&x)f(S3OGUni;Seu}UT~>;S7WA5by4%kz$z3()q=wA zJ@~ajKQ5f|d4Hyiw(z0A2ou;RKbp&Yfr*x7-bRYtDqavo8OY|d4t@xF!85=>*S2jk zG|>Y5xfu^nkMa9z>Rn~I?SW`m9to2p{!g>=cZV!Gf8u=RhOW6-l8I!0!2Fb6As$;_ z+Uj|${o4uDi7J9or_L0pfC_?)prZXMU@QjO@1;x?HWr|)T+nKRj94RwlmGDAt5;af>niL$qd_u#into+sNmshwjU$gk)2X;xtiV zu<-YpfXuN_H8U)Cq_;VL;b8&@)1K&J-dKo_*+JDfIq6@o7Ln^-(8A~yjgJwwh%C^F zkiuQ^#^#G2nRdyv_R2;uyw;pKYsM)lS*dw(IT;y4{fu;~^#h zEU_plGJ{YR$Z{uUgVUg^qM!MkDdo*oI>4if$Ly!8J0hd*givIE7<428MH3TUi9*rD z)?YQ)PxpU8{`DHRe10L_?vH?5Oz!cBHekPB!Oj?kbE+9eW&D9IUZb!#M0K>m9)P{X zi*}9yQ>rVY5Ydk)n4;x*$_@bwp)f>#6E8>MG|w2;SBrG^F|3V#L%Az{&R?Pb=HgxU z4o*@KlckM2 z%MgM8389Y~##I49s@07@GwL*T*YHioE^5F~4Jh8yn(j>G+%%%a>cGSx1%VP4 ze2csQmh+x6_fQ7m)s?mW($C7QH*t$Tf4*NwZZRJd*d+#krLi}NHHgfKZnK@V+ed*j z$|r+y{vxqL9(Bh#TJo`yJ2}nIPd%t}9(jJ=KHDJx{`a0I_s~asAcPj}mz=t&Y;?dy_9Y zftd|L{vRRLK-4a_sYHvM+qeRduVg)aC3C+eKw8Qth}H`FQqz~k|9lnS%N_tWX;}rnx(~MND`LS z#}E8}0ZtaUd%%4jqmX)@erI%as#a#CO$5~!>Oa=z` z9hsX)rZ)QXpT{lJ@JPLp?=-P>y%H2yQUMEpLDH9S0Rt6$vCAN8wuunN=WwZP22iEK zc{q%Hjr)81q;PP|HS5@}?gu(OPYo5PXbxo+MHnJX3tWF4HXjy{RES*q) zALTOCVWq1Y;{*}^l>oEtT|}WXFuxB``0-9??6pvZZd3@+RuTs?o~+ecZx3JN{QMmF z$d5$OFY5Z{&%Vyxz19ffZZiM}lMN66!c2raXtQW+;ud}WTvdy7jd+=n+dz6wnPq)- zZZ>~a_ni%LJ;r+#*K@n4BK-%D8c)@K#f%5fnp|0n)Cte=923WnZ(=pgiQ1{H`w)Eq z?14jw6r>(6)8+j?daSY88w`ADgM2)LV+YtCWPejr zZ%!s$qSmV1SnEwT$2!?W1#(({G};xi=+nJ?8!%ECyw%H5oKL%$AhqS$trq6eRZraH9eufm+UNm1w62KrU;4@ zNAkULe}DJs-Z%3|vZv8Ks=r~U{S<#l7R6|xd^y+A<;z>(ZucBOa1{PHy1GJR9*n%Z zMFs$S8<#I2d11KWP4~slTUwu(^CoO)Ce}*-9 z^e8RxYJ(W+9tz{~jokWwOE@(K?X*m=k$E4(e;3JXayYMjG`;% zpd+j8W3c7qb_v%lSo8as(1$NTfYghV{Qu2SCJpK8MvCi`{Cxs{91_a7!Y^?ao<$#% zWOvn-$L#>GUum8vPZZ(DOXC)G z4zsFN>6|%hjL2tyaOD;JQb$c@A2peI)MUm{lTO^BP2Yby3E?C_4{-JjM?lW-Az}us zYsC@ZJHx8SZxkCozwy~&$vg}}o-6PB)ubeWXvG@}x6!GzukH=c;Gk$W^aOEaw)w0p z@IXC1i!R$sE|PU$`XvdD0*KNC1pS2=QJG%Q|!9Aa#)W`6~YcVb33BawfK zm;C7^5E&imHQyKc%{oG=y7UDgob85zFdqm?D;8mT*r{#7{hJK}1S4!1#M1;I3sDF- z1-1{Hc4vUm8md;@t4U%LQE48W^LgHIoSI9~6=^J`S^ot_RNI4$8$GlW}z46Gx&WxhLSG!+y97QV&)Zy<=K zbW!t1iMPp@11ym<{P7GAn$Jj74=WX{M#bL__TG5 z@dl&JXjpQbTsb#C<*p+UR=QIM?RDCh^{nEbqb)}mD{ev?sZ1-_=4NSCbQ&DFBJ z>j)@+P?VvFwLjnt`N0GX30@9@U3uLf6qu;*#C=5>mYlbeq zZUk(t&2ASATTiHBLW-WE4m!*bYDU1L&!2Znvo`J08Wao&1rkhkxgR)~X^0=Il7IF* zaRDvHuWCLxsH|ZV(PWOV)7)o(gJ6M5Iy`sg&?%ANB)q?;QzHTSVVzKUjmE!sRjpc7#N+AonfI1EZ<_>m#eD)n`|-i%bWPl zH!_xQIWjhJ0-|sI{N20Q(o3bX!0sfB(du=I>8!|qFP*PH zpFfN87#7$rXL17Kvr3mqMz#=EA;5fbfhaYK<-@u|liNeG<(NL&p7^Gtsyo!}tqyl2 z@q!)~ciF5{JHK9R$DBNfeqkYF=XDtuz;X}i^}i% z=250P73{f9m-v5LfQ_9B&fB(sQ(C=-PK{>X?Ny>#`Z(4h6DBoL{3|H{Dxg%@G2XEI zs+F?9kO%e^}ZPmF(RF(i3aRAunTK$%BC26d8wQvc*+_Us-;VGTCgmn?u|Q{BNeda4T7*Sp z1qyW~bSJFB@I)M}aKR*hKTp z1~~cwM|)^#;A}Rj-x1Q3)~szNs;!#hy50lYbHMq;3P>HT!Wv|OVE0`21_~PS6odeO zv-VLntY-L3@Q~r!h83|IwTu(uwDH6vX$_;oZjF|NwxYau#^406~ z({!M;&}oLckRBU<#xvEJUARQ$b~f~Q#hAemo&XUByMfuQ&?VaIOHHD^}`B|@0z}gZmkZejNt7J_W|JEHUK{k_PPRl51#TD zqHGOUkWa@T2L6U%cqXmS#VxiU?~OQb+Oek*KeKg}eWn_Gq`UFK1ge?A+#_ zd`zgBRWHU0{;J- zy#G(79oI#ua`0jF<~xo}Usq>ne8RU3C{yl5CXc0S0A>W7gi}%PHT=>+(`6~?bD{9s zDEliHQRX3kUHUFN!2(^)G~tH1S>4DPHb8&_{caG%w>}8Gt1HmB%*p7pM~N8=3Jay5v0Y*|Wd8-c8ZEW%_)eF*L(_tfal0O_c(-q-CrLMot0W@6d{Pm7HV1;gej&mY^4M zn%6^r8^dDwg02r*w2W`P;o1i++R8cT&T7G1=P zoA|E4K+V6Tb=m54FY9R8s#cN3%c4a+$s5{qN&EDesJumWI)h(hIs=`B&(5;9kG10E zulVcDZAnf8UKN|wt!VI`?Bm+NAsW2RKeecT?r{xPX6R{0M^C5tWrH1zN6s&7={gne zyxCEfmM1IV30>)7VU$fo<}Ts5`NuzYLVbMFW%@-CoT2|Nz6VaEZ!EDI^zGGO zs$IfaP}il|%-3O;A?Kh8$^1Q{rPCcJiz2y~{(#23UJR2bDr7o*8$*9+m7ZUh=6ec% zdInNQYfAoyy#$;vJ3<C>^kC(HvRu(bNhR@OW=*c<2f1UrH;1iAZD+0`uedr2drO zQ^W7y@?uT}0)Lf9zH6svN&`C82PaB3K1DJd!_<^OY8#|kgf;o;=kMAvDG>kod=(#WFceM|QP%QXG~e ztMXXRGR-<_x}rlUlNo5@TlDXCYsS8sH2z`|_cE1n;c)T7#qVLq=u)90+jVQA?>lrC z`FbI@wYcYL)EzAjTr!Zs`ph!S1OdRfL&I!Fe$cDbafSHpZ4J6_(CtBg_aOk6>=a-+ zGd2l|)n+ijR8JzUuB5~4`4*W*7EMvKLDjvr2Xyyorn*O{{0!RDJ?z=khQ2z25(H$0 zj^P$z!Ug3+Rn8tO#}##qlq>ivZ|siAVv5QJS6jQ2zL3cK{5d^PGiB#}Jj5ck#XF@@ zx3ub(R$V2>meh@j$*wbhLE{W{jw@=Q;!sv+?H)VZNWrF<8Uf?~reje@Ptnw4wZV1S zZh!xq>R?i9XZM^`dNzC6s%M&t(et=|d_IxL)z>_zygeFq6RHd7ww0h3)fP8tIlJt5 zVpGClCvqFH?b!O*`T+>De?;OV}L())lBEN=JjiePlm^3veeZ49+C4)UUa;CDKdw6 zEPl}9cI6!dzX31N!^gMI@W}&)$F+~lA)MjO^E}b#xn$&uvtZCz5egicH^q?I8CuMz zQpMs$GVp|mHej89B{Kb$bu^4U(vD|;*#d?wO*K_dIKZBQop{iwGG{9EiCu+nxU52J zK%pk--V1Tkn;sdLoQU-j`-~yBKG|!vfm2a z8Jqg8Lq8C5c67I+FVI?$nj^u~43C<12X^Zoci5u8QO%TpR~W*=o$>ZVx)>aFYTz=) zj2ukLDE3W|irbCGsS{UI zm{r}Nk%a*F^faL8>NWMV6q{pdRiep=R4FsS%{tugV@DJ=PM4bYq=x^-94In5d(9qk zTj?2lSc=Kw+{t2@b*$1`d{x3T&W_3j$O?o;x-z_f1?!s%-RJo~J^I%DrrhN}(19HT zOF3bjlJeN#RULDv*!wHgMzZ#3S;fSxc(- zmNW)%4|40uSZ(1|6I%C4ZgFBib~|lsNv6_BJb2eO;_sD4^yppN1iy*~@_2JAD@W;n zRKB+ya_G7d`8kE-jp8*f2AS?CW-hFoNcMztY4Z`WeHVsFV%sKFZCtDRhDNSZpXtst znrOUo!bXwFm}m@XKH04Xo8-8GH3z*15MHLn2CDC{PR?ipLNorF8r8#2jjXF@EnYYX z=QfDhjLB^gvo%uuYqJ3<)Tr)2uesNMdP&q#dvMpII?ObflQdx1a`4)mOT}Z%@r6!b z6h3#^ySYru1mwmUn=pIR!hV6Dm+3b)yIvLfY9u^$$Gw~6!^gDjT^D36k7i(G(m96N z|HD^WxP@*l(J63q@{Hgly7d&(5CwL!#@h-9tn)N;$J=&xbqzhEio7MG^Bk^V-Fu)d3M#Gqi_~uOIE@(|N?+4|j5G4? zZ`%p^bXlHfU(k^=eMV3Ne)`EgEh)2#;qErvQ;DUd#~T){`|OtGpth2YrY_}6HG*6p zAEgc|ooZY@43*lSVT4@;{o(U}B1qyQ;o;WZyOjbn= zz43N=`XFN24k~PB({zv07v;A-PBStRUP4eZ_IM>U~GqemD5Zzx{eLwraVu)vvpF4Yia&Ns&}VT&sPYWaX}=1bV7y+yLnJ$PFgG zuBPDhVVWAdmsX`mzxN2yYxVUjA2&+-V2KXZi_O-@PP=Yv*7nJ~)Bkoq!v7DQCAB_k zwEUMkiiNT=1yV}xzk(oHe;2tyYiHTjoSeb&QJZpfVhpjOBM}@0Xk-wubwE(@j6!$s zDBxWk1yV$h0)1nEuR`V0tp>8UlnTm+UEZPVJ=OI*&^{oDS83eieTxPF*GaPzdevcF zIi=fEtM~3#rN4+m+j|~nHMjicl{uRgJt5Zt6YP0Q&-8|f`m`2Re{9;f;;>Czdr`Ns zr_dYTxKiN8n=mngB)Sbsd~rIkj}uj9N9w3P1oD#p(YvO;7yu2Jmb6PP%@E-@F8w9r zeT#G=Tg5}L@h!TmCHn?K#eDbVMF^PUKj;&E_?X;@b)W(MHM!%k4q4u#IOn}{Oz}tW z9+f!b-oyd*Q4)Nwe=~K#5?&66cK}J@WQ@m;7>HOn89Lu7A?{K3@$LsyD|nkX1!8FF z``*%%zRCzT`T6Sz-BYKn5vyC!Tzx)6YyJI$qA&HkY;jldkq5$iE7WGquu^`!IIH#k zH~Obsgv9q-Rn|vCtLj%4xGz_$_|BRfw>mvruN8VRlY+4Me;^yFPsUM&mVojs!!6nk zqmT_U!~zJx9E)u{%kLFmTdc@q3B-0Zj-4^P;aP+)Im%rY=Cy*^k3zX$VC6Y4GE5zI z?)NF#8)J@hQnBGq4wf;%fqzg4W+0|{GF#Dhfh{Ey7Y5f$stErf-x}QhMlCdZ6h9s7 zDP}anet!{Pf3Zo3VdJ)|Ok^+-W%A&DdS*YyijB;CU{M+s7^+m7TNL?5>ki-Aq9A%gJ-j3@jCec zLi-GTp`_z=P{E(rgUmdNi)@T27QRXdULSn6kuV}> zn(leS!GNu&Nw2vZ{z;c|;Q=WDH3A>4apS6Bz18`ep;hUxO13iFhY7 z2~@so`QU(0Q=EtK;N`6r->PagFRdF|p&PskK|bj38*gO3rUq`YwTlG?U2 zw%3GLdYRi6xke)g!@kJyP85AtsHi-5tBu9was&J*YWt{PG*umLT2NWB#iE*3x7!w0 zOQMCLqK(FlVK#J@LZV>R#g_*B zpNuhey{l|tvV$~|&<7$deSej`$_9M<#{9s9M~lmr`32drabDQjWitE7`Pgyr6Z-gy z3o9(k{9a*HR-Y~Qki6-BooQa*20ub)EoXUs+c-)6x&0i!BuBkey?p(=^fn*%*`)M_ zMhBd9S22F1Lfw~SLM?j%c4xQO+p=X3#02a<9Qw3vT%bZ_X)E71rGI@FK{~whCn-AZ zB=CmBD;^!H@J&KEKPgGMnXpx9aJbR+EpCJs?WA%j@o{!x#voQ{;;qvsYTjlw zfT1EtqSH{Huu-T^p(r#}1ChRZL}5j;jzT5=MWG?zoOLnfP1DuYng~B>C)NYWxZDxX zh#T(Lf-;TV=RYQkC0g&Nkrxgwcm5P1C8; zR@}BWlA3rPZHEDSq){1FdmF_XG2RQ=7cQNorsj3iG<-=pD%+RZ@?vIEECVj ze|Yt5@A=+yC@ro(T&1PkKss_h9WHO>i{6s5BFQJcr`p?-{pkp@vz-X@S>U?TBUX4dAf? z1jem?bfARQKg3Y>580_fN%Gqmm8F%ljR9E)8gD=5{^ve{#A z8|{zDcWrknpS}mgt(lS7(@s_^EGp3b#Nsv;S0Hi4nvX*9*O66QKOR{f)w>j}BMV(N zXn)RN$7Wq?ETXm}VdG<{xOklV^;+EyZGb(di=jlTuz90lRC5aipW$O^i3?PFI^*h} zKZnOj8R%uhClUd>&mK%zXA7xzER+XwqNgctx=G5n2!%){c-I8_UQG+6hf%G7W7cBG zgvF#Dc+HSl%RAW_)Jh~4l^WQs6;LWY4}UG~$TpQ*%P*gj-(7H#H(h1R9I28rUFc#G zW`scD2~~#%Qq`UUPv2%etN&p0u;2NmmaT0kDnN-xTuYsprxAds-yf z*3hfMdFH&S8pn{Q*@l-=&kQU~$+u`I3zojQpv9OxwD4~rr+GSxLH4-8sD>;W>VJbO z&)}k#VRt9-5)Rt5#60O(7T~z{ai^Hr57&#uoorZHgU1dW&7h&JtO?IC{I0@-Wem^u z{qxj08Y9I^F$a6K$cv;p8WnDwKGm9Ug@BfHhJ8Me*4(D8UgjSv0U+o4`maBAo6UNE z5!GsNWmj!@K9P?nbz@Gf6V>5#x_@mAApZ8&mTpuX>!ZDmnz)QkUB(yHaFVmG7uB^W z@*S>30HkxEzl}lfm9k(|r$kUej%;)Lb+>kHzX&#a_H6*PT6m%K@k8I@!7e9pt~D(< zOvcx1+deHO?|9YL;|}(9W+1N(&JZm&Tis&388&;+fX1P*#dvu1Y(HEpseeuc@@^&9 zUB*4Vh5?P)%Rl_xyoB??VpV)7*OrjAxU#jI>Uo^~{^F~$znG`1WF{n7ZLYISk~!&6 zJ^l)+Md0s-d;?SmL36ik^ZzwXd-WjOnHpiUhgcb5yDzpfQZWCMt&H+wmM$=Yd3I4} zQTk3+$+HIZKg?c7_TADfDSy|XG#T!As(qo6lA>;V5|!eE0R$@h)z|WOiyH(7KXe3W z)x}TrK}gX2!z(+#$9@3GSmg_E4gw_SMx$VQ&tC*k;#VV7RHp@4U(19FdFR&`p!FW# zXtG3A4a2J%ifwO?M9F^H8m6W%TVyeIbX59zjIfqblbY1jQ`R!>cWEf2`#^u=oUdmn z()q1g14Vh0+eM*qP(;R7Mls%8MMsI3@N*=Z1jxBvutT zbcHM;?GWcbZ7FV3f1`vRDeHKmJG+JlV1u-@CR4r7;L9$ORueD=9HlInTKutv zXv)LlrA4oBo1sRm>4>FKC49o-WTzPYQ4 zps-Puu6t-D5@T4=WqY9*%2-q0`kQ5ee@-^K7(MT$~zQFbIejPZvQJUv$#dg6-NUj={v%LlC6)OV^r z=z!&wc+e3mitQM4?yC^hQ6fV`)9Z$nxO3c-w0Y2#xg6uaS>08R)AJkyLt{*v)3YeH zXale?t3PAlM_I*At*L zm`T6P|GET%eH9lNgF#=enupPG7zH~Ki}0;gIhLLw%Ojb+!r~~*dA^KiXkf@Lz4LhW zQTg?XPu;b4ou_|WGo>LJ8=0M+`uovtb*iU+HQCR-8F+o~X^nvmL63GIGyM=x{7gY6 zt}$?3p0SC{i^uAlFY2xv5ZQJa^#+nv&kCQ!`$63!z!t34U44tW&OA@)>j-C6DY{az zRHZ&2!^hYqpWHyEIuhvy5+xg}-V)!Vw;|A3oPCOmdy#*RZ??*d;xbNGdX>3CK=xON zYWjnYHG00JgN^>;Mdj*Squ7GpMljiq+2<4+gW0$fuc?)H5R~hai~^@#mLu0PKVW2eKy-F2-opRRef($}>;fvNJs;AGq{&1Gt0;YXsFwk5CB@R}XKi z-t1hx65J~}v7_STas`}oftR#S?Ke2=cnqMj8D&xj0y`#+AzY++eKApXV|+4y#{=ua zJcJ9gUb%k)@LvmJw{PbbnoneaQrPWv5$VQo_oRQH|NTWy(da&ZRwV}$F51oew43#( ze}l?!Xc+}q7fPTiZ*t*NkZ1PNiJp7haip5}s5QUSc&8NQ*43Is^4k(;b%ZvAuj4Yt zO3^SHcKaay#A6vcm-_46uSO&aUci5bXVC}v&)(UZ(`r)<-}5UJ%Z$k)(iRp;%{5#? zR~LUDM!GI`hw+~8JaKAykcsunT-K)bkBoH`(?^MDm1H<06Cc$Tf5pX}aBnVyHO^P@ z&0jFJ5XB>-fY|D{VJQ9{hk)S_8I?EUkca$L! zPzexnHxjEUJ2UEttZrB-wU?X&iTwm}N4$Sh6Tt|Wd4!db4KfJ-^U=C z-O#DfA3igyz`uQ!p6qd@L4B2{&t(ab#;c$q$~uTr;7zGgv?rR zexO~?*h;!G;N(Ws4ydvZwXuQ}|35@vD)svNo{EE}iaesP%FwDYY?yknVe0L4CJTR7 z&;QO3iOKmnfW~in-iyZvQXyr)?<3|klC?nZUWiv1PdSq)gXdR~1)?H+&dzRClB=>w|)_CMu?RntO9_6YVBFA%r7N%+04 zXFSB|*1dgk2L;As+&^`Niane03RisF3!Nx#1LjrZEax!IA>OIkK_7UB~B@XuPJ5MN>87mV%KRp6ti+_QrvFu%D~M-lvzy*f z6#Az>_$Rzt^WCrQBemK_r9y58ZZJQZHx z)LLM2vNPz8I;L(&hJSyD;bp3(>byD%jZvfHItPG_Jc9~tVg*Lj3su0BNr)zxBq6;@ z^6S#!#b(!nO?(}g9q@(@k8kUJhPTWu3>6GNT6I%RvqhR=c2UPNc9T!@ET1P+44WI5 zP9{Zh55p>k1WRU{_^df6`4vEh-?bq&?f!)q@e(GBQnHiS(DHxxmDYqD^5L%;PL6zp z%sHjSPr0z?Jm4x-f7^yWfAaKbcKDO0J0*TUKt?u@@zrd}iF$qq0avfG*IgK`D=G`) z$rWZWwCju^y`NDS3{G>PDM^L)_^C~2o4TqG)z-aFg@=C9!;0lpl%aZ z^xCf8XGPy=)V;)*^vD#&x(UAc?)==0ufW@tEkl2iEqvYp^znNdq(i+#fw*53Cm@o% z%PPOm&o>!;Z^{iU4Y@A!n_mDOm}Oj8;S>@Apo+Ih&!W6*9)5lwSvc@}nD8mhuZt=c zeo^Jtc`JWrCBIUBzOBvd)pROTIhs|xE2=Qr)osw)cByE<%0k@QuNZNb0jsFO_A{0F zaD`u*@#MzNsA}=VZs!I?Q0Hh;N3Xw9b0*lLO0m|*I;ycJ%S}km(5PV;dw9!hjn}!H z8mEc2(ov_yTYQleWS|U7Y#3h4RNvZ|#8<(A5;=eW_0pJ zbNJ&r`VfT4fY*^&WNN%nY02`WrL>oAAW|{&mo* zw(vV8WBoSuH^+RZx^BF8jP#CVKIIA+=$*;k3{|f*L9UmCBa8TkFeHC17@#70jdn~a zZCx4E_RKQeN&eWE>bbFyEp?;c^3_Lle-gu>=XMh93@TmQUS;0SvC78o=j89^8G!3K zEUHsT(h&wl{bin_8V^V7$^+CyVAAM<3BY>Xzd^bRzqN zC2nCib0se0oJ&h9al{hpl1Ugw^L%!V50!lm<^5)n(60}R>s5cJyYT_H5D&P;!yj;M z^-Tig+3q2iEBtexa2qoZnBl47GVVds)tyw-D(!6Tiy}}|c<@tPl)+0gl9j1&XM^gR zxc|^{%7Mw1kM@`A)&!EjT7yUf2$gIoj9{!r2My$d z%}8~jNA?rS*O)Lcluz*k=sA(?>cQKFj<2&;k^S}h+ge^nWBi^fTCwvDdfCwUm}{D? zm7L8T`)m%gQf0o@JliHd)XyS!%|B!{OVovAw_mDLh+827&v-8x>?He;D$F1CZ(k)IrFt36V`r+38%bm~@kstH9l`=DI}~Vzwwl z6G(CEklUrmxSqBWEP#llb7H9@YJ$hId~DP0|#o#WHFazxhzJHA7AFc z6)@OLfmVMn{WO1k!PD>2gKsi_OdvtQV>f>c2Yd;RvZ7pF6LJd981n`DOk$wTfuSfK zwt8G7Kj)=CT(m`~E3Q1vu=eNA55k1Cm>W}r(8J|l4liD#D`$F4nEjp-KDM@1g{RP@jB z&f;M`*I8Ol^YiHy(BSooB;_!*DHNpa)nsRfLP{BQ>uDLS4p$)11nFUVx;o=9R%LgD zKPG>0B^YJ0sJlj=ck|+rcKcWH(gWc=jst6e$2Ig+o&f@*d$ejEfy@r9jsDDFS-9}@ zOqZTQWxjwuOP)$Bf^1)n=)z{Yu#9ECy6fRc8@7k_&{z~kLSwS%MFOjY)Zq{2o1==q zLod3ukER0(rSL9WU|=01#113GlhOt?do_P;?6_wPl8k$%A&&wBSPXw=OtErw?nupq zZfzA%7gmXtTFw}=+Ndj0<{vmc*Oy9>4hO@Yp-{)kdAcH60`N>a@sjR1SriF23|9#m znDRZ29FV$9Yh&H$J=K9`YbrrW;z%x3XNLkT*cobMv<$4tQ8>iqw9<4~&7&8o(e!^D zQ=ZdmlAWe!II-2EM>vgsmfv)`y_JYiFn^H<$b%IJ`@mK)oTg05kAZ^Id>)R`M=Rc) zgoljNslM8VyD5iov-AXTn|--VJKmkqPe1RNa;K?(?o|x*L(#>T~G4Up|7#LZ6CUOqO*JZx8x!LRz zgoWZ>WlE5Ds_{R1q`(;s$2v(O59Wq^tXN-TY_+is?fPFx>k+_e1aUSGI=X+;rx+oj z8(Ck3dG$U<66oGrSP)qp2V*b; zFkV${#bGgXSYj=ont;%{%GJC{%gY{W($Uz7lDjOEjE%Cm3MO$tuNPx&Ov5J;!O*tN zzT9gWnNv88RDyHDNh?5Q8(e>Hq)r^8!63T0%x`{VN>T3{*!3!b-maF^vGi+kPe}(N zW-mRN5^$;+yzy087rGiXtc4wuu^WCBupwsCqPJisTKy_`E1PtA0hM^RH$`ApQ2>cf z3BhVeRYjfFq8hS#Gf=8Mg6HaCl30%k5Unza+VoH8&=J{N69$auG}eFCdexCDUml#g zf_KWpt`+{st?*G;uQf+hH&)FznoT8@Xz7t}K{uy1blY_12`YT&uN6BG5oGP*g(Y5f z&utp}!JWGeqKDK)!!XaiO}xGsE^?-Vd9j)WU@))aC?|ko{@^5&F06Ux};f8=A+_ z90VQfh2BSTm8fvqFd^5k;T}qBp*M0LyGtcmg4nmpaV&JN##(eEVNWh;{rk_yNi&M7)P?#AFK7L=K=i zrB0e%Ry?Q)yH_cxF`dB5zC6tSb`?i&w^uv!vinX`R^7~CySzb)pyu>wbq_qExL%aF zp|Y6qi{$}*R*0xl4L<(JhT@}o2Mhk!|M;JNSU}#kom_u*On_cy0g-Ev&nSu9ydV5E zBcZX(gY)YJ2K9p;{^J^i_P+hJ^l-_pZl`Y&@V-QC z#~OEYgbR2c&o<_|K6aaQ3|OMThTj%w-L{5KJ(3hOKJ~V>HTsfd3tt*T^72QQ{$XFFR`NR*!z@N~WV!iiwtB zyVZZIl*~DjO+eDx`piakBoWG`X21e3$7)*;;jzm{0F^v*a**9PXC8 z_;0x2;ooZ>F8ndSN`ja2Ni=lcajsX39*Wcte7#xwUpi8>FGRaHscTPVF4tdh`T%ud z6+C*RD*TG`H@@R<4ysf*S3b;mZ1 zS$vgXF$FICWyeNp zWT6m9CrX-YU?})}Nz>;Al=1p&@)0{Y?QEF(All+~WyM~zX+>Q6`%5Mjr=B1gSq*=8 z5E?9du<1gS#h=m(N{A+!BU<9JjAxhjv%Gvh^P_Ci@Xb7L1d+M<7GzVAAi>{LH-f!A zQ8|BHQoT1$Uk8)6U8_djSkl%i0ZDh3DDr|$%v2QNs~f!q@?%-u`2FJgLs70e!*0J= zF4D3C;EE&LkMd58Vd&%2;Tb;bHNSrs8E(U9lw;kW`~Als(2HPdWJA&J*j}qbX+x;1 z^@_`Qg~4I5LgB>h;aore5-*pFyH2mi25>!X_SPL&zj06mqnyX$8~OEz%OsvVAITWc zDU_4$syjcc1ReqnU#~fCkTH20gTw3ZKf~*_2QaGCbu+UGn9v(1tXzV7;@*F&6!OF& z;J&8%slq+_IY6%Q(vKoY`T1sXDw2+dTz*xyT12bj0} zYTn)L?zZ(9*dRM-BMUfj%!z+i?ucFs45_uoiN1}q_##=MwGFc%IO~P+7qUfV#jY9C zDlhX{4wnxM5f(3S3;S#07i3{jbGY|ye*pgsn`?G?GK^*K%{ctoK$Zz~cmX1O$x+hG zI(Q$u|*yPBfI4xI4mT=>l#hQE*% zD4OVBF9R4iFrf^Pv!OL_KeRVuuu3jK;92pH^Ed@A+YjO1niYSr#aPRYmPn~3vzR+M zx|hy1=uTr#aEKFZBD3F-keuD=BOUdOQ(fuTZ+?1n@@CUodsetKw-pXL`UPkyEfUmB zRm*@d9iQGGx1z3V)!54m7A}WDfK}-2~RL*2i?e zo8EMabe?>Ox5$6R*V1i;%jDYzMz0W(XHO2>&GdLKcX zsB!PA=pj4lvB*Zj6~{eRmU=#1<^OO>*C0ZIjF2w?>U$HGrvOVE_&?<6e4sMgEHPNr z0&c^9NCx=NT8CDuX1^J%D-z+oBTSEET14UYxE?#Q?nr-G<@*8lq}a4Ok)fzYR=Cc2 zavonVN;O}O+c`!B0VX=l<~=cN@*MwBBM;Z(>a_YqE^?Ur+8Hzs+|YkO9uP!w`nF*b zVz(J0v%Mas+GLSm4H;ya@W_n{rx@1}YE$pSbAYB%4Mj$q{aEDv%s;2|5kxd`zYs_$LY;I*K zB?JTp%>dxgDF;2UqXQB>N^r5#tA$9(qKBJE&8UC%)GBuazTj%)zXWY(e*(Q5`Q zYdC*VF^w>dc5-CqN#OxXje#XL>R9Qu*Ko(QlxnINI%uoAR!&EfP)#8f^BckGz~?f4DI*aso+Q2dAhn#EWYd#go!kE}_XEJ&F&r z(`wtZUUph-cQ(ood&5zDI2QWzi-RGHwg3$v!6bMK#4s=@Z#8CB^PId-P~0A9qWrwTw|l6c)!D+C^Ef zhi!%LH%^WyrIQ1MTCN@WL%5OJV7ADMgv5c6g2SjjtXZY!9hF1N5oPJK6l#Ak>Y9A~ z)&{dOEyo4OCY`32F<~Ze zr05FoBj61MM*a{fDF^BisaM>j>|K-=@?dxyFO6rWUNXOEsK&lbJX*luqI|AF)wfCS ziixHIxy$$>Dd=L0op>&fDO?-Q=C0V98_yuu>04jIugUs9EhvFukWQt<&*k)4dGk3lSd0qn;Yv1zA= zQREc!>)Y0U9Th810_>a=yh?}C>4%7=j}v}Pf6BKt<3K?aYdQ8FfAUjSRGGNP=}7cX z=#m47GtgWMf!! zwMz7dw=NI@1pxtpmoyOqLIH=DcM$?2f4&D=?@w>yRn`grUDW#bAT5G13<~vX)3Z7)Wzy8FTbauicN@^i3 z2@n4YzOterfYmAc0XjT!e^GYvzy8Pn)ULneKntf;5?@ukXT`wV+@QVa-lY0BhTj}_ zLseDEdoKd(!%4Vjv|*@=`c(|ux6n|!$&FoDJdp)33e`9u!0T7a!rV;{X z3oU?f3tgX{KlW+m46ehPa;R6tCFt2`Ce3MV&M)iXizD?>d%fhGp^tId=UFvO|X4QyN z9!(oQN7`Oh(kVbjf9(ua75TEDlE%uH235mUpU7IMRydY+j;bqTN~$~4=u*|>cLkjw zo{c{|8e(^D787ki*G?V2I3Xq7gsZDPQ=A@_nG97?b+1c>^(qF?A}y;5p=BjQmeC2F zc9ajfi0I{6WF8dZxiw7o8PR-P_!LZ&%9S$HehP5li$}BXfA5aws2l5{`);rJm@JYK zmWN*1GW&f^^iIK7I~i=)1}$$G;l*3M!~xf*nM(f-v#lbO%EI0xN)SRHC|(VwW?l~d z+kVTyU}dKMSUzV(hO;NPtGe=vo_$$9$|y0SQe}2tCj5q}KV0*EB8f2^5HepAUVYJg zLIo~73^6@kGKb?L2zQMSu;ylVr-p{-=f0K#xCHy?{sE8N zCAv3>cWp)77-t^mXL5200i-eGrdx@ItDelT9qu73~^l3{EFVunEYd7i0J62d~=8b&o0sz{Ft zV6d}}HdJv=_mK%4FzQTNd$GrqI{|flBsOjBYV(ume!_tV)c8_rwua5>9#uD@-Q}@; zf4tzOi@uC}pdUn~IKFAb-Gh>i%mxeYxj?98vg?bq$NE+_tEi zqimf7tt&sM|?^Kc+Al%df kJ43378s1IV@i(em$Uo%sJG{w(>~-+}0cLZAbxw^40M{UuDF6Tf delta 76254 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

9|CzvzxA%E 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 Al>h($ diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 81949d1f420..8d62654e4fa 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 81949d1f4209b471845ebed886920d9a488c0926 +Subproject commit 8d62654e4fab84fe6acbde7bda10d85bcb07936e diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html index 040284939d0..5a7a699e237 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html @@ -1,2 +1,2 @@ \ No newline at end of file + clear: both;white-space:pre-wrap}

About


Home Assistant
[[hass.config.core.version]]

Path to configuration.yaml: [[hass.config.core.config_dir]]

Developed by a bunch of awesome people.

Published under the MIT license
Source: server — frontend-ui —

Built using Python 3, Polymer [[polymerVersion]], Icons by Google and MaterialDesignIcons.com.

The following errors have been logged this session:

[[errorLog]]
\ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-info.html.gz index 91027a35abbfdc84fd79ded63990ae447091e155..2a297bf2c7e2e5badbd10dd219a9ecd66642fad2 100644 GIT binary patch literal 1229 zcmV;;1Ty;{iwFovpOIJs1889_aA9s`Y%OGEb}eacW^XQNbZu+^omTCN+%^>b-=|Pj z2s1FU*%U(Sof(>tGz}zeAlv>~mLOZ#wz{$D=$5BQI-g%z9aaRO@8}C|OZU9{^YU_luv!4}85$$IaZT-Fm5PBO0qZ15B$GucdIZ z1tSz}gl_&P5D(SC<^SY6KH+F%5;Jx+2*ou0L-tK9$(yc)2hWyWS z>lL{l-rWrg)@a2>e`^{H=q2OixpDMBX7%fu*q$Gas$*#Xnh4VHKRszhTo~ zVLCqk$Ohc^uXpFm(~>(ZOst9}vD!mP2Mf`K zEKO_MfFO(xC|gW)JYc%1Sn$P)Qy(SjB8_tkX(>0u0MCAWdPBd&wH0S0cUPPiVwsZ8 zv0wi}PTBK=)3|bZNu3YzaFn{De;y7@zq(qcj#6E}msm5jY{Yb4##5Z^WMeXR!hC%G zsI)(LI21dbjsH??I$bz%^YzOKq*%UVlI2}n)XbJlZXv`< z9av`|8LFRZ>2jk(O%|jzL@BI+y?b-PjHYuRAa>+~?L3i|9VJ<5th=1*YaZqM==C^H zk|SzrOoM&-{P+L&Od4u-4fx{-r5`A#M5hm7rix#5+92yfl-;Ai+wC@SJFID*)>nM} zet2fzM<0u?z{eCwSnQvquY=uDI`2mi(PM)DamT6X`Ay_)9NNhcm9>?Dp&beWiSoqr z<2bJepCbQ^h6|CfWCA!>Ac?C2}N=s6i0IUfI8DnHU?zP=zLm84#F8yh`r z2NJanupFRegsg~kSnI$7gxHI0d8EB8KCgJAbVg-(2sLN4iPEk3wD2l=erv0ErjP7L zmfzEx+cY^HbeK%z5JoY(le7n7Olx;nd3ty8)4g7J?eH+(*|}XY5#*UzqL}`(j;=@%jbXi2pZ*78uQ%g8Grrif-lA?evDI`CnQ+y?0&$9uHn-s{;NIa rp9g0>f=YOw55s=}in-@59|`~f$%bim literal 1239 zcmV;|1StC-iwFq1r;b2KFRvG3_3jfc%li}fNEx@NT&tpXy&oK~C} z-hg5PmP|HFMCReS1Ih9s7%xEXQ)QxOPg4R8RE|N++zsY!hUs~NZ zg5_Fin|xCg#W|}TYaLkTKtb*k*`Nci&e;mGd+AT_)%uT98(oy^#zW&bh6{l?Bxm25 zhc4ooZvDo?gJ)dHvPp8pfIU~T0ak%5E1$fCx{H=z9cI7zksG7d6Ncp*j8dRi7Wxzn zrd@>X0Hw`Im}|3uoQ_cm-weerxkaGh_MRClYi`#=7Z3>6YRi-^vB%!(4Q`gQVP2a) z|MN^+f$sZv^FW+dQjo!)3b`LRJRggHbkGgyNo)?wTJN#ILTT<38?2wiKUq+&1)NR4 zBI94KfZK#*+E?eRN_t?<@Ej6jfvqezT^jdOU!>@(ZyGvMd>wjGamQS4wNfEH3nlh? zPU%x9DdYo)$3?HT%D6=eb5=vsj`@>@W6rBNy}22lZf_}Zm0tCrupC}4@fkM)$M>v} z=WJs!$TCEEIUK zyf-e1<4V`S5F?%EjgMqFV6rZWv-zB2AGw!#9OmZYf-n04p8fFh0e_KcN=gRq&M7X0 zGC7`OyZ9NMl8dd=uyS*Qop<4I6tcvB7Pd^ky-j0-sV=U#uZY)Vz_gZ!Qyi^%trBv= ze0aVS(r!I$iyhC#zbQ5zv6xDnTM*K_m=cfd4+3?UDc;=E#p@9yNVX=NWNnjIL>Gjw zz=cW;XrmzNs~>A=GbLSx7N|8yDPIA(e0NQh#B=W;bmW6>Es~ZTC0R;ewHek|ALM)R zdYmW95jHiXLB4$c^S^sW4OQzJ>~Vy`_LLK>mH$JSkM18Lgdsoa=&M#LPg)mb{V3vU zwTjHzSI8G_OS-t~pUJnue)bG}C=rEAe?tkY{^v%$=7GyY^(pz0`@sI!ajJ5 zogYzSf?KKVX4~3Nfhp~}8TX#&s5?o4A{7L5GTnq}MF)MKOuN~^(#`~?8+h>oBK)8( z@%!=`3f?L|na+Ao+Z^Wfz2@SPCV?AYKL14r&>+`bsS6_~^zEB#Ivb{V7p6FkP!OBR z(}4S~;nOGji$3O`1*5G85z#KnWFscQY&z|_DSq>Zp{DV0k&OF`=ieEDFu#8a005%E BUkv~N diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index 4686c1b3648..7e1831dd98c 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","3a3eec44744e457bc383344670563716"],["/frontend/panels/dev-event-5c82300b3cf543a92cf4297506e450e7.html","1bb68c3df5c14307a2550a0cca39b435"],["/frontend/panels/dev-info-27ea4123b8a5e0b789c903e22f119e52.html","2a47633b0b67eaace1bd944df70209a1"],["/frontend/panels/dev-service-9f749635e518a4ca7991975bdefdb10a.html","1bc71eb7620c7b7198fd4b7976d6bc13"],["/frontend/panels/dev-state-041f5b660f7a1fa748e47fc46c0bdb3c.html","f00c0e74a916e44d61c680e23f5aa34d"],["/frontend/panels/dev-template-97f77b69faef8c5975c09431912831cc.html","5a4848a193ba4aed4359bb3e0e05bac6"],["/frontend/panels/map-9c8c7924ba8f731560c9f4093835cc26.html","8ae4874622d23d995ddf2a8b0ffa8d80"],["/static/core-40a73d7be324cb52fbba55d993db126c.js","71bd739508e8725a3e7db7544a58f135"],["/static/frontend-c5b36eabb331256f1a3755b64e204b00.html","3edcec6d5835dac03cd0932ac377a1bb"],["/static/mdi-7a0f14bbf3822449f9060b9c53bd7376.html","8d60ec43a3f8a77b21c312783ae5b892"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","89313f9f2126ddea722150f8154aca03"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.toString().match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a))return e.add(new Request(a,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);var n="index.html";!t&&n&&(a=addDirectoryIndex(a,n),t=urlsToCacheKeys.has(a));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,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 Date: Wed, 1 Feb 2017 10:42:50 +0100 Subject: [PATCH 038/157] Use same pattern for device defaults in both platforms. (#5682) --- homeassistant/components/light/rflink.py | 9 ++------- homeassistant/components/rflink.py | 6 ++++++ homeassistant/components/switch/rflink.py | 9 +++------ 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/light/rflink.py b/homeassistant/components/light/rflink.py index 127121dda86..ab532e2368a 100644 --- a/homeassistant/components/light/rflink.py +++ b/homeassistant/components/light/rflink.py @@ -13,8 +13,8 @@ from homeassistant.components.light import ( from homeassistant.components.rflink import ( CONF_ALIASSES, CONF_DEVICE_DEFAULTS, CONF_DEVICES, CONF_FIRE_EVENT, CONF_IGNORE_DEVICES, CONF_NEW_DEVICES_GROUP, CONF_SIGNAL_REPETITIONS, - DATA_DEVICE_REGISTER, DATA_ENTITY_LOOKUP, DEFAULT_SIGNAL_REPETITIONS, - DOMAIN, EVENT_KEY_COMMAND, EVENT_KEY_ID, SwitchableRflinkDevice, cv, vol) + DATA_DEVICE_REGISTER, DATA_ENTITY_LOOKUP, DEVICE_DEFAULTS_SCHEMA, DOMAIN, + EVENT_KEY_COMMAND, EVENT_KEY_ID, SwitchableRflinkDevice, cv, vol) from homeassistant.const import CONF_NAME, CONF_PLATFORM, CONF_TYPE DEPENDENCIES = ['rflink'] @@ -25,11 +25,6 @@ TYPE_DIMMABLE = 'dimmable' TYPE_SWITCHABLE = 'switchable' TYPE_HYBRID = 'hybrid' -DEVICE_DEFAULTS_SCHEMA = vol.Schema({ - vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean, - vol.Optional(CONF_SIGNAL_REPETITIONS, - default=DEFAULT_SIGNAL_REPETITIONS): vol.Coerce(int), -}) PLATFORM_SCHEMA = vol.Schema({ vol.Required(CONF_PLATFORM): DOMAIN, vol.Optional(CONF_NEW_DEVICES_GROUP, default=None): cv.string, diff --git a/homeassistant/components/rflink.py b/homeassistant/components/rflink.py index 77fb5897828..13696318e01 100644 --- a/homeassistant/components/rflink.py +++ b/homeassistant/components/rflink.py @@ -53,6 +53,12 @@ CONF_WAIT_FOR_ACK = 'wait_for_ack' DEFAULT_SIGNAL_REPETITIONS = 1 DEFAULT_RECONNECT_INTERVAL = 10 +DEVICE_DEFAULTS_SCHEMA = vol.Schema({ + vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean, + vol.Optional(CONF_SIGNAL_REPETITIONS, + default=DEFAULT_SIGNAL_REPETITIONS): vol.Coerce(int), +}) + CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Required(CONF_PORT): vol.Any(cv.port, cv.string), diff --git a/homeassistant/components/switch/rflink.py b/homeassistant/components/switch/rflink.py index 34e5db6f545..aa61987c3dd 100644 --- a/homeassistant/components/switch/rflink.py +++ b/homeassistant/components/switch/rflink.py @@ -9,7 +9,7 @@ import logging from homeassistant.components.rflink import ( CONF_ALIASSES, CONF_DEVICE_DEFAULTS, CONF_DEVICES, CONF_FIRE_EVENT, - CONF_SIGNAL_REPETITIONS, DATA_ENTITY_LOOKUP, DEFAULT_SIGNAL_REPETITIONS, + CONF_SIGNAL_REPETITIONS, DATA_ENTITY_LOOKUP, DEVICE_DEFAULTS_SCHEMA, DOMAIN, EVENT_KEY_COMMAND, SwitchableRflinkDevice, cv, vol) from homeassistant.components.switch import SwitchDevice from homeassistant.const import CONF_NAME, CONF_PLATFORM @@ -21,11 +21,8 @@ _LOGGER = logging.getLogger(__name__) PLATFORM_SCHEMA = vol.Schema({ vol.Required(CONF_PLATFORM): DOMAIN, - vol.Optional(CONF_DEVICE_DEFAULTS, default={}): vol.Schema({ - vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean, - vol.Optional(CONF_SIGNAL_REPETITIONS, - default=DEFAULT_SIGNAL_REPETITIONS): vol.Coerce(int), - }), + vol.Optional(CONF_DEVICE_DEFAULTS, default=DEVICE_DEFAULTS_SCHEMA({})): + DEVICE_DEFAULTS_SCHEMA, vol.Optional(CONF_DEVICES, default={}): vol.Schema({ cv.string: { vol.Optional(CONF_NAME): cv.string, From 32f8622bba3480fcd3984e787d3d3c21d163e3b5 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 1 Feb 2017 16:53:02 +0100 Subject: [PATCH 039/157] Bugfix sonos group coordinator (#5691) * Bugfix sonos group coordinator * Fix tests --- homeassistant/components/media_player/sonos.py | 18 ++++++++++-------- tests/components/media_player/test_sonos.py | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 38408914448..14b32260ca0 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -342,18 +342,20 @@ class SonosDevice(MediaPlayerDevice): if is_available: - if self._player.group.coordinator != self._player: + # set group coordinator + if self._player.is_coordinator: + self._coordinator = None + else: try: self._coordinator = _get_entity_from_soco( self.hass, self._player.group.coordinator) + + # protect for loop + if not self._coordinator.is_coordinator: + # pylint: disable=protected-access + self._coordinator._coordinator = None except ValueError: self._coordinator = None - else: - self._coordinator = None - - if self._coordinator == self: - _LOGGER.warning("Coordinator loop on: %s", self.unique_id) - self._coordinator = None track_info = None if self._last_avtransport_event: @@ -957,7 +959,7 @@ class SonosDevice(MediaPlayerDevice): try: # need catch exception if a coordinator is going to slave. # this state will recover with group part. - self.soco_snapshot.restore(True) + self.soco_snapshot.restore(False) except (TypeError, SoCoException): _LOGGER.debug("Error on restore %s", self.entity_id) diff --git a/tests/components/media_player/test_sonos.py b/tests/components/media_player/test_sonos.py index 3d80536fb82..bcbee544f81 100644 --- a/tests/components/media_player/test_sonos.py +++ b/tests/components/media_player/test_sonos.py @@ -314,4 +314,4 @@ class TestSonosMediaPlayer(unittest.TestCase): device._snapshot_coordinator.soco_device = SoCoMock('192.0.2.17') device.restore() self.assertEqual(restoreMock.call_count, 1) - self.assertEqual(restoreMock.call_args, mock.call(True)) + self.assertEqual(restoreMock.call_args, mock.call(False)) From a72d32b9af2359830c9c88980b34aff2a32c4e21 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 1 Feb 2017 17:20:52 +0100 Subject: [PATCH 040/157] Bugfix async blocking loop with xml parser. (#5694) --- homeassistant/components/device_tracker/upc_connect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/upc_connect.py b/homeassistant/components/device_tracker/upc_connect.py index a8d39baed57..ff526ec7e8a 100644 --- a/homeassistant/components/device_tracker/upc_connect.py +++ b/homeassistant/components/device_tracker/upc_connect.py @@ -92,7 +92,8 @@ class UPCDeviceScanner(DeviceScanner): raw = yield from self._async_ws_function(CMD_DEVICES) try: - xml_root = ET.fromstring(raw) + xml_root = yield from self.hass.loop.run_in_executor( + None, ET.fromstring, raw) return [mac.text for mac in xml_root.iter('MACAddr')] except (ET.ParseError, TypeError): _LOGGER.warning("Can't read device from %s", self.host) From 676519d0cb8478d01e276a22ad2ea55dc6451c5f Mon Sep 17 00:00:00 2001 From: Hugo Dupras Date: Wed, 1 Feb 2017 17:33:32 +0100 Subject: [PATCH 041/157] Hotfix for netatmo cameras (#5644) * Fix for missing netatmo tags in 0.37 Also fix issue with SSL certificate for vpn_url Signed-off-by: Hugo D. (jabesq) * Netatmo welcome: vpn_url can be empty Signed-off-by: Hugo D. (jabesq) * add config floag to disable SSL verification for vpn_url Signed-off-by: Hugo D. (jabesq) * Import CONF_VERIFY_SSL from const --- .../components/binary_sensor/netatmo.py | 30 +++++++++---------- homeassistant/components/camera/netatmo.py | 21 +++++++++---- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/binary_sensor/netatmo.py b/homeassistant/components/binary_sensor/netatmo.py index 4ef29b9e5f5..661d1128086 100644 --- a/homeassistant/components/binary_sensor/netatmo.py +++ b/homeassistant/components/binary_sensor/netatmo.py @@ -26,8 +26,6 @@ WELCOME_SENSOR_TYPES = { "Someone known": "motion", "Someone unknown": "motion", "Motion": "motion", - "Tag Vibration": 'vibration', - "Tag Open": 'opening' } PRESENCE_SENSOR_TYPES = { "Outdoor motion": "motion", @@ -35,11 +33,16 @@ PRESENCE_SENSOR_TYPES = { "Outdoor animal": "motion", "Outdoor vehicle": "motion" } +TAG_SENSOR_TYPES = { + "Tag Vibration": 'vibration', + "Tag Open": 'opening' +} CONF_HOME = 'home' CONF_CAMERAS = 'cameras' CONF_WELCOME_SENSORS = 'welcome_sensors' CONF_PRESENCE_SENSORS = 'presence_sensors' +CONF_TAG_SENSORS = 'tag_sensors' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOME): cv.string, @@ -78,6 +81,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): CONF_WELCOME_SENSORS, WELCOME_SENSOR_TYPES) presence_sensors = config.get( CONF_PRESENCE_SENSORS, PRESENCE_SENSOR_TYPES) + tag_sensors = config.get(CONF_TAG_SENSORS, TAG_SENSOR_TYPES) for camera_name in data.get_camera_names(): camera_type = data.get_camera_type(camera=camera_name, home=home) @@ -103,13 +107,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): variable)]) for module_name in data.get_module_names(camera_name): - for variable in welcome_sensors: - if variable in ('Tag Vibration', 'Tag Open'): - add_devices([NetatmoBinarySensor(data, camera_name, - module_name, home, - timeout, offset, - camera_type, - variable)]) + for variable in tag_sensors: + camera_type = None + add_devices([NetatmoBinarySensor(data, camera_name, + module_name, home, + timeout, offset, + camera_type, + variable)]) class NetatmoBinarySensor(BinarySensorDevice): @@ -157,7 +161,7 @@ class NetatmoBinarySensor(BinarySensorDevice): elif self._cameratype == "NOC": return PRESENCE_SENSOR_TYPES.get(self._sensor_name) else: - return None + return TAG_SENSOR_TYPES.get(self._sensor_name) @property def is_on(self): @@ -184,8 +188,6 @@ class NetatmoBinarySensor(BinarySensorDevice): self._data.camera_data.motionDetected(self._home, self._camera_name, self._timeout*60) - else: - return None elif self._cameratype == "NOC": if self._sensor_name == "Outdoor motion": self._state =\ @@ -206,9 +208,7 @@ class NetatmoBinarySensor(BinarySensorDevice): self._data.camera_data.carDetected(self._home, self._camera_name, self._offset) - else: - return None - elif self._sensor_name == "Tag Vibration": + if self._sensor_name == "Tag Vibration": self._state =\ self._data.camera_data.moduleMotionDetected(self._home, self._module_name, diff --git a/homeassistant/components/camera/netatmo.py b/homeassistant/components/camera/netatmo.py index 563de206dea..6ede7c5a162 100644 --- a/homeassistant/components/camera/netatmo.py +++ b/homeassistant/components/camera/netatmo.py @@ -9,6 +9,7 @@ import logging import requests import voluptuous as vol +from homeassistant.const import CONF_VERIFY_SSL from homeassistant.components.netatmo import CameraData from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA) from homeassistant.loader import get_component @@ -22,6 +23,7 @@ CONF_HOME = 'home' CONF_CAMERAS = 'cameras' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, vol.Optional(CONF_HOME): cv.string, vol.Optional(CONF_CAMERAS, default=[]): vol.All(cv.ensure_list, [cv.string]), @@ -33,6 +35,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup access to Netatmo cameras.""" netatmo = get_component('netatmo') home = config.get(CONF_HOME) + verify_ssl = config.get(CONF_VERIFY_SSL, True) import lnetatmo try: data = CameraData(netatmo.NETATMO_AUTH, home) @@ -42,7 +45,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if config[CONF_CAMERAS] != [] and \ camera_name not in config[CONF_CAMERAS]: continue - add_devices([NetatmoCamera(data, camera_name, home, camera_type)]) + add_devices([NetatmoCamera(data, camera_name, home, + camera_type, verify_ssl)]) except lnetatmo.NoDevice: return None @@ -50,11 +54,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class NetatmoCamera(Camera): """Representation of the images published from a Netatmo camera.""" - def __init__(self, data, camera_name, home, camera_type): + def __init__(self, data, camera_name, home, camera_type, verify_ssl): """Setup for access to the Netatmo camera images.""" super(NetatmoCamera, self).__init__() self._data = data self._camera_name = camera_name + self._verify_ssl = verify_ssl if home: self._name = home + ' / ' + camera_name else: @@ -74,11 +79,17 @@ class NetatmoCamera(Camera): if self._localurl: response = requests.get('{0}/live/snapshot_720.jpg'.format( self._localurl), timeout=10) - else: + elif self._vpnurl: response = requests.get('{0}/live/snapshot_720.jpg'.format( - self._vpnurl), timeout=10) + self._vpnurl), timeout=10, verify=self._verify_ssl) + else: + _LOGGER.error('Welcome VPN url is None') + self._data.update() + (self._vpnurl, self._localurl) = \ + self._data.camera_data.cameraUrls(camera=self._camera_name) + return None except requests.exceptions.RequestException as error: - _LOGGER.error('Welcome VPN url changed: %s', error) + _LOGGER.error('Welcome url changed: %s', error) self._data.update() (self._vpnurl, self._localurl) = \ self._data.camera_data.cameraUrls(camera=self._camera_name) From bdc62730bd88232af70a9ac96d4ffc9476e83efb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 1 Feb 2017 09:03:35 -0800 Subject: [PATCH 042/157] Update frontend (#5696) --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 137556 -> 137597 bytes .../www_static/home-assistant-polymer | 2 +- .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2337 -> 2336 bytes 6 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 346da2ea983..011929dfff9 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,7 +2,7 @@ FINGERPRINTS = { "core.js": "adfeb513cf650acf763e284d76a48d6b", - "frontend.html": "1a6d8876f001c1e83d814b5605ab1e7b", + "frontend.html": "b4cbcaea0e190d802b23328f89c2df61", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index a69eadd28c3..8346cf2bfa0 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -600,4 +600,4 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th this.hass.callService('media_player', service, serviceData); }, }); -}()); \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index f0cbc9b47867988c8f06e2082fce6687ece33722..26084735b403a470418f3bc1e8c52b51ef852b1d 100644 GIT binary patch delta 24957 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 M2jWcg;H!-Y04*TprT_o{ delta 25004 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 G6aWB_5`o?T literal 2337 zcmV++3EuV}iwFowpOIJs19N3^c4=c}Uw3bEYh`jSYI6XkSow3?xE20a6i!zmYl(1E$q%mAgX2MBLXj#7*>P?E?|mR8S+cBTcRG_q3`o4=d&l zHBBLnGtsL`nxd`-Etq%u1($PBpPRCE!Mka|teR>7!8f>WT`w?msNBtly$=?A`S^=f zQ{H)Z$G28+HTVbySMal~Emds_T}W>K^YRiZ^MaS9;PRUbzVU8!(ZKsvJKwI}@NVC! z3Hk?Lal`R{yK(}%<{LhHxQGYlW z3exoG^{>33glcBy!{PcbDo@k8BoW~uR#S5UTN1(zeRF&`z8MKlZrl{$$j z&m*bhD9@5Gg&3t|9SW$22$3>L6{;aI4Kp4kNytMfIn6~(ljC}dO4p+>PV+E|RUWG} z%0kXk7AhSHh-1NXl5W({B+rv9k43`sFjoo51TYeD73(+!&W@{Tp}8z1jB=gDc}f#V z2;;HjS)LR0M<~!rkdWUyBr^gcOQTR`A|pA|Di&Fur79JY&>v_r+yHt+bRyC;)EOt5 zXEB2~(=twFC=|lE(WApqB95{361`O^k?1=_R41I%SRL16V6iN%syx$KCemDU&`c)i zjSTaclAJ`061i2C@R-Gnlbi}3b5IzTTnGvwgbAi_`nW1=E2CU8ndK42g6WKsBn@S* z<1nX;Vp>Jp@GuTB%i=VOR74eqN?{N=6QS0eDHiq`EI@@E%esLPR~ke@FuhXD7pb$9 zLd0T~rD!Z79eiyqNQuVG(nM!T3@ju%$86+^5>BPeqi9d=#(@#xsbVZk5n>_fu80Uz`ZH0li`m?)Wo07Kf-z07z9d3I5g>>#;b{~_B#M6~ z>kX)4wO9+&Kq$l{3$a9Gq-DY|kcck2s{m#HOxOpQtxDdkrEy6$R-{UV;5s3Bsxed; zE~bECM$27kh3(s8%`ff4h~&|C{2MH*nGGq)^N^EX!+XF2rnY4c2kQ2)1Hu z#EGJm@idOml$?f;63%y}U4fAGVp&(%ecMr47$o+h>dS!Tlu*ol3{t8T@C?J1gqjg7 z2FXLj`rPk0;4NRk)M>9q8&ViuMx&8);_xB;mwlNxkxJZ(SL*$h2~PGTlBtbB2zE;RGsKEBO53)r(DFT;rWM zQ|GZa-1B_7XKvBHM_<0oF_a~u4C(y3R9PWFK_-WHR|cC>5j1w1y= z@wIQ=bl}@*Vfm^HrrL|k*l59@eoUUeMzFVq8SZJ3fD|znMCA2-QW2njibn z1UPau*Y~f?=G7DIT+rfxdKR90-6(rh*VnqJHmdq(H0?qD%y~QSFzCzVVy8|VABW}k zQ@u&9wnO6$YTF;L4h*o+nW;6<=lDa;{pvn)eph5=-4A-0AJhF5cB_4xFpHm%4fZy?gKP~OJ1%3k1-D-$h#`QFe41Mg0|sAA6*OM z2l&s*W&rnZ5ITik7rbmwofhpM;kZ02aCF8OT^~AibX}J9m4i@qe-6$*J02pC?YCn2 z1u^Q=!*1}80Blb-ml(Kxg!|ZUPEki)p8Ow?ICA{skK)gN1g<>|?f~4Ma`2l!0+cKZ z%S!mmi^Wf%>JCi%IH48J-(P-mx@On(5e@o7(;7sqouj?Vz2Ac_{D_;piJ3l(LZ4V& zORc6@C`eQNls0*SXT8c&&h&uDT+1f@F=4$lIYlDtgvjC0sc?#z*#z155lLb=Jm3NM z%=z7QpFMGV>c7Ra<*jWJU z@K1x}yAva{fk9%bjey0lf;RPNIk^{Q0W zzn_|cMH}vQ=o-)4zqHQ4cCg-p)4?zAp6;WKe7U|9*e-Vkal9gyt9JfKZA* zkM-R}YfI1H?H7-XY4iH(?aoDsizHc?(h~V0%!ju%-EE75*$%}eC}({sWA9=X7v Date: Wed, 1 Feb 2017 19:47:18 +0100 Subject: [PATCH 043/157] up rfxtrx lib (#5687) --- homeassistant/components/rfxtrx.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rfxtrx.py b/homeassistant/components/rfxtrx.py index 6918a596988..a208bfcfaa4 100644 --- a/homeassistant/components/rfxtrx.py +++ b/homeassistant/components/rfxtrx.py @@ -14,7 +14,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.helpers.entity import Entity from homeassistant.const import (ATTR_ENTITY_ID, TEMP_CELSIUS) -REQUIREMENTS = ['pyRFXtrx==0.15.0'] +REQUIREMENTS = ['pyRFXtrx==0.16.0'] DOMAIN = "rfxtrx" diff --git a/requirements_all.txt b/requirements_all.txt index bdf099aece6..206b2a9a525 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -396,7 +396,7 @@ pyCEC==0.4.12 pyHS100==0.2.3 # homeassistant.components.rfxtrx -pyRFXtrx==0.15.0 +pyRFXtrx==0.16.0 # homeassistant.components.notify.xmpp pyasn1-modules==0.0.8 From b5b1d72ab6d6d7ef782b62ceb886861826e4a2fb Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 1 Feb 2017 23:55:16 +0100 Subject: [PATCH 044/157] Fix bug for UNREACH devices / Variable handling and update. (#5689) * Fix bug for UNREACH devices / Variable handling and update. * fix track_time * update after data after creation * add message output * change unreach * change unreach code * Revert "change unreach code" This reverts commit f58430de3cb854d5f6f886bfe4d59899c1efadbf. * update pyhomematic --- homeassistant/components/homematic.py | 201 ++++++++++--------------- homeassistant/components/services.yaml | 8 +- requirements_all.txt | 2 +- 3 files changed, 88 insertions(+), 123 deletions(-) diff --git a/homeassistant/components/homematic.py b/homeassistant/components/homematic.py index 9b38bb0efea..ce1df98d727 100644 --- a/homeassistant/components/homematic.py +++ b/homeassistant/components/homematic.py @@ -16,17 +16,16 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import ( EVENT_HOMEASSISTANT_STOP, STATE_UNKNOWN, CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM, CONF_HOSTS, CONF_NAME, ATTR_ENTITY_ID) -from homeassistant.helpers.entity import Entity -from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers import discovery +from homeassistant.helpers.entity import Entity +from homeassistant.helpers.event import track_time_interval from homeassistant.config import load_yaml_config_file -from homeassistant.util import Throttle DOMAIN = 'homematic' -REQUIREMENTS = ["pyhomematic==0.1.20"] +REQUIREMENTS = ["pyhomematic==0.1.21"] -MIN_TIME_BETWEEN_UPDATE_HUB = timedelta(seconds=300) -SCAN_INTERVAL = timedelta(seconds=30) +SCAN_INTERVAL_HUB = timedelta(seconds=300) +SCAN_INTERVAL_VARIABLES = timedelta(seconds=30) DISCOVER_SWITCHES = 'homematic.switch' DISCOVER_LIGHTS = 'homematic.light' @@ -176,8 +175,9 @@ SCHEMA_SERVICE_VIRTUALKEY = vol.Schema({ }) SCHEMA_SERVICE_SET_VAR_VALUE = vol.Schema({ - vol.Required(ATTR_ENTITY_ID): cv.entity_ids, + vol.Required(ATTR_NAME): cv.string, vol.Required(ATTR_VALUE): cv.match_all, + vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, }) SCHEMA_SERVICE_SET_DEV_VALUE = vol.Schema({ @@ -236,8 +236,6 @@ def setup(hass, config): """Setup the Homematic component.""" from pyhomematic import HMConnection - component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) - hass.data[DATA_DELAY] = config[DOMAIN].get(CONF_DELAY) hass.data[DATA_DEVINIT] = {} hass.data[DATA_STORE] = [] @@ -281,11 +279,10 @@ def setup(hass, config): hass.config.components.append(DOMAIN) # init homematic hubs - hub_entities = [] + entity_hubs = [] for _, hub_data in hosts.items(): - hub_entities.append(HMHub(hass, component, hub_data[CONF_NAME], - hub_data[CONF_VARIABLES])) - component.add_entities(hub_entities) + entity_hubs.append(HMHub( + hass, hub_data[CONF_NAME], hub_data[CONF_VARIABLES])) # regeister homematic services descriptions = load_yaml_config_file( @@ -323,14 +320,23 @@ def setup(hass, config): schema=SCHEMA_SERVICE_VIRTUALKEY) def _service_handle_value(service): - """Set value on homematic variable object.""" - variable_list = component.extract_from_service(service) - + """Set value on homematic variable.""" + entity_ids = service.data.get(ATTR_ENTITY_ID) + name = service.data[ATTR_NAME] value = service.data[ATTR_VALUE] - for hm_variable in variable_list: - if isinstance(hm_variable, HMVariable): - hm_variable.hm_set(value) + if entity_ids: + entities = [entity for entity in entity_hubs if + entity.entity_id in entity_ids] + else: + entities = entity_hubs + + if not entities: + _LOGGER.error("Homematic controller not found!") + return + + for hub in entities: + hub.hm_set_variable(name, value) hass.services.register( DOMAIN, SERVICE_SET_VAR_VALUE, _service_handle_value, @@ -579,132 +585,87 @@ def _device_from_servicecall(hass, service): class HMHub(Entity): """The Homematic hub. I.e. CCU2/HomeGear.""" - def __init__(self, hass, component, name, use_variables): + def __init__(self, hass, name, use_variables): """Initialize Homematic hub.""" self.hass = hass + self.entity_id = "{}.{}".format(DOMAIN, name.lower()) self._homematic = hass.data[DATA_HOMEMATIC] - self._component = component + self._variables = {} self._name = name self._state = STATE_UNKNOWN - self._store = {} self._use_variables = use_variables # load data - self._update_hub_state() - self._init_variables() + track_time_interval(hass, self._update_hub, SCAN_INTERVAL_HUB) + self._update_hub(None) + + if self._use_variables: + track_time_interval( + hass, self._update_variables, SCAN_INTERVAL_VARIABLES) + self._update_variables(None) @property def name(self): """Return the name of the device.""" return self._name - @property - def state(self): - """Return the state of the entity.""" - return self._state - - @property - def device_state_attributes(self): - """Return device specific state attributes.""" - return {} - - @property - def icon(self): - """Return the icon to use in the frontend, if any.""" - return "mdi:gradient" - - def update(self): - """Update Hub data and all HM variables.""" - self._update_hub_state() - self._update_variables_state() - - @Throttle(MIN_TIME_BETWEEN_UPDATE_HUB) - def _update_hub_state(self): - """Retrieve latest state.""" - state = self._homematic.getServiceMessages(self._name) - self._state = STATE_UNKNOWN if state is None else len(state) - - def _update_variables_state(self): - """Retrive all variable data and update hmvariable states.""" - if not self._use_variables: - return - - variables = self._homematic.getAllSystemVariables(self._name) - if variables is None: - return - - for key, value in variables.items(): - if key in self._store: - self._store.get(key).hm_update(value) - - def _init_variables(self): - """Load variables from hub.""" - if not self._use_variables: - return - - variables = self._homematic.getAllSystemVariables(self._name) - if variables is None: - return - - entities = [] - for key, value in variables.items(): - entities.append(HMVariable(self.hass, self._name, key, value)) - self._component.add_entities(entities) - - -class HMVariable(Entity): - """The Homematic system variable.""" - - def __init__(self, hass, hub_name, name, state): - """Initialize Homematic hub.""" - self.hass = hass - self._homematic = hass.data[DATA_HOMEMATIC] - self._state = state - self._name = name - self._hub_name = hub_name - - @property - def name(self): - """Return the name of the device.""" - return self._name - - @property - def state(self): - """Return the state of the entity.""" - return self._state - - @property - def icon(self): - """Return the icon to use in the frontend, if any.""" - return "mdi:code-string" - @property def should_poll(self): """Return false. Homematic Hub object update variable.""" return False @property - def device_state_attributes(self): - """Return device specific state attributes.""" - attr = { - 'hub': self._hub_name, - } + def state(self): + """Return the state of the entity.""" + return self._state + + @property + def state_attributes(self): + """Return the state attributes.""" + attr = self._variables.copy() return attr - def hm_update(self, value): - """Update variable over Hub object.""" - if value != self._state: - self._state = value + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + return "mdi:gradient" + + def _update_hub(self, now): + """Retrieve latest state.""" + state = self._homematic.getServiceMessages(self._name) + self._state = STATE_UNKNOWN if state is None else len(state) + self.schedule_update_ha_state() + + def _update_variables(self, now): + """Retrive all variable data and update hmvariable states.""" + variables = self._homematic.getAllSystemVariables(self._name) + if variables is None: + return + + state_change = False + for key, value in variables.items(): + if key in self._variables and value == self._variables[key]: + continue + + state_change = True + self._variables.update({key: value}) + + if state_change: self.schedule_update_ha_state() - def hm_set(self, value): + def hm_set_variable(self, name, value): """Set variable on homematic controller.""" - if isinstance(self._state, bool): + if name not in self._variables: + _LOGGER.error("Variable %s not found on %s", name, self.name) + return + old_value = self._variables.get(name) + if isinstance(old_value, bool): value = cv.boolean(value) else: value = float(value) - self._homematic.setSystemVariable(self._hub_name, self._name, value) - self._state = value + self._homematic.setSystemVariable(self.name, name, value) + + self._variables.update({name: value}) self.schedule_update_ha_state() @@ -817,7 +778,7 @@ class HMDevice(Entity): have_change = True # If available it has changed - if attribute is 'UNREACH': + if attribute == 'UNREACH': self._available = bool(value) have_change = True @@ -829,7 +790,7 @@ class HMDevice(Entity): def _subscribe_homematic_events(self): """Subscribe all required events to handle job.""" - channels_to_sub = {} + channels_to_sub = {0: True} # add channel 0 for UNREACH # Push data to channels_to_sub from hmdevice metadata for metadata in (self._hmdevice.SENSORNODE, self._hmdevice.BINARYNODE, @@ -856,7 +817,7 @@ class HMDevice(Entity): # Set callbacks for channel in channels_to_sub: _LOGGER.debug( - "Subscribe channel %s from %s", str(channel), self._name) + "Subscribe channel %d from %s", channel, self._name) self._hmdevice.setEventCallback( callback=self._hm_event_callback, bequeath=False, channel=channel) diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index 45cc36e90be..c6057dcd2a8 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -99,8 +99,12 @@ homematic: fields: entity_id: - description: Name(s) of entities to set value - example: 'homematic.my_variable' + description: Name(s) of homematic central to set value + example: 'homematic.ccu2' + + name: + description: Name of the varaible to set + example: 'testvariable' value: description: New value diff --git a/requirements_all.txt b/requirements_all.txt index 206b2a9a525..055e0a4292c 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -444,7 +444,7 @@ pyharmony==1.0.12 pyhik==0.0.7 # homeassistant.components.homematic -pyhomematic==0.1.20 +pyhomematic==0.1.21 # homeassistant.components.device_tracker.icloud pyicloud==0.9.1 From b2180fba6395336e3ad3bd962686c641658cc842 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 2 Feb 2017 00:02:24 +0100 Subject: [PATCH 045/157] Bugfix sonso source input (#5699) --- homeassistant/components/media_player/sonos.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 14b32260ca0..0bb34eee598 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -523,10 +523,6 @@ class SonosDevice(MediaPlayerDevice): update_media_position |= rel_time is not None and \ self._media_position is None - # used only if a media is playing - if self.state != STATE_PLAYING: - update_media_position = None - # position changed? if rel_time is not None and \ self._media_position is not None: @@ -541,7 +537,7 @@ class SonosDevice(MediaPlayerDevice): update_media_position = \ abs(calculated_position - rel_time) > 1.5 - if update_media_position: + if update_media_position and self.state == STATE_PLAYING: media_position = rel_time media_position_updated_at = utcnow() else: @@ -830,7 +826,7 @@ class SonosDevice(MediaPlayerDevice): """List of available input sources.""" model_name = self._speaker_info['model_name'] - sources = self._favorite_sources + sources = self._favorite_sources.copy() if 'PLAY:5' in model_name: sources += [SUPPORT_SOURCE_LINEIN] From 68d6bcd3edd0eaf20b081fbf154de2942b85ac45 Mon Sep 17 00:00:00 2001 From: John Arild Berentsen Date: Thu, 2 Feb 2017 05:57:57 +0100 Subject: [PATCH 046/157] [lock.zwave] Bugfix Zwave lock (#5619) * Bugfix state * remove debug --- homeassistant/components/lock/zwave.py | 74 +++++++++++++++++--------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/lock/zwave.py b/homeassistant/components/lock/zwave.py index 6ff628f158f..1f5f2ca8b15 100644 --- a/homeassistant/components/lock/zwave.py +++ b/homeassistant/components/lock/zwave.py @@ -21,11 +21,21 @@ ATTR_NOTIFICATION = 'notification' ATTR_LOCK_STATUS = 'lock_status' ATTR_CODE_SLOT = 'code_slot' ATTR_USERCODE = 'usercode' +CONFIG_ADVANCED = 'Advanced' SERVICE_SET_USERCODE = 'set_usercode' SERVICE_GET_USERCODE = 'get_usercode' SERVICE_CLEAR_USERCODE = 'clear_usercode' +POLYCONTROL = 0x10E +DANALOCK_V2_BTZE = 0x2 +POLYCONTROL_DANALOCK_V2_BTZE_LOCK = (POLYCONTROL, DANALOCK_V2_BTZE) +WORKAROUND_V2BTZE = 'v2btze' + +DEVICE_MAPPINGS = { + POLYCONTROL_DANALOCK_V2_BTZE_LOCK: WORKAROUND_V2BTZE +} + LOCK_NOTIFICATION = { 1: 'Manual Lock', 2: 'Manual Unlock', @@ -110,7 +120,7 @@ CLEAR_USERCODE_SCHEMA = vol.Schema({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): - """Find and return Z-Wave switches.""" + """Find and return Z-Wave locks.""" if discovery_info is None or zwave.NETWORK is None: return @@ -197,29 +207,61 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice): - """Representation of a Z-Wave switch.""" + """Representation of a Z-Wave Lock.""" def __init__(self, value): - """Initialize the Z-Wave switch device.""" + """Initialize the Z-Wave lock device.""" zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN) - self._node = value.node self._state = None self._notification = None self._lock_status = None + self._v2btze = None + + # Enable appropriate workaround flags for our device + # Make sure that we have values for the key before converting to int + if (value.node.manufacturer_id.strip() and + value.node.product_id.strip()): + specific_sensor_key = (int(value.node.manufacturer_id, 16), + int(value.node.product_id, 16)) + if specific_sensor_key in DEVICE_MAPPINGS: + if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_V2BTZE: + self._v2btze = 1 + _LOGGER.debug("Polycontrol Danalock v2 BTZE " + "workaround enabled") self.update_properties() def update_properties(self): """Callback on data changes for node values.""" + for value in self._node.get_values( + class_id=zwave.const.COMMAND_CLASS_DOOR_LOCK).values(): + if value.type != zwave.const.TYPE_BOOL: + continue + if value.genre != zwave.const.GENRE_USER: + continue + self._state = value.data + _LOGGER.debug('Lock state set from Bool value and' + ' is %s', value.data) + break + for value in self._node.get_values( class_id=zwave.const.COMMAND_CLASS_ALARM).values(): if value.label != "Access Control": continue self._notification = LOCK_NOTIFICATION.get(value.data) - if self._notification: - self._state = LOCK_STATUS.get(value.data) - _LOGGER.debug('Lock state set from Access Control value and' - ' is %s', value.data) + notification_data = value.data + if self._v2btze: + for value in (self._node.get_values( + class_id=zwave.const.COMMAND_CLASS_CONFIGURATION) + .values()): + if value.index != 12: + continue + if value.data == CONFIG_ADVANCED: + self._state = LOCK_STATUS.get(notification_data) + _LOGGER.debug('Lock state set from Access Control ' + 'value and is %s', notification_data) + break + break for value in self._node.get_values( @@ -227,10 +269,6 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice): if value.label != "Alarm Type": continue alarm_type = LOCK_ALARM_TYPE.get(value.data) - if alarm_type: - self._state = LOCK_STATUS.get(value.data) - _LOGGER.debug('Lock state set from Alarm Type value and' - ' is %s', value.data) break for value in self._node.get_values( @@ -256,18 +294,6 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice): self._lock_status = LOCK_ALARM_TYPE.get(alarm_type) break - if not self._notification and not self._lock_status: - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_DOOR_LOCK).values(): - if value.type != zwave.const.TYPE_BOOL: - continue - if value.genre != zwave.const.GENRE_USER: - continue - self._state = value.data - _LOGGER.debug('Lock state set from Bool value and' - ' is %s', value.data) - break - @property def is_locked(self): """Return true if device is locked.""" From ae1f59970dc7873887f0a6a28c7cf1fced29949f Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Thu, 2 Feb 2017 06:00:05 +0100 Subject: [PATCH 047/157] Prevent infinite loop in crossconfigured mqtt event streams (#5624) * Prevent events about MQTT messages received to cause infinite loop when two HA instances are crossconfigured for mqtt_eventstream. * Fix linting * Publish all MQTT received events except incoming from eventstream. Also make it configurable. --- homeassistant/components/mqtt_eventstream.py | 14 +++++++ tests/components/test_mqtt_eventstream.py | 43 ++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/homeassistant/components/mqtt_eventstream.py b/homeassistant/components/mqtt_eventstream.py index 293b644da1f..8632f8aa99d 100644 --- a/homeassistant/components/mqtt_eventstream.py +++ b/homeassistant/components/mqtt_eventstream.py @@ -15,18 +15,23 @@ from homeassistant.const import ( ATTR_SERVICE_DATA, EVENT_CALL_SERVICE, EVENT_SERVICE_EXECUTED, EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL) from homeassistant.core import EventOrigin, State +import homeassistant.helpers.config_validation as cv from homeassistant.remote import JSONEncoder +from .mqtt import EVENT_MQTT_MESSAGE_RECEIVED DOMAIN = "mqtt_eventstream" DEPENDENCIES = ['mqtt'] CONF_PUBLISH_TOPIC = 'publish_topic' CONF_SUBSCRIBE_TOPIC = 'subscribe_topic' +CONF_PUBLISH_EVENTSTREAM_RECEIVED = 'publish_eventstream_received' CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Optional(CONF_PUBLISH_TOPIC): valid_publish_topic, vol.Optional(CONF_SUBSCRIBE_TOPIC): valid_subscribe_topic, + vol.Optional(CONF_PUBLISH_EVENTSTREAM_RECEIVED, default=False): + cv.boolean, }), }, extra=vol.ALLOW_EXTRA) @@ -45,6 +50,15 @@ def setup(hass, config): if event.event_type == EVENT_TIME_CHANGED: return + # MQTT fires a bus event for every incoming message, also messages from + # eventstream. Disable publishing these messages to other HA instances + # and possibly creating an infinite loop if these instances publish + # back to this one. + if all([not conf.get(CONF_PUBLISH_EVENTSTREAM_RECEIVED), + event.event_type == EVENT_MQTT_MESSAGE_RECEIVED, + event.data.get('topic') == sub_topic]): + return + # Filter out the events that were triggered by publishing # to the MQTT topic, or you will end up in an infinite loop. if event.event_type == EVENT_CALL_SERVICE: diff --git a/tests/components/test_mqtt_eventstream.py b/tests/components/test_mqtt_eventstream.py index a60e54df016..3dbe6338e3f 100644 --- a/tests/components/test_mqtt_eventstream.py +++ b/tests/components/test_mqtt_eventstream.py @@ -1,10 +1,12 @@ """The tests for the MQTT eventstream component.""" +from collections import namedtuple import json import unittest from unittest.mock import ANY, patch from homeassistant.bootstrap import setup_component import homeassistant.components.mqtt_eventstream as eventstream +import homeassistant.components.mqtt as mqtt from homeassistant.const import EVENT_STATE_CHANGED from homeassistant.core import State, callback from homeassistant.remote import JSONEncoder @@ -146,3 +148,44 @@ class TestMqttEventStream(unittest.TestCase): self.hass.block_till_done() self.assertEqual(1, len(calls)) + + @patch('homeassistant.components.mqtt.publish') + def test_mqtt_received_event(self, mock_pub): + """Don't filter events from the mqtt component about received message. + + Mqtt component sends an event if a message is received. Also + messages that originate from an incoming eventstream. + Broadcasting these messages result in an infinite loop if two HA + instances are crossconfigured for the same mqtt topics. + + """ + SUB_TOPIC = 'from_slaves' + self.assertTrue( + self.add_eventstream( + pub_topic='bar', + sub_topic=SUB_TOPIC)) + self.hass.block_till_done() + + # Reset the mock because it will have already gotten calls for the + # mqtt_eventstream state change on initialization, etc. + mock_pub.reset_mock() + + # Use MQTT component message handler to simulate firing message + # received event. + MQTTMessage = namedtuple('MQTTMessage', ['topic', 'qos', 'payload']) + message = MQTTMessage(SUB_TOPIC, 1, 'Hello World!'.encode('utf-8')) + mqtt.MQTT._mqtt_on_message(self, None, {'hass': self.hass}, message) + + self.hass.block_till_done() + + # 'normal' incoming mqtt messages should be broadcasted + self.assertEqual(mock_pub.call_count, 0) + + MQTTMessage = namedtuple('MQTTMessage', ['topic', 'qos', 'payload']) + message = MQTTMessage('test_topic', 1, 'Hello World!'.encode('utf-8')) + mqtt.MQTT._mqtt_on_message(self, None, {'hass': self.hass}, message) + + self.hass.block_till_done() + + # but event from the event stream not + self.assertEqual(mock_pub.call_count, 1) From 2fcaf8bda61ebe77995dbebe4c2b084b7d1875ad Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Thu, 2 Feb 2017 07:01:06 +0200 Subject: [PATCH 048/157] [sensor/sma] handle units correctly (#5657) --- homeassistant/components/sensor/sma.py | 27 +++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/sensor/sma.py b/homeassistant/components/sensor/sma.py index fc074a8defe..dae9b64cff7 100644 --- a/homeassistant/components/sensor/sma.py +++ b/homeassistant/components/sensor/sma.py @@ -54,7 +54,8 @@ PLATFORM_SCHEMA = vol.All(PLATFORM_SCHEMA.extend({ vol.Optional(CONF_CUSTOM, default={}): vol.Schema({ cv.slug: { vol.Required('key'): vol.All(str, vol.Length(min=13, max=13)), - vol.Required('unit'): str + vol.Required('unit'): str, + vol.Optional('factor', default=1): vol.Coerce(float), }}) }, extra=vol.PREVENT_EXTRA), _check_sensor_schema) @@ -63,16 +64,18 @@ def async_setup_platform(hass, config, add_devices, discovery_info=None): """Set up SMA WebConnect sensor.""" import pysma - # Combine sensor_defs from the library and custom config + # sensor_defs from the library sensor_defs = dict(zip(SENSOR_OPTIONS, [ - (pysma.KEY_CURRENT_CONSUMPTION_W, 'W'), - (pysma.KEY_CURRENT_POWER_W, 'W'), - (pysma.KEY_TOTAL_CONSUMPTION_KWH, 'kW/h'), - (pysma.KEY_TOTAL_YIELD_KWH, 'kW/h')])) + (pysma.KEY_CURRENT_CONSUMPTION_W, 'W', 1), + (pysma.KEY_CURRENT_POWER_W, 'W', 1), + (pysma.KEY_TOTAL_CONSUMPTION_KWH, 'kW/h', 1000), + (pysma.KEY_TOTAL_YIELD_KWH, 'kW/h', 1000)])) + + # sensor_defs from the custom config for name, prop in config[CONF_CUSTOM].items(): if name in sensor_defs: _LOGGER.warning("Custom sensor %s replace built-in sensor", name) - sensor_defs[name] = (prop['key'], prop['unit']) + sensor_defs[name] = (prop['key'], prop['unit'], prop['factor']) # Prepare all HASS sensor entities hass_sensors = [] @@ -121,7 +124,9 @@ def async_setup_platform(hass, config, add_devices, discovery_info=None): if values is None: backoff = 3 return + values = [0 if val is None else val for val in values] res = dict(zip(names_to_query, values)) + res = {key: val // sensor_defs[key][2] for key, val in res.items()} _LOGGER.debug("Update sensors %s %s %s", keys_to_query, values, res) tasks = [] for sensor in hass_sensors: @@ -141,7 +146,7 @@ class SMAsensor(Entity): def __init__(self, sensor_name, attr, sensor_defs): """Initialize the sensor.""" self._name = sensor_name - self._key, self._unit_of_measurement = sensor_defs[sensor_name] + self._key, self._unit_of_measurement, _ = sensor_defs[sensor_name] self._state = None self._sensor_defs = sensor_defs self._attr = {att: "" for att in attr} @@ -176,10 +181,10 @@ class SMAsensor(Entity): update = False for key, val in self._attr.items(): - if val.partition(' ')[0] != key_values[key]: + newval = '{} {}'.format(key_values[key], self._sensor_defs[key][1]) + if val != newval: update = True - self._attr[key] = '{} {}'.format(key_values[key], - self._sensor_defs[key][1]) + self._attr[key] = newval new_state = key_values[self._name] if new_state != self._state: From 647a93801ce4a098b50f3b36eca39bf3044cc164 Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 1 Feb 2017 23:06:11 -0600 Subject: [PATCH 049/157] Fix hue lightgroups not syncing state (#5702) --- homeassistant/components/light/hue.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index a934788f36b..65ae9f30cf4 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -200,7 +200,8 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable, for light_id, info in api_lights.items(): if light_id not in lights: - lights[light_id] = HueLight(int(light_id), info, + lights[light_id] = HueLight(hass, + int(light_id), info, bridge, update_lights, bridge_type, allow_unreachable, allow_in_emulated_hue) @@ -218,6 +219,7 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable, if lightgroup_id not in lightgroups: lightgroups[lightgroup_id] = HueLight( + hass, int(lightgroup_id), info, bridge, update_lights, bridge_type, allow_unreachable, allow_in_emulated_hue, True) @@ -280,10 +282,11 @@ def request_configuration(host, hass, add_devices, filename, class HueLight(Light): """Representation of a Hue light.""" - def __init__(self, light_id, info, bridge, update_lights, + def __init__(self, hass, light_id, info, bridge, update_lights, bridge_type, allow_unreachable, allow_in_emulated_hue, is_group=False): """Initialize the light.""" + self.hass = hass self.light_id = light_id self.info = info self.bridge = bridge From 10a104271eb9f1282141bfed5e85c841f744ad21 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 2 Feb 2017 06:44:05 +0100 Subject: [PATCH 050/157] Cleanup climate platform for async update_ha_state / migrate generic thermostat (#5679) * Cleanup climate from blocking stuff / migrate generic * Migrate generic thermostat * fix tests * fix lint --- homeassistant/components/climate/demo.py | 20 +++---- homeassistant/components/climate/ecobee.py | 4 +- .../components/climate/generic_thermostat.py | 58 +++++++++++-------- homeassistant/components/climate/mysensors.py | 6 +- homeassistant/components/climate/netatmo.py | 3 - homeassistant/components/climate/zwave.py | 4 +- homeassistant/components/switch/__init__.py | 26 ++++++++- homeassistant/helpers/condition.py | 7 ++- 8 files changed, 79 insertions(+), 49 deletions(-) diff --git a/homeassistant/components/climate/demo.py b/homeassistant/components/climate/demo.py index a66873cbc63..9830daff69c 100644 --- a/homeassistant/components/climate/demo.py +++ b/homeassistant/components/climate/demo.py @@ -135,27 +135,27 @@ class DemoClimate(ClimateDevice): kwargs.get(ATTR_TARGET_TEMP_LOW) is not None: self._target_temperature_high = kwargs.get(ATTR_TARGET_TEMP_HIGH) self._target_temperature_low = kwargs.get(ATTR_TARGET_TEMP_LOW) - self.update_ha_state() + self.schedule_update_ha_state() def set_humidity(self, humidity): """Set new target temperature.""" self._target_humidity = humidity - self.update_ha_state() + self.schedule_update_ha_state() def set_swing_mode(self, swing_mode): """Set new target temperature.""" self._current_swing_mode = swing_mode - self.update_ha_state() + self.schedule_update_ha_state() def set_fan_mode(self, fan): """Set new target temperature.""" self._current_fan_mode = fan - self.update_ha_state() + self.schedule_update_ha_state() def set_operation_mode(self, operation_mode): """Set new target temperature.""" self._current_operation = operation_mode - self.update_ha_state() + self.schedule_update_ha_state() @property def current_swing_mode(self): @@ -170,24 +170,24 @@ class DemoClimate(ClimateDevice): def turn_away_mode_on(self): """Turn away mode on.""" self._away = True - self.update_ha_state() + self.schedule_update_ha_state() def turn_away_mode_off(self): """Turn away mode off.""" self._away = False - self.update_ha_state() + self.schedule_update_ha_state() def set_hold_mode(self, hold): """Update hold mode on.""" self._hold = hold - self.update_ha_state() + self.schedule_update_ha_state() def turn_aux_heat_on(self): """Turn away auxillary heater on.""" self._aux = True - self.update_ha_state() + self.schedule_update_ha_state() def turn_aux_heat_off(self): """Turn auxillary heater off.""" self._aux = False - self.update_ha_state() + self.schedule_update_ha_state() diff --git a/homeassistant/components/climate/ecobee.py b/homeassistant/components/climate/ecobee.py index dcee6d9ce31..8f5e7f5bba5 100644 --- a/homeassistant/components/climate/ecobee.py +++ b/homeassistant/components/climate/ecobee.py @@ -69,7 +69,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for thermostat in target_thermostats: thermostat.set_fan_min_on_time(str(fan_min_on_time)) - thermostat.update_ha_state(True) + thermostat.schedule_update_ha_state(True) def resume_program_set_service(service): """Resume the program on the target thermostats.""" @@ -85,7 +85,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for thermostat in target_thermostats: thermostat.resume_program(resume_all) - thermostat.update_ha_state(True) + thermostat.schedule_update_ha_state(True) descriptions = load_yaml_config_file( path.join(path.dirname(__file__), 'services.yaml')) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 562847567a3..da746270197 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -4,17 +4,19 @@ Adds support for generic thermostat units. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/climate.generic_thermostat/ """ +import asyncio import logging import voluptuous as vol +from homeassistant.core import callback from homeassistant.components import switch from homeassistant.components.climate import ( STATE_HEAT, STATE_COOL, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA) from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF, ATTR_TEMPERATURE) from homeassistant.helpers import condition -from homeassistant.helpers.event import track_state_change +from homeassistant.helpers.event import async_track_state_change import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -48,7 +50,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -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 the generic thermostat.""" name = config.get(CONF_NAME) heater_entity_id = config.get(CONF_HEATER) @@ -60,7 +63,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): min_cycle_duration = config.get(CONF_MIN_DUR) tolerance = config.get(CONF_TOLERANCE) - add_devices([GenericThermostat( + yield from async_add_devices([GenericThermostat( hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp, ac_mode, min_cycle_duration, tolerance)]) @@ -86,12 +89,14 @@ class GenericThermostat(ClimateDevice): self._target_temp = target_temp self._unit = hass.config.units.temperature_unit - track_state_change(hass, sensor_entity_id, self._sensor_changed) - track_state_change(hass, heater_entity_id, self._switch_changed) + async_track_state_change( + hass, sensor_entity_id, self._async_sensor_changed) + async_track_state_change( + hass, heater_entity_id, self._async_switch_changed) sensor_state = hass.states.get(sensor_entity_id) if sensor_state: - self._update_temp(sensor_state) + self._async_update_temp(sensor_state) @property def should_poll(self): @@ -128,14 +133,15 @@ class GenericThermostat(ClimateDevice): """Return the temperature we try to reach.""" return self._target_temp - def set_temperature(self, **kwargs): + @asyncio.coroutine + def async_set_temperature(self, **kwargs): """Set new target temperature.""" temperature = kwargs.get(ATTR_TEMPERATURE) if temperature is None: return self._target_temp = temperature - self._control_heating() - self.schedule_update_ha_state() + self._async_control_heating() + yield from self.async_update_ha_state() @property def min_temp(self): @@ -157,22 +163,25 @@ class GenericThermostat(ClimateDevice): # Get default temp from super class return ClimateDevice.max_temp.fget(self) - def _sensor_changed(self, entity_id, old_state, new_state): + @asyncio.coroutine + def _async_sensor_changed(self, entity_id, old_state, new_state): """Called when temperature changes.""" if new_state is None: return - self._update_temp(new_state) - self._control_heating() - self.schedule_update_ha_state() + self._async_update_temp(new_state) + self._async_control_heating() + yield from self.async_update_ha_state() - def _switch_changed(self, entity_id, old_state, new_state): + @callback + def _async_switch_changed(self, entity_id, old_state, new_state): """Called when heater switch changes state.""" if new_state is None: return - self.schedule_update_ha_state() + self.hass.async_add_job(self.async_update_ha_state()) - def _update_temp(self, state): + @callback + def _async_update_temp(self, state): """Update thermostat with latest state from sensor.""" unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) @@ -182,7 +191,8 @@ class GenericThermostat(ClimateDevice): except ValueError as ex: _LOGGER.error('Unable to update from sensor: %s', ex) - def _control_heating(self): + @callback + def _async_control_heating(self): """Check if we need to turn heating on or off.""" if not self._active and None not in (self._cur_temp, self._target_temp): @@ -198,9 +208,9 @@ class GenericThermostat(ClimateDevice): current_state = STATE_ON else: current_state = STATE_OFF - long_enough = condition.state(self.hass, self.heater_entity_id, - current_state, - self.min_cycle_duration) + long_enough = condition.state( + self.hass, self.heater_entity_id, current_state, + self.min_cycle_duration) if not long_enough: return @@ -210,12 +220,12 @@ class GenericThermostat(ClimateDevice): too_cold = self._target_temp - self._cur_temp > self._tolerance if too_cold: _LOGGER.info('Turning off AC %s', self.heater_entity_id) - switch.turn_off(self.hass, self.heater_entity_id) + switch.async_turn_off(self.hass, self.heater_entity_id) else: too_hot = self._cur_temp - self._target_temp > self._tolerance if too_hot: _LOGGER.info('Turning on AC %s', self.heater_entity_id) - switch.turn_on(self.hass, self.heater_entity_id) + switch.async_turn_on(self.hass, self.heater_entity_id) else: is_heating = self._is_device_active if is_heating: @@ -223,12 +233,12 @@ class GenericThermostat(ClimateDevice): if too_hot: _LOGGER.info('Turning off heater %s', self.heater_entity_id) - switch.turn_off(self.hass, self.heater_entity_id) + switch.async_turn_off(self.hass, self.heater_entity_id) else: too_cold = self._target_temp - self._cur_temp > self._tolerance if too_cold: _LOGGER.info('Turning on heater %s', self.heater_entity_id) - switch.turn_on(self.hass, self.heater_entity_id) + switch.async_turn_on(self.hass, self.heater_entity_id) @property def _is_device_active(self): diff --git a/homeassistant/components/climate/mysensors.py b/homeassistant/components/climate/mysensors.py index 6c55b3b4451..02979e75f5f 100755 --- a/homeassistant/components/climate/mysensors.py +++ b/homeassistant/components/climate/mysensors.py @@ -135,7 +135,7 @@ class MySensorsHVAC(mysensors.MySensorsDeviceEntity, ClimateDevice): if self.gateway.optimistic: # optimistically assume that switch has changed state self._values[value_type] = value - self.update_ha_state() + self.schedule_update_ha_state() def set_fan_mode(self, fan): """Set new target temperature.""" @@ -145,7 +145,7 @@ class MySensorsHVAC(mysensors.MySensorsDeviceEntity, ClimateDevice): if self.gateway.optimistic: # optimistically assume that switch has changed state self._values[set_req.V_HVAC_SPEED] = fan - self.update_ha_state() + self.schedule_update_ha_state() def set_operation_mode(self, operation_mode): """Set new target temperature.""" @@ -156,7 +156,7 @@ class MySensorsHVAC(mysensors.MySensorsDeviceEntity, ClimateDevice): if self.gateway.optimistic: # optimistically assume that switch has changed state self._values[set_req.V_HVAC_FLOW_STATE] = operation_mode - self.update_ha_state() + self.schedule_update_ha_state() def update(self): """Update the controller with the latest value from a sensor.""" diff --git a/homeassistant/components/climate/netatmo.py b/homeassistant/components/climate/netatmo.py index 163054cd121..0afc8c29bd9 100755 --- a/homeassistant/components/climate/netatmo.py +++ b/homeassistant/components/climate/netatmo.py @@ -111,7 +111,6 @@ class NetatmoThermostat(ClimateDevice): temp = None self._data.thermostatdata.setthermpoint(mode, temp, endTimeOffset=None) self._away = True - self.update_ha_state() def turn_away_mode_off(self): """Turn away off.""" @@ -119,7 +118,6 @@ class NetatmoThermostat(ClimateDevice): temp = None self._data.thermostatdata.setthermpoint(mode, temp, endTimeOffset=None) self._away = False - self.update_ha_state() def set_temperature(self, endTimeOffset=DEFAULT_TIME_OFFSET, **kwargs): """Set new target temperature for 2 hours.""" @@ -131,7 +129,6 @@ class NetatmoThermostat(ClimateDevice): mode, temperature, endTimeOffset) self._target_temperature = temperature self._away = False - self.update_ha_state() @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): diff --git a/homeassistant/components/climate/zwave.py b/homeassistant/components/climate/zwave.py index fc2e8736ee9..76459d4997a 100755 --- a/homeassistant/components/climate/zwave.py +++ b/homeassistant/components/climate/zwave.py @@ -223,10 +223,10 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice): # ZXT-120 responds only to whole int value.data = round(temperature, 0) self._target_temperature = temperature - self.update_ha_state() + self.schedule_update_ha_state() else: value.data = temperature - self.update_ha_state() + self.schedule_update_ha_state() break def set_fan_mode(self, fan): diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index 56ad5ea8966..a5712fcbcbe 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -11,6 +11,7 @@ import os import voluptuous as vol +from homeassistant.core import callback from homeassistant.config import load_yaml_config_file from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import ToggleEntity @@ -20,6 +21,7 @@ from homeassistant.const import ( STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE, ATTR_ENTITY_ID) from homeassistant.components import group +from homeassistant.util.async import run_callback_threadsafe DOMAIN = 'switch' SCAN_INTERVAL = timedelta(seconds=30) @@ -47,21 +49,39 @@ _LOGGER = logging.getLogger(__name__) def is_on(hass, entity_id=None): - """Return if the switch is on based on the statemachine.""" + """Return if the switch is on based on the statemachine. + + Async friendly. + """ entity_id = entity_id or ENTITY_ID_ALL_SWITCHES return hass.states.is_state(entity_id, STATE_ON) def turn_on(hass, entity_id=None): + """Turn all or specified switch on.""" + run_callback_threadsafe( + hass.loop, async_turn_on, hass, entity_id).result() + + +@callback +def async_turn_on(hass, entity_id=None): """Turn all or specified switch on.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_TURN_ON, data) + hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data)) def turn_off(hass, entity_id=None): + """Turn all or specified switch off.""" + run_callback_threadsafe( + hass.loop, async_turn_off, hass, entity_id).result() + + +@callback +def async_turn_off(hass, entity_id=None): """Turn all or specified switch off.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) + hass.async_add_job( + hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data)) def toggle(hass, entity_id=None): diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index 781ef37dc9d..24af8a26351 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -199,7 +199,10 @@ numeric_state_from_config = _threaded_factory(async_numeric_state_from_config) def state(hass, entity, req_state, for_period=None): - """Test if state matches requirements.""" + """Test if state matches requirements. + + Async friendly. + """ if isinstance(entity, str): entity = hass.states.get(entity) @@ -357,7 +360,7 @@ def time_from_config(config, config_validation=True): def zone(hass, zone_ent, entity): """Test if zone-condition matches. - Can be run async. + Async friendly. """ if isinstance(zone_ent, str): zone_ent = hass.states.get(zone_ent) From eefb603f179cc32e14b5561a5b39cd6fd98c6856 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 2 Feb 2017 06:45:19 +0100 Subject: [PATCH 051/157] Cleanup media_player universal platform / blocking platform. (#5671) * Cleanup media_player universal platform / blocking platform. * fix comments * fix unittest * fix lint * fix unittest lint * fix coro * fix test * fix tests part 2 --- .../components/media_player/gpmdp.py | 12 +- .../components/media_player/itunes.py | 4 +- .../components/media_player/squeezebox.py | 139 +++++++------ .../components/media_player/universal.py | 192 ++++++++++++------ .../components/media_player/test_universal.py | 133 +++++++----- 5 files changed, 299 insertions(+), 181 deletions(-) diff --git a/homeassistant/components/media_player/gpmdp.py b/homeassistant/components/media_player/gpmdp.py index c98b32137c7..1678547bee7 100644 --- a/homeassistant/components/media_player/gpmdp.py +++ b/homeassistant/components/media_player/gpmdp.py @@ -311,13 +311,13 @@ class GPMDP(MediaPlayerDevice): """Send media_play command to media player.""" self.send_gpmdp_msg('playback', 'playPause', False) self._status = STATE_PLAYING - self.update_ha_state() + self.schedule_update_ha_state() def media_pause(self): """Send media_pause command to media player.""" self.send_gpmdp_msg('playback', 'playPause', False) self._status = STATE_PAUSED - self.update_ha_state() + self.schedule_update_ha_state() def media_seek(self, position): """Send media_seek command to media player.""" @@ -327,7 +327,7 @@ class GPMDP(MediaPlayerDevice): websocket.send(json.dumps({'namespace': 'playback', 'method': 'setCurrentTime', 'arguments': [position*1000]})) - self.update_ha_state() + self.schedule_update_ha_state() def volume_up(self): """Send volume_up command to media player.""" @@ -335,7 +335,7 @@ class GPMDP(MediaPlayerDevice): if websocket is None: return websocket.send('{"namespace": "volume", "method": "increaseVolume"}') - self.update_ha_state() + self.schedule_update_ha_state() def volume_down(self): """Send volume_down command to media player.""" @@ -343,7 +343,7 @@ class GPMDP(MediaPlayerDevice): if websocket is None: return websocket.send('{"namespace": "volume", "method": "decreaseVolume"}') - self.update_ha_state() + self.schedule_update_ha_state() def set_volume_level(self, volume): """Set volume on media player, range(0..1).""" @@ -353,4 +353,4 @@ class GPMDP(MediaPlayerDevice): websocket.send(json.dumps({'namespace': 'volume', 'method': 'setVolume', 'arguments': [volume*100]})) - self.update_ha_state() + self.schedule_update_ha_state() diff --git a/homeassistant/components/media_player/itunes.py b/homeassistant/components/media_player/itunes.py index 4dc41c7e085..c208990cb67 100644 --- a/homeassistant/components/media_player/itunes.py +++ b/homeassistant/components/media_player/itunes.py @@ -438,13 +438,13 @@ class AirPlayDevice(MediaPlayerDevice): def turn_on(self): """Select AirPlay.""" self.update_state({"selected": True}) - self.update_ha_state() + self.schedule_update_ha_state() response = self.client.toggle_airplay_device(self._id, True) self.update_state(response) def turn_off(self): """Deselect AirPlay.""" self.update_state({"selected": False}) - self.update_ha_state() + self.schedule_update_ha_state() response = self.client.toggle_airplay_device(self._id, False) self.update_state(response) diff --git a/homeassistant/components/media_player/squeezebox.py b/homeassistant/components/media_player/squeezebox.py index 852ce522559..65a543781aa 100644 --- a/homeassistant/components/media_player/squeezebox.py +++ b/homeassistant/components/media_player/squeezebox.py @@ -201,10 +201,6 @@ class SqueezeBoxDevice(MediaPlayerDevice): return self._lms.async_query( *parameters, player=self._id) - def query(self, *parameters): - """Queue up a command to send the LMS.""" - self.hass.loop.create_task(self.async_query(*parameters)) - @asyncio.coroutine def async_update(self): """Retrieve the current state of the player.""" @@ -310,85 +306,108 @@ class SqueezeBoxDevice(MediaPlayerDevice): """Flag of media commands that are supported.""" return SUPPORT_SQUEEZEBOX - def turn_off(self): - """Turn off media player.""" - self.query('power', '0') - self.update_ha_state() + def async_turn_off(self): + """Turn off media player. - def volume_up(self): - """Volume up media player.""" - self.query('mixer', 'volume', '+5') - self.update_ha_state() + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('power', '0') - def volume_down(self): - """Volume down media player.""" - self.query('mixer', 'volume', '-5') - self.update_ha_state() + def async_volume_up(self): + """Volume up media player. - def set_volume_level(self, volume): - """Set volume level, range 0..1.""" + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('mixer', 'volume', '+5') + + def async_volume_down(self): + """Volume down media player. + + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('mixer', 'volume', '-5') + + def async_set_volume_level(self, volume): + """Set volume level, range 0..1. + + This method must be run in the event loop and returns a coroutine. + """ volume_percent = str(int(volume*100)) - self.query('mixer', 'volume', volume_percent) - self.update_ha_state() + return self.async_query('mixer', 'volume', volume_percent) - def mute_volume(self, mute): - """Mute (true) or unmute (false) media player.""" + def async_mute_volume(self, mute): + """Mute (true) or unmute (false) media player. + + This method must be run in the event loop and returns a coroutine. + """ mute_numeric = '1' if mute else '0' - self.query('mixer', 'muting', mute_numeric) - self.update_ha_state() + return self.async_query('mixer', 'muting', mute_numeric) - def media_play_pause(self): - """Send pause command to media player.""" - self.query('pause') - self.update_ha_state() + def async_media_play_pause(self): + """Send pause command to media player. - def media_play(self): - """Send play command to media player.""" - self.query('play') - self.update_ha_state() + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('pause') - def media_pause(self): - """Send pause command to media player.""" - self.query('pause', '1') - self.update_ha_state() + def async_media_play(self): + """Send play command to media player. - def media_next_track(self): - """Send next track command.""" - self.query('playlist', 'index', '+1') - self.update_ha_state() + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('play') - def media_previous_track(self): - """Send next track command.""" - self.query('playlist', 'index', '-1') - self.update_ha_state() + def async_media_pause(self): + """Send pause command to media player. - def media_seek(self, position): - """Send seek command.""" - self.query('time', position) - self.update_ha_state() + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('pause', '1') - def turn_on(self): - """Turn the media player on.""" - self.query('power', '1') - self.update_ha_state() + def async_media_next_track(self): + """Send next track command. - def play_media(self, media_type, media_id, **kwargs): + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('playlist', 'index', '+1') + + def async_media_previous_track(self): + """Send next track command. + + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('playlist', 'index', '-1') + + def async_media_seek(self, position): + """Send seek command. + + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('time', position) + + def async_turn_on(self): + """Turn the media player on. + + This method must be run in the event loop and returns a coroutine. + """ + return self.async_query('power', '1') + + def async_play_media(self, media_type, media_id, **kwargs): """ Send the play_media command to the media player. If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the current playlist. + This method must be run in the event loop and returns a coroutine. """ if kwargs.get(ATTR_MEDIA_ENQUEUE): - self._add_uri_to_playlist(media_id) - else: - self._play_uri(media_id) + return self._add_uri_to_playlist(media_id) + + return self._play_uri(media_id) def _play_uri(self, media_id): """Replace the current play list with the uri.""" - self.query('playlist', 'play', media_id) - self.update_ha_state() + return self.async_query('playlist', 'play', media_id) def _add_uri_to_playlist(self, media_id): """Add a items to the existing playlist.""" - self.query('playlist', 'add', media_id) - self.update_ha_state() + return self.async_query('playlist', 'add', media_id) diff --git a/homeassistant/components/media_player/universal.py b/homeassistant/components/media_player/universal.py index e01717f5693..f1bd61fd007 100644 --- a/homeassistant/components/media_player/universal.py +++ b/homeassistant/components/media_player/universal.py @@ -4,10 +4,12 @@ Combination of multiple media players into one for a universal controller. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/media_player.universal/ """ +import asyncio import logging # pylint: disable=import-error from copy import copy +from homeassistant.core import callback from homeassistant.components.media_player import ( ATTR_APP_ID, ATTR_APP_NAME, ATTR_MEDIA_ALBUM_ARTIST, ATTR_MEDIA_ALBUM_NAME, ATTR_MEDIA_ARTIST, ATTR_MEDIA_CHANNEL, ATTR_MEDIA_CONTENT_ID, @@ -28,8 +30,8 @@ from homeassistant.const import ( SERVICE_TURN_ON, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_MUTE, SERVICE_VOLUME_SET, SERVICE_VOLUME_UP, STATE_IDLE, STATE_OFF, STATE_ON, SERVICE_MEDIA_STOP) -from homeassistant.helpers.event import track_state_change -from homeassistant.helpers.service import call_from_config +from homeassistant.helpers.event import async_track_state_change +from homeassistant.helpers.service import async_call_from_config ATTR_ACTIVE_CHILD = 'active_child' @@ -47,18 +49,21 @@ REQUIREMENTS = [] _LOGGER = logging.getLogger(__name__) -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 the universal media players.""" if not validate_config(config): return - player = UniversalMediaPlayer(hass, - config[CONF_NAME], - config[CONF_CHILDREN], - config[CONF_COMMANDS], - config[CONF_ATTRS]) + player = UniversalMediaPlayer( + hass, + config[CONF_NAME], + config[CONF_CHILDREN], + config[CONF_COMMANDS], + config[CONF_ATTRS] + ) - add_devices([player]) + yield from async_add_devices([player]) def validate_config(config): @@ -143,15 +148,16 @@ class UniversalMediaPlayer(MediaPlayerDevice): self._attrs = attributes self._child_state = None - def on_dependency_update(*_): + @callback + def async_on_dependency_update(*_): """Update ha state when dependencies update.""" - self.update_ha_state(True) + self.hass.add_job(self.async_update_ha_state(True)) depend = copy(children) for entity in attributes.values(): depend.append(entity[0]) - track_state_change(hass, depend, on_dependency_update) + async_track_state_change(hass, depend, async_on_dependency_update) def _entity_lkp(self, entity_id, state_attr=None): """Look up an entity state.""" @@ -177,14 +183,15 @@ class UniversalMediaPlayer(MediaPlayerDevice): active_child = self._child_state return active_child.attributes.get(attr_name) if active_child else None - def _call_service(self, service_name, service_data=None, - allow_override=False): + @asyncio.coroutine + def _async_call_service(self, service_name, service_data=None, + allow_override=False): """Call either a specified or active child's service.""" if service_data is None: service_data = {} if allow_override and service_name in self._cmds: - call_from_config( + yield from async_call_from_config( self.hass, self._cmds[service_name], variables=service_data, blocking=True) return @@ -196,8 +203,8 @@ class UniversalMediaPlayer(MediaPlayerDevice): service_data[ATTR_ENTITY_ID] = active_child.entity_id - self.hass.services.call(DOMAIN, service_name, service_data, - blocking=True) + yield from self.hass.services.async_call( + DOMAIN, service_name, service_data, blocking=True) @property def should_poll(self): @@ -395,77 +402,130 @@ class UniversalMediaPlayer(MediaPlayerDevice): """When was the position of the current playing media valid.""" return self._child_attr(ATTR_MEDIA_POSITION_UPDATED_AT) - def turn_on(self): - """Turn the media player on.""" - self._call_service(SERVICE_TURN_ON, allow_override=True) + def async_turn_on(self): + """Turn the media player on. - def turn_off(self): - """Turn the media player off.""" - self._call_service(SERVICE_TURN_OFF, allow_override=True) + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_TURN_ON, allow_override=True) - def mute_volume(self, is_volume_muted): - """Mute the volume.""" + def async_turn_off(self): + """Turn the media player off. + + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_TURN_OFF, allow_override=True) + + def async_mute_volume(self, is_volume_muted): + """Mute the volume. + + This method must be run in the event loop and returns a coroutine. + """ data = {ATTR_MEDIA_VOLUME_MUTED: is_volume_muted} - self._call_service(SERVICE_VOLUME_MUTE, data, allow_override=True) + return self._async_call_service( + SERVICE_VOLUME_MUTE, data, allow_override=True) - def set_volume_level(self, volume_level): - """Set volume level, range 0..1.""" + def async_set_volume_level(self, volume_level): + """Set volume level, range 0..1. + + This method must be run in the event loop and returns a coroutine. + """ data = {ATTR_MEDIA_VOLUME_LEVEL: volume_level} - self._call_service(SERVICE_VOLUME_SET, data, allow_override=True) + return self._async_call_service( + SERVICE_VOLUME_SET, data, allow_override=True) - def media_play(self): - """Send play commmand.""" - self._call_service(SERVICE_MEDIA_PLAY) + def async_media_play(self): + """Send play commmand. - def media_pause(self): - """Send pause command.""" - self._call_service(SERVICE_MEDIA_PAUSE) + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_MEDIA_PLAY) - def media_stop(self): - """Send stop command.""" - self._call_service(SERVICE_MEDIA_STOP) + def async_media_pause(self): + """Send pause command. - def media_previous_track(self): - """Send previous track command.""" - self._call_service(SERVICE_MEDIA_PREVIOUS_TRACK) + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_MEDIA_PAUSE) - def media_next_track(self): - """Send next track command.""" - self._call_service(SERVICE_MEDIA_NEXT_TRACK) + def async_media_stop(self): + """Send stop command. - def media_seek(self, position): - """Send seek command.""" + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_MEDIA_STOP) + + def async_media_previous_track(self): + """Send previous track command. + + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_MEDIA_PREVIOUS_TRACK) + + def async_media_next_track(self): + """Send next track command. + + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_MEDIA_NEXT_TRACK) + + def async_media_seek(self, position): + """Send seek command. + + This method must be run in the event loop and returns a coroutine. + """ data = {ATTR_MEDIA_SEEK_POSITION: position} - self._call_service(SERVICE_MEDIA_SEEK, data) + return self._async_call_service(SERVICE_MEDIA_SEEK, data) - def play_media(self, media_type, media_id, **kwargs): - """Play a piece of media.""" + def async_play_media(self, media_type, media_id, **kwargs): + """Play a piece of media. + + This method must be run in the event loop and returns a coroutine. + """ data = {ATTR_MEDIA_CONTENT_TYPE: media_type, ATTR_MEDIA_CONTENT_ID: media_id} - self._call_service(SERVICE_PLAY_MEDIA, data) + return self._async_call_service(SERVICE_PLAY_MEDIA, data) - def volume_up(self): - """Turn volume up for media player.""" - self._call_service(SERVICE_VOLUME_UP, allow_override=True) + def async_volume_up(self): + """Turn volume up for media player. - def volume_down(self): - """Turn volume down for media player.""" - self._call_service(SERVICE_VOLUME_DOWN, allow_override=True) + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_VOLUME_UP, allow_override=True) - def media_play_pause(self): - """Play or pause the media player.""" - self._call_service(SERVICE_MEDIA_PLAY_PAUSE) + def async_volume_down(self): + """Turn volume down for media player. - def select_source(self, source): - """Set the input source.""" + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service( + SERVICE_VOLUME_DOWN, allow_override=True) + + def async_media_play_pause(self): + """Play or pause the media player. + + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_MEDIA_PLAY_PAUSE) + + def async_select_source(self, source): + """Set the input source. + + This method must be run in the event loop and returns a coroutine. + """ data = {ATTR_INPUT_SOURCE: source} - self._call_service(SERVICE_SELECT_SOURCE, data, allow_override=True) + return self._async_call_service( + SERVICE_SELECT_SOURCE, data, allow_override=True) - def clear_playlist(self): - """Clear players playlist.""" - self._call_service(SERVICE_CLEAR_PLAYLIST) + def async_clear_playlist(self): + """Clear players playlist. - def update(self): + This method must be run in the event loop and returns a coroutine. + """ + return self._async_call_service(SERVICE_CLEAR_PLAYLIST) + + @asyncio.coroutine + def async_update(self): """Update state in HA.""" for child_name in self._children: child_state = self.hass.states.get(child_name) diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index 4a06d989ce2..76fca3fb6ed 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -1,4 +1,5 @@ """The tests for the Universal Media player platform.""" +import asyncio from copy import copy import unittest @@ -9,6 +10,7 @@ import homeassistant.components.input_slider as input_slider import homeassistant.components.input_select as input_select import homeassistant.components.media_player as media_player import homeassistant.components.media_player.universal as universal +from homeassistant.util.async import run_coroutine_threadsafe from tests.common import mock_service, get_test_home_assistant @@ -256,15 +258,20 @@ class TestMediaPlayer(unittest.TestCase): bad_config = {'platform': 'universal'} entities = [] + @asyncio.coroutine def add_devices(new_entities): """Add devices to list.""" for dev in new_entities: entities.append(dev) - universal.setup_platform(self.hass, bad_config, add_devices) + run_coroutine_threadsafe( + universal.async_setup_platform(self.hass, bad_config, add_devices), + self.hass.loop).result() self.assertEqual(0, len(entities)) - universal.setup_platform(self.hass, config, add_devices) + run_coroutine_threadsafe( + universal.async_setup_platform(self.hass, config, add_devices), + self.hass.loop).result() self.assertEqual(1, len(entities)) self.assertEqual('test', entities[0].name) @@ -305,25 +312,25 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(None, ump._child_state) self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(self.mock_mp_1.entity_id, ump._child_state.entity_id) self.mock_mp_2._state = STATE_PLAYING self.mock_mp_2.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(self.mock_mp_1.entity_id, ump._child_state.entity_id) self.mock_mp_1._state = STATE_OFF self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(self.mock_mp_2.entity_id, ump._child_state.entity_id) @@ -352,13 +359,13 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertTrue(ump.state, STATE_OFF) self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(STATE_PLAYING, ump.state) def test_state_with_children_and_attrs(self): @@ -368,21 +375,21 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(STATE_OFF, ump.state) self.hass.states.set(self.mock_state_switch_id, STATE_ON) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(STATE_ON, ump.state) self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(STATE_PLAYING, ump.state) self.hass.states.set(self.mock_state_switch_id, STATE_OFF) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(STATE_OFF, ump.state) def test_volume_level(self): @@ -392,18 +399,18 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(None, ump.volume_level) self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(0, ump.volume_level) self.mock_mp_1._volume_level = 1 self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(1, ump.volume_level) def test_media_image_url(self): @@ -414,14 +421,14 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(None, ump.media_image_url) self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1._media_image_url = TEST_URL self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() # mock_mp_1 will convert the url to the api proxy url. This test # ensures ump passes through the same url without an additional proxy. self.assertEqual(self.mock_mp_1.entity_picture, ump.entity_picture) @@ -433,18 +440,18 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertFalse(ump.is_volume_muted) self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertFalse(ump.is_volume_muted) self.mock_mp_1._is_volume_muted = True self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertTrue(ump.is_volume_muted) def test_source_list_children_and_attr(self): @@ -502,14 +509,14 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(0, ump.supported_media_commands) self.mock_mp_1._supported_media_commands = 512 self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.assertEqual(512, ump.supported_media_commands) def test_supported_media_commands_children_and_cmds(self): @@ -526,11 +533,11 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() check_flags = universal.SUPPORT_TURN_ON | universal.SUPPORT_TURN_OFF \ | universal.SUPPORT_VOLUME_STEP | universal.SUPPORT_VOLUME_MUTE \ @@ -545,15 +552,17 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.mock_mp_1._state = STATE_OFF self.mock_mp_1.update_ha_state() self.mock_mp_2._state = STATE_OFF self.mock_mp_2.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() - ump.turn_off() + run_coroutine_threadsafe( + ump.async_turn_off(), + self.hass.loop).result() self.assertEqual(0, len(self.mock_mp_1.service_calls['turn_off'])) self.assertEqual(0, len(self.mock_mp_2.service_calls['turn_off'])) @@ -564,60 +573,90 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.mock_mp_2._state = STATE_PLAYING self.mock_mp_2.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() - ump.turn_off() + run_coroutine_threadsafe( + ump.async_turn_off(), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['turn_off'])) - ump.turn_on() + run_coroutine_threadsafe( + ump.async_turn_on(), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['turn_on'])) - ump.mute_volume(True) + run_coroutine_threadsafe( + ump.async_mute_volume(True), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['mute_volume'])) - ump.set_volume_level(0.5) + run_coroutine_threadsafe( + ump.async_set_volume_level(0.5), + self.hass.loop).result() self.assertEqual( 1, len(self.mock_mp_2.service_calls['set_volume_level'])) - ump.media_play() + run_coroutine_threadsafe( + ump.async_media_play(), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['media_play'])) - ump.media_pause() + run_coroutine_threadsafe( + ump.async_media_pause(), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['media_pause'])) - ump.media_previous_track() + run_coroutine_threadsafe( + ump.async_media_previous_track(), + self.hass.loop).result() self.assertEqual( 1, len(self.mock_mp_2.service_calls['media_previous_track'])) - ump.media_next_track() + run_coroutine_threadsafe( + ump.async_media_next_track(), + self.hass.loop).result() self.assertEqual( 1, len(self.mock_mp_2.service_calls['media_next_track'])) - ump.media_seek(100) + run_coroutine_threadsafe( + ump.async_media_seek(100), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['media_seek'])) - ump.play_media('movie', 'batman') + run_coroutine_threadsafe( + ump.async_play_media('movie', 'batman'), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['play_media'])) - ump.volume_up() + run_coroutine_threadsafe( + ump.async_volume_up(), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['volume_up'])) - ump.volume_down() + run_coroutine_threadsafe( + ump.async_volume_down(), + self.hass.loop).result() self.assertEqual(1, len(self.mock_mp_2.service_calls['volume_down'])) - ump.media_play_pause() + run_coroutine_threadsafe( + ump.async_media_play_pause(), + self.hass.loop).result() self.assertEqual( 1, len(self.mock_mp_2.service_calls['media_play_pause'])) - ump.select_source('dvd') + run_coroutine_threadsafe( + ump.async_select_source('dvd'), + self.hass.loop).result() self.assertEqual( 1, len(self.mock_mp_2.service_calls['select_source'])) - ump.clear_playlist() + run_coroutine_threadsafe( + ump.async_clear_playlist(), + self.hass.loop).result() self.assertEqual( 1, len(self.mock_mp_2.service_calls['clear_playlist'])) @@ -632,11 +671,11 @@ class TestMediaPlayer(unittest.TestCase): ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() self.mock_mp_2._state = STATE_PLAYING self.mock_mp_2.update_ha_state() - ump.update() + run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() - ump.turn_off() + run_coroutine_threadsafe(ump.async_turn_off(), self.hass.loop).result() self.assertEqual(1, len(service)) From 6e94f0d7cdb57d6aef845ed0b956c82dfe5ab848 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 1 Feb 2017 21:48:30 -0800 Subject: [PATCH 052/157] Upgrade zeroconf dep" (#5706) --- homeassistant/components/media_player/cast.py | 2 +- homeassistant/components/zeroconf.py | 2 +- requirements_all.txt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 202c877c2b1..7998dafc1e1 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -20,7 +20,7 @@ from homeassistant.const import ( import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['pychromecast==0.7.6'] +REQUIREMENTS = ['pychromecast==0.8.0'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/zeroconf.py b/homeassistant/components/zeroconf.py index 104abd19260..016b99b9b3c 100644 --- a/homeassistant/components/zeroconf.py +++ b/homeassistant/components/zeroconf.py @@ -17,7 +17,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['api'] DOMAIN = 'zeroconf' -REQUIREMENTS = ['zeroconf==0.17.6'] +REQUIREMENTS = ['zeroconf==0.17.7'] ZEROCONF_TYPE = '_home-assistant._tcp.local.' diff --git a/requirements_all.txt b/requirements_all.txt index 055e0a4292c..83db483d425 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -412,7 +412,7 @@ pybbox==0.0.5-alpha # pybluez==0.22 # homeassistant.components.media_player.cast -pychromecast==0.7.6 +pychromecast==0.8.0 # homeassistant.components.media_player.cmus pycmus==0.1.0 @@ -692,4 +692,4 @@ yeelight==0.2.1 zengge==0.2 # homeassistant.components.zeroconf -zeroconf==0.17.6 +zeroconf==0.17.7 From b5f285a789c0a2c3ec8fa29e131b443f1aba82f9 Mon Sep 17 00:00:00 2001 From: Trevor Date: Thu, 2 Feb 2017 00:06:02 -0600 Subject: [PATCH 053/157] Fix OwnTracks state names (#5454) * Fix OwnTracks state names (#5453) * Update owntracks.py * Update tests --- homeassistant/components/device_tracker/owntracks.py | 7 ++++--- tests/components/device_tracker/test_owntracks.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/device_tracker/owntracks.py b/homeassistant/components/device_tracker/owntracks.py index 44ae0359ff6..e2a238a5656 100644 --- a/homeassistant/components/device_tracker/owntracks.py +++ b/homeassistant/components/device_tracker/owntracks.py @@ -190,7 +190,7 @@ def setup_scanner(hass, config, see): return # OwnTracks uses - at the start of a beacon zone # to switch on 'hold mode' - ignore this - location = slugify(data['desc'].lstrip("-")) + location = data['desc'].lstrip("-") if location.lower() == 'home': location = STATE_HOME @@ -198,7 +198,7 @@ def setup_scanner(hass, config, see): def enter_event(): """Execute enter event.""" - zone = hass.states.get("zone.{}".format(location)) + zone = hass.states.get("zone.{}".format(slugify(location))) with LOCK: if zone is None and data.get('t') == 'b': # Not a HA zone, and a beacon so assume mobile @@ -227,7 +227,8 @@ def setup_scanner(hass, config, see): if new_region: # Exit to previous region - zone = hass.states.get("zone.{}".format(new_region)) + zone = hass.states.get( + "zone.{}".format(slugify(new_region))) _set_gps_from_zone(kwargs, new_region, zone) _LOGGER.info("Exit to %s", new_region) see(**kwargs) diff --git a/tests/components/device_tracker/test_owntracks.py b/tests/components/device_tracker/test_owntracks.py index 183bbbd994f..4bea0d3d0b3 100644 --- a/tests/components/device_tracker/test_owntracks.py +++ b/tests/components/device_tracker/test_owntracks.py @@ -377,7 +377,7 @@ class TestDeviceTrackerOwnTracks(BaseMQTT): message = REGION_ENTER_MESSAGE.copy() message['desc'] = "inner 2" self.send_message(EVENT_TOPIC, message) - self.assert_location_state('inner_2') + self.assert_location_state('inner 2') message = REGION_LEAVE_MESSAGE.copy() message['desc'] = "inner 2" From 80a794e587f9f63f28afea741f97e36a7ca8e427 Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Thu, 2 Feb 2017 01:43:12 -0500 Subject: [PATCH 054/157] Wink AC and addidtional sensor support (#5670) * Added door bell sensors * Initial support for AC units. * Added new device service * Quirky Aros AC unit support * Use super() everywhere and error checking for token request. * Ignore camera sensors during setup of alarms. * Added manufacturer/device attributes to all wink devices. * Fixed style errors * Fixed remaining lint errors. --- .../components/alarm_control_panel/wink.py | 13 +- .../components/binary_sensor/wink.py | 129 ++++++++++----- homeassistant/components/climate/wink.py | 147 +++++++++++++++++- homeassistant/components/cover/wink.py | 16 +- homeassistant/components/fan/wink.py | 8 +- homeassistant/components/light/wink.py | 9 +- homeassistant/components/lock/wink.py | 9 +- homeassistant/components/sensor/wink.py | 32 ++-- homeassistant/components/switch/wink.py | 31 +++- homeassistant/components/wink.py | 53 ++++++- requirements_all.txt | 2 +- 11 files changed, 361 insertions(+), 88 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/wink.py b/homeassistant/components/alarm_control_panel/wink.py index 2a600fe70a9..c489b53c9c0 100644 --- a/homeassistant/components/alarm_control_panel/wink.py +++ b/homeassistant/components/alarm_control_panel/wink.py @@ -11,7 +11,7 @@ from homeassistant.const import (STATE_UNKNOWN, STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY) -from homeassistant.components.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN _LOGGER = logging.getLogger(__name__) @@ -24,7 +24,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import pywink for camera in pywink.get_cameras(): - add_devices([WinkCameraDevice(camera, hass)]) + # get_cameras returns multiple device types. + # Only add those that aren't sensors. + try: + camera.capability() + except AttributeError: + _id = camera.object_id() + camera.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkCameraDevice(camera, hass)]) class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanel): @@ -32,7 +39,7 @@ class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanel): def __init__(self, wink, hass): """Initialize the Wink alarm.""" - WinkDevice.__init__(self, wink, hass) + super().__init__(wink, hass) @property def state(self): diff --git a/homeassistant/components/binary_sensor/wink.py b/homeassistant/components/binary_sensor/wink.py index 19ecb853536..4e1969de858 100644 --- a/homeassistant/components/binary_sensor/wink.py +++ b/homeassistant/components/binary_sensor/wink.py @@ -4,11 +4,14 @@ Support for Wink binary sensors. For more details about this platform, please refer to the documentation at at https://home-assistant.io/components/binary_sensor.wink/ """ +import logging from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.components.sensor.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN from homeassistant.helpers.entity import Entity +_LOGGER = logging.getLogger(__name__) + DEPENDENCIES = ['wink'] # These are the available sensors mapped to binary_sensor class @@ -17,11 +20,14 @@ SENSOR_TYPES = { "brightness": "light", "vibration": "vibration", "loudness": "sound", + "noise": "sound", + "capturing_audio": "sound", "liquid_detected": "moisture", "motion": "motion", "presence": "occupancy", "co_detected": "gas", - "smoke_detected": "smoke" + "smoke_detected": "smoke", + "capturing_video": None } @@ -30,26 +36,54 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import pywink for sensor in pywink.get_sensors(): - if sensor.capability() in SENSOR_TYPES: - add_devices([WinkBinarySensorDevice(sensor, hass)]) + _id = sensor.object_id() + sensor.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + if sensor.capability() in SENSOR_TYPES: + add_devices([WinkBinarySensorDevice(sensor, hass)]) for key in pywink.get_keys(): - add_devices([WinkBinarySensorDevice(key, hass)]) + _id = key.object_id() + key.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkBinarySensorDevice(key, hass)]) for sensor in pywink.get_smoke_and_co_detectors(): - add_devices([WinkBinarySensorDevice(sensor, hass)]) + _id = sensor.object_id() + sensor.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkSmokeDetector(sensor, hass)]) for hub in pywink.get_hubs(): - add_devices([WinkHub(hub, hass)]) + _id = hub.object_id() + hub.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkHub(hub, hass)]) for remote in pywink.get_remotes(): - add_devices([WinkRemote(remote, hass)]) + _id = remote.object_id() + remote.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkRemote(remote, hass)]) for button in pywink.get_buttons(): - add_devices([WinkButton(button, hass)]) + _id = button.object_id() + button.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkButton(button, hass)]) for gang in pywink.get_gangs(): - add_devices([WinkGang(gang, hass)]) + _id = gang.object_id() + gang.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkGang(gang, hass)]) + + for door_bell_sensor in pywink.get_door_bells(): + _id = door_bell_sensor.object_id() + door_bell_sensor.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkBinarySensorDevice(door_bell_sensor, hass)]) + + for camera_sensor in pywink.get_cameras(): + _id = camera_sensor.object_id() + camera_sensor.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + try: + if camera_sensor.capability() in SENSOR_TYPES: + add_devices([WinkBinarySensorDevice(camera_sensor, hass)]) + except AttributeError: + _LOGGER.info("Device isn't a sensor, skipping.") class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity): @@ -58,8 +92,14 @@ class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity): def __init__(self, wink, hass): """Initialize the Wink binary sensor.""" super().__init__(wink, hass) - self._unit_of_measurement = self.wink.unit() - self.capability = self.wink.capability() + try: + self._unit_of_measurement = self.wink.unit() + except AttributeError: + self._unit_of_measurement = None + try: + self.capability = self.wink.capability() + except AttributeError: + self.capability = None @property def is_on(self): @@ -72,17 +112,27 @@ class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity): return SENSOR_TYPES.get(self.capability) -class WinkHub(WinkDevice, BinarySensorDevice, Entity): - """Representation of a Wink Hub.""" +class WinkSmokeDetector(WinkBinarySensorDevice): + """Representation of a Wink Smoke detector.""" - def __init(self, wink, hass): - """Initialize the hub sensor.""" - WinkDevice.__init__(self, wink, hass) + def __init__(self, wink, hass): + """Initialize the Wink binary sensor.""" + super().__init__(wink, hass) @property - def is_on(self): - """Return true if the binary sensor is on.""" - return self.wink.state() + def device_state_attributes(self): + """Return the state attributes.""" + return { + 'test_activated': self.wink.test_activated() + } + + +class WinkHub(WinkBinarySensorDevice): + """Representation of a Wink Hub.""" + + def __init__(self, wink, hass): + """Initialize the Wink binary sensor.""" + super().__init__(wink, hass) @property def device_state_attributes(self): @@ -93,17 +143,12 @@ class WinkHub(WinkDevice, BinarySensorDevice, Entity): } -class WinkRemote(WinkDevice, BinarySensorDevice, Entity): +class WinkRemote(WinkBinarySensorDevice): """Representation of a Wink Lutron Connected bulb remote.""" - def __init(self, wink, hass): - """Initialize the hub sensor.""" - WinkDevice.__init__(self, wink, hass) - - @property - def is_on(self): - """Return true if the binary sensor is on.""" - return self.wink.state() + def __init__(self, wink, hass): + """Initialize the Wink binary sensor.""" + super().__init__(wink, hass) @property def device_state_attributes(self): @@ -115,18 +160,18 @@ class WinkRemote(WinkDevice, BinarySensorDevice, Entity): 'button_down_pressed': self.wink.button_down_pressed() } + @property + def sensor_class(self): + """Return the class of this sensor, from SENSOR_CLASSES.""" + return None -class WinkButton(WinkDevice, BinarySensorDevice, Entity): + +class WinkButton(WinkBinarySensorDevice): """Representation of a Wink Relay button.""" - def __init(self, wink, hass): - """Initialize the hub sensor.""" - WinkDevice.__init__(self, wink, hass) - - @property - def is_on(self): - """Return true if the binary sensor is on.""" - return self.wink.state() + def __init__(self, wink, hass): + """Initialize the Wink binary sensor.""" + super().__init__(wink, hass) @property def device_state_attributes(self): @@ -137,12 +182,12 @@ class WinkButton(WinkDevice, BinarySensorDevice, Entity): } -class WinkGang(WinkDevice, BinarySensorDevice, Entity): +class WinkGang(WinkBinarySensorDevice): """Representation of a Wink Relay gang.""" - def __init(self, wink, hass): - """Initialize the gang sensor.""" - WinkDevice.__init__(self, wink, hass) + def __init__(self, wink, hass): + """Initialize the Wink binary sensor.""" + super().__init__(wink, hass) @property def is_on(self): diff --git a/homeassistant/components/climate/wink.py b/homeassistant/components/climate/wink.py index 733d2baddf7..d4785d4a13e 100644 --- a/homeassistant/components/climate/wink.py +++ b/homeassistant/components/climate/wink.py @@ -4,7 +4,7 @@ Support for Wink thermostats. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/climate.wink/ """ -from homeassistant.components.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN from homeassistant.components.climate import ( STATE_AUTO, STATE_COOL, STATE_HEAT, ClimateDevice, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW, @@ -13,12 +13,16 @@ from homeassistant.components.climate import ( from homeassistant.const import ( TEMP_CELSIUS, STATE_ON, STATE_OFF, STATE_UNKNOWN) -from homeassistant.loader import get_component DEPENDENCIES = ['wink'] STATE_AUX = 'aux' STATE_ECO = 'eco' +STATE_FAN = 'fan' +SPEED_LOWEST = 'lowest' +SPEED_LOW = 'low' +SPEED_MEDIUM = 'medium' +SPEED_HIGH = 'high' ATTR_EXTERNAL_TEMPERATURE = "external_temperature" ATTR_SMART_TEMPERATURE = "smart_temperature" @@ -30,8 +34,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Wink thermostat.""" import pywink temp_unit = hass.config.units.temperature_unit - add_devices(WinkThermostat(thermostat, hass, temp_unit) - for thermostat in pywink.get_thermostats()) + for climate in pywink.get_thermostats(): + _id = climate.object_id() + climate.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkThermostat(climate, hass, temp_unit)]) + for climate in pywink.get_air_conditioners(): + _id = climate.object_id() + climate.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkAC(climate, hass, temp_unit)]) # pylint: disable=abstract-method,too-many-public-methods, too-many-branches @@ -41,7 +51,6 @@ class WinkThermostat(WinkDevice, ClimateDevice): def __init__(self, wink, hass, temp_unit): """Initialize the Wink device.""" super().__init__(wink, hass) - wink = get_component('wink') self._config_temp_unit = temp_unit @property @@ -329,3 +338,131 @@ class WinkThermostat(WinkDevice, ClimateDevice): else: return_value = maximum return return_value + + +class WinkAC(WinkDevice, ClimateDevice): + """Representation of a Wink air conditioner.""" + + def __init__(self, wink, hass, temp_unit): + """Initialize the Wink device.""" + super().__init__(wink, hass) + self._config_temp_unit = temp_unit + + @property + def temperature_unit(self): + """Return the unit of measurement.""" + # The Wink API always returns temp in Celsius + return TEMP_CELSIUS + + @property + def device_state_attributes(self): + """Return the optional state attributes.""" + data = {} + target_temp_high = self.target_temperature_high + target_temp_low = self.target_temperature_low + if target_temp_high is not None: + data[ATTR_TARGET_TEMP_HIGH] = self._convert_for_display( + self.target_temperature_high) + if target_temp_low is not None: + data[ATTR_TARGET_TEMP_LOW] = self._convert_for_display( + self.target_temperature_low) + data["total_consumption"] = self.wink.toatl_consumption() + data["schedule_enabled"] = self.wink.toatl_consumption() + + return data + + @property + def current_temperature(self): + """Return the current temperature.""" + return self.wink.current_temperature() + + @property + def current_operation(self): + """Return current operation ie. heat, cool, idle.""" + if not self.wink.is_on(): + current_op = STATE_OFF + elif self.wink.current_mode() == 'cool_only': + current_op = STATE_COOL + elif self.wink.current_mode() == 'auto_eco': + current_op = STATE_ECO + elif self.wink.current_mode() == 'fan_only': + current_op = STATE_FAN + else: + current_op = STATE_UNKNOWN + return current_op + + @property + def operation_list(self): + """List of available operation modes.""" + op_list = ['off'] + modes = self.wink.modes() + if 'cool_only' in modes: + op_list.append(STATE_COOL) + if 'auto_eco' in modes: + op_list.append(STATE_ECO) + if 'fan_eco' in modes: + op_list.append(STATE_FAN) + return op_list + + def set_temperature(self, **kwargs): + """Set new target temperature.""" + target_temp = kwargs.get(ATTR_TEMPERATURE) + self.wink.set_temperature(target_temp) + + def set_operation_mode(self, operation_mode): + """Set operation mode.""" + if operation_mode == STATE_COOL: + self.wink.set_operation_mode('cool_only') + elif operation_mode == STATE_ECO: + self.wink.set_operation_mode('auto_eco') + elif operation_mode == STATE_OFF: + self.wink.set_operation_mode('off') + elif operation_mode == STATE_FAN: + self.wink.set_operation_mode('fan_only') + + @property + def target_temperature(self): + """Return the temperature we try to reach.""" + return self.wink.current_max_set_point() + + @property + def target_temperature_low(self): + """Only supports cool.""" + return None + + @property + def target_temperature_high(self): + """Only supports cool.""" + return None + + @property + def current_fan_mode(self): + """Return the current fan mode.""" + speed = self.wink.current_fan_speed() + if speed <= 0.3 and speed >= 0.0: + return SPEED_LOWEST + elif speed <= 0.5 and speed > 0.3: + return SPEED_LOW + elif speed <= 0.8 and speed > 0.5: + return SPEED_MEDIUM + elif speed <= 1.0 and speed > 0.8: + return SPEED_HIGH + else: + return STATE_UNKNOWN + + @property + def fan_list(self): + """List of available fan modes.""" + return [SPEED_LOWEST, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] + + def set_fan_mode(self, mode): + """Set fan speed.""" + if mode == SPEED_LOWEST: + speed = 0.3 + elif mode == SPEED_LOW: + speed = 0.5 + elif mode == SPEED_MEDIUM: + speed = 0.8 + elif mode == SPEED_HIGH: + speed = 1.0 + self.wink.set_ac_fan_speed(speed) diff --git a/homeassistant/components/cover/wink.py b/homeassistant/components/cover/wink.py index 264cec70a7e..7c42aafa350 100644 --- a/homeassistant/components/cover/wink.py +++ b/homeassistant/components/cover/wink.py @@ -6,7 +6,7 @@ https://home-assistant.io/components/cover.wink/ """ from homeassistant.components.cover import CoverDevice -from homeassistant.components.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN DEPENDENCIES = ['wink'] @@ -15,10 +15,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Wink cover platform.""" import pywink - add_devices(WinkCoverDevice(shade, hass) for shade in - pywink.get_shades()) - add_devices(WinkCoverDevice(door, hass) for door in - pywink.get_garage_doors()) + for shade in pywink.get_shades(): + _id = shade.object_id() + shade.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkCoverDevice(shade, hass)]) + for door in pywink.get_garage_doors(): + _id = door.object_id() + door.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkCoverDevice(door, hass)]) class WinkCoverDevice(WinkDevice, CoverDevice): @@ -26,7 +30,7 @@ class WinkCoverDevice(WinkDevice, CoverDevice): def __init__(self, wink, hass): """Initialize the cover.""" - WinkDevice.__init__(self, wink, hass) + super().__init__(wink, hass) def close_cover(self): """Close the shade.""" diff --git a/homeassistant/components/fan/wink.py b/homeassistant/components/fan/wink.py index 74fd06e5516..00eb082212d 100644 --- a/homeassistant/components/fan/wink.py +++ b/homeassistant/components/fan/wink.py @@ -10,7 +10,7 @@ from homeassistant.components.fan import (FanEntity, SPEED_HIGH, SPEED_LOW, SPEED_MEDIUM, STATE_UNKNOWN) from homeassistant.helpers.entity import ToggleEntity -from homeassistant.components.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN _LOGGER = logging.getLogger(__name__) @@ -22,7 +22,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Wink platform.""" import pywink - add_devices(WinkFanDevice(fan, hass) for fan in pywink.get_fans()) + for fan in pywink.get_fans(): + if fan.object_id() + fan.name() not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkFanDevice(fan, hass)]) class WinkFanDevice(WinkDevice, FanEntity): @@ -30,7 +32,7 @@ class WinkFanDevice(WinkDevice, FanEntity): def __init__(self, wink, hass): """Initialize the fan.""" - WinkDevice.__init__(self, wink, hass) + super().__init__(wink, hass) def set_direction(self: ToggleEntity, direction: str) -> None: """Set the direction of the fan.""" diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py index dcff4b31a5c..c89139171bf 100644 --- a/homeassistant/components/light/wink.py +++ b/homeassistant/components/light/wink.py @@ -9,7 +9,7 @@ import colorsys from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_RGB_COLOR, SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_RGB_COLOR, Light) -from homeassistant.components.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN from homeassistant.util import color as color_util from homeassistant.util.color import \ color_temperature_mired_to_kelvin as mired_to_kelvin @@ -23,7 +23,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Wink lights.""" import pywink - add_devices(WinkLight(light, hass) for light in pywink.get_light_bulbs()) + for light in pywink.get_light_bulbs(): + _id = light.object_id() + light.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkLight(light, hass)]) class WinkLight(WinkDevice, Light): @@ -31,7 +34,7 @@ class WinkLight(WinkDevice, Light): def __init__(self, wink, hass): """Initialize the Wink device.""" - WinkDevice.__init__(self, wink, hass) + super().__init__(wink, hass) @property def is_on(self): diff --git a/homeassistant/components/lock/wink.py b/homeassistant/components/lock/wink.py index 4536387e4ac..09b3a673f2d 100644 --- a/homeassistant/components/lock/wink.py +++ b/homeassistant/components/lock/wink.py @@ -6,7 +6,7 @@ https://home-assistant.io/components/lock.wink/ """ from homeassistant.components.lock import LockDevice -from homeassistant.components.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN DEPENDENCIES = ['wink'] @@ -15,7 +15,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Wink platform.""" import pywink - add_devices(WinkLockDevice(lock, hass) for lock in pywink.get_locks()) + for lock in pywink.get_locks(): + _id = lock.object_id + lock.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkLockDevice(lock, hass)]) class WinkLockDevice(WinkDevice, LockDevice): @@ -23,7 +26,7 @@ class WinkLockDevice(WinkDevice, LockDevice): def __init__(self, wink, hass): """Initialize the lock.""" - WinkDevice.__init__(self, wink, hass) + super().__init__(wink, hass) @property def is_locked(self): diff --git a/homeassistant/components/sensor/wink.py b/homeassistant/components/sensor/wink.py index b43952e6330..27cfbd691ad 100644 --- a/homeassistant/components/sensor/wink.py +++ b/homeassistant/components/sensor/wink.py @@ -8,10 +8,10 @@ import logging from homeassistant.const import TEMP_CELSIUS from homeassistant.helpers.entity import Entity -from homeassistant.components.wink import WinkDevice -from homeassistant.loader import get_component +from homeassistant.components.wink import WinkDevice, DOMAIN DEPENDENCIES = ['wink'] +_LOGGER = logging.getLogger(__name__) SENSOR_TYPES = ['temperature', 'humidity', 'balance', 'proximity'] @@ -21,18 +21,29 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import pywink for sensor in pywink.get_sensors(): - if sensor.capability() in SENSOR_TYPES: - add_devices([WinkSensorDevice(sensor, hass)]) + _id = sensor.object_id() + sensor.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + if sensor.capability() in SENSOR_TYPES: + add_devices([WinkSensorDevice(sensor, hass)]) for eggtray in pywink.get_eggtrays(): - add_devices([WinkSensorDevice(eggtray, hass)]) + _id = eggtray.object_id() + eggtray.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkSensorDevice(eggtray, hass)]) + + for tank in pywink.get_propane_tanks(): + _id = tank.object_id() + tank.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkSensorDevice(tank, hass)]) for piggy_bank in pywink.get_piggy_banks(): - try: - if piggy_bank.capability() in SENSOR_TYPES: - add_devices([WinkSensorDevice(piggy_bank, hass)]) - except AttributeError: - logging.getLogger(__name__).info("Device is not a sensor") + _id = piggy_bank.object_id() + piggy_bank.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + try: + if piggy_bank.capability() in SENSOR_TYPES: + add_devices([WinkSensorDevice(piggy_bank, hass)]) + except AttributeError: + _LOGGER.info("Device is not a sensor") class WinkSensorDevice(WinkDevice, Entity): @@ -41,7 +52,6 @@ class WinkSensorDevice(WinkDevice, Entity): def __init__(self, wink, hass): """Initialize the Wink device.""" super().__init__(wink, hass) - wink = get_component('wink') self.capability = self.wink.capability() if self.wink.unit() == '°': self._unit_of_measurement = TEMP_CELSIUS diff --git a/homeassistant/components/switch/wink.py b/homeassistant/components/switch/wink.py index 5df37d87b53..1f534f7290f 100644 --- a/homeassistant/components/switch/wink.py +++ b/homeassistant/components/switch/wink.py @@ -5,7 +5,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.wink/ """ -from homeassistant.components.wink import WinkDevice +from homeassistant.components.wink import WinkDevice, DOMAIN from homeassistant.helpers.entity import ToggleEntity DEPENDENCIES = ['wink'] @@ -16,13 +16,21 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import pywink for switch in pywink.get_switches(): - add_devices([WinkToggleDevice(switch, hass)]) + _id = switch.object_id() + switch.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkToggleDevice(switch, hass)]) for switch in pywink.get_powerstrips(): - add_devices([WinkToggleDevice(switch, hass)]) + _id = switch.object_id() + switch.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkToggleDevice(switch, hass)]) for switch in pywink.get_sirens(): - add_devices([WinkToggleDevice(switch, hass)]) + _id = switch.object_id() + switch.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkToggleDevice(switch, hass)]) for sprinkler in pywink.get_sprinklers(): - add_devices([WinkToggleDevice(sprinkler, hass)]) + _id = sprinkler.object_id() + sprinkler.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkToggleDevice(sprinkler, hass)]) class WinkToggleDevice(WinkDevice, ToggleEntity): @@ -30,7 +38,7 @@ class WinkToggleDevice(WinkDevice, ToggleEntity): def __init__(self, wink, hass): """Initialize the Wink device.""" - WinkDevice.__init__(self, wink, hass) + super().__init__(wink, hass) @property def is_on(self): @@ -44,3 +52,14 @@ class WinkToggleDevice(WinkDevice, ToggleEntity): def turn_off(self): """Turn the device off.""" self.wink.set_state(False) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + try: + event = self.wink.last_event() + except AttributeError: + event = None + return { + 'last_event': event + } diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index c1de7e340c1..704ede0660c 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -15,7 +15,7 @@ from homeassistant.const import ( from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['python-wink==1.0.0', 'pubnubsub-handler==1.0.0'] +REQUIREMENTS = ['python-wink==1.1.0', 'pubnubsub-handler==1.0.0'] _LOGGER = logging.getLogger(__name__) @@ -87,11 +87,16 @@ def setup(hass, config): password = config[DOMAIN][CONF_PASSWORD] payload = {'username': email, 'password': password} token_response = requests.post(CONF_TOKEN_URL, data=payload) - token = token_response.text.split(':')[1].split()[0].rstrip(' Date: Thu, 2 Feb 2017 10:23:13 +0100 Subject: [PATCH 055/157] Modbus write_register accept list --- homeassistant/components/modbus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/modbus.py b/homeassistant/components/modbus.py index 3bf6cbf031a..1f1363f2060 100644 --- a/homeassistant/components/modbus.py +++ b/homeassistant/components/modbus.py @@ -59,7 +59,7 @@ ATTR_VALUE = "value" SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema({ vol.Required(ATTR_UNIT): cv.positive_int, vol.Required(ATTR_ADDRESS): cv.positive_int, - vol.Required(ATTR_VALUE): cv.positive_int + vol.Required(ATTR_VALUE): vol.All(cv.ensure_list, [cv.positive_int]) }) From ff65c2a114dfc1feb02ae704fa77b97b4df7bead Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Thu, 2 Feb 2017 15:15:27 +0100 Subject: [PATCH 056/157] Support for Nuki.io smart locks (#5715) * Support for Nuki.io smart locks * Update requirements and add lock.nuki to .coveragerc * lint: Re-organize imports * Schedule a state update instead of calling directly update_ha_state * Remove update requests altogether * Make sure there is no IO inside properties * Fix: nuki lock are all initialized as "lock.unnamed_device" * Update pynuki to 1.2 to avoid an extra REST API call for each lock init --- .coveragerc | 1 + homeassistant/components/lock/nuki.py | 74 +++++++++++++++++++++++++++ requirements_all.txt | 3 ++ 3 files changed, 78 insertions(+) create mode 100644 homeassistant/components/lock/nuki.py diff --git a/.coveragerc b/.coveragerc index 1662f10b175..6f9980d2819 100644 --- a/.coveragerc +++ b/.coveragerc @@ -209,6 +209,7 @@ omit = homeassistant/components/light/piglow.py homeassistant/components/light/zengge.py homeassistant/components/lirc.py + homeassistant/components/lock/nuki.py homeassistant/components/media_player/anthemav.py homeassistant/components/media_player/aquostv.py homeassistant/components/media_player/braviatv.py diff --git a/homeassistant/components/lock/nuki.py b/homeassistant/components/lock/nuki.py new file mode 100644 index 00000000000..b167c00b9bc --- /dev/null +++ b/homeassistant/components/lock/nuki.py @@ -0,0 +1,74 @@ +""" +Nuki.io lock platform. + +For more details about this platform, please refer to the documentation +https://home-assistant.io/components/lock.nuki/ +""" +from datetime import timedelta +import logging +import voluptuous as vol + +from homeassistant.components.lock import (LockDevice, PLATFORM_SCHEMA) +from homeassistant.const import (CONF_HOST, CONF_PORT, CONF_TOKEN) +from homeassistant.util import Throttle +import homeassistant.helpers.config_validation as cv + + +REQUIREMENTS = ['pynuki==1.2'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_PORT = 8080 + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Required(CONF_TOKEN): cv.string +}) + + +MIN_TIME_BETWEEN_SCANS = timedelta(seconds=30) +MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=5) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the Demo lock platform.""" + from pynuki import NukiBridge + bridge = NukiBridge(config.get(CONF_HOST), config.get(CONF_TOKEN)) + add_devices([NukiLock(lock) for lock in bridge.locks]) + + +class NukiLock(LockDevice): + """Representation of a Nuki lock.""" + + def __init__(self, nuki_lock): + """Initialize the lock.""" + self._nuki_lock = nuki_lock + self._locked = nuki_lock.is_locked + self._name = nuki_lock.name + + @property + def name(self): + """Return the name of the lock.""" + return self._name + + @property + def is_locked(self): + """Return true if lock is locked.""" + return self._locked + + @Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) + def update(self): + """Update the nuki lock properties.""" + self._nuki_lock.update() + self._name = self._nuki_lock.name + self._locked = self._nuki_lock.is_locked + + def lock(self, **kwargs): + """Lock the device.""" + self._nuki_lock.lock() + + def unlock(self, **kwargs): + """Unlock the device.""" + self._nuki_lock.unlock() diff --git a/requirements_all.txt b/requirements_all.txt index f876fd5b997..71895cc6737 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -470,6 +470,9 @@ pynetgear==0.3.3 # homeassistant.components.switch.netio pynetio==0.1.6 +# homeassistant.components.lock.nuki +pynuki==1.2 + # homeassistant.components.sensor.nut pynut2==2.1.2 From 219337a5744b1484a7b2ed72cae7983af7ff9d55 Mon Sep 17 00:00:00 2001 From: Duoxilian Date: Thu, 2 Feb 2017 08:28:32 -0600 Subject: [PATCH 057/157] Cleanup climate and ecobee (#5616) * Remove redundant input validation which is already accomplished through defined schemata. * Rely on defined state attributes for hold mode. * Remove misleading comment. This comment seems to assume that sleep mode is a hold; it is a schedule instead. The code snippets in the comment could never work. * Remove use of constants for hold mode. Will be made irrelevant by a planned change by nordlead2005. --- homeassistant/components/climate/__init__.py | 36 -------------------- homeassistant/components/climate/ecobee.py | 10 ------ 2 files changed, 46 deletions(-) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 0cd9bbe17d3..efc50b1af2f 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -243,12 +243,6 @@ def async_setup(hass, config): away_mode = service.data.get(ATTR_AWAY_MODE) - if away_mode is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_AWAY_MODE, ATTR_AWAY_MODE) - return - _LOGGER.warning( 'This service has been deprecated; use climate.set_hold_mode') for climate in target_climate: @@ -288,12 +282,6 @@ def async_setup(hass, config): aux_heat = service.data.get(ATTR_AUX_HEAT) - if aux_heat is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_AUX_HEAT, ATTR_AUX_HEAT) - return - for climate in target_climate: if aux_heat: yield from climate.async_turn_aux_heat_on() @@ -340,12 +328,6 @@ def async_setup(hass, config): humidity = service.data.get(ATTR_HUMIDITY) - if humidity is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_HUMIDITY, ATTR_HUMIDITY) - return - for climate in target_climate: yield from climate.async_set_humidity(humidity) @@ -363,12 +345,6 @@ def async_setup(hass, config): fan = service.data.get(ATTR_FAN_MODE) - if fan is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_FAN_MODE, ATTR_FAN_MODE) - return - for climate in target_climate: yield from climate.async_set_fan_mode(fan) @@ -386,12 +362,6 @@ def async_setup(hass, config): operation_mode = service.data.get(ATTR_OPERATION_MODE) - if operation_mode is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_OPERATION_MODE, ATTR_OPERATION_MODE) - return - for climate in target_climate: yield from climate.async_set_operation_mode(operation_mode) @@ -409,12 +379,6 @@ def async_setup(hass, config): swing_mode = service.data.get(ATTR_SWING_MODE) - if swing_mode is None: - _LOGGER.error( - "Received call to %s without attribute %s", - SERVICE_SET_SWING_MODE, ATTR_SWING_MODE) - return - for climate in target_climate: yield from climate.async_set_swing_mode(swing_mode) diff --git a/homeassistant/components/climate/ecobee.py b/homeassistant/components/climate/ecobee.py index 8f5e7f5bba5..cdd8bc98169 100644 --- a/homeassistant/components/climate/ecobee.py +++ b/homeassistant/components/climate/ecobee.py @@ -382,13 +382,3 @@ class Thermostat(ClimateDevice): return default else: return 'nextTransition' - - # Sleep mode isn't used in UI yet: - - # def turn_sleep_mode_on(self): - # """ Turns sleep mode on. """ - # self.data.ecobee.set_climate_hold(self.thermostat_index, "sleep") - - # def turn_sleep_mode_off(self): - # """ Turns sleep mode off. """ - # self.data.ecobee.resume_program(self.thermostat_index) From ee551e2a9c090d51eb74227460e86a9cf82d73ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Thu, 2 Feb 2017 16:18:16 +0100 Subject: [PATCH 058/157] up rfxtrx lib (#5721) --- homeassistant/components/rfxtrx.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rfxtrx.py b/homeassistant/components/rfxtrx.py index a208bfcfaa4..caa44d5a8f2 100644 --- a/homeassistant/components/rfxtrx.py +++ b/homeassistant/components/rfxtrx.py @@ -14,7 +14,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.helpers.entity import Entity from homeassistant.const import (ATTR_ENTITY_ID, TEMP_CELSIUS) -REQUIREMENTS = ['pyRFXtrx==0.16.0'] +REQUIREMENTS = ['pyRFXtrx==0.16.1'] DOMAIN = "rfxtrx" diff --git a/requirements_all.txt b/requirements_all.txt index 71895cc6737..e55911f5943 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -396,7 +396,7 @@ pyCEC==0.4.12 pyHS100==0.2.3 # homeassistant.components.rfxtrx -pyRFXtrx==0.16.0 +pyRFXtrx==0.16.1 # homeassistant.components.notify.xmpp pyasn1-modules==0.0.8 From 574384f44630632a4fc0eb9a02f45116a570baf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Thu, 2 Feb 2017 17:08:10 +0100 Subject: [PATCH 059/157] update miflora lib and allow specification of bluetooth adapter (#5720) --- homeassistant/components/sensor/miflora.py | 11 ++++++++--- requirements_all.txt | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/sensor/miflora.py b/homeassistant/components/sensor/miflora.py index 1922d4832ee..2536bcd2bcc 100644 --- a/homeassistant/components/sensor/miflora.py +++ b/homeassistant/components/sensor/miflora.py @@ -14,22 +14,25 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import ( CONF_MONITORED_CONDITIONS, CONF_NAME, CONF_MAC) -REQUIREMENTS = ['miflora==0.1.14'] +REQUIREMENTS = ['miflora==0.1.15'] _LOGGER = logging.getLogger(__name__) +CONF_ADAPTER = 'adapter' CONF_CACHE = 'cache_value' CONF_FORCE_UPDATE = 'force_update' CONF_MEDIAN = 'median' CONF_RETRIES = 'retries' CONF_TIMEOUT = 'timeout' +DEFAULT_ADAPTER = 'hci0' +DEFAULT_UPDATE_INTERVAL = 1200 DEFAULT_FORCE_UPDATE = False DEFAULT_MEDIAN = 3 DEFAULT_NAME = 'Mi Flora' DEFAULT_RETRIES = 2 DEFAULT_TIMEOUT = 10 -DEFAULT_UPDATE_INTERVAL = 1200 + # Sensor types are defined like: Name, units SENSOR_TYPES = { @@ -50,6 +53,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int, vol.Optional(CONF_RETRIES, default=DEFAULT_RETRIES): cv.positive_int, vol.Optional(CONF_CACHE, default=DEFAULT_UPDATE_INTERVAL): cv.positive_int, + vol.Optional(CONF_ADAPTER, default=DEFAULT_ADAPTER): cv.string, }) @@ -59,7 +63,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): cache = config.get(CONF_CACHE) poller = miflora_poller.MiFloraPoller( - config.get(CONF_MAC), cache_timeout=cache) + config.get(CONF_MAC), cache_timeout=cache, + adapter=config.get(CONF_ADAPTER)) force_update = config.get(CONF_FORCE_UPDATE) median = config.get(CONF_MEDIAN) poller.ble_timeout = config.get(CONF_TIMEOUT) diff --git a/requirements_all.txt b/requirements_all.txt index e55911f5943..1413ad4be85 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -319,7 +319,7 @@ messagebird==1.2.0 mficlient==0.3.0 # homeassistant.components.sensor.miflora -miflora==0.1.14 +miflora==0.1.15 # homeassistant.components.sensor.usps myusps==1.0.2 From 2fc3dfff67b2e3483ef62e8693d7a3b9b80ed0ac Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 2 Feb 2017 21:07:00 +0100 Subject: [PATCH 060/157] Migrate fan component to async. (#5723) * Migrate fan component to async. * Fix lint --- homeassistant/components/fan/__init__.py | 147 +++++++++++++++-------- homeassistant/components/fan/demo.py | 10 +- homeassistant/components/fan/mqtt.py | 10 +- 3 files changed, 107 insertions(+), 60 deletions(-) diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index e6da2ff0fd7..a0079d723d6 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -4,7 +4,9 @@ Provides functionality to interact with fans. For more details about this component, please refer to the documentation at https://home-assistant.io/components/fan/ """ +import asyncio from datetime import timedelta +import functools as ft import logging import os @@ -24,6 +26,8 @@ import homeassistant.helpers.config_validation as cv DOMAIN = 'fan' SCAN_INTERVAL = timedelta(seconds=30) +_LOGGER = logging.getLogger(__name__) + GROUP_NAME_ALL_FANS = 'all fans' ENTITY_ID_ALL_FANS = group.ENTITY_ID_FORMAT.format(GROUP_NAME_ALL_FANS) @@ -88,7 +92,32 @@ FAN_SET_DIRECTION_SCHEMA = vol.Schema({ vol.Optional(ATTR_DIRECTION): cv.string }) # type: dict -_LOGGER = logging.getLogger(__name__) +SERVICE_TO_METHOD = { + SERVICE_TURN_ON: { + 'method': 'async_turn_on', + 'schema': FAN_TURN_ON_SCHEMA, + }, + SERVICE_TURN_OFF: { + 'method': 'async_turn_off', + 'schema': FAN_TURN_OFF_SCHEMA, + }, + SERVICE_TOGGLE: { + 'method': 'async_toggle', + 'schema': FAN_TOGGLE_SCHEMA, + }, + SERVICE_SET_SPEED: { + 'method': 'async_set_speed', + 'schema': FAN_SET_SPEED_SCHEMA, + }, + SERVICE_OSCILLATE: { + 'method': 'async_oscillate', + 'schema': FAN_OSCILLATE_SCHEMA, + }, + SERVICE_SET_DIRECTION: { + 'method': 'async_set_direction', + 'schema': FAN_SET_DIRECTION_SCHEMA, + }, +} def is_on(hass, entity_id: str=None) -> bool: @@ -164,60 +193,53 @@ def set_direction(hass, entity_id: str=None, direction: str=None) -> None: hass.services.call(DOMAIN, SERVICE_SET_DIRECTION, data) -def setup(hass, config: dict) -> None: +@asyncio.coroutine +def async_setup(hass, config: dict): """Expose fan control via statemachine and services.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_FANS) - component.setup(config) - def handle_fan_service(service: str) -> None: + yield from component.async_setup(config) + + @asyncio.coroutine + def async_handle_fan_service(service): """Hande service call for fans.""" - # Get the validated data + method = SERVICE_TO_METHOD.get(service.service) params = service.data.copy() # Convert the entity ids to valid fan ids - target_fans = component.extract_from_service(service) + target_fans = component.async_extract_from_service(service) params.pop(ATTR_ENTITY_ID, None) - service_fun = None - for service_def in [SERVICE_TURN_ON, SERVICE_TURN_OFF, - SERVICE_SET_SPEED, SERVICE_OSCILLATE, - SERVICE_SET_DIRECTION]: - if service_def == service.service: - service_fun = service_def - break + for fan in target_fans: + yield from getattr(fan, method['method'])(**params) - if service_fun: - for fan in target_fans: - getattr(fan, service_fun)(**params) + update_tasks = [] - for fan in target_fans: - if fan.should_poll: - fan.update_ha_state(True) - return + for fan in target_fans: + if not fan.should_poll: + continue + + update_coro = hass.loop.create_task( + fan.async_update_ha_state(True)) + if hasattr(fan, 'async_update'): + update_tasks.append(update_coro) + else: + yield from update_coro + + if update_tasks: + yield from asyncio.wait(update_tasks, loop=hass.loop) # Listen for fan service calls. - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_fan_service, - descriptions.get(SERVICE_TURN_ON), - schema=FAN_TURN_ON_SCHEMA) + descriptions = yield from hass.loop.run_in_executor( + None, load_yaml_config_file, os.path.join( + os.path.dirname(__file__), 'services.yaml')) - hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_fan_service, - descriptions.get(SERVICE_TURN_OFF), - schema=FAN_TURN_OFF_SCHEMA) - - hass.services.register(DOMAIN, SERVICE_SET_SPEED, handle_fan_service, - descriptions.get(SERVICE_SET_SPEED), - schema=FAN_SET_SPEED_SCHEMA) - - hass.services.register(DOMAIN, SERVICE_OSCILLATE, handle_fan_service, - descriptions.get(SERVICE_OSCILLATE), - schema=FAN_OSCILLATE_SCHEMA) - - hass.services.register(DOMAIN, SERVICE_SET_DIRECTION, handle_fan_service, - descriptions.get(SERVICE_SET_DIRECTION), - schema=FAN_SET_DIRECTION_SCHEMA) + for service_name in SERVICE_TO_METHOD: + schema = SERVICE_TO_METHOD[service_name].get('schema') + hass.services.async_register( + DOMAIN, service_name, async_handle_fan_service, + descriptions.get(service_name), schema=schema) return True @@ -225,34 +247,57 @@ def setup(hass, config: dict) -> None: class FanEntity(ToggleEntity): """Representation of a fan.""" - # pylint: disable=no-self-use - def set_speed(self: ToggleEntity, speed: str) -> None: """Set the speed of the fan.""" - if speed is SPEED_OFF: - self.turn_off() - return raise NotImplementedError() + def async_set_speed(self: ToggleEntity, speed: str): + """Set the speed of the fan. + + This method must be run in the event loop and returns a coroutine. + """ + if speed is SPEED_OFF: + return self.async_turn_off() + return self.hass.loop.run_in_executor(None, self.set_speed, speed) + def set_direction(self: ToggleEntity, direction: str) -> None: """Set the direction of the fan.""" raise NotImplementedError() + def async_set_direction(self: ToggleEntity, direction: str): + """Set the direction of the fan. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, self.set_direction, direction) + def turn_on(self: ToggleEntity, speed: str=None, **kwargs) -> None: """Turn on the fan.""" - if speed is SPEED_OFF: - self.turn_off() - return raise NotImplementedError() - def turn_off(self: ToggleEntity, **kwargs) -> None: - """Turn off the fan.""" - raise NotImplementedError() + def async_turn_on(self: ToggleEntity, speed: str=None, **kwargs): + """Turn on the fan. + + This method must be run in the event loop and returns a coroutine. + """ + if speed is SPEED_OFF: + return self.async_turn_off() + return self.hass.loop.run_in_executor( + None, ft.partial(self.turn_on, speed, **kwargs)) def oscillate(self: ToggleEntity, oscillating: bool) -> None: """Oscillate the fan.""" pass + def async_oscillate(self: ToggleEntity, oscillating: bool): + """Oscillate the fan. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, self.oscillate, oscillating) + @property def is_on(self): """Return true if the entity is on.""" diff --git a/homeassistant/components/fan/demo.py b/homeassistant/components/fan/demo.py index 6d24f8d3048..931f4914552 100644 --- a/homeassistant/components/fan/demo.py +++ b/homeassistant/components/fan/demo.py @@ -56,8 +56,10 @@ class DemoFan(FanEntity): """Get the list of available speeds.""" return [STATE_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] - def turn_on(self, speed: str=SPEED_MEDIUM) -> None: + def turn_on(self, speed: str=None) -> None: """Turn on the entity.""" + if speed is None: + speed = SPEED_MEDIUM self.set_speed(speed) def turn_off(self) -> None: @@ -68,17 +70,17 @@ class DemoFan(FanEntity): def set_speed(self, speed: str) -> None: """Set the speed of the fan.""" self._speed = speed - self.update_ha_state() + self.schedule_update_ha_state() def set_direction(self, direction: str) -> None: """Set the direction of the fan.""" self.direction = direction - self.update_ha_state() + self.schedule_update_ha_state() def oscillate(self, oscillating: bool) -> None: """Set oscillation.""" self.oscillating = oscillating - self.update_ha_state() + self.schedule_update_ha_state() @property def current_direction(self) -> str: diff --git a/homeassistant/components/fan/mqtt.py b/homeassistant/components/fan/mqtt.py index 4ca1fc8bae4..1d5b7609897 100644 --- a/homeassistant/components/fan/mqtt.py +++ b/homeassistant/components/fan/mqtt.py @@ -150,7 +150,7 @@ class MqttFan(FanEntity): elif payload == self._payload[STATE_OFF]: self._state = False - self.update_ha_state() + self.schedule_update_ha_state() if self._topic[CONF_STATE_TOPIC] is not None: mqtt.subscribe(self._hass, self._topic[CONF_STATE_TOPIC], @@ -165,7 +165,7 @@ class MqttFan(FanEntity): self._speed = SPEED_MEDIUM elif payload == self._payload[SPEED_HIGH]: self._speed = SPEED_HIGH - self.update_ha_state() + self.schedule_update_ha_state() if self._topic[CONF_SPEED_STATE_TOPIC] is not None: mqtt.subscribe(self._hass, self._topic[CONF_SPEED_STATE_TOPIC], @@ -183,7 +183,7 @@ class MqttFan(FanEntity): self._oscillation = True elif payload == self._payload[OSCILLATE_OFF_PAYLOAD]: self._oscillation = False - self.update_ha_state() + self.schedule_update_ha_state() if self._topic[CONF_OSCILLATION_STATE_TOPIC] is not None: mqtt.subscribe(self._hass, @@ -262,7 +262,7 @@ class MqttFan(FanEntity): self._speed = speed mqtt.publish(self._hass, self._topic[CONF_SPEED_COMMAND_TOPIC], mqtt_payload, self._qos, self._retain) - self.update_ha_state() + self.schedule_update_ha_state() def oscillate(self, oscillating: bool) -> None: """Set oscillation.""" @@ -274,4 +274,4 @@ class MqttFan(FanEntity): mqtt.publish(self._hass, self._topic[CONF_OSCILLATION_COMMAND_TOPIC], payload, self._qos, self._retain) - self.update_ha_state() + self.schedule_update_ha_state() From bc65452efba14c1eed09fd7c3b57273b4e771687 Mon Sep 17 00:00:00 2001 From: Colin O'Dell Date: Thu, 2 Feb 2017 15:29:04 -0500 Subject: [PATCH 061/157] QNAP Sensor (#5666) * Implement the QNAP sensor * Add sensors immediately * Remove unnecessary check * Use CONF_SSL instead of CONF_PROTOCOL --- .coveragerc | 1 + homeassistant/components/sensor/qnap.py | 406 ++++++++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 410 insertions(+) create mode 100644 homeassistant/components/sensor/qnap.py diff --git a/.coveragerc b/.coveragerc index 6f9980d2819..1760d976b9d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -330,6 +330,7 @@ omit = homeassistant/components/sensor/pi_hole.py homeassistant/components/sensor/plex.py homeassistant/components/sensor/pvoutput.py + homeassistant/components/sensor/qnap.py homeassistant/components/sensor/sabnzbd.py homeassistant/components/sensor/scrape.py homeassistant/components/sensor/sensehat.py diff --git a/homeassistant/components/sensor/qnap.py b/homeassistant/components/sensor/qnap.py new file mode 100644 index 00000000000..51a83c9371b --- /dev/null +++ b/homeassistant/components/sensor/qnap.py @@ -0,0 +1,406 @@ +""" +Support for QNAP NAS Sensors. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.qnap/ +""" + +import logging +from datetime import timedelta + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.helpers.entity import Entity +from homeassistant.const import ( + CONF_HOST, CONF_USERNAME, CONF_PASSWORD, CONF_PORT, CONF_SSL, + CONF_MONITORED_CONDITIONS, TEMP_CELSIUS) +from homeassistant.util import Throttle +import homeassistant.helpers.config_validation as cv + +import voluptuous as vol + +REQUIREMENTS = ['qnapstats==0.2.1'] + +_LOGGER = logging.getLogger(__name__) + +ATTR_DRIVE = 'Drive' +ATTR_DRIVE_SIZE = 'Drive Size' +ATTR_IP = 'IP Address' +ATTR_MAC = 'MAC Address' +ATTR_MASK = 'Mask' +ATTR_MAX_SPEED = 'Max Speed' +ATTR_MEMORY_SIZE = 'Memory Size' +ATTR_MODEL = 'Model' +ATTR_NAME = 'Name' +ATTR_PACKETS_TX = 'Packets (TX)' +ATTR_PACKETS_RX = 'Packets (RX)' +ATTR_PACKETS_ERR = 'Packets (Err)' +ATTR_SERIAL = 'Serial #' +ATTR_TYPE = 'Type' +ATTR_UPTIME = 'Uptime' +ATTR_VOLUME_SIZE = 'Volume Size' + +CONF_DRIVES = 'drives' +CONF_NICS = 'nics' +CONF_VOLUMES = 'volumes' +DEFAULT_NAME = 'QNAP' +DEFAULT_PORT = 8080 + +MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1) + +_HEALTH_MON_COND = { + 'status': ['Status', None, 'mdi:checkbox-marked-circle-outline'], +} +_CPU_MON_COND = { + 'cpu_temp': ['CPU Temperature', TEMP_CELSIUS, 'mdi:thermometer'], + 'cpu_usage': ['CPU Usage', '%', 'mdi:chip'], +} +_MEMORY_MON_COND = { + 'memory_free': ['Memory Available', 'GB', 'mdi:memory'], + 'memory_used': ['Memory Used', 'GB', 'mdi:memory'], + 'memory_percent_used': ['Memory Usage', '%', 'mdi:memory'], +} +_NETWORK_MON_COND = { + 'network_link_status': ['Network Link', None, + 'mdi:checkbox-marked-circle-outline'], + 'network_tx': ['Network Up', 'MB/s', 'mdi:upload'], + 'network_rx': ['Network Down', 'MB/s', 'mdi:download'], +} +_DRIVE_MON_COND = { + 'drive_smart_status': ['SMART Status', None, + 'mdi:checkbox-marked-circle-outline'], + 'drive_temp': ['Temperature', TEMP_CELSIUS, 'mdi:thermometer'], +} +_VOLUME_MON_COND = { + 'volume_size_used': ['Used Space', 'GB', 'mdi:chart-pie'], + 'volume_size_free': ['Free Space', 'GB', 'mdi:chart-pie'], + 'volume_percentage_used': ['Volume Used', '%', 'mdi:chart-pie'], +} + +_MONITORED_CONDITIONS = list(_HEALTH_MON_COND.keys()) + \ + list(_CPU_MON_COND.keys()) + \ + list(_MEMORY_MON_COND.keys()) + \ + list(_NETWORK_MON_COND.keys()) + \ + list(_DRIVE_MON_COND.keys()) + \ + list(_VOLUME_MON_COND.keys()) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_SSL, default=False): cv.boolean, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_MONITORED_CONDITIONS): + vol.All(cv.ensure_list, [vol.In(_MONITORED_CONDITIONS)]), + vol.Optional(CONF_NICS, default=None): cv.ensure_list, + vol.Optional(CONF_DRIVES, default=None): cv.ensure_list, + vol.Optional(CONF_VOLUMES, default=None): cv.ensure_list, +}) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the QNAP NAS sensor.""" + api = QNAPStatsAPI(config) + api.update() + + sensors = [] + + # Basic sensors + for variable in config[CONF_MONITORED_CONDITIONS]: + if variable in _HEALTH_MON_COND: + sensors.append(QNAPHealthStatus(api, variable, + _HEALTH_MON_COND[variable])) + if variable in _CPU_MON_COND: + sensors.append(QNAPCPUSensor(api, variable, + _CPU_MON_COND[variable])) + if variable in _MEMORY_MON_COND: + sensors.append(QNAPMemorySensor(api, variable, + _MEMORY_MON_COND[variable])) + + # Network sensors + nics = config[CONF_NICS] + if nics is None: + nics = api.data["system_stats"]["nics"].keys() + + for nic in nics: + sensors += [QNAPNetworkSensor(api, variable, + _NETWORK_MON_COND[variable], nic) + for variable in config[CONF_MONITORED_CONDITIONS] + if variable in _NETWORK_MON_COND] + + # Drive sensors + drives = config[CONF_DRIVES] + if drives is None: + drives = api.data["smart_drive_health"].keys() + + for drive in drives: + sensors += [QNAPDriveSensor(api, variable, + _DRIVE_MON_COND[variable], drive) + for variable in config[CONF_MONITORED_CONDITIONS] + if variable in _DRIVE_MON_COND] + + # Volume sensors + volumes = config[CONF_VOLUMES] + if volumes is None: + volumes = api.data["volumes"].keys() + + for volume in volumes: + sensors += [QNAPVolumeSensor(api, variable, + _VOLUME_MON_COND[variable], volume) + for variable in config[CONF_MONITORED_CONDITIONS] + if variable in _VOLUME_MON_COND] + + add_devices(sensors) + + +def round_nicely(number): + """Round a number based on its size (so it looks nice).""" + if number < 10: + return round(number, 2) + if number < 100: + return round(number, 1) + + return round(number) + + +class QNAPStatsAPI(object): + """Class to interface with the API.""" + + def __init__(self, config): + """Initialize the API wrapper.""" + from qnapstats import QNAPStats + + protocol = "https" if config.get(CONF_SSL) else "http" + self._api = QNAPStats( + protocol + "://" + config.get(CONF_HOST), + config.get(CONF_PORT), + config.get(CONF_USERNAME), + config.get(CONF_PASSWORD)) + + self.data = {} + + # pylint: disable=bare-except + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Update API information and store locally.""" + try: + self.data["system_stats"] = self._api.get_system_stats() + self.data["system_health"] = self._api.get_system_health() + self.data["smart_drive_health"] = self._api.get_smart_disk_health() + self.data["volumes"] = self._api.get_volumes() + self.data["bandwidth"] = self._api.get_bandwidth() + except: + _LOGGER.exception("Failed to fetch QNAP stats from the NAS.") + + +class QNAPSensor(Entity): + """Base class for a QNAP sensor.""" + + def __init__(self, api, variable, variable_info, monitor_device=None): + """Initialize the sensor.""" + self.var_id = variable + self.var_name = variable_info[0] + self.var_units = variable_info[1] + self.var_icon = variable_info[2] + self.monitor_device = monitor_device + self._api = api + + @property + def name(self): + """Return the name of the sensor, if any.""" + server_name = self._api.data["system_stats"]["system"]["name"] + + if self.monitor_device is not None: + return "{} {} ({})".format(server_name, + self.var_name, + self.monitor_device) + else: + return "{} {}".format(server_name, + self.var_name) + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return self.var_icon + + @property + def unit_of_measurement(self): + """Return the unit the value is expressed in.""" + return self.var_units + + def update(self): + """Get the latest data for the states.""" + self._api.update() + + +class QNAPCPUSensor(QNAPSensor): + """A QNAP sensor that monitors CPU stats.""" + + @property + def state(self): + """Return the state of the sensor.""" + if self.var_id == "cpu_temp": + return self._api.data["system_stats"]["cpu"]["temp_c"] + elif self.var_id == "cpu_usage": + return self._api.data["system_stats"]["cpu"]["usage_percent"] + + +class QNAPMemorySensor(QNAPSensor): + """A QNAP sensor that monitors memory stats.""" + + @property + def state(self): + """Return the state of the sensor.""" + free = float(self._api.data["system_stats"]["memory"]["free"]) / 1024 + if self.var_id == "memory_free": + return round_nicely(free) + + total = float(self._api.data["system_stats"]["memory"]["total"]) / 1024 + + used = total - free + if self.var_id == "memory_used": + return round_nicely(used) + + if self.var_id == "memory_percent_used": + return round(used / total * 100) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + if self._api.data: + data = self._api.data["system_stats"]["memory"] + size = round_nicely(float(data["total"]) / 1024) + return { + ATTR_MEMORY_SIZE: "{} GB".format(size), + } + + +class QNAPNetworkSensor(QNAPSensor): + """A QNAP sensor that monitors network stats.""" + + @property + def state(self): + """Return the state of the sensor.""" + if self.var_id == "network_link_status": + nic = self._api.data["system_stats"]["nics"][self.monitor_device] + return nic["link_status"] + + data = self._api.data["bandwidth"][self.monitor_device] + if self.var_id == "network_tx": + return round_nicely(data["tx"] / 1024 / 1024) + + if self.var_id == "network_rx": + return round_nicely(data["rx"] / 1024 / 1024) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + if self._api.data: + data = self._api.data["system_stats"]["nics"][self.monitor_device] + return { + ATTR_IP: data["ip"], + ATTR_MASK: data["mask"], + ATTR_MAC: data["mac"], + ATTR_MAX_SPEED: data["max_speed"], + ATTR_PACKETS_TX: data["tx_packets"], + ATTR_PACKETS_RX: data["rx_packets"], + ATTR_PACKETS_ERR: data["err_packets"] + } + + +class QNAPHealthStatus(QNAPSensor): + """A QNAP sensor that monitors overall system health.""" + + @property + def state(self): + """Return the state of the sensor.""" + return self._api.data["system_health"] + + @property + def device_state_attributes(self): + """Return the state attributes.""" + if self._api.data: + data = self._api.data["system_stats"] + days = int(data["uptime"]["days"]) + hours = int(data["uptime"]["hours"]) + minutes = int(data["uptime"]["minutes"]) + + return { + ATTR_NAME: data["system"]["name"], + ATTR_MODEL: data["system"]["model"], + ATTR_SERIAL: data["system"]["serial_number"], + ATTR_UPTIME: "{:0>2d}d {:0>2d}h {:0>2d}m".format(days, + hours, + minutes) + } + + +class QNAPDriveSensor(QNAPSensor): + """A QNAP sensor that monitors HDD/SSD drive stats.""" + + @property + def state(self): + """Return the state of the sensor.""" + data = self._api.data["smart_drive_health"][self.monitor_device] + + if self.var_id == "drive_smart_status": + return data["health"] + + if self.var_id == "drive_temp": + return int(data["temp_c"]) + + @property + def name(self): + """Return the name of the sensor, if any.""" + server_name = self._api.data["system_stats"]["system"]["name"] + + return "{} {} (Drive {})".format( + server_name, + self.var_name, + self.monitor_device + ) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + if self._api.data: + data = self._api.data["smart_drive_health"][self.monitor_device] + return { + ATTR_DRIVE: data["drive_number"], + ATTR_MODEL: data["model"], + ATTR_SERIAL: data["serial"], + ATTR_TYPE: data["type"], + } + + +class QNAPVolumeSensor(QNAPSensor): + """A QNAP sensor that monitors storage volume stats.""" + + @property + def state(self): + """Return the state of the sensor.""" + data = self._api.data["volumes"][self.monitor_device] + + free_gb = int(data["free_size"]) / 1024 / 1024 / 1024 + if self.var_id == "volume_size_free": + return round_nicely(free_gb) + + total_gb = int(data["total_size"]) / 1024 / 1024 / 1024 + + used_gb = total_gb - free_gb + if self.var_id == "volume_size_used": + return round_nicely(used_gb) + + if self.var_id == "volume_percentage_used": + return round(used_gb / total_gb * 100) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + if self._api.data: + data = self._api.data["volumes"][self.monitor_device] + total_gb = int(data["total_size"]) / 1024 / 1024 / 1024 + + return { + ATTR_VOLUME_SIZE: "{} GB".format(round_nicely(total_gb)), + } diff --git a/requirements_all.txt b/requirements_all.txt index 1413ad4be85..7193b75467d 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -560,6 +560,9 @@ pywemo==0.4.11 # homeassistant.components.zabbix pyzabbix==0.7.4 +# homeassistant.components.sensor.qnap +qnapstats==0.2.1 + # homeassistant.components.climate.radiotherm radiotherm==1.2 From f63874eb8cfea537861b2cf142e6372191543676 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 2 Feb 2017 21:39:13 +0100 Subject: [PATCH 062/157] Migrate cover to async. (#5717) --- homeassistant/components/cover/__init__.py | 125 ++++++++++++++++---- homeassistant/components/cover/demo.py | 4 +- homeassistant/components/cover/garadget.py | 3 +- homeassistant/components/cover/mqtt.py | 4 +- homeassistant/components/cover/mysensors.py | 6 +- 5 files changed, 110 insertions(+), 32 deletions(-) diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index da473df111e..1dc6101f1e9 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -4,9 +4,11 @@ Support for Cover devices. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/cover/ """ -import os +import asyncio from datetime import timedelta +import functools as ft import logging +import os import voluptuous as vol @@ -53,17 +55,17 @@ COVER_SET_COVER_TILT_POSITION_SCHEMA = COVER_SERVICE_SCHEMA.extend({ }) SERVICE_TO_METHOD = { - SERVICE_OPEN_COVER: {'method': 'open_cover'}, - SERVICE_CLOSE_COVER: {'method': 'close_cover'}, + SERVICE_OPEN_COVER: {'method': 'async_open_cover'}, + SERVICE_CLOSE_COVER: {'method': 'async_close_cover'}, SERVICE_SET_COVER_POSITION: { - 'method': 'set_cover_position', + 'method': 'async_set_cover_position', 'schema': COVER_SET_COVER_POSITION_SCHEMA}, - SERVICE_STOP_COVER: {'method': 'stop_cover'}, - SERVICE_OPEN_COVER_TILT: {'method': 'open_cover_tilt'}, - SERVICE_CLOSE_COVER_TILT: {'method': 'close_cover_tilt'}, - SERVICE_STOP_COVER_TILT: {'method': 'stop_cover_tilt'}, + SERVICE_STOP_COVER: {'method': 'async_stop_cover'}, + SERVICE_OPEN_COVER_TILT: {'method': 'async_open_cover_tilt'}, + SERVICE_CLOSE_COVER_TILT: {'method': 'async_close_cover_tilt'}, + SERVICE_STOP_COVER_TILT: {'method': 'async_stop_cover_tilt'}, SERVICE_SET_COVER_TILT_POSITION: { - 'method': 'set_cover_tilt_position', + 'method': 'async_set_cover_tilt_position', 'schema': COVER_SET_COVER_TILT_POSITION_SCHEMA}, } @@ -124,40 +126,53 @@ def stop_cover_tilt(hass, entity_id=None): hass.services.call(DOMAIN, SERVICE_STOP_COVER_TILT, data) -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Track states and offer events for covers.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_COVERS) - component.setup(config) - def handle_cover_service(service): + yield from component.async_setup(config) + + @asyncio.coroutine + def async_handle_cover_service(service): """Handle calls to the cover services.""" + covers = component.async_extract_from_service(service) method = SERVICE_TO_METHOD.get(service.service) params = service.data.copy() params.pop(ATTR_ENTITY_ID, None) - if not method: - return - - covers = component.extract_from_service(service) - + # call method for cover in covers: - getattr(cover, method['method'])(**params) + yield from getattr(cover, method['method'])(**params) + + update_tasks = [] for cover in covers: if not cover.should_poll: continue - cover.update_ha_state(True) + update_coro = hass.loop.create_task( + cover.async_update_ha_state(True)) + if hasattr(cover, 'async_update'): + update_tasks.append(update_coro) + else: + yield from update_coro - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) + if update_tasks: + yield from asyncio.wait(update_tasks, loop=hass.loop) + + descriptions = yield from hass.loop.run_in_executor( + None, load_yaml_config_file, os.path.join( + os.path.dirname(__file__), 'services.yaml')) for service_name in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service_name].get( 'schema', COVER_SERVICE_SCHEMA) - hass.services.register(DOMAIN, service_name, handle_cover_service, - descriptions.get(service_name), schema=schema) + hass.services.async_register( + DOMAIN, service_name, async_handle_cover_service, + descriptions.get(service_name), schema=schema) + return True @@ -215,30 +230,94 @@ class CoverDevice(Entity): """Open the cover.""" raise NotImplementedError() + def async_open_cover(self, **kwargs): + """Open the cover. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.open_cover, **kwargs)) + def close_cover(self, **kwargs): """Close cover.""" raise NotImplementedError() + def async_close_cover(self, **kwargs): + """Close cover. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.close_cover, **kwargs)) + def set_cover_position(self, **kwargs): """Move the cover to a specific position.""" pass + def async_set_cover_position(self, **kwargs): + """Move the cover to a specific position. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.set_cover_position, **kwargs)) + def stop_cover(self, **kwargs): """Stop the cover.""" pass + def async_stop_cover(self, **kwargs): + """Stop the cover. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.stop_cover, **kwargs)) + def open_cover_tilt(self, **kwargs): """Open the cover tilt.""" pass + def async_open_cover_tilt(self, **kwargs): + """Open the cover tilt. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.open_cover_tilt, **kwargs)) + def close_cover_tilt(self, **kwargs): """Close the cover tilt.""" pass + def async_close_cover_tilt(self, **kwargs): + """Close the cover tilt. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.close_cover_tilt, **kwargs)) + def set_cover_tilt_position(self, **kwargs): """Move the cover tilt to a specific position.""" pass + def async_set_cover_tilt_position(self, **kwargs): + """Move the cover tilt to a specific position. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.set_cover_tilt_position, **kwargs)) + def stop_cover_tilt(self, **kwargs): """Stop the cover.""" pass + + def async_stop_cover_tilt(self, **kwargs): + """Stop the cover. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.stop_cover_tilt, **kwargs)) diff --git a/homeassistant/components/cover/demo.py b/homeassistant/components/cover/demo.py index 5929ab1851a..070c37a0e3c 100644 --- a/homeassistant/components/cover/demo.py +++ b/homeassistant/components/cover/demo.py @@ -149,7 +149,7 @@ class DemoCover(CoverDevice): if self._position in (100, 0, self._set_position): self.stop_cover() - self.update_ha_state() + self.schedule_update_ha_state() def _listen_cover_tilt(self): """Listen for changes in cover tilt.""" @@ -167,4 +167,4 @@ class DemoCover(CoverDevice): if self._tilt_position in (100, 0, self._set_tilt_position): self.stop_cover_tilt() - self.update_ha_state() + self.schedule_update_ha_state() diff --git a/homeassistant/components/cover/garadget.py b/homeassistant/components/cover/garadget.py index 813ddea7170..1847e58c4a5 100644 --- a/homeassistant/components/cover/garadget.py +++ b/homeassistant/components/cover/garadget.py @@ -199,8 +199,7 @@ class GaradgetCover(CoverDevice): def _check_state(self, now): """Check the state of the service during an operation.""" - self.update() - self.update_ha_state() + self.schedule_update_ha_state(True) def close_cover(self): """Close the cover.""" diff --git a/homeassistant/components/cover/mqtt.py b/homeassistant/components/cover/mqtt.py index 44b59133d21..aa549986533 100644 --- a/homeassistant/components/cover/mqtt.py +++ b/homeassistant/components/cover/mqtt.py @@ -151,7 +151,7 @@ class MqttCover(CoverDevice): if self._optimistic: # Optimistically assume that cover has changed state. self._state = False - self.update_ha_state() + self.schedule_update_ha_state() def close_cover(self, **kwargs): """Move the cover down.""" @@ -160,7 +160,7 @@ class MqttCover(CoverDevice): if self._optimistic: # Optimistically assume that cover has changed state. self._state = True - self.update_ha_state() + self.schedule_update_ha_state() def stop_cover(self, **kwargs): """Stop the device.""" diff --git a/homeassistant/components/cover/mysensors.py b/homeassistant/components/cover/mysensors.py index a75ad36354b..7daadebadad 100644 --- a/homeassistant/components/cover/mysensors.py +++ b/homeassistant/components/cover/mysensors.py @@ -75,7 +75,7 @@ class MySensorsCover(mysensors.MySensorsDeviceEntity, CoverDevice): self._values[set_req.V_DIMMER] = 100 else: self._values[set_req.V_LIGHT] = STATE_ON - self.update_ha_state() + self.schedule_update_ha_state() def close_cover(self, **kwargs): """Move the cover down.""" @@ -88,7 +88,7 @@ class MySensorsCover(mysensors.MySensorsDeviceEntity, CoverDevice): self._values[set_req.V_DIMMER] = 0 else: self._values[set_req.V_LIGHT] = STATE_OFF - self.update_ha_state() + self.schedule_update_ha_state() def set_cover_position(self, **kwargs): """Move the cover to a specific position.""" @@ -99,7 +99,7 @@ class MySensorsCover(mysensors.MySensorsDeviceEntity, CoverDevice): if self.gateway.optimistic: # Optimistically assume that cover has changed state. self._values[set_req.V_DIMMER] = position - self.update_ha_state() + self.schedule_update_ha_state() def stop_cover(self, **kwargs): """Stop the device.""" From dfb991ce1953d5aaf8c852d24d0273db24b35501 Mon Sep 17 00:00:00 2001 From: Valentin Alexeev Date: Thu, 2 Feb 2017 22:59:52 +0200 Subject: [PATCH 063/157] Bump pwaqi to 1.4 to fix a typo in the underlying library. (#5716) --- homeassistant/components/sensor/waqi.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/waqi.py b/homeassistant/components/sensor/waqi.py index 73de98c0168..699b617b7ee 100644 --- a/homeassistant/components/sensor/waqi.py +++ b/homeassistant/components/sensor/waqi.py @@ -16,7 +16,7 @@ from homeassistant.helpers.config_validation import PLATFORM_SCHEMA from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle -REQUIREMENTS = ['pwaqi==1.3'] +REQUIREMENTS = ['pwaqi==1.4'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 7193b75467d..684c6e712f4 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -384,7 +384,7 @@ pushbullet.py==0.10.0 pushetta==1.0.15 # homeassistant.components.sensor.waqi -pwaqi==1.3 +pwaqi==1.4 # homeassistant.components.sensor.cpuspeed py-cpuinfo==0.2.3 From 4b62a0d924f49ddd10251e0464c48acd88d65804 Mon Sep 17 00:00:00 2001 From: miniconfig Date: Thu, 2 Feb 2017 21:46:35 -0500 Subject: [PATCH 064/157] Updated openvse sensor component to use new structure of openevsewifi library. --- homeassistant/components/sensor/openevse.py | 4 ++-- requirements_all.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/openevse.py b/homeassistant/components/sensor/openevse.py index 25b068be5ad..4d1fad49fb0 100644 --- a/homeassistant/components/sensor/openevse.py +++ b/homeassistant/components/sensor/openevse.py @@ -18,7 +18,7 @@ from homeassistant.const import CONF_MONITORED_VARIABLES from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['openevsewifi==0.2'] +REQUIREMENTS = ['openevsewifi==0.4'] SENSOR_TYPES = { 'status': ['Charging Status', None], 'charge_time': ['Charge Time Elapsed', 'minutes'], @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the OpenEVSE sensor.""" - from openevsewifi import openevsewifi + import openevsewifi host = config.get(CONF_HOST) monitored_variables = config.get(CONF_MONITORED_VARIABLES) diff --git a/requirements_all.txt b/requirements_all.txt index 5a82a3e383f..c85b365050b 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -334,7 +334,7 @@ neurio==0.3.1 oauth2client==3.0.0 # homeassistant.components.sensor.openevse -openevsewifi==0.2 +openevsewifi==0.4 # homeassistant.components.switch.orvibo orvibo==1.1.1 From 6a64e79d7b780418f1af39b895d37d5c1a8fecab Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Thu, 2 Feb 2017 22:04:14 -0500 Subject: [PATCH 065/157] [recorder] Index events time_fired to improve logbook performance (#5633) * Index events time_fired to improve logbook perf. * Updated implementation to track schema versions * Added tests for schema migration support logic * Rename check_schema to migrate_schema --- homeassistant/components/recorder/__init__.py | 74 +++++++++++++++++++ homeassistant/components/recorder/models.py | 13 +++- tests/components/recorder/test_init.py | 24 ++++++ 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 3d8d1357b0f..9040d1f9fde 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -305,8 +305,82 @@ class Recorder(threading.Thread): models.Base.metadata.create_all(self.engine) session_factory = sessionmaker(bind=self.engine) Session = scoped_session(session_factory) + self._migrate_schema() self.db_ready.set() + def _migrate_schema(self): + """Check if the schema needs to be upgraded.""" + import homeassistant.components.recorder.models as models + schema_changes = models.SchemaChanges + current_version = getattr(Session.query(schema_changes).order_by( + schema_changes.change_id.desc()).first(), 'schema_version', None) + + if current_version == models.SCHEMA_VERSION: + return + _LOGGER.debug("Schema version incorrect: %d", current_version) + + if current_version is None: + current_version = self._inspect_schema_version() + _LOGGER.debug("No schema version found. Inspected version: %d", + current_version) + + for version in range(current_version, models.SCHEMA_VERSION): + new_version = version + 1 + _LOGGER.info( + "Upgrading recorder db schema to version %d", new_version) + self._apply_update(new_version) + self._commit(schema_changes(schema_version=new_version)) + _LOGGER.info( + "Upgraded recorder db schema to version %d", new_version) + + def _apply_update(self, new_version): + """Perform operations to bring schema up to date.""" + from sqlalchemy import Index, Table + import homeassistant.components.recorder.models as models + + if new_version == 1: + def create_index(table_name, column_name): + """Create an index for the specified table and column.""" + table = Table(table_name, models.Base.metadata) + index_name = "_".join(("ix", table_name, column_name)) + index = Index(index_name, getattr(table.c, column_name)) + _LOGGER.debug("Creating index for table %s column %s", + table_name, column_name) + index.create(self.engine) + _LOGGER.debug("Index creation done for table %s column %s", + table_name, column_name) + + create_index("events", "time_fired") + else: + raise ValueError("No schema migration defined for version {}" + .format(new_version)) + + def _inspect_schema_version(self): + """Determine the schema version by inspecting the db structure. + + When the schema verison is not present in the db, either db was just + created with the correct schema, or this is a db created before schema + versions were tracked. For now, we'll test if the changes for schema + version 1 are present to make the determination. Eventually this logic + can be removed and we can assume a new db is being created. + """ + from sqlalchemy.engine import reflection + import homeassistant.components.recorder.models as models + inspector = reflection.Inspector.from_engine(self.engine) + indexes = inspector.get_indexes("events") + for index in indexes: + if index['column_names'] == ["time_fired"]: + # Schema addition from version 1 detected. This is a new db. + current_version = models.SchemaChanges( + schema_version=models.SCHEMA_VERSION) + self._commit(current_version) + return models.SCHEMA_VERSION + + # Version 1 schema changes not found, this db needs to be migrated. + current_version = models.SchemaChanges(schema_version=0) + self._commit(current_version) + return current_version.schema_version + def _close_connection(self): """Close the connection.""" global Session # pylint: disable=global-statement diff --git a/homeassistant/components/recorder/models.py b/homeassistant/components/recorder/models.py index 3b7b5aca1cb..4bc044a51bd 100644 --- a/homeassistant/components/recorder/models.py +++ b/homeassistant/components/recorder/models.py @@ -16,6 +16,8 @@ from homeassistant.remote import JSONEncoder # pylint: disable=invalid-name Base = declarative_base() +SCHEMA_VERSION = 1 + _LOGGER = logging.getLogger(__name__) @@ -27,7 +29,7 @@ class Events(Base): # type: ignore event_type = Column(String(32), index=True) event_data = Column(Text) origin = Column(String(32)) - time_fired = Column(DateTime(timezone=True)) + time_fired = Column(DateTime(timezone=True), index=True) created = Column(DateTime(timezone=True), default=datetime.utcnow) @staticmethod @@ -149,6 +151,15 @@ class RecorderRuns(Base): # type: ignore return self +class SchemaChanges(Base): # type: ignore + """Representation of schema version changes.""" + + __tablename__ = 'schema_changes' + change_id = Column(Integer, primary_key=True) + schema_version = Column(Integer) + changed = Column(DateTime(timezone=True), default=datetime.utcnow) + + def _process_timestamp(ts): """Process a timestamp into datetime object.""" if ts is None: diff --git a/tests/components/recorder/test_init.py b/tests/components/recorder/test_init.py index e8a73e347ff..f729303c685 100644 --- a/tests/components/recorder/test_init.py +++ b/tests/components/recorder/test_init.py @@ -3,6 +3,7 @@ import json from datetime import datetime, timedelta import unittest +from unittest.mock import patch, call import pytest from homeassistant.core import callback @@ -190,6 +191,29 @@ class TestRecorder(unittest.TestCase): self.assertEqual(states.count(), 5) self.assertEqual(events.count(), 5) + def test_schema_no_recheck(self): + """Test that schema is not double-checked when up-to-date.""" + with patch.object(recorder._INSTANCE, '_apply_update') as update, \ + patch.object(recorder._INSTANCE, '_inspect_schema_version') \ + as inspect: + recorder._INSTANCE._migrate_schema() + self.assertEqual(update.call_count, 0) + self.assertEqual(inspect.call_count, 0) + + def test_invalid_update(self): + """Test that an invalid new version raises an exception.""" + with self.assertRaises(ValueError): + recorder._INSTANCE._apply_update(-1) + + def test_schema_update_calls(self): + """Test that schema migrations occurr in correct order.""" + test_version = recorder.models.SchemaChanges(schema_version=0) + self.session.add(test_version) + with patch.object(recorder._INSTANCE, '_apply_update') as update: + recorder._INSTANCE._migrate_schema() + update.assert_has_calls([call(version+1) for version in range( + 0, recorder.models.SCHEMA_VERSION)]) + @pytest.fixture def hass_recorder(): From 537355924fd6190f6e3fd996afd4fef74fc4092b Mon Sep 17 00:00:00 2001 From: Ryan Kraus Date: Fri, 3 Feb 2017 00:20:51 -0500 Subject: [PATCH 066/157] Alert Component (#5201) --- homeassistant/components/alert.py | 275 +++++++++++++++++++++++++ homeassistant/components/services.yaml | 25 +++ tests/components/test_alert.py | 172 ++++++++++++++++ 3 files changed, 472 insertions(+) create mode 100644 homeassistant/components/alert.py create mode 100644 tests/components/test_alert.py diff --git a/homeassistant/components/alert.py b/homeassistant/components/alert.py new file mode 100644 index 00000000000..dc0774edef2 --- /dev/null +++ b/homeassistant/components/alert.py @@ -0,0 +1,275 @@ +""" +Support for repeating alerts when conditions are met. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/alert/ +""" +import asyncio +from datetime import datetime, timedelta +import logging +import os + +import voluptuous as vol + +from homeassistant.core import callback +from homeassistant.config import load_yaml_config_file +from homeassistant.const import (CONF_ENTITY_ID, STATE_IDLE, CONF_NAME, + CONF_STATE, STATE_ON, STATE_OFF, + SERVICE_TURN_ON, SERVICE_TURN_OFF, + SERVICE_TOGGLE, ATTR_ENTITY_ID) +from homeassistant.helpers.entity import ToggleEntity +from homeassistant.helpers import service, event +from homeassistant.util.async import run_callback_threadsafe +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = 'alert' +ENTITY_ID_FORMAT = DOMAIN + '.{}' + +CONF_CAN_ACK = 'can_acknowledge' +CONF_NOTIFIERS = 'notifiers' +CONF_REPEAT = 'repeat' +CONF_SKIP_FIRST = 'skip_first' + +ALERT_SCHEMA = vol.Schema({ + vol.Required(CONF_NAME): cv.string, + vol.Required(CONF_ENTITY_ID): cv.entity_id, + vol.Required(CONF_STATE, default=STATE_ON): cv.string, + vol.Required(CONF_REPEAT): vol.All(cv.ensure_list, [vol.Coerce(float)]), + vol.Required(CONF_CAN_ACK, default=True): cv.boolean, + vol.Required(CONF_SKIP_FIRST, default=False): cv.boolean, + vol.Required(CONF_NOTIFIERS): cv.ensure_list}) + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + cv.slug: ALERT_SCHEMA, + }), +}, extra=vol.ALLOW_EXTRA) + + +ALERT_SERVICE_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_ids, +}) + + +def is_on(hass, entity_id): + """Return if the alert is firing and not acknowledged.""" + return hass.states.is_state(entity_id, STATE_ON) + + +def turn_on(hass, entity_id): + """Reset the alert.""" + run_callback_threadsafe(hass.loop, async_turn_on, hass, entity_id) + + +@callback +def async_turn_on(hass, entity_id): + """Async reset the alert.""" + data = {ATTR_ENTITY_ID: entity_id} + hass.async_add_job( + hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data)) + + +def turn_off(hass, entity_id): + """Acknowledge alert.""" + run_callback_threadsafe(hass.loop, async_turn_off, hass, entity_id) + + +@callback +def async_turn_off(hass, entity_id): + """Async acknowledge the alert.""" + data = {ATTR_ENTITY_ID: entity_id} + hass.async_add_job( + hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data)) + + +def toggle(hass, entity_id): + """Toggle acknowledgement of alert.""" + run_callback_threadsafe(hass.loop, async_toggle, hass, entity_id) + + +@callback +def async_toggle(hass, entity_id): + """Async toggle acknowledgement of alert.""" + data = {ATTR_ENTITY_ID: entity_id} + hass.async_add_job( + hass.services.async_call(DOMAIN, SERVICE_TOGGLE, data)) + + +@asyncio.coroutine +def async_setup(hass, config): + """Setup alert component.""" + alerts = config.get(DOMAIN) + all_alerts = {} + + @asyncio.coroutine + def async_handle_alert_service(service_call): + """Handle calls to alert services.""" + alert_ids = service.extract_entity_ids(hass, service_call) + + for alert_id in alert_ids: + alert = all_alerts[alert_id] + if service_call.service == SERVICE_TURN_ON: + yield from alert.async_turn_on() + elif service_call.service == SERVICE_TOGGLE: + yield from alert.async_toggle() + else: + yield from alert.async_turn_off() + + # setup alerts + for entity_id, alert in alerts.items(): + entity = Alert(hass, entity_id, + alert[CONF_NAME], alert[CONF_ENTITY_ID], + alert[CONF_STATE], alert[CONF_REPEAT], + alert[CONF_SKIP_FIRST], alert[CONF_NOTIFIERS], + alert[CONF_CAN_ACK]) + all_alerts[entity.entity_id] = entity + + # read descriptions + descriptions = yield from hass.loop.run_in_executor( + None, load_yaml_config_file, os.path.join( + os.path.dirname(__file__), 'services.yaml')) + descriptions = descriptions.get(DOMAIN, {}) + + # setup service calls + hass.services.async_register( + DOMAIN, SERVICE_TURN_OFF, async_handle_alert_service, + descriptions.get(SERVICE_TURN_OFF), schema=ALERT_SERVICE_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_TURN_ON, async_handle_alert_service, + descriptions.get(SERVICE_TURN_ON), schema=ALERT_SERVICE_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_TOGGLE, async_handle_alert_service, + descriptions.get(SERVICE_TOGGLE), schema=ALERT_SERVICE_SCHEMA) + + tasks = [alert.async_update_ha_state() for alert in all_alerts.values()] + if tasks: + yield from asyncio.wait(tasks, loop=hass.loop) + + return True + + +class Alert(ToggleEntity): + """Representation of an alert.""" + + def __init__(self, hass, entity_id, name, watched_entity_id, state, + repeat, skip_first, notifiers, can_ack): + """Initialize the alert.""" + self.hass = hass + self._name = name + self._alert_state = state + self._skip_first = skip_first + self._notifiers = notifiers + self._can_ack = can_ack + + self._delay = [timedelta(minutes=val) for val in repeat] + self._next_delay = 0 + + self._firing = False + self._ack = False + self._cancel = None + self.entity_id = ENTITY_ID_FORMAT.format(entity_id) + + event.async_track_state_change(hass, watched_entity_id, + self.watched_entity_change) + + @property + def name(self): + """Return the name of the alert.""" + return self._name + + @property + def should_poll(self): + """HASS need not poll these entities.""" + return False + + @property + def state(self): + """Return the alert status.""" + if self._firing: + if self._ack: + return STATE_OFF + return STATE_ON + return STATE_IDLE + + @property + def hidden(self): + """Hide the alert when it is not firing.""" + return not self._can_ack or not self._firing + + @asyncio.coroutine + def watched_entity_change(self, entity, from_state, to_state): + """Determine if the alert should start or stop.""" + _LOGGER.debug('Watched entity (%s) has changed.', entity) + if to_state.state == self._alert_state and not self._firing: + yield from self.begin_alerting() + if to_state.state != self._alert_state and self._firing: + yield from self.end_alerting() + + @asyncio.coroutine + def begin_alerting(self): + """Begin the alert procedures.""" + _LOGGER.debug('Beginning Alert: %s', self._name) + self._ack = False + self._firing = True + self._next_delay = 0 + + if not self._skip_first: + yield from self._notify() + else: + yield from self._schedule_notify() + + self.hass.async_add_job(self.async_update_ha_state) + + @asyncio.coroutine + def end_alerting(self): + """End the alert procedures.""" + _LOGGER.debug('Ending Alert: %s', self._name) + self._cancel() + self._ack = False + self._firing = False + self.hass.async_add_job(self.async_update_ha_state) + + @asyncio.coroutine + def _schedule_notify(self): + """Schedule a notification.""" + delay = self._delay[self._next_delay] + next_msg = datetime.now() + delay + self._cancel = \ + event.async_track_point_in_time(self.hass, self._notify, next_msg) + self._next_delay = min(self._next_delay + 1, len(self._delay) - 1) + + @asyncio.coroutine + def _notify(self, *args): + """Send the alert notification.""" + if not self._firing: + return + + if not self._ack: + _LOGGER.info('Alerting: %s', self._name) + for target in self._notifiers: + yield from self.hass.services.async_call( + 'notify', target, {'message': self._name}) + yield from self._schedule_notify() + + @asyncio.coroutine + def async_turn_on(self): + """Async Unacknowledge alert.""" + _LOGGER.debug('Reset Alert: %s', self._name) + self._ack = False + yield from self.async_update_ha_state() + + @asyncio.coroutine + def async_turn_off(self): + """Async Acknowledge alert.""" + _LOGGER.debug('Acknowledged Alert: %s', self._name) + self._ack = True + yield from self.async_update_ha_state() + + @asyncio.coroutine + def async_toggle(self): + """Async toggle alert.""" + if self._ack: + return self.async_turn_on() + return self.async_turn_off() diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index c6057dcd2a8..661f8be8dab 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -211,6 +211,31 @@ verisure: description: The serial number of the smartcam you want to capture an image from. example: '2DEU AT5Z' +alert: + turn_off: + description: Silence alert's notifications. + + fields: + entity_id: + description: Name of the alert to silence. + example: 'alert.garage_door_open' + + turn_on: + description: Reset alert's notifications. + + fields: + entity_id: + description: Name of the alert to reset. + example: 'alert.garage_door_open' + + toggle: + description: Toggle alert's notifications. + + fields: + entity_id: + description: Name of the alert to toggle. + example: 'alert.garage_door_open' + hdmi_cec: send_command: description: Sends CEC command into HDMI CEC capable adapter. diff --git a/tests/components/test_alert.py b/tests/components/test_alert.py new file mode 100644 index 00000000000..00e4abec25b --- /dev/null +++ b/tests/components/test_alert.py @@ -0,0 +1,172 @@ +"""The tests for the Alert component.""" +# pylint: disable=protected-access +from copy import deepcopy +import unittest + +from homeassistant.bootstrap import setup_component +from homeassistant.core import callback +import homeassistant.components.alert as alert +import homeassistant.components.notify as notify +from homeassistant.const import (CONF_ENTITY_ID, STATE_IDLE, CONF_NAME, + CONF_STATE, STATE_ON, STATE_OFF) + +from tests.common import get_test_home_assistant + +NAME = "alert_test" +NOTIFIER = 'test' +TEST_CONFIG = \ + {alert.DOMAIN: { + NAME: { + CONF_NAME: NAME, + CONF_ENTITY_ID: "sensor.test", + CONF_STATE: STATE_ON, + alert.CONF_REPEAT: 30, + alert.CONF_SKIP_FIRST: False, + alert.CONF_NOTIFIERS: [NOTIFIER]} + }} +TEST_NOACK = [NAME, NAME, "sensor.test", STATE_ON, + [30], False, NOTIFIER, False] +ENTITY_ID = alert.ENTITY_ID_FORMAT.format(NAME) + + +# pylint: disable=invalid-name +class TestAlert(unittest.TestCase): + """Test the alert module.""" + + def setUp(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + + def test_is_on(self): + """Test is_on method.""" + self.hass.states.set(ENTITY_ID, STATE_ON) + self.hass.block_till_done() + self.assertTrue(alert.is_on(self.hass, ENTITY_ID)) + self.hass.states.set(ENTITY_ID, STATE_OFF) + self.hass.block_till_done() + self.assertFalse(alert.is_on(self.hass, ENTITY_ID)) + + def test_setup(self): + """Test setup method.""" + assert setup_component(self.hass, alert.DOMAIN, TEST_CONFIG) + self.assertEqual(STATE_IDLE, self.hass.states.get(ENTITY_ID).state) + + def test_fire(self): + """Test the alert firing.""" + assert setup_component(self.hass, alert.DOMAIN, TEST_CONFIG) + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + self.assertEqual(STATE_ON, self.hass.states.get(ENTITY_ID).state) + + def test_silence(self): + """Test silencing the alert.""" + assert setup_component(self.hass, alert.DOMAIN, TEST_CONFIG) + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + alert.turn_off(self.hass, ENTITY_ID) + self.hass.block_till_done() + self.assertEqual(STATE_OFF, self.hass.states.get(ENTITY_ID).state) + + # alert should not be silenced on next fire + self.hass.states.set("sensor.test", STATE_OFF) + self.hass.block_till_done() + self.assertEqual(STATE_IDLE, self.hass.states.get(ENTITY_ID).state) + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + self.assertEqual(STATE_ON, self.hass.states.get(ENTITY_ID).state) + + def test_reset(self): + """Test resetting the alert.""" + assert setup_component(self.hass, alert.DOMAIN, TEST_CONFIG) + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + alert.turn_off(self.hass, ENTITY_ID) + self.hass.block_till_done() + self.assertEqual(STATE_OFF, self.hass.states.get(ENTITY_ID).state) + alert.turn_on(self.hass, ENTITY_ID) + self.hass.block_till_done() + self.assertEqual(STATE_ON, self.hass.states.get(ENTITY_ID).state) + + def test_toggle(self): + """Test toggling alert.""" + assert setup_component(self.hass, alert.DOMAIN, TEST_CONFIG) + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + self.assertEqual(STATE_ON, self.hass.states.get(ENTITY_ID).state) + alert.toggle(self.hass, ENTITY_ID) + self.hass.block_till_done() + self.assertEqual(STATE_OFF, self.hass.states.get(ENTITY_ID).state) + alert.toggle(self.hass, ENTITY_ID) + self.hass.block_till_done() + self.assertEqual(STATE_ON, self.hass.states.get(ENTITY_ID).state) + + def test_hidden(self): + """Test entity hidding.""" + assert setup_component(self.hass, alert.DOMAIN, TEST_CONFIG) + hidden = self.hass.states.get(ENTITY_ID).attributes.get('hidden') + self.assertTrue(hidden) + + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + hidden = self.hass.states.get(ENTITY_ID).attributes.get('hidden') + self.assertFalse(hidden) + + alert.turn_off(self.hass, ENTITY_ID) + hidden = self.hass.states.get(ENTITY_ID).attributes.get('hidden') + self.assertFalse(hidden) + + def test_notification(self): + """Test notifications.""" + events = [] + + @callback + def record_event(event): + """Add recorded event to set.""" + events.append(event) + + self.hass.services.register( + notify.DOMAIN, NOTIFIER, record_event) + + assert setup_component(self.hass, alert.DOMAIN, TEST_CONFIG) + self.assertEqual(0, len(events)) + + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + self.assertEqual(1, len(events)) + + self.hass.states.set("sensor.test", STATE_OFF) + self.hass.block_till_done() + self.assertEqual(1, len(events)) + + def test_skipfirst(self): + """Test skipping first notification.""" + config = deepcopy(TEST_CONFIG) + config[alert.DOMAIN][NAME][alert.CONF_SKIP_FIRST] = True + events = [] + + @callback + def record_event(event): + """Add recorded event to set.""" + events.append(event) + + self.hass.services.register( + notify.DOMAIN, NOTIFIER, record_event) + + assert setup_component(self.hass, alert.DOMAIN, config) + self.assertEqual(0, len(events)) + + self.hass.states.set("sensor.test", STATE_ON) + self.hass.block_till_done() + self.assertEqual(0, len(events)) + + def test_noack(self): + """Test no ack feature.""" + entity = alert.Alert(self.hass, *TEST_NOACK) + self.hass.async_add_job(entity.begin_alerting) + self.hass.block_till_done() + + self.assertEqual(True, entity.hidden) From e831a2705e5ed2c240af3ba9e6a6acc8f110c960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolf-Bastian=20P=C3=B6ttner?= Date: Fri, 3 Feb 2017 08:29:18 +0100 Subject: [PATCH 067/157] Add support for FRITZ!DECT wireless switches based on fritzhome (#5541) --- .coveragerc | 1 + homeassistant/components/switch/fritzdect.py | 165 +++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 169 insertions(+) create mode 100644 homeassistant/components/switch/fritzdect.py diff --git a/.coveragerc b/.coveragerc index dbccf546c36..093b0e4d526 100644 --- a/.coveragerc +++ b/.coveragerc @@ -367,6 +367,7 @@ omit = homeassistant/components/switch/digitalloggers.py homeassistant/components/switch/dlink.py homeassistant/components/switch/edimax.py + homeassistant/components/switch/fritzdect.py homeassistant/components/switch/hdmi_cec.py homeassistant/components/switch/hikvisioncam.py homeassistant/components/switch/hook.py diff --git a/homeassistant/components/switch/fritzdect.py b/homeassistant/components/switch/fritzdect.py new file mode 100644 index 00000000000..fc185c9f6a3 --- /dev/null +++ b/homeassistant/components/switch/fritzdect.py @@ -0,0 +1,165 @@ +""" +Support for FRITZ!DECT Switches. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.fritzdect/ +""" +import logging + +import voluptuous as vol + +from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) +from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_USERNAME) +import homeassistant.helpers.config_validation as cv +from homeassistant.const import TEMP_CELSIUS, STATE_UNKNOWN + +REQUIREMENTS = ['fritzhome==1.0.2'] + +_LOGGER = logging.getLogger(__name__) + +# Standard Fritz Box IP +DEFAULT_HOST = 'fritz.box' + +ATTR_CURRENT_CONSUMPTION = 'Current Consumption' +ATTR_CURRENT_CONSUMPTION_UNIT = 'W' + +ATTR_TOTAL_CONSUMPTION = 'Total Consumption' +ATTR_TOTAL_CONSUMPTION_UNIT = 'kWh' + +ATTR_TEMPERATURE = 'Temperature' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Add all switches connected to Fritz Box.""" + from fritzhome.fritz import FritzBox + + host = config.get(CONF_HOST) + username = config.get(CONF_USERNAME) + password = config.get(CONF_PASSWORD) + + # Hack: fritzhome only throws Exception. To prevent pylint from + # complaining, we disable the warning here: + # pylint: disable=W0703 + + # Log into Fritz Box + fritz = FritzBox(host, username, password) + try: + fritz.login() + except Exception: + _LOGGER.error("Login to Fritz!Box failed") + return + + # Add all actors to hass + for actor in fritz.get_actors(): + # Only add devices that support switching + if actor.has_switch: + data = FritzDectSwitchData(fritz, actor.actor_id) + add_devices([FritzDectSwitch(hass, data, actor.name)], True) + + +class FritzDectSwitch(SwitchDevice): + """Representation of a FRITZ!DECT switch.""" + + def __init__(self, hass, data, name): + """Initialize the switch.""" + self.units = hass.config.units + self.data = data + self._name = name + + @property + def name(self): + """Return the name of the FRITZ!DECT switch, if any.""" + return self._name + + @property + def device_state_attributes(self): + """Return the state attributes of the device.""" + attrs = {} + + if self.data.has_powermeter and \ + self.data.current_consumption != STATE_UNKNOWN and \ + self.data.total_consumption != STATE_UNKNOWN: + attrs[ATTR_CURRENT_CONSUMPTION] = "%.1f %s" % \ + (self.data.current_consumption, ATTR_CURRENT_CONSUMPTION_UNIT) + attrs[ATTR_TOTAL_CONSUMPTION] = "%.3f %s" % \ + (self.data.total_consumption, ATTR_TOTAL_CONSUMPTION_UNIT) + + if self.data.has_temperature and \ + self.data.temperature != STATE_UNKNOWN: + attrs[ATTR_TEMPERATURE] = "%.1f %s" % \ + (self.units.temperature(self.data.temperature, TEMP_CELSIUS), + self.units.temperature_unit) + + return attrs + + @property + def current_power_watt(self): + """Return the current power usage in Watt.""" + try: + return float(self.data.current_consumption) + except ValueError: + return None + + @property + def is_on(self): + """Return true if switch is on.""" + return self.data.state + + def turn_on(self, **kwargs): + """Turn the switch on.""" + actor = self.data.fritz.get_actor_by_ain(self.data.ain) + actor.switch_on() + + def turn_off(self): + """Turn the switch off.""" + actor = self.data.fritz.get_actor_by_ain(self.data.ain) + actor.switch_off() + + def update(self): + """Get the latest data from the fritz box and updates the states.""" + self.data.update() + + +class FritzDectSwitchData(object): + """Get the latest data from the fritz box.""" + + def __init__(self, fritz, ain): + """Initialize the data object.""" + self.fritz = fritz + self.ain = ain + self.state = STATE_UNKNOWN + self.temperature = STATE_UNKNOWN + self.current_consumption = STATE_UNKNOWN + self.total_consumption = STATE_UNKNOWN + self.has_switch = STATE_UNKNOWN + self.has_temperature = STATE_UNKNOWN + self.has_powermeter = STATE_UNKNOWN + + def update(self): + """Get the latest data from the fritz box.""" + from requests.exceptions import RequestException + + try: + actor = self.fritz.get_actor_by_ain(self.ain) + self.state = actor.get_state() + except RequestException: + _LOGGER.error("Request to actor failed") + self.state = STATE_UNKNOWN + self.temperature = STATE_UNKNOWN + self.current_consumption = STATE_UNKNOWN + self.total_consumption = STATE_UNKNOWN + return + + self.temperature = actor.temperature + self.current_consumption = (actor.get_power() or 0.0) / 1000 + self.total_consumption = (actor.get_energy() or 0.0) / 100000 + self.has_switch = actor.has_switch + self.has_temperature = actor.has_temperature + self.has_powermeter = actor.has_powermeter diff --git a/requirements_all.txt b/requirements_all.txt index d2d19cc23b0..957a1c3b75c 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -154,6 +154,9 @@ freesms==0.1.1 # homeassistant.components.device_tracker.fritz # fritzconnection==0.6 +# homeassistant.components.switch.fritzdect +fritzhome==1.0.2 + # homeassistant.components.conversation fuzzywuzzy==0.14.0 From 4aa7f030e8959a56dffdf381a307306dcf0319f6 Mon Sep 17 00:00:00 2001 From: Joseph Piron Date: Fri, 3 Feb 2017 08:33:15 +0100 Subject: [PATCH 068/157] Adds average load to systemmonitor (#5686) * Adds average load to systemmonitor * split the values in 3 sensors * hound ok --- homeassistant/components/sensor/systemmonitor.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 4feb5ed3a59..30f0c2c97ef 100755 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -5,6 +5,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.systemmonitor/ """ import logging +import os import voluptuous as vol @@ -38,7 +39,10 @@ SENSOR_TYPES = { 'ipv4_address': ['IPv4 address', '', 'mdi:server-network'], 'ipv6_address': ['IPv6 address', '', 'mdi:server-network'], 'last_boot': ['Last Boot', '', 'mdi:clock'], - 'since_last_boot': ['Since Last Boot', '', 'mdi:clock'] + 'since_last_boot': ['Since Last Boot', '', 'mdi:clock'], + 'load_1m': ['Average Load (1m)', '', 'mdi:memory'], + 'load_5m': ['Average Load (5m)', '', 'mdi:memory'], + 'load_15m': ['Average Load (15m)', '', 'mdi:memory'] } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -164,3 +168,9 @@ class SystemMonitorSensor(Entity): elif self.type == 'since_last_boot': self._state = dt_util.utcnow() - dt_util.utc_from_timestamp( psutil.boot_time()) + elif self.type == 'load_1m': + self._state = os.getloadavg()[0] + elif self.type == 'load_5m': + self._state = os.getloadavg()[1] + elif self.type == 'load_15m': + self._state = os.getloadavg()[2] From f9ede73a559492d44a5832c6ef8e65e0a73786fc Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 3 Feb 2017 08:43:03 +0100 Subject: [PATCH 069/157] Add moon sensor (#5726) * Add moon sensor * Update moon.py --- homeassistant/components/sensor/moon.py | 81 +++++++++++++++++++++++++ requirements_all.txt | 1 + tests/components/sensor/test_moon.py | 56 +++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 homeassistant/components/sensor/moon.py create mode 100644 tests/components/sensor/test_moon.py diff --git a/homeassistant/components/sensor/moon.py b/homeassistant/components/sensor/moon.py new file mode 100644 index 00000000000..b2ee4574eda --- /dev/null +++ b/homeassistant/components/sensor/moon.py @@ -0,0 +1,81 @@ +""" +Support for tracking the moon phases. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.moon/ +""" +import asyncio +import logging + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import (CONF_NAME) +import homeassistant.util.dt as dt_util +from homeassistant.helpers.entity import Entity +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['astral==1.3.3'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'Moon' + +ICON = 'mdi:brightness-3' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + + +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + """Set up the Moon sensor.""" + name = config.get(CONF_NAME) + + yield from async_add_devices([MoonSensor(name)], True) + return True + + +class MoonSensor(Entity): + """Representation of a Moon sensor.""" + + def __init__(self, name): + """Initialize the sensor.""" + self._name = name + self._state = None + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def state(self): + """Return the state of the device.""" + if self._state >= 21: + return 'Last quarter' + elif self._state >= 14: + return 'Full moon' + elif self._state >= 7: + return 'First quarter' + else: + return 'New moon' + + @property + def unit_of_measurement(self): + """Return the unit the value is expressed in.""" + return 'Phase' + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return ICON + + @asyncio.coroutine + def async_update(self): + """Get the time and updates the states.""" + from astral import Astral + + today = dt_util.as_local(dt_util.utcnow()).date() + self._state = Astral().moon_phase(today) diff --git a/requirements_all.txt b/requirements_all.txt index 957a1c3b75c..f48a900dc91 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -51,6 +51,7 @@ apcaccess==0.0.4 apns2==0.1.1 # homeassistant.components.sun +# homeassistant.components.sensor.moon astral==1.3.3 # homeassistant.components.light.avion diff --git a/tests/components/sensor/test_moon.py b/tests/components/sensor/test_moon.py new file mode 100644 index 00000000000..1125dab1201 --- /dev/null +++ b/tests/components/sensor/test_moon.py @@ -0,0 +1,56 @@ +"""The test for the moon sensor platform.""" +import unittest +from datetime import datetime +from unittest.mock import patch + +import homeassistant.util.dt as dt_util +from homeassistant.bootstrap import setup_component + +from tests.common import get_test_home_assistant + +DAY1 = datetime(2017, 1, 1, 1, tzinfo=dt_util.UTC) +DAY2 = datetime(2017, 1, 18, 1, tzinfo=dt_util.UTC) + + +class TestMoonSensor(unittest.TestCase): + """Test the Moon sensor.""" + + def setup_method(self, method): + """Set up things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def teardown_method(self, method): + """Stop everything that was started.""" + self.hass.stop() + + @patch('homeassistant.components.sensor.moon.dt_util.utcnow', + return_value=DAY1) + def test_moon_day1(self, mock_request): + """Test the Moon sensor.""" + config = { + 'sensor': { + 'platform': 'moon', + 'name': 'moon_day1', + } + } + + assert setup_component(self.hass, 'sensor', config) + + state = self.hass.states.get('sensor.moon_day1') + self.assertEqual(state.state, 'New moon') + + @patch('homeassistant.components.sensor.moon.dt_util.utcnow', + return_value=DAY2) + def test_moon_day2(self, mock_request): + """Test the Moon sensor.""" + config = { + 'sensor': { + 'platform': 'moon', + 'name': 'moon_day2', + } + } + + assert setup_component(self.hass, 'sensor', config) + + state = self.hass.states.get('sensor.moon_day2') + self.assertEqual(state.state, 'Full moon') From 7506569db920fc5505d2a529eb27156f7700a3b6 Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Fri, 3 Feb 2017 08:52:52 +0100 Subject: [PATCH 070/157] Support for the Orange Livebox Play TV appliance (#5533) * Support for the Orage Livebox Play TV appliance * Add liveboxplaytv to coveragerc * Minor refactoring * Update requirements * Adjust comments * Fix alignment * Fix some coding-style issues highlighted by Travis CI * The livebox play TV does not support playing media * Lint: shorten line * Remove unused callback function * Remove redundant backslash * Implement changes requested by balloob * Don't error out if channel name or media url could not be retrieved * Support current program (media title property) * Remove unnecessary check * Clean up: Remove another unnecessary check, _CONFIGURING variable and _playing attribute * Update liveboxplaytv dependency to version 1.4.4 * Fix liveboxplaytv requirement * Improve media state (support for playing and pause state) * Update liveboxplaytv.py --- .coveragerc | 1 + .../components/media_player/liveboxplaytv.py | 207 ++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 211 insertions(+) create mode 100644 homeassistant/components/media_player/liveboxplaytv.py diff --git a/.coveragerc b/.coveragerc index 093b0e4d526..be2f12aa434 100644 --- a/.coveragerc +++ b/.coveragerc @@ -226,6 +226,7 @@ omit = homeassistant/components/media_player/itunes.py homeassistant/components/media_player/kodi.py homeassistant/components/media_player/lg_netcast.py + homeassistant/components/media_player/liveboxplaytv.py homeassistant/components/media_player/mpchc.py homeassistant/components/media_player/mpd.py homeassistant/components/media_player/nad.py diff --git a/homeassistant/components/media_player/liveboxplaytv.py b/homeassistant/components/media_player/liveboxplaytv.py new file mode 100644 index 00000000000..7386f51df4c --- /dev/null +++ b/homeassistant/components/media_player/liveboxplaytv.py @@ -0,0 +1,207 @@ +""" +Support for interface with an Orange Livebox Play TV appliance. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/media_player.liveboxplaytv/ +""" +import logging +from datetime import timedelta + +import requests +import voluptuous as vol + +import homeassistant.util as util +from homeassistant.components.media_player import ( + SUPPORT_TURN_ON, SUPPORT_TURN_OFF, SUPPORT_PLAY, + SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK, + SUPPORT_VOLUME_STEP, SUPPORT_VOLUME_MUTE, SUPPORT_SELECT_SOURCE, + MEDIA_TYPE_CHANNEL, MediaPlayerDevice, PLATFORM_SCHEMA) +from homeassistant.const import ( + CONF_HOST, CONF_PORT, STATE_ON, STATE_OFF, STATE_PLAYING, + STATE_PAUSED, STATE_UNKNOWN, CONF_NAME) +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['liveboxplaytv==1.4.7'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'Livebox Play TV' +DEFAULT_PORT = 8080 + +SUPPORT_LIVEBOXPLAYTV = SUPPORT_TURN_OFF | SUPPORT_TURN_ON | \ + SUPPORT_NEXT_TRACK | SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | \ + SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | SUPPORT_SELECT_SOURCE | \ + SUPPORT_PLAY + +MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) +MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string +}) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the Orange Livebox Play TV platform.""" + host = config.get(CONF_HOST) + port = config.get(CONF_PORT) + name = config.get(CONF_NAME) + + add_devices([LiveboxPlayTvDevice(host, port, name)], True) + + +class LiveboxPlayTvDevice(MediaPlayerDevice): + """Representation of an Orange Livebox Play TV.""" + + def __init__(self, host, port, name): + """Initialize the Livebox Play TV device.""" + from liveboxplaytv import LiveboxPlayTv + self._client = LiveboxPlayTv(host, port) + # Assume that the appliance is not muted + self._muted = False + # Assume that the TV is in Play mode + self._name = name + self._current_source = None + self._state = STATE_UNKNOWN + self._channel_list = {} + self._current_channel = None + self._current_program = None + self._media_image_url = None + + @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) + def update(self): + """Retrieve the latest data.""" + try: + self._state = self.refresh_state() + # Update current channel + channel = self._client.get_current_channel() + if channel is not None: + self._current_program = self._client.program + self._current_channel = channel.get('name', None) + self._media_image_url = \ + self._client.get_current_channel_image(img_size=300) + self.refresh_channel_list() + except requests.ConnectionError: + self._state = STATE_OFF + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def state(self): + """Return the state of the device.""" + return self._state + + @property + def is_volume_muted(self): + """Boolean if volume is currently muted.""" + return self._muted + + @property + def source(self): + """Return the current input source.""" + return self._current_channel + + @property + def source_list(self): + """List of available input sources.""" + # Sort channels by tvIndex + return [self._channel_list[c] for c in + sorted(self._channel_list.keys())] + + @property + def media_content_type(self): + """Content type of current playing media.""" + # return self._client.media_type + return MEDIA_TYPE_CHANNEL + + @property + def media_image_url(self): + """Image url of current playing media.""" + return self._media_image_url + + @property + def media_title(self): + """Title of current playing media.""" + if self._current_channel: + return '{}: {}'.format(self._current_channel, + self._current_program) + + @property + def supported_media_commands(self): + """Flag of media commands that are supported.""" + return SUPPORT_LIVEBOXPLAYTV + + def refresh_channel_list(self): + """Refresh the list of available channels.""" + new_channel_list = {} + # update channels + for channel in self._client.get_channels(): + new_channel_list[int(channel['index'])] = channel['name'] + self._channel_list = new_channel_list + + def refresh_state(self): + """Refresh the current media state.""" + state = self._client.media_state + if state == 'PLAY': + return STATE_PLAYING + elif state == 'PAUSE': + return STATE_PAUSED + else: + return STATE_ON if self._client.is_on else STATE_OFF + return STATE_UNKNOWN + + def turn_off(self): + """Turn off media player.""" + self._state = STATE_OFF + self._client.turn_off() + + def turn_on(self): + """Turn on the media player.""" + self._state = STATE_ON + self._client.turn_on() + + def volume_up(self): + """Volume up the media player.""" + self._client.volume_up() + + def volume_down(self): + """Volume down media player.""" + self._client.volume_down() + + def mute_volume(self, mute): + """Send mute command.""" + self._muted = mute + self._client.mute() + + def media_play_pause(self): + """Simulate play pause media player.""" + self._client.play_pause() + + def select_source(self, source): + """Select input source.""" + self._current_source = source + self._client.set_channel(source) + + def media_play(self): + """Send play command.""" + self._state = STATE_PLAYING + self._client.play() + + def media_pause(self): + """Send media pause command to media player.""" + self._state = STATE_PAUSED + self._client.pause() + + def media_next_track(self): + """Send next track command.""" + self._client.channel_up() + + def media_previous_track(self): + """Send the previous track command.""" + self._client.channel_down() diff --git a/requirements_all.txt b/requirements_all.txt index f48a900dc91..693785b9ae0 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -312,6 +312,9 @@ liffylights==0.9.4 # homeassistant.components.light.limitlessled limitlessled==1.0.2 +# homeassistant.components.media_player.liveboxplaytv +liveboxplaytv==1.4.7 + # homeassistant.components.notify.matrix matrix-client==0.0.5 From 6786f83c2664d92d0d5baae182b89c2aab2e6e02 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 3 Feb 2017 09:43:29 +0100 Subject: [PATCH 071/157] Upgrade pyowm to 2.6.1 (#5729) --- homeassistant/components/sensor/openweathermap.py | 2 +- homeassistant/components/weather/openweathermap.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/openweathermap.py b/homeassistant/components/sensor/openweathermap.py index 08b2a4c0f65..4a2530b74c5 100755 --- a/homeassistant/components/sensor/openweathermap.py +++ b/homeassistant/components/sensor/openweathermap.py @@ -17,7 +17,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle -REQUIREMENTS = ['pyowm==2.6.0'] +REQUIREMENTS = ['pyowm==2.6.1'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/weather/openweathermap.py b/homeassistant/components/weather/openweathermap.py index 931ce7bdf6b..c08666881f3 100644 --- a/homeassistant/components/weather/openweathermap.py +++ b/homeassistant/components/weather/openweathermap.py @@ -15,7 +15,7 @@ from homeassistant.const import ( import homeassistant.helpers.config_validation as cv from homeassistant.util import Throttle -REQUIREMENTS = ['pyowm==2.6.0'] +REQUIREMENTS = ['pyowm==2.6.1'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 693785b9ae0..8bd24126ff9 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -492,7 +492,7 @@ pynx584==0.4 # homeassistant.components.sensor.openweathermap # homeassistant.components.weather.openweathermap -pyowm==2.6.0 +pyowm==2.6.1 # homeassistant.components.qwikswitch pyqwikswitch==0.4 From c0dcef6c3e6909bdb5299c44fa5f4023cf69ae41 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 3 Feb 2017 09:44:07 +0100 Subject: [PATCH 072/157] Add wind bearing (#5730) --- homeassistant/components/sensor/openweathermap.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/sensor/openweathermap.py b/homeassistant/components/sensor/openweathermap.py index 4a2530b74c5..4c556e61ae2 100755 --- a/homeassistant/components/sensor/openweathermap.py +++ b/homeassistant/components/sensor/openweathermap.py @@ -32,6 +32,7 @@ SENSOR_TYPES = { 'weather': ['Condition', None], 'temperature': ['Temperature', None], 'wind_speed': ['Wind speed', 'm/s'], + 'wind_bearing': ['Wind bearing', '°'], 'humidity': ['Humidity', '%'], 'pressure': ['Pressure', 'mbar'], 'clouds': ['Cloud coverage', '%'], @@ -64,9 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): owm = OWM(config.get(CONF_API_KEY)) if not owm: - _LOGGER.error( - "Connection error " - "Please check your settings for OpenWeatherMap") + _LOGGER.error("Unable to connect to OpenWeatherMap") return False data = WeatherData(owm, forecast, hass.config.latitude, @@ -130,8 +129,7 @@ class OpenWeatherMapSensor(Entity): self._state = data.get_detailed_status() elif self.type == 'temperature': if self.temp_unit == TEMP_CELSIUS: - self._state = round(data.get_temperature('celsius')['temp'], - 1) + self._state = round(data.get_temperature('celsius')['temp'], 1) elif self.temp_unit == TEMP_FAHRENHEIT: self._state = round(data.get_temperature('fahrenheit')['temp'], 1) @@ -139,6 +137,8 @@ class OpenWeatherMapSensor(Entity): self._state = round(data.get_temperature()['temp'], 1) elif self.type == 'wind_speed': self._state = round(data.get_wind()['speed'], 1) + elif self.type == 'wind_bearing': + self._state = round(data.get_wind()['deg'], 1) elif self.type == 'humidity': self._state = round(data.get_humidity(), 1) elif self.type == 'pressure': From 25a68f3ce9b38ea56531eb366de6a40bdfa28728 Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Fri, 3 Feb 2017 10:37:00 -0500 Subject: [PATCH 073/157] Update python-wink version (#5734) --- homeassistant/components/wink.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 704ede0660c..569def22401 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -15,7 +15,7 @@ from homeassistant.const import ( from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['python-wink==1.1.0', 'pubnubsub-handler==1.0.0'] +REQUIREMENTS = ['python-wink==1.1.1', 'pubnubsub-handler==1.0.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 8bd24126ff9..0204e72ac01 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -547,7 +547,7 @@ python-twitch==1.3.0 python-vlc==1.1.2 # homeassistant.components.wink -python-wink==1.1.0 +python-wink==1.1.1 # homeassistant.components.device_tracker.trackr pytrackr==0.0.5 From b29c167dde829ffc86d6284458cca60fc01d7d46 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 3 Feb 2017 18:09:14 +0100 Subject: [PATCH 074/157] Upgrade psutil to 5.1.1 (#5736) --- .../components/sensor/systemmonitor.py | 34 +++++++++---------- requirements_all.txt | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 30f0c2c97ef..6a627becdc8 100755 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -16,33 +16,33 @@ from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['psutil==5.0.1'] +REQUIREMENTS = ['psutil==5.1.1'] _LOGGER = logging.getLogger(__name__) SENSOR_TYPES = { - 'disk_use_percent': ['Disk Use', '%', 'mdi:harddisk'], - 'disk_use': ['Disk Use', 'GiB', 'mdi:harddisk'], 'disk_free': ['Disk Free', 'GiB', 'mdi:harddisk'], - 'memory_use_percent': ['RAM Use', '%', 'mdi:memory'], - 'memory_use': ['RAM Use', 'MiB', 'mdi:memory'], - 'memory_free': ['RAM Free', 'MiB', 'mdi:memory'], - 'processor_use': ['CPU Use', '%', 'mdi:memory'], - 'process': ['Process', ' ', 'mdi:memory'], - 'swap_use_percent': ['Swap Use', '%', 'mdi:harddisk'], - 'swap_use': ['Swap Use', 'GiB', 'mdi:harddisk'], - 'swap_free': ['Swap Free', 'GiB', 'mdi:harddisk'], - 'network_out': ['Sent', 'MiB', 'mdi:server-network'], - 'network_in': ['Received', 'MiB', 'mdi:server-network'], - 'packets_out': ['Packets sent', ' ', 'mdi:server-network'], - 'packets_in': ['Packets received', ' ', 'mdi:server-network'], + 'disk_use': ['Disk Use', 'GiB', 'mdi:harddisk'], + 'disk_use_percent': ['Disk Use', '%', 'mdi:harddisk'], 'ipv4_address': ['IPv4 address', '', 'mdi:server-network'], 'ipv6_address': ['IPv6 address', '', 'mdi:server-network'], 'last_boot': ['Last Boot', '', 'mdi:clock'], - 'since_last_boot': ['Since Last Boot', '', 'mdi:clock'], + 'load_15m': ['Average Load (15m)', '', 'mdi:memory'], 'load_1m': ['Average Load (1m)', '', 'mdi:memory'], 'load_5m': ['Average Load (5m)', '', 'mdi:memory'], - 'load_15m': ['Average Load (15m)', '', 'mdi:memory'] + 'memory_free': ['RAM Free', 'MiB', 'mdi:memory'], + 'memory_use': ['RAM Use', 'MiB', 'mdi:memory'], + 'memory_use_percent': ['RAM Use', '%', 'mdi:memory'], + 'network_in': ['Received', 'MiB', 'mdi:server-network'], + 'network_out': ['Sent', 'MiB', 'mdi:server-network'], + 'packets_in': ['Packets received', ' ', 'mdi:server-network'], + 'packets_out': ['Packets sent', ' ', 'mdi:server-network'], + 'process': ['Process', ' ', 'mdi:memory'], + 'processor_use': ['CPU Use', '%', 'mdi:memory'], + 'since_last_boot': ['Since Last Boot', '', 'mdi:clock'], + 'swap_free': ['Swap Free', 'GiB', 'mdi:harddisk'], + 'swap_use': ['Swap Use', 'GiB', 'mdi:harddisk'], + 'swap_use_percent': ['Swap Use', '%', 'mdi:harddisk'], } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ diff --git a/requirements_all.txt b/requirements_all.txt index 0204e72ac01..232ce6bd797 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -382,7 +382,7 @@ pmsensor==0.3 proliphix==0.4.1 # homeassistant.components.sensor.systemmonitor -psutil==5.0.1 +psutil==5.1.1 # homeassistant.components.wink pubnubsub-handler==1.0.0 From 0ea81c1269478774da679a8eba0995b1736f72dd Mon Sep 17 00:00:00 2001 From: Joeboyc2 Date: Sat, 4 Feb 2017 07:36:25 +0000 Subject: [PATCH 075/157] Change CONF_DEFAULT_COLOR CV type (#5700) * Change CONF_DEFAULT_COLOR CV type Changed vol.Optional(CONF_DEFAULT_COLOR, default=DEFAULT_COLOR) from cv.string to cv.ensure_list This allows the optional parameter default_color to be picked up correctly and to function the option needs to be specifed as follows: default_color: [0,255,0] Solution provided by @scossa2020 in issue #5338 https://github.com/home-assistant/home-assistant/issues/5338 * Update hyperion.py --- homeassistant/components/light/hyperion.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/light/hyperion.py b/homeassistant/components/light/hyperion.py index 385cc43717f..cfa9a64580e 100644 --- a/homeassistant/components/light/hyperion.py +++ b/homeassistant/components/light/hyperion.py @@ -28,7 +28,9 @@ SUPPORT_HYPERION = SUPPORT_RGB_COLOR PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port, - vol.Optional(CONF_DEFAULT_COLOR, default=DEFAULT_COLOR): cv.string, + vol.Optional(CONF_DEFAULT_COLOR, default=DEFAULT_COLOR): + vol.All(list, vol.Length(min=3, max=3), + [vol.All(vol.Coerce(int), vol.Range(min=0, max=255))]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) From 4cb20ce6d97d892a1f88d133e1e29891bdcf2d57 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 4 Feb 2017 20:51:22 +0100 Subject: [PATCH 076/157] Upgrade astral to 1.3.4 (#5744) --- homeassistant/components/sensor/moon.py | 2 +- homeassistant/components/sun.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/moon.py b/homeassistant/components/sensor/moon.py index b2ee4574eda..3b13e625bb4 100644 --- a/homeassistant/components/sensor/moon.py +++ b/homeassistant/components/sensor/moon.py @@ -15,7 +15,7 @@ import homeassistant.util.dt as dt_util from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['astral==1.3.3'] +REQUIREMENTS = ['astral==1.3.4'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py index 92349be6376..00a9370a446 100644 --- a/homeassistant/components/sun.py +++ b/homeassistant/components/sun.py @@ -17,7 +17,7 @@ from homeassistant.util import dt as dt_util import homeassistant.helpers.config_validation as cv import homeassistant.util as util -REQUIREMENTS = ['astral==1.3.3'] +REQUIREMENTS = ['astral==1.3.4'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 232ce6bd797..0cda98cf8d6 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -52,7 +52,7 @@ apns2==0.1.1 # homeassistant.components.sun # homeassistant.components.sensor.moon -astral==1.3.3 +astral==1.3.4 # homeassistant.components.light.avion # avion==0.5 From 6164b61e14b483ec4f62b0dfdbef235c36edbd28 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 4 Feb 2017 20:51:49 +0100 Subject: [PATCH 077/157] Upgrade psutil to 5.1.2 (#5745) --- homeassistant/components/sensor/systemmonitor.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 6a627becdc8..da9c9457aa0 100755 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -16,7 +16,7 @@ from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['psutil==5.1.1'] +REQUIREMENTS = ['psutil==5.1.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 0cda98cf8d6..5b13e5f0837 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -382,7 +382,7 @@ pmsensor==0.3 proliphix==0.4.1 # homeassistant.components.sensor.systemmonitor -psutil==5.1.1 +psutil==5.1.2 # homeassistant.components.wink pubnubsub-handler==1.0.0 From 02dfd9660e2d79632fa331c9da765c43f24b8ffe Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 4 Feb 2017 20:52:11 +0100 Subject: [PATCH 078/157] Upgrade zeroconf to 0.18.0 (#5746) --- homeassistant/components/zeroconf.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zeroconf.py b/homeassistant/components/zeroconf.py index 016b99b9b3c..d0a61e0cec0 100644 --- a/homeassistant/components/zeroconf.py +++ b/homeassistant/components/zeroconf.py @@ -17,7 +17,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['api'] DOMAIN = 'zeroconf' -REQUIREMENTS = ['zeroconf==0.17.7'] +REQUIREMENTS = ['zeroconf==0.18.0'] ZEROCONF_TYPE = '_home-assistant._tcp.local.' diff --git a/requirements_all.txt b/requirements_all.txt index 5b13e5f0837..7fd6eee2785 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -708,4 +708,4 @@ yeelight==0.2.1 zengge==0.2 # homeassistant.components.zeroconf -zeroconf==0.17.7 +zeroconf==0.18.0 From 82c99f81fca21402cb573b61709546c5694faa8b Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sun, 5 Feb 2017 06:54:20 +0100 Subject: [PATCH 079/157] Fix validation of serial port on windows (#5749) * Fix validation of serial port on windows * Use pyserial to check serial ports. * Check that persistence file ends with either `.json` or `.pickle`. * Change fix to not rely on pyserial * Use generator expr instead of list comprehension --- homeassistant/components/mysensors.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mysensors.py b/homeassistant/components/mysensors.py index 52b851d1983..4b4f1798d7f 100644 --- a/homeassistant/components/mysensors.py +++ b/homeassistant/components/mysensors.py @@ -7,6 +7,7 @@ https://home-assistant.io/components/sensor.mysensors/ import logging import os import socket +import sys import voluptuous as vol @@ -81,15 +82,37 @@ def has_all_unique_files(value): return value +def is_persistence_file(value): + """Validate that persistence file path ends in either .pickle or .json.""" + if value.endswith(('.json', '.pickle')): + return value + else: + raise vol.Invalid( + '{} does not end in either `.json` or `.pickle`'.format(value)) + + +def is_serial_port(value): + """Validate that value is a windows serial port or a unix device.""" + if sys.platform.startswith('win'): + ports = ('COM{}'.format(idx + 1) for idx in range(256)) + if value in ports: + return value + else: + raise vol.Invalid( + '{} is not a serial port'.format(value)) + else: + return cv.isdevice(value) + + CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Required(CONF_GATEWAYS): vol.All( cv.ensure_list, has_all_unique_files, [{ vol.Required(CONF_DEVICE): - vol.Any(cv.isdevice, MQTT_COMPONENT, is_socket_address), + vol.Any(MQTT_COMPONENT, is_socket_address, is_serial_port), vol.Optional(CONF_PERSISTENCE_FILE): - vol.All(cv.string, has_parent_dir), + vol.All(cv.string, is_persistence_file, has_parent_dir), vol.Optional( CONF_BAUD_RATE, default=DEFAULT_BAUD_RATE): cv.positive_int, From d88c903537fdfce135c7625b315375d3523c227c Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 5 Feb 2017 10:16:57 +0100 Subject: [PATCH 080/157] Upgrade pyasn1 to 0.2.1 (#5755) --- homeassistant/components/notify/xmpp.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/xmpp.py b/homeassistant/components/notify/xmpp.py index 27bfd2aa607..8befb709ddb 100644 --- a/homeassistant/components/notify/xmpp.py +++ b/homeassistant/components/notify/xmpp.py @@ -15,7 +15,7 @@ from homeassistant.const import CONF_PASSWORD, CONF_SENDER, CONF_RECIPIENT REQUIREMENTS = ['sleekxmpp==1.3.1', 'dnspython3==1.15.0', - 'pyasn1==0.1.9', + 'pyasn1==0.2.1', 'pyasn1-modules==0.0.8'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 7fd6eee2785..da99ab3ad80 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -412,7 +412,7 @@ pyRFXtrx==0.16.1 pyasn1-modules==0.0.8 # homeassistant.components.notify.xmpp -pyasn1==0.1.9 +pyasn1==0.2.1 # homeassistant.components.device_tracker.bbox # homeassistant.components.sensor.bbox From 573fc651dc37eb0cd0a757569764af51aeb72440 Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Sun, 5 Feb 2017 10:39:04 +0100 Subject: [PATCH 081/157] Store the key file in the config dir (#5732) * webostv: Store the key file in the config dir * Update the pylgtv source to use the repo by @TheRealLink * Add missing config parameter --- .../components/media_player/webostv.py | 28 +++++++++++-------- homeassistant/components/notify/webostv.py | 11 +++++--- requirements_all.txt | 2 +- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/media_player/webostv.py b/homeassistant/components/media_player/webostv.py index fbd3bb14e74..cb0b992926d 100644 --- a/homeassistant/components/media_player/webostv.py +++ b/homeassistant/components/media_player/webostv.py @@ -20,13 +20,13 @@ from homeassistant.components.media_player import ( from homeassistant.const import ( CONF_HOST, CONF_MAC, CONF_CUSTOMIZE, STATE_OFF, STATE_PLAYING, STATE_PAUSED, - STATE_UNKNOWN, CONF_NAME) + STATE_UNKNOWN, CONF_NAME, CONF_FILENAME) from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['https://github.com/TheRealLink/pylgtv' - '/archive/v0.1.2.zip' - '#pylgtv==0.1.2', + '/archive/v0.1.3.zip' + '#pylgtv==0.1.3', 'websockets==3.2', 'wakeonlan==0.2.2'] @@ -37,6 +37,8 @@ CONF_SOURCES = 'sources' DEFAULT_NAME = 'LG webOS Smart TV' +WEBOSTV_CONFIG_FILE = 'webostv.conf' + SUPPORT_WEBOSTV = SUPPORT_TURN_OFF | \ SUPPORT_NEXT_TRACK | SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | \ SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_STEP | \ @@ -55,6 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST): cv.string, vol.Optional(CONF_MAC): cv.string, vol.Optional(CONF_CUSTOMIZE, default={}): CUSTOMIZE_SCHEMA, + vol.Optional(CONF_FILENAME, default=WEBOSTV_CONFIG_FILE): cv.string }) @@ -77,16 +80,17 @@ def setup_platform(hass, config, add_devices, discovery_info=None): mac = config.get(CONF_MAC) name = config.get(CONF_NAME) customize = config.get(CONF_CUSTOMIZE) - setup_tv(host, mac, name, customize, hass, add_devices) + config = hass.config.path(config.get(CONF_FILENAME)) + setup_tv(host, mac, name, customize, config, hass, add_devices) -def setup_tv(host, mac, name, customize, hass, add_devices): +def setup_tv(host, mac, name, customize, config, hass, add_devices): """Setup a LG WebOS TV based on host parameter.""" from pylgtv import WebOsClient from pylgtv import PyLGTVPairException from websockets.exceptions import ConnectionClosed - client = WebOsClient(host) + client = WebOsClient(host, config) if not client.is_registered(): if host in _CONFIGURING: @@ -104,7 +108,7 @@ def setup_tv(host, mac, name, customize, hass, add_devices): # Not registered, request configuration. _LOGGER.warning("LG webOS TV %s needs to be paired", host) request_configuration( - host, mac, name, customize, hass, add_devices) + host, mac, name, customize, config, hass, add_devices) return # If we came here and configuring this host, mark as done. @@ -113,11 +117,11 @@ def setup_tv(host, mac, name, customize, hass, add_devices): configurator = get_component('configurator') configurator.request_done(request_id) - add_devices([LgWebOSDevice(host, mac, name, customize)], True) + add_devices([LgWebOSDevice(host, mac, name, customize, config)], True) def request_configuration( - host, mac, name, customize, hass, add_devices): + host, mac, name, customize, config, hass, add_devices): """Request configuration steps from the user.""" configurator = get_component('configurator') @@ -130,7 +134,7 @@ def request_configuration( # pylint: disable=unused-argument def lgtv_configuration_callback(data): """The actions to do when our configuration callback is called.""" - setup_tv(host, mac, name, customize, hass, add_devices) + setup_tv(host, mac, name, customize, config, hass, add_devices) _CONFIGURING[host] = configurator.request_config( hass, name, lgtv_configuration_callback, @@ -143,11 +147,11 @@ def request_configuration( class LgWebOSDevice(MediaPlayerDevice): """Representation of a LG WebOS TV.""" - def __init__(self, host, mac, name, customize): + def __init__(self, host, mac, name, customize, config): """Initialize the webos device.""" from pylgtv import WebOsClient from wakeonlan import wol - self._client = WebOsClient(host) + self._client = WebOsClient(host, config) self._wol = wol self._mac = mac self._customize = customize diff --git a/homeassistant/components/notify/webostv.py b/homeassistant/components/notify/webostv.py index 815e2ff750a..edaab1b5521 100644 --- a/homeassistant/components/notify/webostv.py +++ b/homeassistant/components/notify/webostv.py @@ -11,16 +11,18 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.components.notify import ( BaseNotificationService, PLATFORM_SCHEMA) -from homeassistant.const import CONF_HOST +from homeassistant.const import (CONF_FILENAME, CONF_HOST) -REQUIREMENTS = ['https://github.com/TheRealLink/pylgtv/archive/v0.1.2.zip' - '#pylgtv==0.1.2'] +REQUIREMENTS = ['https://github.com/TheRealLink/pylgtv/archive/v0.1.3.zip' + '#pylgtv==0.1.3'] _LOGGER = logging.getLogger(__name__) +WEBOSTV_CONFIG_FILE = 'webostv.conf' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_FILENAME, default=WEBOSTV_CONFIG_FILE): cv.string }) @@ -29,7 +31,8 @@ def get_service(hass, config, discovery_info=None): from pylgtv import WebOsClient from pylgtv import PyLGTVPairException - client = WebOsClient(config.get(CONF_HOST)) + path = hass.config.path(config.get(CONF_FILENAME)) + client = WebOsClient(config.get(CONF_HOST), key_file_path=path) try: client.register() diff --git a/requirements_all.txt b/requirements_all.txt index da99ab3ad80..b21a78803c8 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -205,7 +205,7 @@ https://github.com/LinuxChristian/pyW215/archive/v0.3.7.zip#pyW215==0.3.7 # homeassistant.components.media_player.webostv # homeassistant.components.notify.webostv -https://github.com/TheRealLink/pylgtv/archive/v0.1.2.zip#pylgtv==0.1.2 +https://github.com/TheRealLink/pylgtv/archive/v0.1.3.zip#pylgtv==0.1.3 # homeassistant.components.sensor.thinkingcleaner # homeassistant.components.switch.thinkingcleaner From 91bebca0b6664b26b8385331384b4b38b9404444 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 5 Feb 2017 11:22:32 +0100 Subject: [PATCH 082/157] Upgrade pysnmp to 4.3.3 (#5757) --- .../components/device_tracker/snmp.py | 26 +++++++++---------- homeassistant/components/sensor/snmp.py | 8 +++--- requirements_all.txt | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/device_tracker/snmp.py b/homeassistant/components/device_tracker/snmp.py index 43c0662e568..4cbaa557517 100644 --- a/homeassistant/components/device_tracker/snmp.py +++ b/homeassistant/components/device_tracker/snmp.py @@ -17,24 +17,24 @@ from homeassistant.components.device_tracker import ( from homeassistant.const import CONF_HOST from homeassistant.util import Throttle -# Return cached results if last scan was less then this time ago. -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['pysnmp==4.3.2'] -CONF_COMMUNITY = "community" -CONF_AUTHKEY = "authkey" -CONF_PRIVKEY = "privkey" -CONF_BASEOID = "baseoid" +REQUIREMENTS = ['pysnmp==4.3.3'] -DEFAULT_COMMUNITY = "public" +CONF_COMMUNITY = 'community' +CONF_AUTHKEY = 'authkey' +CONF_PRIVKEY = 'privkey' +CONF_BASEOID = 'baseoid' + +DEFAULT_COMMUNITY = 'public' + +MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_COMMUNITY, default=DEFAULT_COMMUNITY): cv.string, - vol.Inclusive(CONF_AUTHKEY, "keys"): cv.string, - vol.Inclusive(CONF_PRIVKEY, "keys"): cv.string, + vol.Inclusive(CONF_AUTHKEY, 'keys'): cv.string, + vol.Inclusive(CONF_PRIVKEY, 'keys'): cv.string, vol.Required(CONF_BASEOID): cv.string }) @@ -119,14 +119,14 @@ class SnmpScanner(DeviceScanner): return # pylint: disable=no-member if errstatus: - _LOGGER.error('SNMP error: %s at %s', errstatus.prettyPrint(), + _LOGGER.error("SNMP error: %s at %s", errstatus.prettyPrint(), errindex and restable[int(errindex) - 1][0] or '?') return for resrow in restable: for _, val in resrow: mac = binascii.hexlify(val.asOctets()).decode('utf-8') - _LOGGER.debug('Found mac %s', mac) + _LOGGER.debug("Found MAC %s", mac) mac = ':'.join([mac[i:i+2] for i in range(0, len(mac), 2)]) devices.append({'mac': mac}) return devices diff --git a/homeassistant/components/sensor/snmp.py b/homeassistant/components/sensor/snmp.py index b5e3b16b5d1..6a991f28898 100644 --- a/homeassistant/components/sensor/snmp.py +++ b/homeassistant/components/sensor/snmp.py @@ -16,7 +16,7 @@ from homeassistant.const import ( import homeassistant.helpers.config_validation as cv from homeassistant.util import Throttle -REQUIREMENTS = ['pysnmp==4.3.2'] +REQUIREMENTS = ['pysnmp==4.3.3'] _LOGGER = logging.getLogger(__name__) @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the SNMP sensor.""" + """Set up the SNMP sensor.""" from pysnmp.hlapi import (getCmd, CommunityData, SnmpEngine, UdpTransportTarget, ContextData, ObjectType, ObjectIdentity) @@ -61,7 +61,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ObjectType(ObjectIdentity(baseoid)))) if errindication: - _LOGGER.error('Please check the details in the configuration file') + _LOGGER.error("Please check the details in the configuration file") return False else: data = SnmpData(host, port, community, baseoid) @@ -128,7 +128,7 @@ class SnmpData(object): if errindication: _LOGGER.error("SNMP error: %s", errindication) elif errstatus: - _LOGGER.error('SNMP error: %s at %s', errstatus.prettyPrint(), + _LOGGER.error("SNMP error: %s at %s", errstatus.prettyPrint(), errindex and restable[-1][int(errindex) - 1] or '?') else: for resrow in restable: diff --git a/requirements_all.txt b/requirements_all.txt index b21a78803c8..9dcf8198d2d 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -505,7 +505,7 @@ pysma==0.1.3 # homeassistant.components.device_tracker.snmp # homeassistant.components.sensor.snmp -pysnmp==4.3.2 +pysnmp==4.3.3 # homeassistant.components.digital_ocean python-digitalocean==1.10.1 From 2a139d6bc7159e9dbe49efd2c68f25d51593a3cc Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 5 Feb 2017 14:24:38 +0100 Subject: [PATCH 083/157] Add unittest for multible entities in one line (#5759) --- tests/helpers/test_template.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 463f073eeb1..1948d8ab052 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -688,3 +688,14 @@ is_state_attr('device_tracker.phone_2', 'battery', 40) states.sensor.pick_humidity.state ~ „ %“ }} """))) + + self.assertListEqual( + sorted([ + 'sensor.luftfeuchtigkeit_mean', + 'input_slider.luftfeuchtigkeit', + ]), + sorted(template.extract_entities( + "{% if (states('sensor.luftfeuchtigkeit_mean') | int)" + " > (states('input_slider.luftfeuchtigkeit') | int +1.5)" + " %}true{% endif %}" + ))) From 0d89f2bc69f49e1d63d8b058f6e9ea8238e586a9 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sun, 5 Feb 2017 21:07:30 +0100 Subject: [PATCH 084/157] Update mysensors sensors (#5764) * Add V_DIRECTION type for S_WIND. * Add more predefined units of measurement. --- homeassistant/components/sensor/mysensors.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/sensor/mysensors.py b/homeassistant/components/sensor/mysensors.py index 6c1f65606da..9f750e3c10b 100644 --- a/homeassistant/components/sensor/mysensors.py +++ b/homeassistant/components/sensor/mysensors.py @@ -33,7 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): pres.S_TEMP: [set_req.V_TEMP], pres.S_HUM: [set_req.V_HUM], pres.S_BARO: [set_req.V_PRESSURE, set_req.V_FORECAST], - pres.S_WIND: [set_req.V_WIND, set_req.V_GUST], + pres.S_WIND: [set_req.V_WIND, set_req.V_GUST, set_req.V_DIRECTION], pres.S_RAIN: [set_req.V_RAIN, set_req.V_RAINRATE], pres.S_UV: [set_req.V_UV], pres.S_WEIGHT: [set_req.V_WEIGHT, set_req.V_IMPEDANCE], @@ -106,6 +106,7 @@ class MySensorsSensor(mysensors.MySensorsDeviceEntity, Entity): @property def unit_of_measurement(self): """Return the unit of measurement of this entity.""" + pres = self.gateway.const.Presentation set_req = self.gateway.const.SetReq unit_map = { set_req.V_TEMP: (TEMP_CELSIUS @@ -113,13 +114,14 @@ class MySensorsSensor(mysensors.MySensorsDeviceEntity, Entity): set_req.V_HUM: '%', set_req.V_DIMMER: '%', set_req.V_LIGHT_LEVEL: '%', + set_req.V_DIRECTION: '°', set_req.V_WEIGHT: 'kg', set_req.V_DISTANCE: 'm', set_req.V_IMPEDANCE: 'ohm', set_req.V_WATT: 'W', set_req.V_KWH: 'kWh', set_req.V_FLOW: 'm', - set_req.V_VOLUME: 'm3', + set_req.V_VOLUME: 'm³', set_req.V_VOLTAGE: 'V', set_req.V_CURRENT: 'A', } @@ -127,7 +129,11 @@ class MySensorsSensor(mysensors.MySensorsDeviceEntity, Entity): if set_req.V_UNIT_PREFIX in self._values: return self._values[ set_req.V_UNIT_PREFIX] - unit_map.update({set_req.V_PERCENTAGE: '%'}) + unit_map.update({ + set_req.V_PERCENTAGE: '%', + set_req.V_LEVEL: { + pres.S_SOUND: 'dB', pres.S_VIBRATION: 'Hz', + pres.S_LIGHT_LEVEL: 'lux'}}) if float(self.gateway.protocol_version) >= 2.0: unit_map.update({ set_req.V_ORP: 'mV', @@ -135,4 +141,7 @@ class MySensorsSensor(mysensors.MySensorsDeviceEntity, Entity): set_req.V_VAR: 'var', set_req.V_VA: 'VA', }) - return unit_map.get(self.value_type) + unit = unit_map.get(self.value_type) + if isinstance(unit, dict): + unit = unit.get(self.child_type) + return unit From 4a341ff55f8013eb117157115ef3fce29217b506 Mon Sep 17 00:00:00 2001 From: Yannic-HAW Date: Mon, 6 Feb 2017 07:53:58 +0100 Subject: [PATCH 085/157] - added send packet service to send ir packets directly from scripts (no need to define a switch for each command) (#5768) - changed ip suffix of SERVICE_LEARN to use _ instead of . as ip seperator to avoid errors if used in yaml --- homeassistant/components/switch/broadlink.py | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/broadlink.py b/homeassistant/components/switch/broadlink.py index 7c561a3eb1f..52a5c1e4e80 100644 --- a/homeassistant/components/switch/broadlink.py +++ b/homeassistant/components/switch/broadlink.py @@ -28,7 +28,9 @@ _LOGGER = logging.getLogger(__name__) DOMAIN = "broadlink" DEFAULT_NAME = 'Broadlink switch' DEFAULT_TIMEOUT = 10 +DEFAULT_RETRY = 3 SERVICE_LEARN = "learn_command" +SERVICE_SEND = "send_packet" RM_TYPES = ["rm", "rm2", "rm_mini", "rm_pro_phicomm", "rm2_home_plus", "rm2_home_plus_gdt", "rm2_pro_plus", "rm2_pro_plus2", @@ -101,10 +103,30 @@ def setup_platform(hass, config, add_devices, discovery_info=None): "Did not received any signal", title='Broadlink switch') + @asyncio.coroutine + def _send_packet(call): + packets = call.data.get('packet', []) + for packet in packets: + for retry in range(DEFAULT_RETRY): + try: + payload = b64decode(packet) + yield from hass.loop.run_in_executor( + None, broadlink_device.send_data, payload) + break + except (socket.timeout, ValueError): + try: + yield from hass.loop.run_in_executor( + None, broadlink_device.auth) + except socket.timeout: + if retry == DEFAULT_RETRY-1: + _LOGGER.error("Failed to send packet to device.") + if switch_type in RM_TYPES: broadlink_device = broadlink.rm((ip_addr, 80), mac_addr) - hass.services.register(DOMAIN, SERVICE_LEARN + '_' + ip_addr, - _learn_command) + hass.services.register(DOMAIN, SERVICE_LEARN + '_' + + ip_addr.replace('.', '_'), _learn_command) + hass.services.register(DOMAIN, SERVICE_SEND + '_' + + ip_addr.replace('.', '_'), _send_packet) switches = [] for object_id, device_config in devices.items(): switches.append( From 150c8ac11ce5b26d8cbc03b53bab09ef539eccae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 6 Feb 2017 11:32:37 +0100 Subject: [PATCH 086/157] flux led o.13 (#5774) --- homeassistant/components/light/flux_led.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/flux_led.py b/homeassistant/components/light/flux_led.py index 46eec35724a..5a2cf93f45e 100644 --- a/homeassistant/components/light/flux_led.py +++ b/homeassistant/components/light/flux_led.py @@ -17,7 +17,7 @@ from homeassistant.components.light import ( PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['flux_led==0.12'] +REQUIREMENTS = ['flux_led==0.13'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 9dcf8198d2d..bcf935e7e69 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -147,7 +147,7 @@ fitbit==0.2.3 fixerio==0.1.1 # homeassistant.components.light.flux_led -flux_led==0.12 +flux_led==0.13 # homeassistant.components.notify.free_mobile freesms==0.1.1 From 264bdc9d569fd81668fd87601d0a4a6e73025f51 Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Mon, 6 Feb 2017 11:32:51 +0100 Subject: [PATCH 087/157] Make brightness display work for rgb devices. (#5675) * Make brightness display work for rgb devices. Non rgbw devices return 255 for getWarmWhite255. This is part 2 to make the brightness slider work for these devices. https://github.com/Danielhiversen/flux_led/pull/25 * Query brightness property which return WW level or RGB brightness equivalent. https://github.com/Danielhiversen/flux_led/pull/25 --- homeassistant/components/light/flux_led.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/light/flux_led.py b/homeassistant/components/light/flux_led.py index 5a2cf93f45e..2b517425110 100644 --- a/homeassistant/components/light/flux_led.py +++ b/homeassistant/components/light/flux_led.py @@ -121,7 +121,7 @@ class FluxLight(Light): @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self._bulb.getWarmWhite255() + return self._bulb.brightness @property def rgb_color(self): From 4cc711357ab3419f054cf44d60d9fbb8db86290c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20L=C3=B3pez?= Date: Mon, 6 Feb 2017 14:01:41 +0100 Subject: [PATCH 088/157] Allow to use data for enhanced messages (#5763) Add notification data field to the message send to Facebook. Allows to construct richer messages like cards, quick replies, attach images, videos, etc --- homeassistant/components/notify/facebook.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/facebook.py b/homeassistant/components/notify/facebook.py index e598b0e818b..8f8bb98bbe1 100644 --- a/homeassistant/components/notify/facebook.py +++ b/homeassistant/components/notify/facebook.py @@ -12,7 +12,7 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.components.notify import ( - ATTR_TARGET, PLATFORM_SCHEMA, BaseNotificationService) + ATTR_TARGET, ATTR_DATA, PLATFORM_SCHEMA, BaseNotificationService) from homeassistant.const import CONTENT_TYPE_JSON _LOGGER = logging.getLogger(__name__) @@ -41,6 +41,15 @@ class FacebookNotificationService(BaseNotificationService): """Send some message.""" payload = {'access_token': self.page_access_token} targets = kwargs.get(ATTR_TARGET) + data = kwargs.get(ATTR_DATA) + + body_message = {"text": message} + + if data is not None: + body_message.update(data) + # Only one of text or attachment can be specified + if 'attachment' in body_message: + body_message.pop('text') if not targets: _LOGGER.error("At least 1 target is required") @@ -49,7 +58,7 @@ class FacebookNotificationService(BaseNotificationService): for target in targets: body = { "recipient": {"phone_number": target}, - "message": {"text": message} + "message": body_message } import json resp = requests.post(BASE_URL, data=json.dumps(body), From 32dc276c53a2cc6bfbd868dc480f5a38ea647608 Mon Sep 17 00:00:00 2001 From: Alberto Arias Maestro Date: Mon, 6 Feb 2017 05:43:36 -0800 Subject: [PATCH 089/157] Add support for position on wink cover (#5751) Add support for position property for wink covers and fix state when stopped in the middle. --- homeassistant/components/cover/wink.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/cover/wink.py b/homeassistant/components/cover/wink.py index 7c42aafa350..79e2ee334dc 100644 --- a/homeassistant/components/cover/wink.py +++ b/homeassistant/components/cover/wink.py @@ -40,13 +40,17 @@ class WinkCoverDevice(WinkDevice, CoverDevice): """Open the shade.""" self.wink.set_state(1) + def set_cover_position(self, position, **kwargs): + """Move the roller shutter to a specific position.""" + self.wink.set_state(float(position)/100) + + @property + def current_cover_position(self): + """Return the current position of roller shutter.""" + return int(self.wink.state()*100) + @property def is_closed(self): """Return if the cover is closed.""" state = self.wink.state() - if state == 0: - return True - elif state == 1: - return False - else: - return None + return bool(state == 0) From 2b124a008c9bf2119db27efdbc6f0e7ef1700f14 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 6 Feb 2017 21:25:34 +0100 Subject: [PATCH 090/157] Migrate lock component to async (#5748) --- homeassistant/components/lock/__init__.py | 70 +++++++++++++++++------ homeassistant/components/lock/demo.py | 4 +- homeassistant/components/lock/mqtt.py | 8 +-- homeassistant/components/lock/vera.py | 2 - 4 files changed, 58 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index a7d392b321e..790f0783a9a 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -4,7 +4,9 @@ Component to interface with various locks that can be controlled remotely. For more details about this component, please refer to the documentation at https://home-assistant.io/components/lock/ """ +import asyncio from datetime import timedelta +import functools as ft import logging import os @@ -67,38 +69,54 @@ def unlock(hass, entity_id=None, code=None): hass.services.call(DOMAIN, SERVICE_UNLOCK, data) -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Track states and offer events for locks.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_LOCKS) - component.setup(config) - def handle_lock_service(service): + yield from component.async_setup(config) + + @asyncio.coroutine + def async_handle_lock_service(service): """Handle calls to the lock services.""" - target_locks = component.extract_from_service(service) + target_locks = component.async_extract_from_service(service) code = service.data.get(ATTR_CODE) - for item in target_locks: + for entity in target_locks: if service.service == SERVICE_LOCK: - item.lock(code=code) + yield from entity.async_lock(code=code) else: - item.unlock(code=code) + yield from entity.async_unlock(code=code) - for item in target_locks: - if not item.should_poll: + update_tasks = [] + + for entity in target_locks: + if not entity.should_poll: continue - item.update_ha_state(True) + update_coro = hass.loop.create_task( + entity.async_update_ha_state(True)) + if hasattr(entity, 'async_update'): + update_tasks.append(update_coro) + else: + yield from update_coro + + if update_tasks: + yield from asyncio.wait(update_tasks, loop=hass.loop) + + descriptions = yield from hass.loop.run_in_executor( + None, load_yaml_config_file, os.path.join( + os.path.dirname(__file__), 'services.yaml')) + + hass.services.async_register( + DOMAIN, SERVICE_UNLOCK, async_handle_lock_service, + descriptions.get(SERVICE_UNLOCK), schema=LOCK_SERVICE_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_LOCK, async_handle_lock_service, + descriptions.get(SERVICE_LOCK), schema=LOCK_SERVICE_SCHEMA) - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service, - descriptions.get(SERVICE_UNLOCK), - schema=LOCK_SERVICE_SCHEMA) - hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service, - descriptions.get(SERVICE_LOCK), - schema=LOCK_SERVICE_SCHEMA) return True @@ -125,10 +143,26 @@ class LockDevice(Entity): """Lock the lock.""" raise NotImplementedError() + def async_lock(self, **kwargs): + """Lock the lock. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.lock, **kwargs)) + def unlock(self, **kwargs): """Unlock the lock.""" raise NotImplementedError() + def async_unlock(self, **kwargs): + """Unlock the lock. + + This method must be run in the event loop and returns a coroutine. + """ + return self.hass.loop.run_in_executor( + None, ft.partial(self.unlock, **kwargs)) + @property def state_attributes(self): """Return the state attributes.""" diff --git a/homeassistant/components/lock/demo.py b/homeassistant/components/lock/demo.py index 55929227039..fca922b11e2 100644 --- a/homeassistant/components/lock/demo.py +++ b/homeassistant/components/lock/demo.py @@ -43,9 +43,9 @@ class DemoLock(LockDevice): def lock(self, **kwargs): """Lock the device.""" self._state = STATE_LOCKED - self.update_ha_state() + self.schedule_update_ha_state() def unlock(self, **kwargs): """Unlock the device.""" self._state = STATE_UNLOCKED - self.update_ha_state() + self.schedule_update_ha_state() diff --git a/homeassistant/components/lock/mqtt.py b/homeassistant/components/lock/mqtt.py index da6e595914b..fde62c8695e 100644 --- a/homeassistant/components/lock/mqtt.py +++ b/homeassistant/components/lock/mqtt.py @@ -82,10 +82,10 @@ class MqttLock(LockDevice): payload) if payload == self._payload_lock: self._state = True - self.update_ha_state() + self.schedule_update_ha_state() elif payload == self._payload_unlock: self._state = False - self.update_ha_state() + self.schedule_update_ha_state() if self._state_topic is None: # Force into optimistic mode. @@ -121,7 +121,7 @@ class MqttLock(LockDevice): if self._optimistic: # Optimistically assume that switch has changed state. self._state = True - self.update_ha_state() + self.schedule_update_ha_state() def unlock(self, **kwargs): """Unlock the device.""" @@ -130,4 +130,4 @@ class MqttLock(LockDevice): if self._optimistic: # Optimistically assume that switch has changed state. self._state = False - self.update_ha_state() + self.schedule_update_ha_state() diff --git a/homeassistant/components/lock/vera.py b/homeassistant/components/lock/vera.py index 0307bbf4312..14606c0853c 100644 --- a/homeassistant/components/lock/vera.py +++ b/homeassistant/components/lock/vera.py @@ -35,13 +35,11 @@ class VeraLock(VeraDevice, LockDevice): """Lock the device.""" self.vera_device.lock() self._state = STATE_LOCKED - self.update_ha_state() def unlock(self, **kwargs): """Unlock the device.""" self.vera_device.unlock() self._state = STATE_UNLOCKED - self.update_ha_state() @property def is_locked(self): From 34c7bac9b4b946493e48ae32b865797e8e6501f5 Mon Sep 17 00:00:00 2001 From: Andrzej Date: Mon, 6 Feb 2017 22:16:17 +0100 Subject: [PATCH 091/157] Update package.py (#5783) --- homeassistant/util/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index cf65e319552..6f632f47dbe 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -35,7 +35,7 @@ def install_package(package: str, upgrade: bool=True, try: return subprocess.call(args) == 0 except subprocess.SubprocessError: - _LOGGER.exception('Unable to install pacakge %s', package) + _LOGGER.exception('Unable to install package %s', package) return False From 305d2612cf417c322ee657327c0112fad5f4f568 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Tue, 7 Feb 2017 01:00:20 -0500 Subject: [PATCH 092/157] Fix attribute error for media_player/roku if roku device is unreachable and shows a persistent notification (#5785) (#5786) --- homeassistant/components/media_player/roku.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/media_player/roku.py b/homeassistant/components/media_player/roku.py index 26649d0be96..af54e285bdc 100644 --- a/homeassistant/components/media_player/roku.py +++ b/homeassistant/components/media_player/roku.py @@ -15,6 +15,7 @@ from homeassistant.components.media_player import ( from homeassistant.const import ( CONF_HOST, STATE_IDLE, STATE_PLAYING, STATE_UNKNOWN, STATE_HOME) import homeassistant.helpers.config_validation as cv +import homeassistant.loader as loader REQUIREMENTS = [ 'https://github.com/bah2830/python-roku/archive/3.1.3.zip' @@ -23,6 +24,9 @@ REQUIREMENTS = [ KNOWN_HOSTS = [] DEFAULT_PORT = 8060 +NOTIFICATION_ID = 'roku_notification' +NOTIFICATION_TITLE = 'Roku Media Player Setup' + _LOGGER = logging.getLogger(__name__) SUPPORT_ROKU = SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK |\ @@ -48,15 +52,28 @@ def setup_platform(hass, config, add_devices, discovery_info=None): elif CONF_HOST in config: hosts.append(config.get(CONF_HOST)) + persistent_notification = loader.get_component('persistent_notification') rokus = [] for host in hosts: new_roku = RokuDevice(host) - if new_roku.name is None: + try: + if new_roku.name is not None: + rokus.append(RokuDevice(host)) + KNOWN_HOSTS.append(host) + else: + _LOGGER.error("Unable to initialize roku at %s", host) + + except AttributeError: _LOGGER.error("Unable to initialize roku at %s", host) - else: - rokus.append(RokuDevice(host)) - KNOWN_HOSTS.append(host) + persistent_notification.create( + hass, 'Error: Unable to initialize roku at {}
' + 'Check its network connection or consider ' + 'using auto discovery.
' + 'You will need to restart hass after fixing.' + ''.format(config.get(CONF_HOST)), + title=NOTIFICATION_TITLE, + notification_id=NOTIFICATION_ID) add_devices(rokus) From 1546ec777857af6669e42f0d686f8dab797641ac Mon Sep 17 00:00:00 2001 From: ray0711 Date: Tue, 7 Feb 2017 08:52:07 +0100 Subject: [PATCH 093/157] Fix brightness slider for mqtt template lights (#5780) Add the missing supported_features declaration. --- homeassistant/components/light/mqtt_template.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/homeassistant/components/light/mqtt_template.py b/homeassistant/components/light/mqtt_template.py index 55d4afac231..b7520fce682 100755 --- a/homeassistant/components/light/mqtt_template.py +++ b/homeassistant/components/light/mqtt_template.py @@ -284,3 +284,16 @@ class MqttTemplate(Light): if self._optimistic: self.schedule_update_ha_state() + + @property + def supported_features(self): + """Flag supported features.""" + features = 0 + if self._brightness is not None: + features = features | SUPPORT_BRIGHTNESS + if self._rgb is not None: + features = features | SUPPORT_RGB_COLOR + if self._effect_list is not None: + features = features | SUPPORT_EFFECT + + return features From 7927a6b58822eb454b8d414dbf19e1c70428b07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Tue, 7 Feb 2017 09:25:47 +0100 Subject: [PATCH 094/157] add min and max jinja filters (#5765) --- homeassistant/helpers/template.py | 2 ++ tests/helpers/test_template.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index d3f49c003c8..8d55615f661 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -425,6 +425,8 @@ ENV.filters['timestamp_custom'] = timestamp_custom ENV.filters['timestamp_local'] = timestamp_local ENV.filters['timestamp_utc'] = timestamp_utc ENV.filters['is_defined'] = fail_when_undefined +ENV.filters['max'] = max +ENV.filters['min'] = min ENV.globals['float'] = forgiving_float ENV.globals['now'] = dt_util.now ENV.globals['utcnow'] = dt_util.utcnow diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 1948d8ab052..b2134879640 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -186,6 +186,20 @@ class TestHelpersTemplate(unittest.TestCase): template.Template('{{ %s | timestamp_local }}' % inp, self.hass).render()) + def test_min(self): + """Test the min filter.""" + self.assertEqual( + '1', + template.Template('{{ [1, 2, 3] | min }}', + self.hass).render()) + + def test_max(self): + """Test the max filter.""" + self.assertEqual( + '3', + template.Template('{{ [1, 2, 3] | max }}', + self.hass).render()) + def test_timestamp_utc(self): """Test the timestamps to local filter.""" tests = { From 48161697f817e2316ebaa3f7b2a7e99a270b6476 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 7 Feb 2017 09:27:55 +0100 Subject: [PATCH 095/157] Sonos fix favorite, coordinator, cleanup update (#5778) * Sonos fix favorite, coordinator, cleanup update * Bugfix snapshot restore --- .../components/media_player/sonos.py | 539 +++++++++--------- tests/components/media_player/test_sonos.py | 4 + 2 files changed, 278 insertions(+), 265 deletions(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 0bb34eee598..7be9a878c06 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -334,271 +334,15 @@ class SonosDevice(MediaPlayerDevice): self._speaker_info = self._player.get_speaker_info(True) self._name = self._speaker_info['zone_name'].replace( ' (R)', '').replace(' (L)', '') + self._favorite_sources = \ + self._player.get_sonos_favorites()['favorites'] if self._last_avtransport_event: is_available = True else: is_available = self._is_available() - if is_available: - - # set group coordinator - if self._player.is_coordinator: - self._coordinator = None - else: - try: - self._coordinator = _get_entity_from_soco( - self.hass, self._player.group.coordinator) - - # protect for loop - if not self._coordinator.is_coordinator: - # pylint: disable=protected-access - self._coordinator._coordinator = None - except ValueError: - self._coordinator = None - - track_info = None - if self._last_avtransport_event: - variables = self._last_avtransport_event.variables - current_track_metadata = variables.get( - 'current_track_meta_data', {} - ) - - self._status = variables.get('transport_state') - - if current_track_metadata: - # no need to ask speaker for information we already have - current_track_metadata = current_track_metadata.__dict__ - - track_info = { - 'uri': variables.get('current_track_uri'), - 'artist': current_track_metadata.get('creator'), - 'album': current_track_metadata.get('album'), - 'title': current_track_metadata.get('title'), - 'playlist_position': variables.get('current_track'), - 'duration': variables.get('current_track_duration') - } - else: - self._player_volume = self._player.volume - self._player_volume_muted = self._player.mute - transport_info = self._player.get_current_transport_info() - self._status = transport_info.get('current_transport_state') - - if not track_info: - track_info = self._player.get_current_track_info() - - if not self._coordinator: - - is_playing_tv = self._player.is_playing_tv - is_playing_line_in = self._player.is_playing_line_in - - media_info = self._player.avTransport.GetMediaInfo( - [('InstanceID', 0)] - ) - - current_media_uri = media_info['CurrentURI'] - media_artist = track_info.get('artist') - media_album_name = track_info.get('album') - media_title = track_info.get('title') - media_image_url = track_info.get('album_art', None) - - media_position = None - media_position_updated_at = None - source_name = None - - is_radio_stream = \ - current_media_uri.startswith('x-sonosapi-stream:') or \ - current_media_uri.startswith('x-rincon-mp3radio:') - - if is_playing_tv or is_playing_line_in: - # playing from line-in/tv. - - support_previous_track = False - support_next_track = False - support_stop = False - support_pause = False - - if is_playing_tv: - media_artist = SUPPORT_SOURCE_TV - else: - media_artist = SUPPORT_SOURCE_LINEIN - - source_name = media_artist - - media_album_name = None - media_title = None - media_image_url = None - - elif is_radio_stream: - media_image_url = self._format_media_image_url( - media_image_url, - current_media_uri - ) - support_previous_track = False - support_next_track = False - support_stop = False - support_pause = False - - source_name = 'Radio' - # Check if currently playing radio station is in favorites - favs = self._player.get_sonos_favorites()['favorites'] - favc = [ - fav for fav in favs if fav['uri'] == current_media_uri - ] - if len(favc) == 1: - src = favc.pop() - source_name = src['title'] - - # for radio streams we set the radio station name as the - # title. - if media_artist and media_title: - # artist and album name are in the data, concatenate - # that do display as artist. - # "Information" field in the sonos pc app - - media_artist = '{artist} - {title}'.format( - artist=media_artist, - title=media_title - ) - else: - # "On Now" field in the sonos pc app - media_artist = self._media_radio_show - - current_uri_metadata = media_info["CurrentURIMetaData"] - if current_uri_metadata not in \ - ('', 'NOT_IMPLEMENTED', None): - - # currently soco does not have an API for this - import soco - current_uri_metadata = soco.xml.XML.fromstring( - soco.utils.really_utf8(current_uri_metadata)) - - md_title = current_uri_metadata.findtext( - './/{http://purl.org/dc/elements/1.1/}title') - - if md_title not in ('', 'NOT_IMPLEMENTED', None): - media_title = md_title - - if media_artist and media_title: - # some radio stations put their name into the artist - # name, e.g.: - # media_title = "Station" - # media_artist = "Station - Artist - Title" - # detect this case and trim from the front of - # media_artist for cosmetics - str_to_trim = '{title} - '.format( - title=media_title - ) - chars = min(len(media_artist), len(str_to_trim)) - - if media_artist[:chars].upper() == \ - str_to_trim[:chars].upper(): - - media_artist = media_artist[chars:] - - else: - # not a radio stream - media_image_url = self._format_media_image_url( - media_image_url, - track_info['uri'] - ) - support_previous_track = True - support_next_track = True - support_stop = True - support_pause = True - - position_info = self._player.avTransport.GetPositionInfo( - [('InstanceID', 0), - ('Channel', 'Master')] - ) - rel_time = _parse_timespan( - position_info.get("RelTime") - ) - - # player no longer reports position? - update_media_position = rel_time is None and \ - self._media_position is not None - - # player started reporting position? - update_media_position |= rel_time is not None and \ - self._media_position is None - - # position changed? - if rel_time is not None and \ - self._media_position is not None: - - time_diff = utcnow() - self._media_position_updated_at - time_diff = time_diff.total_seconds() - - calculated_position = \ - self._media_position + \ - time_diff - - update_media_position = \ - abs(calculated_position - rel_time) > 1.5 - - if update_media_position and self.state == STATE_PLAYING: - media_position = rel_time - media_position_updated_at = utcnow() - else: - # don't update media_position (don't want unneeded - # state transitions) - media_position = self._media_position - media_position_updated_at = \ - self._media_position_updated_at - - playlist_position = track_info.get('playlist_position') - if playlist_position in ('', 'NOT_IMPLEMENTED', None): - playlist_position = None - else: - playlist_position = int(playlist_position) - - playlist_size = media_info.get('NrTracks') - if playlist_size in ('', 'NOT_IMPLEMENTED', None): - playlist_size = None - else: - playlist_size = int(playlist_size) - - if playlist_position is not None and \ - playlist_size is not None: - - if playlist_position == 1: - support_previous_track = False - - if playlist_position == playlist_size: - support_next_track = False - - self._media_content_id = track_info.get('title') - self._media_duration = _parse_timespan( - track_info.get('duration') - ) - self._media_position = media_position - self._media_position_updated_at = media_position_updated_at - self._media_image_url = media_image_url - self._media_artist = media_artist - self._media_album_name = media_album_name - self._media_title = media_title - self._current_track_uri = track_info['uri'] - self._current_track_is_radio_stream = is_radio_stream - self._support_previous_track = support_previous_track - self._support_next_track = support_next_track - self._support_stop = support_stop - self._support_pause = support_pause - self._is_playing_tv = is_playing_tv - self._is_playing_line_in = is_playing_line_in - self._source_name = source_name - - # update state of the whole group - for device in [x for x in self.hass.data[DATA_SONOS] - if x.coordinator == self]: - if device.entity_id is not self.entity_id: - self.schedule_update_ha_state() - - if self._queue is None and self.entity_id is not None: - self._subscribe_to_player_events() - favs = self._player.get_sonos_favorites().get('favorites', []) - self._favorite_sources = [fav['title'] for fav in favs] - else: + if not is_available: self._player_volume = None self._player_volume_muted = None self._status = 'OFF' @@ -623,6 +367,255 @@ class SonosDevice(MediaPlayerDevice): self._is_playing_line_in = False self._favorite_sources = None self._source_name = None + self._last_avtransport_event = None + return + + # set group coordinator + if self._player.is_coordinator: + self._coordinator = None + else: + try: + self._coordinator = _get_entity_from_soco( + self.hass, self._player.group.coordinator) + + # protect for loop + if not self._coordinator.is_coordinator: + # pylint: disable=protected-access + self._coordinator._coordinator = None + except ValueError: + self._coordinator = None + + track_info = None + if self._last_avtransport_event: + variables = self._last_avtransport_event.variables + current_track_metadata = variables.get( + 'current_track_meta_data', {} + ) + + self._status = variables.get('transport_state') + + if current_track_metadata: + # no need to ask speaker for information we already have + current_track_metadata = current_track_metadata.__dict__ + + track_info = { + 'uri': variables.get('current_track_uri'), + 'artist': current_track_metadata.get('creator'), + 'album': current_track_metadata.get('album'), + 'title': current_track_metadata.get('title'), + 'playlist_position': variables.get('current_track'), + 'duration': variables.get('current_track_duration') + } + else: + self._player_volume = self._player.volume + self._player_volume_muted = self._player.mute + transport_info = self._player.get_current_transport_info() + self._status = transport_info.get('current_transport_state') + + if not track_info: + track_info = self._player.get_current_track_info() + + if self._coordinator: + self._last_avtransport_event = None + return + + is_playing_tv = self._player.is_playing_tv + is_playing_line_in = self._player.is_playing_line_in + + media_info = self._player.avTransport.GetMediaInfo( + [('InstanceID', 0)] + ) + + current_media_uri = media_info['CurrentURI'] + media_artist = track_info.get('artist') + media_album_name = track_info.get('album') + media_title = track_info.get('title') + media_image_url = track_info.get('album_art', None) + + media_position = None + media_position_updated_at = None + source_name = None + + is_radio_stream = \ + current_media_uri.startswith('x-sonosapi-stream:') or \ + current_media_uri.startswith('x-rincon-mp3radio:') + + if is_playing_tv or is_playing_line_in: + # playing from line-in/tv. + + support_previous_track = False + support_next_track = False + support_stop = False + support_pause = False + + if is_playing_tv: + media_artist = SUPPORT_SOURCE_TV + else: + media_artist = SUPPORT_SOURCE_LINEIN + + source_name = media_artist + + media_album_name = None + media_title = None + media_image_url = None + + elif is_radio_stream: + media_image_url = self._format_media_image_url( + media_image_url, + current_media_uri + ) + support_previous_track = False + support_next_track = False + support_stop = False + support_pause = False + + source_name = 'Radio' + # Check if currently playing radio station is in favorites + favc = [fav for fav in self._favorite_sources + if fav['uri'] == current_media_uri] + if len(favc) == 1: + src = favc.pop() + source_name = src['title'] + + # for radio streams we set the radio station name as the + # title. + if media_artist and media_title: + # artist and album name are in the data, concatenate + # that do display as artist. + # "Information" field in the sonos pc app + + media_artist = '{artist} - {title}'.format( + artist=media_artist, + title=media_title + ) + else: + # "On Now" field in the sonos pc app + media_artist = self._media_radio_show + + current_uri_metadata = media_info["CurrentURIMetaData"] + if current_uri_metadata not in ('', 'NOT_IMPLEMENTED', None): + + # currently soco does not have an API for this + import soco + current_uri_metadata = soco.xml.XML.fromstring( + soco.utils.really_utf8(current_uri_metadata)) + + md_title = current_uri_metadata.findtext( + './/{http://purl.org/dc/elements/1.1/}title') + + if md_title not in ('', 'NOT_IMPLEMENTED', None): + media_title = md_title + + if media_artist and media_title: + # some radio stations put their name into the artist + # name, e.g.: + # media_title = "Station" + # media_artist = "Station - Artist - Title" + # detect this case and trim from the front of + # media_artist for cosmetics + str_to_trim = '{title} - '.format( + title=media_title + ) + chars = min(len(media_artist), len(str_to_trim)) + + if media_artist[:chars].upper() == str_to_trim[:chars].upper(): + media_artist = media_artist[chars:] + + else: + # not a radio stream + media_image_url = self._format_media_image_url( + media_image_url, + track_info['uri'] + ) + support_previous_track = True + support_next_track = True + support_stop = True + support_pause = True + + position_info = self._player.avTransport.GetPositionInfo( + [('InstanceID', 0), + ('Channel', 'Master')] + ) + rel_time = _parse_timespan( + position_info.get("RelTime") + ) + + # player no longer reports position? + update_media_position = rel_time is None and \ + self._media_position is not None + + # player started reporting position? + update_media_position |= rel_time is not None and \ + self._media_position is None + + # position changed? + if rel_time is not None and self._media_position is not None: + + time_diff = utcnow() - self._media_position_updated_at + time_diff = time_diff.total_seconds() + + calculated_position = self._media_position + time_diff + + update_media_position = \ + abs(calculated_position - rel_time) > 1.5 + + if update_media_position and self.state == STATE_PLAYING: + media_position = rel_time + media_position_updated_at = utcnow() + else: + # don't update media_position (don't want unneeded + # state transitions) + media_position = self._media_position + media_position_updated_at = self._media_position_updated_at + + playlist_position = track_info.get('playlist_position') + if playlist_position in ('', 'NOT_IMPLEMENTED', None): + playlist_position = None + else: + playlist_position = int(playlist_position) + + playlist_size = media_info.get('NrTracks') + if playlist_size in ('', 'NOT_IMPLEMENTED', None): + playlist_size = None + else: + playlist_size = int(playlist_size) + + if playlist_position is not None and playlist_size is not None: + + if playlist_position == 1: + support_previous_track = False + + if playlist_position == playlist_size: + support_next_track = False + + self._media_content_id = track_info.get('title') + self._media_duration = _parse_timespan( + track_info.get('duration') + ) + self._media_position = media_position + self._media_position_updated_at = media_position_updated_at + self._media_image_url = media_image_url + self._media_artist = media_artist + self._media_album_name = media_album_name + self._media_title = media_title + self._current_track_uri = track_info['uri'] + self._current_track_is_radio_stream = is_radio_stream + self._support_previous_track = support_previous_track + self._support_next_track = support_next_track + self._support_stop = support_stop + self._support_pause = support_pause + self._is_playing_tv = is_playing_tv + self._is_playing_line_in = is_playing_line_in + self._source_name = source_name + + # update state of the whole group + for device in [x for x in self.hass.data[DATA_SONOS] + if x.coordinator == self]: + if device.entity_id is not self.entity_id: + self.schedule_update_ha_state() + + if self._queue is None and self.entity_id is not None: + self._subscribe_to_player_events() self._last_avtransport_event = None @@ -807,15 +800,17 @@ class SonosDevice(MediaPlayerDevice): def select_source(self, source): """Select input source.""" - if source == SUPPORT_SOURCE_LINEIN: + if self._coordinator: + self._coordinator.select_source(source) + elif source == SUPPORT_SOURCE_LINEIN: self._source_name = SUPPORT_SOURCE_LINEIN self._player.switch_to_line_in() elif source == SUPPORT_SOURCE_TV: self._source_name = SUPPORT_SOURCE_TV self._player.switch_to_tv() else: - favorites = self._player.get_sonos_favorites()['favorites'] - fav = [fav for fav in favorites if fav['title'] == source] + fav = [fav for fav in self._favorite_sources + if fav['title'] == source] if len(fav) == 1: src = fav.pop() self._source_name = src['title'] @@ -824,9 +819,15 @@ class SonosDevice(MediaPlayerDevice): @property def source_list(self): """List of available input sources.""" - model_name = self._speaker_info['model_name'] + if self._coordinator: + return self._coordinator.source_list - sources = self._favorite_sources.copy() + model_name = self._speaker_info['model_name'] + sources = [] + + if self._favorite_sources: + for fav in self._favorite_sources: + sources.append(fav['title']) if 'PLAY:5' in model_name: sources += [SUPPORT_SOURCE_LINEIN] @@ -940,7 +941,15 @@ class SonosDevice(MediaPlayerDevice): def snapshot(self, with_group=True): """Snapshot the player.""" - self.soco_snapshot.snapshot() + from soco.exceptions import SoCoException + try: + self.soco_snapshot.is_playing_queue = False + self.soco_snapshot.is_coordinator = False + self.soco_snapshot.snapshot() + except SoCoException: + _LOGGER.debug("Error on snapshot %s", self.entity_id) + self._snapshot_group = None + return if with_group: self._snapshot_group = self._player.group diff --git a/tests/components/media_player/test_sonos.py b/tests/components/media_player/test_sonos.py index bcbee544f81..58691d44516 100644 --- a/tests/components/media_player/test_sonos.py +++ b/tests/components/media_player/test_sonos.py @@ -52,6 +52,10 @@ class SoCoMock(): """Clear the sleep timer.""" return + def get_sonos_favorites(self): + """Get favorites list from sonos.""" + return {'favorites': []} + def get_speaker_info(self, force): """Return a dict with various data points about the speaker.""" return {'serial_number': 'B8-E9-37-BO-OC-BA:2', From 86da4f511da5d7498126bed3f4dcc0c36c546247 Mon Sep 17 00:00:00 2001 From: Alessandro Mogavero Date: Tue, 7 Feb 2017 08:28:33 +0000 Subject: [PATCH 096/157] Improve Sky Hub error handling (#5762) * Added error handling in function _get_skyhub_data * Error line split for readability --- homeassistant/components/device_tracker/sky_hub.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/device_tracker/sky_hub.py b/homeassistant/components/device_tracker/sky_hub.py index 647731d8485..15d07f761df 100644 --- a/homeassistant/components/device_tracker/sky_hub.py +++ b/homeassistant/components/device_tracker/sky_hub.py @@ -111,6 +111,9 @@ def _get_skyhub_data(url): def _parse_skyhub_response(data_str): """Parse the Sky Hub data format.""" pattmatch = re.search('attach_dev = \'(.*)\'', data_str) + if pattmatch is None: + raise IOError('Error: Impossible to fetch data from' + + ' Sky Hub. Try to reboot the rooter.') patt = pattmatch.group(1) dev = [patt1.split(',') for patt1 in patt.split('')] From 9a2c84ee8a9fedae3d4b5b65c2389729aecac797 Mon Sep 17 00:00:00 2001 From: Jesse Osiecki Date: Tue, 7 Feb 2017 03:43:03 -0500 Subject: [PATCH 097/157] Added error checking to the MIMEImage encoding for smtp.py (#5753) * Added error checking to the MIMEImage encoding for smtp.py Added fallback to file attachment rather than inline image for images without a known MIME * PEP8 reqs to fix previous commit --- homeassistant/components/notify/smtp.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/notify/smtp.py b/homeassistant/components/notify/smtp.py index 45b477cdfb8..89a71db3cf4 100644 --- a/homeassistant/components/notify/smtp.py +++ b/homeassistant/components/notify/smtp.py @@ -10,6 +10,7 @@ from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage import email.utils +from email.mime.application import MIMEApplication import voluptuous as vol @@ -179,9 +180,19 @@ def _build_multipart_msg(message, images): body_text.append('
'.format(cid)) try: with open(atch_name, 'rb') as attachment_file: - attachment = MIMEImage(attachment_file.read()) - msg.attach(attachment) - attachment.add_header('Content-ID', '<{}>'.format(cid)) + file_bytes = attachment_file.read() + try: + attachment = MIMEImage(file_bytes) + msg.attach(attachment) + attachment.add_header('Content-ID', '<{}>'.format(cid)) + except TypeError: + _LOGGER.warning('Attachment %s has an unkown MIME type.' + ' Falling back to file', atch_name) + attachment = MIMEApplication(file_bytes, Name=atch_name) + attachment['Content-Disposition'] = ('attachment; ' + 'filename="%s"' % + atch_name) + msg.attach(attachment) except FileNotFoundError: _LOGGER.warning('Attachment %s not found. Skipping', atch_name) From c7e282257a2840d289174d4b1aa47b19736a6337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20St=C3=A5hl?= Date: Tue, 7 Feb 2017 09:55:19 +0100 Subject: [PATCH 098/157] Initial support for Apple TV (#5698) * Initial support for Apple TV * hash_wip * Add media_play support to Apple TV --- .coveragerc | 1 + .../components/media_player/apple_tv.py | 246 ++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 250 insertions(+) create mode 100644 homeassistant/components/media_player/apple_tv.py diff --git a/.coveragerc b/.coveragerc index be2f12aa434..251d9a7b6dc 100644 --- a/.coveragerc +++ b/.coveragerc @@ -211,6 +211,7 @@ omit = homeassistant/components/lirc.py homeassistant/components/lock/nuki.py homeassistant/components/media_player/anthemav.py + homeassistant/components/media_player/apple_tv.py homeassistant/components/media_player/aquostv.py homeassistant/components/media_player/braviatv.py homeassistant/components/media_player/cast.py diff --git a/homeassistant/components/media_player/apple_tv.py b/homeassistant/components/media_player/apple_tv.py new file mode 100644 index 00000000000..0eec30a3f70 --- /dev/null +++ b/homeassistant/components/media_player/apple_tv.py @@ -0,0 +1,246 @@ +""" +Support for Apple TV. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/media_player.apple_tv/ +""" +import asyncio +import logging +import hashlib + +import voluptuous as vol + +from homeassistant.components.media_player import ( + SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK, + SUPPORT_STOP, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, MediaPlayerDevice, + PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC, MEDIA_TYPE_VIDEO, MEDIA_TYPE_TVSHOW) +from homeassistant.const import ( + STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_STANDBY, CONF_HOST, + CONF_NAME, EVENT_HOMEASSISTANT_STOP) +import homeassistant.helpers.config_validation as cv +import homeassistant.util.dt as dt_util + + +REQUIREMENTS = ['pyatv==0.0.1'] + +_LOGGER = logging.getLogger(__name__) + +CONF_LOGIN_ID = 'login_id' + +DEFAULT_NAME = 'Apple TV' + +DATA_APPLE_TV = 'apple_tv' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_LOGIN_ID): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + + +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): + """Setup the Apple TV platform.""" + import pyatv + + if DATA_APPLE_TV not in hass.data: + hass.data[DATA_APPLE_TV] = [] + + name = config.get(CONF_NAME) + host = config.get(CONF_HOST) + login_id = config.get(CONF_LOGIN_ID) + + key = '{}:{}'.format(host, name) + if key in hass.data[DATA_APPLE_TV]: + return False + hass.data[DATA_APPLE_TV].append(key) + + details = pyatv.AppleTVDevice(name, host, login_id) + atv = pyatv.connect_to_apple_tv(details, hass.loop) + entity = AppleTvDevice(atv, name) + + @asyncio.coroutine + def async_stop_subscription(event): + """Logout device to close its session.""" + _LOGGER.info("Closing Apple TV session") + yield from atv.logout() + + hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, + async_stop_subscription) + + yield from async_add_entities([entity], update_before_add=True) + + +class AppleTvDevice(MediaPlayerDevice): + """Representation of an Apple TV device.""" + + def __init__(self, atv, name): + """Initialize the Apple TV device.""" + self._name = name + self._atv = atv + self._playing = None + self._artwork = None + self._artwork_hash = None + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def state(self): + """Return the state of the device.""" + if self._playing is not None: + from pyatv import const + state = self._playing.play_state + if state == const.PLAY_STATE_NO_MEDIA: + return STATE_IDLE + elif state == const.PLAY_STATE_PLAYING or \ + state == const.PLAY_STATE_LOADING: + return STATE_PLAYING + elif state == const.PLAY_STATE_PAUSED or \ + state == const.PLAY_STATE_FAST_FORWARD or \ + state == const.PLAY_STATE_FAST_BACKWARD: + # Catch fast forward/backward here so "play" is default action + return STATE_PAUSED + else: + return STATE_STANDBY # Bad or unknown state? + + @asyncio.coroutine + def async_update(self): + """Retrieve latest state.""" + from pyatv import exceptions + try: + playing = yield from self._atv.metadata.playing() + + if self._should_download_artwork(playing): + self._artwork = None + self._artwork_hash = None + self._artwork = yield from self._atv.metadata.artwork() + if self._artwork: + self._artwork_hash = hashlib.md5(self._artwork).hexdigest() + + self._playing = playing + except exceptions.AuthenticationError as ex: + _LOGGER.warning('%s (bad login id?)', str(ex)) + except asyncio.TimeoutError: + _LOGGER.warning('timed out while connecting to Apple TV') + + def _should_download_artwork(self, new_playing): + if self._playing is None: + return True + old_playing = self._playing + return new_playing.media_type != old_playing.media_type or \ + new_playing.title != old_playing.title + + @property + def media_content_type(self): + """Content type of current playing media.""" + if self._playing is not None: + from pyatv import const + media_type = self._playing.media_type + if media_type == const.MEDIA_TYPE_VIDEO: + return MEDIA_TYPE_VIDEO + elif media_type == const.MEDIA_TYPE_MUSIC: + return MEDIA_TYPE_MUSIC + elif media_type == const.MEDIA_TYPE_TV: + return MEDIA_TYPE_TVSHOW + + @property + def media_duration(self): + """Duration of current playing media in seconds.""" + if self._playing is not None: + return self._playing.total_time + + @property + def media_position(self): + """Position of current playing media in seconds.""" + if self._playing is not None: + return self._playing.position + + @property + def media_position_updated_at(self): + """Last valid time of media position.""" + state = self.state + if state == STATE_PLAYING or state == STATE_PAUSED: + return dt_util.utcnow() + + @asyncio.coroutine + def async_play_media(self, media_type, media_id, **kwargs): + """Send the play_media command to the media player.""" + yield from self._atv.remote_control.play_url(media_id, 0) + + @property + def media_image(self): + """Artwork for what is currently playing.""" + return self._artwork, 'image/png', self._artwork_hash + + @property + def media_title(self): + """Title of current playing media.""" + if self._playing is not None: + title = self._playing.title + return title if title else "No title" + + @property + def supported_media_commands(self): + """Flag of media commands that are supported.""" + if self._playing is not None: + if self.state != STATE_IDLE: + return SUPPORT_PAUSE | SUPPORT_PLAY | \ + SUPPORT_SEEK | SUPPORT_STOP | \ + SUPPORT_NEXT_TRACK | SUPPORT_PREVIOUS_TRACK | \ + SUPPORT_PLAY_MEDIA + else: + return SUPPORT_PLAY_MEDIA + + def async_media_play_pause(self): + """Pause media on media player. + + This method must be run in the event loop and returns a coroutine. + """ + if self._playing is not None: + state = self.state + if state == STATE_PAUSED: + return self._atv.remote_control.play() + elif state == STATE_PLAYING: + return self._atv.remote_control.pause() + + def async_media_play(self): + """Play media. + + This method must be run in the event loop and returns a coroutine. + """ + if self._playing is not None: + return self._atv.remote_control.play() + + def async_media_pause(self): + """Pause the media player. + + This method must be run in the event loop and returns a coroutine. + """ + if self._playing is not None: + return self._atv.remote_control.pause() + + def async_media_next_track(self): + """Send next track command. + + This method must be run in the event loop and returns a coroutine. + """ + if self._playing is not None: + return self._atv.remote_control.next() + + def async_media_previous_track(self): + """Send previous track command. + + This method must be run in the event loop and returns a coroutine. + """ + if self._playing is not None: + return self._atv.remote_control.previous() + + @asyncio.coroutine + def async_media_seek(self, position): + """Send seek command.""" + if self._playing is not None: + yield from self._atv.remote_control.set_position(position) diff --git a/requirements_all.txt b/requirements_all.txt index bcf935e7e69..e3e06dcebe8 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -414,6 +414,9 @@ pyasn1-modules==0.0.8 # homeassistant.components.notify.xmpp pyasn1==0.2.1 +# homeassistant.components.media_player.apple_tv +pyatv==0.0.1 + # homeassistant.components.device_tracker.bbox # homeassistant.components.sensor.bbox pybbox==0.0.5-alpha From 51810620fbce3a1244a9da5df903509d3da4299e Mon Sep 17 00:00:00 2001 From: Hermann Kraus Date: Tue, 7 Feb 2017 10:13:00 +0100 Subject: [PATCH 099/157] Check for command topics when determinig the capabilities of an MQTT light. (#5770) Previous code used the state topic which is obviously wrong: - The state topic is already used to select optimistic mode. - A light with only the state topic but no command topic would still announce the capability. --- homeassistant/components/light/mqtt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/light/mqtt.py b/homeassistant/components/light/mqtt.py index 54fa6b30598..5f227af97b6 100644 --- a/homeassistant/components/light/mqtt.py +++ b/homeassistant/components/light/mqtt.py @@ -121,12 +121,12 @@ class MqttLight(Light): self._state = False self._supported_features = 0 self._supported_features |= ( - topic[CONF_RGB_STATE_TOPIC] is not None and SUPPORT_RGB_COLOR) + topic[CONF_RGB_COMMAND_TOPIC] is not None and SUPPORT_RGB_COLOR) self._supported_features |= ( - topic[CONF_BRIGHTNESS_STATE_TOPIC] is not None and + topic[CONF_BRIGHTNESS_COMMAND_TOPIC] is not None and SUPPORT_BRIGHTNESS) self._supported_features |= ( - topic[CONF_COLOR_TEMP_STATE_TOPIC] is not None and + topic[CONF_COLOR_TEMP_COMMAND_TOPIC] is not None and SUPPORT_COLOR_TEMP) for key, tpl in list(templates.items()): From f774538e663dbe5b4f1a58b41ff1a5ed36ee7191 Mon Sep 17 00:00:00 2001 From: andrey-git Date: Tue, 7 Feb 2017 11:19:08 +0200 Subject: [PATCH 100/157] Check config before restarting (#5609) * Check config before restarting. * Make check_config on restart async * don't check if notification service exists * Use .communicate() * Reduce the number of notifications. Add tests. --- homeassistant/core.py | 33 +++++++++++++++++++++-- homeassistant/scripts/check_config.py | 2 +- tests/common.py | 5 ++++ tests/test_core.py | 38 +++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/homeassistant/core.py b/homeassistant/core.py index e2831a63d75..2cf2e3c85e4 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -330,11 +330,40 @@ class HomeAssistant(object): self.exit_code = 0 self.loop.create_task(self.async_stop()) + @asyncio.coroutine + def _async_check_config_and_restart(self): + """Restart Home Assistant if config is valid. + + This method is a coroutine. + """ + proc = yield from asyncio.create_subprocess_exec( + sys.argv[0], + '--script', + 'check_config', + stdout=asyncio.subprocess.PIPE) + # Wait for the subprocess exit + (stdout_data, dummy) = yield from proc.communicate() + result = yield from proc.wait() + if result: + _LOGGER.error("check_config failed. Not restarting.") + content = re.sub(r'\033\[[^m]*m', '', str(stdout_data, 'utf-8')) + # Put error cleaned from color codes in the error log so it + # will be visible at the UI. + _LOGGER.error(content) + yield from self.services.async_call( + 'persistent_notification', 'create', { + 'message': 'Config error. See dev-info panel for details.', + 'title': 'Restarting', + 'notification_id': '{}.restart'.format(DOMAIN)}) + return + + self.exit_code = RESTART_EXIT_CODE + yield from self.async_stop() + @callback def _async_restart_handler(self, *args): """Restart Home Assistant.""" - self.exit_code = RESTART_EXIT_CODE - self.loop.create_task(self.async_stop()) + self.loop.create_task(self._async_check_config_and_restart()) class EventOrigin(enum.Enum): diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index cb825ad44c8..b1ecaaa57ba 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -96,7 +96,6 @@ def run(script_args: List) -> int: domain_info = args.info.split(',') res = check(config_path) - if args.files: print(color(C_HEAD, 'yaml files'), '(used /', color('red', 'not used') + ')') @@ -247,6 +246,7 @@ def check(config_path): res['secret_cache'] = dict(yaml.__SECRET_CACHE) except Exception as err: # pylint: disable=broad-except print(color('red', 'Fatal error while loading config:'), str(err)) + res['except'].setdefault(ERROR_STR, []).append(err) finally: # Stop all patches for pat in PATCHES.values(): diff --git a/tests/common.py b/tests/common.py index b602edbd717..98a3102edf7 100644 --- a/tests/common.py +++ b/tests/common.py @@ -388,6 +388,11 @@ def mock_coro(return_value=None): return coro +def mock_generator(return_value=None): + """Helper method to return a coro generator that returns a value.""" + return mock_coro(return_value)() + + @contextmanager def assert_setup_component(count, domain=None): """Collect valid configuration from setup_component. diff --git a/tests/test_core.py b/tests/test_core.py index 14276584ae2..72c459a4eac 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -14,9 +14,10 @@ from homeassistant.util.async import run_coroutine_threadsafe import homeassistant.util.dt as dt_util from homeassistant.util.unit_system import (METRIC_SYSTEM) from homeassistant.const import ( - __version__, EVENT_STATE_CHANGED, ATTR_FRIENDLY_NAME, CONF_UNIT_SYSTEM) + __version__, EVENT_STATE_CHANGED, ATTR_FRIENDLY_NAME, CONF_UNIT_SYSTEM, + SERVICE_HOMEASSISTANT_RESTART, RESTART_EXIT_CODE) -from tests.common import get_test_home_assistant +from tests.common import get_test_home_assistant, mock_generator PST = pytz.timezone('America/Los_Angeles') @@ -220,6 +221,39 @@ class TestHomeAssistant(unittest.TestCase): with pytest.raises(ValueError): self.hass.add_job(None, 'test_arg') + @patch('asyncio.create_subprocess_exec') + def test_restart(self, mock_create): + """Check that restart propagates to stop.""" + process_mock = MagicMock() + attrs = { + 'communicate.return_value': mock_generator(('output', 'error')), + 'wait.return_value': mock_generator(0)} + process_mock.configure_mock(**attrs) + mock_create.return_value = mock_generator(process_mock) + + self.hass.start() + with patch.object(self.hass, 'async_stop') as mock_stop: + self.hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART) + mock_stop.assert_called_once_with() + self.assertEqual(RESTART_EXIT_CODE, self.hass.exit_code) + + @patch('asyncio.create_subprocess_exec') + def test_restart_bad_config(self, mock_create): + """Check that restart with a bad config doesn't propagate to stop.""" + process_mock = MagicMock() + attrs = { + 'communicate.return_value': + mock_generator((r'\033[hellom'.encode('utf-8'), 'error')), + 'wait.return_value': mock_generator(1)} + process_mock.configure_mock(**attrs) + mock_create.return_value = mock_generator(process_mock) + + self.hass.start() + with patch.object(self.hass, 'async_stop') as mock_stop: + self.hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART) + mock_stop.assert_not_called() + self.assertEqual(None, self.hass.exit_code) + class TestEvent(unittest.TestCase): """A Test Event class.""" From f0da5763152355add85f36ab6ffa46637d9c545d Mon Sep 17 00:00:00 2001 From: Trevor Date: Tue, 7 Feb 2017 03:51:05 -0600 Subject: [PATCH 101/157] Fix Hue groups with same names (#5737) * Revert "Fix hue lightgroups not syncing state (#5702)" * Use light_id in unique_id for Hue groups * Make sure HueLight unique_id is unique * Update hue.py * Update hue.py * Update hue.py --- homeassistant/components/light/hue.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 65ae9f30cf4..372dec04fbc 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -200,8 +200,7 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable, for light_id, info in api_lights.items(): if light_id not in lights: - lights[light_id] = HueLight(hass, - int(light_id), info, + lights[light_id] = HueLight(int(light_id), info, bridge, update_lights, bridge_type, allow_unreachable, allow_in_emulated_hue) @@ -219,7 +218,6 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable, if lightgroup_id not in lightgroups: lightgroups[lightgroup_id] = HueLight( - hass, int(lightgroup_id), info, bridge, update_lights, bridge_type, allow_unreachable, allow_in_emulated_hue, True) @@ -282,11 +280,10 @@ def request_configuration(host, hass, add_devices, filename, class HueLight(Light): """Representation of a Hue light.""" - def __init__(self, hass, light_id, info, bridge, update_lights, + def __init__(self, light_id, info, bridge, update_lights, bridge_type, allow_unreachable, allow_in_emulated_hue, is_group=False): """Initialize the light.""" - self.hass = hass self.light_id = light_id self.info = info self.bridge = bridge @@ -304,8 +301,14 @@ class HueLight(Light): @property def unique_id(self): """Return the ID of this Hue light.""" - return "{}.{}".format( - self.__class__, self.info.get('uniqueid', self.name)) + lid = self.info.get('uniqueid') + + if lid is None: + default_type = 'Group' if self.is_group else 'Light' + ltype = self.info.get('type', default_type) + lid = '{}.{}.{}'.format(self.name, ltype, self.light_id) + + return '{}.{}'.format(self.__class__, lid) @property def name(self): From 063c0e8f441a51f76487a390260fcf25077081a3 Mon Sep 17 00:00:00 2001 From: Trevor Date: Tue, 7 Feb 2017 03:51:44 -0600 Subject: [PATCH 102/157] Add icon_template to template sensor (#5766) * Add icon_template to template sensor * Update test_template.py * Update test_template.py again * Update template.py * Update test_template.py * Update test_template.py --- homeassistant/components/sensor/template.py | 29 ++++++++++++++++++++- tests/components/sensor/test_template.py | 27 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/template.py b/homeassistant/components/sensor/template.py index 44c6d2e08ea..2535bea1539 100644 --- a/homeassistant/components/sensor/template.py +++ b/homeassistant/components/sensor/template.py @@ -21,8 +21,11 @@ import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) +CONF_ICON_TEMPLATE = 'icon_template' + SENSOR_SCHEMA = vol.Schema({ vol.Required(CONF_VALUE_TEMPLATE): cv.template, + vol.Optional(CONF_ICON_TEMPLATE): cv.template, vol.Optional(ATTR_FRIENDLY_NAME): cv.string, vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(ATTR_ENTITY_ID): cv.entity_ids @@ -41,6 +44,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for device, device_config in config[CONF_SENSORS].items(): state_template = device_config[CONF_VALUE_TEMPLATE] + icon_template = device_config.get(CONF_ICON_TEMPLATE) entity_ids = (device_config.get(ATTR_ENTITY_ID) or state_template.extract_entities()) friendly_name = device_config.get(ATTR_FRIENDLY_NAME, device) @@ -48,6 +52,9 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): state_template.hass = hass + if icon_template is not None: + icon_template.hass = hass + sensors.append( SensorTemplate( hass, @@ -55,6 +62,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): friendly_name, unit_of_measurement, state_template, + icon_template, entity_ids) ) if not sensors: @@ -69,7 +77,7 @@ class SensorTemplate(Entity): """Representation of a Template Sensor.""" def __init__(self, hass, device_id, friendly_name, unit_of_measurement, - state_template, entity_ids): + state_template, icon_template, entity_ids): """Initialize the sensor.""" self.hass = hass self.entity_id = async_generate_entity_id(ENTITY_ID_FORMAT, device_id, @@ -78,6 +86,8 @@ class SensorTemplate(Entity): self._unit_of_measurement = unit_of_measurement self._template = state_template self._state = None + self._icon_template = icon_template + self._icon = None @callback def template_sensor_state_listener(entity, old_state, new_state): @@ -97,6 +107,11 @@ class SensorTemplate(Entity): """Return the state of the sensor.""" return self._state + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + return self._icon + @property def unit_of_measurement(self): """Return the unit_of_measurement of the device.""" @@ -120,3 +135,15 @@ class SensorTemplate(Entity): return self._state = None _LOGGER.error(ex) + + if self._icon_template is not None: + try: + self._icon = self._icon_template.async_render() + except TemplateError as ex: + if ex.args and ex.args[0].startswith( + "UndefinedError: 'None' has no attribute"): + # Common during HA startup - so just a warning + _LOGGER.warning(ex) + return + self._icon = super().icon + _LOGGER.error(ex) diff --git a/tests/components/sensor/test_template.py b/tests/components/sensor/test_template.py index 58f0fb84ac7..0f5e863f328 100644 --- a/tests/components/sensor/test_template.py +++ b/tests/components/sensor/test_template.py @@ -41,6 +41,33 @@ class TestTemplateSensor: state = self.hass.states.get('sensor.test_template_sensor') assert state.state == 'It Works.' + def test_icon_template(self): + """Test icon template.""" + with assert_setup_component(1): + assert setup_component(self.hass, 'sensor', { + 'sensor': { + 'platform': 'template', + 'sensors': { + 'test_template_sensor': { + 'value_template': "State", + 'icon_template': + "{% if states.sensor.test_state.state == " + "'Works' %}" + "mdi:check" + "{% endif %}" + } + } + } + }) + + state = self.hass.states.get('sensor.test_template_sensor') + assert 'icon' not in state.attributes + + self.hass.states.set('sensor.test_state', 'Works') + self.hass.block_till_done() + state = self.hass.states.get('sensor.test_template_sensor') + assert state.attributes['icon'] == 'mdi:check' + def test_template_syntax_error(self): """Test templating syntax error.""" with assert_setup_component(0): From 45507cd9d1a8f97d20a41b5c20ad0edc0b713f01 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Tue, 7 Feb 2017 03:07:11 -0800 Subject: [PATCH 103/157] TTS ID3 support (#5773) * Add support for writing ID3 tags to the file for improved display in media players * Lint and async fixes * Use mutagen instead of taglib * Fix tests * Add fallback for album * Requested changes * move import * Fix album name * Change default options handling * Move to member function / minor fix * fix style * fix lint * change mutagen handling * fix lint / add name to bytesio * Update __init__.py * Fix test, some cleanups * Add mutagen exeption handling, fix tests * fix mutagen taging --- homeassistant/components/tts/__init__.py | 43 +++++++++++++++++++- homeassistant/components/tts/amazon_polly.py | 1 + homeassistant/components/tts/demo.py | 1 + homeassistant/components/tts/google.py | 1 + homeassistant/components/tts/picotts.py | 1 + homeassistant/components/tts/voicerss.py | 1 + homeassistant/components/tts/yandextts.py | 1 + requirements_all.txt | 3 ++ tests/components/tts/test_init.py | 9 ++++ 9 files changed, 60 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index 9b4df2749c0..fb99219416f 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -12,6 +12,7 @@ import logging import mimetypes import os import re +import io from aiohttp import web import voluptuous as vol @@ -30,6 +31,7 @@ import homeassistant.helpers.config_validation as cv DOMAIN = 'tts' DEPENDENCIES = ['http'] +REQUIREMENTS = ["mutagen==1.36.2"] _LOGGER = logging.getLogger(__name__) @@ -255,6 +257,8 @@ class SpeechManager(object): def async_register_engine(self, engine, provider, config): """Register a TTS provider.""" provider.hass = self.hass + if provider.name is None: + provider.name = engine self.providers[engine] = provider @asyncio.coroutine @@ -276,6 +280,8 @@ class SpeechManager(object): language)) # options + if provider.default_options and options: + options = provider.default_options.copy().update(options) options = options or provider.default_options if options is not None: invalid_opts = [opt_name for opt_name in options.keys() @@ -296,7 +302,7 @@ class SpeechManager(object): # is file store in file cache elif use_cache and key in self.file_cache: filename = self.file_cache[key] - self.hass.async_add_job(self.async_file_to_mem(key)) + yield from self.async_file_to_mem(key) # load speech from provider into memory else: filename = yield from self.async_get_tts_audio( @@ -323,6 +329,9 @@ class SpeechManager(object): # create file infos filename = ("{}.{}".format(key, extension)).lower() + data = self.write_tags( + filename, data, provider, message, language, options) + # save to memory self._async_store_to_memcache(key, filename, data) @@ -412,11 +421,43 @@ class SpeechManager(object): content, _ = mimetypes.guess_type(filename) return (content, self.mem_cache[key][MEM_CACHE_VOICE]) + @staticmethod + def write_tags(filename, data, provider, message, language, options): + """Write ID3 tags to file. + + Async friendly. + """ + import mutagen + + data_bytes = io.BytesIO(data) + data_bytes.name = filename + data_bytes.seek(0) + + album = provider.name + artist = language + + if options is not None: + if options.get('voice') is not None: + artist = options.get('voice') + + try: + tts_file = mutagen.File(data_bytes, easy=True) + if tts_file is not None: + tts_file['artist'] = artist + tts_file['album'] = album + tts_file['title'] = message + tts_file.save(data_bytes) + except mutagen.MutagenError as err: + _LOGGER.error("ID3 tag error: %s", err) + + return data_bytes.getvalue() + class Provider(object): """Represent a single provider.""" hass = None + name = None @property def default_language(self): diff --git a/homeassistant/components/tts/amazon_polly.py b/homeassistant/components/tts/amazon_polly.py index e40c10f5e14..7dab49482ed 100644 --- a/homeassistant/components/tts/amazon_polly.py +++ b/homeassistant/components/tts/amazon_polly.py @@ -138,6 +138,7 @@ class AmazonPollyProvider(Provider): self.supported_langs = supported_languages self.all_voices = all_voices self.default_voice = self.config.get(CONF_VOICE) + self.name = 'Amazon Polly' @property def supported_languages(self): diff --git a/homeassistant/components/tts/demo.py b/homeassistant/components/tts/demo.py index 95362b49db9..d9d1eccec8d 100644 --- a/homeassistant/components/tts/demo.py +++ b/homeassistant/components/tts/demo.py @@ -32,6 +32,7 @@ class DemoProvider(Provider): def __init__(self, lang): """Initialize demo provider.""" self._lang = lang + self.name = 'Demo' @property def default_language(self): diff --git a/homeassistant/components/tts/google.py b/homeassistant/components/tts/google.py index 32c9663eedc..be84e0e029b 100644 --- a/homeassistant/components/tts/google.py +++ b/homeassistant/components/tts/google.py @@ -58,6 +58,7 @@ class GoogleProvider(Provider): "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/47.0.2526.106 Safari/537.36") } + self.name = 'Google' @property def default_language(self): diff --git a/homeassistant/components/tts/picotts.py b/homeassistant/components/tts/picotts.py index 49addd9b177..a22196cfbe0 100644 --- a/homeassistant/components/tts/picotts.py +++ b/homeassistant/components/tts/picotts.py @@ -38,6 +38,7 @@ class PicoProvider(Provider): def __init__(self, lang): """Initialize Pico TTS provider.""" self._lang = lang + self.name = 'PicoTTS' @property def default_language(self): diff --git a/homeassistant/components/tts/voicerss.py b/homeassistant/components/tts/voicerss.py index b0c74d1de30..ee50cc30cca 100644 --- a/homeassistant/components/tts/voicerss.py +++ b/homeassistant/components/tts/voicerss.py @@ -95,6 +95,7 @@ class VoiceRSSProvider(Provider): self.hass = hass self._extension = conf[CONF_CODEC] self._lang = conf[CONF_LANG] + self.name = 'VoiceRSS' self._form_data = { 'key': conf[CONF_API_KEY], diff --git a/homeassistant/components/tts/yandextts.py b/homeassistant/components/tts/yandextts.py index 824ca6ca38f..b60f9cab61e 100644 --- a/homeassistant/components/tts/yandextts.py +++ b/homeassistant/components/tts/yandextts.py @@ -82,6 +82,7 @@ class YandexSpeechKitProvider(Provider): self._language = conf.get(CONF_LANG) self._emotion = conf.get(CONF_EMOTION) self._speed = str(conf.get(CONF_SPEED)) + self.name = 'YandexTTS' @property def default_language(self): diff --git a/requirements_all.txt b/requirements_all.txt index e3e06dcebe8..d8d598dc17f 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -328,6 +328,9 @@ mficlient==0.3.0 # homeassistant.components.sensor.miflora miflora==0.1.15 +# homeassistant.components.tts +mutagen==1.36.2 + # homeassistant.components.sensor.usps myusps==1.0.2 diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py index f7985b8af74..0db7c1a5bef 100644 --- a/tests/components/tts/test_init.py +++ b/tests/components/tts/test_init.py @@ -341,6 +341,10 @@ class TestTTS(object): assert len(calls) == 1 req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID]) _, demo_data = self.demo_provider.get_tts_audio("bla", 'en') + demo_data = tts.SpeechManager.write_tags( + "265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3", + demo_data, self.demo_provider, + "I person is on front of your door.", 'en', None) assert req.status_code == 200 assert req.content == demo_data @@ -351,6 +355,7 @@ class TestTTS(object): config = { tts.DOMAIN: { 'platform': 'demo', + 'language': 'de', } } @@ -367,6 +372,10 @@ class TestTTS(object): assert len(calls) == 1 req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID]) _, demo_data = self.demo_provider.get_tts_audio("bla", "de") + demo_data = tts.SpeechManager.write_tags( + "265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3", + demo_data, self.demo_provider, + "I person is on front of your door.", 'de', None) assert req.status_code == 200 assert req.content == demo_data From c7fd28c10f3ca2c59301c9b553bb6098590927f6 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 7 Feb 2017 18:13:24 +0100 Subject: [PATCH 104/157] MQTT discovery (#5724) * Change implementation * Re-write * Remove unused consts * Update discovery.py * Add tests * fix other tests * Fix check_config script test * Lint * Lint --- .../components/binary_sensor/mqtt.py | 5 +- homeassistant/components/mqtt/__init__.py | 44 +++++++++-- homeassistant/components/mqtt/discovery.py | 62 ++++++++++++++++ tests/common.py | 12 ++- tests/components/mqtt/test_discovery.py | 74 +++++++++++++++++++ tests/conftest.py | 19 ++++- tests/scripts/test_check_config.py | 8 +- 7 files changed, 213 insertions(+), 11 deletions(-) create mode 100644 homeassistant/components/mqtt/discovery.py create mode 100644 tests/components/mqtt/test_discovery.py diff --git a/homeassistant/components/binary_sensor/mqtt.py b/homeassistant/components/binary_sensor/mqtt.py index 28d9566b2ab..8c8beaddb6e 100644 --- a/homeassistant/components/binary_sensor/mqtt.py +++ b/homeassistant/components/binary_sensor/mqtt.py @@ -36,7 +36,10 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the MQTT binary sensor.""" + """Set up the MQTT binary sensor.""" + if discovery_info is not None: + config = PLATFORM_SCHEMA(discovery_info) + value_template = config.get(CONF_VALUE_TEMPLATE) if value_template is not None: value_template.hass = hass diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index ad4cce15cf3..e880be177e8 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -4,7 +4,6 @@ Support for MQTT message handling. For more details about this component, please refer to the documentation at https://home-assistant.io/components/mqtt/ """ -import asyncio import logging import os import socket @@ -12,6 +11,7 @@ import time import voluptuous as vol +from homeassistant.core import callback from homeassistant.bootstrap import prepare_setup_platform from homeassistant.config import load_yaml_config_file from homeassistant.exceptions import HomeAssistantError @@ -36,6 +36,8 @@ REQUIREMENTS = ['paho-mqtt==1.2'] CONF_EMBEDDED = 'embedded' CONF_BROKER = 'broker' CONF_CLIENT_ID = 'client_id' +CONF_DISCOVERY = 'discovery' +CONF_DISCOVERY_PREFIX = 'discovery_prefix' CONF_KEEPALIVE = 'keepalive' CONF_CERTIFICATE = 'certificate' CONF_CLIENT_KEY = 'client_key' @@ -58,6 +60,8 @@ DEFAULT_KEEPALIVE = 60 DEFAULT_QOS = 0 DEFAULT_RETAIN = False DEFAULT_PROTOCOL = PROTOCOL_311 +DEFAULT_DISCOVERY = False +DEFAULT_DISCOVERY_PREFIX = 'homeassistant' ATTR_TOPIC = 'topic' ATTR_PAYLOAD = 'payload' @@ -70,7 +74,8 @@ MAX_RECONNECT_WAIT = 300 # seconds def valid_subscribe_topic(value, invalid_chars='\0'): """Validate that we can subscribe using this MQTT topic.""" - if isinstance(value, str) and all(c not in value for c in invalid_chars): + value = cv.string(value) + if all(c not in value for c in invalid_chars): return vol.Length(min=1, max=65535)(value) raise vol.Invalid('Invalid MQTT topic name') @@ -80,6 +85,11 @@ def valid_publish_topic(value): return valid_subscribe_topic(value, invalid_chars='#+\0') +def valid_discovery_topic(value): + """Validate a discovery topic.""" + return valid_subscribe_topic(value, invalid_chars='#+\0/') + + _VALID_QOS_SCHEMA = vol.All(vol.Coerce(int), vol.In([0, 1, 2])) CLIENT_KEY_AUTH_MSG = 'client_key and client_cert must both be present in ' \ @@ -111,7 +121,10 @@ CONFIG_SCHEMA = vol.Schema({ vol.All(cv.string, vol.In([PROTOCOL_31, PROTOCOL_311])), vol.Optional(CONF_EMBEDDED): HBMQTT_CONFIG_SCHEMA, vol.Optional(CONF_WILL_MESSAGE): MQTT_WILL_BIRTH_SCHEMA, - vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA + vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA, + vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): cv.boolean, + vol.Optional(CONF_DISCOVERY_PREFIX, + default=DEFAULT_DISCOVERY_PREFIX): valid_discovery_topic, }), }, extra=vol.ALLOW_EXTRA) @@ -170,15 +183,16 @@ def publish_template(hass, topic, payload_template, qos=None, retain=None): hass.services.call(DOMAIN, SERVICE_PUBLISH, data) -def async_subscribe(hass, topic, callback, qos=DEFAULT_QOS): +@callback +def async_subscribe(hass, topic, msg_callback, qos=DEFAULT_QOS): """Subscribe to an MQTT topic.""" - @asyncio.coroutine + @callback def mqtt_topic_subscriber(event): """Match subscribed MQTT topic.""" if not _match_topic(topic, event.data[ATTR_TOPIC]): return - hass.async_run_job(callback, event.data[ATTR_TOPIC], + hass.async_run_job(msg_callback, event.data[ATTR_TOPIC], event.data[ATTR_PAYLOAD], event.data[ATTR_QOS]) async_remove = hass.bus.async_listen(EVENT_MQTT_MESSAGE_RECEIVED, @@ -213,6 +227,21 @@ def _setup_server(hass, config): return success and broker_config +def _setup_discovery(hass, config): + """Try to start the discovery of MQTT devices.""" + conf = config.get(DOMAIN, {}) + + discovery = prepare_setup_platform(hass, config, DOMAIN, 'discovery') + + if discovery is None: + _LOGGER.error("Unable to load MQTT discovery") + return None + + success = discovery.start(hass, conf[CONF_DISCOVERY_PREFIX], config) + + return success + + def setup(hass, config): """Start the MQTT protocol service.""" conf = config.get(DOMAIN, {}) @@ -301,6 +330,9 @@ def setup(hass, config): descriptions.get(SERVICE_PUBLISH), schema=MQTT_PUBLISH_SCHEMA) + if conf.get(CONF_DISCOVERY): + _setup_discovery(hass, config) + return True diff --git a/homeassistant/components/mqtt/discovery.py b/homeassistant/components/mqtt/discovery.py new file mode 100644 index 00000000000..ca2d37bbbba --- /dev/null +++ b/homeassistant/components/mqtt/discovery.py @@ -0,0 +1,62 @@ +""" +Support for MQTT discovery. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/mqtt/#discovery +""" +import asyncio +import json +import logging +import re + +from homeassistant.core import callback +import homeassistant.components.mqtt as mqtt +from homeassistant.components.mqtt import DOMAIN +from homeassistant.helpers.discovery import async_load_platform +from homeassistant.const import CONF_PLATFORM +from homeassistant.components.mqtt import CONF_STATE_TOPIC + +_LOGGER = logging.getLogger(__name__) + +TOPIC_MATCHER = re.compile( + r'homeassistant/(?P\w+)/(?P\w+)/config') +SUPPORTED_COMPONENTS = ['binary_sensor'] + + +@callback +def async_start(hass, discovery_topic, hass_config): + """Initialization of MQTT Discovery.""" + @asyncio.coroutine + def async_device_message_received(topic, payload, qos): + """Process the received message.""" + match = TOPIC_MATCHER.match(topic) + + if not match: + return + + component, object_id = match.groups() + + try: + payload = json.loads(payload) + except ValueError: + _LOGGER.warning( + "Unable to parse JSON %s: %s", object_id, payload) + return + + if component not in SUPPORTED_COMPONENTS: + _LOGGER.warning("Component %s is not supported", component) + return + + payload = dict(payload) + payload[CONF_PLATFORM] = 'mqtt' + if CONF_STATE_TOPIC not in payload: + payload[CONF_STATE_TOPIC] = '{}/{}/{}/state'.format( + discovery_topic, component, object_id) + + yield from async_load_platform( + hass, component, DOMAIN, payload, hass_config) + + mqtt.async_subscribe(hass, discovery_topic + '/#', + async_device_message_received, 0) + + return True diff --git a/tests/common.py b/tests/common.py index 98a3102edf7..5ebca8640cc 100644 --- a/tests/common.py +++ b/tests/common.py @@ -26,6 +26,7 @@ from homeassistant.components import sun, mqtt from homeassistant.components.http.auth import auth_middleware from homeassistant.components.http.const import ( KEY_USE_X_FORWARDED_FOR, KEY_BANS_ENABLED, KEY_TRUSTED_NETWORKS) +from homeassistant.util.async import run_callback_threadsafe _TEST_INSTANCE_PORT = SERVER_PORT _LOGGER = logging.getLogger(__name__) @@ -147,15 +148,22 @@ def mock_service(hass, domain, service): return calls -def fire_mqtt_message(hass, topic, payload, qos=0): +@ha.callback +def async_fire_mqtt_message(hass, topic, payload, qos=0): """Fire the MQTT message.""" - hass.bus.fire(mqtt.EVENT_MQTT_MESSAGE_RECEIVED, { + hass.bus.async_fire(mqtt.EVENT_MQTT_MESSAGE_RECEIVED, { mqtt.ATTR_TOPIC: topic, mqtt.ATTR_PAYLOAD: payload, mqtt.ATTR_QOS: qos, }) +def fire_mqtt_message(hass, topic, payload, qos=0): + """Fire the MQTT message.""" + run_callback_threadsafe( + hass.loop, async_fire_mqtt_message, hass, topic, payload, qos).result() + + def fire_time_changed(hass, time): """Fire a time changes event.""" hass.bus.fire(EVENT_TIME_CHANGED, {'now': time}) diff --git a/tests/components/mqtt/test_discovery.py b/tests/components/mqtt/test_discovery.py new file mode 100644 index 00000000000..bf6fa2f2603 --- /dev/null +++ b/tests/components/mqtt/test_discovery.py @@ -0,0 +1,74 @@ +"""The tests for the MQTT component.""" +import asyncio +from unittest.mock import patch + +from homeassistant.components.mqtt.discovery import async_start + +from tests.common import async_fire_mqtt_message, mock_coro + + +@asyncio.coroutine +def test_subscribing_config_topic(hass, mqtt_mock): + """Test setting up discovery.""" + hass_config = {} + discovery_topic = 'homeassistant' + async_start(hass, discovery_topic, hass_config) + assert mqtt_mock.subscribe.called + call_args = mqtt_mock.subscribe.mock_calls[0][1] + assert call_args[0] == discovery_topic + '/#' + assert call_args[1] == 0 + + +@asyncio.coroutine +@patch('homeassistant.components.mqtt.discovery.async_load_platform') +def test_invalid_topic(mock_load_platform, hass, mqtt_mock): + """Test sending in invalid JSON.""" + mock_load_platform.return_value = mock_coro() + async_start(hass, 'homeassistant', {}) + + async_fire_mqtt_message(hass, 'homeassistant/binary_sensor/bla/not_config', + '{}') + yield from hass.async_block_till_done() + assert not mock_load_platform.called + + +@asyncio.coroutine +@patch('homeassistant.components.mqtt.discovery.async_load_platform') +def test_invalid_json(mock_load_platform, hass, mqtt_mock, caplog): + """Test sending in invalid JSON.""" + mock_load_platform.return_value = mock_coro() + async_start(hass, 'homeassistant', {}) + + async_fire_mqtt_message(hass, 'homeassistant/binary_sensor/bla/config', + 'not json') + yield from hass.async_block_till_done() + assert 'Unable to parse JSON' in caplog.text + assert not mock_load_platform.called + + +@asyncio.coroutine +@patch('homeassistant.components.mqtt.discovery.async_load_platform') +def test_only_valid_components(mock_load_platform, hass, mqtt_mock, caplog): + """Test sending in invalid JSON.""" + mock_load_platform.return_value = mock_coro() + async_start(hass, 'homeassistant', {}) + + async_fire_mqtt_message(hass, 'homeassistant/climate/bla/config', '{}') + yield from hass.async_block_till_done() + assert 'Component climate is not supported' in caplog.text + assert not mock_load_platform.called + + +@asyncio.coroutine +def test_correct_config_discovery(hass, mqtt_mock, caplog): + """Test sending in invalid JSON.""" + async_start(hass, 'homeassistant', {}) + + async_fire_mqtt_message(hass, 'homeassistant/binary_sensor/bla/config', + '{ "name": "Beer" }') + yield from hass.async_block_till_done() + + state = hass.states.get('binary_sensor.beer') + + assert state is not None + assert state.name == 'Beer' diff --git a/tests/conftest.py b/tests/conftest.py index 54f5404d72d..d408ed254f2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,12 +1,14 @@ """Setup some common test helper things.""" import functools import logging +from unittest.mock import patch import pytest import requests_mock as _requests_mock -from homeassistant import util +from homeassistant import util, bootstrap from homeassistant.util import location +from homeassistant.components import mqtt from .common import async_test_home_assistant from .test_util.aiohttp import mock_aiohttp_client @@ -58,3 +60,18 @@ def aioclient_mock(): """Fixture to mock aioclient calls.""" with mock_aiohttp_client() as mock_session: yield mock_session + + +@pytest.fixture +def mqtt_mock(loop, hass): + """Fixture to mock MQTT.""" + with patch('homeassistant.components.mqtt.MQTT') as mock_mqtt: + loop.run_until_complete(bootstrap.async_setup_component( + hass, mqtt.DOMAIN, { + mqtt.DOMAIN: { + mqtt.CONF_BROKER: 'mock-broker', + } + })) + client = mock_mqtt() + client.reset_mock() + return client diff --git a/tests/scripts/test_check_config.py b/tests/scripts/test_check_config.py index 1d0bbbd8dfd..23dde3a8244 100644 --- a/tests/scripts/test_check_config.py +++ b/tests/scripts/test_check_config.py @@ -101,7 +101,13 @@ class TestCheckConfig(unittest.TestCase): res = check_config.check(get_test_config_dir('platform.yaml')) change_yaml_files(res) self.assertDictEqual( - {'mqtt': {'keepalive': 60, 'port': 1883, 'protocol': '3.1.1'}, + {'mqtt': { + 'keepalive': 60, + 'port': 1883, + 'protocol': '3.1.1', + 'discovery': False, + 'discovery_prefix': 'homeassistant', + }, 'light': []}, res['components'] ) From 45a7c27280e5349218b498d7b2697c953d46ab6b Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Tue, 7 Feb 2017 20:47:11 +0100 Subject: [PATCH 105/157] Add mysensors device tracker and platform discovery (#5781) * Add mysensors device_tracker platform * Add discovery of device_tracker platforms * Enable discovery of device_tracker platforms that are not DeviceScanner. * Update signature of setup_scanner function in all affected platforms. * Add test. * Use discovery for mysensors device_tracker platform. * Remove gps accuracy * Small change to core like schema * fix depency --- .../components/device_tracker/__init__.py | 12 +++- .../components/device_tracker/automatic.py | 2 +- .../device_tracker/bluetooth_le_tracker.py | 2 +- .../device_tracker/bluetooth_tracker.py | 2 +- .../components/device_tracker/demo.py | 2 +- .../components/device_tracker/gpslogger.py | 2 +- .../components/device_tracker/icloud.py | 2 +- .../components/device_tracker/locative.py | 2 +- .../components/device_tracker/mqtt.py | 2 +- .../components/device_tracker/mysensors.py | 60 +++++++++++++++++++ .../components/device_tracker/owntracks.py | 2 +- .../components/device_tracker/ping.py | 2 +- .../components/device_tracker/trackr.py | 2 +- .../components/device_tracker/volvooncall.py | 2 +- homeassistant/components/mysensors.py | 3 + tests/components/device_tracker/test_init.py | 18 ++++++ tests/components/device_tracker/test_mqtt.py | 2 +- 17 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 homeassistant/components/device_tracker/mysensors.py diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 21e7c7b0da1..bb6730a562f 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -158,10 +158,11 @@ def async_setup(hass: HomeAssistantType, config: ConfigType): None, platform.get_scanner, hass, {DOMAIN: p_config}) elif hasattr(platform, 'async_setup_scanner'): setup = yield from platform.async_setup_scanner( - hass, p_config, tracker.async_see) + hass, p_config, tracker.async_see, disc_info) elif hasattr(platform, 'setup_scanner'): setup = yield from hass.loop.run_in_executor( - None, platform.setup_scanner, hass, p_config, tracker.see) + None, platform.setup_scanner, hass, p_config, tracker.see, + disc_info) else: raise HomeAssistantError("Invalid device_tracker platform.") @@ -193,6 +194,13 @@ def async_setup(hass: HomeAssistantType, config: ConfigType): discovery.async_listen( hass, DISCOVERY_PLATFORMS.keys(), async_device_tracker_discovered) + @asyncio.coroutine + def async_platform_discovered(platform, info): + """Callback to load a platform.""" + yield from async_setup_platform(platform, {}, disc_info=info) + + discovery.async_listen_platform(hass, DOMAIN, async_platform_discovered) + # Clean up stale devices async_track_utc_time_change( hass, tracker.async_update_stale, second=range(0, 60, 5)) diff --git a/homeassistant/components/device_tracker/automatic.py b/homeassistant/components/device_tracker/automatic.py index d47aa818673..3b4612edf6c 100644 --- a/homeassistant/components/device_tracker/automatic.py +++ b/homeassistant/components/device_tracker/automatic.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_scanner(hass, config: dict, see): +def setup_scanner(hass, config: dict, see, discovery_info=None): """Validate the configuration and return an Automatic scanner.""" try: AutomaticDeviceScanner(hass, config, see) diff --git a/homeassistant/components/device_tracker/bluetooth_le_tracker.py b/homeassistant/components/device_tracker/bluetooth_le_tracker.py index 454ab127af0..a4a933fe778 100644 --- a/homeassistant/components/device_tracker/bluetooth_le_tracker.py +++ b/homeassistant/components/device_tracker/bluetooth_le_tracker.py @@ -25,7 +25,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Setup the Bluetooth LE Scanner.""" # pylint: disable=import-error from gattlib import DiscoveryService diff --git a/homeassistant/components/device_tracker/bluetooth_tracker.py b/homeassistant/components/device_tracker/bluetooth_tracker.py index a8b3861cdc5..1de0629c7c5 100644 --- a/homeassistant/components/device_tracker/bluetooth_tracker.py +++ b/homeassistant/components/device_tracker/bluetooth_tracker.py @@ -21,7 +21,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Setup the Bluetooth Scanner.""" # pylint: disable=import-error import bluetooth diff --git a/homeassistant/components/device_tracker/demo.py b/homeassistant/components/device_tracker/demo.py index 08242c2034d..dfd50a2b991 100644 --- a/homeassistant/components/device_tracker/demo.py +++ b/homeassistant/components/device_tracker/demo.py @@ -4,7 +4,7 @@ import random from homeassistant.components.device_tracker import DOMAIN -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Setup the demo tracker.""" def offset(): """Return random offset.""" diff --git a/homeassistant/components/device_tracker/gpslogger.py b/homeassistant/components/device_tracker/gpslogger.py index 22099630bd1..c76c8fdd51b 100644 --- a/homeassistant/components/device_tracker/gpslogger.py +++ b/homeassistant/components/device_tracker/gpslogger.py @@ -19,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['http'] -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Setup an endpoint for the GPSLogger application.""" hass.http.register_view(GPSLoggerView(see)) diff --git a/homeassistant/components/device_tracker/icloud.py b/homeassistant/components/device_tracker/icloud.py index 0878f8b005b..f6396ba7c34 100644 --- a/homeassistant/components/device_tracker/icloud.py +++ b/homeassistant/components/device_tracker/icloud.py @@ -71,7 +71,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_scanner(hass, config: dict, see): +def setup_scanner(hass, config: dict, see, discovery_info=None): """Set up the iCloud Scanner.""" username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) diff --git a/homeassistant/components/device_tracker/locative.py b/homeassistant/components/device_tracker/locative.py index 32eb033a284..75cebbd95e7 100644 --- a/homeassistant/components/device_tracker/locative.py +++ b/homeassistant/components/device_tracker/locative.py @@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['http'] -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Setup an endpoint for the Locative application.""" hass.http.register_view(LocativeView(see)) diff --git a/homeassistant/components/device_tracker/mqtt.py b/homeassistant/components/device_tracker/mqtt.py index f9a85da98b2..a93263fada9 100644 --- a/homeassistant/components/device_tracker/mqtt.py +++ b/homeassistant/components/device_tracker/mqtt.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(mqtt.SCHEMA_BASE).extend({ }) -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Setup the MQTT tracker.""" devices = config[CONF_DEVICES] qos = config[CONF_QOS] diff --git a/homeassistant/components/device_tracker/mysensors.py b/homeassistant/components/device_tracker/mysensors.py new file mode 100644 index 00000000000..2ba19924089 --- /dev/null +++ b/homeassistant/components/device_tracker/mysensors.py @@ -0,0 +1,60 @@ +""" +Support for tracking MySensors devices. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.mysensors/ +""" +import logging + +from homeassistant.components import mysensors +from homeassistant.util import slugify + +DEPENDENCIES = ['mysensors'] + +_LOGGER = logging.getLogger(__name__) + + +def setup_scanner(hass, config, see, discovery_info=None): + """Setup the MySensors tracker.""" + def mysensors_callback(gateway, node_id): + """Callback for mysensors platform.""" + node = gateway.sensors[node_id] + if node.sketch_name is None: + _LOGGER.info('No sketch_name: node %s', node_id) + return + + pres = gateway.const.Presentation + set_req = gateway.const.SetReq + + for child in node.children.values(): + position = child.values.get(set_req.V_POSITION) + if child.type != pres.S_GPS or position is None: + continue + try: + latitude, longitude, _ = position.split(',') + except ValueError: + _LOGGER.error('Payload for V_POSITION %s is not of format ' + 'latitude,longitude,altitude', position) + continue + name = '{} {} {}'.format( + node.sketch_name, node_id, child.id) + attr = { + mysensors.ATTR_CHILD_ID: child.id, + mysensors.ATTR_DESCRIPTION: child.description, + mysensors.ATTR_DEVICE: gateway.device, + mysensors.ATTR_NODE_ID: node_id, + } + see( + dev_id=slugify(name), + host_name=name, + gps=(latitude, longitude), + battery=node.battery_level, + attributes=attr + ) + + gateways = hass.data.get(mysensors.MYSENSORS_GATEWAYS) + + for gateway in gateways: + gateway.platform_callbacks.append(mysensors_callback) + + return True diff --git a/homeassistant/components/device_tracker/owntracks.py b/homeassistant/components/device_tracker/owntracks.py index e2a238a5656..c03041b6317 100644 --- a/homeassistant/components/device_tracker/owntracks.py +++ b/homeassistant/components/device_tracker/owntracks.py @@ -71,7 +71,7 @@ def get_cipher(): return (KEYLEN, decrypt) -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Set up an OwnTracks tracker.""" max_gps_accuracy = config.get(CONF_MAX_GPS_ACCURACY) waypoint_import = config.get(CONF_WAYPOINT_IMPORT) diff --git a/homeassistant/components/device_tracker/ping.py b/homeassistant/components/device_tracker/ping.py index f0f2ac9f49c..2af400ba89c 100644 --- a/homeassistant/components/device_tracker/ping.py +++ b/homeassistant/components/device_tracker/ping.py @@ -73,7 +73,7 @@ class Host: _LOGGER.debug("ping KO on ip=%s failed=%d", self.ip_address, failed) -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Setup the Host objects and return the update function.""" hosts = [Host(ip, dev_id, hass, config) for (dev_id, ip) in config[const.CONF_HOSTS].items()] diff --git a/homeassistant/components/device_tracker/trackr.py b/homeassistant/components/device_tracker/trackr.py index 2eb0def278f..cf66fd33272 100644 --- a/homeassistant/components/device_tracker/trackr.py +++ b/homeassistant/components/device_tracker/trackr.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_scanner(hass, config: dict, see): +def setup_scanner(hass, config: dict, see, discovery_info=None): """Validate the configuration and return a TrackR scanner.""" TrackRDeviceScanner(hass, config, see) return True diff --git a/homeassistant/components/device_tracker/volvooncall.py b/homeassistant/components/device_tracker/volvooncall.py index 1be76d6139c..834ec7e55bd 100644 --- a/homeassistant/components/device_tracker/volvooncall.py +++ b/homeassistant/components/device_tracker/volvooncall.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_scanner(hass, config, see): +def setup_scanner(hass, config, see, discovery_info=None): """Validate the configuration and return a scanner.""" from volvooncall import Connection connection = Connection( diff --git a/homeassistant/components/mysensors.py b/homeassistant/components/mysensors.py index 4b4f1798d7f..d9c8584a5e9 100644 --- a/homeassistant/components/mysensors.py +++ b/homeassistant/components/mysensors.py @@ -234,6 +234,9 @@ def setup(hass, config): 'cover']: discovery.load_platform(hass, component, DOMAIN, {}, config) + discovery.load_platform( + hass, 'device_tracker', DOMAIN, {}, config) + discovery.load_platform( hass, 'notify', DOMAIN, {CONF_NAME: DOMAIN}, config) diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index c083557294b..524eda22634 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -11,6 +11,7 @@ import os from homeassistant.components import zone from homeassistant.core import callback from homeassistant.bootstrap import setup_component +from homeassistant.helpers import discovery from homeassistant.loader import get_component from homeassistant.util.async import run_coroutine_threadsafe import homeassistant.util.dt as dt_util @@ -324,6 +325,23 @@ class TestComponentsDeviceTracker(unittest.TestCase): fire_service_discovered(self.hass, 'test', {}) self.assertTrue(mock_scan.called) + @patch( + 'homeassistant.components.device_tracker.DeviceTracker.see') + @patch( + 'homeassistant.components.device_tracker.demo.setup_scanner', + autospec=True) + def test_discover_platform(self, mock_demo_setup_scanner, mock_see): + """Test discovery of device_tracker demo platform.""" + assert device_tracker.DOMAIN not in self.hass.config.components + discovery.load_platform( + self.hass, device_tracker.DOMAIN, 'demo', {'test_key': 'test_val'}, + {}) + self.hass.block_till_done() + assert device_tracker.DOMAIN in self.hass.config.components + assert mock_demo_setup_scanner.called + assert mock_demo_setup_scanner.call_args[0] == ( + self.hass, {}, mock_see, {'test_key': 'test_val'}) + def test_update_stale(self): """Test stalled update.""" scanner = get_component('device_tracker.test').SCANNER diff --git a/tests/components/device_tracker/test_mqtt.py b/tests/components/device_tracker/test_mqtt.py index 6eb5ba2381c..9405c944552 100644 --- a/tests/components/device_tracker/test_mqtt.py +++ b/tests/components/device_tracker/test_mqtt.py @@ -33,7 +33,7 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase): def test_ensure_device_tracker_platform_validation(self): \ # pylint: disable=invalid-name """Test if platform validation was done.""" - def mock_setup_scanner(hass, config, see): + def mock_setup_scanner(hass, config, see, discovery_info=None): """Check that Qos was added by validation.""" self.assertTrue('qos' in config) From acdda1f42bf4b5c7d570ea31115574776f6f1f03 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 7 Feb 2017 22:54:52 +0100 Subject: [PATCH 106/157] Revert last change on TTS cache load for more speed (#5797) --- homeassistant/components/tts/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index fb99219416f..9d31667cc14 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -302,7 +302,7 @@ class SpeechManager(object): # is file store in file cache elif use_cache and key in self.file_cache: filename = self.file_cache[key] - yield from self.async_file_to_mem(key) + self.hass.async_add_job(self.async_file_to_mem(key)) # load speech from provider into memory else: filename = yield from self.async_get_tts_audio( From 12bc7c73167a33bfd71f3d1935ee751359ae7461 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 7 Feb 2017 22:55:21 +0100 Subject: [PATCH 107/157] Upgrade pyasn1 to 0.2.2 (#5796) --- homeassistant/components/notify/xmpp.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/xmpp.py b/homeassistant/components/notify/xmpp.py index 8befb709ddb..2b72dfc4f8c 100644 --- a/homeassistant/components/notify/xmpp.py +++ b/homeassistant/components/notify/xmpp.py @@ -15,7 +15,7 @@ from homeassistant.const import CONF_PASSWORD, CONF_SENDER, CONF_RECIPIENT REQUIREMENTS = ['sleekxmpp==1.3.1', 'dnspython3==1.15.0', - 'pyasn1==0.2.1', + 'pyasn1==0.2.2', 'pyasn1-modules==0.0.8'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index d8d598dc17f..afa2f0af517 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -415,7 +415,7 @@ pyRFXtrx==0.16.1 pyasn1-modules==0.0.8 # homeassistant.components.notify.xmpp -pyasn1==0.2.1 +pyasn1==0.2.2 # homeassistant.components.media_player.apple_tv pyatv==0.0.1 From 35f6dbc9dc0fb12d1d04837acbf09dabb325f4fe Mon Sep 17 00:00:00 2001 From: Josh Wright Date: Tue, 7 Feb 2017 16:55:49 -0500 Subject: [PATCH 108/157] Update python-nest dependency version (#5795) The nest-cam changes have now been merged into the upstream library, so there is no need to track a specific branch. Updating to 3.1.0 also fixes a structure parsing bug I was experiencing. --- homeassistant/components/nest.py | 5 +---- requirements_all.txt | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/nest.py b/homeassistant/components/nest.py index 13c2ddc7bed..94a0db35f4d 100644 --- a/homeassistant/components/nest.py +++ b/homeassistant/components/nest.py @@ -19,10 +19,7 @@ from homeassistant.loader import get_component _CONFIGURING = {} _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = [ - 'http://github.com/technicalpickles/python-nest' - '/archive/e6c9d56a8df455d4d7746389811f2c1387e8cb33.zip' # nest-cam branch - '#python-nest==3.0.2'] +REQUIREMENTS = ['python-nest==3.1.0'] DOMAIN = 'nest' diff --git a/requirements_all.txt b/requirements_all.txt index afa2f0af517..d6d1b6aa674 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -197,9 +197,6 @@ hikvision==0.4 # homeassistant.components.sensor.dht # http://github.com/adafruit/Adafruit_Python_DHT/archive/310c59b0293354d07d94375f1365f7b9b9110c7d.zip#Adafruit_DHT==1.3.0 -# homeassistant.components.nest -http://github.com/technicalpickles/python-nest/archive/e6c9d56a8df455d4d7746389811f2c1387e8cb33.zip#python-nest==3.0.2 - # homeassistant.components.switch.dlink https://github.com/LinuxChristian/pyW215/archive/v0.3.7.zip#pyW215==0.3.7 @@ -534,6 +531,9 @@ python-mpd2==0.5.5 # homeassistant.components.switch.mystrom python-mystrom==0.3.6 +# homeassistant.components.nest +python-nest==3.1.0 + # homeassistant.components.device_tracker.nmap_tracker python-nmap==0.6.1 From b8a07924240f89d1ad710e7ab8dd85028471b5ce Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Tue, 7 Feb 2017 14:11:51 -0800 Subject: [PATCH 109/157] Bump netdisco to 0.8.2 --- homeassistant/components/discovery.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 32d57b4bf85..5764735bf35 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -14,7 +14,7 @@ import voluptuous as vol from homeassistant.const import EVENT_HOMEASSISTANT_START from homeassistant.helpers.discovery import load_platform, discover -REQUIREMENTS = ['netdisco==0.8.1'] +REQUIREMENTS = ['netdisco==0.8.2'] DOMAIN = 'discovery' diff --git a/requirements_all.txt b/requirements_all.txt index d6d1b6aa674..a9056817036 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -332,7 +332,7 @@ mutagen==1.36.2 myusps==1.0.2 # homeassistant.components.discovery -netdisco==0.8.1 +netdisco==0.8.2 # homeassistant.components.sensor.neurio_energy neurio==0.3.1 From 1b54218d465827de39f6ca28745fc536ede64278 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 8 Feb 2017 06:37:11 +0200 Subject: [PATCH 110/157] Create a file for zwave workarounds. (#5798) * Create a file for zwave workarounds. Add sensor->binary_sensor for fgfs101 (#2) * Don't use default None --- .../components/binary_sensor/zwave.py | 45 ++++--------- homeassistant/components/zwave/__init__.py | 13 +++- homeassistant/components/zwave/workaround.py | 67 +++++++++++++++++++ 3 files changed, 90 insertions(+), 35 deletions(-) create mode 100644 homeassistant/components/zwave/workaround.py diff --git a/homeassistant/components/binary_sensor/zwave.py b/homeassistant/components/binary_sensor/zwave.py index b0054d7b00f..8dd02cc4b43 100644 --- a/homeassistant/components/binary_sensor/zwave.py +++ b/homeassistant/components/binary_sensor/zwave.py @@ -9,6 +9,7 @@ import datetime import homeassistant.util.dt as dt_util from homeassistant.helpers.event import track_point_in_time from homeassistant.components import zwave +from homeassistant.components.zwave import workaround from homeassistant.components.binary_sensor import ( DOMAIN, BinarySensorDevice) @@ -16,22 +17,6 @@ from homeassistant.components.binary_sensor import ( _LOGGER = logging.getLogger(__name__) DEPENDENCIES = [] -PHILIO = 0x013c -PHILIO_SLIM_SENSOR = 0x0002 -PHILIO_SLIM_SENSOR_MOTION = (PHILIO, PHILIO_SLIM_SENSOR, 0) -PHILIO_3_IN_1_SENSOR_GEN_4 = 0x000d -PHILIO_3_IN_1_SENSOR_GEN_4_MOTION = (PHILIO, PHILIO_3_IN_1_SENSOR_GEN_4, 0) -WENZHOU = 0x0118 -WENZHOU_SLIM_SENSOR_MOTION = (WENZHOU, PHILIO_SLIM_SENSOR, 0) - -WORKAROUND_NO_OFF_EVENT = 'trigger_no_off_event' - -DEVICE_MAPPINGS = { - PHILIO_SLIM_SENSOR_MOTION: WORKAROUND_NO_OFF_EVENT, - PHILIO_3_IN_1_SENSOR_GEN_4_MOTION: WORKAROUND_NO_OFF_EVENT, - WENZHOU_SLIM_SENSOR_MOTION: WORKAROUND_NO_OFF_EVENT, -} - def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Z-Wave platform for binary sensors.""" @@ -42,23 +27,19 @@ def setup_platform(hass, config, add_devices, discovery_info=None): value = node.values[discovery_info[zwave.const.ATTR_VALUE_ID]] value.set_change_verified(False) - # Make sure that we have values for the key before converting to int - if (value.node.manufacturer_id.strip() and - value.node.product_id.strip()): - specific_sensor_key = (int(value.node.manufacturer_id, 16), - int(value.node.product_id, 16), - value.index) + device_mapping = workaround.get_device_mapping(value) + if device_mapping == workaround.WORKAROUND_NO_OFF_EVENT: + # Default the multiplier to 4 + re_arm_multiplier = (zwave.get_config_value(value.node, 9) or 4) + add_devices([ + ZWaveTriggerSensor(value, "motion", + hass, re_arm_multiplier * 8) + ]) + return - if specific_sensor_key in DEVICE_MAPPINGS: - if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_NO_OFF_EVENT: - # Default the multiplier to 4 - re_arm_multiplier = (zwave.get_config_value(value.node, - 9) or 4) - add_devices([ - ZWaveTriggerSensor(value, "motion", - hass, re_arm_multiplier * 8) - ]) - return + if workaround.get_device_component_mapping(value) == DOMAIN: + add_devices([ZWaveBinarySensor(value, None)]) + return if value.command_class == zwave.const.COMMAND_CLASS_SENSOR_BINARY: add_devices([ZWaveBinarySensor(value, None)]) diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 5afd74c1503..4268ebcd2bb 100755 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -21,6 +21,7 @@ from homeassistant.util import convert, slugify import homeassistant.config as conf_util import homeassistant.helpers.config_validation as cv from . import const +from . import workaround REQUIREMENTS = ['pydispatcher==2.0.5'] @@ -343,12 +344,18 @@ def setup(hass, config): _LOGGER.debug("Adding Node_id=%s Generic_command_class=%s, " "Specific_command_class=%s, " "Command_class=%s, Value type=%s, " - "Genre=%s", node.node_id, + "Genre=%s as %s", node.node_id, node.generic, node.specific, value.command_class, value.type, - value.genre) - name = "{}.{}".format(component, object_id(value)) + value.genre, component) + workaround_component = workaround.get_device_component_mapping( + value) + if workaround_component != component: + _LOGGER.debug("Using %s instead of %s", + workaround_component, component) + component = workaround_component + name = "{}.{}".format(component, object_id(value)) node_config = customize.get_overrides(hass, DOMAIN, name) if node_config.get(CONF_IGNORED): diff --git a/homeassistant/components/zwave/workaround.py b/homeassistant/components/zwave/workaround.py new file mode 100644 index 00000000000..7712c1868db --- /dev/null +++ b/homeassistant/components/zwave/workaround.py @@ -0,0 +1,67 @@ +"""Zwave workarounds.""" +from . import const + +# Manufacturers +FIBARO = 0x010f +PHILIO = 0x013c +WENZHOU = 0x0118 + +# Product IDs +PHILIO_SLIM_SENSOR = 0x0002 +PHILIO_3_IN_1_SENSOR_GEN_4 = 0x000d + +# Product Types +FGFS101_FLOOD_SENSOR_TYPE = 0x0b00 +PHILIO_SENSOR = 0x0002 + +# Mapping devices +PHILIO_SLIM_SENSOR_MOTION = (PHILIO, PHILIO_SENSOR, PHILIO_SLIM_SENSOR, 0) +PHILIO_3_IN_1_SENSOR_GEN_4_MOTION = ( + PHILIO, PHILIO_SENSOR, PHILIO_3_IN_1_SENSOR_GEN_4, 0) +WENZHOU_SLIM_SENSOR_MOTION = (WENZHOU, PHILIO_SENSOR, PHILIO_SLIM_SENSOR, 0) + +# Workarounds +WORKAROUND_NO_OFF_EVENT = 'trigger_no_off_event' + +# List of workarounds by (manufacturer_id, product_type, product_id, index) +DEVICE_MAPPINGS = { + PHILIO_SLIM_SENSOR_MOTION: WORKAROUND_NO_OFF_EVENT, + PHILIO_3_IN_1_SENSOR_GEN_4_MOTION: WORKAROUND_NO_OFF_EVENT, + WENZHOU_SLIM_SENSOR_MOTION: WORKAROUND_NO_OFF_EVENT, +} + +# Component mapping devices +FIBARO_FGFS101_SENSOR_ALARM = ( + FIBARO, FGFS101_FLOOD_SENSOR_TYPE, const.COMMAND_CLASS_SENSOR_ALARM) + +# List of component workarounds by +# (manufacturer_id, product_type, command_class) +DEVICE_COMPONENT_MAPPING = { + FIBARO_FGFS101_SENSOR_ALARM: 'binary_sensor', +} + + +def get_device_component_mapping(value): + """Get mapping of value to another component.""" + if (value.node.manufacturer_id.strip() and + value.node.product_type.strip()): + manufacturer_id = int(value.node.manufacturer_id, 16) + product_type = int(value.node.product_type, 16) + return DEVICE_COMPONENT_MAPPING.get( + (manufacturer_id, product_type, value.command_class)) + + return None + + +def get_device_mapping(value): + """Get mapping of value to a workaround.""" + if (value.node.manufacturer_id.strip() and + value.node.product_id.strip() and + value.node.product_type.strip()): + manufacturer_id = int(value.node.manufacturer_id, 16) + product_type = int(value.node.product_type, 16) + product_id = int(value.node.product_id, 16) + return DEVICE_MAPPINGS.get( + (manufacturer_id, product_type, product_id, value.index)) + + return None From 4fa4d7347f0117e85a1aa712d3a20c471c244563 Mon Sep 17 00:00:00 2001 From: Jeff Wilson Date: Tue, 7 Feb 2017 23:38:16 -0500 Subject: [PATCH 111/157] Fix climate.set_fan_mode yaml (#5799) --- homeassistant/components/climate/services.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/climate/services.yaml b/homeassistant/components/climate/services.yaml index 899a3dcfe33..4aebb1c85c9 100644 --- a/homeassistant/components/climate/services.yaml +++ b/homeassistant/components/climate/services.yaml @@ -78,7 +78,7 @@ set_fan_mode: description: Name(s) of entities to change example: 'climate.nest' - fan: + fan_mode: description: New value of fan mode example: On Low From ecfe8e0a9a9f104fa5c37f37da37bf20b18b4fb0 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 7 Feb 2017 23:42:45 -0500 Subject: [PATCH 112/157] Formalize supported_features as entity property (#5794) * Formalize supported_features as entity property * Remove extra emulated_hue conditions * Generate log message in executor --- .../components/emulated_hue/hue_api.py | 36 +++++----- homeassistant/components/fan/__init__.py | 2 - homeassistant/components/light/__init__.py | 4 -- .../components/media_player/__init__.py | 72 +++++++++++++------ .../components/media_player/anthemav.py | 4 +- .../components/media_player/apple_tv.py | 4 +- .../components/media_player/aquostv.py | 4 +- .../components/media_player/braviatv.py | 4 +- homeassistant/components/media_player/cast.py | 4 +- homeassistant/components/media_player/cmus.py | 4 +- homeassistant/components/media_player/demo.py | 12 ++-- .../components/media_player/denon.py | 4 +- .../components/media_player/denonavr.py | 4 +- .../components/media_player/directv.py | 4 +- .../components/media_player/dunehd.py | 4 +- homeassistant/components/media_player/emby.py | 4 +- .../components/media_player/firetv.py | 4 +- .../components/media_player/gpmdp.py | 4 +- .../components/media_player/hdmi_cec.py | 4 +- .../components/media_player/itunes.py | 8 +-- homeassistant/components/media_player/kodi.py | 10 +-- .../components/media_player/lg_netcast.py | 4 +- .../components/media_player/liveboxplaytv.py | 4 +- .../components/media_player/mpchc.py | 4 +- homeassistant/components/media_player/mpd.py | 4 +- homeassistant/components/media_player/nad.py | 4 +- .../components/media_player/onkyo.py | 4 +- .../media_player/panasonic_viera.py | 4 +- .../components/media_player/pandora.py | 4 +- .../components/media_player/philips_js.py | 4 +- .../components/media_player/pioneer.py | 4 +- homeassistant/components/media_player/plex.py | 4 +- homeassistant/components/media_player/roku.py | 4 +- .../components/media_player/russound_rnet.py | 4 +- .../components/media_player/samsungtv.py | 4 +- .../components/media_player/snapcast.py | 4 +- .../components/media_player/sonos.py | 6 +- .../components/media_player/soundtouch.py | 4 +- .../components/media_player/squeezebox.py | 4 +- .../components/media_player/universal.py | 10 +-- homeassistant/components/media_player/vlc.py | 4 +- .../components/media_player/webostv.py | 4 +- .../components/media_player/yamaha.py | 10 +-- homeassistant/const.py | 3 + homeassistant/helpers/entity.py | 9 ++- tests/components/emulated_hue/test_hue_api.py | 2 +- tests/components/media_player/test_demo.py | 20 +++--- .../media_player/test_soundtouch.py | 2 +- .../components/media_player/test_universal.py | 20 +++--- 49 files changed, 193 insertions(+), 165 deletions(-) diff --git a/homeassistant/components/emulated_hue/hue_api.py b/homeassistant/components/emulated_hue/hue_api.py index b56be3484fe..7ff174b32b6 100644 --- a/homeassistant/components/emulated_hue/hue_api.py +++ b/homeassistant/components/emulated_hue/hue_api.py @@ -8,14 +8,13 @@ from homeassistant import core from homeassistant.const import ( ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_SET, SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, STATE_ON, STATE_OFF, - HTTP_BAD_REQUEST, HTTP_NOT_FOUND, + HTTP_BAD_REQUEST, HTTP_NOT_FOUND, ATTR_SUPPORTED_FEATURES, ) from homeassistant.components.light import ( - ATTR_BRIGHTNESS, ATTR_SUPPORTED_FEATURES, SUPPORT_BRIGHTNESS + ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS ) from homeassistant.components.media_player import ( - ATTR_MEDIA_VOLUME_LEVEL, ATTR_SUPPORTED_MEDIA_COMMANDS, - SUPPORT_VOLUME_SET, + ATTR_MEDIA_VOLUME_LEVEL, SUPPORT_VOLUME_SET, ) from homeassistant.components.fan import ( ATTR_SPEED, SUPPORT_SET_SPEED, SPEED_OFF, SPEED_LOW, @@ -178,11 +177,10 @@ class HueOneLightChangeView(HomeAssistantView): # Make sure the entity actually supports brightness entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) - if (entity_features & - SUPPORT_BRIGHTNESS & - (entity.domain == "light")) == SUPPORT_BRIGHTNESS: - if brightness is not None: - data[ATTR_BRIGHTNESS] = brightness + if entity.domain == "light": + if entity_features & SUPPORT_BRIGHTNESS: + if brightness is not None: + data[ATTR_BRIGHTNESS] = brightness # If the requested entity is a script add some variables elif entity.domain == "script": @@ -195,9 +193,7 @@ class HueOneLightChangeView(HomeAssistantView): # If the requested entity is a media player, convert to volume elif entity.domain == "media_player": - media_commands = entity.attributes.get( - ATTR_SUPPORTED_MEDIA_COMMANDS, 0) - if media_commands & SUPPORT_VOLUME_SET == SUPPORT_VOLUME_SET: + if entity_features & SUPPORT_VOLUME_SET: if brightness is not None: turn_on_needed = True domain = entity.domain @@ -215,9 +211,7 @@ class HueOneLightChangeView(HomeAssistantView): # If the requested entity is a fan, convert to speed elif entity.domain == "fan": - functions = entity.attributes.get( - ATTR_SUPPORTED_FEATURES, 0) - if (functions & SUPPORT_SET_SPEED) == SUPPORT_SET_SPEED: + if entity_features & SUPPORT_SET_SPEED: if brightness is not None: domain = entity.domain # Convert 0-100 to a fan speed @@ -288,9 +282,10 @@ def parse_hue_api_put_light_body(request_json, entity): # Make sure the entity actually supports brightness entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) - if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS: - report_brightness = True - result = (brightness > 0) + if entity.domain == "light": + if entity_features & SUPPORT_BRIGHTNESS: + report_brightness = True + result = (brightness > 0) elif (entity.domain == "script" or entity.domain == "media_player" or @@ -316,8 +311,9 @@ def get_entity_state(config, entity): # Make sure the entity actually supports brightness entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) - if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS: - pass + if entity.domain == "light": + if entity_features & SUPPORT_BRIGHTNESS: + pass elif entity.domain == "media_player": level = entity.attributes.get( diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index a0079d723d6..dd8dda36121 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -34,7 +34,6 @@ ENTITY_ID_ALL_FANS = group.ENTITY_ID_FORMAT.format(GROUP_NAME_ALL_FANS) ENTITY_ID_FORMAT = DOMAIN + '.{}' # Bitfield of features supported by the fan entity -ATTR_SUPPORTED_FEATURES = 'supported_features' SUPPORT_SET_SPEED = 1 SUPPORT_OSCILLATE = 2 SUPPORT_DIRECTION = 4 @@ -60,7 +59,6 @@ PROP_TO_ATTR = { 'speed': ATTR_SPEED, 'speed_list': ATTR_SPEED_LIST, 'oscillating': ATTR_OSCILLATING, - 'supported_features': ATTR_SUPPORTED_FEATURES, 'direction': ATTR_DIRECTION, } # type: dict diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index efbb9447fcf..5c3e7f4d177 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -35,7 +35,6 @@ ENTITY_ID_ALL_LIGHTS = group.ENTITY_ID_FORMAT.format('all_lights') ENTITY_ID_FORMAT = DOMAIN + ".{}" # Bitfield of features supported by the light entity -ATTR_SUPPORTED_FEATURES = 'supported_features' SUPPORT_BRIGHTNESS = 1 SUPPORT_COLOR_TEMP = 2 SUPPORT_EFFECT = 4 @@ -85,7 +84,6 @@ PROP_TO_ATTR = { 'white_value': ATTR_WHITE_VALUE, 'effect_list': ATTR_EFFECT_LIST, 'effect': ATTR_EFFECT, - 'supported_features': ATTR_SUPPORTED_FEATURES, } # Service call validation schemas @@ -364,8 +362,6 @@ class Light(ToggleEntity): data[ATTR_RGB_COLOR] = color_util.color_xy_brightness_to_RGB( data[ATTR_XY_COLOR][0], data[ATTR_XY_COLOR][1], data[ATTR_BRIGHTNESS]) - else: - data[ATTR_SUPPORTED_FEATURES] = self.supported_features return data diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 71901b6256a..a1077b1f132 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -77,7 +77,6 @@ ATTR_MEDIA_CHANNEL = 'media_channel' ATTR_MEDIA_PLAYLIST = 'media_playlist' ATTR_APP_ID = 'app_id' ATTR_APP_NAME = 'app_name' -ATTR_SUPPORTED_MEDIA_COMMANDS = 'supported_media_commands' ATTR_INPUT_SOURCE = 'source' ATTR_INPUT_SOURCE_LIST = 'source_list' ATTR_MEDIA_ENQUEUE = 'enqueue' @@ -183,7 +182,6 @@ ATTR_TO_PROPERTY = [ ATTR_MEDIA_PLAYLIST, ATTR_APP_ID, ATTR_APP_NAME, - ATTR_SUPPORTED_MEDIA_COMMANDS, ATTR_INPUT_SOURCE, ATTR_INPUT_SOURCE_LIST, ] @@ -523,7 +521,39 @@ class MediaPlayerDevice(Entity): @property def supported_media_commands(self): - """Flag media commands that are supported.""" + """Flag media commands that are supported. + + DEPRECATED: Included for temporary custom platform compatibility. + """ + return None + + @property + def supported_features(self): + """Flag media player features that are supported.""" + # Begin temporary transition logic + + if self.supported_media_commands is not None: + # If this platform is still using supported_media_commands, issue + # a logger warning once with instructions on how to fix it. + if not getattr(self, '_supported_features_warned', False): + def show_warning(): + """Show a deprecation warning in the log for this class.""" + import inspect + _LOGGER.warning( + "supported_media_commands is deprecated. Please " + "rename supported_media_commands to " + "supported_features in '%s' to ensure future support.", + inspect.getfile(self.__class__)) + # This is a temporary attribute. We don't want to pollute + # __init__ so it can be easily removed. + # pylint: disable=attribute-defined-outside-init + self._supported_features_warned = True + self.hass.add_job(show_warning) + + # Return the old property + return self.supported_media_commands + + # End temporary transition logic return 0 def turn_on(self): @@ -686,57 +716,57 @@ class MediaPlayerDevice(Entity): @property def support_play(self): """Boolean if play is supported.""" - return bool(self.supported_media_commands & SUPPORT_PLAY) + return bool(self.supported_features & SUPPORT_PLAY) @property def support_pause(self): """Boolean if pause is supported.""" - return bool(self.supported_media_commands & SUPPORT_PAUSE) + return bool(self.supported_features & SUPPORT_PAUSE) @property def support_stop(self): """Boolean if stop is supported.""" - return bool(self.supported_media_commands & SUPPORT_STOP) + return bool(self.supported_features & SUPPORT_STOP) @property def support_seek(self): """Boolean if seek is supported.""" - return bool(self.supported_media_commands & SUPPORT_SEEK) + return bool(self.supported_features & SUPPORT_SEEK) @property def support_volume_set(self): """Boolean if setting volume is supported.""" - return bool(self.supported_media_commands & SUPPORT_VOLUME_SET) + return bool(self.supported_features & SUPPORT_VOLUME_SET) @property def support_volume_mute(self): """Boolean if muting volume is supported.""" - return bool(self.supported_media_commands & SUPPORT_VOLUME_MUTE) + return bool(self.supported_features & SUPPORT_VOLUME_MUTE) @property def support_previous_track(self): """Boolean if previous track command supported.""" - return bool(self.supported_media_commands & SUPPORT_PREVIOUS_TRACK) + return bool(self.supported_features & SUPPORT_PREVIOUS_TRACK) @property def support_next_track(self): """Boolean if next track command supported.""" - return bool(self.supported_media_commands & SUPPORT_NEXT_TRACK) + return bool(self.supported_features & SUPPORT_NEXT_TRACK) @property def support_play_media(self): """Boolean if play media command supported.""" - return bool(self.supported_media_commands & SUPPORT_PLAY_MEDIA) + return bool(self.supported_features & SUPPORT_PLAY_MEDIA) @property def support_select_source(self): """Boolean if select source command supported.""" - return bool(self.supported_media_commands & SUPPORT_SELECT_SOURCE) + return bool(self.supported_features & SUPPORT_SELECT_SOURCE) @property def support_clear_playlist(self): """Boolean if clear playlist command supported.""" - return bool(self.supported_media_commands & SUPPORT_CLEAR_PLAYLIST) + return bool(self.supported_features & SUPPORT_CLEAR_PLAYLIST) def toggle(self): """Toggle the power on the media player.""" @@ -821,14 +851,12 @@ class MediaPlayerDevice(Entity): def state_attributes(self): """Return the state attributes.""" if self.state == STATE_OFF: - state_attr = { - ATTR_SUPPORTED_MEDIA_COMMANDS: self.supported_media_commands, - } - else: - state_attr = { - attr: getattr(self, attr) for attr - in ATTR_TO_PROPERTY if getattr(self, attr) is not None - } + return None + + state_attr = { + attr: getattr(self, attr) for attr + in ATTR_TO_PROPERTY if getattr(self, attr) is not None + } return state_attr diff --git a/homeassistant/components/media_player/anthemav.py b/homeassistant/components/media_player/anthemav.py index f53f5cf9264..01b4b32deb2 100644 --- a/homeassistant/components/media_player/anthemav.py +++ b/homeassistant/components/media_player/anthemav.py @@ -79,8 +79,8 @@ class AnthemAVR(MediaPlayerDevice): return getattr(self.avr.protocol, propname, dval) @property - def supported_media_commands(self): - """Return flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_ANTHEMAV @property diff --git a/homeassistant/components/media_player/apple_tv.py b/homeassistant/components/media_player/apple_tv.py index 0eec30a3f70..acfdac088aa 100644 --- a/homeassistant/components/media_player/apple_tv.py +++ b/homeassistant/components/media_player/apple_tv.py @@ -184,8 +184,8 @@ class AppleTvDevice(MediaPlayerDevice): return title if title else "No title" @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self._playing is not None: if self.state != STATE_IDLE: return SUPPORT_PAUSE | SUPPORT_PLAY | \ diff --git a/homeassistant/components/media_player/aquostv.py b/homeassistant/components/media_player/aquostv.py index 0654e393780..65d3e2c93fd 100644 --- a/homeassistant/components/media_player/aquostv.py +++ b/homeassistant/components/media_player/aquostv.py @@ -191,8 +191,8 @@ class SharpAquosTVDevice(MediaPlayerDevice): return self._muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_SHARPTV @_retry diff --git a/homeassistant/components/media_player/braviatv.py b/homeassistant/components/media_player/braviatv.py index 20eb4fc7cca..d6e7261ec4f 100644 --- a/homeassistant/components/media_player/braviatv.py +++ b/homeassistant/components/media_player/braviatv.py @@ -316,8 +316,8 @@ class BraviaTVDevice(MediaPlayerDevice): return self._muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_BRAVIA @property diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 7998dafc1e1..b7e7504b2f8 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -226,8 +226,8 @@ class CastDevice(MediaPlayerDevice): return self.cast.app_display_name @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_CAST @property diff --git a/homeassistant/components/media_player/cmus.py b/homeassistant/components/media_player/cmus.py index ac6885e3450..de946b3e349 100644 --- a/homeassistant/components/media_player/cmus.py +++ b/homeassistant/components/media_player/cmus.py @@ -151,8 +151,8 @@ class CmusDevice(MediaPlayerDevice): return int(volume)/100 @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_CMUS def turn_off(self): diff --git a/homeassistant/components/media_player/demo.py b/homeassistant/components/media_player/demo.py index 4e9867b49e9..aab75f702d4 100644 --- a/homeassistant/components/media_player/demo.py +++ b/homeassistant/components/media_player/demo.py @@ -155,8 +155,8 @@ class DemoYoutubePlayer(AbstractDemoPlayer): return "YouTube" @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return YOUTUBE_PLAYER_SUPPORT @property @@ -269,8 +269,8 @@ class DemoMusicPlayer(AbstractDemoPlayer): return self._cur_track + 1 @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" support = MUSIC_PLAYER_SUPPORT if self._cur_track > 0: @@ -364,8 +364,8 @@ class DemoTVShowPlayer(AbstractDemoPlayer): return self._source @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" support = NETFLIX_PLAYER_SUPPORT if self._cur_episode > 1: diff --git a/homeassistant/components/media_player/denon.py b/homeassistant/components/media_player/denon.py index 22ccd2f0d56..4b3347a832a 100755 --- a/homeassistant/components/media_player/denon.py +++ b/homeassistant/components/media_player/denon.py @@ -193,8 +193,8 @@ class DenonDevice(MediaPlayerDevice): return self._mediainfo @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self._mediasource in MEDIA_MODES.values(): return SUPPORT_DENON | SUPPORT_MEDIA_MODES else: diff --git a/homeassistant/components/media_player/denonavr.py b/homeassistant/components/media_player/denonavr.py index e6f0bf99d42..eba2d031158 100644 --- a/homeassistant/components/media_player/denonavr.py +++ b/homeassistant/components/media_player/denonavr.py @@ -167,8 +167,8 @@ class DenonDevice(MediaPlayerDevice): return self._source_list @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self._current_source in self._receiver.netaudio_func_list: return SUPPORT_DENON | SUPPORT_MEDIA_MODES else: diff --git a/homeassistant/components/media_player/directv.py b/homeassistant/components/media_player/directv.py index e63301db4d9..035fe6d9cd6 100644 --- a/homeassistant/components/media_player/directv.py +++ b/homeassistant/components/media_player/directv.py @@ -133,8 +133,8 @@ class DirecTvDevice(MediaPlayerDevice): return None @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_DTV @property diff --git a/homeassistant/components/media_player/dunehd.py b/homeassistant/components/media_player/dunehd.py index 9deab4bcdff..1facb523da6 100644 --- a/homeassistant/components/media_player/dunehd.py +++ b/homeassistant/components/media_player/dunehd.py @@ -97,8 +97,8 @@ class DuneHDPlayerEntity(MediaPlayerDevice): return list(self._sources.keys()) @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return DUNEHD_PLAYER_SUPPORT def volume_up(self): diff --git a/homeassistant/components/media_player/emby.py b/homeassistant/components/media_player/emby.py index 4aac93c42d9..3ff3a40e5cc 100644 --- a/homeassistant/components/media_player/emby.py +++ b/homeassistant/components/media_player/emby.py @@ -309,8 +309,8 @@ class EmbyClient(MediaPlayerDevice): return self.now_playing_item['IndexNumber'] @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self.supports_remote_control: return SUPPORT_EMBY else: diff --git a/homeassistant/components/media_player/firetv.py b/homeassistant/components/media_player/firetv.py index 1b0a9b02b63..237faddaaea 100644 --- a/homeassistant/components/media_player/firetv.py +++ b/homeassistant/components/media_player/firetv.py @@ -122,8 +122,8 @@ class FireTVDevice(MediaPlayerDevice): return True @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_FIRETV @property diff --git a/homeassistant/components/media_player/gpmdp.py b/homeassistant/components/media_player/gpmdp.py index 1678547bee7..c3283aca382 100644 --- a/homeassistant/components/media_player/gpmdp.py +++ b/homeassistant/components/media_player/gpmdp.py @@ -295,8 +295,8 @@ class GPMDP(MediaPlayerDevice): return self._name @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_GPMDP def media_next_track(self): diff --git a/homeassistant/components/media_player/hdmi_cec.py b/homeassistant/components/media_player/hdmi_cec.py index c7e9be562cc..aa3b44e9e90 100644 --- a/homeassistant/components/media_player/hdmi_cec.py +++ b/homeassistant/components/media_player/hdmi_cec.py @@ -158,8 +158,8 @@ class CecPlayerDevice(CecDevice, MediaPlayerDevice): self.schedule_update_ha_state() @property - def supported_media_commands(self): - """Flag media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" from pycec.const import TYPE_RECORDER, TYPE_PLAYBACK, TYPE_TUNER, \ TYPE_AUDIO if self.type_id == TYPE_RECORDER or self.type == TYPE_PLAYBACK: diff --git a/homeassistant/components/media_player/itunes.py b/homeassistant/components/media_player/itunes.py index c208990cb67..5d53518256e 100644 --- a/homeassistant/components/media_player/itunes.py +++ b/homeassistant/components/media_player/itunes.py @@ -306,8 +306,8 @@ class ItunesDevice(MediaPlayerDevice): return self.current_playlist @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_ITUNES def set_volume_level(self, volume): @@ -425,8 +425,8 @@ class AirPlayDevice(MediaPlayerDevice): return MEDIA_TYPE_MUSIC @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_AIRPLAY def set_volume_level(self, volume): diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index acb6a6f45db..75a54c6fac2 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -228,14 +228,14 @@ class KodiDevice(MediaPlayerDevice): self._item.get('label', self._item.get('file', 'unknown'))) @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" - supported_media_commands = SUPPORT_KODI + def supported_features(self): + """Flag media player features that are supported.""" + supported_features = SUPPORT_KODI if self._turn_off_action in TURN_OFF_ACTION: - supported_media_commands |= SUPPORT_TURN_OFF + supported_features |= SUPPORT_TURN_OFF - return supported_media_commands + return supported_features @asyncio.coroutine def async_turn_off(self): diff --git a/homeassistant/components/media_player/lg_netcast.py b/homeassistant/components/media_player/lg_netcast.py index ab6cfa701ca..00e405c17b2 100644 --- a/homeassistant/components/media_player/lg_netcast.py +++ b/homeassistant/components/media_player/lg_netcast.py @@ -163,8 +163,8 @@ class LgTVDevice(MediaPlayerDevice): return self._program_name @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_LGTV @property diff --git a/homeassistant/components/media_player/liveboxplaytv.py b/homeassistant/components/media_player/liveboxplaytv.py index 7386f51df4c..b36d52a161c 100644 --- a/homeassistant/components/media_player/liveboxplaytv.py +++ b/homeassistant/components/media_player/liveboxplaytv.py @@ -133,8 +133,8 @@ class LiveboxPlayTvDevice(MediaPlayerDevice): self._current_program) @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_LIVEBOXPLAYTV def refresh_channel_list(self): diff --git a/homeassistant/components/media_player/mpchc.py b/homeassistant/components/media_player/mpchc.py index e51d91aa95c..168497c4052 100644 --- a/homeassistant/components/media_player/mpchc.py +++ b/homeassistant/components/media_player/mpchc.py @@ -126,8 +126,8 @@ class MpcHcDevice(MediaPlayerDevice): int(duration[2]) @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_MPCHC def volume_up(self): diff --git a/homeassistant/components/media_player/mpd.py b/homeassistant/components/media_player/mpd.py index 2f16410e783..48d22dab021 100644 --- a/homeassistant/components/media_player/mpd.py +++ b/homeassistant/components/media_player/mpd.py @@ -184,8 +184,8 @@ class MpdDevice(MediaPlayerDevice): return int(self.status['volume'])/100 @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_MPD @property diff --git a/homeassistant/components/media_player/nad.py b/homeassistant/components/media_player/nad.py index 27122fcfc93..332aed4a839 100644 --- a/homeassistant/components/media_player/nad.py +++ b/homeassistant/components/media_player/nad.py @@ -136,8 +136,8 @@ class NAD(MediaPlayerDevice): return self._mute @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_NAD def turn_off(self): diff --git a/homeassistant/components/media_player/onkyo.py b/homeassistant/components/media_player/onkyo.py index 3db9413490f..017581f8186 100644 --- a/homeassistant/components/media_player/onkyo.py +++ b/homeassistant/components/media_player/onkyo.py @@ -150,8 +150,8 @@ class OnkyoDevice(MediaPlayerDevice): return self._muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_ONKYO @property diff --git a/homeassistant/components/media_player/panasonic_viera.py b/homeassistant/components/media_player/panasonic_viera.py index 09f4845effe..30672069558 100644 --- a/homeassistant/components/media_player/panasonic_viera.py +++ b/homeassistant/components/media_player/panasonic_viera.py @@ -123,8 +123,8 @@ class PanasonicVieraTVDevice(MediaPlayerDevice): return self._muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self._mac: return SUPPORT_VIERATV | SUPPORT_TURN_ON return SUPPORT_VIERATV diff --git a/homeassistant/components/media_player/pandora.py b/homeassistant/components/media_player/pandora.py index 0d554093be2..f742618822a 100644 --- a/homeassistant/components/media_player/pandora.py +++ b/homeassistant/components/media_player/pandora.py @@ -158,8 +158,8 @@ class PandoraMediaPlayer(MediaPlayerDevice): self.schedule_update_ha_state() @property - def supported_media_commands(self): - """Show what this supports.""" + def supported_features(self): + """Flag media player features that are supported.""" return PANDORA_SUPPORT @property diff --git a/homeassistant/components/media_player/philips_js.py b/homeassistant/components/media_player/philips_js.py index 22f257f31dc..a4d3b02381a 100644 --- a/homeassistant/components/media_player/philips_js.py +++ b/homeassistant/components/media_player/philips_js.py @@ -86,8 +86,8 @@ class PhilipsTV(MediaPlayerDevice): return True @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self._watching_tv: return SUPPORT_PHILIPS_JS_TV else: diff --git a/homeassistant/components/media_player/pioneer.py b/homeassistant/components/media_player/pioneer.py index dec8bd12bb2..73f0d18f597 100644 --- a/homeassistant/components/media_player/pioneer.py +++ b/homeassistant/components/media_player/pioneer.py @@ -176,8 +176,8 @@ class PioneerDevice(MediaPlayerDevice): return self._muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_PIONEER @property diff --git a/homeassistant/components/media_player/plex.py b/homeassistant/components/media_player/plex.py index 409a480443a..27e61a7863b 100644 --- a/homeassistant/components/media_player/plex.py +++ b/homeassistant/components/media_player/plex.py @@ -334,8 +334,8 @@ class PlexClient(MediaPlayerDevice): return self._convert_na_to_none(self.session.index) @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_PLEX def set_volume_level(self, volume): diff --git a/homeassistant/components/media_player/roku.py b/homeassistant/components/media_player/roku.py index af54e285bdc..08a3eec17e8 100644 --- a/homeassistant/components/media_player/roku.py +++ b/homeassistant/components/media_player/roku.py @@ -142,8 +142,8 @@ class RokuDevice(MediaPlayerDevice): return STATE_UNKNOWN @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_ROKU @property diff --git a/homeassistant/components/media_player/russound_rnet.py b/homeassistant/components/media_player/russound_rnet.py index b8f79c45cec..64042f4633d 100644 --- a/homeassistant/components/media_player/russound_rnet.py +++ b/homeassistant/components/media_player/russound_rnet.py @@ -95,8 +95,8 @@ class RussoundRNETDevice(MediaPlayerDevice): return self._state @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_RUSSOUND @property diff --git a/homeassistant/components/media_player/samsungtv.py b/homeassistant/components/media_player/samsungtv.py index d2d3d2e25a6..794fefffecc 100644 --- a/homeassistant/components/media_player/samsungtv.py +++ b/homeassistant/components/media_player/samsungtv.py @@ -156,8 +156,8 @@ class SamsungTVDevice(MediaPlayerDevice): return self._muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_SAMSUNGTV def turn_off(self): diff --git a/homeassistant/components/media_player/snapcast.py b/homeassistant/components/media_player/snapcast.py index 98dad3486a2..3e06cca38a5 100644 --- a/homeassistant/components/media_player/snapcast.py +++ b/homeassistant/components/media_player/snapcast.py @@ -72,8 +72,8 @@ class SnapcastDevice(MediaPlayerDevice): return self._client.muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_SNAPCAST @property diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 7be9a878c06..e052cfcaea3 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -761,10 +761,10 @@ class SonosDevice(MediaPlayerDevice): return self._media_title @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self._coordinator: - return self._coordinator.supported_media_commands + return self._coordinator.supported_features supported = SUPPORT_SONOS diff --git a/homeassistant/components/media_player/soundtouch.py b/homeassistant/components/media_player/soundtouch.py index 22191a0ee17..90a870a8c65 100644 --- a/homeassistant/components/media_player/soundtouch.py +++ b/homeassistant/components/media_player/soundtouch.py @@ -287,8 +287,8 @@ class SoundTouchDevice(MediaPlayerDevice): return self._volume.muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_SOUNDTOUCH def turn_off(self): diff --git a/homeassistant/components/media_player/squeezebox.py b/homeassistant/components/media_player/squeezebox.py index 65a543781aa..efab17a61a9 100644 --- a/homeassistant/components/media_player/squeezebox.py +++ b/homeassistant/components/media_player/squeezebox.py @@ -302,8 +302,8 @@ class SqueezeBoxDevice(MediaPlayerDevice): return self._status['album'] @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_SQUEEZEBOX def async_turn_off(self): diff --git a/homeassistant/components/media_player/universal.py b/homeassistant/components/media_player/universal.py index f1bd61fd007..3eccafba20c 100644 --- a/homeassistant/components/media_player/universal.py +++ b/homeassistant/components/media_player/universal.py @@ -17,7 +17,7 @@ from homeassistant.components.media_player import ( ATTR_MEDIA_PLAYLIST, ATTR_MEDIA_SEASON, ATTR_MEDIA_SEEK_POSITION, ATTR_MEDIA_SERIES_TITLE, ATTR_MEDIA_TITLE, ATTR_MEDIA_TRACK, ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_MUTED, ATTR_INPUT_SOURCE_LIST, - ATTR_SUPPORTED_MEDIA_COMMANDS, ATTR_MEDIA_POSITION, + ATTR_MEDIA_POSITION, ATTR_MEDIA_POSITION_UPDATED_AT, DOMAIN, SERVICE_PLAY_MEDIA, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP, SUPPORT_SELECT_SOURCE, SUPPORT_CLEAR_PLAYLIST, @@ -29,7 +29,7 @@ from homeassistant.const import ( SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_MUTE, SERVICE_VOLUME_SET, SERVICE_VOLUME_UP, STATE_IDLE, STATE_OFF, STATE_ON, - SERVICE_MEDIA_STOP) + SERVICE_MEDIA_STOP, ATTR_SUPPORTED_FEATURES) from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.service import async_call_from_config @@ -357,9 +357,9 @@ class UniversalMediaPlayer(MediaPlayerDevice): return self._override_or_child_attr(ATTR_INPUT_SOURCE_LIST) @property - def supported_media_commands(self): - """Flag media commands that are supported.""" - flags = self._child_attr(ATTR_SUPPORTED_MEDIA_COMMANDS) or 0 + def supported_features(self): + """Flag media player features that are supported.""" + flags = self._child_attr(ATTR_SUPPORTED_FEATURES) or 0 if SERVICE_TURN_ON in self._cmds: flags |= SUPPORT_TURN_ON diff --git a/homeassistant/components/media_player/vlc.py b/homeassistant/components/media_player/vlc.py index c961811f168..9439e6da5ad 100644 --- a/homeassistant/components/media_player/vlc.py +++ b/homeassistant/components/media_player/vlc.py @@ -97,8 +97,8 @@ class VlcDevice(MediaPlayerDevice): return self._muted @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" return SUPPORT_VLC @property diff --git a/homeassistant/components/media_player/webostv.py b/homeassistant/components/media_player/webostv.py index cb0b992926d..da498dc3d5b 100644 --- a/homeassistant/components/media_player/webostv.py +++ b/homeassistant/components/media_player/webostv.py @@ -244,8 +244,8 @@ class LgWebOSDevice(MediaPlayerDevice): return None @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" + def supported_features(self): + """Flag media player features that are supported.""" if self._mac: return SUPPORT_WEBOSTV | SUPPORT_TURN_ON return SUPPORT_WEBOSTV diff --git a/homeassistant/components/media_player/yamaha.py b/homeassistant/components/media_player/yamaha.py index 84778cef2d5..928d15b5950 100644 --- a/homeassistant/components/media_player/yamaha.py +++ b/homeassistant/components/media_player/yamaha.py @@ -181,9 +181,9 @@ class YamahaDevice(MediaPlayerDevice): return self._source_list @property - def supported_media_commands(self): - """Flag of media commands that are supported.""" - supported_commands = SUPPORT_YAMAHA + def supported_features(self): + """Flag media player features that are supported.""" + supported_features = SUPPORT_YAMAHA supports = self._playback_support mapping = {'play': (SUPPORT_PLAY | SUPPORT_PLAY_MEDIA), @@ -193,8 +193,8 @@ class YamahaDevice(MediaPlayerDevice): 'skip_r': SUPPORT_PREVIOUS_TRACK} for attr, feature in mapping.items(): if getattr(supports, attr, False): - supported_commands |= feature - return supported_commands + supported_features |= feature + return supported_features def turn_off(self): """Turn off media player.""" diff --git a/homeassistant/const.py b/homeassistant/const.py index 9769649f008..ac5aeec581f 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -286,6 +286,9 @@ ATTR_STATE = 'state' ATTR_OPTION = 'option' +# Bitfield of supported component features for the entity +ATTR_SUPPORTED_FEATURES = 'supported_features' + # #### SERVICES #### SERVICE_HOMEASSISTANT_STOP = 'stop' SERVICE_HOMEASSISTANT_RESTART = 'restart' diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index ac124b3abf3..854d1bc169d 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -10,7 +10,7 @@ from homeassistant.const import ( ATTR_ASSUMED_STATE, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, DEVICE_DEFAULT_NAME, STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT, - ATTR_ENTITY_PICTURE) + ATTR_ENTITY_PICTURE, ATTR_SUPPORTED_FEATURES) from homeassistant.core import HomeAssistant, DOMAIN as CORE_DOMAIN from homeassistant.exceptions import NoEntitySpecifiedError from homeassistant.util import ensure_unique_string, slugify @@ -148,6 +148,11 @@ class Entity(object): """ return False + @property + def supported_features(self) -> int: + """Flag supported features.""" + return None + def update(self): """Retrieve latest state. @@ -231,6 +236,8 @@ class Entity(object): self._attr_setter('entity_picture', str, ATTR_ENTITY_PICTURE, attr) self._attr_setter('hidden', bool, ATTR_HIDDEN, attr) self._attr_setter('assumed_state', bool, ATTR_ASSUMED_STATE, attr) + self._attr_setter('supported_features', int, ATTR_SUPPORTED_FEATURES, + attr) end = timer() diff --git a/tests/components/emulated_hue/test_hue_api.py b/tests/components/emulated_hue/test_hue_api.py index c3888bd9cf7..fdd9bc90946 100644 --- a/tests/components/emulated_hue/test_hue_api.py +++ b/tests/components/emulated_hue/test_hue_api.py @@ -301,7 +301,7 @@ def test_put_light_state_fan(hass_hue, hue_client): blocking=True) # Emulated hue converts 0-100% to 0-255. - level = 23 + level = 43 brightness = round(level * 255 / 100) fan_result = yield from perform_put_light_state( diff --git a/tests/components/media_player/test_demo.py b/tests/components/media_player/test_demo.py index d6079ee0351..1e53245d8a5 100644 --- a/tests/components/media_player/test_demo.py +++ b/tests/components/media_player/test_demo.py @@ -155,28 +155,28 @@ class TestDemoMediaPlayer(unittest.TestCase): state = self.hass.states.get(entity_id) assert 1 == state.attributes.get('media_track') assert 0 == (mp.SUPPORT_PREVIOUS_TRACK & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) mp.media_next_track(self.hass, entity_id) self.hass.block_till_done() state = self.hass.states.get(entity_id) assert 2 == state.attributes.get('media_track') assert 0 < (mp.SUPPORT_PREVIOUS_TRACK & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) mp.media_next_track(self.hass, entity_id) self.hass.block_till_done() state = self.hass.states.get(entity_id) assert 3 == state.attributes.get('media_track') assert 0 < (mp.SUPPORT_PREVIOUS_TRACK & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) mp.media_previous_track(self.hass, entity_id) self.hass.block_till_done() state = self.hass.states.get(entity_id) assert 2 == state.attributes.get('media_track') assert 0 < (mp.SUPPORT_PREVIOUS_TRACK & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) assert setup_component( self.hass, mp.DOMAIN, @@ -185,21 +185,21 @@ class TestDemoMediaPlayer(unittest.TestCase): state = self.hass.states.get(ent_id) assert 1 == state.attributes.get('media_episode') assert 0 == (mp.SUPPORT_PREVIOUS_TRACK & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) mp.media_next_track(self.hass, ent_id) self.hass.block_till_done() state = self.hass.states.get(ent_id) assert 2 == state.attributes.get('media_episode') assert 0 < (mp.SUPPORT_PREVIOUS_TRACK & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) mp.media_previous_track(self.hass, ent_id) self.hass.block_till_done() state = self.hass.states.get(ent_id) assert 1 == state.attributes.get('media_episode') assert 0 == (mp.SUPPORT_PREVIOUS_TRACK & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) @patch('homeassistant.components.media_player.demo.DemoYoutubePlayer.' 'media_seek', autospec=True) @@ -211,21 +211,21 @@ class TestDemoMediaPlayer(unittest.TestCase): ent_id = 'media_player.living_room' state = self.hass.states.get(ent_id) assert 0 < (mp.SUPPORT_PLAY_MEDIA & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) assert state.attributes.get('media_content_id') is not None mp.play_media(self.hass, None, 'some_id', ent_id) self.hass.block_till_done() state = self.hass.states.get(ent_id) assert 0 < (mp.SUPPORT_PLAY_MEDIA & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) assert not 'some_id' == state.attributes.get('media_content_id') mp.play_media(self.hass, 'youtube', 'some_id', ent_id) self.hass.block_till_done() state = self.hass.states.get(ent_id) assert 0 < (mp.SUPPORT_PLAY_MEDIA & - state.attributes.get('supported_media_commands')) + state.attributes.get('supported_features')) assert 'some_id' == state.attributes.get('media_content_id') assert not mock_seek.called diff --git a/tests/components/media_player/test_soundtouch.py b/tests/components/media_player/test_soundtouch.py index 69d80e30f59..84551241694 100644 --- a/tests/components/media_player/test_soundtouch.py +++ b/tests/components/media_player/test_soundtouch.py @@ -318,7 +318,7 @@ class TestSoundtouchMediaPlayer(unittest.TestCase): default_component(), mock.MagicMock()) self.assertEqual(mocked_sountouch_device.call_count, 1) - self.assertEqual(soundtouch.DEVICES[0].supported_media_commands, 17853) + self.assertEqual(soundtouch.DEVICES[0].supported_features, 17853) @mock.patch('libsoundtouch.device.SoundTouchDevice.power_off') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume') diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index 76fca3fb6ed..1ca0846b1fd 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -27,7 +27,7 @@ class MockMediaPlayer(media_player.MediaPlayerDevice): self._volume_level = 0 self._is_volume_muted = False self._media_title = None - self._supported_media_commands = 0 + self._supported_features = 0 self._source = None self._tracks = 12 self._media_image_url = None @@ -91,9 +91,9 @@ class MockMediaPlayer(media_player.MediaPlayerDevice): return self._is_volume_muted @property - def supported_media_commands(self): - """Supported media commands flag.""" - return self._supported_media_commands + def supported_features(self): + """Flag media player features that are supported.""" + return self._supported_features @property def media_image_url(self): @@ -502,7 +502,7 @@ class TestMediaPlayer(unittest.TestCase): self.hass.states.set(self.mock_mute_switch_id, STATE_ON) self.assertTrue(ump.is_volume_muted) - def test_supported_media_commands_children_only(self): + def test_supported_features_children_only(self): """Test supported media commands with only children.""" config = self.config_children_only universal.validate_config(config) @@ -511,15 +511,15 @@ class TestMediaPlayer(unittest.TestCase): ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() - self.assertEqual(0, ump.supported_media_commands) + self.assertEqual(0, ump.supported_features) - self.mock_mp_1._supported_media_commands = 512 + self.mock_mp_1._supported_features = 512 self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result() - self.assertEqual(512, ump.supported_media_commands) + self.assertEqual(512, ump.supported_features) - def test_supported_media_commands_children_and_cmds(self): + def test_supported_features_children_and_cmds(self): """Test supported media commands with children and attrs.""" config = self.config_children_and_attr universal.validate_config(config) @@ -543,7 +543,7 @@ class TestMediaPlayer(unittest.TestCase): | universal.SUPPORT_VOLUME_STEP | universal.SUPPORT_VOLUME_MUTE \ | universal.SUPPORT_SELECT_SOURCE - self.assertEqual(check_flags, ump.supported_media_commands) + self.assertEqual(check_flags, ump.supported_features) def test_service_call_no_active_child(self): """Test a service call to children with no active child.""" From bdebe5d53cf15361de16294d1de5bb1f2d8784fb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 7 Feb 2017 21:30:24 -0800 Subject: [PATCH 113/157] Update frontend (#5800) --- homeassistant/components/frontend/version.py | 4 ++-- .../frontend/www_static/frontend.html | 22 +++++++++--------- .../frontend/www_static/frontend.html.gz | Bin 137597 -> 137578 bytes .../www_static/home-assistant-polymer | 2 +- .../www_static/panels/ha-panel-dev-state.html | 2 +- .../panels/ha-panel-dev-state.html.gz | Bin 2904 -> 2941 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2336 -> 2336 bytes 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 011929dfff9..0394bc0b674 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,13 +2,13 @@ FINGERPRINTS = { "core.js": "adfeb513cf650acf763e284d76a48d6b", - "frontend.html": "b4cbcaea0e190d802b23328f89c2df61", + "frontend.html": "eb9d6679ac0d1b79067949a827aed992", "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", "panels/ha-panel-dev-info.html": "0469024d94d6270a8680df2be44ba916", "panels/ha-panel-dev-service.html": "9f749635e518a4ca7991975bdefdb10a", - "panels/ha-panel-dev-state.html": "041f5b660f7a1fa748e47fc46c0bdb3c", + "panels/ha-panel-dev-state.html": "7d069ba8fd5379fa8f59858b8c0a7473", "panels/ha-panel-dev-template.html": "97f77b69faef8c5975c09431912831cc", "panels/ha-panel-history.html": "8955c1d093a2c417c89ed90dd627c7d3", "panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 8346cf2bfa0..ae60e2c736d 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -473,43 +473,43 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th /* eslint-disable no-bitwise */ addGetter('supportsPause', function () { - return (this.stateObj.attributes.supported_media_commands & 1) !== 0; + return (this.stateObj.attributes.supported_features & 1) !== 0; }); addGetter('supportsVolumeSet', function () { - return (this.stateObj.attributes.supported_media_commands & 4) !== 0; + return (this.stateObj.attributes.supported_features & 4) !== 0; }); addGetter('supportsVolumeMute', function () { - return (this.stateObj.attributes.supported_media_commands & 8) !== 0; + return (this.stateObj.attributes.supported_features & 8) !== 0; }); addGetter('supportsPreviousTrack', function () { - return (this.stateObj.attributes.supported_media_commands & 16) !== 0; + return (this.stateObj.attributes.supported_features & 16) !== 0; }); addGetter('supportsNextTrack', function () { - return (this.stateObj.attributes.supported_media_commands & 32) !== 0; + return (this.stateObj.attributes.supported_features & 32) !== 0; }); addGetter('supportsTurnOn', function () { - return (this.stateObj.attributes.supported_media_commands & 128) !== 0; + return (this.stateObj.attributes.supported_features & 128) !== 0; }); addGetter('supportsTurnOff', function () { - return (this.stateObj.attributes.supported_media_commands & 256) !== 0; + return (this.stateObj.attributes.supported_features & 256) !== 0; }); addGetter('supportsPlayMedia', function () { - return (this.stateObj.attributes.supported_media_commands & 512) !== 0; + return (this.stateObj.attributes.supported_features & 512) !== 0; }); addGetter('supportsVolumeButtons', function () { - return (this.stateObj.attributes.supported_media_commands & 1024) !== 0; + return (this.stateObj.attributes.supported_features & 1024) !== 0; }); addGetter('supportsPlay', function () { - return (this.stateObj.attributes.supported_media_commands & 16384) !== 0; + return (this.stateObj.attributes.supported_features & 16384) !== 0; }); /* eslint-enable no-bitwise */ @@ -600,4 +600,4 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th this.hass.callService('media_player', service, serviceData); }, }); -}()); \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 26084735b403a470418f3bc1e8c52b51ef852b1d..605f35e77f0297ce44b5553345e1061ba58f99c3 100644 GIT binary patch delta 28803 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 Kl?I?KjR*k!4#?C1 delta 28822 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

9|CzvzxA%EF9tvZrX}rC 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index da62d1bf181..bdd3157087a 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit da62d1bf181819de2f91d88992137780d1d7caa3 +Subproject commit bdd3157087a8eb4a64a6a10cd2c8b626c499297b diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html index d271289788f..52ea7fff18e 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html @@ -1 +1 @@ -

\ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz index 17d4f3d76ae04d09d412fcc9b7c99dbb07536042..0b8a61e04263470ff0810db9bd2ad997fdf5b281 100644 GIT binary patch delta 2940 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 delta 2903 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 Brh)(f diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index bee0772d9af..195785eba46 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","9a2c46641b0e22fe74cd4f7bf0df6675"],["/frontend/panels/dev-event-5c82300b3cf543a92cf4297506e450e7.html","1bb68c3df5c14307a2550a0cca39b435"],["/frontend/panels/dev-info-0469024d94d6270a8680df2be44ba916.html","35995794b5a909d517be812ad4f46ea8"],["/frontend/panels/dev-service-9f749635e518a4ca7991975bdefdb10a.html","1bc71eb7620c7b7198fd4b7976d6bc13"],["/frontend/panels/dev-state-041f5b660f7a1fa748e47fc46c0bdb3c.html","f00c0e74a916e44d61c680e23f5aa34d"],["/frontend/panels/dev-template-97f77b69faef8c5975c09431912831cc.html","5a4848a193ba4aed4359bb3e0e05bac6"],["/frontend/panels/map-9c8c7924ba8f731560c9f4093835cc26.html","8ae4874622d23d995ddf2a8b0ffa8d80"],["/static/core-adfeb513cf650acf763e284d76a48d6b.js","f5fdf5f1f754e801f9f54ad31a3cc922"],["/static/frontend-b4cbcaea0e190d802b23328f89c2df61.html","ab6fe3c525a29d8e96c359441a36613e"],["/static/mdi-7a0f14bbf3822449f9060b9c53bd7376.html","8d60ec43a3f8a77b21c312783ae5b892"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","89313f9f2126ddea722150f8154aca03"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.toString().match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a))return e.add(new Request(a,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);var n="index.html";!t&&n&&(a=addDirectoryIndex(a,n),t=urlsToCacheKeys.has(a));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,n;for(a=0;aNgPj`){Z@Xj6b-J2agMhHbtr=w41HH|GgKaq?J}HJDJYd77Y^jaqi<>z}s{% z>TFvo>&?ujR<>;FQ3v+9c`Vct^qaQodB7P_CI@%o7y6llh^31cj<}sy4pHA{n$0N7yh_G zA#M5Je(lox2}BF+$h)w&K`0x2bNSC#&wq_v=F|(cVhGxmXh-W7l*=5{V9Le(-8*mU zgp;BgrV%nsNCXD1FPE#U?Qi5@ru=Kp1vNp|xBpD}hqIsgT zI47dW3ZhLcAxWg*G~20RDd%a<6PXH5xK3#O6S2S5+VUlZ-aVc~C{$U+g3Cpp{eDKd0A&wwzXlqV`@3Gjk)9y6H}d0vl&)w*)3cy97sW~c;Ap;Gil z5uPy0X)J|0@k|HSttZtD35=~ztOs0pqvEjhcH8bVK`yq|2$sYJ)l^Ze7tL59 zvLr@RI3tizAr7TogH+9G-PG89yGd1AB=)i%%AnwkGR%Dp61H#-i{@wD$+yQ$VM#GzzzdYUr#<#(RH}@WT zBZ44QN9LB@3-smf5<^)b%AoJzQySk5DzF_(g2C8FWOfXk4fdGK_M=_btl*)MPHcVa zr-RT<3+rF{VCti2{;^1*v;mR%?qM4%8blq=FV;t-g7fp|_M5rqhEP*hsQIA}ZGiXD}^-k6BjHcbopQY%QJqAOWd^o5RFT`QFd)@4k ztLxEthT4wDs}lnpbaw6x317%#ZnT3j6i3O_;@x=nnmN^?~uB zdVd=PvtAz7T|bvUbxBntre2A2ERLgIcxV|!*P^s$ix} zkREPBcm`m1vbn;*9V0x%es_vG>+rgD@c#bfwbwVhc8F*+9GbQuV(pymRsP)`bm42<6wK`WeiVkp>RW0( z$3j7x8m6?_BRuQXj&kNFMCLm-3C{@|q^UU)SuaG5$6k$7#KI-Wv5!a+m zeE)|>{y_a-@ND_THHqrW_OSBdx@kW_i{$@hCF;^RS?-jG*Gm}n zD)nfvsDqJR3Ol+M-3WePW1#R=*^MyqJ9I4ah74A{1rPKnH|I5#tHQSSzkl3pDqa8k zdpmMy!<`P(;CcJI&KtQ7Hdt^u`tJGn$7my8ZZ8G)%Y8wduZZ=gTRzY@X2T5w1`qjT zdw0>f(hCp!#RFs7vbp~C;G)Dwk}PfIi2M}h)7zTg0I#4;hhck33nlK>gxGBC9mJ(3<2l((G8HQnhyMvi&ogbPLWkwuzoaPVwv~rLdl1u3*iPnfTjoe4B}jivY8_#wkGH6yOwMGeDKd zN@~+#?-|v*jIX19%@1a{V`qk|wYR$i^O`&+Ke)ck0$4~)C{iUMJ8t6ty$e#3B};PdrZY*zfW$t&eS8a8s}={X zZVI8TiCR@c7j-pgQNK~oK+I8oY|7R~=X-;C)l>uYzT!=5JD#3nWp6g@eXxM#@fWM6 zymf9*Z>{ip@E$d-&}Um)s#+JS5MciE{0b}m49b#&_-do8o$sn>@a?LdZ&$xVx9?ng z{evq(1O0DTj%U_f4YT{}wB+iWC7$E0dt{6EFu-xwp z)bm=NTW{aI|6sXu1c^<1ZqWTl|7?G^p4F8mEJq*6S?k<_<+5BmI{wnumE}HNk&veN zZ?|@C{ff|FGqBF|t>f}q-kksQ{hQaG$((9NR`fx;f@ZL6P?*di4XT(;FD|UH(ZqURnwUz$4jWNY{wF>MrdL_ibWQLzRyFU;wXeX z5Go4tH1-pWVjt5E1=7PfPcjio6$=)HehNVx```-!Va}uQ0X;>f>X9EMxgSI_k7N?0 zK4eKo1_m6Xh(pejjhZmd^Ek~T9z*WuGG-~qj0HeGMF~Q7T1|`1RUvSct2D}!Fvgf= z5D7^0oRL3VqLQ5XaOaRn8S*p9fMHC0AVCg>(RJamPS>csx;+Et^idgV)91# zc@(mo1zE_%R#gm97G=QlkV6D0DJ(hXA^PaYl)}kzRn%5SxyVGC2Na7;r6G$GU*szC z^DqlzA%bmqGQcQHqa+Aq5K0P_q##1ZeWf6incr(L02N{^>IO$374n!-dL@)ELZwNF zK^Dn0A!7+??@MbyiWOy+Vk(Uz%zUPD%0`eOgHVV(2=?S|92oIPZ~+KDvfL-_0T043 z$W)e#fU=)$tOlMa3`HEo5acq$JQ0LU6p{2KVIl5GU&vyVg0EP_xeBu&h@xEOe&X|7 z#37eynBKu56CVYYO{g-U5Cu$xEJ(8uFy>j_o4v7`jBdwG&1+qc-*rEuU+YqOS}PJI z!yp$T;~^Dusu-huiK8F@07<2tgg+DYvY5^FT2{(q#j{K?sxOgIxl#^dKnWiPLBN9O zXR=E-@{AxNgCM1x^2tMvxz89|x4mO> zJo<2T`$r8MZ_Ojr_bIXy7xIy((O3lH7syywb!E!DU7ay(a1WpTP&5=;H)45=@{n8!HU<4nuyr49JiQN zRHHPByoH7&YND`LKs-p)Grbu9zS4`&<4YH${EZ0N(C5vIO5(Ta-Hc&)*^m=V4Gn&L z_mcQ((vKZPPsFz1EkVyKlJ2#{glLbLGaTA?%V$&VxZvsfeMfn=bL)x*sqJ-R(!cO# zPn!#F)oT=o8VA*ID0U>##AHala(?`mEOF1M4by;8c;9%OQ#!UPwM(o7u7~p|4gRc%bz*4^A3Z)Og`__iRIF; z+-w~4a&5!;}D zQSBJ-ipyKanRN1~?z*}BrAexaFtrMrV`&_<++EAiyM{u4taMS@od>N)^Asu7xMG(3wpfD2*rh>NNBp+=9 z<2(G%%47hz-w8TNUKdcd=T=Mhk7!(;6*M~2i>?oyTdFS0`r0C>x<3bJpB)bg$o6Zo z{6rY_>0vgwCjd4ln=1<3KEi$MH>aqRE>HfCNSrwS!BPC-A#lxUa0lT2ltbVA5uij_ z7*?WRC>B3~syi_4<3v_ie}DeL>Y82CN7U;NO=}RTc24#x`)&`p@DMjS6Ft2jg+8&m zmRe1zP>81bDQ)tI&U%%hoaq6P*@jKrQ^I;_VoF5T2@%7gRnZhNGYPWqBay^#c)$bp zh4s5_KY3*L)c=FdmOo6BD1WREE1$3H<|{Tt{y!E_70Spmr$j0r=dXXEsbLS2jyJbW zN8D>VyG`VzN3J%9;s#qHGx@2|^FN=bJ@4F?Kf{h05BE_{;5Hj4dfwF6gXc|CQwDvQ ze5tUQ`wK7)vHog z|9-3o25r34p=vsB|I%6m)4_TR&IiA|dAyG{@#XqbV7uHE#OaDyuG;yL#xdz{7$|te zAM3k|)|8&R+b@ocY4iH}_0C0!O(a?9(h&I}%!ju%-EE6S*^b2(N^5;7WA0(r_crFo zT*lnpzc>%o`|h0$^$Bw!a_H*mJ0+{zV+=v#_}&eWDC-vOgXJEzBa0?HYdDX->$7~P z7q8n|m%2}>fv&;1rZ&;B$RVEHq~ul;$`z_Pe*%BojBgV-J98+jE1Cj;rU0XmngOXK zRuZe0de5NRWPIgyYqm3?9UC)Dt$pfLZ$3MGWB<8u5PtjNcrXz3br*+QXYxN{l4F0T G6aWB_5`o?T From 490ef6afad92cc8ade7872b26fb9d33fd2bc25ee Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Wed, 8 Feb 2017 07:47:41 +0200 Subject: [PATCH 114/157] WIP: [component/recorder] Refactoring & better handling of SQLAlchemy Sessions (#5607) * Refactor recorder and Sessions * Cover #4352 * NO_reset_on_return * contextmanager * coverage --- homeassistant/components/history.py | 2 +- homeassistant/components/recorder/__init__.py | 229 +++++++++--------- tests/components/recorder/test_init.py | 143 +++++++---- 3 files changed, 221 insertions(+), 153 deletions(-) diff --git a/homeassistant/components/history.py b/homeassistant/components/history.py index 6875eaabcdd..69ed528f661 100644 --- a/homeassistant/components/history.py +++ b/homeassistant/components/history.py @@ -64,7 +64,7 @@ def get_significant_states(start_time, end_time=None, entity_id=None, """ entity_ids = (entity_id.lower(), ) if entity_id is not None else None states = recorder.get_model('States') - query = recorder.query('States').filter( + query = recorder.query(states).filter( (states.domain.in_(SIGNIFICANT_DOMAINS) | (states.last_changed == states.last_updated)) & (states.last_updated > start_time)) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 9040d1f9fde..6577d4af91d 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -13,6 +13,7 @@ import threading import time from datetime import timedelta, datetime from typing import Any, Union, Optional, List, Dict +from contextlib import contextmanager import voluptuous as vol @@ -22,7 +23,7 @@ from homeassistant.const import ( CONF_INCLUDE, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL) import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.event import track_point_in_utc_time +from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.typing import ConfigType, QueryType import homeassistant.util.dt as dt_util @@ -39,6 +40,7 @@ CONF_PURGE_DAYS = 'purge_days' RETRIES = 3 CONNECT_RETRY_WAIT = 10 QUERY_RETRY_WAIT = 0.1 +ERROR_QUERY = "Error during query: %s" CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -62,28 +64,43 @@ _INSTANCE = None # type: Any _LOGGER = logging.getLogger(__name__) # These classes will be populated during setup() -# pylint: disable=invalid-name,no-member -Session = None # pylint: disable=no-member +# scoped_session, in the same thread session_scope() stays the same +_SESSION = None + + +@contextmanager +def session_scope(): + """Provide a transactional scope around a series of operations.""" + session = _SESSION() + try: + yield session + session.commit() + except Exception as err: # pylint: disable=broad-except + _LOGGER.error(ERROR_QUERY, err) + session.rollback() + raise + finally: + session.close() # pylint: disable=invalid-sequence-index -def execute(q: QueryType) -> List[Any]: +def execute(qry: QueryType) -> List[Any]: """Query the database and convert the objects to HA native form. This method also retries a few times in the case of stale connections. """ import sqlalchemy.exc - try: + with session_scope() as session: for _ in range(0, RETRIES): try: return [ row for row in - (row.to_native() for row in q) + (row.to_native() for row in qry) if row is not None] - except sqlalchemy.exc.SQLAlchemyError as e: - log_error(e, retry_wait=QUERY_RETRY_WAIT, rollback=True) - finally: - Session.close() + except sqlalchemy.exc.SQLAlchemyError as err: + _LOGGER.error(ERROR_QUERY, err) + session.rollback() + time.sleep(QUERY_RETRY_WAIT) return [] @@ -101,9 +118,10 @@ def run_information(point_in_time: Optional[datetime]=None): start=_INSTANCE.recording_start, closed_incorrect=False) - return query('RecorderRuns').filter( - (recorder_runs.start < point_in_time) & - (recorder_runs.end > point_in_time)).first() + with session_scope(): + return query('RecorderRuns').filter( + (recorder_runs.start < point_in_time) & + (recorder_runs.end > point_in_time)).first() def setup(hass: HomeAssistant, config: ConfigType) -> bool: @@ -132,10 +150,9 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: def query(model_name: Union[str, Any], *args) -> QueryType: """Helper to return a query handle.""" _verify_instance() - if isinstance(model_name, str): - return Session.query(get_model(model_name), *args) - return Session.query(model_name, *args) + return _SESSION().query(get_model(model_name), *args) + return _SESSION().query(model_name, *args) def get_model(model_name: str) -> Any: @@ -148,22 +165,6 @@ def get_model(model_name: str) -> Any: return None -def log_error(e: Exception, retry_wait: Optional[float]=0, - rollback: Optional[bool]=True, - message: Optional[str]="Error during query: %s") -> None: - """Log about SQLAlchemy errors in a sane manner.""" - import sqlalchemy.exc - if not isinstance(e, sqlalchemy.exc.OperationalError): - _LOGGER.exception(str(e)) - else: - _LOGGER.error(message, str(e)) - if rollback: - Session.rollback() - if retry_wait: - _LOGGER.info("Retrying in %s seconds", retry_wait) - time.sleep(retry_wait) - - class Recorder(threading.Thread): """A threaded recorder class.""" @@ -204,18 +205,14 @@ class Recorder(threading.Thread): self._setup_connection() self._setup_run() break - except sqlalchemy.exc.SQLAlchemyError as e: - log_error(e, retry_wait=CONNECT_RETRY_WAIT, rollback=False, - message="Error during connection setup: %s") + except sqlalchemy.exc.SQLAlchemyError as err: + _LOGGER.error("Error during connection setup: %s (retrying " + "in %s seconds)", err, CONNECT_RETRY_WAIT) + time.sleep(CONNECT_RETRY_WAIT) if self.purge_days is not None: - def purge_ticker(event): - """Rerun purge every second day.""" - self._purge_old_data() - track_point_in_utc_time(self.hass, purge_ticker, - dt_util.utcnow() + timedelta(days=2)) - track_point_in_utc_time(self.hass, purge_ticker, - dt_util.utcnow() + timedelta(minutes=5)) + async_track_time_interval( + self.hass, self._purge_old_data, timedelta(days=2)) while True: event = self.queue.get() @@ -250,16 +247,17 @@ class Recorder(threading.Thread): self.queue.task_done() continue - dbevent = Events.from_event(event) - self._commit(dbevent) + with session_scope() as session: + dbevent = Events.from_event(event) + self._commit(session, dbevent) - if event.event_type != EVENT_STATE_CHANGED: - self.queue.task_done() - continue + if event.event_type != EVENT_STATE_CHANGED: + self.queue.task_done() + continue - dbstate = States.from_event(event) - dbstate.event_id = dbevent.event_id - self._commit(dbstate) + dbstate = States.from_event(event) + dbstate.event_id = dbevent.event_id + self._commit(session, dbstate) self.queue.task_done() @@ -282,11 +280,14 @@ class Recorder(threading.Thread): def block_till_db_ready(self): """Block until the database session is ready.""" - self.db_ready.wait() + self.db_ready.wait(10) + while not self.db_ready.is_set(): + _LOGGER.warning('Database not ready, waiting another 10 seconds.') + self.db_ready.wait(10) def _setup_connection(self): """Ensure database is ready to fly.""" - global Session # pylint: disable=global-statement + global _SESSION # pylint: disable=invalid-name,global-statement import homeassistant.components.recorder.models as models from sqlalchemy import create_engine @@ -298,40 +299,44 @@ class Recorder(threading.Thread): self.engine = create_engine( 'sqlite://', connect_args={'check_same_thread': False}, - poolclass=StaticPool) + poolclass=StaticPool, + pool_reset_on_return=None) else: self.engine = create_engine(self.db_url, echo=False) models.Base.metadata.create_all(self.engine) session_factory = sessionmaker(bind=self.engine) - Session = scoped_session(session_factory) + _SESSION = scoped_session(session_factory) self._migrate_schema() self.db_ready.set() def _migrate_schema(self): """Check if the schema needs to be upgraded.""" - import homeassistant.components.recorder.models as models - schema_changes = models.SchemaChanges - current_version = getattr(Session.query(schema_changes).order_by( - schema_changes.change_id.desc()).first(), 'schema_version', None) + from homeassistant.components.recorder.models import SCHEMA_VERSION + schema_changes = get_model('SchemaChanges') + with session_scope() as session: + res = session.query(schema_changes).order_by( + schema_changes.change_id.desc()).first() + current_version = getattr(res, 'schema_version', None) - if current_version == models.SCHEMA_VERSION: - return - _LOGGER.debug("Schema version incorrect: %d", current_version) + if current_version == SCHEMA_VERSION: + return + _LOGGER.debug("Schema version incorrect: %s", current_version) - if current_version is None: - current_version = self._inspect_schema_version() - _LOGGER.debug("No schema version found. Inspected version: %d", - current_version) + if current_version is None: + current_version = self._inspect_schema_version() + _LOGGER.debug("No schema version found. Inspected version: %s", + current_version) - for version in range(current_version, models.SCHEMA_VERSION): - new_version = version + 1 - _LOGGER.info( - "Upgrading recorder db schema to version %d", new_version) - self._apply_update(new_version) - self._commit(schema_changes(schema_version=new_version)) - _LOGGER.info( - "Upgraded recorder db schema to version %d", new_version) + for version in range(current_version, SCHEMA_VERSION): + new_version = version + 1 + _LOGGER.info("Upgrading recorder db schema to version %s", + new_version) + self._apply_update(new_version) + self._commit(session, + schema_changes(schema_version=new_version)) + _LOGGER.info("Upgraded recorder db schema to version %s", + new_version) def _apply_update(self, new_version): """Perform operations to bring schema up to date.""" @@ -368,51 +373,54 @@ class Recorder(threading.Thread): import homeassistant.components.recorder.models as models inspector = reflection.Inspector.from_engine(self.engine) indexes = inspector.get_indexes("events") - for index in indexes: - if index['column_names'] == ["time_fired"]: - # Schema addition from version 1 detected. This is a new db. - current_version = models.SchemaChanges( - schema_version=models.SCHEMA_VERSION) - self._commit(current_version) - return models.SCHEMA_VERSION + with session_scope() as session: + for index in indexes: + if index['column_names'] == ["time_fired"]: + # Schema addition from version 1 detected. New DB. + current_version = models.SchemaChanges( + schema_version=models.SCHEMA_VERSION) + self._commit(session, current_version) + return models.SCHEMA_VERSION - # Version 1 schema changes not found, this db needs to be migrated. - current_version = models.SchemaChanges(schema_version=0) - self._commit(current_version) - return current_version.schema_version + # Version 1 schema changes not found, this db needs to be migrated. + current_version = models.SchemaChanges(schema_version=0) + self._commit(session, current_version) + return current_version.schema_version def _close_connection(self): """Close the connection.""" - global Session # pylint: disable=global-statement + global _SESSION # pylint: disable=invalid-name,global-statement self.engine.dispose() self.engine = None - Session = None + _SESSION = None def _setup_run(self): """Log the start of the current run.""" recorder_runs = get_model('RecorderRuns') - for run in query('RecorderRuns').filter_by(end=None): - run.closed_incorrect = True - run.end = self.recording_start - _LOGGER.warning("Ended unfinished session (id=%s from %s)", - run.run_id, run.start) - Session.add(run) + with session_scope() as session: + for run in query('RecorderRuns').filter_by(end=None): + run.closed_incorrect = True + run.end = self.recording_start + _LOGGER.warning("Ended unfinished session (id=%s from %s)", + run.run_id, run.start) + session.add(run) - _LOGGER.warning("Found unfinished sessions") + _LOGGER.warning("Found unfinished sessions") - self._run = recorder_runs( - start=self.recording_start, - created=dt_util.utcnow() - ) - self._commit(self._run) + self._run = recorder_runs( + start=self.recording_start, + created=dt_util.utcnow() + ) + self._commit(session, self._run) def _close_run(self): """Save end time for current run.""" self._run.end = dt_util.utcnow() - self._commit(self._run) + with session_scope() as session: + self._commit(session, self._run) self._run = None - def _purge_old_data(self): + def _purge_old_data(self, _=None): """Purge events and states older than purge_days ago.""" from homeassistant.components.recorder.models import Events, States @@ -429,8 +437,9 @@ class Recorder(threading.Thread): .delete(synchronize_session=False) _LOGGER.debug("Deleted %s states", deleted_rows) - if self._commit(_purge_states): - _LOGGER.info("Purged states created before %s", purge_before) + with session_scope() as session: + if self._commit(session, _purge_states): + _LOGGER.info("Purged states created before %s", purge_before) def _purge_events(session): deleted_rows = session.query(Events) \ @@ -438,10 +447,9 @@ class Recorder(threading.Thread): .delete(synchronize_session=False) _LOGGER.debug("Deleted %s events", deleted_rows) - if self._commit(_purge_events): - _LOGGER.info("Purged events created before %s", purge_before) - - Session.expire_all() + with session_scope() as session: + if self._commit(session, _purge_events): + _LOGGER.info("Purged events created before %s", purge_before) # Execute sqlite vacuum command to free up space on disk if self.engine.driver == 'sqlite': @@ -449,10 +457,9 @@ class Recorder(threading.Thread): self.engine.execute("VACUUM") @staticmethod - def _commit(work): + def _commit(session, work): """Commit & retry work: Either a model or in a function.""" import sqlalchemy.exc - session = Session() for _ in range(0, RETRIES): try: if callable(work): @@ -461,8 +468,10 @@ class Recorder(threading.Thread): session.add(work) session.commit() return True - except sqlalchemy.exc.OperationalError as e: - log_error(e, retry_wait=QUERY_RETRY_WAIT, rollback=True) + except sqlalchemy.exc.OperationalError as err: + _LOGGER.error(ERROR_QUERY, err) + session.rollback() + time.sleep(QUERY_RETRY_WAIT) return False diff --git a/tests/components/recorder/test_init.py b/tests/components/recorder/test_init.py index f729303c685..ce395044d11 100644 --- a/tests/components/recorder/test_init.py +++ b/tests/components/recorder/test_init.py @@ -3,7 +3,7 @@ import json from datetime import datetime, timedelta import unittest -from unittest.mock import patch, call +from unittest.mock import patch, call, MagicMock import pytest from homeassistant.core import callback @@ -24,7 +24,6 @@ class TestRecorder(unittest.TestCase): recorder.DOMAIN: {recorder.CONF_DB_URL: db_uri}}) self.hass.start() recorder._verify_instance() - self.session = recorder.Session() recorder._INSTANCE.block_till_done() def tearDown(self): # pylint: disable=invalid-name @@ -42,26 +41,25 @@ class TestRecorder(unittest.TestCase): self.hass.block_till_done() recorder._INSTANCE.block_till_done() - for event_id in range(5): - if event_id < 3: - timestamp = five_days_ago - state = 'purgeme' - else: - timestamp = now - state = 'dontpurgeme' + with recorder.session_scope() as session: + for event_id in range(5): + if event_id < 3: + timestamp = five_days_ago + state = 'purgeme' + else: + timestamp = now + state = 'dontpurgeme' - self.session.add(recorder.get_model('States')( - entity_id='test.recorder2', - domain='sensor', - state=state, - attributes=json.dumps(attributes), - last_changed=timestamp, - last_updated=timestamp, - created=timestamp, - event_id=event_id + 1000 - )) - - self.session.commit() + session.add(recorder.get_model('States')( + entity_id='test.recorder2', + domain='sensor', + state=state, + attributes=json.dumps(attributes), + last_changed=timestamp, + last_updated=timestamp, + created=timestamp, + event_id=event_id + 1000 + )) def _add_test_events(self): """Add a few events for testing.""" @@ -71,21 +69,23 @@ class TestRecorder(unittest.TestCase): self.hass.block_till_done() recorder._INSTANCE.block_till_done() - for event_id in range(5): - if event_id < 2: - timestamp = five_days_ago - event_type = 'EVENT_TEST_PURGE' - else: - timestamp = now - event_type = 'EVENT_TEST' - self.session.add(recorder.get_model('Events')( - event_type=event_type, - event_data=json.dumps(event_data), - origin='LOCAL', - created=timestamp, - time_fired=timestamp, - )) + with recorder.session_scope() as session: + for event_id in range(5): + if event_id < 2: + timestamp = five_days_ago + event_type = 'EVENT_TEST_PURGE' + else: + timestamp = now + event_type = 'EVENT_TEST' + + session.add(recorder.get_model('Events')( + event_type=event_type, + event_data=json.dumps(event_data), + origin='LOCAL', + created=timestamp, + time_fired=timestamp, + )) def test_saving_state(self): """Test saving and restoring a state.""" @@ -205,14 +205,15 @@ class TestRecorder(unittest.TestCase): with self.assertRaises(ValueError): recorder._INSTANCE._apply_update(-1) - def test_schema_update_calls(self): + def test_schema_update_calls(self): # pylint: disable=no-self-use """Test that schema migrations occurr in correct order.""" test_version = recorder.models.SchemaChanges(schema_version=0) - self.session.add(test_version) - with patch.object(recorder._INSTANCE, '_apply_update') as update: - recorder._INSTANCE._migrate_schema() - update.assert_has_calls([call(version+1) for version in range( - 0, recorder.models.SCHEMA_VERSION)]) + with recorder.session_scope() as session: + session.add(test_version) + with patch.object(recorder._INSTANCE, '_apply_update') as update: + recorder._INSTANCE._migrate_schema() + update.assert_has_calls([call(version+1) for version in range( + 0, recorder.models.SCHEMA_VERSION)]) @pytest.fixture @@ -220,7 +221,7 @@ def hass_recorder(): """HASS fixture with in-memory recorder.""" hass = get_test_home_assistant() - def setup_recorder(config): + def setup_recorder(config={}): """Setup with params.""" db_uri = 'sqlite://' # In memory DB conf = {recorder.CONF_DB_URL: db_uri} @@ -301,3 +302,61 @@ def test_saving_state_include_domain_exclude_entity(hass_recorder): assert len(states) == 1 assert hass.states.get('test.ok') == states[0] assert hass.states.get('test.ok').state == 'state2' + + +def test_recorder_errors_exceptions(hass_recorder): \ + # pylint: disable=redefined-outer-name + """Test session_scope and get_model errors.""" + # Model cannot be resolved + assert recorder.get_model('dont-exist') is None + + # Verify the instance fails before setup + with pytest.raises(RuntimeError): + recorder._verify_instance() + + # Setup the recorder + hass_recorder() + + recorder._verify_instance() + + # Verify session scope raises (and prints) an exception + with patch('homeassistant.components.recorder._LOGGER.error') as e_mock, \ + pytest.raises(Exception) as err: + with recorder.session_scope() as session: + session.execute('select * from notthere') + assert e_mock.call_count == 1 + assert recorder.ERROR_QUERY[:-4] in e_mock.call_args[0][0] + assert 'no such table' in str(err.value) + + +def test_recorder_bad_commit(hass_recorder): + """Bad _commit should retry 3 times.""" + hass_recorder() + + def work(session): + """Bad work.""" + session.execute('select * from notthere') + + with patch('homeassistant.components.recorder.time.sleep') as e_mock, \ + recorder.session_scope() as session: + res = recorder._INSTANCE._commit(session, work) + assert res is False + assert e_mock.call_count == 3 + + +def test_recorder_bad_execute(hass_recorder): + """Bad execute, retry 3 times.""" + hass_recorder() + + def to_native(): + """Rasie exception.""" + from sqlalchemy.exc import SQLAlchemyError + raise SQLAlchemyError() + + mck1 = MagicMock() + mck1.to_native = to_native + + with patch('homeassistant.components.recorder.time.sleep') as e_mock: + res = recorder.execute((mck1,)) + assert res == [] + assert e_mock.call_count == 3 From 0e6dd39c150b481249090a0a6f45a60c7e90c216 Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Wed, 8 Feb 2017 06:49:36 +0100 Subject: [PATCH 115/157] Add support for fluxled discovery. (#5784) * Add support for fluxled discovery. * Make use of device type/protocol auto detection. --- homeassistant/components/discovery.py | 1 + homeassistant/components/light/flux_led.py | 36 +++++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 5764735bf35..79b5b768801 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -39,6 +39,7 @@ SERVICE_HANDLERS = { 'denonavr': ('media_player', 'denonavr'), 'samsung_tv': ('media_player', 'samsungtv'), 'yeelight': ('light', 'yeelight'), + 'flux_led': ('light', 'flux_led'), } CONFIG_SCHEMA = vol.Schema({ diff --git a/homeassistant/components/light/flux_led.py b/homeassistant/components/light/flux_led.py index 2b517425110..11acdac6bc7 100644 --- a/homeassistant/components/light/flux_led.py +++ b/homeassistant/components/light/flux_led.py @@ -29,10 +29,13 @@ DOMAIN = 'flux_led' SUPPORT_FLUX_LED = (SUPPORT_BRIGHTNESS | SUPPORT_EFFECT | SUPPORT_RGB_COLOR) +MODE_RGB = 'rgb' +MODE_RGBW = 'rgbw' + DEVICE_SCHEMA = vol.Schema({ vol.Optional(CONF_NAME): cv.string, - vol.Optional(ATTR_MODE, default='rgbw'): - vol.All(cv.string, vol.In(['rgbw', 'rgb'])), + vol.Optional(ATTR_MODE, default=MODE_RGBW): + vol.All(cv.string, vol.In([MODE_RGBW, MODE_RGB])), vol.Optional(CONF_PROTOCOL, default=None): vol.All(cv.string, vol.In(['ledenet'])), }) @@ -48,7 +51,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import flux_led lights = [] light_ips = [] - for ipaddr, device_config in config[CONF_DEVICES].items(): + + for ipaddr, device_config in config.get(CONF_DEVICES, {}).items(): device = {} device['name'] = device_config[CONF_NAME] device['ipaddr'] = ipaddr @@ -59,7 +63,21 @@ def setup_platform(hass, config, add_devices, discovery_info=None): lights.append(light) light_ips.append(ipaddr) - if not config[CONF_AUTOMATIC_ADD]: + if discovery_info: + device = {} + # discovery_info: ip address,device id,device type + device['ipaddr'] = discovery_info[0] + device['name'] = discovery_info[1] + # As we don't know protocol and mode set to none to autodetect. + device[CONF_PROTOCOL] = None + device[ATTR_MODE] = None + + light = FluxLight(device) + if light.is_valid: + lights.append(light) + light_ips.append(device['ipaddr']) + + if not config.get(CONF_AUTOMATIC_ADD, False): add_devices(lights) return @@ -94,10 +112,20 @@ class FluxLight(Light): self._mode = device[ATTR_MODE] self.is_valid = True self._bulb = None + try: self._bulb = flux_led.WifiLedBulb(self._ipaddr) if self._protocol: self._bulb.setProtocol(self._protocol) + + # After bulb object is created the status is updated. We can + # now set the correct mode if it was not explicitly defined. + if not self._mode: + if self._bulb.rgbwcapable: + self._mode = MODE_RGBW + else: + self._mode = MODE_RGB + except socket.error: self.is_valid = False _LOGGER.error( From 2dab6cbb0e63e3f925441c56cc0126b1f3ca656e Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Wed, 8 Feb 2017 07:22:19 +0100 Subject: [PATCH 116/157] Mailgun notify service (#5782) * Mailgun notify service * Update dependency to version 1.3 - The provided credentials (including the domain) are now checked during startup, as requested by @balloob - The domain name is now optional - There's a new config item "sandbox" which indicates whether to use the sandboxed domain in case the domain is not set * Fix a few lint issues * Disable lint check no-value-for-parameter --- .coveragerc | 1 + homeassistant/components/notify/mailgun.py | 109 +++++++++++++++++++++ homeassistant/const.py | 1 + requirements_all.txt | 3 + 4 files changed, 114 insertions(+) create mode 100644 homeassistant/components/notify/mailgun.py diff --git a/.coveragerc b/.coveragerc index 251d9a7b6dc..2f1b0d1e857 100644 --- a/.coveragerc +++ b/.coveragerc @@ -258,6 +258,7 @@ omit = homeassistant/components/notify/kodi.py homeassistant/components/notify/lannouncer.py homeassistant/components/notify/llamalab_automate.py + homeassistant/components/notify/mailgun.py homeassistant/components/notify/matrix.py homeassistant/components/notify/message_bird.py homeassistant/components/notify/nfandroidtv.py diff --git a/homeassistant/components/notify/mailgun.py b/homeassistant/components/notify/mailgun.py new file mode 100644 index 00000000000..4765bd6893a --- /dev/null +++ b/homeassistant/components/notify/mailgun.py @@ -0,0 +1,109 @@ +""" +Support for the Mailgun mail service. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.mailgun/ +""" +import logging + +import voluptuous as vol + +from homeassistant.components.notify import ( + PLATFORM_SCHEMA, BaseNotificationService, + ATTR_TITLE, ATTR_TITLE_DEFAULT, ATTR_DATA) +from homeassistant.const import (CONF_TOKEN, CONF_DOMAIN, + CONF_RECIPIENT, CONF_SENDER) +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) +REQUIREMENTS = ['https://github.com/pschmitt/pymailgun/' + 'archive/1.3.zip#' + 'pymailgun==1.3'] + +# Images to attach to notification +ATTR_IMAGES = 'images' + +# Configuration item for the domain to use. +CONF_SANDBOX = 'sandbox' + +# Default sender name +DEFAULT_SENDER = 'hass@{domain}' +# Default sandbox value +DEFAULT_SANDBOX = False + +# pylint: disable=no-value-for-parameter +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_TOKEN): cv.string, + vol.Required(CONF_RECIPIENT): vol.Email(), + vol.Optional(CONF_DOMAIN): cv.string, + vol.Optional(CONF_SENDER): vol.Email(), + vol.Optional(CONF_SANDBOX, default=DEFAULT_SANDBOX): cv.boolean, +}) + + +def get_service(hass, config, discovery_info=None): + """Get the Mailgun notification service.""" + mailgun_service = MailgunNotificationService(config.get(CONF_DOMAIN), + config.get(CONF_SANDBOX), + config.get(CONF_TOKEN), + config.get(CONF_SENDER), + config.get(CONF_RECIPIENT)) + if mailgun_service.connection_is_valid(): + return mailgun_service + else: + return None + + +class MailgunNotificationService(BaseNotificationService): + """Implement a notification service for the Mailgun mail service.""" + + def __init__(self, domain, sandbox, token, sender, recipient): + """Initialize the service.""" + self._client = None # Mailgun API client + self._domain = domain + self._sandbox = sandbox + self._token = token + self._sender = sender + self._recipient = recipient + + def initialize_client(self): + """Initialize the connection to Mailgun.""" + from pymailgun import Client + self._client = Client(self._token, self._domain, self._sandbox) + _LOGGER.debug('Mailgun domain: %s', self._client.domain) + self._domain = self._client.domain + if not self._sender: + self._sender = DEFAULT_SENDER.format(domain=self._domain) + + def connection_is_valid(self): + """Check whether the provided credentials are valid.""" + from pymailgun import (MailgunCredentialsError, MailgunDomainError) + try: + self.initialize_client() + except MailgunCredentialsError: + _LOGGER.exception('Invalid credentials') + return False + except MailgunDomainError as mailgun_error: + _LOGGER.exception(mailgun_error) + return False + return True + + def send_message(self, message="", **kwargs): + """Send a mail to the recipient.""" + from pymailgun import MailgunError + subject = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) + data = kwargs.get(ATTR_DATA) + files = data.get(ATTR_IMAGES) if data else None + + try: + # Initialize the client in case it was not. + if self._client is None: + self.initialize_client() + resp = self._client.send_mail(sender=self._sender, + to=self._recipient, + subject=subject, + text=message, + files=files) + _LOGGER.debug('Message sent: %s', resp) + except MailgunError as mailgun_error: + _LOGGER.exception('Failed to send message: %s', mailgun_error) diff --git a/homeassistant/const.py b/homeassistant/const.py index ac5aeec581f..eda303a552e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -82,6 +82,7 @@ CONF_DEVICES = 'devices' CONF_DISARM_AFTER_TRIGGER = 'disarm_after_trigger' CONF_DISCOVERY = 'discovery' CONF_DISPLAY_OPTIONS = 'display_options' +CONF_DOMAIN = 'domain' CONF_DOMAINS = 'domains' CONF_ELEVATION = 'elevation' CONF_EMAIL = 'email' diff --git a/requirements_all.txt b/requirements_all.txt index a9056817036..5118d9351cb 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -248,6 +248,9 @@ https://github.com/nkgilley/python-ecobee-api/archive/4856a704670c53afe1882178a8 # homeassistant.components.notify.joaoapps_join https://github.com/nkgilley/python-join-api/archive/3e1e849f1af0b4080f551b62270c6d244d5fbcbd.zip#python-join-api==0.0.1 +# homeassistant.components.notify.mailgun +https://github.com/pschmitt/pymailgun/archive/1.3.zip#pymailgun==1.3 + # homeassistant.components.switch.edimax https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip#pyedimax==0.1 From 250523c1d820b3de6b82afc5cf2d3b1285ad0c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20St=C3=A5hl?= Date: Wed, 8 Feb 2017 12:17:23 +0100 Subject: [PATCH 117/157] Add discovery suppport to Apple TV (#5801) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/discovery.py | 1 + .../components/media_player/apple_tv.py | 20 +++++++++++-------- requirements_all.txt | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 79b5b768801..45a3944e6fe 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -40,6 +40,7 @@ SERVICE_HANDLERS = { 'samsung_tv': ('media_player', 'samsungtv'), 'yeelight': ('light', 'yeelight'), 'flux_led': ('light', 'flux_led'), + 'apple_tv': ('media_player', 'apple_tv'), } CONFIG_SCHEMA = vol.Schema({ diff --git a/homeassistant/components/media_player/apple_tv.py b/homeassistant/components/media_player/apple_tv.py index acfdac088aa..19700e2f8d7 100644 --- a/homeassistant/components/media_player/apple_tv.py +++ b/homeassistant/components/media_player/apple_tv.py @@ -21,7 +21,7 @@ import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['pyatv==0.0.1'] +REQUIREMENTS = ['pyatv==0.1.1'] _LOGGER = logging.getLogger(__name__) @@ -44,17 +44,21 @@ def async_setup_platform(hass, config, async_add_entities, """Setup the Apple TV platform.""" import pyatv + if discovery_info is not None: + name = discovery_info['name'] + host = discovery_info['host'] + login_id = discovery_info['hsgid'] + else: + name = config.get(CONF_NAME) + host = config.get(CONF_HOST) + login_id = config.get(CONF_LOGIN_ID) + if DATA_APPLE_TV not in hass.data: hass.data[DATA_APPLE_TV] = [] - name = config.get(CONF_NAME) - host = config.get(CONF_HOST) - login_id = config.get(CONF_LOGIN_ID) - - key = '{}:{}'.format(host, name) - if key in hass.data[DATA_APPLE_TV]: + if host in hass.data[DATA_APPLE_TV]: return False - hass.data[DATA_APPLE_TV].append(key) + hass.data[DATA_APPLE_TV].append(host) details = pyatv.AppleTVDevice(name, host, login_id) atv = pyatv.connect_to_apple_tv(details, hass.loop) diff --git a/requirements_all.txt b/requirements_all.txt index 5118d9351cb..e93a4565ae3 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -418,7 +418,7 @@ pyasn1-modules==0.0.8 pyasn1==0.2.2 # homeassistant.components.media_player.apple_tv -pyatv==0.0.1 +pyatv==0.1.1 # homeassistant.components.device_tracker.bbox # homeassistant.components.sensor.bbox From 8951e1bdc07eacd883f6493839e8c9e842fd7e98 Mon Sep 17 00:00:00 2001 From: "George.M" Date: Wed, 8 Feb 2017 11:28:45 +0000 Subject: [PATCH 118/157] The word `router` was misspelt (#5803) fixed as this message is user facing --- homeassistant/components/device_tracker/sky_hub.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/sky_hub.py b/homeassistant/components/device_tracker/sky_hub.py index 15d07f761df..ef58c50991c 100644 --- a/homeassistant/components/device_tracker/sky_hub.py +++ b/homeassistant/components/device_tracker/sky_hub.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def get_scanner(hass, config): - """Return a Sky Hub 5 scanner if successful.""" + """Return a Sky Hub scanner if successful.""" scanner = SkyHubDeviceScanner(config[DOMAIN]) return scanner if scanner.success_init else None @@ -113,7 +113,7 @@ def _parse_skyhub_response(data_str): pattmatch = re.search('attach_dev = \'(.*)\'', data_str) if pattmatch is None: raise IOError('Error: Impossible to fetch data from' + - ' Sky Hub. Try to reboot the rooter.') + ' Sky Hub. Try to reboot the router.') patt = pattmatch.group(1) dev = [patt1.split(',') for patt1 in patt.split('')] From db6c166abead95bcf9d09b4bacaf62008383f62b Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Wed, 8 Feb 2017 19:07:04 +0200 Subject: [PATCH 119/157] Update sma.py (#5807) --- homeassistant/components/sensor/sma.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/sma.py b/homeassistant/components/sensor/sma.py index dae9b64cff7..bbd0d92018f 100644 --- a/homeassistant/components/sensor/sma.py +++ b/homeassistant/components/sensor/sma.py @@ -68,8 +68,8 @@ def async_setup_platform(hass, config, add_devices, discovery_info=None): sensor_defs = dict(zip(SENSOR_OPTIONS, [ (pysma.KEY_CURRENT_CONSUMPTION_W, 'W', 1), (pysma.KEY_CURRENT_POWER_W, 'W', 1), - (pysma.KEY_TOTAL_CONSUMPTION_KWH, 'kW/h', 1000), - (pysma.KEY_TOTAL_YIELD_KWH, 'kW/h', 1000)])) + (pysma.KEY_TOTAL_CONSUMPTION_KWH, 'kWh', 1000), + (pysma.KEY_TOTAL_YIELD_KWH, 'kWh', 1000)])) # sensor_defs from the custom config for name, prop in config[CONF_CUSTOM].items(): From 08efe2bf6d6c93f1f6c0d2dc915e3917232af751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Wed, 8 Feb 2017 18:07:43 +0100 Subject: [PATCH 120/157] Improve warning message in template rendering (#5806) * improve warning message when template is none * improve error message when template is none * improve error message when template is none * improve error message when template is none --- homeassistant/components/binary_sensor/template.py | 5 +++-- homeassistant/components/sensor/template.py | 11 +++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/binary_sensor/template.py b/homeassistant/components/binary_sensor/template.py index e097c7c0ea4..fa60412c77f 100644 --- a/homeassistant/components/binary_sensor/template.py +++ b/homeassistant/components/binary_sensor/template.py @@ -118,7 +118,8 @@ class BinarySensorTemplate(BinarySensorDevice): if ex.args and ex.args[0].startswith( "UndefinedError: 'None' has no attribute"): # Common during HA startup - so just a warning - _LOGGER.warning(ex) + _LOGGER.warning('Could not render template %s,' + ' the state is unknown.', self._name) return - _LOGGER.error(ex) + _LOGGER.error('Could not render template %s: %s', self._name, ex) self._state = False diff --git a/homeassistant/components/sensor/template.py b/homeassistant/components/sensor/template.py index 2535bea1539..aba42519e60 100644 --- a/homeassistant/components/sensor/template.py +++ b/homeassistant/components/sensor/template.py @@ -131,10 +131,11 @@ class SensorTemplate(Entity): if ex.args and ex.args[0].startswith( "UndefinedError: 'None' has no attribute"): # Common during HA startup - so just a warning - _LOGGER.warning(ex) + _LOGGER.warning('Could not render template %s,' + ' the state is unknown.', self._name) return self._state = None - _LOGGER.error(ex) + _LOGGER.error('Could not render template %s: %s', self._name, ex) if self._icon_template is not None: try: @@ -143,7 +144,9 @@ class SensorTemplate(Entity): if ex.args and ex.args[0].startswith( "UndefinedError: 'None' has no attribute"): # Common during HA startup - so just a warning - _LOGGER.warning(ex) + _LOGGER.warning('Could not render icon template %s,' + ' the state is unknown.', self._name) return self._icon = super().icon - _LOGGER.error(ex) + _LOGGER.error('Could not render icon template %s: %s', + self._name, ex) From 3f82ef64a1bf23c989405b647eeb40050e8ca0ea Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 8 Feb 2017 18:17:52 +0100 Subject: [PATCH 121/157] Move core service from core to components (#5787) * Move core servcie from core to components * add new handler for signals/exception * Static persistent id * Move unittest * fix coro/callback * Add more unittest for new services * Address comments * Update __init__.py --- homeassistant/components/__init__.py | 59 ++++++++++++++++++++----- homeassistant/config.py | 29 +++++++++++++ homeassistant/core.py | 64 +++++----------------------- tests/components/test_init.py | 44 ++++++++++++++++++- tests/test_config.py | 33 +++++++++++++- tests/test_core.py | 38 +---------------- 6 files changed, 165 insertions(+), 102 deletions(-) diff --git a/homeassistant/components/__init__.py b/homeassistant/components/__init__.py index a4f18250d17..0e9d554a579 100644 --- a/homeassistant/components/__init__.py +++ b/homeassistant/components/__init__.py @@ -12,14 +12,19 @@ import itertools as it import logging import homeassistant.core as ha +import homeassistant.config as conf_util +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.service import extract_entity_ids from homeassistant.loader import get_component from homeassistant.const import ( - ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE) + ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE, + SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART, + RESTART_EXIT_CODE) _LOGGER = logging.getLogger(__name__) SERVICE_RELOAD_CORE_CONFIG = 'reload_core_config' +SERVICE_CHECK_CONFIG = 'check_config' def is_on(hass, entity_id=None): @@ -75,6 +80,21 @@ def toggle(hass, entity_id=None, **service_data): hass.services.call(ha.DOMAIN, SERVICE_TOGGLE, service_data) +def stop(hass): + """Stop Home Assistant.""" + hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP) + + +def restart(hass): + """Stop Home Assistant.""" + hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART) + + +def check_config(hass): + """Check the config files.""" + hass.services.call(ha.DOMAIN, SERVICE_CHECK_CONFIG) + + def reload_core_config(hass): """Reload the core config.""" hass.services.call(ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG) @@ -84,7 +104,7 @@ def reload_core_config(hass): def async_setup(hass, config): """Setup general services related to Home Assistant.""" @asyncio.coroutine - def handle_turn_service(service): + def async_handle_turn_service(service): """Method to handle calls to homeassistant.turn_on/off.""" entity_ids = extract_entity_ids(hass, service) @@ -122,18 +142,37 @@ def async_setup(hass, config): yield from asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( - ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service) + ha.DOMAIN, SERVICE_TURN_OFF, async_handle_turn_service) hass.services.async_register( - ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service) + ha.DOMAIN, SERVICE_TURN_ON, async_handle_turn_service) hass.services.async_register( - ha.DOMAIN, SERVICE_TOGGLE, handle_turn_service) + ha.DOMAIN, SERVICE_TOGGLE, async_handle_turn_service) @asyncio.coroutine - def handle_reload_config(call): - """Service handler for reloading core config.""" - from homeassistant.exceptions import HomeAssistantError - from homeassistant import config as conf_util + def async_handle_core_service(call): + """Service handler for handling core services.""" + if call.service == SERVICE_HOMEASSISTANT_STOP: + hass.async_add_job(hass.async_stop()) + return + try: + yield from conf_util.async_check_ha_config_file(hass) + except HomeAssistantError: + return + + if call.service == SERVICE_HOMEASSISTANT_RESTART: + hass.async_add_job(hass.async_stop(RESTART_EXIT_CODE)) + + hass.services.async_register( + ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP, async_handle_core_service) + hass.services.async_register( + ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART, async_handle_core_service) + hass.services.async_register( + ha.DOMAIN, SERVICE_CHECK_CONFIG, async_handle_core_service) + + @asyncio.coroutine + def async_handle_reload_config(call): + """Service handler for reloading core config.""" try: conf = yield from conf_util.async_hass_config_yaml(hass) except HomeAssistantError as err: @@ -144,6 +183,6 @@ def async_setup(hass, config): hass, conf.get(ha.DOMAIN) or {}) hass.services.async_register( - ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG, handle_reload_config) + ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG, async_handle_reload_config) return True diff --git a/homeassistant/config.py b/homeassistant/config.py index 23d52f6bc66..101c1a1dc87 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -3,7 +3,9 @@ import asyncio from collections import OrderedDict import logging import os +import re import shutil +import sys # pylint: disable=unused-import from typing import Any, List, Tuple # NOQA @@ -453,3 +455,30 @@ def merge_packages_customize(core_customize, packages): conf = schema(pkg) cust.extend(conf.get(CONF_CORE, {}).get(CONF_CUSTOMIZE, [])) return cust + + +@asyncio.coroutine +def async_check_ha_config_file(hass): + """Check if HA config file valid. + + This method is a coroutine. + """ + import homeassistant.components.persistent_notification as pn + + proc = yield from asyncio.create_subprocess_exec( + sys.argv[0], + '--script', + 'check_config', + stdout=asyncio.subprocess.PIPE) + # Wait for the subprocess exit + (stdout_data, dummy) = yield from proc.communicate() + result = yield from proc.wait() + if result: + content = re.sub(r'\033\[[^m]*m', '', str(stdout_data, 'utf-8')) + # Put error cleaned from color codes in the error log so it + # will be visible at the UI. + _LOGGER.error(content) + pn.async_create( + hass, "Config error. See dev-info panel for details.", + "Config validating", "{0}.check_config".format(CONF_CORE)) + raise HomeAssistantError("Invalid config") diff --git a/homeassistant/core.py b/homeassistant/core.py index 2cf2e3c85e4..db186fb1b1c 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -26,8 +26,7 @@ from homeassistant.const import ( ATTR_SERVICE_CALL_ID, ATTR_SERVICE_DATA, EVENT_CALL_SERVICE, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_SERVICE_EXECUTED, EVENT_SERVICE_REGISTERED, EVENT_STATE_CHANGED, - EVENT_TIME_CHANGED, MATCH_ALL, RESTART_EXIT_CODE, - SERVICE_HOMEASSISTANT_RESTART, SERVICE_HOMEASSISTANT_STOP, __version__) + EVENT_TIME_CHANGED, MATCH_ALL, RESTART_EXIT_CODE, __version__) from homeassistant.exceptions import ( HomeAssistantError, InvalidEntityFormatError, ShuttingDown) from homeassistant.util.async import ( @@ -137,7 +136,7 @@ class HomeAssistant(object): _LOGGER.info("Starting Home Assistant core loop") self.loop.run_forever() except KeyboardInterrupt: - self.loop.call_soon(self._async_stop_handler) + self.loop.create_task(self.async_stop()) self.loop.run_forever() finally: self.loop.close() @@ -149,26 +148,23 @@ class HomeAssistant(object): This method is a coroutine. """ _LOGGER.info("Starting Home Assistant") - self.state = CoreState.starting - # Register the restart/stop event - self.services.async_register( - DOMAIN, SERVICE_HOMEASSISTANT_STOP, self._async_stop_handler) - self.services.async_register( - DOMAIN, SERVICE_HOMEASSISTANT_RESTART, self._async_restart_handler) - # Setup signal handling if sys.platform != 'win32': + def _async_signal_handle(exit_code): + """Wrap signal handling.""" + self.async_add_job(self.async_stop(exit_code)) + try: self.loop.add_signal_handler( - signal.SIGTERM, self._async_stop_handler) + signal.SIGTERM, _async_signal_handle, 0) except ValueError: _LOGGER.warning("Could not bind to SIGTERM") try: self.loop.add_signal_handler( - signal.SIGHUP, self._async_restart_handler) + signal.SIGHUP, _async_signal_handle, RESTART_EXIT_CODE) except ValueError: _LOGGER.warning("Could not bind to SIGHUP") @@ -283,7 +279,7 @@ class HomeAssistant(object): run_coroutine_threadsafe(self.async_stop(), self.loop) @asyncio.coroutine - def async_stop(self) -> None: + def async_stop(self, exit_code=0) -> None: """Stop Home Assistant and shuts down all threads. This method is a coroutine. @@ -306,6 +302,7 @@ class HomeAssistant(object): logging.getLogger('').removeHandler(handler) yield from handler.async_close(blocking=True) + self.exit_code = exit_code self.loop.stop() # pylint: disable=no-self-use @@ -324,47 +321,6 @@ class HomeAssistant(object): _LOGGER.error("Error doing job: %s", context['message'], **kwargs) - @callback - def _async_stop_handler(self, *args): - """Stop Home Assistant.""" - self.exit_code = 0 - self.loop.create_task(self.async_stop()) - - @asyncio.coroutine - def _async_check_config_and_restart(self): - """Restart Home Assistant if config is valid. - - This method is a coroutine. - """ - proc = yield from asyncio.create_subprocess_exec( - sys.argv[0], - '--script', - 'check_config', - stdout=asyncio.subprocess.PIPE) - # Wait for the subprocess exit - (stdout_data, dummy) = yield from proc.communicate() - result = yield from proc.wait() - if result: - _LOGGER.error("check_config failed. Not restarting.") - content = re.sub(r'\033\[[^m]*m', '', str(stdout_data, 'utf-8')) - # Put error cleaned from color codes in the error log so it - # will be visible at the UI. - _LOGGER.error(content) - yield from self.services.async_call( - 'persistent_notification', 'create', { - 'message': 'Config error. See dev-info panel for details.', - 'title': 'Restarting', - 'notification_id': '{}.restart'.format(DOMAIN)}) - return - - self.exit_code = RESTART_EXIT_CODE - yield from self.async_stop() - - @callback - def _async_restart_handler(self, *args): - """Restart Home Assistant.""" - self.loop.create_task(self._async_check_config_and_restart()) - class EventOrigin(enum.Enum): """Represent the origin of an event.""" diff --git a/tests/components/test_init.py b/tests/components/test_init.py index 833319646a2..14066d65f2a 100644 --- a/tests/components/test_init.py +++ b/tests/components/test_init.py @@ -11,11 +11,12 @@ from homeassistant import config from homeassistant.const import ( STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE) import homeassistant.components as comps +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity from homeassistant.util.async import run_coroutine_threadsafe from tests.common import ( - get_test_home_assistant, mock_service, patch_yaml_files) + get_test_home_assistant, mock_service, patch_yaml_files, mock_coro) class TestComponentsCore(unittest.TestCase): @@ -150,3 +151,44 @@ class TestComponentsCore(unittest.TestCase): assert mock_error.called assert mock_process.called is False + + @patch('homeassistant.core.HomeAssistant.async_stop', + return_value=mock_coro()()) + def test_stop_homeassistant(self, mock_stop): + """Test stop service.""" + comps.stop(self.hass) + self.hass.block_till_done() + assert mock_stop.called + + @patch('homeassistant.core.HomeAssistant.async_stop', + return_value=mock_coro()()) + @patch('homeassistant.config.async_check_ha_config_file', + return_value=mock_coro()()) + def test_restart_homeassistant(self, mock_check, mock_restart): + """Test stop service.""" + comps.restart(self.hass) + self.hass.block_till_done() + assert mock_restart.called + assert mock_check.called + + @patch('homeassistant.core.HomeAssistant.async_stop', + return_value=mock_coro()()) + @patch('homeassistant.config.async_check_ha_config_file', + side_effect=HomeAssistantError("Test error")) + def test_restart_homeassistant_wrong_conf(self, mock_check, mock_restart): + """Test stop service.""" + comps.restart(self.hass) + self.hass.block_till_done() + assert mock_check.called + assert not mock_restart.called + + @patch('homeassistant.core.HomeAssistant.async_stop', + return_value=mock_coro()()) + @patch('homeassistant.config.async_check_ha_config_file', + return_value=mock_coro()()) + def test_check_config(self, mock_check, mock_stop): + """Test stop service.""" + comps.check_config(self.hass) + self.hass.block_till_done() + assert mock_check.called + assert not mock_stop.called diff --git a/tests/test_config.py b/tests/test_config.py index 1197a0130d8..2ad25dece11 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -18,7 +18,7 @@ from homeassistant.util.async import run_coroutine_threadsafe from homeassistant.helpers.entity import Entity from tests.common import ( - get_test_config_dir, get_test_home_assistant) + get_test_config_dir, get_test_home_assistant, mock_generator) CONFIG_DIR = get_test_config_dir() YAML_PATH = os.path.join(CONFIG_DIR, config_util.YAML_CONFIG_FILE) @@ -376,6 +376,37 @@ class TestConfig(unittest.TestCase): assert self.hass.config.units == blankConfig.units assert self.hass.config.time_zone == blankConfig.time_zone + @mock.patch('asyncio.create_subprocess_exec') + def test_check_ha_config_file_correct(self, mock_create): + """Check that restart propagates to stop.""" + process_mock = mock.MagicMock() + attrs = { + 'communicate.return_value': mock_generator(('output', 'error')), + 'wait.return_value': mock_generator(0)} + process_mock.configure_mock(**attrs) + mock_create.return_value = mock_generator(process_mock) + + assert run_coroutine_threadsafe( + config_util.async_check_ha_config_file(self.hass), self.hass.loop + ).result() is None + + @mock.patch('asyncio.create_subprocess_exec') + def test_check_ha_config_file_wrong(self, mock_create): + """Check that restart with a bad config doesn't propagate to stop.""" + process_mock = mock.MagicMock() + attrs = { + 'communicate.return_value': + mock_generator((r'\033[hellom'.encode('utf-8'), 'error')), + 'wait.return_value': mock_generator(1)} + process_mock.configure_mock(**attrs) + mock_create.return_value = mock_generator(process_mock) + + with self.assertRaises(HomeAssistantError): + run_coroutine_threadsafe( + config_util.async_check_ha_config_file(self.hass), + self.hass.loop + ).result() + # pylint: disable=redefined-outer-name @pytest.fixture diff --git a/tests/test_core.py b/tests/test_core.py index 72c459a4eac..14276584ae2 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -14,10 +14,9 @@ from homeassistant.util.async import run_coroutine_threadsafe import homeassistant.util.dt as dt_util from homeassistant.util.unit_system import (METRIC_SYSTEM) from homeassistant.const import ( - __version__, EVENT_STATE_CHANGED, ATTR_FRIENDLY_NAME, CONF_UNIT_SYSTEM, - SERVICE_HOMEASSISTANT_RESTART, RESTART_EXIT_CODE) + __version__, EVENT_STATE_CHANGED, ATTR_FRIENDLY_NAME, CONF_UNIT_SYSTEM) -from tests.common import get_test_home_assistant, mock_generator +from tests.common import get_test_home_assistant PST = pytz.timezone('America/Los_Angeles') @@ -221,39 +220,6 @@ class TestHomeAssistant(unittest.TestCase): with pytest.raises(ValueError): self.hass.add_job(None, 'test_arg') - @patch('asyncio.create_subprocess_exec') - def test_restart(self, mock_create): - """Check that restart propagates to stop.""" - process_mock = MagicMock() - attrs = { - 'communicate.return_value': mock_generator(('output', 'error')), - 'wait.return_value': mock_generator(0)} - process_mock.configure_mock(**attrs) - mock_create.return_value = mock_generator(process_mock) - - self.hass.start() - with patch.object(self.hass, 'async_stop') as mock_stop: - self.hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART) - mock_stop.assert_called_once_with() - self.assertEqual(RESTART_EXIT_CODE, self.hass.exit_code) - - @patch('asyncio.create_subprocess_exec') - def test_restart_bad_config(self, mock_create): - """Check that restart with a bad config doesn't propagate to stop.""" - process_mock = MagicMock() - attrs = { - 'communicate.return_value': - mock_generator((r'\033[hellom'.encode('utf-8'), 'error')), - 'wait.return_value': mock_generator(1)} - process_mock.configure_mock(**attrs) - mock_create.return_value = mock_generator(process_mock) - - self.hass.start() - with patch.object(self.hass, 'async_stop') as mock_stop: - self.hass.services.call(ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART) - mock_stop.assert_not_called() - self.assertEqual(None, self.hass.exit_code) - class TestEvent(unittest.TestCase): """A Test Event class.""" From 881d53339bbb91e223f9b4da27d353921eca16a3 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 8 Feb 2017 18:19:40 +0100 Subject: [PATCH 122/157] [Image_Processing][Breaking Change] Cleanup Base face class add support for microsoft face detect (#5802) * [Image_Processing] Cleanup Base face class add support for microsoft face detect * fix lint * add unittest for micosoft detect * fix test --- .../components/image_processing/demo.py | 32 ++-- .../image_processing/microsoft_face_detect.py | 122 ++++++++++++++ .../microsoft_face_identify.py | 87 ++++++---- .../image_processing/openalpr_local.py | 2 +- .../components/image_processing/test_init.py | 44 ++++- .../test_microsoft_face_detect.py | 159 ++++++++++++++++++ .../test_microsoft_face_identify.py | 4 +- .../image_processing/test_openalpr_cloud.py | 2 +- .../image_processing/test_openalpr_local.py | 2 +- 9 files changed, 400 insertions(+), 54 deletions(-) create mode 100644 homeassistant/components/image_processing/microsoft_face_detect.py create mode 100644 tests/components/image_processing/test_microsoft_face_detect.py diff --git a/homeassistant/components/image_processing/demo.py b/homeassistant/components/image_processing/demo.py index 97f0eace41d..3cc2c17654c 100644 --- a/homeassistant/components/image_processing/demo.py +++ b/homeassistant/components/image_processing/demo.py @@ -4,19 +4,19 @@ Support for the demo image processing. For more details about this component, please refer to the documentation at https://home-assistant.io/components/demo/ """ - +from homeassistant.components.image_processing import ATTR_CONFIDENCE from homeassistant.components.image_processing.openalpr_local import ( ImageProcessingAlprEntity) from homeassistant.components.image_processing.microsoft_face_identify import ( - ImageProcessingFaceIdentifyEntity) + ImageProcessingFaceEntity, ATTR_NAME, ATTR_AGE, ATTR_GENDER) def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the demo image_processing platform.""" add_devices([ DemoImageProcessingAlpr('camera.demo_camera', "Demo Alpr"), - DemoImageProcessingFaceIdentify( - 'camera.demo_camera', "Demo Face Identify") + DemoImageProcessingFace( + 'camera.demo_camera', "Demo Face") ]) @@ -57,7 +57,7 @@ class DemoImageProcessingAlpr(ImageProcessingAlprEntity): self.process_plates(demo_data, 1) -class DemoImageProcessingFaceIdentify(ImageProcessingFaceIdentifyEntity): +class DemoImageProcessingFace(ImageProcessingFaceEntity): """Demo face identify image processing entity.""" def __init__(self, camera_entity, name): @@ -84,10 +84,22 @@ class DemoImageProcessingFaceIdentify(ImageProcessingFaceIdentifyEntity): def process_image(self, image): """Process image.""" - demo_data = { - 'Hans': 98.34, - 'Helena': 82.53, - 'Luna': 62.53, - } + demo_data = [ + { + ATTR_CONFIDENCE: 98.34, + ATTR_NAME: 'Hans', + ATTR_AGE: 16.0, + ATTR_GENDER: 'male', + }, + { + ATTR_NAME: 'Helena', + ATTR_AGE: 28.0, + ATTR_GENDER: 'female', + }, + { + ATTR_CONFIDENCE: 62.53, + ATTR_NAME: 'Luna', + }, + ] self.process_faces(demo_data, 4) diff --git a/homeassistant/components/image_processing/microsoft_face_detect.py b/homeassistant/components/image_processing/microsoft_face_detect.py new file mode 100644 index 00000000000..43c5c9dd7f0 --- /dev/null +++ b/homeassistant/components/image_processing/microsoft_face_detect.py @@ -0,0 +1,122 @@ +""" +Component that will help set the microsoft face detect processing. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/image_processing.microsoft_face_detect/ +""" +import asyncio +import logging + +import voluptuous as vol + +from homeassistant.core import split_entity_id +from homeassistant.exceptions import HomeAssistantError +from homeassistant.components.microsoft_face import DATA_MICROSOFT_FACE +from homeassistant.components.image_processing import ( + PLATFORM_SCHEMA, CONF_SOURCE, CONF_ENTITY_ID, CONF_NAME) +from homeassistant.components.image_processing.microsoft_face_identify import ( + ImageProcessingFaceEntity, ATTR_GENDER, ATTR_AGE, ATTR_GLASSES) +import homeassistant.helpers.config_validation as cv + +DEPENDENCIES = ['microsoft_face'] + +_LOGGER = logging.getLogger(__name__) + +EVENT_IDENTIFY_FACE = 'detect_face' + +SUPPORTED_ATTRIBUTES = [ + ATTR_AGE, + ATTR_GENDER, + ATTR_GLASSES +] + +CONF_ATTRIBUTES = 'attributes' +DEFAULT_ATTRIBUTES = [ATTR_AGE, ATTR_GENDER] + + +def validate_attributes(list_attributes): + """Validate face attributes.""" + for attr in list_attributes: + if attr not in SUPPORTED_ATTRIBUTES: + raise vol.Invalid("Invalid attribtue {0}".format(attr)) + return list_attributes + + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_ATTRIBUTES, default=DEFAULT_ATTRIBUTES): + vol.All(cv.ensure_list, validate_attributes), +}) + + +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + """Set up the microsoft face detection platform.""" + api = hass.data[DATA_MICROSOFT_FACE] + attributes = config[CONF_ATTRIBUTES] + + entities = [] + for camera in config[CONF_SOURCE]: + entities.append(MicrosoftFaceDetectEntity( + camera[CONF_ENTITY_ID], api, attributes, camera.get(CONF_NAME) + )) + + yield from async_add_devices(entities) + + +class MicrosoftFaceDetectEntity(ImageProcessingFaceEntity): + """Microsoft face api entity for identify.""" + + def __init__(self, camera_entity, api, attributes, name=None): + """Initialize openalpr local api.""" + super().__init__() + + self._api = api + self._camera = camera_entity + self._attributes = attributes + + if name: + self._name = name + else: + self._name = "MicrosoftFace {0}".format( + split_entity_id(camera_entity)[1]) + + @property + def camera_entity(self): + """Return camera entity id from process pictures.""" + return self._camera + + @property + def name(self): + """Return the name of the entity.""" + return self._name + + @asyncio.coroutine + def async_process_image(self, image): + """Process image. + + This method is a coroutine. + """ + face_data = None + try: + face_data = yield from self._api.call_api( + 'post', 'detect', image, binary=True, + params={'returnFaceAttributes': ",".join(self._attributes)}) + + except HomeAssistantError as err: + _LOGGER.error("Can't process image on microsoft face: %s", err) + return + + if face_data is None or len(face_data) < 1: + return + + faces = [] + for face in face_data: + face_attr = {} + for attr in self._attributes: + if attr in face['faceAttributes']: + face_attr[attr] = face['faceAttributes'][attr] + + if face_attr: + faces.append(face_attr) + + self.async_process_faces(faces, len(face_data)) diff --git a/homeassistant/components/image_processing/microsoft_face_identify.py b/homeassistant/components/image_processing/microsoft_face_identify.py index 0402f272eeb..1cc17f1443b 100644 --- a/homeassistant/components/image_processing/microsoft_face_identify.py +++ b/homeassistant/components/image_processing/microsoft_face_identify.py @@ -23,11 +23,16 @@ DEPENDENCIES = ['microsoft_face'] _LOGGER = logging.getLogger(__name__) -EVENT_IDENTIFY_FACE = 'identify_face' +EVENT_DETECT_FACE = 'image_processing.detect_face' ATTR_NAME = 'name' ATTR_TOTAL_FACES = 'total_faces' -ATTR_KNOWN_FACES = 'known_faces' +ATTR_AGE = 'age' +ATTR_GENDER = 'gender' +ATTR_MOTION = 'motion' +ATTR_GLASSES = 'glasses' +ATTR_FACES = 'faces' + CONF_GROUP = 'group' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -52,71 +57,90 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): yield from async_add_devices(entities) -class ImageProcessingFaceIdentifyEntity(ImageProcessingEntity): - """Base entity class for face identify/verify image processing.""" +class ImageProcessingFaceEntity(ImageProcessingEntity): + """Base entity class for face image processing.""" def __init__(self): """Initialize base face identify/verify entity.""" - self.known_faces = {} # last scan data + self.faces = [] # last scan data self.total_faces = 0 # face count @property def state(self): """Return the state of the entity.""" confidence = 0 - face_name = STATE_UNKNOWN + state = STATE_UNKNOWN - # search high verify face - for i_name, i_co in self.known_faces.items(): - if i_co > confidence: - confidence = i_co - face_name = i_name - return face_name + # no confidence support + if not self.confidence: + return self.total_faces + + # search high confidence + for face in self.faces: + if ATTR_CONFIDENCE not in face: + continue + + f_co = face[ATTR_CONFIDENCE] + if f_co > confidence: + confidence = f_co + for attr in [ATTR_NAME, ATTR_MOTION]: + if attr in face: + state = face[attr] + break + + return state @property def state_attributes(self): """Return device specific state attributes.""" attr = { - ATTR_KNOWN_FACES: self.known_faces, + ATTR_FACES: self.faces, ATTR_TOTAL_FACES: self.total_faces, } return attr - def process_faces(self, known, total): + def process_faces(self, faces, total): """Send event with detected faces and store data.""" run_callback_threadsafe( - self.hass.loop, self.async_process_faces, known, total + self.hass.loop, self.async_process_faces, faces, total ).result() @callback - def async_process_faces(self, known, total): + def async_process_faces(self, faces, total): """Send event with detected faces and store data. known are a dict in follow format: - { 'name': confidence } + [ + { + ATTR_CONFIDENCE: 80, + ATTR_NAME: 'Name', + ATTR_AGE: 12.0, + ATTR_GENDER: 'man', + ATTR_MOTION: 'smile', + ATTR_GLASSES: 'sunglasses' + }, + ] This method must be run in the event loop. """ - detect = {name: confidence for name, confidence in known.items() - if confidence >= self.confidence} - # send events - for name, confidence in detect.items(): + for face in faces: + if ATTR_CONFIDENCE in face and self.confidence: + if face[ATTR_CONFIDENCE] < self.confidence: + continue + + face.update({ATTR_ENTITY_ID: self.entity_id}) self.hass.async_add_job( - self.hass.bus.async_fire, EVENT_IDENTIFY_FACE, { - ATTR_NAME: name, - ATTR_ENTITY_ID: self.entity_id, - ATTR_CONFIDENCE: confidence, - } + self.hass.bus.async_fire, EVENT_DETECT_FACE, face ) # update entity store - self.known_faces = detect + self.faces = faces self.total_faces = total -class MicrosoftFaceIdentifyEntity(ImageProcessingFaceIdentifyEntity): +class MicrosoftFaceIdentifyEntity(ImageProcessingFaceEntity): """Microsoft face api entity for identify.""" def __init__(self, camera_entity, api, face_group, confidence, name=None): @@ -173,7 +197,7 @@ class MicrosoftFaceIdentifyEntity(ImageProcessingFaceIdentifyEntity): return # parse data - knwon_faces = {} + knwon_faces = [] total = 0 for face in detect: total += 1 @@ -187,7 +211,10 @@ class MicrosoftFaceIdentifyEntity(ImageProcessingFaceIdentifyEntity): name = s_name break - knwon_faces[name] = data['confidence'] * 100 + knwon_faces.append({ + ATTR_NAME: name, + ATTR_CONFIDENCE: data['confidence'] * 100, + }) # process data self.async_process_faces(knwon_faces, total) diff --git a/homeassistant/components/image_processing/openalpr_local.py b/homeassistant/components/image_processing/openalpr_local.py index 319f14c1f3d..dbd404dd04c 100644 --- a/homeassistant/components/image_processing/openalpr_local.py +++ b/homeassistant/components/image_processing/openalpr_local.py @@ -24,7 +24,7 @@ _LOGGER = logging.getLogger(__name__) RE_ALPR_PLATE = re.compile(r"^plate\d*:") RE_ALPR_RESULT = re.compile(r"- (\w*)\s*confidence: (\d*.\d*)") -EVENT_FOUND_PLATE = 'found_plate' +EVENT_FOUND_PLATE = 'image_processing.found_plate' ATTR_PLATE = 'plate' ATTR_PLATES = 'plates' diff --git a/tests/components/image_processing/test_init.py b/tests/components/image_processing/test_init.py index b13dcf48a72..2ac64891e95 100644 --- a/tests/components/image_processing/test_init.py +++ b/tests/components/image_processing/test_init.py @@ -110,7 +110,7 @@ class TestImageProcessing(object): class TestImageProcessingAlpr(object): - """Test class for image processing.""" + """Test class for alpr image processing.""" def setup_method(self): """Setup things to be run when tests are started.""" @@ -142,7 +142,7 @@ class TestImageProcessingAlpr(object): """Mock event.""" self.alpr_events.append(event) - self.hass.bus.listen('found_plate', mock_alpr_event) + self.hass.bus.listen('image_processing.found_plate', mock_alpr_event) def teardown_method(self): """Stop everything that was started.""" @@ -211,8 +211,8 @@ class TestImageProcessingAlpr(object): assert event_data[0]['entity_id'] == 'image_processing.demo_alpr' -class TestImageProcessingFaceIdentify(object): - """Test class for image processing.""" +class TestImageProcessingFace(object): + """Test class for face image processing.""" def setup_method(self): """Setup things to be run when tests are started.""" @@ -228,7 +228,7 @@ class TestImageProcessingFaceIdentify(object): } with patch('homeassistant.components.image_processing.demo.' - 'DemoImageProcessingFaceIdentify.should_poll', + 'DemoImageProcessingFace.should_poll', new_callable=PropertyMock(return_value=False)): setup_component(self.hass, ip.DOMAIN, config) @@ -244,7 +244,7 @@ class TestImageProcessingFaceIdentify(object): """Mock event.""" self.face_events.append(event) - self.hass.bus.listen('identify_face', mock_face_event) + self.hass.bus.listen('image_processing.detect_face', mock_face_event) def teardown_method(self): """Stop everything that was started.""" @@ -254,10 +254,10 @@ class TestImageProcessingFaceIdentify(object): """Setup and scan a picture and test faces from event.""" aioclient_mock.get(self.url, content=b'image') - ip.scan(self.hass, entity_id='image_processing.demo_face_identify') + ip.scan(self.hass, entity_id='image_processing.demo_face') self.hass.block_till_done() - state = self.hass.states.get('image_processing.demo_face_identify') + state = self.hass.states.get('image_processing.demo_face') assert len(self.face_events) == 2 assert state.state == 'Hans' @@ -268,5 +268,31 @@ class TestImageProcessingFaceIdentify(object): assert len(event_data) == 1 assert event_data[0]['name'] == 'Hans' assert event_data[0]['confidence'] == 98.34 + assert event_data[0]['gender'] == 'male' assert event_data[0]['entity_id'] == \ - 'image_processing.demo_face_identify' + 'image_processing.demo_face' + + @patch('homeassistant.components.image_processing.demo.' + 'DemoImageProcessingFace.confidence', + new_callable=PropertyMock(return_value=None)) + def test_face_event_call_no_confidence(self, mock_confi, aioclient_mock): + """Setup and scan a picture and test faces from event.""" + aioclient_mock.get(self.url, content=b'image') + + ip.scan(self.hass, entity_id='image_processing.demo_face') + self.hass.block_till_done() + + state = self.hass.states.get('image_processing.demo_face') + + assert len(self.face_events) == 3 + assert state.state == '4' + assert state.attributes['total_faces'] == 4 + + event_data = [event.data for event in self.face_events if + event.data.get('name') == 'Hans'] + assert len(event_data) == 1 + assert event_data[0]['name'] == 'Hans' + assert event_data[0]['confidence'] == 98.34 + assert event_data[0]['gender'] == 'male' + assert event_data[0]['entity_id'] == \ + 'image_processing.demo_face' diff --git a/tests/components/image_processing/test_microsoft_face_detect.py b/tests/components/image_processing/test_microsoft_face_detect.py new file mode 100644 index 00000000000..82fd54f1633 --- /dev/null +++ b/tests/components/image_processing/test_microsoft_face_detect.py @@ -0,0 +1,159 @@ +"""The tests for the microsoft face detect platform.""" +from unittest.mock import patch, PropertyMock + +from homeassistant.core import callback +from homeassistant.const import ATTR_ENTITY_PICTURE +from homeassistant.bootstrap import setup_component +import homeassistant.components.image_processing as ip +import homeassistant.components.microsoft_face as mf + +from tests.common import ( + get_test_home_assistant, assert_setup_component, load_fixture, mock_coro) + + +class TestMicrosoftFaceDetectSetup(object): + """Test class for image processing.""" + + def setup_method(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def teardown_method(self): + """Stop everything that was started.""" + self.hass.stop() + + @patch('homeassistant.components.microsoft_face.' + 'MicrosoftFace.update_store', return_value=mock_coro()()) + def test_setup_platform(self, store_mock): + """Setup platform with one entity.""" + config = { + ip.DOMAIN: { + 'platform': 'microsoft_face_detect', + 'source': { + 'entity_id': 'camera.demo_camera' + }, + 'attributes': ['age', 'gender'], + }, + 'camera': { + 'platform': 'demo' + }, + mf.DOMAIN: { + 'api_key': '12345678abcdef6', + } + } + + with assert_setup_component(1, ip.DOMAIN): + setup_component(self.hass, ip.DOMAIN, config) + + assert self.hass.states.get( + 'image_processing.microsoftface_demo_camera') + + @patch('homeassistant.components.microsoft_face.' + 'MicrosoftFace.update_store', return_value=mock_coro()()) + def test_setup_platform_name(self, store_mock): + """Setup platform with one entity and set name.""" + config = { + ip.DOMAIN: { + 'platform': 'microsoft_face_detect', + 'source': { + 'entity_id': 'camera.demo_camera', + 'name': 'test local' + }, + }, + 'camera': { + 'platform': 'demo' + }, + mf.DOMAIN: { + 'api_key': '12345678abcdef6', + } + } + + with assert_setup_component(1, ip.DOMAIN): + setup_component(self.hass, ip.DOMAIN, config) + + assert self.hass.states.get('image_processing.test_local') + + +class TestMicrosoftFaceDetect(object): + """Test class for image processing.""" + + def setup_method(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + self.config = { + ip.DOMAIN: { + 'platform': 'microsoft_face_detect', + 'source': { + 'entity_id': 'camera.demo_camera', + 'name': 'test local' + }, + 'attributes': ['age', 'gender'], + }, + 'camera': { + 'platform': 'demo' + }, + mf.DOMAIN: { + 'api_key': '12345678abcdef6', + } + } + + def teardown_method(self): + """Stop everything that was started.""" + self.hass.stop() + + @patch('homeassistant.components.image_processing.microsoft_face_detect.' + 'MicrosoftFaceDetectEntity.should_poll', + new_callable=PropertyMock(return_value=False)) + def test_ms_detect_process_image(self, poll_mock, aioclient_mock): + """Setup and scan a picture and test plates from event.""" + aioclient_mock.get( + mf.FACE_API_URL.format("persongroups"), + text=load_fixture('microsoft_face_persongroups.json') + ) + aioclient_mock.get( + mf.FACE_API_URL.format("persongroups/test_group1/persons"), + text=load_fixture('microsoft_face_persons.json') + ) + aioclient_mock.get( + mf.FACE_API_URL.format("persongroups/test_group2/persons"), + text=load_fixture('microsoft_face_persons.json') + ) + + setup_component(self.hass, ip.DOMAIN, self.config) + + state = self.hass.states.get('camera.demo_camera') + url = "{0}{1}".format( + self.hass.config.api.base_url, + state.attributes.get(ATTR_ENTITY_PICTURE)) + + face_events = [] + + @callback + def mock_face_event(event): + """Mock event.""" + face_events.append(event) + + self.hass.bus.listen('image_processing.detect_face', mock_face_event) + + aioclient_mock.get(url, content=b'image') + + aioclient_mock.post( + mf.FACE_API_URL.format("detect"), + text=load_fixture('microsoft_face_detect.json'), + params={'returnFaceAttributes': "age,gender"} + ) + + ip.scan(self.hass, entity_id='image_processing.test_local') + self.hass.block_till_done() + + state = self.hass.states.get('image_processing.test_local') + + assert len(face_events) == 1 + assert state.attributes.get('total_faces') == 1 + assert state.state == '1' + + assert face_events[0].data['age'] == 71.0 + assert face_events[0].data['gender'] == 'male' + assert face_events[0].data['entity_id'] == \ + 'image_processing.test_local' diff --git a/tests/components/image_processing/test_microsoft_face_identify.py b/tests/components/image_processing/test_microsoft_face_identify.py index 8d75f6ff1d3..8812c1c050e 100644 --- a/tests/components/image_processing/test_microsoft_face_identify.py +++ b/tests/components/image_processing/test_microsoft_face_identify.py @@ -106,7 +106,7 @@ class TestMicrosoftFaceIdentify(object): @patch('homeassistant.components.image_processing.microsoft_face_identify.' 'MicrosoftFaceIdentifyEntity.should_poll', new_callable=PropertyMock(return_value=False)) - def test_openalpr_process_image(self, poll_mock, aioclient_mock): + def test_ms_identify_process_image(self, poll_mock, aioclient_mock): """Setup and scan a picture and test plates from event.""" aioclient_mock.get( mf.FACE_API_URL.format("persongroups"), @@ -135,7 +135,7 @@ class TestMicrosoftFaceIdentify(object): """Mock event.""" face_events.append(event) - self.hass.bus.listen('identify_face', mock_face_event) + self.hass.bus.listen('image_processing.detect_face', mock_face_event) aioclient_mock.get(url, content=b'image') diff --git a/tests/components/image_processing/test_openalpr_cloud.py b/tests/components/image_processing/test_openalpr_cloud.py index 8e9f35eb0b2..8bce672e0d9 100644 --- a/tests/components/image_processing/test_openalpr_cloud.py +++ b/tests/components/image_processing/test_openalpr_cloud.py @@ -143,7 +143,7 @@ class TestOpenAlprCloud(object): """Mock event.""" self.alpr_events.append(event) - self.hass.bus.listen('found_plate', mock_alpr_event) + self.hass.bus.listen('image_processing.found_plate', mock_alpr_event) self.params = { 'secret_key': "sk_abcxyz123456", diff --git a/tests/components/image_processing/test_openalpr_local.py b/tests/components/image_processing/test_openalpr_local.py index 5186332661b..ffe2eadc8d6 100644 --- a/tests/components/image_processing/test_openalpr_local.py +++ b/tests/components/image_processing/test_openalpr_local.py @@ -134,7 +134,7 @@ class TestOpenAlprLocal(object): """Mock event.""" self.alpr_events.append(event) - self.hass.bus.listen('found_plate', mock_alpr_event) + self.hass.bus.listen('image_processing.found_plate', mock_alpr_event) def teardown_method(self): """Stop everything that was started.""" From 4b15946a9b252a93de9708ca787d5efd35356dc0 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 8 Feb 2017 21:11:36 +0200 Subject: [PATCH 123/157] Make sure workaround_component is not none (#5808) --- homeassistant/components/zwave/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 4268ebcd2bb..ccb4464a96b 100755 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -350,7 +350,7 @@ def setup(hass, config): value.genre, component) workaround_component = workaround.get_device_component_mapping( value) - if workaround_component != component: + if workaround_component and workaround_component != component: _LOGGER.debug("Using %s instead of %s", workaround_component, component) component = workaround_component From 061985bc65382269666fb6c2792e32be4a00906b Mon Sep 17 00:00:00 2001 From: Teemu R Date: Wed, 8 Feb 2017 21:13:07 +0100 Subject: [PATCH 124/157] Add available property and typing hints (#5593) * light.demo: add available property, add typing hints * light.demo: keep all lights available, fix init ordering * Fix issues raised during review * Update demo.py --- homeassistant/components/light/demo.py | 54 ++++++++++++++++---------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/light/demo.py b/homeassistant/components/light/demo.py index 614374ce65f..068efbbfe5f 100644 --- a/homeassistant/components/light/demo.py +++ b/homeassistant/components/light/demo.py @@ -28,19 +28,21 @@ SUPPORT_DEMO = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_EFFECT | def setup_platform(hass, config, add_devices_callback, discovery_info=None): """Setup the demo light platform.""" add_devices_callback([ - DemoLight("Bed Light", False, effect_list=LIGHT_EFFECT_LIST, + DemoLight("Bed Light", False, True, effect_list=LIGHT_EFFECT_LIST, effect=LIGHT_EFFECT_LIST[0]), - DemoLight("Ceiling Lights", True, LIGHT_COLORS[0], LIGHT_TEMPS[1]), - DemoLight("Kitchen Lights", True, LIGHT_COLORS[1], LIGHT_TEMPS[0]) + DemoLight("Ceiling Lights", True, True, + LIGHT_COLORS[0], LIGHT_TEMPS[1]), + DemoLight("Kitchen Lights", True, True, + LIGHT_COLORS[1], LIGHT_TEMPS[0]) ]) class DemoLight(Light): - """Represenation of a demo light.""" + """Representation of a demo light.""" - def __init__( - self, name, state, rgb=None, ct=None, brightness=180, - xy_color=(.5, .5), white=200, effect_list=None, effect=None): + def __init__(self, name, state, available=False, rgb=None, ct=None, + brightness=180, xy_color=(.5, .5), white=200, + effect_list=None, effect=None): """Initialize the light.""" self._name = name self._state = state @@ -53,61 +55,68 @@ class DemoLight(Light): self._effect = effect @property - def should_poll(self): + def should_poll(self) -> bool: """No polling needed for a demo light.""" return False @property - def name(self): + def name(self) -> str: """Return the name of the light if any.""" return self._name @property - def brightness(self): + def available(self) -> bool: + """Return availability.""" + # This demo light is always available, but well-behaving components + # should implement this to inform Home Assistant accordingly. + return True + + @property + def brightness(self) -> int: """Return the brightness of this light between 0..255.""" return self._brightness @property - def xy_color(self): + def xy_color(self) -> tuple: """Return the XY color value [float, float].""" return self._xy_color @property - def rgb_color(self): + def rgb_color(self) -> tuple: """Return the RBG color value.""" return self._rgb @property - def color_temp(self): + def color_temp(self) -> int: """Return the CT color temperature.""" return self._ct @property - def white_value(self): + def white_value(self) -> int: """Return the white value of this light between 0..255.""" return self._white @property - def effect_list(self): + def effect_list(self) -> list: """Return the list of supported effects.""" return self._effect_list @property - def effect(self): + def effect(self) -> str: """Return the current effect.""" return self._effect @property - def is_on(self): + def is_on(self) -> bool: """Return true if light is on.""" return self._state @property - def supported_features(self): + def supported_features(self) -> int: """Flag supported features.""" return SUPPORT_DEMO - def turn_on(self, **kwargs): + def turn_on(self, **kwargs) -> None: """Turn the light on.""" self._state = True @@ -129,9 +138,14 @@ class DemoLight(Light): if ATTR_EFFECT in kwargs: self._effect = kwargs[ATTR_EFFECT] + # As we have disabled polling, we need to inform + # Home Assistant about updates in our state ourselves. self.schedule_update_ha_state() - def turn_off(self, **kwargs): + def turn_off(self, **kwargs) -> None: """Turn the light off.""" self._state = False + + # As we have disabled polling, we need to inform + # Home Assistant about updates in our state ourselves. self.schedule_update_ha_state() From 4f20a2d3eab49d059e774e545583ea9c0d3f4730 Mon Sep 17 00:00:00 2001 From: Andreas Cambitsis Date: Wed, 8 Feb 2017 22:53:59 +0200 Subject: [PATCH 125/157] Upgrade Russound integration to v0.1.7 (#5756) * Bumped up version to use 0.1.7 of Russound integration module. Fixed bug arising from not supporting TURN_ON state (fixes issue https://github.com/home-assistant/home-assistant/issues/5012) Implemented state support in 0.1.7 such that component state is returned from the actual AMP. (Still uses polling model though). Tested it with home-assitant users @laf (original developer of the module) and @hofsta. Works fine with their Russounds. * Made styling / compliance changes and updated correct version of russound module on requirements_all.txt. * Changed handling of properties to be compliant with https://github.com/home-assistant/home-assistant/issues/4210 (Specifcailly added member variables for state, volume and source to cache these values, and introduced Update() method to set their values). Now returns None if the selected source index that is returned from russound is greater than the length of the specified source list in the yaml config. Removed unnecesary comment. * Removed blank line after docstring. * Removed updated() in class init and added True paramter to add_devices in setup_platform. * Dropped the no longer needed self.update() --- .../components/media_player/russound_rnet.py | 68 ++++++++++++++----- requirements_all.txt | 2 +- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/media_player/russound_rnet.py b/homeassistant/components/media_player/russound_rnet.py index 64042f4633d..7ae16adcce3 100644 --- a/homeassistant/components/media_player/russound_rnet.py +++ b/homeassistant/components/media_player/russound_rnet.py @@ -4,20 +4,20 @@ Support for interfacing with Russound via RNET Protocol. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/media_player.russound_rnet/ """ -import logging +import logging import voluptuous as vol from homeassistant.components.media_player import ( - SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, - SUPPORT_SELECT_SOURCE, SUPPORT_PLAY, MediaPlayerDevice, PLATFORM_SCHEMA) + SUPPORT_TURN_ON, SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, + SUPPORT_SELECT_SOURCE, MediaPlayerDevice, PLATFORM_SCHEMA) from homeassistant.const import ( CONF_HOST, CONF_PORT, STATE_OFF, STATE_ON, CONF_NAME) import homeassistant.helpers.config_validation as cv REQUIREMENTS = [ - 'https://github.com/laf/russound/archive/0.1.6.zip' - '#russound==0.1.6'] + 'https://github.com/laf/russound/archive/0.1.7.zip' + '#russound==0.1.7'] _LOGGER = logging.getLogger(__name__) @@ -25,7 +25,7 @@ CONF_ZONES = 'zones' CONF_SOURCES = 'sources' SUPPORT_RUSSOUND = SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | \ - SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE | SUPPORT_PLAY + SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE ZONE_SCHEMA = vol.Schema({ vol.Required(CONF_NAME): cv.string, @@ -48,7 +48,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Russound RNET platform.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) - keypad = config.get('keypad', '70') if host is None or port is None: _LOGGER.error("Invalid config. Expected %s and %s", @@ -58,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): from russound import russound russ = russound.Russound(host, port) - russ.connect(keypad) + russ.connect() sources = [] for source in config[CONF_SOURCES]: @@ -67,7 +66,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if russ.is_connected(): for zone_id, extra in config[CONF_ZONES].items(): add_devices([RussoundRNETDevice( - hass, russ, sources, zone_id, extra)]) + hass, russ, sources, zone_id, extra)], True) else: _LOGGER.error('Not connected to %s:%s', host, port) @@ -79,10 +78,32 @@ class RussoundRNETDevice(MediaPlayerDevice): """Initialise the Russound RNET device.""" self._name = extra['name'] self._russ = russ - self._state = STATE_OFF self._sources = sources self._zone_id = zone_id - self._volume = 0 + + self._state = None + self._volume = None + self._source = None + + def update(self): + """Retrieve latest state.""" + if self._russ.get_power('1', self._zone_id) == 0: + self._state = STATE_OFF + else: + self._state = STATE_ON + + self._volume = self._russ.get_volume('1', self._zone_id) / 100.0 + + # Returns 0 based index for source. + index = self._russ.get_source('1', self._zone_id) + # Possibility exists that user has defined list of all sources. + # If a source is set externally that is beyond the defined list then + # an exception will be thrown. + # In this case return and unknown source (None) + try: + self._source = self._sources[index] + except IndexError: + self._source = None @property def name(self): @@ -99,25 +120,35 @@ class RussoundRNETDevice(MediaPlayerDevice): """Flag media player features that are supported.""" return SUPPORT_RUSSOUND + @property + def source(self): + """Get the currently selected source.""" + return self._source + @property def volume_level(self): - """Volume level of the media player (0..1).""" + """Volume level of the media player (0..1). + + Value is returned based on a range (0..100). + Therefore float divide by 100 to get to the required range. + """ return self._volume def set_volume_level(self, volume): - """Set volume level, range 0..1.""" - self._volume = volume * 100 - self._russ.set_volume('1', self._zone_id, self._volume) + """Set volume level. Volume has a range (0..1). + + Translate this to a range of (0..100) as expected expected + by _russ.set_volume() + """ + self._russ.set_volume('1', self._zone_id, volume * 100) def turn_on(self): """Turn the media player on.""" self._russ.set_power('1', self._zone_id, '1') - self._state = STATE_ON def turn_off(self): """Turn off media player.""" self._russ.set_power('1', self._zone_id, '0') - self._state = STATE_OFF def mute_volume(self, mute): """Send mute command.""" @@ -126,7 +157,8 @@ class RussoundRNETDevice(MediaPlayerDevice): def select_source(self, source): """Set the input source.""" if source in self._sources: - index = self._sources.index(source)+1 + index = self._sources.index(source) + # 0 based value for source self._russ.set_source('1', self._zone_id, index) @property diff --git a/requirements_all.txt b/requirements_all.txt index e93a4565ae3..3f267095551 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -236,7 +236,7 @@ https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad591540925 https://github.com/joopert/nad_receiver/archive/0.0.3.zip#nad_receiver==0.0.3 # homeassistant.components.media_player.russound_rnet -https://github.com/laf/russound/archive/0.1.6.zip#russound==0.1.6 +https://github.com/laf/russound/archive/0.1.7.zip#russound==0.1.7 # homeassistant.components.switch.anel_pwrctrl https://github.com/mweinelt/anel-pwrctrl/archive/ed26e8830e28a2bfa4260a9002db23ce3e7e63d7.zip#anel_pwrctrl==0.0.1 From 612aa1cf21a2df4bff7db9a007e4a362eb57a937 Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Wed, 8 Feb 2017 23:16:39 +0200 Subject: [PATCH 126/157] Initial (#5811) --- homeassistant/components/recorder/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 6577d4af91d..dba5f25b956 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -118,10 +118,12 @@ def run_information(point_in_time: Optional[datetime]=None): start=_INSTANCE.recording_start, closed_incorrect=False) - with session_scope(): - return query('RecorderRuns').filter( + with session_scope() as session: + res = query(recorder_runs).filter( (recorder_runs.start < point_in_time) & (recorder_runs.end > point_in_time)).first() + session.expunge(res) + return res def setup(hass: HomeAssistant, config: ConfigType) -> bool: From d29b7f691075441ab52bcd90dad423a25d00b8e0 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 8 Feb 2017 23:18:23 +0100 Subject: [PATCH 127/157] Ffmpeg update 1.4 (#5813) * Pump ffmpeg version * update entity * next 1.4 --- homeassistant/components/ffmpeg.py | 9 ++++++++- requirements_all.txt | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/ffmpeg.py b/homeassistant/components/ffmpeg.py index 2bcc8932ae0..64a81687fd3 100644 --- a/homeassistant/components/ffmpeg.py +++ b/homeassistant/components/ffmpeg.py @@ -18,7 +18,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity DOMAIN = 'ffmpeg' -REQUIREMENTS = ["ha-ffmpeg==1.2"] +REQUIREMENTS = ["ha-ffmpeg==1.4"] _LOGGER = logging.getLogger(__name__) @@ -107,6 +107,13 @@ def async_setup(hass, config): if tasks: yield from asyncio.wait(tasks, loop=hass.loop) + tasks.clear() + for device in devices: + tasks.append(device.async_update_ha_state()) + + if tasks: + yield from asyncio.wait(tasks, loop=hass.loop) + hass.services.async_register( DOMAIN, SERVICE_START, async_service_handle, descriptions[DOMAIN].get(SERVICE_START), schema=SERVICE_FFMPEG_SCHEMA) diff --git a/requirements_all.txt b/requirements_all.txt index 3f267095551..7e75d925af2 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -180,7 +180,7 @@ googlemaps==2.4.4 gps3==0.33.3 # homeassistant.components.ffmpeg -ha-ffmpeg==1.2 +ha-ffmpeg==1.4 # homeassistant.components.media_player.philips_js ha-philipsjs==0.0.1 From 76db4cc09919a9cffaebd87d358676338929b605 Mon Sep 17 00:00:00 2001 From: Teagan Glenn Date: Wed, 8 Feb 2017 20:55:48 -0700 Subject: [PATCH 128/157] Change medium state for filtering (#5817) --- homeassistant/components/fan/isy994.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/fan/isy994.py b/homeassistant/components/fan/isy994.py index 30c1d2ed2a3..f8c7b2e867d 100644 --- a/homeassistant/components/fan/isy994.py +++ b/homeassistant/components/fan/isy994.py @@ -29,7 +29,7 @@ STATE_TO_VALUE = {} for key in VALUE_TO_STATE: STATE_TO_VALUE[VALUE_TO_STATE[key]] = key -STATES = [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] +STATES = [SPEED_OFF, SPEED_LOW, 'med', SPEED_HIGH] # pylint: disable=unused-argument From 49f254073082824caf8583939975397ad9d3190e Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Wed, 8 Feb 2017 22:56:44 -0500 Subject: [PATCH 129/157] Enhancements to ARWN platform (#5816) * Fix arwn platform discover_sensors The discover_sensors function can return either singletons or a list of sensors. However the consumer was always expecting a list. This fixes it to work in both cases. * Add custom icons to arwn sensors. This adds some custom icons for different kinds of weather sensors that the arwn platform returns. Makes it a little easier to see what's going on. --- homeassistant/components/sensor/arwn.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/sensor/arwn.py b/homeassistant/components/sensor/arwn.py index c0012b4ac92..834efa1b415 100644 --- a/homeassistant/components/sensor/arwn.py +++ b/homeassistant/components/sensor/arwn.py @@ -35,11 +35,12 @@ def discover_sensors(topic, payload): unit = TEMP_CELSIUS return ArwnSensor(name, 'temp', unit) if domain == 'barometer': - return ArwnSensor('Barometer', 'pressure', unit) + return ArwnSensor('Barometer', 'pressure', unit, + "mdi:thermometer-lines") if domain == 'wind': - return (ArwnSensor('Wind Speed', 'speed', unit), - ArwnSensor('Wind Gust', 'gust', unit), - ArwnSensor('Wind Direction', 'direction', '°')) + return (ArwnSensor('Wind Speed', 'speed', unit, "mdi:speedometer"), + ArwnSensor('Wind Gust', 'gust', unit, "mdi:speedometer"), + ArwnSensor('Wind Direction', 'direction', '°', "mdi:compass")) def _slug(name): @@ -66,6 +67,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not sensors: return + if isinstance(sensors, ArwnSensor): + sensors = (sensors, ) + if 'timestamp' in event: del event['timestamp'] @@ -88,7 +92,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class ArwnSensor(Entity): """Representation of an ARWN sensor.""" - def __init__(self, name, state_key, units): + def __init__(self, name, state_key, units, icon=None): """Initialize the sensor.""" self.hass = None self.entity_id = _slug(name) @@ -96,6 +100,7 @@ class ArwnSensor(Entity): self._state_key = state_key self.event = {} self._unit_of_measurement = units + self._icon = icon def set_event(self, event): """Update the sensor with the most recent event.""" @@ -126,3 +131,11 @@ class ArwnSensor(Entity): def should_poll(self): """Should we poll.""" return False + + @property + def icon(self): + """Icon of device based on its type.""" + if self._icon: + return self._icon + else: + return super().icon From 628b169393e9e442aa9c2d32b4cbc3441a4f8b5f Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Wed, 8 Feb 2017 22:57:58 -0500 Subject: [PATCH 130/157] Fixed call to object_id() (#5814) --- homeassistant/components/lock/wink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/lock/wink.py b/homeassistant/components/lock/wink.py index 09b3a673f2d..76922cf9d62 100644 --- a/homeassistant/components/lock/wink.py +++ b/homeassistant/components/lock/wink.py @@ -16,7 +16,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import pywink for lock in pywink.get_locks(): - _id = lock.object_id + lock.name() + _id = lock.object_id() + lock.name() if _id not in hass.data[DOMAIN]['unique_ids']: add_devices([WinkLockDevice(lock, hass)]) From 415500de2380dc20314594da536d804f47b9e768 Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Thu, 9 Feb 2017 05:58:43 +0200 Subject: [PATCH 131/157] [recorder] Protect against running in the event loop (#5812) --- homeassistant/components/recorder/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index dba5f25b956..14b9fe11574 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -89,6 +89,8 @@ def execute(qry: QueryType) -> List[Any]: This method also retries a few times in the case of stale connections. """ + _verify_instance() + import sqlalchemy.exc with session_scope() as session: for _ in range(0, RETRIES): @@ -152,6 +154,7 @@ def setup(hass: HomeAssistant, config: ConfigType) -> bool: def query(model_name: Union[str, Any], *args) -> QueryType: """Helper to return a query handle.""" _verify_instance() + if isinstance(model_name, str): return _SESSION().query(get_model(model_name), *args) return _SESSION().query(model_name, *args) @@ -481,4 +484,9 @@ def _verify_instance() -> None: """Throw error if recorder not initialized.""" if _INSTANCE is None: raise RuntimeError("Recorder not initialized.") + + ident = _INSTANCE.hass.loop.__dict__.get("_thread_ident") + if ident is not None and ident == threading.get_ident(): + raise RuntimeError('Cannot be called from within the event loop') + _INSTANCE.block_till_db_ready() From fdcf5fe233c9752a7a8a836a321122566ef9118c Mon Sep 17 00:00:00 2001 From: John Arild Berentsen Date: Thu, 9 Feb 2017 04:59:47 +0100 Subject: [PATCH 132/157] Bugfixes (#5740) * wrong data for lock alarm_type * missing whitespace * Not possible to set codes starting with 0 --- homeassistant/components/lock/zwave.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/lock/zwave.py b/homeassistant/components/lock/zwave.py index 1f5f2ca8b15..5bec21d5ea6 100644 --- a/homeassistant/components/lock/zwave.py +++ b/homeassistant/components/lock/zwave.py @@ -14,6 +14,7 @@ import voluptuous as vol from homeassistant.components.lock import DOMAIN, LockDevice from homeassistant.components import zwave from homeassistant.config import load_yaml_config_file +import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -49,7 +50,7 @@ LOCK_NOTIFICATION = { LOCK_ALARM_TYPE = { 9: 'Deadbolt Jammed', - 18: 'Locked with Keypad by user', + 18: 'Locked with Keypad by user ', 19: 'Unlocked with Keypad by user ', 21: 'Manually Locked by', 22: 'Manually Unlocked by Key or Inside thumb turn', @@ -104,7 +105,7 @@ ALARM_TYPE_STD = [ SET_USERCODE_SCHEMA = vol.Schema({ vol.Required(zwave.const.ATTR_NODE_ID): vol.Coerce(int), vol.Required(ATTR_CODE_SLOT): vol.Coerce(int), - vol.Required(ATTR_USERCODE): vol.Coerce(int), + vol.Required(ATTR_USERCODE): cv.string, }) GET_USERCODE_SCHEMA = vol.Schema({ @@ -268,7 +269,7 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice): class_id=zwave.const.COMMAND_CLASS_ALARM).values(): if value.label != "Alarm Type": continue - alarm_type = LOCK_ALARM_TYPE.get(value.data) + alarm_type = value.data break for value in self._node.get_values( From 7fa08059dc944626241b7a1b1d1f0d5a3be874cb Mon Sep 17 00:00:00 2001 From: Duoxilian Date: Thu, 9 Feb 2017 05:04:09 +0100 Subject: [PATCH 133/157] Support away_mode as permanent hold and hold_mode as temporary hold. (#5725) * Support away_mode as permanent hold and hold_mode as temporary hold. * Add comments to explain code better. Remove indefinite hold preference to be consistent with 'away_mode'. --- homeassistant/components/climate/__init__.py | 4 -- homeassistant/components/climate/ecobee.py | 60 ++++++++++---------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index efc50b1af2f..cb684785207 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -122,8 +122,6 @@ def set_away_mode(hass, away_mode, entity_id=None): if entity_id: data[ATTR_ENTITY_ID] = entity_id - _LOGGER.warning( - 'This service has been deprecated; use climate.set_hold_mode') hass.services.call(DOMAIN, SERVICE_SET_AWAY_MODE, data) @@ -243,8 +241,6 @@ def async_setup(hass, config): away_mode = service.data.get(ATTR_AWAY_MODE) - _LOGGER.warning( - 'This service has been deprecated; use climate.set_hold_mode') for climate in target_climate: if away_mode: yield from climate.async_turn_away_mode_on() diff --git a/homeassistant/components/climate/ecobee.py b/homeassistant/components/climate/ecobee.py index cdd8bc98169..18ccff459b0 100644 --- a/homeassistant/components/climate/ecobee.py +++ b/homeassistant/components/climate/ecobee.py @@ -186,12 +186,27 @@ class Thermostat(ClimateDevice): @property def current_hold_mode(self): """Return current hold mode.""" - if self.is_away_mode_on: + events = self.thermostat['events'] + if any((event['holdClimateRef'] == 'away' and + int(event['endDate'][0:4])-int(event['startDate'][0:4]) <= 1) + or event['type'] == 'autoAway' + for event in events): + # away hold is auto away or a temporary hold from away climate hold = 'away' - elif self.is_home_mode_on: + elif any(event['holdClimateRef'] == 'away' and + int(event['endDate'][0:4])-int(event['startDate'][0:4]) > 1 + for event in events): + # a permanent away is not considered a hold, but away_mode + hold = None + elif any(event['holdClimateRef'] == 'home' or + event['type'] == 'autoHome' + for event in events): + # home mode is auto home or any home hold hold = 'home' - elif self.is_temp_hold_on(): + elif any(event['type'] == 'hold' and event['running'] + for event in events): hold = 'temp' + # temperature hold is any other hold not based on climate else: hold = None return hold @@ -255,42 +270,23 @@ class Thermostat(ClimateDevice): return any(event['type'] == 'vacation' and event['running'] for event in events) - def is_temp_hold_on(self): - """Return true if temperature hold is on.""" - events = self.thermostat['events'] - return any(event['type'] == 'hold' and event['running'] - for event in events) - @property def is_away_mode_on(self): """Return true if away mode is on.""" events = self.thermostat['events'] - return any(event['holdClimateRef'] == 'away' or - event['type'] == 'autoAway' + return any(event['holdClimateRef'] == 'away' and + int(event['endDate'][0:4])-int(event['startDate'][0:4]) > 1 for event in events) def turn_away_mode_on(self): """Turn away on.""" self.data.ecobee.set_climate_hold(self.thermostat_index, - "away", self.hold_preference()) + "away", 'indefinite') self.update_without_throttle = True def turn_away_mode_off(self): """Turn away off.""" - self.set_hold_mode(None) - - @property - def is_home_mode_on(self): - """Return true if home mode is on.""" - events = self.thermostat['events'] - return any(event['holdClimateRef'] == 'home' or - event['type'] == 'autoHome' - for event in events) - - def turn_home_mode_on(self): - """Turn home on.""" - self.data.ecobee.set_climate_hold(self.thermostat_index, - "home", self.hold_preference()) + self.data.ecobee.resume_program(self.thermostat_index) self.update_without_throttle = True def set_hold_mode(self, hold_mode): @@ -298,11 +294,14 @@ class Thermostat(ClimateDevice): hold = self.current_hold_mode if hold == hold_mode: + # no change, so no action required return elif hold_mode == 'away': - self.turn_away_mode_on() + self.data.ecobee.set_climate_hold(self.thermostat_index, + "away", self.hold_preference()) elif hold_mode == 'home': - self.turn_home_mode_on() + self.data.ecobee.set_climate_hold(self.thermostat_index, + "home", self.hold_preference()) elif hold_mode == 'temp': self.set_temp_hold(int(self.current_temperature)) else: @@ -378,7 +377,8 @@ class Thermostat(ClimateDevice): default = self.thermostat['settings']['holdAction'] if default == 'nextTransition': return default - elif default == 'indefinite': - return default + # add further conditions if other hold durations should be + # supported; note that this should not include 'indefinite' + # as an indefinite away hold is interpreted as away_mode else: return 'nextTransition' From 03fe5b04b5be86f2f69377bcf36a2938de9b7dd3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 8 Feb 2017 20:31:36 -0800 Subject: [PATCH 134/157] Remove non-working webfont preload (#5819) --- homeassistant/components/frontend/templates/index.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/homeassistant/components/frontend/templates/index.html b/homeassistant/components/frontend/templates/index.html index 05e33dc5dcc..4b1aa2033ea 100644 --- a/homeassistant/components/frontend/templates/index.html +++ b/homeassistant/components/frontend/templates/index.html @@ -10,9 +10,6 @@ href='/static/icons/favicon-apple-180x180.png'> - - - {% for panel in panels.values() -%} {% endfor -%} From ebceca36ec3a91e56e46cf0768f6b67720eefcf8 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 8 Feb 2017 20:55:15 -0800 Subject: [PATCH 135/157] Update frontend (#5820) --- .../components/frontend/templates/index.html | 17 +++++++++++------ homeassistant/components/frontend/version.py | 6 +++--- .../frontend/www_static/frontend.html | 8 ++++---- .../frontend/www_static/frontend.html.gz | Bin 137578 -> 138154 bytes .../www_static/home-assistant-polymer | 2 +- .../components/frontend/www_static/mdi.html | 2 +- .../frontend/www_static/mdi.html.gz | Bin 188451 -> 188917 bytes .../panels/ha-panel-dev-template.html | 2 +- .../panels/ha-panel-dev-template.html.gz | Bin 7368 -> 7370 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2336 -> 2338 bytes .../www_static/webcomponents-lite.min.js | 2 +- .../www_static/webcomponents-lite.min.js.gz | Bin 12360 -> 12360 bytes 13 files changed, 23 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/frontend/templates/index.html b/homeassistant/components/frontend/templates/index.html index 4b1aa2033ea..858afc696b6 100644 --- a/homeassistant/components/frontend/templates/index.html +++ b/homeassistant/components/frontend/templates/index.html @@ -25,7 +25,7 @@
- Home Assistant had trouble
connecting to the server.

TRY AGAIN + Home Assistant had trouble
connecting to the server.

+ TRY AGAIN
diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 0394bc0b674..4f8b6aed2d0 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,14 +2,14 @@ FINGERPRINTS = { "core.js": "adfeb513cf650acf763e284d76a48d6b", - "frontend.html": "eb9d6679ac0d1b79067949a827aed992", - "mdi.html": "7a0f14bbf3822449f9060b9c53bd7376", + "frontend.html": "ae96f5256a562f35a652f31560a3b550", + "mdi.html": "c1dde43ccf5667f687c418fc8daf9668", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", "panels/ha-panel-dev-info.html": "0469024d94d6270a8680df2be44ba916", "panels/ha-panel-dev-service.html": "9f749635e518a4ca7991975bdefdb10a", "panels/ha-panel-dev-state.html": "7d069ba8fd5379fa8f59858b8c0a7473", - "panels/ha-panel-dev-template.html": "97f77b69faef8c5975c09431912831cc", + "panels/ha-panel-dev-template.html": "2b618508510afa5281c9ecae0c3a3dbd", "panels/ha-panel-history.html": "8955c1d093a2c417c89ed90dd627c7d3", "panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab", "panels/ha-panel-logbook.html": "f36297a894524518fa70883f264492b0", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index ae60e2c736d..70a7063556b 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -1,7 +1,7 @@ - \ No newline at end of file + clear: both;white-space:pre-wrap}.rendered.error{color:red}
Templates

Templates are rendered using the Jinja2 template engine with some Home Assistant specific extensions.

[[processed]]
\ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html.gz index c1d37f78c05be8f807b3053deecfc1aadc4f652f..1e281bb5322c474bc58d6e860cc9ccb9653555f1 100644 GIT binary patch delta 51 zcmV-30L=f$Im$T)ABzYGk@cIg2caAyREi`IS8`(*m~t8)rs~^%w)`hVM)XgP{2y%g Jj?8&v000`773Tl| delta 49 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[34,35,60,62,63,96].indexOf(t)==-1?e:encodeURIComponent(e)}function i(e){var t=e.charCodeAt(0);return t>32&&t<127&&[34,35,60,62,96].indexOf(t)==-1?e:encodeURIComponent(e)}function a(e,a,s){function c(e){g.push(e)}var d=a||"scheme start",l=0,u="",w=!1,_=!1,g=[];e:for(;(e[l-1]!=p||0==l)&&!this._isInvalid;){var b=e[l];switch(d){case"scheme start":if(!b||!m.test(b)){if(a){c("Invalid scheme.");break e}u="",d="no scheme";continue}u+=b.toLowerCase(),d="scheme";break;case"scheme":if(b&&v.test(b))u+=b.toLowerCase();else{if(":"!=b){if(a){if(p==b)break e;c("Code point not allowed in scheme: "+b);break e}u="",l=0,d="no scheme";continue}if(this._scheme=u,u="",a)break e;t(this._scheme)&&(this._isRelative=!0),d="file"==this._scheme?"relative":this._isRelative&&s&&s._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==b?(this._query="?",d="query"):"#"==b?(this._fragment="#",d="fragment"):p!=b&&"\t"!=b&&"\n"!=b&&"\r"!=b&&(this._schemeData+=r(b));break;case"no scheme":if(s&&t(s._scheme)){d="relative";continue}c("Missing scheme."),n.call(this);break;case"relative or authority":if("/"!=b||"/"!=e[l+1]){c("Expected /, got: "+b),d="relative";continue}d="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=s._scheme),p==b){this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._username=s._username,this._password=s._password;break e}if("/"==b||"\\"==b)"\\"==b&&c("\\ is an invalid code point."),d="relative slash";else if("?"==b)this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query="?",this._username=s._username,this._password=s._password,d="query";else{if("#"!=b){var y=e[l+1],E=e[l+2];("file"!=this._scheme||!m.test(b)||":"!=y&&"|"!=y||p!=E&&"/"!=E&&"\\"!=E&&"?"!=E&&"#"!=E)&&(this._host=s._host,this._port=s._port,this._username=s._username,this._password=s._password,this._path=s._path.slice(),this._path.pop()),d="relative path";continue}this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._fragment="#",this._username=s._username,this._password=s._password,d="fragment"}break;case"relative slash":if("/"!=b&&"\\"!=b){"file"!=this._scheme&&(this._host=s._host,this._port=s._port,this._username=s._username,this._password=s._password),d="relative path";continue}"\\"==b&&c("\\ is an invalid code point."),d="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=b){c("Expected '/', got: "+b),d="authority ignore slashes";continue}d="authority second slash";break;case"authority second slash":if(d="authority ignore slashes","/"!=b){c("Expected '/', got: "+b);continue}break;case"authority ignore slashes":if("/"!=b&&"\\"!=b){d="authority";continue}c("Expected authority, got: "+b);break;case"authority":if("@"==b){w&&(c("@ already seen."),u+="%40"),w=!0;for(var L=0;L>>0)+(t++ +"__")};n.prototype={set:function(t,n){var o=t[this.name];return o&&o[0]===t?o[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return!(!t||t[0]!==e)&&(t[0]=t[1]=void 0,!0)},has:function(e){var t=e[this.name];return!!t&&t[0]===e}},window.WeakMap=n}(),function(e){function t(e){b.push(e),g||(g=!0,m(o))}function n(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function o(){g=!1;var e=b;b=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var n=e.takeRecords();r(e),n.length&&(e.callback_(n,e),t=!0)}),t&&o()}function r(e){e.nodes_.forEach(function(t){var n=v.get(t);n&&n.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var n=e;n;n=n.parentNode){var o=v.get(n);if(o)for(var r=0;r0){var r=n[o-1],i=f(r,e);if(i)return void(n[o-1]=i)}else t(this.observer);n[o]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),n=0;n":return">";case" ":return" "}}function t(t){return t.replace(u,e)}var n="undefined"==typeof HTMLTemplateElement;/Trident/.test(navigator.userAgent)&&!function(){var e=document.importNode;document.importNode=function(){var t=e.apply(document,arguments);if(t.nodeType===Node.DOCUMENT_FRAGMENT_NODE){var n=document.createDocumentFragment();return n.appendChild(t),n}return t}}();var o=function(){if(!n){var e=document.createElement("template"),t=document.createElement("template");t.content.appendChild(document.createElement("div")),e.content.appendChild(t);var o=e.cloneNode(!0);return 0===o.content.childNodes.length||0===o.content.firstChild.content.childNodes.length}}(),r="template",i=function(){};if(n){var a=document.implementation.createHTMLDocument("template"),s=!0,c=document.createElement("style");c.textContent=r+"{display:none;}";var d=document.head;d.insertBefore(c,d.firstElementChild),i.prototype=Object.create(HTMLElement.prototype),i.decorate=function(e){if(!e.content){e.content=a.createDocumentFragment();for(var n;n=e.firstChild;)e.content.appendChild(n);if(e.cloneNode=function(e){return i.cloneNode(this,e)},s)try{Object.defineProperty(e,"innerHTML",{get:function(){for(var e="",n=this.content.firstChild;n;n=n.nextSibling)e+=n.outerHTML||t(n.data);return e},set:function(e){for(a.body.innerHTML=e,i.bootstrap(a);this.content.firstChild;)this.content.removeChild(this.content.firstChild);for(;a.body.firstChild;)this.content.appendChild(a.body.firstChild)},configurable:!0})}catch(o){s=!1}i.bootstrap(e.content)}},i.bootstrap=function(e){for(var t,n=e.querySelectorAll(r),o=0,a=n.length;o]/g}if(n||o){var h=Node.prototype.cloneNode;i.cloneNode=function(e,t){var n=h.call(e,!1);return this.decorate&&this.decorate(n),t&&(n.content.appendChild(h.call(e.content,!0)),this.fixClonedDom(n.content,e.content)),n},i.fixClonedDom=function(e,t){if(t.querySelectorAll)for(var n,o,i=t.querySelectorAll(r),a=e.querySelectorAll(r),s=0,c=a.length;s=200&&e.status<300||304===e.status||0===e.status},load:function(n,o,r){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(e){if(4===i.readyState){var n=null;try{var a=i.getResponseHeader("Location");a&&(n="/"===a.substr(0,1)?location.origin+a:a)}catch(e){console.error(e.message)}o.call(r,!t.ok(i)&&i,i.response||i.responseText,n)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),window.HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,o=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};o.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,o=e.length;n-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,o,null,a)}.bind(this),0)}else{var s=function(t,n,r){this.receive(e,o,t,n,r)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,o,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,o,r){this.cache[e]=o;for(var i,a=this.pending[e],s=0,c=a.length;s=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(e["import"]=e.__doc,window.HTMLImports.__importsParsingHook&&window.HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.__resource&&!e.__error?e.dispatchEvent(new CustomEvent("load",{bubbles:!1})):e.dispatchEvent(new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),t.__appliedElement=e,e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,o=function(r){e.removeEventListener("load",o),e.removeEventListener("error",o),t&&t(r),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",o),e.addEventListener("error",o),d&&"style"===e.localName){var r=!1;if(e.textContent.indexOf("@import")==-1)r=!0;else if(e.sheet){r=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;c=0},hasResource:function(e){return!t(e)||void 0!==e.__doc}};e.parser=h,e.IMPORT_SELECTOR=u}),window.HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function o(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function r(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var r=n.createElement("base");r.setAttribute("href",t),n.baseURI||o(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(r),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,c=e.rootDocument,d=e.Loader,l=e.Observer,u=e.parser,h={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){f.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);f.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===c?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,o,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=o,n.__error=a,t(n)){var c=this.documents[e];void 0===c&&(c=a?null:r(o,s||e),c&&(c.__importLink=n,this.bootDocument(c)),this.documents[e]=c),n.__doc=c}u.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),u.parseNext()},loadedAll:function(){u.parseNext()}},f=new d(h.loaded.bind(h),h.loadedAll.bind(h));if(h.observer=new l,!document.baseURI){var p={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",p),Object.defineProperty(c,"baseURI",p)}e.importer=h,e.importLoader=f}),window.HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,o={added:function(e){for(var o,r,i,a,s=0,c=e.length;s=0)){n.push(e);for(var o,r=e.querySelectorAll("link[rel="+a+"]"),s=0,c=r.length;s=0&&g(o,HTMLElement),o)}function p(e,t){var n=e[t];e[t]=function(){var e=n.apply(this,arguments);return w(e),e}}var m,v=(e.isIE,e.upgradeDocumentTree),w=e.upgradeAll,_=e.upgradeWithDefinition,g=e.implementPrototype,b=e.useNative,y=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],E={},L="http://www.w3.org/1999/xhtml",N=document.createElement.bind(document),M=document.createElementNS.bind(document);m=Object.__proto__||b?function(e,t){return e instanceof t}:function(e,t){if(e instanceof t)return!0;for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},p(Node.prototype,"cloneNode"),p(document,"importNode"),document.registerElement=t,document.createElement=f,document.createElementNS=h,e.registry=E,e["instanceof"]=m,e.reservedTagList=y,e.getRegisteredDefinition=d,document.register=document.registerElement}),function(e){function t(){i(window.wrap(document)),window.CustomElements.ready=!0;var e=window.requestAnimationFrame||function(e){setTimeout(e,16)};e(function(){setTimeout(function(){window.CustomElements.readyTime=Date.now(),window.HTMLImports&&(window.CustomElements.elapsed=window.CustomElements.readyTime-window.HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})})}var n=e.useNative,o=e.initializeModules;e.isIE;if(n){var r=function(){};e.watchShadow=r,e.upgrade=r,e.upgradeAll=r,e.upgradeDocumentTree=r,e.upgradeSubtree=r,e.takeRecords=r,e["instanceof"]=function(e,t){return e instanceof t}}else o();var i=e.upgradeDocumentTree,a=e.upgradeDocument;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=window.ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=window.ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),window.HTMLImports&&(window.HTMLImports.__importsParsingHook=function(e){e["import"]&&a(wrap(e["import"]))}),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!window.HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t()}(window.CustomElements),function(e){var t=document.createElement("style");t.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var n=document.querySelector("head");n.insertBefore(t,n.firstChild)}(window.WebComponents); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/webcomponents-lite.min.js.gz b/homeassistant/components/frontend/www_static/webcomponents-lite.min.js.gz index c5fe12d2303e5b2d7e1f40f018bf774b42f15b6d..28fff2c7c34655c16aec96ee5dfc232ec5ed6631 100644 GIT binary patch delta 32 ocmX?+a3X+pVYX> Date: Wed, 8 Feb 2017 21:27:36 -0800 Subject: [PATCH 136/157] Upgrade aiohttp to 1.3 (#5821) --- requirements_all.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements_all.txt b/requirements_all.txt index 7e75d925af2..12aaaab9666 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -6,7 +6,7 @@ pip>=7.0.0 jinja2>=2.8 voluptuous==0.9.3 typing>=3,<4 -aiohttp==1.2 +aiohttp==1.3 async_timeout==1.1.0 # homeassistant.components.nuimo_controller diff --git a/setup.py b/setup.py index 4f223eb9b8a..b9d5d3460fb 100755 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ REQUIRES = [ 'jinja2>=2.8', 'voluptuous==0.9.3', 'typing>=3,<4', - 'aiohttp==1.2', + 'aiohttp==1.3', 'async_timeout==1.1.0', ] From 2cbed9cd96df0fee659c3680c94eab1781e42b83 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 9 Feb 2017 06:58:45 +0100 Subject: [PATCH 137/157] Move signal handling out of core to bootstrap (#5815) * Move signal handling out of core to bootstrap * Fix tests --- .coveragerc | 1 + homeassistant/bootstrap.py | 2 ++ homeassistant/core.py | 21 +-------------------- homeassistant/helpers/signal.py | 31 +++++++++++++++++++++++++++++++ tests/common.py | 3 +-- tests/helpers/test_discovery.py | 3 ++- tests/test_bootstrap.py | 9 ++++++--- 7 files changed, 44 insertions(+), 26 deletions(-) create mode 100644 homeassistant/helpers/signal.py diff --git a/.coveragerc b/.coveragerc index 2f1b0d1e857..9de3b6f8cf6 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,6 +5,7 @@ omit = homeassistant/__main__.py homeassistant/scripts/*.py homeassistant/helpers/typing.py + homeassistant/helpers/signal.py # omit pieces of code that rely on external devices being present homeassistant/components/apcupsd.py diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 0c8b0bc688e..87fd9f7d9e5 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -26,6 +26,7 @@ from homeassistant.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import ( event_decorators, service, config_per_platform, extract_domain_configs) +from homeassistant.helpers.signal import async_register_signal_handling _LOGGER = logging.getLogger(__name__) @@ -435,6 +436,7 @@ def async_from_config_dict(config: Dict[str, Any], yield from hass.async_stop_track_tasks() + async_register_signal_handling(hass) return hass diff --git a/homeassistant/core.py b/homeassistant/core.py index db186fb1b1c..5bede3da7a6 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -11,7 +11,6 @@ import enum import logging import os import re -import signal import sys import threading @@ -26,7 +25,7 @@ from homeassistant.const import ( ATTR_SERVICE_CALL_ID, ATTR_SERVICE_DATA, EVENT_CALL_SERVICE, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_SERVICE_EXECUTED, EVENT_SERVICE_REGISTERED, EVENT_STATE_CHANGED, - EVENT_TIME_CHANGED, MATCH_ALL, RESTART_EXIT_CODE, __version__) + EVENT_TIME_CHANGED, MATCH_ALL, __version__) from homeassistant.exceptions import ( HomeAssistantError, InvalidEntityFormatError, ShuttingDown) from homeassistant.util.async import ( @@ -150,24 +149,6 @@ class HomeAssistant(object): _LOGGER.info("Starting Home Assistant") self.state = CoreState.starting - # Setup signal handling - if sys.platform != 'win32': - def _async_signal_handle(exit_code): - """Wrap signal handling.""" - self.async_add_job(self.async_stop(exit_code)) - - try: - self.loop.add_signal_handler( - signal.SIGTERM, _async_signal_handle, 0) - except ValueError: - _LOGGER.warning("Could not bind to SIGTERM") - - try: - self.loop.add_signal_handler( - signal.SIGHUP, _async_signal_handle, RESTART_EXIT_CODE) - except ValueError: - _LOGGER.warning("Could not bind to SIGHUP") - # pylint: disable=protected-access self.loop._thread_ident = threading.get_ident() _async_create_timer(self) diff --git a/homeassistant/helpers/signal.py b/homeassistant/helpers/signal.py new file mode 100644 index 00000000000..de4c344d375 --- /dev/null +++ b/homeassistant/helpers/signal.py @@ -0,0 +1,31 @@ +"""Signal handling related helpers.""" +import logging +import signal +import sys + +from homeassistant.core import callback +from homeassistant.const import RESTART_EXIT_CODE + +_LOGGER = logging.getLogger(__name__) + + +@callback +def async_register_signal_handling(hass): + """Register system signal handler for core.""" + if sys.platform != 'win32': + @callback + def async_signal_handle(exit_code): + """Wrap signal handling.""" + hass.async_add_job(hass.async_stop(exit_code)) + + try: + hass.loop.add_signal_handler( + signal.SIGTERM, async_signal_handle, 0) + except ValueError: + _LOGGER.warning("Could not bind to SIGTERM") + + try: + hass.loop.add_signal_handler( + signal.SIGHUP, async_signal_handle, RESTART_EXIT_CODE) + except ValueError: + _LOGGER.warning("Could not bind to SIGHUP") diff --git a/tests/common.py b/tests/common.py index 5ebca8640cc..e384a4f1b37 100644 --- a/tests/common.py +++ b/tests/common.py @@ -108,8 +108,7 @@ def async_test_home_assistant(loop): @asyncio.coroutine def mock_async_start(): """Start the mocking.""" - with patch.object(loop, 'add_signal_handler'), \ - patch('homeassistant.core._async_create_timer'): + with patch('homeassistant.core._async_create_timer'): yield from orig_start() hass.async_start = mock_async_start diff --git a/tests/helpers/test_discovery.py b/tests/helpers/test_discovery.py index 5d6faf2f7c4..fcbec64cc98 100644 --- a/tests/helpers/test_discovery.py +++ b/tests/helpers/test_discovery.py @@ -155,7 +155,8 @@ class TestHelpersDiscovery: assert 'test_component' in self.hass.config.components assert 'switch' in self.hass.config.components - def test_1st_discovers_2nd_component(self): + @patch('homeassistant.bootstrap.async_register_signal_handling') + def test_1st_discovers_2nd_component(self, mock_signal): """Test that we don't break if one component discovers the other. If the first component fires a discovery event to setup the diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 887ef7c2c20..0a1e3633916 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -58,7 +58,8 @@ class TestBootstrap: autospec=True) @mock.patch('homeassistant.util.location.detect_location_info', autospec=True, return_value=None) - def test_from_config_file(self, mock_upgrade, mock_detect): + @mock.patch('homeassistant.helpers.signal.async_register_signal_handling') + def test_from_config_file(self, mock_upgrade, mock_detect, mock_signal): """Test with configuration file.""" components = ['browser', 'conversation', 'script'] files = { @@ -289,7 +290,8 @@ class TestBootstrap: assert 'comp' not in self.hass.config.components @mock.patch('homeassistant.bootstrap.enable_logging') - def test_home_assistant_core_config_validation(self, log_mock): + @mock.patch('homeassistant.helpers.signal.async_register_signal_handling') + def test_home_assistant_core_config_validation(self, log_mock, sig_mock): """Test if we pass in wrong information for HA conf.""" # Extensive HA conf validation testing is done in test_config.py assert None is bootstrap.from_config_dict({ @@ -393,7 +395,8 @@ class TestBootstrap: assert loader.get_component('disabled_component') is not None assert 'disabled_component' in self.hass.config.components - def test_all_work_done_before_start(self): + @mock.patch('homeassistant.bootstrap.async_register_signal_handling') + def test_all_work_done_before_start(self, signal_mock): """Test all init work done till start.""" call_order = [] From 4398b8b5c6cd8ed4c10bfcd678adb5e09d21108b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 9 Feb 2017 00:10:38 -0800 Subject: [PATCH 138/157] Deprecate event decorators (#5822) --- homeassistant/helpers/event_decorators.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/homeassistant/helpers/event_decorators.py b/homeassistant/helpers/event_decorators.py index 90a85628e59..d8c24544b7c 100644 --- a/homeassistant/helpers/event_decorators.py +++ b/homeassistant/helpers/event_decorators.py @@ -1,5 +1,6 @@ """Event Decorators for custom components.""" import functools +import logging # pylint: disable=unused-import from typing import Optional # NOQA @@ -8,10 +9,14 @@ from homeassistant.core import HomeAssistant # NOQA from homeassistant.helpers import event HASS = None # type: Optional[HomeAssistant] +_LOGGER = logging.getLogger(__name__) +_MSG = 'Event decorators are deprecated. Support will be removed in 0.40.' def track_state_change(entity_ids, from_state=None, to_state=None): """Decorator factory to track state changes for entity id.""" + _LOGGER.warning(_MSG) + def track_state_change_decorator(action): """Decorator to track state changes.""" event.track_state_change(HASS, entity_ids, @@ -24,6 +29,8 @@ def track_state_change(entity_ids, from_state=None, to_state=None): def track_sunrise(offset=None): """Decorator factory to track sunrise events.""" + _LOGGER.warning(_MSG) + def track_sunrise_decorator(action): """Decorator to track sunrise events.""" event.track_sunrise(HASS, @@ -36,6 +43,8 @@ def track_sunrise(offset=None): def track_sunset(offset=None): """Decorator factory to track sunset events.""" + _LOGGER.warning(_MSG) + def track_sunset_decorator(action): """Decorator to track sunset events.""" event.track_sunset(HASS, @@ -49,6 +58,8 @@ def track_sunset(offset=None): def track_time_change(year=None, month=None, day=None, hour=None, minute=None, second=None): """Decorator factory to track time changes.""" + _LOGGER.warning(_MSG) + def track_time_change_decorator(action): """Decorator to track time changes.""" event.track_time_change(HASS, @@ -62,6 +73,8 @@ def track_time_change(year=None, month=None, day=None, hour=None, minute=None, def track_utc_time_change(year=None, month=None, day=None, hour=None, minute=None, second=None): """Decorator factory to track time changes.""" + _LOGGER.warning(_MSG) + def track_utc_time_change_decorator(action): """Decorator to track time changes.""" event.track_utc_time_change(HASS, From c550a316a46ee424d98032c9144b26805f7f2157 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 9 Feb 2017 00:10:53 -0800 Subject: [PATCH 139/157] Make device sun light trigger async (#5823) --- .../components/device_sun_light_trigger.py | 99 ++++++++++--------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/homeassistant/components/device_sun_light_trigger.py b/homeassistant/components/device_sun_light_trigger.py index 9da4348362d..0a4d7173c20 100644 --- a/homeassistant/components/device_sun_light_trigger.py +++ b/homeassistant/components/device_sun_light_trigger.py @@ -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 https://home-assistant.io/components/device_sun_light_trigger/ """ +import asyncio import logging from datetime import timedelta @@ -12,8 +13,8 @@ import voluptuous as vol from homeassistant.core import callback 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 -from homeassistant.helpers.event_decorators import track_state_change +from homeassistant.helpers.event import ( + async_track_point_in_time, async_track_state_change) from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv @@ -42,20 +43,20 @@ CONFIG_SCHEMA = vol.Schema({ }, 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.""" 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 = config[DOMAIN].get(CONF_DISABLE_TURN_OFF) - light_group = config[DOMAIN].get(CONF_LIGHT_GROUP, - light.ENTITY_ID_ALL_LIGHTS) - light_profile = config[DOMAIN].get(CONF_LIGHT_PROFILE) - device_group = config[DOMAIN].get(CONF_DEVICE_GROUP, - device_tracker.ENTITY_ID_ALL_DEVICES) + conf = config[DOMAIN] + disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF) + light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS) + light_profile = conf.get(CONF_LIGHT_PROFILE) + device_group = conf.get(CONF_DEVICE_GROUP, + device_tracker.ENTITY_ID_ALL_DEVICES) device_entity_ids = group.get_entity_ids(hass, device_group, device_tracker.DOMAIN) @@ -74,6 +75,8 @@ def setup(hass, config): """Calculate the time when to start fading lights in when sun sets. Returns None if no next_setting data available. + + Async friendly. """ next_setting = sun.next_setting(hass) if not next_setting: @@ -81,22 +84,26 @@ def setup(hass, config): return next_setting - LIGHT_TRANSITION_TIME * len(light_ids) def async_turn_on_before_sunset(light_id): - """Helper function to turn on lights. - - Speed is slow if there are devices home and the light is not on yet. - """ + """Helper function to turn on lights.""" if not device_tracker.is_on(hass) or light.is_on(hass, light_id): return light.async_turn_on(hass, light_id, transition=LIGHT_TRANSITION_TIME.seconds, 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 # pre-sun set event - @track_state_change(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON, - sun.STATE_ABOVE_HORIZON) @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. We will schedule to have each light start after one another @@ -106,35 +113,23 @@ def setup(hass, config): if not start_point: 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): - track_point_in_time(hass, async_turn_on_factory(light_id), - start_point + index * LIGHT_TRANSITION_TIME) + async_track_point_in_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 # event. 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 - 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.""" - # pylint: disable=unused-variable lights_are_on = group.is_on(hass, light_group) - light_needed = not (lights_are_on or sun.is_on(hass)) # These variables are needed for the elif check @@ -164,17 +159,25 @@ def setup(hass, config): # will all the following then, break. break - if not disable_turn_off: - @track_state_change(device_group, STATE_HOME, STATE_NOT_HOME) - @callback - 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 + async_track_state_change( + hass, device_entity_ids, check_light_on_dev_state_change, + STATE_NOT_HOME, STATE_HOME) - logger.info( - "Everyone has left but there are lights on. Turning them off") - light.async_turn_off(hass, light_ids) + if disable_turn_off: + return True + + @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 From 298575f7cbb6efef6c80af54a95faaf8cf9fe4c0 Mon Sep 17 00:00:00 2001 From: John Arild Berentsen Date: Thu, 9 Feb 2017 13:40:35 +0100 Subject: [PATCH 140/157] Adding helper for get and set values (#5743) * cleanup * Update __init__.py * Update __init__.py * Update __init__.py --- homeassistant/components/climate/zwave.py | 141 +++++++------- homeassistant/components/cover/zwave.py | 50 ++--- homeassistant/components/light/zwave.py | 8 +- homeassistant/components/lock/zwave.py | 204 ++++++++++----------- homeassistant/components/zwave/__init__.py | 42 +++++ 5 files changed, 219 insertions(+), 226 deletions(-) diff --git a/homeassistant/components/climate/zwave.py b/homeassistant/components/climate/zwave.py index 76459d4997a..545d3b41432 100755 --- a/homeassistant/components/climate/zwave.py +++ b/homeassistant/components/climate/zwave.py @@ -83,45 +83,52 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice): def update_properties(self): """Callback on data changes for node values.""" # Operation Mode - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE).values(): - self._current_operation = value.data - self._operation_list = list(value.data_items) - _LOGGER.debug("self._operation_list=%s", self._operation_list) - _LOGGER.debug("self._current_operation=%s", - self._current_operation) + self._current_operation = self.get_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE, member='data') + operation_list = self.get_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE, + member='data_items') + if operation_list: + self._operation_list = list(operation_list) + _LOGGER.debug("self._operation_list=%s", self._operation_list) + _LOGGER.debug("self._current_operation=%s", self._current_operation) + # Current Temp - for value in ( - self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL) - .values()): - if value.label == 'Temperature': - self._current_temperature = round((float(value.data)), 1) - self._unit = value.units + self._current_temperature = self.get_value( + class_id=zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL, + label=['Temperature'], member='data') + self._unit = self.get_value( + class_id=zwave.const.COMMAND_CLASS_SENSOR_MULTILEVEL, + label=['Temperature'], member='units') + # Fan Mode - for value in ( - self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE) - .values()): - self._current_fan_mode = value.data - self._fan_list = list(value.data_items) - _LOGGER.debug("self._fan_list=%s", self._fan_list) - _LOGGER.debug("self._current_fan_mode=%s", - self._current_fan_mode) + self._current_fan_mode = self.get_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE, + member='data') + fan_list = self.get_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE, + member='data_items') + if fan_list: + self._fan_list = list(fan_list) + _LOGGER.debug("self._fan_list=%s", self._fan_list) + _LOGGER.debug("self._current_fan_mode=%s", + self._current_fan_mode) # Swing mode if self._zxt_120 == 1: - for value in ( - self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_CONFIGURATION) - .values()): - if value.command_class == \ - zwave.const.COMMAND_CLASS_CONFIGURATION and \ - value.index == 33: - self._current_swing_mode = value.data - self._swing_list = list(value.data_items) - _LOGGER.debug("self._swing_list=%s", self._swing_list) - _LOGGER.debug("self._current_swing_mode=%s", - self._current_swing_mode) + self._current_swing_mode = ( + self.get_value( + class_id=zwave.const.COMMAND_CLASS_CONFIGURATION, + index=33, + member='data')) + swing_list = self.get_value(class_id=zwave.const + .COMMAND_CLASS_CONFIGURATION, + index=33, + member='data_items') + if swing_list: + self._swing_list = list(swing_list) + _LOGGER.debug("self._swing_list=%s", self._swing_list) + _LOGGER.debug("self._current_swing_mode=%s", + self._current_swing_mode) # Set point temps = [] for value in ( @@ -139,19 +146,16 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice): break else: self._target_temperature = round((float(value.data)), 1) + # Operating state - for value in ( - self._node.get_values( - class_id=zwave.const - .COMMAND_CLASS_THERMOSTAT_OPERATING_STATE).values()): - self._operating_state = value.data + self._operating_state = self.get_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_OPERATING_STATE, + member='data') # Fan operating state - for value in ( - self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_STATE) - .values()): - self._fan_state = value.data + self._fan_state = self.get_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_STATE, + member='data') @property def should_poll(self): @@ -215,50 +219,29 @@ class ZWaveClimate(ZWaveDeviceEntity, ClimateDevice): else: return - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT) - .values()): - if value.index == self._index: - if self._zxt_120: - # ZXT-120 responds only to whole int - value.data = round(temperature, 0) - self._target_temperature = temperature - self.schedule_update_ha_state() - else: - value.data = temperature - self.schedule_update_ha_state() - break + self.set_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_SETPOINT, + index=self._index, data=temperature) + self.update_ha_state() def set_fan_mode(self, fan): """Set new target fan mode.""" - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE). - values()): - if value.command_class == \ - zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE and \ - value.index == 0: - value.data = bytes(fan, 'utf-8') - break + self.set_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_FAN_MODE, + index=0, data=bytes(fan, 'utf-8')) def set_operation_mode(self, operation_mode): """Set new target operation mode.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_THERMOSTAT_MODE and value.index == 0: - value.data = bytes(operation_mode, 'utf-8') - break + self.set_value( + class_id=zwave.const.COMMAND_CLASS_THERMOSTAT_MODE, + index=0, data=bytes(operation_mode, 'utf-8')) def set_swing_mode(self, swing_mode): """Set new target swing mode.""" if self._zxt_120 == 1: - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_CONFIGURATION).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_CONFIGURATION and \ - value.index == 33: - value.data = bytes(swing_mode, 'utf-8') - break + self.set_value( + class_id=zwave.const.COMMAND_CLASS_CONFIGURATION, + index=33, data=bytes(swing_mode, 'utf-8')) @property def device_state_attributes(self): diff --git a/homeassistant/components/cover/zwave.py b/homeassistant/components/cover/zwave.py index d9d33942e15..0e40b46a3f9 100644 --- a/homeassistant/components/cover/zwave.py +++ b/homeassistant/components/cover/zwave.py @@ -52,12 +52,11 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): def __init__(self, value): """Initialize the zwave rollershutter.""" - import libopenzwave ZWaveDeviceEntity.__init__(self, value, DOMAIN) # pylint: disable=no-member - self._lozwmgr = libopenzwave.PyManager() - self._lozwmgr.create() self._node = value.node + self._open_id = None + self._close_id = None self._current_position = None self._workaround = None if (value.node.manufacturer_id.strip() and @@ -73,12 +72,15 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): def update_properties(self): """Callback on data changes for node values.""" # Position value - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and \ - value.label == 'Level': - self._current_position = value.data + self._current_position = self.get_value( + class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL, + label=['Level'], member='data') + self._open_id = self.get_value( + class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL, + label=['Open', 'Up'], member='value_id') + self._close_id = self.get_value( + class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL, + label=['Close', 'Down'], member='value_id') @property def is_closed(self): @@ -104,27 +106,11 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): def open_cover(self, **kwargs): """Move the roller shutter up.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Open' or value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Up': - self._lozwmgr.pressButton(value.value_id) - break + zwave.NETWORK.manager.pressButton(self._open_id) def close_cover(self, **kwargs): """Move the roller shutter down.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Down' or value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Close': - self._lozwmgr.pressButton(value.value_id) - break + zwave.NETWORK.manager.pressButton(self._close_id) def set_cover_position(self, position, **kwargs): """Move the roller shutter to a specific position.""" @@ -132,15 +118,7 @@ class ZwaveRollershutter(zwave.ZWaveDeviceEntity, CoverDevice): def stop_cover(self, **kwargs): """Stop the roller shutter.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL).values(): - if value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Open' or value.command_class == \ - zwave.const.COMMAND_CLASS_SWITCH_MULTILEVEL and value.label == \ - 'Down': - self._lozwmgr.releaseButton(value.value_id) - break + zwave.NETWORK.manager.releaseButton(self._open_id) class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice): diff --git a/homeassistant/components/light/zwave.py b/homeassistant/components/light/zwave.py index 5bab9ace4c6..a0804097830 100644 --- a/homeassistant/components/light/zwave.py +++ b/homeassistant/components/light/zwave.py @@ -217,11 +217,9 @@ class ZwaveColorLight(ZwaveDimmer): self._value_color = value_color if self._value_color_channels is None: - for value_color_channels in self._value.node.get_values( - class_id=zwave.const.COMMAND_CLASS_SWITCH_COLOR, - genre=zwave.const.GENRE_SYSTEM, - type=zwave.const.TYPE_INT).values(): - self._value_color_channels = value_color_channels + self._value_color_channels = self.get_value( + class_id=zwave.const.COMMAND_CLASS_SWITCH_COLOR, + genre=zwave.const.GENRE_SYSTEM, type=zwave.const.TYPE_INT) if self._value_color and self._value_color_channels: _LOGGER.debug("Zwave node color values found.") diff --git a/homeassistant/components/lock/zwave.py b/homeassistant/components/lock/zwave.py index 5bec21d5ea6..6501c7d1b74 100644 --- a/homeassistant/components/lock/zwave.py +++ b/homeassistant/components/lock/zwave.py @@ -38,68 +38,68 @@ DEVICE_MAPPINGS = { } LOCK_NOTIFICATION = { - 1: 'Manual Lock', - 2: 'Manual Unlock', - 3: 'RF Lock', - 4: 'RF Unlock', - 5: 'Keypad Lock', - 6: 'Keypad Unlock', - 11: 'Lock Jammed', - 254: 'Unknown Event' + '1': 'Manual Lock', + '2': 'Manual Unlock', + '3': 'RF Lock', + '4': 'RF Unlock', + '5': 'Keypad Lock', + '6': 'Keypad Unlock', + '11': 'Lock Jammed', + '254': 'Unknown Event' } LOCK_ALARM_TYPE = { - 9: 'Deadbolt Jammed', - 18: 'Locked with Keypad by user ', - 19: 'Unlocked with Keypad by user ', - 21: 'Manually Locked by', - 22: 'Manually Unlocked by Key or Inside thumb turn', - 24: 'Locked by RF', - 25: 'Unlocked by RF', - 27: 'Auto re-lock', - 33: 'User deleted: ', - 112: 'Master code changed or User added: ', - 113: 'Duplicate Pin-code: ', - 130: 'RF module, power restored', - 161: 'Tamper Alarm: ', - 167: 'Low Battery', - 168: 'Critical Battery Level', - 169: 'Battery too low to operate' + '9': 'Deadbolt Jammed', + '18': 'Locked with Keypad by user ', + '19': 'Unlocked with Keypad by user ', + '21': 'Manually Locked by', + '22': 'Manually Unlocked by Key or Inside thumb turn', + '24': 'Locked by RF', + '25': 'Unlocked by RF', + '27': 'Auto re-lock', + '33': 'User deleted: ', + '112': 'Master code changed or User added: ', + '113': 'Duplicate Pin-code: ', + '130': 'RF module, power restored', + '161': 'Tamper Alarm: ', + '167': 'Low Battery', + '168': 'Critical Battery Level', + '169': 'Battery too low to operate' } MANUAL_LOCK_ALARM_LEVEL = { - 1: 'Key Cylinder or Inside thumb turn', - 2: 'Touch function (lock and leave)' + '1': 'Key Cylinder or Inside thumb turn', + '2': 'Touch function (lock and leave)' } TAMPER_ALARM_LEVEL = { - 1: 'Too many keypresses', - 2: 'Cover removed' + '1': 'Too many keypresses', + '2': 'Cover removed' } LOCK_STATUS = { - 1: True, - 2: False, - 3: True, - 4: False, - 5: True, - 6: False, - 9: False, - 18: True, - 19: False, - 21: True, - 22: False, - 24: True, - 25: False, - 27: True + '1': True, + '2': False, + '3': True, + '4': False, + '5': True, + '6': False, + '9': False, + '18': True, + '19': False, + '21': True, + '22': False, + '24': True, + '25': False, + '27': True } ALARM_TYPE_STD = [ - 18, - 19, - 33, - 112, - 113 + '18', + '19', + '33', + '112', + '113' ] SET_USERCODE_SCHEMA = vol.Schema({ @@ -234,66 +234,58 @@ class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice): def update_properties(self): """Callback on data changes for node values.""" - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_DOOR_LOCK).values(): - if value.type != zwave.const.TYPE_BOOL: - continue - if value.genre != zwave.const.GENRE_USER: - continue - self._state = value.data - _LOGGER.debug('Lock state set from Bool value and' - ' is %s', value.data) - break + self._state = self.get_value(class_id=zwave + .const.COMMAND_CLASS_DOOR_LOCK, + type=zwave.const.TYPE_BOOL, + genre=zwave.const.GENRE_USER, + member='data') + _LOGGER.debug('Lock state set from Bool value and' + ' is %s', self._state) + notification_data = self.get_value(class_id=zwave.const + .COMMAND_CLASS_ALARM, + label=['Access Control'], + member='data') + if notification_data: + self._notification = LOCK_NOTIFICATION.get(str(notification_data)) + if self._v2btze: + advanced_config = self.get_value(class_id=zwave.const + .COMMAND_CLASS_CONFIGURATION, + index=12, + data=CONFIG_ADVANCED, + member='data') + if advanced_config: + self._state = LOCK_STATUS.get(str(notification_data)) + _LOGGER.debug('Lock state set from Access Control ' + 'value and is %s, get=%s', + str(notification_data), + self.state) - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_ALARM).values(): - if value.label != "Access Control": - continue - self._notification = LOCK_NOTIFICATION.get(value.data) - notification_data = value.data - if self._v2btze: - for value in (self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_CONFIGURATION) - .values()): - if value.index != 12: - continue - if value.data == CONFIG_ADVANCED: - self._state = LOCK_STATUS.get(notification_data) - _LOGGER.debug('Lock state set from Access Control ' - 'value and is %s', notification_data) - break - - break - - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_ALARM).values(): - if value.label != "Alarm Type": - continue - alarm_type = value.data - break - - for value in self._node.get_values( - class_id=zwave.const.COMMAND_CLASS_ALARM).values(): - if value.label != "Alarm Level": - continue - alarm_level = value.data - _LOGGER.debug('Lock alarm_level is %s', alarm_level) - if alarm_type is 21: - self._lock_status = '{}{}'.format( - LOCK_ALARM_TYPE.get(alarm_type), - MANUAL_LOCK_ALARM_LEVEL.get(alarm_level)) - if alarm_type in ALARM_TYPE_STD: - self._lock_status = '{}{}'.format( - LOCK_ALARM_TYPE.get(alarm_type), alarm_level) - break - if alarm_type is 161: - self._lock_status = '{}{}'.format( - LOCK_ALARM_TYPE.get(alarm_type), - TAMPER_ALARM_LEVEL.get(alarm_level)) - break - if alarm_type != 0: - self._lock_status = LOCK_ALARM_TYPE.get(alarm_type) - break + alarm_type = self.get_value(class_id=zwave.const + .COMMAND_CLASS_ALARM, + label=['Alarm Type'], member='data') + _LOGGER.debug('Lock alarm_type is %s', str(alarm_type)) + alarm_level = self.get_value(class_id=zwave.const + .COMMAND_CLASS_ALARM, + label=['Alarm Level'], member='data') + _LOGGER.debug('Lock alarm_level is %s', str(alarm_level)) + if not alarm_type: + return + if alarm_type is 21: + self._lock_status = '{}{}'.format( + LOCK_ALARM_TYPE.get(str(alarm_type)), + MANUAL_LOCK_ALARM_LEVEL.get(str(alarm_level))) + if alarm_type in ALARM_TYPE_STD: + self._lock_status = '{}{}'.format( + LOCK_ALARM_TYPE.get(str(alarm_type)), str(alarm_level)) + return + if alarm_type is 161: + self._lock_status = '{}{}'.format( + LOCK_ALARM_TYPE.get(str(alarm_type)), + TAMPER_ALARM_LEVEL.get(str(alarm_level))) + return + if alarm_type != 0: + self._lock_status = LOCK_ALARM_TYPE.get(str(alarm_type)) + return @property def is_locked(self): diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index ccb4464a96b..8fcfd3897a7 100755 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -27,6 +27,7 @@ REQUIREMENTS = ['pydispatcher==2.0.5'] _LOGGER = logging.getLogger(__name__) +CLASS_ID = 'class_id' CONF_AUTOHEAL = 'autoheal' CONF_DEBUG = 'debug' CONF_POLLING_INTENSITY = 'polling_intensity' @@ -634,6 +635,47 @@ class ZWaveDeviceEntity(Entity): self.update_properties() self.schedule_update_ha_state() + def _value_handler(self, method=None, class_id=None, index=None, + label=None, data=None, member=None, **kwargs): + """Get the values for a given command_class with arguments.""" + varname = member + if class_id is not None: + kwargs[CLASS_ID] = class_id + _LOGGER.debug('method=%s, class_id=%s, index=%s, label=%s, data=%s,' + ' member=%s, kwargs=%s', + method, class_id, index, label, data, member, kwargs) + values = self._value.node.get_values(**kwargs).values() + _LOGGER.debug('values=%s', values) + if not values: + return None + for value in values: + if index is not None and value.index != index: + continue + if label is not None: + for entry in label: + if entry is not None and value.label != entry: + continue + if method == 'set': + value.data = data + return + if data is not None and value.data != data: + continue + if member is not None: + results = getattr(value, varname) + else: + results = value + break + _LOGGER.debug('final result=%s', results) + return results + + def get_value(self, **kwargs): + """Simplifyer to get values.""" + return self._value_handler(method='get', **kwargs) + + def set_value(self, **kwargs): + """Simplifyer to set a value.""" + return self._value_handler(method='set', **kwargs) + def update_properties(self): """Callback on data changes for node values.""" pass From 0fdf1391e210f4e7aefb2b0e79ac6a0a549fb35a Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Thu, 9 Feb 2017 18:00:18 +0100 Subject: [PATCH 141/157] Don't thow exception if connection to server is lost (#5775) --- homeassistant/components/sensor/tellduslive.py | 4 +++- homeassistant/components/tellduslive.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/tellduslive.py b/homeassistant/components/sensor/tellduslive.py index b7f3cf60892..9bebbe6e3dc 100644 --- a/homeassistant/components/sensor/tellduslive.py +++ b/homeassistant/components/sensor/tellduslive.py @@ -85,7 +85,9 @@ class TelldusLiveSensor(TelldusLiveEntity): @property def state(self): """Return the state of the sensor.""" - if self._type == SENSOR_TYPE_TEMP: + if not self.available: + return None + elif self._type == SENSOR_TYPE_TEMP: return self._value_as_temperature elif self._type == SENSOR_TYPE_HUMIDITY: return self._value_as_humidity diff --git a/homeassistant/components/tellduslive.py b/homeassistant/components/tellduslive.py index 259d4e1becb..84ab96841d9 100644 --- a/homeassistant/components/tellduslive.py +++ b/homeassistant/components/tellduslive.py @@ -17,7 +17,7 @@ import voluptuous as vol DOMAIN = 'tellduslive' -REQUIREMENTS = ['tellduslive==0.3.0'] +REQUIREMENTS = ['tellduslive==0.3.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 12aaaab9666..21c5538c76b 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -645,7 +645,7 @@ steamodd==4.21 tellcore-py==1.1.2 # homeassistant.components.tellduslive -tellduslive==0.3.0 +tellduslive==0.3.2 # homeassistant.components.sensor.temper temperusb==1.5.1 From 60f85b1e094f0a54675abe519ba6ebd3ef5686ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20St=C3=A5hl?= Date: Thu, 9 Feb 2017 22:25:06 +0100 Subject: [PATCH 142/157] Handle connection errors when connecting to Apple TVs (#5829) * Handle connection errors when connecting to Apple TVs Also bump pyatv to 0.1.2 which fixes a request leak. * Fix pylint error * Fix import order --- homeassistant/components/media_player/apple_tv.py | 5 ++++- requirements_all.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/apple_tv.py b/homeassistant/components/media_player/apple_tv.py index 19700e2f8d7..a4632c5a12d 100644 --- a/homeassistant/components/media_player/apple_tv.py +++ b/homeassistant/components/media_player/apple_tv.py @@ -8,6 +8,7 @@ import asyncio import logging import hashlib +import aiohttp import voluptuous as vol from homeassistant.components.media_player import ( @@ -21,7 +22,7 @@ import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['pyatv==0.1.1'] +REQUIREMENTS = ['pyatv==0.1.2'] _LOGGER = logging.getLogger(__name__) @@ -128,6 +129,8 @@ class AppleTvDevice(MediaPlayerDevice): self._playing = playing except exceptions.AuthenticationError as ex: _LOGGER.warning('%s (bad login id?)', str(ex)) + except aiohttp.errors.ClientOSError as ex: + _LOGGER.error('failed to connect to Apple TV (%s)', str(ex)) except asyncio.TimeoutError: _LOGGER.warning('timed out while connecting to Apple TV') diff --git a/requirements_all.txt b/requirements_all.txt index 21c5538c76b..e67826fa1f6 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -418,7 +418,7 @@ pyasn1-modules==0.0.8 pyasn1==0.2.2 # homeassistant.components.media_player.apple_tv -pyatv==0.1.1 +pyatv==0.1.2 # homeassistant.components.device_tracker.bbox # homeassistant.components.sensor.bbox From 7259082de59dcec83ab08b9487e26c2324c158bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20St=C3=A5hl?= Date: Thu, 9 Feb 2017 23:07:46 +0100 Subject: [PATCH 143/157] Reuse default aiohttp session (#5836) --- homeassistant/components/media_player/apple_tv.py | 6 ++++-- requirements_all.txt | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/media_player/apple_tv.py b/homeassistant/components/media_player/apple_tv.py index a4632c5a12d..2f47b1ba0a8 100644 --- a/homeassistant/components/media_player/apple_tv.py +++ b/homeassistant/components/media_player/apple_tv.py @@ -18,11 +18,12 @@ from homeassistant.components.media_player import ( from homeassistant.const import ( STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_STANDBY, CONF_HOST, CONF_NAME, EVENT_HOMEASSISTANT_STOP) +from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['pyatv==0.1.2'] +REQUIREMENTS = ['pyatv==0.1.3'] _LOGGER = logging.getLogger(__name__) @@ -62,7 +63,8 @@ def async_setup_platform(hass, config, async_add_entities, hass.data[DATA_APPLE_TV].append(host) details = pyatv.AppleTVDevice(name, host, login_id) - atv = pyatv.connect_to_apple_tv(details, hass.loop) + session = async_get_clientsession(hass) + atv = pyatv.connect_to_apple_tv(details, hass.loop, session=session) entity = AppleTvDevice(atv, name) @asyncio.coroutine diff --git a/requirements_all.txt b/requirements_all.txt index e67826fa1f6..605bc2b0de9 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -418,7 +418,7 @@ pyasn1-modules==0.0.8 pyasn1==0.2.2 # homeassistant.components.media_player.apple_tv -pyatv==0.1.2 +pyatv==0.1.3 # homeassistant.components.device_tracker.bbox # homeassistant.components.sensor.bbox From 3f87d28616de97acb09c35a73af1f547969ebbe3 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 10 Feb 2017 02:31:20 +0100 Subject: [PATCH 144/157] Update aiohttp 1.3.1 (#5838) --- requirements_all.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements_all.txt b/requirements_all.txt index 605bc2b0de9..07943439eb6 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -6,7 +6,7 @@ pip>=7.0.0 jinja2>=2.8 voluptuous==0.9.3 typing>=3,<4 -aiohttp==1.3 +aiohttp==1.3.1 async_timeout==1.1.0 # homeassistant.components.nuimo_controller diff --git a/setup.py b/setup.py index b9d5d3460fb..b6b679315e1 100755 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ REQUIRES = [ 'jinja2>=2.8', 'voluptuous==0.9.3', 'typing>=3,<4', - 'aiohttp==1.3', + 'aiohttp==1.3.1', 'async_timeout==1.1.0', ] From 7bf7c727d1582fb82ac726a41fbd04d587a2fd5c Mon Sep 17 00:00:00 2001 From: Philipp Schmitt Date: Fri, 10 Feb 2017 02:57:19 +0100 Subject: [PATCH 145/157] Refactoring and JSON decode error handling (#5826) * Refactoring and JSON decode error handling * Catch ValueError instead of simplejson.scanner.JSONDecodeError --- homeassistant/components/zoneminder.py | 43 ++++++++++++-------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/zoneminder.py b/homeassistant/components/zoneminder.py index 4920a5a6ce2..0fbe807fb2a 100644 --- a/homeassistant/components/zoneminder.py +++ b/homeassistant/components/zoneminder.py @@ -5,7 +5,6 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/zoneminder/ """ import logging -import json from urllib.parse import urljoin import requests @@ -79,46 +78,44 @@ def login(): ZM['url'] + 'api/host/getVersion.json', cookies=ZM['cookies'], timeout=DEFAULT_TIMEOUT) - if req.status_code != requests.codes.ok: + if not req.ok: _LOGGER.error("Connection error logging into ZoneMinder") return False return True -# pylint: disable=no-member -def get_state(api_url): - """Get a state from the ZoneMinder API service.""" +def _zm_request(method, api_url, data=None): + """Perform a Zoneminder request.""" # Since the API uses sessions that expire, sometimes we need to re-auth # if the call fails. for _ in range(LOGIN_RETRIES): - req = requests.get(urljoin(ZM['url'], api_url), cookies=ZM['cookies'], - timeout=DEFAULT_TIMEOUT) + req = requests.request( + method, urljoin(ZM['url'], api_url), data=data, + cookies=ZM['cookies'], timeout=DEFAULT_TIMEOUT) - if req.status_code != requests.codes.ok: + if not req.ok: login() else: break + else: _LOGGER.exception("Unable to get API response from ZoneMinder") - return json.loads(req.text) + try: + return req.json() + except ValueError: + _LOGGER.exception('JSON decode exception caught while attempting to ' + 'decode "%s"', req.text) + + +# pylint: disable=no-member +def get_state(api_url): + """Get a state from the ZoneMinder API service.""" + return _zm_request('get', api_url) # pylint: disable=no-member def change_state(api_url, post_data): """Update a state using the Zoneminder API.""" - for _ in range(LOGIN_RETRIES): - req = requests.post( - urljoin(ZM['url'], api_url), data=post_data, cookies=ZM['cookies'], - timeout=DEFAULT_TIMEOUT) - - if req.status_code != requests.codes.ok: - login() - else: - break - - else: - _LOGGER.exception("Unable to get API response from ZoneMinder") - - return json.loads(req.text) + return _zm_request('post', api_url, data=post_data) From 3d7b79f523d0c2d040adfe2378ba79958045b4fc Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Thu, 9 Feb 2017 21:17:17 -0500 Subject: [PATCH 146/157] [recorder] Add tests for full schema migration (#5831) * [recorder] Add tests for full schema migration * Remove leftover code * Fix duplicate creation of sqlalchemy Index object * It's that kind of day... * Improve models_original docstring --- homeassistant/components/recorder/__init__.py | 7 +- tests/components/recorder/models_original.py | 163 ++++++++++++++++++ tests/components/recorder/test_init.py | 58 ++++++- 3 files changed, 216 insertions(+), 12 deletions(-) create mode 100644 tests/components/recorder/models_original.py diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 14b9fe11574..8d3213a4805 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -345,15 +345,16 @@ class Recorder(threading.Thread): def _apply_update(self, new_version): """Perform operations to bring schema up to date.""" - from sqlalchemy import Index, Table + from sqlalchemy import Table import homeassistant.components.recorder.models as models if new_version == 1: def create_index(table_name, column_name): """Create an index for the specified table and column.""" table = Table(table_name, models.Base.metadata) - index_name = "_".join(("ix", table_name, column_name)) - index = Index(index_name, getattr(table.c, column_name)) + name = "_".join(("ix", table_name, column_name)) + # Look up the index object that was created from the models + index = next(idx for idx in table.indexes if idx.name == name) _LOGGER.debug("Creating index for table %s column %s", table_name, column_name) index.create(self.engine) diff --git a/tests/components/recorder/models_original.py b/tests/components/recorder/models_original.py new file mode 100644 index 00000000000..31ec5ee7ed7 --- /dev/null +++ b/tests/components/recorder/models_original.py @@ -0,0 +1,163 @@ +"""Models for SQLAlchemy. + +This file contains the original models definitions before schema tracking was +implemented. It is used to test the schema migration logic. +""" + +import json +from datetime import datetime +import logging + +from sqlalchemy import (Boolean, Column, DateTime, ForeignKey, Index, Integer, + String, Text, distinct) +from sqlalchemy.ext.declarative import declarative_base + +import homeassistant.util.dt as dt_util +from homeassistant.core import Event, EventOrigin, State, split_entity_id +from homeassistant.remote import JSONEncoder + +# SQLAlchemy Schema +# pylint: disable=invalid-name +Base = declarative_base() + +_LOGGER = logging.getLogger(__name__) + + +class Events(Base): # type: ignore + """Event history data.""" + + __tablename__ = 'events' + event_id = Column(Integer, primary_key=True) + event_type = Column(String(32), index=True) + event_data = Column(Text) + origin = Column(String(32)) + time_fired = Column(DateTime(timezone=True)) + created = Column(DateTime(timezone=True), default=datetime.utcnow) + + @staticmethod + def from_event(event): + """Create an event database object from a native event.""" + return Events(event_type=event.event_type, + event_data=json.dumps(event.data, cls=JSONEncoder), + origin=str(event.origin), + time_fired=event.time_fired) + + def to_native(self): + """Convert to a natve HA Event.""" + try: + return Event( + self.event_type, + json.loads(self.event_data), + EventOrigin(self.origin), + _process_timestamp(self.time_fired) + ) + except ValueError: + # When json.loads fails + _LOGGER.exception("Error converting to event: %s", self) + return None + + +class States(Base): # type: ignore + """State change history.""" + + __tablename__ = 'states' + state_id = Column(Integer, primary_key=True) + domain = Column(String(64)) + entity_id = Column(String(255)) + state = Column(String(255)) + attributes = Column(Text) + event_id = Column(Integer, ForeignKey('events.event_id')) + last_changed = Column(DateTime(timezone=True), default=datetime.utcnow) + last_updated = Column(DateTime(timezone=True), default=datetime.utcnow) + created = Column(DateTime(timezone=True), default=datetime.utcnow) + + __table_args__ = (Index('states__state_changes', + 'last_changed', 'last_updated', 'entity_id'), + Index('states__significant_changes', + 'domain', 'last_updated', 'entity_id'), ) + + @staticmethod + def from_event(event): + """Create object from a state_changed event.""" + entity_id = event.data['entity_id'] + state = event.data.get('new_state') + + dbstate = States(entity_id=entity_id) + + # State got deleted + if state is None: + dbstate.state = '' + dbstate.domain = split_entity_id(entity_id)[0] + dbstate.attributes = '{}' + dbstate.last_changed = event.time_fired + dbstate.last_updated = event.time_fired + else: + dbstate.domain = state.domain + dbstate.state = state.state + dbstate.attributes = json.dumps(dict(state.attributes), + cls=JSONEncoder) + dbstate.last_changed = state.last_changed + dbstate.last_updated = state.last_updated + + return dbstate + + def to_native(self): + """Convert to an HA state object.""" + try: + return State( + self.entity_id, self.state, + json.loads(self.attributes), + _process_timestamp(self.last_changed), + _process_timestamp(self.last_updated) + ) + except ValueError: + # When json.loads fails + _LOGGER.exception("Error converting row to state: %s", self) + return None + + +class RecorderRuns(Base): # type: ignore + """Representation of recorder run.""" + + __tablename__ = 'recorder_runs' + run_id = Column(Integer, primary_key=True) + start = Column(DateTime(timezone=True), default=datetime.utcnow) + end = Column(DateTime(timezone=True)) + closed_incorrect = Column(Boolean, default=False) + created = Column(DateTime(timezone=True), default=datetime.utcnow) + + def entity_ids(self, point_in_time=None): + """Return the entity ids that existed in this run. + + Specify point_in_time if you want to know which existed at that point + in time inside the run. + """ + from sqlalchemy.orm.session import Session + + session = Session.object_session(self) + + assert session is not None, 'RecorderRuns need to be persisted' + + query = session.query(distinct(States.entity_id)).filter( + States.last_updated >= self.start) + + if point_in_time is not None: + query = query.filter(States.last_updated < point_in_time) + elif self.end is not None: + query = query.filter(States.last_updated < self.end) + + return [row[0] for row in query] + + def to_native(self): + """Return self, native format is this model.""" + return self + + +def _process_timestamp(ts): + """Process a timestamp into datetime object.""" + if ts is None: + return None + elif ts.tzinfo is None: + return dt_util.UTC.localize(ts) + else: + return dt_util.as_utc(ts) diff --git a/tests/components/recorder/test_init.py b/tests/components/recorder/test_init.py index ce395044d11..0bfa3a20997 100644 --- a/tests/components/recorder/test_init.py +++ b/tests/components/recorder/test_init.py @@ -6,15 +6,18 @@ import unittest from unittest.mock import patch, call, MagicMock import pytest +from sqlalchemy import create_engine + from homeassistant.core import callback from homeassistant.const import MATCH_ALL from homeassistant.components import recorder from homeassistant.bootstrap import setup_component from tests.common import get_test_home_assistant +from tests.components.recorder import models_original -class TestRecorder(unittest.TestCase): - """Test the recorder module.""" +class BaseTestRecorder(unittest.TestCase): + """Base class for common recorder tests.""" def setUp(self): # pylint: disable=invalid-name """Setup things to be run when tests are started.""" @@ -87,6 +90,10 @@ class TestRecorder(unittest.TestCase): time_fired=timestamp, )) + +class TestRecorder(BaseTestRecorder): + """Test the recorder module.""" + def test_saving_state(self): """Test saving and restoring a state.""" entity_id = 'test.recorder' @@ -205,15 +212,48 @@ class TestRecorder(unittest.TestCase): with self.assertRaises(ValueError): recorder._INSTANCE._apply_update(-1) + +def create_engine_test(*args, **kwargs): + """Test version of create_engine that initializes with old schema. + + This simulates an existing db with the old schema. + """ + engine = create_engine(*args, **kwargs) + models_original.Base.metadata.create_all(engine) + return engine + + +class TestMigrateRecorder(BaseTestRecorder): + """Test recorder class that starts with an original schema db.""" + + @patch('sqlalchemy.create_engine', new=create_engine_test) + @patch('homeassistant.components.recorder.Recorder._migrate_schema') + def setUp(self, migrate): # pylint: disable=invalid-name + """Setup things to be run when tests are started. + + create_engine is patched to create a db that starts with the old + schema. + + _migrate_schema is mocked to ensure it isn't run, so we can test it + below. + """ + super().setUp() + def test_schema_update_calls(self): # pylint: disable=no-self-use """Test that schema migrations occurr in correct order.""" - test_version = recorder.models.SchemaChanges(schema_version=0) - with recorder.session_scope() as session: - session.add(test_version) - with patch.object(recorder._INSTANCE, '_apply_update') as update: - recorder._INSTANCE._migrate_schema() - update.assert_has_calls([call(version+1) for version in range( - 0, recorder.models.SCHEMA_VERSION)]) + with patch.object(recorder._INSTANCE, '_apply_update') as update: + recorder._INSTANCE._migrate_schema() + update.assert_has_calls([call(version+1) for version in range( + 0, recorder.models.SCHEMA_VERSION)]) + + def test_schema_migrate(self): # pylint: disable=no-self-use + """Test the full schema migration logic. + + We're just testing that the logic can execute successfully here without + throwing exceptions. Maintaining a set of assertions based on schema + inspection could quickly become quite cumbersome. + """ + recorder._INSTANCE._migrate_schema() @pytest.fixture From 2b62e9f008a59cdd3132a501e2b09aff98d4330a Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 10 Feb 2017 12:30:44 +0200 Subject: [PATCH 147/157] Fix zwave helper getter not to fail on some None results. (#5845) --- homeassistant/components/zwave/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 8fcfd3897a7..867a0f96062 100755 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -646,6 +646,7 @@ class ZWaveDeviceEntity(Entity): method, class_id, index, label, data, member, kwargs) values = self._value.node.get_values(**kwargs).values() _LOGGER.debug('values=%s', values) + results = None if not values: return None for value in values: From cee389f62106ad95013c4f6a69e163496a9a0b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Br=C3=A6dstrup?= Date: Fri, 10 Feb 2017 12:00:28 +0100 Subject: [PATCH 148/157] D-Link switch version bump of external library (#5843) --- homeassistant/components/switch/dlink.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/dlink.py b/homeassistant/components/switch/dlink.py index 3e1f7db3ddb..11aff81a0d5 100644 --- a/homeassistant/components/switch/dlink.py +++ b/homeassistant/components/switch/dlink.py @@ -15,7 +15,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import TEMP_CELSIUS, STATE_UNKNOWN REQUIREMENTS = ['https://github.com/LinuxChristian/pyW215/archive/' - 'v0.3.7.zip#pyW215==0.3.7'] + 'v0.4.zip#pyW215==0.4'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 07943439eb6..229ec1229fd 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -198,7 +198,7 @@ hikvision==0.4 # http://github.com/adafruit/Adafruit_Python_DHT/archive/310c59b0293354d07d94375f1365f7b9b9110c7d.zip#Adafruit_DHT==1.3.0 # homeassistant.components.switch.dlink -https://github.com/LinuxChristian/pyW215/archive/v0.3.7.zip#pyW215==0.3.7 +https://github.com/LinuxChristian/pyW215/archive/v0.4.zip#pyW215==0.4 # homeassistant.components.media_player.webostv # homeassistant.components.notify.webostv From 0f6aed16a2b89ec4fd8aa42e8deff5f53baf7666 Mon Sep 17 00:00:00 2001 From: Teemu R Date: Fri, 10 Feb 2017 14:45:31 +0100 Subject: [PATCH 149/157] bump python-yeelight version (#5850) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/light/yeelight.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/yeelight.py b/homeassistant/components/light/yeelight.py index 616bae94a91..5eae4c66bb6 100644 --- a/homeassistant/components/light/yeelight.py +++ b/homeassistant/components/light/yeelight.py @@ -22,7 +22,7 @@ from homeassistant.components.light import ( Light, PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['yeelight==0.2.1'] +REQUIREMENTS = ['yeelight==0.2.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 229ec1229fd..34f74ca6bd9 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -711,7 +711,7 @@ yahoo-finance==1.4.0 yahooweather==0.8 # homeassistant.components.light.yeelight -yeelight==0.2.1 +yeelight==0.2.2 # homeassistant.components.light.zengge zengge==0.2 From a071cd21f2c1b30affb5f9cc86b6a60fe65b0515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Vran=C3=ADk?= Date: Fri, 10 Feb 2017 14:56:49 +0100 Subject: [PATCH 150/157] version bump (#5846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/hdmi_cec.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/hdmi_cec.py b/homeassistant/components/hdmi_cec.py index 11a3f0f2d02..a154bdf609e 100644 --- a/homeassistant/components/hdmi_cec.py +++ b/homeassistant/components/hdmi_cec.py @@ -26,7 +26,7 @@ from homeassistant.const import (EVENT_HOMEASSISTANT_START, STATE_UNKNOWN, from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['pyCEC==0.4.12'] +REQUIREMENTS = ['pyCEC==0.4.13'] DOMAIN = 'hdmi_cec' diff --git a/requirements_all.txt b/requirements_all.txt index 34f74ca6bd9..695b7144fa3 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -403,7 +403,7 @@ pwaqi==1.4 py-cpuinfo==0.2.3 # homeassistant.components.hdmi_cec -pyCEC==0.4.12 +pyCEC==0.4.13 # homeassistant.components.switch.tplink pyHS100==0.2.3 From eaa6392535b55f49106b12693e8804a9ab589db1 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 10 Feb 2017 17:51:08 +0100 Subject: [PATCH 151/157] Fix check_config script. (#5853) --- homeassistant/scripts/check_config.py | 1 + tests/test_bootstrap.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index b1ecaaa57ba..154754c667a 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -33,6 +33,7 @@ MOCKS = { } SILENCE = ( 'homeassistant.bootstrap.clear_secret_cache', + 'homeassistant.bootstrap.async_register_signal_handling', 'homeassistant.core._LOGGER.info', 'homeassistant.loader._LOGGER.info', 'homeassistant.bootstrap._LOGGER.info', diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 0a1e3633916..0fede71a63d 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -58,7 +58,7 @@ class TestBootstrap: autospec=True) @mock.patch('homeassistant.util.location.detect_location_info', autospec=True, return_value=None) - @mock.patch('homeassistant.helpers.signal.async_register_signal_handling') + @mock.patch('homeassistant.bootstrap.async_register_signal_handling') def test_from_config_file(self, mock_upgrade, mock_detect, mock_signal): """Test with configuration file.""" components = ['browser', 'conversation', 'script'] @@ -290,7 +290,7 @@ class TestBootstrap: assert 'comp' not in self.hass.config.components @mock.patch('homeassistant.bootstrap.enable_logging') - @mock.patch('homeassistant.helpers.signal.async_register_signal_handling') + @mock.patch('homeassistant.bootstrap.async_register_signal_handling') def test_home_assistant_core_config_validation(self, log_mock, sig_mock): """Test if we pass in wrong information for HA conf.""" # Extensive HA conf validation testing is done in test_config.py From 0e6ab3ace6fa8f62e8dbcbe57546244349eabe58 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 10 Feb 2017 09:30:13 -0800 Subject: [PATCH 152/157] Update frontend (#5855) --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 138154 -> 138153 bytes .../www_static/home-assistant-polymer | 2 +- .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2338 -> 2337 bytes 6 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 4f8b6aed2d0..40cda09ae24 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,7 +2,7 @@ FINGERPRINTS = { "core.js": "adfeb513cf650acf763e284d76a48d6b", - "frontend.html": "ae96f5256a562f35a652f31560a3b550", + "frontend.html": "43340b2369646b779e04a9925c225ab4", "mdi.html": "c1dde43ccf5667f687c418fc8daf9668", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 70a7063556b..31f8a0789dd 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -600,4 +600,4 @@ this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,th this.hass.callService('media_player', service, serviceData); }, }); -}()); \ No newline at end of file +}()); \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 2e368d5b7f80e50e9f04a54b610ee75669fe1a4e..2790cc1ddf447ff91abfdf445239ca8e335103ea 100644 GIT binary patch delta 10641 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 delta 10642 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 44ed8271458..f3808ff4d44 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 44ed827145879dd12e20183be75a2af9594240a1 +Subproject commit f3808ff4d44733f5810e21131e0daa1425bf5f22 diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index 39156226abe..334d21443f1 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","7fd1a89b1d937df60e7a50429eec0d2b"],["/frontend/panels/dev-event-5c82300b3cf543a92cf4297506e450e7.html","1bb68c3df5c14307a2550a0cca39b435"],["/frontend/panels/dev-info-0469024d94d6270a8680df2be44ba916.html","35995794b5a909d517be812ad4f46ea8"],["/frontend/panels/dev-service-9f749635e518a4ca7991975bdefdb10a.html","1bc71eb7620c7b7198fd4b7976d6bc13"],["/frontend/panels/dev-state-7d069ba8fd5379fa8f59858b8c0a7473.html","18694d76e03e1194c734e9819923b70b"],["/frontend/panels/dev-template-2b618508510afa5281c9ecae0c3a3dbd.html","554e7f893ab24c8548813382142207d4"],["/frontend/panels/map-9c8c7924ba8f731560c9f4093835cc26.html","8ae4874622d23d995ddf2a8b0ffa8d80"],["/static/core-adfeb513cf650acf763e284d76a48d6b.js","f5fdf5f1f754e801f9f54ad31a3cc922"],["/static/frontend-ae96f5256a562f35a652f31560a3b550.html","d2a5bfe0753090d2abc2f1a57bab6627"],["/static/mdi-7a0f14bbf3822449f9060b9c53bd7376.html","8d60ec43a3f8a77b21c312783ae5b892"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","32b5a9b7ada86304bec6b43d3f2194f0"]],cacheName="sw-precache-v2--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.toString().match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a))return e.add(new Request(a,{credentials:"same-origin",redirect:"follow"}))}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);var n="index.html";!t&&n&&(a=addDirectoryIndex(a,n),t=urlsToCacheKeys.has(a));var c="/";!t&&c&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL(c,self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url,t&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,n;for(a=0;an!PY&O%T%{4hDKe*lujt7YeMXDrZ$F=>x_komT$+Dc?=}ZzaAn}gx9p3|-RSSdG zG=((IM6W7oinp!q1_;zV_OgqrsS)`x@1L*H&haXO-(|6(< zNYkU&zw&|-s+pM&hwD#eU120v($vj%!*IAK&eve%+;zr$S&TdLu7bH)l<`=uZE*bS z1()|KNwU!jnu z_;0s%>ii14fo9;Gm|M>mwYoa}=f`(%1DiS346W#ccEOv$vH@u`2Q}zoHa$CY#*XhO zt|?U^13_Y;!i4B3Nurb`OvNB`;hg*Up>8^})Og7&DBH1uixJqEk7Aio7KVaJ9Y>7k zRO*Q4X&fdH#UZ2}3aEz&kz|r79ZM3iFy%CkLmo=WSuP?LAJd887W zhCEBMP-!Y4iUiL|vQfk0Jde{n5;4!iT*V|6kP*sNgnj|fj;m>*xhN!za-Bwb!eWR? z#v{qoJSXUnP@t6{A-{7-rUXQq&`_o#C3&V*B+@)hR3ao{k7zR7z$itqbHQ;}%+g%r zL!4)ECNdfF6a%o;lO^bMngGU#kUWwpiy+TPo>L~$@R0x+SS(Acii(6}ahSzuzUDE_ zh|Dn;Ae4+VCDcY$97mAqEN5KMNM>=AWrVSel8DkURnfz$u&s=8naMP#k@Y8KBu+w^ z>nO}w#$qYyHar=JC`+RRQ;sr)p;8z`o{3N+04fW64Hlq6j%D4zh${^uCYW9c=8M#6 z!hmKL5FTZSbnvZ3xjNRES(@k+UC2VBbIeAr7~xFHoYFnH8wW-aV^Jt5OY$U2M4ILh zMjUaCC8aSJ(Z*^eDN6y+N5Vpy^ITEE6Nwp56wT`Z8eD_C1kug$bc)>z+1k6sncGLHl#4Rpres<;x)y{Z)anBL78mX|F#@u{W3&mUeR zUrqY41L+CbmIq62<`qg0T4X|SN5mTr-Mi(JsquUsnEGQ!d9HWs%LcIRbz{=M;A&5s z&;6>`C=WFbs^L)XNWzK9l6vLc+_*Amk!j`pWV(HP<_sMR!wFQfR`B`5s~4NVxW+qi zrp`lexaawD&)lMYkG_1FV<<~R8Pq*|3hmlK1=eGU*BkpJoa_TA<(s!tzxYOtlxyKNcyJ)*~|AJgj3yyr9MT#kh!+cYOX_e=~LL5UPt3H9z#B z32@|SuI^r$&8sKaxuC@X^(;L1x>5G1u5WcwZB+HoXxhE}ne%quVbGV!*PS|Xd>oeB zPxU6b+7693sBM3|IxxUOXQtLbpW_cX_p7_e`CXBfbwB7~eoXgM*sb<$!YqD5Ht3&K zJI4F+{MPd(ojk0&ZZ3aqld3{YodV}r97i30*D?q$d0{?RrYPOcgEqkWuH0>-IDRlV zJdWJ^bQ__;`=(wLEd;3Eecm+uDnJ@uxcATuE_k^DJjUFMAn&RG!;CQ43fhJfeRM61 zAK*VLn*rRvM(7lJUGTC!by~E4gyZt8z|k3BbbaX5(REqYmkvVJ{W&=M?0ASkw%?28 z7sRMf54*uX0hujKZrkn3|xB}+yS^h<={7e1SnY+ zmX+|A7mJ@j)g74jaY8GczrXzCbj_~mBO3IFrZtFIJ4bt!d$$K&c#NC8iJ9JyLZ4V& zORc6@C`eQNls0*SXT8c&&h&uDT+1f@F=4$lIYlDtgvjC0sc?#z*#z155lLb=Jm3NM z%=z7QpFMGV>c7FW<&A9;<<0uA^7XQAzC(lLf3x6Kp{*=?O2qQ<{`wc38ulRRcyrry zQ$+# ze?K(?i#FWp&^4a7e`%e8?O?qHr-NVKJ>5qe`Eq?JuwCv7;&??YSMB_P#xdz{7%+Iq zAM3k|)|Q^X+b=X7vnfxiGvT HrxXAH-n*4K literal 2338 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 Date: Fri, 10 Feb 2017 22:22:15 +0200 Subject: [PATCH 153/157] [recorder] Run end model changed in session scope (#5858) --- homeassistant/components/recorder/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 8d3213a4805..66eb06f4d27 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -421,8 +421,8 @@ class Recorder(threading.Thread): def _close_run(self): """Save end time for current run.""" - self._run.end = dt_util.utcnow() with session_scope() as session: + self._run.end = dt_util.utcnow() self._commit(session, self._run) self._run = None From 849ae9903cccff7bed5056c1abb999c29183ca0b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 10 Feb 2017 12:55:59 -0800 Subject: [PATCH 154/157] Recorder run can be None (#5854) --- homeassistant/components/recorder/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 66eb06f4d27..b227a8ce76a 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -124,7 +124,8 @@ def run_information(point_in_time: Optional[datetime]=None): res = query(recorder_runs).filter( (recorder_runs.start < point_in_time) & (recorder_runs.end > point_in_time)).first() - session.expunge(res) + if res: + session.expunge(res) return res From bb043c47f8e6b60b783096ee3f2a64a90dfab2a1 Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Sat, 11 Feb 2017 00:24:07 +0100 Subject: [PATCH 155/157] Rflink update and small refactor. (#5789) * Use same pattern for device defaults in both platforms. * Update Rflink that passes loop downstream. * Update requirements. --- homeassistant/components/rflink.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/rflink.py b/homeassistant/components/rflink.py index 13696318e01..9a9e6d1145f 100644 --- a/homeassistant/components/rflink.py +++ b/homeassistant/components/rflink.py @@ -36,7 +36,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity import voluptuous as vol -REQUIREMENTS = ['rflink==0.0.24'] +REQUIREMENTS = ['rflink==0.0.28'] DOMAIN = 'rflink' diff --git a/requirements_all.txt b/requirements_all.txt index 695b7144fa3..fff2eaef756 100755 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -586,7 +586,7 @@ qnapstats==0.2.1 radiotherm==1.2 # homeassistant.components.rflink -rflink==0.0.24 +rflink==0.0.28 # homeassistant.components.switch.rpi_rf # rpi-rf==0.9.6 From 3fb70afb1439a433d2fef57260cc610aa9d9769c Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Fri, 10 Feb 2017 23:51:19 -0500 Subject: [PATCH 156/157] Avoid traceback for Amcrest cameras/firmware that does not have the software_information API call (#5865) * Avoid traceback for Amcrest cameras/firmware that does not have the software_information API call * Make lint happy --- homeassistant/components/sensor/amcrest.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/sensor/amcrest.py b/homeassistant/components/sensor/amcrest.py index 08d551b8fde..f250905e952 100644 --- a/homeassistant/components/sensor/amcrest.py +++ b/homeassistant/components/sensor/amcrest.py @@ -122,10 +122,18 @@ class AmcrestSensor(Entity): def update(self): """Get the latest data and updates the state.""" - version, build_date = self._camera.software_information - self._attrs['Build Date'] = build_date.split('=')[-1] - self._attrs['Serial Number'] = self._camera.serial_number - self._attrs['Version'] = version.split('=')[-1] + try: + version, build_date = self._camera.software_information + self._attrs['Build Date'] = build_date.split('=')[-1] + self._attrs['Version'] = version.split('=')[-1] + except ValueError: + self._attrs['Build Date'] = 'Not Available' + self._attrs['Version'] = 'Not Available' + + try: + self._attrs['Serial Number'] = self._camera.serial_number + except ValueError: + self._attrs['Serial Number'] = 'Not Available' if self._sensor_type == 'motion_detector': self._state = self._camera.is_motion_detected From d8a34877d4f94332b41d8ee2c4b7c1b9248369ca Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 10 Feb 2017 20:55:52 -0800 Subject: [PATCH 157/157] Version bump to 0.38 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index eda303a552e..358294dde4d 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 38 -PATCH_VERSION = '0.dev0' +PATCH_VERSION = '0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 4, 2)


Home Assistant
[[hass.config.core.version]]

Path to configuration.yaml: [[hass.config.core.config_dir]]

Developed by a bunch of awesome people.

Published under the MIT license
Source: server — frontend-ui — frontend-core

Built using Python 3, Polymer [[polymerVersion]], Icons by Google and MaterialDesignIcons.com.

The following errors have been logged this session:

[[errorLog]]