From bbb251c0cf8abf2c3e5952d7eab094fb6854f2b0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 3 Dec 2016 12:17:16 -0800 Subject: [PATCH 001/141] Version bump to 0.35.0dev0 --- homeassistant/const.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 8e45ec4bb43..d9191eaedf2 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 = 34 -PATCH_VERSION = '0' +MINOR_VERSION = 35 +PATCH_VERSION = '0.dev0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 4, 2) From efdf51b54296020c916ce839c2408d57f6337073 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 4 Dec 2016 00:31:27 +0100 Subject: [PATCH 002/141] Bugfix sonos hosts (#4698) --- homeassistant/components/media_player/sonos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index b5367486e38..1fa1a39633d 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -59,7 +59,7 @@ ATTR_SLEEP_TIME = 'sleep_time' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_ADVERTISE_ADDR): cv.string, vol.Optional(CONF_INTERFACE_ADDR): cv.string, - vol.Optional(CONF_HOSTS): cv.ensure_list(cv.string), + vol.Optional(CONF_HOSTS): vol.All(cv.ensure_list, [cv.string]), }) SONOS_SCHEMA = vol.Schema({ From c89e6ec915abd6681087d3c09c1c6e1532766a64 Mon Sep 17 00:00:00 2001 From: Jacob Minnis Date: Sat, 3 Dec 2016 18:56:42 -0600 Subject: [PATCH 003/141] Updated email message headers to have 'Date' and 'Message-Id' fields (#4693) (#4695) --- homeassistant/components/notify/smtp.py | 4 ++++ tests/components/notify/test_smtp.py | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/notify/smtp.py b/homeassistant/components/notify/smtp.py index 3171509b008..6ef9bc32990 100644 --- a/homeassistant/components/notify/smtp.py +++ b/homeassistant/components/notify/smtp.py @@ -9,6 +9,7 @@ import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage +import email.utils import voluptuous as vol @@ -18,6 +19,7 @@ from homeassistant.components.notify import ( from homeassistant.const import ( CONF_USERNAME, CONF_PASSWORD, CONF_PORT, CONF_SENDER, CONF_RECIPIENT) import homeassistant.helpers.config_validation as cv +import homeassistant.util.dt as dt_util _LOGGER = logging.getLogger(__name__) @@ -134,6 +136,8 @@ class MailNotificationService(BaseNotificationService): msg['To'] = self.recipient msg['From'] = self._sender msg['X-Mailer'] = 'HomeAssistant' + msg['Date'] = email.utils.format_datetime(dt_util.now()) + msg['Message-Id'] = email.utils.make_msgid() return self._send_email(msg) diff --git a/tests/components/notify/test_smtp.py b/tests/components/notify/test_smtp.py index bbaca71ee13..6a2f8c7acbf 100644 --- a/tests/components/notify/test_smtp.py +++ b/tests/components/notify/test_smtp.py @@ -34,16 +34,18 @@ class TestNotifySmtp(unittest.TestCase): def test_text_email(self): """Test build of default text email behavior.""" msg = self.mailer.send_message('Test msg') - expected = ('Content-Type: text/plain; charset="us-ascii"\n' + expected = ('^Content-Type: text/plain; charset="us-ascii"\n' 'MIME-Version: 1.0\n' 'Content-Transfer-Encoding: 7bit\n' 'Subject: Home Assistant\n' 'To: testrecip@test.com\n' 'From: test@test.com\n' 'X-Mailer: HomeAssistant\n' + 'Date: [^\n]+\n' + 'Message-Id: <[^@]+@[^>]+>\n' '\n' - 'Test msg') - self.assertEqual(msg, expected) + 'Test msg$') + self.assertRegex(msg, expected) def test_mixed_email(self): """Test build of mixed text email behavior.""" From 97cc76b43e0156d02b723f4e0a24509f946e668a Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Sun, 4 Dec 2016 02:27:55 +0100 Subject: [PATCH 004/141] Remove global variable from tellstick code (#4700) * Refactor tellstick code for increased readability. Especially highlight if "device" is a telldus core device or a HA entity. * Refactor Tellstick object model for increased clarity. * Update comments. Unify better with sensors. Fix typo bug. Add debug logging. * Refactor tellstick code for increased readability. Especially highlight if "device" is a telldus core device or a HA entity. * Refactor Tellstick object model for increased clarity. * Update comments. Unify better with sensors. Fix typo bug. Add debug logging. * Fix lint issues. * Remove global variable according to hint from balloob. --- homeassistant/components/light/tellstick.py | 7 ++++--- homeassistant/components/switch/tellstick.py | 3 ++- homeassistant/components/tellstick.py | 13 ++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/light/tellstick.py b/homeassistant/components/light/tellstick.py index 9afc826e83c..90add8f012e 100644 --- a/homeassistant/components/light/tellstick.py +++ b/homeassistant/components/light/tellstick.py @@ -29,16 +29,17 @@ def setup_platform(hass, config, add_devices, discovery_info=None): signal_repetitions = discovery_info.get(ATTR_DISCOVER_CONFIG, DEFAULT_SIGNAL_REPETITIONS) - add_devices(TellstickLight(tellcore_id, signal_repetitions) + add_devices(TellstickLight(tellcore_id, hass.data['tellcore_registry'], + signal_repetitions) for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]) class TellstickLight(TellstickDevice, Light): """Representation of a Tellstick light.""" - def __init__(self, tellcore_id, signal_repetitions): + def __init__(self, tellcore_id, tellcore_registry, signal_repetitions): """Initialize the light.""" - super().__init__(tellcore_id, signal_repetitions) + super().__init__(tellcore_id, tellcore_registry, signal_repetitions) self._brightness = 255 diff --git a/homeassistant/components/switch/tellstick.py b/homeassistant/components/switch/tellstick.py index d3660ab36ca..46b1ad0aa49 100644 --- a/homeassistant/components/switch/tellstick.py +++ b/homeassistant/components/switch/tellstick.py @@ -26,7 +26,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): signal_repetitions = discovery_info.get(ATTR_DISCOVER_CONFIG, DEFAULT_SIGNAL_REPETITIONS) - add_devices(TellstickSwitch(tellcore_id, signal_repetitions) + add_devices(TellstickSwitch(tellcore_id, hass.data['tellcore_registry'], + signal_repetitions) for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]) diff --git a/homeassistant/components/tellstick.py b/homeassistant/components/tellstick.py index cbd5ff20583..e957ef5e2a8 100644 --- a/homeassistant/components/tellstick.py +++ b/homeassistant/components/tellstick.py @@ -62,8 +62,6 @@ def setup(hass, config): from tellcore.library import DirectCallbackDispatcher from tellcore.telldus import TelldusCore - global TELLCORE_REGISTRY - try: tellcore_lib = TelldusCore( callback_dispatcher=DirectCallbackDispatcher()) @@ -75,8 +73,9 @@ def setup(hass, config): all_tellcore_devices = tellcore_lib.devices() # Register devices - TELLCORE_REGISTRY = TellstickRegistry(hass, tellcore_lib) - TELLCORE_REGISTRY.register_tellcore_devices(all_tellcore_devices) + tellcore_registry = TellstickRegistry(hass, tellcore_lib) + tellcore_registry.register_tellcore_devices(all_tellcore_devices) + hass.data['tellcore_registry'] = tellcore_registry # Discover the switches _discover(hass, config, 'switch', @@ -153,17 +152,17 @@ class TellstickDevice(Entity): Contains the common logic for all Tellstick devices. """ - def __init__(self, tellcore_id, signal_repetitions): + def __init__(self, tellcore_id, tellcore_registry, signal_repetitions): """Initalize the Tellstick device.""" self._signal_repetitions = signal_repetitions self._state = None # Look up our corresponding tellcore device - self._tellcore_device = TELLCORE_REGISTRY.get_tellcore_device( + self._tellcore_device = tellcore_registry.get_tellcore_device( tellcore_id) # Query tellcore for the current state self.update() # Add ourselves to the mapping - TELLCORE_REGISTRY.register_ha_device(tellcore_id, self) + tellcore_registry.register_ha_device(tellcore_id, self) @property def should_poll(self): From cf0ff54d14ab72c2e614c98ec57de098ce736f10 Mon Sep 17 00:00:00 2001 From: Sebastian von Minckwitz Date: Sun, 4 Dec 2016 02:50:11 +0100 Subject: [PATCH 005/141] Add option to hide the group card switch (#4631) * Add option to hide the group card switch * Disallow control of hidden group switches * Revert "Disallow control of hidden group switches" This reverts commit 75e5ddfe3092327647e2873cb03ccf3b4a75b85a. * Changed hide_switch to control --- homeassistant/components/group.py | 22 ++++++++++++++++------ tests/components/test_group.py | 4 ++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py index cbdfef85942..0dfabdd8a35 100644 --- a/homeassistant/components/group.py +++ b/homeassistant/components/group.py @@ -29,11 +29,13 @@ ENTITY_ID_FORMAT = DOMAIN + '.{}' CONF_ENTITIES = 'entities' CONF_VIEW = 'view' +CONF_CONTROL = 'control' ATTR_AUTO = 'auto' ATTR_ORDER = 'order' ATTR_VIEW = 'view' ATTR_VISIBLE = 'visible' +ATTR_CONTROL = 'control' SERVICE_SET_VISIBILITY = 'set_visibility' SET_VISIBILITY_SERVICE_SCHEMA = vol.Schema({ @@ -61,6 +63,7 @@ CONFIG_SCHEMA = vol.Schema({ CONF_VIEW: cv.boolean, CONF_NAME: cv.string, CONF_ICON: cv.icon, + CONF_CONTROL: cv.string, }, cv.match_all)) }, extra=vol.ALLOW_EXTRA) @@ -206,11 +209,13 @@ def _async_process_config(hass, config, component): entity_ids = conf.get(CONF_ENTITIES) or [] icon = conf.get(CONF_ICON) view = conf.get(CONF_VIEW) + control = conf.get(CONF_CONTROL) # Don't create tasks and await them all. The order is important as # groups get a number based on creation order. group = yield from Group.async_create_group( - hass, name, entity_ids, icon=icon, view=view, object_id=object_id) + hass, name, entity_ids, icon=icon, view=view, + control=control, object_id=object_id) groups.append(group) if groups: @@ -221,7 +226,7 @@ class Group(Entity): """Track a group of entity ids.""" def __init__(self, hass, name, order=None, user_defined=True, icon=None, - view=False): + view=False, control=None): """Initialize a group. This Object has factory function for creation. @@ -239,20 +244,22 @@ class Group(Entity): self._assumed_state = False self._async_unsub_state_changed = None self._visible = True + self._control = control @staticmethod def create_group(hass, name, entity_ids=None, user_defined=True, - icon=None, view=False, object_id=None): + icon=None, view=False, control=None, object_id=None): """Initialize a group.""" return run_coroutine_threadsafe( Group.async_create_group(hass, name, entity_ids, user_defined, - icon, view, object_id), + icon, view, control, object_id), hass.loop).result() @staticmethod @asyncio.coroutine def async_create_group(hass, name, entity_ids=None, user_defined=True, - icon=None, view=False, object_id=None): + icon=None, view=False, control=None, + object_id=None): """Initialize a group. This method must be run in the event loop. @@ -260,7 +267,8 @@ class Group(Entity): group = Group( hass, name, order=len(hass.states.async_entity_ids(DOMAIN)), - user_defined=user_defined, icon=icon, view=view) + user_defined=user_defined, icon=icon, view=view, + control=control) group.entity_id = async_generate_entity_id( ENTITY_ID_FORMAT, object_id or name, hass=hass) @@ -319,6 +327,8 @@ class Group(Entity): data[ATTR_AUTO] = True if self._view: data[ATTR_VIEW] = True + if self._control: + data[ATTR_CONTROL] = self._control return data @property diff --git a/tests/components/test_group.py b/tests/components/test_group.py index c5b705cbc43..00b75c3a854 100644 --- a/tests/components/test_group.py +++ b/tests/components/test_group.py @@ -228,6 +228,7 @@ class TestComponentsGroup(unittest.TestCase): 'entities': 'light.Bowl, ' + test_group.entity_id, 'icon': 'mdi:work', 'view': True, + 'control': 'hidden', } group_conf['test_group'] = 'hello.world,sensor.happy' group_conf['empty_group'] = {'name': 'Empty Group', 'entities': None} @@ -243,6 +244,8 @@ class TestComponentsGroup(unittest.TestCase): self.assertEqual('mdi:work', group_state.attributes.get(ATTR_ICON)) self.assertTrue(group_state.attributes.get(group.ATTR_VIEW)) + self.assertEqual('hidden', + group_state.attributes.get(group.ATTR_CONTROL)) self.assertTrue(group_state.attributes.get(ATTR_HIDDEN)) self.assertEqual(1, group_state.attributes.get(group.ATTR_ORDER)) @@ -254,6 +257,7 @@ class TestComponentsGroup(unittest.TestCase): self.assertIsNone(group_state.attributes.get(group.ATTR_AUTO)) self.assertIsNone(group_state.attributes.get(ATTR_ICON)) self.assertIsNone(group_state.attributes.get(group.ATTR_VIEW)) + self.assertIsNone(group_state.attributes.get(group.ATTR_CONTROL)) self.assertIsNone(group_state.attributes.get(ATTR_HIDDEN)) self.assertEqual(2, group_state.attributes.get(group.ATTR_ORDER)) From 10d1496f5a7d72d9ad8c13d500e67b6aaa648697 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Sat, 3 Dec 2016 20:55:14 -0500 Subject: [PATCH 006/141] Updated python-nest to fix a camera bug when loading images (#4701) --- homeassistant/components/nest.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/nest.py b/homeassistant/components/nest.py index 01f7d6ab287..e19011c47b8 100644 --- a/homeassistant/components/nest.py +++ b/homeassistant/components/nest.py @@ -19,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) REQUIREMENTS = [ 'http://github.com/technicalpickles/python-nest' - '/archive/0be5c8a6307ee81540f21aac4fcd22cc5d98c988.zip' # nest-cam branch + '/archive/2512973b4b390d3965da43529cd20402ad374bfa.zip' # nest-cam branch '#python-nest==3.0.0'] DOMAIN = 'nest' diff --git a/requirements_all.txt b/requirements_all.txt index 56772281632..aefb21a93c9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -164,7 +164,7 @@ hikvision==0.4 # 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/0be5c8a6307ee81540f21aac4fcd22cc5d98c988.zip#python-nest==3.0.0 +http://github.com/technicalpickles/python-nest/archive/2512973b4b390d3965da43529cd20402ad374bfa.zip#python-nest==3.0.0 # homeassistant.components.light.flux_led https://github.com/Danielhiversen/flux_led/archive/0.9.zip#flux_led==0.9 From 7746ecd98ea644ecc2e6a70df209d93479c1560a Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 4 Dec 2016 02:58:44 +0100 Subject: [PATCH 007/141] Migrate weather to async (#4677) --- homeassistant/components/weather/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/weather/__init__.py b/homeassistant/components/weather/__init__.py index 26a5a41bf10..67dc7924aa3 100644 --- a/homeassistant/components/weather/__init__.py +++ b/homeassistant/components/weather/__init__.py @@ -4,6 +4,7 @@ Weather component that handles meteorological data for your location. For more details about this component, please refer to the documentation at https://home-assistant.io/components/weather/ """ +import asyncio import logging from numbers import Number @@ -30,11 +31,12 @@ ATTR_WEATHER_WIND_BEARING = 'wind_bearing' ATTR_WEATHER_WIND_SPEED = 'wind_speed' -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Setup the weather component.""" component = EntityComponent(_LOGGER, DOMAIN, hass) - component.setup(config) + yield from component.async_setup(config) return True From a099430834e702ec839fea209098449c0c71a05b Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 3 Dec 2016 23:09:28 -0500 Subject: [PATCH 008/141] Universal source list (#4086) * Add source_list to universal media player * Expanded attirubte and command support for UMP Added support to the universal media player for the following: Volume Set Current Source Set Source Current Volume The goal is to facilitate a single-card media player that includes source selection and setting the volume of the receiver. Example setup: ``` media_player: - platform: universal name: Media Center children: - media_player.kodi - media_player.cast commands: select_source: service: media_player.select_source data: entity_id: media_player.receiver volume_set: service: media_player.volume_set data: entity_id: media_player.receiver volume_mute: service: media_player.volume_mute data: entity_id: media_player.receiver turn_on: service: homeassistant.turn_on data: entity_id: media_player.receiver turn_off: service: homeassistant.turn_off data: entity_id: media_player.receiver attributes: state: media_player.receiver is_volume_muted: media_player.receiver|is_volume_muted volume_level: media_player.receiver|volume_level source: media_player.receiver|source source_list: media_player.receiver|source_list ``` * Remove print statements * Change service call back to use call_from_config * Modified service calls to use template data * linting fixes * Add tests * linting fices * More pylinting --- .../components/media_player/universal.py | 31 ++++++---- .../components/media_player/test_universal.py | 58 ++++++++++++++++++- 2 files changed, 76 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/media_player/universal.py b/homeassistant/components/media_player/universal.py index 9923782872a..cedaeed4985 100644 --- a/homeassistant/components/media_player/universal.py +++ b/homeassistant/components/media_player/universal.py @@ -14,7 +14,7 @@ from homeassistant.components.media_player import ( ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_DURATION, ATTR_MEDIA_EPISODE, 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_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_MUTED, ATTR_INPUT_SOURCE_LIST, ATTR_SUPPORTED_MEDIA_COMMANDS, 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, @@ -38,6 +38,7 @@ CONF_COMMANDS = 'commands' CONF_PLATFORM = 'platform' CONF_SERVICE = 'service' CONF_SERVICE_DATA = 'service_data' +ATTR_DATA = 'data' CONF_STATE = 'state' OFF_STATES = [STATE_IDLE, STATE_OFF] @@ -178,14 +179,15 @@ class UniversalMediaPlayer(MediaPlayerDevice): def _call_service(self, service_name, service_data=None, allow_override=False): """Call either a specified or active child's service.""" - if allow_override and service_name in self._cmds: - call_from_config( - self.hass, self._cmds[service_name], blocking=True) - return - if service_data is None: service_data = {} + if allow_override and service_name in self._cmds: + call_from_config( + self.hass, self._cmds[service_name], + variables=service_data, blocking=True) + return + active_child = self._child_state service_data[ATTR_ENTITY_ID] = active_child.entity_id @@ -233,7 +235,7 @@ class UniversalMediaPlayer(MediaPlayerDevice): @property def volume_level(self): """Volume level of entity specified in attributes or active child.""" - return self._child_attr(ATTR_MEDIA_VOLUME_LEVEL) + return self._override_or_child_attr(ATTR_MEDIA_VOLUME_LEVEL) @property def is_volume_muted(self): @@ -322,9 +324,14 @@ class UniversalMediaPlayer(MediaPlayerDevice): return self._child_attr(ATTR_APP_NAME) @property - def current_source(self): + def source(self): """"Return the current input source of the device.""" - return self._child_attr(ATTR_INPUT_SOURCE) + return self._override_or_child_attr(ATTR_INPUT_SOURCE) + + @property + def source_list(self): + """List of available input sources.""" + return self._override_or_child_attr(ATTR_INPUT_SOURCE_LIST) @property def supported_media_commands(self): @@ -340,6 +347,8 @@ class UniversalMediaPlayer(MediaPlayerDevice): SERVICE_VOLUME_DOWN]]): flags |= SUPPORT_VOLUME_STEP flags &= ~SUPPORT_VOLUME_SET + elif SERVICE_VOLUME_SET in self._cmds: + flags |= SUPPORT_VOLUME_SET if SERVICE_VOLUME_MUTE in self._cmds and \ ATTR_MEDIA_VOLUME_MUTED in self._attrs: @@ -376,7 +385,7 @@ class UniversalMediaPlayer(MediaPlayerDevice): def set_volume_level(self, volume_level): """Set volume level, range 0..1.""" data = {ATTR_MEDIA_VOLUME_LEVEL: volume_level} - self._call_service(SERVICE_VOLUME_SET, data) + self._call_service(SERVICE_VOLUME_SET, data, allow_override=True) def media_play(self): """Send play commmand.""" @@ -424,7 +433,7 @@ class UniversalMediaPlayer(MediaPlayerDevice): def select_source(self, source): """Set the input source.""" data = {ATTR_INPUT_SOURCE: source} - self._call_service(SERVICE_SELECT_SOURCE, data) + self._call_service(SERVICE_SELECT_SOURCE, data, allow_override=True) def clear_playlist(self): """Clear players playlist.""" diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index b7018945551..76e80f8236e 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -5,6 +5,8 @@ import unittest from homeassistant.const import ( STATE_OFF, STATE_ON, STATE_UNKNOWN, STATE_PLAYING, STATE_PAUSED) import homeassistant.components.switch as switch +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 @@ -142,6 +144,17 @@ class TestMediaPlayer(unittest.TestCase): self.mock_state_switch_id = switch.ENTITY_ID_FORMAT.format('state') self.hass.states.set(self.mock_state_switch_id, STATE_OFF) + self.mock_volume_id = input_slider.ENTITY_ID_FORMAT.format( + 'volume_level') + self.hass.states.set(self.mock_volume_id, 0) + + self.mock_source_list_id = input_select.ENTITY_ID_FORMAT.format( + 'source_list') + self.hass.states.set(self.mock_source_list_id, ['dvd', 'htpc']) + + self.mock_source_id = input_select.ENTITY_ID_FORMAT.format('source') + self.hass.states.set(self.mock_source_id, 'dvd') + self.config_children_only = { 'name': 'test', 'platform': 'universal', 'children': [media_player.ENTITY_ID_FORMAT.format('mock1'), @@ -153,6 +166,9 @@ class TestMediaPlayer(unittest.TestCase): media_player.ENTITY_ID_FORMAT.format('mock2')], 'attributes': { 'is_volume_muted': self.mock_mute_switch_id, + 'volume_level': self.mock_volume_id, + 'source': self.mock_source_id, + 'source_list': self.mock_source_list_id, 'state': self.mock_state_switch_id } } @@ -405,6 +421,42 @@ class TestMediaPlayer(unittest.TestCase): ump.update() self.assertTrue(ump.is_volume_muted) + def test_source_list_children_and_attr(self): + """Test source list property w/ children and attrs.""" + config = self.config_children_and_attr + universal.validate_config(config) + + ump = universal.UniversalMediaPlayer(self.hass, **config) + + self.assertEqual("['dvd', 'htpc']", ump.source_list) + + self.hass.states.set(self.mock_source_list_id, ['dvd', 'htpc', 'game']) + self.assertEqual("['dvd', 'htpc', 'game']", ump.source_list) + + def test_source_children_and_attr(self): + """Test source property w/ children and attrs.""" + config = self.config_children_and_attr + universal.validate_config(config) + + ump = universal.UniversalMediaPlayer(self.hass, **config) + + self.assertEqual('dvd', ump.source) + + self.hass.states.set(self.mock_source_id, 'htpc') + self.assertEqual('htpc', ump.source) + + def test_volume_level_children_and_attr(self): + """Test volume level property w/ children and attrs.""" + config = self.config_children_and_attr + universal.validate_config(config) + + ump = universal.UniversalMediaPlayer(self.hass, **config) + + self.assertEqual('0', ump.volume_level) + + self.hass.states.set(self.mock_volume_id, 100) + self.assertEqual('100', ump.volume_level) + def test_is_volume_muted_children_and_attr(self): """Test is volume muted property w/ children and attrs.""" config = self.config_children_and_attr @@ -443,18 +495,20 @@ class TestMediaPlayer(unittest.TestCase): config['commands']['volume_up'] = 'test' config['commands']['volume_down'] = 'test' config['commands']['volume_mute'] = 'test' + config['commands']['volume_set'] = 'test' + config['commands']['select_source'] = 'test' ump = universal.UniversalMediaPlayer(self.hass, **config) ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) ump.update() - self.mock_mp_1._supported_media_commands = universal.SUPPORT_VOLUME_SET self.mock_mp_1._state = STATE_PLAYING self.mock_mp_1.update_ha_state() ump.update() check_flags = universal.SUPPORT_TURN_ON | universal.SUPPORT_TURN_OFF \ - | universal.SUPPORT_VOLUME_STEP | universal.SUPPORT_VOLUME_MUTE + | universal.SUPPORT_VOLUME_STEP | universal.SUPPORT_VOLUME_MUTE \ + | universal.SUPPORT_SELECT_SOURCE self.assertEqual(check_flags, ump.supported_media_commands) From 776e53a7f096429cc0105650c04c5563ba29ff03 Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Sun, 4 Dec 2016 05:45:42 +0100 Subject: [PATCH 009/141] Dsmr hourly gas usage. (#4609) * Hourly rate of Gas consumption. Use proper unknown state. * Import unknown state constant. * doh * Cleanup device add. * Fix lint. * Add test for derivative calculation. * Remove conflict. * Document and move calculation into update call. --- homeassistant/components/sensor/dsmr.py | 101 +++++++++++++++++++----- tests/components/sensor/test_dsmr.py | 36 +++++++++ 2 files changed, 117 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/sensor/dsmr.py b/homeassistant/components/sensor/dsmr.py index 8d27f7188d2..0c42033006c 100644 --- a/homeassistant/components/sensor/dsmr.py +++ b/homeassistant/components/sensor/dsmr.py @@ -26,15 +26,15 @@ stores/caches the latest telegram and notifies the Entities that the telegram has been updated. """ import asyncio -import logging from datetime import timedelta +import logging -import voluptuous as vol - -import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import CONF_PORT, EVENT_HOMEASSISTANT_STOP +from homeassistant.const import ( + CONF_PORT, EVENT_HOMEASSISTANT_STOP, STATE_UNKNOWN) +import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity +import voluptuous as vol _LOGGER = logging.getLogger(__name__) @@ -65,30 +65,37 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): # Suppress logging logging.getLogger('dsmr_parser').setLevel(logging.ERROR) - from dsmr_parser import obis_references as obis + from dsmr_parser import obis_references as obis_ref from dsmr_parser.protocol import create_dsmr_reader dsmr_version = config[CONF_DSMR_VERSION] # Define list of name,obis mappings to generate entities obis_mapping = [ - ['Power Consumption', obis.CURRENT_ELECTRICITY_USAGE], - ['Power Production', obis.CURRENT_ELECTRICITY_DELIVERY], - ['Power Tariff', obis.ELECTRICITY_ACTIVE_TARIFF], - ['Power Consumption (low)', obis.ELECTRICITY_USED_TARIFF_1], - ['Power Consumption (normal)', obis.ELECTRICITY_USED_TARIFF_2], - ['Power Production (low)', obis.ELECTRICITY_DELIVERED_TARIFF_1], - ['Power Production (normal)', obis.ELECTRICITY_DELIVERED_TARIFF_2], + ['Power Consumption', obis_ref.CURRENT_ELECTRICITY_USAGE], + ['Power Production', obis_ref.CURRENT_ELECTRICITY_DELIVERY], + ['Power Tariff', obis_ref.ELECTRICITY_ACTIVE_TARIFF], + ['Power Consumption (low)', obis_ref.ELECTRICITY_USED_TARIFF_1], + ['Power Consumption (normal)', obis_ref.ELECTRICITY_USED_TARIFF_2], + ['Power Production (low)', obis_ref.ELECTRICITY_DELIVERED_TARIFF_1], + ['Power Production (normal)', obis_ref.ELECTRICITY_DELIVERED_TARIFF_2], ] - # Protocol version specific obis - if dsmr_version == '4': - obis_mapping.append(['Gas Consumption', obis.HOURLY_GAS_METER_READING]) - else: - obis_mapping.append(['Gas Consumption', obis.GAS_METER_READING]) # Generate device entities devices = [DSMREntity(name, obis) for name, obis in obis_mapping] + # Protocol version specific obis + if dsmr_version == '4': + gas_obis = obis_ref.HOURLY_GAS_METER_READING + else: + gas_obis = obis_ref.GAS_METER_READING + + # add gas meter reading and derivative for usage + devices += [ + DSMREntity('Gas Consumption', gas_obis), + DerivativeDSMREntity('Hourly Gas Consumption', gas_obis), + ] + yield from async_add_devices(devices) def update_entities_telegram(telegram): @@ -151,7 +158,10 @@ class DSMREntity(Entity): if self._obis == obis.ELECTRICITY_ACTIVE_TARIFF: return self.translate_tariff(value) else: - return value + if value: + return value + else: + return STATE_UNKNOWN @property def unit_of_measurement(self): @@ -168,4 +178,55 @@ class DSMREntity(Entity): elif value == '0001': return 'low' else: - return None + return STATE_UNKNOWN + + +class DerivativeDSMREntity(DSMREntity): + """Calculated derivative for values where the DSMR doesn't offer one. + + Gas readings are only reported per hour and don't offer a rate only + the current meter reading. This entity converts subsequents readings + into a hourly rate. + """ + + _previous_reading = None + _previous_timestamp = None + _state = STATE_UNKNOWN + + @property + def state(self): + """Return the calculated current hourly rate.""" + return self._state + + @asyncio.coroutine + def async_update(self): + """Recalculate hourly rate if timestamp has changed. + + DSMR updates gas meter reading every hour. Along with the + new value a timestamp is provided for the reading. Test + if the last known timestamp differs from the current one + then calculate a new rate for the previous hour. + """ + # check if the timestamp for the object differs from the previous one + timestamp = self.get_dsmr_object_attr('datetime') + if timestamp and timestamp != self._previous_timestamp: + current_reading = self.get_dsmr_object_attr('value') + + if self._previous_reading is None: + # can't calculate rate without previous datapoint + # just store current point + pass + else: + # recalculate the rate + diff = current_reading - self._previous_reading + self._state = diff + + self._previous_reading = current_reading + self._previous_timestamp = timestamp + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, per hour, if any.""" + unit = self.get_dsmr_object_attr('unit') + if unit: + return unit + '/h' diff --git a/tests/components/sensor/test_dsmr.py b/tests/components/sensor/test_dsmr.py index 166a4af9657..e76b26a811b 100644 --- a/tests/components/sensor/test_dsmr.py +++ b/tests/components/sensor/test_dsmr.py @@ -9,6 +9,8 @@ from decimal import Decimal from unittest.mock import Mock from homeassistant.bootstrap import async_setup_component +from homeassistant.components.sensor.dsmr import DerivativeDSMREntity +from homeassistant.const import STATE_UNKNOWN from tests.common import assert_setup_component @@ -62,3 +64,37 @@ def test_default_setup(hass, monkeypatch): power_tariff = hass.states.get('sensor.power_tariff') assert power_tariff.state == 'low' assert power_tariff.attributes.get('unit_of_measurement') is None + + +def test_derivative(): + """Test calculation of derivative value.""" + from dsmr_parser.objects import MBusObject + + entity = DerivativeDSMREntity('test', '1.0.0') + yield from entity.async_update() + + assert entity.state == STATE_UNKNOWN, 'initial state not unknown' + + entity.telegram = { + '1.0.0': MBusObject([ + {'value': 1}, + {'value': 1, 'unit': 'm3'}, + ]) + } + yield from entity.async_update() + + assert entity.state == STATE_UNKNOWN, \ + 'state after first update shoudl still be unknown' + + entity.telegram = { + '1.0.0': MBusObject([ + {'value': 2}, + {'value': 2, 'unit': 'm3'}, + ]) + } + yield from entity.async_update() + + assert entity.state == 1, \ + 'state should be difference between first and second update' + + assert entity.unit_of_measurement == 'm3/h' From ca63e4422701d6db8c34fe4db71677f5f63ae39b Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Sun, 4 Dec 2016 00:39:48 -0500 Subject: [PATCH 010/141] Wink hub sensor (#4704) --- .../components/binary_sensor/wink.py | 24 +++++++++++++++++++ homeassistant/components/wink.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/binary_sensor/wink.py b/homeassistant/components/binary_sensor/wink.py index 2d0e3f7226f..b129b5f24d4 100644 --- a/homeassistant/components/binary_sensor/wink.py +++ b/homeassistant/components/binary_sensor/wink.py @@ -40,6 +40,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for sensor in pywink.get_smoke_and_co_detectors(): add_devices([WinkBinarySensorDevice(sensor, hass)]) + for hub in pywink.get_hubs(): + add_devices([WinkHub(hub, hass)]) + class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity): """Representation of a Wink binary sensor.""" @@ -79,3 +82,24 @@ class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity): def sensor_class(self): """Return the class of this sensor, from SENSOR_CLASSES.""" return SENSOR_TYPES.get(self.capability) + + +class WinkHub(WinkDevice, BinarySensorDevice, Entity): + """Representation of a Wink Hub.""" + + def __init(self, wink, hass): + """Initialize the hub sensor.""" + WinkDevice.__init__(self, wink, hass) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return { + 'update needed': self.wink.update_needed(), + 'firmware version': self.wink.firmware_version() + } + + @property + def is_on(self): + """Return true if the binary sensor is on.""" + return self.wink.state() diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index bb374afaf86..affeb376f5c 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==0.10.1', 'pubnubsub-handler==0.0.5'] +REQUIREMENTS = ['python-wink==0.11.0', 'pubnubsub-handler==0.0.5'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index aefb21a93c9..cd16e47d620 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -471,7 +471,7 @@ python-telegram-bot==5.2.0 python-twitch==1.3.0 # homeassistant.components.wink -python-wink==0.10.1 +python-wink==0.11.0 # homeassistant.components.keyboard # pyuserinput==0.1.11 From e8c9dcf0fe6f34352210f18cfcb5e7ee1e94e104 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 4 Dec 2016 07:08:24 +0100 Subject: [PATCH 011/141] Migrate remote to async (#4678) * Migrate remote to async * add coro * remove sync from init since only used in harmony * import ATTR from remote * remove unused sync stuff from tests --- homeassistant/components/remote/__init__.py | 76 +++++++++++---------- homeassistant/components/remote/harmony.py | 7 +- tests/components/remote/test_demo.py | 17 ----- tests/components/remote/test_init.py | 1 - 4 files changed, 43 insertions(+), 58 deletions(-) diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index 8223c33d944..d6f534eae5b 100755 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -4,7 +4,9 @@ Component to interface with universal remote control devices. For more details about this component, please refer to the documentation at https://home-assistant.io/components/remote/ """ +import asyncio from datetime import timedelta +import functools as ft import logging import os @@ -80,50 +82,57 @@ def send_command(hass, device, command, entity_id=None): hass.services.call(DOMAIN, SERVICE_SEND_COMMAND, data) -def sync(hass, entity_id=None): - """Sync remote device.""" - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_SYNC, data) - - -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Track states and offer events for remotes.""" component = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_REMOTES) - component.setup(config) + yield from component.async_setup(config) - def handle_remote_service(service): + @asyncio.coroutine + def async_handle_remote_service(service): """Handle calls to the remote services.""" - target_remotes = component.extract_from_service(service) + target_remotes = component.async_extract_from_service(service) activity_id = service.data.get(ATTR_ACTIVITY) device = service.data.get(ATTR_DEVICE) command = service.data.get(ATTR_COMMAND) + update_tasks = [] for remote in target_remotes: if service.service == SERVICE_TURN_ON: - remote.turn_on(activity=activity_id) + yield from remote.async_turn_on(activity=activity_id) elif service.service == SERVICE_SEND_COMMAND: - remote.send_command(device=device, command=command) - elif service.service == SERVICE_SYNC: - remote.sync() + yield from remote.async_send_command( + device=device, command=command) else: - remote.turn_off() + yield from remote.async_turn_off() if remote.should_poll: - remote.update_ha_state(True) + update_coro = remote.async_update_ha_state(True) + if hasattr(remote, 'async_update'): + update_tasks.append(hass.loop.create_task(update_coro)) + else: + yield from update_coro - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_remote_service, - descriptions.get(SERVICE_TURN_OFF), - schema=REMOTE_SERVICE_SCHEMA) - hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_remote_service, - descriptions.get(SERVICE_TURN_ON), - schema=REMOTE_SERVICE_TURN_ON_SCHEMA) - hass.services.register(DOMAIN, SERVICE_SEND_COMMAND, handle_remote_service, - descriptions.get(SERVICE_SEND_COMMAND), - schema=REMOTE_SERVICE_SEND_COMMAND_SCHEMA) + 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_TURN_OFF, async_handle_remote_service, + descriptions.get(SERVICE_TURN_OFF), + schema=REMOTE_SERVICE_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_TURN_ON, async_handle_remote_service, + descriptions.get(SERVICE_TURN_ON), + schema=REMOTE_SERVICE_TURN_ON_SCHEMA) + hass.services.async_register( + DOMAIN, SERVICE_SEND_COMMAND, async_handle_remote_service, + descriptions.get(SERVICE_SEND_COMMAND), + schema=REMOTE_SERVICE_SEND_COMMAND_SCHEMA) return True @@ -131,14 +140,11 @@ def setup(hass, config): class RemoteDevice(ToggleEntity): """Representation of a remote.""" - def turn_on(self, **kwargs): - """Turn a device on with the remote.""" - raise NotImplementedError() - - def turn_off(self, **kwargs): - """Turn a device off with the remote.""" - raise NotImplementedError() - def send_command(self, **kwargs): """Send a command to a device.""" raise NotImplementedError() + + def async_send_command(self, **kwargs): + """Send a command to a device.""" + yield from self.hass.loop.run_in_executor( + None, ft.partial(self.send_command, **kwargs)) diff --git a/homeassistant/components/remote/harmony.py b/homeassistant/components/remote/harmony.py index 1bd1e1b94cc..60d0b29c51d 100755 --- a/homeassistant/components/remote/harmony.py +++ b/homeassistant/components/remote/harmony.py @@ -14,7 +14,8 @@ import homeassistant.components.remote as remote import homeassistant.helpers.config_validation as cv from homeassistant.const import ( CONF_NAME, CONF_HOST, CONF_PORT, ATTR_ENTITY_ID) -from homeassistant.components.remote import PLATFORM_SCHEMA, DOMAIN +from homeassistant.components.remote import ( + PLATFORM_SCHEMA, DOMAIN, ATTR_DEVICE, ATTR_COMMAND, ATTR_ACTIVITY) from homeassistant.util import slugify from homeassistant.config import load_yaml_config_file @@ -22,10 +23,6 @@ REQUIREMENTS = ['pyharmony==1.0.12'] _LOGGER = logging.getLogger(__name__) -ATTR_DEVICE = 'device' -ATTR_COMMAND = 'command' -ATTR_ACTIVITY = 'activity' - DEFAULT_PORT = 5222 DEVICES = [] diff --git a/tests/components/remote/test_demo.py b/tests/components/remote/test_demo.py index f43f9e8610c..7dc8f2c8976 100755 --- a/tests/components/remote/test_demo.py +++ b/tests/components/remote/test_demo.py @@ -9,7 +9,6 @@ from homeassistant.const import ( SERVICE_TURN_ON, SERVICE_TURN_OFF) from tests.common import get_test_home_assistant, mock_service -SERVICE_SYNC = 'sync' SERVICE_SEND_COMMAND = 'send_command' @@ -83,22 +82,6 @@ class TestDemoRemote(unittest.TestCase): self.assertEqual(SERVICE_TURN_OFF, call.service) self.assertEqual('entity_id_val', call.data[ATTR_ENTITY_ID]) - # Test sync - sync_calls = mock_service( - self.hass, remote.DOMAIN, SERVICE_SYNC) - - remote.sync( - self.hass, entity_id='entity_id_val') - - self.hass.block_till_done() - - self.assertEqual(1, len(sync_calls)) - call = sync_calls[-1] - - self.assertEqual(remote.DOMAIN, call.domain) - self.assertEqual(SERVICE_SYNC, call.service) - self.assertEqual('entity_id_val', call.data[ATTR_ENTITY_ID]) - # Test send_command send_command_calls = mock_service( self.hass, remote.DOMAIN, SERVICE_SEND_COMMAND) diff --git a/tests/components/remote/test_init.py b/tests/components/remote/test_init.py index 799ed3b5ea7..a5d711f8680 100755 --- a/tests/components/remote/test_init.py +++ b/tests/components/remote/test_init.py @@ -11,7 +11,6 @@ import homeassistant.components.remote as remote from tests.common import mock_service, get_test_home_assistant TEST_PLATFORM = {remote.DOMAIN: {CONF_PLATFORM: 'test'}} -SERVICE_SYNC = 'sync' SERVICE_SEND_COMMAND = 'send_command' From c25aa56751301a02e49ce64c6f70acd0c6cc4e8e Mon Sep 17 00:00:00 2001 From: Thibault Cohen Date: Sun, 4 Dec 2016 01:09:49 -0500 Subject: [PATCH 012/141] Add Sharp AquosTV component (#4679) --- .coveragerc | 1 + .../components/media_player/aquostv.py | 161 ++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 165 insertions(+) create mode 100644 homeassistant/components/media_player/aquostv.py diff --git a/.coveragerc b/.coveragerc index d0967918a60..a41a8470cb0 100644 --- a/.coveragerc +++ b/.coveragerc @@ -183,6 +183,7 @@ omit = homeassistant/components/light/x10.py homeassistant/components/light/yeelight.py homeassistant/components/lirc.py + homeassistant/components/media_player/aquostv.py homeassistant/components/media_player/braviatv.py homeassistant/components/media_player/cast.py homeassistant/components/media_player/cmus.py diff --git a/homeassistant/components/media_player/aquostv.py b/homeassistant/components/media_player/aquostv.py new file mode 100644 index 00000000000..c39986d7588 --- /dev/null +++ b/homeassistant/components/media_player/aquostv.py @@ -0,0 +1,161 @@ +""" +Support for interface with an Aquos TV. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/media_player.aquostv/ +""" +import logging + +import voluptuous as vol + +from homeassistant.components.media_player import ( + SUPPORT_TURN_ON, SUPPORT_TURN_OFF, + SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP, + SUPPORT_VOLUME_SET, MediaPlayerDevice, PLATFORM_SCHEMA) + +from homeassistant.const import ( + CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN, + CONF_PORT, CONF_USERNAME, CONF_PASSWORD) + + +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['sharp-aquos-rc==0.2'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'Sharp Aquos TV' +DEFAULT_PORT = 10002 +DEFAULT_USERNAME = 'admin' +DEFAULT_PASSWORD = 'password' + +SUPPORT_SHARPTV = SUPPORT_VOLUME_STEP | \ + SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ + SUPPORT_TURN_OFF | SUPPORT_TURN_ON + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, + vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string, +}) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the Sharp Aquos TV platform.""" + import sharp_aquos_rc + + name = config.get(CONF_NAME) + port = config.get(CONF_PORT) + username = config.get(CONF_USERNAME) + password = config.get(CONF_PASSWORD) + + if discovery_info: + _LOGGER.debug('%s', discovery_info) + vals = discovery_info.split(':') + if len(vals) > 1: + port = vals[1] + + host = vals[0] + remote = sharp_aquos_rc.TV(host, + port, + username, + password) + add_devices([SharpAquosTVDevice(name, remote)]) + return True + + host = config.get(CONF_HOST) + remote = sharp_aquos_rc.TV(host, + port, + username, + password) + + add_devices([SharpAquosTVDevice(name, remote)]) + return True + + +# pylint: disable=abstract-method +class SharpAquosTVDevice(MediaPlayerDevice): + """Representation of a Aquos TV.""" + + # pylint: disable=too-many-public-methods + def __init__(self, name, remote): + """Initialize the aquos device.""" + # Save a reference to the imported class + self._name = name + # Assume that the TV is not muted + self._muted = False + # Assume that the TV is in Play mode + self._playing = True + self._state = STATE_UNKNOWN + self._remote = remote + self._volume = 0 + + def update(self): + """Retrieve the latest data.""" + try: + if self._remote.power() == 1: + self._state = STATE_ON + else: + self._state = STATE_OFF + + # Set TV to be able to remotely power on + # self._remote.power_on_command_settings(2) + if self._remote.mute() == 2: + self._muted = False + else: + self._muted = True + self._volume = self._remote.volume() / 60 + except OSError: + 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 volume_level(self): + """Volume level of the media player (0..1).""" + return self._volume + + @property + def is_volume_muted(self): + """Boolean if volume is currently muted.""" + return self._muted + + @property + def supported_media_commands(self): + """Flag of media commands that are supported.""" + return SUPPORT_SHARPTV + + def turn_off(self): + """Turn off tvplayer.""" + self._remote.power(0) + + def volume_up(self): + """Volume up the media player.""" + self._remote.volume(int(self._volume * 60) + 2) + + def volume_down(self): + """Volume down media player.""" + self._remote.volume(int(self._volume * 60) - 2) + + def set_volume_level(self, level): + """Set Volume media player.""" + self._remote.volume(int(level * 60)) + + def mute_volume(self, mute): + """Send mute command.""" + self._remote.mute(0) + + def turn_on(self): + """Turn the media player on.""" + self._remote.power(1) diff --git a/requirements_all.txt b/requirements_all.txt index cd16e47d620..65e96319843 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -509,6 +509,9 @@ scsgate==0.1.0 # homeassistant.components.notify.sendgrid sendgrid==3.6.3 +# homeassistant.components.media_player.aquostv +sharp-aquos-rc==0.2 + # homeassistant.components.notify.slack slacker==0.9.30 From 53c1b93b6139500cdd1dbe4df7c6173de1438f21 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Sun, 4 Dec 2016 01:11:52 -0500 Subject: [PATCH 013/141] Added persistent_notification in case of error during Unifi device_tracker setup (#4682) --- homeassistant/components/device_tracker/unifi.py | 14 +++++++++++++- tests/components/device_tracker/test_unifi.py | 15 ++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/device_tracker/unifi.py b/homeassistant/components/device_tracker/unifi.py index d654c3e3eef..e139775e031 100644 --- a/homeassistant/components/device_tracker/unifi.py +++ b/homeassistant/components/device_tracker/unifi.py @@ -9,6 +9,7 @@ import urllib import voluptuous as vol import homeassistant.helpers.config_validation as cv +import homeassistant.loader as loader from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD @@ -19,6 +20,9 @@ _LOGGER = logging.getLogger(__name__) CONF_PORT = 'port' CONF_SITE_ID = 'site_id' +NOTIFICATION_ID = 'unifi_notification' +NOTIFICATION_TITLE = 'Unifi Device Tracker Setup' + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST, default='localhost'): cv.string, vol.Optional(CONF_SITE_ID, default='default'): cv.string, @@ -38,10 +42,18 @@ def get_scanner(hass, config): site_id = config[DOMAIN].get(CONF_SITE_ID) port = config[DOMAIN].get(CONF_PORT) + persistent_notification = loader.get_component('persistent_notification') try: ctrl = Controller(host, username, password, port, 'v4', site_id) except urllib.error.HTTPError as ex: - _LOGGER.error('Failed to connect to unifi: %s', ex) + _LOGGER.error('Failed to connect to Unifi: %s', ex) + persistent_notification.create( + hass, 'Failed to connect to Unifi. ' + 'Error: {}
' + 'You will need to restart hass after fixing.' + ''.format(ex), + title=NOTIFICATION_TITLE, + notification_id=NOTIFICATION_ID) return False return UnifiScanner(ctrl) diff --git a/tests/components/device_tracker/test_unifi.py b/tests/components/device_tracker/test_unifi.py index 32ef8976196..5482740ce11 100644 --- a/tests/components/device_tracker/test_unifi.py +++ b/tests/components/device_tracker/test_unifi.py @@ -6,6 +6,7 @@ import urllib from unifi import controller import voluptuous as vol +from tests.common import get_test_home_assistant from homeassistant.components.device_tracker import DOMAIN, unifi as unifi from homeassistant.const import (CONF_HOST, CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM) @@ -14,6 +15,14 @@ from homeassistant.const import (CONF_HOST, CONF_USERNAME, CONF_PASSWORD, class TestUnifiScanner(unittest.TestCase): """Test the Unifiy platform.""" + def setUp(self): + """Initialize values for this testcase class.""" + self.hass = get_test_home_assistant() + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + @mock.patch('homeassistant.components.device_tracker.unifi.UnifiScanner') @mock.patch.object(controller, 'Controller') def test_config_minimal(self, mock_ctrl, mock_scanner): @@ -25,7 +34,7 @@ class TestUnifiScanner(unittest.TestCase): CONF_PASSWORD: 'password', }) } - result = unifi.get_scanner(None, config) + result = unifi.get_scanner(self.hass, config) self.assertEqual(mock_scanner.return_value, result) self.assertEqual(mock_ctrl.call_count, 1) self.assertEqual( @@ -52,7 +61,7 @@ class TestUnifiScanner(unittest.TestCase): 'site_id': 'abcdef01', }) } - result = unifi.get_scanner(None, config) + result = unifi.get_scanner(self.hass, config) self.assertEqual(mock_scanner.return_value, result) self.assertEqual(mock_ctrl.call_count, 1) self.assertEqual( @@ -96,7 +105,7 @@ class TestUnifiScanner(unittest.TestCase): } mock_ctrl.side_effect = urllib.error.HTTPError( '/', 500, 'foo', {}, None) - result = unifi.get_scanner(None, config) + result = unifi.get_scanner(self.hass, config) self.assertFalse(result) def test_scanner_update(self): # pylint: disable=no-self-use From 4d35f2805f6c910876a6d64da579520e50d30023 Mon Sep 17 00:00:00 2001 From: DaveSergeant Date: Sat, 3 Dec 2016 23:40:22 -0800 Subject: [PATCH 014/141] New support Digital Loggers relays (#4684) * initial commit Previous work included with no history. Sorry, I was figuring out how to use git, branches and deal with open source projects. At this point this is a working switch but with the shortcomings of each of the 8 ports causes a network query. This needs to be rewritten so that the SwitchDevice is part of a larger device group that is only queried once, saving traffic and preventing the small device from timing out. * Device polls independent of switches now Used anel_pwrctrl.py as a basis to extract the per-switch polling out to per-device so it can be trottled properly. Likewise, no longer touching the device independently for relay status AND relay name. Getting them both from the same statuslist() return. * Final comments and tweaks Lowered cycle and update time since the device update is working so well now. Effectively no timeouts anymore. * Added dlipower to requirements homeassistant.components.switch.digitalloggers * Tox fixes pydocstyle updates * More tox errors * Yet more tox Removed useful future TODO and helpful details on the structure of the statuslocal list. Good catch on not initializing .update(), though it worked. * Blank line fix * Added file to .coveragerc --- .coveragerc | 1 + .../components/switch/digitalloggers.py | 148 ++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 152 insertions(+) create mode 100755 homeassistant/components/switch/digitalloggers.py diff --git a/.coveragerc b/.coveragerc index a41a8470cb0..9078b199a3e 100644 --- a/.coveragerc +++ b/.coveragerc @@ -318,6 +318,7 @@ omit = homeassistant/components/switch/acer_projector.py homeassistant/components/switch/anel_pwrctrl.py homeassistant/components/switch/arest.py + homeassistant/components/switch/digitalloggers.py homeassistant/components/switch/dlink.py homeassistant/components/switch/edimax.py homeassistant/components/switch/hikvisioncam.py diff --git a/homeassistant/components/switch/digitalloggers.py b/homeassistant/components/switch/digitalloggers.py new file mode 100755 index 00000000000..a9d30e52ee6 --- /dev/null +++ b/homeassistant/components/switch/digitalloggers.py @@ -0,0 +1,148 @@ +""" +Support for Digital Loggers DIN III Relays. + +Support for Digital Loggers DIN III Relays and possibly other items +through Dwight Hubbard's, python-dlipower. + +For more details about python-dlipower, please see +https://github.com/dwighthubbard/python-dlipower + +Custom ports are NOT supported due to a limitation of the dlipower +library, not the digital loggers switch + +""" +import logging +from datetime import timedelta + +import voluptuous as vol + +from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) +from homeassistant.const import ( + CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_TIMEOUT) +import homeassistant.helpers.config_validation as cv +from homeassistant.util import Throttle + + +REQUIREMENTS = ['dlipower==0.7.165'] + +CONF_CYCLETIME = 'cycletime' + +DEFAULT_NAME = 'DINRelay' +DEFAULT_USERNAME = 'admin' +DEFAULT_PASSWORD = 'admin' +DEFAULT_TIMEOUT = 20 +DEFAULT_CYCLETIME = 2 + +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=5) + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, + vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string, + vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): + vol.All(vol.Coerce(int), vol.Range(min=1, max=600)), + vol.Optional(CONF_CYCLETIME, default=DEFAULT_CYCLETIME): + vol.All(vol.Coerce(int), vol.Range(min=1, max=600)), + +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Find and return DIN III Relay switch.""" + import dlipower + + host = config.get(CONF_HOST) + controllername = config.get(CONF_NAME) + user = config.get(CONF_USERNAME) + pswd = config.get(CONF_PASSWORD) + tout = config.get(CONF_TIMEOUT) + cycl = config.get(CONF_CYCLETIME) + + power_switch = dlipower.PowerSwitch( + hostname=host, userid=user, password=pswd, + timeout=tout, cycletime=cycl + ) + + if not power_switch.verify(): + _LOGGER.error('Could not connect to DIN III Relay') + return False + + devices = [] + parent_device = DINRelayDevice(power_switch) + + devices.extend( + DINRelay(controllername, device.outlet_number, parent_device) + for device in power_switch + ) + + add_devices(devices) + + +class DINRelay(SwitchDevice): + """Representation of a individual DIN III relay port.""" + + def __init__(self, name, outletnumber, parent_device): + """Initialize the DIN III Relay switch.""" + self._parent_device = parent_device + self.controllername = name + self.outletnumber = outletnumber + self.update() + + @property + def name(self): + """Return the display name of this relay.""" + return self._outletname + + @property + def is_on(self): + """Return true if relay is on.""" + return self._is_on + + @property + def should_poll(self): + """Polling is needed.""" + return True + + def turn_on(self, **kwargs): + """Instruct the relay to turn on.""" + self._parent_device.turn_on(outlet=self.outletnumber) + + def turn_off(self, **kwargs): + """Instruct the relay to turn off.""" + self._parent_device.turn_off(outlet=self.outletnumber) + + def update(self): + """Trigger update for all switches on the parent device.""" + self._parent_device.update() + self._is_on = ( + self._parent_device.statuslocal[self.outletnumber - 1][2] == 'ON' + ) + self._outletname = "{}_{}".format( + self.controllername, + self._parent_device.statuslocal[self.outletnumber - 1][1] + ) + + +class DINRelayDevice(object): + """Device representation for per device throttling.""" + + def __init__(self, device): + """Initialize the DINRelay device.""" + self._device = device + self.update() + + def turn_on(self, **kwargs): + """Instruct the relay to turn on.""" + self._device.on(**kwargs) + + def turn_off(self, **kwargs): + """Instruct the relay to turn off.""" + self._device.off(**kwargs) + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Fetch new state data for this device.""" + self.statuslocal = self._device.statuslist() diff --git a/requirements_all.txt b/requirements_all.txt index 65e96319843..9dc2b5f0264 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -84,6 +84,9 @@ directpy==0.1 # homeassistant.components.updater distro==1.0.1 +# homeassistant.components.switch.digitalloggers +dlipower==0.7.165 + # homeassistant.components.notify.xmpp dnspython3==1.15.0 From b5c2be8ffa1dcf4e4bf2f763e7d2cbf6efe50990 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 4 Dec 2016 15:31:24 +0100 Subject: [PATCH 015/141] Protect hm thread for hangs on events (#4717) --- homeassistant/components/homematic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/homematic.py b/homeassistant/components/homematic.py index bf38b12237e..245e6a12cc2 100644 --- a/homeassistant/components/homematic.py +++ b/homeassistant/components/homematic.py @@ -544,19 +544,19 @@ def _hm_event_handler(hass, proxy, device, caller, attribute, value): # keypress event if attribute in HM_PRESS_EVENTS: - hass.bus.fire(EVENT_KEYPRESS, { + hass.add_job(hass.bus.async_fire(EVENT_KEYPRESS, { ATTR_NAME: hmdevice.NAME, ATTR_PARAM: attribute, ATTR_CHANNEL: channel - }) + })) return # impulse event if attribute in HM_IMPULSE_EVENTS: - hass.bus.fire(EVENT_KEYPRESS, { + hass.add_job(hass.bus.async_fire(EVENT_KEYPRESS, { ATTR_NAME: hmdevice.NAME, ATTR_CHANNEL: channel - }) + })) return _LOGGER.warning("Event is unknown and not forwarded to HA") From c8c6bee539273f39e4562b04f6b864845453783b Mon Sep 17 00:00:00 2001 From: hexa- Date: Sun, 4 Dec 2016 18:50:43 +0100 Subject: [PATCH 016/141] Revert "Update reference to correct tplink switch" (#4722) --- homeassistant/components/switch/tplink.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/tplink.py b/homeassistant/components/switch/tplink.py index 41c1d0462b3..bcc1b329fa8 100644 --- a/homeassistant/components/switch/tplink.py +++ b/homeassistant/components/switch/tplink.py @@ -15,7 +15,7 @@ from homeassistant.const import (CONF_HOST, CONF_NAME) import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['https://github.com/GadgetReactor/pyHS100/archive/' - 'fadb76c5a0e04f4995f16055845ffedc6d658316.zip#pyHS100==0.2.1'] + '1f771b7d8090a91c6a58931532e42730b021cbde.zip#pyHS100==0.2.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 9dc2b5f0264..3fdf12c086a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -173,7 +173,7 @@ http://github.com/technicalpickles/python-nest/archive/2512973b4b390d3965da43529 https://github.com/Danielhiversen/flux_led/archive/0.9.zip#flux_led==0.9 # homeassistant.components.switch.tplink -https://github.com/GadgetReactor/pyHS100/archive/fadb76c5a0e04f4995f16055845ffedc6d658316.zip#pyHS100==0.2.1 +https://github.com/GadgetReactor/pyHS100/archive/1f771b7d8090a91c6a58931532e42730b021cbde.zip#pyHS100==0.2.0 # homeassistant.components.switch.dlink https://github.com/LinuxChristian/pyW215/archive/v0.3.7.zip#pyW215==0.3.7 From 9bf13231f705c2a20d1d551cbb535ab5efacd0f8 Mon Sep 17 00:00:00 2001 From: Johan Bloemberg Date: Sun, 4 Dec 2016 18:51:40 +0100 Subject: [PATCH 017/141] Actually test calling async macvendor lookup and fix it. (#4718) --- .../components/device_tracker/__init__.py | 2 +- tests/components/device_tracker/test_init.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 91f0720e927..4c27b4075e3 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -282,7 +282,7 @@ class DeviceTracker(object): list(self.group.tracking) + [device.entity_id]) # lookup mac vendor string to be stored in config - device.set_vendor_for_mac() + yield from device.set_vendor_for_mac() # update known_devices.yaml self.hass.async_add_job( diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index e2ee21ab90d..013920985ff 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -256,6 +256,24 @@ class TestComponentsDeviceTracker(unittest.TestCase): self.assertEqual(device.vendor, 'unknown') + def test_mac_vendor_lookup_on_see(self): + """Test if macvendor is looked up when device is seen.""" + mac = 'B8:27:EB:00:00:00' + vendor_string = 'Raspberry Pi Foundation' + + tracker = device_tracker.DeviceTracker( + self.hass, timedelta(seconds=60), 0, []) + + with mock_aiohttp_client() as aioclient_mock: + aioclient_mock.get('http://api.macvendors.com/b8:27:eb', + text=vendor_string) + + run_coroutine_threadsafe( + tracker.async_see(mac=mac), self.hass.loop).result() + assert aioclient_mock.call_count == 1, \ + 'No http request for macvendor made!' + self.assertEqual(tracker.devices['b827eb000000'].vendor, vendor_string) + def test_discovery(self): """Test discovery.""" scanner = get_component('device_tracker.test').SCANNER From b2a15e17d3fd846fa750b9e319779edcf0b47a99 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 4 Dec 2016 09:53:05 -0800 Subject: [PATCH 018/141] MQTT Automation: parse payload as JSON (#4703) --- homeassistant/components/automation/mqtt.py | 21 +++++++++++++++------ tests/components/automation/test_mqtt.py | 7 ++++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/automation/mqtt.py b/homeassistant/components/automation/mqtt.py index 39deae3d66e..4818c02d9ff 100644 --- a/homeassistant/components/automation/mqtt.py +++ b/homeassistant/components/automation/mqtt.py @@ -4,6 +4,8 @@ Offer MQTT listening automation rules. For more details about this automation rule, please refer to the documentation at https://home-assistant.io/components/automation/#mqtt-trigger """ +import json + import voluptuous as vol from homeassistant.core import callback @@ -31,13 +33,20 @@ def async_trigger(hass, config, action): def mqtt_automation_listener(msg_topic, msg_payload, qos): """Listen for MQTT messages.""" if payload is None or payload == msg_payload: + data = { + 'platform': 'mqtt', + 'topic': msg_topic, + 'payload': msg_payload, + 'qos': qos, + } + + try: + data['payload_json'] = json.loads(msg_payload) + except ValueError: + pass + hass.async_run_job(action, { - 'trigger': { - 'platform': 'mqtt', - 'topic': msg_topic, - 'payload': msg_payload, - 'qos': qos, - } + 'trigger': data }) return mqtt.async_subscribe(hass, topic, mqtt_automation_listener) diff --git a/tests/components/automation/test_mqtt.py b/tests/components/automation/test_mqtt.py index e704b9b2d64..7ee2aadeaf6 100644 --- a/tests/components/automation/test_mqtt.py +++ b/tests/components/automation/test_mqtt.py @@ -42,16 +42,17 @@ class TestAutomationMQTT(unittest.TestCase): 'service': 'test.automation', 'data_template': { 'some': '{{ trigger.platform }} - {{ trigger.topic }}' - ' - {{ trigger.payload }}' + ' - {{ trigger.payload }} - ' + '{{ trigger.payload_json.hello }}' }, } } }) - fire_mqtt_message(self.hass, 'test-topic', 'test_payload') + fire_mqtt_message(self.hass, 'test-topic', '{ "hello": "world" }') self.hass.block_till_done() self.assertEqual(1, len(self.calls)) - self.assertEqual('mqtt - test-topic - test_payload', + self.assertEqual('mqtt - test-topic - { "hello": "world" } - world', self.calls[0].data['some']) automation.turn_off(self.hass) From 93872590b67424784c3fe309978ee0bcac935ffa Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 4 Dec 2016 09:54:49 -0800 Subject: [PATCH 019/141] Fix synology dsm doing I/O inside loop (#4699) --- .../components/sensor/synologydsm.py | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/sensor/synologydsm.py b/homeassistant/components/sensor/synologydsm.py index 31201879207..6dc23a71d9b 100644 --- a/homeassistant/components/sensor/synologydsm.py +++ b/homeassistant/components/sensor/synologydsm.py @@ -151,15 +151,9 @@ class SynoApi(): except: _LOGGER.error("Error setting up Synology DSM") - def utilisation(self): - """Return utilisation information from API.""" - if self._api is not None: - return self._api.utilisation - - def storage(self): - """Return storage information from API.""" - if self._api is not None: - return self._api.storage + # Will be updated when `update` gets called. + self.utilisation = self._api.utilisation + self.storage = self._api.storage @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): @@ -219,14 +213,14 @@ class SynoNasUtilSensor(SynoNasSensor): 'memory_total_swap', 'memory_total_real'] if self.var_id in network_sensors or self.var_id in memory_sensors: - attr = getattr(self._api.utilisation(), self.var_id)(False) + attr = getattr(self._api.utilisation, self.var_id)(False) if self.var_id in network_sensors: return round(attr / 1024.0, 1) elif self.var_id in memory_sensors: return round(attr / 1024.0 / 1024.0, 1) else: - return getattr(self._api.utilisation(), self.var_id) + return getattr(self._api.utilisation, self.var_id) class SynoNasStorageSensor(SynoNasSensor): @@ -240,7 +234,7 @@ class SynoNasStorageSensor(SynoNasSensor): if self.monitor_device is not None: if self.var_id in temp_sensors: - attr = getattr(self._api.storage(), + attr = getattr(self._api.storage, self.var_id)(self.monitor_device) if self._api.temp_unit == TEMP_CELSIUS: @@ -248,5 +242,5 @@ class SynoNasStorageSensor(SynoNasSensor): else: return round(attr * 1.8 + 32.0, 1) else: - return getattr(self._api.storage(), + return getattr(self._api.storage, self.var_id)(self.monitor_device) From 1b35f0878ee75f1b87587a6f60d6786b9fa6290d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 4 Dec 2016 10:57:24 -0800 Subject: [PATCH 020/141] Fix CORS when static resources registered (#4727) --- homeassistant/components/http/__init__.py | 6 ++++++ tests/components/http/test_init.py | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index dc18dd2481d..11a9e755bb4 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -277,9 +277,15 @@ class HomeAssistantWSGI(object): @asyncio.coroutine def start(self): """Start the wsgi server.""" + cors_added = set() if self.cors is not None: for route in list(self.app.router.routes()): + if hasattr(route, 'resource'): + route = route.resource + if route in cors_added: + continue self.cors.add(route) + cors_added.add(route) if self.ssl_certificate: context = ssl.SSLContext(SSL_VERSION) diff --git a/tests/components/http/test_init.py b/tests/components/http/test_init.py index cd0d4fe1ffa..f50e1fb9dbf 100644 --- a/tests/components/http/test_init.py +++ b/tests/components/http/test_init.py @@ -44,6 +44,10 @@ def setUpModule(): bootstrap.setup_component(hass, 'api') + # Registering static path as it caused CORS to blow up + hass.http.register_static_path( + '/custom_components', hass.config.path('custom_components')) + hass.start() @@ -53,11 +57,12 @@ def tearDownModule(): hass.stop() -class TestHttp: +class TestCors: """Test HTTP component.""" def test_cors_allowed_with_password_in_url(self): """Test cross origin resource sharing with password in url.""" + req = requests.get(_url(const.URL_API), params={'api_password': API_PASSWORD}, headers={const.HTTP_HEADER_ORIGIN: HTTP_BASE_URL}) From a9be6c36f1129eb32377f3fc994606337ce3b929 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 4 Dec 2016 10:57:48 -0800 Subject: [PATCH 021/141] Re-org emulated_hue and fix google home (#4708) --- homeassistant/components/emulated_hue.py | 566 ------------- .../components/emulated_hue/__init__.py | 198 +++++ .../components/emulated_hue/hue_api.py | 275 ++++++ homeassistant/components/emulated_hue/upnp.py | 166 ++++ tests/components/emulated_hue/__init__.py | 1 + .../test_hue_api.py} | 784 ++++++++---------- tests/components/emulated_hue/test_init.py | 55 ++ tests/components/emulated_hue/test_upnp.py | 120 +++ 8 files changed, 1170 insertions(+), 995 deletions(-) delete mode 100644 homeassistant/components/emulated_hue.py create mode 100644 homeassistant/components/emulated_hue/__init__.py create mode 100644 homeassistant/components/emulated_hue/hue_api.py create mode 100644 homeassistant/components/emulated_hue/upnp.py create mode 100644 tests/components/emulated_hue/__init__.py rename tests/components/{test_emulated_hue.py => emulated_hue/test_hue_api.py} (78%) mode change 100755 => 100644 create mode 100755 tests/components/emulated_hue/test_init.py create mode 100644 tests/components/emulated_hue/test_upnp.py diff --git a/homeassistant/components/emulated_hue.py b/homeassistant/components/emulated_hue.py deleted file mode 100644 index 7fd187daa4d..00000000000 --- a/homeassistant/components/emulated_hue.py +++ /dev/null @@ -1,566 +0,0 @@ -""" -Support for local control of entities by emulating the Phillips Hue bridge. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/emulated_hue/ -""" -import asyncio -import threading -import socket -import logging -import os -import select - -from aiohttp import web -import voluptuous as vol - -from homeassistant import util, core -from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, SERVICE_TURN_OFF, SERVICE_TURN_ON, - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, - STATE_ON, STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, -) -from homeassistant.components.light import ( - ATTR_BRIGHTNESS, ATTR_SUPPORTED_FEATURES, SUPPORT_BRIGHTNESS -) -from homeassistant.components.http import ( - HomeAssistantView, HomeAssistantWSGI -) -import homeassistant.helpers.config_validation as cv - -DOMAIN = 'emulated_hue' - -_LOGGER = logging.getLogger(__name__) - -CONF_HOST_IP = 'host_ip' -CONF_LISTEN_PORT = 'listen_port' -CONF_OFF_MAPS_TO_ON_DOMAINS = 'off_maps_to_on_domains' -CONF_EXPOSE_BY_DEFAULT = 'expose_by_default' -CONF_EXPOSED_DOMAINS = 'exposed_domains' - -ATTR_EMULATED_HUE = 'emulated_hue' -ATTR_EMULATED_HUE_NAME = 'emulated_hue_name' - -DEFAULT_LISTEN_PORT = 8300 -DEFAULT_OFF_MAPS_TO_ON_DOMAINS = ['script', 'scene'] -DEFAULT_EXPOSE_BY_DEFAULT = True -DEFAULT_EXPOSED_DOMAINS = [ - 'switch', 'light', 'group', 'input_boolean', 'media_player', 'fan' -] - -HUE_API_STATE_ON = 'on' -HUE_API_STATE_BRI = 'bri' - -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Optional(CONF_HOST_IP): cv.string, - vol.Optional(CONF_LISTEN_PORT, default=DEFAULT_LISTEN_PORT): - vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)), - vol.Optional(CONF_OFF_MAPS_TO_ON_DOMAINS): cv.ensure_list, - vol.Optional(CONF_EXPOSE_BY_DEFAULT): cv.boolean, - vol.Optional(CONF_EXPOSED_DOMAINS): cv.ensure_list - }) -}, extra=vol.ALLOW_EXTRA) - - -def setup(hass, yaml_config): - """Activate the emulated_hue component.""" - config = Config(yaml_config) - - server = HomeAssistantWSGI( - hass, - development=False, - server_host=config.host_ip_addr, - server_port=config.listen_port, - api_password=None, - ssl_certificate=None, - ssl_key=None, - cors_origins=None, - use_x_forwarded_for=False, - trusted_networks=[], - login_threshold=0, - is_ban_enabled=False - ) - - server.register_view(DescriptionXmlView(config)) - server.register_view(HueUsernameView) - server.register_view(HueLightsView(config)) - - upnp_listener = UPNPResponderThread( - config.host_ip_addr, config.listen_port) - - @asyncio.coroutine - def stop_emulated_hue_bridge(event): - """Stop the emulated hue bridge.""" - upnp_listener.stop() - yield from server.stop() - - @asyncio.coroutine - def start_emulated_hue_bridge(event): - """Start the emulated hue bridge.""" - upnp_listener.start() - hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, - stop_emulated_hue_bridge) - yield from server.start() - - hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_emulated_hue_bridge) - - return True - - -class Config(object): - """Holds configuration variables for the emulated hue bridge.""" - - def __init__(self, yaml_config): - """Initialize the instance.""" - conf = yaml_config.get(DOMAIN, {}) - - # Get the IP address that will be passed to the Echo during discovery - self.host_ip_addr = conf.get(CONF_HOST_IP) - if self.host_ip_addr is None: - self.host_ip_addr = util.get_local_ip() - _LOGGER.warning( - "Listen IP address not specified, auto-detected address is %s", - self.host_ip_addr) - - # Get the port that the Hue bridge will listen on - self.listen_port = conf.get(CONF_LISTEN_PORT) - if not isinstance(self.listen_port, int): - self.listen_port = DEFAULT_LISTEN_PORT - _LOGGER.warning( - "Listen port not specified, defaulting to %s", - self.listen_port) - - # Get domains that cause both "on" and "off" commands to map to "on" - # This is primarily useful for things like scenes or scripts, which - # don't really have a concept of being off - self.off_maps_to_on_domains = conf.get(CONF_OFF_MAPS_TO_ON_DOMAINS) - if not isinstance(self.off_maps_to_on_domains, list): - self.off_maps_to_on_domains = DEFAULT_OFF_MAPS_TO_ON_DOMAINS - - # Get whether or not entities should be exposed by default, or if only - # explicitly marked ones will be exposed - self.expose_by_default = conf.get( - CONF_EXPOSE_BY_DEFAULT, DEFAULT_EXPOSE_BY_DEFAULT) - - # Get domains that are exposed by default when expose_by_default is - # True - self.exposed_domains = conf.get( - CONF_EXPOSED_DOMAINS, DEFAULT_EXPOSED_DOMAINS) - - -class DescriptionXmlView(HomeAssistantView): - """Handles requests for the description.xml file.""" - - url = '/description.xml' - name = 'description:xml' - requires_auth = False - - def __init__(self, config): - """Initialize the instance of the view.""" - self.config = config - - @core.callback - def get(self, request): - """Handle a GET request.""" - xml_template = """ - - -1 -0 - -http://{0}:{1}/ - -urn:schemas-upnp-org:device:Basic:1 -HASS Bridge ({0}) -Royal Philips Electronics -http://www.philips.com -Philips hue Personal Wireless Lighting -Philips hue bridge 2015 -BSB002 -http://www.meethue.com -1234 -uuid:2f402f80-da50-11e1-9b23-001788255acc - - -""" - - resp_text = xml_template.format( - self.config.host_ip_addr, self.config.listen_port) - - return web.Response(text=resp_text, content_type='text/xml') - - -class HueUsernameView(HomeAssistantView): - """Handle requests to create a username for the emulated hue bridge.""" - - url = '/api' - name = 'hue:api' - extra_urls = ['/api/'] - requires_auth = False - - @asyncio.coroutine - def post(self, request): - """Handle a POST request.""" - try: - data = yield from request.json() - except ValueError: - return self.json_message('Invalid JSON', HTTP_BAD_REQUEST) - - if 'devicetype' not in data: - return self.json_message('devicetype not specified', - HTTP_BAD_REQUEST) - - return self.json([{'success': {'username': '12345678901234567890'}}]) - - -class HueLightsView(HomeAssistantView): - """Handle requests for getting and setting info about entities.""" - - url = '/api/{username}/lights' - name = 'api:username:lights' - extra_urls = ['/api/{username}/lights/{entity_id}', - '/api/{username}/lights/{entity_id}/state'] - requires_auth = False - - def __init__(self, config): - """Initialize the instance of the view.""" - self.config = config - self.cached_states = {} - - @core.callback - def get(self, request, username, entity_id=None): - """Handle a GET request.""" - hass = request.app['hass'] - - if entity_id is None: - return self.async_get_lights_list(hass) - - if not request.path.endswith('state'): - return self.async_get_light_state(hass, entity_id) - - return web.Response(text="Method not allowed", status=405) - - @asyncio.coroutine - def put(self, request, username, entity_id=None): - """Handle a PUT request.""" - hass = request.app['hass'] - - if not request.path.endswith('state'): - return web.Response(text="Method not allowed", status=405) - - if entity_id and hass.states.get(entity_id) is None: - return self.json_message('Entity not found', HTTP_NOT_FOUND) - - try: - json_data = yield from request.json() - except ValueError: - return self.json_message('Invalid JSON', HTTP_BAD_REQUEST) - - result = yield from self.async_put_light_state(hass, json_data, - entity_id) - return result - - @core.callback - def async_get_lights_list(self, hass): - """Process a request to get the list of available lights.""" - json_response = {} - - for entity in hass.states.async_all(): - if self.is_entity_exposed(entity): - json_response[entity.entity_id] = entity_to_json(entity) - - return self.json(json_response) - - @core.callback - def async_get_light_state(self, hass, entity_id): - """Process a request to get the state of an individual light.""" - entity = hass.states.get(entity_id) - if entity is None or not self.is_entity_exposed(entity): - return web.Response(text="Entity not found", status=404) - - cached_state = self.cached_states.get(entity_id, None) - - if cached_state is None: - final_state = entity.state == STATE_ON - final_brightness = entity.attributes.get( - ATTR_BRIGHTNESS, 255 if final_state else 0) - else: - final_state, final_brightness = cached_state - - json_response = entity_to_json(entity, final_state, final_brightness) - - return self.json(json_response) - - @asyncio.coroutine - def async_put_light_state(self, hass, request_json, entity_id): - """Process a request to set the state of an individual light.""" - config = self.config - - # Retrieve the entity from the state machine - entity = hass.states.get(entity_id) - if entity is None: - return web.Response(text="Entity not found", status=404) - - if not self.is_entity_exposed(entity): - return web.Response(text="Entity not found", status=404) - - # Parse the request into requested "on" status and brightness - parsed = parse_hue_api_put_light_body(request_json, entity) - - if parsed is None: - return web.Response(text="Bad request", status=400) - - result, brightness = parsed - - # Convert the resulting "on" status into the service we need to call - service = SERVICE_TURN_ON if result else SERVICE_TURN_OFF - - # Construct what we need to send to the service - data = {ATTR_ENTITY_ID: entity_id} - - # If the requested entity is a script add some variables - if entity.domain.lower() == "script": - data['variables'] = { - 'requested_state': STATE_ON if result else STATE_OFF - } - - if brightness is not None: - data['variables']['requested_level'] = brightness - - elif brightness is not None: - data[ATTR_BRIGHTNESS] = brightness - - if entity.domain.lower() in config.off_maps_to_on_domains: - # Map the off command to on - service = SERVICE_TURN_ON - - # Caching is required because things like scripts and scenes won't - # report as "off" to Alexa if an "off" command is received, because - # they'll map to "on". Thus, instead of reporting its actual - # status, we report what Alexa will want to see, which is the same - # as the actual requested command. - self.cached_states[entity_id] = (result, brightness) - - # Perform the requested action - yield from hass.services.async_call(core.DOMAIN, service, data, - blocking=True) - - json_response = \ - [create_hue_success_response(entity_id, HUE_API_STATE_ON, result)] - - if brightness is not None: - json_response.append(create_hue_success_response( - entity_id, HUE_API_STATE_BRI, brightness)) - - return self.json(json_response) - - def is_entity_exposed(self, entity): - """Determine if an entity should be exposed on the emulated bridge. - - Async friendly. - """ - config = self.config - - if entity.attributes.get('view') is not None: - # Ignore entities that are views - return False - - domain = entity.domain.lower() - explicit_expose = entity.attributes.get(ATTR_EMULATED_HUE, None) - - domain_exposed_by_default = \ - config.expose_by_default and domain in config.exposed_domains - - # Expose an entity if the entity's domain is exposed by default and - # the configuration doesn't explicitly exclude it from being - # exposed, or if the entity is explicitly exposed - is_default_exposed = \ - domain_exposed_by_default and explicit_expose is not False - - return is_default_exposed or explicit_expose - - -def parse_hue_api_put_light_body(request_json, entity): - """Parse the body of a request to change the state of a light.""" - if HUE_API_STATE_ON in request_json: - if not isinstance(request_json[HUE_API_STATE_ON], bool): - return None - - if request_json['on']: - # Echo requested device be turned on - brightness = None - report_brightness = False - result = True - else: - # Echo requested device be turned off - brightness = None - report_brightness = False - result = False - - if HUE_API_STATE_BRI in request_json: - # Make sure the entity actually supports brightness - entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) - - if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS: - try: - # Clamp brightness from 0 to 255 - brightness = \ - max(0, min(int(request_json[HUE_API_STATE_BRI]), 255)) - except ValueError: - return None - - report_brightness = True - result = (brightness > 0) - elif entity.domain.lower() == "script": - # Convert 0-255 to 0-100 - level = int(request_json[HUE_API_STATE_BRI]) / 255 * 100 - - brightness = round(level) - report_brightness = True - result = True - - return (result, brightness) if report_brightness else (result, None) - - -def entity_to_json(entity, is_on=None, brightness=None): - """Convert an entity to its Hue bridge JSON representation.""" - if is_on is None: - is_on = entity.state == STATE_ON - - if brightness is None: - brightness = 255 if is_on else 0 - - name = entity.attributes.get( - ATTR_EMULATED_HUE_NAME, entity.attributes[ATTR_FRIENDLY_NAME]) - - return { - 'state': - { - HUE_API_STATE_ON: is_on, - HUE_API_STATE_BRI: brightness, - 'reachable': True - }, - 'type': 'Dimmable light', - 'name': name, - 'modelid': 'HASS123', - 'uniqueid': entity.entity_id, - 'swversion': '123' - } - - -def create_hue_success_response(entity_id, attr, value): - """Create a success response for an attribute set on a light.""" - success_key = '/lights/{}/state/{}'.format(entity_id, attr) - return {'success': {success_key: value}} - - -class UPNPResponderThread(threading.Thread): - """Handle responding to UPNP/SSDP discovery requests.""" - - _interrupted = False - - def __init__(self, host_ip_addr, listen_port): - """Initialize the class.""" - threading.Thread.__init__(self) - - self.host_ip_addr = host_ip_addr - self.listen_port = listen_port - - # Note that the double newline at the end of - # this string is required per the SSDP spec - resp_template = """HTTP/1.1 200 OK -CACHE-CONTROL: max-age=60 -EXT: -LOCATION: http://{0}:{1}/description.xml -SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1 -ST: urn:schemas-upnp-org:device:basic:1 -USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1 - -""" - - self.upnp_response = resp_template.format(host_ip_addr, listen_port) \ - .replace("\n", "\r\n") \ - .encode('utf-8') - - # Set up a pipe for signaling to the receiver that it's time to - # shutdown. Essentially, we place the SSDP socket into nonblocking - # mode and use select() to wait for data to arrive on either the SSDP - # socket or the pipe. If data arrives on either one, select() returns - # and tells us which filenos have data ready to read. - # - # When we want to stop the responder, we write data to the pipe, which - # causes the select() to return and indicate that said pipe has data - # ready to be read, which indicates to us that the responder needs to - # be shutdown. - self._interrupted_read_pipe, self._interrupted_write_pipe = os.pipe() - - def run(self): - """Run the server.""" - # Listen for UDP port 1900 packets sent to SSDP multicast address - ssdp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - ssdp_socket.setblocking(False) - - # Required for receiving multicast - ssdp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - ssdp_socket.setsockopt( - socket.SOL_IP, - socket.IP_MULTICAST_IF, - socket.inet_aton(self.host_ip_addr)) - - ssdp_socket.setsockopt( - socket.SOL_IP, - socket.IP_ADD_MEMBERSHIP, - socket.inet_aton("239.255.255.250") + - socket.inet_aton(self.host_ip_addr)) - - ssdp_socket.bind(("239.255.255.250", 1900)) - - while True: - if self._interrupted: - clean_socket_close(ssdp_socket) - return - - try: - read, _, _ = select.select( - [self._interrupted_read_pipe, ssdp_socket], [], - [ssdp_socket]) - - if self._interrupted_read_pipe in read: - # Implies self._interrupted is True - clean_socket_close(ssdp_socket) - return - elif ssdp_socket in read: - data, addr = ssdp_socket.recvfrom(1024) - else: - continue - except socket.error as ex: - if self._interrupted: - clean_socket_close(ssdp_socket) - return - - _LOGGER.error("UPNP Responder socket exception occured: %s", - ex.__str__) - - if "M-SEARCH" in data.decode('utf-8'): - # SSDP M-SEARCH method received, respond to it with our info - resp_socket = socket.socket( - socket.AF_INET, socket.SOCK_DGRAM) - - resp_socket.sendto(self.upnp_response, addr) - resp_socket.close() - - def stop(self): - """Stop the server.""" - # Request for server - self._interrupted = True - os.write(self._interrupted_write_pipe, bytes([0])) - self.join() - - -def clean_socket_close(sock): - """Close a socket connection and logs its closure.""" - _LOGGER.info("UPNP responder shutting down.") - - sock.close() diff --git a/homeassistant/components/emulated_hue/__init__.py b/homeassistant/components/emulated_hue/__init__.py new file mode 100644 index 00000000000..2efce06528d --- /dev/null +++ b/homeassistant/components/emulated_hue/__init__.py @@ -0,0 +1,198 @@ +""" +Support for local control of entities by emulating the Phillips Hue bridge. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/emulated_hue/ +""" +import asyncio +import logging + +import voluptuous as vol + +from homeassistant import util +from homeassistant.const import ( + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, +) +from homeassistant.components.http import HomeAssistantWSGI +import homeassistant.helpers.config_validation as cv +from .hue_api import ( + HueUsernameView, HueAllLightsStateView, HueOneLightStateView, + HueOneLightChangeView) +from .upnp import DescriptionXmlView, UPNPResponderThread + +DOMAIN = 'emulated_hue' + +_LOGGER = logging.getLogger(__name__) + +CONF_HOST_IP = 'host_ip' +CONF_LISTEN_PORT = 'listen_port' +CONF_OFF_MAPS_TO_ON_DOMAINS = 'off_maps_to_on_domains' +CONF_EXPOSE_BY_DEFAULT = 'expose_by_default' +CONF_EXPOSED_DOMAINS = 'exposed_domains' +CONF_TYPE = 'type' + +TYPE_ALEXA = 'alexa' +TYPE_GOOGLE = 'google_home' + +DEFAULT_LISTEN_PORT = 8300 +DEFAULT_OFF_MAPS_TO_ON_DOMAINS = ['script', 'scene'] +DEFAULT_EXPOSE_BY_DEFAULT = True +DEFAULT_EXPOSED_DOMAINS = [ + 'switch', 'light', 'group', 'input_boolean', 'media_player', 'fan' +] +DEFAULT_TYPE = TYPE_ALEXA + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Optional(CONF_HOST_IP): cv.string, + vol.Optional(CONF_LISTEN_PORT, default=DEFAULT_LISTEN_PORT): + vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)), + vol.Optional(CONF_OFF_MAPS_TO_ON_DOMAINS): cv.ensure_list, + vol.Optional(CONF_EXPOSE_BY_DEFAULT): cv.boolean, + vol.Optional(CONF_EXPOSED_DOMAINS): cv.ensure_list, + vol.Optional(CONF_TYPE, default=DEFAULT_TYPE): + vol.Any(TYPE_ALEXA, TYPE_GOOGLE) + }) +}, extra=vol.ALLOW_EXTRA) + +ATTR_EMULATED_HUE = 'emulated_hue' + + +def setup(hass, yaml_config): + """Activate the emulated_hue component.""" + config = Config(yaml_config.get(DOMAIN, {})) + + server = HomeAssistantWSGI( + hass, + development=False, + server_host=config.host_ip_addr, + server_port=config.listen_port, + api_password=None, + ssl_certificate=None, + ssl_key=None, + cors_origins=None, + use_x_forwarded_for=False, + trusted_networks=[], + login_threshold=0, + is_ban_enabled=False + ) + + server.register_view(DescriptionXmlView(config)) + server.register_view(HueUsernameView) + server.register_view(HueAllLightsStateView(config)) + server.register_view(HueOneLightStateView(config)) + server.register_view(HueOneLightChangeView(config)) + + upnp_listener = UPNPResponderThread( + config.host_ip_addr, config.listen_port) + + @asyncio.coroutine + def stop_emulated_hue_bridge(event): + """Stop the emulated hue bridge.""" + upnp_listener.stop() + yield from server.stop() + + @asyncio.coroutine + def start_emulated_hue_bridge(event): + """Start the emulated hue bridge.""" + upnp_listener.start() + yield from server.start() + hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, + stop_emulated_hue_bridge) + + hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_emulated_hue_bridge) + + return True + + +class Config(object): + """Holds configuration variables for the emulated hue bridge.""" + + def __init__(self, conf): + """Initialize the instance.""" + self.type = conf.get(CONF_TYPE) + self.numbers = {} + self.cached_states = {} + + # Get the IP address that will be passed to the Echo during discovery + self.host_ip_addr = conf.get(CONF_HOST_IP) + if self.host_ip_addr is None: + self.host_ip_addr = util.get_local_ip() + _LOGGER.warning( + "Listen IP address not specified, auto-detected address is %s", + self.host_ip_addr) + + # Get the port that the Hue bridge will listen on + self.listen_port = conf.get(CONF_LISTEN_PORT) + if not isinstance(self.listen_port, int): + self.listen_port = DEFAULT_LISTEN_PORT + _LOGGER.warning( + "Listen port not specified, defaulting to %s", + self.listen_port) + + if self.type == TYPE_GOOGLE and self.listen_port != 80: + _LOGGER.warning('When targetting Google Home, listening port has ' + 'to be port 80') + + # Get domains that cause both "on" and "off" commands to map to "on" + # This is primarily useful for things like scenes or scripts, which + # don't really have a concept of being off + self.off_maps_to_on_domains = conf.get(CONF_OFF_MAPS_TO_ON_DOMAINS) + if not isinstance(self.off_maps_to_on_domains, list): + self.off_maps_to_on_domains = DEFAULT_OFF_MAPS_TO_ON_DOMAINS + + # Get whether or not entities should be exposed by default, or if only + # explicitly marked ones will be exposed + self.expose_by_default = conf.get( + CONF_EXPOSE_BY_DEFAULT, DEFAULT_EXPOSE_BY_DEFAULT) + + # Get domains that are exposed by default when expose_by_default is + # True + self.exposed_domains = conf.get( + CONF_EXPOSED_DOMAINS, DEFAULT_EXPOSED_DOMAINS) + + def entity_id_to_number(self, entity_id): + """Get a unique number for the entity id.""" + if self.type == TYPE_ALEXA: + return entity_id + + # Google Home + for number, ent_id in self.numbers.items(): + if entity_id == ent_id: + return number + + number = str(len(self.numbers) + 1) + self.numbers[number] = entity_id + return number + + def number_to_entity_id(self, number): + """Convert unique number to entity id.""" + if self.type == TYPE_ALEXA: + return number + + # Google Home + assert isinstance(number, str) + return self.numbers.get(number) + + def is_entity_exposed(self, entity): + """Determine if an entity should be exposed on the emulated bridge. + + Async friendly. + """ + if entity.attributes.get('view') is not None: + # Ignore entities that are views + return False + + domain = entity.domain.lower() + explicit_expose = entity.attributes.get(ATTR_EMULATED_HUE, None) + + domain_exposed_by_default = \ + self.expose_by_default and domain in self.exposed_domains + + # Expose an entity if the entity's domain is exposed by default and + # the configuration doesn't explicitly exclude it from being + # exposed, or if the entity is explicitly exposed + is_default_exposed = \ + domain_exposed_by_default and explicit_expose is not False + + return is_default_exposed or explicit_expose diff --git a/homeassistant/components/emulated_hue/hue_api.py b/homeassistant/components/emulated_hue/hue_api.py new file mode 100644 index 00000000000..ed06da9495b --- /dev/null +++ b/homeassistant/components/emulated_hue/hue_api.py @@ -0,0 +1,275 @@ +"""Provides a Hue API to control Home Assistant.""" +import asyncio +import logging + +from aiohttp import web + +from homeassistant import core +from homeassistant.const import ( + ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, SERVICE_TURN_OFF, SERVICE_TURN_ON, + STATE_ON, STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, +) +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, ATTR_SUPPORTED_FEATURES, SUPPORT_BRIGHTNESS +) +from homeassistant.components.http import HomeAssistantView + +_LOGGER = logging.getLogger(__name__) + +ATTR_EMULATED_HUE = 'emulated_hue' +ATTR_EMULATED_HUE_NAME = 'emulated_hue_name' + +HUE_API_STATE_ON = 'on' +HUE_API_STATE_BRI = 'bri' + + +class HueUsernameView(HomeAssistantView): + """Handle requests to create a username for the emulated hue bridge.""" + + url = '/api' + name = 'emulated_hue:api:create_username' + extra_urls = ['/api/'] + requires_auth = False + + @asyncio.coroutine + def post(self, request): + """Handle a POST request.""" + try: + data = yield from request.json() + except ValueError: + return self.json_message('Invalid JSON', HTTP_BAD_REQUEST) + + if 'devicetype' not in data: + return self.json_message('devicetype not specified', + HTTP_BAD_REQUEST) + + return self.json([{'success': {'username': '12345678901234567890'}}]) + + +class HueAllLightsStateView(HomeAssistantView): + """Handle requests for getting and setting info about entities.""" + + url = '/api/{username}/lights' + name = 'emulated_hue:lights:state' + requires_auth = False + + def __init__(self, config): + """Initialize the instance of the view.""" + self.config = config + + @core.callback + def get(self, request, username): + """Process a request to get the list of available lights.""" + hass = request.app['hass'] + json_response = {} + + for entity in hass.states.async_all(): + if self.config.is_entity_exposed(entity): + number = self.config.entity_id_to_number(entity.entity_id) + json_response[number] = entity_to_json(entity) + + return self.json(json_response) + + +class HueOneLightStateView(HomeAssistantView): + """Handle requests for getting and setting info about entities.""" + + url = '/api/{username}/lights/{entity_id}' + name = 'emulated_hue:light:state' + requires_auth = False + + def __init__(self, config): + """Initialize the instance of the view.""" + self.config = config + + @core.callback + def get(self, request, username, entity_id=None): + """Process a request to get the state of an individual light.""" + hass = request.app['hass'] + entity_id = self.config.number_to_entity_id(entity_id) + entity = hass.states.get(entity_id) + + if entity is None: + _LOGGER.error('Entity not found: %s', entity_id) + return web.Response(text="Entity not found", status=404) + + if not self.config.is_entity_exposed(entity): + _LOGGER.error('Entity not exposed: %s', entity_id) + return web.Response(text="Entity not exposed", status=404) + + cached_state = self.config.cached_states.get(entity_id, None) + + if cached_state is None: + final_state = entity.state == STATE_ON + final_brightness = entity.attributes.get( + ATTR_BRIGHTNESS, 255 if final_state else 0) + else: + final_state, final_brightness = cached_state + + json_response = entity_to_json(entity, final_state, final_brightness) + + return self.json(json_response) + + +class HueOneLightChangeView(HomeAssistantView): + """Handle requests for getting and setting info about entities.""" + + url = '/api/{username}/lights/{entity_number}/state' + name = 'emulated_hue:light:state' + requires_auth = False + + def __init__(self, config): + """Initialize the instance of the view.""" + self.config = config + + @asyncio.coroutine + def put(self, request, username, entity_number): + """Process a request to set the state of an individual light.""" + config = self.config + hass = request.app['hass'] + entity_id = config.number_to_entity_id(entity_number) + + if entity_id is None: + _LOGGER.error('Unknown entity number: %s', entity_number) + return self.json_message('Entity not found', HTTP_NOT_FOUND) + + entity = hass.states.get(entity_id) + + if entity is None: + _LOGGER.error('Entity not found: %s', entity_id) + return self.json_message('Entity not found', HTTP_NOT_FOUND) + + if not config.is_entity_exposed(entity): + _LOGGER.error('Entity not exposed: %s', entity_id) + return web.Response(text="Entity not exposed", status=404) + + try: + request_json = yield from request.json() + except ValueError: + _LOGGER.error('Received invalid json') + return self.json_message('Invalid JSON', HTTP_BAD_REQUEST) + + # Parse the request into requested "on" status and brightness + parsed = parse_hue_api_put_light_body(request_json, entity) + + if parsed is None: + _LOGGER.error('Unable to parse data: %s', request_json) + return web.Response(text="Bad request", status=400) + + result, brightness = parsed + + # Convert the resulting "on" status into the service we need to call + service = SERVICE_TURN_ON if result else SERVICE_TURN_OFF + + # Construct what we need to send to the service + data = {ATTR_ENTITY_ID: entity_id} + + # If the requested entity is a script add some variables + if entity.domain == "script": + data['variables'] = { + 'requested_state': STATE_ON if result else STATE_OFF + } + + if brightness is not None: + data['variables']['requested_level'] = brightness + + elif brightness is not None: + data[ATTR_BRIGHTNESS] = brightness + + if entity.domain in config.off_maps_to_on_domains: + # Map the off command to on + service = SERVICE_TURN_ON + + # Caching is required because things like scripts and scenes won't + # report as "off" to Alexa if an "off" command is received, because + # they'll map to "on". Thus, instead of reporting its actual + # status, we report what Alexa will want to see, which is the same + # as the actual requested command. + config.cached_states[entity_id] = (result, brightness) + + # Perform the requested action + yield from hass.services.async_call(core.DOMAIN, service, data, + blocking=True) + + json_response = \ + [create_hue_success_response(entity_id, HUE_API_STATE_ON, result)] + + if brightness is not None: + json_response.append(create_hue_success_response( + entity_id, HUE_API_STATE_BRI, brightness)) + + return self.json(json_response) + + +def parse_hue_api_put_light_body(request_json, entity): + """Parse the body of a request to change the state of a light.""" + if HUE_API_STATE_ON in request_json: + if not isinstance(request_json[HUE_API_STATE_ON], bool): + return None + + if request_json['on']: + # Echo requested device be turned on + brightness = None + report_brightness = False + result = True + else: + # Echo requested device be turned off + brightness = None + report_brightness = False + result = False + + if HUE_API_STATE_BRI in request_json: + # Make sure the entity actually supports brightness + entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) + + if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS: + try: + # Clamp brightness from 0 to 255 + brightness = \ + max(0, min(int(request_json[HUE_API_STATE_BRI]), 255)) + except ValueError: + return None + + report_brightness = True + result = (brightness > 0) + elif entity.domain.lower() == "script": + # Convert 0-255 to 0-100 + level = int(request_json[HUE_API_STATE_BRI]) / 255 * 100 + + brightness = round(level) + report_brightness = True + result = True + + return (result, brightness) if report_brightness else (result, None) + + +def entity_to_json(entity, is_on=None, brightness=None): + """Convert an entity to its Hue bridge JSON representation.""" + if is_on is None: + is_on = entity.state == STATE_ON + + if brightness is None: + brightness = 255 if is_on else 0 + + name = entity.attributes.get( + ATTR_EMULATED_HUE_NAME, entity.attributes[ATTR_FRIENDLY_NAME]) + + return { + 'state': + { + HUE_API_STATE_ON: is_on, + HUE_API_STATE_BRI: brightness, + 'reachable': True + }, + 'type': 'Dimmable light', + 'name': name, + 'modelid': 'HASS123', + 'uniqueid': entity.entity_id, + 'swversion': '123' + } + + +def create_hue_success_response(entity_id, attr, value): + """Create a success response for an attribute set on a light.""" + success_key = '/lights/{}/state/{}'.format(entity_id, attr) + return {'success': {success_key: value}} diff --git a/homeassistant/components/emulated_hue/upnp.py b/homeassistant/components/emulated_hue/upnp.py new file mode 100644 index 00000000000..f81a8c1b68d --- /dev/null +++ b/homeassistant/components/emulated_hue/upnp.py @@ -0,0 +1,166 @@ +"""Provides a UPNP discovery method that mimicks Hue hubs.""" +import threading +import socket +import logging +import os +import select + +from aiohttp import web + +from homeassistant import core +from homeassistant.components.http import HomeAssistantView + +_LOGGER = logging.getLogger(__name__) + + +class DescriptionXmlView(HomeAssistantView): + """Handles requests for the description.xml file.""" + + url = '/description.xml' + name = 'description:xml' + requires_auth = False + + def __init__(self, config): + """Initialize the instance of the view.""" + self.config = config + + @core.callback + def get(self, request): + """Handle a GET request.""" + xml_template = """ + + +1 +0 + +http://{0}:{1}/ + +urn:schemas-upnp-org:device:Basic:1 +HASS Bridge ({0}) +Royal Philips Electronics +http://www.philips.com +Philips hue Personal Wireless Lighting +Philips hue bridge 2015 +BSB002 +http://www.meethue.com +1234 +uuid:2f402f80-da50-11e1-9b23-001788255acc + + +""" + + resp_text = xml_template.format( + self.config.host_ip_addr, self.config.listen_port) + + return web.Response(text=resp_text, content_type='text/xml') + + +class UPNPResponderThread(threading.Thread): + """Handle responding to UPNP/SSDP discovery requests.""" + + _interrupted = False + + def __init__(self, host_ip_addr, listen_port): + """Initialize the class.""" + threading.Thread.__init__(self) + + self.host_ip_addr = host_ip_addr + self.listen_port = listen_port + + # Note that the double newline at the end of + # this string is required per the SSDP spec + resp_template = """HTTP/1.1 200 OK +CACHE-CONTROL: max-age=60 +EXT: +LOCATION: http://{0}:{1}/description.xml +SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1 +ST: urn:schemas-upnp-org:device:basic:1 +USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1 + +""" + + self.upnp_response = resp_template.format(host_ip_addr, listen_port) \ + .replace("\n", "\r\n") \ + .encode('utf-8') + + # Set up a pipe for signaling to the receiver that it's time to + # shutdown. Essentially, we place the SSDP socket into nonblocking + # mode and use select() to wait for data to arrive on either the SSDP + # socket or the pipe. If data arrives on either one, select() returns + # and tells us which filenos have data ready to read. + # + # When we want to stop the responder, we write data to the pipe, which + # causes the select() to return and indicate that said pipe has data + # ready to be read, which indicates to us that the responder needs to + # be shutdown. + self._interrupted_read_pipe, self._interrupted_write_pipe = os.pipe() + + def run(self): + """Run the server.""" + # Listen for UDP port 1900 packets sent to SSDP multicast address + ssdp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + ssdp_socket.setblocking(False) + + # Required for receiving multicast + ssdp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + ssdp_socket.setsockopt( + socket.SOL_IP, + socket.IP_MULTICAST_IF, + socket.inet_aton(self.host_ip_addr)) + + ssdp_socket.setsockopt( + socket.SOL_IP, + socket.IP_ADD_MEMBERSHIP, + socket.inet_aton("239.255.255.250") + + socket.inet_aton(self.host_ip_addr)) + + ssdp_socket.bind(("239.255.255.250", 1900)) + + while True: + if self._interrupted: + clean_socket_close(ssdp_socket) + return + + try: + read, _, _ = select.select( + [self._interrupted_read_pipe, ssdp_socket], [], + [ssdp_socket]) + + if self._interrupted_read_pipe in read: + # Implies self._interrupted is True + clean_socket_close(ssdp_socket) + return + elif ssdp_socket in read: + data, addr = ssdp_socket.recvfrom(1024) + else: + continue + except socket.error as ex: + if self._interrupted: + clean_socket_close(ssdp_socket) + return + + _LOGGER.error("UPNP Responder socket exception occured: %s", + ex.__str__) + + if "M-SEARCH" in data.decode('utf-8'): + # SSDP M-SEARCH method received, respond to it with our info + resp_socket = socket.socket( + socket.AF_INET, socket.SOCK_DGRAM) + + resp_socket.sendto(self.upnp_response, addr) + resp_socket.close() + + def stop(self): + """Stop the server.""" + # Request for server + self._interrupted = True + os.write(self._interrupted_write_pipe, bytes([0])) + self.join() + + +def clean_socket_close(sock): + """Close a socket connection and logs its closure.""" + _LOGGER.info("UPNP responder shutting down.") + + sock.close() diff --git a/tests/components/emulated_hue/__init__.py b/tests/components/emulated_hue/__init__.py new file mode 100644 index 00000000000..b13b95a080a --- /dev/null +++ b/tests/components/emulated_hue/__init__.py @@ -0,0 +1 @@ +"""Tests for emulated_hue.""" diff --git a/tests/components/test_emulated_hue.py b/tests/components/emulated_hue/test_hue_api.py old mode 100755 new mode 100644 similarity index 78% rename from tests/components/test_emulated_hue.py rename to tests/components/emulated_hue/test_hue_api.py index 7bb8da09e47..9cee27f570f --- a/tests/components/test_emulated_hue.py +++ b/tests/components/emulated_hue/test_hue_api.py @@ -1,429 +1,355 @@ -"""The tests for the emulated Hue component.""" -import json - -import unittest -import requests - -from homeassistant import bootstrap, const, core -import homeassistant.components as core_components -from homeassistant.components import emulated_hue, http, light, script -from homeassistant.const import STATE_ON, STATE_OFF -from homeassistant.components.emulated_hue import ( - HUE_API_STATE_ON, HUE_API_STATE_BRI) -from homeassistant.util.async import run_coroutine_threadsafe - -from tests.common import get_test_instance_port, get_test_home_assistant - -HTTP_SERVER_PORT = get_test_instance_port() -BRIDGE_SERVER_PORT = get_test_instance_port() - -BRIDGE_URL_BASE = 'http://127.0.0.1:{}'.format(BRIDGE_SERVER_PORT) + '{}' -JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON} - - -def setup_hass_instance(emulated_hue_config): - """Set up the Home Assistant instance to test.""" - hass = get_test_home_assistant() - - # We need to do this to get access to homeassistant/turn_(on,off) - run_coroutine_threadsafe( - core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop - ).result() - - bootstrap.setup_component( - hass, http.DOMAIN, - {http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}}) - - bootstrap.setup_component(hass, emulated_hue.DOMAIN, emulated_hue_config) - - return hass - - -def start_hass_instance(hass): - """Start the Home Assistant instance to test.""" - hass.start() - - -class TestEmulatedHue(unittest.TestCase): - """Test the emulated Hue component.""" - - hass = None - - @classmethod - def setUpClass(cls): - """Setup the class.""" - cls.hass = setup_hass_instance({ - emulated_hue.DOMAIN: { - emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT - }}) - - start_hass_instance(cls.hass) - - @classmethod - def tearDownClass(cls): - """Stop the class.""" - cls.hass.stop() - - def test_description_xml(self): - """Test the description.""" - import xml.etree.ElementTree as ET - - result = requests.get( - BRIDGE_URL_BASE.format('/description.xml'), timeout=5) - - self.assertEqual(result.status_code, 200) - self.assertTrue('text/xml' in result.headers['content-type']) - - # Make sure the XML is parsable - # pylint: disable=bare-except - try: - ET.fromstring(result.text) - except: - self.fail('description.xml is not valid XML!') - - def test_create_username(self): - """Test the creation of an username.""" - request_json = {'devicetype': 'my_device'} - - result = requests.post( - BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json), - timeout=5) - - self.assertEqual(result.status_code, 200) - self.assertTrue('application/json' in result.headers['content-type']) - - resp_json = result.json() - success_json = resp_json[0] - - self.assertTrue('success' in success_json) - self.assertTrue('username' in success_json['success']) - - def test_valid_username_request(self): - """Test request with a valid username.""" - request_json = {'invalid_key': 'my_device'} - - result = requests.post( - BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json), - timeout=5) - - self.assertEqual(result.status_code, 400) - - -class TestEmulatedHueExposedByDefault(unittest.TestCase): - """Test class for emulated hue component.""" - - @classmethod - def setUpClass(cls): - """Setup the class.""" - cls.hass = setup_hass_instance({ - emulated_hue.DOMAIN: { - emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT, - emulated_hue.CONF_EXPOSE_BY_DEFAULT: True - } - }) - - bootstrap.setup_component(cls.hass, light.DOMAIN, { - 'light': [ - { - 'platform': 'demo', - } - ] - }) - - bootstrap.setup_component(cls.hass, script.DOMAIN, { - 'script': { - 'set_kitchen_light': { - 'sequence': [ - { - 'service_template': - "light.turn_{{ requested_state }}", - 'data_template': { - 'entity_id': 'light.kitchen_lights', - 'brightness': "{{ requested_level }}" - } - } - ] - } - } - }) - - start_hass_instance(cls.hass) - - # Kitchen light is explicitly excluded from being exposed - kitchen_light_entity = cls.hass.states.get('light.kitchen_lights') - attrs = dict(kitchen_light_entity.attributes) - attrs[emulated_hue.ATTR_EMULATED_HUE] = False - cls.hass.states.set( - kitchen_light_entity.entity_id, kitchen_light_entity.state, - attributes=attrs) - - # Expose the script - script_entity = cls.hass.states.get('script.set_kitchen_light') - attrs = dict(script_entity.attributes) - attrs[emulated_hue.ATTR_EMULATED_HUE] = True - cls.hass.states.set( - script_entity.entity_id, script_entity.state, attributes=attrs - ) - - @classmethod - def tearDownClass(cls): - """Stop the class.""" - cls.hass.stop() - - def test_discover_lights(self): - """Test the discovery of lights.""" - result = requests.get( - BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5) - - self.assertEqual(result.status_code, 200) - self.assertTrue('application/json' in result.headers['content-type']) - - result_json = result.json() - - # Make sure the lights we added to the config are there - self.assertTrue('light.ceiling_lights' in result_json) - self.assertTrue('light.bed_light' in result_json) - self.assertTrue('script.set_kitchen_light' in result_json) - self.assertTrue('light.kitchen_lights' not in result_json) - - def test_get_light_state(self): - """Test the getting of light state.""" - # Turn office light on and set to 127 brightness - self.hass.services.call( - light.DOMAIN, const.SERVICE_TURN_ON, - { - const.ATTR_ENTITY_ID: 'light.ceiling_lights', - light.ATTR_BRIGHTNESS: 127 - }, - blocking=True) - - office_json = self.perform_get_light_state('light.ceiling_lights', 200) - - self.assertEqual(office_json['state'][HUE_API_STATE_ON], True) - self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127) - - # Turn bedroom light off - self.hass.services.call( - light.DOMAIN, const.SERVICE_TURN_OFF, - { - const.ATTR_ENTITY_ID: 'light.bed_light' - }, - blocking=True) - - bedroom_json = self.perform_get_light_state('light.bed_light', 200) - - self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False) - self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0) - - # Make sure kitchen light isn't accessible - kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights') - kitchen_result = requests.get( - BRIDGE_URL_BASE.format(kitchen_url), timeout=5) - - self.assertEqual(kitchen_result.status_code, 404) - - def test_put_light_state(self): - """Test the seeting of light states.""" - self.perform_put_test_on_ceiling_lights() - - # Turn the bedroom light on first - self.hass.services.call( - light.DOMAIN, const.SERVICE_TURN_ON, - {const.ATTR_ENTITY_ID: 'light.bed_light', - light.ATTR_BRIGHTNESS: 153}, - blocking=True) - - bed_light = self.hass.states.get('light.bed_light') - self.assertEqual(bed_light.state, STATE_ON) - self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153) - - # Go through the API to turn it off - bedroom_result = self.perform_put_light_state( - 'light.bed_light', False) - - bedroom_result_json = bedroom_result.json() - - self.assertEqual(bedroom_result.status_code, 200) - self.assertTrue( - 'application/json' in bedroom_result.headers['content-type']) - - self.assertEqual(len(bedroom_result_json), 1) - - # Check to make sure the state changed - bed_light = self.hass.states.get('light.bed_light') - self.assertEqual(bed_light.state, STATE_OFF) - - # Make sure we can't change the kitchen light state - kitchen_result = self.perform_put_light_state( - 'light.kitchen_light', True) - self.assertEqual(kitchen_result.status_code, 404) - - def test_put_light_state_script(self): - """Test the setting of script variables.""" - # Turn the kitchen light off first - self.hass.services.call( - light.DOMAIN, const.SERVICE_TURN_OFF, - {const.ATTR_ENTITY_ID: 'light.kitchen_lights'}, - blocking=True) - - # Emulated hue converts 0-100% to 0-255. - level = 23 - brightness = round(level * 255 / 100) - - script_result = self.perform_put_light_state( - 'script.set_kitchen_light', True, brightness) - - script_result_json = script_result.json() - - self.assertEqual(script_result.status_code, 200) - self.assertEqual(len(script_result_json), 2) - - # Wait until script is complete before continuing - self.hass.block_till_done() - - kitchen_light = self.hass.states.get('light.kitchen_lights') - self.assertEqual(kitchen_light.state, 'on') - self.assertEqual( - kitchen_light.attributes[light.ATTR_BRIGHTNESS], - level) - - # pylint: disable=invalid-name - def test_put_with_form_urlencoded_content_type(self): - """Test the form with urlencoded content.""" - # Needed for Alexa - self.perform_put_test_on_ceiling_lights( - 'application/x-www-form-urlencoded') - - # Make sure we fail gracefully when we can't parse the data - data = {'key1': 'value1', 'key2': 'value2'} - result = requests.put( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}/state'.format( - 'light.ceiling_lights')), data=data) - - self.assertEqual(result.status_code, 400) - - def test_entity_not_found(self): - """Test for entity which are not found.""" - result = requests.get( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}'.format("not.existant_entity")), - timeout=5) - - self.assertEqual(result.status_code, 404) - - result = requests.put( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}/state'.format("non.existant_entity")), - timeout=5) - - self.assertEqual(result.status_code, 404) - - def test_allowed_methods(self): - """Test the allowed methods.""" - result = requests.get( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}/state'.format( - "light.ceiling_lights"))) - - self.assertEqual(result.status_code, 405) - - result = requests.put( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}'.format("light.ceiling_lights")), - data={'key1': 'value1'}) - - self.assertEqual(result.status_code, 405) - - result = requests.put( - BRIDGE_URL_BASE.format('/api/username/lights'), - data={'key1': 'value1'}) - - self.assertEqual(result.status_code, 405) - - def test_proper_put_state_request(self): - """Test the request to set the state.""" - # Test proper on value parsing - result = requests.put( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}/state'.format( - 'light.ceiling_lights')), - data=json.dumps({HUE_API_STATE_ON: 1234})) - - self.assertEqual(result.status_code, 400) - - # Test proper brightness value parsing - result = requests.put( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}/state'.format( - 'light.ceiling_lights')), data=json.dumps({ - HUE_API_STATE_ON: True, - HUE_API_STATE_BRI: 'Hello world!' - })) - - self.assertEqual(result.status_code, 400) - - # pylint: disable=invalid-name - def perform_put_test_on_ceiling_lights(self, - content_type='application/json'): - """Test the setting of a light.""" - # Turn the office light off first - self.hass.services.call( - light.DOMAIN, const.SERVICE_TURN_OFF, - {const.ATTR_ENTITY_ID: 'light.ceiling_lights'}, - blocking=True) - - ceiling_lights = self.hass.states.get('light.ceiling_lights') - self.assertEqual(ceiling_lights.state, STATE_OFF) - - # Go through the API to turn it on - office_result = self.perform_put_light_state( - 'light.ceiling_lights', True, 56, content_type) - - office_result_json = office_result.json() - - self.assertEqual(office_result.status_code, 200) - self.assertTrue( - 'application/json' in office_result.headers['content-type']) - - self.assertEqual(len(office_result_json), 2) - - # Check to make sure the state changed - ceiling_lights = self.hass.states.get('light.ceiling_lights') - self.assertEqual(ceiling_lights.state, STATE_ON) - self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56) - - def perform_get_light_state(self, entity_id, expected_status): - """Test the gettting of a light state.""" - result = requests.get( - BRIDGE_URL_BASE.format( - '/api/username/lights/{}'.format(entity_id)), timeout=5) - - self.assertEqual(result.status_code, expected_status) - - if expected_status == 200: - self.assertTrue( - 'application/json' in result.headers['content-type']) - - return result.json() - - return None - - # pylint: disable=no-self-use - def perform_put_light_state(self, entity_id, is_on, brightness=None, - content_type='application/json'): - """Test the setting of a light state.""" - url = BRIDGE_URL_BASE.format( - '/api/username/lights/{}/state'.format(entity_id)) - - req_headers = {'Content-Type': content_type} - - data = {HUE_API_STATE_ON: is_on} - - if brightness is not None: - data[HUE_API_STATE_BRI] = brightness - - result = requests.put( - url, data=json.dumps(data), timeout=5, headers=req_headers) - - return result +"""The tests for the emulated Hue component.""" +import json + +import unittest +from unittest.mock import patch +import requests + +from homeassistant import bootstrap, const, core +import homeassistant.components as core_components +from homeassistant.components import emulated_hue, http, light, script +from homeassistant.const import STATE_ON, STATE_OFF +from homeassistant.components.emulated_hue.hue_api import ( + HUE_API_STATE_ON, HUE_API_STATE_BRI) +from homeassistant.util.async import run_coroutine_threadsafe + +from tests.common import get_test_instance_port, get_test_home_assistant + +HTTP_SERVER_PORT = get_test_instance_port() +BRIDGE_SERVER_PORT = get_test_instance_port() + +BRIDGE_URL_BASE = 'http://127.0.0.1:{}'.format(BRIDGE_SERVER_PORT) + '{}' +JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON} + + +class TestEmulatedHueExposedByDefault(unittest.TestCase): + """Test class for emulated hue component.""" + + @classmethod + def setUpClass(cls): + """Setup the class.""" + cls.hass = hass = get_test_home_assistant() + + # We need to do this to get access to homeassistant/turn_(on,off) + run_coroutine_threadsafe( + core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop + ).result() + + bootstrap.setup_component( + hass, http.DOMAIN, + {http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}}) + + with patch('homeassistant.components' + '.emulated_hue.UPNPResponderThread'): + bootstrap.setup_component(hass, emulated_hue.DOMAIN, { + emulated_hue.DOMAIN: { + emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT, + emulated_hue.CONF_EXPOSE_BY_DEFAULT: True + } + }) + + bootstrap.setup_component(cls.hass, light.DOMAIN, { + 'light': [ + { + 'platform': 'demo', + } + ] + }) + + bootstrap.setup_component(cls.hass, script.DOMAIN, { + 'script': { + 'set_kitchen_light': { + 'sequence': [ + { + 'service_template': + "light.turn_{{ requested_state }}", + 'data_template': { + 'entity_id': 'light.kitchen_lights', + 'brightness': "{{ requested_level }}" + } + } + ] + } + } + }) + + cls.hass.start() + + # Kitchen light is explicitly excluded from being exposed + kitchen_light_entity = cls.hass.states.get('light.kitchen_lights') + attrs = dict(kitchen_light_entity.attributes) + attrs[emulated_hue.ATTR_EMULATED_HUE] = False + cls.hass.states.set( + kitchen_light_entity.entity_id, kitchen_light_entity.state, + attributes=attrs) + + # Expose the script + script_entity = cls.hass.states.get('script.set_kitchen_light') + attrs = dict(script_entity.attributes) + attrs[emulated_hue.ATTR_EMULATED_HUE] = True + cls.hass.states.set( + script_entity.entity_id, script_entity.state, attributes=attrs + ) + + @classmethod + def tearDownClass(cls): + """Stop the class.""" + cls.hass.stop() + + def test_discover_lights(self): + """Test the discovery of lights.""" + result = requests.get( + BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5) + + self.assertEqual(result.status_code, 200) + self.assertTrue('application/json' in result.headers['content-type']) + + result_json = result.json() + + # Make sure the lights we added to the config are there + self.assertTrue('light.ceiling_lights' in result_json) + self.assertTrue('light.bed_light' in result_json) + self.assertTrue('script.set_kitchen_light' in result_json) + self.assertTrue('light.kitchen_lights' not in result_json) + + def test_get_light_state(self): + """Test the getting of light state.""" + # Turn office light on and set to 127 brightness + self.hass.services.call( + light.DOMAIN, const.SERVICE_TURN_ON, + { + const.ATTR_ENTITY_ID: 'light.ceiling_lights', + light.ATTR_BRIGHTNESS: 127 + }, + blocking=True) + + office_json = self.perform_get_light_state('light.ceiling_lights', 200) + + self.assertEqual(office_json['state'][HUE_API_STATE_ON], True) + self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127) + + # Turn bedroom light off + self.hass.services.call( + light.DOMAIN, const.SERVICE_TURN_OFF, + { + const.ATTR_ENTITY_ID: 'light.bed_light' + }, + blocking=True) + + bedroom_json = self.perform_get_light_state('light.bed_light', 200) + + self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False) + self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0) + + # Make sure kitchen light isn't accessible + kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights') + kitchen_result = requests.get( + BRIDGE_URL_BASE.format(kitchen_url), timeout=5) + + self.assertEqual(kitchen_result.status_code, 404) + + def test_put_light_state(self): + """Test the seeting of light states.""" + self.perform_put_test_on_ceiling_lights() + + # Turn the bedroom light on first + self.hass.services.call( + light.DOMAIN, const.SERVICE_TURN_ON, + {const.ATTR_ENTITY_ID: 'light.bed_light', + light.ATTR_BRIGHTNESS: 153}, + blocking=True) + + bed_light = self.hass.states.get('light.bed_light') + self.assertEqual(bed_light.state, STATE_ON) + self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153) + + # Go through the API to turn it off + bedroom_result = self.perform_put_light_state( + 'light.bed_light', False) + + bedroom_result_json = bedroom_result.json() + + self.assertEqual(bedroom_result.status_code, 200) + self.assertTrue( + 'application/json' in bedroom_result.headers['content-type']) + + self.assertEqual(len(bedroom_result_json), 1) + + # Check to make sure the state changed + bed_light = self.hass.states.get('light.bed_light') + self.assertEqual(bed_light.state, STATE_OFF) + + # Make sure we can't change the kitchen light state + kitchen_result = self.perform_put_light_state( + 'light.kitchen_light', True) + self.assertEqual(kitchen_result.status_code, 404) + + def test_put_light_state_script(self): + """Test the setting of script variables.""" + # Turn the kitchen light off first + self.hass.services.call( + light.DOMAIN, const.SERVICE_TURN_OFF, + {const.ATTR_ENTITY_ID: 'light.kitchen_lights'}, + blocking=True) + + # Emulated hue converts 0-100% to 0-255. + level = 23 + brightness = round(level * 255 / 100) + + script_result = self.perform_put_light_state( + 'script.set_kitchen_light', True, brightness) + + script_result_json = script_result.json() + + self.assertEqual(script_result.status_code, 200) + self.assertEqual(len(script_result_json), 2) + + # Wait until script is complete before continuing + self.hass.block_till_done() + + kitchen_light = self.hass.states.get('light.kitchen_lights') + self.assertEqual(kitchen_light.state, 'on') + self.assertEqual( + kitchen_light.attributes[light.ATTR_BRIGHTNESS], + level) + + # pylint: disable=invalid-name + def test_put_with_form_urlencoded_content_type(self): + """Test the form with urlencoded content.""" + # Needed for Alexa + self.perform_put_test_on_ceiling_lights( + 'application/x-www-form-urlencoded') + + # Make sure we fail gracefully when we can't parse the data + data = {'key1': 'value1', 'key2': 'value2'} + result = requests.put( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}/state'.format( + 'light.ceiling_lights')), data=data) + + self.assertEqual(result.status_code, 400) + + def test_entity_not_found(self): + """Test for entity which are not found.""" + result = requests.get( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}'.format("not.existant_entity")), + timeout=5) + + self.assertEqual(result.status_code, 404) + + result = requests.put( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}/state'.format("non.existant_entity")), + timeout=5) + + self.assertEqual(result.status_code, 404) + + def test_allowed_methods(self): + """Test the allowed methods.""" + result = requests.get( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}/state'.format( + "light.ceiling_lights"))) + + self.assertEqual(result.status_code, 405) + + result = requests.put( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}'.format("light.ceiling_lights")), + data={'key1': 'value1'}) + + self.assertEqual(result.status_code, 405) + + result = requests.put( + BRIDGE_URL_BASE.format('/api/username/lights'), + data={'key1': 'value1'}) + + self.assertEqual(result.status_code, 405) + + def test_proper_put_state_request(self): + """Test the request to set the state.""" + # Test proper on value parsing + result = requests.put( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}/state'.format( + 'light.ceiling_lights')), + data=json.dumps({HUE_API_STATE_ON: 1234})) + + self.assertEqual(result.status_code, 400) + + # Test proper brightness value parsing + result = requests.put( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}/state'.format( + 'light.ceiling_lights')), data=json.dumps({ + HUE_API_STATE_ON: True, + HUE_API_STATE_BRI: 'Hello world!' + })) + + self.assertEqual(result.status_code, 400) + + # pylint: disable=invalid-name + def perform_put_test_on_ceiling_lights(self, + content_type='application/json'): + """Test the setting of a light.""" + # Turn the office light off first + self.hass.services.call( + light.DOMAIN, const.SERVICE_TURN_OFF, + {const.ATTR_ENTITY_ID: 'light.ceiling_lights'}, + blocking=True) + + ceiling_lights = self.hass.states.get('light.ceiling_lights') + self.assertEqual(ceiling_lights.state, STATE_OFF) + + # Go through the API to turn it on + office_result = self.perform_put_light_state( + 'light.ceiling_lights', True, 56, content_type) + + office_result_json = office_result.json() + + self.assertEqual(office_result.status_code, 200) + self.assertTrue( + 'application/json' in office_result.headers['content-type']) + + self.assertEqual(len(office_result_json), 2) + + # Check to make sure the state changed + ceiling_lights = self.hass.states.get('light.ceiling_lights') + self.assertEqual(ceiling_lights.state, STATE_ON) + self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56) + + def perform_get_light_state(self, entity_id, expected_status): + """Test the gettting of a light state.""" + result = requests.get( + BRIDGE_URL_BASE.format( + '/api/username/lights/{}'.format(entity_id)), timeout=5) + + self.assertEqual(result.status_code, expected_status) + + if expected_status == 200: + self.assertTrue( + 'application/json' in result.headers['content-type']) + + return result.json() + + return None + + # pylint: disable=no-self-use + def perform_put_light_state(self, entity_id, is_on, brightness=None, + content_type='application/json'): + """Test the setting of a light state.""" + url = BRIDGE_URL_BASE.format( + '/api/username/lights/{}/state'.format(entity_id)) + + req_headers = {'Content-Type': content_type} + + data = {HUE_API_STATE_ON: is_on} + + if brightness is not None: + data[HUE_API_STATE_BRI] = brightness + + result = requests.put( + url, data=json.dumps(data), timeout=5, headers=req_headers) + + return result diff --git a/tests/components/emulated_hue/test_init.py b/tests/components/emulated_hue/test_init.py new file mode 100755 index 00000000000..ec3cc0a11cb --- /dev/null +++ b/tests/components/emulated_hue/test_init.py @@ -0,0 +1,55 @@ +from unittest.mock import patch + +from homeassistant.components.emulated_hue import Config, _LOGGER + + +def test_config_google_home_entity_id_to_number(): + """Test config adheres to the type.""" + conf = Config({ + 'type': 'google_home' + }) + + number = conf.entity_id_to_number('light.test') + assert number == '1' + + number = conf.entity_id_to_number('light.test') + assert number == '1' + + number = conf.entity_id_to_number('light.test2') + assert number == '2' + + entity_id = conf.number_to_entity_id('1') + assert entity_id == 'light.test' + + +def test_config_alexa_entity_id_to_number(): + """Test config adheres to the type.""" + conf = Config({ + 'type': 'alexa' + }) + + number = conf.entity_id_to_number('light.test') + assert number == 'light.test' + + number = conf.entity_id_to_number('light.test') + assert number == 'light.test' + + number = conf.entity_id_to_number('light.test2') + assert number == 'light.test2' + + entity_id = conf.number_to_entity_id('light.test') + assert entity_id == 'light.test' + + +def test_warning_config_google_home_listen_port(): + """Test we warn when non-default port is used for Google Home.""" + with patch.object(_LOGGER, 'warning') as mock_warn: + Config({ + 'type': 'google_home', + 'host_ip': '123.123.123.123', + 'listen_port': 8300 + }) + + assert mock_warn.called + assert mock_warn.mock_calls[0][1][0] == \ + "When targetting Google Home, listening port has to be port 80" diff --git a/tests/components/emulated_hue/test_upnp.py b/tests/components/emulated_hue/test_upnp.py new file mode 100644 index 00000000000..03b9e993a9b --- /dev/null +++ b/tests/components/emulated_hue/test_upnp.py @@ -0,0 +1,120 @@ +"""The tests for the emulated Hue component.""" +import json + +import unittest +from unittest.mock import patch +import requests + +from homeassistant import bootstrap, const, core +import homeassistant.components as core_components +from homeassistant.components import emulated_hue, http +from homeassistant.util.async import run_coroutine_threadsafe + +from tests.common import get_test_instance_port, get_test_home_assistant + +HTTP_SERVER_PORT = get_test_instance_port() +BRIDGE_SERVER_PORT = get_test_instance_port() + +BRIDGE_URL_BASE = 'http://127.0.0.1:{}'.format(BRIDGE_SERVER_PORT) + '{}' +JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON} + + +def setup_hass_instance(emulated_hue_config): + """Set up the Home Assistant instance to test.""" + hass = get_test_home_assistant() + + # We need to do this to get access to homeassistant/turn_(on,off) + run_coroutine_threadsafe( + core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop + ).result() + + bootstrap.setup_component( + hass, http.DOMAIN, + {http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}}) + + bootstrap.setup_component(hass, emulated_hue.DOMAIN, emulated_hue_config) + + return hass + + +def start_hass_instance(hass): + """Start the Home Assistant instance to test.""" + hass.start() + + +class TestEmulatedHue(unittest.TestCase): + """Test the emulated Hue component.""" + + hass = None + + @classmethod + def setUpClass(cls): + """Setup the class.""" + cls.hass = hass = get_test_home_assistant() + + # We need to do this to get access to homeassistant/turn_(on,off) + run_coroutine_threadsafe( + core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop + ).result() + + bootstrap.setup_component( + hass, http.DOMAIN, + {http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}}) + + with patch('homeassistant.components' + '.emulated_hue.UPNPResponderThread'): + bootstrap.setup_component(hass, emulated_hue.DOMAIN, { + emulated_hue.DOMAIN: { + emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT + }}) + + cls.hass.start() + + @classmethod + def tearDownClass(cls): + """Stop the class.""" + cls.hass.stop() + + def test_description_xml(self): + """Test the description.""" + import xml.etree.ElementTree as ET + + result = requests.get( + BRIDGE_URL_BASE.format('/description.xml'), timeout=5) + + self.assertEqual(result.status_code, 200) + self.assertTrue('text/xml' in result.headers['content-type']) + + # Make sure the XML is parsable + # pylint: disable=bare-except + try: + ET.fromstring(result.text) + except: + self.fail('description.xml is not valid XML!') + + def test_create_username(self): + """Test the creation of an username.""" + request_json = {'devicetype': 'my_device'} + + result = requests.post( + BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json), + timeout=5) + + self.assertEqual(result.status_code, 200) + self.assertTrue('application/json' in result.headers['content-type']) + + resp_json = result.json() + success_json = resp_json[0] + + self.assertTrue('success' in success_json) + self.assertTrue('username' in success_json['success']) + + def test_valid_username_request(self): + """Test request with a valid username.""" + request_json = {'invalid_key': 'my_device'} + + result = requests.post( + BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json), + timeout=5) + + self.assertEqual(result.status_code, 400) From cffc7ac4d871fe31f5ee75d0cbbff1f70899476b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 4 Dec 2016 10:59:18 -0800 Subject: [PATCH 022/141] Update netdisco to 0.8 (#4723) --- 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 142764ea522..3c4dff6eac5 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.7.7'] +REQUIREMENTS = ['netdisco==0.8.0'] DOMAIN = 'discovery' diff --git a/requirements_all.txt b/requirements_all.txt index 3fdf12c086a..622faa3719d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -296,7 +296,7 @@ mficlient==0.3.0 miflora==0.1.13 # homeassistant.components.discovery -netdisco==0.7.7 +netdisco==0.8.0 # homeassistant.components.sensor.neurio_energy neurio==0.2.10 From 87dab37b8a9aad9e63e49c36d1ded3294b4dc10d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 4 Dec 2016 13:49:46 -0800 Subject: [PATCH 023/141] Fix Nest interpreting Celsius temperature as Fahrenheit (#4729) --- homeassistant/components/climate/nest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index 01c3b3782b1..06ec500f9e2 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -229,7 +229,7 @@ class NestThermostat(ClimateDevice): self._eco_temperature = self.device.eco_temperature self._locked_temperature = self.device.locked_temperature self._is_locked = self.device.is_locked - if self.device.temperature == 'C': + if self.device.temperature_scale == 'C': self._temperature_scale = TEMP_CELSIUS else: self._temperature_scale = TEMP_FAHRENHEIT From 64b1179c1309b8d0b93fd80a29a7f508bcbbc082 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Sun, 4 Dec 2016 17:33:50 -0500 Subject: [PATCH 024/141] Make sure all nest platforms require discovery info (#4734) --- homeassistant/components/binary_sensor/nest.py | 3 +++ homeassistant/components/camera/nest.py | 1 + homeassistant/components/climate/nest.py | 3 ++- homeassistant/components/sensor/nest.py | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/binary_sensor/nest.py b/homeassistant/components/binary_sensor/nest.py index d78e33c9f95..070703df32a 100644 --- a/homeassistant/components/binary_sensor/nest.py +++ b/homeassistant/components/binary_sensor/nest.py @@ -60,6 +60,9 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices, discovery_info=None): """Setup Nest binary sensors.""" + if discovery_info is None: + return + nest = hass.data[DATA_NEST] conf = config.get(CONF_MONITORED_CONDITIONS, _VALID_BINARY_SENSOR_TYPES) diff --git a/homeassistant/components/camera/nest.py b/homeassistant/components/camera/nest.py index 8bda0e8eb9c..aa2041e07a6 100644 --- a/homeassistant/components/camera/nest.py +++ b/homeassistant/components/camera/nest.py @@ -26,6 +26,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up a Nest Cam.""" if discovery_info is None: return + camera_devices = hass.data[nest.DATA_NEST].camera_devices() cameras = [NestCamera(structure, device) for structure, device in camera_devices] diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index 06ec500f9e2..dbc68162579 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -31,10 +31,11 @@ STATE_HEAT_COOL = 'heat-cool' def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Nest thermostat.""" - _LOGGER.debug("Setting up nest thermostat") if discovery_info is None: return + _LOGGER.debug("Setting up nest thermostat") + temp_unit = hass.config.units.temperature_unit add_devices( diff --git a/homeassistant/components/sensor/nest.py b/homeassistant/components/sensor/nest.py index b4909aebae3..53f767ab494 100644 --- a/homeassistant/components/sensor/nest.py +++ b/homeassistant/components/sensor/nest.py @@ -68,6 +68,9 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Nest Sensor.""" + if discovery_info is None: + return + nest = hass.data[DATA_NEST] conf = config.get(CONF_MONITORED_CONDITIONS, _VALID_SENSOR_TYPES) From 2099d023ef0b86195adeaa41d3d80e02dfdfa2ec Mon Sep 17 00:00:00 2001 From: Lukas Date: Mon, 5 Dec 2016 00:08:14 +0100 Subject: [PATCH 025/141] [0.34] bugfix influxdb node_id (#4712) * Bugfix for #4709 - do not convert node_id to float * Update influxdb.py --- homeassistant/components/influxdb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/influxdb.py b/homeassistant/components/influxdb.py index 167767bc00e..08296ad65c7 100644 --- a/homeassistant/components/influxdb.py +++ b/homeassistant/components/influxdb.py @@ -120,7 +120,8 @@ def setup(hass, config): for key, value in state.attributes.items(): if key != 'unit_of_measurement': - if isinstance(value, (str, float, bool)): + if isinstance(value, (str, float, bool)) or \ + key.endswith('_id'): json_body[0]['fields'][key] = value elif isinstance(value, int): # Prevent column data errors in influxDB. From 2b3caa716a66075543856382056fafa72d3718df Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 4 Dec 2016 15:30:55 -0800 Subject: [PATCH 026/141] Cast progress (#4735) * add progress to google cast * Add progress to media player demo --- homeassistant/components/media_player/cast.py | 27 ++++++++ homeassistant/components/media_player/demo.py | 68 ++++++++++++++----- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 1d01f0058ec..0f3b98cab46 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -18,6 +18,7 @@ from homeassistant.const import ( CONF_HOST, STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN) import homeassistant.helpers.config_validation as cv +import homeassistant.util.dt as dt_util REQUIREMENTS = ['pychromecast==0.7.6'] @@ -105,6 +106,7 @@ class CastDevice(MediaPlayerDevice): self.cast_status = self.cast.status self.media_status = self.cast.media_controller.status + self.media_status_received = None @property def should_poll(self): @@ -231,6 +233,30 @@ class CastDevice(MediaPlayerDevice): """Flag of media commands that are supported.""" return SUPPORT_CAST + @property + def media_position(self): + """Position of current playing media in seconds.""" + if self.media_status is None or not ( + self.media_status.player_is_playing or + self.media_status.player_is_idle): + return None + + position = self.media_status.current_time + + if self.media_status.player_is_playing: + position += (dt_util.utcnow() - + self.media_status_received).total_seconds() + + return position + + @property + def media_position_updated_at(self): + """When was the position of the current playing media valid. + + Returns value from homeassistant.util.dt.utcnow(). + """ + return self.media_status_received + def turn_on(self): """Turn on the ChromeCast.""" # The only way we can turn the Chromecast is on is by launching an app @@ -292,4 +318,5 @@ class CastDevice(MediaPlayerDevice): def new_media_status(self, status): """Called when a new media status is received.""" self.media_status = status + self.media_status_received = dt_util.utcnow() self.schedule_update_ha_state() diff --git a/homeassistant/components/media_player/demo.py b/homeassistant/components/media_player/demo.py index 1c1687de319..226ddfe4769 100644 --- a/homeassistant/components/media_player/demo.py +++ b/homeassistant/components/media_player/demo.py @@ -10,6 +10,7 @@ from homeassistant.components.media_player import ( SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_SELECT_SOURCE, SUPPORT_CLEAR_PLAYLIST, MediaPlayerDevice) from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING +import homeassistant.util.dt as dt_util # pylint: disable=unused-argument @@ -18,8 +19,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): add_devices([ DemoYoutubePlayer( 'Living Room', 'eyU3bRy2x44', - '♥♥ The Best Fireplace Video (3 hours)'), - DemoYoutubePlayer('Bedroom', 'kxopViU98Xo', 'Epic sax guy 10 hours'), + '♥♥ The Best Fireplace Video (3 hours)', 300), + DemoYoutubePlayer('Bedroom', 'kxopViU98Xo', 'Epic sax guy 10 hours', + 360000), DemoMusicPlayer(), DemoTVShowPlayer(), ]) @@ -78,32 +80,32 @@ class AbstractDemoPlayer(MediaPlayerDevice): def turn_on(self): """Turn the media player on.""" self._player_state = STATE_PLAYING - self.update_ha_state() + self.schedule_update_ha_state() def turn_off(self): """Turn the media player off.""" self._player_state = STATE_OFF - self.update_ha_state() + self.schedule_update_ha_state() def mute_volume(self, mute): """Mute the volume.""" self._volume_muted = mute - self.update_ha_state() + self.schedule_update_ha_state() def set_volume_level(self, volume): """Set the volume level, range 0..1.""" self._volume_level = volume - self.update_ha_state() + self.schedule_update_ha_state() def media_play(self): """Send play command.""" self._player_state = STATE_PLAYING - self.update_ha_state() + self.schedule_update_ha_state() def media_pause(self): """Send pause command.""" self._player_state = STATE_PAUSED - self.update_ha_state() + self.schedule_update_ha_state() class DemoYoutubePlayer(AbstractDemoPlayer): @@ -111,11 +113,14 @@ class DemoYoutubePlayer(AbstractDemoPlayer): # We only implement the methods that we support - def __init__(self, name, youtube_id=None, media_title=None): + def __init__(self, name, youtube_id=None, media_title=None, duration=360): """Initialize the demo device.""" super().__init__(name) self.youtube_id = youtube_id self._media_title = media_title + self._duration = duration + self._progress = int(duration * .15) + self._progress_updated_at = dt_util.utcnow() @property def media_content_id(self): @@ -130,7 +135,7 @@ class DemoYoutubePlayer(AbstractDemoPlayer): @property def media_duration(self): """Return the duration of current playing media in seconds.""" - return 360 + return self._duration @property def media_image_url(self): @@ -152,10 +157,39 @@ class DemoYoutubePlayer(AbstractDemoPlayer): """Flag of media commands that are supported.""" return YOUTUBE_PLAYER_SUPPORT + @property + def media_position(self): + """Position of current playing media in seconds.""" + if self._progress is None: + return None + + position = self._progress + + if self._player_state == STATE_PLAYING: + position += (dt_util.utcnow() - + self._progress_updated_at).total_seconds() + + return position + + @property + def media_position_updated_at(self): + """When was the position of the current playing media valid. + + Returns value from homeassistant.util.dt.utcnow(). + """ + if self._player_state == STATE_PLAYING: + return self._progress_updated_at + def play_media(self, media_type, media_id, **kwargs): """Play a piece of media.""" self.youtube_id = media_id - self.update_ha_state() + self.schedule_update_ha_state() + + def media_pause(self): + """Send pause command.""" + self._progress = self.media_position + self._progress_updated_at = dt_util.utcnow() + super().media_pause() class DemoMusicPlayer(AbstractDemoPlayer): @@ -249,20 +283,20 @@ class DemoMusicPlayer(AbstractDemoPlayer): """Send previous track command.""" if self._cur_track > 0: self._cur_track -= 1 - self.update_ha_state() + self.schedule_update_ha_state() def media_next_track(self): """Send next track command.""" if self._cur_track < len(self.tracks) - 1: self._cur_track += 1 - self.update_ha_state() + self.schedule_update_ha_state() def clear_playlist(self): """Clear players playlist.""" self.tracks = [] self._cur_track = 0 self._player_state = STATE_OFF - self.update_ha_state() + self.schedule_update_ha_state() class DemoTVShowPlayer(AbstractDemoPlayer): @@ -344,15 +378,15 @@ class DemoTVShowPlayer(AbstractDemoPlayer): """Send previous track command.""" if self._cur_episode > 1: self._cur_episode -= 1 - self.update_ha_state() + self.schedule_update_ha_state() def media_next_track(self): """Send next track command.""" if self._cur_episode < self._episode_count: self._cur_episode += 1 - self.update_ha_state() + self.schedule_update_ha_state() def select_source(self, source): """Set the input source.""" self._source = source - self.update_ha_state() + self.schedule_update_ha_state() From 5a7e44664694d940db4c98b456a6c89b5cc7f694 Mon Sep 17 00:00:00 2001 From: Daniel Hoyer Iversen Date: Sat, 3 Dec 2016 23:44:06 +0100 Subject: [PATCH 027/141] device tracker --- homeassistant/components/device_tracker/__init__.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 91f0720e927..eaa0621b04c 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -332,7 +332,6 @@ class Device(Entity): gps = None # type: GPSType gps_accuracy = 0 last_seen = None # type: dt_util.dt.datetime - battery = None # type: str attributes = None # type: dict vendor = None # type: str @@ -396,9 +395,6 @@ class Device(Entity): attr[ATTR_LONGITUDE] = self.gps[1] attr[ATTR_GPS_ACCURACY] = self.gps_accuracy - if self.battery: - attr[ATTR_BATTERY] = self.battery - if self.attributes: for key, value in self.attributes.items(): attr[key] = value @@ -419,8 +415,13 @@ class Device(Entity): self.host_name = host_name self.location_name = location_name self.gps_accuracy = gps_accuracy or 0 - self.battery = battery - self.attributes = attributes + if (battery or attributes) and self.attributes is None: + self.attributes = {} + if battery: + self.attributes[ATTR_BATTERY] = battery + if attributes: + for key, value in attributes.items(): + self.attributes[key] = value self.gps = None if gps is not None: From 03d19ec2f1b58001fdf829d080f0e0e981c4ebd3 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 5 Dec 2016 11:19:20 +0100 Subject: [PATCH 028/141] Netdata sensor (#4743) * Added netdata sensor * Typo * Add netdata sensor * Improvement of the work done by @ezar --- .coveragerc | 1 + homeassistant/components/sensor/netdata.py | 147 +++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 homeassistant/components/sensor/netdata.py diff --git a/.coveragerc b/.coveragerc index 9078b199a3e..6d5abe745f8 100644 --- a/.coveragerc +++ b/.coveragerc @@ -281,6 +281,7 @@ omit = homeassistant/components/sensor/mhz19.py homeassistant/components/sensor/miflora.py homeassistant/components/sensor/mqtt_room.py + homeassistant/components/sensor/netdata.py homeassistant/components/sensor/neurio_energy.py homeassistant/components/sensor/nut.py homeassistant/components/sensor/nzbget.py diff --git a/homeassistant/components/sensor/netdata.py b/homeassistant/components/sensor/netdata.py new file mode 100644 index 00000000000..3a87eeb5ceb --- /dev/null +++ b/homeassistant/components/sensor/netdata.py @@ -0,0 +1,147 @@ +""" +Support gathering system information of hosts which are running netdata. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.netdata/ +""" +import logging +from datetime import timedelta + +import requests +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + CONF_HOST, CONF_PORT, STATE_UNKNOWN, CONF_NAME, CONF_RESOURCES) +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +_LOGGER = logging.getLogger(__name__) +_RESOURCE = 'api/v1' +_REALTIME = 'before=0&after=-1&options=seconds' + +DEFAULT_HOST = 'localhost' +DEFAULT_NAME = 'Netdata' +DEFAULT_PORT = '19999' + +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) + +SENSOR_TYPES = { + 'memory_free': ['RAM Free', 'MiB', 'system.ram', 'free', 1], + 'memory_used': ['RAM Used', 'MiB', 'system.ram', 'used', 1], + 'memory_cached': ['RAM Cached', 'MiB', 'system.ram', 'cached', 1], + 'memory_buffers': ['RAM Buffers', 'MiB', 'system.ram', 'buffers', 1], + 'swap_free': ['Swap Free', 'MiB', 'system.swap', 'free', 1], + 'swap_used': ['Swap Used', 'MiB', 'system.swap', 'used', 1], + 'processes_running': ['Processes Running', 'Count', 'system.processes', + 'running', 0], + 'processes_blocked': ['Processes Blocked', 'Count', 'system.processes', + 'blocked', 0], + 'system_load': ['System Load', '15 min', 'system.processes', 'running', 2], + 'system_io_in': ['System IO In', 'Count', 'system.io', 'in', 0], + 'system_io_out': ['System IO Out', 'Count', 'system.io', 'out', 0], +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_RESOURCES, default=['memory_free']): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), +}) + + +# pylint: disable=unused-variable +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the Netdata sensor.""" + name = config.get(CONF_NAME) + host = config.get(CONF_HOST) + port = config.get(CONF_PORT) + url = 'http://{}:{}'.format(host, port) + version_url = '{}/version.txt'.format(url) + data_url = '{}/{}/data?chart='.format(url, _RESOURCE) + resources = config.get(CONF_RESOURCES) + + try: + response = requests.get(version_url, timeout=10) + if not response.ok: + _LOGGER.error("Response status is '%s'", response.status_code) + return False + except requests.exceptions.ConnectionError: + _LOGGER.error("No route to resource/endpoint: %s", url) + return False + + values = {} + for key, value in sorted(SENSOR_TYPES.items()): + if key in resources: + values.setdefault(value[2], []).append(key) + + dev = [] + for chart in values: + rest_url = '{}{}&{}'.format(data_url, chart, _REALTIME) + rest = NetdataData(rest_url) + for sensor_type in values[chart]: + dev.append(NetdataSensor(rest, name, sensor_type)) + + add_devices(dev) + + +class NetdataSensor(Entity): + """Implementation of a Netdata sensor.""" + + def __init__(self, rest, name, sensor_type): + """Initialize the sensor.""" + self.rest = rest + self.type = sensor_type + self._name = '{} {}'.format(name, SENSOR_TYPES[self.type][0]) + self._precision = SENSOR_TYPES[self.type][4] + self._unit_of_measurement = SENSOR_TYPES[self.type][1] + self.update() + + @property + def name(self): + """The name of the sensor.""" + return self._name + + @property + def unit_of_measurement(self): + """Return the unit the value is expressed in.""" + return self._unit_of_measurement + + @property + def state(self): + """Return the state of the resources.""" + value = self.rest.data + + if value is not None: + netdata_id = SENSOR_TYPES[self.type][3] + if netdata_id in value: + return "{0:.{1}f}".format(value[netdata_id], self._precision) + else: + return STATE_UNKNOWN + + def update(self): + """Get the latest data from Netdata REST API.""" + self.rest.update() + + +class NetdataData(object): + """The class for handling the data retrieval.""" + + def __init__(self, resource): + """Initialize the data object.""" + self._resource = resource + self.data = None + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Get the latest data from the Netdata REST API.""" + try: + response = requests.get(self._resource, timeout=5) + det = response.json() + self.data = {k: v for k, v in zip(det['labels'], det['data'][0])} + + except requests.exceptions.ConnectionError: + _LOGGER.error("No route to host/endpoint: %s", self._resource) + self.data = None From e21382cd3e810e152f5f3191fa4fd407d84b3213 Mon Sep 17 00:00:00 2001 From: rubund Date: Mon, 5 Dec 2016 17:15:36 +0100 Subject: [PATCH 029/141] Fix broken EnOcean support (#4710) * ensure_list * CONF_ID is not required configuration for enocean lights * Use vol.All(cv.ensure_list, [vol.Coerce(int)]) as suggested in pull request review * Fix line too long --- homeassistant/components/binary_sensor/enocean.py | 2 +- homeassistant/components/light/enocean.py | 5 +++-- homeassistant/components/sensor/enocean.py | 2 +- homeassistant/components/switch/enocean.py | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/binary_sensor/enocean.py b/homeassistant/components/binary_sensor/enocean.py index 631ed0021e1..bd68a232f22 100644 --- a/homeassistant/components/binary_sensor/enocean.py +++ b/homeassistant/components/binary_sensor/enocean.py @@ -20,7 +20,7 @@ DEPENDENCIES = ['enocean'] DEFAULT_NAME = 'EnOcean binary sensor' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ID): cv.string, + vol.Required(CONF_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_SENSOR_CLASS, default=None): SENSOR_CLASSES_SCHEMA, }) diff --git a/homeassistant/components/light/enocean.py b/homeassistant/components/light/enocean.py index ce65d8cc041..e24aca4902d 100644 --- a/homeassistant/components/light/enocean.py +++ b/homeassistant/components/light/enocean.py @@ -26,8 +26,9 @@ DEPENDENCIES = ['enocean'] SUPPORT_ENOCEAN = SUPPORT_BRIGHTNESS PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ID): cv.string, - vol.Required(CONF_SENDER_ID): cv.string, + vol.Optional(CONF_ID, default=[]): vol.All(cv.ensure_list, + [vol.Coerce(int)]), + vol.Required(CONF_SENDER_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) diff --git a/homeassistant/components/sensor/enocean.py b/homeassistant/components/sensor/enocean.py index e998b5c9c46..009718dd720 100644 --- a/homeassistant/components/sensor/enocean.py +++ b/homeassistant/components/sensor/enocean.py @@ -20,7 +20,7 @@ DEFAULT_NAME = 'EnOcean sensor' DEPENDENCIES = ['enocean'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ID): cv.string, + vol.Required(CONF_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) diff --git a/homeassistant/components/switch/enocean.py b/homeassistant/components/switch/enocean.py index 71bd180ad10..ead5d789bbd 100644 --- a/homeassistant/components/switch/enocean.py +++ b/homeassistant/components/switch/enocean.py @@ -20,7 +20,7 @@ DEFAULT_NAME = 'EnOcean Switch' DEPENDENCIES = ['enocean'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_ID): cv.string, + vol.Required(CONF_ID): vol.All(cv.ensure_list, [vol.Coerce(int)]), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) From 13006cee685111e7de106f369f6ae8b09c250439 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 5 Dec 2016 11:32:17 -0800 Subject: [PATCH 030/141] Device tracker attributes (#4753) --- .../components/device_tracker/__init__.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index e95b556b998..7c4c74708db 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -332,6 +332,7 @@ class Device(Entity): gps = None # type: GPSType gps_accuracy = 0 last_seen = None # type: dt_util.dt.datetime + battery = None # type: str attributes = None # type: dict vendor = None # type: str @@ -369,6 +370,7 @@ class Device(Entity): self.away_hide = hide_if_away self.vendor = vendor + self._attributes = {} @property def name(self): @@ -395,12 +397,16 @@ class Device(Entity): attr[ATTR_LONGITUDE] = self.gps[1] attr[ATTR_GPS_ACCURACY] = self.gps_accuracy - if self.attributes: - for key, value in self.attributes.items(): - attr[key] = value + if self.battery: + attr[ATTR_BATTERY] = self.battery return attr + @property + def device_state_attributes(self): + """Return device state attributes.""" + return self._attributes + @property def hidden(self): """If device should be hidden.""" @@ -415,13 +421,10 @@ class Device(Entity): self.host_name = host_name self.location_name = location_name self.gps_accuracy = gps_accuracy or 0 - if (battery or attributes) and self.attributes is None: - self.attributes = {} - if battery: - self.attributes[ATTR_BATTERY] = battery + if attributes: - for key, value in attributes.items(): - self.attributes[key] = value + self._attributes.update(attributes) + self.gps = None if gps is not None: From 308744d8a022c7fc25af4f2ef8a6214cdcf014f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 5 Dec 2016 20:33:51 +0100 Subject: [PATCH 031/141] Add additional attributes to GPSLogger (#4755) --- homeassistant/components/device_tracker/gpslogger.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/gpslogger.py b/homeassistant/components/device_tracker/gpslogger.py index 2e897ccb10c..d8e7ca8b074 100644 --- a/homeassistant/components/device_tracker/gpslogger.py +++ b/homeassistant/components/device_tracker/gpslogger.py @@ -63,10 +63,20 @@ class GPSLoggerView(HomeAssistantView): accuracy = int(float(data['accuracy'])) if 'battery' in data: battery = float(data['battery']) + attrs = {} + if 'speed' in data: + attrs['speed'] = float(data['speed']) + if 'direction' in data: + attrs['direction'] = float(data['direction']) + if 'altitude' in data: + attrs['altitude'] = float(data['altitude']) + if 'provider' in data: + attrs['provider'] = data['provider'] yield from hass.loop.run_in_executor( None, partial(self.see, dev_id=device, gps=gps_location, battery=battery, - gps_accuracy=accuracy)) + gps_accuracy=accuracy, + attributes=attrs)) return 'Setting location for {}'.format(device) From b3253403aae44d47cd624050ee5f39e5a56ccec5 Mon Sep 17 00:00:00 2001 From: Jeff Wilson Date: Mon, 5 Dec 2016 20:39:40 -0500 Subject: [PATCH 032/141] Set hue-bridgeid in UPNP response (#4740) --- homeassistant/components/emulated_hue/upnp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/emulated_hue/upnp.py b/homeassistant/components/emulated_hue/upnp.py index f81a8c1b68d..fd880c40e6e 100644 --- a/homeassistant/components/emulated_hue/upnp.py +++ b/homeassistant/components/emulated_hue/upnp.py @@ -74,6 +74,7 @@ CACHE-CONTROL: max-age=60 EXT: LOCATION: http://{0}:{1}/description.xml SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1 +hue-bridgeid: 1234 ST: urn:schemas-upnp-org:device:basic:1 USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1 From 1ae8256ffd63983738adf7ed7d947e4d689d889d Mon Sep 17 00:00:00 2001 From: "Martin J. Laubach" Date: Tue, 6 Dec 2016 02:50:50 +0100 Subject: [PATCH 033/141] Add sensor for reading Austrian ZAMG weather conditions (#4347) * Add sensor for reading ZAMG weather conditions * Add to coveragerc; Correct some doc style problems * More doc fixes * More doc fixes * Lose license and whatever. * Don't return UNKNOWN for unknown variables * Verify that the configured station id is actually one in the data set. Don't warn about unknown stations, this cannot happen any more as the configuration parser now checks that. This could still happen if the data set is incomplete though ... * Clean up imports * Clarify comment on throttling interval * Base zamg sensor on Entity, not WeatherEntity, and delete unused code * Fix formatting nits from flake8 * Use ATTR_FRIENDLY_NAME, clean up imports, remove unnecessary indirection. * Use {}.format() instead of "" % * Re-add unit of measurement that got lost somehow * Use guard clauses instead of if-matroshka. Wrap requests.get() in try/except for RequestException. * Huh, how did this happen? White space corrections... * Add sensor for reading ZAMG weather conditions * Add to coveragerc; Correct some doc style problems * More doc fixes * More doc fixes * Verify that the configured station id is actually one in the data set. Don't warn about unknown stations, this cannot happen any more as the configuration parser now checks that. This could still happen if the data set is incomplete though ... * Lose license and whatever. * Don't return UNKNOWN for unknown variables * Clean up imports * Clarify comment on throttling interval * Base zamg sensor on Entity, not WeatherEntity, and delete unused code * Fix formatting nits from flake8 * Use ATTR_FRIENDLY_NAME, clean up imports, remove unnecessary indirection. * Use {}.format() instead of "" % * Re-add unit of measurement that got lost somehow * Use guard clauses instead of if-matroshka. Wrap requests.get() in try/except for RequestException. * Huh, how did this happen? White space corrections... * Precipitation actually is a float, good it rained today * Logger needs no module visibility * Do not name sensors with _ to be in line with the other weather sensor platforms. * Remove manually set friendly_name * comment format police * Less comments * Update zamg.py --- .coveragerc | 2 +- homeassistant/components/sensor/zamg.py | 247 ++++++++++++++++++++++++ 2 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/sensor/zamg.py diff --git a/.coveragerc b/.coveragerc index 6d5abe745f8..5dcc37e1402 100644 --- a/.coveragerc +++ b/.coveragerc @@ -315,7 +315,7 @@ omit = homeassistant/components/sensor/waqi.py homeassistant/components/sensor/xbox_live.py homeassistant/components/sensor/yweather.py - homeassistant/components/sensor/waqi.py + homeassistant/components/sensor/zamg.py homeassistant/components/switch/acer_projector.py homeassistant/components/switch/anel_pwrctrl.py homeassistant/components/switch/arest.py diff --git a/homeassistant/components/sensor/zamg.py b/homeassistant/components/sensor/zamg.py new file mode 100644 index 00000000000..d3d64690ef6 --- /dev/null +++ b/homeassistant/components/sensor/zamg.py @@ -0,0 +1,247 @@ +""" +Sensor for data from Austrian "Zentralanstalt für Meteorologie und Geodynamik". + +This is a sensor for the Austrian weather service "Zentralanstalt für +Meteorologie und Geodynamik" (aka ZAMG). + +The configuration should look like this: + + - platform: zamg + station_id: 11035 + monitored_conditions: + - temperature + - humidity + - pressure + - wind_speed + - precipitation + +Recognised conditions are: + + pressure (Pressure at station level) + pressure_sealevel (Pressure at Sea Level) + humidity (Humidity) + wind_speed (Wind Speed) + wind_bearing (Wind Bearing) + wind_max_speed (Top Wind Speed) + wind_max_bearing (Top Wind Bearing) + sun_last_hour (Sun Last Hour Percentage) + temperature (Temperature) + precipitation (Precipitation) + dewpoint (Dew Point) + +The following stations are available in the data set: + + 11010 Linz/Hörsching + 11012 Kremsmünster + 11022 Retz + 11035 Wien/Hohe Warte + 11036 Wien/Schwechat + 11101 Bregenz + 11121 Innsbruck + 11126 Patscherkofel + 11130 Kufstein + 11150 Salzburg + 11155 Feuerkogel + 11157 Aigen im Ennstal + 11171 Mariazell + 11190 Eisenstadt + 11204 Lienz +""" + +import csv +from datetime import timedelta +import logging +import requests + +import voluptuous as vol + +from homeassistant.components.weather import ( + ATTR_WEATHER_HUMIDITY, ATTR_WEATHER_ATTRIBUTION, + ATTR_WEATHER_PRESSURE, ATTR_WEATHER_TEMPERATURE, + ATTR_WEATHER_WIND_BEARING, ATTR_WEATHER_WIND_SPEED, +) +import homeassistant.helpers.config_validation as cv +from homeassistant.const import ( + CONF_MONITORED_CONDITIONS, CONF_NAME, __version__ +) +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +DEFAULT_NAME = 'zamg' +ATTRIBUTION = 'Data provided by ZAMG' + +# Data source only updates once per hour, so throttle to 30min to have +# reasonably recent data +MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30) + +CONF_STATION_ID = "station_id" + +VALID_STATION_IDS = ( + '11010', '11012', '11022', '11035', '11036', '11101', '11121', '11126', + '11130', '11150', '11155', '11157', '11171', '11190', '11204' +) + +SENSOR_TYPES = { + ATTR_WEATHER_PRESSURE: ('Pressure', 'hPa', 'LDstat hPa', float), + 'pressure_sealevel': ('Pressure at Sea Level', 'hPa', 'LDred hPa', float), + ATTR_WEATHER_HUMIDITY: ('Humidity', '%', 'RF %', int), + ATTR_WEATHER_WIND_SPEED: ('Wind Speed', 'km/h', 'WG km/h', float), + ATTR_WEATHER_WIND_BEARING: ('Wind Bearing', '°', 'WR °', int), + 'wind_max_speed': ('Top Wind Speed', 'km/h', 'WSG km/h', float), + 'wind_max_bearing': ('Top Wind Bearing', '°', 'WSR °', int), + 'sun_last_hour': ('Sun Last Hour', '%', 'SO %', int), + ATTR_WEATHER_TEMPERATURE: ('Temperature', '°C', 'T °C', float), + 'precipitation': ('Precipitation', 'l/m²', 'N l/m²', float), + 'dewpoint': ('Dew Point', '°C', 'TP °C', float), + # The following probably not useful for general consumption, + # but we need them to fill in internal attributes + 'station_name': ('Station Name', None, 'Name', str), + 'station_elevation': ('Station Elevation', 'm', 'Höhe m', int), + 'update_date': ('Update Date', None, 'Datum', str), + 'update_time': ('Update Time', None, 'Zeit', str), +} + +PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Required(CONF_STATION_ID): + vol.All(cv.string, vol.In(VALID_STATION_IDS)), + vol.Required(CONF_MONITORED_CONDITIONS): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup platform.""" + station_id = config.get(CONF_STATION_ID) + name = config.get(CONF_NAME) + + logger = logging.getLogger(__name__) + probe = ZamgData(station_id=station_id, logger=logger) + + sensors = [ZAMGWeather(probe, variable, name) + for variable in config[CONF_MONITORED_CONDITIONS]] + + add_devices(sensors, True) + + +class ZAMGWeather(Entity): + """ + I am a weather wrapper for a specific station and a specific attribute. + + Multiple instances (one for each condition) will refer to the same + probe, so things will only get fetched once. + """ + + def __init__(self, probe, variable, name): + """Init condition sensor.""" + self.probe = probe + self.client_name = name + self.variable = variable + + def update(self): + """Delegate update to probe.""" + self.probe.update() + + @property + def name(self): + """Build name of sensor.""" + return '{} {}'.format(self.client_name, self.variable) + + @property + def state(self): + """Return state.""" + return self.probe.get_data(self.variable) + + @property + def unit_of_measurement(self): + """Unit of measurement.""" + return SENSOR_TYPES[self.variable][1] + + @property + def state_attributes(self): + """Return the state attributes.""" + return { + ATTR_WEATHER_ATTRIBUTION: ATTRIBUTION, + "station": self.probe.get_data('station_name'), + "updated": "%s %s" % (self.probe.get_data('update_date'), + self.probe.get_data('update_time')) + } + + +class ZamgData(object): + """ + I represent weather data for a specific site. + + From the web site: + + Sie beinhalten neben Stationsnummer, Stationsname, Seehöhe der Station, + Messdatum und Messzeit (Lokalzeit) die meteorologischen Messwerte von + Temperatur, Taupunkt, relative Luftfeuchtigkeit, Richtung und + Geschwindigkeit des Windmittels und der Windspitze, Niederschlagssumme + der letzten Stunde, Luftdruck reduziert auf Meeresniveau und Luftdruck + auf Stationsniveau sowie die Sonnenscheindauer der letzten Stunde (in + Prozent). Die Messstationen, die diese Daten liefern, sind über das + Bundesgebiet verteilt und beinhalten alle Landeshauptstädte sowie + die wichtigsten Bergstationen. + """ + + API_URL = "http://www.zamg.ac.at/ogd/" + + API_FIELDS = { + v[2]: (k, v[3]) + for k, v in SENSOR_TYPES.items() + } + + API_HEADERS = { + 'User-Agent': 'home-assistant.zamg/' + __version__, + } + + def __init__(self, logger, station_id): + """Initialize the probe.""" + self._logger = logger + self._station_id = station_id + self.data = {} + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """ + Update data set. + + Fetch a new data set from the zamg server, parse it and + update internal state accordingly + """ + try: + response = requests.get(self.API_URL, + headers=self.API_HEADERS, timeout=15) + except requests.exceptions.RequestException: + self._logger.exception("While fetching data from server") + return + + if response.status_code != 200: + self._logger.error("API call returned with status %s", + response.status_code) + return + + content_type = response.headers.get('Content-Type', 'whatever') + if content_type != 'text/csv': + self._logger.error("Expected text/csv but got %s", + content_type) + return + + response.encoding = 'UTF8' + content = response.text + data = (line for line in content.split('\n')) + reader = csv.DictReader(data, delimiter=';', quotechar='"') + for row in reader: + if row.get("Station", None) == self._station_id: + self.data = { + self.API_FIELDS.get(k)[0]: + self.API_FIELDS.get(k)[1](v.replace(',', '.')) + for k, v in row.items() + if v and k in self.API_FIELDS + } + break + + def get_data(self, variable): + """Generic accessor for data.""" + return self.data.get(variable) From fa8bc0a36ccefdf64b78ab63be9ccd7d4c0f890e Mon Sep 17 00:00:00 2001 From: John Arild Berentsen Date: Tue, 6 Dec 2016 02:51:58 +0100 Subject: [PATCH 034/141] Add Verisure smartcam capture service (#4559) * Add verisure capture as service * docstyle --- homeassistant/components/services.yaml | 9 +++++++++ homeassistant/components/verisure.py | 27 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index 46a3a46ced6..54c0e18a3ee 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -144,3 +144,12 @@ openalpr: restart: description: Restart ffmpeg process of device. + +verisure: + capture_smartcam: + description: Capture a new image from a smartcam. + + fields: + device_serial: + description: The serial number of the smartcam you want to capture an image from. + example: '2DEU AT5Z' diff --git a/homeassistant/components/verisure.py b/homeassistant/components/verisure.py index c8241d8fae5..f2b091aa0f1 100644 --- a/homeassistant/components/verisure.py +++ b/homeassistant/components/verisure.py @@ -7,6 +7,7 @@ https://home-assistant.io/components/verisure/ import logging import threading import time +import os.path from datetime import timedelta import voluptuous as vol @@ -14,12 +15,14 @@ import voluptuous as vol from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.helpers import discovery from homeassistant.util import Throttle +import homeassistant.config as conf_util import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['vsure==0.11.1'] _LOGGER = logging.getLogger(__name__) +ATTR_DEVICE_SERIAL = 'device_serial' CONF_ALARM = 'alarm' CONF_CODE_DIGITS = 'code_digits' CONF_HYDROMETERS = 'hygrometers' @@ -29,6 +32,7 @@ CONF_SMARTPLUGS = 'smartplugs' CONF_THERMOMETERS = 'thermometers' CONF_SMARTCAM = 'smartcam' DOMAIN = 'verisure' +SERVICE_CAPTURE_SMARTCAM = 'capture_smartcam' HUB = None @@ -47,6 +51,10 @@ CONFIG_SCHEMA = vol.Schema({ }), }, extra=vol.ALLOW_EXTRA) +CAPTURE_IMAGE_SCHEMA = vol.Schema({ + vol.Required(ATTR_DEVICE_SERIAL): cv.string +}) + def setup(hass, config): """Setup the Verisure component.""" @@ -60,6 +68,20 @@ def setup(hass, config): 'camera'): discovery.load_platform(hass, component, DOMAIN, {}, config) + descriptions = conf_util.load_yaml_config_file( + os.path.join(os.path.dirname(__file__), 'services.yaml')) + + def capture_smartcam(service): + """Capture a new picture from a smartcam.""" + device_id = service.data.get(ATTR_DEVICE_SERIAL) + HUB.smartcam_capture(device_id) + _LOGGER.debug('Capturing new image from %s', ATTR_DEVICE_SERIAL) + + hass.services.register(DOMAIN, SERVICE_CAPTURE_SMARTCAM, + capture_smartcam, + descriptions[DOMAIN][SERVICE_CAPTURE_SMARTCAM], + schema=CAPTURE_IMAGE_SCHEMA) + return True @@ -150,6 +172,11 @@ class VerisureHub(object): self.smartcam_dict = self.my_pages.smartcam.get_imagelist() _LOGGER.debug('New dict: %s', self.smartcam_dict) + @Throttle(timedelta(seconds=30)) + def smartcam_capture(self, device_id): + """Capture a new image from a smartcam.""" + self.my_pages.smartcam.capture(device_id) + @property def available(self): """Return True if hub is available.""" From b60f5714fc088d672322d3c4b6565558cc254c9b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 5 Dec 2016 18:03:06 -0800 Subject: [PATCH 035/141] Fix websocket async (#4752) * Ensure we write to websocket from inside event loop * Inline service call helper --- homeassistant/components/websocket_api.py | 70 ++++++++++++----------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/websocket_api.py b/homeassistant/components/websocket_api.py index 09f8699f5d1..70b35e00247 100644 --- a/homeassistant/components/websocket_api.py +++ b/homeassistant/components/websocket_api.py @@ -204,7 +204,6 @@ class ActiveConnection: self.hass = hass self.request = request self.wsock = None - self.socket_task = None self.event_listeners = {} def debug(self, message1, message2=''): @@ -220,34 +219,6 @@ class ActiveConnection: self.debug('Sending', message) self.wsock.send_json(message, dumps=JSON_DUMP) - @callback - def _cancel_connection(self, event): - """Cancel this connection.""" - self.socket_task.cancel() - - @asyncio.coroutine - def _call_service_helper(self, msg): - """Helper to call a service and fire complete message.""" - yield from self.hass.services.async_call(msg['domain'], msg['service'], - msg['service_data'], True) - try: - self.send_message(result_message(msg['id'])) - except RuntimeError: - # Socket has been closed. - pass - - @callback - def _forward_event(self, iden, event): - """Helper to forward events to websocket.""" - if event.event_type == EVENT_TIME_CHANGED: - return - - try: - self.send_message(event_message(iden, event)) - except RuntimeError: - # Socket has been closed. - pass - @asyncio.coroutine def handle(self): """Handle the websocket connection.""" @@ -255,9 +226,15 @@ class ActiveConnection: yield from wsock.prepare(self.request) # Set up to cancel this connection when Home Assistant shuts down - self.socket_task = asyncio.Task.current_task(loop=self.hass.loop) - self.hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, - self._cancel_connection) + socket_task = asyncio.Task.current_task(loop=self.hass.loop) + + @callback + def cancel_connection(event): + """Cancel this connection.""" + socket_task.cancel() + + unsub_stop = self.hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, + cancel_connection) self.debug('Connected') @@ -351,6 +328,8 @@ class ActiveConnection: _LOGGER.exception(error) finally: + unsub_stop() + for unsub in self.event_listeners.values(): unsub() @@ -363,8 +342,20 @@ class ActiveConnection: """Handle subscribe events command.""" msg = SUBSCRIBE_EVENTS_MESSAGE_SCHEMA(msg) + @callback + def forward_events(event): + """Helper to forward events to websocket.""" + if event.event_type == EVENT_TIME_CHANGED: + return + + try: + self.send_message(event_message(msg['id'], event)) + except RuntimeError: + # Socket has been closed. + pass + self.event_listeners[msg['id']] = self.hass.bus.async_listen( - msg['event_type'], partial(self._forward_event, msg['id'])) + msg['event_type'], forward_events) self.send_message(result_message(msg['id'])) @@ -386,7 +377,18 @@ class ActiveConnection: """Handle call service command.""" msg = CALL_SERVICE_MESSAGE_SCHEMA(msg) - self.hass.async_add_job(self._call_service_helper(msg)) + @asyncio.coroutine + def call_service_helper(msg): + """Helper to call a service and fire complete message.""" + yield from self.hass.services.async_call( + msg['domain'], msg['service'], msg['service_data'], True) + try: + self.send_message(result_message(msg['id'])) + except RuntimeError: + # Socket has been closed. + pass + + self.hass.async_add_job(call_service_helper(msg)) def handle_get_states(self, msg): """Handle get states command.""" From 8afd30b7d45f1dd6f7c9bbc9a07fd51a51ba1bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Tue, 6 Dec 2016 03:04:04 +0100 Subject: [PATCH 036/141] fix setting battery in device_tracker (#4756) --- homeassistant/components/device_tracker/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 7c4c74708db..d497ea4c314 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -421,7 +421,8 @@ class Device(Entity): self.host_name = host_name self.location_name = location_name self.gps_accuracy = gps_accuracy or 0 - + if battery: + self.battery = battery if attributes: self._attributes.update(attributes) From 776455030fd7b2a8321af8842cdd7943325550f1 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Mon, 5 Dec 2016 21:07:04 -0500 Subject: [PATCH 037/141] Fix media_image_urls for universal media player (#4765) * Fix media_image_urls for universal media player * Linter fixes --- .../components/media_player/universal.py | 11 ++++++++ .../components/media_player/test_universal.py | 26 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/homeassistant/components/media_player/universal.py b/homeassistant/components/media_player/universal.py index cedaeed4985..85a3eb42aa5 100644 --- a/homeassistant/components/media_player/universal.py +++ b/homeassistant/components/media_player/universal.py @@ -263,6 +263,17 @@ class UniversalMediaPlayer(MediaPlayerDevice): """Image url of current playing media.""" return self._child_attr(ATTR_ENTITY_PICTURE) + @property + def entity_picture(self): + """ + Return image of the media playing. + + The universal media player doesn't use the parent class logic, since + the url is coming from child entity pictures which have already been + sent through the API proxy. + """ + return self.media_image_url + @property def media_title(self): """Title of current playing media.""" diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index 76e80f8236e..ff70fe36a17 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -28,6 +28,7 @@ class MockMediaPlayer(media_player.MediaPlayerDevice): self._supported_media_commands = 0 self._source = None self._tracks = 12 + self._media_image_url = None self.service_calls = { 'turn_on': mock_service( @@ -92,6 +93,11 @@ class MockMediaPlayer(media_player.MediaPlayerDevice): """Supported media commands flag.""" return self._supported_media_commands + @property + def media_image_url(self): + """Image url of current playing media.""" + return self._media_image_url + def turn_on(self): """Mock turn_on function.""" self._state = STATE_UNKNOWN @@ -400,6 +406,26 @@ class TestMediaPlayer(unittest.TestCase): ump.update() self.assertEqual(1, ump.volume_level) + def test_media_image_url(self): + """Test media_image_url property.""" + TEST_URL = "test_url" + config = self.config_children_only + universal.validate_config(config) + + ump = universal.UniversalMediaPlayer(self.hass, **config) + ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name']) + ump.update() + + 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() + # 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) + def test_is_volume_muted_children_only(self): """Test is volume muted property w/ children only.""" config = self.config_children_only From 81d38c34631e1418000c9ed08764985cfab07bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Oldag?= Date: Tue, 6 Dec 2016 06:12:24 +0100 Subject: [PATCH 038/141] Add flic smart button component (#4681) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added component for flic smart buttons. * Apply home-assistant coding styles. * Fixed flic configuration. * Made logging for scanning for new buttons less verbose. * Fixed flic event data. * Follow async conventions. * Added new requirements to requirements_all.txt. * Added flic component to .coveragerc * Updated flic threshold configuration key names. * Flic devices are now removed when they disconnect. * Include review feedback. * Fixed stopping of clients in flic component when home assistant is stopped. * Updated flic component by integrating input of #4738. Use library method to determine click type. Merge three click events into single one with click_type parameter. * Use a single client for both handling click events and scanning for new buttons. * Renamed flic ‘auto_scan’ configuration variable to ‘discovery’ using HA constants. --- .coveragerc | 1 + .../components/binary_sensor/flic.py | 196 ++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 200 insertions(+) create mode 100644 homeassistant/components/binary_sensor/flic.py diff --git a/.coveragerc b/.coveragerc index 5dcc37e1402..0d34382659b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -122,6 +122,7 @@ omit = homeassistant/components/alarm_control_panel/simplisafe.py homeassistant/components/binary_sensor/arest.py homeassistant/components/binary_sensor/concord232.py + homeassistant/components/binary_sensor/flic.py homeassistant/components/binary_sensor/rest.py homeassistant/components/browser.py homeassistant/components/camera/amcrest.py diff --git a/homeassistant/components/binary_sensor/flic.py b/homeassistant/components/binary_sensor/flic.py new file mode 100644 index 00000000000..63323155d31 --- /dev/null +++ b/homeassistant/components/binary_sensor/flic.py @@ -0,0 +1,196 @@ +"""Contains functionality to use flic buttons as a binary sensor.""" +import asyncio +import logging + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.const import ( + CONF_HOST, CONF_PORT, CONF_DISCOVERY, EVENT_HOMEASSISTANT_STOP) +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, PLATFORM_SCHEMA) +from homeassistant.util.async import run_callback_threadsafe + + +REQUIREMENTS = ['https://github.com/soldag/pyflic/archive/0.4.zip#pyflic==0.4'] + +_LOGGER = logging.getLogger(__name__) + + +EVENT_NAME = "flic_click" +EVENT_DATA_NAME = "button_name" +EVENT_DATA_ADDRESS = "button_address" +EVENT_DATA_TYPE = "click_type" + +# Validation of the user's configuration +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_HOST, default='localhost'): cv.string, + vol.Optional(CONF_PORT, default=5551): cv.port, + vol.Optional(CONF_DISCOVERY, default=True): cv.boolean +}) + + +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): + """Setup the flic platform.""" + import pyflic + + # Initialize flic client responsible for + # connecting to buttons and retrieving events + host = config.get(CONF_HOST) + port = config.get(CONF_PORT) + discovery = config.get(CONF_DISCOVERY) + + try: + client = pyflic.FlicClient(host, port) + except ConnectionRefusedError: + _LOGGER.error("Failed to connect to flic server.") + return + + def new_button_callback(address): + """Setup newly verified button as device in home assistant.""" + hass.add_job(async_setup_button(hass, config, async_add_entities, + client, address)) + + client.on_new_verified_button = new_button_callback + if discovery: + start_scanning(hass, config, async_add_entities, client) + + hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, + lambda event: client.close()) + hass.loop.run_in_executor(None, client.handle_events) + + # Get addresses of already verified buttons + addresses = yield from async_get_verified_addresses(client) + if addresses: + for address in addresses: + yield from async_setup_button(hass, config, async_add_entities, + client, address) + + +def start_scanning(hass, config, async_add_entities, client): + """Start a new flic client for scanning & connceting to new buttons.""" + import pyflic + + scan_wizard = pyflic.ScanWizard() + + def scan_completed_callback(scan_wizard, result, address, name): + """Restart scan wizard to constantly check for new buttons.""" + if result == pyflic.ScanWizardResult.WizardSuccess: + _LOGGER.info("Found new button (%s)", address) + elif result != pyflic.ScanWizardResult.WizardFailedTimeout: + _LOGGER.warning("Failed to connect to button (%s). Reason: %s", + address, result) + + # Restart scan wizard + start_scanning(hass, config, async_add_entities, client) + + scan_wizard.on_completed = scan_completed_callback + client.add_scan_wizard(scan_wizard) + + +@asyncio.coroutine +def async_setup_button(hass, config, async_add_entities, client, address): + """Setup single button device.""" + button = FlicButton(hass, client, address) + _LOGGER.info("Connected to button (%s)", address) + + yield from async_add_entities([button]) + + +@asyncio.coroutine +def async_get_verified_addresses(client): + """Retrieve addresses of verified buttons.""" + future = asyncio.Future() + loop = asyncio.get_event_loop() + + def get_info_callback(items): + """Set the addressed of connected buttons as result of the future.""" + addresses = items["bd_addr_of_verified_buttons"] + run_callback_threadsafe(loop, future.set_result, addresses) + client.get_info(get_info_callback) + + return future + + +class FlicButton(BinarySensorDevice): + """Representation of a flic button.""" + + def __init__(self, hass, client, address): + """Initialize the flic button.""" + import pyflic + + self._hass = hass + self._address = address + self._is_down = False + self._click_types = { + pyflic.ClickType.ButtonSingleClick: "single", + pyflic.ClickType.ButtonDoubleClick: "double", + pyflic.ClickType.ButtonHold: "hold", + } + + # Initialize connection channel + self._channel = pyflic.ButtonConnectionChannel(self._address) + self._channel.on_button_up_or_down = self._on_up_down + self._channel.on_button_single_or_double_click_or_hold = self._on_click + client.add_connection_channel(self._channel) + + @property + def name(self): + """Return the name of the device.""" + return "flic_%s" % self.address.replace(":", "") + + @property + def address(self): + """Return the bluetooth address of the device.""" + return self._address + + @property + def is_on(self): + """Return true if sensor is on.""" + return self._is_down + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def state_attributes(self): + """Return device specific state attributes.""" + attr = super(FlicButton, self).state_attributes + attr["address"] = self.address + + return attr + + def _on_up_down(self, channel, click_type, was_queued, time_diff): + """Update device state, if event was not queued.""" + import pyflic + + if was_queued: + return + + self._is_down = click_type == pyflic.ClickType.ButtonDown + self.schedule_update_ha_state() + + def _on_click(self, channel, click_type, was_queued, time_diff): + """Fire click event, if event was not queued.""" + if was_queued: + return + + self._hass.bus.fire(EVENT_NAME, { + EVENT_DATA_NAME: self.name, + EVENT_DATA_ADDRESS: self.address, + EVENT_DATA_TYPE: self._click_types[click_type] + }) + + def _connection_status_changed(self, channel, + connection_status, disconnect_reason): + """Remove device, if button disconnects.""" + import pyflic + + if connection_status == pyflic.ConnectionStatus.Disconnected: + _LOGGER.info("Button (%s) disconnected. Reason: %s", + self.address, disconnect_reason) + self.remove() diff --git a/requirements_all.txt b/requirements_all.txt index 622faa3719d..0cae8b32af1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -241,6 +241,9 @@ https://github.com/robbiet480/pygtfs/archive/00546724e4bbcb3053110d844ca44e22462 # homeassistant.components.scene.hunterdouglas_powerview https://github.com/sander76/powerviewApi/archive/246e782d60d5c0addcc98d7899a0186f9d5640b0.zip#powerviewApi==0.3.15 +# homeassistant.components.binary_sensor.flic +https://github.com/soldag/pyflic/archive/0.4.zip#pyflic==0.4 + # homeassistant.components.light.osramlightify https://github.com/tfriedel/python-lightify/archive/d6eadcf311e6e21746182d1480e97b350dda2b3e.zip#lightify==1.0.4 From 8c628071f30ae7c6822244011c489b8b648e46ae Mon Sep 17 00:00:00 2001 From: Hugo Dupras Date: Tue, 6 Dec 2016 06:35:33 +0100 Subject: [PATCH 039/141] Add support for Netatmo tags (#4761) * Add support for Netatmo Welcome Tags Signed-off-by: Hugo D. (jabesq) * Add size parameter for WelcomeData * minor fixes * Add Throttling mechanism for update event This will prevent to reach the API limit Signed-off-by: Hugo D. (jabesq) * Change scan interval for Netatmo Binary sensors Signed-off-by: Hugo D. (jabesq) * Minor fixes Signed-off-by: Hugo D. (jabesq) * Update netatmo.py --- .../components/binary_sensor/netatmo.py | 41 +++++++++++++++---- homeassistant/components/netatmo.py | 24 +++++++++-- requirements_all.txt | 2 +- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/binary_sensor/netatmo.py b/homeassistant/components/binary_sensor/netatmo.py index 93b3bb5817c..94ef0faaad0 100644 --- a/homeassistant/components/binary_sensor/netatmo.py +++ b/homeassistant/components/binary_sensor/netatmo.py @@ -23,9 +23,11 @@ _LOGGER = logging.getLogger(__name__) # These are the available sensors mapped to binary_sensor class SENSOR_TYPES = { - "Someone known": "motion", - "Someone unknown": "motion", - "Motion": "motion", + "Someone known": 'occupancy', + "Someone unknown": 'motion', + "Motion": 'motion', + "Tag Vibration": 'vibration', + "Tag Open": 'opening', } CONF_HOME = 'home' @@ -48,6 +50,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): home = config.get(CONF_HOME, None) timeout = config.get(CONF_TIMEOUT, 15) + module_name = None + import lnetatmo try: data = WelcomeData(netatmo.NETATMO_AUTH, home) @@ -64,23 +68,35 @@ def setup_platform(hass, config, add_devices, discovery_info=None): camera_name not in config[CONF_CAMERAS]: continue for variable in sensors: - add_devices([WelcomeBinarySensor(data, camera_name, home, timeout, - variable)]) + if variable in ('Tag Vibration', 'Tag Open'): + continue + add_devices([WelcomeBinarySensor(data, camera_name, module_name, + home, timeout, variable)]) + + for module_name in data.get_module_names(camera_name): + for variable in sensors: + if variable in ('Tag Vibration', 'Tag Open'): + add_devices([WelcomeBinarySensor(data, camera_name, + module_name, home, + timeout, variable)]) class WelcomeBinarySensor(BinarySensorDevice): """Represent a single binary sensor in a Netatmo Welcome device.""" - def __init__(self, data, camera_name, home, timeout, sensor): + def __init__(self, data, camera_name, module_name, home, timeout, sensor): """Setup for access to the Netatmo camera events.""" self._data = data self._camera_name = camera_name + self._module_name = module_name self._home = home self._timeout = timeout if home: self._name = home + ' / ' + camera_name else: self._name = camera_name + if module_name: + self._name += ' / ' + module_name self._sensor_name = sensor self._name += ' ' + sensor camera_id = data.welcomedata.cameraByName(camera=camera_name, @@ -112,7 +128,7 @@ class WelcomeBinarySensor(BinarySensorDevice): def update(self): """Request an update from the Netatmo API.""" self._data.update() - self._data.welcomedata.updateEvent(home=self._data.home) + self._data.update_event() if self._sensor_name == "Someone known": self._state =\ @@ -129,5 +145,16 @@ class WelcomeBinarySensor(BinarySensorDevice): self._data.welcomedata.motionDetected(self._home, self._camera_name, self._timeout*60) + elif self._sensor_name == "Tag Vibration": + self._state =\ + self._data.welcomedata.moduleMotionDetected(self._home, + self._module_name, + self._camera_name, + self._timeout*60) + elif self._sensor_name == "Tag Open": + self._state =\ + self._data.welcomedata.moduleOpened(self._home, + self._module_name, + self._camera_name) else: return None diff --git a/homeassistant/components/netatmo.py b/homeassistant/components/netatmo.py index d6e0101e4e0..3bb98a00b87 100644 --- a/homeassistant/components/netatmo.py +++ b/homeassistant/components/netatmo.py @@ -18,7 +18,7 @@ from homeassistant.util import Throttle REQUIREMENTS = [ 'https://github.com/jabesq/netatmo-api-python/archive/' - 'v0.7.0.zip#lnetatmo==0.7.0'] + 'v0.8.0.zip#lnetatmo==0.8.0'] _LOGGER = logging.getLogger(__name__) @@ -30,6 +30,7 @@ NETATMO_AUTH = None DEFAULT_DISCOVERY = True MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10) +MIN_TIME_BETWEEN_EVENT_UPDATES = timedelta(seconds=10) CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -72,10 +73,11 @@ class WelcomeData(object): self.auth = auth self.welcomedata = None self.camera_names = [] + self.module_names = [] self.home = home def get_camera_names(self): - """Return all module available on the API as a list.""" + """Return all camera available on the API as a list.""" self.camera_names = [] self.update() if not self.home: @@ -87,8 +89,24 @@ class WelcomeData(object): self.camera_names.append(camera['name']) return self.camera_names + def get_module_names(self, camera_name): + """Return all module available on the API as a list.""" + self.module_names = [] + self.update() + cam_id = self.welcomedata.cameraByName(camera=camera_name, + home=self.home)['id'] + for module in self.welcomedata.modules.values(): + if cam_id == module['cam_id']: + self.module_names.append(module['name']) + return self.module_names + @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Call the Netatmo API to update the data.""" import lnetatmo - self.welcomedata = lnetatmo.WelcomeData(self.auth) + self.welcomedata = lnetatmo.WelcomeData(self.auth, size=100) + + @Throttle(MIN_TIME_BETWEEN_EVENT_UPDATES) + def update_event(self): + """Call the Netatmo API to update the list of events.""" + self.welcomedata.updateEvent(home=self.home) diff --git a/requirements_all.txt b/requirements_all.txt index 0cae8b32af1..d468f2aa863 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -205,7 +205,7 @@ https://github.com/danieljkemp/onkyo-eiscp/archive/python3.zip#onkyo-eiscp==0.9. # https://github.com/deisi/fritzconnection/archive/b5c14515e1c8e2652b06b6316a7f3913df942841.zip#fritzconnection==0.4.6 # homeassistant.components.netatmo -https://github.com/jabesq/netatmo-api-python/archive/v0.7.0.zip#lnetatmo==0.7.0 +https://github.com/jabesq/netatmo-api-python/archive/v0.8.0.zip#lnetatmo==0.8.0 # homeassistant.components.neato https://github.com/jabesq/pybotvac/archive/v0.0.1.zip#pybotvac==0.0.1 From 8ca2345fd4fde5b6ecc924a03c9338f05474ac51 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 5 Dec 2016 23:35:54 -0600 Subject: [PATCH 040/141] Pyunifi dep (#4754) * change unifi dependency to pyunifi * Change dependency to fix #4336 * Run gen_requirements_all.py script * Changed import statement to reflect new package * Updated test_unifiy.py with different module * Update requirements_all.txt --- homeassistant/components/device_tracker/unifi.py | 4 ++-- requirements_all.txt | 6 +++--- tests/components/device_tracker/test_unifi.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/device_tracker/unifi.py b/homeassistant/components/device_tracker/unifi.py index e139775e031..ab84eb22e04 100644 --- a/homeassistant/components/device_tracker/unifi.py +++ b/homeassistant/components/device_tracker/unifi.py @@ -14,7 +14,7 @@ from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD # Unifi package doesn't list urllib3 as a requirement -REQUIREMENTS = ['urllib3', 'unifi==1.2.5'] +REQUIREMENTS = ['urllib3', 'pyunifi==1.3'] _LOGGER = logging.getLogger(__name__) CONF_PORT = 'port' @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def get_scanner(hass, config): """Setup Unifi device_tracker.""" - from unifi.controller import Controller + from pyunifi.controller import Controller host = config[DOMAIN].get(CONF_HOST) username = config[DOMAIN].get(CONF_USERNAME) diff --git a/requirements_all.txt b/requirements_all.txt index d468f2aa863..6f1ca5eb4e1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -479,6 +479,9 @@ python-twitch==1.3.0 # homeassistant.components.wink python-wink==0.11.0 +# homeassistant.components.device_tracker.unifi +pyunifi==1.3 + # homeassistant.components.keyboard # pyuserinput==0.1.11 @@ -569,9 +572,6 @@ twilio==5.4.0 # homeassistant.components.sensor.uber uber_rides==0.2.7 -# homeassistant.components.device_tracker.unifi -unifi==1.2.5 - # homeassistant.components.device_tracker.unifi urllib3 diff --git a/tests/components/device_tracker/test_unifi.py b/tests/components/device_tracker/test_unifi.py index 5482740ce11..12d296959dc 100644 --- a/tests/components/device_tracker/test_unifi.py +++ b/tests/components/device_tracker/test_unifi.py @@ -3,7 +3,7 @@ import unittest from unittest import mock import urllib -from unifi import controller +from pyunifi import controller import voluptuous as vol from tests.common import get_test_home_assistant From a11b68c560d91cfb1af3b94b8dd088496d66a77c Mon Sep 17 00:00:00 2001 From: dasos Date: Tue, 6 Dec 2016 05:37:05 +0000 Subject: [PATCH 041/141] Fix connection check (#4732) * Fix connection check * Release instead * Remove if * Update hook.py --- homeassistant/components/switch/hook.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/switch/hook.py b/homeassistant/components/switch/hook.py index eba64c6aeb1..689ab675b5f 100644 --- a/homeassistant/components/switch/hook.py +++ b/homeassistant/components/switch/hook.py @@ -50,7 +50,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): return False finally: if response is not None: - yield from response.close() + yield from response.release() try: token = data['data']['token'] @@ -72,7 +72,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): return False finally: if response is not None: - yield from response.close() + yield from response.release() yield from async_add_devices( HookSmartHome( @@ -127,7 +127,7 @@ class HookSmartHome(SwitchDevice): finally: if response is not None: - yield from response.close() + yield from response.release() _LOGGER.debug("Got: %s", data) return data['return_value'] == '1' From 64290d74f09c9df66f116894dc19dad92d908b0c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 5 Dec 2016 21:40:34 -0800 Subject: [PATCH 042/141] Update frontend --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 4 ++-- .../frontend/www_static/frontend.html.gz | Bin 130456 -> 130476 bytes .../www_static/home-assistant-polymer | 2 +- .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2325 -> 2326 bytes 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 837fdd0e1fe..14650b47cb7 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,7 +2,7 @@ FINGERPRINTS = { "core.js": "5dfb2d3e567fad37af0321d4b29265ed", - "frontend.html": "6a89b74ab2b76c7d28fad2aea9444ec2", + "frontend.html": "d4f164e559944b8abc560d7b46131714", "mdi.html": "46a76f877ac9848899b8ed382427c16f", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "c2d5ec676be98d4474d19f94d0262c1e", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index d0a3e75d8db..54b9cc4d5e4 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -1,5 +1,5 @@ \ No newline at end of file +},customStyle:null,getComputedStyleValue:function(e){return!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 2e509569ab2ffe7c98d3aa9a446f426cc3d9bf52..3bf5bab1b5944da1c6375064d0b6d982ab667b5d 100644 GIT binary patch delta 62822 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
`Ei0$|B-HinS?sl*Kewdg&h2>E4 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

G2v3b19$!pg2ioGFQ+SiM=kM%6(%a% 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

|2Y;*r^~Vill3n@Qkt{S+I7Wpw`q%2 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 R9KZLUb@oR?&8gBH3;>JBPW1o) delta 62835 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�S+3;*jf&GOu@84bV&;0J=`E>t1 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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 2652823d35b..4697af1b0d9 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 2652823d35b77411988751cc74820dcfc3a0e2ac +Subproject commit 4697af1b0d96e7a21454539888c68189668fa80d diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index 25535a72081..b125336669c 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=[["/","71255a0807fe2c461c870c5f3aaedc56"],["/frontend/panels/dev-event-c2d5ec676be98d4474d19f94d0262c1e.html","6c55fc819751923ab00c62ae3fbb7222"],["/frontend/panels/dev-info-a9c07bf281fe9791fb15827ec1286825.html","931f9327e368db710fcdf5f7202f2588"],["/frontend/panels/dev-service-b3fe49532c5c03198fafb0c6ed58b76a.html","4194cb43b74108dc6d10354da2fd81fd"],["/frontend/panels/dev-state-65e5f791cc467561719bf591f1386054.html","78158786a6597ef86c3fd6f4985cde92"],["/frontend/panels/dev-template-7d744ab7f7c08b6d6ad42069989de400.html","8a6ee994b1cdb45b081299b8609915ed"],["/frontend/panels/map-1bf6965b24d76db71a1871865cd4a3a2.html","a74c01c2ee68c83c9938af067ec33b81"],["/static/core-5dfb2d3e567fad37af0321d4b29265ed.js","9a50270db7613e3af449f6c773366f4d"],["/static/frontend-6a89b74ab2b76c7d28fad2aea9444ec2.html","db91a94d9dcb88f12188d3d88c1200a2"],["/static/mdi-46a76f877ac9848899b8ed382427c16f.html","a846c4082dd5cffd88ac72cbe943e691"],["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","b0f32ad3c7749c40d486603f31c9d8b1"]],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"}))}))})}).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: Tue, 6 Dec 2016 00:20:21 -0600 Subject: [PATCH 043/141] Match uppercase MAC addresses in asuswrt 'arp -n' output (#4742) (#4764) --- homeassistant/components/device_tracker/asuswrt.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/asuswrt.py b/homeassistant/components/device_tracker/asuswrt.py index 2eced1b4dd4..4e860846f8e 100644 --- a/homeassistant/components/device_tracker/asuswrt.py +++ b/homeassistant/components/device_tracker/asuswrt.py @@ -286,8 +286,10 @@ class AsusWrtDeviceScanner(object): # match mac addresses to IP addresses in ARP table for arp in result.arp: - if match.group('mac').lower() in arp.decode('utf-8'): - arp_match = _ARP_REGEX.search(arp.decode('utf-8')) + if match.group('mac').lower() in \ + arp.decode('utf-8').lower(): + arp_match = _ARP_REGEX.search( + arp.decode('utf-8').lower()) if not arp_match: _LOGGER.warning('Could not parse arp row: %s', arp) continue From fa0dbaf065af549e5211c350a68cb9017fbdd919 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 5 Dec 2016 23:39:22 -0800 Subject: [PATCH 044/141] Fix default auth influxdb (#4771) --- homeassistant/components/influxdb.py | 44 ++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/influxdb.py b/homeassistant/components/influxdb.py index 08296ad65c7..c712cf6a27e 100644 --- a/homeassistant/components/influxdb.py +++ b/homeassistant/components/influxdb.py @@ -24,23 +24,20 @@ CONF_TAGS = 'tags' CONF_DEFAULT_MEASUREMENT = 'default_measurement' DEFAULT_DATABASE = 'home_assistant' -DEFAULT_HOST = 'localhost' -DEFAULT_PORT = 8086 -DEFAULT_SSL = False -DEFAULT_VERIFY_SSL = False +DEFAULT_VERIFY_SSL = True DOMAIN = 'influxdb' TIMEOUT = 5 CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ - vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Optional(CONF_HOST): cv.string, vol.Inclusive(CONF_USERNAME, 'authentication'): cv.string, vol.Inclusive(CONF_PASSWORD, 'authentication'): cv.string, vol.Optional(CONF_BLACKLIST, default=[]): vol.All(cv.ensure_list, [cv.entity_id]), vol.Optional(CONF_DB_NAME, default=DEFAULT_DATABASE): cv.string, - vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, - vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, + vol.Optional(CONF_PORT): cv.port, + vol.Optional(CONF_SSL): cv.boolean, vol.Optional(CONF_DEFAULT_MEASUREMENT): cv.string, vol.Optional(CONF_TAGS, default={}): vol.Schema({cv.string: cv.string}), @@ -57,23 +54,34 @@ def setup(hass, config): conf = config[DOMAIN] - host = conf.get(CONF_HOST) - port = conf.get(CONF_PORT) - database = conf.get(CONF_DB_NAME) - username = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) - ssl = conf.get(CONF_SSL) - verify_ssl = conf.get(CONF_VERIFY_SSL) + kwargs = { + 'database': conf[CONF_DB_NAME], + 'verify_ssl': conf[CONF_VERIFY_SSL], + 'timeout': TIMEOUT + } + + if CONF_HOST in conf: + kwargs['host'] = conf[CONF_HOST] + + if CONF_PORT in conf: + kwargs['port'] = conf[CONF_PORT] + + if CONF_USERNAME in conf: + kwargs['username'] = conf[CONF_USERNAME] + + if CONF_PASSWORD in conf: + kwargs['password'] = conf[CONF_PASSWORD] + + if CONF_SSL in conf: + kwargs['ssl'] = conf[CONF_SSL] + blacklist = conf.get(CONF_BLACKLIST) whitelist = conf.get(CONF_WHITELIST) tags = conf.get(CONF_TAGS) default_measurement = conf.get(CONF_DEFAULT_MEASUREMENT) try: - influx = InfluxDBClient( - host=host, port=port, username=username, password=password, - database=database, ssl=ssl, verify_ssl=verify_ssl, - timeout=TIMEOUT) + influx = InfluxDBClient(**kwargs) influx.query("select * from /.*/ LIMIT 1;") except exceptions.InfluxDBClientError as exc: _LOGGER.error("Database host is not accessible due to '%s', please " From d968e1d0110f949eb43bd4bbfa15dfdfea85b1e6 Mon Sep 17 00:00:00 2001 From: Lewis Juggins Date: Tue, 6 Dec 2016 13:01:24 +0000 Subject: [PATCH 045/141] Add test to ensure device_tracker records state correctly. (#4776) --- tests/components/device_tracker/test_init.py | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index 013920985ff..c3087b108e9 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -458,6 +458,45 @@ class TestComponentsDeviceTracker(unittest.TestCase): timedelta(seconds=0)) assert len(config) == 0 + def test_see_state(self): + """Test device tracker see records state correctly.""" + self.assertTrue(setup_component(self.hass, device_tracker.DOMAIN, + TEST_PLATFORM)) + + params = { + 'mac': 'AA:BB:CC:DD:EE:FF', + 'dev_id': 'some_device', + 'host_name': 'example.com', + 'location_name': 'Work', + 'gps': [.3, .8], + 'gps_accuracy': 1, + 'battery': 100, + 'attributes': { + 'test': 'test', + 'number': 1, + }, + } + + device_tracker.see(self.hass, **params) + self.hass.block_till_done() + + config = device_tracker.load_config(self.yaml_devices, self.hass, + timedelta(seconds=0)) + assert len(config) == 1 + + state = self.hass.states.get('device_tracker.examplecom') + attrs = state.attributes + self.assertEqual(state.state, 'Work') + self.assertEqual(state.object_id, 'examplecom') + self.assertEqual(state.name, 'example.com') + self.assertEqual(attrs['friendly_name'], 'example.com') + self.assertEqual(attrs['battery'], 100) + self.assertEqual(attrs['latitude'], 0.3) + self.assertEqual(attrs['longitude'], 0.8) + self.assertEqual(attrs['test'], 'test') + self.assertEqual(attrs['gps_accuracy'], 1) + self.assertEqual(attrs['number'], 1) + @patch('homeassistant.components.device_tracker._LOGGER.warning') def test_see_failures(self, mock_warning): """Test that the device tracker see failures.""" From 76ff934bd34cb04cf3a028add2a7d6bb572b565f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 6 Dec 2016 15:49:59 +0100 Subject: [PATCH 046/141] Move details to docs, update doc strings, and use consts (#4777) --- homeassistant/components/sensor/zamg.py | 145 +++++++----------------- 1 file changed, 38 insertions(+), 107 deletions(-) diff --git a/homeassistant/components/sensor/zamg.py b/homeassistant/components/sensor/zamg.py index d3d64690ef6..6bb9dd0748d 100644 --- a/homeassistant/components/sensor/zamg.py +++ b/homeassistant/components/sensor/zamg.py @@ -1,81 +1,38 @@ """ Sensor for data from Austrian "Zentralanstalt für Meteorologie und Geodynamik". -This is a sensor for the Austrian weather service "Zentralanstalt für -Meteorologie und Geodynamik" (aka ZAMG). - -The configuration should look like this: - - - platform: zamg - station_id: 11035 - monitored_conditions: - - temperature - - humidity - - pressure - - wind_speed - - precipitation - -Recognised conditions are: - - pressure (Pressure at station level) - pressure_sealevel (Pressure at Sea Level) - humidity (Humidity) - wind_speed (Wind Speed) - wind_bearing (Wind Bearing) - wind_max_speed (Top Wind Speed) - wind_max_bearing (Top Wind Bearing) - sun_last_hour (Sun Last Hour Percentage) - temperature (Temperature) - precipitation (Precipitation) - dewpoint (Dew Point) - -The following stations are available in the data set: - - 11010 Linz/Hörsching - 11012 Kremsmünster - 11022 Retz - 11035 Wien/Hohe Warte - 11036 Wien/Schwechat - 11101 Bregenz - 11121 Innsbruck - 11126 Patscherkofel - 11130 Kufstein - 11150 Salzburg - 11155 Feuerkogel - 11157 Aigen im Ennstal - 11171 Mariazell - 11190 Eisenstadt - 11204 Lienz +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.zamg/ """ - import csv -from datetime import timedelta import logging -import requests +from datetime import timedelta +import requests import voluptuous as vol -from homeassistant.components.weather import ( - ATTR_WEATHER_HUMIDITY, ATTR_WEATHER_ATTRIBUTION, - ATTR_WEATHER_PRESSURE, ATTR_WEATHER_TEMPERATURE, - ATTR_WEATHER_WIND_BEARING, ATTR_WEATHER_WIND_SPEED, -) import homeassistant.helpers.config_validation as cv +from homeassistant.components.weather import ( + ATTR_WEATHER_HUMIDITY, ATTR_WEATHER_ATTRIBUTION, ATTR_WEATHER_PRESSURE, + ATTR_WEATHER_TEMPERATURE, ATTR_WEATHER_WIND_BEARING, + ATTR_WEATHER_WIND_SPEED) from homeassistant.const import ( - CONF_MONITORED_CONDITIONS, CONF_NAME, __version__ -) + CONF_MONITORED_CONDITIONS, CONF_NAME, __version__) from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle -DEFAULT_NAME = 'zamg' +ATTR_STATION = 'station' +ATTR_UPDATED = 'updated' ATTRIBUTION = 'Data provided by ZAMG' -# Data source only updates once per hour, so throttle to 30min to have +CONF_STATION_ID = 'station_id' + +DEFAULT_NAME = 'zamg' + +# Data source only updates once per hour, so throttle to 30 min to have # reasonably recent data MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30) -CONF_STATION_ID = "station_id" - VALID_STATION_IDS = ( '11010', '11012', '11022', '11035', '11036', '11101', '11121', '11126', '11130', '11150', '11155', '11157', '11171', '11190', '11204' @@ -102,41 +59,37 @@ SENSOR_TYPES = { } PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Required(CONF_STATION_ID): - vol.All(cv.string, vol.In(VALID_STATION_IDS)), vol.Required(CONF_MONITORED_CONDITIONS): vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), + vol.Required(CONF_STATION_ID): + vol.All(cv.string, vol.In(VALID_STATION_IDS)), + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup platform.""" + """Set up the ZAMG sensor platform.""" station_id = config.get(CONF_STATION_ID) name = config.get(CONF_NAME) logger = logging.getLogger(__name__) probe = ZamgData(station_id=station_id, logger=logger) - sensors = [ZAMGWeather(probe, variable, name) + sensors = [ZamgSensor(probe, variable, name) for variable in config[CONF_MONITORED_CONDITIONS]] add_devices(sensors, True) -class ZAMGWeather(Entity): - """ - I am a weather wrapper for a specific station and a specific attribute. - - Multiple instances (one for each condition) will refer to the same - probe, so things will only get fetched once. - """ +class ZamgSensor(Entity): + """Implementation of a ZAMG sensor.""" def __init__(self, probe, variable, name): - """Init condition sensor.""" + """Initialize the sensor.""" self.probe = probe self.client_name = name self.variable = variable + self.update() def update(self): """Delegate update to probe.""" @@ -144,17 +97,17 @@ class ZAMGWeather(Entity): @property def name(self): - """Build name of sensor.""" + """Return the name of the sensor.""" return '{} {}'.format(self.client_name, self.variable) @property def state(self): - """Return state.""" + """Return the state of the sensor.""" return self.probe.get_data(self.variable) @property def unit_of_measurement(self): - """Unit of measurement.""" + """Return the unit of measurement of this entity, if any.""" return SENSOR_TYPES[self.variable][1] @property @@ -162,38 +115,22 @@ class ZAMGWeather(Entity): """Return the state attributes.""" return { ATTR_WEATHER_ATTRIBUTION: ATTRIBUTION, - "station": self.probe.get_data('station_name'), - "updated": "%s %s" % (self.probe.get_data('update_date'), - self.probe.get_data('update_time')) + ATTR_STATION: self.probe.get_data('station_name'), + ATTR_UPDATED: '{} {}'.format(self.probe.get_data('update_date'), + self.probe.get_data('update_time')), } class ZamgData(object): - """ - I represent weather data for a specific site. - - From the web site: - - Sie beinhalten neben Stationsnummer, Stationsname, Seehöhe der Station, - Messdatum und Messzeit (Lokalzeit) die meteorologischen Messwerte von - Temperatur, Taupunkt, relative Luftfeuchtigkeit, Richtung und - Geschwindigkeit des Windmittels und der Windspitze, Niederschlagssumme - der letzten Stunde, Luftdruck reduziert auf Meeresniveau und Luftdruck - auf Stationsniveau sowie die Sonnenscheindauer der letzten Stunde (in - Prozent). Die Messstationen, die diese Daten liefern, sind über das - Bundesgebiet verteilt und beinhalten alle Landeshauptstädte sowie - die wichtigsten Bergstationen. - """ - - API_URL = "http://www.zamg.ac.at/ogd/" + """The class for handling the data retrieval.""" + API_URL = 'http://www.zamg.ac.at/ogd/' API_FIELDS = { v[2]: (k, v[3]) for k, v in SENSOR_TYPES.items() } - API_HEADERS = { - 'User-Agent': 'home-assistant.zamg/' + __version__, + 'User-Agent': '{} {}'.format('home-assistant.zamg/', __version__), } def __init__(self, logger, station_id): @@ -204,15 +141,10 @@ class ZamgData(object): @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): - """ - Update data set. - - Fetch a new data set from the zamg server, parse it and - update internal state accordingly - """ + """Get the latest data from ZAMG.""" try: - response = requests.get(self.API_URL, - headers=self.API_HEADERS, timeout=15) + response = requests.get( + self.API_URL, headers=self.API_HEADERS, timeout=15) except requests.exceptions.RequestException: self._logger.exception("While fetching data from server") return @@ -224,8 +156,7 @@ class ZamgData(object): content_type = response.headers.get('Content-Type', 'whatever') if content_type != 'text/csv': - self._logger.error("Expected text/csv but got %s", - content_type) + self._logger.error("Expected text/csv but got %s", content_type) return response.encoding = 'UTF8' From 860a12cffbecbfb547dcb3d91f20a162e0445963 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 6 Dec 2016 07:43:11 -0800 Subject: [PATCH 047/141] Fix Kodi auth (#4770) --- homeassistant/components/media_player/kodi.py | 25 ++++++++++++++----- homeassistant/components/notify/kodi.py | 22 +++++++++++----- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index ae9f8c8d721..68161deea2f 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -36,10 +36,10 @@ SUPPORT_KODI = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_PASSWORD): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_TURN_OFF_ACTION, default=None): vol.In(TURN_OFF_ACTION), - vol.Optional(CONF_USERNAME): cv.string, + vol.Inclusive(CONF_USERNAME, 'auth'): cv.string, + vol.Inclusive(CONF_PASSWORD, 'auth'): cv.string, }) @@ -51,11 +51,19 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if jsonrpc_url: url = jsonrpc_url.rstrip('/jsonrpc') + username = config.get(CONF_USERNAME) + password = config.get(CONF_PASSWORD) + + if username is not None: + auth = (username, password) + else: + auth = None + add_devices([ KodiDevice( config.get(CONF_NAME), url, - auth=(config.get(CONF_USERNAME), config.get(CONF_PASSWORD)), + auth=auth, turn_off_action=config.get(CONF_TURN_OFF_ACTION)), ]) @@ -68,10 +76,15 @@ class KodiDevice(MediaPlayerDevice): import jsonrpc_requests self._name = name self._url = url + + kwargs = {'timeout': 5} + + if auth is not None: + kwargs['auth'] = auth + self._server = jsonrpc_requests.Server( - '{}/jsonrpc'.format(self._url), - auth=auth, - timeout=5) + '{}/jsonrpc'.format(self._url), **kwargs) + self._turn_off_action = turn_off_action self._players = list() self._properties = None diff --git a/homeassistant/components/notify/kodi.py b/homeassistant/components/notify/kodi.py index 6f725d63d47..1d95920d00b 100644 --- a/homeassistant/components/notify/kodi.py +++ b/homeassistant/components/notify/kodi.py @@ -22,8 +22,8 @@ DEFAULT_PORT = 8080 PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, - vol.Optional(CONF_USERNAME): cv.string, - vol.Optional(CONF_PASSWORD): cv.string, + vol.Inclusive(CONF_USERNAME, 'auth'): cv.string, + vol.Inclusive(CONF_PASSWORD, 'auth'): cv.string, }) ATTR_DISPLAYTIME = 'displaytime' @@ -33,7 +33,13 @@ def get_service(hass, config): """Return the notify service.""" url = '{}:{}'.format(config.get(CONF_HOST), config.get(CONF_PORT)) - auth = (config.get(CONF_USERNAME), config.get(CONF_PASSWORD)) + username = config.get(CONF_USERNAME) + password = config.get(CONF_PASSWORD) + + if username is not None: + auth = (username, password) + else: + auth = None return KODINotificationService( url, @@ -48,10 +54,14 @@ class KODINotificationService(BaseNotificationService): """Initialize the service.""" import jsonrpc_requests self._url = url + + kwargs = {'timeout': 5} + + if auth is not None: + kwargs['auth'] = auth + self._server = jsonrpc_requests.Server( - '{}/jsonrpc'.format(self._url), - auth=auth, - timeout=5) + '{}/jsonrpc'.format(self._url), **kwargs) def send_message(self, message="", **kwargs): """Send a message to Kodi.""" From 8826e6a8d0613948669a8784aa76270bf6a2df63 Mon Sep 17 00:00:00 2001 From: Audun Ytterdal Date: Tue, 6 Dec 2016 18:01:47 +0100 Subject: [PATCH 048/141] Add support for telldus in the Docker image. (#4680) * Add support for telldus in the Docker image. Start with -v /tmp/TelldusClient:/tmp/TelldusClient -v /tmp/TelldusEvents:/tmp/TelldusEvents * Merged telldus install with the others * Clean up indenting * Stream apt-key --- Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index b42d7edcc89..02e3db616ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,12 @@ WORKDIR /usr/src/app RUN pip3 install --no-cache-dir colorlog cython -# For the nmap tracker, bluetooth tracker, Z-Wave -RUN apt-get update && \ - apt-get install -y --no-install-recommends nmap net-tools cython3 libudev-dev sudo libglib2.0-dev bluetooth libbluetooth-dev && \ +# For the nmap tracker, bluetooth tracker, Z-Wave, tellstick +RUN echo "deb http://download.telldus.com/debian/ stable main" >> /etc/apt/sources.list.d/telldus.list && \ + wget -qO - http://download.telldus.se/debian/telldus-public.key | apt-key add - && \ + apt-get update && \ + apt-get install -y --no-install-recommends nmap net-tools cython3 libudev-dev sudo libglib2.0-dev bluetooth libbluetooth-dev \ + libtelldus-core2 libtelldus-core-dev && \ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* COPY script/build_python_openzwave script/build_python_openzwave From 9a3fe691b1a52be49dc0da602b7e6a9812da57c7 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Tue, 6 Dec 2016 23:31:07 -0500 Subject: [PATCH 049/141] Updated python-nest dependency (#4785) * Updated python-nest dependency This sha fixes two issues: - min and max temperatures not being set when temperature isn't locked - fixes error when setting farenheit with a .5 * gen requirements all * Add fix for https://github.com/home-assistant/home-assistant/issues/4731 --- homeassistant/components/climate/nest.py | 14 ++++++-------- homeassistant/components/nest.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index dbc68162579..ab41c10e6d1 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -86,6 +86,8 @@ class NestThermostat(ClimateDevice): self._eco_temperature = None self._is_locked = None self._locked_temperature = None + self._min_temperature = None + self._max_temperature = None @property def name(self): @@ -204,18 +206,12 @@ class NestThermostat(ClimateDevice): @property def min_temp(self): """Identify min_temp in Nest API or defaults if not available.""" - if self._is_locked: - return self._locked_temperature[0] - else: - return None + return self._min_temperature @property def max_temp(self): """Identify max_temp in Nest API or defaults if not available.""" - if self._is_locked: - return self._locked_temperature[1] - else: - return None + return self._max_temperature def update(self): """Cache value from Python-nest.""" @@ -229,6 +225,8 @@ class NestThermostat(ClimateDevice): self._away = self.structure.away == 'away' self._eco_temperature = self.device.eco_temperature self._locked_temperature = self.device.locked_temperature + self._min_temperature = self.device.min_temperature + self._max_temperature = self.device.max_temperature self._is_locked = self.device.is_locked if self.device.temperature_scale == 'C': self._temperature_scale = TEMP_CELSIUS diff --git a/homeassistant/components/nest.py b/homeassistant/components/nest.py index e19011c47b8..0952129c439 100644 --- a/homeassistant/components/nest.py +++ b/homeassistant/components/nest.py @@ -19,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) REQUIREMENTS = [ 'http://github.com/technicalpickles/python-nest' - '/archive/2512973b4b390d3965da43529cd20402ad374bfa.zip' # nest-cam branch + '/archive/dd628f90772d170b9602f262d5d2e7d61bdd3cf5.zip' # nest-cam branch '#python-nest==3.0.0'] DOMAIN = 'nest' diff --git a/requirements_all.txt b/requirements_all.txt index 6f1ca5eb4e1..bcc9836fdc9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -167,7 +167,7 @@ hikvision==0.4 # 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/2512973b4b390d3965da43529cd20402ad374bfa.zip#python-nest==3.0.0 +http://github.com/technicalpickles/python-nest/archive/dd628f90772d170b9602f262d5d2e7d61bdd3cf5.zip#python-nest==3.0.0 # homeassistant.components.light.flux_led https://github.com/Danielhiversen/flux_led/archive/0.9.zip#flux_led==0.9 From c40ddf18c79e2149c95a0e9e649869ecd6a80071 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Wed, 7 Dec 2016 00:03:49 -0500 Subject: [PATCH 050/141] Fix incorrect caching of /api/error_log (#4789) --- homeassistant/components/http/__init__.py | 4 ++-- homeassistant/components/http/static.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index 11a9e755bb4..de864a0c193 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -32,7 +32,7 @@ from .const import ( KEY_USE_X_FORWARDED_FOR, KEY_TRUSTED_NETWORKS, KEY_BANS_ENABLED, KEY_LOGIN_THRESHOLD, KEY_DEVELOPMENT, KEY_AUTHENTICATED) -from .static import GZIP_FILE_SENDER, staticresource_middleware +from .static import FILE_SENDER, GZIP_FILE_SENDER, staticresource_middleware from .util import get_real_ip DOMAIN = 'http' @@ -344,7 +344,7 @@ class HomeAssistantView(object): def file(self, request, fil): """Return a file.""" assert isinstance(fil, str), 'only string paths allowed' - response = yield from GZIP_FILE_SENDER.send(request, Path(fil)) + response = yield from FILE_SENDER.send(request, Path(fil)) return response def register(self, router): diff --git a/homeassistant/components/http/static.py b/homeassistant/components/http/static.py index c8c55870e0f..0bd68d6136e 100644 --- a/homeassistant/components/http/static.py +++ b/homeassistant/components/http/static.py @@ -63,6 +63,7 @@ class GzipFileSender(FileSender): GZIP_FILE_SENDER = GzipFileSender() +FILE_SENDER = FileSender() @asyncio.coroutine From 76b79019ce8b7535d5a22d472356b9ee68fbddfa Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 6 Dec 2016 21:47:58 -0800 Subject: [PATCH 051/141] Add faster reviews link to contributing --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8621851ffb6..3dbc2a7022c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,14 @@ # Contributing to Home Assistant -Everybody is invited and welcome to contribute to Home Assistant. There is a lot to do...if you are not a developer perhaps you would like to help with the documentation on [home-assistant.io](https://home-assistant.io/)? If you are a developer and have devices in your home which aren't working with Home Assistant yet, why not spent a couple of hours and help to integrate them? +Everybody is invited and welcome to contribute to Home Assistant. There is a lot to do...if you are not a developer perhaps you would like to help with the documentation on [home-assistant.io](https://home-assistant.io/)? If you are a developer and have devices in your home which aren't working with Home Assistant yet, why not spent a couple of hours and help to integrate them? The process is straight-forward. + - Read [How to get faster PR reviews](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md) by Kubernetes - Fork the Home Assistant [git repository](https://github.com/home-assistant/home-assistant). - Write the code for your device, notification service, sensor, or IoT thing. - Ensure tests work. - Create a Pull Request against the [**dev**](https://github.com/home-assistant/home-assistant/tree/dev) branch of Home Assistant. -Still interested? Then you should take a peak at the [developer documentation](https://home-assistant.io/developers/) to get more details. +Still interested? Then you should take a peak at the [developer documentation](https://home-assistant.io/developers/) to get more details. From 37e3c2a1336a0ae31bde9356f0a7cb7c06618081 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 6 Dec 2016 21:48:44 -0800 Subject: [PATCH 052/141] Contributing: add skip step 0 --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3dbc2a7022c..a63c1400723 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ Everybody is invited and welcome to contribute to Home Assistant. There is a lot The process is straight-forward. - - Read [How to get faster PR reviews](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md) by Kubernetes + - Read [How to get faster PR reviews](https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md) by Kubernetes (but skip step 0) - Fork the Home Assistant [git repository](https://github.com/home-assistant/home-assistant). - Write the code for your device, notification service, sensor, or IoT thing. - Ensure tests work. From 98fe50d5adea8a4322641ed5c23a745065a8766c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 6 Dec 2016 22:30:47 -0800 Subject: [PATCH 053/141] Update after service calls (#4795) * Update after service calls * Service update: wrap async_update in create_task --- .../alarm_control_panel/__init__.py | 8 ++++++-- homeassistant/components/cover/__init__.py | 17 ++++++++++++----- homeassistant/components/light/__init__.py | 19 ++++++++++++------- homeassistant/components/lock/__init__.py | 7 +++++-- homeassistant/components/remote/__init__.py | 18 +++++++++++------- homeassistant/components/switch/__init__.py | 18 +++++++++++------- 6 files changed, 57 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 2030c8f88d8..49decfc62fe 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -59,8 +59,12 @@ def setup(hass, config): for alarm in target_alarms: getattr(alarm, method)(code) - if alarm.should_poll: - alarm.update_ha_state(True) + + for alarm in target_alarms: + if not alarm.should_poll: + continue + + alarm.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index db517aec978..6c268e49be6 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -135,12 +135,19 @@ def setup(hass, config): params = service.data.copy() params.pop(ATTR_ENTITY_ID, None) - if method: - for cover in component.extract_from_service(service): - getattr(cover, method['method'])(**params) + if not method: + return - if cover.should_poll: - cover.update_ha_state(True) + covers = component.extract_from_service(service) + + for cover in covers: + getattr(cover, method['method'])(**params) + + for cover in covers: + if not cover.should_poll: + continue + + cover.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 04eb8fabc68..869bbd90e7d 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -236,7 +236,6 @@ def async_setup(hass, config): if color_name is not None: params[ATTR_RGB_COLOR] = color_util.color_name_to_rgb(color_name) - update_tasks = [] for light in target_lights: if service.service == SERVICE_TURN_ON: yield from light.async_turn_on(**params) @@ -245,12 +244,18 @@ def async_setup(hass, config): else: yield from light.async_toggle(**params) - if light.should_poll: - update_coro = light.async_update_ha_state(True) - if hasattr(light, 'async_update'): - update_tasks.append(hass.loop.create_task(update_coro)) - else: - yield from update_coro + update_tasks = [] + + for light in target_lights: + if not light.should_poll: + continue + + update_coro = hass.loop.create_task( + light.async_update_ha_state(True)) + if hasattr(light, 'async_update'): + update_tasks.append(hass.loop.create_task(update_coro)) + else: + yield from update_coro if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index 95db9d2b33a..e74b675733b 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -85,8 +85,11 @@ def setup(hass, config): else: item.unlock(code=code) - if item.should_poll: - item.update_ha_state(True) + for item in target_locks: + if not item.should_poll: + continue + + item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index d6f534eae5b..3a481e83830 100755 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -98,7 +98,6 @@ def async_setup(hass, config): device = service.data.get(ATTR_DEVICE) command = service.data.get(ATTR_COMMAND) - update_tasks = [] for remote in target_remotes: if service.service == SERVICE_TURN_ON: yield from remote.async_turn_on(activity=activity_id) @@ -108,12 +107,17 @@ def async_setup(hass, config): else: yield from remote.async_turn_off() - if remote.should_poll: - update_coro = remote.async_update_ha_state(True) - if hasattr(remote, 'async_update'): - update_tasks.append(hass.loop.create_task(update_coro)) - else: - yield from update_coro + update_tasks = [] + for remote in target_remotes: + if not remote.should_poll: + continue + + update_coro = hass.loop.create_task( + remote.async_update_ha_state(True)) + if hasattr(remote, 'async_update'): + update_tasks.append(hass.loop.create_task(update_coro)) + else: + yield from update_coro if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index 02a313c675f..846a87f5067 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -82,7 +82,6 @@ def async_setup(hass, config): """Handle calls to the switch services.""" target_switches = component.async_extract_from_service(service) - update_tasks = [] for switch in target_switches: if service.service == SERVICE_TURN_ON: yield from switch.async_turn_on() @@ -91,12 +90,17 @@ def async_setup(hass, config): else: yield from switch.async_turn_off() - if switch.should_poll: - update_coro = switch.async_update_ha_state(True) - if hasattr(switch, 'async_update'): - update_tasks.append(hass.loop.create_task(update_coro)) - else: - yield from update_coro + update_tasks = [] + for switch in target_switches: + if not switch.should_poll: + continue + + update_coro = hass.loop.create_task( + switch.async_update_ha_state(True)) + if hasattr(switch, 'async_update'): + update_tasks.append(hass.loop.create_task(update_coro)) + else: + yield from update_coro if update_tasks: yield from asyncio.wait(update_tasks, loop=hass.loop) From 82ad8b0a8fbc978693ef63c4a4ad506f353088fa Mon Sep 17 00:00:00 2001 From: Nolan Gilley Date: Wed, 7 Dec 2016 03:15:48 -0500 Subject: [PATCH 054/141] round $ to 2 decimals (#4786) --- homeassistant/components/sensor/coinmarketcap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/coinmarketcap.py b/homeassistant/components/sensor/coinmarketcap.py index 61545fa3944..e041352af58 100644 --- a/homeassistant/components/sensor/coinmarketcap.py +++ b/homeassistant/components/sensor/coinmarketcap.py @@ -77,7 +77,7 @@ class CoinMarketCapSensor(Entity): @property def state(self): """Return the state of the sensor.""" - return self._ticker.get('price_usd') + return round(self._ticker.get('price_usd'), 2) @property def unit_of_measurement(self): From d0dcd1bb732c2b260c6fe7fe96d5ff0d2fbb2aee Mon Sep 17 00:00:00 2001 From: Jan Losinski Date: Wed, 7 Dec 2016 14:33:41 +0100 Subject: [PATCH 055/141] Scene: add support for input_select (#4674) This adds support for the scene component to handle input_select devices and set their options. This fixes bug #4673 Signed-off-by: Jan Losinski --- homeassistant/const.py | 4 ++++ homeassistant/helpers/state.py | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index d9191eaedf2..0a014c0b603 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -278,6 +278,8 @@ ATTR_GPS_ACCURACY = 'gps_accuracy' ATTR_ASSUMED_STATE = 'assumed_state' ATTR_STATE = 'state' +ATTR_OPTION = 'option' + # #### SERVICES #### SERVICE_HOMEASSISTANT_STOP = 'stop' SERVICE_HOMEASSISTANT_RESTART = 'restart' @@ -318,6 +320,8 @@ SERVICE_SET_COVER_TILT_POSITION = 'set_cover_tilt_position' SERVICE_STOP_COVER = 'stop_cover' SERVICE_STOP_COVER_TILT = 'stop_cover_tilt' +SERVICE_SELECT_OPTION = 'select_option' + # #### API / REMOTE #### SERVER_PORT = 8123 diff --git a/homeassistant/helpers/state.py b/homeassistant/helpers/state.py index 9980ad11a8d..46b7837dc15 100644 --- a/homeassistant/helpers/state.py +++ b/homeassistant/helpers/state.py @@ -32,7 +32,7 @@ from homeassistant.const import ( SERVICE_CLOSE_COVER, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, STATE_CLOSED, STATE_LOCKED, STATE_OFF, STATE_ON, STATE_OPEN, STATE_PAUSED, STATE_PLAYING, - STATE_UNKNOWN, STATE_UNLOCKED) + STATE_UNKNOWN, STATE_UNLOCKED, SERVICE_SELECT_OPTION, ATTR_OPTION) from homeassistant.core import State from homeassistant.util.async import run_coroutine_threadsafe @@ -58,7 +58,8 @@ SERVICE_ATTRIBUTES = { SERVICE_SET_OPERATION_MODE: [ATTR_OPERATION_MODE], SERVICE_SET_AUX_HEAT: [ATTR_AUX_HEAT], SERVICE_SELECT_SOURCE: [ATTR_INPUT_SOURCE], - SERVICE_SEND_IR_CODE: [ATTR_IR_CODE] + SERVICE_SEND_IR_CODE: [ATTR_IR_CODE], + SERVICE_SELECT_OPTION: [ATTR_OPTION] } # Update this dict when new services are added to HA. From 8295fc8b4c8098931fba3822ce7e302d505f4e64 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 7 Dec 2016 17:37:35 +0100 Subject: [PATCH 056/141] Pararell execute state restore by domain (#4801) * Pararell execute state restore per domain * fix spell --- homeassistant/helpers/state.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/homeassistant/helpers/state.py b/homeassistant/helpers/state.py index 46b7837dc15..536975c100e 100644 --- a/homeassistant/helpers/state.py +++ b/homeassistant/helpers/state.py @@ -164,11 +164,28 @@ def async_reproduce_state(hass, states, blocking=False): json.dumps(dict(state.attributes), sort_keys=True)) to_call[key].append(state.entity_id) + domain_tasks = {} for (service_domain, service, service_data), entity_ids in to_call.items(): data = json.loads(service_data) data[ATTR_ENTITY_ID] = entity_ids - yield from hass.services.async_call( - service_domain, service, data, blocking) + + if service_domain not in domain_tasks: + domain_tasks[service_domain] = [] + + domain_tasks[service_domain].append( + hass.services.async_call(service_domain, service, data, blocking) + ) + + @asyncio.coroutine + def async_handle_service_calls(coro_list): + """Handle service calls by domain sequence.""" + for coro in coro_list: + yield from coro + + execute_tasks = [async_handle_service_calls(coro_list) + for coro_list in domain_tasks.values()] + if execute_tasks: + yield from asyncio.wait(execute_tasks, loop=hass.loop) def state_as_number(state): From 194b268ae3938b1e80cbac5b984815a5e93f823d Mon Sep 17 00:00:00 2001 From: Keaton Taylor Date: Wed, 7 Dec 2016 23:45:18 -0600 Subject: [PATCH 057/141] Get entity name from entity.name (#4798) Grabbing the ATTR_FRIENDLY_NAME directly produces an error. Instead grab from entity.name. --- homeassistant/components/emulated_hue/hue_api.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/emulated_hue/hue_api.py b/homeassistant/components/emulated_hue/hue_api.py index ed06da9495b..32fb4af071c 100644 --- a/homeassistant/components/emulated_hue/hue_api.py +++ b/homeassistant/components/emulated_hue/hue_api.py @@ -6,8 +6,8 @@ from aiohttp import web from homeassistant import core from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, SERVICE_TURN_OFF, SERVICE_TURN_ON, - STATE_ON, STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, + ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON, + STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, ) from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_SUPPORTED_FEATURES, SUPPORT_BRIGHTNESS @@ -251,8 +251,7 @@ def entity_to_json(entity, is_on=None, brightness=None): if brightness is None: brightness = 255 if is_on else 0 - name = entity.attributes.get( - ATTR_EMULATED_HUE_NAME, entity.attributes[ATTR_FRIENDLY_NAME]) + name = entity.attributes.get(ATTR_EMULATED_HUE_NAME, entity.name) return { 'state': From 695f062e298cf58ce81ee3c40d0dea837ad6fbef Mon Sep 17 00:00:00 2001 From: R1chardTM Date: Thu, 8 Dec 2016 06:45:43 +0100 Subject: [PATCH 058/141] Fix python-nest version bump (#4799) * Fix python-nest version bump * Change SHA so version in HASS and dependency are the same --- homeassistant/components/nest.py | 4 ++-- requirements_all.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/nest.py b/homeassistant/components/nest.py index 0952129c439..fd5627987a3 100644 --- a/homeassistant/components/nest.py +++ b/homeassistant/components/nest.py @@ -19,8 +19,8 @@ _LOGGER = logging.getLogger(__name__) REQUIREMENTS = [ 'http://github.com/technicalpickles/python-nest' - '/archive/dd628f90772d170b9602f262d5d2e7d61bdd3cf5.zip' # nest-cam branch - '#python-nest==3.0.0'] + '/archive/7a2eb38d391bddeb78079437f001224c370b555a.zip' # nest-cam branch + '#python-nest==3.0.1'] DOMAIN = 'nest' diff --git a/requirements_all.txt b/requirements_all.txt index bcc9836fdc9..27573a2c587 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -167,7 +167,7 @@ hikvision==0.4 # 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/dd628f90772d170b9602f262d5d2e7d61bdd3cf5.zip#python-nest==3.0.0 +http://github.com/technicalpickles/python-nest/archive/7a2eb38d391bddeb78079437f001224c370b555a.zip#python-nest==3.0.1 # homeassistant.components.light.flux_led https://github.com/Danielhiversen/flux_led/archive/0.9.zip#flux_led==0.9 From 2e2b764dbee5ef598d9ff6907925de94b78831e2 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Wed, 7 Dec 2016 23:46:42 -0600 Subject: [PATCH 059/141] Add exception handling when turning on Onkyo receivers (#4813) --- homeassistant/components/media_player/onkyo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/onkyo.py b/homeassistant/components/media_player/onkyo.py index 5829d119f95..28f8dd1bf6b 100644 --- a/homeassistant/components/media_player/onkyo.py +++ b/homeassistant/components/media_player/onkyo.py @@ -89,7 +89,7 @@ class OnkyoDevice(MediaPlayerDevice): except (ValueError, OSError, AttributeError, AssertionError): if self._receiver.command_socket: self._receiver.command_socket = None - _LOGGER.info('Reseting connection to %s.', self._name) + _LOGGER.info('Resetting connection to %s.', self._name) else: _LOGGER.info('%s is disconnected. Attempting to reconnect.', self._name) @@ -173,7 +173,7 @@ class OnkyoDevice(MediaPlayerDevice): def turn_on(self): """Turn the media player on.""" - self._receiver.power_on() + self.command('system-power on') def select_source(self, source): """Set the input source.""" From 14446c5731e788c67af819234cf158cc9f3c6f16 Mon Sep 17 00:00:00 2001 From: Lewis Juggins Date: Thu, 8 Dec 2016 08:36:37 +0000 Subject: [PATCH 060/141] [media_player.sonos] Add stop support. (#4788) --- .../components/media_player/sonos.py | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 1fa1a39633d..c6e9c1e6655 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -15,7 +15,7 @@ from homeassistant.components.media_player import ( ATTR_MEDIA_ENQUEUE, DOMAIN, MEDIA_TYPE_MUSIC, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_CLEAR_PLAYLIST, - SUPPORT_SELECT_SOURCE, MediaPlayerDevice, PLATFORM_SCHEMA) + SUPPORT_SELECT_SOURCE, MediaPlayerDevice, PLATFORM_SCHEMA, SUPPORT_STOP) from homeassistant.const import ( STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_OFF, ATTR_ENTITY_ID, CONF_HOSTS) @@ -36,9 +36,10 @@ _SOCO_LOGGER.setLevel(logging.ERROR) _REQUESTS_LOGGER = logging.getLogger('requests') _REQUESTS_LOGGER.setLevel(logging.ERROR) -SUPPORT_SONOS = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE |\ - SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | SUPPORT_PLAY_MEDIA |\ - SUPPORT_SEEK | SUPPORT_CLEAR_PLAYLIST | SUPPORT_SELECT_SOURCE +SUPPORT_SONOS = SUPPORT_STOP | SUPPORT_PAUSE | SUPPORT_VOLUME_SET |\ + SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK |\ + SUPPORT_PLAY_MEDIA | SUPPORT_SEEK | SUPPORT_CLEAR_PLAYLIST |\ + SUPPORT_SELECT_SOURCE SERVICE_GROUP_PLAYERS = 'sonos_group_players' SERVICE_UNJOIN = 'sonos_unjoin' @@ -289,6 +290,7 @@ class SonosDevice(MediaPlayerDevice): self._media_next_title = None self._support_previous_track = False self._support_next_track = False + self._support_stop = False self._support_pause = False self._current_track_uri = None self._current_track_is_radio_stream = False @@ -433,6 +435,7 @@ class SonosDevice(MediaPlayerDevice): support_previous_track = False support_next_track = False + support_stop = False support_pause = False if is_playing_tv: @@ -450,6 +453,7 @@ class SonosDevice(MediaPlayerDevice): ) support_previous_track = False support_next_track = False + support_stop = False support_pause = False # for radio streams we set the radio station name as the @@ -506,6 +510,7 @@ class SonosDevice(MediaPlayerDevice): ) support_previous_track = True support_next_track = True + support_stop = True support_pause = True position_info = self._player.avTransport.GetPositionInfo( @@ -583,6 +588,7 @@ class SonosDevice(MediaPlayerDevice): 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 @@ -614,6 +620,7 @@ class SonosDevice(MediaPlayerDevice): self._current_track_is_radio_stream = False self._support_previous_track = False self._support_next_track = False + self._support_stop = False self._support_pause = False self._is_playing_tv = False self._is_playing_line_in = False @@ -774,6 +781,9 @@ class SonosDevice(MediaPlayerDevice): if not self._support_next_track: supported = supported ^ SUPPORT_NEXT_TRACK + if not self._support_stop: + supported = supported ^ SUPPORT_STOP + if not self._support_pause: supported = supported ^ SUPPORT_PAUSE @@ -836,6 +846,13 @@ class SonosDevice(MediaPlayerDevice): else: self._player.play() + def media_stop(self): + """Send stop command.""" + if self._coordinator: + self._coordinator.media_stop() + else: + self._player.stop() + def media_pause(self): """Send pause command.""" if self._coordinator: From c90a1b97605648f9855926b86b147ec4347151c4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 8 Dec 2016 22:31:23 -0800 Subject: [PATCH 061/141] Update frontend --- homeassistant/components/frontend/version.py | 6 +- .../frontend/www_static/frontend.html | 4 +- .../frontend/www_static/frontend.html.gz | Bin 130476 -> 130643 bytes .../www_static/home-assistant-polymer | 2 +- .../panels/ha-panel-dev-service.html | 2 +- .../panels/ha-panel-dev-service.html.gz | Bin 17702 -> 17764 bytes .../www_static/panels/ha-panel-map.html | 184 +++++++++++++++++- .../www_static/panels/ha-panel-map.html.gz | Bin 42075 -> 43807 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2326 -> 2323 bytes .../www_static/webcomponents-lite.min.js | 6 +- .../www_static/webcomponents-lite.min.js.gz | Bin 12355 -> 12360 bytes 12 files changed, 191 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 14650b47cb7..e6211c145e2 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,17 +2,17 @@ FINGERPRINTS = { "core.js": "5dfb2d3e567fad37af0321d4b29265ed", - "frontend.html": "d4f164e559944b8abc560d7b46131714", + "frontend.html": "ac15b11435132aab3da592f9e7b05400", "mdi.html": "46a76f877ac9848899b8ed382427c16f", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "c2d5ec676be98d4474d19f94d0262c1e", "panels/ha-panel-dev-info.html": "a9c07bf281fe9791fb15827ec1286825", - "panels/ha-panel-dev-service.html": "b3fe49532c5c03198fafb0c6ed58b76a", + "panels/ha-panel-dev-service.html": "20420e2387fd93db53c8d778097e3d59", "panels/ha-panel-dev-state.html": "65e5f791cc467561719bf591f1386054", "panels/ha-panel-dev-template.html": "7d744ab7f7c08b6d6ad42069989de400", "panels/ha-panel-history.html": "efe1bcdd7733b09e55f4f965d171c295", "panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab", "panels/ha-panel-logbook.html": "4bc5c8370a85a4215413fbae8f85addb", - "panels/ha-panel-map.html": "1bf6965b24d76db71a1871865cd4a3a2", + "panels/ha-panel-map.html": "3b0ca63286cbe80f27bd36dbc2434e89", "websocket_test.html": "575de64b431fe11c3785bf96d7813450" } diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 54b9cc4d5e4..dd0eba180ec 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -1,5 +1,5 @@

\ No newline at end of file +},customStyle:null,getComputedStyleValue:function(e){return!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 3bf5bab1b5944da1c6375064d0b6d982ab667b5d..b1488e61a11ee39c694803a710a4e6b8eea2e090 100644 GIT binary patch delta 101571 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 ZI&$9QL0UOj$+arTmW#%i?} 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 delta 101406 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%0A));T_Lf^B;F~c(o%B%dr1U3e-LH;Ca%f6&LPG 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

`sl5S9Vu2lN8{hGSR|I2d}>DE*6cs? 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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 4697af1b0d9..336e974fe6f 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 4697af1b0d96e7a21454539888c68189668fa80d +Subproject commit 336e974fe6f4196aaf0b309e805a009ef0fdfd66 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 51805ebd91d..e4fd1211753 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 f6c74234e4d56e43ca9be97211a2b65756a5e07c..2419c25adbd0c227748e2991b75bdd3295e45bd4 100644 GIT binary patch delta 12168 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 delta 12105 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 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 d63acba7549..38dd2b6e961 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-map.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-map.html @@ -1,4 +1,180 @@ - \ No newline at end of file + \ 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 e153a5290fbbb505b414fb4b8b7b05b3455437f5..56a98ed3431887e2fdb5c9f724ac501f8244834b 100644 GIT binary patch literal 43807 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 literal 42075 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 RHva$5czDkIKC>fC3;;#Qs}ukL diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index b125336669c..d2ef4b42439 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=[["/","e14330e71c13caf3a8ad2ec699e46047"],["/frontend/panels/dev-event-c2d5ec676be98d4474d19f94d0262c1e.html","6c55fc819751923ab00c62ae3fbb7222"],["/frontend/panels/dev-info-a9c07bf281fe9791fb15827ec1286825.html","931f9327e368db710fcdf5f7202f2588"],["/frontend/panels/dev-service-b3fe49532c5c03198fafb0c6ed58b76a.html","4194cb43b74108dc6d10354da2fd81fd"],["/frontend/panels/dev-state-65e5f791cc467561719bf591f1386054.html","78158786a6597ef86c3fd6f4985cde92"],["/frontend/panels/dev-template-7d744ab7f7c08b6d6ad42069989de400.html","8a6ee994b1cdb45b081299b8609915ed"],["/frontend/panels/map-1bf6965b24d76db71a1871865cd4a3a2.html","a74c01c2ee68c83c9938af067ec33b81"],["/static/core-5dfb2d3e567fad37af0321d4b29265ed.js","9a50270db7613e3af449f6c773366f4d"],["/static/frontend-d4f164e559944b8abc560d7b46131714.html","fd803353b0ff1844aa4677b8a0f79fea"],["/static/mdi-46a76f877ac9848899b8ed382427c16f.html","a846c4082dd5cffd88ac72cbe943e691"],["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","b0f32ad3c7749c40d486603f31c9d8b1"]],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"}))}))})}).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;n)0$4N*ZXno_quMj zd+TofEcIbK1Z%)3|`0kt% ztEz-Uy?OkPhb30E%KIAXO>C?FYU^t(oHg@j!H#=cuep>rPFj|?O`fN{`cVz9+qu~E zGt-amFn+H#W47zeo~O6ij{o1sV7&h7&d=Y@{^swqXJ5A<^Sth^|1aj>eSdEAE~Ad8 zFPN=f&#|uAsdK%rZ~vCkr$79|HI``pyS;X<^?s)O1(Fu&&#rxTU7L6A|IdGC>t7#8 z^D}kU{ushg)YHd3Vk5)z_P|@v(KHU#W=EBq6z0t3@j5HX)I7R9co8UO$&E zZ~khTv3KwEJx!ZrwRcE0_Wtw;n%dyAIfUVKs7(4sC7;a^ttLw+IkYpq@=TqSF;jS& zYRkorZi6YBPX#g+jl5oF+PW@%Etqa}rlo$F<;4R=Zd(*Q{fsBHJj?W(+$$v}cvh)K zaOqAVNzSbyRu?6CS1$9MH$UvMQ*o$=#6^Q;iWfA_Z%LXcvHQ#UHOPV!|2Wd4PS=0NiL@>&Q6+=(!x1+LAuJR%Lbk1RhwjN z&wiRxznn8_!RHXSsHIkEl}e%;*c*&DL`(|{ZTr}>^F)c-;g}^_Pq}J+Bu~$5vfwda zRWy&uK#W^yYKO4kvlb(@3o^$%m|pGB%F$lz(K2bd;4vqz6VATI3m1iOdOp@@tKput zNQ9xIXOYZyCT`Dp3QSsFOF9HyRKI=T5^wjX3i-4o6WpAdM=PL82 zO1b4iu7OL1R@QGlRjg;+C1Av&oVrAK&qk@9s_llQ9BNy|Mw6iyqsGNk_ZxnVtHt=GLZOAG7I{Od8C%5l)NY*I+^ z8UoZCH_QxcR?R*0^NZg5p@;F`H9T!|^O(X? zFUI4?ye0)Cvv=-%qL}pe=6j0=rtt@^WUhCY4w8tyc=3c~akNJ1g#&9Gm|jXeJ9*IS z!YQfF8-+IeXM{#9w&>jRl-J9|BXPaOCxxK%Uy}a(KBc2~e17e^EBPKLrrFi!$Axh1 z^L?MjbNckOIjdGKJ=p&~PAT5^*GA@-oHw^|O}leOdy3qa6D<$=I?QEum7h)ze*Duy z;mUjKQ^k9u(8m@d)+Em6dq`I-l@!~uIByf&hL+hr#g1~Xg^QC z{PwYM`ilsOa|}~Xyrp)ejZn9y;SA0 zY<7F;nhx*W%kH;J)d>He_! zdhaIn(%Sl!-C2uQ)w^AO_w@Xn?VtIY_xb3RzdG`Hq`x z+?i3#f4S;8rX7ua@@L(NQ@iB97}ziSt@-9t?QDZ?`H8&0#A}XM#MkZny2n$U|Mj}r zr{ixeStSs>{D7s{@xbHvxAHV)$Ia-Us_C`;^8(%t`?Sk%Yxvd6^YHa6f8Um;Y*KOi zO825xhO4{%XSdyF@i@%=U2fJvQT_0S<1?xS*X+_dV4%#it!djs7x`H3$JRg2pGtFh zTJQcsq$>8qCfo9;E%hyrKdo6I!?NsmalxgVAK4SL_luqO@9>z<^NsmG%bagA#jT0A zj&JV&^6X5>rGqE`H~#KC99Lf|^7fUY#@n0u?C1XZG*|!Q2-u{f!~RfTU(CL7m9^a4 z$1PzN_4WS_zKn{#d|dxUzel#f#vs2kweRnwOCBn!eNs!SvgfLmD&?KxzfotxlwUJ* zK5_V$-4QzTrD0plY1x08iF-{fU2nZ=Iq~qq%7U~RH(73e7t~C&uzB(8UF+xF(y#3* zpL}!q&+I?RKF3?5eoepH^y{UcMWvSflAqkiE?d9Eecwj+2W(MG^uDe%_-sFax$WsY z)9su4*!lM#p3{(P=67b#%JuB$XD>U(^UI*!ad{ALRdlFOLj}%=!*KgA2SwFwwp!2qf`ypGlefe{@t}sPo_Vw%Q z%h$QaEID#$%Cv3#iFSKtzkC-abEZsV-3N(n`a`(AIZS)L=l{&v*#UH%&z z*B#t>%q%e8`uMw(yLO&pJ9q-%posdM6HW@ zW6QknWQANw_B!)}`etc2qJCdlc`wJh=JCIs1qyY)A66I$?AYCXc&+(QdA95s3R6WG F7y#*Ua+m-B delta 2324 zcmbO%G)<^pzMF%?+}|yNiMcqns4O!%HNHH*C_A-CFRPegX~gg1*{4MRg^Mf;ZK0V}Ly=>3dy#D;P4~jkr^6Wd98XdjrmdLINcm6$p${O;FRp0yI({k~e$FZ*$ zHGW@Rwy(DO?C#p-YA@t#j`AM=|MnE;8|(WYZvOrLm6pv?fo}dd`iICGc^`5`cq3=Cq{S%o8RU={BWK{eDlQO z>yn>S4d0#F&GjrTP%U}qwu2wnizhtWYE^n~|L-3sKR!PoYVvla>v#FTo2%dMS)tt= z(Py`C^SPCWr=Ko*`{GA*ba>zYnpUS-kM`f)9sE4}0j~-3^CNev_N};j^`*W2zWQqE z8)sIgWw^?3;l9T+jn`wgv3oik4k66sYNM^)%rWn zCI1mv?$g=R5~Vfwg$|dptZI*J_+_W!Ko5z|2hR`zW5GCdoqB>JSEAw6NE&e~NzsZ)w3zVvDHS)%o{%T2Lu##62g ziM$ZQc}!0%MP0NUg$0d-p6+xg{xnCW;D~CDwz5*mtmT~@D^3M$nPQ_E&DX zc)(c8SxLEJil^9Vn|{gbiCv97$p<~wA7lzSv2l&GglfH4x5v>5OJ+XPI#*CCBk1Zn z#hqgz*S@W0Z)`Xh>$sfN>{NU<>r%{eqtlNpT-RKgcc+(G+11ojQ-$-F59?zmwagVp zj)5GNu_Cbk?wJ(>ctm$QHnSfAYS7qaDj^yiHFV=@q+4ZdPdOiga1* zGbtqhVS>q2laz_|L7i7tv=z>D74q&pHsP7AjP&Y@FUsy*S!DM0hx2#iUt9G;6MEbN zwfc%QXLe+Ec?ddH&by%TXpXkhA(MYIS6n}ulXq>C(Zq~{Gt?$B=tN4rHfZVKkW5}U zspFr|HR*t(SsTTcF)BNGiX}Cj_BhS5SxIGrV#6u3`SUq{Gi(k$IlF$VN#D)+Pj`B? zJdm>XTxD6tq&I`fEm^62spz)+e$)LM_?6#S*?-92uqLhc>odhP8K)Muk333Zi`qMC zJUC8HT3p2Rhy8oINtf`#ingeOyI3Pkn3Njl8c(g_UzBt({eqI9$*Y>i3m=MgPHShJ zJDQWr+pk$>)@nQBXlK_(wIHebg_@RS&!!aY(|#+|vPS&$u0!u`_nkVVuu(iTo^8g0 z!j{mcPXA&b9oNWNZ5!PZijJ~8yBxm%al`f+#^B|9WpX_dO9Xq}&UM~)TG`B&#wz4- z+~7RlJ(jg=CU(dk|J)tfYT7mVMD@J|F3lp}+LZZ~zWSU$wtxMZM>T)0KKJ_D)>5DI z^7E_Er4NpO$vd`TPtM7ev!bN_{CQ~l>FN@B>k0EFj&~guhZk0V z|CN$uBhTLQE7`qrUHR+NY#ZK|CSThBAj^Mt{LektHTX^WeiUewt2{iC;yJh4+{`p-E?|1S@yP4mS|Pu0jmG!HCZ8S}`B<*o{9uy!v*OgQOK)v5nAf~Nb+_KE>oI%t;m0TT zF1^jcd(Zsqq6|fcukSuDdl=4m>BFJD?P&!EPm4Y2Q^I^M6nDJ76ZQo_6ob^ycZl!O3j3vkor^UdguCRhQ??oY@Ce^VvTn zcQzjKceOrnB>&>Z122su%EW9gOneg(K7AY4>{GSB7R60n_3L}E@rI1UbNON)zx*}* zn&geTtI-8kKc3#bT)SnWZ2k3chTGR;9c9*cJY6-{{(^Lqine!RfwHS+)|F%h9Q@eVyvpw?c#LwDKYE}!( zW?WTLq8qOJZ64$O6dV3s32&&127>t&&-1==[34,35,60,62,63,96].indexOf(t)?e:encodeURIComponent(e)}function i(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,96].indexOf(t)?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&&" "!=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):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},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;a>o&&(t=n[o]);o++)i.decorate(t)},document.addEventListener("DOMContentLoaded",function(){i.bootstrap(document)});var l=document.createElement;document.createElement=function(){"use strict";var e=l.apply(document,arguments);return"template"===e.localName&&i.decorate(e),e};var u=/[&\u00A0<>]/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;c>s;s++)o=i[s],n=a[s],this.decorate&&this.decorate(o),n.parentNode.replaceChild(o.cloneNode(!0),n)};var f=document.importNode;Node.prototype.cloneNode=function(e){var t=h.call(this,e);return e&&i.fixClonedDom(t,this),t},document.importNode=function(e,t){if(e.localName===r)return i.cloneNode(e,t);var n=f.call(document,e,t);return t&&i.fixClonedDom(n,e),n},o&&(HTMLTemplateElement.prototype.cloneNode=function(e){return i.cloneNode(this,e)})}n&&(window.HTMLTemplateElement=i)}(),function(e){"use strict";if(!window.performance){var t=Date.now();window.performance={now:function(){return Date.now()-t}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var e=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return e?function(t){return e(function(){t(performance.now())})}:function(e){return window.setTimeout(e,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(e){clearTimeout(e)}}());var n=function(){var e=document.createEvent("Event");return e.initEvent("foo",!0,!0),e.preventDefault(),e.defaultPrevented}();if(!n){var o=Event.prototype.preventDefault;Event.prototype.preventDefault=function(){this.cancelable&&(o.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0},configurable:!0}))}}var r=/Trident/.test(navigator.userAgent);if((!window.CustomEvent||r&&"function"!=typeof window.CustomEvent)&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),!window.Event||r&&"function"!=typeof window.Event){var i=window.Event;window.Event=function(e,t){t=t||{};var n=document.createEvent("Event");return n.initEvent(e,Boolean(t.bubbles),Boolean(t.cancelable)),n},window.Event.prototype=i.prototype}}(window.WebComponents),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||p,o(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===w}function o(e,t){if(n(t))e&&e();else{var r=function(){"complete"!==t.readyState&&t.readyState!==w||(t.removeEventListener(_,r),o(e,t))};t.addEventListener(_,r)}}function r(e){e.target.__loaded=!0}function i(e,t){function n(){c==d&&e&&e({allImports:s,loadedImports:l,errorImports:u})}function o(e){r(e),l.push(this),c++,n()}function i(e){u.push(this),c++,n()}var s=t.querySelectorAll("link[rel=import]"),c=0,d=s.length,l=[],u=[];if(d)for(var h,f=0;d>f&&(h=s[f]);f++)a(h)?(l.push(this),c++,n()):(h.addEventListener("load",o),h.addEventListener("error",i));else n()}function a(e){return u?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)c(t)&&d(t)}function c(e){return"link"===e.localName&&"import"===e.rel}function d(e){var t=e["import"];t?r({target:e}):(e.addEventListener("load",r),e.addEventListener("error",r))}var l="import",u=Boolean(l in document.createElement("link")),h=Boolean(window.ShadowDOMPolyfill),f=function(e){return h?window.ShadowDOMPolyfill.wrapIfNeeded(e):e},p=f(document),m={get:function(){var e=window.HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return f(e)},configurable:!0};Object.defineProperty(document,"_currentScript",m),Object.defineProperty(p,"_currentScript",m);var v=/Trident/.test(navigator.userAgent),w=v?"complete":"interactive",_="readystatechange";u&&(new MutationObserver(function(e){for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,o=t.length;o>n&&(e=t[n]);n++)d(e)}()),t(function(e){window.HTMLImports.ready=!0,window.HTMLImports.readyTime=(new Date).getTime();var t=p.createEvent("CustomEvent");t.initCustomEvent("HTMLImportsLoaded",!0,!0,e),p.dispatchEvent(t)}),e.IMPORT_LINK_TYPE=l,e.useNative=u,e.rootDocument=p,e.whenReady=t,e.isIE=v}(window.HTMLImports),function(e){var t=[],n=function(e){t.push(e)},o=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=o}(window.HTMLImports),window.HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,o={resolveUrlsInStyle:function(e,t){var n=e.ownerDocument,o=n.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,t,o),e},resolveUrlsInCssText:function(e,o,r){var i=this.replaceUrls(e,r,o,t);return i=this.replaceUrls(i,r,o,n)},replaceUrls:function(e,t,n,o){return e.replace(o,function(e,o,r,i){var a=r.replace(/["']/g,"");return n&&(a=new URL(a,n).href),t.href=a,a=t.href,o+"'"+a+"'"+i})}};e.path=o}),window.HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=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;o>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,o){if(n.load&&console.log("fetch",e,o),e)if(e.match(/^data:/)){var r=e.split(","),i=r[0],a=r[1];a=i.indexOf(";base64")>-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;c>s&&(i=a[s]);s++)this.onload(e,i,o,n,r),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=o}),window.HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,o=e.length;o>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),window.HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===l}function n(e){var t=o(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function o(e){return e.textContent+r(e)}function r(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,o=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+o+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,c=e.flags,d=e.isIE,l=e.IMPORT_LINK_TYPE,u="link[rel="+l+"]",h={documentSelectors:u,importsSelectors:[u,"link[rel=stylesheet]:not([type])","style:not([type])","script:not([type])",'script[type="application/javascript"]','script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(c.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){c.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,c.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=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(-1==e.textContent.indexOf("@import"))r=!0;else if(e.sheet){r=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;s>c&&(i=a[c]);c++)i.type===CSSRule.IMPORT_RULE&&(r=r&&Boolean(i.styleSheet))}r&&setTimeout(function(){e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))})}},parseScript:function(t){var o=document.createElement("script");o.__importElement=t,o.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(o,function(t){o.parentNode&&o.parentNode.removeChild(o),e.currentScript=null}),this.addElementToDocument(o)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var o,r=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=r.length;a>i&&(o=r[i]);i++)if(!this.isParsed(o))return this.hasResource(o)?t(o)?this.nextToParseInDoc(o.__doc,o):o:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=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;c>s&&(a=e[s]);s++)o||(o=a.ownerDocument,r=t.isParsed(o)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&r&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&r.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&r.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=o.added.bind(o);var r=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){window.HTMLImports.importer.bootDocument(o)}var n=e.initializeModules;e.isIE;if(!e.useNative){n();var o=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(window.HTMLImports),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],o=function(e){n.push(e)},r=function(){n.forEach(function(t){t(e)})};e.addModule=o,e.initializeModules=r,e.hasNative=Boolean(document.registerElement),e.isIE=/Trident/.test(navigator.userAgent),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||window.HTMLImports.useNative)}(window.CustomElements),window.CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void o(e,t)}),o(e,t)}function n(e,t,o){var r=e.firstElementChild;if(!r)for(r=e.firstChild;r&&r.nodeType!==Node.ELEMENT_NODE;)r=r.nextSibling;for(;r;)t(r,o)!==!0&&n(r,t,o),r=r.nextElementSibling;return null}function o(e,n){for(var o=e.shadowRoot;o;)t(o,n),o=o.olderShadowRoot}function r(e,t){i(e,t,[])}function i(e,t,n){if(e=window.wrap(e),!(n.indexOf(e)>=0)){n.push(e);for(var o,r=e.querySelectorAll("link[rel="+a+"]"),s=0,c=r.length;c>s&&(o=r[s]);s++)o["import"]&&i(o["import"],t,n);t(e)}}var a=window.HTMLImports?window.HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=r,e.forSubtree=t}),window.CustomElements.addModule(function(e){function t(e,t){return n(e,t)||o(e,t)}function n(t,n){return e.upgrade(t,n)?!0:void(n&&a(t))}function o(e,t){g(e,function(e){return n(e,t)?!0:void 0})}function r(e){L.push(e),E||(E=!0,setTimeout(i))}function i(){E=!1;for(var e,t=L,n=0,o=t.length;o>n&&(e=t[n]);n++)e();L=[]}function a(e){y?r(function(){s(e)}):s(e)}function s(e){ -e.__upgraded__&&!e.__attached&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function c(e){d(e),g(e,function(e){d(e)})}function d(e){y?r(function(){l(e)}):l(e)}function l(e){e.__upgraded__&&e.__attached&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function u(e){for(var t=e,n=window.wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&t.host}}function h(e){if(e.shadowRoot&&!e.shadowRoot.__watched){_.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)m(t),t=t.olderShadowRoot}}function f(e,n){if(_.dom){var o=n[0];if(o&&"childList"===o.type&&o.addedNodes&&o.addedNodes){for(var r=o.addedNodes[0];r&&r!==document&&!r.host;)r=r.parentNode;var i=r&&(r.URL||r._URL||r.host&&r.host.localName)||"";i=i.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",n.length,i||"")}var a=u(e);n.forEach(function(e){"childList"===e.type&&(N(e.addedNodes,function(e){e.localName&&t(e,a)}),N(e.removedNodes,function(e){e.localName&&c(e)}))}),_.dom&&console.groupEnd()}function p(e){for(e=window.wrap(e),e||(e=window.wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(f(e,t.takeRecords()),i())}function m(e){if(!e.__observer){var t=new MutationObserver(f.bind(this,e));t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function v(e){e=window.wrap(e),_.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop());var n=e===window.wrap(document);t(e,n),m(e),_.dom&&console.groupEnd()}function w(e){b(e,v)}var _=e.flags,g=e.forSubtree,b=e.forDocumentTree,y=window.MutationObserver._isPolyfilled&&_["throttle-attached"];e.hasPolyfillMutations=y,e.hasThrottledAttached=y;var E=!1,L=[],N=Array.prototype.forEach.call.bind(Array.prototype.forEach),M=Element.prototype.createShadowRoot;M&&(Element.prototype.createShadowRoot=function(){var e=M.call(this);return window.CustomElements.watchShadow(this),e}),e.watchShadow=h,e.upgradeDocumentTree=w,e.upgradeDocument=v,e.upgradeSubtree=o,e.upgradeAll=t,e.attached=a,e.takeRecords=p}),window.CustomElements.addModule(function(e){function t(t,o){if("template"===t.localName&&window.HTMLTemplateElement&&HTMLTemplateElement.decorate&&HTMLTemplateElement.decorate(t),!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var r=t.getAttribute("is"),i=e.getRegisteredDefinition(t.localName)||e.getRegisteredDefinition(r);if(i&&(r&&i.tag==t.localName||!r&&!i["extends"]))return n(t,i,o)}}function n(t,n,r){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),o(t,n),t.__upgraded__=!0,i(t),r&&e.attached(t),e.upgradeSubtree(t,r),a.upgrade&&console.groupEnd(),t}function o(e,t){Object.__proto__?e.__proto__=t.prototype:(r(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function r(e,t,n){for(var o={},r=t;r!==n&&r!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(r),s=0;i=a[s];s++)o[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(r,i)),o[i]=1);r=Object.getPrototypeOf(r)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=o}),window.CustomElements.addModule(function(e){function t(t,o){var c=o||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(r(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(d(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return c.prototype||(c.prototype=Object.create(HTMLElement.prototype)),c.__name=t.toLowerCase(),c["extends"]&&(c["extends"]=c["extends"].toLowerCase()),c.lifecycle=c.lifecycle||{},c.ancestry=i(c["extends"]),a(c),s(c),n(c.prototype),l(c.__name,c),c.ctor=u(c),c.ctor.prototype=c.prototype,c.prototype.constructor=c.ctor,e.ready&&v(document),c.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){o.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){o.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function o(e,t,n){e=e.toLowerCase();var o=this.getAttribute(e);n.apply(this,arguments);var r=this.getAttribute(e);this.attributeChangedCallback&&r!==o&&this.attributeChangedCallback(e,o,r)}function r(e){for(var t=0;t=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 +// @version 0.7.23 +!function(){window.WebComponents=window.WebComponents||{flags:{}};var e="webcomponents-lite.js",t=document.querySelector('script[src*="'+e+'"]'),n={};if(!n.noOpts){if(location.search.slice(1).split("&").forEach(function(e){var t,o=e.split("=");o[0]&&(t=o[0].match(/wc-(.+)/))&&(n[t[1]]=o[1]||!0)}),t)for(var o,r=0;o=t.attributes[r];r++)"src"!==o.name&&(n[o.name]=o.value||!0);if(n.log&&n.log.split){var i=n.log.split(",");n.log={},i.forEach(function(e){n.log[e]=!0})}else n.log={}}n.register&&(window.CustomElements=window.CustomElements||{flags:{}},window.CustomElements.flags.register=n.register),WebComponents.flags=n}(),function(e){"use strict";function t(e){return void 0!==h[e]}function n(){s.call(this),this._isInvalid=!0}function o(e){return""==e&&n.call(this),e.toLowerCase()}function r(e){var t=e.charCodeAt(0);return t>32&&t<127&&[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 0bd0568f231d72b785de5e0e10c0a21228f6b5c7..c5fe12d2303e5b2d7e1f40f018bf774b42f15b6d 100644 GIT binary patch literal 12360 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 Date: Fri, 9 Dec 2016 08:19:14 +0100 Subject: [PATCH 062/141] Pilight receive match fix for bug 4637 (#4639) * Pilight: dont protocol as list in COMMAND_SCHEMA As described in bug #4637 the protocol should not be wrapped in a list in the spec of COMMAND_SCHEMA because this causes the component to never successfully match any received rf code. As pointed ot in PR #4639 the easiest way to do this, is to not derive COMMAND_SCHEMA from RF_CODE_SCHEMA and specify protocol as simple string there. This fixes bug #4637. Signed-off-by: Jan Losinski * Pilight: Add "unitcode" to command schema. This adds "unitcode" to the COMMAND_SCHEMA. It is used for example in the brennenstuhl protocol of pilight. Signed-off-by: Jan Losinski --- homeassistant/components/switch/pilight.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/pilight.py b/homeassistant/components/switch/pilight.py index 6e16c9fa2e5..a052848cb21 100644 --- a/homeassistant/components/switch/pilight.py +++ b/homeassistant/components/switch/pilight.py @@ -11,7 +11,8 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv import homeassistant.components.pilight as pilight from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) -from homeassistant.const import (CONF_NAME, CONF_ID, CONF_SWITCHES, CONF_STATE) +from homeassistant.const import (CONF_NAME, CONF_ID, CONF_SWITCHES, CONF_STATE, + CONF_PROTOCOL) _LOGGER = logging.getLogger(__name__) @@ -21,13 +22,16 @@ CONF_ON_CODE = 'on_code' CONF_ON_CODE_RECIEVE = 'on_code_receive' CONF_SYSTEMCODE = 'systemcode' CONF_UNIT = 'unit' +CONF_UNITCODE = 'unitcode' DEPENDENCIES = ['pilight'] -COMMAND_SCHEMA = pilight.RF_CODE_SCHEMA.extend({ +COMMAND_SCHEMA = vol.Schema({ + vol.Optional(CONF_PROTOCOL): cv.string, vol.Optional('on'): cv.positive_int, 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_STATE): cv.string, vol.Optional(CONF_SYSTEMCODE): cv.positive_int, From 0bf9e6d4bb1d38a782824fb8af89ec9bb8406247 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 9 Dec 2016 08:24:03 +0100 Subject: [PATCH 063/141] Bugfix error on automation reload (#4823) --- homeassistant/components/automation/state.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/homeassistant/components/automation/state.py b/homeassistant/components/automation/state.py index fb146991602..65cca462ed9 100644 --- a/homeassistant/components/automation/state.py +++ b/homeassistant/components/automation/state.py @@ -64,10 +64,19 @@ def async_trigger(hass, config, action): call_action() return + @callback + def clear_listener(): + """Clear all unsub listener.""" + nonlocal async_remove_state_for_cancel + nonlocal async_remove_state_for_listener + async_remove_state_for_listener = None + async_remove_state_for_cancel = None + @callback def state_for_listener(now): """Fire on state changes after a delay and calls action.""" async_remove_state_for_cancel() + clear_listener() call_action() @callback @@ -77,6 +86,7 @@ def async_trigger(hass, config, action): return async_remove_state_for_listener() async_remove_state_for_cancel() + clear_listener() async_remove_state_for_listener = async_track_point_in_utc_time( hass, state_for_listener, dt_util.utcnow() + time_delta) From 0aac4d64e1d8336ebe71fe108245409646a82c75 Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Fri, 9 Dec 2016 01:26:02 -0600 Subject: [PATCH 064/141] Add away mode for Radio Thermostat/3M Filtrete (#4793) --- .../components/climate/radiotherm.py | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/climate/radiotherm.py b/homeassistant/components/climate/radiotherm.py index d06e148cfdd..9a0e5666036 100644 --- a/homeassistant/components/climate/radiotherm.py +++ b/homeassistant/components/climate/radiotherm.py @@ -23,10 +23,19 @@ ATTR_FAN = 'fan' ATTR_MODE = 'mode' CONF_HOLD_TEMP = 'hold_temp' +CONF_AWAY_TEMPERATURE_HEAT = 'away_temperature_heat' +CONF_AWAY_TEMPERATURE_COOL = 'away_temperature_cool' + +DEFAULT_AWAY_TEMPERATURE_HEAT = 60 +DEFAULT_AWAY_TEMPERATURE_COOL = 85 PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_HOLD_TEMP, default=False): cv.boolean, + vol.Optional(CONF_AWAY_TEMPERATURE_HEAT, + default=DEFAULT_AWAY_TEMPERATURE_HEAT): vol.Coerce(float), + vol.Optional(CONF_AWAY_TEMPERATURE_COOL, + default=DEFAULT_AWAY_TEMPERATURE_COOL): vol.Coerce(float), }) @@ -45,12 +54,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False hold_temp = config.get(CONF_HOLD_TEMP) + away_temps = [ + config.get(CONF_AWAY_TEMPERATURE_HEAT), + config.get(CONF_AWAY_TEMPERATURE_COOL) + ] tstats = [] for host in hosts: try: tstat = radiotherm.get_thermostat(host) - tstats.append(RadioThermostat(tstat, hold_temp)) + tstats.append(RadioThermostat(tstat, hold_temp, away_temps)) except OSError: _LOGGER.exception("Unable to connect to Radio Thermostat: %s", host) @@ -61,7 +74,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class RadioThermostat(ClimateDevice): """Representation of a Radio Thermostat.""" - def __init__(self, device, hold_temp): + def __init__(self, device, hold_temp, away_temps): """Initialize the thermostat.""" self.device = device self.set_time() @@ -71,7 +84,10 @@ class RadioThermostat(ClimateDevice): self._name = None self._fmode = None self._tmode = None - self.hold_temp = hold_temp + self._hold_temp = hold_temp + self._away = False + self._away_temps = away_temps + self._prev_temp = None self.update() self._operation_list = [STATE_AUTO, STATE_COOL, STATE_HEAT, STATE_OFF] @@ -113,6 +129,11 @@ class RadioThermostat(ClimateDevice): """Return the temperature we try to reach.""" return self._target_temperature + @property + def is_away_mode_on(self): + """Return true if away mode is on.""" + return self._away + def update(self): """Update the data from the thermostat.""" self._current_temperature = self.device.temp['raw'] @@ -138,7 +159,7 @@ class RadioThermostat(ClimateDevice): self.device.t_cool = round(temperature * 2.0) / 2.0 elif self._current_operation == STATE_HEAT: self.device.t_heat = round(temperature * 2.0) / 2.0 - if self.hold_temp: + if self._hold_temp or self._away: self.device.hold = 1 else: self.device.hold = 0 @@ -162,3 +183,23 @@ class RadioThermostat(ClimateDevice): self.device.t_cool = round(self._target_temperature * 2.0) / 2.0 elif operation_mode == STATE_HEAT: self.device.t_heat = round(self._target_temperature * 2.0) / 2.0 + + def turn_away_mode_on(self): + """Turn away on. + + The RTCOA app simulates away mode by using a hold. + """ + away_temp = None + if not self._away: + self._prev_temp = self._target_temperature + if self._current_operation == STATE_HEAT: + away_temp = self._away_temps[0] + elif self._current_operation == STATE_COOL: + away_temp = self._away_temps[1] + self._away = True + self.set_temperature(temperature=away_temp) + + def turn_away_mode_off(self): + """Turn away off.""" + self._away = False + self.set_temperature(temperature=self._prev_temp) From d02899216dae86c0b41d60ceefb4aab3a1be1222 Mon Sep 17 00:00:00 2001 From: Keaton Taylor Date: Fri, 9 Dec 2016 10:45:14 -0600 Subject: [PATCH 065/141] Prevent emulated hue discovery by hue component (#4819) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Prevent emulated hue discovery Test for “HASS Bridge” in discovery info, pass if found, else try and setup the bridge. * Solved coding error Duplicate commands and return false added for component. --- homeassistant/components/light/hue.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 8fd8a6ef097..da2158ba78d 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -90,6 +90,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if discovery_info is not None: host = urlparse(discovery_info[1]).hostname + + if "HASS Bridge" in discovery_info[0]: + _LOGGER.info('Emulated hue found, will not add') + return False else: host = config.get(CONF_HOST, None) From 1547045f2c292a3558b9dccac48a16aefc541533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Oldag?= Date: Fri, 9 Dec 2016 17:52:14 +0100 Subject: [PATCH 066/141] Flic: Support ignoring individual click types. (#4827) --- .../components/binary_sensor/flic.py | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/binary_sensor/flic.py b/homeassistant/components/binary_sensor/flic.py index 63323155d31..92301330605 100644 --- a/homeassistant/components/binary_sensor/flic.py +++ b/homeassistant/components/binary_sensor/flic.py @@ -17,6 +17,13 @@ REQUIREMENTS = ['https://github.com/soldag/pyflic/archive/0.4.zip#pyflic==0.4'] _LOGGER = logging.getLogger(__name__) +CLICK_TYPE_SINGLE = "single" +CLICK_TYPE_DOUBLE = "double" +CLICK_TYPE_HOLD = "hold" +CLICK_TYPES = [CLICK_TYPE_SINGLE, CLICK_TYPE_DOUBLE, CLICK_TYPE_HOLD] + +CONF_IGNORED_CLICK_TYPES = "ignored_click_types" + EVENT_NAME = "flic_click" EVENT_DATA_NAME = "button_name" EVENT_DATA_ADDRESS = "button_address" @@ -26,7 +33,9 @@ EVENT_DATA_TYPE = "click_type" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST, default='localhost'): cv.string, vol.Optional(CONF_PORT, default=5551): cv.port, - vol.Optional(CONF_DISCOVERY, default=True): cv.boolean + vol.Optional(CONF_DISCOVERY, default=True): cv.boolean, + vol.Optional(CONF_IGNORED_CLICK_TYPES): vol.All(cv.ensure_list, + [vol.In(CLICK_TYPES)]) }) @@ -93,7 +102,8 @@ def start_scanning(hass, config, async_add_entities, client): @asyncio.coroutine def async_setup_button(hass, config, async_add_entities, client, address): """Setup single button device.""" - button = FlicButton(hass, client, address) + ignored_click_types = config.get(CONF_IGNORED_CLICK_TYPES) + button = FlicButton(hass, client, address, ignored_click_types) _LOGGER.info("Connected to button (%s)", address) yield from async_add_entities([button]) @@ -117,25 +127,47 @@ def async_get_verified_addresses(client): class FlicButton(BinarySensorDevice): """Representation of a flic button.""" - def __init__(self, hass, client, address): + def __init__(self, hass, client, address, ignored_click_types): """Initialize the flic button.""" import pyflic self._hass = hass self._address = address self._is_down = False - self._click_types = { - pyflic.ClickType.ButtonSingleClick: "single", - pyflic.ClickType.ButtonDoubleClick: "double", - pyflic.ClickType.ButtonHold: "hold", + self._ignored_click_types = ignored_click_types or [] + self._hass_click_types = { + pyflic.ClickType.ButtonClick: CLICK_TYPE_SINGLE, + pyflic.ClickType.ButtonSingleClick: CLICK_TYPE_SINGLE, + pyflic.ClickType.ButtonDoubleClick: CLICK_TYPE_DOUBLE, + pyflic.ClickType.ButtonHold: CLICK_TYPE_HOLD, } - # Initialize connection channel - self._channel = pyflic.ButtonConnectionChannel(self._address) - self._channel.on_button_up_or_down = self._on_up_down - self._channel.on_button_single_or_double_click_or_hold = self._on_click + self._channel = self._create_channel() client.add_connection_channel(self._channel) + def _create_channel(self): + """Create a new connection channel to the button.""" + import pyflic + + channel = pyflic.ButtonConnectionChannel(self._address) + channel.on_button_up_or_down = self._on_up_down + + # If all types of clicks should be ignored, skip registering callbacks + if set(self._ignored_click_types) == set(CLICK_TYPES): + return channel + + if CLICK_TYPE_DOUBLE in self._ignored_click_types: + # Listen to all but double click type events + channel.on_button_click_or_hold = self._on_click + elif CLICK_TYPE_HOLD in self._ignored_click_types: + # Listen to all but hold click type events + channel.on_button_single_or_double_click = self._on_click + else: + # Listen to all click type events + channel.on_button_single_or_double_click_or_hold = self._on_click + + return channel + @property def name(self): """Return the name of the device.""" @@ -176,13 +208,14 @@ class FlicButton(BinarySensorDevice): def _on_click(self, channel, click_type, was_queued, time_diff): """Fire click event, if event was not queued.""" - if was_queued: + hass_click_type = self._hass_click_types[click_type] + if was_queued or hass_click_type in self._ignored_click_types: return self._hass.bus.fire(EVENT_NAME, { EVENT_DATA_NAME: self.name, EVENT_DATA_ADDRESS: self.address, - EVENT_DATA_TYPE: self._click_types[click_type] + EVENT_DATA_TYPE: hass_click_type }) def _connection_status_changed(self, channel, From 64de1c9777f09b641694a3c53375bac5db9d4fdf Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Fri, 9 Dec 2016 14:04:40 -0500 Subject: [PATCH 067/141] Bump python-nest to fix issue with Nest Cam without activity zones (#4820) * Bump python-nest to fix issue with Nest Cam without activity zones * bump to include fix python-nest dependency with hvac_state * regenerate requirements_all.txt --- homeassistant/components/nest.py | 4 ++-- requirements_all.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/nest.py b/homeassistant/components/nest.py index fd5627987a3..cd871c8e039 100644 --- a/homeassistant/components/nest.py +++ b/homeassistant/components/nest.py @@ -19,8 +19,8 @@ _LOGGER = logging.getLogger(__name__) REQUIREMENTS = [ 'http://github.com/technicalpickles/python-nest' - '/archive/7a2eb38d391bddeb78079437f001224c370b555a.zip' # nest-cam branch - '#python-nest==3.0.1'] + '/archive/b8391d2b3cb8682f8b0c2bdff477179983609f39.zip' # nest-cam branch + '#python-nest==3.0.2'] DOMAIN = 'nest' diff --git a/requirements_all.txt b/requirements_all.txt index 27573a2c587..b67ef6f9d2b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -167,7 +167,7 @@ hikvision==0.4 # 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/7a2eb38d391bddeb78079437f001224c370b555a.zip#python-nest==3.0.1 +http://github.com/technicalpickles/python-nest/archive/b8391d2b3cb8682f8b0c2bdff477179983609f39.zip#python-nest==3.0.2 # homeassistant.components.light.flux_led https://github.com/Danielhiversen/flux_led/archive/0.9.zip#flux_led==0.9 From 167260bcc65317aa74212bbcb78ecf14c20263e2 Mon Sep 17 00:00:00 2001 From: r-jordan Date: Sat, 10 Dec 2016 11:36:35 +0100 Subject: [PATCH 068/141] [climate.generic_thermostat] Make tolerance work both ways (#4830) --- .../components/climate/generic_thermostat.py | 36 ++++---- .../climate/test_generic_thermostat.py | 84 ++++++++++++------- 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 1b3d20d8b59..a40795c37c5 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -198,24 +198,30 @@ class GenericThermostat(ClimateDevice): return if self.ac_mode: - too_hot = self._cur_temp - self._target_temp > self._tolerance is_cooling = self._is_device_active - if too_hot and not is_cooling: - _LOGGER.info('Turning on AC %s', self.heater_entity_id) - switch.turn_on(self.hass, self.heater_entity_id) - elif not too_hot and is_cooling: - _LOGGER.info('Turning off AC %s', self.heater_entity_id) - switch.turn_off(self.hass, self.heater_entity_id) + if is_cooling: + 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) + 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) else: - too_cold = self._target_temp - self._cur_temp > self._tolerance is_heating = self._is_device_active - - if too_cold and not is_heating: - _LOGGER.info('Turning on heater %s', self.heater_entity_id) - switch.turn_on(self.hass, self.heater_entity_id) - elif not too_cold and is_heating: - _LOGGER.info('Turning off heater %s', self.heater_entity_id) - switch.turn_off(self.hass, self.heater_entity_id) + if is_heating: + too_hot = self._cur_temp - self._target_temp > self._tolerance + if too_hot: + _LOGGER.info('Turning off heater %s', + self.heater_entity_id) + switch.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) @property def _is_device_active(self): diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 1730c3e003b..7c4ee8db58f 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -181,34 +181,10 @@ class TestClimateGenericThermostat(unittest.TestCase): self.assertEqual(SERVICE_TURN_OFF, call.service) self.assertEqual(ENT_SWITCH, call.data['entity_id']) - def test_set_temp_change_heater_on(self): - """Test if temperature change turn heater on.""" - self._setup_switch(False) - climate.set_temperature(self.hass, 30) - self.hass.block_till_done() - self._setup_sensor(25) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_ON, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - - def test_temp_change_heater_off(self): - """Test if temperature change turn heater off.""" - self._setup_switch(True) - climate.set_temperature(self.hass, 25) - self.hass.block_till_done() - self._setup_sensor(30) - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - call = self.calls[0] - self.assertEqual('switch', call.domain) - self.assertEqual(SERVICE_TURN_OFF, call.service) - self.assertEqual(ENT_SWITCH, call.data['entity_id']) - def test_temp_change_heater_on_within_tolerance(self): - """Test if temperature change turn heater on within tolerance.""" + """Test if temperature change doesn't turn heater on within + tolerance. + """ self._setup_switch(False) climate.set_temperature(self.hass, 30) self.hass.block_till_done() @@ -217,9 +193,7 @@ class TestClimateGenericThermostat(unittest.TestCase): self.assertEqual(0, len(self.calls)) def test_temp_change_heater_on_outside_tolerance(self): - """Test if temperature change doesn't turn heater on outside - tolerance. - """ + """Test if temperature change turn heater on outside tolerance.""" self._setup_switch(False) climate.set_temperature(self.hass, 30) self.hass.block_till_done() @@ -231,6 +205,30 @@ class TestClimateGenericThermostat(unittest.TestCase): self.assertEqual(SERVICE_TURN_ON, call.service) self.assertEqual(ENT_SWITCH, call.data['entity_id']) + def test_temp_change_heater_off_within_tolerance(self): + """Test if temperature change doesn't turn heater off within + tolerance. + """ + self._setup_switch(True) + climate.set_temperature(self.hass, 30) + self.hass.block_till_done() + self._setup_sensor(31) + self.hass.block_till_done() + self.assertEqual(0, len(self.calls)) + + def test_temp_change_heater_off_outside_tolerance(self): + """Test if temperature change turn heater off outside tolerance.""" + self._setup_switch(True) + climate.set_temperature(self.hass, 30) + self.hass.block_till_done() + self._setup_sensor(35) + self.hass.block_till_done() + self.assertEqual(1, len(self.calls)) + call = self.calls[0] + self.assertEqual('switch', call.domain) + self.assertEqual(SERVICE_TURN_OFF, call.service) + self.assertEqual(ENT_SWITCH, call.data['entity_id']) + def _setup_sensor(self, temp, unit=TEMP_CELSIUS): """Setup the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { @@ -297,7 +295,18 @@ class TestClimateGenericThermostatACMode(unittest.TestCase): self.assertEqual(SERVICE_TURN_ON, call.service) self.assertEqual(ENT_SWITCH, call.data['entity_id']) - def test_set_temp_change_ac_off(self): + def test_temp_change_ac_off_within_tolerance(self): + """Test if temperature change doesn't turn ac off within + tolerance. + """ + self._setup_switch(True) + climate.set_temperature(self.hass, 30) + self.hass.block_till_done() + self._setup_sensor(29.8) + self.hass.block_till_done() + self.assertEqual(0, len(self.calls)) + + def test_set_temp_change_ac_off_outside_tolerance(self): """Test if temperature change turn ac off.""" self._setup_switch(True) climate.set_temperature(self.hass, 30) @@ -310,7 +319,18 @@ class TestClimateGenericThermostatACMode(unittest.TestCase): self.assertEqual(SERVICE_TURN_OFF, call.service) self.assertEqual(ENT_SWITCH, call.data['entity_id']) - def test_temp_change_ac_on(self): + def test_temp_change_ac_on_within_tolerance(self): + """Test if temperature change doesn't turn ac on within + tolerance. + """ + self._setup_switch(False) + climate.set_temperature(self.hass, 25) + self.hass.block_till_done() + self._setup_sensor(25.2) + self.hass.block_till_done() + self.assertEqual(0, len(self.calls)) + + def test_temp_change_ac_on_outside_tolerance(self): """Test if temperature change turn ac on.""" self._setup_switch(False) climate.set_temperature(self.hass, 25) From ee5b9e72910718843af27a5023e1a022ba7ef435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Sat, 10 Dec 2016 18:53:25 +0100 Subject: [PATCH 069/141] Configurable scan options for nmap (#4838) --- .../components/device_tracker/nmap_tracker.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/device_tracker/nmap_tracker.py b/homeassistant/components/device_tracker/nmap_tracker.py index 2e8bbc5d2a1..404492e35cf 100644 --- a/homeassistant/components/device_tracker/nmap_tracker.py +++ b/homeassistant/components/device_tracker/nmap_tracker.py @@ -25,6 +25,8 @@ _LOGGER = logging.getLogger(__name__) CONF_EXCLUDE = 'exclude' # Interval in minutes to exclude devices from a scan while they are home CONF_HOME_INTERVAL = 'home_interval' +CONF_OPTIONS = 'scan_options' +DEFAULT_OPTIONS = '-F --host-timeout 5s' MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) @@ -33,7 +35,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOSTS): cv.ensure_list, vol.Required(CONF_HOME_INTERVAL, default=0): cv.positive_int, vol.Optional(CONF_EXCLUDE, default=[]): - vol.All(cv.ensure_list, vol.Length(min=1)) + vol.All(cv.ensure_list, vol.Length(min=1)), + vol.Optional(CONF_OPTIONS, default=DEFAULT_OPTIONS): + cv.string }) @@ -69,8 +73,9 @@ class NmapDeviceScanner(object): self.last_results = [] self.hosts = config[CONF_HOSTS] - self.exclude = config.get(CONF_EXCLUDE, []) + self.exclude = config[CONF_EXCLUDE] minutes = config[CONF_HOME_INTERVAL] + self._options = config[CONF_OPTIONS] self.home_interval = timedelta(minutes=minutes) self.success_init = self._update_info() @@ -103,7 +108,7 @@ class NmapDeviceScanner(object): from nmap import PortScanner, PortScannerError scanner = PortScanner() - options = '-F --host-timeout 5s ' + options = self._options if self.home_interval: boundary = dt_util.now() - self.home_interval From 7ba25f35260fe6a046c90adbf44fed711a3903dd Mon Sep 17 00:00:00 2001 From: Stefan Jonasson Date: Sun, 11 Dec 2016 09:54:50 +0100 Subject: [PATCH 070/141] Fixed crash during light objects initizilation (#4835) * Fixed crash when lights objects was inited --- homeassistant/components/light/tellstick.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/light/tellstick.py b/homeassistant/components/light/tellstick.py index 90add8f012e..d23d5e2c4d6 100644 --- a/homeassistant/components/light/tellstick.py +++ b/homeassistant/components/light/tellstick.py @@ -72,7 +72,11 @@ class TellstickLight(TellstickDevice, Light): if brightness is not None: self._brightness = brightness - self._state = (self._brightness > 0) + # _brightness is not defined when called from super + try: + self._state = (self._brightness > 0) + except AttributeError: + self._state = True else: self._state = False From cdf94646989d23023f3ddf92c1f3045e7ff8032a Mon Sep 17 00:00:00 2001 From: Lewis Juggins Date: Sun, 11 Dec 2016 09:05:56 +0000 Subject: [PATCH 071/141] [device_tracker.gpslogger] Add additional activity attribute. --- homeassistant/components/device_tracker/gpslogger.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/device_tracker/gpslogger.py b/homeassistant/components/device_tracker/gpslogger.py index d8e7ca8b074..22099630bd1 100644 --- a/homeassistant/components/device_tracker/gpslogger.py +++ b/homeassistant/components/device_tracker/gpslogger.py @@ -63,6 +63,7 @@ class GPSLoggerView(HomeAssistantView): accuracy = int(float(data['accuracy'])) if 'battery' in data: battery = float(data['battery']) + attrs = {} if 'speed' in data: attrs['speed'] = float(data['speed']) @@ -72,6 +73,8 @@ class GPSLoggerView(HomeAssistantView): attrs['altitude'] = float(data['altitude']) if 'provider' in data: attrs['provider'] = data['provider'] + if 'activity' in data: + attrs['activity'] = data['activity'] yield from hass.loop.run_in_executor( None, partial(self.see, dev_id=device, From e0552ad89918efd95e5ab8f2e2373c8236955b00 Mon Sep 17 00:00:00 2001 From: Lewis Juggins Date: Sun, 11 Dec 2016 13:13:43 +0000 Subject: [PATCH 072/141] [device_tracker] Don't clear GPS coordinates if no GPS seen (#4848) --- homeassistant/components/device_tracker/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index d497ea4c314..ba5e28ff48f 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -426,12 +426,11 @@ class Device(Entity): if attributes: self._attributes.update(attributes) - self.gps = None - if gps is not None: try: self.gps = float(gps[0]), float(gps[1]) except (ValueError, TypeError, IndexError): + self.gps = None _LOGGER.warning('Could not parse gps value for %s: %s', self.dev_id, gps) From 46cad514d46480e3aa17f9991fa7f41f14182246 Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Sun, 11 Dec 2016 19:18:11 +0200 Subject: [PATCH 073/141] Revert "[device_tracker] Don't clear GPS coordinates when using two device trackers." (#4851) --- homeassistant/components/device_tracker/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index ba5e28ff48f..d497ea4c314 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -426,11 +426,12 @@ class Device(Entity): if attributes: self._attributes.update(attributes) + self.gps = None + if gps is not None: try: self.gps = float(gps[0]), float(gps[1]) except (ValueError, TypeError, IndexError): - self.gps = None _LOGGER.warning('Could not parse gps value for %s: %s', self.dev_id, gps) From 99f1ea9b59edf03a1155381677002698f6cede88 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sun, 11 Dec 2016 23:39:20 +0100 Subject: [PATCH 074/141] Migrate alarm control panel to async (#4807) * Merge alarm control panel to async * fix lint --- .../alarm_control_panel/__init__.py | 106 ++++++++++++------ .../alarm_control_panel/alarmdotcom.py | 5 - .../alarm_control_panel/concord232.py | 9 -- .../alarm_control_panel/envisalink.py | 2 +- .../components/alarm_control_panel/manual.py | 8 +- .../components/alarm_control_panel/nx584.py | 9 -- .../alarm_control_panel/simplisafe.py | 8 -- .../alarm_control_panel/verisure.py | 3 - 8 files changed, 77 insertions(+), 73 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 49decfc62fe..1b64431c7a1 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -4,6 +4,7 @@ Component to interface with an alarm control panel. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/alarm_control_panel/ """ +import asyncio import logging import os @@ -42,40 +43,6 @@ ALARM_SERVICE_SCHEMA = vol.Schema({ }) -def setup(hass, config): - """Track states and offer events for sensors.""" - component = EntityComponent( - logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) - - component.setup(config) - - def alarm_service_handler(service): - """Map services to methods on Alarm.""" - target_alarms = component.extract_from_service(service) - - code = service.data.get(ATTR_CODE) - - method = SERVICE_TO_METHOD[service.service] - - for alarm in target_alarms: - getattr(alarm, method)(code) - - for alarm in target_alarms: - if not alarm.should_poll: - continue - - alarm.update_ha_state(True) - - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - - for service in SERVICE_TO_METHOD: - hass.services.register(DOMAIN, service, alarm_service_handler, - descriptions.get(service), - schema=ALARM_SERVICE_SCHEMA) - return True - - def alarm_disarm(hass, code=None, entity_id=None): """Send the alarm the command for disarm.""" data = {} @@ -120,6 +87,53 @@ def alarm_trigger(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data) +@asyncio.coroutine +def async_setup(hass, config): + """Track states and offer events for sensors.""" + component = EntityComponent( + logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) + + yield from component.async_setup(config) + + @asyncio.coroutine + def async_alarm_service_handler(service): + """Map services to methods on Alarm.""" + target_alarms = component.async_extract_from_service(service) + + code = service.data.get(ATTR_CODE) + + method = "async_{}".format(SERVICE_TO_METHOD[service.service]) + + for alarm in target_alarms: + yield from getattr(alarm, method)(code) + + update_tasks = [] + for alarm in target_alarms: + if not alarm.should_poll: + continue + + update_coro = hass.loop.create_task( + alarm.async_update_ha_state(True)) + if hasattr(alarm, 'async_update'): + update_tasks.append(hass.loop.create_task(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')) + + for service in SERVICE_TO_METHOD: + hass.services.async_register( + DOMAIN, service, async_alarm_service_handler, + descriptions.get(service), schema=ALARM_SERVICE_SCHEMA) + + return True + + # pylint: disable=no-self-use class AlarmControlPanel(Entity): """An abstract class for alarm control devices.""" @@ -138,18 +152,42 @@ class AlarmControlPanel(Entity): """Send disarm command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_disarm(self, code=None): + """Send disarm command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_disarm, code) + def alarm_arm_home(self, code=None): """Send arm home command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_arm_home(self, code=None): + """Send arm home command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_arm_home, code) + def alarm_arm_away(self, code=None): """Send arm away command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_arm_away(self, code=None): + """Send arm away command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_arm_away, code) + def alarm_trigger(self, code=None): """Send alarm trigger command.""" raise NotImplementedError() + @asyncio.coroutine + def async_alarm_trigger(self, code=None): + """Send alarm trigger command.""" + yield from self.hass.loop.run_in_executor( + None, self.alarm_trigger, code) + @property def state_attributes(self): """Return the state attributes.""" diff --git a/homeassistant/components/alarm_control_panel/alarmdotcom.py b/homeassistant/components/alarm_control_panel/alarmdotcom.py index cd37fc6a828..07f90cf4476 100644 --- a/homeassistant/components/alarm_control_panel/alarmdotcom.py +++ b/homeassistant/components/alarm_control_panel/alarmdotcom.py @@ -56,11 +56,6 @@ class AlarmDotCom(alarm.AlarmControlPanel): self._password = password self._state = STATE_UNKNOWN - @property - def should_poll(self): - """No polling needed.""" - return True - def update(self): """Fetch the latest state.""" self._state = self._alarm.state diff --git a/homeassistant/components/alarm_control_panel/concord232.py b/homeassistant/components/alarm_control_panel/concord232.py index 0bdcf274c08..de153a9e0a5 100755 --- a/homeassistant/components/alarm_control_panel/concord232.py +++ b/homeassistant/components/alarm_control_panel/concord232.py @@ -71,11 +71,6 @@ class Concord232Alarm(alarm.AlarmControlPanel): self._alarm.last_partition_update = datetime.datetime.now() self.update() - @property - def should_poll(self): - """Polling needed.""" - return True - @property def name(self): """Return the name of the device.""" @@ -126,7 +121,3 @@ class Concord232Alarm(alarm.AlarmControlPanel): def alarm_arm_away(self, code=None): """Send arm away command.""" self._alarm.arm('auto') - - def alarm_trigger(self, code=None): - """Alarm trigger command.""" - raise NotImplementedError() diff --git a/homeassistant/components/alarm_control_panel/envisalink.py b/homeassistant/components/alarm_control_panel/envisalink.py index e84320738a2..96b0fc83ea7 100644 --- a/homeassistant/components/alarm_control_panel/envisalink.py +++ b/homeassistant/components/alarm_control_panel/envisalink.py @@ -97,7 +97,7 @@ class EnvisalinkAlarm(EnvisalinkDevice, alarm.AlarmControlPanel): def _update_callback(self, partition): """Update HA state, if needed.""" if partition is None or int(partition) == self._partition_number: - self.hass.async_add_job(self.update_ha_state) + self.hass.async_add_job(self.async_update_ha_state()) @property def code_format(self): diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index 073d55508ed..cc67795d713 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -116,7 +116,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_DISARMED self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() def alarm_arm_home(self, code=None): """Send arm home command.""" @@ -125,7 +125,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_ARMED_HOME self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() if self._pending_time: track_point_in_time( @@ -139,7 +139,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_ARMED_AWAY self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() if self._pending_time: track_point_in_time( @@ -151,7 +151,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self._pre_trigger_state = self._state self._state = STATE_ALARM_TRIGGERED self._state_ts = dt_util.utcnow() - self.update_ha_state() + self.schedule_update_ha_state() if self._trigger_time: track_point_in_time( diff --git a/homeassistant/components/alarm_control_panel/nx584.py b/homeassistant/components/alarm_control_panel/nx584.py index cb32fc924e6..58ec8d915ab 100644 --- a/homeassistant/components/alarm_control_panel/nx584.py +++ b/homeassistant/components/alarm_control_panel/nx584.py @@ -62,11 +62,6 @@ class NX584Alarm(alarm.AlarmControlPanel): self._alarm.list_zones() self._state = STATE_UNKNOWN - @property - def should_poll(self): - """Polling needed.""" - return True - @property def name(self): """Return the name of the device.""" @@ -122,7 +117,3 @@ class NX584Alarm(alarm.AlarmControlPanel): def alarm_arm_away(self, code=None): """Send arm away command.""" self._alarm.arm('exit') - - def alarm_trigger(self, code=None): - """Alarm trigger command.""" - raise NotImplementedError() diff --git a/homeassistant/components/alarm_control_panel/simplisafe.py b/homeassistant/components/alarm_control_panel/simplisafe.py index 40ebfb2f39f..7a8f8409c59 100644 --- a/homeassistant/components/alarm_control_panel/simplisafe.py +++ b/homeassistant/components/alarm_control_panel/simplisafe.py @@ -61,11 +61,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): else: self._state = STATE_UNKNOWN - @property - def should_poll(self): - """Poll the SimpliSafe API.""" - return True - @property def name(self): """Return the name of the device.""" @@ -104,7 +99,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): return self.simplisafe.set_state('off') _LOGGER.info('SimpliSafe alarm disarming') - self.update() def alarm_arm_home(self, code=None): """Send arm home command.""" @@ -112,7 +106,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): return self.simplisafe.set_state('home') _LOGGER.info('SimpliSafe alarm arming home') - self.update() def alarm_arm_away(self, code=None): """Send arm away command.""" @@ -120,7 +113,6 @@ class SimpliSafeAlarm(alarm.AlarmControlPanel): return self.simplisafe.set_state('away') _LOGGER.info('SimpliSafe alarm arming away') - self.update() def _validate_code(self, code, state): """Validate given code.""" diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index 4ef07c68f59..c1a394fe462 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -84,18 +84,15 @@ class VerisureAlarm(alarm.AlarmControlPanel): hub.my_pages.alarm.set(code, 'DISARMED') _LOGGER.info('verisure alarm disarming') hub.my_pages.alarm.wait_while_pending() - self.update() def alarm_arm_home(self, code=None): """Send arm home command.""" hub.my_pages.alarm.set(code, 'ARMED_HOME') _LOGGER.info('verisure alarm arming home') hub.my_pages.alarm.wait_while_pending() - self.update() def alarm_arm_away(self, code=None): """Send arm away command.""" hub.my_pages.alarm.set(code, 'ARMED_AWAY') _LOGGER.info('verisure alarm arming away') hub.my_pages.alarm.wait_while_pending() - self.update() From 080c4efb000ebc0ea52f314ac4c17b3989858bc9 Mon Sep 17 00:00:00 2001 From: devdelay Date: Sun, 11 Dec 2016 17:46:10 -0500 Subject: [PATCH 075/141] Ecobee detect Smart Away (#4769) * Ecobee autoAway Event * Update ecobee.py Checking if event['running'] true is pointless because if false event['type'] will equal template and when true type will only be 'hold' or 'autoAway' so I've removed this check from the statement --- homeassistant/components/climate/ecobee.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/climate/ecobee.py b/homeassistant/components/climate/ecobee.py index c98ac6d0106..84d8c32f9ff 100644 --- a/homeassistant/components/climate/ecobee.py +++ b/homeassistant/components/climate/ecobee.py @@ -195,8 +195,9 @@ class Thermostat(ClimateDevice): mode = self.mode events = self.thermostat['events'] for event in events: - if event['running']: - mode = event['holdClimateRef'] + if event['holdClimateRef'] == 'away' or \ + event['type'] == 'autoAway': + mode = "away" break return 'away' in mode From c3923b2768b0e544579ac4fd58a4c79112054c5f Mon Sep 17 00:00:00 2001 From: Jean-Philippe Bouillot Date: Sun, 11 Dec 2016 23:47:27 +0100 Subject: [PATCH 076/141] Netatmo improving Battery info (#4724) * Improving Battery info Improving battery status info (to reflect NetAtmo API documentation and change deprecated DeviceList for WeatherStationData * Fixes from previous update Fix the hound issue. add battery_lvl, WindAngle_value, GustAngle_value, rf_status_lvl, wifi_status_lvl --- homeassistant/components/sensor/netatmo.py | 73 ++++++++++++++++++---- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/sensor/netatmo.py b/homeassistant/components/sensor/netatmo.py index c3503207d8b..20c0f94a500 100644 --- a/homeassistant/components/sensor/netatmo.py +++ b/homeassistant/components/sensor/netatmo.py @@ -38,14 +38,19 @@ SENSOR_TYPES = { 'sum_rain_1': ['sum_rain_1', 'mm', 'mdi:weather-rainy'], 'sum_rain_24': ['sum_rain_24', 'mm', 'mdi:weather-rainy'], 'battery_vp': ['Battery', '', 'mdi:battery'], + 'battery_lvl': ['Battery_lvl', '', 'mdi:battery'], 'min_temp': ['Min Temp.', TEMP_CELSIUS, 'mdi:thermometer'], 'max_temp': ['Max Temp.', TEMP_CELSIUS, 'mdi:thermometer'], 'WindAngle': ['Angle', '', 'mdi:compass'], + 'WindAngle_value': ['Angle Value', 'º', 'mdi:compass'], 'WindStrength': ['Strength', 'km/h', 'mdi:weather-windy'], 'GustAngle': ['Gust Angle', '', 'mdi:compass'], + 'GustAngle_value': ['Gust Angle Value', 'º', 'mdi:compass'], 'GustStrength': ['Gust Strength', 'km/h', 'mdi:weather-windy'], 'rf_status': ['Radio', '', 'mdi:signal'], - 'wifi_status': ['Wifi', '', 'mdi:wifi'] + 'rf_status_lvl': ['Radio_lvl', '', 'mdi:signal'], + 'wifi_status': ['Wifi', '', 'mdi:wifi'], + 'wifi_status_lvl': ['Wifi_lvl', 'dBm', 'mdi:wifi'] } MODULE_SCHEMA = vol.Schema({ @@ -103,6 +108,7 @@ class NetAtmoSensor(Entity): self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] module_id = self.netatmo_data.\ station_data.moduleByName(module=module_name)['_id'] + self.module_id = module_id[1] self._unique_id = "Netatmo Sensor {0} - {1} ({2})".format(self._name, module_id, self.type) @@ -154,21 +160,58 @@ class NetAtmoSensor(Entity): self._state = data['CO2'] elif self.type == 'pressure': self._state = round(data['Pressure'], 1) - elif self.type == 'battery_vp': + elif self.type == 'battery_lvl': + self._state = data['battery_vp'] + elif self.type == 'battery_vp' and self.module_id == '6': + if data['battery_vp'] >= 5590: + self._state = "Full" + elif data['battery_vp'] >= 5180: + self._state = "High" + elif data['battery_vp'] >= 4770: + self._state = "Medium" + elif data['battery_vp'] >= 4360: + self._state = "Low" + elif data['battery_vp'] < 4360: + self._state = "Very Low" + elif self.type == 'battery_vp' and self.module_id == '5': if data['battery_vp'] >= 5500: self._state = "Full" - elif data['battery_vp'] >= 5100: + elif data['battery_vp'] >= 5000: self._state = "High" - elif data['battery_vp'] >= 4600: + elif data['battery_vp'] >= 4500: self._state = "Medium" - elif data['battery_vp'] >= 4100: + elif data['battery_vp'] >= 4000: self._state = "Low" - elif data['battery_vp'] < 4100: + elif data['battery_vp'] < 4000: + self._state = "Very Low" + elif self.type == 'battery_vp' and self.module_id == '3': + if data['battery_vp'] >= 5640: + self._state = "Full" + elif data['battery_vp'] >= 5280: + self._state = "High" + elif data['battery_vp'] >= 4920: + self._state = "Medium" + elif data['battery_vp'] >= 4560: + self._state = "Low" + elif data['battery_vp'] < 4560: + self._state = "Very Low" + elif self.type == 'battery_vp' and self.module_id == '2': + if data['battery_vp'] >= 5500: + self._state = "Full" + elif data['battery_vp'] >= 5000: + self._state = "High" + elif data['battery_vp'] >= 4500: + self._state = "Medium" + elif data['battery_vp'] >= 4000: + self._state = "Low" + elif data['battery_vp'] < 4000: self._state = "Very Low" elif self.type == 'min_temp': self._state = data['min_temp'] elif self.type == 'max_temp': self._state = data['max_temp'] + elif self.type == 'WindAngle_value': + self._state = data['WindAngle'] elif self.type == 'WindAngle': if data['WindAngle'] >= 330: self._state = "North (%d\xb0)" % data['WindAngle'] @@ -190,6 +233,8 @@ class NetAtmoSensor(Entity): self._state = "North (%d\xb0)" % data['WindAngle'] elif self.type == 'WindStrength': self._state = data['WindStrength'] + elif self.type == 'GustAngle_value': + self._state = data['GustAngle'] elif self.type == 'GustAngle': if data['GustAngle'] >= 330: self._state = "North (%d\xb0)" % data['GustAngle'] @@ -211,6 +256,8 @@ class NetAtmoSensor(Entity): self._state = "North (%d\xb0)" % data['GustAngle'] elif self.type == 'GustStrength': self._state = data['GustStrength'] + elif self.type == 'rf_status_lvl': + self._state = data['rf_status'] elif self.type == 'rf_status': if data['rf_status'] >= 90: self._state = "Low" @@ -220,13 +267,17 @@ class NetAtmoSensor(Entity): self._state = "High" elif data['rf_status'] <= 59: self._state = "Full" + elif self.type == 'wifi_status_lvl': + self._state = data['wifi_status'] elif self.type == 'wifi_status': if data['wifi_status'] >= 86: - self._state = "Bad" + self._state = "Low" elif data['wifi_status'] >= 71: - self._state = "Middle" - elif data['wifi_status'] <= 70: - self._state = "Good" + self._state = "Medium" + elif data['wifi_status'] >= 56: + self._state = "High" + elif data['wifi_status'] <= 55: + self._state = "Full" class NetAtmoData(object): @@ -248,7 +299,7 @@ class NetAtmoData(object): def update(self): """Call the Netatmo API to update the data.""" import lnetatmo - self.station_data = lnetatmo.DeviceList(self.auth) + self.station_data = lnetatmo.WeatherStationData(self.auth) if self.station is not None: self.data = self.station_data.lastData(station=self.station, From 2708e193ec95c70bc434bc7f9510cb0ed0582724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Sun, 11 Dec 2016 23:59:12 +0100 Subject: [PATCH 077/141] vlc media player (#4800) * vlc media player * Update vlc.py --- .coveragerc | 1 + homeassistant/components/media_player/vlc.py | 152 +++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 156 insertions(+) create mode 100644 homeassistant/components/media_player/vlc.py diff --git a/.coveragerc b/.coveragerc index 0d34382659b..f993482093d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -212,6 +212,7 @@ omit = homeassistant/components/media_player/snapcast.py homeassistant/components/media_player/sonos.py homeassistant/components/media_player/squeezebox.py + homeassistant/components/media_player/vlc.py homeassistant/components/media_player/yamaha.py homeassistant/components/notify/aws_lambda.py homeassistant/components/notify/aws_sns.py diff --git a/homeassistant/components/media_player/vlc.py b/homeassistant/components/media_player/vlc.py new file mode 100644 index 00000000000..ee4fef3cfde --- /dev/null +++ b/homeassistant/components/media_player/vlc.py @@ -0,0 +1,152 @@ +""" +Provide functionality to interact with vlc devices on the network. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/media_player.vlc/ +""" +import logging + +import voluptuous as vol + +from homeassistant.components.media_player import ( + SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, + MediaPlayerDevice, PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC) +from homeassistant.const import (CONF_NAME, STATE_IDLE, STATE_PAUSED, + STATE_PLAYING) +import homeassistant.helpers.config_validation as cv +import homeassistant.util.dt as dt_util + +REQUIREMENTS = ['python-vlc==1.1.2'] + +_LOGGER = logging.getLogger(__name__) + + +SUPPORT_VLC = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ + SUPPORT_PLAY_MEDIA + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME): cv.string, +}) + + +# 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))]) + + +class VlcDevice(MediaPlayerDevice): + """Representation of a vlc player.""" + + def __init__(self, name): + """Initialize the vlc device.""" + import vlc + self._instance = vlc.Instance() + self._vlc = self._instance.media_player_new() + self._name = name + self._volume = None + self._muted = None + self._state = None + self._media_position_updated_at = None + self._media_position = None + self._media_duration = None + + def update(self): + """Get the latest details from the device.""" + import vlc + status = self._vlc.get_state() + if status == vlc.State.Playing: + self._state = STATE_PLAYING + elif status == vlc.State.Paused: + self._state = STATE_PAUSED + else: + self._state = STATE_IDLE + self._media_duration = self._vlc.get_length()/1000 + self._media_position = self._vlc.get_position() * self._media_duration + self._media_position_updated_at = dt_util.utcnow() + + self._volume = self._vlc.audio_get_volume() / 100 + self._muted = (self._vlc.audio_get_mute() == 1) + + return True + + @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 volume_level(self): + """Volume level of the media player (0..1).""" + return self._volume + + @property + def is_volume_muted(self): + """Boolean if volume is currently muted.""" + return self._muted + + @property + def supported_media_commands(self): + """Flag of media commands that are supported.""" + return SUPPORT_VLC + + @property + def media_content_type(self): + """Content type of current playing media.""" + return MEDIA_TYPE_MUSIC + + @property + def media_duration(self): + """Duration of current playing media in seconds.""" + return self._media_duration + + @property + def media_position(self): + """Position of current playing media in seconds.""" + return self._media_position + + @property + def media_position_updated_at(self): + """When was the position of the current playing media valid.""" + return self._media_position_updated_at + + def media_seek(self, position): + """Seek the media to a specific location.""" + track_length = self._vlc.get_length()/1000 + self._vlc.set_position(position/track_length) + + def mute_volume(self, mute): + """Mute the volume.""" + self._vlc.audio_set_mute(mute) + self._muted = mute + + def set_volume_level(self, volume): + """Set volume level, range 0..1.""" + self._vlc.audio_set_volume(int(volume * 100)) + self._volume = volume + + def media_play(self): + """Send play commmand.""" + self._vlc.play() + self._state = STATE_PLAYING + + def media_pause(self): + """Send pause command.""" + self._vlc.pause() + self._state = STATE_PAUSED + + def play_media(self, media_type, media_id, **kwargs): + """Play media from a URL or file.""" + if not media_type == MEDIA_TYPE_MUSIC: + _LOGGER.error( + "Invalid media type %s. Only %s is supported", + media_type, MEDIA_TYPE_MUSIC) + return + self._vlc.set_media(self._instance.media_new(media_id)) + self._vlc.play() + self._state = STATE_PLAYING diff --git a/requirements_all.txt b/requirements_all.txt index b67ef6f9d2b..f4e4bf6dbf3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -476,6 +476,9 @@ python-telegram-bot==5.2.0 # homeassistant.components.sensor.twitch python-twitch==1.3.0 +# homeassistant.components.media_player.vlc +python-vlc==1.1.2 + # homeassistant.components.wink python-wink==0.11.0 From 4d2480bbd19220a6a7135debceb2a25652884632 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Sun, 11 Dec 2016 18:43:42 -0500 Subject: [PATCH 078/141] Added support to language codes on Weather Underground (#4815) * Added supported to language codes to Weather Underground * Removed unecessary None assigments --- .../components/sensor/wunderground.py | 35 ++++++++++++++++--- tests/components/sensor/test_wunderground.py | 20 ++++++----- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/sensor/wunderground.py b/homeassistant/components/sensor/wunderground.py index 3194afbe94e..2f6558cd9da 100644 --- a/homeassistant/components/sensor/wunderground.py +++ b/homeassistant/components/sensor/wunderground.py @@ -19,12 +19,15 @@ from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle import homeassistant.helpers.config_validation as cv -_RESOURCE = 'http://api.wunderground.com/api/{}/conditions/q/' -_ALERTS = 'http://api.wunderground.com/api/{}/alerts/q/' +_RESOURCE = 'http://api.wunderground.com/api/{}/conditions/{}/q/' +_ALERTS = 'http://api.wunderground.com/api/{}/alerts/{}/q/' _LOGGER = logging.getLogger(__name__) CONF_ATTRIBUTION = "Data provided by the WUnderground weather service" CONF_PWS_ID = 'pws_id' +CONF_LANG = 'lang' + +DEFAULT_LANG = 'EN' MIN_TIME_BETWEEN_UPDATES_ALERTS = timedelta(minutes=15) MIN_TIME_BETWEEN_UPDATES_OBSERVATION = timedelta(minutes=5) @@ -80,9 +83,29 @@ ALERTS_ATTRS = [ 'message', ] +# Language Supported Codes +LANG_CODES = [ + 'AF', 'AL', 'AR', 'HY', 'AZ', 'EU', + 'BY', 'BU', 'LI', 'MY', 'CA', 'CN', + 'TW', 'CR', 'CZ', 'DK', 'DV', 'NL', + 'EN', 'EO', 'ET', 'FA', 'FI', 'FR', + 'FC', 'GZ', 'DL', 'KA', 'GR', 'GU', + 'HT', 'IL', 'HI', 'HU', 'IS', 'IO', + 'ID', 'IR', 'IT', 'JP', 'JW', 'KM', + 'KR', 'KU', 'LA', 'LV', 'LT', 'ND', + 'MK', 'MT', 'GM', 'MI', 'MR', 'MN', + 'NO', 'OC', 'PS', 'GN', 'PL', 'BR', + 'PA', 'PU', 'RO', 'RU', 'SR', 'SK', + 'SL', 'SP', 'SI', 'SW', 'CH', 'TL', + 'TT', 'TH', 'UA', 'UZ', 'VU', 'CY', + 'SN', 'JI', 'YI', +] + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_API_KEY): cv.string, vol.Optional(CONF_PWS_ID): cv.string, + vol.Optional(CONF_LANG, default=DEFAULT_LANG): + vol.All(vol.In(LANG_CODES)), vol.Required(CONF_MONITORED_CONDITIONS, default=[]): vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), }) @@ -92,7 +115,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the WUnderground sensor.""" rest = WUndergroundData(hass, config.get(CONF_API_KEY), - config.get(CONF_PWS_ID, None)) + config.get(CONF_PWS_ID), + config.get(CONF_LANG)) sensors = [] for variable in config[CONF_MONITORED_CONDITIONS]: sensors.append(WUndergroundSensor(rest, variable)) @@ -192,18 +216,19 @@ class WUndergroundSensor(Entity): class WUndergroundData(object): """Get data from WUnderground.""" - def __init__(self, hass, api_key, pws_id=None): + def __init__(self, hass, api_key, pws_id, lang): """Initialize the data object.""" self._hass = hass self._api_key = api_key self._pws_id = pws_id + self._lang = 'lang:{}'.format(lang) self._latitude = hass.config.latitude self._longitude = hass.config.longitude self.data = None self.alerts = None def _build_url(self, baseurl=_RESOURCE): - url = baseurl.format(self._api_key) + url = baseurl.format(self._api_key, self._lang) if self._pws_id: url = url + 'pws:{}'.format(self._pws_id) else: diff --git a/tests/components/sensor/test_wunderground.py b/tests/components/sensor/test_wunderground.py index 05c7fc93921..7c92ac20424 100644 --- a/tests/components/sensor/test_wunderground.py +++ b/tests/components/sensor/test_wunderground.py @@ -23,6 +23,16 @@ VALID_CONFIG = { ] } +INVALID_CONFIG = { + 'platform': 'wunderground', + 'api_key': 'BOB', + 'pws_id': 'bar', + 'lang': 'foo', + 'monitored_conditions': [ + 'weather', 'feelslike_c', 'alerts' + ] +} + FEELS_LIKE = '40' WEATHER = 'Clear' HTTPS_ICON_URL = 'https://icons.wxug.com/i/c/k/clear.gif' @@ -128,17 +138,9 @@ class TestWundergroundSetup(unittest.TestCase): self.assertTrue( wunderground.setup_platform(self.hass, VALID_CONFIG, self.add_devices, None)) - invalid_config = { - 'platform': 'wunderground', - 'api_key': 'BOB', - 'pws_id': 'bar', - 'monitored_conditions': [ - 'weather', 'feelslike_c', 'alerts' - ] - } self.assertTrue( - wunderground.setup_platform(self.hass, invalid_config, + wunderground.setup_platform(self.hass, INVALID_CONFIG, self.add_devices, None)) @unittest.mock.patch('requests.get', side_effect=mocked_requests_get) From 6edb54052f203961f11bfd7df8b6dd646d540afd Mon Sep 17 00:00:00 2001 From: IoTGuy Date: Mon, 12 Dec 2016 00:46:55 +0100 Subject: [PATCH 079/141] adding sensehat plugin (#4775) * adding sensehat plugin * added * fix PR * requirement updated * Update sensehat.py --- .coveragerc | 1 + homeassistant/components/sensor/sensehat.py | 134 ++++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 138 insertions(+) create mode 100644 homeassistant/components/sensor/sensehat.py diff --git a/.coveragerc b/.coveragerc index f993482093d..4aae4cbc242 100644 --- a/.coveragerc +++ b/.coveragerc @@ -296,6 +296,7 @@ omit = homeassistant/components/sensor/pvoutput.py homeassistant/components/sensor/sabnzbd.py homeassistant/components/sensor/scrape.py + homeassistant/components/sensor/sensehat.py homeassistant/components/sensor/serial_pm.py homeassistant/components/sensor/snmp.py homeassistant/components/sensor/sonarr.py diff --git a/homeassistant/components/sensor/sensehat.py b/homeassistant/components/sensor/sensehat.py new file mode 100644 index 00000000000..50cd233b39b --- /dev/null +++ b/homeassistant/components/sensor/sensehat.py @@ -0,0 +1,134 @@ +""" +Support for Sense HAT sensors. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/sensor.sensehat +""" +import os +import logging +from datetime import timedelta + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import (TEMP_CELSIUS, CONF_DISPLAY_OPTIONS, CONF_NAME) +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +REQUIREMENTS = ['sense-hat==2.2.0'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'sensehat' + +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) + +SENSOR_TYPES = { + 'temperature': ['temperature', TEMP_CELSIUS], + 'humidity': ['humidity', "%"], + 'pressure': ['pressure', "mb"], +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_DISPLAY_OPTIONS, default=SENSOR_TYPES): + [vol.In(SENSOR_TYPES)], + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + + +def get_cpu_temp(): + """Get CPU temperature.""" + res = os.popen("vcgencmd measure_temp").readline() + t_cpu = float(res.replace("temp=", "").replace("'C\n", "")) + return t_cpu + + +def get_average(temp_base): + """Use moving average to get better readings.""" + if not hasattr(get_average, "temp"): + get_average.temp = [temp_base, temp_base, temp_base] + get_average.temp[2] = get_average.temp[1] + get_average.temp[1] = get_average.temp[0] + get_average.temp[0] = temp_base + temp_avg = (get_average.temp[0]+get_average.temp[1]+get_average.temp[2])/3 + return temp_avg + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the sensor platform.""" + data = SenseHatData() + dev = [] + + for variable in config[CONF_DISPLAY_OPTIONS]: + dev.append(SenseHatSensor(data, variable)) + + add_devices(dev) + + +class SenseHatSensor(Entity): + """Representation of a sensehat sensor.""" + + def __init__(self, data, sensor_types): + """Initialize the sensor.""" + self.data = data + self._name = SENSOR_TYPES[sensor_types][0] + self._unit_of_measurement = SENSOR_TYPES[sensor_types][1] + self.type = sensor_types + self._state = None + """updating data.""" + self.update() + + @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 the value is expressed in.""" + return self._unit_of_measurement + + def update(self): + """Get the latest data and updates the states.""" + self.data.update() + if not self.data.humidity: + _LOGGER.error("Don't receive data!") + return + + if self.type == 'temperature': + self._state = self.data.temperature + if self.type == 'humidity': + self._state = self.data.humidity + if self.type == 'pressure': + self._state = self.data.pressure + + +class SenseHatData(object): + """Get the latest data and update.""" + + def __init__(self): + """Initialize the data object.""" + self.temperature = None + self.humidity = None + self.pressure = None + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Get the latest data from sensehat.""" + from sense_hat import SenseHat + sense = SenseHat() + temp_from_h = sense.get_temperature_from_humidity() + temp_from_p = sense.get_temperature_from_pressure() + t_cpu = get_cpu_temp() + t_total = (temp_from_h+temp_from_p)/2 + t_correct = t_total - ((t_cpu-t_total)/1.5) + t_correct = get_average(t_correct) + self.temperature = t_correct + self.humidity = sense.get_humidity() + self.pressure = sense.get_pressure() diff --git a/requirements_all.txt b/requirements_all.txt index f4e4bf6dbf3..4b2763f26bb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -521,6 +521,9 @@ scsgate==0.1.0 # homeassistant.components.notify.sendgrid sendgrid==3.6.3 +# homeassistant.components.sensor.sensehat +sense-hat==2.2.0 + # homeassistant.components.media_player.aquostv sharp-aquos-rc==0.2 From ecc514b7e487e5dc4a9f740070c21c21d3dae04d Mon Sep 17 00:00:00 2001 From: Jeff Wilson Date: Sun, 11 Dec 2016 18:48:47 -0500 Subject: [PATCH 080/141] Use current mode to determine which temperature attributes to use (#4858) --- homeassistant/components/climate/nest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index ab41c10e6d1..e098c3c3709 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -155,8 +155,8 @@ class NestThermostat(ClimateDevice): """Set new target temperature.""" target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW) target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH) - if target_temp_low is not None and target_temp_high is not None: - if self._mode == STATE_HEAT_COOL: + if self._mode == STATE_HEAT_COOL: + if target_temp_low is not None and target_temp_high is not None: temp = (target_temp_low, target_temp_high) else: temp = kwargs.get(ATTR_TEMPERATURE) From f4b5c439a1365ed79dc8740742c5fb4b969f3221 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Dec 2016 17:34:13 -0800 Subject: [PATCH 081/141] Fix Plex from doing I/O inside event loop (#4857) --- homeassistant/components/media_player/plex.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/media_player/plex.py b/homeassistant/components/media_player/plex.py index 76278722291..5aaee6a341e 100644 --- a/homeassistant/components/media_player/plex.py +++ b/homeassistant/components/media_player/plex.py @@ -200,6 +200,7 @@ class PlexClient(MediaPlayerDevice): self.update_devices = update_devices self.update_sessions = update_sessions self.set_device(device) + self._season = None def set_device(self, device): """Set the device property.""" @@ -240,9 +241,15 @@ class PlexClient(MediaPlayerDevice): def update(self): """Get the latest details.""" + from plexapi.video import Show + self.update_devices(no_throttle=True) self.update_sessions(no_throttle=True) + if isinstance(self.session, Show): + self._season = self._convert_na_to_none( + self.session.seasons()[0].index) + # pylint: disable=no-self-use, singleton-comparison def _convert_na_to_none(self, value): """Convert PlexAPI _NA() instances to None.""" @@ -310,9 +317,7 @@ class PlexClient(MediaPlayerDevice): @property def media_season(self): """Season of curent playing media (TV Show only).""" - from plexapi.video import Show - if isinstance(self.session, Show): - return self._convert_na_to_none(self.session.seasons()[0].index) + return self._season @property def media_series_title(self): From df98d5b3c12206c858d3dd7c2943d3bad6228a39 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Dec 2016 17:34:26 -0800 Subject: [PATCH 082/141] Fix Nest doing I/O inside event loop (#4855) --- homeassistant/components/sensor/nest.py | 31 +++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/sensor/nest.py b/homeassistant/components/sensor/nest.py index 53f767ab494..b9dde96a98c 100644 --- a/homeassistant/components/sensor/nest.py +++ b/homeassistant/components/sensor/nest.py @@ -128,13 +128,20 @@ class NestSensor(Entity): # device specific self._location = self.device.where - self._name = self.device.name_long + self._name = "{} {}".format(self.device.name_long, + self.variable.replace("_", " ")) self._state = None + self._unit = None @property def name(self): """Return the name of the nest, if any.""" - return "{} {}".format(self._name, self.variable.replace("_", " ")) + return self._name + + @property + def unit_of_measurement(self): + """Return the unit the value is expressed in.""" + return self._unit class NestBasicSensor(NestSensor): @@ -145,13 +152,10 @@ class NestBasicSensor(NestSensor): """Return the state of the sensor.""" return self._state - @property - def unit_of_measurement(self): - """Return the unit the value is expressed in.""" - return SENSOR_UNITS.get(self.variable, None) - def update(self): """Retrieve latest state.""" + self._unit = SENSOR_UNITS.get(self.variable, None) + if self.variable == 'operation_mode': self._state = getattr(self.device, "mode") else: @@ -161,14 +165,6 @@ class NestBasicSensor(NestSensor): class NestTempSensor(NestSensor): """Representation of a Nest Temperature sensor.""" - @property - def unit_of_measurement(self): - """Return the unit the value is expressed in.""" - if self.device.temperature_scale == 'C': - return TEMP_CELSIUS - else: - return TEMP_FAHRENHEIT - @property def state(self): """Return the state of the sensor.""" @@ -176,6 +172,11 @@ class NestTempSensor(NestSensor): def update(self): """Retrieve latest state.""" + if self.device.temperature_scale == 'C': + self._unit = TEMP_CELSIUS + else: + self._unit = TEMP_FAHRENHEIT + temp = getattr(self.device, self.variable) if temp is None: self._state = None From 48928d1f9e128b63ef7f5d96e07f4ee8bde7b422 Mon Sep 17 00:00:00 2001 From: David-Leon Pohl Date: Mon, 12 Dec 2016 02:38:33 +0100 Subject: [PATCH 083/141] Fix config validation (#4853) (#4854) --- 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 a052848cb21..84cbbd9fb0e 100644 --- a/homeassistant/components/switch/pilight.py +++ b/homeassistant/components/switch/pilight.py @@ -35,7 +35,7 @@ COMMAND_SCHEMA = vol.Schema({ vol.Optional(CONF_ID): cv.positive_int, vol.Optional(CONF_STATE): cv.string, vol.Optional(CONF_SYSTEMCODE): cv.positive_int, -}) +}, extra=vol.ALLOW_EXTRA) SWITCHES_SCHEMA = vol.Schema({ vol.Required(CONF_ON_CODE): COMMAND_SCHEMA, From b156ae7812251c064af23e6a3548b5f0ddc08a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Mon, 12 Dec 2016 02:59:30 +0100 Subject: [PATCH 084/141] Add support for Hue LightGroups (#4744) * Add support for Hue LightGroup entity * Don't filter on LightGroup and add properties for a group * Reuse code from HueLight in HueLightGroup * Remove HueLightGroup and add is_group variable to HueLight * Make linter happy * Update light or lightgroup state when a new state is available * Use schedule_update_ha_state() to schedule the state update. Drop new_lightgroups and use new_lights instead. * code style fix --- homeassistant/components/light/hue.py | 66 ++++++++++++++++++++------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index da2158ba78d..74247ad24ef 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -142,6 +142,7 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable): configurator.request_done(request_id) lights = {} + lightgroups = {} @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update_lights(): @@ -153,9 +154,15 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable): _LOGGER.exception("Cannot reach the bridge") return - api_states = api.get('lights') + api_lights = api.get('lights') - if not isinstance(api_states, dict): + if not isinstance(api_lights, dict): + _LOGGER.error("Got unexpected result from Hue API") + return + + api_groups = api.get('groups') + + if not isinstance(api_groups, dict): _LOGGER.error("Got unexpected result from Hue API") return @@ -167,7 +174,7 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable): else: bridge_type = 'hue' - for light_id, info in api_states.items(): + for light_id, info in api_lights.items(): if light_id not in lights: lights[light_id] = HueLight(int(light_id), info, bridge, update_lights, @@ -175,6 +182,17 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable): new_lights.append(lights[light_id]) else: lights[light_id].info = info + lights[light_id].schedule_update_ha_state() + + for lightgroup_id, info in api_groups.items(): + if lightgroup_id not in lightgroups: + lightgroups[lightgroup_id] = HueLight( + int(lightgroup_id), info, bridge, update_lights, + bridge_type, allow_unreachable, True) + new_lights.append(lightgroups[lightgroup_id]) + else: + lightgroups[lightgroup_id].info = info + lightgroups[lightgroup_id].schedule_update_ha_state() if new_lights: add_devices(new_lights) @@ -229,15 +247,20 @@ class HueLight(Light): """Representation of a Hue light.""" def __init__(self, light_id, info, bridge, update_lights, - bridge_type, allow_unreachable): + bridge_type, allow_unreachable, is_group=False): """Initialize the light.""" self.light_id = light_id self.info = info self.bridge = bridge self.update_lights = update_lights self.bridge_type = bridge_type - self.allow_unreachable = allow_unreachable + self.is_group = is_group + + if is_group: + self._command_func = self.bridge.set_group + else: + self._command_func = self.bridge.set_light @property def unique_id(self): @@ -247,33 +270,44 @@ class HueLight(Light): @property def name(self): - """Return the mame of the Hue light.""" + """Return the name of the Hue light.""" return self.info.get('name', DEVICE_DEFAULT_NAME) @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self.info['state'].get('bri') + if self.is_group: + return self.info['action'].get('bri') + else: + return self.info['state'].get('bri') @property def xy_color(self): """Return the XY color value.""" - return self.info['state'].get('xy') + if self.is_group: + return self.info['action'].get('xy') + else: + return self.info['state'].get('xy') @property def color_temp(self): """Return the CT color value.""" - return self.info['state'].get('ct') + if self.is_group: + return self.info['action'].get('ct') + else: + return self.info['state'].get('ct') @property def is_on(self): """Return true if device is on.""" - self.update_lights() - - if self.allow_unreachable: - return self.info['state']['on'] + if self.is_group: + return self.info['state']['any_on'] else: - return self.info['state']['reachable'] and self.info['state']['on'] + if self.allow_unreachable: + return self.info['state']['on'] + else: + return self.info['state']['reachable'] and \ + self.info['state']['on'] @property def supported_features(self): @@ -322,7 +356,7 @@ class HueLight(Light): elif self.bridge_type == 'hue': command['effect'] = 'none' - self.bridge.set_light(self.light_id, command) + self._command_func(self.light_id, command) def turn_off(self, **kwargs): """Turn the specified or all lights off.""" @@ -344,7 +378,7 @@ class HueLight(Light): elif self.bridge_type == 'hue': command['alert'] = 'none' - self.bridge.set_light(self.light_id, command) + self._command_func(self.light_id, command) def update(self): """Synchronize state with bridge.""" From 04aa4e898a31e459a4f478989ea13c6d6f3efd97 Mon Sep 17 00:00:00 2001 From: Anton Lundin Date: Mon, 12 Dec 2016 06:04:36 +0100 Subject: [PATCH 085/141] Improve denon media_player (#4836) * Add debug level logging of messages in denon * Added media stop for Denon AVR Media Player * Sort source list * Rework input selection for Denon AVR This reworks the input selection, adding more modes and making it so that the media controls are only announced in modes where they actually makes sense. * Added real media info for Denon AVR Media modes * Read more configuration from denon devices This reads network name, and overrides the local name with that. This also reads the source names and reconfigures the input list to those names, and also reads the source deleted list and removes the inputs that are set to deleted in the device. * Discover and handle max volume in Denon media player * Rework source discovery in Denon media player This uses SSFUN as authorative source for which sources that we should present. --- .../components/media_player/denon.py | 113 +++++++++++++++--- 1 file changed, 95 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/media_player/denon.py b/homeassistant/components/media_player/denon.py index b167ee52808..badbae162a2 100755 --- a/homeassistant/components/media_player/denon.py +++ b/homeassistant/components/media_player/denon.py @@ -13,7 +13,7 @@ from homeassistant.components.media_player import ( PLATFORM_SCHEMA, SUPPORT_NEXT_TRACK, SUPPORT_SELECT_SOURCE, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, - MediaPlayerDevice) + SUPPORT_STOP, MediaPlayerDevice) from homeassistant.const import ( CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN) import homeassistant.helpers.config_validation as cv @@ -22,16 +22,32 @@ _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = 'Music station' -SUPPORT_DENON = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | \ - SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | \ - SUPPORT_SELECT_SOURCE | SUPPORT_NEXT_TRACK | \ - SUPPORT_TURN_ON | SUPPORT_TURN_OFF +SUPPORT_DENON = SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ + SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE \ + +SUPPORT_MEDIA_MODES = SUPPORT_PAUSE | SUPPORT_STOP | \ + SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) +NORMAL_INPUTS = {'Cd': 'CD', 'Dvd': 'DVD', 'Blue ray': 'BD', 'TV': 'TV', + 'Satelite / Cable': 'SAT/CBL', 'Game': 'GAME', + 'Game2': 'GAME2', 'Video Aux': 'V.AUX', 'Dock': 'DOCK'} + +MEDIA_MODES = {'Tuner': 'TUNER', 'Media server': 'SERVER', + 'Ipod dock': 'IPOD', 'Net/USB': 'NET/USB', + 'Rapsody': 'RHAPSODY', 'Napster': 'NAPSTER', + 'Pandora': 'PANDORA', 'LastFM': 'LASTFM', + 'Flickr': 'FLICKR', 'Favorites': 'FAVORITES', + 'Internet Radio': 'IRADIO', 'USB/IPOD': 'USB/IPOD'} + +# Sub-modes of 'NET/USB' +# {'USB': 'USB', 'iPod Direct': 'IPD', 'Internet Radio': 'IRP', +# 'Favorites': 'FVP'} + def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Denon platform.""" @@ -53,14 +69,39 @@ class DenonDevice(MediaPlayerDevice): self._host = host self._pwstate = 'PWSTANDBY' self._volume = 0 - self._source_list = {'TV': 'SITV', 'Tuner': 'SITUNER', - 'Internet Radio': 'SIIRP', 'Favorites': 'SIFVP'} + # Initial value 60dB, changed if we get a MVMAX + self._volume_max = 60 + self._source_list = NORMAL_INPUTS.copy() + self._source_list.update(MEDIA_MODES) self._muted = False self._mediasource = '' + self._mediainfo = '' + + self._should_setup_sources = True + + def _setup_sources(self, telnet): + # NSFRN - Network name + self._name = self.telnet_request(telnet, 'NSFRN ?')[len('NSFRN '):] + + # SSFUN - Configured sources with names + self._source_list = {} + for line in self.telnet_request(telnet, 'SSFUN ?', all_lines=True): + source, configured_name = line[len('SSFUN'):].split(" ", 1) + self._source_list[configured_name] = source + + # SSSOD - Deleted sources + for line in self.telnet_request(telnet, 'SSSOD ?', all_lines=True): + source, status = line[len('SSSOD'):].split(" ", 1) + if status == 'DEL': + for pretty_name, name in self._source_list.items(): + if source == name: + del self._source_list[pretty_name] + break @classmethod - def telnet_request(cls, telnet, command): + def telnet_request(cls, telnet, command, all_lines=False): """Execute `command` and return the response.""" + _LOGGER.debug('Sending: "%s"', command) telnet.write(command.encode('ASCII') + b'\r') lines = [] while True: @@ -68,12 +109,16 @@ class DenonDevice(MediaPlayerDevice): if not line: break lines.append(line.decode('ASCII').strip()) + _LOGGER.debug('Recived: "%s"', line) + if all_lines: + return lines return lines[0] def telnet_command(self, command): """Establish a telnet connection and sends `command`.""" telnet = telnetlib.Telnet(self._host) + _LOGGER.debug('Sending: "%s"', command) telnet.write(command.encode('ASCII') + b'\r') telnet.read_very_eager() # skip response telnet.close() @@ -85,12 +130,30 @@ class DenonDevice(MediaPlayerDevice): except OSError: return False + if self._should_setup_sources: + self._setup_sources(telnet) + self._should_setup_sources = False + self._pwstate = self.telnet_request(telnet, 'PW?') - volume_str = self.telnet_request(telnet, 'MV?')[len('MV'):] - self._volume = int(volume_str) / 60 + for line in self.telnet_request(telnet, 'MV?', all_lines=True): + if line.startswith('MVMAX '): + # only grab two digit max, don't care about any half digit + self._volume_max = int(line[len('MVMAX '):len('MVMAX XX')]) + continue + if line.startswith('MV'): + self._volume = int(line[len('MV'):]) self._muted = (self.telnet_request(telnet, 'MU?') == 'MUON') self._mediasource = self.telnet_request(telnet, 'SI?')[len('SI'):] + if self._mediasource in MEDIA_MODES.values(): + self._mediainfo = "" + answer_codes = ["NSE0", "NSE1X", "NSE2X", "NSE3X", "NSE4", "NSE5", + "NSE6", "NSE7", "NSE8"] + for line in self.telnet_request(telnet, 'NSE', all_lines=True): + self._mediainfo += line[len(answer_codes.pop()):] + '\n' + else: + self._mediainfo = self.source + telnet.close() return True @@ -112,7 +175,7 @@ class DenonDevice(MediaPlayerDevice): @property def volume_level(self): """Volume level of the media player (0..1).""" - return self._volume + return self._volume / self._volume_max @property def is_volume_muted(self): @@ -122,17 +185,27 @@ class DenonDevice(MediaPlayerDevice): @property def source_list(self): """List of available input sources.""" - return list(self._source_list.keys()) + return sorted(list(self._source_list.keys())) @property def media_title(self): - """Current media source.""" - return self._mediasource + """Current media info.""" + return self._mediainfo @property def supported_media_commands(self): """Flag of media commands that are supported.""" - return SUPPORT_DENON + if self._mediasource in MEDIA_MODES.values(): + return SUPPORT_DENON | SUPPORT_MEDIA_MODES + else: + return SUPPORT_DENON + + @property + def source(self): + """Return the current input source.""" + for pretty_name, name in self._source_list.items(): + if self._mediasource == name: + return pretty_name def turn_off(self): """Turn off media player.""" @@ -148,8 +221,8 @@ class DenonDevice(MediaPlayerDevice): def set_volume_level(self, volume): """Set volume level, range 0..1.""" - # 60dB max - self.telnet_command('MV' + str(round(volume * 60)).zfill(2)) + self.telnet_command('MV' + + str(round(volume * self._volume_max)).zfill(2)) def mute_volume(self, mute): """Mute (true) or unmute (false) media player.""" @@ -163,6 +236,10 @@ class DenonDevice(MediaPlayerDevice): """Pause media player.""" self.telnet_command('NS9B') + def media_stop(self): + """Pause media player.""" + self.telnet_command('NS9C') + def media_next_track(self): """Send the next track command.""" self.telnet_command('NS9D') @@ -177,4 +254,4 @@ class DenonDevice(MediaPlayerDevice): def select_source(self, source): """Select input source.""" - self.telnet_command(self._source_list.get(source)) + self.telnet_command('SI' + self._source_list.get(source)) From 2a7fa5afc352ffd7ba9c5542e0d7133e43b9d0f1 Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Mon, 12 Dec 2016 06:39:37 +0100 Subject: [PATCH 086/141] Telldus Live: (#4645) - Implemented support for covers and dimmable lights. - Removed global object, use hass.data. - Disabled polling via update. - Inherit from common TelldusLiveEntity device. - Configurable polling interval - Use https API endpoint - Use tellduslive package --- homeassistant/components/cover/tellduslive.py | 46 +++ homeassistant/components/light/tellduslive.py | 59 ++++ .../components/sensor/tellduslive.py | 138 +++----- .../components/switch/tellduslive.py | 46 +-- homeassistant/components/tellduslive.py | 298 +++++++++--------- requirements_all.txt | 2 +- 6 files changed, 314 insertions(+), 275 deletions(-) create mode 100644 homeassistant/components/cover/tellduslive.py create mode 100644 homeassistant/components/light/tellduslive.py diff --git a/homeassistant/components/cover/tellduslive.py b/homeassistant/components/cover/tellduslive.py new file mode 100644 index 00000000000..c48a14e9133 --- /dev/null +++ b/homeassistant/components/cover/tellduslive.py @@ -0,0 +1,46 @@ +""" +Support for Tellstick covers using Tellstick Net. + +This platform uses the Telldus Live online service. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/cover.tellduslive/ + +""" +import logging + +from homeassistant.components.cover import CoverDevice +from homeassistant.components.tellduslive import TelldusLiveEntity + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup covers.""" + if discovery_info is None: + return + add_devices(TelldusLiveCover(hass, cover) for cover in discovery_info) + + +class TelldusLiveCover(TelldusLiveEntity, CoverDevice): + """Representation of a cover.""" + + @property + def is_closed(self): + """Return the current position of the cover.""" + return self.device.is_down + + def close_cover(self, **kwargs): + """Close the cover.""" + self.device.down() + self.changed() + + def open_cover(self, **kwargs): + """Open the cover.""" + self.device.up() + self.changed() + + def stop_cover(self, **kwargs): + """Stop the cover.""" + self.device.stop() + self.changed() diff --git a/homeassistant/components/light/tellduslive.py b/homeassistant/components/light/tellduslive.py new file mode 100644 index 00000000000..f919268c380 --- /dev/null +++ b/homeassistant/components/light/tellduslive.py @@ -0,0 +1,59 @@ +""" +Support for Tellstick switches using Tellstick Net. + +This platform uses the Telldus Live online service. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/light.tellduslive/ + +""" +import logging + +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) +from homeassistant.components.tellduslive import TelldusLiveEntity + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup lights.""" + if discovery_info is None: + return + add_devices(TelldusLiveLight(hass, light) for light in discovery_info) + + +class TelldusLiveLight(TelldusLiveEntity, Light): + """Representation of a light.""" + + def changed(self): + """A property of the device might have changed.""" + # pylint: disable=attribute-defined-outside-init + self._last_brightness = self.brightness + super().changed() + + @property + def brightness(self): + """Return the brightness of this light between 0..255.""" + return self.device.dim_level + + @property + def supported_features(self): + """Flag supported features.""" + return SUPPORT_BRIGHTNESS + + @property + def is_on(self): + """Return true if light is on.""" + return self.device.is_on + + def turn_on(self, **kwargs): + """Turn the light on.""" + brightness = kwargs.get(ATTR_BRIGHTNESS, self._last_brightness) + self.device.dim(level=brightness) + self.changed() + + def turn_off(self, **kwargs): + """Turn the light off.""" + self.device.turn_off() + self.changed() diff --git a/homeassistant/components/sensor/tellduslive.py b/homeassistant/components/sensor/tellduslive.py index 915bbac429f..abc5843ad91 100644 --- a/homeassistant/components/sensor/tellduslive.py +++ b/homeassistant/components/sensor/tellduslive.py @@ -6,37 +6,32 @@ https://home-assistant.io/components/sensor.tellduslive/ """ import logging -from datetime import datetime -from homeassistant.components import tellduslive -from homeassistant.const import ( - ATTR_BATTERY_LEVEL, DEVICE_DEFAULT_NAME, TEMP_CELSIUS) -from homeassistant.helpers.entity import Entity - -ATTR_LAST_UPDATED = "time_last_updated" +from homeassistant.components.tellduslive import TelldusLiveEntity +from homeassistant.const import TEMP_CELSIUS _LOGGER = logging.getLogger(__name__) -SENSOR_TYPE_TEMP = "temp" -SENSOR_TYPE_HUMIDITY = "humidity" -SENSOR_TYPE_RAINRATE = "rrate" -SENSOR_TYPE_RAINTOTAL = "rtot" -SENSOR_TYPE_WINDDIRECTION = "wdir" -SENSOR_TYPE_WINDAVERAGE = "wavg" -SENSOR_TYPE_WINDGUST = "wgust" -SENSOR_TYPE_WATT = "watt" -SENSOR_TYPE_LUMINANCE = "lum" +SENSOR_TYPE_TEMP = 'temp' +SENSOR_TYPE_HUMIDITY = 'humidity' +SENSOR_TYPE_RAINRATE = 'rrate' +SENSOR_TYPE_RAINTOTAL = 'rtot' +SENSOR_TYPE_WINDDIRECTION = 'wdir' +SENSOR_TYPE_WINDAVERAGE = 'wavg' +SENSOR_TYPE_WINDGUST = 'wgust' +SENSOR_TYPE_WATT = 'watt' +SENSOR_TYPE_LUMINANCE = 'lum' SENSOR_TYPES = { - SENSOR_TYPE_TEMP: ['Temperature', TEMP_CELSIUS, "mdi:thermometer"], - SENSOR_TYPE_HUMIDITY: ['Humidity', '%', "mdi:water"], - SENSOR_TYPE_RAINRATE: ['Rain rate', 'mm', "mdi:water"], - SENSOR_TYPE_RAINTOTAL: ['Rain total', 'mm', "mdi:water"], - SENSOR_TYPE_WINDDIRECTION: ['Wind direction', '', ""], - SENSOR_TYPE_WINDAVERAGE: ['Wind average', 'm/s', ""], - SENSOR_TYPE_WINDGUST: ['Wind gust', 'm/s', ""], - SENSOR_TYPE_WATT: ['Watt', 'W', ""], - SENSOR_TYPE_LUMINANCE: ['Luminance', 'lx', ""], + SENSOR_TYPE_TEMP: ['Temperature', TEMP_CELSIUS, 'mdi:thermometer'], + SENSOR_TYPE_HUMIDITY: ['Humidity', '%', 'mdi:water'], + SENSOR_TYPE_RAINRATE: ['Rain rate', 'mm', 'mdi:water'], + SENSOR_TYPE_RAINTOTAL: ['Rain total', 'mm', 'mdi:water'], + SENSOR_TYPE_WINDDIRECTION: ['Wind direction', '', ''], + SENSOR_TYPE_WINDAVERAGE: ['Wind average', 'm/s', ''], + SENSOR_TYPE_WINDGUST: ['Wind gust', 'm/s', ''], + SENSOR_TYPE_WATT: ['Watt', 'W', ''], + SENSOR_TYPE_LUMINANCE: ['Luminance', 'lx', ''], } @@ -44,114 +39,75 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup Tellstick sensors.""" if discovery_info is None: return - add_devices(TelldusLiveSensor(sensor) for sensor in discovery_info) + add_devices(TelldusLiveSensor(hass, sensor) for sensor in discovery_info) -class TelldusLiveSensor(Entity): +class TelldusLiveSensor(TelldusLiveEntity): """Representation of a Telldus Live sensor.""" - def __init__(self, sensor_id): - """Initialize the sensor.""" - self._id = sensor_id - self.update() - _LOGGER.debug("created sensor %s", self) - - def update(self): - """Update sensor values.""" - tellduslive.NETWORK.update_sensors() - self._sensor = tellduslive.NETWORK.get_sensor(self._id) + @property + def device_id(self): + """Return id of the device.""" + return self._id[0] @property - def _sensor_name(self): - """Return the name of the sensor.""" - return self._sensor["name"] - - @property - def _sensor_value(self): - """Return the value the sensor.""" - return self._sensor["data"]["value"] - - @property - def _sensor_type(self): + def _type(self): """Return the type of the sensor.""" - return self._sensor["data"]["name"] + return self._id[1] @property - def _battery_level(self): - """Return the battery level of a sensor.""" - sensor_battery_level = self._sensor.get("battery") - return round(sensor_battery_level * 100 / 255) \ - if sensor_battery_level else None - - @property - def _last_updated(self): - """Return the last update.""" - sensor_last_updated = self._sensor.get("lastUpdated") - return str(datetime.fromtimestamp(sensor_last_updated)) \ - if sensor_last_updated else None + def _value(self): + """Return value of the sensor.""" + return self.device.value(self._id[1:]) @property def _value_as_temperature(self): """Return the value as temperature.""" - return round(float(self._sensor_value), 1) + return round(float(self._value), 1) @property def _value_as_luminance(self): """Return the value as luminance.""" - return round(float(self._sensor_value), 1) + return round(float(self._value), 1) @property def _value_as_humidity(self): """Return the value as humidity.""" - return int(round(float(self._sensor_value))) + return int(round(float(self._value))) @property def name(self): """Return the name of the sensor.""" - return "{} {}".format(self._sensor_name or DEVICE_DEFAULT_NAME, - self.quantity_name or "") - - @property - def available(self): - """Return true if the sensor is available.""" - return not self._sensor.get("offline", False) + return '{} {}'.format( + super().name, + self.quantity_name or '') @property def state(self): """Return the state of the sensor.""" - if self._sensor_type == SENSOR_TYPE_TEMP: + if self._type == SENSOR_TYPE_TEMP: return self._value_as_temperature - elif self._sensor_type == SENSOR_TYPE_HUMIDITY: + elif self._type == SENSOR_TYPE_HUMIDITY: return self._value_as_humidity - elif self._sensor_type == SENSOR_TYPE_LUMINANCE: + elif self._type == SENSOR_TYPE_LUMINANCE: return self._value_as_luminance else: - return self._sensor_value - - @property - def device_state_attributes(self): - """Return the state attributes.""" - attrs = {} - if self._battery_level is not None: - attrs[ATTR_BATTERY_LEVEL] = self._battery_level - if self._last_updated is not None: - attrs[ATTR_LAST_UPDATED] = self._last_updated - return attrs + return self._value @property def quantity_name(self): """Name of quantity.""" - return SENSOR_TYPES[self._sensor_type][0] \ - if self._sensor_type in SENSOR_TYPES else None + return SENSOR_TYPES[self._type][0] \ + if self._type in SENSOR_TYPES else None @property def unit_of_measurement(self): """Return the unit of measurement.""" - return SENSOR_TYPES[self._sensor_type][1] \ - if self._sensor_type in SENSOR_TYPES else None + return SENSOR_TYPES[self._type][1] \ + if self._type in SENSOR_TYPES else None @property def icon(self): """Return the icon.""" - return SENSOR_TYPES[self._sensor_type][2] \ - if self._sensor_type in SENSOR_TYPES else None + return SENSOR_TYPES[self._type][2] \ + if self._type in SENSOR_TYPES else None diff --git a/homeassistant/components/switch/tellduslive.py b/homeassistant/components/switch/tellduslive.py index eaa78412c27..b1450de6c5e 100644 --- a/homeassistant/components/switch/tellduslive.py +++ b/homeassistant/components/switch/tellduslive.py @@ -9,7 +9,7 @@ https://home-assistant.io/components/switch.tellduslive/ """ import logging -from homeassistant.components import tellduslive +from homeassistant.components.tellduslive import TelldusLiveEntity from homeassistant.helpers.entity import ToggleEntity _LOGGER = logging.getLogger(__name__) @@ -19,53 +19,23 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup Tellstick switches.""" if discovery_info is None: return - add_devices(TelldusLiveSwitch(switch) for switch in discovery_info) + add_devices(TelldusLiveSwitch(hass, switch) for switch in discovery_info) -class TelldusLiveSwitch(ToggleEntity): +class TelldusLiveSwitch(TelldusLiveEntity, ToggleEntity): """Representation of a Tellstick switch.""" - def __init__(self, switch_id): - """Initialize the switch.""" - self._id = switch_id - self.update() - _LOGGER.debug("created switch %s", self) - - def update(self): - """Get the latest date and update the state.""" - tellduslive.NETWORK.update_switches() - self._switch = tellduslive.NETWORK.get_switch(self._id) - - @property - def should_poll(self): - """Polling is needed.""" - return True - - @property - def assumed_state(self): - """Return true if unable to access real state of entity.""" - return True - - @property - def name(self): - """Return the name of the switch if any.""" - return self._switch["name"] - - @property - def available(self): - """Return the state of the switch.""" - return not self._switch.get("offline", False) - @property def is_on(self): """Return true if switch is on.""" - from tellive.live import const - return self._switch["state"] == const.TELLSTICK_TURNON + return self.device.is_on() def turn_on(self, **kwargs): """Turn the switch on.""" - tellduslive.NETWORK.turn_switch_on(self._id) + self.device.turn_on() + self.changed() def turn_off(self, **kwargs): """Turn the switch off.""" - tellduslive.NETWORK.turn_switch_off(self._id) + self.device.turn_off() + self.changed() diff --git a/homeassistant/components/tellduslive.py b/homeassistant/components/tellduslive.py index 36e9b01d511..cf62a28b552 100644 --- a/homeassistant/components/tellduslive.py +++ b/homeassistant/components/tellduslive.py @@ -4,18 +4,20 @@ Support for Telldus Live. For more details about this component, please refer to the documentation at https://home-assistant.io/components/tellduslive/ """ +from datetime import datetime, timedelta import logging -from datetime import timedelta - -import voluptuous as vol +from homeassistant.const import ATTR_BATTERY_LEVEL, DEVICE_DEFAULT_NAME from homeassistant.helpers import discovery -from homeassistant.util import Throttle import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity +from homeassistant.helpers.event import track_point_in_utc_time +from homeassistant.util.dt import utcnow +import voluptuous as vol DOMAIN = 'tellduslive' -REQUIREMENTS = ['tellive-py==0.5.2'] +REQUIREMENTS = ['tellduslive==0.1.9'] _LOGGER = logging.getLogger(__name__) @@ -23,11 +25,10 @@ CONF_PUBLIC_KEY = 'public_key' CONF_PRIVATE_KEY = 'private_key' CONF_TOKEN = 'token' CONF_TOKEN_SECRET = 'token_secret' +CONF_UPDATE_INTERVAL = 'update_interval' -MIN_TIME_BETWEEN_SWITCH_UPDATES = timedelta(minutes=1) -MIN_TIME_BETWEEN_SENSOR_UPDATES = timedelta(minutes=5) - -NETWORK = None +MIN_UPDATE_INTERVAL = timedelta(seconds=5) +DEFAULT_UPDATE_INTERVAL = timedelta(minutes=1) CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -35,183 +36,190 @@ CONFIG_SCHEMA = vol.Schema({ vol.Required(CONF_PRIVATE_KEY): cv.string, vol.Required(CONF_TOKEN): cv.string, vol.Required(CONF_TOKEN_SECRET): cv.string, + vol.Optional(CONF_UPDATE_INTERVAL, default=DEFAULT_UPDATE_INTERVAL): ( + vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL))) }), }, extra=vol.ALLOW_EXTRA) +ATTR_LAST_UPDATED = 'time_last_updated' + + def setup(hass, config): """Setup the Telldus Live component.""" - # fixme: aquire app key and provide authentication using username+password + client = TelldusLiveClient(hass, config) - global NETWORK - NETWORK = TelldusLiveData(hass, config) - - if not NETWORK.validate_session(): + if not client.validate_session(): _LOGGER.error( - "Authentication Error: " - "Please make sure you have configured your keys " - "that can be aquired from https://api.telldus.com/keys/index") + 'Authentication Error: ' + 'Please make sure you have configured your keys ' + 'that can be aquired from https://api.telldus.com/keys/index') return False - NETWORK.discover() + hass.data[DOMAIN] = client + client.update(utcnow()) return True -@Throttle(MIN_TIME_BETWEEN_SWITCH_UPDATES) -def request_switches(): - """Make request to online service.""" - _LOGGER.debug("Updating switches from Telldus Live") - switches = NETWORK.request('devices/list') - # Filter out any group of switches. - if switches and 'device' in switches: - return {switch["id"]: switch for switch in switches['device'] - if switch["type"] == "device"} - return None - - -@Throttle(MIN_TIME_BETWEEN_SENSOR_UPDATES) -def request_sensors(): - """Make request to online service.""" - _LOGGER.debug("Updating sensors from Telldus Live") - units = NETWORK.request('sensors/list') - # One unit can contain many sensors. - if units and 'sensor' in units: - return {(unit['id'], sensor['name'], sensor['scale']): - dict(unit, data=sensor) - for unit in units['sensor'] - for sensor in unit['data']} - return None - - -class TelldusLiveData(object): +class TelldusLiveClient(object): """Get the latest data and update the states.""" def __init__(self, hass, config): """Initialize the Tellus data object.""" + from tellduslive import Client + public_key = config[DOMAIN].get(CONF_PUBLIC_KEY) private_key = config[DOMAIN].get(CONF_PRIVATE_KEY) token = config[DOMAIN].get(CONF_TOKEN) token_secret = config[DOMAIN].get(CONF_TOKEN_SECRET) - from tellive.client import LiveClient - - self._switches = {} - self._sensors = {} + self.entities = [] self._hass = hass self._config = config - self._client = LiveClient( - public_key=public_key, private_key=private_key, access_token=token, - access_secret=token_secret) + self._interval = config[DOMAIN].get(CONF_UPDATE_INTERVAL) + _LOGGER.debug('Update interval %s', self._interval) + + self._client = Client(public_key, + private_key, + token, + token_secret) def validate_session(self): - """Make a dummy request to see if the session is valid.""" - response = self.request("user/profile") + """Make a request to see if the session is valid.""" + response = self._client.request_user() return response and 'email' in response - def discover(self): - """Update states, will trigger discover.""" - self.update_sensors() - self.update_switches() - - def _discover(self, found_devices, component_name): - """Send discovery event if component not yet discovered.""" - if not found_devices: - return - - _LOGGER.info("discovered %d new %s devices", - len(found_devices), component_name) - - discovery.load_platform(self._hass, component_name, DOMAIN, - found_devices, self._config) - - def request(self, what, **params): - """Send a request to the Tellstick Live API.""" - from tellive.live import const - - supported_methods = const.TELLSTICK_TURNON \ - | const.TELLSTICK_TURNOFF \ - | const.TELLSTICK_TOGGLE \ - - # Tellstick device methods not yet supported - # | const.TELLSTICK_BELL \ - # | const.TELLSTICK_DIM \ - # | const.TELLSTICK_LEARN \ - # | const.TELLSTICK_EXECUTE \ - # | const.TELLSTICK_UP \ - # | const.TELLSTICK_DOWN \ - # | const.TELLSTICK_STOP - - default_params = {'supportedMethods': supported_methods, - 'includeValues': 1, - 'includeScale': 1, - 'includeIgnored': 0} - params.update(default_params) - - # room for improvement: the telllive library doesn't seem to - # re-use sessions, instead it opens a new session for each request - # this needs to be fixed - + def update(self, now): + """Periodically poll the servers for current state.""" + _LOGGER.debug('Updating') try: - response = self._client.request(what, params) - _LOGGER.debug("got response %s", response) - return response - except OSError as error: - _LOGGER.error("failed to make request to Tellduslive servers: %s", - error) - return None + self._sync() + finally: + track_point_in_utc_time(self._hass, + self.update, + now + self._interval) - def update_devices(self, local_devices, remote_devices, component_name): - """Update local device list and discover new devices.""" - if remote_devices is None: - return local_devices + def _sync(self): + """Update local list of devices.""" + self._client.update() - remote_ids = remote_devices.keys() - local_ids = local_devices.keys() + def identify_device(device): + """Find out what type of HA component to create.""" + from tellduslive import (DIM, UP, TURNON) + if device.methods & DIM: + return 'light' + elif device.methods & UP: + return 'cover' + elif device.methods & TURNON: + return 'switch' + else: + _LOGGER.warning('Unidentified device type (methods: %d)', + device.methods) + return 'switch' - added_devices = list(remote_ids - local_ids) - self._discover(added_devices, - component_name) + def discover(device_id, component): + """Discover the component.""" + discovery.load_platform(self._hass, + component, + DOMAIN, + [device_id], + self._config) - removed_devices = list(local_ids - remote_ids) - remote_devices.update({id: dict(local_devices[id], offline=True) - for id in removed_devices}) + known_ids = set([entity.device_id for entity in self.entities]) + for device in self._client.devices: + if device.device_id in known_ids: + continue + if device.is_sensor: + for item_id in device.items: + discover((device.device_id,) + item_id, + 'sensor') + else: + discover(device.device_id, + identify_device(device)) - return remote_devices + for entity in self.entities: + entity.changed() - def update_sensors(self): - """Update local list of sensors.""" - self._sensors = self.update_devices( - self._sensors, request_sensors(), 'sensor') + def device(self, device_id): + """Return device representation.""" + import tellduslive + return tellduslive.Device(self._client, device_id) - def update_switches(self): - """Update local list of switches.""" - self._switches = self.update_devices( - self._switches, request_switches(), 'switch') + def is_available(self, device_id): + """Return device availability.""" + return device_id in self._client.device_ids - def _check_request(self, what, **params): - """Make request, check result if successful.""" - response = self.request(what, **params) - return response and response.get('status') == 'success' - def get_switch(self, switch_id): - """Return the switch representation.""" - return self._switches[switch_id] +class TelldusLiveEntity(Entity): + """Base class for all Telldus Live entities.""" - def get_sensor(self, sensor_id): - """Return the sensor representation.""" - return self._sensors[sensor_id] + def __init__(self, hass, device_id): + """Initialize the entity.""" + self._id = device_id + self._client = hass.data[DOMAIN] + self._client.entities.append(self) + _LOGGER.debug('Created device %s', self) - def turn_switch_on(self, switch_id): - """Turn switch off.""" - if self._check_request('device/turnOn', id=switch_id): - from tellive.live import const - self.get_switch(switch_id)['state'] = const.TELLSTICK_TURNON + def changed(self): + """A property of the device might have changed.""" + self.schedule_update_ha_state() - def turn_switch_off(self, switch_id): - """Turn switch on.""" - if self._check_request('device/turnOff', id=switch_id): - from tellive.live import const - self.get_switch(switch_id)['state'] = const.TELLSTICK_TURNOFF + @property + def device_id(self): + """Return the id of the device.""" + return self._id + + @property + def device(self): + """Return the representaion of the device.""" + return self._client.device(self.device_id) + + @property + def _state(self): + """Return the state of the device.""" + return self.device.state + + @property + def should_poll(self): + """Polling is not needed.""" + return False + + @property + def assumed_state(self): + """Return true if unable to access real state of entity.""" + return True + + @property + def name(self): + """Return name of device.""" + return self.device.name or DEVICE_DEFAULT_NAME + + @property + def available(self): + """Return true if device is not offline.""" + return self._client.is_available(self.device_id) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attrs = {} + if self._battery_level: + attrs[ATTR_BATTERY_LEVEL] = self._battery_level + if self._last_updated: + attrs[ATTR_LAST_UPDATED] = self._last_updated + return attrs + + @property + def _battery_level(self): + """Return the battery level of a device.""" + return round(self.device.battery * 100 / 255) \ + if self.device.battery else None + + @property + def _last_updated(self): + """Return the last update of a device.""" + return str(datetime.fromtimestamp(self.device.last_updated)) \ + if self.device.last_updated else None diff --git a/requirements_all.txt b/requirements_all.txt index 4b2763f26bb..fe37b085b2c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -560,7 +560,7 @@ steamodd==4.21 tellcore-py==1.1.2 # homeassistant.components.tellduslive -tellive-py==0.5.2 +tellduslive==0.1.9 # homeassistant.components.sensor.temper temperusb==1.5.1 From d7ccf079228565ec35dffdccd4c9eac4ce6e4588 Mon Sep 17 00:00:00 2001 From: John Mihalic Date: Mon, 12 Dec 2016 00:43:53 -0500 Subject: [PATCH 087/141] Add media position support and trailer type to Emby (#4792) * Add media position support and trailer type to Emby * Adjustments to mitigate TypeError * Simplify media_position property * Update handling when data isn't available * Update emby.py --- homeassistant/components/media_player/emby.py | 41 ++++++++++++++++--- requirements_all.txt | 2 +- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/media_player/emby.py b/homeassistant/components/media_player/emby.py index 5349e74ed40..3fae52dd052 100644 --- a/homeassistant/components/media_player/emby.py +++ b/homeassistant/components/media_player/emby.py @@ -20,12 +20,15 @@ from homeassistant.const import ( STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN) from homeassistant.helpers.event import (track_utc_time_change) from homeassistant.util import Throttle +import homeassistant.util.dt as dt_util -REQUIREMENTS = ['pyemby==0.1'] +REQUIREMENTS = ['pyemby==0.2'] MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1) +MEDIA_TYPE_TRAILER = 'trailer' + DEFAULT_PORT = 8096 _LOGGER = logging.getLogger(__name__) @@ -119,6 +122,8 @@ class EmbyClient(MediaPlayerDevice): self.update_sessions = update_sessions self.client = client self.set_device(device) + self.media_status_last_position = None + self.media_status_received = None def set_device(self, device): """Set the device property.""" @@ -178,6 +183,17 @@ class EmbyClient(MediaPlayerDevice): """Get the latest details.""" self.update_devices(no_throttle=True) self.update_sessions(no_throttle=True) + # Check if we should update progress + try: + position = self.session['PlayState']['PositionTicks'] + except (KeyError, TypeError): + self.media_status_last_position = None + self.media_status_received = None + else: + position = int(position) / 10000000 + if position != self.media_status_last_position: + self.media_status_last_position = position + self.media_status_received = dt_util.utcnow() def play_percent(self): """Return current media percent complete.""" @@ -220,6 +236,8 @@ class EmbyClient(MediaPlayerDevice): return MEDIA_TYPE_TVSHOW elif media_type == 'Movie': return MEDIA_TYPE_VIDEO + elif media_type == 'Trailer': + return MEDIA_TYPE_TRAILER return None except KeyError: return None @@ -233,19 +251,32 @@ class EmbyClient(MediaPlayerDevice): except KeyError: return None + @property + def media_position(self): + """Position of current playing media in seconds.""" + return self.media_status_last_position + + @property + def media_position_updated_at(self): + """ + When was the position of the current playing media valid. + + Returns value from homeassistant.util.dt.utcnow(). + """ + return self.media_status_received + @property def media_image_url(self): """Image url of current playing media.""" if self.now_playing_item is not None: try: return self.client.get_image( - self.now_playing_item['ThumbItemId'], 'Thumb', - self.play_percent()) + self.now_playing_item['ThumbItemId'], 'Thumb', 0) except KeyError: try: return self.client.get_image( - self.now_playing_item['PrimaryImageItemId'], 'Primary', - self.play_percent()) + self.now_playing_item[ + 'PrimaryImageItemId'], 'Primary', 0) except KeyError: return None diff --git a/requirements_all.txt b/requirements_all.txt index fe37b085b2c..f9d1b36fb5f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -390,7 +390,7 @@ pycmus==0.1.0 pydispatcher==2.0.5 # homeassistant.components.media_player.emby -pyemby==0.1 +pyemby==0.2 # homeassistant.components.envisalink pyenvisalink==1.9 From 4114884cdc91a9a238120501fe20c517475b7362 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Mon, 12 Dec 2016 00:43:59 -0500 Subject: [PATCH 088/141] Flic: Support use of queued events within timeout (#4822) * Flic: Support use of queued events within timeout * Linter fixes --- .../components/binary_sensor/flic.py | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/binary_sensor/flic.py b/homeassistant/components/binary_sensor/flic.py index 92301330605..980af069f38 100644 --- a/homeassistant/components/binary_sensor/flic.py +++ b/homeassistant/components/binary_sensor/flic.py @@ -6,7 +6,8 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.const import ( - CONF_HOST, CONF_PORT, CONF_DISCOVERY, EVENT_HOMEASSISTANT_STOP) + CONF_HOST, CONF_PORT, CONF_DISCOVERY, CONF_TIMEOUT, + EVENT_HOMEASSISTANT_STOP) from homeassistant.components.binary_sensor import ( BinarySensorDevice, PLATFORM_SCHEMA) from homeassistant.util.async import run_callback_threadsafe @@ -16,6 +17,7 @@ REQUIREMENTS = ['https://github.com/soldag/pyflic/archive/0.4.zip#pyflic==0.4'] _LOGGER = logging.getLogger(__name__) +DEFAULT_TIMEOUT = 3 CLICK_TYPE_SINGLE = "single" CLICK_TYPE_DOUBLE = "double" @@ -28,12 +30,14 @@ EVENT_NAME = "flic_click" EVENT_DATA_NAME = "button_name" EVENT_DATA_ADDRESS = "button_address" EVENT_DATA_TYPE = "click_type" +EVENT_DATA_QUEUED_TIME = "queued_time" # Validation of the user's configuration PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST, default='localhost'): cv.string, vol.Optional(CONF_PORT, default=5551): cv.port, vol.Optional(CONF_DISCOVERY, default=True): cv.boolean, + vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int, vol.Optional(CONF_IGNORED_CLICK_TYPES): vol.All(cv.ensure_list, [vol.In(CLICK_TYPES)]) }) @@ -102,8 +106,9 @@ def start_scanning(hass, config, async_add_entities, client): @asyncio.coroutine def async_setup_button(hass, config, async_add_entities, client, address): """Setup single button device.""" + timeout = config.get(CONF_TIMEOUT) ignored_click_types = config.get(CONF_IGNORED_CLICK_TYPES) - button = FlicButton(hass, client, address, ignored_click_types) + button = FlicButton(hass, client, address, timeout, ignored_click_types) _LOGGER.info("Connected to button (%s)", address) yield from async_add_entities([button]) @@ -127,12 +132,13 @@ def async_get_verified_addresses(client): class FlicButton(BinarySensorDevice): """Representation of a flic button.""" - def __init__(self, hass, client, address, ignored_click_types): + def __init__(self, hass, client, address, timeout, ignored_click_types): """Initialize the flic button.""" import pyflic self._hass = hass self._address = address + self._timeout = timeout self._is_down = False self._ignored_click_types = ignored_click_types or [] self._hass_click_types = { @@ -196,11 +202,27 @@ class FlicButton(BinarySensorDevice): return attr + def _queued_event_check(self, click_type, time_diff): + """Generate a log message and returns true if timeout exceeded.""" + time_string = "{:d} {}".format( + time_diff, "second" if time_diff == 1 else "seconds") + + if time_diff > self._timeout: + _LOGGER.warning( + "Queued %s dropped for %s. Time in queue was %s.", + click_type, self.address, time_string) + return True + else: + _LOGGER.info( + "Queued %s allowed for %s. Time in queue was %s.", + click_type, self.address, time_string) + return False + def _on_up_down(self, channel, click_type, was_queued, time_diff): """Update device state, if event was not queued.""" import pyflic - if was_queued: + if was_queued and self._queued_event_check(click_type, time_diff): return self._is_down = click_type == pyflic.ClickType.ButtonDown @@ -208,13 +230,19 @@ class FlicButton(BinarySensorDevice): def _on_click(self, channel, click_type, was_queued, time_diff): """Fire click event, if event was not queued.""" + # Return if click event was queued beyond allowed timeout + if was_queued and self._queued_event_check(click_type, time_diff): + return + + # Return if click event is in ignored click types hass_click_type = self._hass_click_types[click_type] - if was_queued or hass_click_type in self._ignored_click_types: + if hass_click_type in self._ignored_click_types: return self._hass.bus.fire(EVENT_NAME, { EVENT_DATA_NAME: self.name, EVENT_DATA_ADDRESS: self.address, + EVENT_DATA_QUEUED_TIME: time_diff, EVENT_DATA_TYPE: hass_click_type }) From 3467020dbf1d4747c07900d8f5fe2c1c0baf5292 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Mon, 12 Dec 2016 00:46:19 -0500 Subject: [PATCH 089/141] Added resolution support to Amcrest cameras (#4860) * Added resolution support to Amcrest cameras * Ordered alphabetically DEFAULT_ options --- homeassistant/components/camera/amcrest.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/camera/amcrest.py b/homeassistant/components/camera/amcrest.py index 97ed45f21e4..c6568677583 100644 --- a/homeassistant/components/camera/amcrest.py +++ b/homeassistant/components/camera/amcrest.py @@ -18,16 +18,26 @@ REQUIREMENTS = ['amcrest==1.0.0'] _LOGGER = logging.getLogger(__name__) -DEFAULT_PORT = 80 +CONF_RESOLUTION = 'resolution' + DEFAULT_NAME = 'Amcrest Camera' +DEFAULT_PORT = 80 +DEFAULT_RESOLUTION = 'high' NOTIFICATION_ID = 'amcrest_notification' NOTIFICATION_TITLE = 'Amcrest Camera Setup' +RESOLUTION_LIST = { + 'high': 0, + 'low': 1, +} + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_RESOLUTION, default=DEFAULT_RESOLUTION): + vol.All(vol.In(RESOLUTION_LIST)), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, }) @@ -64,13 +74,14 @@ class AmcrestCam(Camera): def __init__(self, device_info, data): """Initialize an Amcrest camera.""" super(AmcrestCam, self).__init__() - self._name = device_info.get(CONF_NAME) self._data = data + self._name = device_info.get(CONF_NAME) + self._resolution = RESOLUTION_LIST[device_info.get(CONF_RESOLUTION)] def camera_image(self): """Return a still image reponse from the camera.""" # Send the request to snap a picture and return raw jpg data - response = self._data.camera.snapshot() + response = self._data.camera.snapshot(channel=self._resolution) return response.data @property From dbb4e4c3fac75e819d5c9dc699847c245244438b Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Mon, 12 Dec 2016 19:05:38 +0100 Subject: [PATCH 090/141] [tellduslive] Upgrade requirement (#4865) --- homeassistant/components/tellduslive.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tellduslive.py b/homeassistant/components/tellduslive.py index cf62a28b552..b470ae7daec 100644 --- a/homeassistant/components/tellduslive.py +++ b/homeassistant/components/tellduslive.py @@ -17,7 +17,7 @@ import voluptuous as vol DOMAIN = 'tellduslive' -REQUIREMENTS = ['tellduslive==0.1.9'] +REQUIREMENTS = ['tellduslive==0.1.13'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index f9d1b36fb5f..3e95167c1ee 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -560,7 +560,7 @@ steamodd==4.21 tellcore-py==1.1.2 # homeassistant.components.tellduslive -tellduslive==0.1.9 +tellduslive==0.1.13 # homeassistant.components.sensor.temper temperusb==1.5.1 From 12f790c7cf9548a811baae3f5cad3b9d12b4da01 Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Tue, 13 Dec 2016 07:02:24 +0100 Subject: [PATCH 091/141] Display error message instead of exception (#4866) * Display error message instead of exception Display error message in log instead of stack trace. (Usually happens when a server is already running at the same port.) * Update __init__.py Better error handling when reading SSL certificate * Update __init__.py * Update __init__.py --- homeassistant/components/http/__init__.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index de864a0c193..bfc5d662105 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -288,10 +288,16 @@ class HomeAssistantWSGI(object): cors_added.add(route) if self.ssl_certificate: - context = ssl.SSLContext(SSL_VERSION) - context.options |= SSL_OPTS - context.set_ciphers(CIPHERS) - context.load_cert_chain(self.ssl_certificate, self.ssl_key) + try: + context = ssl.SSLContext(SSL_VERSION) + context.options |= SSL_OPTS + context.set_ciphers(CIPHERS) + context.load_cert_chain(self.ssl_certificate, self.ssl_key) + except OSError as error: + _LOGGER.error("Could not read SSL certificate from %s: %s", + self.ssl_certificate, error) + context = None + return else: context = None @@ -305,8 +311,12 @@ class HomeAssistantWSGI(object): self._handler = self.app.make_handler() - self.server = yield from self.hass.loop.create_server( - self._handler, self.server_host, self.server_port, ssl=context) + try: + self.server = yield from self.hass.loop.create_server( + self._handler, self.server_host, self.server_port, ssl=context) + except OSError as error: + _LOGGER.error("Failed to create HTTP server at port %d: %s", + self.server_port, error) self.app._frozen = False # pylint: disable=protected-access From eeb8bc391377c4f8a0422d3b2dc56f2ac420dad0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 12 Dec 2016 22:18:20 -0800 Subject: [PATCH 092/141] Fix dev tag detection in release script (#4873) --- script/release | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/script/release b/script/release index 40d906b17bf..43af9b92cb1 100755 --- a/script/release +++ b/script/release @@ -2,7 +2,15 @@ cd "$(dirname "$0")/.." -head -n 3 homeassistant/const.py | tail -n 1 | grep dev +head -n 5 homeassistant/const.py | tail -n 1 | grep PATCH_VERSION > /dev/null + +if [ $? -eq 1 ] +then + echo "Patch version not found on const.py line 5" + exit 1 +fi + +head -n 5 homeassistant/const.py | tail -n 1 | grep dev > /dev/null if [ $? -eq 0 ] then From acb841a1f4bf2507bbec4826ec5516e9c8c47d9c Mon Sep 17 00:00:00 2001 From: John Mihalic Date: Tue, 13 Dec 2016 02:10:16 -0500 Subject: [PATCH 093/141] Add Hikvision binary sensor component (#4825) * Add Hikvision binary sensor component * Simplify customize configuration * Add delay attribute * Remove use of threading timer, fix delay functionality --- .coveragerc | 1 + .../components/binary_sensor/hikvision.py | 262 ++++++++++++++++++ requirements_all.txt | 4 + 3 files changed, 267 insertions(+) create mode 100644 homeassistant/components/binary_sensor/hikvision.py diff --git a/.coveragerc b/.coveragerc index 4aae4cbc242..3168a20bd8c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -123,6 +123,7 @@ omit = homeassistant/components/binary_sensor/arest.py homeassistant/components/binary_sensor/concord232.py homeassistant/components/binary_sensor/flic.py + homeassistant/components/binary_sensor/hikvision.py homeassistant/components/binary_sensor/rest.py homeassistant/components/browser.py homeassistant/components/camera/amcrest.py diff --git a/homeassistant/components/binary_sensor/hikvision.py b/homeassistant/components/binary_sensor/hikvision.py new file mode 100644 index 00000000000..90d61cbf3b7 --- /dev/null +++ b/homeassistant/components/binary_sensor/hikvision.py @@ -0,0 +1,262 @@ +""" +Support for Hikvision event stream events represented as binary sensors. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.hikvision/ +""" +import logging +from datetime import timedelta +import voluptuous as vol + +from homeassistant.helpers.event import track_point_in_utc_time +from homeassistant.util.dt import utcnow +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, PLATFORM_SCHEMA) +import homeassistant.helpers.config_validation as cv +from homeassistant.const import ( + CONF_HOST, CONF_PORT, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, + CONF_SSL, EVENT_HOMEASSISTANT_STOP, ATTR_LAST_TRIP_TIME, CONF_CUSTOMIZE) + +REQUIREMENTS = ['pyhik==0.0.6', 'pydispatcher==2.0.5'] +_LOGGER = logging.getLogger(__name__) + +CONF_IGNORED = 'ignored' +CONF_DELAY = 'delay' + +DEFAULT_PORT = 80 +DEFAULT_IGNORED = False +DEFAULT_DELAY = 0 + +ATTR_DELAY = 'delay' + +SENSOR_CLASS_MAP = { + 'Motion': 'motion', + 'Line Crossing': 'motion', + 'IO Trigger': None, + 'Field Detection': 'motion', + 'Video Loss': None, + 'Tamper Detection': 'motion', + 'Shelter Alarm': None, + 'Disk Full': None, + 'Disk Error': None, + 'Net Interface Broken': 'connectivity', + 'IP Conflict': 'connectivity', + 'Illegal Access': None, + 'Video Mismatch': None, + 'Bad Video': None, + 'PIR Alarm': 'motion', + 'Face Detection': 'motion', +} + +CUSTOMIZE_SCHEMA = vol.Schema({ + vol.Optional(CONF_IGNORED, default=DEFAULT_IGNORED): cv.boolean, + vol.Optional(CONF_DELAY, default=DEFAULT_DELAY): cv.positive_int + }) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=None): cv.string, + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_SSL, default=False): cv.boolean, + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Optional(CONF_CUSTOMIZE, default={}): + vol.Schema({cv.string: CUSTOMIZE_SCHEMA}), +}) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Setup Hikvision binary sensor devices.""" + name = config.get(CONF_NAME) + host = config.get(CONF_HOST) + port = config.get(CONF_PORT) + username = config.get(CONF_USERNAME) + password = config.get(CONF_PASSWORD) + + customize = config.get(CONF_CUSTOMIZE) + + if config.get(CONF_SSL): + protocol = "https" + else: + protocol = "http" + + url = '{}://{}'.format(protocol, host) + + data = HikvisionData(hass, url, port, name, username, password) + + if data.sensors is None: + _LOGGER.error('Hikvision event stream has no data, unable to setup.') + return False + + entities = [] + + for sensor in data.sensors: + # Build sensor name, then parse customize config. + sensor_name = sensor.replace(' ', '_') + + custom = customize.get(sensor_name.lower(), {}) + ignore = custom.get(CONF_IGNORED) + delay = custom.get(CONF_DELAY) + + _LOGGER.debug('Entity: %s - %s, Options - Ignore: %s, Delay: %s', + data.name, sensor_name, ignore, delay) + if not ignore: + entities.append(HikvisionBinarySensor(hass, sensor, data, delay)) + + add_entities(entities) + + +class HikvisionData(object): + """Hikvision camera event stream object.""" + + def __init__(self, hass, url, port, name, username, password): + """Initialize the data oject.""" + from pyhik.hikvision import HikCamera + self._url = url + self._port = port + self._name = name + self._username = username + self._password = password + + # Establish camera + self._cam = HikCamera(self._url, self._port, + self._username, self._password) + + if self._name is None: + self._name = self._cam.get_name + + # Start event stream + self._cam.start_stream() + + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, self.stop_hik) + + def stop_hik(self, event): + """Shutdown Hikvision subscriptions and subscription thread on exit.""" + self._cam.disconnect() + + @property + def sensors(self): + """Return list of available sensors and their states.""" + return self._cam.current_event_states + + @property + def cam_id(self): + """Return camera id.""" + return self._cam.get_id + + @property + def name(self): + """Return camera name.""" + return self._name + + +class HikvisionBinarySensor(BinarySensorDevice): + """Representation of a Hikvision binary sensor.""" + + def __init__(self, hass, sensor, cam, delay): + """Initialize the binary_sensor.""" + from pydispatch import dispatcher + + self._hass = hass + self._cam = cam + self._name = self._cam.name + ' ' + sensor + self._id = self._cam.cam_id + '.' + sensor + self._sensor = sensor + + if delay is None: + self._delay = 0 + else: + self._delay = delay + + self._timer = None + + # Form signal for dispatcher + signal = 'ValueChanged.{}'.format(self._cam.cam_id) + + dispatcher.connect(self._update_callback, + signal=signal, + sender=self._sensor) + + def _sensor_state(self): + """Extract sensor state.""" + return self._cam.sensors[self._sensor][0] + + def _sensor_last_update(self): + """Extract sensor last update time.""" + return self._cam.sensors[self._sensor][3] + + @property + def name(self): + """Return the name of the Hikvision sensor.""" + return self._name + + @property + def unique_id(self): + """Return an unique ID.""" + return '{}.{}'.format(self.__class__, self._id) + + @property + def is_on(self): + """Return true if sensor is on.""" + return self._sensor_state() + + @property + def sensor_class(self): + """Return the class of this sensor, from SENSOR_CLASSES.""" + try: + return SENSOR_CLASS_MAP[self._sensor] + except KeyError: + # Sensor must be unknown to us, add as generic + return None + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attr = {} + attr[ATTR_LAST_TRIP_TIME] = self._sensor_last_update() + + if self._delay != 0: + attr[ATTR_DELAY] = self._delay + + return attr + + def _update_callback(self, signal, sender): + """Update the sensor's state, if needed.""" + _LOGGER.debug('Dispatcher callback, signal: %s, sender: %s', + signal, sender) + + if sender is not self._sensor: + return + + if self._delay > 0 and not self.is_on: + # Set timer to wait until updating the state + def _delay_update(now): + """Timer callback for sensor update.""" + _LOGGER.debug('%s Called delayed (%ssec) update.', + self._name, self._delay) + self.schedule_update_ha_state() + self._timer = None + + if self._timer is not None: + self._timer() + self._timer = None + + self._timer = track_point_in_utc_time( + self._hass, _delay_update, + utcnow() + timedelta(seconds=self._delay)) + + elif self._delay > 0 and self.is_on: + # For delayed sensors kill any callbacks on true events and update + if self._timer is not None: + self._timer() + self._timer = None + + self.schedule_update_ha_state() + + else: + self.schedule_update_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index 3e95167c1ee..799b2b29b11 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -387,6 +387,7 @@ pycmus==0.1.0 # homeassistant.components.envisalink # homeassistant.components.zwave +# homeassistant.components.binary_sensor.hikvision pydispatcher==2.0.5 # homeassistant.components.media_player.emby @@ -401,6 +402,9 @@ pyfttt==0.3 # homeassistant.components.remote.harmony pyharmony==1.0.12 +# homeassistant.components.binary_sensor.hikvision +pyhik==0.0.6 + # homeassistant.components.homematic pyhomematic==0.1.18 From 2dec38d8d4f2461448fc05de352e619bc09167dd Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 13 Dec 2016 08:23:08 +0100 Subject: [PATCH 094/141] TTS Component / Google speech platform (#4837) * TTS Component / Google speech platform * Change file backend handling / cache * Use mimetype / rename Provider function / allow cache on service call * Add a memcache for faster response * Add demo platform * First version of unittest * Address comments * improve error handling / address comments * Add google unittest & check http response code * Change url param handling * add test for other language * Change hash to sha256 for same hash on every os/hardware * add unittest for receive demo data * add test for error cases * Test case load from file to mem over aiohttp server * Use cache SpeechManager level, address other comments * Add service for clear cache * Update service.yaml * add support for spliting google message --- .../components/media_player/__init__.py | 2 +- homeassistant/components/tts/__init__.py | 421 ++++++++++++++++++ homeassistant/components/tts/demo.mp3 | Bin 0 -> 8256 bytes homeassistant/components/tts/demo.py | 29 ++ homeassistant/components/tts/google.py | 117 +++++ homeassistant/components/tts/services.yaml | 14 + requirements_all.txt | 3 + tests/components/tts/__init__.py | 1 + tests/components/tts/test_google.py | 199 +++++++++ tests/components/tts/test_init.py | 320 +++++++++++++ tests/test_util/aiohttp.py | 9 +- 11 files changed, 1110 insertions(+), 5 deletions(-) create mode 100644 homeassistant/components/tts/__init__.py create mode 100644 homeassistant/components/tts/demo.mp3 create mode 100644 homeassistant/components/tts/demo.py create mode 100644 homeassistant/components/tts/google.py create mode 100644 homeassistant/components/tts/services.yaml create mode 100644 tests/components/tts/__init__.py create mode 100644 tests/components/tts/test_google.py create mode 100644 tests/components/tts/test_init.py diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index fa2ecee4337..3dea75df874 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -162,7 +162,7 @@ MEDIA_PLAYER_MEDIA_SEEK_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ vol.Required(ATTR_MEDIA_CONTENT_TYPE): cv.string, vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string, - ATTR_MEDIA_ENQUEUE: cv.boolean, + vol.Optional(ATTR_MEDIA_ENQUEUE): cv.boolean, }) MEDIA_PLAYER_SELECT_SOURCE_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py new file mode 100644 index 00000000000..0e75de88cc5 --- /dev/null +++ b/homeassistant/components/tts/__init__.py @@ -0,0 +1,421 @@ +""" +Provide functionality to TTS. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/tts/ +""" +import asyncio +import logging +import hashlib +import mimetypes +import os +import re + +from aiohttp import web +import voluptuous as vol + +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.bootstrap import async_prepare_setup_platform +from homeassistant.core import callback +from homeassistant.config import load_yaml_config_file +from homeassistant.components.http import HomeAssistantView +from homeassistant.components.media_player import ( + SERVICE_PLAY_MEDIA, MEDIA_TYPE_MUSIC, ATTR_MEDIA_CONTENT_ID, + ATTR_MEDIA_CONTENT_TYPE, DOMAIN as DOMAIN_MP) +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import config_per_platform +import homeassistant.helpers.config_validation as cv + +DOMAIN = 'tts' +DEPENDENCIES = ['http'] + +_LOGGER = logging.getLogger(__name__) + +MEM_CACHE_FILENAME = 'filename' +MEM_CACHE_VOICE = 'voice' + +CONF_LANG = 'language' +CONF_CACHE = 'cache' +CONF_CACHE_DIR = 'cache_dir' +CONF_TIME_MEMORY = 'time_memory' + +DEFAULT_CACHE = True +DEFAULT_CACHE_DIR = "tts" +DEFAULT_LANG = 'en' +DEFAULT_TIME_MEMORY = 300 + +SERVICE_SAY = 'say' +SERVICE_CLEAR_CACHE = 'clear_cache' + +ATTR_MESSAGE = 'message' +ATTR_CACHE = 'cache' + +_RE_VOICE_FILE = re.compile(r"([a-f0-9]{40})_([a-z]+)\.[a-z0-9]{3,4}") + +PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_LANG, default=DEFAULT_LANG): cv.string, + vol.Optional(CONF_CACHE, default=DEFAULT_CACHE): cv.boolean, + vol.Optional(CONF_CACHE_DIR, default=DEFAULT_CACHE_DIR): cv.string, + vol.Optional(CONF_TIME_MEMORY, default=DEFAULT_TIME_MEMORY): + vol.All(vol.Coerce(int), vol.Range(min=60, max=57600)), +}) + + +SCHEMA_SERVICE_SAY = vol.Schema({ + vol.Required(ATTR_MESSAGE): cv.string, + vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, + vol.Optional(ATTR_CACHE): cv.boolean, +}) + +SCHEMA_SERVICE_CLEAR_CACHE = vol.Schema({}) + + +@asyncio.coroutine +def async_setup(hass, config): + """Setup TTS.""" + tts = SpeechManager(hass) + + try: + conf = config[DOMAIN][0] if len(config.get(DOMAIN, [])) > 0 else {} + use_cache = conf.get(CONF_CACHE, DEFAULT_CACHE) + cache_dir = conf.get(CONF_CACHE_DIR, DEFAULT_CACHE_DIR) + time_memory = conf.get(CONF_TIME_MEMORY, DEFAULT_LANG) + + yield from tts.async_init_cache(use_cache, cache_dir, time_memory) + except (HomeAssistantError, KeyError) as err: + _LOGGER.error("Error on cache init %s", err) + return False + + hass.http.register_view(TextToSpeechView(tts)) + + descriptions = yield from hass.loop.run_in_executor( + None, load_yaml_config_file, + os.path.join(os.path.dirname(__file__), 'services.yaml')) + + @asyncio.coroutine + def async_setup_platform(p_type, p_config, disc_info=None): + """Setup a tts platform.""" + platform = yield from async_prepare_setup_platform( + hass, config, DOMAIN, p_type) + if platform is None: + return + + try: + if hasattr(platform, 'async_get_engine'): + provider = yield from platform.async_get_engine( + hass, p_config) + else: + provider = yield from hass.loop.run_in_executor( + None, platform.get_engine, hass, p_config) + + if provider is None: + _LOGGER.error('Error setting up platform %s', p_type) + return + + tts.async_register_engine(p_type, provider, p_config) + except Exception: # pylint: disable=broad-except + _LOGGER.exception('Error setting up platform %s', p_type) + return + + @asyncio.coroutine + def async_say_handle(service): + """Service handle for say.""" + entity_ids = service.data.get(ATTR_ENTITY_ID) + message = service.data.get(ATTR_MESSAGE) + cache = service.data.get(ATTR_CACHE) + + try: + url = yield from tts.async_get_url( + p_type, message, cache=cache) + except HomeAssistantError as err: + _LOGGER.error("Error on init tts: %s", err) + return + + data = { + ATTR_MEDIA_CONTENT_ID: url, + ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_MUSIC, + } + + if entity_ids: + data[ATTR_ENTITY_ID] = entity_ids + + yield from hass.services.async_call( + DOMAIN_MP, SERVICE_PLAY_MEDIA, data, blocking=True) + + hass.services.async_register( + DOMAIN, "{}_{}".format(p_type, SERVICE_SAY), async_say_handle, + descriptions.get(SERVICE_SAY), schema=SCHEMA_SERVICE_SAY) + + setup_tasks = [async_setup_platform(p_type, p_config) for p_type, p_config + in config_per_platform(config, DOMAIN)] + + if setup_tasks: + yield from asyncio.wait(setup_tasks, loop=hass.loop) + + @asyncio.coroutine + def async_clear_cache_handle(service): + """Handle clear cache service call.""" + yield from tts.async_clear_cache() + + hass.services.async_register( + DOMAIN, SERVICE_CLEAR_CACHE, async_clear_cache_handle, + descriptions.get(SERVICE_CLEAR_CACHE), schema=SERVICE_CLEAR_CACHE) + + return True + + +class SpeechManager(object): + """Representation of a speech store.""" + + def __init__(self, hass): + """Initialize a speech store.""" + self.hass = hass + self.providers = {} + + self.use_cache = True + self.cache_dir = None + self.time_memory = None + self.file_cache = {} + self.mem_cache = {} + + @asyncio.coroutine + def async_init_cache(self, use_cache, cache_dir, time_memory): + """Init config folder and load file cache.""" + self.use_cache = use_cache + self.time_memory = time_memory + + def init_tts_cache_dir(cache_dir): + """Init cache folder.""" + if not os.path.isabs(cache_dir): + cache_dir = self.hass.config.path(cache_dir) + if not os.path.isdir(cache_dir): + _LOGGER.info("Create cache dir %s.", cache_dir) + os.mkdir(cache_dir) + return cache_dir + + try: + self.cache_dir = yield from self.hass.loop.run_in_executor( + None, init_tts_cache_dir, cache_dir) + except OSError as err: + raise HomeAssistantError( + "Can't init cache dir {}".format(err)) + + def get_cache_files(): + """Return a dict of given engine files.""" + cache = {} + + folder_data = os.listdir(self.cache_dir) + for file_data in folder_data: + record = _RE_VOICE_FILE.match(file_data) + if record: + key = "{}_{}".format(record.group(1), record.group(2)) + cache[key.lower()] = file_data.lower() + return cache + + try: + cache_files = yield from self.hass.loop.run_in_executor( + None, get_cache_files) + except OSError as err: + raise HomeAssistantError( + "Can't read cache dir {}".format(err)) + + if cache_files: + self.file_cache.update(cache_files) + + @asyncio.coroutine + def async_clear_cache(self): + """Read file cache and delete files.""" + self.mem_cache = {} + + def remove_files(): + """Remove files from filesystem.""" + for _, filename in self.file_cache.items(): + try: + os.remove(os.path.join(self.cache_dir), filename) + except OSError: + pass + + yield from self.hass.loop.run_in_executor(None, remove_files) + self.file_cache = {} + + @callback + def async_register_engine(self, engine, provider, config): + """Register a TTS provider.""" + provider.hass = self.hass + provider.language = config.get(CONF_LANG) + self.providers[engine] = provider + + @asyncio.coroutine + def async_get_url(self, engine, message, cache=None): + """Get URL for play message. + + This method is a coroutine. + """ + msg_hash = hashlib.sha1(bytes(message, 'utf-8')).hexdigest() + key = ("{}_{}".format(msg_hash, engine)).lower() + use_cache = cache if cache is not None else self.use_cache + + # is speech allready in memory + if key in self.mem_cache: + filename = self.mem_cache[key][MEM_CACHE_FILENAME] + # 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(engine, key)) + # load speech from provider into memory + else: + filename = yield from self.async_get_tts_audio( + engine, key, message, use_cache) + + return "{}/api/tts_proxy/{}".format( + self.hass.config.api.base_url, filename) + + @asyncio.coroutine + def async_get_tts_audio(self, engine, key, message, cache): + """Receive TTS and store for view in cache. + + This method is a coroutine. + """ + provider = self.providers[engine] + extension, data = yield from provider.async_get_tts_audio(message) + + if data is None or extension is None: + raise HomeAssistantError( + "No TTS from {} for '{}'".format(engine, message)) + + # create file infos + filename = ("{}.{}".format(key, extension)).lower() + + # save to memory + self._async_store_to_memcache(key, filename, data) + + if cache: + self.hass.async_add_job( + self.async_save_tts_audio(key, filename, data)) + + return filename + + @asyncio.coroutine + def async_save_tts_audio(self, key, filename, data): + """Store voice data to file and file_cache. + + This method is a coroutine. + """ + voice_file = os.path.join(self.cache_dir, filename) + + def save_speech(): + """Store speech to filesystem.""" + with open(voice_file, 'wb') as speech: + speech.write(data) + + try: + yield from self.hass.loop.run_in_executor(None, save_speech) + self.file_cache[key] = filename + except OSError: + _LOGGER.error("Can't write %s", filename) + + @asyncio.coroutine + def async_file_to_mem(self, engine, key): + """Load voice from file cache into memory. + + This method is a coroutine. + """ + filename = self.file_cache.get(key) + if not filename: + raise HomeAssistantError("Key {} not in file cache!".format(key)) + + voice_file = os.path.join(self.cache_dir, filename) + + def load_speech(): + """Load a speech from filesystem.""" + with open(voice_file, 'rb') as speech: + return speech.read() + + try: + data = yield from self.hass.loop.run_in_executor(None, load_speech) + except OSError: + raise HomeAssistantError("Can't read {}".format(voice_file)) + + self._async_store_to_memcache(key, filename, data) + + @callback + def _async_store_to_memcache(self, key, filename, data): + """Store data to memcache and set timer to remove it.""" + self.mem_cache[key] = { + MEM_CACHE_FILENAME: filename, + MEM_CACHE_VOICE: data, + } + + @callback + def async_remove_from_mem(): + """Cleanup memcache.""" + self.mem_cache.pop(key) + + self.hass.loop.call_later(self.time_memory, async_remove_from_mem) + + @asyncio.coroutine + def async_read_tts(self, filename): + """Read a voice file and return binary. + + This method is a coroutine. + """ + record = _RE_VOICE_FILE.match(filename.lower()) + if not record: + raise HomeAssistantError("Wrong tts file format!") + + key = "{}_{}".format(record.group(1), record.group(2)) + + if key not in self.mem_cache: + if key not in self.file_cache: + raise HomeAssistantError("%s not in cache!", key) + engine = record.group(2) + yield from self.async_file_to_mem(engine, key) + + content, _ = mimetypes.guess_type(filename) + return (content, self.mem_cache[key][MEM_CACHE_VOICE]) + + +class Provider(object): + """Represent a single provider.""" + + hass = None + language = DEFAULT_LANG + + def get_tts_audio(self, message): + """Load tts audio file from provider.""" + raise NotImplementedError() + + @asyncio.coroutine + def async_get_tts_audio(self, message): + """Load tts audio file from provider. + + Return a tuple of file extension and data as bytes. + + This method is a coroutine. + """ + extension, data = yield from self.hass.loop.run_in_executor( + None, self.get_tts_audio, message) + return (extension, data) + + +class TextToSpeechView(HomeAssistantView): + """TTS view to serve an speech audio.""" + + requires_auth = False + url = "/api/tts_proxy/{filename}" + name = "api:tts:speech" + + def __init__(self, tts): + """Initialize a tts view.""" + self.tts = tts + + @asyncio.coroutine + def get(self, request, filename): + """Start a get request.""" + try: + content, data = yield from self.tts.async_read_tts(filename) + except HomeAssistantError as err: + _LOGGER.error("Error on load tts: %s", err) + return web.Response(status=404) + + return web.Response(body=data, content_type=content) diff --git a/homeassistant/components/tts/demo.mp3 b/homeassistant/components/tts/demo.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..f34241c769856718331a5e523f7d9b8b026a2c30 GIT binary patch literal 8256 zcmezW+2sg>;KpwX3@47v;Nz_j|ETR-?wP{6LZXU|og;S3lZMnQi(2wu*8cv_d2dsA zr~kh>K5Nu3dtbhK`TyVl_kZo=Vr#n4K9@!F-lG41*c8<5S1>MgX9;Fw<(WF;Oq{^67BSMQ(qb@pF%>%LJI zi~sar`yRNQ{i}Fic<%2BllT7zfz^vwlsEkU|NqNckFu!C?F??powFNc;z8!~if(*X z!0?!B#x{$%V2<9NIc(XVRykhqOuE)kBx_#q<5SvdeUlUwlVg(`j|9F}XWe&N-F|i) zyP3PH7lZNCx%>bB{Qmd<#cdXi7dm9N{{R2CrY(171KOXN`HtFuUA^i6wU;na6c9Y%yuKm5`{ncOf ze-Bm8Uj6fDXPM+=<$91W{(me^d-{KwAS3&Zz%9Q!^-@6Q^NJJ}En&D6FlA}0x8~cv ziCfpO-b&igyZ@O2kM#!$?#%9)5^IxOTNxc9l9CuIo^NcO_n4L6#i2&L$GBPbi^%$? z@8S!+1UT3%?0-4b1>Ha9zQO29(9u(E_V-0Dg3RX=c{y(fLyg#!1h>W+VyAN_wf*X! zYNqU+KclDdm6qtkPu4s=6`2wId_G%*+Rw>p@_#?r@n-cy@jn;;&y4;qy-#yX?IWT0 z0diqw=qF^8#aFNE%tPWz>NIO52} zTIUsIW(yC!ikuMA@;2g~v}ll0Rn#&I;lu}-u1ftyh5Hs2{px<7;wwK@{GLi>KZ}__u!Esp-Twdo ze;vKLH;uu&TXsg45F5yRF5$vS2N-f@Oqn{n;fHYJVUM4}E|wwdeyN7P$@_Da?cbiw z^AfbUINK-9D39BCia(oQW>wN;9?Q`Ee&;ezo?CzKd*iD#ABD!ERc~{gS3WoYtziAX ze#QlZ454*8D?#S-i*hbHz;O7+ln+rW)z3yOy#FW4)c%O}k?ZHS|NEQqyhLsFtEw33 zWH{a%2T5s+1T(m&$_nT>60qeJ@ zOcTGYb9Jrfysa;N*UEL*-TPX1tw%-0|Lp(&{}+7~ab!6%H&To{PChf*@{b1l!mfYq zKSAb;39j6Bgki>{DgOUgw|~0QEAgjgN=J-Yx`x~Tf;rmpW( zwIj=Zwc7vxzxuDg@3(?Y2g1(^XwKDScWGb2vEP7We_MW2{?U4tb~c|#2NiB#koii2 zovRKoOqejmL**iin95D1MN7iB>V*Gst>1Egt&G*t)2#cp)&KwXg?n4}evVc5|JzPr zR^yx1&FPntloXlv%fVOjN6EzW6){KWt@7A4H`LUm-{6^P$+gY~tJdcr^YsJ{O6_1c z6;6*?e3~7uTeotW zaltpOC1?ZR}^X@vTD(}!|drD|x z=I?)H7_lCEwU+f3$oxS0&q_6nvoaWet-h95aaJi- z*=dq!{mZCn`(h$B(t=e^mb;ot*Z-}X%fJ03Q^2p&j}KDxbmy0pUWTH%d0KR z1b^JV_o~67?RKH`n(4+7=ahP0TnSjoD6|k{zKZl@sWpr60Pd-ly6ZKwbL zP$~7Bzdx-wu|0K@M&Csv`MRL?a3(!Q6|7(E5l zw=H)HQupD@0GZD(8u@GmLuK2Hsx?MWPdxWaOIX0^;*_At%(rykGix8SpWUGm62Uzh z?`w8FPfPP(K21e>k;uDw9nYtp|IM~_6;C6d$mQT!NBbtcC^;Os_O9v5R0*cDw=TQ; zrQ03_na?An#J7RL;mC}h7!Jpi+S@t&4jz8dle=Tfgw>nR1hwwy*z)b>scw^PUk`-6 z>$$D7=hoZRi>;d2InMRjOV+M)v?{3$wT)y|YN|PW|6YvVCXp1Yvk@~Kx1|U=au$Qk z7ZW@sw1$D>*bIY${)TlSQli#p?#-L9eaf-Zn(N%tKF41<|2oyq+iGpv6P`e>lKq>6 zeb;Wic2eqH@@Xy0FH4{7fBjkHXi~(&F2(a~(hfc;VVth#x^0BplcvoSEC89WDA>fe zhJmAP#-BU;Z&m&=iuQP%7eCkZbj{kocM6>vZtOBFYl&y*UWM0UyWOfkme*I)MA?N6V_F}uBg$0_9b~?qkm0;F41zsV zdcGaCJ6jhfAGq!GG@aMSZCS5uId=H}@4f$8R&_txsPIKt{+iF6jE~X<{ny0rH!Dnc z?lgC*nxvPqDye4)gPe?wmo$50LPXJtriKvlz;Hp2rM_!G=35A9Y+AvPc#1R|tF# zUDQ`9QkA{vV*jhQ)fzLm8Qb5!@?YFIOF(vk4Y>Sw5^QW+z;MQE%Acnzr)~fFP*p}F zA#lG?lz7tuC8eGRNeRvk9-{smE4r9Hc(<}}pG%ASI@3N#vqbreVy&O%8trHFY{PkVOd`b+iJ@9tT6A8~R%KhOQf^cfzNmjswEs`ky$&$Dn9lDc~O zvV_7N}@c(d;dS)4P*o}!ndyDak%RXi{TqTAt z4RfY2O9)s7RqV(CnV%|naMlclD_&DPS>|&XR2b?BeAu)_I*P-r{8{c3d5i6VVo{$A zoD7AY{5~VUZ4nRm76m59S3XWf;Wf=q^~FJL!c|j)5AgN`C?t3|rq7mo(#EJ1toPb^ z#nKBUAoB}FPac}Ua8+cAxunHX5xwTMHM?4t9d9@-A9^dnZ-${D=gRAME$^Ivw#wP& z{P$LU`wtuAf3H2a@T!u}eVj zUmXmmFU>fg_M@ETR<~)@8CL(4*J5e6vr9F%XFU>G%d^|Zu{Nl-v`26&&*>?}aZ4T_ znXV>yNZ+JR=SA|~Et4la2d5M6MWTtYzzPPU3p82fWc-Vw-G%qpNcbrr~b zOTkskd>DfS7;Z^j5v@Gd!_;wi4cnVd`;(R`ZC_DtKc&fqWBGrpn_0!KJ3Ac`?b7n% z_2vpYt>1Ik$44wVuN7IgM1exzDe_E)6 zaYhEC?*AaZ7>6B~9p8BNA3v^@Dt!3*|I5B6&t9cFPSBgk>nGCFecX4>k^ldH3A^sK z%J;i<*2mXRsqu(s*HuHkiGgQXR?JXxIU%xPv(i(Aw=&op66Qo%I|fLb2HcqODr@`c_&?#rA~%v>dOA+^@%{33 z(JRr@^{Pzo%C~U{aqanT?wsC!U3_1DbA$cdS6iog{MHAVFDJOLYX!rBxT&21z4KRH zE(qe+KJ2^T!Np(urLU@OD`d9%*()ylYgWW2120ad)BBgdoO=JEhM9IyMczAkKc+YJ-CxVHc`6*Ij~m!Yu6f#Y^#;g%Ey2WPD;N$$Onp!gvhC2yo4f00 z_FUWZNb7pk%isIsj^z|GDc-;OEIO-A=we9kjC+&9%04*$J^0DqJT_+MFVRiWe|JZV zi5?exGmrhmO3&uRskK|(_nyD}UEBC?&RLN8=7J{=tzbAXW9s(5cDuLTZLk0L**N3c z>qPBU|2`fT+WNDj#71<*s&%j96}P|ne1B?O@SMjNnp+nVYsPMwRWEZcubK=p-$_t$+X{vQ6Q*)nTFpP6+UmY&+J(g%`o_{3`}e`E9X4gZ2ByJ(mAsNb9eUtf2%$f=`t>P6frYwq1X0#UCSo6Pkt3* z(J%hW&EZASZii?zAk%6Lw%L*_5bhB@5o_X(D%7iP1^PN9#x)&x@itZ5_cQtIDAu@f9d|y=HFT$GhDPw z-)N~{xSnbaGCxC5bK3-l(?_QCq%{1Q)w`Sk70M8vFL$x4eeJpQqgS2&{9>qb-TzK~Q>f>02eTLL6Af-2 zkaPC9c~GFu;a57p&FSf-tLHubr}WQg=aTqZvp6FTG`N(!D3ndUlFmiQiVZdw-gm_PBt+CwWRzWuGa zXx1Bt)L?<$-E4e9FWM9vc1VNF7Zh80X$Hf^8&mG?5Zdx7V(#a2XWuW}Iq&BAS=RI7 zh5GhX%S>0%^j)CiUMI8a;EyY*?dd#!&+a>!`^7UuB2ZRB*KF_Ccx$uG8!sl^|NsB? z?esrKa_`>^f2HVa#JLS*KBu7Mq9qI`CQW(2Gke$l3wGfrkG=o>{q3Lsi7%!Zgz<%B zSU!lnciL@|&}JsXj4!-is;X}-9{HWHo#_zJ?OgQii01$Qf4vSrJ1HMF_lsHK=XtpS zo6fD`UoO5lrT#X^d~u=3MJpH%%$O4A_AD)Fj%V18WgFhCV~=?)7Ip3QcikPmM@_Ei zZTkB4xX5d7rRitx)>-d8KQmM0TmApPrl)7BxM;2B64;itc!`fsUFNncHGjXp{#9Jx zvHxAJiy1imD+nH3w1(lpyeW1ouH?=27n_xHMD=E`+U0jvs~%rn8`|UE{oMc6>NhuT z)m3|n>#cnqCvW)Tc*9ERbF4=z&1WC@daq{l9NlTV_GH*U9s%T*y+C8I#q5oCrIhxd(5Z zik^BX%=Vh&kz00WuU&ofv_LRy$s)PSp?ei%bhg_0`)BF4fXt5&m^fpab1ReHSNgh$&JD#mL_4U=2Uz>Tu4U9}2nV7gNvt+jZdFsgd{I+0Mi;9()gNMwq z$k@Zb?Ra|*-4;9bf~WPX8QV&5Ew6SJml*ueTJQnAUXs4~^_ z)sl-TF*HkId)yYXX^+SaW) zYvvTXD~o*A&I>3|;}SfmFvXYg!v>J~wL%jo&0x3~H6@q7A%nB`2$OEW&s#hG|Nh^- zq9k`k;_9c$$B%Lq?=-Pr*`D%#;#xPGjcYsnWVBZNdC|kq!Kypmc>Pb$yk1Gp;?|7F zsI9-Q=0BIdI=SPnN{5Gi_QtLh|Wdak7i(ofiTTzIMP@rC+6*)gY`o_DbKsWo~@{b1m=i@SB< z>>LBXN7*a4gUy#TT2{kwnQI4=P*+vxwcub zd$Vji_rHAo<=?YZ3ENd$13v{Di+FI!@Jh&utpC^c|NnQdH*>vqOe*yZt-U{Gvhni? zQh^}zi=~2A{#Kv*-!HS|NZ4J&RgA`D(jmvRj2a64td_whM?iiO z+sQX81f|?!!uoIRzkh4}za{05PT9&7o;vXVvQgS*r4>HrVaq}0hYQX)=fQBXtzhk} z#SUxUNf?x9uq%WQdfQHEF#59WPrLtva~zTiOJ<}doewBn%q_^o4KhDjAfn8H;gE}m4VTVt(@P$K zYm$0)Uej3N?XNU#y600lN3rW0xFX-^8d^J=4moH9SFEn}kdIh7VY1JU zP4X9bx~1f%ehm8>cR*m}oIsJ5j@=;h>jf4V$uJx~#_)n`lH3GAD<4N+S7SX(OFh$7 z6aa`RAoKeL7WkfFFgT_{sgWqIL6|?Efq~hBfq{X6M&_>>H6JD9Asj^bkA@E MESSAGE_SIZE: + idx = fullstring.rfind(' ', 0, MESSAGE_SIZE) + return [fullstring[:idx]] + split_by_space(fullstring[idx:]) + else: + return [fullstring] + + msg_parts = [] + for part in parts: + msg_parts += split_by_space(part) + + return [msg for msg in msg_parts if len(msg) > 0] diff --git a/homeassistant/components/tts/services.yaml b/homeassistant/components/tts/services.yaml new file mode 100644 index 00000000000..aba1334da87 --- /dev/null +++ b/homeassistant/components/tts/services.yaml @@ -0,0 +1,14 @@ +say: + description: Say some things on a media player. + + fields: + entity_id: + description: Name(s) of media player entities + example: 'media_player.floor' + + message: + description: Text to speak on devices + example: 'My name is hanna' + +clear_cache: + description: Remove cache files and RAM cache. diff --git a/requirements_all.txt b/requirements_all.txt index 799b2b29b11..c85e3285e7e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -130,6 +130,9 @@ freesms==0.1.1 # homeassistant.components.conversation fuzzywuzzy==0.14.0 +# homeassistant.components.tts.google +gTTS-token==1.1.1 + # homeassistant.components.device_tracker.bluetooth_le_tracker # gattlib==0.20150805 diff --git a/tests/components/tts/__init__.py b/tests/components/tts/__init__.py new file mode 100644 index 00000000000..f5eb0731409 --- /dev/null +++ b/tests/components/tts/__init__.py @@ -0,0 +1 @@ +"""The tests for tts platforms.""" diff --git a/tests/components/tts/test_google.py b/tests/components/tts/test_google.py new file mode 100644 index 00000000000..623a96f1dfb --- /dev/null +++ b/tests/components/tts/test_google.py @@ -0,0 +1,199 @@ +"""The tests for the Google speech platform.""" +import asyncio +import os +import shutil +from unittest.mock import patch + +import homeassistant.components.tts as tts +from homeassistant.components.media_player import ( + SERVICE_PLAY_MEDIA, ATTR_MEDIA_CONTENT_ID, DOMAIN as DOMAIN_MP) +from homeassistant.bootstrap import setup_component + +from tests.common import ( + get_test_home_assistant, assert_setup_component, mock_service) + + +class TestTTSGooglePlatform(object): + """Test the Google speech component.""" + + def setup_method(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + self.url = "http://translate.google.com/translate_tts" + self.url_param = { + 'tl': 'en', + 'q': 'I%20person%20is%20on%20front%20of%20your%20door.', + 'tk': 5, + 'client': 'tw-ob', + 'textlen': 34, + 'total': 1, + 'idx': 0, + 'ie': 'UTF-8', + } + + def teardown_method(self): + """Stop everything that was started.""" + default_tts = self.hass.config.path(tts.DEFAULT_CACHE_DIR) + if os.path.isdir(default_tts): + shutil.rmtree(default_tts) + + self.hass.stop() + + def test_setup_component(self): + """Test setup component.""" + config = { + tts.DOMAIN: { + 'platform': 'google', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + @patch('gtts_token.gtts_token.Token.calculate_token', autospec=True, + return_value=5) + def test_service_say(self, mock_calculate, aioclient_mock): + """Test service call say.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + aioclient_mock.get( + self.url, params=self.url_param, status=200, content=b'test') + + config = { + tts.DOMAIN: { + 'platform': 'google', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'google_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert len(aioclient_mock.mock_calls) == 1 + assert calls[0].data[ATTR_MEDIA_CONTENT_ID].find(".mp3") != -1 + + @patch('gtts_token.gtts_token.Token.calculate_token', autospec=True, + return_value=5) + def test_service_say_german(self, mock_calculate, aioclient_mock): + """Test service call say with german code.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + self.url_param['tl'] = 'de' + aioclient_mock.get( + self.url, params=self.url_param, status=200, content=b'test') + + config = { + tts.DOMAIN: { + 'platform': 'google', + 'language': 'de', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'google_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert len(aioclient_mock.mock_calls) == 1 + + @patch('gtts_token.gtts_token.Token.calculate_token', autospec=True, + return_value=5) + def test_service_say_error(self, mock_calculate, aioclient_mock): + """Test service call say with http response 400.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + aioclient_mock.get( + self.url, params=self.url_param, status=400, content=b'test') + + config = { + tts.DOMAIN: { + 'platform': 'google', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'google_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 0 + assert len(aioclient_mock.mock_calls) == 1 + + @patch('gtts_token.gtts_token.Token.calculate_token', autospec=True, + return_value=5) + def test_service_say_timeout(self, mock_calculate, aioclient_mock): + """Test service call say with http timeout.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + aioclient_mock.get( + self.url, params=self.url_param, exc=asyncio.TimeoutError()) + + config = { + tts.DOMAIN: { + 'platform': 'google', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'google_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 0 + assert len(aioclient_mock.mock_calls) == 1 + + @patch('gtts_token.gtts_token.Token.calculate_token', autospec=True, + return_value=5) + def test_service_say_long_size(self, mock_calculate, aioclient_mock): + """Test service call say with a lot of text.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + self.url_param['total'] = 9 + self.url_param['q'] = "I%20person%20is%20on%20front%20of%20your%20door" + self.url_param['textlen'] = 33 + for idx in range(0, 9): + self.url_param['idx'] = idx + aioclient_mock.get( + self.url, params=self.url_param, status=200, content=b'test') + + config = { + tts.DOMAIN: { + 'platform': 'google', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'google_say', { + tts.ATTR_MESSAGE: ("I person is on front of your door." + "I person is on front of your door." + "I person is on front of your door." + "I person is on front of your door." + "I person is on front of your door." + "I person is on front of your door." + "I person is on front of your door." + "I person is on front of your door." + "I person is on front of your door."), + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert len(aioclient_mock.mock_calls) == 9 + assert calls[0].data[ATTR_MEDIA_CONTENT_ID].find(".mp3") != -1 diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py new file mode 100644 index 00000000000..fbdbddb8db5 --- /dev/null +++ b/tests/components/tts/test_init.py @@ -0,0 +1,320 @@ +"""The tests for the TTS component.""" +import os +import shutil +from unittest.mock import patch + +import requests + +import homeassistant.components.tts as tts +from homeassistant.components.tts.demo import DemoProvider +from homeassistant.components.media_player import ( + SERVICE_PLAY_MEDIA, MEDIA_TYPE_MUSIC, ATTR_MEDIA_CONTENT_ID, + ATTR_MEDIA_CONTENT_TYPE, DOMAIN as DOMAIN_MP) +from homeassistant.bootstrap import setup_component + +from tests.common import ( + get_test_home_assistant, assert_setup_component, mock_service) + + +class TestTTS(object): + """Test the Google speech component.""" + + def setup_method(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.demo_provider = DemoProvider() + self.default_tts_cache = self.hass.config.path(tts.DEFAULT_CACHE_DIR) + + def teardown_method(self): + """Stop everything that was started.""" + if os.path.isdir(self.default_tts_cache): + shutil.rmtree(self.default_tts_cache) + + self.hass.stop() + + def test_setup_component_demo(self): + """Setup the demo platform with defaults.""" + config = { + tts.DOMAIN: { + 'platform': 'demo', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + assert self.hass.services.has_service(tts.DOMAIN, 'demo_say') + assert self.hass.services.has_service(tts.DOMAIN, 'clear_cache') + + @patch('os.mkdir', side_effect=OSError(2, "No access")) + def test_setup_component_demo_no_access_cache_folder(self, mock_mkdir): + """Setup the demo platform with defaults.""" + config = { + tts.DOMAIN: { + 'platform': 'demo', + } + } + + assert not setup_component(self.hass, tts.DOMAIN, config) + + assert not self.hass.services.has_service(tts.DOMAIN, 'demo_say') + assert not self.hass.services.has_service(tts.DOMAIN, 'clear_cache') + + def test_setup_component_and_test_service(self): + """Setup the demo platform and call service.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + config = { + tts.DOMAIN: { + 'platform': 'demo', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'demo_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert calls[0].data[ATTR_MEDIA_CONTENT_TYPE] == MEDIA_TYPE_MUSIC + assert calls[0].data[ATTR_MEDIA_CONTENT_ID].find( + "/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd" + "_demo.mp3") \ + != -1 + assert os.path.isfile(os.path.join( + self.default_tts_cache, + "265944c108cbb00b2a621be5930513e03a0bb2cd_demo.mp3")) + + def test_setup_component_and_test_service_clear_cache(self): + """Setup the demo platform and call service clear cache.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + config = { + tts.DOMAIN: { + 'platform': 'demo', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'demo_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert os.path.isfile(os.path.join( + self.default_tts_cache, + "265944c108cbb00b2a621be5930513e03a0bb2cd_demo.mp3")) + + self.hass.services.call(tts.DOMAIN, tts.SERVICE_CLEAR_CACHE, {}) + self.hass.block_till_done() + + assert not os.path.isfile(os.path.join( + self.default_tts_cache, + "265944c108cbb00b2a621be5930513e03a0bb2cd_demo.mp3")) + + def test_setup_component_and_test_service_with_receive_voice(self): + """Setup the demo platform and call service and receive voice.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + config = { + tts.DOMAIN: { + 'platform': 'demo', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.start() + + self.hass.services.call(tts.DOMAIN, 'demo_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + req = requests.get(calls[0].data[ATTR_MEDIA_CONTENT_ID]) + _, demo_data = self.demo_provider.get_tts_audio("bla") + assert req.status_code == 200 + assert req.content == demo_data + + def test_setup_component_and_web_view_wrong_file(self): + """Setup the demo platform and receive wrong file from web.""" + config = { + tts.DOMAIN: { + 'platform': 'demo', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.start() + + url = ("{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd" + "_demo.mp3").format(self.hass.config.api.base_url) + + req = requests.get(url) + assert req.status_code == 404 + + def test_setup_component_and_web_view_wrong_filename(self): + """Setup the demo platform and receive wrong filename from web.""" + config = { + tts.DOMAIN: { + 'platform': 'demo', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.start() + + url = ("{}/api/tts_proxy/265944dsk32c1b2a621be5930510bb2cd" + "_demo.mp3").format(self.hass.config.api.base_url) + + req = requests.get(url) + assert req.status_code == 404 + + def test_setup_component_test_without_cache(self): + """Setup demo platform without cache.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + config = { + tts.DOMAIN: { + 'platform': 'demo', + 'cache': False, + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'demo_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert not os.path.isfile(os.path.join( + self.default_tts_cache, + "265944c108cbb00b2a621be5930513e03a0bb2cd_demo.mp3")) + + def test_setup_component_test_with_cache_call_service_without_cache(self): + """Setup demo platform with cache and call service without cache.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + config = { + tts.DOMAIN: { + 'platform': 'demo', + 'cache': True, + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'demo_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + tts.ATTR_CACHE: False, + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert not os.path.isfile(os.path.join( + self.default_tts_cache, + "265944c108cbb00b2a621be5930513e03a0bb2cd_demo.mp3")) + + def test_setup_component_test_with_cache_dir(self): + """Setup demo platform with cache and call service without cache.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + _, demo_data = self.demo_provider.get_tts_audio("bla") + cache_file = os.path.join( + self.default_tts_cache, + "265944c108cbb00b2a621be5930513e03a0bb2cd_demo.mp3") + + os.mkdir(self.default_tts_cache) + with open(cache_file, "wb") as voice_file: + voice_file.write(demo_data) + + config = { + tts.DOMAIN: { + 'platform': 'demo', + 'cache': True, + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + with patch('homeassistant.components.tts.demo.DemoProvider.' + 'get_tts_audio', return_value=None): + self.hass.services.call(tts.DOMAIN, 'demo_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert calls[0].data[ATTR_MEDIA_CONTENT_ID].find( + "/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd" + "_demo.mp3") \ + != -1 + + @patch('homeassistant.components.tts.demo.DemoProvider.get_tts_audio', + return_value=None) + def test_setup_component_test_with_error_on_get_tts(self, tts_mock): + """Setup demo platform with wrong get_tts_audio.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + config = { + tts.DOMAIN: { + 'platform': 'demo' + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'demo_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 0 + + def test_setup_component_load_cache_retrieve_without_mem_cache(self): + """Setup component and load cache and get without mem cache.""" + _, demo_data = self.demo_provider.get_tts_audio("bla") + cache_file = os.path.join( + self.default_tts_cache, + "265944c108cbb00b2a621be5930513e03a0bb2cd_demo.mp3") + + os.mkdir(self.default_tts_cache) + with open(cache_file, "wb") as voice_file: + voice_file.write(demo_data) + + config = { + tts.DOMAIN: { + 'platform': 'demo', + 'cache': True, + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.start() + + url = ("{}/api/tts_proxy/265944c108cbb00b2a621be5930513e03a0bb2cd" + "_demo.mp3").format(self.hass.config.api.base_url) + + req = requests.get(url) + assert req.status_code == 200 + assert req.content == demo_data diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index d6f0c80b435..4abf43a6e42 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -23,6 +23,7 @@ class AiohttpClientMocker: content=None, json=None, params=None, + headers=None, exc=None): """Mock a request.""" if json: @@ -65,8 +66,8 @@ class AiohttpClientMocker: return len(self.mock_calls) @asyncio.coroutine - def match_request(self, method, url, *, auth=None, params=None): \ - # pylint: disable=unused-variable + def match_request(self, method, url, *, auth=None, params=None, + headers=None): # pylint: disable=unused-variable """Match a request against pre-registered requests.""" for response in self._mocks: if response.match_request(method, url, params): @@ -76,8 +77,8 @@ class AiohttpClientMocker: raise self.exc return response - assert False, "No mock registered for {} {}".format(method.upper(), - url) + assert False, "No mock registered for {} {} {}".format(method.upper(), + url, params) class AiohttpClientMockResponse: From 72bd9fb5c7cc4c65fa74fe3bbfa120b7e7feefed Mon Sep 17 00:00:00 2001 From: Audun Ytterdal Date: Tue, 13 Dec 2016 17:53:42 +0100 Subject: [PATCH 095/141] Remove libtelldus-core-dev from Dockerfile (#4878) Remove unnecessary libtelldus-core-dev from Dockerfile . Ref https://github.com/home-assistant/home-assistant/pull/4680#issuecomment-266006310 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 02e3db616ae..634edb8af59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ RUN echo "deb http://download.telldus.com/debian/ stable main" >> /etc/apt/sourc wget -qO - http://download.telldus.se/debian/telldus-public.key | apt-key add - && \ apt-get update && \ apt-get install -y --no-install-recommends nmap net-tools cython3 libudev-dev sudo libglib2.0-dev bluetooth libbluetooth-dev \ - libtelldus-core2 libtelldus-core-dev && \ + libtelldus-core2 && \ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* COPY script/build_python_openzwave script/build_python_openzwave From e4b6395250022a9badb5d776d187499c23606a68 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 13 Dec 2016 17:55:13 +0100 Subject: [PATCH 096/141] Migrate REST switch to async (#4517) * Migrate REST switch to async * Update rest.py * Address comments from paulus --- homeassistant/components/switch/rest.py | 108 ++++++++--- tests/components/switch/test_rest.py | 228 +++++++++++++----------- tests/test_util/aiohttp.py | 5 +- 3 files changed, 204 insertions(+), 137 deletions(-) diff --git a/homeassistant/components/switch/rest.py b/homeassistant/components/switch/rest.py index 36674c16d16..cfa11897de9 100644 --- a/homeassistant/components/switch/rest.py +++ b/homeassistant/components/switch/rest.py @@ -4,23 +4,27 @@ Support for RESTful switches. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.rest/ """ +import asyncio import logging -import requests +import aiohttp +import async_timeout import voluptuous as vol from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) from homeassistant.const import (CONF_NAME, CONF_RESOURCE, CONF_TIMEOUT) +from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv from homeassistant.helpers.template import Template CONF_BODY_OFF = 'body_off' CONF_BODY_ON = 'body_on' +CONF_IS_ON_TEMPLATE = 'is_on_template' + DEFAULT_BODY_OFF = Template('OFF') DEFAULT_BODY_ON = Template('ON') DEFAULT_NAME = 'REST Switch' DEFAULT_TIMEOUT = 10 -CONF_IS_ON_TEMPLATE = 'is_on_template' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_RESOURCE): cv.url, @@ -35,13 +39,15 @@ _LOGGER = logging.getLogger(__name__) # pylint: disable=unused-argument, -def setup_platform(hass, config, add_devices, discovery_info=None): +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the RESTful switch.""" name = config.get(CONF_NAME) resource = config.get(CONF_RESOURCE) body_on = config.get(CONF_BODY_ON) body_off = config.get(CONF_BODY_OFF) is_on_template = config.get(CONF_IS_ON_TEMPLATE) + websession = async_get_clientsession(hass) if is_on_template is not None: is_on_template.hass = hass @@ -51,19 +57,24 @@ def setup_platform(hass, config, add_devices, discovery_info=None): body_off.hass = hass timeout = config.get(CONF_TIMEOUT) + req = None try: - requests.get(resource, timeout=10) - except requests.exceptions.MissingSchema: + with async_timeout.timeout(timeout, loop=hass.loop): + req = yield from websession.get(resource) + except (TypeError, ValueError): _LOGGER.error("Missing resource or schema in configuration. " "Add http:// or https:// to your URL") return False - except requests.exceptions.ConnectionError: + except (asyncio.TimeoutError, aiohttp.errors.ClientError): _LOGGER.error("No route to resource/endpoint: %s", resource) return False + finally: + if req is not None: + yield from req.release() - add_devices( - [RestSwitch( - hass, name, resource, body_on, body_off, is_on_template, timeout)]) + yield from async_add_devices( + [RestSwitch(hass, name, resource, body_on, body_off, + is_on_template, timeout)]) class RestSwitch(SwitchDevice): @@ -73,7 +84,7 @@ class RestSwitch(SwitchDevice): is_on_template, timeout): """Initialize the REST switch.""" self._state = None - self._hass = hass + self.hass = hass self._name = name self._resource = resource self._body_on = body_on @@ -91,46 +102,85 @@ class RestSwitch(SwitchDevice): """Return true if device is on.""" return self._state - def turn_on(self, **kwargs): + @asyncio.coroutine + def async_turn_on(self, **kwargs): """Turn the device on.""" - body_on_t = self._body_on.render() - request = requests.post( - self._resource, data=body_on_t, timeout=self._timeout) - if request.status_code == 200: + body_on_t = self._body_on.async_render() + websession = async_get_clientsession(self.hass) + + request = None + try: + with async_timeout.timeout(self._timeout, loop=self.hass.loop): + request = yield from websession.post( + self._resource, data=bytes(body_on_t, 'utf-8')) + except (asyncio.TimeoutError, aiohttp.errors.ClientError): + _LOGGER.error("Error while turn on %s", self._resource) + return + finally: + if request is not None: + yield from request.release() + + if request.status == 200: self._state = True else: _LOGGER.error("Can't turn on %s. Is resource/endpoint offline?", self._resource) - def turn_off(self, **kwargs): + @asyncio.coroutine + def async_turn_off(self, **kwargs): """Turn the device off.""" - body_off_t = self._body_off.render() - request = requests.post( - self._resource, data=body_off_t, timeout=self._timeout) - if request.status_code == 200: + body_off_t = self._body_off.async_render() + websession = async_get_clientsession(self.hass) + + request = None + try: + with async_timeout.timeout(self._timeout, loop=self.hass.loop): + request = yield from websession.post( + self._resource, data=bytes(body_off_t, 'utf-8')) + except (asyncio.TimeoutError, aiohttp.errors.ClientError): + _LOGGER.error("Error while turn off %s", self._resource) + return + finally: + if request is not None: + yield from request.release() + + if request.status == 200: self._state = False else: _LOGGER.error("Can't turn off %s. Is resource/endpoint offline?", self._resource) - def update(self): + @asyncio.coroutine + def async_update(self): """Get the latest data from REST API and update the state.""" - request = requests.get(self._resource, timeout=self._timeout) + websession = async_get_clientsession(self.hass) + + request = None + try: + with async_timeout.timeout(self._timeout, loop=self.hass.loop): + request = yield from websession.get(self._resource) + text = yield from request.text() + except (asyncio.TimeoutError, aiohttp.errors.ClientError): + _LOGGER.exception("Error while fetch data.") + return + finally: + if request is not None: + yield from request.release() if self._is_on_template is not None: - response = self._is_on_template.render_with_possible_json_value( - request.text, 'None') - response = response.lower() - if response == 'true': + text = self._is_on_template.async_render_with_possible_json_value( + text, 'None') + text = text.lower() + if text == 'true': self._state = True - elif response == 'false': + elif text == 'false': self._state = False else: self._state = None else: - if request.text == self._body_on.template: + if text == self._body_on.template: self._state = True - elif request.text == self._body_off.template: + elif text == self._body_off.template: self._state = False else: self._state = None diff --git a/tests/components/switch/test_rest.py b/tests/components/switch/test_rest.py index dc6c58db928..38ddad5e9a2 100644 --- a/tests/components/switch/test_rest.py +++ b/tests/components/switch/test_rest.py @@ -1,76 +1,83 @@ """The tests for the REST switch platform.""" -import unittest -from unittest.mock import patch +import asyncio -import pytest -import requests -from requests.exceptions import Timeout -import requests_mock +import aiohttp import homeassistant.components.switch.rest as rest from homeassistant.bootstrap import setup_component +from homeassistant.util.async import run_coroutine_threadsafe +from homeassistant.helpers.template import Template from tests.common import get_test_home_assistant, assert_setup_component -class TestRestSwitchSetup(unittest.TestCase): +class TestRestSwitchSetup: """Tests for setting up the REST switch platform.""" - def setUp(self): + def setup_method(self): """Setup things to be run when tests are started.""" self.hass = get_test_home_assistant() - def tearDown(self): + def teardown_method(self): """Stop everything that was started.""" self.hass.stop() def test_setup_missing_config(self): """Test setup with configuration missing required entries.""" - self.assertFalse(rest.setup_platform(self.hass, { - 'platform': 'rest' - }, None)) + assert not run_coroutine_threadsafe( + rest.async_setup_platform(self.hass, { + 'platform': 'rest' + }, None), + self.hass.loop + ).result() def test_setup_missing_schema(self): """Test setup with resource missing schema.""" - self.assertFalse(rest.setup_platform(self.hass, { - 'platform': 'rest', - 'resource': 'localhost' - }, None)) + assert not run_coroutine_threadsafe( + rest.async_setup_platform(self.hass, { + 'platform': 'rest', + 'resource': 'localhost' + }, None), + self.hass.loop + ).result() - @patch('requests.get', side_effect=requests.exceptions.ConnectionError()) - def test_setup_failed_connect(self, mock_req): + def test_setup_failed_connect(self, aioclient_mock): """Test setup when connection error occurs.""" - self.assertFalse(rest.setup_platform(self.hass, { - 'platform': 'rest', - 'resource': 'http://localhost', - }, None)) - - @patch('requests.get', side_effect=Timeout()) - def test_setup_timeout(self, mock_req): - """Test setup when connection timeout occurs.""" - with self.assertRaises(Timeout): - rest.setup_platform(self.hass, { + aioclient_mock.get('http://localhost', exc=aiohttp.errors.ClientError) + assert not run_coroutine_threadsafe( + rest.async_setup_platform(self.hass, { 'platform': 'rest', 'resource': 'http://localhost', - }, None) + }, None), + self.hass.loop + ).result() - @requests_mock.Mocker() - def test_setup_minimum(self, mock_req): - """Test setup with minimum configuration.""" - mock_req.get('http://localhost', status_code=200) - self.assertTrue(setup_component(self.hass, 'switch', { - 'switch': { + def test_setup_timeout(self, aioclient_mock): + """Test setup when connection timeout occurs.""" + aioclient_mock.get('http://localhost', exc=asyncio.TimeoutError()) + assert not run_coroutine_threadsafe( + rest.async_setup_platform(self.hass, { 'platform': 'rest', - 'resource': 'http://localhost' - } - })) - self.assertEqual(1, mock_req.call_count) - assert_setup_component(1, 'switch') + 'resource': 'http://localhost', + }, None), + self.hass.loop + ).result() - @requests_mock.Mocker() - def test_setup(self, mock_req): + def test_setup_minimum(self, aioclient_mock): + """Test setup with minimum configuration.""" + aioclient_mock.get('http://localhost', status=200) + with assert_setup_component(1, 'switch'): + assert setup_component(self.hass, 'switch', { + 'switch': { + 'platform': 'rest', + 'resource': 'http://localhost' + } + }) + assert aioclient_mock.call_count == 1 + + def test_setup(self, aioclient_mock): """Test setup with valid configuration.""" - mock_req.get('localhost', status_code=200) - self.assertTrue(setup_component(self.hass, 'switch', { + aioclient_mock.get('http://localhost', status=200) + assert setup_component(self.hass, 'switch', { 'switch': { 'platform': 'rest', 'name': 'foo', @@ -78,111 +85,120 @@ class TestRestSwitchSetup(unittest.TestCase): 'body_on': 'custom on text', 'body_off': 'custom off text', } - })) - self.assertEqual(1, mock_req.call_count) + }) + assert aioclient_mock.call_count == 1 assert_setup_component(1, 'switch') -@pytest.mark.skip -class TestRestSwitch(unittest.TestCase): +class TestRestSwitch: """Tests for REST switch platform.""" - def setUp(self): + def setup_method(self): """Setup things to be run when tests are started.""" self.hass = get_test_home_assistant() self.name = 'foo' self.resource = 'http://localhost/' - self.body_on = 'on' - self.body_off = 'off' + self.body_on = Template('on', self.hass) + self.body_off = Template('off', self.hass) self.switch = rest.RestSwitch(self.hass, self.name, self.resource, - self.body_on, self.body_off) + self.body_on, self.body_off, None, 10) - def tearDown(self): + def teardown_method(self): """Stop everything that was started.""" self.hass.stop() def test_name(self): """Test the name.""" - self.assertEqual(self.name, self.switch.name) + assert self.name == self.switch.name def test_is_on_before_update(self): """Test is_on in initial state.""" - self.assertEqual(None, self.switch.is_on) + assert self.switch.is_on is None - @requests_mock.Mocker() - def test_turn_on_success(self, mock_req): + def test_turn_on_success(self, aioclient_mock): """Test turn_on.""" - mock_req.post(self.resource, status_code=200) - self.switch.turn_on() + aioclient_mock.post(self.resource, status=200) + run_coroutine_threadsafe( + self.switch.async_turn_on(), self.hass.loop).result() - self.assertEqual(self.body_on, mock_req.last_request.text) - self.assertEqual(True, self.switch.is_on) + assert self.body_on.template == \ + aioclient_mock.mock_calls[-1][2].decode() + assert self.switch.is_on - @requests_mock.Mocker() - def test_turn_on_status_not_ok(self, mock_req): + def test_turn_on_status_not_ok(self, aioclient_mock): """Test turn_on when error status returned.""" - mock_req.post(self.resource, status_code=500) - self.switch.turn_on() + aioclient_mock.post(self.resource, status=500) + run_coroutine_threadsafe( + self.switch.async_turn_on(), self.hass.loop).result() - self.assertEqual(self.body_on, mock_req.last_request.text) - self.assertEqual(None, self.switch.is_on) + assert self.body_on.template == \ + aioclient_mock.mock_calls[-1][2].decode() + assert self.switch.is_on is None - @patch('requests.post', side_effect=Timeout()) - def test_turn_on_timeout(self, mock_req): + def test_turn_on_timeout(self, aioclient_mock): """Test turn_on when timeout occurs.""" - with self.assertRaises(Timeout): - self.switch.turn_on() + aioclient_mock.post(self.resource, status=500) + run_coroutine_threadsafe( + self.switch.async_turn_on(), self.hass.loop).result() - @requests_mock.Mocker() - def test_turn_off_success(self, mock_req): + assert self.switch.is_on is None + + def test_turn_off_success(self, aioclient_mock): """Test turn_off.""" - mock_req.post(self.resource, status_code=200) - self.switch.turn_off() + aioclient_mock.post(self.resource, status=200) + run_coroutine_threadsafe( + self.switch.async_turn_off(), self.hass.loop).result() - self.assertEqual(self.body_off, mock_req.last_request.text) - self.assertEqual(False, self.switch.is_on) + assert self.body_off.template == \ + aioclient_mock.mock_calls[-1][2].decode() + assert not self.switch.is_on - @requests_mock.Mocker() - def test_turn_off_status_not_ok(self, mock_req): + def test_turn_off_status_not_ok(self, aioclient_mock): """Test turn_off when error status returned.""" - mock_req.post(self.resource, status_code=500) - self.switch.turn_off() + aioclient_mock.post(self.resource, status=500) + run_coroutine_threadsafe( + self.switch.async_turn_off(), self.hass.loop).result() - self.assertEqual(self.body_off, mock_req.last_request.text) - self.assertEqual(None, self.switch.is_on) + assert self.body_off.template == \ + aioclient_mock.mock_calls[-1][2].decode() + assert self.switch.is_on is None - @patch('requests.post', side_effect=Timeout()) - def test_turn_off_timeout(self, mock_req): + def test_turn_off_timeout(self, aioclient_mock): """Test turn_off when timeout occurs.""" - with self.assertRaises(Timeout): - self.switch.turn_on() + aioclient_mock.post(self.resource, exc=asyncio.TimeoutError()) + run_coroutine_threadsafe( + self.switch.async_turn_on(), self.hass.loop).result() - @requests_mock.Mocker() - def test_update_when_on(self, mock_req): + assert self.switch.is_on is None + + def test_update_when_on(self, aioclient_mock): """Test update when switch is on.""" - mock_req.get(self.resource, text=self.body_on) - self.switch.update() + aioclient_mock.get(self.resource, text=self.body_on.template) + run_coroutine_threadsafe( + self.switch.async_update(), self.hass.loop).result() - self.assertEqual(True, self.switch.is_on) + assert self.switch.is_on - @requests_mock.Mocker() - def test_update_when_off(self, mock_req): + def test_update_when_off(self, aioclient_mock): """Test update when switch is off.""" - mock_req.get(self.resource, text=self.body_off) - self.switch.update() + aioclient_mock.get(self.resource, text=self.body_off.template) + run_coroutine_threadsafe( + self.switch.async_update(), self.hass.loop).result() - self.assertEqual(False, self.switch.is_on) + assert not self.switch.is_on - @requests_mock.Mocker() - def test_update_when_unknown(self, mock_req): + def test_update_when_unknown(self, aioclient_mock): """Test update when unknown status returned.""" - mock_req.get(self.resource, text='unknown status') - self.switch.update() + aioclient_mock.get(self.resource, text='unknown status') + run_coroutine_threadsafe( + self.switch.async_update(), self.hass.loop).result() - self.assertEqual(None, self.switch.is_on) + assert self.switch.is_on is None - @patch('requests.get', side_effect=Timeout()) - def test_update_timeout(self, mock_req): + def test_update_timeout(self, aioclient_mock): """Test update when timeout occurs.""" - with self.assertRaises(Timeout): - self.switch.update() + aioclient_mock.get(self.resource, exc=asyncio.TimeoutError()) + run_coroutine_threadsafe( + self.switch.async_update(), self.hass.loop).result() + + assert self.switch.is_on is None diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index 4abf43a6e42..c0ed579f197 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -20,6 +20,7 @@ class AiohttpClientMocker: auth=None, status=200, text=None, + data=None, content=None, json=None, params=None, @@ -66,12 +67,12 @@ class AiohttpClientMocker: return len(self.mock_calls) @asyncio.coroutine - def match_request(self, method, url, *, auth=None, params=None, + def match_request(self, method, url, *, data=None, auth=None, params=None, headers=None): # pylint: disable=unused-variable """Match a request against pre-registered requests.""" for response in self._mocks: if response.match_request(method, url, params): - self.mock_calls.append((method, url)) + self.mock_calls.append((method, url, data)) if self.exc: raise self.exc From 6da3e23436bdf6e7690696fcd80df9634b6f2f80 Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Tue, 13 Dec 2016 17:57:33 +0100 Subject: [PATCH 097/141] Update __init__.py (#4877) Cleaner exit by not throwing exception if server was not set during initialization of component (ref https://github.com/home-assistant/home-assistant/pull/4866) --- homeassistant/components/http/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index bfc5d662105..446b1f5f28b 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -323,10 +323,12 @@ class HomeAssistantWSGI(object): @asyncio.coroutine def stop(self): """Stop the wsgi server.""" - self.server.close() - yield from self.server.wait_closed() + if self.server: + self.server.close() + yield from self.server.wait_closed() yield from self.app.shutdown() - yield from self._handler.finish_connections(60.0) + if self._handler: + yield from self._handler.finish_connections(60.0) yield from self.app.cleanup() From dc551b825fb94fa6a708aed3524642073291065b Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 14 Dec 2016 05:04:40 +0100 Subject: [PATCH 098/141] =?UTF-8?q?Added=20a=20volume=20set=20option=20and?= =?UTF-8?q?=20autodiscovery=20functions=20to=20Denon=20AVR=20rece=E2=80=A6?= =?UTF-8?q?=20(#4845)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Volume Set option and autodiscovery functions to Denon AVR receivers * Corrected issues in SSDP discovery and in case no host could be discovered * Corrected discovery handling / added denonavr to discovery platform * No needless discoveries anymore / add_devices() with list instead of loop --- homeassistant/components/discovery.py | 3 +- .../components/media_player/denonavr.py | 78 ++++++++++++++++--- requirements_all.txt | 4 +- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 3c4dff6eac5..74dc5d69220 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.0'] +REQUIREMENTS = ['netdisco==0.8.1'] DOMAIN = 'discovery' @@ -36,6 +36,7 @@ SERVICE_HANDLERS = { 'yamaha': ('media_player', 'yamaha'), 'logitech_mediaserver': ('media_player', 'squeezebox'), 'directv': ('media_player', 'directv'), + 'denonavr': ('media_player', 'denonavr'), } CONFIG_SCHEMA = vol.Schema({ diff --git a/homeassistant/components/media_player/denonavr.py b/homeassistant/components/media_player/denonavr.py index 6db223bc6ec..5784fd6c829 100644 --- a/homeassistant/components/media_player/denonavr.py +++ b/homeassistant/components/media_player/denonavr.py @@ -13,26 +13,27 @@ from homeassistant.components.media_player import ( SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP, SUPPORT_SELECT_SOURCE, SUPPORT_PLAY_MEDIA, MEDIA_TYPE_CHANNEL, MediaPlayerDevice, PLATFORM_SCHEMA, SUPPORT_TURN_ON, - MEDIA_TYPE_MUSIC) + MEDIA_TYPE_MUSIC, SUPPORT_VOLUME_SET) from homeassistant.const import ( CONF_HOST, STATE_OFF, STATE_PLAYING, STATE_PAUSED, CONF_NAME, STATE_ON) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['denonavr==0.1.6'] +REQUIREMENTS = ['denonavr==0.2.2'] _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = None +KEY_DENON_CACHE = 'denonavr_hosts' SUPPORT_DENON = SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | \ SUPPORT_TURN_ON | SUPPORT_TURN_OFF | \ SUPPORT_SELECT_SOURCE | SUPPORT_PLAY_MEDIA | \ SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | \ - SUPPORT_NEXT_TRACK + SUPPORT_NEXT_TRACK | SUPPORT_VOLUME_SET PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_HOST): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) @@ -41,11 +42,53 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Denon platform.""" import denonavr - receiver = denonavr.DenonAVR(config.get(CONF_HOST), config.get(CONF_NAME)) + # Initialize list with receivers to be started + receivers = [] - add_devices([DenonDevice(receiver)]) - _LOGGER.info("Denon receiver at host %s initialized", - config.get(CONF_HOST)) + cache = hass.data.get(KEY_DENON_CACHE) + if cache is None: + cache = hass.data[KEY_DENON_CACHE] = set() + + # Start assignment of host and name + # 1. option: manual setting + if config.get(CONF_HOST) is not None: + host = config.get(CONF_HOST) + name = config.get(CONF_NAME) + # Check if host not in cache, append it and save for later starting + if host not in cache: + cache.add(host) + receivers.append( + DenonDevice(denonavr.DenonAVR(host, name))) + _LOGGER.info("Denon receiver at host %s initialized", host) + # 2. option: discovery using netdisco + if discovery_info is not None: + host = discovery_info[0] + name = discovery_info[1] + # Check if host not in cache, append it and save for later starting + if host not in cache: + cache.add(host) + receivers.append( + DenonDevice(denonavr.DenonAVR(host, name))) + _LOGGER.info("Denon receiver at host %s initialized", host) + # 3. option: discovery using denonavr library + if config.get(CONF_HOST) is None and discovery_info is None: + d_receivers = denonavr.discover() + # More than one receiver could be discovered by that method + if d_receivers is not None: + for d_receiver in d_receivers: + host = d_receiver["host"] + name = d_receiver["friendlyName"] + # Check if host not in cache, append it and save for later + # starting + if host not in cache: + cache.add(host) + receivers.append( + DenonDevice(denonavr.DenonAVR(host, name))) + _LOGGER.info("Denon receiver at host %s initialized", host) + + # Add all freshly discovered receivers + if receivers: + add_devices(receivers) class DenonDevice(MediaPlayerDevice): @@ -107,7 +150,8 @@ class DenonDevice(MediaPlayerDevice): @property def volume_level(self): """Volume level of the media player (0..1).""" - # Volume is send in a format like -50.0. Minimum is around -80.0 + # Volume is sent in a format like -50.0. Minimum is -80.0, + # maximum is 18.0 return (float(self._volume) + 80) / 100 @property @@ -240,6 +284,22 @@ class DenonDevice(MediaPlayerDevice): """Volume down media player.""" return self._receiver.volume_down() + def set_volume_level(self, volume): + """Set volume level, range 0..1.""" + # Volume has to be sent in a format like -50.0. Minimum is -80.0, + # maximum is 18.0 + volume_denon = float((volume * 100) - 80) + if volume_denon > 18: + volume_denon = float(18) + try: + if self._receiver.set_volume(volume_denon): + self._volume = volume_denon + return True + else: + return False + except ValueError: + return False + def mute_volume(self, mute): """Send mute command.""" return self._receiver.mute(mute) diff --git a/requirements_all.txt b/requirements_all.txt index c85e3285e7e..924f534145d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -76,7 +76,7 @@ colorlog>2.1,<3 concord232==0.14 # homeassistant.components.media_player.denonavr -denonavr==0.1.6 +denonavr==0.2.2 # homeassistant.components.media_player.directv directpy==0.1 @@ -302,7 +302,7 @@ mficlient==0.3.0 miflora==0.1.13 # homeassistant.components.discovery -netdisco==0.8.0 +netdisco==0.8.1 # homeassistant.components.sensor.neurio_energy neurio==0.2.10 From 570cfc60c54ea073ada7d157e4f6b19950eb6b34 Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Wed, 14 Dec 2016 07:58:43 +0100 Subject: [PATCH 099/141] bugfix: is_on is a property (#4889) --- homeassistant/components/switch/tellduslive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/switch/tellduslive.py b/homeassistant/components/switch/tellduslive.py index b1450de6c5e..5f3901d79b8 100644 --- a/homeassistant/components/switch/tellduslive.py +++ b/homeassistant/components/switch/tellduslive.py @@ -28,7 +28,7 @@ class TelldusLiveSwitch(TelldusLiveEntity, ToggleEntity): @property def is_on(self): """Return true if switch is on.""" - return self.device.is_on() + return self.device.is_on def turn_on(self, **kwargs): """Turn the switch on.""" From 7ca025f653a3bfe008bf1d3ef7fdb17b3a429fcf Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Wed, 14 Dec 2016 02:01:14 -0500 Subject: [PATCH 100/141] Fixes issues #4844 to avoid traceback when self.rest.data is None (#4886) 6-12-09 18:12:30 homeassistant.core: Error doing job: Task exception was never retrieved Traceback (most recent call last): File "/usr/lib/python3.4/asyncio/tasks.py", line 237, in _step result = next(coro) File "/srv/hass/hass_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 386, in _update_entity_states yield from update_coro File "/srv/hass/hass_venv/lib/python3.4/site-packages/homeassistant/helpers/entity.py", line 240, in async_update_ha_state self._attr_setter('entity_picture', str, ATTR_ENTITY_PICTURE, attr) File "/srv/hass/hass_venv/lib/python3.4/site-packages/homeassistant/helpers/entity.py", line 307, in _attr_setter value = getattr(self, name) File "/srv/hass/hass_venv/lib/python3.4/site-packages/homeassistant/components/sensor/wunderground.py", line 176, in entity_picture url = self.rest.data['icon_url'] TypeError: 'NoneType' object is not subscriptable --- homeassistant/components/sensor/wunderground.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/wunderground.py b/homeassistant/components/sensor/wunderground.py index 2f6558cd9da..67e19f225d5 100644 --- a/homeassistant/components/sensor/wunderground.py +++ b/homeassistant/components/sensor/wunderground.py @@ -196,7 +196,7 @@ class WUndergroundSensor(Entity): @property def entity_picture(self): """Return the entity picture.""" - if self._condition == 'weather': + if self.rest.data and self._condition == 'weather': url = self.rest.data['icon_url'] return re.sub(r'^http://', 'https://', url, flags=re.IGNORECASE) From da6bdf275e79b82c4eeaac3662db9a05deb3d465 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Dec 2016 23:29:54 -0800 Subject: [PATCH 101/141] Update frontend --- homeassistant/components/frontend/version.py | 6 +++--- .../components/frontend/www_static/core.js | 8 ++++---- .../components/frontend/www_static/core.js.gz | Bin 33524 -> 32904 bytes .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 130643 -> 130940 bytes .../www_static/home-assistant-polymer | 2 +- .../panels/ha-panel-dev-service.html | 2 +- .../panels/ha-panel-dev-service.html.gz | Bin 17764 -> 17796 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2323 -> 2326 bytes 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index e6211c145e2..f316a07dab9 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -1,13 +1,13 @@ """DO NOT MODIFY. Auto-generated by script/fingerprint_frontend.""" FINGERPRINTS = { - "core.js": "5dfb2d3e567fad37af0321d4b29265ed", - "frontend.html": "ac15b11435132aab3da592f9e7b05400", + "core.js": "ad1ebcd0614c98a390d982087a7ca75c", + "frontend.html": "920bb20410f9a1b8458600b15a1d40ae", "mdi.html": "46a76f877ac9848899b8ed382427c16f", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "c2d5ec676be98d4474d19f94d0262c1e", "panels/ha-panel-dev-info.html": "a9c07bf281fe9791fb15827ec1286825", - "panels/ha-panel-dev-service.html": "20420e2387fd93db53c8d778097e3d59", + "panels/ha-panel-dev-service.html": "ac74f7ce66fd7136d25c914ea12f4351", "panels/ha-panel-dev-state.html": "65e5f791cc467561719bf591f1386054", "panels/ha-panel-dev-template.html": "7d744ab7f7c08b6d6ad42069989de400", "panels/ha-panel-history.html": "efe1bcdd7733b09e55f4f965d171c295", diff --git a/homeassistant/components/frontend/www_static/core.js b/homeassistant/components/frontend/www_static/core.js index a70b70d2fd8..6cab0b713f3 100644 --- a/homeassistant/components/frontend/www_static/core.js +++ b/homeassistant/components/frontend/www_static/core.js @@ -1,4 +1,4 @@ -!(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(Mo.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 Qr.getInitialState()}function St(t,e){var n=e.date,r=e.stateHistory;return 0===r.length?t.set(n,$r({})):t.withMutations((function(t){r.forEach((function(e){return t.setIn([n,e[0].entity_id],$r(e.map(In.fromJSON)))}))}))}function Et(){return ti.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,ii(e.map(In.fromJSON)))}))}))}function It(){return oi.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(si,r)}))}function wt(){return ci.getInitialState()}function Tt(t,e){t.dispatch(Wr.ENTITY_HISTORY_DATE_SELECTED,{date:e})}function At(t,e){void 0===e&&(e=null),t.dispatch(Wr.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(Wr.RECENT_ENTITY_HISTORY_FETCH_SUCCESS,{stateHistory:e})}),(function(){return t.dispatch(Wr.RECENT_ENTITY_HISTORY_FETCH_ERROR,{})}))}function Ct(t,e){return t.dispatch(Wr.ENTITY_HISTORY_FETCH_START,{date:e}),on(t,"GET","history/period/"+e).then((function(n){return t.dispatch(Wr.ENTITY_HISTORY_FETCH_SUCCESS,{date:e,stateHistory:n})}),(function(){return t.dispatch(Wr.ENTITY_HISTORY_FETCH_ERROR,{})}))}function Dt(t){var e=t.evaluate(li);return Ct(t,e)}function zt(t){t.registerStores({currentEntityHistoryDate:Qr,entityHistory:ti,isLoadingEntityHistory:ni,recentEntityHistory:oi,recentEntityHistoryUpdated:ci})}function Rt(t){t.registerStores({moreInfoEntityId:Yr})}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=fo[t.hassId];e&&(e.scheduleHealthCheck.clear(),e.conn.close(),fo[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(Mo.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()}),so);r(),e.socket.addEventListener("message",r),fo[t.hassId]={conn:e,scheduleHealthCheck:r},co.forEach((function(n){return e.subscribeEvents(ao.bind(null,t),n)})),t.batch((function(){t.dispatch(Ye.STREAM_START),n&&io.fetchAll(t)})),e.addEventListener("disconnected",(function(){t.dispatch(Ye.STREAM_ERROR)})),e.addEventListener("ready",(function(){t.batch((function(){t.dispatch(Ye.STREAM_START),io.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}),io.fetchAll(t).then((function(){t.dispatch(Ue.VALID_AUTH_TOKEN,{authToken:e,host:i,rememberAuth:r}),vo.start(t,{syncOnInitialConnect:!1})}),(function(e){void 0===e&&(e={});var n=e.message;void 0===n&&(n=mo),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 Uo({debug:!1});return t.hassId=Ho++,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 xo(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 Jo.getInitialState()}function ue(t,e){var n=e.date,r=e.entries;return t.set(n,eu(r.map($o.fromJSON)))}function ae(){return nu.getInitialState()}function se(t,e){var n=e.date;return t.set(n,(new Date).getTime())}function ce(){return ou.getInitialState()}function fe(t,e){t.dispatch(Bo.LOGBOOK_DATE_SELECTED,{date:e})}function he(t,e){t.dispatch(Bo.LOGBOOK_ENTRIES_FETCH_START,{date:e}),on(t,"GET","logbook/"+e).then((function(n){return t.dispatch(Bo.LOGBOOK_ENTRIES_FETCH_SUCCESS,{date:e,entries:n})}),(function(){return t.dispatch(Bo.LOGBOOK_ENTRIES_FETCH_ERROR,{})}))}function le(t){return!t||(new Date).getTime()-t>su}function pe(t){t.registerStores({currentLogbookDate:Jo,isLoadingLogbookEntries:Xo,logbookEntries:nu,logbookEntriesUpdated:ou})}function _e(t){return t.set("active",!0)}function de(t){return t.set("active",!1)}function ve(){return Su.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(yu.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),Vn.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(yu.PUSH_NOTIFICATIONS_UNSUBSCRIBE,{})})).then((function(){return!0}))})).catch((function(e){var n="Failed unsubscribing for push notifications.";return console.error(e),Vn.createNotification(t,n),!1}))}function me(t){t.registerStores({pushNotifications:Su})}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 Nu.getInitialState()}function we(){return Nu.getInitialState()}function Te(){return Nu.getInitialState()}function Ae(t){return Pu[t.hassId]}function Ce(t){var e=Ae(t);if(e){var n=e.finalTranscript||e.interimTranscript;t.dispatch(Lu.VOICE_TRANSMITTING,{finalTranscript:n}),tr.callService(t,"conversation","process",{text:n}).then((function(){t.dispatch(Lu.VOICE_DONE)}),(function(){t.dispatch(Lu.VOICE_ERROR)}))}}function De(t){var e=Ae(t);e&&(e.recognition.stop(),Pu[t.hassId]=!1)}function ze(t){Ce(t),De(t)}function Re(t){var e=ze.bind(null,t);e();var n=new webkitSpeechRecognition;Pu[t.hassId]={recognition:n,interimTranscript:"",finalTranscript:""},n.interimResults=!0,n.onstart=function(){return t.dispatch(Lu.VOICE_START)},n.onerror=function(){return t.dispatch(Lu.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.prototype.hasOwnProperty,hn=Object.prototype.propertyIsEnumerable,ln=A()?Object.assign:function(t,e){for(var n,r,i=arguments,o=T(t),u=1;u199&&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 mt(t,e){var n=e.date;return n.toISOString()}function gt(){return Qr.getInitialState()}function St(t,e){var n=e.date,r=e.stateHistory;return 0===r.length?t.set(n,$r({})):t.withMutations((function(t){r.forEach((function(e){return t.setIn([n,e[0].entity_id],$r(e.map(In.fromJSON)))}))}))}function bt(){return ti.getInitialState()}function Et(t,e){var n=e.stateHistory;return t.withMutations((function(t){n.forEach((function(e){return t.set(e[0].entity_id,ii(e.map(In.fromJSON)))}))}))}function It(){return oi.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(si,r)}))}function wt(){return ci.getInitialState()}function Tt(t,e){t.dispatch(Wr.ENTITY_HISTORY_DATE_SELECTED,{date:e})}function At(t,e){void 0===e&&(e=null),t.dispatch(Wr.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(Wr.RECENT_ENTITY_HISTORY_FETCH_SUCCESS,{stateHistory:e})}),(function(){return t.dispatch(Wr.RECENT_ENTITY_HISTORY_FETCH_ERROR,{})}))}function Dt(t,e){return t.dispatch(Wr.ENTITY_HISTORY_FETCH_START,{date:e}),on(t,"GET","history/period/"+e).then((function(n){return t.dispatch(Wr.ENTITY_HISTORY_FETCH_SUCCESS,{date:e,stateHistory:n})}),(function(){return t.dispatch(Wr.ENTITY_HISTORY_FETCH_ERROR,{})}))}function Ct(t){var e=t.evaluate(li);return Dt(t,e)}function zt(t){t.registerStores({currentEntityHistoryDate:Qr,entityHistory:ti,isLoadingEntityHistory:ni,recentEntityHistory:oi,recentEntityHistoryUpdated:ci})}function Rt(t){t.registerStores({moreInfoEntityId:Yr})}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=fo[t.hassId];e&&(e.scheduleHealthCheck.clear(),e.conn.close(),fo[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(Mo.authToken),i="https:"===document.location.protocol?"wss://":"ws://";i+=document.location.hostname,document.location.port&&(i+=":"+document.location.port),i+="/api/websocket",E(i,{authToken:r}).then((function(e){var r=Bt((function(){return e.ping()}),so);r(),e.socket.addEventListener("message",r),fo[t.hassId]={conn:e,scheduleHealthCheck:r},co.forEach((function(n){return e.subscribeEvents(ao.bind(null,t),n)})),t.batch((function(){t.dispatch(Ye.STREAM_START),n&&io.fetchAll(t)})),e.addEventListener("disconnected",(function(){t.dispatch(Ye.STREAM_ERROR)})),e.addEventListener("ready",(function(){t.batch((function(){t.dispatch(Ye.STREAM_START),io.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}),io.fetchAll(t).then((function(){t.dispatch(Ue.VALID_AUTH_TOKEN,{authToken:e,host:i,rememberAuth:r}),vo.start(t,{syncOnInitialConnect:!1})}),(function(e){void 0===e&&(e={});var n=e.message;void 0===n&&(n=go),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 Uo({debug:!1});return t.hassId=Ho++,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 xo(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 Jo.getInitialState()}function ue(t,e){var n=e.date,r=e.entries;return t.set(n,eu(r.map($o.fromJSON)))}function ae(){return nu.getInitialState()}function se(t,e){var n=e.date;return t.set(n,(new Date).getTime())}function ce(){return ou.getInitialState()}function fe(t,e){t.dispatch(Bo.LOGBOOK_DATE_SELECTED,{date:e})}function he(t,e){t.dispatch(Bo.LOGBOOK_ENTRIES_FETCH_START,{date:e}),on(t,"GET","logbook/"+e).then((function(n){return t.dispatch(Bo.LOGBOOK_ENTRIES_FETCH_SUCCESS,{date:e,entries:n})}),(function(){return t.dispatch(Bo.LOGBOOK_ENTRIES_FETCH_ERROR,{})}))}function le(t){return!t||(new Date).getTime()-t>su}function pe(t){t.registerStores({currentLogbookDate:Jo,isLoadingLogbookEntries:Xo,logbookEntries:nu,logbookEntriesUpdated:ou})}function _e(t){return t.set("active",!0)}function de(t){return t.set("active",!1)}function ve(){return Su.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(yu.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),Vn.createNotification(t,n),!1}))}function me(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(yu.PUSH_NOTIFICATIONS_UNSUBSCRIBE,{})})).then((function(){return!0}))})).catch((function(e){var n="Failed unsubscribing for push notifications.";return console.error(e),Vn.createNotification(t,n),!1}))}function ge(t){t.registerStores({pushNotifications:Su})}function Se(t,e){return on(t,"POST","template",{template:e})}function be(t){return t.set("isListening",!0)}function Ee(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 ku.getInitialState()}function we(){return ku.getInitialState()}function Te(){return ku.getInitialState()}function Ae(t){return Pu[t.hassId]}function De(t){var e=Ae(t);if(e){var n=e.finalTranscript||e.interimTranscript;t.dispatch(Lu.VOICE_TRANSMITTING,{finalTranscript:n}),tr.callService(t,"conversation","process",{text:n}).then((function(){t.dispatch(Lu.VOICE_DONE)}),(function(){t.dispatch(Lu.VOICE_ERROR)}))}}function Ce(t){var e=Ae(t);e&&(e.recognition.stop(),Pu[t.hassId]=!1)}function ze(t){De(t),Ce(t)}function Re(t){var e=ze.bind(null,t);e();var n=new webkitSpeechRecognition;Pu[t.hassId]={recognition:n,interimTranscript:"",finalTranscript:""},n.interimResults=!0,n.onstart=function(){return t.dispatch(Lu.VOICE_START)},n.onerror=function(){return t.dispatch(Lu.VOICE_ERROR)},n.onend=e,n.onresult=function(e){var n=Ae(t);if(n){for(var r="",i="",o=e.resultIndex;o=n)}function c(t,e){return h(t,e,0)}function f(t,e){return h(t,e,e)}function h(t,e,n){return void 0===t?n:t<0?Math.max(0,e+t):void 0===e?t:Math.min(e,t)}function l(t){return v(t)?t:C(t)}function p(t){return y(t)?t:z(t)}function _(t){return m(t)?t:R(t)}function d(t){return v(t)&&!g(t)?t:M(t)}function v(t){return!(!t||!t[dn])}function y(t){return!(!t||!t[vn])}function m(t){return!(!t||!t[yn])}function g(t){return y(t)||m(t)}function S(t){return!(!t||!t[mn])}function b(t){this.next=t}function E(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&&(En&&t[En]||t[In]);if("function"==typeof e)return e}function D(t){return t&&"number"==typeof t.length}function C(t){return null===t||void 0===t?U():v(t)?t.toSeq():V(t)}function z(t){return null===t||void 0===t?U().toKeyedSeq():v(t)?y(t)?t.toSeq():t.fromEntrySeq():H(t)}function R(t){return null===t||void 0===t?U():v(t)?y(t)?t.entrySeq():t.toIndexedSeq():x(t)}function M(t){return(null===t||void 0===t?U():v(t)?y(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 N(t){this._iterable=t,this.size=t.length||t.size}function k(t){this._iterator=t,this._iteratorCache=[]}function P(t){return!(!t||!t[wn])}function U(){return Tn||(Tn=new L([]))}function H(t){var e=Array.isArray(t)?new L(t).fromEntrySeq():w(t)?new k(t).fromEntrySeq():O(t)?new N(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 D(t)?new L(t):w(t)?new k(t):O(t)?new N(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 b(function(){var t=i[n?o-u:u];return u++>o?I():E(e,r?t[0]:u-1,t[1])})}return t.__iteratorUncached(e,n)}function K(){throw TypeError("Abstract")}function B(){}function Y(){}function J(){}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){return e?Q(e,t,"",{"":t}):Z(t)}function Q(t,e,n,r){return Array.isArray(e)?t.call(r,n,R(e).map((function(n,r){return Q(t,n,r,e)}))):$(e)?t.call(r,n,z(e).map((function(n,r){return Q(t,n,r,e)}))):e}function Z(t){return Array.isArray(t)?R(t).map(Z).toList():$(t)?z(t).map(Z).toMap():t}function $(t){return t&&(t.constructor===Object||void 0===t.constructor)}function tt(t){return t>>>1&1073741824|3221225471&t}function et(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){var n=0|t;for(n!==t&&(n^=4294967295*t);t>4294967295;)t/=4294967295,n^=t;return tt(n)}return"string"===e?t.length>jn?nt(t):rt(t):"function"==typeof t.hashCode?t.hashCode():it(t)}function nt(t){var e=Pn[t];return void 0===e&&(e=rt(t),kn===Nn&&(kn=0,Pn={}),kn++,Pn[t]=e),e}function rt(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 ut(t,e){if(!t)throw new Error(e)}function at(t){ut(t!==1/0,"Cannot perform this action with an infinite size.")}function st(t,e){this._iter=t,this._useKeys=e,this.size=t.size}function ct(t){this._iter=t,this.size=t.size}function ft(t){this._iter=t,this.size=t.size}function ht(t){this._iter=t,this.size=t.size}function lt(t){var e=Lt(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=jt,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 b(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===Sn?gn:Sn,n)},e}function pt(t,e,n){var r=Lt(t);return r.size=t.size,r.has=function(e){return t.has(e)},r.get=function(r,i){var o=t.get(r,ln);return o===ln?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 b(function(){var i=o.next();if(i.done)return i;var u=i.value,a=u[0];return E(r,a,e.call(n,u[1],a,t),i)})},r}function _t(t,e){var n=Lt(t);return n._iter=t,n.size=t.size,n.reverse=function(){return t},t.flip&&(n.flip=function(){var e=lt(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=jt,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 dt(t,e,n,r){var i=Lt(t);return r&&(i.has=function(r){var i=t.get(r,ln);return i!==ln&&!!e.call(n,i,r,t)},i.get=function(r,i){var o=t.get(r,ln);return o!==ln&&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 b(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 E(i,r?c:a++,f,o)}})},i}function vt(t,e,n){var r=Pt().asMutable();return t.__iterate((function(i,o){r.update(e.call(n,i,o,t),0,(function(t){return t+1}))})),r.asImmutable()}function yt(t,e,n){var r=y(t),i=(S(t)?Ie():Pt()).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=Mt(t);return i.map((function(e){return Ct(t,o(e))}))}function mt(t,e,n,r){var i=t.size;if(void 0!==e&&(e|=0),void 0!==n&&(n|=0),s(e,n,i))return t;var o=c(e,i),a=f(n,i);if(o!==o||a!==a)return mt(t.toSeq().cacheResult(),e,n,r);var h,l=a-o;l===l&&(h=l<0?0:l);var p=Lt(t);return p.size=0===h?h:t.size&&h||void 0,!r&&P(t)&&h>=0&&(p.get=function(e,n){return e=u(this,e),e>=0&&eh)return I();var t=i.next();return r||e===Sn?t:e===gn?E(e,a-1,void 0,t):E(e,a-1,t.value[1],t)})},p}function gt(t,e,n){var r=Lt(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 b(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:E(r,s,c,t):(a=!1,I())})},r}function St(t,e,n,r){var i=Lt(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 b(function(){var t,o,f;do{if(t=a.next(),t.done)return r||i===Sn?t:i===gn?E(i,c++,void 0,t):E(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:E(i,o,f,t)})},i}function bt(t,e){var n=y(t),r=[t].concat(e).map((function(t){return v(t)?n&&(t=p(t)):t=n?H(t):x(Array.isArray(t)?t:[t]),t})).filter((function(t){return 0!==t.size}));if(0===r.length)return t;if(1===r.length){var i=r[0];if(i===t||n&&y(i)||m(t)&&m(i))return i}var o=new L(r);return n?o=o.toKeyedSeq():m(t)||(o=o.toSetSeq()),o=o.flatten(!0),o.size=r.reduce((function(t,e){if(void 0!==t){var n=e.size;if(void 0!==n)return t+n}}),0),o}function Et(t,e,n){var r=Lt(t);return r.__iterateUncached=function(r,i){function o(t,s){var c=this;t.__iterate((function(t,i){return(!e||s0}function Dt(t,e,n){var r=Lt(t);return r.size=new L(n).map((function(t){return t.size})).min(),r.__iterate=function(t,e){for(var n,r=this,i=this.__iterator(Sn,e),o=0;!(n=i.next()).done&&t(n.value,o++,r)!==!1;);return o},r.__iteratorUncached=function(t,r){var i=n.map((function(t){return t=l(t),T(r?t.reverse():t)})),o=0,u=!1; +return new b(function(){var n;return u||(n=i.map((function(t){return t.next()})),u=n.some((function(t){return t.done}))),u?I():E(t,o++,e.apply(null,n.map((function(t){return t.value}))))})},r}function Ct(t,e){return P(t)?e:t.constructor(e)}function zt(t){if(t!==Object(t))throw new TypeError("Expected [K, V] tuple: "+t)}function Rt(t){return at(t.size),o(t)}function Mt(t){return y(t)?p:m(t)?_:d}function Lt(t){return Object.create((y(t)?z:m(t)?R:M).prototype)}function jt(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):C.prototype.cacheResult.call(this)}function Nt(t,e){return t>e?1:t>>n)&hn,a=(0===n?r:r>>>n)&hn,s=u===a?[Zt(t,e,n+cn,r,i)]:(o=new Ft(e,r,i),u>>=1)u[a]=1&n?e[o++]:void 0;return u[r]=i,new Vt(t,o+1,u)}function ne(t,e,n){for(var r=[],i=0;i>1&1431655765,t=(858993459&t)+(t>>2&858993459),t=t+(t>>4)&252645135,t+=t>>8,t+=t>>16,127&t}function ae(t,e,n,r){var o=r?t:i(t);return o[e]=n,o}function se(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&&ro?0:o-n,c=u-n;return c>fn&&(c=fn),function(){if(i===c)return Yn;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>fn&&(f=fn),function(){for(;;){if(a){var t=a();if(t!==Yn)return t;a=null}if(c===f)return Yn;var o=e?--f:c++;a=n(s&&s[o],r-cn,i+(o<=t.size||n<0)return t.withMutations((function(t){n<0?Se(t,n).set(0,r):Se(t,0,n+1).set(n,r)}));n+=t._origin;var i=t._tail,o=t._root,a=e(_n);return n>=Ee(t._capacity)?i=ye(i,t.__ownerID,0,n,r,a):o=ye(o,t.__ownerID,t._level,n,r,a),a.value?t.__ownerID?(t._root=o,t._tail=i,t.__hash=void 0,t.__altered=!0,t):_e(t._origin,t._capacity,t._level,o,i):t}function ye(t,e,r,i,o,u){var a=i>>>r&hn,s=t&&a0){var f=t&&t.array[a],h=ye(f,e,r-cn,i,o,u);return h===f?t:(c=me(t,e),c.array[a]=h,c)}return s&&t.array[a]===o?t:(n(u),c=me(t,e),void 0===o&&a===c.array.length-1?c.array.pop():c.array[a]=o,c)}function me(t,e){return e&&t&&e===t.ownerID?t:new le(t?t.array.slice():[],e)}function ge(t,e){if(e>=Ee(t._capacity))return t._tail;if(e<1<0;)n=n.array[e>>>r&hn],r-=cn;return n}}function Se(t,e,n){void 0!==e&&(e|=0),void 0!==n&&(n|=0);var i=t.__ownerID||new r,o=t._origin,u=t._capacity,a=o+e,s=void 0===n?u:n<0?u+n:o+n;if(a===o&&s===u)return t;if(a>=s)return t.clear();for(var c=t._level,f=t._root,h=0;a+h<0;)f=new le(f&&f.array.length?[void 0,f]:[],i),c+=cn,h+=1<=1<l?new le([],i):_;if(_&&p>l&&acn;y-=cn){var m=l>>>y&hn;v=v.array[m]=me(v.array[m],i)}v.array[l>>>cn&hn]=_}if(s=p)a-=p,s-=p,c=cn,f=null,d=d&&d.removeBefore(i,0,a);else if(a>o||p>>c&hn;if(g!==p>>>c&hn)break;g&&(h+=(1<o&&(f=f.removeBefore(i,c,a-h)),f&&pi&&(i=a.size),v(u)||(a=a.map((function(t){return X(t)}))),r.push(a)}return i>t.size&&(t=t.setSize(i)),ie(t,e,r)}function Ee(t){return t>>cn<=fn&&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):we(r,i)}function De(t){return null===t||void 0===t?Re():Ce(t)?t:Re().unshiftAll(t)}function Ce(t){return!(!t||!t[Wn])}function ze(t,e,n,r){var i=Object.create(Xn);return i.size=t,i._head=e,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function Re(){return Qn||(Qn=ze(0))}function Me(t){return null===t||void 0===t?ke():Le(t)&&!S(t)?t:ke().withMutations((function(e){var n=d(t);at(n.size),n.forEach((function(t){return e.add(t)}))}))}function Le(t){return!(!t||!t[Zn])}function je(t,e){return t.__ownerID?(t.size=e.size,t._map=e,t):e===t._map?t:0===e.size?t.__empty():t.__make(e)}function Ne(t,e){var n=Object.create($n);return n.size=t?t.size:0,n._map=t,n.__ownerID=e,n}function ke(){return tr||(tr=Ne(Jt()))}function Pe(t){return null===t||void 0===t?xe():Ue(t)?t:xe().withMutations((function(e){var n=d(t);at(n.size),n.forEach((function(t){return e.add(t)}))}))}function Ue(t){return Le(t)&&S(t)}function He(t,e){var n=Object.create(er);return n.size=t?t.size:0,n._map=t,n.__ownerID=e,n}function xe(){return nr||(nr=He(Te()))}function Ve(t,e){var n,r=function(o){if(o instanceof r)return o;if(!(this instanceof r))return new r(o);if(!n){n=!0;var u=Object.keys(t);Ge(i,u),i.size=u.length,i._name=e,i._keys=u,i._defaultValues=t}this._map=Pt(o)},i=r.prototype=Object.create(rr);return i.constructor=r,r}function qe(t,e,n){var r=Object.create(Object.getPrototypeOf(t));return r._map=e,r.__ownerID=n,r}function Fe(t){return t._name||t.constructor.name||"Record"}function Ge(t,e){try{e.forEach(Ke.bind(void 0,t))}catch(t){}}function Ke(t,e){Object.defineProperty(t,e,{get:function(){return this.get(e)},set:function(t){ut(this.__ownerID,"Cannot set on an immutable record."),this.set(e,t)}})}function Be(t,e){if(t===e)return!0;if(!v(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||y(t)!==y(e)||m(t)!==m(e)||S(t)!==S(e))return!1;if(0===t.size&&0===e.size)return!0;var n=!g(t);if(S(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 o=t;t=e,e=o}var u=!0,a=e.__iterate((function(e,r){if(n?!t.has(e):i?!W(e,t.get(r,ln)):!W(t.get(r,ln),e))return u=!1,!1}));return u&&t.size===a}function Ye(t,e,n){if(!(this instanceof Ye))return new Ye(t,e,n);if(ut(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),ee?-1:0}function rn(t){if(t.size===1/0)return 0;var e=S(t),n=y(t),r=e?1:0,i=t.__iterate(n?e?function(t,e){r=31*r+un(et(t),et(e))|0}:function(t,e){r=r+un(et(t),et(e))|0}:e?function(t){r=31*r+et(t)|0}:function(t){r=r+et(t)|0});return on(i,r)}function on(t,e){return e=Dn(e,3432918353),e=Dn(e<<15|e>>>-15,461845907),e=Dn(e<<13|e>>>-13,5),e=(e+3864292196|0)^t,e=Dn(e^e>>>16,2246822507),e=Dn(e^e>>>13,3266489909),e=tt(e^e>>>16)}function un(t,e){return t^e+2654435769+(t<<6)+(t>>2)|0}var an=Array.prototype.slice,sn="delete",cn=5,fn=1<r?I():E(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 b(function(){var u=r[e?i-o:o];return o++>i?I():E(t,u,n[u])})},j.prototype[mn]=!0,t(N,R),N.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},N.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 b(I);var i=0;return new b(function(){var e=r.next();return e.done?e:E(t,i++,e.value)})},t(k,R),k.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 E(t,i,r[i++])})};var Tn;t(K,l),t(B,K),t(Y,K),t(J,K),K.Keyed=B,K.Indexed=Y,K.Set=J;var An,Dn="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},Cn=Object.isExtensible,zn=(function(){try{return Object.defineProperty({},"@",{}),!0}catch(t){return!1}})(),Rn="function"==typeof WeakMap;Rn&&(An=new WeakMap);var Mn=0,Ln="__immutablehash__";"function"==typeof Symbol&&(Ln=Symbol(Ln));var jn=16,Nn=255,kn=0,Pn={};t(st,z),st.prototype.get=function(t,e){return this._iter.get(t,e)},st.prototype.has=function(t){return this._iter.has(t)},st.prototype.valueSeq=function(){return this._iter.valueSeq()},st.prototype.reverse=function(){var t=this,e=_t(this,!0);return this._useKeys||(e.valueSeq=function(){return t._iter.toSeq().reverse()}),e},st.prototype.map=function(t,e){var n=this,r=pt(this,t,e);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(t,e)}),r},st.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?Rt(this):0,function(i){return t(i,e?--n:n++,r)}),e)},st.prototype.__iterator=function(t,e){if(this._useKeys)return this._iter.__iterator(t,e);var n=this._iter.__iterator(Sn,e),r=e?Rt(this):0;return new b(function(){var i=n.next();return i.done?i:E(t,e?--r:r++,i.value,i)})},st.prototype[mn]=!0,t(ct,R),ct.prototype.includes=function(t){return this._iter.includes(t)},ct.prototype.__iterate=function(t,e){var n=this,r=0;return this._iter.__iterate((function(e){return t(e,r++,n)}),e)},ct.prototype.__iterator=function(t,e){var n=this._iter.__iterator(Sn,e),r=0;return new b(function(){var e=n.next();return e.done?e:E(t,r++,e.value,e)})},t(ft,M),ft.prototype.has=function(t){return this._iter.includes(t)},ft.prototype.__iterate=function(t,e){var n=this;return this._iter.__iterate((function(e){return t(e,e,n)}),e)},ft.prototype.__iterator=function(t,e){var n=this._iter.__iterator(Sn,e);return new b(function(){var e=n.next();return e.done?e:E(t,e.value,e.value,e)})},t(ht,z),ht.prototype.entrySeq=function(){return this._iter.toSeq()},ht.prototype.__iterate=function(t,e){var n=this;return this._iter.__iterate((function(e){if(e){zt(e);var r=v(e);return t(r?e.get(1):e[1],r?e.get(0):e[0],n)}}),e)},ht.prototype.__iterator=function(t,e){var n=this._iter.__iterator(Sn,e);return new b(function(){for(;;){var e=n.next();if(e.done)return e;var r=e.value;if(r){zt(r);var i=v(r);return E(t,i?r.get(0):r[0],i?r.get(1):r[1],e)}}})},ct.prototype.cacheResult=st.prototype.cacheResult=ft.prototype.cacheResult=ht.prototype.cacheResult=jt,t(Pt,B),Pt.prototype.toString=function(){return this.__toString("Map {","}")},Pt.prototype.get=function(t,e){return this._root?this._root.get(0,void 0,t,e):e},Pt.prototype.set=function(t,e){return Wt(this,t,e)},Pt.prototype.setIn=function(t,e){return this.updateIn(t,ln,(function(){return e}))},Pt.prototype.remove=function(t){return Wt(this,t,ln)},Pt.prototype.deleteIn=function(t){return this.updateIn(t,(function(){return ln}))},Pt.prototype.update=function(t,e,n){return 1===arguments.length?t(this):this.updateIn([t],e,n)},Pt.prototype.updateIn=function(t,e,n){n||(n=e,e=void 0);var r=oe(this,kt(t),e,n);return r===ln?void 0:r},Pt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):Jt()},Pt.prototype.merge=function(){return ne(this,void 0,arguments)},Pt.prototype.mergeWith=function(t){var e=an.call(arguments,1);return ne(this,t,e)},Pt.prototype.mergeIn=function(t){var e=an.call(arguments,1);return this.updateIn(t,Jt(),(function(t){return"function"==typeof t.merge?t.merge.apply(t,e):e[e.length-1]}))},Pt.prototype.mergeDeep=function(){return ne(this,re(void 0),arguments)},Pt.prototype.mergeDeepWith=function(t){var e=an.call(arguments,1);return ne(this,re(t),e)},Pt.prototype.mergeDeepIn=function(t){var e=an.call(arguments,1);return this.updateIn(t,Jt(),(function(t){return"function"==typeof t.mergeDeep?t.mergeDeep.apply(t,e):e[e.length-1]}))},Pt.prototype.sort=function(t){return Ie(wt(this,t))},Pt.prototype.sortBy=function(t,e){return Ie(wt(this,e,t))},Pt.prototype.withMutations=function(t){var e=this.asMutable();return t(e),e.wasAltered()?e.__ensureOwner(this.__ownerID):this},Pt.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new r)},Pt.prototype.asImmutable=function(){return this.__ensureOwner()},Pt.prototype.wasAltered=function(){return this.__altered},Pt.prototype.__iterator=function(t,e){return new Gt(this,t,e)},Pt.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},Pt.prototype.__ensureOwner=function(t){return t===this.__ownerID?this:t?Yt(this.size,this._root,t,this.__hash):(this.__ownerID=t,this.__altered=!1,this)},Pt.isMap=Ut;var Un="@@__IMMUTABLE_MAP__@@",Hn=Pt.prototype;Hn[Un]=!0,Hn[sn]=Hn.remove,Hn.removeIn=Hn.deleteIn,Ht.prototype.get=function(t,e,n,r){for(var i=this.entries,o=0,u=i.length;o=Vn)return $t(t,f,o,u);var _=t&&t===this.ownerID,d=_?f:i(f);return p?c?h===l-1?d.pop():d[h]=d.pop():d[h]=[o,u]:d.push([o,u]),_?(this.entries=d,this):new Ht(t,d)}},xt.prototype.get=function(t,e,n,r){void 0===e&&(e=et(n));var i=1<<((0===t?e:e>>>t)&hn),o=this.bitmap;return 0===(o&i)?r:this.nodes[ue(o&i-1)].get(t+cn,e,n,r)},xt.prototype.update=function(t,e,n,r,i,o,u){void 0===n&&(n=et(r));var a=(0===e?n:n>>>e)&hn,s=1<=qn)return ee(t,l,c,a,_);if(f&&!_&&2===l.length&&Qt(l[1^h]))return l[1^h];if(f&&_&&1===l.length&&Qt(_))return _;var d=t&&t===this.ownerID,v=f?_?c:c^s:c|s,y=f?_?ae(l,h,_,d):ce(l,h,d):se(l,h,_,d);return d?(this.bitmap=v,this.nodes=y,this):new xt(t,v,y)},Vt.prototype.get=function(t,e,n,r){void 0===e&&(e=et(n));var i=(0===t?e:e>>>t)&hn,o=this.nodes[i];return o?o.get(t+cn,e,n,r):r},Vt.prototype.update=function(t,e,n,r,i,o,u){void 0===n&&(n=et(r));var a=(0===e?n:n>>>e)&hn,s=i===ln,c=this.nodes,f=c[a];if(s&&!f)return this;var h=Xt(f,t,e+cn,n,r,i,o,u);if(h===f)return this;var l=this.count;if(f){if(!h&&(l--,l=0&&t>>e&hn;if(r>=this.array.length)return new le([],t);var i,o=0===r;if(e>0){var u=this.array[r];if(i=u&&u.removeBefore(t,e-cn,n),i===u&&o)return this}if(o&&!i)return this;var a=me(this,t);if(!o)for(var s=0;s>>e&hn;if(r>=this.array.length)return this;var i;if(e>0){var o=this.array[r];if(i=o&&o.removeAfter(t,e-cn,n),i===o&&r===this.array.length-1)return this}var u=me(this,t);return u.array.splice(r+1),i&&(u.array[r]=i),u};var Bn,Yn={};t(Ie,Pt),Ie.of=function(){return this(arguments)},Ie.prototype.toString=function(){return this.__toString("OrderedMap {","}")},Ie.prototype.get=function(t,e){var n=this._map.get(t);return void 0!==n?this._list.get(n)[1]:e},Ie.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):Te()},Ie.prototype.set=function(t,e){return Ae(this,t,e)},Ie.prototype.remove=function(t){return Ae(this,t,ln)},Ie.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},Ie.prototype.__iterate=function(t,e){var n=this;return this._list.__iterate((function(e){return e&&t(e[1],e[0],n)}),e)},Ie.prototype.__iterator=function(t,e){return this._list.fromEntrySeq().__iterator(t,e)},Ie.prototype.__ensureOwner=function(t){if(t===this.__ownerID)return this;var e=this._map.__ensureOwner(t),n=this._list.__ensureOwner(t);return t?we(e,n,t,this.__hash):(this.__ownerID=t,this._map=e,this._list=n,this)},Ie.isOrderedMap=Oe,Ie.prototype[mn]=!0,Ie.prototype[sn]=Ie.prototype.remove;var Jn;t(De,Y),De.of=function(){return this(arguments)},De.prototype.toString=function(){return this.__toString("Stack [","]")},De.prototype.get=function(t,e){var n=this._head;for(t=u(this,t);n&&t--;)n=n.next;return n?n.value:e},De.prototype.peek=function(){return this._head&&this._head.value},De.prototype.push=function(){var t=arguments;if(0===arguments.length)return this;for(var e=this.size+arguments.length,n=this._head,r=arguments.length-1;r>=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):ze(e,n)},De.prototype.pushAll=function(t){if(t=_(t),0===t.size)return this;at(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):ze(e,n)},De.prototype.pop=function(){return this.slice(1)},De.prototype.unshift=function(){return this.push.apply(this,arguments)},De.prototype.unshiftAll=function(t){return this.pushAll(t)},De.prototype.shift=function(){return this.pop.apply(this,arguments)},De.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):Re()},De.prototype.slice=function(t,e){if(s(t,e,this.size))return this;var n=c(t,this.size),r=f(e,this.size);if(r!==this.size)return Y.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):ze(i,o)},De.prototype.__ensureOwner=function(t){return t===this.__ownerID?this:t?ze(this.size,this._head,t,this.__hash):(this.__ownerID=t,this.__altered=!1,this)},De.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},De.prototype.__iterator=function(t,e){if(e)return this.reverse().__iterator(t);var n=0,r=this._head;return new b(function(){if(r){var e=r.value;return r=r.next,E(t,n++,e)}return I()})},De.isStack=Ce;var Wn="@@__IMMUTABLE_STACK__@@",Xn=De.prototype;Xn[Wn]=!0,Xn.withMutations=Hn.withMutations,Xn.asMutable=Hn.asMutable,Xn.asImmutable=Hn.asImmutable,Xn.wasAltered=Hn.wasAltered;var Qn;t(Me,J),Me.of=function(){return this(arguments)},Me.fromKeys=function(t){return this(p(t).keySeq())},Me.prototype.toString=function(){return this.__toString("Set {","}")},Me.prototype.has=function(t){return this._map.has(t)},Me.prototype.add=function(t){return je(this,this._map.set(t,!0))},Me.prototype.remove=function(t){return je(this,this._map.remove(t))},Me.prototype.clear=function(){return je(this,this._map.clear())},Me.prototype.union=function(){var t=an.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;n1?" by "+this._step:"")+" ]"},Ye.prototype.get=function(t,e){return this.has(t)?this._start+u(this,t)*this._step:e},Ye.prototype.includes=function(t){var e=(t-this._start)/this._step;return e>=0&&e=0&&nn?I():E(t,o++,u)})},Ye.prototype.equals=function(t){return t instanceof Ye?this._start===t._start&&this._end===t._end&&this._step===t._step:Be(this,t)};var ir;t(Je,R),Je.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},Je.prototype.get=function(t,e){return this.has(t)?this._value:e},Je.prototype.includes=function(t){return W(this._value,t)},Je.prototype.slice=function(t,e){var n=this.size;return s(t,e,n)?this:new Je(this._value,f(e,n)-c(t,n))},Je.prototype.reverse=function(){return this},Je.prototype.indexOf=function(t){return W(this._value,t)?0:-1},Je.prototype.lastIndexOf=function(t){return W(this._value,t)?this.size:-1},Je.prototype.__iterate=function(t,e){for(var n=this,r=0;rthis.size?e:this.find((function(e,n){return n===t}),void 0,e)},has:function(t){return t=u(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,y.toFactory)(g),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 M({result:t,reactorState:e})}function o(t,e){return t.withMutations((function(t){(0,R.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,D.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 I(t,[n])}))})),E(t)}))}function u(t,e){return t.withMutations((function(t){(0,R.each)(e,(function(e,n){t.update("stores",(function(t){return t.set(n,e)}))}))}))}function a(t,e,n){if(void 0===e&&f(t,"throwOnUndefinedActionType"))throw new Error("`dispatch` cannot be called with an `undefined` action type.");var r=t.get("state"),i=t.get("dirtyStores"),o=r.withMutations((function(r){A.default.dispatchStart(t,e,n),t.get("stores").forEach((function(o,u){var a=r.get(u),s=void 0;try{s=o.handle(a,e,n)}catch(e){throw A.default.dispatchError(t,e.message),e}if(void 0===s&&f(t,"throwOnUndefinedStoreReturnValue")){var c="Store handler must return a value, did you forget a return statement";throw A.default.dispatchError(t,c),new Error(c)}r.set(u,s),a!==s&&(i=i.add(u))})),A.default.dispatchEnd(t,r,i)})),u=t.set("state",o).set("dirtyStores",i).update("storeStates",(function(t){return I(t,i)}));return E(u)}function s(t,e){var n=[],r=(0,D.toImmutable)({}).withMutations((function(r){(0,R.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=w.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 I(t,n)}))}function c(t,e,n){var r=e;(0,z.isKeyPath)(e)&&(e=(0,C.fromKeyPath)(e));var i=t.get("nextId"),o=(0,C.getStoreDeps)(e),u=w.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,w.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,z.isKeyPath)(e)&&(0,z.isKeyPath)(r)?(0,z.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,D.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 I(t,r)})),v(t)}))}function _(t,e){var n=t.get("state");if((0,z.isKeyPath)(e))return i(n.getIn(e),t);if(!(0,C.isGetter)(e))throw new Error("evaluate must be passed a keyPath or Getter");if(g(t,e))return i(b(t,e),t);var r=(0,C.getDeps)(e).map((function(e){return _(t,e).result})),o=(0,C.getComputeFn)(e).apply(null,r);return i(o,S(t,e,o))}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",w.default.Set())}function y(t){return t}function m(t,e){var n=y(e);return t.getIn(["cache",n])}function g(t,e){var n=m(t,e);if(!n)return!1;var r=n.get("storeStates");return 0!==r.size&&r.every((function(e,n){return t.getIn(["storeStates",n])===e}))}function S(t,e,n){var r=y(e),i=t.get("dispatchId"),o=(0,C.getStoreDeps)(e),u=(0,D.toImmutable)({}).withMutations((function(e){o.forEach((function(n){var r=t.getIn(["storeStates",n]);e.set(n,r)}))}));return t.setIn(["cache",r],w.default.Map({value:n,storeStates:u,dispatchId:i}))}function b(t,e){var n=y(e);return t.getIn(["cache",n,"value"])}function E(t){return t.update("dispatchId",(function(t){return t+1}))}function I(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 O=n(3),w=r(O),T=n(9),A=r(T),D=n(5),C=n(10),z=n(11),R=n(4),M=w.default.Record({result:null,reactorState:null})},function(t,e,n){var r=n(8);e.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())},e.dispatchError=function(t,e){(0,r.getOption)(t,"logDispatches")&&console.group&&(console.debug("Dispatch error: "+e),console.groupEnd())},e.dispatchEnd=function(t,e,n){(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())}},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(3),i=(0,r.Map)({logDispatches:!1,logAppState:!1,logDirtyStores:!1,throwOnUndefinedActionType:!1,throwOnUndefinedStoreReturnValue:!1,throwOnNonImmutableStore:!1,throwOnDispatchInDispatch:!1});e.PROD_OPTIONS=i;var o=(0,r.Map)({logDispatches:!0,logAppState:!0,logDirtyStores:!0,throwOnUndefinedActionType:!0,throwOnUndefinedStoreReturnValue:!0,throwOnNonImmutableStore:!0,throwOnDispatchInDispatch:!0});e.DEBUG_OPTIONS=o;var u=(0,r.Record)({dispatchId:0,state:(0,r.Map)(),stores:(0,r.Map)(),cache:(0,r.Map)(),storeStates:(0,r.Map)(),dirtyStores:(0,r.Set)(),debug:!1,options:i});e.ReactorState=u;var a=(0,r.Record)({any:(0,r.Set)(),stores:(0,r.Map)({}),observersMap:(0,r.Map)({}),nextId:1});e.ObserverState=a}])}))})),Ne=t(je),ke=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=ke,Ue=Pe({VALIDATING_AUTH_TOKEN:null,VALID_AUTH_TOKEN:null,INVALID_AUTH_TOKEN:null,LOG_OUT:null}),He=Ne.Store,xe=Ne.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=Ne.Store,Fe=Ne.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=Ne.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=Ne.Store,We=Ne.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(b)},tn.prototype.getServices=function(){return this.sendMessagePromise(_()).then(b)},tn.prototype.getPanels=function(){return this.sendMessagePromise(d()).then(b)},tn.prototype.getConfig=function(){return this.sendMessagePromise(p()).then(b)},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(m(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(g())},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=Ne.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=Ne.Store,sn=Ne.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.prototype.hasOwnProperty,hn=Object.prototype.propertyIsEnumerable,ln=A()?Object.assign:function(t,e){for(var n,r,i=arguments,o=T(t),u=1;uOo{Ejrd((vP>02w?`K3)Z(#rQ` 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 literal 33524 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 diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index dd0eba180ec..474db7d63c4 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -2,4 +2,4 @@ },_distributeDirtyRoots:function(){for(var e,t=this.shadyRoot._dirtyRoots,o=0,i=t.length;o0?~setTimeout(e,t):(this._twiddle.textContent=this._twiddleContent++,this._callbacks.push(e),this._currVal++)},cancel:function(e){if(e<0)clearTimeout(~e);else{var t=e-this._lastVal;if(t>=0){if(!this._callbacks[t])throw"invalid async handle: "+e;this._callbacks[t]=null}}},_atEndOfMicrotask:function(){for(var e=this._callbacks.length,t=0;t \ No newline at end of file +this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},i=window.Element.prototype.animate;window.Element.prototype.animate=function(n,r){var o=i.call(this,n,r);o._cancelHandlers=[],o.oncancel=null;var a=o.cancel;o.cancel=function(){a.call(this);var i=new e(this,null,t()),n=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){n.forEach(function(t){t.call(i.target,i)})},0)};var s=o.addEventListener;o.addEventListener=function(t,e){"function"==typeof e&&"cancel"==t?this._cancelHandlers.push(e):s.call(this,t,e)};var u=o.removeEventListener;return o.removeEventListener=function(t,e){if("cancel"==t){var i=this._cancelHandlers.indexOf(e);i>=0&&this._cancelHandlers.splice(i,1)}else u.call(this,t,e)},o}}}(),function(t){var e=document.documentElement,i=null,n=!1;try{var r=getComputedStyle(e).getPropertyValue("opacity"),o="0"==r?"1":"0";i=e.animate({opacity:[o,o]},{duration:1}),i.currentTime=0,n=getComputedStyle(e).getPropertyValue("opacity")==o}catch(t){}finally{i&&i.cancel()}if(!n){var a=window.Element.prototype.animate;window.Element.prototype.animate=function(e,i){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&e[Symbol.iterator]&&(e=Array.from(e)),Array.isArray(e)||null===e||(e=t.convertToArrayForm(e)),a.call(this,e,i)}}}(c),!function(t,e,i){function n(t){var i=e.timeline;i.currentTime=t,i._discardAnimations(),0==i._animations.length?o=!1:requestAnimationFrame(n)}var r=window.requestAnimationFrame;window.requestAnimationFrame=function(t){return r(function(i){e.timeline._updateAnimationsPromises(),t(i),e.timeline._updateAnimationsPromises()})},e.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},e.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){e.animationsWithPromises=e.animationsWithPromises.filter(function(t){return t._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(t){return"finished"!=t.playState&&"idle"!=t.playState})},_play:function(t){var i=new e.Animation(t,this);return this._animations.push(i),e.restartWebAnimationsNextTick(),i._updatePromises(),i._animation.play(),i._updatePromises(),i},play:function(t){return t&&t.remove(),this._play(t)}};var o=!1;e.restartWebAnimationsNextTick=function(){o||(o=!0,requestAnimationFrame(n))};var a=new e.AnimationTimeline;e.timeline=a;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return a}})}catch(t){}try{window.document.timeline=a}catch(t){}}(c,e,f),function(t,e,i){e.animationsWithPromises=[],e.Animation=function(e,i){if(this.id="",e&&e._id&&(this.id=e._id),this.effect=e,e&&(e._animation=this),!i)throw new Error("Animation with null timeline is not supported");this._timeline=i,this._sequenceNumber=t.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},e.Animation.prototype={_updatePromises:function(){var t=this._oldPlayState,e=this.playState;return this._readyPromise&&e!==t&&("idle"==e?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==t?this._resolveReadyPromise():"pending"==e&&(this._readyPromise=void 0)),this._finishedPromise&&e!==t&&("idle"==e?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==e?this._resolveFinishedPromise():"finished"==t&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var t,i,n,r,o=!!this._animation;o&&(t=this.playbackRate,i=this._paused,n=this.startTime,r=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=e.newUnderlyingAnimationForKeyframeEffect(this.effect),e.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=e.newUnderlyingAnimationForGroup(this.effect),e.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&e.bindAnimationForCustomEffect(this),o&&(1!=t&&(this.playbackRate=t),null!==n?this.startTime=n:null!==r?this.currentTime=r:null!==this._holdTime&&(this.currentTime=this._holdTime),i&&this.pause()),this._updatePromises()},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var t=this.effect._timing.delay;this._childAnimations.forEach(function(i){this._arrangeChildren(i,t),this.effect instanceof window.SequenceEffect&&(t+=e.groupChildDuration(i.effect))}.bind(this))}},_setExternalAnimation:function(t){if(this.effect&&this._isGroup)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 b1488e61a11ee39c694803a710a4e6b8eea2e090..7d29d3b9612a0a75b3204479f3f6ee038cf9e6bf 100644 GIT binary patch delta 19846 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 H;$Q#(ZnT#H delta 19541 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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 336e974fe6f..b8a7c6624d5 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 336e974fe6f4196aaf0b309e805a009ef0fdfd66 +Subproject commit b8a7c6624d54d3f579ff22079c9dc01843a0fc6e 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 e4fd1211753..9ce5304213e 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 2419c25adbd0c227748e2991b75bdd3295e45bd4..e9007a00c9334d6e15c94e2b0ac8bd11bfbec312 100644 GIT binary patch delta 8811 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 delta 8727 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 Lb&(~KpOFCoz_=Qj diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index d2ef4b42439..c445793b953 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=[["/","082f309161a30f32189a0d74551164af"],["/frontend/panels/dev-event-c2d5ec676be98d4474d19f94d0262c1e.html","6c55fc819751923ab00c62ae3fbb7222"],["/frontend/panels/dev-info-a9c07bf281fe9791fb15827ec1286825.html","931f9327e368db710fcdf5f7202f2588"],["/frontend/panels/dev-service-20420e2387fd93db53c8d778097e3d59.html","99f1c9e09f0200bd1f9744dd23d976da"],["/frontend/panels/dev-state-65e5f791cc467561719bf591f1386054.html","78158786a6597ef86c3fd6f4985cde92"],["/frontend/panels/dev-template-7d744ab7f7c08b6d6ad42069989de400.html","8a6ee994b1cdb45b081299b8609915ed"],["/frontend/panels/map-3b0ca63286cbe80f27bd36dbc2434e89.html","d22eee1c33886ce901851ccd35cb43ed"],["/static/core-5dfb2d3e567fad37af0321d4b29265ed.js","9a50270db7613e3af449f6c773366f4d"],["/static/frontend-ac15b11435132aab3da592f9e7b05400.html","8ca51f4e1e2f8eebda6408891010eb09"],["/static/mdi-46a76f877ac9848899b8ed382427c16f.html","a846c4082dd5cffd88ac72cbe943e691"],["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"}))}))})}).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,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 Date: Tue, 13 Dec 2016 23:46:27 -0800 Subject: [PATCH 102/141] Fix hue groups on older hubs (#4884) --- homeassistant/components/light/hue.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 74247ad24ef..259553cc620 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -143,10 +143,13 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable): lights = {} lightgroups = {} + skip_groups = False @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update_lights(): """Update the Hue light objects with latest info from the bridge.""" + nonlocal skip_groups + try: api = bridge.get_api() except socket.error: @@ -160,7 +163,10 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable): _LOGGER.error("Got unexpected result from Hue API") return - api_groups = api.get('groups') + if skip_groups: + api_groups = {} + else: + api_groups = api.get('groups') if not isinstance(api_groups, dict): _LOGGER.error("Got unexpected result from Hue API") @@ -185,6 +191,12 @@ def setup_bridge(host, hass, add_devices, filename, allow_unreachable): lights[light_id].schedule_update_ha_state() for lightgroup_id, info in api_groups.items(): + if 'state' not in info: + _LOGGER.warning('Group info does not contain state. ' + 'Please update your hub.') + skip_groups = True + break + if lightgroup_id not in lightgroups: lightgroups[lightgroup_id] = HueLight( int(lightgroup_id), info, bridge, update_lights, From be552a59c956d70405571ae532bb6582fa2082e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Wed, 14 Dec 2016 18:45:05 +0100 Subject: [PATCH 103/141] Bug in rpi_camera --- homeassistant/components/camera/rpi_camera.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/camera/rpi_camera.py b/homeassistant/components/camera/rpi_camera.py index c5603dac142..b42c62e56d0 100644 --- a/homeassistant/components/camera/rpi_camera.py +++ b/homeassistant/components/camera/rpi_camera.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_FILE_PATH): cv.string, vol.Optional(CONF_HORIZONTAL_FLIP, default=DEFAULT_HORIZONTAL_FLIP): vol.All(vol.Coerce(int), vol.Range(min=0, max=1)), - vol.Optional(CONF_IMAGE_HEIGHT, default=DEFAULT_HORIZONTAL_FLIP): + vol.Optional(CONF_IMAGE_HEIGHT, default=DEFAULT_IMAGE_HEIGHT): vol.Coerce(int), vol.Optional(CONF_IMAGE_QUALITY, default=DEFAULT_IMAGE_QUALITIY): vol.All(vol.Coerce(int), vol.Range(min=0, max=100)), From a359d21799edbfa3819e9073f0f0874ebae0c605 Mon Sep 17 00:00:00 2001 From: Valentin Alexeev Date: Wed, 14 Dec 2016 20:05:03 +0200 Subject: [PATCH 104/141] [media_player.sonos] Source selection from favorites (#4804) --- .../components/media_player/sonos.py | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index c6e9c1e6655..e9653d2a8d8 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -298,6 +298,8 @@ class SonosDevice(MediaPlayerDevice): self._last_avtransport_event = None self._is_playing_line_in = None self._is_playing_tv = None + self._favorite_sources = None + self._source_name = None self.soco_snapshot = Snapshot(self._player) @property @@ -443,6 +445,8 @@ class SonosDevice(MediaPlayerDevice): else: media_artist = SUPPORT_SOURCE_LINEIN + source_name = media_artist + media_album_name = None media_title = None media_image_url = None @@ -456,6 +460,16 @@ class SonosDevice(MediaPlayerDevice): 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: @@ -592,6 +606,7 @@ class SonosDevice(MediaPlayerDevice): 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 # pylint: disable=protected-access @@ -601,6 +616,8 @@ class SonosDevice(MediaPlayerDevice): 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: self._player_volume = None self._player_volume_muted = None @@ -624,6 +641,8 @@ class SonosDevice(MediaPlayerDevice): self._support_pause = False self._is_playing_tv = False self._is_playing_line_in = False + self._favorite_sources = None + self._source_name = None self._last_avtransport_event = None @@ -771,10 +790,6 @@ class SonosDevice(MediaPlayerDevice): supported = SUPPORT_SONOS - if not self.source_list: - # some devices do not allow source selection - supported = supported ^ SUPPORT_SELECT_SOURCE - if not self._support_previous_track: supported = supported ^ SUPPORT_PREVIOUS_TRACK @@ -808,19 +823,31 @@ class SonosDevice(MediaPlayerDevice): def select_source(self, source): """Select input source.""" if 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] + if len(fav) == 1: + src = fav.pop() + self._source_name = src['title'] + self._player.play_uri(src['uri'], src['meta'], src['title']) @property def source_list(self): """List of available input sources.""" model_name = self._speaker_info['model_name'] + sources = self._favorite_sources + if 'PLAY:5' in model_name: - return [SUPPORT_SOURCE_LINEIN] + sources += [SUPPORT_SOURCE_LINEIN] elif 'PLAYBAR' in model_name: - return [SUPPORT_SOURCE_LINEIN, SUPPORT_SOURCE_TV] + sources += [SUPPORT_SOURCE_LINEIN, SUPPORT_SOURCE_TV] + return sources @property def source(self): @@ -828,12 +855,7 @@ class SonosDevice(MediaPlayerDevice): if self._coordinator: return self._coordinator.source else: - if self._is_playing_line_in: - return SUPPORT_SOURCE_LINEIN - elif self._is_playing_tv: - return SUPPORT_SOURCE_TV - - return None + return self._source_name def turn_off(self): """Turn off media player.""" From 6d2de67620451a725d0b949a7992d653d531c03e Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 14 Dec 2016 22:32:20 +0100 Subject: [PATCH 105/141] TTS add google language list for config check (#4912) * Add config check for language * update default * move language from component to platform * fix lint --- homeassistant/components/tts/__init__.py | 6 ++---- homeassistant/components/tts/google.py | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/tts/__init__.py b/homeassistant/components/tts/__init__.py index 0e75de88cc5..d0faa60684f 100644 --- a/homeassistant/components/tts/__init__.py +++ b/homeassistant/components/tts/__init__.py @@ -41,7 +41,6 @@ CONF_TIME_MEMORY = 'time_memory' DEFAULT_CACHE = True DEFAULT_CACHE_DIR = "tts" -DEFAULT_LANG = 'en' DEFAULT_TIME_MEMORY = 300 SERVICE_SAY = 'say' @@ -53,7 +52,6 @@ ATTR_CACHE = 'cache' _RE_VOICE_FILE = re.compile(r"([a-f0-9]{40})_([a-z]+)\.[a-z0-9]{3,4}") PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ - vol.Optional(CONF_LANG, default=DEFAULT_LANG): cv.string, vol.Optional(CONF_CACHE, default=DEFAULT_CACHE): cv.boolean, vol.Optional(CONF_CACHE_DIR, default=DEFAULT_CACHE_DIR): cv.string, vol.Optional(CONF_TIME_MEMORY, default=DEFAULT_TIME_MEMORY): @@ -79,7 +77,7 @@ def async_setup(hass, config): conf = config[DOMAIN][0] if len(config.get(DOMAIN, [])) > 0 else {} use_cache = conf.get(CONF_CACHE, DEFAULT_CACHE) cache_dir = conf.get(CONF_CACHE_DIR, DEFAULT_CACHE_DIR) - time_memory = conf.get(CONF_TIME_MEMORY, DEFAULT_LANG) + time_memory = conf.get(CONF_TIME_MEMORY, DEFAULT_TIME_MEMORY) yield from tts.async_init_cache(use_cache, cache_dir, time_memory) except (HomeAssistantError, KeyError) as err: @@ -379,7 +377,7 @@ class Provider(object): """Represent a single provider.""" hass = None - language = DEFAULT_LANG + language = None def get_tts_audio(self, message): """Load tts audio file from provider.""" diff --git a/homeassistant/components/tts/google.py b/homeassistant/components/tts/google.py index b271b2468d1..92794cd00b6 100644 --- a/homeassistant/components/tts/google.py +++ b/homeassistant/components/tts/google.py @@ -10,9 +10,10 @@ import re import aiohttp import async_timeout +import voluptuous as vol import yarl -from homeassistant.components.tts import Provider +from homeassistant.components.tts import Provider, PLATFORM_SCHEMA, CONF_LANG from homeassistant.helpers.aiohttp_client import async_get_clientsession REQUIREMENTS = ["gTTS-token==1.1.1"] @@ -22,6 +23,21 @@ _LOGGER = logging.getLogger(__name__) GOOGLE_SPEECH_URL = "http://translate.google.com/translate_tts" MESSAGE_SIZE = 148 +SUPPORT_LANGUAGES = [ + 'af', 'sq', 'ar', 'hy', 'bn', 'ca', 'zh', 'zh-cn', 'zh-tw', 'zh-yue', + 'hr', 'cs', 'da', 'nl', 'en', 'en-au', 'en-uk', 'en-us', 'eo', 'fi', + 'fr', 'de', 'el', 'hi', 'hu', 'is', 'id', 'it', 'ja', 'ko', 'la', 'lv', + 'mk', 'no', 'pl', 'pt', 'pt-br', 'ro', 'ru', 'sr', 'sk', 'es', 'es-es', + 'es-us', 'sw', 'sv', 'ta', 'th', 'tr', 'vi', 'cy', +] + +DEFAULT_LANG = 'en' + + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORT_LANGUAGES), +}) + @asyncio.coroutine def async_get_engine(hass, config): From 58ea3c25df9b9d8ee0b1d3197da529bb3015afa9 Mon Sep 17 00:00:00 2001 From: Daniel Hoyer Iversen Date: Thu, 15 Dec 2016 07:58:58 +0100 Subject: [PATCH 106/141] Update flux led lib --- homeassistant/components/light/flux_led.py | 4 ++-- requirements_all.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/light/flux_led.py b/homeassistant/components/light/flux_led.py index 1e1d4136142..a5474612496 100644 --- a/homeassistant/components/light/flux_led.py +++ b/homeassistant/components/light/flux_led.py @@ -17,8 +17,8 @@ from homeassistant.components.light import ( PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['https://github.com/Danielhiversen/flux_led/archive/0.9.zip' - '#flux_led==0.9'] +REQUIREMENTS = ['https://github.com/Danielhiversen/flux_led/archive/0.10.zip' + '#flux_led==0.10'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 924f534145d..f56c576f366 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -173,7 +173,7 @@ hikvision==0.4 http://github.com/technicalpickles/python-nest/archive/b8391d2b3cb8682f8b0c2bdff477179983609f39.zip#python-nest==3.0.2 # homeassistant.components.light.flux_led -https://github.com/Danielhiversen/flux_led/archive/0.9.zip#flux_led==0.9 +https://github.com/Danielhiversen/flux_led/archive/0.10.zip#flux_led==0.10 # homeassistant.components.switch.tplink https://github.com/GadgetReactor/pyHS100/archive/1f771b7d8090a91c6a58931532e42730b021cbde.zip#pyHS100==0.2.0 From 1a7895b1d802aade6a3089f01022f38d861460bf Mon Sep 17 00:00:00 2001 From: Lewis Juggins Date: Thu, 15 Dec 2016 11:46:18 +0000 Subject: [PATCH 107/141] [media_player.sonos] Bugfix, initalise source_name. (#4911) --- homeassistant/components/media_player/sonos.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index e9653d2a8d8..94649b3a597 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -427,6 +427,7 @@ class SonosDevice(MediaPlayerDevice): media_position = None media_position_updated_at = None + source_name = None is_radio_stream = \ current_media_uri.startswith('x-sonosapi-stream:') or \ From 43d18daebdbdf82133c8c1dbbae73bb50e894db8 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 15 Dec 2016 21:26:13 +0100 Subject: [PATCH 108/141] Homematic faster update with async (#4929) --- homeassistant/components/homematic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/homematic.py b/homeassistant/components/homematic.py index 245e6a12cc2..00adf3701c0 100644 --- a/homeassistant/components/homematic.py +++ b/homeassistant/components/homematic.py @@ -825,7 +825,7 @@ class HMDevice(Entity): if have_change: _LOGGER.debug("%s update_ha_state after '%s'", self._name, attribute) - self.update_ha_state() + self.schedule_update_ha_state() def _subscribe_homematic_events(self): """Subscribe all required events to handle job.""" From 1d60760e21de6c0727458e5a4fafd2358e179b7a Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 16 Dec 2016 06:30:09 +0100 Subject: [PATCH 109/141] Protect add_job (#4932) --- homeassistant/core.py | 2 ++ tests/test_core.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/homeassistant/core.py b/homeassistant/core.py index 86cfec7099c..da4fd2ed102 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -184,6 +184,8 @@ class HomeAssistant(object): target: target to call. args: parameters for method to call. """ + if target is None: + raise ValueError("Don't call add_job with None.") self.loop.call_soon_threadsafe(self.async_add_job, target, *args) @callback diff --git a/tests/test_core.py b/tests/test_core.py index 9221ad68352..4049d10d32d 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6,6 +6,7 @@ from unittest.mock import patch, MagicMock from datetime import datetime, timedelta import pytz +import pytest import homeassistant.core as ha from homeassistant.exceptions import InvalidEntityFormatError @@ -214,6 +215,11 @@ class TestHomeAssistant(unittest.TestCase): assert len(self.hass._pending_tasks) == 0 assert len(call_count) == 2 + def test_add_job_with_none(self): + """Try to add a job with None as function.""" + with pytest.raises(ValueError): + self.hass.add_job(None, 'test_arg') + class TestEvent(unittest.TestCase): """A Test Event class.""" From 7bb0abdf09121b30e83b6337f5ac8f735ea9980f Mon Sep 17 00:00:00 2001 From: joopert Date: Fri, 16 Dec 2016 06:35:01 +0100 Subject: [PATCH 110/141] kodi fanart fix basic auth (#4930) --- homeassistant/components/media_player/kodi.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index 68161deea2f..9676fe451c7 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -76,11 +76,17 @@ class KodiDevice(MediaPlayerDevice): import jsonrpc_requests self._name = name self._url = url + self._basic_auth_url = None kwargs = {'timeout': 5} if auth is not None: kwargs['auth'] = auth + scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url) + self._basic_auth_url = \ + urllib.parse.urlunsplit((scheme, '{}:{}@{}'.format + (auth[0], auth[1], netloc), + path, query, fragment)) self._server = jsonrpc_requests.Server( '{}/jsonrpc'.format(self._url), **kwargs) @@ -195,6 +201,11 @@ class KodiDevice(MediaPlayerDevice): url_components = urllib.parse.urlparse(self._item['thumbnail']) if url_components.scheme == 'image': + if self._basic_auth_url is not None: + return '{}/image/{}'.format( + self._basic_auth_url, + urllib.parse.quote_plus(self._item['thumbnail'])) + return '{}/image/{}'.format( self._url, urllib.parse.quote_plus(self._item['thumbnail'])) From ceac9eab94c7b9982296d74e956e8a7905815cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Fri, 16 Dec 2016 06:35:47 +0100 Subject: [PATCH 111/141] Bug fix for #4903 (#4927) --- homeassistant/components/sensor/systemmonitor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 14eadb48984..b59c5d0cd43 100755 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -27,14 +27,14 @@ SENSOR_TYPES = { 'memory_use': ['RAM Use', 'MiB', 'mdi:memory'], 'memory_free': ['RAM Free', 'MiB', 'mdi:memory'], 'processor_use': ['CPU Use', '%', 'mdi:memory'], - 'process': ['Process', '', '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'], + 'packets_out': ['Packets sent', ' ', 'mdi:server-network'], + 'packets_in': ['Packets received', ' ', 'mdi:server-network'], 'ipv4_address': ['IPv4 address', '', 'mdi:server-network'], 'ipv6_address': ['IPv6 address', '', 'mdi:server-network'], 'last_boot': ['Last Boot', '', 'mdi:clock'], From f90b89bc746acb71772e60f287ff626873607802 Mon Sep 17 00:00:00 2001 From: Joe Rocklin Date: Fri, 16 Dec 2016 00:39:59 -0500 Subject: [PATCH 112/141] Add nest hvac state (#4810) * Add basic property details for Nest hvac_state * Add the hvac_state sensor * Update requirements and remove trailing whitespace Clean up the multiline docstring Adding a space between summary and description * Removing the hvac_state as a property on the nest climate * Update nest.py --- homeassistant/components/sensor/nest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/nest.py b/homeassistant/components/sensor/nest.py index b9dde96a98c..f7bbf41cff9 100644 --- a/homeassistant/components/sensor/nest.py +++ b/homeassistant/components/sensor/nest.py @@ -18,7 +18,8 @@ from homeassistant.const import ( DEPENDENCIES = ['nest'] SENSOR_TYPES = ['humidity', - 'operation_mode'] + 'operation_mode', + 'hvac_state'] SENSOR_TYPES_DEPRECATED = ['last_ip', 'local_ip', From c125c4af4f4044d6bae4d0ca9c79125747a1db28 Mon Sep 17 00:00:00 2001 From: Hugo Dupras Date: Fri, 16 Dec 2016 06:40:33 +0100 Subject: [PATCH 113/141] Fix for GTFS sensor (#4828) * Fix for GTFS sensor Signed-off-by: Hugo D. (jabesq) * GTFS fix Signed-off-by: Hugo D. (jabesq) --- homeassistant/components/sensor/gtfs.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/homeassistant/components/sensor/gtfs.py b/homeassistant/components/sensor/gtfs.py index e76b8ed07ed..5769860284c 100644 --- a/homeassistant/components/sensor/gtfs.py +++ b/homeassistant/components/sensor/gtfs.py @@ -95,6 +95,9 @@ def get_next_departure(sched, start_station_id, end_station_id): for row in result: item = row + if item == {}: + return None + today = datetime.datetime.today().strftime('%Y-%m-%d') departure_time_string = '{} {}'.format(today, item[2]) arrival_time_string = '{} {}'.format(today, item[3]) @@ -221,6 +224,13 @@ class GTFSDepartureSensor(Entity): with self.lock: self._departure = get_next_departure(self._pygtfs, self.origin, self.destination) + if not self._departure: + self._state = 0 + self._attributes = {'Info': 'No more bus today'} + if self._name == '': + self._name = (self._custom_name or "GTFS Sensor") + return + self._state = self._departure['minutes_until_departure'] origin_station = self._departure['origin_station'] From 394d53e748f3bea40990074fcc516de2695aa25b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Fri, 16 Dec 2016 06:42:00 +0100 Subject: [PATCH 114/141] Broadlink sensor and switch (#4834) * Broadlink sensor and switch * broadlink logging * Use async * style * style --- .coveragerc | 2 + homeassistant/components/sensor/broadlink.py | 130 +++++++++++++++ homeassistant/components/switch/broadlink.py | 158 +++++++++++++++++++ requirements_all.txt | 4 + 4 files changed, 294 insertions(+) create mode 100644 homeassistant/components/sensor/broadlink.py create mode 100644 homeassistant/components/switch/broadlink.py diff --git a/.coveragerc b/.coveragerc index 3168a20bd8c..d929d50271b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -252,6 +252,7 @@ omit = homeassistant/components/sensor/bbox.py homeassistant/components/sensor/bitcoin.py homeassistant/components/sensor/bom.py + homeassistant/components/sensor/broadlink.py homeassistant/components/sensor/coinmarketcap.py homeassistant/components/sensor/cpuspeed.py homeassistant/components/sensor/cups.py @@ -323,6 +324,7 @@ omit = homeassistant/components/switch/acer_projector.py homeassistant/components/switch/anel_pwrctrl.py homeassistant/components/switch/arest.py + homeassistant/components/switch/broadlink.py homeassistant/components/switch/digitalloggers.py homeassistant/components/switch/dlink.py homeassistant/components/switch/edimax.py diff --git a/homeassistant/components/sensor/broadlink.py b/homeassistant/components/sensor/broadlink.py new file mode 100644 index 00000000000..53aac3d353a --- /dev/null +++ b/homeassistant/components/sensor/broadlink.py @@ -0,0 +1,130 @@ + +""" +Support for the Broadlink RM2 Pro (only temperature) and A1 devices. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.broadlink/ +""" +from datetime import timedelta +import binascii +import logging +import socket +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import (CONF_HOST, CONF_MAC, + CONF_MONITORED_CONDITIONS, + CONF_NAME, TEMP_CELSIUS, CONF_TIMEOUT) +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['broadlink==0.2'] + +_LOGGER = logging.getLogger(__name__) + +CONF_UPDATE_INTERVAL = 'update_interval' +DEVICE_DEFAULT_NAME = 'Broadlink sensor' +DEFAULT_TIMEOUT = 10 + +SENSOR_TYPES = { + 'temperature': ['Temperature', TEMP_CELSIUS], + 'air_quality': ['Air Quality', ' '], + 'humidity': ['Humidity', '%'], + 'light': ['Light', ' '], + 'noise': ['Noise', ' '] +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEVICE_DEFAULT_NAME): vol.Coerce(str), + vol.Optional(CONF_MONITORED_CONDITIONS, default=[]): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), + vol.Optional(CONF_UPDATE_INTERVAL, default=timedelta(seconds=300)): ( + vol.All(cv.time_period, cv.positive_timedelta)), + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_MAC): cv.string, + vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int +}) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup the Broadlink device sensors.""" + mac = config.get(CONF_MAC).encode().replace(b':', b'') + mac_addr = binascii.unhexlify(mac) + broadlink_data = BroadlinkData( + config.get(CONF_UPDATE_INTERVAL), + config.get(CONF_HOST), + mac_addr, config.get(CONF_TIMEOUT)) + + dev = [] + for variable in config[CONF_MONITORED_CONDITIONS]: + dev.append(BroadlinkSensor( + config.get(CONF_NAME), + broadlink_data, + variable)) + add_devices(dev) + + +class BroadlinkSensor(Entity): + """Representation of a Broadlink device sensor.""" + + def __init__(self, name, broadlink_data, sensor_type): + """Initialize the sensor.""" + self._name = "%s %s" % (name, SENSOR_TYPES[sensor_type][0]) + self._state = None + self._type = sensor_type + self._broadlink_data = broadlink_data + self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] + self.update() + + @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 this state is expressed in.""" + return self._unit_of_measurement + + def update(self): + """Get the latest data from the sensor.""" + self._broadlink_data.update() + if self._broadlink_data.data is None: + return + self._state = self._broadlink_data.data[self._type] + + +class BroadlinkData(object): + """Representation of a Broadlink data object.""" + + def __init__(self, interval, ip_addr, mac_addr, timeout): + """Initialize the data object.""" + import broadlink + self.data = None + self._device = broadlink.a1((ip_addr, 80), mac_addr) + self._device.timeout = timeout + self.update = Throttle(interval)(self._update) + try: + self._device.auth() + except socket.timeout: + _LOGGER.error("Failed to connect to device.") + + def _update(self, retry=2): + try: + self.data = self._device.check_sensors_raw() + except socket.timeout as error: + if retry < 1: + _LOGGER.error(error) + return + try: + self._device.auth() + except socket.timeout: + pass + return self._update(max(0, retry-1)) diff --git a/homeassistant/components/switch/broadlink.py b/homeassistant/components/switch/broadlink.py new file mode 100644 index 00000000000..ee71de3a22e --- /dev/null +++ b/homeassistant/components/switch/broadlink.py @@ -0,0 +1,158 @@ +""" +Support for Broadlink RM devices. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.broadlink/ +""" +from datetime import timedelta +from base64 import b64encode, b64decode +import asyncio +import binascii +import logging +import socket +import voluptuous as vol + +import homeassistant.loader as loader +from homeassistant.util.dt import utcnow +from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) +from homeassistant.const import (CONF_FRIENDLY_NAME, CONF_SWITCHES, + CONF_COMMAND_OFF, CONF_COMMAND_ON, + CONF_TIMEOUT, CONF_HOST, CONF_MAC) +import homeassistant.helpers.config_validation as cv + +REQUIREMENTS = ['broadlink==0.2'] + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = "broadlink" +DEFAULT_NAME = 'Broadlink switch' +DEFAULT_TIMEOUT = 10 +SERVICE_LEARN = "learn_command" + +SWITCH_SCHEMA = vol.Schema({ + vol.Optional(CONF_COMMAND_OFF, default=None): cv.string, + vol.Optional(CONF_COMMAND_ON, default=None): cv.string, + vol.Optional(CONF_FRIENDLY_NAME, default=DEFAULT_NAME): cv.string, +}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_SWITCHES): vol.Schema({cv.slug: SWITCH_SCHEMA}), + vol.Required(CONF_HOST): cv.string, + vol.Required(CONF_MAC): cv.string, + vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup Broadlink switches.""" + import broadlink + devices = config.get(CONF_SWITCHES, {}) + switches = [] + ip_addr = config.get(CONF_HOST) + mac_addr = binascii.unhexlify( + config.get(CONF_MAC).encode().replace(b':', b'')) + broadlink_device = broadlink.rm((ip_addr, 80), mac_addr) + broadlink_device.timeout = config.get(CONF_TIMEOUT) + try: + broadlink_device.auth() + except socket.timeout: + _LOGGER.error("Failed to connect to device.") + + persistent_notification = loader.get_component('persistent_notification') + + @asyncio.coroutine + def _learn_command(call): + try: + yield from hass.loop.run_in_executor(None, broadlink_device.auth) + except socket.timeout: + _LOGGER.error("Failed to connect to device.") + return + yield from hass.loop.run_in_executor(None, + broadlink_device.enter_learning) + + _LOGGER.info("Press the key you want HASS to learn") + start_time = utcnow() + while (utcnow() - start_time) < timedelta(seconds=20): + packet = yield from hass.loop.run_in_executor(None, + broadlink_device. + check_data) + if packet: + log_msg = 'Recieved packet is: {}'.\ + format(b64encode(packet).decode('utf8')) + _LOGGER.info(log_msg) + persistent_notification.async_create(hass, log_msg, + title='Broadlink switch') + return + yield from asyncio.sleep(1, loop=hass.loop) + _LOGGER.error('Did not received any signal.') + persistent_notification.async_create(hass, + "Did not received any signal", + title='Broadlink switch') + hass.services.register(DOMAIN, SERVICE_LEARN, _learn_command) + + for object_id, device_config in devices.items(): + switches.append( + BroadlinkRM2Switch( + device_config.get(CONF_FRIENDLY_NAME, object_id), + device_config.get(CONF_COMMAND_ON), + device_config.get(CONF_COMMAND_OFF), + broadlink_device + ) + ) + + add_devices(switches) + + +class BroadlinkRM2Switch(SwitchDevice): + """Representation of an Broadlink switch.""" + + def __init__(self, friendly_name, command_on, command_off, device): + """Initialize the switch.""" + self._name = friendly_name + self._state = False + self._command_on = b64decode(command_on) if command_on else None + self._command_off = b64decode(command_off) if command_off else None + self._device = device + + @property + def name(self): + """Return the name of the switch.""" + return self._name + + @property + def assumed_state(self): + """Return true if unable to access real state of entity.""" + return True + + @property + def is_on(self): + """Return true if device is on.""" + return self._state + + def turn_on(self, **kwargs): + """Turn the device on.""" + if self._sendpacket(self._command_on): + self._state = True + + def turn_off(self, **kwargs): + """Turn the device off.""" + if self._sendpacket(self._command_off): + self._state = False + + def _sendpacket(self, packet, retry=2): + """Send packet to device.""" + if packet is None: + _LOGGER.debug("Empty packet.") + return True + try: + self._device.send_data(packet) + except socket.timeout as error: + if retry < 1: + _LOGGER.error(error) + return False + try: + self._device.auth() + except socket.timeout: + pass + return self._sendpacket(packet, max(0, retry-1)) + return True diff --git a/requirements_all.txt b/requirements_all.txt index f56c576f366..81b6eef84a4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -65,6 +65,10 @@ blockchain==1.3.3 # homeassistant.components.notify.aws_sqs boto3==1.3.1 +# homeassistant.components.sensor.broadlink +# homeassistant.components.switch.broadlink +broadlink==0.2 + # homeassistant.components.sensor.coinmarketcap coinmarketcap==2.0.1 From 7b45cf8e59bf7c40cf3b18c446c912b9874e0dbd Mon Sep 17 00:00:00 2001 From: Albert Lee Date: Thu, 15 Dec 2016 23:47:23 -0600 Subject: [PATCH 115/141] Expose media volume as emulated Hue brightness (#4869) * Allow virtual Hue bridge to set volume level of media_player entities * Show correct states in all lights view --- .../components/emulated_hue/hue_api.py | 111 ++++++++++++------ tests/components/emulated_hue/test_hue_api.py | 63 +++++++++- 2 files changed, 136 insertions(+), 38 deletions(-) diff --git a/homeassistant/components/emulated_hue/hue_api.py b/homeassistant/components/emulated_hue/hue_api.py index 32fb4af071c..57a4f18825a 100644 --- a/homeassistant/components/emulated_hue/hue_api.py +++ b/homeassistant/components/emulated_hue/hue_api.py @@ -6,12 +6,16 @@ from aiohttp import web from homeassistant import core from homeassistant.const import ( - ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON, - STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, + ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_SET, + STATE_ON, STATE_OFF, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, ) from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_SUPPORTED_FEATURES, SUPPORT_BRIGHTNESS ) +from homeassistant.components.media_player import ( + ATTR_MEDIA_VOLUME_LEVEL, ATTR_SUPPORTED_MEDIA_COMMANDS, + SUPPORT_VOLUME_SET, +) from homeassistant.components.http import HomeAssistantView _LOGGER = logging.getLogger(__name__) @@ -65,8 +69,11 @@ class HueAllLightsStateView(HomeAssistantView): for entity in hass.states.async_all(): if self.config.is_entity_exposed(entity): + state, brightness = get_entity_state(self.config, entity) + number = self.config.entity_id_to_number(entity.entity_id) - json_response[number] = entity_to_json(entity) + json_response[number] = entity_to_json( + entity, state, brightness) return self.json(json_response) @@ -97,16 +104,9 @@ class HueOneLightStateView(HomeAssistantView): _LOGGER.error('Entity not exposed: %s', entity_id) return web.Response(text="Entity not exposed", status=404) - cached_state = self.config.cached_states.get(entity_id, None) + state, brightness = get_entity_state(self.config, entity) - if cached_state is None: - final_state = entity.state == STATE_ON - final_brightness = entity.attributes.get( - ATTR_BRIGHTNESS, 255 if final_state else 0) - else: - final_state, final_brightness = cached_state - - json_response = entity_to_json(entity, final_state, final_brightness) + json_response = entity_to_json(entity, state, brightness) return self.json(json_response) @@ -158,14 +158,24 @@ class HueOneLightChangeView(HomeAssistantView): result, brightness = parsed + # Choose general HA domain + domain = core.DOMAIN + # Convert the resulting "on" status into the service we need to call service = SERVICE_TURN_ON if result else SERVICE_TURN_OFF # Construct what we need to send to the service data = {ATTR_ENTITY_ID: entity_id} + # Make sure the entity actually supports brightness + entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) + + if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS: + if brightness is not None: + data[ATTR_BRIGHTNESS] = brightness + # If the requested entity is a script add some variables - if entity.domain == "script": + elif entity.domain == "script": data['variables'] = { 'requested_state': STATE_ON if result else STATE_OFF } @@ -173,8 +183,16 @@ class HueOneLightChangeView(HomeAssistantView): if brightness is not None: data['variables']['requested_level'] = brightness - elif brightness is not None: - data[ATTR_BRIGHTNESS] = brightness + # 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 brightness is not None: + domain = entity.domain + service = SERVICE_VOLUME_SET + # Convert 0-100 to 0.0-1.0 + data[ATTR_MEDIA_VOLUME_LEVEL] = brightness / 100.0 if entity.domain in config.off_maps_to_on_domains: # Map the off command to on @@ -187,9 +205,14 @@ class HueOneLightChangeView(HomeAssistantView): # as the actual requested command. config.cached_states[entity_id] = (result, brightness) - # Perform the requested action - yield from hass.services.async_call(core.DOMAIN, service, data, - blocking=True) + # Separate call to turn on needed + if domain != core.DOMAIN: + hass.async_add_job(hass.services.async_call( + core.DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}, + blocking=True)) + + hass.async_add_job(hass.services.async_call( + domain, service, data, blocking=True)) json_response = \ [create_hue_success_response(entity_id, HUE_API_STATE_ON, result)] @@ -219,23 +242,23 @@ def parse_hue_api_put_light_body(request_json, entity): result = False if HUE_API_STATE_BRI in request_json: + try: + # Clamp brightness from 0 to 255 + brightness = \ + max(0, min(int(request_json[HUE_API_STATE_BRI]), 255)) + except ValueError: + return None + # Make sure the entity actually supports brightness entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS: - try: - # Clamp brightness from 0 to 255 - brightness = \ - max(0, min(int(request_json[HUE_API_STATE_BRI]), 255)) - except ValueError: - return None - report_brightness = True result = (brightness > 0) - elif entity.domain.lower() == "script": - # Convert 0-255 to 0-100 - level = int(request_json[HUE_API_STATE_BRI]) / 255 * 100 + elif entity.domain == "script" or entity.domain == "media_player": + # Convert 0-255 to 0-100 + level = brightness / 255 * 100 brightness = round(level) report_brightness = True result = True @@ -243,14 +266,34 @@ def parse_hue_api_put_light_body(request_json, entity): return (result, brightness) if report_brightness else (result, None) +def get_entity_state(config, entity): + """Retrieve and convert state and brightness values for an entity.""" + cached_state = config.cached_states.get(entity.entity_id, None) + + if cached_state is None: + final_state = entity.state != STATE_OFF + final_brightness = entity.attributes.get( + ATTR_BRIGHTNESS, 255 if final_state else 0) + + # Make sure the entity actually supports brightness + entity_features = entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0) + + if (entity_features & SUPPORT_BRIGHTNESS) == SUPPORT_BRIGHTNESS: + pass + + elif entity.domain == "media_player": + level = entity.attributes.get( + ATTR_MEDIA_VOLUME_LEVEL, 1.0 if final_state else 0.0) + # Convert 0.0-1.0 to 0-255 + final_brightness = round(min(1.0, level) * 255) + else: + final_state, final_brightness = cached_state + + return (final_state, final_brightness) + + def entity_to_json(entity, is_on=None, brightness=None): """Convert an entity to its Hue bridge JSON representation.""" - if is_on is None: - is_on = entity.state == STATE_ON - - if brightness is None: - brightness = 255 if is_on else 0 - name = entity.attributes.get(ATTR_EMULATED_HUE_NAME, entity.name) return { diff --git a/tests/components/emulated_hue/test_hue_api.py b/tests/components/emulated_hue/test_hue_api.py index 9cee27f570f..4aab6401939 100644 --- a/tests/components/emulated_hue/test_hue_api.py +++ b/tests/components/emulated_hue/test_hue_api.py @@ -7,7 +7,9 @@ import requests from homeassistant import bootstrap, const, core import homeassistant.components as core_components -from homeassistant.components import emulated_hue, http, light, script +from homeassistant.components import ( + emulated_hue, http, light, script, media_player +) from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.components.emulated_hue.hue_api import ( HUE_API_STATE_ON, HUE_API_STATE_BRI) @@ -73,6 +75,14 @@ class TestEmulatedHueExposedByDefault(unittest.TestCase): } }) + bootstrap.setup_component(cls.hass, media_player.DOMAIN, { + 'media_player': [ + { + 'platform': 'demo', + } + ] + }) + cls.hass.start() # Kitchen light is explicitly excluded from being exposed @@ -111,6 +121,10 @@ class TestEmulatedHueExposedByDefault(unittest.TestCase): self.assertTrue('light.bed_light' in result_json) self.assertTrue('script.set_kitchen_light' in result_json) self.assertTrue('light.kitchen_lights' not in result_json) + self.assertTrue('media_player.living_room' in result_json) + self.assertTrue('media_player.bedroom' in result_json) + self.assertTrue('media_player.walkman' in result_json) + self.assertTrue('media_player.lounge_room' in result_json) def test_get_light_state(self): """Test the getting of light state.""" @@ -128,6 +142,21 @@ class TestEmulatedHueExposedByDefault(unittest.TestCase): self.assertEqual(office_json['state'][HUE_API_STATE_ON], True) self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127) + # Check all lights view + result = requests.get( + BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5) + + self.assertEqual(result.status_code, 200) + self.assertTrue('application/json' in result.headers['content-type']) + + result_json = result.json() + + self.assertTrue('light.ceiling_lights' in result_json) + self.assertEqual( + result_json['light.ceiling_lights']['state'][HUE_API_STATE_BRI], + 127, + ) + # Turn bedroom light off self.hass.services.call( light.DOMAIN, const.SERVICE_TURN_OFF, @@ -204,15 +233,38 @@ class TestEmulatedHueExposedByDefault(unittest.TestCase): self.assertEqual(script_result.status_code, 200) self.assertEqual(len(script_result_json), 2) - # Wait until script is complete before continuing - self.hass.block_till_done() - kitchen_light = self.hass.states.get('light.kitchen_lights') self.assertEqual(kitchen_light.state, 'on') self.assertEqual( kitchen_light.attributes[light.ATTR_BRIGHTNESS], level) + def test_put_light_state_media_player(self): + """Test turning on media player and setting volume.""" + # Turn the music player off first + self.hass.services.call( + media_player.DOMAIN, const.SERVICE_TURN_OFF, + {const.ATTR_ENTITY_ID: 'media_player.walkman'}, + blocking=True) + + # Emulated hue converts 0.0-1.0 to 0-255. + level = 0.25 + brightness = round(level * 255) + + mp_result = self.perform_put_light_state( + 'media_player.walkman', True, brightness) + + mp_result_json = mp_result.json() + + self.assertEqual(mp_result.status_code, 200) + self.assertEqual(len(mp_result_json), 2) + + walkman = self.hass.states.get('media_player.walkman') + self.assertEqual(walkman.state, 'playing') + self.assertEqual( + walkman.attributes[media_player.ATTR_MEDIA_VOLUME_LEVEL], + level) + # pylint: disable=invalid-name def test_put_with_form_urlencoded_content_type(self): """Test the form with urlencoded content.""" @@ -352,4 +404,7 @@ class TestEmulatedHueExposedByDefault(unittest.TestCase): result = requests.put( url, data=json.dumps(data), timeout=5, headers=req_headers) + # Wait until state change is complete before continuing + self.hass.block_till_done() + return result From 5b70ada7b4d352d998d1d35fd604943499becf0d Mon Sep 17 00:00:00 2001 From: Magas Date: Fri, 16 Dec 2016 01:11:58 -0500 Subject: [PATCH 116/141] Panasonic viera fix (#4888) * Removed return False so the Panasonic Viera TV can be added even if it doesn't connect * Removed return False so the Panasonic Viera TV can be added even if it doesn't connect * Removed return False so the Panasonic Viera TV can be added even if it doesn't connect * Remove try/except to connect to the TV * Update panasonic_viera.py * Update panasonic_viera.py --- homeassistant/components/media_player/panasonic_viera.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/homeassistant/components/media_player/panasonic_viera.py b/homeassistant/components/media_player/panasonic_viera.py index 987364bbf63..bbac8f243d3 100644 --- a/homeassistant/components/media_player/panasonic_viera.py +++ b/homeassistant/components/media_player/panasonic_viera.py @@ -57,13 +57,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): host = config.get(CONF_HOST) remote = RemoteControl(host, port) - try: - remote.get_mute() - except OSError as error: - _LOGGER.error('Panasonic Viera TV is not available at %s:%d: %s', - host, port, error) - return False - add_devices([PanasonicVieraTVDevice(name, remote)]) return True From 2a31bb48c6907731ca729101fc687c98344a8ecc Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 16 Dec 2016 07:12:33 +0100 Subject: [PATCH 117/141] Clean-up (#4894) --- homeassistant/components/sensor/arwn.py | 42 +++++++++++++------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/sensor/arwn.py b/homeassistant/components/sensor/arwn.py index 5eb95ba16d1..c0012b4ac92 100644 --- a/homeassistant/components/sensor/arwn.py +++ b/homeassistant/components/sensor/arwn.py @@ -1,23 +1,25 @@ -"""Support for collecting data from the ARWN project. - -For more details about this platform, please refer to the -documentation at https://home-assistant.io/components/sensor.arwn/ +""" +Support for collecting data from the ARWN project. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.arwn/ """ import json import logging -from homeassistant.helpers.entity import Entity + import homeassistant.components.mqtt as mqtt from homeassistant.const import (TEMP_FAHRENHEIT, TEMP_CELSIUS) +from homeassistant.helpers.entity import Entity from homeassistant.util import slugify -DEPENDENCIES = ['mqtt'] +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['mqtt'] +DOMAIN = 'arwn' -DOMAIN = "arwn" -TOPIC = 'arwn/#' SENSORS = {} -_LOGGER = logging.getLogger(__name__) +TOPIC = 'arwn/#' def discover_sensors(topic, payload): @@ -25,23 +27,23 @@ def discover_sensors(topic, payload): parts = topic.split('/') unit = payload.get('units', '') domain = parts[1] - if domain == "temperature": + if domain == 'temperature': name = parts[2] - if unit == "F": + if unit == 'F': unit = TEMP_FAHRENHEIT else: unit = TEMP_CELSIUS - return (ArwnSensor(name, 'temp', unit),) - if domain == "barometer": - return (ArwnSensor("Barometer", 'pressure', unit),) - if domain == "wind": - return (ArwnSensor("Wind Speed", 'speed', unit), - ArwnSensor("Wind Gust", 'gust', unit), - ArwnSensor("Wind Direction", 'direction', '°')) + return ArwnSensor(name, 'temp', unit) + if domain == 'barometer': + return ArwnSensor('Barometer', 'pressure', unit) + if domain == 'wind': + return (ArwnSensor('Wind Speed', 'speed', unit), + ArwnSensor('Wind Gust', 'gust', unit), + ArwnSensor('Wind Direction', 'direction', '°')) def _slug(name): - return "sensor.arwn_%s" % slugify(name) + return 'sensor.arwn_{}'.format(slugify(name)) def setup_platform(hass, config, add_devices, discovery_info=None): @@ -84,7 +86,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class ArwnSensor(Entity): - """Represents an ARWN sensor.""" + """Representation of an ARWN sensor.""" def __init__(self, name, state_key, units): """Initialize the sensor.""" From 02517ae5ec148d021cbeaed9bab86fef5e2e7a2a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 15 Dec 2016 22:13:38 -0800 Subject: [PATCH 118/141] Fix synologydsm (#4895) --- homeassistant/components/sensor/synologydsm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/synologydsm.py b/homeassistant/components/sensor/synologydsm.py index 6dc23a71d9b..8ee0d6eae18 100644 --- a/homeassistant/components/sensor/synologydsm.py +++ b/homeassistant/components/sensor/synologydsm.py @@ -107,7 +107,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): # Handle all Volumes volumes = config['volumes'] if volumes is None: - volumes = api.storage().volumes + volumes = api.storage.volumes for volume in volumes: sensors += [SynoNasStorageSensor(api, variable, @@ -119,7 +119,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): # Handle all Disks disks = config['disks'] if disks is None: - disks = api.storage().disks + disks = api.storage.disks for disk in disks: sensors += [SynoNasStorageSensor(api, variable, From 7748867732b4314db6d84d3ffeca4c0cf93b2f23 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 16 Dec 2016 07:14:59 +0100 Subject: [PATCH 119/141] Avoid TypeError for state (#4897) --- homeassistant/components/sensor/coinmarketcap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/coinmarketcap.py b/homeassistant/components/sensor/coinmarketcap.py index e041352af58..eee43328f29 100644 --- a/homeassistant/components/sensor/coinmarketcap.py +++ b/homeassistant/components/sensor/coinmarketcap.py @@ -77,7 +77,7 @@ class CoinMarketCapSensor(Entity): @property def state(self): """Return the state of the sensor.""" - return round(self._ticker.get('price_usd'), 2) + return round(float(self._ticker.get('price_usd')), 2) @property def unit_of_measurement(self): From 103fffa0f4498a09b32c3f9547dcb974978b7729 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Fri, 16 Dec 2016 07:20:00 +0100 Subject: [PATCH 120/141] Add support for new netdisco detection of Samsung Smart TV. (#4925) --- homeassistant/components/discovery.py | 1 + .../components/media_player/samsungtv.py | 54 ++++++++++++++----- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 74dc5d69220..32cb205fa0f 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -37,6 +37,7 @@ SERVICE_HANDLERS = { 'logitech_mediaserver': ('media_player', 'squeezebox'), 'directv': ('media_player', 'directv'), 'denonavr': ('media_player', 'denonavr'), + 'samsung_tv': ('media_player', 'samsungtv'), } CONFIG_SCHEMA = vol.Schema({ diff --git a/homeassistant/components/media_player/samsungtv.py b/homeassistant/components/media_player/samsungtv.py index a43e8b551a3..c7705393381 100644 --- a/homeassistant/components/media_player/samsungtv.py +++ b/homeassistant/components/media_player/samsungtv.py @@ -5,6 +5,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/media_player.samsungtv/ """ import logging +import socket import voluptuous as vol @@ -26,6 +27,8 @@ DEFAULT_NAME = 'Samsung TV Remote' DEFAULT_PORT = 55000 DEFAULT_TIMEOUT = 0 +KNOWN_DEVICES_KEY = 'samsungtv_known_devices' + SUPPORT_SAMSUNGTV = SUPPORT_PAUSE | SUPPORT_VOLUME_STEP | \ SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | \ SUPPORT_NEXT_TRACK | SUPPORT_TURN_OFF @@ -41,25 +44,42 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """Setup the Samsung TV platform.""" - name = config.get(CONF_NAME) + known_devices = hass.data.get(KNOWN_DEVICES_KEY) + if known_devices is None: + known_devices = set() + hass.data[KNOWN_DEVICES_KEY] = known_devices - # Generate a configuration for the Samsung library - remote_config = { - 'name': 'HomeAssistant', - 'description': config.get(CONF_NAME), - 'id': 'ha.component.samsung', - 'port': config.get(CONF_PORT), - 'host': config.get(CONF_HOST), - 'timeout': config.get(CONF_TIMEOUT), - } + # Is this a manual configuration? + if config.get(CONF_HOST) is not None: + host = config.get(CONF_HOST) + port = config.get(CONF_PORT) + name = config.get(CONF_NAME) + timeout = config.get(CONF_TIMEOUT) + elif discovery_info is not None: + tv_name, model, host = discovery_info + name = "{} ({})".format(tv_name, model) + port = DEFAULT_PORT + timeout = DEFAULT_TIMEOUT + else: + _LOGGER.warning( + 'Internal error on samsungtv component. Cannot determine device') + return - add_devices([SamsungTVDevice(name, remote_config)]) + # Only add a device once, so discovered devices do not override manual + # config. + ip_addr = socket.gethostbyname(host) + if ip_addr not in known_devices: + known_devices.add(ip_addr) + add_devices([SamsungTVDevice(host, port, name, timeout)]) + _LOGGER.info("Samsung TV %s:%d added as '%s'", host, port, name) + else: + _LOGGER.info("Ignoring duplicate Samsung TV %s:%d", host, port) class SamsungTVDevice(MediaPlayerDevice): """Representation of a Samsung TV.""" - def __init__(self, name, config): + def __init__(self, host, port, name, timeout): """Initialize the Samsung device.""" from samsungctl import Remote # Save a reference to the imported class @@ -71,7 +91,15 @@ class SamsungTVDevice(MediaPlayerDevice): self._playing = True self._state = STATE_UNKNOWN self._remote = None - self._config = config + # Generate a configuration for the Samsung library + self._config = { + 'name': 'HomeAssistant', + 'description': name, + 'id': 'ha.component.samsung', + 'port': port, + 'host': host, + 'timeout': timeout, + } def update(self): """Retrieve the latest data.""" From b9dcc2777b0cff2f874ad7de1b846958070e4777 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Fri, 16 Dec 2016 01:27:37 -0500 Subject: [PATCH 121/141] Setup DarkSky platform when offline during init (#4919) * Setup DarkSky platform when offline during init * Fail setup_platform if fetch was unsuccessful --- homeassistant/components/sensor/darksky.py | 42 +++++++++++----------- tests/components/sensor/test_darksky.py | 13 ++++++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/sensor/darksky.py b/homeassistant/components/sensor/darksky.py index c57b4ba30e8..173990a6a2f 100644 --- a/homeassistant/components/sensor/darksky.py +++ b/homeassistant/components/sensor/darksky.py @@ -104,19 +104,17 @@ def setup_platform(hass, config, add_devices, discovery_info=None): else: units = 'us' - # Create a data fetcher to support all of the configured sensors. Then make - # the first call to init the data and confirm we can connect. - try: - forecast_data = DarkSkyData( - api_key=config.get(CONF_API_KEY, None), - latitude=hass.config.latitude, - longitude=hass.config.longitude, - units=units, - interval=config.get(CONF_UPDATE_INTERVAL)) - forecast_data.update() - forecast_data.update_currently() - except ValueError as error: - _LOGGER.error(error) + forecast_data = DarkSkyData( + api_key=config.get(CONF_API_KEY, None), + latitude=hass.config.latitude, + longitude=hass.config.longitude, + units=units, + interval=config.get(CONF_UPDATE_INTERVAL)) + forecast_data.update() + forecast_data.update_currently() + + # If connection failed don't setup platform. + if forecast_data.data is None: return False name = config.get(CONF_NAME) @@ -227,7 +225,10 @@ class DarkSkySensor(Entity): If the sensor type is unknown, the current state is returned. """ lookup_type = convert_to_camel(self.type) - state = getattr(data, lookup_type, 0) + state = getattr(data, lookup_type, None) + + if state is None: + return state # Some state data needs to be rounded to whole values or converted to # percentages @@ -284,21 +285,22 @@ class DarkSkyData(object): self.data = forecastio.load_forecast( self._api_key, self.latitude, self.longitude, units=self.units) except (ConnectError, HTTPError, Timeout, ValueError) as error: - raise ValueError("Unable to init Dark Sky. %s", error) - self.unit_system = self.data.json['flags']['units'] + _LOGGER.error("Unable to connect to Dark Sky. %s", error) + self.data = None + self.unit_system = self.data and self.data.json['flags']['units'] def _update_currently(self): """Update currently data.""" - self.data_currently = self.data.currently() + self.data_currently = self.data and self.data.currently() def _update_minutely(self): """Update minutely data.""" - self.data_minutely = self.data.minutely() + self.data_minutely = self.data and self.data.minutely() def _update_hourly(self): """Update hourly data.""" - self.data_hourly = self.data.hourly() + self.data_hourly = self.data and self.data.hourly() def _update_daily(self): """Update daily data.""" - self.data_daily = self.data.daily() + self.data_daily = self.data and self.data.daily() diff --git a/tests/components/sensor/test_darksky.py b/tests/components/sensor/test_darksky.py index 09ced049b58..976a9278452 100644 --- a/tests/components/sensor/test_darksky.py +++ b/tests/components/sensor/test_darksky.py @@ -17,6 +17,15 @@ from tests.common import load_fixture, get_test_home_assistant class TestDarkSkySetup(unittest.TestCase): """Test the Dark Sky platform.""" + def add_entities(self, new_entities, update_before_add=False): + """Mock add entities.""" + if update_before_add: + for entity in new_entities: + entity.update() + + for entity in new_entities: + self.entities.append(entity) + def setUp(self): """Initialize values for this testcase class.""" self.hass = get_test_home_assistant() @@ -30,6 +39,7 @@ class TestDarkSkySetup(unittest.TestCase): self.lon = -122.423 self.hass.config.latitude = self.lat self.hass.config.longitude = self.lon + self.entities = [] def test_setup_with_config(self): """Test the platform setup with configuration.""" @@ -63,6 +73,7 @@ class TestDarkSkySetup(unittest.TestCase): r'(-?\d+\.?\d*),(-?\d+\.?\d*)') mock_req.get(re.compile(uri), text=load_fixture('darksky.json')) - darksky.setup_platform(self.hass, self.config, MagicMock()) + darksky.setup_platform(self.hass, self.config, self.add_entities) self.assertTrue(mock_get_forecast.called) self.assertEqual(mock_get_forecast.call_count, 1) + self.assertEqual(len(self.entities), 2) From 757f6278eb93db41d0a57137969635c24afc3304 Mon Sep 17 00:00:00 2001 From: Erik Eriksson Date: Fri, 16 Dec 2016 07:35:53 +0100 Subject: [PATCH 122/141] initialize self._last_brightness (#4917) --- homeassistant/components/light/tellduslive.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/light/tellduslive.py b/homeassistant/components/light/tellduslive.py index f919268c380..31f9eb1d253 100644 --- a/homeassistant/components/light/tellduslive.py +++ b/homeassistant/components/light/tellduslive.py @@ -26,9 +26,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class TelldusLiveLight(TelldusLiveEntity, Light): """Representation of a light.""" + def __init__(self, hass, device_id): + """Initialize the light.""" + super().__init__(hass, device_id) + self._last_brightness = self.brightness + def changed(self): """A property of the device might have changed.""" - # pylint: disable=attribute-defined-outside-init self._last_brightness = self.brightness super().changed() From 5c4f04e9fc54a192f368be343a7426df55839d08 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Fri, 16 Dec 2016 08:51:08 +0200 Subject: [PATCH 123/141] Fix webostv component to accept any custom sources (#4915) Updated the schema check to accept any string Search custom sources in app title and app id The makes the short list redundant and thus removed Tested by adding livetv, netflix, youtube, makovod and others This is also compatible with the list that was supported till now so current users won't see any difference. Signed-off-by: Roi Dayan --- .../components/media_player/webostv.py | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/media_player/webostv.py b/homeassistant/components/media_player/webostv.py index e131cad97cd..40792c338b2 100644 --- a/homeassistant/components/media_player/webostv.py +++ b/homeassistant/components/media_player/webostv.py @@ -41,19 +41,9 @@ SUPPORT_WEBOSTV = SUPPORT_PAUSE | SUPPORT_VOLUME_STEP | \ MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1) -WEBOS_APP_LIVETV = 'com.webos.app.livetv' -WEBOS_APP_YOUTUBE = 'youtube.leanback.v4' -WEBOS_APP_MAKO = 'makotv' - -WEBOS_APPS_SHORT = { - 'livetv': WEBOS_APP_LIVETV, - 'youtube': WEBOS_APP_YOUTUBE, - 'makotv': WEBOS_APP_MAKO -} - CUSTOMIZE_SCHEMA = vol.Schema({ vol.Optional(CONF_SOURCES): - vol.All(cv.ensure_list, [vol.In(WEBOS_APPS_SHORT)]), + vol.All(cv.ensure_list, [cv.string]), }) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -175,20 +165,16 @@ class LgWebOSDevice(MediaPlayerDevice): self._source_list = {} self._app_list = {} - custom_sources = [] - for source in self._customize.get(CONF_SOURCES, []): - app_id = WEBOS_APPS_SHORT.get(source, None) - if app_id: - custom_sources.append(app_id) - else: - custom_sources.append(source) + custom_sources = self._customize.get(CONF_SOURCES, []) for app in self._client.get_apps(): self._app_list[app['id']] = app if app['id'] == self._current_source_id: self._current_source = app['title'] self._source_list[app['title']] = app - if app['id'] in custom_sources: + elif (app['id'] in custom_sources or + any(word in app['title'] for word in custom_sources) or + any(word in app['id'] for word in custom_sources)): self._source_list[app['title']] = app for source in self._client.get_inputs(): From 9f9b87692a3176719990a8d12e01334c9efba4f4 Mon Sep 17 00:00:00 2001 From: Nolan Gilley Date: Fri, 16 Dec 2016 01:55:51 -0500 Subject: [PATCH 124/141] add manual option to prevent scheduled tests. (#4906) --- homeassistant/components/sensor/fastdotcom.py | 13 ++++++++----- homeassistant/components/sensor/speedtest.py | 13 ++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/sensor/fastdotcom.py b/homeassistant/components/sensor/fastdotcom.py index 0390ea0e9d6..a055d1795e1 100644 --- a/homeassistant/components/sensor/fastdotcom.py +++ b/homeassistant/components/sensor/fastdotcom.py @@ -22,6 +22,7 @@ CONF_SECOND = 'second' CONF_MINUTE = 'minute' CONF_HOUR = 'hour' CONF_DAY = 'day' +CONF_MANUAL = 'manual' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_SECOND, default=[0]): @@ -32,6 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(0, 23))]), vol.Optional(CONF_DAY): vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(1, 31))]), + vol.Optional(CONF_MANUAL, default=False): cv.boolean, }) @@ -104,11 +106,12 @@ class SpeedtestData(object): def __init__(self, hass, config): """Initialize the data object.""" self.data = None - track_time_change(hass, self.update, - second=config.get(CONF_SECOND), - minute=config.get(CONF_MINUTE), - hour=config.get(CONF_HOUR), - day=config.get(CONF_DAY)) + if not config.get(CONF_MANUAL): + track_time_change(hass, self.update, + second=config.get(CONF_SECOND), + minute=config.get(CONF_MINUTE), + hour=config.get(CONF_HOUR), + day=config.get(CONF_DAY)) def update(self, now): """Get the latest data from fast.com.""" diff --git a/homeassistant/components/sensor/speedtest.py b/homeassistant/components/sensor/speedtest.py index 3087c74d474..dff6f1c9dde 100644 --- a/homeassistant/components/sensor/speedtest.py +++ b/homeassistant/components/sensor/speedtest.py @@ -31,6 +31,7 @@ CONF_MINUTE = 'minute' CONF_HOUR = 'hour' CONF_DAY = 'day' CONF_SERVER_ID = 'server_id' +CONF_MANUAL = 'manual' SENSOR_TYPES = { 'ping': ['Ping', 'ms'], @@ -50,6 +51,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(0, 23))]), vol.Optional(CONF_DAY): vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(1, 31))]), + vol.Optional(CONF_MANUAL, default=False): cv.boolean, }) @@ -135,11 +137,12 @@ class SpeedtestData(object): """Initialize the data object.""" self.data = None self._server_id = config.get(CONF_SERVER_ID) - track_time_change(hass, self.update, - second=config.get(CONF_SECOND), - minute=config.get(CONF_MINUTE), - hour=config.get(CONF_HOUR), - day=config.get(CONF_DAY)) + if not config.get(CONF_MANUAL): + track_time_change(hass, self.update, + second=config.get(CONF_SECOND), + minute=config.get(CONF_MINUTE), + hour=config.get(CONF_HOUR), + day=config.get(CONF_DAY)) def update(self, now): """Get the latest data from speedtest.net.""" From a0b2105ea032c953195012928953694b214c5755 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 16 Dec 2016 09:10:48 +0100 Subject: [PATCH 125/141] Add voicerss for TTS (#4916) * Add voicerss for TTS * add unittests * fix tests * fix status bug in google/voicerss * remove ssl --- homeassistant/components/tts/google.py | 4 +- homeassistant/components/tts/voicerss.py | 120 +++++++++++++++++ tests/components/tts/test_voicerss.py | 162 +++++++++++++++++++++++ 3 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 homeassistant/components/tts/voicerss.py create mode 100644 tests/components/tts/test_voicerss.py diff --git a/homeassistant/components/tts/google.py b/homeassistant/components/tts/google.py index 92794cd00b6..49d53961062 100644 --- a/homeassistant/components/tts/google.py +++ b/homeassistant/components/tts/google.py @@ -92,8 +92,8 @@ class GoogleProvider(Provider): ) if request.status != 200: - _LOGGER.error("Error %d on load url %s", request.code, - request.url) + _LOGGER.error("Error %d on load url %s", + request.status, request.url) return (None, None) data += yield from request.read() diff --git a/homeassistant/components/tts/voicerss.py b/homeassistant/components/tts/voicerss.py new file mode 100644 index 00000000000..728a1996a5d --- /dev/null +++ b/homeassistant/components/tts/voicerss.py @@ -0,0 +1,120 @@ +""" +Support for the voicerss speech service. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/tts/voicerss/ +""" +import asyncio +import logging + +import aiohttp +import async_timeout +import voluptuous as vol + +from homeassistant.const import CONF_API_KEY +from homeassistant.components.tts import Provider, PLATFORM_SCHEMA, CONF_LANG +from homeassistant.helpers.aiohttp_client import async_get_clientsession +import homeassistant.helpers.config_validation as cv + + +_LOGGER = logging.getLogger(__name__) + +VOICERSS_API_URL = "https://api.voicerss.org/" + +SUPPORT_LANGUAGES = [ + 'ca-es', 'zh-cn', 'zh-hk', 'zh-tw', 'da-dk', 'nl-nl', 'en-au', 'en-ca', + 'en-gb', 'en-in', 'en-us', 'fi-fi', 'fr-ca', 'fr-fr', 'de-de', 'it-it', + 'ja-jp', 'ko-kr', 'nb-no', 'pl-pl', 'pt-br', 'pt-pt', 'ru-ru', 'es-mx', + 'es-es', 'sv-se', +] + +SUPPORT_CODECS = [ + 'mp3', 'wav', 'aac', 'ogg', 'caf' +] + +SUPPORT_FORMATS = [ + '8khz_8bit_mono', '8khz_8bit_stereo', '8khz_16bit_mono', + '8khz_16bit_stereo', '11khz_8bit_mono', '11khz_8bit_stereo', + '11khz_16bit_mono', '11khz_16bit_stereo', '12khz_8bit_mono', + '12khz_8bit_stereo', '12khz_16bit_mono', '12khz_16bit_stereo', + '16khz_8bit_mono', '16khz_8bit_stereo', '16khz_16bit_mono', + '16khz_16bit_stereo', '22khz_8bit_mono', '22khz_8bit_stereo', + '22khz_16bit_mono', '22khz_16bit_stereo', '24khz_8bit_mono', + '24khz_8bit_stereo', '24khz_16bit_mono', '24khz_16bit_stereo', + '32khz_8bit_mono', '32khz_8bit_stereo', '32khz_16bit_mono', + '32khz_16bit_stereo', '44khz_8bit_mono', '44khz_8bit_stereo', + '44khz_16bit_mono', '44khz_16bit_stereo', '48khz_8bit_mono', + '48khz_8bit_stereo', '48khz_16bit_mono', '48khz_16bit_stereo', + 'alaw_8khz_mono', 'alaw_8khz_stereo', 'alaw_11khz_mono', + 'alaw_11khz_stereo', 'alaw_22khz_mono', 'alaw_22khz_stereo', + 'alaw_44khz_mono', 'alaw_44khz_stereo', 'ulaw_8khz_mono', + 'ulaw_8khz_stereo', 'ulaw_11khz_mono', 'ulaw_11khz_stereo', + 'ulaw_22khz_mono', 'ulaw_22khz_stereo', 'ulaw_44khz_mono', + 'ulaw_44khz_stereo', +] + +CONF_CODEC = 'codec' +CONF_FORMAT = 'format' + +DEFAULT_LANG = 'en-us' +DEFAULT_CODEC = 'mp3' +DEFAULT_FORMAT = '8khz_8bit_mono' + + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_API_KEY): cv.string, + vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORT_LANGUAGES), + vol.Optional(CONF_CODEC, default=DEFAULT_CODEC): vol.In(SUPPORT_CODECS), + vol.Optional(CONF_FORMAT, default=DEFAULT_FORMAT): vol.In(SUPPORT_FORMATS), +}) + + +@asyncio.coroutine +def async_get_engine(hass, config): + """Setup VoiceRSS speech component.""" + return VoiceRSSProvider(hass, config) + + +class VoiceRSSProvider(Provider): + """VoiceRSS speech api provider.""" + + def __init__(self, hass, conf): + """Init VoiceRSS TTS service.""" + self.hass = hass + self.extension = conf.get(CONF_CODEC) + + self.params = { + 'key': conf.get(CONF_API_KEY), + 'hl': conf.get(CONF_LANG), + 'c': (conf.get(CONF_CODEC)).upper(), + 'f': conf.get(CONF_FORMAT), + } + + @asyncio.coroutine + def async_get_tts_audio(self, message): + """Load TTS from voicerss.""" + websession = async_get_clientsession(self.hass) + + request = None + try: + with async_timeout.timeout(10, loop=self.hass.loop): + request = yield from websession.post( + VOICERSS_API_URL, params=self.params, + data=bytes(message, 'utf-8') + ) + + if request.status != 200: + _LOGGER.error("Error %d on load url %s", + request.status, request.url) + return (None, None) + data = yield from request.read() + + except (asyncio.TimeoutError, aiohttp.errors.ClientError): + _LOGGER.error("Timeout for voicerss api.") + return (None, None) + + finally: + if request is not None: + yield from request.release() + + return (self.extension, data) diff --git a/tests/components/tts/test_voicerss.py b/tests/components/tts/test_voicerss.py new file mode 100644 index 00000000000..44ce0d6739f --- /dev/null +++ b/tests/components/tts/test_voicerss.py @@ -0,0 +1,162 @@ +"""The tests for the VoiceRSS speech platform.""" +import asyncio +import os +import shutil + +import homeassistant.components.tts as tts +from homeassistant.components.media_player import ( + SERVICE_PLAY_MEDIA, ATTR_MEDIA_CONTENT_ID, DOMAIN as DOMAIN_MP) +from homeassistant.bootstrap import setup_component + +from tests.common import ( + get_test_home_assistant, assert_setup_component, mock_service) + + +class TestTTSVoiceRSSPlatform(object): + """Test the voicerss speech component.""" + + def setup_method(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + self.url = "https://api.voicerss.org/" + self.url_param = { + 'key': '1234567xx', + 'hl': 'en-us', + 'c': 'MP3', + 'f': '8khz_8bit_mono', + } + + def teardown_method(self): + """Stop everything that was started.""" + default_tts = self.hass.config.path(tts.DEFAULT_CACHE_DIR) + if os.path.isdir(default_tts): + shutil.rmtree(default_tts) + + self.hass.stop() + + def test_setup_component(self): + """Test setup component.""" + config = { + tts.DOMAIN: { + 'platform': 'voicerss', + 'api_key': '1234567xx' + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + def test_setup_component_without_api_key(self): + """Test setup component without api key.""" + config = { + tts.DOMAIN: { + 'platform': 'voicerss', + } + } + + with assert_setup_component(0, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + def test_service_say(self, aioclient_mock): + """Test service call say.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + aioclient_mock.post( + self.url, params=self.url_param, status=200, content=b'test') + + config = { + tts.DOMAIN: { + 'platform': 'voicerss', + 'api_key': '1234567xx', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'voicerss_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert len(aioclient_mock.mock_calls) == 1 + assert calls[0].data[ATTR_MEDIA_CONTENT_ID].find(".mp3") != -1 + + def test_service_say_german(self, aioclient_mock): + """Test service call say with german code.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + self.url_param['hl'] = 'de-de' + aioclient_mock.post( + self.url, params=self.url_param, status=200, content=b'test') + + config = { + tts.DOMAIN: { + 'platform': 'voicerss', + 'api_key': '1234567xx', + 'language': 'de-de', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'voicerss_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 1 + assert len(aioclient_mock.mock_calls) == 1 + + def test_service_say_error(self, aioclient_mock): + """Test service call say with http response 400.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + aioclient_mock.post( + self.url, params=self.url_param, status=400, content=b'test') + + config = { + tts.DOMAIN: { + 'platform': 'voicerss', + 'api_key': '1234567xx', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'voicerss_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 0 + assert len(aioclient_mock.mock_calls) == 1 + + def test_service_say_timeout(self, aioclient_mock): + """Test service call say with http timeout.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + aioclient_mock.post( + self.url, params=self.url_param, exc=asyncio.TimeoutError()) + + config = { + tts.DOMAIN: { + 'platform': 'voicerss', + 'api_key': '1234567xx', + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'voicerss_say', { + tts.ATTR_MESSAGE: "I person is on front of your door.", + }) + self.hass.block_till_done() + + assert len(calls) == 0 + assert len(aioclient_mock.mock_calls) == 1 From b318a033bbf7f71538e865552df01f9502a30a6f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 16 Dec 2016 00:10:56 -0800 Subject: [PATCH 126/141] Cast fix (#4939) * Update frontend * Fix exception on cast startup --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 8 ++++---- .../frontend/www_static/frontend.html.gz | Bin 130940 -> 131040 bytes .../www_static/home-assistant-polymer | 2 +- .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2326 -> 2324 bytes homeassistant/components/media_player/cast.py | 6 +++--- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index f316a07dab9..6c480254cb8 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -2,7 +2,7 @@ FINGERPRINTS = { "core.js": "ad1ebcd0614c98a390d982087a7ca75c", - "frontend.html": "920bb20410f9a1b8458600b15a1d40ae", + "frontend.html": "826ee6a4b39c939e31aa468b1ef618f9", "mdi.html": "46a76f877ac9848899b8ed382427c16f", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-dev-event.html": "c2d5ec676be98d4474d19f94d0262c1e", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 474db7d63c4..d8ab01b320f 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -1,5 +1,5 @@ - \ 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 7d29d3b9612a0a75b3204479f3f6ee038cf9e6bf..3708f52a28065a5713abca93a753c689e6d1d4b8 100644 GIT binary patch delta 123746 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