From 15538442795685b06be8c387751a2a87fea4def4 Mon Sep 17 00:00:00 2001 From: Heiko Rothe Date: Tue, 22 Sep 2015 22:48:43 +0200 Subject: [PATCH 001/226] Added support for the newest tp-link firmware Currently this seemingly only applies to the Archer C9 --- .../components/device_tracker/tplink.py | 111 +++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 6b12000cf45..2ecfaea4eb2 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -54,10 +54,13 @@ def get_scanner(hass, config): _LOGGER): return None - scanner = Tplink2DeviceScanner(config[DOMAIN]) + scanner = Tplink3DeviceScanner(config[DOMAIN]) if not scanner.success_init: - scanner = TplinkDeviceScanner(config[DOMAIN]) + scanner = Tplink2DeviceScanner(config[DOMAIN]) + + if not scanner.success_init: + scanner = TplinkDeviceScanner(config[DOMAIN]) return scanner if scanner.success_init else None @@ -79,6 +82,9 @@ class TplinkDeviceScanner(object): self.username = username self.password = password + self.stok = '' + self.sysauth = '' + self.last_results = {} self.lock = threading.Lock() self.success_init = self._update_info() @@ -187,3 +193,104 @@ class Tplink2DeviceScanner(TplinkDeviceScanner): return True return False + +class Tplink3DeviceScanner(TplinkDeviceScanner): + """ + This class queries the Archer C9 router running version 150811 or higher + of TP-Link firmware for connected devices. + """ + + def scan_devices(self): + """ + Scans for new devices and return a list containing found device ids. + """ + + self._update_info() + return self.last_results.keys() + + # pylint: disable=no-self-use + def get_device_name(self, device): + """ + The TP-Link firmware doesn't save the name of the wireless device. + We are forced to use the MAC address as name here. + """ + + return self.last_results.get(device) + + def _get_auth_tokens(self): + """ + Retrieves auth tokens from the router. + """ + + _LOGGER.info("Retrieving auth tokens...") + + url = 'http://{}/cgi-bin/luci/;stok=/login?form=login'\ + .format(self.host) + referer = 'http://{}/webpages/login.html'.format(self.host) + + # if possible implement rsa encryption of password here + + response = requests.post(url, params={'operation': 'login', + 'username': self.username, + 'password': self.password}, + headers={'referer': referer}) + + try: + self.stok = response.json().get('data').get('stok') + _LOGGER.info(self.stok) + regex_result = re.search('sysauth=(.*);', response.headers['set-cookie']) + self.sysauth = regex_result.group(1) + _LOGGER.info(self.sysauth) + return True + except: + _LOGGER.error("Couldn't fetch auth tokens!") + return False + + return False + + @Throttle(MIN_TIME_BETWEEN_SCANS) + def _update_info(self): + """ + Ensures the information from the TP-Link router is up to date. + Returns boolean if scanning successful. + """ + + with self.lock: + if (self.stok == '') or (self.sysauth == ''): + self._get_auth_tokens() + + _LOGGER.info("Loading wireless clients...") + + url = 'http://{}/cgi-bin/luci/;stok={}/admin/wireless?form=statistics'\ + .format(self.host, self.stok) + referer = 'http://{}/webpages/index.html'.format(self.host) + + response = requests.post(url, params={'operation': 'load'}, headers={'referer': referer}, cookies={'sysauth': self.sysauth}) + + try: + json_response = response.json() + + if json_response.get('success'): + result = response.json().get('data') + else: + if json_response.get('errorcode') == 'timeout': + _LOGGER.info("Token timed out. Relogging on next scan.") + self.stok = '' + self.sysauth = '' + return False + else: + _LOGGER.error("An unknown error happened while fetching data.") + return False + except ValueError: + _LOGGER.error("Router didn't respond with JSON. " + "Check if credentials are correct.") + return False + + if result: + self.last_results = { + device['mac'].replace('-', ':'): device['mac'] + for device in result + } + return True + + return False From e57b3ae847a6d12c571b4f1eae1bbd49550a6479 Mon Sep 17 00:00:00 2001 From: sfam Date: Mon, 28 Sep 2015 23:36:46 +0000 Subject: [PATCH 002/226] add manual alarm --- .../alarm_control_panel/__init__.py | 23 ++- .../components/alarm_control_panel/manual.py | 142 ++++++++++++++++++ .../components/alarm_control_panel/mqtt.py | 4 + .../alarm_control_panel/verisure.py | 4 + homeassistant/const.py | 3 + 5 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 homeassistant/components/alarm_control_panel/manual.py diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 49eb5eafba7..f922ecdacc0 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -8,7 +8,7 @@ import os from homeassistant.components import verisure from homeassistant.const import ( - ATTR_ENTITY_ID, + ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER, SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY) from homeassistant.config import load_yaml_config_file from homeassistant.helpers.entity import Entity @@ -29,6 +29,7 @@ SERVICE_TO_METHOD = { SERVICE_ALARM_DISARM: 'alarm_disarm', SERVICE_ALARM_ARM_HOME: 'alarm_arm_home', SERVICE_ALARM_ARM_AWAY: 'alarm_arm_away', + SERVICE_ALARM_TRIGGER: 'alarm_trigger' } ATTR_CODE = 'code' @@ -53,9 +54,9 @@ def setup(hass, config): target_alarms = component.extract_from_service(service) if ATTR_CODE not in service.data: - return - - code = service.data[ATTR_CODE] + code = None + else: + code = service.data[ATTR_CODE] method = SERVICE_TO_METHOD[service.service] @@ -102,6 +103,16 @@ def alarm_arm_away(hass, code, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data) +def alarm_trigger(hass, code, entity_id=None): + """ Send the alarm the command for trigger. """ + data = {ATTR_CODE: code} + + if entity_id: + data[ATTR_ENTITY_ID] = entity_id + + hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data) + + # pylint: disable=no-self-use class AlarmControlPanel(Entity): """ ABC for alarm control devices. """ @@ -123,6 +134,10 @@ class AlarmControlPanel(Entity): """ Send arm away command. """ raise NotImplementedError() + def alarm_trigger(self, code=None): + """ Send alarm trigger command. """ + raise NotImplementedError() + @property def state_attributes(self): """ Return the state attributes. """ diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py new file mode 100644 index 00000000000..e83a2e9da2f --- /dev/null +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -0,0 +1,142 @@ +""" +homeassistant.components.alarm_control_panel.manual + +Configuration: + +alarm_control_panel: + platform: manual + name: "HA Alarm" + code: "mySecretCode" + pending_time: 60 + trigger_time: 120 + +Variables: + +name +*Optional +The name of the alarm. Default is 'HA Alarm'. + +code +*Optional +If defined, specifies a code to arm or disarm the alarm in the frontend. + +pending_time +*Optional +The time in seconds of the pending time before arming the alarm. +Default is 60 seconds. + +trigger_time +*Optional +The time in seconds of the trigger time in which the alarm is firing. +Default is 120 seconds. + +""" + +import logging +import time +import homeassistant.components.alarm_control_panel as alarm + +from homeassistant.const import ( + STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = [] + +DEFAULT_ALARM_NAME = 'HA Alarm' +DEFAULT_PENDING_TIME = 60 +DEFAULT_TRIGGER_TIME = 120 + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the manual alarm platform. """ + + add_devices([ManualAlarm( + hass, + config.get('name', DEFAULT_ALARM_NAME), + config.get('code'), + config.get('pending_time', DEFAULT_PENDING_TIME), + config.get('trigger_time', DEFAULT_TRIGGER_TIME), + )]) + + +# pylint: disable=too-many-arguments, too-many-instance-attributes +class ManualAlarm(alarm.AlarmControlPanel): + """ represents an alarm status within home assistant. """ + + def __init__(self, hass, name, code, pending_time, trigger_time): + self._state = STATE_ALARM_DISARMED + self._hass = hass + self._name = name + self._code = code + self._pending_time = pending_time + self._trigger_time = trigger_time + self._pending_to = None + + @property + def should_poll(self): + """ No polling needed """ + return False + + @property + def name(self): + """ Returns the name of the device. """ + return self._name + + @property + def state(self): + """ Returns the state of the device. """ + return self._state + + @property + def code_format(self): + """ One or more characters """ + return None if self._code is None else '.+' + + def change_alarm_state(self, begin, end, delay=0): + """ changes between state with delay """ + self._state = begin + self._pending_to = end + self.update_ha_state() + time.sleep(delay) + if self._pending_to == end and begin != end: + self._state = end + self._pending_to = None + self.update_ha_state() + + def alarm_disarm(self, code=None): + """ Send disarm command. """ + if code == str(self._code) or self.code_format is None: + self.change_alarm_state( + STATE_ALARM_DISARMED, STATE_ALARM_DISARMED) + else: + _LOGGER.warning("Wrong code entered while disarming!") + + def alarm_arm_home(self, code=None): + """ Send arm home command. """ + if code == str(self._code) or self.code_format is None: + self.change_alarm_state( + STATE_ALARM_PENDING, STATE_ALARM_ARMED_HOME, + self._pending_time) + else: + _LOGGER.warning("Wrong code entered while arming home!") + + def alarm_arm_away(self, code=None): + """ Send arm away command. """ + if code == str(self._code) or self.code_format is None: + self.change_alarm_state( + STATE_ALARM_PENDING, STATE_ALARM_ARMED_AWAY, + self._pending_time) + else: + _LOGGER.warning("Wrong code entered while arming away!") + + def alarm_trigger(self, code=None): + """ Send alarm trigger command. No code needed. """ + self.change_alarm_state( + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, + self._pending_time) + if self._state == STATE_ALARM_TRIGGERED: + self.change_alarm_state( + STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED, + self._trigger_time) diff --git a/homeassistant/components/alarm_control_panel/mqtt.py b/homeassistant/components/alarm_control_panel/mqtt.py index f4d89e5a847..27e78cb38fe 100644 --- a/homeassistant/components/alarm_control_panel/mqtt.py +++ b/homeassistant/components/alarm_control_panel/mqtt.py @@ -166,3 +166,7 @@ class MqttAlarm(alarm.AlarmControlPanel): self._payload_arm_away, self._qos) else: _LOGGER.warning("Wrong code entered while arming away!") + + def alarm_trigger(self, code=None): + """ Send alarm trigger command. No code needed. """ + return diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index 7923f7c97e7..f590d462e9b 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -91,3 +91,7 @@ class VerisureAlarm(alarm.AlarmControlPanel): code, verisure.MY_PAGES.ALARM_ARMED_AWAY) _LOGGER.warning('arming away') + + def alarm_trigger(self, code=None): + """ Send alarm trigger command. No code needed. """ + return diff --git a/homeassistant/const.py b/homeassistant/const.py index 5fc3ad4f4a9..7df5e27fbe7 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -51,6 +51,8 @@ STATE_STANDBY = 'standby' STATE_ALARM_DISARMED = 'disarmed' STATE_ALARM_ARMED_HOME = 'armed_home' STATE_ALARM_ARMED_AWAY = 'armed_away' +STATE_ALARM_PENDING = 'pending' +STATE_ALARM_TRIGGERED = 'triggered' # #### STATE AND EVENT ATTRIBUTES #### # Contains current time for a TIME_CHANGED event @@ -121,6 +123,7 @@ SERVICE_MEDIA_SEEK = "media_seek" SERVICE_ALARM_DISARM = "alarm_disarm" SERVICE_ALARM_ARM_HOME = "alarm_arm_home" SERVICE_ALARM_ARM_AWAY = "alarm_arm_away" +SERVICE_ALARM_TRIGGER = "alarm_trigger" # #### API / REMOTE #### SERVER_PORT = 8123 From 4ac9e9fc4c61cf94515a32c091126acbb52c0e62 Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Thu, 8 Oct 2015 17:48:03 -0500 Subject: [PATCH 003/226] initial commit --- .../components/thermostat/radiotherm.py | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 homeassistant/components/thermostat/radiotherm.py diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py new file mode 100644 index 00000000000..28899fac56e --- /dev/null +++ b/homeassistant/components/thermostat/radiotherm.py @@ -0,0 +1,109 @@ +""" +homeassistant.components.thermostat.radiotherm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Adds support for Radio Thermostat wifi-enabled home thermostats +""" +import logging + +from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, + STATE_IDLE, STATE_HEAT) +from homeassistant.const import (CONF_HOST, CONF_NAME, TEMP_FAHRENHEIT) +from urllib.error import URLError + +#TODO: investigate why this fails +# REQUIREMENTS = ['radiotherm-1.2'] + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Radio Thermostat. """ + logger = logging.getLogger(__name__) + + try: + import radiotherm + except ImportError: + logger.exception( + "Error while importing dependency radiotherm. " + "Did you maybe not install the radiotherm dependency?") + return + + host = config.get(CONF_HOST) + if host is None: + logger.error("host not defined in config.") + return + + try: + tstat = radiotherm.get_thermostat(host) + except URLError as err: + logger.Exception( + "Unable to connect to Radio Thermostat") + return + + add_devices([RadioThermostat(tstat)]) + + +class RadioThermostat(ThermostatDevice): + """ Represent a Radio Thermostat. """ + + def __init__(self, device, name=None): + self.device = device + self._name = name + + @property + def name(self): + """ Returns the name of the Radio Thermostat. """ + return 'radiothermostat' + #return self.device.name + + @property + def unit_of_measurement(self): + """ Unit of measurement this thermostat expresses itself in. """ + return TEMP_FAHRENHEIT + + @property + def device_state_attributes(self): + """ Returns device specific state attributes. """ + # Move these to Thermostat Device and make them global + return { + "humidity": None, + "target_humidity": None, + "fan": self.device.fmode['human'], + "mode": self.device.tmode['human'] + } + + + @property + def current_temperature(self): + """ Returns the current temperature. """ + return self.device.temp['raw'] + + @property + def operation(self): + """ Returns current operation. head, cool idle """ + if self.device.tmode['human'] == 'Cool': + return STATE_COOL + elif self.device.tmode['human'] == 'Heat': + return STATE_HEAT + else: + return STATE_IDLE + + @property + def target_temperature(self): + """ Returns the temperature we try to reach. """ + + if self.operation == STATE_COOL: + temp = self.device.t_cool['raw'] + elif self.operation == STATE_HEAT: + temp = self.device.t_heat['raw'] + + return round(temp, 1) + + + def set_temperate(self, temperature): + """ Set new target temperature """ + if self.operation == STATE_COOL: + self.device.t_cool = temperature + elif self.operation == STATE_HEAT: + self.device.t_heat + + + From e5d68d8a1e32e09d25c534a5eac8b5159a6301cb Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Fri, 9 Oct 2015 10:43:14 -0500 Subject: [PATCH 004/226] set name of device through hass config --- homeassistant/components/thermostat/radiotherm.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index 28899fac56e..229fed220cd 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -27,6 +27,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return host = config.get(CONF_HOST) + name = config.get(CONF_NAME) if host is None: logger.error("host not defined in config.") return @@ -38,7 +39,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): "Unable to connect to Radio Thermostat") return - add_devices([RadioThermostat(tstat)]) + add_devices([RadioThermostat(tstat, name)]) class RadioThermostat(ThermostatDevice): @@ -46,13 +47,13 @@ class RadioThermostat(ThermostatDevice): def __init__(self, device, name=None): self.device = device - self._name = name + if name: + self.set_name(name) @property def name(self): """ Returns the name of the Radio Thermostat. """ - return 'radiothermostat' - #return self.device.name + return self.device.name['raw'] @property def unit_of_measurement(self): @@ -98,12 +99,16 @@ class RadioThermostat(ThermostatDevice): return round(temp, 1) - def set_temperate(self, temperature): + def set_temperature(self, temperature): """ Set new target temperature """ if self.operation == STATE_COOL: self.device.t_cool = temperature elif self.operation == STATE_HEAT: self.device.t_heat + def set_name(self, name): + """ Set thermostat name """ + self.device.name = name + From fc1cf49fd3392624202d9a03696e43126c4ad55e Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Fri, 9 Oct 2015 10:49:54 -0500 Subject: [PATCH 005/226] added REQUIREMENTS for radiotherm python module --- homeassistant/components/thermostat/radiotherm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index 229fed220cd..8936ab15292 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -10,8 +10,7 @@ from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, from homeassistant.const import (CONF_HOST, CONF_NAME, TEMP_FAHRENHEIT) from urllib.error import URLError -#TODO: investigate why this fails -# REQUIREMENTS = ['radiotherm-1.2'] +REQUIREMENTS = ['radiotherm'] def setup_platform(hass, config, add_devices, discovery_info=None): From 0cf909cce9ba47f34297e87ae800f49b7ea4e18a Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Fri, 9 Oct 2015 11:34:14 -0500 Subject: [PATCH 006/226] Correct ci failed tests --- homeassistant/components/thermostat/radiotherm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index 8936ab15292..dcdb70840d4 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -33,8 +33,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): try: tstat = radiotherm.get_thermostat(host) - except URLError as err: - logger.Exception( + except URLError: + logger.exception( "Unable to connect to Radio Thermostat") return @@ -103,7 +103,7 @@ class RadioThermostat(ThermostatDevice): if self.operation == STATE_COOL: self.device.t_cool = temperature elif self.operation == STATE_HEAT: - self.device.t_heat + self.device.t_heat = temperature def set_name(self, name): """ Set thermostat name """ From a3d295d88588f1dfd08d1dd23d7feb16fd4762f3 Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Fri, 9 Oct 2015 11:38:39 -0500 Subject: [PATCH 007/226] Correct formatting --- homeassistant/components/thermostat/radiotherm.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index dcdb70840d4..6aee1aa061d 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -70,7 +70,6 @@ class RadioThermostat(ThermostatDevice): "mode": self.device.tmode['human'] } - @property def current_temperature(self): """ Returns the current temperature. """ @@ -97,7 +96,6 @@ class RadioThermostat(ThermostatDevice): return round(temp, 1) - def set_temperature(self, temperature): """ Set new target temperature """ if self.operation == STATE_COOL: @@ -108,6 +106,3 @@ class RadioThermostat(ThermostatDevice): def set_name(self, name): """ Set thermostat name """ self.device.name = name - - - From d4d91bfdbbd06d74397ac8570073e14b70e75b9f Mon Sep 17 00:00:00 2001 From: happyleavesaoc Date: Thu, 8 Oct 2015 21:07:36 -0400 Subject: [PATCH 008/226] Amazon Fire TV device support --- .coveragerc | 1 + README.md | 2 +- .../components/media_player/firetv.py | 214 ++++++++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/media_player/firetv.py diff --git a/.coveragerc b/.coveragerc index 26fae1ba3f9..82f23130c9e 100644 --- a/.coveragerc +++ b/.coveragerc @@ -51,6 +51,7 @@ omit = homeassistant/components/light/blinksticklight.py homeassistant/components/media_player/cast.py homeassistant/components/media_player/denon.py + homeassistant/components/media_player/firetv.py homeassistant/components/media_player/itunes.py homeassistant/components/media_player/kodi.py homeassistant/components/media_player/mpd.py diff --git a/README.md b/README.md index 6d1baa5c50f..b10c3c04352 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Examples of devices it can interface it: * Monitoring connected devices to a wireless router: [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), [DD-WRT](http://www.dd-wrt.com/site/index), [TPLink](http://www.tp-link.us/), [ASUSWRT](http://event.asus.com/2013/nw/ASUSWRT/) and any SNMP capable WAP/WRT * [Philips Hue](http://meethue.com) lights, [WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) switches, [Edimax](http://www.edimax.com/) switches, [Efergy](https://efergy.com) energy monitoring, RFXtrx sensors, and [Tellstick](http://www.telldus.se/products/tellstick) devices and sensors - * [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast), [Music Player Daemon](http://www.musicpd.org/), [Logitech Squeezebox](https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29), [Kodi (XBMC)](http://kodi.tv/), and iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api)) + * [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast), [Music Player Daemon](http://www.musicpd.org/), [Logitech Squeezebox](https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29), [Kodi (XBMC)](http://kodi.tv/), iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api)), and Amazon Fire TV (by way of [python-firetv](https://github.com/happyleavesaoc/python-firetv)) * Support for [ISY994](https://www.universal-devices.com/residential/isy994i-series/) (Insteon and X10 devices), [Z-Wave](http://www.z-wave.com/), [Nest Thermostats](https://nest.com/), [Arduino](https://www.arduino.cc/), [Raspberry Pi](https://www.raspberrypi.org/), and [Modbus](http://www.modbus.org/) * Integrate data from the [Bitcoin](https://bitcoin.org) network, meteorological data from [OpenWeatherMap](http://openweathermap.org/) and [Forecast.io](https://forecast.io/), [Transmission](http://www.transmissionbt.com/), or [SABnzbd](http://sabnzbd.org). * [See full list of supported devices](https://home-assistant.io/components/) diff --git a/homeassistant/components/media_player/firetv.py b/homeassistant/components/media_player/firetv.py new file mode 100644 index 00000000000..c0dedb27b77 --- /dev/null +++ b/homeassistant/components/media_player/firetv.py @@ -0,0 +1,214 @@ +""" +homeassistant.components.media_player.firetv +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Provides control over an Amazon Fire TV (/stick) via +python-firetv, a Python 2.x module with a helper script +that exposes a HTTP server to fetch state and perform +actions. + +Steps to configure your Amazon Fire TV stick with Home Assistant: + +1. Turn on ADB Debugging on your Amazon Fire TV: + a. From the main (Launcher) screen, select Settings. + b. Select System > Developer Options. + c. Select ADB Debugging. +2. Find Amazon Fire TV device IP: + a. From the main (Launcher) screen, select Settings. + b. Select System > About > Network. +3. `pip install firetv[firetv-server]` into a Python 2.x environment +4. `firetv-server -d :5555`, background the process +5. Configure Home Assistant as follows: + +media_player: + platform: firetv + # optional: where firetv-server is running (default is 'localhost:5556') + host: localhost:5556 + # optional: device id (default is 'default') + device: livingroom-firetv + # optional: friendly name (default is 'Amazon Fire TV') + name: My Amazon Fire TV + +Note that python-firetv has support for multiple Amazon Fire TV devices. +If you have more than one configured, be sure to specify the device id used. +Run `firetv-server -h` and/or view the source for complete capabilities. + +Possible states are: + - off (TV screen is dark) + - standby (standard UI is active - not apps) + - idle (screen saver is active) + - play (video is playing) + - pause (video is paused) + - disconnected (can't communicate with device) +""" + +import requests + +from homeassistant.const import ( + STATE_PLAYING, STATE_PAUSED, STATE_IDLE, STATE_OFF, + STATE_UNKNOWN, STATE_STANDBY) + +from homeassistant.components.media_player import ( + MediaPlayerDevice, + SUPPORT_PAUSE, SUPPORT_VOLUME_SET, + SUPPORT_TURN_ON, SUPPORT_TURN_OFF, + SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK) + +SUPPORT_FIRETV = SUPPORT_PAUSE | \ + SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \ + SUPPORT_NEXT_TRACK | SUPPORT_VOLUME_SET + +DOMAIN = 'firetv' + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the firetv platform. """ + add_devices([ + FireTVDevice( + config.get('host', 'localhost:5556'), + config.get('device', 'default'), + config.get('name', 'Amazon Fire TV') + ) + ]) + + +class FireTV(object): + """ firetv-server client. + + Should a native Python 3 ADB module become available, + python-firetv can support Python 3, it can be added + as a dependency, and this class can be dispensed of. + + For now, it acts as a client to the firetv-server + HTTP server (which must be running via Python 2). + """ + + DEVICE_STATE_URL = 'http://{0}/devices/state/{1}' + DEVICE_ACTION_URL = 'http://{0}/devices/action/{1}/{2}' + + def __init__(self, host, device_id): + self.host = host + self.device_id = device_id + + @property + def state(self): + """ Get the device state. + + An exception means UNKNOWN state. + """ + try: + response = requests.get( + FireTV.DEVICE_STATE_URL.format( + self.host, + self.device_id + ) + ) + return response.json()['state'] + except requests.exceptions.HTTPError: + return STATE_UNKNOWN + except requests.exceptions.RequestException: + return STATE_UNKNOWN + + def action(self, action_id): + """ Perform an action on the device. + + There is no action acknowledgment, so exceptions + result in a pass. + """ + try: + requests.get( + FireTV.DEVICE_ACTION_URL.format( + self.host, + self.device_id, + action_id + ) + ) + except requests.exceptions.HTTPError: + pass + except requests.exceptions.RequestException: + pass + + +class FireTVDevice(MediaPlayerDevice): + """ Represents an Amazon Fire TV device on the network. """ + + def __init__(self, host, device, name): + self._firetv = FireTV(host, device) + self._name = name + + @property + def name(self): + """ Get the device name. """ + return self._name + + @property + def should_poll(self): + """ Device should be polled. """ + return True + + @property + def supported_media_commands(self): + """ Flags of media commands that are supported. """ + return SUPPORT_FIRETV + + @property + def state(self): + """ State of the player. """ + state_map = { + 'idle': STATE_IDLE, + 'off': STATE_OFF, + 'play': STATE_PLAYING, + 'pause': STATE_PAUSED, + 'standby': STATE_STANDBY, + 'disconnected': STATE_UNKNOWN, + } + return state_map.get(self._firetv.state, STATE_UNKNOWN) + + def turn_on(self): + """ Turns on the device. """ + self._firetv.action('turn_on') + + def turn_off(self): + """ Turns off the device. """ + self._firetv.action('turn_off') + + def media_play(self): + """ Send play commmand. """ + self._firetv.action('media_play') + + def media_pause(self): + """ Send pause command. """ + self._firetv.action('media_pause') + + def media_play_pause(self): + """ Send play/pause command. """ + self._firetv.action('media_play_pause') + + def volume_up(self): + """ Send volume up command. """ + self._firetv.action('volume_up') + + def volume_down(self): + """ Send volume down command. """ + self._firetv.action('volume_down') + + def media_previous_track(self): + """ Send previous track command (results in rewind). """ + self._firetv.action('media_previous') + + def media_next_track(self): + """ Send next track command (results in fast-forward). """ + self._firetv.action('media_next') + + def media_seek(self, position): + raise NotImplementedError() + + def mute_volume(self, mute): + raise NotImplementedError() + + def play_youtube(self, media_id): + raise NotImplementedError() + + def set_volume_level(self, volume): + raise NotImplementedError() From 37278aab20e8a85357eac2ed3a2e38747704c309 Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Sat, 10 Oct 2015 11:36:34 -0500 Subject: [PATCH 009/226] add set_time and begin discovery --- .../components/thermostat/radiotherm.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index 6aee1aa061d..b0ae38461b3 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -4,13 +4,14 @@ homeassistant.components.thermostat.radiotherm Adds support for Radio Thermostat wifi-enabled home thermostats """ import logging +import datetime +from urllib.error import URLError from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) from homeassistant.const import (CONF_HOST, CONF_NAME, TEMP_FAHRENHEIT) -from urllib.error import URLError -REQUIREMENTS = ['radiotherm'] +REQUIREMENTS = ['radiotherm==1.2'] def setup_platform(hass, config, add_devices, discovery_info=None): @@ -25,6 +26,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): "Did you maybe not install the radiotherm dependency?") return + hosts = [] + logger.info(discovery_info) + + host = config.get(CONF_HOST) name = config.get(CONF_NAME) if host is None: @@ -48,6 +53,7 @@ class RadioThermostat(ThermostatDevice): self.device = device if name: self.set_name(name) + self.set_time() @property def name(self): @@ -106,3 +112,9 @@ class RadioThermostat(ThermostatDevice): def set_name(self, name): """ Set thermostat name """ self.device.name = name + + def set_time(self): + """ Set device time """ + now = datetime.datetime.now() + self.device.time = {'day': now.weekday(), + 'hour': now.hour, 'minute': now.minute} From 94df5acbf334c4cd13c127d9287406f396ae2a8a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 10 Oct 2015 11:45:25 -0700 Subject: [PATCH 010/226] Version bump to 0.7.6.dev0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index a84f4571b8e..278ffea218a 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """ Constants used by Home Assistant components. """ -__version__ = "0.7.5" +__version__ = "0.7.6.dev0" # Can be used to specify a catch all when registering state or event listeners. MATCH_ALL = '*' From 168516f5daa3c5904b1220f09e61b3853ccd5e99 Mon Sep 17 00:00:00 2001 From: happyleavesaoc Date: Sat, 10 Oct 2015 16:45:13 -0400 Subject: [PATCH 011/226] addressed PR comments --- .../components/media_player/firetv.py | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/media_player/firetv.py b/homeassistant/components/media_player/firetv.py index c0dedb27b77..9db17416bda 100644 --- a/homeassistant/components/media_player/firetv.py +++ b/homeassistant/components/media_player/firetv.py @@ -42,6 +42,7 @@ Possible states are: - disconnected (can't communicate with device) """ +import logging import requests from homeassistant.const import ( @@ -59,18 +60,35 @@ SUPPORT_FIRETV = SUPPORT_PAUSE | \ SUPPORT_NEXT_TRACK | SUPPORT_VOLUME_SET DOMAIN = 'firetv' +DEVICE_LIST_URL = 'http://{0}/devices/list' +DEVICE_STATE_URL = 'http://{0}/devices/state/{1}' +DEVICE_ACTION_URL = 'http://{0}/devices/action/{1}/{2}' + +_LOGGER = logging.getLogger(__name__) # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the firetv platform. """ - add_devices([ - FireTVDevice( - config.get('host', 'localhost:5556'), - config.get('device', 'default'), - config.get('name', 'Amazon Fire TV') - ) - ]) + host = config.get('host', 'localhost:5556') + device_id = config.get('device', 'default') + try: + response = requests.get(DEVICE_LIST_URL.format(host)).json() + if device_id in response['devices'].keys(): + add_devices([ + FireTVDevice( + host, + device_id, + config.get('name', 'Amazon Fire TV') + ) + ]) + _LOGGER.info( + 'Device %s accessible and ready for control', device_id) + else: + _LOGGER.warn( + 'Device %s is not registered with firetv-server', device_id) + except requests.exceptions.RequestException: + _LOGGER.error('Could not connect to firetv-server at %s', host) class FireTV(object): @@ -84,9 +102,6 @@ class FireTV(object): HTTP server (which must be running via Python 2). """ - DEVICE_STATE_URL = 'http://{0}/devices/state/{1}' - DEVICE_ACTION_URL = 'http://{0}/devices/action/{1}/{2}' - def __init__(self, host, device_id): self.host = host self.device_id = device_id @@ -99,15 +114,15 @@ class FireTV(object): """ try: response = requests.get( - FireTV.DEVICE_STATE_URL.format( + DEVICE_STATE_URL.format( self.host, self.device_id ) - ) - return response.json()['state'] - except requests.exceptions.HTTPError: - return STATE_UNKNOWN + ).json() + return response.get('state', STATE_UNKNOWN) except requests.exceptions.RequestException: + _LOGGER.error( + 'Could not retrieve device state for %s', self.device_id) return STATE_UNKNOWN def action(self, action_id): @@ -118,16 +133,16 @@ class FireTV(object): """ try: requests.get( - FireTV.DEVICE_ACTION_URL.format( + DEVICE_ACTION_URL.format( self.host, self.device_id, action_id ) ) - except requests.exceptions.HTTPError: - pass except requests.exceptions.RequestException: - pass + _LOGGER.error( + 'Action request for %s was not accepted for device %s', + action_id, self.device_id) class FireTVDevice(MediaPlayerDevice): @@ -136,6 +151,7 @@ class FireTVDevice(MediaPlayerDevice): def __init__(self, host, device, name): self._firetv = FireTV(host, device) self._name = name + self._state = STATE_UNKNOWN @property def name(self): @@ -155,15 +171,18 @@ class FireTVDevice(MediaPlayerDevice): @property def state(self): """ State of the player. """ - state_map = { + return self._state + + def update(self): + """ Update device state. """ + self._state = { 'idle': STATE_IDLE, 'off': STATE_OFF, 'play': STATE_PLAYING, 'pause': STATE_PAUSED, 'standby': STATE_STANDBY, 'disconnected': STATE_UNKNOWN, - } - return state_map.get(self._firetv.state, STATE_UNKNOWN) + }.get(self._firetv.state, STATE_UNKNOWN) def turn_on(self): """ Turns on the device. """ From a1e5bea3ab3a0ad61a379c4827604560ef221d83 Mon Sep 17 00:00:00 2001 From: Guillaume SABBE Date: Sun, 11 Oct 2015 15:21:53 +0200 Subject: [PATCH 012/226] When IPv6 is enabled, dnsmasq has a configuration line with the DUID. This looks like this 61072 b8:27:eb:e1:4e:4d 192.168.0.4 domotycoon * 61072 b8:27:eb:b8:10:6b 192.168.0.5 pimonitor * duid 00:03:00:01:ac:22:0b:e9:98:50 When using match.group() without testing if match != None, you get a traceback. --- homeassistant/components/device_tracker/asuswrt.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/device_tracker/asuswrt.py b/homeassistant/components/device_tracker/asuswrt.py index 1e3ac20b6f2..5284d45835b 100644 --- a/homeassistant/components/device_tracker/asuswrt.py +++ b/homeassistant/components/device_tracker/asuswrt.py @@ -161,9 +161,10 @@ class AsusWrtDeviceScanner(object): # For leases where the client doesn't set a hostname, ensure # it is blank and not '*', which breaks the entity_id down # the line - host = match.group('host') - if host == '*': - host = '' + if match: + host = match.group('host') + if host == '*': + host = '' devices[match.group('ip')] = { 'host': host, @@ -174,6 +175,6 @@ class AsusWrtDeviceScanner(object): for neighbor in neighbors: match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8')) - if match.group('ip') in devices: + if match and match.group('ip') in devices: devices[match.group('ip')]['status'] = match.group('status') return devices From 84c72ebf634e0f89c381b46b44e9d050a053b9d0 Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Sun, 11 Oct 2015 09:28:25 -0500 Subject: [PATCH 013/226] Add support for multiple thermostats (via hass-config) and auto-discovery via ratiotherm module --- .../components/thermostat/radiotherm.py | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index b0ae38461b3..e11f845b0b4 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -26,24 +26,31 @@ def setup_platform(hass, config, add_devices, discovery_info=None): "Did you maybe not install the radiotherm dependency?") return + # Detect hosts with hass discovery, config or radiotherm discovery hosts = [] - logger.info(discovery_info) + if discovery_info: + logger.info('hass radiotherm discovery', discovery_info) + elif CONF_HOST in config: + hosts = [config[CONF_HOST]] + else: + hosts.append(radiotherm.discover.discover_address()) - - host = config.get(CONF_HOST) name = config.get(CONF_NAME) - if host is None: - logger.error("host not defined in config.") + if hosts is None: + logger.error("no radiotherm thermostats detected") return - try: - tstat = radiotherm.get_thermostat(host) - except URLError: - logger.exception( - "Unable to connect to Radio Thermostat") - return + tstats = [] - add_devices([RadioThermostat(tstat, name)]) + for host in hosts: + try: + tstat = radiotherm.get_thermostat(host) + tstats.append(RadioThermostat(tstat)) + except (URLError, OSError): + logger.exception( + "Unable to connect to Radio Thermostat @{}".format(host)) + + add_devices(tstats) class RadioThermostat(ThermostatDevice): From 6c1c2430002db665a82266230a39a31e7b509c1a Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Sun, 11 Oct 2015 11:42:24 -0500 Subject: [PATCH 014/226] start away mode --- .../components/thermostat/radiotherm.py | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index e11f845b0b4..850bdcc2b83 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -9,7 +9,7 @@ from urllib.error import URLError from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) -from homeassistant.const import (CONF_HOST, CONF_NAME, TEMP_FAHRENHEIT) +from homeassistant.const import (CONF_HOST, TEMP_FAHRENHEIT) REQUIREMENTS = ['radiotherm==1.2'] @@ -29,13 +29,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): # Detect hosts with hass discovery, config or radiotherm discovery hosts = [] if discovery_info: - logger.info('hass radiotherm discovery', discovery_info) + logger.info('hass radiotherm discovery: %s', discovery_info) elif CONF_HOST in config: hosts = [config[CONF_HOST]] else: hosts.append(radiotherm.discover.discover_address()) - name = config.get(CONF_NAME) if hosts is None: logger.error("no radiotherm thermostats detected") return @@ -48,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): tstats.append(RadioThermostat(tstat)) except (URLError, OSError): logger.exception( - "Unable to connect to Radio Thermostat @{}".format(host)) + "Unable to connect to Radio Thermostat: %s", host) add_devices(tstats) @@ -61,12 +60,19 @@ class RadioThermostat(ThermostatDevice): if name: self.set_name(name) self.set_time() + self._away = False + self._away_cool = 82 + self._away_heat = 70 @property def name(self): """ Returns the name of the Radio Thermostat. """ return self.device.name['raw'] + def set_name(self, name): + """ Set thermostat name """ + self.device.name = name + @property def unit_of_measurement(self): """ Unit of measurement this thermostat expresses itself in. """ @@ -116,9 +122,18 @@ class RadioThermostat(ThermostatDevice): elif self.operation == STATE_HEAT: self.device.t_heat = temperature - def set_name(self, name): - """ Set thermostat name """ - self.device.name = name + @property + def is_away_mode_on(self): + """ Returns away mode """ + return self._away + + def turn_away_mode_on(self): + """ Turns away mode on. """ + self._away = True + + def turn_away_mode_off(self): + """ Turns away mode off. """ + self._away = False def set_time(self): """ Set device time """ From dcfc91e71ca840dfcff6774e49020ef8d88b1b63 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 10:42:42 -0700 Subject: [PATCH 015/226] Fix throttle applied to methods --- homeassistant/util/__init__.py | 20 ++++++++++++++++---- tests/util/test_init.py | 13 +++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/homeassistant/util/__init__.py b/homeassistant/util/__init__.py index 2d449285493..ec693f312f3 100644 --- a/homeassistant/util/__init__.py +++ b/homeassistant/util/__init__.py @@ -236,11 +236,18 @@ class Throttle(object): if self.limit_no_throttle is not None: method = Throttle(self.limit_no_throttle)(method) - # We want to be able to differentiate between function and method calls + # Different methods that can be passed in: + # - a function + # - an unbound function on a class + # - a method (bound function on a class) + + # We want to be able to differentiate between function and unbound + # methods (which are considered functions). # All methods have the classname in their qualname seperated by a '.' # Functions have a '.' in their qualname if defined inline, but will # be prefixed by '..' so we strip that out. - is_func = '.' not in method.__qualname__.split('..')[-1] + is_func = (not hasattr(method, '__self__') and + '.' not in method.__qualname__.split('..')[-1]) @wraps(method) def wrapper(*args, **kwargs): @@ -248,8 +255,13 @@ class Throttle(object): Wrapper that allows wrapped to be called only once per min_time. If we cannot acquire the lock, it is running so return None. """ - # pylint: disable=protected-access - host = wrapper if is_func else args[0] + if hasattr(method, '__self__'): + host = method.__self__ + elif is_func: + host = wrapper + else: + host = args[0] if args else wrapper + if not hasattr(host, '_throttle_lock'): host._throttle_lock = threading.Lock() diff --git a/tests/util/test_init.py b/tests/util/test_init.py index 2bf917f4e25..2e520ac4980 100644 --- a/tests/util/test_init.py +++ b/tests/util/test_init.py @@ -229,3 +229,16 @@ class TestUtil(unittest.TestCase): self.assertTrue(Tester().hello()) self.assertTrue(Tester().hello()) + + def test_throttle_on_method(self): + """ Test that throttle works when wrapping a method. """ + + class Tester(object): + def hello(self): + return True + + tester = Tester() + throttled = util.Throttle(timedelta(seconds=1))(tester.hello) + + self.assertTrue(throttled()) + self.assertIsNone(throttled()) From b05f2e32218ee14312443b85b6274918ee0820f8 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 11:04:16 -0700 Subject: [PATCH 016/226] Fix style issue --- homeassistant/util/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/util/__init__.py b/homeassistant/util/__init__.py index ec693f312f3..ada6d150188 100644 --- a/homeassistant/util/__init__.py +++ b/homeassistant/util/__init__.py @@ -255,6 +255,7 @@ class Throttle(object): Wrapper that allows wrapped to be called only once per min_time. If we cannot acquire the lock, it is running so return None. """ + # pylint: disable=protected-access if hasattr(method, '__self__'): host = method.__self__ elif is_func: From 384b3d0d1769b9e6db8c93397a875825b68e7384 Mon Sep 17 00:00:00 2001 From: Andrew Thigpen Date: Sun, 11 Oct 2015 17:05:08 -0500 Subject: [PATCH 017/226] Update to latest mysensors library. * Adds JSON persistence support. * Adds documentation comments for configuration options. --- homeassistant/components/sensor/mysensors.py | 32 ++++++++++++++++++-- requirements_all.txt | 2 +- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/sensor/mysensors.py b/homeassistant/components/sensor/mysensors.py index 60e84059cad..84c62b26469 100644 --- a/homeassistant/components/sensor/mysensors.py +++ b/homeassistant/components/sensor/mysensors.py @@ -17,6 +17,26 @@ Variables: port *Required Port of your connection to your MySensors device. + +debug +*Optional +Enable or disable verbose debug logging. + +persistence +*Optional +Enable or disable local persistence of sensor information. +Note: If this is disabled, then each sensor will need to send presentation + messages after Home Assistant starts + +persistence_file +*Optional +Path to a file to save sensor information. +Note: The file extension determines the file type. Currently supported file + types are 'pickle' and 'json'. + +version +*Optional +Specifies the MySensors protocol version to use (ex. 1.4, 1.5). """ import logging @@ -30,14 +50,16 @@ from homeassistant.const import ( CONF_PORT = "port" CONF_DEBUG = "debug" CONF_PERSISTENCE = "persistence" +CONF_PERSISTENCE_FILE = "persistence_file" +CONF_VERSION = "version" ATTR_NODE_ID = "node_id" ATTR_CHILD_ID = "child_id" _LOGGER = logging.getLogger(__name__) REQUIREMENTS = ['https://github.com/theolind/pymysensors/archive/' - '35b87d880147a34107da0d40cb815d75e6cb4af7.zip' - '#pymysensors==0.2'] + 'd4b809c2167650691058d1e29bfd2c4b1792b4b0.zip' + '#pymysensors==0.3'] def setup_platform(hass, config, add_devices, discovery_info=None): @@ -86,9 +108,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False persistence = config.get(CONF_PERSISTENCE, True) + persistence_file = config.get(CONF_PERSISTENCE_FILE, 'mysensors.pickle') + version = config.get(CONF_VERSION, '1.4') gateway = mysensors.SerialGateway(port, sensor_update, - persistence=persistence) + persistence=persistence, + persistence_file=persistence_file, + protocol_version=version) gateway.metric = is_metric gateway.debug = config.get(CONF_DEBUG, False) gateway.start() diff --git a/requirements_all.txt b/requirements_all.txt index c9afec10ad0..12797da4e5a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -81,7 +81,7 @@ PyMata==2.07a https://github.com/Danielhiversen/pyRFXtrx/archive/ec7a1aaddf8270db6e5da1c13d58c1547effd7cf.zip#RFXtrx==0.15 # Mysensors (sensor.mysensors) -https://github.com/theolind/pymysensors/archive/35b87d880147a34107da0d40cb815d75e6cb4af7.zip#pymysensors==0.2 +https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3 # Netgear (device_tracker.netgear) pynetgear==0.3 From 6a969208e9e1f727dd047d059ac6d05a5d2e2c0b Mon Sep 17 00:00:00 2001 From: Hans Bakker Date: Mon, 12 Oct 2015 00:14:05 +0200 Subject: [PATCH 018/226] Initial commit for Geofancy device tracker. --- .../components/device_tracker/geofancy.py | 74 +++++++++++++++++++ homeassistant/const.py | 2 + 2 files changed, 76 insertions(+) create mode 100644 homeassistant/components/device_tracker/geofancy.py diff --git a/homeassistant/components/device_tracker/geofancy.py b/homeassistant/components/device_tracker/geofancy.py new file mode 100644 index 00000000000..b0834e4be36 --- /dev/null +++ b/homeassistant/components/device_tracker/geofancy.py @@ -0,0 +1,74 @@ +""" +homeassistant.components.device_tracker.geofancy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Geofancy platform for the device tracker. + +device_tracker: + platform: geofancy +""" + +from homeassistant.const import ( + URL_API_GEOFANCY_ENDPOINT, + HTTP_UNPROCESSABLE_ENTITY, HTTP_INTERNAL_SERVER_ERROR) + +DEPENDENCIES = ['http'] + +_SEE = 0 + + +def setup_scanner(hass, config, see): + """ Set up an endpoint for the Geofancy app. """ + + # Use a global variable to keep setup_scanner compact when using a callback + global _SEE + _SEE = see + + """ POST would be semantically better, but that currently does not work + since Geofancy sends the data as key1=value1&key2=value2 in the request body, + while Home Assistant expects json there. """ + + hass.http.register_path( + 'GET', URL_API_GEOFANCY_ENDPOINT, _handle_get_api_geofancy) + + return True + + +def _handle_get_api_geofancy(handler, path_match, data): + """ Geofancy message received. """ + + if not isinstance(data, dict): + handler.write_json_message( + "Error while parsing Geofancy message.", HTTP_INTERNAL_SERVER_ERROR) + return + if 'latitude' not in data or 'longitude' not in data: + handler.write_json_message( + "Location not specified.", HTTP_UNPROCESSABLE_ENTITY) + return + if 'device' not in data or 'id' not in data: + handler.write_json_message( + "Device id or location id not specified.", HTTP_UNPROCESSABLE_ENTITY) + return + + try: + gps_coords = (float(data['latitude']), float(data['longitude'])) + except ValueError: + # If invalid latitude / longitude format + handler.write_json_message( + "Invalid latitude / longitude format.", HTTP_UNPROCESSABLE_ENTITY) + return + + + # entity id's in Home Assistant must be alphanumerical + device_uuid = data['device'] + device_entity_id = device_uuid.replace('-', '') + + kwargs = { + 'dev_id': device_entity_id, + 'gps': gps_coords, + 'location_name': data['id'] + } + + _SEE(**kwargs) + + handler.write_json_message("Geofancy message processed") diff --git a/homeassistant/const.py b/homeassistant/const.py index 278ffea218a..ddda08001b9 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -145,6 +145,7 @@ URL_API_SERVICES_SERVICE = "/api/services/{}/{}" URL_API_EVENT_FORWARD = "/api/event_forwarding" URL_API_COMPONENTS = "/api/components" URL_API_BOOTSTRAP = "/api/bootstrap" +URL_API_GEOFANCY_ENDPOINT = '/api/geofancy' HTTP_OK = 200 HTTP_CREATED = 201 @@ -154,6 +155,7 @@ HTTP_UNAUTHORIZED = 401 HTTP_NOT_FOUND = 404 HTTP_METHOD_NOT_ALLOWED = 405 HTTP_UNPROCESSABLE_ENTITY = 422 +HTTP_INTERNAL_SERVER_ERROR = 500 HTTP_HEADER_HA_AUTH = "X-HA-access" HTTP_HEADER_ACCEPT_ENCODING = "Accept-Encoding" From 1eb3610a11dcd5871c6e79ef24355f54d60e47cf Mon Sep 17 00:00:00 2001 From: Hans Bakker Date: Mon, 12 Oct 2015 00:28:39 +0200 Subject: [PATCH 019/226] Style fixes --- .../components/device_tracker/geofancy.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/device_tracker/geofancy.py b/homeassistant/components/device_tracker/geofancy.py index b0834e4be36..8e8611e00b3 100644 --- a/homeassistant/components/device_tracker/geofancy.py +++ b/homeassistant/components/device_tracker/geofancy.py @@ -24,9 +24,9 @@ def setup_scanner(hass, config, see): global _SEE _SEE = see - """ POST would be semantically better, but that currently does not work - since Geofancy sends the data as key1=value1&key2=value2 in the request body, - while Home Assistant expects json there. """ + # POST would be semantically better, but that currently does not work + # since Geofancy sends the data as key1=value1&key2=value2 + # in the request body, while Home Assistant expects json there. hass.http.register_path( 'GET', URL_API_GEOFANCY_ENDPOINT, _handle_get_api_geofancy) @@ -39,15 +39,18 @@ def _handle_get_api_geofancy(handler, path_match, data): if not isinstance(data, dict): handler.write_json_message( - "Error while parsing Geofancy message.", HTTP_INTERNAL_SERVER_ERROR) + "Error while parsing Geofancy message.", + HTTP_INTERNAL_SERVER_ERROR) return if 'latitude' not in data or 'longitude' not in data: handler.write_json_message( - "Location not specified.", HTTP_UNPROCESSABLE_ENTITY) + "Location not specified.", + HTTP_UNPROCESSABLE_ENTITY) return if 'device' not in data or 'id' not in data: handler.write_json_message( - "Device id or location id not specified.", HTTP_UNPROCESSABLE_ENTITY) + "Device id or location id not specified.", + HTTP_UNPROCESSABLE_ENTITY) return try: @@ -55,10 +58,10 @@ def _handle_get_api_geofancy(handler, path_match, data): except ValueError: # If invalid latitude / longitude format handler.write_json_message( - "Invalid latitude / longitude format.", HTTP_UNPROCESSABLE_ENTITY) + "Invalid latitude / longitude format.", + HTTP_UNPROCESSABLE_ENTITY) return - # entity id's in Home Assistant must be alphanumerical device_uuid = data['device'] device_entity_id = device_uuid.replace('-', '') From bf1970b78cdfb5d0e467bbacfd10e6b265704657 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 18:16:55 -0700 Subject: [PATCH 020/226] Make thermostat more robust --- .../components/thermostat/__init__.py | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py index 7d26c78f0f8..b021ec86c35 100644 --- a/homeassistant/components/thermostat/__init__.py +++ b/homeassistant/components/thermostat/__init__.py @@ -136,22 +136,16 @@ class ThermostatDevice(Entity): def state_attributes(self): """ Returns optional state attributes. """ - thermostat_unit = self.unit_of_measurement - user_unit = self.hass.config.temperature_unit - data = { - ATTR_CURRENT_TEMPERATURE: round(convert( - self.current_temperature, thermostat_unit, user_unit), 1), - ATTR_MIN_TEMP: round(convert( - self.min_temp, thermostat_unit, user_unit), 0), - ATTR_MAX_TEMP: round(convert( - self.max_temp, thermostat_unit, user_unit), 0), - ATTR_TEMPERATURE: round(convert( - self.target_temperature, thermostat_unit, user_unit), 0), - ATTR_TEMPERATURE_LOW: round(convert( - self.target_temperature_low, thermostat_unit, user_unit), 0), - ATTR_TEMPERATURE_HIGH: round(convert( - self.target_temperature_high, thermostat_unit, user_unit), 0), + ATTR_CURRENT_TEMPERATURE: + self._convert(self.current_temperature, 1), + ATTR_MIN_TEMP: self._convert(self.min_temp, 0), + ATTR_MAX_TEMP: self._convert(self.max_temp, 0), + ATTR_TEMPERATURE: self._convert(self.target_temperature, 0), + ATTR_TEMPERATURE_LOW: + self._convert(self.target_temperature_low, 0), + ATTR_TEMPERATURE_HIGH: + self._convert(self.target_temperature_high, 0), } operation = self.operation @@ -228,3 +222,14 @@ class ThermostatDevice(Entity): def max_temp(self): """ Return maxmum temperature. """ return convert(35, TEMP_CELCIUS, self.unit_of_measurement) + + def _convert(self, temp, round_dec=None): + """ Convert temperature from this thermost into user preferred + temperature. """ + if temp is None: + return None + + value = convert(temp, self.unit_of_measurement, + self.hass.config.temperature_unit) + + return value if round_dec is None else round(value, round_dec) From b6d26597c06de9e0ec4851d619bb78e1a2da82ee Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 18:30:25 -0700 Subject: [PATCH 021/226] Automation - state platfor: Flag if user makes config error --- homeassistant/components/automation/state.py | 5 +++++ tests/components/automation/test_state.py | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/homeassistant/components/automation/state.py b/homeassistant/components/automation/state.py index 8baa0a01d46..5fc36300ed0 100644 --- a/homeassistant/components/automation/state.py +++ b/homeassistant/components/automation/state.py @@ -28,6 +28,11 @@ def trigger(hass, config, action): from_state = config.get(CONF_FROM, MATCH_ALL) to_state = config.get(CONF_TO) or config.get(CONF_STATE) or MATCH_ALL + if isinstance(from_state, bool) or isinstance(to_state, bool): + logging.getLogger(__name__).error( + 'Config error. Surround to/from values with quotes.') + return False + def state_automation_listener(entity, from_s, to_s): """ Listens for state changes and calls action. """ action() diff --git a/tests/components/automation/test_state.py b/tests/components/automation/test_state.py index a7c13e866c6..a31f694f8c0 100644 --- a/tests/components/automation/test_state.py +++ b/tests/components/automation/test_state.py @@ -8,6 +8,7 @@ import unittest import homeassistant.core as ha import homeassistant.components.automation as automation +import homeassistant.components.automation.state as state class TestAutomationState(unittest.TestCase): @@ -334,3 +335,19 @@ class TestAutomationState(unittest.TestCase): self.hass.pool.block_till_done() self.assertEqual(1, len(self.calls)) + + def test_if_fails_setup_if_to_boolean_value(self): + self.assertFalse(state.trigger( + self.hass, { + 'platform': 'state', + 'entity_id': 'test.entity', + 'to': True, + }, lambda x: x)) + + def test_if_fails_setup_if_from_boolean_value(self): + self.assertFalse(state.trigger( + self.hass, { + 'platform': 'state', + 'entity_id': 'test.entity', + 'from': True, + }, lambda x: x)) From 90d4a2c0b87c20569027b7d66e7b3a7610ebed65 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 20:10:32 -0700 Subject: [PATCH 022/226] Update frontend version --- .../components/frontend/www_static/home-assistant-polymer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 6989009b2d5..3d6792691a3 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 6989009b2d59e39fd39b3025ff5899877f618bd3 +Subproject commit 3d6792691a3d6beae5d446a6fbeb83c9025d040d From 7786b52d93ea88f19d8e9a774eefe0a1eef400f3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 20:11:30 -0700 Subject: [PATCH 023/226] Add shell_command component --- homeassistant/components/shell_command.py | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 homeassistant/components/shell_command.py diff --git a/homeassistant/components/shell_command.py b/homeassistant/components/shell_command.py new file mode 100644 index 00000000000..2fceaf71519 --- /dev/null +++ b/homeassistant/components/shell_command.py @@ -0,0 +1,48 @@ +""" +homeassistant.components.shell_command +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Component to expose shell commands as services. + +shell_command: + restart_pow: touch ~/.pow/restart.txt + +""" +import logging +import subprocess + +from homeassistant.util import slugify + +DOMAIN = 'shell_command' +DEPENDENCIES = [] + +_LOGGER = logging.getLogger(__name__) + + +def setup(hass, config): + """ Sets up the shell_command component. """ + conf = config.get(DOMAIN) + + if not isinstance(conf, dict): + _LOGGER.error('Expected configuration to be a dictionary') + return False + + for name in conf.keys(): + if name != slugify(name): + _LOGGER.error('Invalid service name: %s. Try %s', + name, slugify(name)) + return False + + def service_handler(call): + """ Execute a shell command service. """ + try: + subprocess.call(conf[call.service].split(' '), + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + except subprocess.SubprocessError: + _LOGGER.exception('Error running command') + + for name in conf.keys(): + hass.services.register(DOMAIN, name, service_handler) + + return True From 916c453d2ba939fb7eb15f4d87557c37bfc57a21 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 21:30:17 -0700 Subject: [PATCH 024/226] Add test for shell command --- tests/components/test_shell_command.py | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/components/test_shell_command.py diff --git a/tests/components/test_shell_command.py b/tests/components/test_shell_command.py new file mode 100644 index 00000000000..7cd7217449b --- /dev/null +++ b/tests/components/test_shell_command.py @@ -0,0 +1,38 @@ +""" +tests.test_shell_command +~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests demo component. +""" +import os +import tempfile +import unittest + +from homeassistant import core +from homeassistant.components import shell_command + + +class TestShellCommand(unittest.TestCase): + """ Test the demo module. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = core.HomeAssistant() + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_executing_service(self): + """ Test if able to call a configured service. """ + with tempfile.TemporaryDirectory() as tempdirname: + path = os.path.join(tempdirname, 'called.txt') + shell_command.setup(self.hass, { + 'shell_command': { + 'test_service': "touch {}".format(path) + } + }) + + self.hass.services.call('shell_command', 'test_service', + blocking=True) + + self.assertTrue(os.path.isfile(path)) From 6d77b15e4444a7ee1e29f055d36e163431442648 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 21:41:44 -0700 Subject: [PATCH 025/226] Few more tests --- tests/components/test_shell_command.py | 37 ++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/components/test_shell_command.py b/tests/components/test_shell_command.py index 7cd7217449b..d9248d8f861 100644 --- a/tests/components/test_shell_command.py +++ b/tests/components/test_shell_command.py @@ -7,6 +7,8 @@ Tests demo component. import os import tempfile import unittest +from unittest.mock import patch +from subprocess import SubprocessError from homeassistant import core from homeassistant.components import shell_command @@ -26,13 +28,44 @@ class TestShellCommand(unittest.TestCase): """ Test if able to call a configured service. """ with tempfile.TemporaryDirectory() as tempdirname: path = os.path.join(tempdirname, 'called.txt') - shell_command.setup(self.hass, { + self.assertTrue(shell_command.setup(self.hass, { 'shell_command': { 'test_service': "touch {}".format(path) } - }) + })) self.hass.services.call('shell_command', 'test_service', blocking=True) self.assertTrue(os.path.isfile(path)) + + def test_config_not_dict(self): + """ Test if config is not a dict. """ + self.assertFalse(shell_command.setup(self.hass, { + 'shell_command': ['some', 'weird', 'list'] + })) + + def test_config_not_valid_service_names(self): + """ Test if config contains invalid service names. """ + self.assertFalse(shell_command.setup(self.hass, { + 'shell_command': { + 'this is invalid because space': 'touch bla.txt' + }})) + + @patch('homeassistant.components.shell_command.subprocess.call', + side_effect=SubprocessError) + @patch('homeassistant.components.shell_command._LOGGER.error') + def test_subprocess_raising_error(self, mock_call, mock_error): + with tempfile.TemporaryDirectory() as tempdirname: + path = os.path.join(tempdirname, 'called.txt') + self.assertTrue(shell_command.setup(self.hass, { + 'shell_command': { + 'test_service': "touch {}".format(path) + } + })) + + self.hass.services.call('shell_command', 'test_service', + blocking=True) + + self.assertFalse(os.path.isfile(path)) + self.assertEqual(1, mock_error.call_count) From d6bbc671127af572502bf2d35de9adcda1da4f4e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 23:48:17 -0700 Subject: [PATCH 026/226] Add tests for scene --- homeassistant/components/scene.py | 15 ++++++- tests/components/test_scene.py | 68 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 tests/components/test_scene.py diff --git a/homeassistant/components/scene.py b/homeassistant/components/scene.py index 4a85adefd17..61fa86ff21b 100644 --- a/homeassistant/components/scene.py +++ b/homeassistant/components/scene.py @@ -36,6 +36,16 @@ CONF_ENTITIES = "entities" SceneConfig = namedtuple('SceneConfig', ['name', 'states', 'fuzzy_match']) +def activate(hass, entity_id=None): + """ Activate a scene. """ + data = {} + + if entity_id: + data[ATTR_ENTITY_ID] = entity_id + + hass.services.call(DOMAIN, SERVICE_TURN_ON, data) + + def setup(hass, config): """ Sets up scenes. """ @@ -43,8 +53,9 @@ def setup(hass, config): scene_configs = config.get(DOMAIN) - if not isinstance(scene_configs, list): - logger.error('Scene config should be a list of scenes') + if not isinstance(scene_configs, list) or \ + any(not isinstance(item, dict) for item in scene_configs): + logger.error('Scene config should be a list of dictionaries') return False component = EntityComponent(logger, DOMAIN, hass) diff --git a/tests/components/test_scene.py b/tests/components/test_scene.py new file mode 100644 index 00000000000..2fc8fe085c2 --- /dev/null +++ b/tests/components/test_scene.py @@ -0,0 +1,68 @@ +""" +tests.components.test_scene +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests scene component. +""" +import unittest + +from homeassistant import loader +from homeassistant.components import light, scene + +from tests.common import get_test_home_assistant + + +class TestScene(unittest.TestCase): + """ Test scene component. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = get_test_home_assistant() + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_config_not_list(self): + self.assertFalse(scene.setup(self.hass, { + 'scene': {'some': 'dict'} + })) + + def test_config_no_dict_in_list(self): + self.assertFalse(scene.setup(self.hass, { + 'scene': [[]] + })) + + def test_activate_scene(self): + test_light = loader.get_component('light.test') + test_light.init() + + self.assertTrue(light.setup(self.hass, { + light.DOMAIN: {'platform': 'test'} + })) + + light_1, light_2 = test_light.DEVICES[0:2] + + light.turn_off(self.hass, [light_1.entity_id, light_2.entity_id]) + + self.hass.pool.block_till_done() + + self.assertTrue(scene.setup(self.hass, { + 'scene': [{ + 'name': 'test', + 'entities': { + light_1.entity_id: 'on', + light_2.entity_id: { + 'state': 'on', + 'brightness': 100, + } + } + }] + })) + + scene.activate(self.hass, 'scene.test') + self.hass.pool.block_till_done() + + self.assertTrue(light_1.is_on) + self.assertTrue(light_2.is_on) + self.assertEqual(100, + light_2.last_call('turn_on')[1].get('brightness')) From cddc87b0ab0635fdb1e72cc27d9c086639741f60 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 11 Oct 2015 23:48:55 -0700 Subject: [PATCH 027/226] Remove turn off from scene --- homeassistant/components/scene.py | 125 +++--------------------------- 1 file changed, 11 insertions(+), 114 deletions(-) diff --git a/homeassistant/components/scene.py b/homeassistant/components/scene.py index 61fa86ff21b..66c15f8272f 100644 --- a/homeassistant/components/scene.py +++ b/homeassistant/components/scene.py @@ -6,34 +6,24 @@ Allows users to set and activate scenes within Home Assistant. A scene is a set of states that describe how you want certain entities to be. For example, light A should be red with 100 brightness. Light B should be on. - -A scene is active if all states of the scene match the real states. - -If a scene is manually activated it will store the previous state of the -entities. These will be restored when the state is deactivated manually. - -If one of the enties that are being tracked change state on its own, the -old state will not be restored when it is being deactivated. """ import logging from collections import namedtuple from homeassistant.core import State -from homeassistant.helpers.event import track_state_change -from homeassistant.helpers.entity import ToggleEntity +from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.state import reproduce_state from homeassistant.const import ( - ATTR_ENTITY_ID, STATE_OFF, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF) + ATTR_ENTITY_ID, STATE_OFF, STATE_ON, SERVICE_TURN_ON) DOMAIN = 'scene' DEPENDENCIES = ['group'] - -ATTR_ACTIVE_REQUESTED = "active_requested" +STATE = 'scening' CONF_ENTITIES = "entities" -SceneConfig = namedtuple('SceneConfig', ['name', 'states', 'fuzzy_match']) +SceneConfig = namedtuple('SceneConfig', ['name', 'states']) def activate(hass, entity_id=None): @@ -68,12 +58,8 @@ def setup(hass, config): target_scenes = component.extract_from_service(service) for scene in target_scenes: - if service.service == SERVICE_TURN_ON: - scene.turn_on() - else: - scene.turn_off() + scene.activate() - hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_scene_service) hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_scene_service) return True @@ -83,14 +69,6 @@ def _process_config(scene_config): """ Process passed in config into a format to work with. """ name = scene_config.get('name') - fuzzy_match = scene_config.get('fuzzy_match') - if fuzzy_match: - # default to 1% - if isinstance(fuzzy_match, int): - fuzzy_match /= 100.0 - else: - fuzzy_match = 0.01 - states = {} c_entities = dict(scene_config.get(CONF_ENTITIES, {})) @@ -111,23 +89,16 @@ def _process_config(scene_config): states[entity_id.lower()] = State(entity_id, state, attributes) - return SceneConfig(name, states, fuzzy_match) + return SceneConfig(name, states) -class Scene(ToggleEntity): +class Scene(Entity): """ A scene is a group of entities and the states we want them to be. """ def __init__(self, hass, scene_config): self.hass = hass self.scene_config = scene_config - self.is_active = False - self.prev_states = None - self.ignore_updates = False - - track_state_change( - self.hass, self.entity_ids, self.entity_state_changed) - self.update() @property @@ -139,8 +110,8 @@ class Scene(ToggleEntity): return self.scene_config.name @property - def is_on(self): - return self.is_active + def state(self): + return STATE @property def entity_ids(self): @@ -152,82 +123,8 @@ class Scene(ToggleEntity): """ Scene state attributes. """ return { ATTR_ENTITY_ID: list(self.entity_ids), - ATTR_ACTIVE_REQUESTED: self.prev_states is not None, } - def turn_on(self): + def activate(self): """ Activates scene. Tries to get entities into requested state. """ - self.prev_states = tuple(self.hass.states.get(entity_id) - for entity_id in self.entity_ids) - - self._reproduce_state(self.scene_config.states.values()) - - def turn_off(self): - """ Deactivates scene and restores old states. """ - if self.prev_states: - self._reproduce_state(self.prev_states) - self.prev_states = None - - def entity_state_changed(self, entity_id, old_state, new_state): - """ Called when an entity part of this scene changes state. """ - if self.ignore_updates: - return - - # If new state is not what we expect, it can never be active - if self._state_as_requested(new_state): - self.update() - else: - self.is_active = False - self.prev_states = None - - self.update_ha_state() - - def update(self): - """ - Update if the scene is active. - - Will look at each requested state and see if the current entity - has the same state and has at least the same attributes with the - same values. The real state can have more attributes. - """ - self.is_active = all( - self._state_as_requested(self.hass.states.get(entity_id)) - for entity_id in self.entity_ids) - - def _state_as_requested(self, cur_state): - """ Returns if given state is as requested. """ - state = self.scene_config.states.get(cur_state and cur_state.entity_id) - - return (cur_state is not None and state.state == cur_state.state and - all(self._compare_state_attribites( - value, cur_state.attributes.get(key)) - for key, value in state.attributes.items())) - - def _fuzzy_attribute_compare(self, attr_a, attr_b): - """ - Compare the attributes passed, use fuzzy logic if they are floats. - """ - - if not (isinstance(attr_a, float) and isinstance(attr_b, float)): - return False - diff = abs(attr_a - attr_b) / (abs(attr_a) + abs(attr_b)) - return diff <= self.scene_config.fuzzy_match - - def _compare_state_attribites(self, attr1, attr2): - """ Compare the attributes passed, using fuzzy logic if specified. """ - if attr1 == attr2: - return True - if not self.scene_config.fuzzy_match: - return False - if isinstance(attr1, list): - return all(self._fuzzy_attribute_compare(a, b) - for a, b in zip(attr1, attr2)) - return self._fuzzy_attribute_compare(attr1, attr2) - - def _reproduce_state(self, states): - """ Wraps reproduce state with Scence specific logic. """ - self.ignore_updates = True - reproduce_state(self.hass, states, True) - self.ignore_updates = False - - self.update_ha_state(True) + reproduce_state(self.hass, self.scene_config.states.values(), True) From 2f2bd7a616a0e47e4db1ad00655b1e9a5428f3b4 Mon Sep 17 00:00:00 2001 From: Heiko Rothe Date: Mon, 12 Oct 2015 09:18:55 +0200 Subject: [PATCH 028/226] Fixed pylint and pep8 violations --- .../components/device_tracker/tplink.py | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 2ecfaea4eb2..60c337309d4 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -82,9 +82,6 @@ class TplinkDeviceScanner(object): self.username = username self.password = password - self.stok = '' - self.sysauth = '' - self.last_results = {} self.lock = threading.Lock() self.success_init = self._update_info() @@ -162,7 +159,7 @@ class Tplink2DeviceScanner(TplinkDeviceScanner): with self.lock: _LOGGER.info("Loading wireless clients...") - url = 'http://{}/data/map_access_wireless_client_grid.json'\ + url = 'http://{}/data/map_access_wireless_client_grid.json' \ .format(self.host) referer = 'http://{}'.format(self.host) @@ -172,7 +169,7 @@ class Tplink2DeviceScanner(TplinkDeviceScanner): b64_encoded_username_password = base64.b64encode( username_password.encode('ascii') ).decode('ascii') - cookie = 'Authorization=Basic {}'\ + cookie = 'Authorization=Basic {}' \ .format(b64_encoded_username_password) response = requests.post(url, headers={'referer': referer, @@ -189,17 +186,23 @@ class Tplink2DeviceScanner(TplinkDeviceScanner): self.last_results = { device['mac_addr'].replace('-', ':'): device['name'] for device in result - } + } return True return False + class Tplink3DeviceScanner(TplinkDeviceScanner): """ This class queries the Archer C9 router running version 150811 or higher of TP-Link firmware for connected devices. """ + def __init__(self, config): + super(Tplink3DeviceScanner, self).__init__(config) + self.stok = '' + self.sysauth = '' + def scan_devices(self): """ Scans for new devices and return a list containing found device ids. @@ -224,30 +227,30 @@ class Tplink3DeviceScanner(TplinkDeviceScanner): _LOGGER.info("Retrieving auth tokens...") - url = 'http://{}/cgi-bin/luci/;stok=/login?form=login'\ + url = 'http://{}/cgi-bin/luci/;stok=/login?form=login' \ .format(self.host) referer = 'http://{}/webpages/login.html'.format(self.host) # if possible implement rsa encryption of password here - response = requests.post(url, params={'operation': 'login', - 'username': self.username, - 'password': self.password}, - headers={'referer': referer}) + response = requests.post(url, + params={'operation': 'login', + 'username': self.username, + 'password': self.password}, + headers={'referer': referer}) try: self.stok = response.json().get('data').get('stok') _LOGGER.info(self.stok) - regex_result = re.search('sysauth=(.*);', response.headers['set-cookie']) + regex_result = re.search('sysauth=(.*);', + response.headers['set-cookie']) self.sysauth = regex_result.group(1) _LOGGER.info(self.sysauth) return True - except: + except ValueError: _LOGGER.error("Couldn't fetch auth tokens!") return False - return False - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """ @@ -261,11 +264,14 @@ class Tplink3DeviceScanner(TplinkDeviceScanner): _LOGGER.info("Loading wireless clients...") - url = 'http://{}/cgi-bin/luci/;stok={}/admin/wireless?form=statistics'\ + url = 'http://{}/cgi-bin/luci/;stok={}/admin/wireless?form=statistics' \ .format(self.host, self.stok) referer = 'http://{}/webpages/index.html'.format(self.host) - response = requests.post(url, params={'operation': 'load'}, headers={'referer': referer}, cookies={'sysauth': self.sysauth}) + response = requests.post(url, + params={'operation': 'load'}, + headers={'referer': referer}, + cookies={'sysauth': self.sysauth}) try: json_response = response.json() @@ -274,12 +280,14 @@ class Tplink3DeviceScanner(TplinkDeviceScanner): result = response.json().get('data') else: if json_response.get('errorcode') == 'timeout': - _LOGGER.info("Token timed out. Relogging on next scan.") + _LOGGER.info("Token timed out. " + "Relogging on next scan.") self.stok = '' self.sysauth = '' return False else: - _LOGGER.error("An unknown error happened while fetching data.") + _LOGGER.error("An unknown error happened " + "while fetching data.") return False except ValueError: _LOGGER.error("Router didn't respond with JSON. " @@ -290,7 +298,7 @@ class Tplink3DeviceScanner(TplinkDeviceScanner): self.last_results = { device['mac'].replace('-', ':'): device['mac'] for device in result - } + } return True return False From b74e70d4e08262417675a75d693d1866dac948d4 Mon Sep 17 00:00:00 2001 From: Hans Bakker Date: Mon, 12 Oct 2015 20:58:24 +0200 Subject: [PATCH 029/226] Fixes based on balloob's comments --- homeassistant/components/device_tracker/geofancy.py | 11 +++-------- homeassistant/const.py | 1 - 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/device_tracker/geofancy.py b/homeassistant/components/device_tracker/geofancy.py index 8e8611e00b3..55ebf2e0d1b 100644 --- a/homeassistant/components/device_tracker/geofancy.py +++ b/homeassistant/components/device_tracker/geofancy.py @@ -9,13 +9,14 @@ device_tracker: """ from homeassistant.const import ( - URL_API_GEOFANCY_ENDPOINT, HTTP_UNPROCESSABLE_ENTITY, HTTP_INTERNAL_SERVER_ERROR) DEPENDENCIES = ['http'] _SEE = 0 +URL_API_GEOFANCY_ENDPOINT = "/api/geofancy" + def setup_scanner(hass, config, see): """ Set up an endpoint for the Geofancy app. """ @@ -66,12 +67,6 @@ def _handle_get_api_geofancy(handler, path_match, data): device_uuid = data['device'] device_entity_id = device_uuid.replace('-', '') - kwargs = { - 'dev_id': device_entity_id, - 'gps': gps_coords, - 'location_name': data['id'] - } - - _SEE(**kwargs) + _SEE(dev_id=device_entity_id, gps=gps_coords, location_name=data['id']) handler.write_json_message("Geofancy message processed") diff --git a/homeassistant/const.py b/homeassistant/const.py index ddda08001b9..d742b345384 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -145,7 +145,6 @@ URL_API_SERVICES_SERVICE = "/api/services/{}/{}" URL_API_EVENT_FORWARD = "/api/event_forwarding" URL_API_COMPONENTS = "/api/components" URL_API_BOOTSTRAP = "/api/bootstrap" -URL_API_GEOFANCY_ENDPOINT = '/api/geofancy' HTTP_OK = 200 HTTP_CREATED = 201 From a6cb19b27dea2af515875de5d5bc3b7192200b92 Mon Sep 17 00:00:00 2001 From: Heiko Rothe Date: Mon, 12 Oct 2015 22:42:45 +0200 Subject: [PATCH 030/226] Fixed an issue with the initiation of the new attributes --- homeassistant/components/device_tracker/tplink.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 60c337309d4..d368637cd6b 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -199,9 +199,9 @@ class Tplink3DeviceScanner(TplinkDeviceScanner): """ def __init__(self, config): - super(Tplink3DeviceScanner, self).__init__(config) self.stok = '' self.sysauth = '' + super(Tplink3DeviceScanner, self).__init__(config) def scan_devices(self): """ From 1b7ce2146c21262d2a0c2eda7569ce980ba426d9 Mon Sep 17 00:00:00 2001 From: sfam Date: Tue, 13 Oct 2015 00:56:24 +0000 Subject: [PATCH 031/226] replace sleeps with track_point_in_time --- .../alarm_control_panel/__init__.py | 28 ++++--- .../components/alarm_control_panel/manual.py | 77 ++++++++++++------- .../components/alarm_control_panel/mqtt.py | 5 +- .../alarm_control_panel/verisure.py | 5 +- 4 files changed, 69 insertions(+), 46 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index f922ecdacc0..802faaac958 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -73,40 +73,44 @@ def setup(hass, config): return True -def alarm_disarm(hass, code, entity_id=None): +def alarm_disarm(hass, code=None, entity_id=None): """ Send the alarm the command for disarm. """ - data = {ATTR_CODE: code} - + data = {} + if code: + data[ATTR_CODE] = code if entity_id: data[ATTR_ENTITY_ID] = entity_id hass.services.call(DOMAIN, SERVICE_ALARM_DISARM, data) -def alarm_arm_home(hass, code, entity_id=None): +def alarm_arm_home(hass, code=None, entity_id=None): """ Send the alarm the command for arm home. """ - data = {ATTR_CODE: code} - + data = {} + if code: + data[ATTR_CODE] = code if entity_id: data[ATTR_ENTITY_ID] = entity_id hass.services.call(DOMAIN, SERVICE_ALARM_ARM_HOME, data) -def alarm_arm_away(hass, code, entity_id=None): +def alarm_arm_away(hass, code=None, entity_id=None): """ Send the alarm the command for arm away. """ - data = {ATTR_CODE: code} - + data = {} + if code: + data[ATTR_CODE] = code if entity_id: data[ATTR_ENTITY_ID] = entity_id hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data) -def alarm_trigger(hass, code, entity_id=None): +def alarm_trigger(hass, code=None, entity_id=None): """ Send the alarm the command for trigger. """ - data = {ATTR_CODE: code} - + data = {} + if code: + data[ATTR_CODE] = code if entity_id: data[ATTR_ENTITY_ID] = entity_id diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index e83a2e9da2f..eaeda59719b 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -33,8 +33,10 @@ Default is 120 seconds. """ import logging -import time +import datetime import homeassistant.components.alarm_control_panel as alarm +from homeassistant.helpers.event import track_point_in_time +import homeassistant.util.dt as dt_util from homeassistant.const import ( STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, @@ -62,6 +64,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): # pylint: disable=too-many-arguments, too-many-instance-attributes +# pylint: disable=abstract-method class ManualAlarm(alarm.AlarmControlPanel): """ represents an alarm status within home assistant. """ @@ -70,8 +73,9 @@ class ManualAlarm(alarm.AlarmControlPanel): self._hass = hass self._name = name self._code = code - self._pending_time = pending_time - self._trigger_time = trigger_time + self._pending_time = datetime.timedelta(seconds=pending_time) + self._trigger_time = datetime.timedelta(seconds=trigger_time) + self._state_ts = None self._pending_to = None @property @@ -94,49 +98,70 @@ class ManualAlarm(alarm.AlarmControlPanel): """ One or more characters """ return None if self._code is None else '.+' - def change_alarm_state(self, begin, end, delay=0): + def update_state(self, state, pending_to): """ changes between state with delay """ - self._state = begin - self._pending_to = end + self._state = state + self._state_ts = dt_util.utcnow() + self._pending_to = pending_to self.update_ha_state() - time.sleep(delay) - if self._pending_to == end and begin != end: - self._state = end - self._pending_to = None - self.update_ha_state() def alarm_disarm(self, code=None): """ Send disarm command. """ if code == str(self._code) or self.code_format is None: - self.change_alarm_state( - STATE_ALARM_DISARMED, STATE_ALARM_DISARMED) + self.update_state(STATE_ALARM_DISARMED, None) else: _LOGGER.warning("Wrong code entered while disarming!") def alarm_arm_home(self, code=None): """ Send arm home command. """ if code == str(self._code) or self.code_format is None: - self.change_alarm_state( - STATE_ALARM_PENDING, STATE_ALARM_ARMED_HOME, - self._pending_time) + self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_HOME) + + def delayed_alarm_arm_home(event_time): + """ callback for delayed action """ + if self._pending_to == STATE_ALARM_ARMED_HOME and \ + dt_util.utcnow() - self._state_ts >= self._pending_time: + self.update_state(STATE_ALARM_ARMED_HOME, None) + track_point_in_time( + self._hass, delayed_alarm_arm_home, + dt_util.utcnow() + self._pending_time) else: _LOGGER.warning("Wrong code entered while arming home!") def alarm_arm_away(self, code=None): """ Send arm away command. """ if code == str(self._code) or self.code_format is None: - self.change_alarm_state( - STATE_ALARM_PENDING, STATE_ALARM_ARMED_AWAY, - self._pending_time) + self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_AWAY) + + def delayed_alarm_arm_away(event_time): + """ callback for delayed action """ + if self._pending_to == STATE_ALARM_ARMED_AWAY and \ + dt_util.utcnow() - self._state_ts >= self._pending_time: + self.update_state(STATE_ALARM_ARMED_AWAY, None) + track_point_in_time( + self._hass, delayed_alarm_arm_away, + dt_util.utcnow() + self._pending_time) else: _LOGGER.warning("Wrong code entered while arming away!") def alarm_trigger(self, code=None): """ Send alarm trigger command. No code needed. """ - self.change_alarm_state( - STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, - self._pending_time) - if self._state == STATE_ALARM_TRIGGERED: - self.change_alarm_state( - STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED, - self._trigger_time) + self.update_state(STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) + + def delayed_alarm_trigger(event_time): + """ callback for delayed action """ + if self._pending_to == STATE_ALARM_TRIGGERED and \ + dt_util.utcnow() - self._state_ts >= self._pending_time: + self.update_state(STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED) + + def delayed_alarm_disarm(event_time): + """ callback for delayed action """ + if self._pending_to == STATE_ALARM_DISARMED and \ + dt_util.utcnow() - self._state_ts >= self._trigger_time: + self.update_state(STATE_ALARM_DISARMED, None) + track_point_in_time( + self._hass, delayed_alarm_disarm, + dt_util.utcnow() + self._trigger_time) + track_point_in_time( + self._hass, delayed_alarm_trigger, + dt_util.utcnow() + self._pending_time) diff --git a/homeassistant/components/alarm_control_panel/mqtt.py b/homeassistant/components/alarm_control_panel/mqtt.py index 27e78cb38fe..cd71e223481 100644 --- a/homeassistant/components/alarm_control_panel/mqtt.py +++ b/homeassistant/components/alarm_control_panel/mqtt.py @@ -100,6 +100,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): # pylint: disable=too-many-arguments, too-many-instance-attributes +# pylint: disable=abstract-method class MqttAlarm(alarm.AlarmControlPanel): """ represents a MQTT alarm status within home assistant. """ @@ -166,7 +167,3 @@ class MqttAlarm(alarm.AlarmControlPanel): self._payload_arm_away, self._qos) else: _LOGGER.warning("Wrong code entered while arming away!") - - def alarm_trigger(self, code=None): - """ Send alarm trigger command. No code needed. """ - return diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index f590d462e9b..b2c10e6114e 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -33,6 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): add_devices(alarms) +# pylint: disable=abstract-method class VerisureAlarm(alarm.AlarmControlPanel): """ represents a Verisure alarm status within home assistant. """ @@ -91,7 +92,3 @@ class VerisureAlarm(alarm.AlarmControlPanel): code, verisure.MY_PAGES.ALARM_ARMED_AWAY) _LOGGER.warning('arming away') - - def alarm_trigger(self, code=None): - """ Send alarm trigger command. No code needed. """ - return From 383efee4703cd7dca10232e3f145fc000654b7e9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 12 Oct 2015 23:40:09 -0700 Subject: [PATCH 032/226] Scene turn off for frontend --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 30 ++++++++++++------- .../www_static/home-assistant-polymer | 2 +- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index abf0c498b1a..98deab3f447 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -1,2 +1,2 @@ """ DO NOT MODIFY. Auto-generated by build_frontend script """ -VERSION = "c4722afa376379bc4457d54bb9a38cee" +VERSION = "90c41bfbaa56f9a1c88db27a54f7d36b" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 73fdb905114..18bb5c557f9 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -4010,6 +4010,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN transition: border .3s ease-in-out; } .label-badge .value { + font-size: 90%; overflow: hidden; text-overflow: ellipsis; } @@ -4060,7 +4061,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } .blue { - --ha-label-badge-color: #039be5; + --ha-label-badge-color: #039be5; + } + + .green { + --ha-label-badge-color: #0DA035; } .grey { @@ -4269,7 +4274,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN .current { color: var(--secondary-text-color); - } \ No newline at end of file +console.group&&(console.groupCollapsed("Dispatch: %s",t),console.group("payload"),console.debug(e),console.groupEnd())},e.dispatchError=function(t){console.group&&(console.debug("Dispatch error: "+t),console.groupEnd())},e.storeHandled=function(t,e,n){console.group&&e!==n&&console.debug("Store "+t+" handled action")},e.dispatchEnd=function(t){console.group&&(console.debug("Dispatch done, new state: ",t.toJS()),console.groupEnd())}},function(t,e,n){function r(t,e){this.__prevState=t,this.__evaluator=e,this.__prevValues=i.Map(),this.__observers=[]}var i=n(2),o=n(7),u=n(8);Object.defineProperty(r.prototype,"notifyObservers",{writable:!0,configurable:!0,value:function(t){if(this.__observers.length>0){var e=i.Map();this.__observers.forEach(function(n){var r,i=n.getter,a=o(i),s=this.__prevState;this.__prevValues.has(a)?r=this.__prevValues.get(a):(r=this.__evaluator.evaluate(s,i),this.__prevValues=this.__prevValues.set(a,r));var c=this.__evaluator.evaluate(t,i);u(r,c)||(n.handler.call(null,c),e=e.set(a,c))}.bind(this)),this.__prevValues=e}this.__prevState=t}}),Object.defineProperty(r.prototype,"onChange",{writable:!0,configurable:!0,value:function(t,e){var n={getter:t,handler:e};return this.__observers.push(n),function(){var t=this.__observers.indexOf(n);t>-1&&this.__observers.splice(t,1)}.bind(this)}}),Object.defineProperty(r.prototype,"reset",{writable:!0,configurable:!0,value:function(t){this.__prevState=t,this.__prevValues=i.Map(),this.__observers=[]}}),t.exports=r},function(t,e,n){var r=n(2);t.exports=function(t,e){if(t.hasOwnProperty("__hashCode"))return t.__hashCode;var n=r.fromJS(t).hashCode();return e||(Object.defineProperty(t,"__hashCode",{enumerable:!1,configurable:!1,writable:!1,value:n}),Object.freeze(t)),n}},function(t,e,n){var r=n(2);t.exports=function(t,e){return r.is(t,e)}},function(t,e,n){function r(t){return s(t)&&a(t[t.length-1])}function i(t){return t[t.length-1]}function o(t){return t.slice(0,t.length-1)}function u(t){if(!c(t))throw new Error("Cannot create Getter from KeyPath: "+t);return[t,l]}var a=n(3).isFunction,s=n(3).isArray,c=n(10).isKeyPath,l=function(t){return t};t.exports={isGetter:r,getComputeFn:i,getDeps:o,fromKeyPath:u}},function(t,e,n){var r=n(3).isArray,i=n(3).isFunction;e.isKeyPath=function(t){return r(t)&&!i(t[t.length-1])}},function(t,e,n){function r(){this.__cachedGetters=i.Map({})}var i=n(2),o=n(1).toImmutable,u=n(7),a=n(8),s=n(9).getComputeFn,c=n(9).getDeps,l=n(10).isKeyPath,f=n(9).isGetter,d=!1;Object.defineProperty(r.prototype,"evaluate",{writable:!0,configurable:!0,value:function(t,e){if(l(e))return t.getIn(e);if(!f(e))throw new Error("evaluate must be passed a keyPath or Getter");var n=u(e);if(this.__isCached(t,e))return this.__cachedGetters.getIn([n,"value"]);var r=c(e).map(function(e){return this.evaluate(t,e)}.bind(this));if(this.__hasStaleValue(t,e)){var i=this.__cachedGetters.getIn([n,"args"]);if(a(i,o(r))){var p=this.__cachedGetters.getIn([n,"value"]);return this.__cacheValue(t,e,i,p),p}}if(d===!0)throw d=!1,new Error("Evaluate may not be called within a Getters computeFn");var h;d=!0;try{h=s(e).apply(null,r),d=!1}catch(v){throw d=!1,v}return this.__cacheValue(t,e,r,h),h}}),Object.defineProperty(r.prototype,"__hasStaleValue",{writable:!0,configurable:!0,value:function(t,e){var n=u(e),r=this.__cachedGetters;return r.has(n)&&r.getIn([n,"stateHashCode"])!==t.hashCode()}}),Object.defineProperty(r.prototype,"__cacheValue",{writable:!0,configurable:!0,value:function(t,e,n,r){var a=u(e);this.__cachedGetters=this.__cachedGetters.set(a,i.Map({value:r,args:o(n),stateHashCode:t.hashCode()}))}}),Object.defineProperty(r.prototype,"__isCached",{writable:!0,configurable:!0,value:function(t,e){var n=u(e);return this.__cachedGetters.hasIn([n,"value"])&&this.__cachedGetters.getIn([n,"stateHashCode"])===t.hashCode()}}),Object.defineProperty(r.prototype,"untrack",{writable:!0,configurable:!0,value:function(t){}}),Object.defineProperty(r.prototype,"reset",{writable:!0,configurable:!0,value:function(){this.__cachedGetters=i.Map({})}}),t.exports=r},function(t,e,n){function r(t,e){var n={};return i(e,function(e,r){n[r]=t.evaluate(e)}),n}var i=n(3).each;t.exports=function(t){return{getInitialState:function(){return r(t,this.getDataBindings())},componentDidMount:function(){var e=this;e.__unwatchFns=[],i(this.getDataBindings(),function(n,r){var i=t.observe(n,function(t){var n={};n[r]=t,e.setState(n)});e.__unwatchFns.push(i)})},componentWillUnmount:function(){for(;this.__unwatchFns.length;)this.__unwatchFns.shift()()}}}},function(t,e,n){function r(t){return this instanceof r?(this.__handlers=o({}),t&&u(this,t),void this.initialize()):new r(t)}function i(t){return t instanceof r}var o=n(2).Map,u=n(3).extend,a=n(1).toJS,s=n(1).toImmutable;Object.defineProperty(r.prototype,"initialize",{writable:!0,configurable:!0,value:function(){}}),Object.defineProperty(r.prototype,"getInitialState",{writable:!0,configurable:!0,value:function(){return o()}}),Object.defineProperty(r.prototype,"handle",{writable:!0,configurable:!0,value:function(t,e,n){var r=this.__handlers.get(e);return"function"==typeof r?r.call(this,t,n,e):t}}),Object.defineProperty(r.prototype,"handleReset",{writable:!0,configurable:!0,value:function(t){return this.getInitialState()}}),Object.defineProperty(r.prototype,"on",{writable:!0,configurable:!0,value:function(t,e){this.__handlers=this.__handlers.set(t,e)}}),Object.defineProperty(r.prototype,"serialize",{writable:!0,configurable:!0,value:function(t){return a(t)}}),Object.defineProperty(r.prototype,"deserialize",{writable:!0,configurable:!0,value:function(t){return s(t)}}),t.exports=r,t.exports.isStore=i}])})},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(179),u=r(o);e["default"]=u["default"](i.reactor),t.exports=e["default"]},function(t,e){"use strict";var n=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};t.exports=n},function(t,e){"use strict";function n(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}t.exports=n},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(188),o=r(i);e.callApi=o["default"]},function(t,e,n){"use strict";function r(t){return i(t)?t:Object(t)}var i=n(6);t.exports=r},function(t,e,n){"use strict";var r=n(20),i=n(12),o=n(13),u="[object Array]",a=Object.prototype,s=a.toString,c=r(Array,"isArray"),l=c||function(t){return o(t)&&i(t.length)&&s.call(t)==u};t.exports=l},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(204),u=i(o),a=n(205),s=r(a),c=u["default"];e.actions=c;var l=s;e.getters=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){t.registerStores({restApiCache:l["default"]})}function o(t){return[["restApiCache",t.entity],function(t){return!!t}]}function u(t){return[["restApiCache",t.entity],function(t){return t||s.toImmutable({})}]}function a(t){return function(e){return["restApiCache",t.entity,e]}}Object.defineProperty(e,"__esModule",{value:!0}),e.register=i,e.createHasDataGetter=o,e.createEntityMapGetter=u,e.createByIdGetter=a;var s=n(3),c=n(228),l=r(c),f=n(227),d=r(f);e.createApiActions=d["default"]},function(t,e){"use strict";function n(t){return"number"==typeof t&&t>-1&&t%1==0&&r>=t}var r=9007199254740991;t.exports=n},function(t,e){"use strict";function n(t){return!!t&&"object"==typeof t}t.exports=n},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(138),n(59),e["default"]=new o["default"]({is:"state-info",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"partial-base",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1}},computeMenuButtonClass:function(t,e){return!t&&e?"invisible":""},toggleMenu:function(){this.fire("open-menu")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({ENTITY_HISTORY_DATE_SELECTED:null,ENTITY_HISTORY_FETCH_START:null,ENTITY_HISTORY_FETCH_ERROR:null,ENTITY_HISTORY_FETCH_SUCCESS:null,RECENT_ENTITY_HISTORY_FETCH_START:null,RECENT_ENTITY_HISTORY_FETCH_ERROR:null,RECENT_ENTITY_HISTORY_FETCH_SUCCESS:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return null!=t&&o(i(t))}var i=n(50),o=n(12);t.exports=r},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({LOGBOOK_DATE_SELECTED:null,LOGBOOK_ENTRIES_FETCH_START:null,LOGBOOK_ENTRIES_FETCH_ERROR:null,LOGBOOK_ENTRIES_FETCH_SUCCESS:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(229),u=i(o),a=n(79),s=r(a),c=u["default"];e.actions=c;var l=s;e.getters=l},function(t,e,n){"use strict";function r(t,e){var n=null==t?void 0:t[e];return i(n)?n:void 0}var i=n(126);t.exports=r},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({VALIDATING_AUTH_TOKEN:null,VALID_AUTH_TOKEN:null,INVALID_AUTH_TOKEN:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({authAttempt:a["default"],authCurrent:c["default"],rememberAuth:f["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(191),a=i(u),s=n(192),c=i(s),l=n(193),f=i(l),d=n(189),p=r(d),h=n(190),v=r(h),_=p;e.actions=_;var y=v;e.getters=y},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=t[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!e||n.length!==e);r=!0);}catch(s){i=!0,o=s}finally{try{!r&&a["return"]&&a["return"]()}finally{if(i)throw o}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),a=function(){function t(t,e){for(var n=0;n-1&&t%1==0&&e>t}var r=/^\d+$/,i=9007199254740991;t.exports=n},function(t,e,n){"use strict";function r(t,e,n){if(!u(n))return!1;var r=typeof e;if("number"==r?i(n)&&o(e,n.length):"string"==r&&e in n){var a=n[e];return t===t?t===a:a!==a}return!1}var i=n(17),o=n(25),u=n(6);t.exports=r},function(t,e,n){"use strict";function r(t){return o(t)&&i(t)&&a.call(t,"callee")&&!s.call(t,"callee")}var i=n(17),o=n(13),u=Object.prototype,a=u.hasOwnProperty,s=u.propertyIsEnumerable;t.exports=r},function(t,e,n){"use strict";var r=n(20),i=n(17),o=n(6),u=n(123),a=r(Object,"keys"),s=a?function(t){var e=null==t?void 0:t.constructor;return"function"==typeof e&&e.prototype===t||"function"!=typeof t&&i(t)?u(t):o(t)?a(t):[]}:u;t.exports=s},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(62),a=r(u);e["default"]=new o["default"]({is:"domain-icon",properties:{domain:{type:String,value:""},state:{type:String,value:""}},computeIcon:function(t,e){return a["default"](t,e)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"ha-label-badge",properties:{value:{type:String},icon:{type:String},label:{type:String},description:{type:String},image:{type:String,observe:"imageChanged"}},computeClasses:function(t){return t&&t.length>5?"value big":"value"}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"loading-box"}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(180),a=r(u);n(61),n(178),n(177),n(174),n(176),n(175),e["default"]=new o["default"]({is:"state-card-content",properties:{stateObj:{type:Object,observer:"stateObjChanged"}},stateObjChanged:function(t,e){var n=o["default"].dom(this);if(!t)return void(n.lastChild&&n.removeChild(n.lastChild));var r=a["default"](t);if(e&&a["default"](e)===r)n.lastChild.stateObj=t;else{n.lastChild&&n.removeChild(n.lastChild);var i=document.createElement("state-card-"+r);i.stateObj=t,n.appendChild(i)}}}),t.exports=e["default"]},function(t,e){"use strict";function n(t,e){return t?e.map(function(e){return e in t.attributes?"has-"+e:""}).join(" "):""}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return i.reactor.evaluate(i.serviceGetters.canToggleEntity(t))}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=r;var i=n(2);t.exports=e["default"]},function(t,e,n){"use strict";function r(t,e,n){function r(){y&&clearTimeout(y),p&&clearTimeout(p),g=0,p=y=m=void 0}function s(e,n){n&&clearTimeout(n),p=y=m=void 0,e&&(g=o(),h=t.apply(_,d),y||p||(d=_=void 0))}function c(){var t=e-(o()-v);0>=t||t>e?s(m,p):y=setTimeout(c,t)}function l(){s(O,y)}function f(){if(d=arguments,v=o(),_=this,m=O&&(y||!w),b===!1)var n=w&&!y;else{p||w||(g=v);var r=b-(v-g),i=0>=r||r>b;i?(p&&(p=clearTimeout(p)),g=v,h=t.apply(_,d)):p||(p=setTimeout(l,r))}return i&&y?y=clearTimeout(y):y||e===b||(y=setTimeout(c,e)),n&&(i=!0,h=t.apply(_,d)),!i||y||p||(d=_=void 0),h}var d,p,h,v,_,y,m,g=0,b=!1,O=!0;if("function"!=typeof t)throw new TypeError(u);if(e=0>e?0:+e||0,n===!0){var w=!0;O=!1}else i(n)&&(w=!!n.leading,b="maxWait"in n&&a(+n.maxWait||0,e),O="trailing"in n?!!n.trailing:O);return f.cancel=r,f}var i=n(68),o=n(184),u="Expected a function",a=Math.max;t.exports=r},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({SERVER_CONFIG_LOADED:null,COMPONENT_LOADED:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({serverComponent:a["default"],serverConfig:c["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(196),a=i(u),s=n(197),c=i(s),l=n(194),f=r(l),d=n(195),p=r(d),h=f;e.actions=h;var v=p;e.getters=v},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(206),u=i(o),a=n(207),s=r(a),c=u["default"];e.actions=c;var l=s;e.getters=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({NAVIGATE:null,SHOW_SIDEBAR:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({notifications:a["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(224),a=i(u),s=n(222),c=r(s),l=n(223),f=r(l),d=c;e.actions=d;var p=f;e.getters=p},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({streamStatus:a["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(236),a=i(u),s=n(232),c=r(s),l=n(233),f=r(l),d=c;e.actions=d;var p=f;e.getters=p},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({API_FETCH_ALL_START:null,API_FETCH_ALL_SUCCESS:null,API_FETCH_ALL_FAIL:null,SYNC_SCHEDULED:null,SYNC_SCHEDULE_CANCELLED:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({isFetchingData:a["default"],isSyncScheduled:c["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(238),a=i(u),s=n(239),c=i(s),l=n(237),f=r(l),d=n(82),p=r(d),h=f;e.actions=h;var v=p;e.getters=v},function(t,e){"use strict";function n(t){return t.getFullYear()+"-"+(t.getMonth()+1)+"-"+t.getDate()}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e){"use strict";function n(t){var e=t.split(" "),n=r(e,2),i=n[0],o=n[1],u=i.split(":"),a=r(u,3),s=a[0],c=a[1],l=a[2],f=o.split("-"),d=r(f,3),p=d[0],h=d[1],v=d[2];return new Date(Date.UTC(v,parseInt(h,10)-1,p,s,c,l))}Object.defineProperty(e,"__esModule",{value:!0});var r=function(){function t(t,e){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=t[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!e||n.length!==e);r=!0);}catch(s){i=!0,o=s}finally{try{!r&&a["return"]&&a["return"]()}finally{if(i)throw o}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t,e,n){if(null!=t){void 0!==n&&n in i(t)&&(e=[n]);for(var r=0,o=e.length;null!=t&&o>r;)t=t[e[r++]];return r&&r==o?t:void 0}}var i=n(8);t.exports=r},function(t,e,n){"use strict";function r(t,e,n,a,s,c){return t===e?!0:null==t||null==e||!o(t)&&!u(e)?t!==t&&e!==e:i(t,e,r,n,a,s,c)}var i=n(102),o=n(6),u=n(13);t.exports=r},function(t,e,n){"use strict";function r(t,e){var n=-1,r=o(t)?Array(t.length):[];return i(t,function(t,i,o){r[++n]=e(t,i,o)}),r}var i=n(97),o=n(17);t.exports=r},function(t,e){"use strict";function n(t){return function(e){return null==e?void 0:e[t]}}t.exports=n},function(t,e,n){"use strict";var r=n(49),i=r("length");t.exports=i},function(t,e,n){"use strict";function r(t,e){var n=typeof t;if("string"==n&&a.test(t)||"number"==n)return!0;if(i(t))return!1;var r=!u.test(t);return r||null!=e&&t in o(e)}var i=n(9),o=n(8),u=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,a=/^\w*$/;t.exports=r},function(t,e,n){"use strict";function r(t){return t===t&&!i(t)}var i=n(6);t.exports=r},function(t,e,n){"use strict";function r(t){if(o(t))return t;var e=[];return i(t).replace(u,function(t,n,r,i){e.push(r?i.replace(a,"$1"):n||t)}),e}var i=n(109),o=n(9),u=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g,a=/\\(\\)?/g;t.exports=r},function(t,e){"use strict";function n(t){return t}t.exports=n},function(t,e,n){"use strict";function r(t){return u(t)?i(t):o(t)}var i=n(49),o=n(106),u=n(51);t.exports=r},function(t,e,n){(function(t){"use strict";!function(e,n){t.exports=n()}(void 0,function(){function e(){return Ln.apply(null,arguments)}function n(t){Ln=t}function r(t){return"[object Array]"===Object.prototype.toString.call(t)}function i(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function o(t,e){var n,r=[];for(n=0;n0)for(n in Rn)r=Rn[n],i=e[r],"undefined"!=typeof i&&(t[r]=i);return t}function h(t){p(this,t),this._d=new Date(null!=t._d?t._d.getTime():NaN),zn===!1&&(zn=!0,e.updateOffset(this),zn=!1)}function v(t){return t instanceof h||null!=t&&null!=t._isAMomentObject}function _(t){return 0>t?Math.ceil(t):Math.floor(t)}function y(t){var e=+t,n=0;return 0!==e&&isFinite(e)&&(n=_(e)),n}function m(t,e,n){var r,i=Math.min(t.length,e.length),o=Math.abs(t.length-e.length),u=0;for(r=0;i>r;r++)(n&&t[r]!==e[r]||!n&&y(t[r])!==y(e[r]))&&u++;return u+o}function g(){}function b(t){return t?t.toLowerCase().replace("_","-"):t}function O(t){for(var e,n,r,i,o=0;o0;){if(r=w(i.slice(0,e).join("-")))return r;if(n&&n.length>=e&&m(i,n,!0)>=e-1)break;e--}o++}return null}function w(e){var n=null;if(!Hn[e]&&"undefined"!=typeof t&&t&&t.exports)try{n=Nn._abbr,!function(){var t=new Error('Cannot find module "./locale"');throw t.code="MODULE_NOT_FOUND",t}(),S(n)}catch(r){}return Hn[e]}function S(t,e){var n;return t&&(n="undefined"==typeof e?j(t):M(t,e),n&&(Nn=n)),Nn._abbr}function M(t,e){return null!==e?(e.abbr=t,Hn[t]=Hn[t]||new g,Hn[t].set(e),S(t),Hn[t]):(delete Hn[t],null)}function j(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Nn;if(!r(t)){if(e=w(t))return e;t=[t]}return O(t)}function T(t,e){var n=t.toLowerCase();Yn[n]=Yn[n+"s"]=Yn[e]=t}function E(t){return"string"==typeof t?Yn[t]||Yn[t.toLowerCase()]:void 0}function I(t){var e,n,r={};for(n in t)u(t,n)&&(e=E(n),e&&(r[e]=t[n]));return r}function P(t,n){return function(r){return null!=r?(C(this,t,r),e.updateOffset(this,n),this):D(this,t)}}function D(t,e){return t._d["get"+(t._isUTC?"UTC":"")+e]()}function C(t,e,n){return t._d["set"+(t._isUTC?"UTC":"")+e](n)}function A(t,e){var n;if("object"==typeof t)for(n in t)this.set(n,t[n]);else if(t=E(t),"function"==typeof this[t])return this[t](e);return this}function x(t,e,n){var r=""+Math.abs(t),i=e-r.length,o=t>=0;return(o?n?"+":"":"-")+Math.pow(10,Math.max(0,i)).toString().substr(1)+r}function k(t,e,n,r){var i=r;"string"==typeof r&&(i=function(){return this[r]()}),t&&(Bn[t]=i),e&&(Bn[e[0]]=function(){return x(i.apply(this,arguments),e[1],e[2])}),n&&(Bn[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),t)})}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function N(t){var e,n,r=t.match(Gn);for(e=0,n=r.length;n>e;e++)Bn[r[e]]?r[e]=Bn[r[e]]:r[e]=L(r[e]);return function(i){var o="";for(e=0;n>e;e++)o+=r[e]instanceof Function?r[e].call(i,t):r[e];return o}}function R(t,e){return t.isValid()?(e=z(e,t.localeData()),Un[e]=Un[e]||N(e),Un[e](t)):t.localeData().invalidDate()}function z(t,e){function n(t){return e.longDateFormat(t)||t}var r=5;for(Fn.lastIndex=0;r>=0&&Fn.test(t);)t=t.replace(Fn,n),Fn.lastIndex=0,r-=1;return t}function H(t){return"function"==typeof t&&"[object Function]"===Object.prototype.toString.call(t)}function Y(t,e,n){or[t]=H(e)?e:function(t){return t&&n?n:e}}function G(t,e){return u(or,t)?or[t](e._strict,e._locale):new RegExp(F(t))}function F(t){return t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,n,r,i){return e||n||r||i}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t,e){var n,r=e;for("string"==typeof t&&(t=[t]),"number"==typeof e&&(r=function(t,n){n[e]=y(t)}),n=0;nr;r++){if(i=s([2e3,r]),n&&!this._longMonthsParse[r]&&(this._longMonthsParse[r]=new RegExp("^"+this.months(i,"").replace(".","")+"$","i"),this._shortMonthsParse[r]=new RegExp("^"+this.monthsShort(i,"").replace(".","")+"$","i")),n||this._monthsParse[r]||(o="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[r]=new RegExp(o.replace(".",""),"i")),n&&"MMMM"===e&&this._longMonthsParse[r].test(t))return r;if(n&&"MMM"===e&&this._shortMonthsParse[r].test(t))return r;if(!n&&this._monthsParse[r].test(t))return r}}function $(t,e){var n;return"string"==typeof e&&(e=t.localeData().monthsParse(e),"number"!=typeof e)?t:(n=Math.min(t.date(),q(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,n),t)}function Z(t){return null!=t?($(this,t),e.updateOffset(this,!0),this):D(this,"Month")}function X(){return q(this.year(),this.month())}function Q(t){var e,n=t._a;return n&&-2===l(t).overflow&&(e=n[sr]<0||n[sr]>11?sr:n[cr]<1||n[cr]>q(n[ar],n[sr])?cr:n[lr]<0||n[lr]>24||24===n[lr]&&(0!==n[fr]||0!==n[dr]||0!==n[pr])?lr:n[fr]<0||n[fr]>59?fr:n[dr]<0||n[dr]>59?dr:n[pr]<0||n[pr]>999?pr:-1,l(t)._overflowDayOfYear&&(ar>e||e>cr)&&(e=cr),l(t).overflow=e),t}function tt(t){e.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function et(t,e){var n=!0;return a(function(){return n&&(tt(t+"\n"+(new Error).stack),n=!1),e.apply(this,arguments)},e)}function nt(t,e){_r[t]||(tt(e),_r[t]=!0)}function rt(t){var e,n,r=t._i,i=yr.exec(r);if(i){for(l(t).iso=!0,e=0,n=mr.length;n>e;e++)if(mr[e][1].exec(r)){t._f=mr[e][0];break}for(e=0,n=gr.length;n>e;e++)if(gr[e][1].exec(r)){t._f+=(i[6]||" ")+gr[e][0];break}r.match(nr)&&(t._f+="Z"),wt(t)}else t._isValid=!1}function it(t){var n=br.exec(t._i);return null!==n?void(t._d=new Date(+n[1])):(rt(t),void(t._isValid===!1&&(delete t._isValid,e.createFromInputFallback(t))))}function ot(t,e,n,r,i,o,u){var a=new Date(t,e,n,r,i,o,u);return 1970>t&&a.setFullYear(t),a}function ut(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function at(t){return st(t)?366:365}function st(t){return t%4===0&&t%100!==0||t%400===0}function ct(){return st(this.year())}function lt(t,e,n){var r,i=n-e,o=n-t.day();return o>i&&(o-=7),i-7>o&&(o+=7),r=Dt(t).add(o,"d"),{week:Math.ceil(r.dayOfYear()/7),year:r.year()}}function ft(t){return lt(t,this._week.dow,this._week.doy).week}function dt(){return this._week.dow}function pt(){return this._week.doy}function ht(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")}function vt(t){var e=lt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")}function _t(t,e,n,r,i){var o,u=6+i-r,a=ut(t,0,1+u),s=a.getUTCDay();return i>s&&(s+=7),n=null!=n?1*n:i,o=1+u+7*(e-1)-s+n,{year:o>0?t:t-1,dayOfYear:o>0?o:at(t-1)+o}}function yt(t){var e=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")}function mt(t,e,n){return null!=t?t:null!=e?e:n}function gt(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function bt(t){var e,n,r,i,o=[];if(!t._d){for(r=gt(t),t._w&&null==t._a[cr]&&null==t._a[sr]&&Ot(t),t._dayOfYear&&(i=mt(t._a[ar],r[ar]),t._dayOfYear>at(i)&&(l(t)._overflowDayOfYear=!0), +n=ut(i,0,t._dayOfYear),t._a[sr]=n.getUTCMonth(),t._a[cr]=n.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=o[e]=r[e];for(;7>e;e++)t._a[e]=o[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[lr]&&0===t._a[fr]&&0===t._a[dr]&&0===t._a[pr]&&(t._nextDay=!0,t._a[lr]=0),t._d=(t._useUTC?ut:ot).apply(null,o),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[lr]=24)}}function Ot(t){var e,n,r,i,o,u,a;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(o=1,u=4,n=mt(e.GG,t._a[ar],lt(Dt(),1,4).year),r=mt(e.W,1),i=mt(e.E,1)):(o=t._locale._week.dow,u=t._locale._week.doy,n=mt(e.gg,t._a[ar],lt(Dt(),o,u).year),r=mt(e.w,1),null!=e.d?(i=e.d,o>i&&++r):i=null!=e.e?e.e+o:o),a=_t(n,r,i,u,o),t._a[ar]=a.year,t._dayOfYear=a.dayOfYear}function wt(t){if(t._f===e.ISO_8601)return void rt(t);t._a=[],l(t).empty=!0;var n,r,i,o,u,a=""+t._i,s=a.length,c=0;for(i=z(t._f,t._locale).match(Gn)||[],n=0;n0&&l(t).unusedInput.push(u),a=a.slice(a.indexOf(r)+r.length),c+=r.length),Bn[o]?(r?l(t).empty=!1:l(t).unusedTokens.push(o),V(o,r,t)):t._strict&&!r&&l(t).unusedTokens.push(o);l(t).charsLeftOver=s-c,a.length>0&&l(t).unusedInput.push(a),l(t).bigHour===!0&&t._a[lr]<=12&&t._a[lr]>0&&(l(t).bigHour=void 0),t._a[lr]=St(t._locale,t._a[lr],t._meridiem),bt(t),Q(t)}function St(t,e,n){var r;return null==n?e:null!=t.meridiemHour?t.meridiemHour(e,n):null!=t.isPM?(r=t.isPM(n),r&&12>e&&(e+=12),r||12!==e||(e=0),e):e}function Mt(t){var e,n,r,i,o;if(0===t._f.length)return l(t).invalidFormat=!0,void(t._d=new Date(NaN));for(i=0;io)&&(r=o,n=e));a(t,n||e)}function jt(t){if(!t._d){var e=I(t._i);t._a=[e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],bt(t)}}function Tt(t){var e=new h(Q(Et(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function Et(t){var e=t._i,n=t._f;return t._locale=t._locale||j(t._l),null===e||void 0===n&&""===e?d({nullInput:!0}):("string"==typeof e&&(t._i=e=t._locale.preparse(e)),v(e)?new h(Q(e)):(r(n)?Mt(t):n?wt(t):i(e)?t._d=e:It(t),t))}function It(t){var n=t._i;void 0===n?t._d=new Date:i(n)?t._d=new Date(+n):"string"==typeof n?it(t):r(n)?(t._a=o(n.slice(0),function(t){return parseInt(t,10)}),bt(t)):"object"==typeof n?jt(t):"number"==typeof n?t._d=new Date(n):e.createFromInputFallback(t)}function Pt(t,e,n,r,i){var o={};return"boolean"==typeof n&&(r=n,n=void 0),o._isAMomentObject=!0,o._useUTC=o._isUTC=i,o._l=n,o._i=t,o._f=e,o._strict=r,Tt(o)}function Dt(t,e,n,r){return Pt(t,e,n,r,!1)}function Ct(t,e){var n,i;if(1===e.length&&r(e[0])&&(e=e[0]),!e.length)return Dt();for(n=e[0],i=1;it&&(t=-t,n="-"),n+x(~~(t/60),2)+e+x(~~t%60,2)})}function Rt(t){var e=(t||"").match(nr)||[],n=e[e.length-1]||[],r=(n+"").match(jr)||["-",0,0],i=+(60*r[1])+y(r[2]);return"+"===r[0]?i:-i}function zt(t,n){var r,o;return n._isUTC?(r=n.clone(),o=(v(t)||i(t)?+t:+Dt(t))-+r,r._d.setTime(+r._d+o),e.updateOffset(r,!1),r):Dt(t).local()}function Ht(t){return 15*-Math.round(t._d.getTimezoneOffset()/15)}function Yt(t,n){var r,i=this._offset||0;return null!=t?("string"==typeof t&&(t=Rt(t)),Math.abs(t)<16&&(t=60*t),!this._isUTC&&n&&(r=Ht(this)),this._offset=t,this._isUTC=!0,null!=r&&this.add(r,"m"),i!==t&&(!n||this._changeInProgress?ne(this,Zt(t-i,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,e.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?i:Ht(this)}function Gt(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}function Ft(t){return this.utcOffset(0,t)}function Ut(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(Ht(this),"m")),this}function Bt(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Rt(this._i)),this}function Vt(t){return t=t?Dt(t).utcOffset():0,(this.utcOffset()-t)%60===0}function qt(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Wt(){if("undefined"!=typeof this._isDSTShifted)return this._isDSTShifted;var t={};if(p(t,this),t=Et(t),t._a){var e=t._isUTC?s(t._a):Dt(t._a);this._isDSTShifted=this.isValid()&&m(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Kt(){return!this._isUTC}function Jt(){return this._isUTC}function $t(){return this._isUTC&&0===this._offset}function Zt(t,e){var n,r,i,o=t,a=null;return Lt(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(a=Tr.exec(t))?(n="-"===a[1]?-1:1,o={y:0,d:y(a[cr])*n,h:y(a[lr])*n,m:y(a[fr])*n,s:y(a[dr])*n,ms:y(a[pr])*n}):(a=Er.exec(t))?(n="-"===a[1]?-1:1,o={y:Xt(a[2],n),M:Xt(a[3],n),d:Xt(a[4],n),h:Xt(a[5],n),m:Xt(a[6],n),s:Xt(a[7],n),w:Xt(a[8],n)}):null==o?o={}:"object"==typeof o&&("from"in o||"to"in o)&&(i=te(Dt(o.from),Dt(o.to)),o={},o.ms=i.milliseconds,o.M=i.months),r=new kt(o),Lt(t)&&u(t,"_locale")&&(r._locale=t._locale),r}function Xt(t,e){var n=t&&parseFloat(t.replace(",","."));return(isNaN(n)?0:n)*e}function Qt(t,e){var n={milliseconds:0,months:0};return n.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(n.months,"M").isAfter(e)&&--n.months,n.milliseconds=+e-+t.clone().add(n.months,"M"),n}function te(t,e){var n;return e=zt(e,t),t.isBefore(e)?n=Qt(t,e):(n=Qt(e,t),n.milliseconds=-n.milliseconds,n.months=-n.months),n}function ee(t,e){return function(n,r){var i,o;return null===r||isNaN(+r)||(nt(e,"moment()."+e+"(period, number) is deprecated. Please use moment()."+e+"(number, period)."),o=n,n=r,r=o),n="string"==typeof n?+n:n,i=Zt(n,r),ne(this,i,t),this}}function ne(t,n,r,i){var o=n._milliseconds,u=n._days,a=n._months;i=null==i?!0:i,o&&t._d.setTime(+t._d+o*r),u&&C(t,"Date",D(t,"Date")+u*r),a&&$(t,D(t,"Month")+a*r),i&&e.updateOffset(t,u||a)}function re(t,e){var n=t||Dt(),r=zt(n,this).startOf("day"),i=this.diff(r,"days",!0),o=-6>i?"sameElse":-1>i?"lastWeek":0>i?"lastDay":1>i?"sameDay":2>i?"nextDay":7>i?"nextWeek":"sameElse";return this.format(e&&e[o]||this.localeData().calendar(o,this,Dt(n)))}function ie(){return new h(this)}function oe(t,e){var n;return e=E("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=v(t)?t:Dt(t),+this>+t):(n=v(t)?+t:+Dt(t),n<+this.clone().startOf(e))}function ue(t,e){var n;return e=E("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=v(t)?t:Dt(t),+t>+this):(n=v(t)?+t:+Dt(t),+this.clone().endOf(e)e-o?(n=t.clone().add(i-1,"months"),r=(e-o)/(o-n)):(n=t.clone().add(i+1,"months"),r=(e-o)/(n-o)),-(i+r)}function fe(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function de(){var t=this.clone().utc();return 0e;e++)if(this._weekdaysParse[e]||(n=Dt([2e3,1]).day(e),r="^"+this.weekdays(n,"")+"|^"+this.weekdaysShort(n,"")+"|^"+this.weekdaysMin(n,""),this._weekdaysParse[e]=new RegExp(r.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e}function Fe(t){var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=Re(t,this.localeData()),this.add(t-e,"d")):e}function Ue(t){var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")}function Be(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)}function Ve(t,e){k(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function qe(t,e){return e._meridiemParse}function We(t){return"p"===(t+"").toLowerCase().charAt(0)}function Ke(t,e,n){return t>11?n?"pm":"PM":n?"am":"AM"}function Je(t,e){e[pr]=y(1e3*("0."+t))}function $e(){return this._isUTC?"UTC":""}function Ze(){return this._isUTC?"Coordinated Universal Time":""}function Xe(t){return Dt(1e3*t)}function Qe(){return Dt.apply(null,arguments).parseZone()}function tn(t,e,n){var r=this._calendar[t];return"function"==typeof r?r.call(e,n):r}function en(t){var e=this._longDateFormat[t],n=this._longDateFormat[t.toUpperCase()];return e||!n?e:(this._longDateFormat[t]=n.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])}function nn(){return this._invalidDate}function rn(t){return this._ordinal.replace("%d",t)}function on(t){return t}function un(t,e,n,r){var i=this._relativeTime[n];return"function"==typeof i?i(t,e,n,r):i.replace(/%d/i,t)}function an(t,e){var n=this._relativeTime[t>0?"future":"past"];return"function"==typeof n?n(e):n.replace(/%s/i,e)}function sn(t){var e,n;for(n in t)e=t[n],"function"==typeof e?this[n]=e:this["_"+n]=e;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function cn(t,e,n,r){var i=j(),o=s().set(r,e);return i[n](o,t)}function ln(t,e,n,r,i){if("number"==typeof t&&(e=t,t=void 0),t=t||"",null!=e)return cn(t,e,n,i);var o,u=[];for(o=0;r>o;o++)u[o]=cn(t,o,n,i);return u}function fn(t,e){return ln(t,e,"months",12,"month")}function dn(t,e){return ln(t,e,"monthsShort",12,"month")}function pn(t,e){return ln(t,e,"weekdays",7,"day")}function hn(t,e){return ln(t,e,"weekdaysShort",7,"day")}function vn(t,e){return ln(t,e,"weekdaysMin",7,"day")}function _n(){var t=this._data;return this._milliseconds=$r(this._milliseconds),this._days=$r(this._days),this._months=$r(this._months),t.milliseconds=$r(t.milliseconds),t.seconds=$r(t.seconds),t.minutes=$r(t.minutes),t.hours=$r(t.hours),t.months=$r(t.months),t.years=$r(t.years),this}function yn(t,e,n,r){var i=Zt(e,n);return t._milliseconds+=r*i._milliseconds,t._days+=r*i._days,t._months+=r*i._months,t._bubble()}function mn(t,e){return yn(this,t,e,1)}function gn(t,e){return yn(this,t,e,-1)}function bn(t){return 0>t?Math.floor(t):Math.ceil(t)}function On(){var t,e,n,r,i,o=this._milliseconds,u=this._days,a=this._months,s=this._data;return o>=0&&u>=0&&a>=0||0>=o&&0>=u&&0>=a||(o+=864e5*bn(Sn(a)+u),u=0,a=0),s.milliseconds=o%1e3,t=_(o/1e3),s.seconds=t%60,e=_(t/60),s.minutes=e%60,n=_(e/60),s.hours=n%24,u+=_(n/24),i=_(wn(u)),a+=i,u-=bn(Sn(i)),r=_(a/12),a%=12,s.days=u,s.months=a,s.years=r,this}function wn(t){return 4800*t/146097}function Sn(t){return 146097*t/4800}function Mn(t){var e,n,r=this._milliseconds;if(t=E(t),"month"===t||"year"===t)return e=this._days+r/864e5,n=this._months+wn(e),"month"===t?n:n/12;switch(e=this._days+Math.round(Sn(this._months)),t){case"week":return e/7+r/6048e5;case"day":return e+r/864e5;case"hour":return 24*e+r/36e5;case"minute":return 1440*e+r/6e4;case"second":return 86400*e+r/1e3;case"millisecond":return Math.floor(864e5*e)+r;default:throw new Error("Unknown unit "+t)}}function jn(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*y(this._months/12)}function Tn(t){return function(){return this.as(t)}}function En(t){return t=E(t),this[t+"s"]()}function In(t){return function(){return this._data[t]}}function Pn(){return _(this.days()/7)}function Dn(t,e,n,r,i){return i.relativeTime(e||1,!!n,t,r)}function Cn(t,e,n){var r=Zt(t).abs(),i=di(r.as("s")),o=di(r.as("m")),u=di(r.as("h")),a=di(r.as("d")),s=di(r.as("M")),c=di(r.as("y")),l=i0,l[4]=n,Dn.apply(null,l)}function An(t,e){return void 0===pi[t]?!1:void 0===e?pi[t]:(pi[t]=e,!0)}function xn(t){var e=this.localeData(),n=Cn(this,!t,e);return t&&(n=e.pastFuture(+this,n)),e.postformat(n)}function kn(){var t,e,n,r=hi(this._milliseconds)/1e3,i=hi(this._days),o=hi(this._months);t=_(r/60),e=_(t/60),r%=60,t%=60,n=_(o/12),o%=12;var u=n,a=o,s=i,c=e,l=t,f=r,d=this.asSeconds();return d?(0>d?"-":"")+"P"+(u?u+"Y":"")+(a?a+"M":"")+(s?s+"D":"")+(c||l||f?"T":"")+(c?c+"H":"")+(l?l+"M":"")+(f?f+"S":""):"P0D"}var Ln,Nn,Rn=e.momentProperties=[],zn=!1,Hn={},Yn={},Gn=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Fn=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Un={},Bn={},Vn=/\d/,qn=/\d\d/,Wn=/\d{3}/,Kn=/\d{4}/,Jn=/[+-]?\d{6}/,$n=/\d\d?/,Zn=/\d{1,3}/,Xn=/\d{1,4}/,Qn=/[+-]?\d{1,6}/,tr=/\d+/,er=/[+-]?\d+/,nr=/Z|[+-]\d\d:?\d\d/gi,rr=/[+-]?\d+(\.\d{1,3})?/,ir=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,or={},ur={},ar=0,sr=1,cr=2,lr=3,fr=4,dr=5,pr=6;k("M",["MM",2],"Mo",function(){return this.month()+1}),k("MMM",0,0,function(t){return this.localeData().monthsShort(this,t)}),k("MMMM",0,0,function(t){return this.localeData().months(this,t)}),T("month","M"),Y("M",$n),Y("MM",$n,qn),Y("MMM",ir),Y("MMMM",ir),U(["M","MM"],function(t,e){e[sr]=y(t)-1}),U(["MMM","MMMM"],function(t,e,n,r){var i=n._locale.monthsParse(t,r,n._strict);null!=i?e[sr]=i:l(n).invalidMonth=t});var hr="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),vr="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),_r={};e.suppressDeprecationWarnings=!1;var yr=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,mr=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],gr=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],br=/^\/?Date\((\-?\d+)/i;e.createFromInputFallback=et("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),k(0,["YY",2],0,function(){return this.year()%100}),k(0,["YYYY",4],0,"year"),k(0,["YYYYY",5],0,"year"),k(0,["YYYYYY",6,!0],0,"year"),T("year","y"),Y("Y",er),Y("YY",$n,qn),Y("YYYY",Xn,Kn),Y("YYYYY",Qn,Jn),Y("YYYYYY",Qn,Jn),U(["YYYYY","YYYYYY"],ar),U("YYYY",function(t,n){n[ar]=2===t.length?e.parseTwoDigitYear(t):y(t)}),U("YY",function(t,n){n[ar]=e.parseTwoDigitYear(t)}),e.parseTwoDigitYear=function(t){return y(t)+(y(t)>68?1900:2e3)};var Or=P("FullYear",!1);k("w",["ww",2],"wo","week"),k("W",["WW",2],"Wo","isoWeek"),T("week","w"),T("isoWeek","W"),Y("w",$n),Y("ww",$n,qn),Y("W",$n),Y("WW",$n,qn),B(["w","ww","W","WW"],function(t,e,n,r){e[r.substr(0,1)]=y(t)});var wr={dow:0,doy:6};k("DDD",["DDDD",3],"DDDo","dayOfYear"),T("dayOfYear","DDD"),Y("DDD",Zn),Y("DDDD",Wn),U(["DDD","DDDD"],function(t,e,n){n._dayOfYear=y(t)}),e.ISO_8601=function(){};var Sr=et("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var t=Dt.apply(null,arguments);return this>t?this:t}),Mr=et("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var t=Dt.apply(null,arguments);return t>this?this:t});Nt("Z",":"),Nt("ZZ",""),Y("Z",nr),Y("ZZ",nr),U(["Z","ZZ"],function(t,e,n){n._useUTC=!0,n._tzm=Rt(t)});var jr=/([\+\-]|\d\d)/gi;e.updateOffset=function(){};var Tr=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Er=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Zt.fn=kt.prototype;var Ir=ee(1,"add"),Pr=ee(-1,"subtract");e.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Dr=et("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return void 0===t?this.localeData():this.locale(t)});k(0,["gg",2],0,function(){return this.weekYear()%100}),k(0,["GG",2],0,function(){return this.isoWeekYear()%100}),De("gggg","weekYear"),De("ggggg","weekYear"),De("GGGG","isoWeekYear"),De("GGGGG","isoWeekYear"),T("weekYear","gg"),T("isoWeekYear","GG"),Y("G",er),Y("g",er),Y("GG",$n,qn),Y("gg",$n,qn),Y("GGGG",Xn,Kn),Y("gggg",Xn,Kn),Y("GGGGG",Qn,Jn),Y("ggggg",Qn,Jn),B(["gggg","ggggg","GGGG","GGGGG"],function(t,e,n,r){e[r.substr(0,2)]=y(t)}),B(["gg","GG"],function(t,n,r,i){n[i]=e.parseTwoDigitYear(t)}),k("Q",0,0,"quarter"),T("quarter","Q"),Y("Q",Vn),U("Q",function(t,e){e[sr]=3*(y(t)-1)}),k("D",["DD",2],"Do","date"),T("date","D"),Y("D",$n),Y("DD",$n,qn),Y("Do",function(t,e){return t?e._ordinalParse:e._ordinalParseLenient}),U(["D","DD"],cr),U("Do",function(t,e){e[cr]=y(t.match($n)[0],10)});var Cr=P("Date",!0);k("d",0,"do","day"),k("dd",0,0,function(t){return this.localeData().weekdaysMin(this,t)}),k("ddd",0,0,function(t){return this.localeData().weekdaysShort(this,t)}),k("dddd",0,0,function(t){return this.localeData().weekdays(this,t)}),k("e",0,0,"weekday"),k("E",0,0,"isoWeekday"),T("day","d"),T("weekday","e"),T("isoWeekday","E"),Y("d",$n),Y("e",$n),Y("E",$n),Y("dd",ir),Y("ddd",ir),Y("dddd",ir),B(["dd","ddd","dddd"],function(t,e,n){var r=n._locale.weekdaysParse(t);null!=r?e.d=r:l(n).invalidWeekday=t}),B(["d","e","E"],function(t,e,n,r){e[r]=y(t)});var Ar="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),xr="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),kr="Su_Mo_Tu_We_Th_Fr_Sa".split("_");k("H",["HH",2],0,"hour"),k("h",["hh",2],0,function(){return this.hours()%12||12}),Ve("a",!0),Ve("A",!1),T("hour","h"),Y("a",qe),Y("A",qe),Y("H",$n),Y("h",$n),Y("HH",$n,qn),Y("hh",$n,qn),U(["H","HH"],lr),U(["a","A"],function(t,e,n){n._isPm=n._locale.isPM(t),n._meridiem=t}),U(["h","hh"],function(t,e,n){e[lr]=y(t),l(n).bigHour=!0});var Lr=/[ap]\.?m?\.?/i,Nr=P("Hours",!0);k("m",["mm",2],0,"minute"),T("minute","m"),Y("m",$n),Y("mm",$n,qn),U(["m","mm"],fr);var Rr=P("Minutes",!1);k("s",["ss",2],0,"second"),T("second","s"),Y("s",$n),Y("ss",$n,qn),U(["s","ss"],dr);var zr=P("Seconds",!1);k("S",0,0,function(){return~~(this.millisecond()/100)}),k(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),k(0,["SSS",3],0,"millisecond"),k(0,["SSSS",4],0,function(){return 10*this.millisecond()}),k(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),k(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),k(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),k(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),k(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),T("millisecond","ms"),Y("S",Zn,Vn),Y("SS",Zn,qn),Y("SSS",Zn,Wn);var Hr;for(Hr="SSSS";Hr.length<=9;Hr+="S")Y(Hr,tr);for(Hr="S";Hr.length<=9;Hr+="S")U(Hr,Je);var Yr=P("Milliseconds",!1);k("z",0,0,"zoneAbbr"),k("zz",0,0,"zoneName");var Gr=h.prototype;Gr.add=Ir,Gr.calendar=re,Gr.clone=ie,Gr.diff=ce,Gr.endOf=Oe,Gr.format=pe,Gr.from=he,Gr.fromNow=ve,Gr.to=_e,Gr.toNow=ye,Gr.get=A,Gr.invalidAt=Pe,Gr.isAfter=oe,Gr.isBefore=ue,Gr.isBetween=ae,Gr.isSame=se,Gr.isValid=Ee,Gr.lang=Dr,Gr.locale=me,Gr.localeData=ge,Gr.max=Mr,Gr.min=Sr,Gr.parsingFlags=Ie,Gr.set=A,Gr.startOf=be,Gr.subtract=Pr,Gr.toArray=je,Gr.toObject=Te,Gr.toDate=Me,Gr.toISOString=de,Gr.toJSON=de,Gr.toString=fe,Gr.unix=Se,Gr.valueOf=we,Gr.year=Or,Gr.isLeapYear=ct,Gr.weekYear=Ae,Gr.isoWeekYear=xe,Gr.quarter=Gr.quarters=Ne,Gr.month=Z,Gr.daysInMonth=X,Gr.week=Gr.weeks=ht,Gr.isoWeek=Gr.isoWeeks=vt,Gr.weeksInYear=Le,Gr.isoWeeksInYear=ke,Gr.date=Cr,Gr.day=Gr.days=Fe,Gr.weekday=Ue,Gr.isoWeekday=Be,Gr.dayOfYear=yt,Gr.hour=Gr.hours=Nr,Gr.minute=Gr.minutes=Rr,Gr.second=Gr.seconds=zr,Gr.millisecond=Gr.milliseconds=Yr,Gr.utcOffset=Yt,Gr.utc=Ft,Gr.local=Ut,Gr.parseZone=Bt,Gr.hasAlignedHourOffset=Vt,Gr.isDST=qt,Gr.isDSTShifted=Wt,Gr.isLocal=Kt,Gr.isUtcOffset=Jt,Gr.isUtc=$t,Gr.isUTC=$t,Gr.zoneAbbr=$e,Gr.zoneName=Ze,Gr.dates=et("dates accessor is deprecated. Use date instead.",Cr),Gr.months=et("months accessor is deprecated. Use month instead",Z),Gr.years=et("years accessor is deprecated. Use year instead",Or),Gr.zone=et("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Gt);var Fr=Gr,Ur={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Br={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Vr="Invalid date",qr="%d",Wr=/\d{1,2}/,Kr={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Jr=g.prototype;Jr._calendar=Ur,Jr.calendar=tn,Jr._longDateFormat=Br,Jr.longDateFormat=en,Jr._invalidDate=Vr,Jr.invalidDate=nn,Jr._ordinal=qr,Jr.ordinal=rn,Jr._ordinalParse=Wr,Jr.preparse=on,Jr.postformat=on,Jr._relativeTime=Kr,Jr.relativeTime=un,Jr.pastFuture=an,Jr.set=sn,Jr.months=W,Jr._months=hr,Jr.monthsShort=K,Jr._monthsShort=vr,Jr.monthsParse=J,Jr.week=ft,Jr._week=wr,Jr.firstDayOfYear=pt,Jr.firstDayOfWeek=dt,Jr.weekdays=ze,Jr._weekdays=Ar,Jr.weekdaysMin=Ye,Jr._weekdaysMin=kr,Jr.weekdaysShort=He,Jr._weekdaysShort=xr,Jr.weekdaysParse=Ge,Jr.isPM=We,Jr._meridiemParse=Lr,Jr.meridiem=Ke,S("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,n=1===y(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+n}}),e.lang=et("moment.lang is deprecated. Use moment.locale instead.",S),e.langData=et("moment.langData is deprecated. Use moment.localeData instead.",j);var $r=Math.abs,Zr=Tn("ms"),Xr=Tn("s"),Qr=Tn("m"),ti=Tn("h"),ei=Tn("d"),ni=Tn("w"),ri=Tn("M"),ii=Tn("y"),oi=In("milliseconds"),ui=In("seconds"),ai=In("minutes"),si=In("hours"),ci=In("days"),li=In("months"),fi=In("years"),di=Math.round,pi={s:45,m:45,h:22,d:26,M:11},hi=Math.abs,vi=kt.prototype;vi.abs=_n,vi.add=mn,vi.subtract=gn,vi.as=Mn,vi.asMilliseconds=Zr,vi.asSeconds=Xr,vi.asMinutes=Qr,vi.asHours=ti,vi.asDays=ei,vi.asWeeks=ni,vi.asMonths=ri,vi.asYears=ii,vi.valueOf=jn,vi._bubble=On,vi.get=En,vi.milliseconds=oi,vi.seconds=ui,vi.minutes=ai,vi.hours=si,vi.days=ci,vi.weeks=Pn,vi.months=li,vi.years=fi,vi.humanize=xn,vi.toISOString=kn,vi.toString=kn,vi.toJSON=kn,vi.locale=me,vi.localeData=ge,vi.toIsoString=et("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",kn),vi.lang=Dr,k("X",0,0,"unix"),k("x",0,0,"valueOf"),Y("x",er),Y("X",rr),U("X",function(t,e,n){n._d=new Date(1e3*parseFloat(t,10))}),U("x",function(t,e,n){n._d=new Date(y(t))}),e.version="2.10.6",n(Dt),e.fn=Fr,e.min=At,e.max=xt,e.utc=s,e.unix=Xe,e.months=fn,e.isDate=i,e.locale=S,e.invalid=d,e.duration=Zt,e.isMoment=v,e.weekdays=pn,e.parseZone=Qe,e.localeData=j,e.isDuration=Lt,e.monthsShort=dn,e.weekdaysMin=vn,e.defineLocale=M,e.weekdaysShort=hn,e.normalizeUnits=E,e.relativeTimeThreshold=An;var _i=e;return _i})}).call(e,n(130)(t))},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);e["default"]=new u["default"]({is:"ha-entity-toggle",properties:{stateObj:{type:Object,observer:"stateObjChanged"},toggleChecked:{type:Boolean,value:!1}},ready:function(){this.forceStateChange()},toggleChanged:function(t){var e=t.target.checked;e&&"off"===this.stateObj.state?this.turn_on():e||"off"===this.stateObj.state||this.turn_off()},stateObjChanged:function(t){t&&this.updateToggle(t)},updateToggle:function(t){this.toggleChecked=t&&"off"!==t.state},forceStateChange:function(){this.updateToggle(this.stateObj)},turn_on:function(){var t=this;i.serviceActions.callTurnOn(this.stateObj.entityId).then(function(){return t.forceStateChange()})},turn_off:function(){var t=this;i.serviceActions.callTurnOff(this.stateObj.entityId).then(function(){return t.forceStateChange()})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"ha-card",properties:{title:{type:String},header:{type:String}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(56),o=r(i),u=n(2),a=n(1),s=r(a),c=6e4,l=u.util.parseDateTime;e["default"]=new s["default"]({is:"relative-ha-datetime",properties:{datetime:{type:String,observer:"datetimeChanged"},datetimeObj:{type:Object,observer:"datetimeObjChanged"},parsedDateTime:{type:Object},relativeTime:{type:String,value:"not set"}},created:function(){this.updateRelative=this.updateRelative.bind(this)},attached:function(){this._interval=setInterval(this.updateRelative,c)},detached:function(){clearInterval(this._interval)},datetimeChanged:function(t){this.parsedDateTime=t?l(t):null,this.updateRelative()},datetimeObjChanged:function(t){this.parsedDateTime=t,this.updateRelative()},updateRelative:function(){this.relativeTime=this.parsedDateTime?o["default"](this.parsedDateTime).fromNow():""}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(31),n(149),n(148),e["default"]=new o["default"]({is:"state-history-charts",properties:{stateHistory:{type:Object},isLoadingData:{type:Boolean,value:!1},apiLoaded:{type:Boolean,value:!1},isLoading:{type:Boolean,computed:"computeIsLoading(isLoadingData, apiLoaded)"},groupedStateHistory:{type:Object,computed:"computeGroupedStateHistory(isLoading, stateHistory)"},isSingleDevice:{type:Boolean,computed:"computeIsSingleDevice(stateHistory)"}},computeIsSingleDevice:function(t){return t&&1===t.size},computeGroupedStateHistory:function(t,e){if(t||!e)return{line:[],timeline:[]};var n={},r=[];e.forEach(function(t){if(t&&0!==t.size){var e=t.find(function(t){return"unit_of_measurement"in t.attributes}),i=e?e.attributes.unit_of_measurement:!1;i?i in n?n[i].push(t.toArray()):n[i]=[t.toArray()]:r.push(t.toArray())}}),r=r.length>0&&r;var i=Object.keys(n).map(function(t){return[t,n[t]]});return{line:i,timeline:r}},googleApiLoaded:function(){var t=this;google.load("visualization","1",{packages:["timeline","corechart"],callback:function(){return t.apiLoaded=!0}})},computeContentClasses:function(t){return t?"loading":""},computeIsLoading:function(t,e){return t||!e},computeIsEmpty:function(t){return t&&0===t.size},extractUnit:function(t){return t[0]},extractData:function(t){return t[1]}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(14),e["default"]=new o["default"]({is:"state-card-display",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e){"use strict";function n(t,e){switch(t){case"homeassistant":return"home";case"group":return"homeassistant-24:group";case"device_tracker":return"social:person";case"switch":return"image:flash-on";case"alarm_control_panel":return e&&"disarmed"===e?"icons:lock-open":"icons:lock";case"media_player":var n="hardware:cast";return e&&"off"!==e&&"idle"!==e&&(n+="-connected"),n;case"sun":return"image:wb-sunny";case"light":return"image:wb-incandescent";case"simple_alarm":return"social:notifications";case"notify":return"announcement";case"thermostat":return"homeassistant-100:thermostat";case"sensor":return"visibility";case"configurator":return"settings";case"conversation":return"av:hearing";case"script":return"description";case"scene":return"social:pages";case"updater":return"update_available"===e?"icons:cloud-download":"icons:cloud-done";default:return"bookmark"}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return u["default"](t).format("LT")}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(56),u=r(o);t.exports=e["default"]},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(2);e["default"]=function(t,e){r.authActions.validate(t,{rememberAuth:e,useStreaming:r.localStoragePreferences.useStreaming})},t.exports=e["default"]},function(t,e,n){"use strict";function r(t,e){var n=null==t?void 0:t[e];return i(n)?n:void 0}var i=n(187);t.exports=r},function(t,e){"use strict";function n(t){return!!t&&"object"==typeof t}t.exports=n},function(t,e,n){"use strict";function r(t){return i(t)&&a.call(t)==o}var i=n(68),o="[object Function]",u=Object.prototype,a=u.toString; +t.exports=r},function(t,e){"use strict";function n(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}t.exports=n},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(3),i=["isLoadingEntityHistory"];e.isLoadingEntityHistory=i;var o=["currentEntityHistoryDate"];e.currentDate=o;var u=["entityHistory"];e.entityHistoryMap=u;var a=[o,u,function(t,e){return e.get(t)||r.toImmutable({})}];e.entityHistoryForCurrentDate=a;var s=[o,u,function(t,e){return!!e.get(t)}];e.hasDataForCurrentDate=s;var c=["recentEntityHistory"];e.recentEntityHistoryMap=c;var l=["recentEntityHistory"];e.recentEntityHistoryUpdatedMap=l},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({currentEntityHistoryDate:a["default"],entityHistory:c["default"],isLoadingEntityHistory:f["default"],recentEntityHistory:p["default"],recentEntityHistoryUpdated:v["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(199),a=i(u),s=n(200),c=i(s),l=n(201),f=i(l),d=n(202),p=i(d),h=n(203),v=i(h),_=n(198),y=r(_),m=n(69),g=r(m),b=y;e.actions=b;var O=g;e.getters=O},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var o=function(){function t(t,e){for(var n=0;n6e4}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var u=n(225),a=n(245),s=i(a),c=n(247),l=i(c),f=n(249),d=i(f),p=n(22),h=r(p),v=n(37),_=r(v),y=n(10),m=r(y),g=n(70),b=r(g),O=n(38),w=r(O),S=n(210),M=r(S),j=n(73),T=r(j),E=n(76),I=r(E),P=n(40),D=r(P),C=n(19),A=r(C),x=n(41),k=r(x),L=n(43),N=r(L),R=n(242),z=r(R),H=n(11),Y=r(H),G=function F(){o(this,F);var t=s["default"]();Object.defineProperties(this,{demo:{value:!1,enumerable:!0},localStoragePreferences:{value:u.localStoragePreferences,enumerable:!0},reactor:{value:t,enumerable:!0},util:{value:d["default"],enumerable:!0},startLocalStoragePreferencesSync:{value:u.localStoragePreferences.startSync.bind(u.localStoragePreferences,t)},startUrlSync:{value:I.urlSync.startSync.bind(null,t)},stopUrlSync:{value:I.urlSync.stopSync.bind(null,t)}}),l["default"](this,t,{auth:h,config:_,entity:m,entityHistory:b,event:w,logbook:M,moreInfo:T,navigation:I,notification:D,service:A,stream:k,sync:N,voice:z,restApi:Y})};e["default"]=G,t.exports=e["default"]},function(t,e,n){"use strict";function r(t,e,n){var r=t?t.length:0;return n&&o(t,e,n)&&(e=!1),r?i(t,e):[]}var i=n(98),o=n(26);t.exports=r},function(t,e){"use strict";function n(t){var e=t?t.length:0;return e?t[e-1]:void 0}t.exports=n},function(t,e,n){"use strict";function r(t,e,n,r){var s=t?t.length:0;return s?(null!=e&&"boolean"!=typeof e&&(r=n,n=u(t,e,r)?void 0:e,e=!1),n=null==n?n:i(n,r,3),e?a(t,n):o(t,n)):[]}var i=n(24),o=n(110),u=n(26),a=n(124);t.exports=r},function(t,e,n){"use strict";function r(t,e,n){var r=a(t)?i:u;return e=o(e,n,3),r(t,e)}var i=n(93),o=n(24),u=n(48),a=n(9);t.exports=r},function(t,e,n){"use strict";function r(t,e){return i(t,o(e))}var i=n(89),o=n(55);t.exports=r},function(t,e,n){"use strict";function r(t,e,n){if(null==t)return[];n&&s(t,e,n)&&(e=void 0);var r=-1;e=i(e,n,3);var c=o(t,function(t,n,i){return{criteria:e(t,n,i),index:++r,value:t}});return u(c,a)}var i=n(24),o=n(48),u=n(108),a=n(114),s=n(26);t.exports=r},function(t,e,n){(function(e){"use strict";function r(t){var e=t?t.length:0;for(this.data={hash:a(null),set:new u};e--;)this.push(t[e])}var i=n(113),o=n(20),u=o(e,"Set"),a=o(Object,"create");r.prototype.push=i,t.exports=r}).call(e,function(){return this}())},function(t,e){"use strict";function n(t,e){for(var n=-1,r=t.length,i=Array(r);++ne&&!o||!i||n&&!u&&a||r&&a)return 1;if(e>t&&!n||!a||o&&!r&&i||u&&i)return-1}return 0}t.exports=n},function(t,e,n){"use strict";var r=n(100),i=n(115),o=i(r);t.exports=o},function(t,e,n){"use strict";function r(t,e,n,c){c||(c=[]);for(var l=-1,f=t.length;++le&&(e=-e>i?0:i+e),n=void 0===n||n>i?i:+n||0,0>n&&(n+=i),i=e>n?0:n-e>>>0,e>>>=0;for(var o=Array(i);++r=a,f=l?u():null,d=[];f?(r=o,c=!1):(l=!1,f=e?[]:d);t:for(;++nc))return!1;for(;++s0;++r1}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(58),e["default"]=new o["default"]({is:"ha-introduction-card",properties:{showInstallInstruction:{type:Boolean,value:!1},showHideInstruction:{type:Boolean,value:!0}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(63),a=r(u);e["default"]=new o["default"]({is:"display-time",properties:{dateObj:{type:Object}},computeTime:function(t){return t?a["default"](t):""}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"entity-list",behaviors:[s["default"]],properties:{entities:{type:Array,bindNuclear:[i.entityGetters.entityMap,function(t){return t.valueSeq().sortBy(function(t){return t.entityId}).toArray()}]}},entitySelected:function(t){t.preventDefault(),this.fire("entity-selected",{entityId:t.model.entity.entityId})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2);n(30),e["default"]=new o["default"]({is:"ha-entity-marker",properties:{entityId:{type:String,value:""},state:{type:Object,computed:"computeState(entityId)"},icon:{type:Object,computed:"computeIcon(state)"},image:{type:Object,computed:"computeImage(state)"},value:{type:String,computed:"computeValue(state)"}},listeners:{click:"badgeTap"},badgeTap:function(t){var e=this;t.stopPropagation(),this.entityId&&this.async(function(){return u.moreInfoActions.selectEntity(e.entityId)},1)},computeState:function(t){return t&&u.reactor.evaluate(u.entityGetters.byId(t))},computeIcon:function(t){return!t&&"home"},computeImage:function(t){return t&&t.attributes.entity_picture},computeValue:function(t){return t&&t.entityDisplay.split(" ").map(function(t){return t.substr(0,1)}).join("")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2),a=n(62),s=r(a),c=n(34),l=r(c);n(30),e["default"]=new o["default"]({is:"ha-state-label-badge",properties:{state:{type:Object,observer:"stateChanged"}},listeners:{click:"badgeTap"},badgeTap:function(t){var e=this;return t.stopPropagation(),l["default"](this.state.entityId)?void("scene"===this.state.domain?u.serviceActions.callTurnOn(this.state.entityId):"off"===this.state.state?u.serviceActions.callTurnOn(this.state.entityId):u.serviceActions.callTurnOff(this.state.entityId)):void this.async(function(){return u.moreInfoActions.selectEntity(e.state.entityId)},1)},computeClasses:function(t){switch(t.domain){case"scene":return"green";case"script":return"on"===t.state?"blue":"grey";default:return""}},computeGlow:function(t){switch(t.domain){case"scene":case"script":return"on"===t.state;default:return!1}},computeValue:function(t){switch(t.domain){case"device_tracker":case"sun":case"scene":case"script":case"alarm_control_panel":return void 0;case"sensor":return t.attributes.unit_of_measurement&&t.state;default:return t.state}},computeIcon:function(t){switch(t.domain){case"device_tracker":case"alarm_control_panel":case"scene":case"script":return s["default"](t.domain,t.state);case"sensor":return!t.attributes.unit_of_measurement&&s["default"](t.domain);case"sun":return"above_horizon"===t.state?"image:wb-sunny":"image:brightness-3";default:return void 0}},computeImage:function(t){return t.attributes.entity_picture},computeLabel:function(t){switch(t.domain){case"scene":case"script":return t.domain;case"sensor":return t.attributes.unit_of_measurement||t.state;case"device_tracker":return"not_home"===t.state?"Away":t.state;case"alarm_control_panel":return t.state;default:return t.attributes.unit_of_measurement}},computeDescription:function(t){return t.entityDisplay},stateChanged:function(){this.updateStyles()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(182),a=r(u);n(29),e["default"]=new o["default"]({is:"state-badge",properties:{stateObj:{type:Object,observer:"updateIconColor"}},updateIconColor:function(t){if("light"===t.domain&&"on"===t.state&&t.attributes.brightness&&t.attributes.xy_color){var e=a["default"](t.attributes.xy_color[0],t.attributes.xy_color[1],t.attributes.brightness);this.$.icon.style.color="rgb("+e.map(Math.floor).join(",")+")"}else this.$.icon.style.color=null}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"events-list",behaviors:[s["default"]],properties:{events:{type:Array,bindNuclear:[i.eventGetters.entityMap,function(t){return t.valueSeq().sortBy(function(t){return t.event}).toArray()}]}},eventSelected:function(t){t.preventDefault(),this.fire("event-selected",{eventType:t.model.event.event})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function o(t){return"#"+i(t.r)+i(t.g)+i(t.b)}Object.defineProperty(e,"__esModule",{value:!0});var u=n(1),a=r(u);e["default"]=new a["default"]({is:"ha-color-picker",properties:{width:{type:Number,value:300},height:{type:Number,value:300},color:{type:Object}},listeners:{mousedown:"onMouseDown",mouseup:"onMouseUp",touchstart:"onTouchStart",touchend:"onTouchEnd",tap:"onTap"},onMouseDown:function(t){this.onMouseMove(t),this.addEventListener("mousemove",this.onMouseMove)},onMouseUp:function(){this.removeEventListener("mousemove",this.onMouseMove)},onTouchStart:function(t){this.onTouchMove(t),this.addEventListener("touchmove",this.onTouchMove)},onTouchEnd:function(){this.removeEventListener("touchmove",this.onTouchMove)},onTap:function(t){t.stopPropagation()},onTouchMove:function(t){var e=t.touches[0];this.onColorSelect(t,{x:e.clientX,y:e.clientY})},onMouseMove:function(t){var e=this;t.preventDefault(),this.mouseMoveIsThrottled&&(this.mouseMoveIsThrottled=!1,this.onColorSelect(t),this.async(function(){return e.mouseMoveIsThrottled=!0},100))},onColorSelect:function(t,e){if(this.context){var n=e||this.relativeMouseCoordinates(t),r=this.context.getImageData(n.x,n.y,1,1).data;this.setColor({r:r[0],g:r[1],b:r[2]})}},setColor:function(t){this.color={hex:o(t),rgb:t},this.fire("colorselected",{rgb:this.color.rgb,hex:this.color.hex})},relativeMouseCoordinates:function(t){var e=0,n=0;if(this.canvas){var r=this.canvas.getBoundingClientRect();e=t.clientX-r.left,n=t.clientY-r.top}return{x:e,y:n}},ready:function(){this.setColor=this.setColor.bind(this),this.mouseMoveIsThrottled=!0,this.canvas=this.children[0],this.context=this.canvas.getContext("2d");var t=this.context.createLinearGradient(0,0,this.width,0);t.addColorStop(0,"rgb(255,0,0)"),t.addColorStop(.16,"rgb(255,0,255)"),t.addColorStop(.32,"rgb(0,0,255)"),t.addColorStop(.48,"rgb(0,255,255)"),t.addColorStop(.64,"rgb(0,255,0)"),t.addColorStop(.8,"rgb(255,255,0)"),t.addColorStop(1,"rgb(255,0,0)"),this.context.fillStyle=t,this.context.fillRect(0,0,this.width,this.height);var e=this.context.createLinearGradient(0,0,0,this.height);e.addColorStop(0,"rgba(255,255,255,1)"),e.addColorStop(.5,"rgba(255,255,255,0)"),e.addColorStop(.5,"rgba(0,0,0,0)"),e.addColorStop(1,"rgba(0,0,0,1)"),this.context.fillStyle=e,this.context.fillRect(0,0,this.width,this.height)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(30),e["default"]=new o["default"]({is:"ha-demo-badge"}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(146),e["default"]=new o["default"]({is:"ha-logbook",properties:{entries:{type:Object,value:[]}},noEntries:function(t){return!t.length}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(150),e["default"]=new u["default"]({is:"ha-sidebar",behaviors:[s["default"]],properties:{menuShown:{type:Boolean},menuSelected:{type:String},selected:{type:String,bindNuclear:i.navigationGetters.activePane,observer:"selectedChanged"},hasHistoryComponent:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("history")},hasLogbookComponent:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("logbook")}},selectedChanged:function(t){for(var e=this.querySelectorAll(".menu [data-panel]"),n=0;nd;d++)f._columns[d]=[];var p=0;return n&&u(),c.keySeq().sortBy(function(t){return i(t)}).forEach(function(t){if("a"===t)return void(f._demo=!0);var n=i(t);n>=0&&10>n?f._badges.push.apply(f._badges,r(c.get(t)).sortBy(o).toArray()):"group"===t?c.get(t).filter(function(t){return!t.attributes.auto}).sortBy(o).forEach(function(t){var n=s.util.expandGroup(t,e);n.forEach(function(t){return l[t.entityId]=!0}),a(t.entityDisplay,n.toArray(),t)}):a(t,r(c.get(t)).sortBy(o).toArray())}),f},computeShouldRenderColumn:function(t,e){return 0===t||e.length},computeShowIntroduction:function(t,e,n){return 0===t&&(e||n._demo)},computeShowHideInstruction:function(t,e){return t.size>0&&!0&&!e._demo},computeGroupEntityOfCard:function(t,e){return t[e].groupEntity},computeStatesOfCard:function(t,e){return t[e].entities}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(29),n(134),n(59),e["default"]=new u["default"]({is:"logbook-entry",entityClicked:function(t){t.preventDefault(),i.moreInfoActions.selectEntity(this.entryObj.entityId)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(29),e["default"]=new u["default"]({is:"services-list",behaviors:[s["default"]],properties:{serviceDomains:{type:Array,bindNuclear:i.serviceGetters.entityMap}},computeDomains:function(t){return t.valueSeq().map(function(t){return t.domain}).sort().toJS()},computeServices:function(t,e){return t.get(e).get("services").keySeq().toArray()},serviceClicked:function(t){t.preventDefault(),this.fire("service-selected",{domain:t.model.domain,service:t.model.service})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(90),o=r(i),u=n(86),a=r(u),s=n(88),c=r(s),l=n(91),f=r(l),d=n(1),p=r(d);e["default"]=new p["default"]({is:"state-history-chart-line",properties:{data:{type:Object,observer:"dataChanged"},unit:{type:String},isSingleDevice:{type:Boolean,value:!1},isAttached:{type:Boolean,value:!1,observer:"dataChanged"}},created:function(){this.style.display="block"},attached:function(){this.isAttached=!0},dataChanged:function(){this.drawChart()},drawChart:function(){if(this.isAttached){for(var t=p["default"].dom(this),e=this.unit,n=this.data;t.lastChild;)t.removeChild(t.lastChild);if(0!==n.length){var r=new google.visualization.LineChart(this),i=new google.visualization.DataTable;i.addColumn({type:"datetime",id:"Time"});var u={legend:{position:"top"},titlePosition:"none",vAxes:{0:{title:e}},hAxis:{format:"H:mm"},lineWidth:1,chartArea:{left:"60",width:"95%"},explorer:{actions:["dragToZoom","rightClickToReset","dragToPan"],keepInBounds:!0,axis:"horizontal",maxZoomIn:.1}};this.isSingleDevice&&(u.legend.position="none",u.vAxes[0].title=null,u.chartArea.left=40,u.chartArea.height="80%",u.chartArea.top=5,u.enableInteractivity=!1);var s=o["default"](a["default"](n),"lastChangedAsDate");s=f["default"](c["default"](s,function(t){return t.getTime()}));for(var l=[],d=new Array(n.length),h=0;hnew Date&&(a=new Date);var s=0;n.forEach(function(e){if(0!==e.length){var n=e[0].entityDisplay,r=void 0,i=null,o=null;e.forEach(function(e){null!==i&&e.state!==i?(r=e.lastChangedAsDate,t(n,i,o,r),i=e.state,o=r):null===i&&(i=e.state,o=e.lastChangedAsDate)}),t(n,i,o,a),s++}}),r.draw(i,{height:55+42*s,timeline:{showRowLabels:n.length>1},hAxis:{format:"H:mm"}})}}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"stream-status",behaviors:[s["default"]],properties:{isStreaming:{type:Boolean,bindNuclear:i.streamGetters.isStreamingEvents},hasError:{type:Boolean,bindNuclear:i.streamGetters.hasStreamingEventsError}},toggleChanged:function(){this.isStreaming?i.streamActions.stop():i.streamActions.start()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(32),n(60),n(165);var c=["camera","configurator","scene"];e["default"]=new u["default"]({is:"more-info-dialog",behaviors:[s["default"]],properties:{stateObj:{type:Object,bindNuclear:i.moreInfoGetters.currentEntity,observer:"stateObjChanged"},stateHistory:{type:Object,bindNuclear:[i.moreInfoGetters.currentEntityHistory,function(t){return t?[t]:!1}]},isLoadingHistoryData:{type:Boolean,computed:"computeIsLoadingHistoryData(_delayedDialogOpen, _isLoadingHistoryData)"},_isLoadingHistoryData:{type:Boolean,bindNuclear:i.entityHistoryGetters.isLoadingEntityHistory},hasHistoryComponent:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("history"),observer:"fetchHistoryData"},shouldFetchHistory:{type:Boolean,bindNuclear:i.moreInfoGetters.isCurrentEntityHistoryStale,observer:"fetchHistoryData"},showHistoryComponent:{type:Boolean,value:!1},dialogOpen:{type:Boolean,value:!1,observer:"dialogOpenChanged"},_delayedDialogOpen:{type:Boolean,value:!1},_boundOnBackdropTap:{type:Function,value:function(){return this._onBackdropTap.bind(this)}}},computeIsLoadingHistoryData:function(t,e){return!t||e},fetchHistoryData:function(){this.stateObj&&this.hasHistoryComponent&&this.shouldFetchHistory&&i.entityHistoryActions.fetchRecent(this.stateObj.entityId)},stateObjChanged:function(t){var e=this;return t?(this.showHistoryComponent=this.hasHistoryComponent&&-1===c.indexOf(this.stateObj.domain),void this.async(function(){e.fetchHistoryData(),e.dialogOpen=!0},10)):void(this.dialogOpen=!1)},dialogOpenChanged:function(t){var e=this;t?(this.$.dialog.backdropElement.addEventListener("click",this._boundOnBackdropTap),this.async(function(){return e._delayedDialogOpen=!0},10)):!t&&this.stateObj&&(i.moreInfoActions.deselectEntity(),this._delayedDialogOpen=!1)},_onBackdropTap:function(){this.$.dialog.backdropElement.removeEventListener("click",this._boundOnBackdropTap),this.dialogOpen=!1}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(4),u=r(o);n(143),n(160),n(158),n(157),n(159),n(154),n(155),n(156),n(161),n(151),e["default"]=new Polymer({is:"home-assistant-main",behaviors:[u["default"]],properties:{narrow:{type:Boolean,value:!1},activePane:{type:String,bindNuclear:i.navigationGetters.activePane,observer:"activePaneChanged"},isSelectedStates:{type:Boolean,bindNuclear:i.navigationGetters.isActivePane("states")},isSelectedHistory:{type:Boolean,bindNuclear:i.navigationGetters.isActivePane("history")},isSelectedMap:{type:Boolean,bindNuclear:i.navigationGetters.isActivePane("map")},isSelectedLogbook:{type:Boolean,bindNuclear:i.navigationGetters.isActivePane("logbook")},isSelectedDevEvent:{type:Boolean,bindNuclear:i.navigationGetters.isActivePane("devEvent")},isSelectedDevState:{type:Boolean,bindNuclear:i.navigationGetters.isActivePane("devState")},isSelectedDevService:{type:Boolean,bindNuclear:i.navigationGetters.isActivePane("devService")},showSidebar:{type:Boolean,bindNuclear:i.navigationGetters.showSidebar}},listeners:{"open-menu":"openMenu","close-menu":"closeMenu"},openMenu:function(){this.narrow?this.$.drawer.openDrawer():i.navigationActions.showSidebar(!0)},closeMenu:function(){this.$.drawer.closeDrawer(),this.showSidebar&&i.navigationActions.showSidebar(!1)},activePaneChanged:function(){this.narrow&&this.$.drawer.closeDrawer()},attached:function(){i.startUrlSync()},computeForceNarrow:function(t,e){return t||!e},detached:function(){i.stopUrlSync()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2),a=n(4),s=r(a),c=n(64),l=r(c);e["default"]=new o["default"]({is:"login-form",behaviors:[s["default"]],properties:{isValidating:{type:Boolean,observer:"isValidatingChanged",bindNuclear:u.authGetters.isValidating},isInvalid:{type:Boolean,bindNuclear:u.authGetters.isInvalidAttempt},errorMessage:{type:String,bindNuclear:u.authGetters.attemptErrorMessage}},listeners:{keydown:"passwordKeyDown","loginButton.click":"validatePassword"},observers:["validatingChanged(isValidating, isInvalid)"],validatingChanged:function(t,e){t||e||(this.$.passwordInput.value="")},isValidatingChanged:function(t){var e=this;t||this.async(function(){return e.$.passwordInput.focus()},10)},passwordKeyDown:function(t){13===t.keyCode?(this.validatePassword(),t.preventDefault()):this.isInvalid&&(this.isInvalid=!1)},validatePassword:function(){this.$.hideKeyboardOnFocus.focus(),l["default"](this.$.passwordInput.value,this.$.rememberLogin.checked)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(15),n(147),e["default"]=new u["default"]({is:"partial-dev-call-service",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},domain:{type:String,value:""},service:{type:String,value:""},serviceData:{type:String,value:""},description:{type:String,computed:"computeDescription(domain, service)"}},computeDescription:function(t,e){return i.reactor.evaluate([i.serviceGetters.entityMap,function(n){return n.has(t)&&n.get(t).get("services").has(e)?JSON.stringify(n.get(t).get("services").get(e).toJS(),null,2):"No description available"}])},serviceSelected:function(t){this.domain=t.detail.domain,this.service=t.detail.service},callService:function(){var t=void 0;try{t=this.serviceData?JSON.parse(this.serviceData):{}}catch(e){return void alert("Error parsing JSON: "+e)}i.serviceActions.callService(this.domain,this.service,t)},computeFormClasses:function(t){return"layout "+(t?"vertical":"horizontal")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(15),n(139),e["default"]=new u["default"]({is:"partial-dev-fire-event",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},eventType:{type:String,value:""},eventData:{type:String,value:""}},eventSelected:function(t){this.eventType=t.detail.eventType},fireEvent:function(){var t=void 0;try{t=this.eventData?JSON.parse(this.eventData):{}}catch(e){return void alert("Error parsing JSON: "+e)}i.eventActions.fireEvent(this.eventType,t)},computeFormClasses:function(t){return"layout "+(t?"vertical":"horizontal")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(15),n(135),e["default"]=new u["default"]({is:"partial-dev-set-state",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},entityId:{type:String,value:""},state:{type:String,value:""},stateAttributes:{type:String,value:""}},setStateData:function(t){var e=t?JSON.stringify(t,null," "):"";this.$.inputData.value=e,this.$.inputDataWrapper.update(this.$.inputData)},entitySelected:function(t){var e=i.reactor.evaluate(i.entityGetters.byId(t.detail.entityId));this.entityId=e.entityId,this.state=e.state,this.stateAttributes=JSON.stringify(e.attributes,null," ")},handleSetState:function(){var t=void 0;try{t=this.stateAttributes?JSON.parse(this.stateAttributes):{}}catch(e){return void alert("Error parsing JSON: "+e)}i.entityActions.save({entityId:this.entityId,state:this.state,attributes:t})},computeFormClasses:function(t){return"layout "+(t?"vertical":"horizontal")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(15),n(60),e["default"]=new u["default"]({is:"partial-history",behaviors:[s["default"]],properties:{narrow:{type:Boolean},showMenu:{type:Boolean,value:!1},isDataLoaded:{type:Boolean,bindNuclear:i.entityHistoryGetters.hasDataForCurrentDate,observer:"isDataLoadedChanged"},stateHistory:{type:Object,bindNuclear:i.entityHistoryGetters.entityHistoryForCurrentDate},isLoadingData:{type:Boolean,bindNuclear:i.entityHistoryGetters.isLoadingEntityHistory},selectedDate:{type:String,value:null,bindNuclear:i.entityHistoryGetters.currentDate}},isDataLoadedChanged:function(t){t||this.async(function(){return i.entityHistoryActions.fetchSelectedDate()},1)},handleRefreshClick:function(){i.entityHistoryActions.fetchSelectedDate()},datepickerFocus:function(){this.datePicker.adjustPosition()},attached:function(){this.datePicker=new Pikaday({field:this.$.datePicker.inputElement,onSelect:i.entityHistoryActions.changeCurrentDate})},detached:function(){this.datePicker.destroy()},computeContentClasses:function(t){return"flex content "+(t?"narrow":"wide")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(15),n(142),n(31),e["default"]=new u["default"]({is:"partial-logbook",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},selectedDate:{type:String,bindNuclear:i.logbookGetters.currentDate},isLoading:{type:Boolean,bindNuclear:i.logbookGetters.isLoadingEntries},isStale:{type:Boolean,bindNuclear:i.logbookGetters.isCurrentStale,observer:"isStaleChanged"},entries:{type:Array,bindNuclear:[i.logbookGetters.currentEntries,function(t){return t.reverse().toArray()}]},datePicker:{type:Object}},isStaleChanged:function(t){var e=this;t&&this.async(function(){return i.logbookActions.fetchDate(e.selectedDate)},1)},handleRefresh:function(){i.logbookActions.fetchDate(this.selectedDate)},datepickerFocus:function(){this.datePicker.adjustPosition()},attached:function(){this.datePicker=new Pikaday({field:this.$.datePicker.inputElement,onSelect:i.logbookActions.changeCurrentDate})},detached:function(){this.datePicker.destroy()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(136),L.Icon.Default.imagePath="/static/images/leaflet",e["default"]=new u["default"]({is:"partial-map",behaviors:[s["default"]],properties:{locationGPS:{type:Number,bindNuclear:i.configGetters.locationGPS},locationName:{type:String,bindNuclear:i.configGetters.locationName},locationEntities:{type:Array,bindNuclear:[i.entityGetters.visibleEntityMap,function(t){return t.valueSeq().filter(function(t){return t.attributes.latitude&&"home"!==t.state}).toArray()}]},zoneEntities:{type:Array,bindNuclear:[i.entityGetters.entityMap,function(t){return t.valueSeq().filter(function(t){return"zone"===t.domain}).toArray()}]},narrow:{type:Boolean},showMenu:{type:Boolean,value:!1}},attached:function(){var t=this;L.Browser.mobileWebkit&&this.async(function(){var e=t.$.map,n=e.style.display;e.style.display="none",t.async(function(){e.style.display=n},1)},1)},computeMenuButtonClass:function(t,e){return!t&&e?"invisible":""},toggleMenu:function(){this.fire("open-menu")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(15),n(144),n(145),e["default"]=new u["default"]({is:"partial-zone",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},isFetching:{type:Boolean,bindNuclear:i.syncGetters.isFetching},isStreaming:{type:Boolean,bindNuclear:i.streamGetters.isStreamingEvents},canListen:{type:Boolean,bindNuclear:[i.voiceGetters.isVoiceSupported,i.configGetters.isComponentLoaded("conversation"),function(t,e){return t&&e}]},isListening:{type:Boolean,bindNuclear:i.voiceGetters.isListening},showListenInterface:{type:Boolean,bindNuclear:[i.voiceGetters.isListening,i.voiceGetters.isTransmitting,function(t,e){return t||e}]},introductionLoaded:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("introduction")},locationName:{type:String,bindNuclear:i.configGetters.locationName},showMenu:{type:Boolean,value:!1,observer:"windowChange"},states:{type:Object,bindNuclear:i.entityGetters.visibleEntityMap},columns:{type:Number}},created:function(){var t=this;this.windowChange=this.windowChange.bind(this);for(var e=[],n=0;5>n;n++)e.push(278+278*n);this.mqls=e.map(function(e){var n=window.matchMedia("(min-width: "+e+"px)");return n.addListener(t.windowChange),n})},detached:function(){var t=this;this.mqls.forEach(function(e){return e.removeListener(t.windowChange)})},windowChange:function(){var t=this.mqls.reduce(function(t,e){return t+e.matches},0);this.columns=Math.max(1,t-this.showMenu)},handleRefresh:function(){i.syncActions.fetchAll()},handleListenClick:function(){this.isListening?i.voiceActions.stop():i.voiceActions.listen()},computeDomains:function(t){return t.keySeq().toArray()},computeMenuButtonClass:function(t,e){return!t&&e?"invisible":""},computeStatesOfDomain:function(t,e){return t.get(e).toArray()},computeListenButtonIcon:function(t){return t?"av:mic-off":"av:mic"},computeRefreshButtonClass:function(t){return t?"ha-spin":void 0},computeShowIntroduction:function(t,e){return t||0===e.size},toggleMenu:function(){this.fire("open-menu")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"notification-manager",behaviors:[s["default"]],properties:{text:{type:String,bindNuclear:i.notificationGetters.lastNotificationMessage,observer:"showNotification"}},showNotification:function(t){t&&this.$.toast.show()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);e["default"]=new u["default"]({is:"more-info-alarm_control_panel",handleDisarmTap:function(){this.callService("alarm_disarm",{code:this.enteredCode})},handleHomeTap:function(){this.callService("alarm_arm_home",{code:this.enteredCode})},handleAwayTap:function(){this.callService("alarm_arm_away",{code:this.enteredCode})},properties:{stateObj:{type:Object,observer:"stateObjChanged"},enteredCode:{type:String,value:""},disarmButtonVisible:{type:Boolean,value:!1},armHomeButtonVisible:{type:Boolean,value:!1},armAwayButtonVisible:{type:Boolean,value:!1},codeInputVisible:{type:Boolean,value:!1},codeInputEnabled:{type:Boolean,value:!1},codeFormat:{type:String,value:""},codeValid:{type:Boolean,computed:"validateCode(enteredCode, codeFormat)"}},validateCode:function(t,e){var n=new RegExp(e);return null===e?!0:n.test(t)},stateObjChanged:function(t){var e=this;t&&(this.codeFormat=t.attributes.code_format,this.codeInputVisible=null!==this.codeFormat,this.codeInputEnabled="armed_home"===t.state||"armed_away"===t.state||"disarmed"===t.state||"pending"===t.state||"triggered"===t.state,this.disarmButtonVisible="armed_home"===t.state||"armed_away"===t.state||"pending"===t.state||"triggered"===t.state,this.armHomeButtonVisible="disarmed"===t.state,this.armAwayButtonVisible="disarmed"===t.state),this.async(function(){return e.fire("iron-resize")},500)},callService:function(t,e){var n=e||{};n.entity_id=this.stateObj.entityId,i.serviceActions.callService("alarm_control_panel",t,n)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"more-info-camera",properties:{stateObj:{type:Object},dialogOpen:{type:Boolean}},imageLoaded:function(){this.fire("iron-resize")},computeCameraImageUrl:function(t){return t?"/api/camera_proxy_stream/"+this.stateObj.entityId:"data:image/gif;base64,R0lGODlhAQABAAAAACw="}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(31),e["default"]=new u["default"]({is:"more-info-configurator",behaviors:[s["default"]],properties:{stateObj:{type:Object},action:{type:String,value:"display"},isStreaming:{type:Boolean,bindNuclear:i.streamGetters.isStreamingEvents},isConfigurable:{type:Boolean,computed:"computeIsConfigurable(stateObj)"},isConfiguring:{type:Boolean,value:!1},submitCaption:{type:String,computed:"computeSubmitCaption(stateObj)"}},computeIsConfigurable:function(t){return"configure"===t.state},computeSubmitCaption:function(t){return t.attributes.submit_caption||"Set configuration"},submitClicked:function(){var t=this;this.isConfiguring=!0;var e={configure_id:this.stateObj.attributes.configure_id};i.serviceActions.callService("configurator","configure",e).then(function(){t.isConfiguring=!1,t.isStreaming||i.syncActions.fetchAll()},function(){t.isConfiguring=!1})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(181),a=r(u);n(166),n(167),n(171),n(164),n(172),n(170),n(168),n(169),n(163),n(173),n(162),e["default"]=new o["default"]({is:"more-info-content",properties:{stateObj:{type:Object,observer:"stateObjChanged"},dialogOpen:{type:Boolean,value:!1,observer:"dialogOpenChanged"}},dialogOpenChanged:function(t){var e=o["default"].dom(this);e.lastChild&&(e.lastChild.dialogOpen=t)},stateObjChanged:function(t,e){var n=o["default"].dom(this);if(!t)return void(n.lastChild&&n.removeChild(n.lastChild));var r=a["default"](t);if(e&&a["default"](e)===r)n.lastChild.dialogOpen=this.dialogOpen,n.lastChild.stateObj=t;else{n.lastChild&&n.removeChild(n.lastChild);var i=document.createElement("more-info-"+r);i.stateObj=t,i.dialogOpen=this.dialogOpen,n.appendChild(i)}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=["entity_picture","friendly_name","unit_of_measurement"];e["default"]=new o["default"]({is:"more-info-default",properties:{stateObj:{type:Object}},computeDisplayAttributes:function(t){return t?Object.keys(t.attributes).filter(function(t){return-1===u.indexOf(t)}):[]},getAttributeValue:function(t,e){return t.attributes[e]}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(32),e["default"]=new u["default"]({is:"more-info-group",behaviors:[s["default"]],properties:{stateObj:{type:Object},states:{type:Array,bindNuclear:[i.moreInfoGetters.currentEntity,i.entityGetters.entityMap,function(t,e){return t?t.attributes.entity_id.map(e.get.bind(e)):[]}]}},updateStates:function(){this.states=this.stateObj&&this.stateObj.attributes.entity_id?stateStore.gets(this.stateObj.attributes.entity_id).toArray():[]}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(33),s=r(a);n(140);var c=["brightness","xy_color"];e["default"]=new u["default"]({is:"more-info-light",properties:{stateObj:{type:Object,observer:"stateObjChanged"},brightnessSliderValue:{type:Number,value:0}},stateObjChanged:function(t){var e=this;t&&"on"===t.state&&(this.brightnessSliderValue=t.attributes.brightness),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return s["default"](t,c)},brightnessSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||(0===e?i.serviceActions.callTurnOff(this.stateObj.entityId):i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,brightness:e}))},colorPicked:function(t){var e=t.detail.rgb;i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,rgb_color:[e.r,e.g,e.b]})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(33),s=r(a),c=["volume_level"];e["default"]=new u["default"]({is:"more-info-media_player",properties:{stateObj:{type:Object,observer:"stateObjChanged"},isOff:{type:Boolean,value:!1},isPlaying:{type:Boolean,value:!1},isMuted:{type:Boolean,value:!1},volumeSliderValue:{type:Number,value:0},supportsPause:{type:Boolean,value:!1},supportsVolumeSet:{type:Boolean,value:!1},supportsVolumeMute:{type:Boolean,value:!1},supportsPreviousTrack:{type:Boolean,value:!1},supportsNextTrack:{type:Boolean,value:!1},supportsTurnOn:{type:Boolean,value:!1},supportsTurnOff:{type:Boolean,value:!1}},stateObjChanged:function(t){var e=this;t&&(this.isOff="off"===t.state,this.isPlaying="playing"===t.state,this.volumeSliderValue=100*t.attributes.volume_level,this.isMuted=t.attributes.is_volume_muted,this.supportsPause=0!==(1&t.attributes.supported_media_commands),this.supportsVolumeSet=0!==(4&t.attributes.supported_media_commands),this.supportsVolumeMute=0!==(8&t.attributes.supported_media_commands),this.supportsPreviousTrack=0!==(16&t.attributes.supported_media_commands),this.supportsNextTrack=0!==(32&t.attributes.supported_media_commands),this.supportsTurnOn=0!==(128&t.attributes.supported_media_commands),this.supportsTurnOff=0!==(256&t.attributes.supported_media_commands)),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return s["default"](t,c)},computeIsOff:function(t){return"off"===t.state},computeMuteVolumeIcon:function(t){return t?"av:volume-off":"av:volume-up"},computePlaybackControlIcon:function(){return this.isPlaying?this.supportsPause?"av:pause":"av:stop":"av:play-arrow"},computeHidePowerButton:function(t,e,n){return t?!e:!n},handleTogglePower:function(){this.callService(this.isOff?"turn_on":"turn_off")},handlePrevious:function(){this.callService("media_previous_track")},handlePlaybackControl:function(){this.callService("media_play_pause")},handleNext:function(){this.callService("media_next_track")},handleVolumeTap:function(){this.supportsVolumeMute&&this.callService("volume_mute",{is_volume_muted:!this.isMuted})},volumeSliderChanged:function(t){var e=parseFloat(t.target.value),n=e>0?e/100:0;this.callService("volume_set",{volume_level:n})},callService:function(t,e){var n=e||{};n.entity_id=this.stateObj.entityId,i.serviceActions.callService("media_player",t,n)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"more-info-script",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(63),u=r(o),a=i.util.parseDateTime;e["default"]=new Polymer({is:"more-info-sun",properties:{stateObj:{type:Object},risingDate:{type:Object,computed:"computeRising(stateObj)"},settingDate:{type:Object,computed:"computeSetting(stateObj)"}},computeRising:function(t){return a(t.attributes.next_rising)},computeSetting:function(t){return a(t.attributes.next_setting)},computeOrder:function(t,e){return t>e?["set","ris"]:["ris","set"]},itemCaption:function(t){return"ris"===t?"Rising ":"Setting "},itemDate:function(t){return"ris"===t?this.risingDate:this.settingDate},itemValue:function(t){return u["default"](this.itemDate(t))}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(33),s=r(a),c=["away_mode"];e["default"]=new u["default"]({is:"more-info-thermostat",properties:{stateObj:{type:Object,observer:"stateObjChanged"},tempMin:{type:Number},tempMax:{type:Number},targetTemperatureSliderValue:{type:Number},awayToggleChecked:{type:Boolean}},stateObjChanged:function(t){this.targetTemperatureSliderValue=t.state,this.awayToggleChecked="on"===t.attributes.away_mode,this.tempMin=t.attributes.min_temp,this.tempMax=t.attributes.max_temp},computeClassNames:function(t){return s["default"](t,c)},targetTemperatureSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||i.serviceActions.callService("thermostat","set_temperature",{entity_id:this.stateObj.entityId,temperature:e})},toggleChanged:function(t){var e=t.target.checked;e&&"off"===this.stateObj.attributes.away_mode?this.service_set_away(!0):e||"on"!==this.stateObj.attributes.away_mode||this.service_set_away(!1)},service_set_away:function(t){var e=this;i.serviceActions.callService("thermostat","set_away_mode",{away_mode:t,entity_id:this.stateObj.entityId}).then(function(){return e.stateObjChanged(e.stateObj)})}}),t.exports=e["default"]},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(2);e["default"]=new Polymer({is:"more-info-updater",properties:{stateObj:{type:Object}},updateTapped:function(){r.serviceActions.callService("updater","update",{})},linkTapped:function(){window.open(this.stateObj.attributes.link,"_blank")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(14),n(61),e["default"]=new o["default"]({is:"state-card-configurator",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e,n){"use strict"; +function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(14);var u=["playing","paused"];e["default"]=new o["default"]({is:"state-card-media_player",properties:{stateObj:{type:Object},isPlaying:{type:Boolean,computed:"computeIsPlaying(stateObj)"}},computeIsPlaying:function(t){return-1!==u.indexOf(t.state)},computePrimaryText:function(t,e){return e?t.attributes.media_title:t.stateDisplay},computeSecondaryText:function(t){var e=void 0;return"music"===t.attributes.media_content_type?t.attributes.media_artist:"tvshow"===t.attributes.media_content_type?(e=t.attributes.media_series_title,t.attributes.media_season&&t.attributes.media_episode&&(e+=" S"+t.attributes.media_season+"E"+t.attributes.media_episode),e):t.attributes.app_name?t.attributes.app_name:""}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2);n(14),e["default"]=new o["default"]({is:"state-card-scene",properties:{stateObj:{type:Object}},activateScene:function(t){u.serviceActions.callTurnOn(this.stateObj.entityId)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(14),e["default"]=new o["default"]({is:"state-card-thermostat",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(14),n(57),e["default"]=new o["default"]({is:"state-card-toggle"}),t.exports=e["default"]},function(t,e){"use strict";function n(t){return{attached:function(){var e=this;this.__unwatchFns=Object.keys(this.properties).reduce(function(n,r){if(!("bindNuclear"in e.properties[r]))return n;var i=e.properties[r].bindNuclear;if(!i)throw new Error("Undefined getter specified for key "+r);return e[r]=t.evaluate(i),n.concat(t.observe(i,function(t){e[r]=t}))},[])},detached:function(){for(;this.__unwatchFns.length;)this.__unwatchFns.shift()()}}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return-1!==a.indexOf(t.domain)?t.domain:u["default"](t.entityId)?"toggle":"display"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(34),u=r(o),a=["thermostat","configurator","scene","media_player"];t.exports=e["default"]},function(t,e){"use strict";function n(t){return-1!==r.indexOf(t.domain)?t.domain:"default"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n;var r=["light","group","sun","configurator","thermostat","script","media_player","camera","updater","alarm_control_panel"];t.exports=e["default"]},function(t,e){"use strict";function n(t,e,n){var r=1-t-e,i=n/255,o=i/e*t,u=i/e*r,a=1.612*o-.203*i-.302*u,s=.509*-o+1.412*i+.066*u,c=.026*o-.072*i+.962*u;a=.0031308>=a?12.92*a:1.055*Math.pow(a,1/2.4)-.055,s=.0031308>=s?12.92*s:1.055*Math.pow(s,1/2.4)-.055,c=.0031308>=c?12.92*c:1.055*Math.pow(c,1/2.4)-.055;var l=Math.max(a,s,c);return a/=l,s/=l,c/=l,a=255*a,0>a&&(a=255),s=255*s,0>s&&(s=255),c=255*c,0>c&&(c=255),[a,s,c]}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){var r;(function(t,i,o){"use strict";(function(){function u(t){return"function"==typeof t||"object"==typeof t&&null!==t}function a(t){return"function"==typeof t}function s(t){return"object"==typeof t&&null!==t}function c(t){W=t}function l(t){Z=t}function f(){return function(){t.nextTick(_)}}function d(){return function(){q(_)}}function p(){var t=0,e=new tt(_),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function h(){var t=new MessageChannel;return t.port1.onmessage=_,function(){t.port2.postMessage(0)}}function v(){return function(){setTimeout(_,1)}}function _(){for(var t=0;$>t;t+=2){var e=rt[t],n=rt[t+1];e(n),rt[t]=void 0,rt[t+1]=void 0}$=0}function y(){try{var t=n(254);return q=t.runOnLoop||t.runOnContext,d()}catch(e){return v()}}function m(){}function g(){return new TypeError("You cannot resolve a promise with itself")}function b(){return new TypeError("A promises callback cannot return that same promise.")}function O(t){try{return t.then}catch(e){return at.error=e,at}}function w(t,e,n,r){try{t.call(e,n,r)}catch(i){return i}}function S(t,e,n){Z(function(t){var r=!1,i=w(n,e,function(n){r||(r=!0,e!==n?T(t,n):I(t,n))},function(e){r||(r=!0,P(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&i&&(r=!0,P(t,i))},t)}function M(t,e){e._state===ot?I(t,e._result):e._state===ut?P(t,e._result):D(e,void 0,function(e){T(t,e)},function(e){P(t,e)})}function j(t,e){if(e.constructor===t.constructor)M(t,e);else{var n=O(e);n===at?P(t,at.error):void 0===n?I(t,e):a(n)?S(t,e,n):I(t,e)}}function T(t,e){t===e?P(t,g()):u(e)?j(t,e):I(t,e)}function E(t){t._onerror&&t._onerror(t._result),C(t)}function I(t,e){t._state===it&&(t._result=e,t._state=ot,0!==t._subscribers.length&&Z(C,t))}function P(t,e){t._state===it&&(t._state=ut,t._result=e,Z(E,t))}function D(t,e,n,r){var i=t._subscribers,o=i.length;t._onerror=null,i[o]=e,i[o+ot]=n,i[o+ut]=r,0===o&&t._state&&Z(C,t)}function C(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r,i,o=t._result,u=0;uu;u++)D(r.resolve(t[u]),void 0,e,n);return i}function H(t){var e=this;if(t&&"object"==typeof t&&t.constructor===e)return t;var n=new e(m);return T(n,t),n}function Y(t){var e=this,n=new e(m);return P(n,t),n}function G(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function F(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function U(t){this._id=ht++,this._state=void 0,this._result=void 0,this._subscribers=[],m!==t&&(a(t)||G(),this instanceof U||F(),L(this,t))}function B(){var t;if("undefined"!=typeof i)t=i;else if("undefined"!=typeof self)t=self;else try{t=Function("return this")()}catch(e){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=t.Promise;(!n||"[object Promise]"!==Object.prototype.toString.call(n.resolve())||n.cast)&&(t.Promise=vt)}var V;V=Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)};var q,W,K,J=V,$=0,Z=({}.toString,function(t,e){rt[$]=t,rt[$+1]=e,$+=2,2===$&&(W?W(_):K())}),X="undefined"!=typeof window?window:void 0,Q=X||{},tt=Q.MutationObserver||Q.WebKitMutationObserver,et="undefined"!=typeof t&&"[object process]"==={}.toString.call(t),nt="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,rt=new Array(1e3);K=et?f():tt?p():nt?h():void 0===X?y():v();var it=void 0,ot=1,ut=2,at=new A,st=new A;N.prototype._validateInput=function(t){return J(t)},N.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},N.prototype._init=function(){this._result=new Array(this.length)};var ct=N;N.prototype._enumerate=function(){for(var t=this,e=t.length,n=t.promise,r=t._input,i=0;n._state===it&&e>i;i++)t._eachEntry(r[i],i)},N.prototype._eachEntry=function(t,e){var n=this,r=n._instanceConstructor;s(t)?t.constructor===r&&t._state!==it?(t._onerror=null,n._settledAt(t._state,e,t._result)):n._willSettleAt(r.resolve(t),e):(n._remaining--,n._result[e]=t)},N.prototype._settledAt=function(t,e,n){var r=this,i=r.promise;i._state===it&&(r._remaining--,t===ut?P(i,n):r._result[e]=n),0===r._remaining&&I(i,r._result)},N.prototype._willSettleAt=function(t,e){var n=this;D(t,void 0,function(t){n._settledAt(ot,e,t)},function(t){n._settledAt(ut,e,t)})};var lt=R,ft=z,dt=H,pt=Y,ht=0,vt=U;U.all=lt,U.race=ft,U.resolve=dt,U.reject=pt,U._setScheduler=c,U._setAsap=l,U._asap=Z,U.prototype={constructor:U,then:function(t,e){var n=this,r=n._state;if(r===ot&&!t||r===ut&&!e)return this;var i=new this.constructor(m),o=n._result;if(r){var u=arguments[r-1];Z(function(){k(r,i,u,o)})}else D(n,i,t,e);return i},"catch":function(t){return this.then(null,t)}};var _t=B,yt={Promise:vt,polyfill:_t};n(253).amd?(r=function(){return yt}.call(e,n,e,o),!(void 0!==r&&(o.exports=r))):"undefined"!=typeof o&&o.exports?o.exports=yt:"undefined"!=typeof this&&(this.ES6Promise=yt),_t()}).call(void 0)}).call(e,n(250),function(){return this}(),n(251)(t))},function(t,e,n){"use strict";var r=n(65),i=r(Date,"now"),o=i||function(){return(new Date).getTime()};t.exports=o},function(t,e){"use strict";function n(t){return"number"==typeof t&&t>-1&&t%1==0&&r>=t}var r=9007199254740991;t.exports=n},function(t,e,n){"use strict";var r=n(65),i=n(185),o=n(66),u="[object Array]",a=Object.prototype,s=a.toString,c=r(Array,"isArray"),l=c||function(t){return o(t)&&i(t.length)&&s.call(t)==u};t.exports=l},function(t,e,n){"use strict";function r(t){return null==t?!1:i(t)?l.test(s.call(t)):o(t)&&u.test(t)}var i=n(67),o=n(66),u=/^\[object .+?Constructor\]$/,a=Object.prototype,s=Function.prototype.toString,c=a.hasOwnProperty,l=RegExp("^"+s.call(c).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.exports=r},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(183),i=n(22),o=function(t,e,n){var o=arguments.length<=3||void 0===arguments[3]?null:arguments[3],u=t.evaluate(i.getters.authInfo),a=u.host+"/api/"+n;return new r.Promise(function(t,n){var r=new XMLHttpRequest;r.open(e,a,!0),r.setRequestHeader("X-HA-access",u.authToken),r.onload=function(){if(r.status>199&&r.status<300)t(JSON.parse(r.responseText));else try{n(JSON.parse(r.responseText))}catch(e){n({})}},r.onerror=function(){return n({})},o?r.send(JSON.stringify(o)):r.send()})};e["default"]=o,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){var n=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],r=n.useStreaming,i=void 0===r?t.evaluate(s.getters.isSupported):r,o=n.rememberAuth,u=void 0===o?!1:o,f=n.host,d=void 0===f?"":f;t.dispatch(a["default"].VALIDATING_AUTH_TOKEN,{authToken:e,host:d}),c.actions.fetchAll(t).then(function(){t.dispatch(a["default"].VALID_AUTH_TOKEN,{authToken:e,host:d,rememberAuth:u}),i?s.actions.start(t,{syncOnInitialConnect:!1}):c.actions.start(t,{skipInitialSync:!0})},function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=e.message,r=void 0===n?l:n;t.dispatch(a["default"].INVALID_AUTH_TOKEN,{errorMessage:r})})}function o(t){t.dispatch(a["default"].LOG_OUT,{})}Object.defineProperty(e,"__esModule",{value:!0}),e.validate=i,e.logOut=o;var u=n(21),a=r(u),s=n(41),c=n(43),l="Unexpected result from API"},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=[["authAttempt","isValidating"],function(t){return!!t}];e.isValidating=n;var r=[["authAttempt","isInvalid"],function(t){return!!t}];e.isInvalidAttempt=r;var i=["authAttempt","errorMessage"];e.attemptErrorMessage=i;var o=["rememberAuth"];e.rememberAuth=o;var u=[["authAttempt","authToken"],["authAttempt","host"],function(t,e){return{authToken:t,host:e}}];e.attemptAuthInfo=u;var a=["authCurrent","authToken"];e.currentAuthToken=a;var s=[a,["authCurrent","host"],function(t,e){return{authToken:t,host:e}}];e.currentAuthInfo=s;var c=[n,["authAttempt","authToken"],["authCurrent","authToken"],function(t,e,n){return t?e:n}];e.authToken=c;var l=[n,u,s,function(t,e,n){return t?e:n}];e.authInfo=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){if(null==t)throw new TypeError("Cannot destructure undefined")}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t,e){var n=e.authToken,r=e.host;return d.toImmutable({authToken:n,host:r,isValidating:"true",isInvalid:!1,errorMessage:""})}function s(t,e){return i(e),_.getInitialState()}function c(t,e){var n=e.errorMessage;return t.withMutations(function(t){return t.set("isValidating",!1).set("isInvalid","true").set("errorMessage",n)})}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n1&&t.set(p,r)})}function a(){return v.getInitialState()}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function t(t,e){for(var n=0;no}Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),o=6e4,u=["currentLogbookDate"];e.currentDate=u;var a=[u,["logbookEntriesUpdated"],function(t,e){return r(e.get(t))}];e.isCurrentStale=a;var s=[u,["logbookEntries"],function(t,e){return e.get(t)||i.toImmutable([])}];e.currentEntries=s;var c=["isLoadingLogbookEntries"];e.isLoadingEntries=c},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({currentLogbookDate:a["default"],isLoadingLogbookEntries:c["default"],logbookEntries:f["default"],logbookEntriesUpdated:p["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(212),a=i(u),s=n(213),c=i(s),l=n(214),f=i(l),d=n(215),p=i(d),h=n(208),v=r(h),_=n(209),y=r(_),m=v;e.actions=m;var g=y;e.getters=g},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n1)for(var n=1;n \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 3d6792691a3..5973dd41715 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 3d6792691a3d6beae5d446a6fbeb83c9025d040d +Subproject commit 5973dd41715f7aca1bd03cdc0aa6625afb34c94a From 38e1cef30e245d7fec86102c9e4e46c270c14bb1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Oct 2015 08:58:15 -0700 Subject: [PATCH 033/226] Update frontend for style fix --- .../components/frontend/www_static/home-assistant-polymer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 5973dd41715..c91fcccf29c 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 5973dd41715f7aca1bd03cdc0aa6625afb34c94a +Subproject commit c91fcccf29c977bb0f8e1143fb26fc75613b6a0f From a583525110d2bb1e201d0b388c98b142dff84126 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:01:23 +0200 Subject: [PATCH 034/226] Move configuration details to docs --- .../components/alarm_control_panel/manual.py | 48 +++++-------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index eaeda59719b..2aee8b89e17 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -1,37 +1,11 @@ """ homeassistant.components.alarm_control_panel.manual +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for manual alarms. -Configuration: - -alarm_control_panel: - platform: manual - name: "HA Alarm" - code: "mySecretCode" - pending_time: 60 - trigger_time: 120 - -Variables: - -name -*Optional -The name of the alarm. Default is 'HA Alarm'. - -code -*Optional -If defined, specifies a code to arm or disarm the alarm in the frontend. - -pending_time -*Optional -The time in seconds of the pending time before arming the alarm. -Default is 60 seconds. - -trigger_time -*Optional -The time in seconds of the trigger time in which the alarm is firing. -Default is 120 seconds. - +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/alarm_control_panel.manual.html """ - import logging import datetime import homeassistant.components.alarm_control_panel as alarm @@ -66,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): # pylint: disable=too-many-arguments, too-many-instance-attributes # pylint: disable=abstract-method class ManualAlarm(alarm.AlarmControlPanel): - """ represents an alarm status within home assistant. """ + """ Represents an alarm status. """ def __init__(self, hass, name, code, pending_time, trigger_time): self._state = STATE_ALARM_DISARMED @@ -80,7 +54,7 @@ class ManualAlarm(alarm.AlarmControlPanel): @property def should_poll(self): - """ No polling needed """ + """ No polling needed. """ return False @property @@ -95,11 +69,11 @@ class ManualAlarm(alarm.AlarmControlPanel): @property def code_format(self): - """ One or more characters """ + """ One or more characters. """ return None if self._code is None else '.+' def update_state(self, state, pending_to): - """ changes between state with delay """ + """ Changes between state with delay. """ self._state = state self._state_ts = dt_util.utcnow() self._pending_to = pending_to @@ -118,7 +92,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_HOME) def delayed_alarm_arm_home(event_time): - """ callback for delayed action """ + """ Callback for delayed action. """ if self._pending_to == STATE_ALARM_ARMED_HOME and \ dt_util.utcnow() - self._state_ts >= self._pending_time: self.update_state(STATE_ALARM_ARMED_HOME, None) @@ -134,7 +108,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_AWAY) def delayed_alarm_arm_away(event_time): - """ callback for delayed action """ + """ Callback for delayed action. """ if self._pending_to == STATE_ALARM_ARMED_AWAY and \ dt_util.utcnow() - self._state_ts >= self._pending_time: self.update_state(STATE_ALARM_ARMED_AWAY, None) @@ -155,7 +129,7 @@ class ManualAlarm(alarm.AlarmControlPanel): self.update_state(STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED) def delayed_alarm_disarm(event_time): - """ callback for delayed action """ + """ Callback for delayed action. """ if self._pending_to == STATE_ALARM_DISARMED and \ dt_util.utcnow() - self._state_ts >= self._trigger_time: self.update_state(STATE_ALARM_DISARMED, None) From 47448d1dc0380cb3b45833e404eb23a76ec55ccc Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:40:59 +0200 Subject: [PATCH 035/226] Add link to docs --- homeassistant/components/shell_command.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/shell_command.py b/homeassistant/components/shell_command.py index 2fceaf71519..c5c60e98e7d 100644 --- a/homeassistant/components/shell_command.py +++ b/homeassistant/components/shell_command.py @@ -1,12 +1,10 @@ """ homeassistant.components.shell_command ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Exposes regular shell commands as services. -Component to expose shell commands as services. - -shell_command: - restart_pow: touch ~/.pow/restart.txt - +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/shell_command.html """ import logging import subprocess From 62cfb8aeb26ba80d87afc93edc1d17f9f8893fad Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:42:05 +0200 Subject: [PATCH 036/226] Move configuration details to docs --- .../components/alarm_control_panel/mqtt.py | 56 +------------------ 1 file changed, 2 insertions(+), 54 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/mqtt.py b/homeassistant/components/alarm_control_panel/mqtt.py index 6005a307fbd..3b2f745693d 100644 --- a/homeassistant/components/alarm_control_panel/mqtt.py +++ b/homeassistant/components/alarm_control_panel/mqtt.py @@ -1,62 +1,10 @@ """ homeassistant.components.alarm_control_panel.mqtt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - This platform enables the possibility to control a MQTT alarm. -In this platform, 'state_topic' and 'command_topic' are required. -The alarm will only change state after receiving the a new state -from 'state_topic'. If these messages are published with RETAIN flag, -the MQTT alarm will receive an instant state update after subscription -and will start with correct state. Otherwise, the initial state will -be 'unknown'. -Configuration: - -alarm_control_panel: - platform: mqtt - name: "MQTT Alarm" - state_topic: "home/alarm" - command_topic: "home/alarm/set" - qos: 0 - payload_disarm: "DISARM" - payload_arm_home: "ARM_HOME" - payload_arm_away: "ARM_AWAY" - code: "mySecretCode" - -Variables: - -name -*Optional -The name of the alarm. Default is 'MQTT Alarm'. - -state_topic -*Required -The MQTT topic subscribed to receive state updates. - -command_topic -*Required -The MQTT topic to publish commands to change the alarm state. - -qos -*Optional -The maximum QoS level of the state topic. Default is 0. -This QoS will also be used to publishing messages. - -payload_disarm -*Optional -The payload do disarm alarm. Default is "DISARM". - -payload_arm_home -*Optional -The payload to set armed-home mode. Default is "ARM_HOME". - -payload_arm_away -*Optional -The payload to set armed-away mode. Default is "ARM_AWAY". - -code -*Optional -If defined, specifies a code to enable or disable the alarm in the frontend. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/alarm_control_panel.mqtt.html """ import logging import homeassistant.components.mqtt as mqtt From b0d8eaeda98b8d84b7cf7c5aedbea3bafa10d765 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:44:18 +0200 Subject: [PATCH 037/226] Move configuration details to docs --- .../components/device_tracker/actiontec.py | 39 ++----------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/device_tracker/actiontec.py b/homeassistant/components/device_tracker/actiontec.py index f926b182983..a2f94f34c3a 100644 --- a/homeassistant/components/device_tracker/actiontec.py +++ b/homeassistant/components/device_tracker/actiontec.py @@ -4,41 +4,8 @@ homeassistant.components.device_tracker.actiontec Device tracker platform that supports scanning an Actiontec MI424WR (Verizon FIOS) router for device presence. -This device tracker needs telnet to be enabled on the router. - -Configuration: - -To use the Actiontec tracker you will need to add something like the -following to your configuration.yaml file. If you experience disconnects -you can modify the home_interval variable. - -device_tracker: - platform: actiontec - host: YOUR_ROUTER_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - # optional: - home_interval: 10 - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. - -home_interval -*Optional -If the home_interval is set then the component will not let a device -be AWAY if it has been HOME in the last home_interval minutes. This is -in addition to the 3 minute wait built into the device_tracker component. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.actiontec.html """ import logging from datetime import timedelta @@ -56,7 +23,7 @@ from homeassistant.components.device_tracker import DOMAIN # Return cached results if last scan was less then this time ago MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) -# interval in minutes to exclude devices from a scan while they are home +# Interval in minutes to exclude devices from a scan while they are home CONF_HOME_INTERVAL = "home_interval" _LOGGER = logging.getLogger(__name__) From cb7b5f8d15312dc119da98df81928ff95d79488e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:45:29 +0200 Subject: [PATCH 038/226] Move configuration details to docs --- .../components/device_tracker/aruba.py | 30 ++----------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/device_tracker/aruba.py b/homeassistant/components/device_tracker/aruba.py index 68ff8390216..ef8fa76a5b4 100644 --- a/homeassistant/components/device_tracker/aruba.py +++ b/homeassistant/components/device_tracker/aruba.py @@ -4,34 +4,8 @@ homeassistant.components.device_tracker.aruba Device tracker platform that supports scanning a Aruba Access Point for device presence. -This device tracker needs telnet to be enabled on the router. - -Configuration: - -To use the Aruba tracker you will need to add something like the following -to your configuration.yaml file. You also need to enable Telnet in the -configuration page of your router. - -device_tracker: - platform: aruba - host: YOUR_ACCESS_POINT_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. -""" +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.aruba.html""" import logging from datetime import timedelta import re From 8253fdfc13f49dff22b492ec35f59cc166d7f513 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:49:14 +0200 Subject: [PATCH 039/226] Add newline --- homeassistant/components/device_tracker/aruba.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/aruba.py b/homeassistant/components/device_tracker/aruba.py index ef8fa76a5b4..d46264fa264 100644 --- a/homeassistant/components/device_tracker/aruba.py +++ b/homeassistant/components/device_tracker/aruba.py @@ -5,7 +5,8 @@ Device tracker platform that supports scanning a Aruba Access Point for device presence. For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/device_tracker.aruba.html""" +https://home-assistant.io/components/device_tracker.aruba.html +""" import logging from datetime import timedelta import re From 966fd8f24d46a1176885aab07b7682635e2ac334 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:49:28 +0200 Subject: [PATCH 040/226] Move configuration details to docs --- .../components/device_tracker/ddwrt.py | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/device_tracker/ddwrt.py b/homeassistant/components/device_tracker/ddwrt.py index 947876c85b5..d8734a55a17 100644 --- a/homeassistant/components/device_tracker/ddwrt.py +++ b/homeassistant/components/device_tracker/ddwrt.py @@ -4,30 +4,8 @@ homeassistant.components.device_tracker.ddwrt Device tracker platform that supports scanning a DD-WRT router for device presence. -Configuration: - -To use the DD-WRT tracker you will need to add something like the following -to your configuration.yaml file. - -device_tracker: - platform: ddwrt - host: YOUR_ROUTER_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.ddwrt.html """ import logging from datetime import timedelta From c74f46794e1d02d9c47f7dfd84396f0e64cfd51d Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:50:15 +0200 Subject: [PATCH 041/226] Move configuration details to docs --- homeassistant/components/device_tracker/geofancy.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/device_tracker/geofancy.py b/homeassistant/components/device_tracker/geofancy.py index 55ebf2e0d1b..91d3978326b 100644 --- a/homeassistant/components/device_tracker/geofancy.py +++ b/homeassistant/components/device_tracker/geofancy.py @@ -1,11 +1,10 @@ """ homeassistant.components.device_tracker.geofancy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Geofancy platform for the device tracker. -device_tracker: - platform: geofancy +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.geofancy.html """ from homeassistant.const import ( From 3b91f89173b9b6130d97cd608690ff66bbeea900 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:50:53 +0200 Subject: [PATCH 042/226] Move configuration details to docs --- .../components/device_tracker/luci.py | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/homeassistant/components/device_tracker/luci.py b/homeassistant/components/device_tracker/luci.py index 4cbc6a2d492..2ce032f90fd 100644 --- a/homeassistant/components/device_tracker/luci.py +++ b/homeassistant/components/device_tracker/luci.py @@ -4,33 +4,8 @@ homeassistant.components.device_tracker.luci Device tracker platform that supports scanning a OpenWRT router for device presence. -It's required that the luci RPC package is installed on the OpenWRT router: -# opkg install luci-mod-rpc - -Configuration: - -To use the Luci tracker you will need to add something like the following -to your configuration.yaml file. - -device_tracker: - platform: luci - host: YOUR_ROUTER_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.luci.html """ import logging import json From c33942d6e212d121b86d1af8876c0dd10aa4e9b3 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:51:30 +0200 Subject: [PATCH 043/226] Move configuration details to docs --- .../components/device_tracker/tplink.py | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index d368637cd6b..3769229f101 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -4,30 +4,8 @@ homeassistant.components.device_tracker.tplink Device tracker platform that supports scanning a TP-Link router for device presence. -Configuration: - -To use the TP-Link tracker you will need to add something like the following -to your configuration.yaml file. - -device_tracker: - platform: tplink - host: YOUR_ROUTER_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.tplink.html """ import base64 import logging From 77430c06872ee4cc3e63b95e7937936571beabe3 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:52:08 +0200 Subject: [PATCH 044/226] Move configuration details to docs --- .../components/device_tracker/tomato.py | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/device_tracker/tomato.py b/homeassistant/components/device_tracker/tomato.py index a23b7b80ff0..df0c9c8d93d 100644 --- a/homeassistant/components/device_tracker/tomato.py +++ b/homeassistant/components/device_tracker/tomato.py @@ -4,36 +4,8 @@ homeassistant.components.device_tracker.tomato Device tracker platform that supports scanning a Tomato router for device presence. -Configuration: - -To use the Tomato tracker you will need to add something like the following -to your configuration.yaml file. - -device_tracker: - platform: tomato - host: YOUR_ROUTER_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - http_id: ABCDEFG - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. - -http_id -*Required -The value can be obtained by logging in to the Tomato admin interface and -search for http_id in the page source code. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.tomato.html """ import logging import json From 796cce78bc1f12b9cc5bdb813172331433dd9e72 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:52:30 +0200 Subject: [PATCH 045/226] Move configuration details to docs --- .../components/device_tracker/thomson.py | 28 ++----------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/device_tracker/thomson.py b/homeassistant/components/device_tracker/thomson.py index 408daa94d81..c6679e6c320 100644 --- a/homeassistant/components/device_tracker/thomson.py +++ b/homeassistant/components/device_tracker/thomson.py @@ -4,32 +4,8 @@ homeassistant.components.device_tracker.thomson Device tracker platform that supports scanning a THOMSON router for device presence. -This device tracker needs telnet to be enabled on the router. - -Configuration: - -To use the THOMSON tracker you will need to add something like the following -to your configuration.yaml file. - -device_tracker: - platform: thomson - host: YOUR_ROUTER_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.thomson.html """ import logging from datetime import timedelta From 5a6ff9a69a2d769f6ac363f20afb89a23dd2290d Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:54:15 +0200 Subject: [PATCH 046/226] Move configuration details to docs --- homeassistant/components/device_tracker/mqtt.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/device_tracker/mqtt.py b/homeassistant/components/device_tracker/mqtt.py index 34cee8f6733..f78cb3420f5 100644 --- a/homeassistant/components/device_tracker/mqtt.py +++ b/homeassistant/components/device_tracker/mqtt.py @@ -1,15 +1,10 @@ """ homeassistant.components.device_tracker.mqtt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - MQTT platform for the device tracker. -device_tracker: - platform: mqtt - qos: 1 - devices: - paulus_oneplus: /location/paulus - annetherese_n4: /location/annetherese +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.mqtt.html """ import logging from homeassistant import util From 0369a9ee0dcaef0ec4b35079f93c292177b0fa18 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:54:48 +0200 Subject: [PATCH 047/226] Move configuration details to docs --- .../components/device_tracker/netgear.py | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/device_tracker/netgear.py b/homeassistant/components/device_tracker/netgear.py index 46c515dcb1f..2d138cf5c70 100644 --- a/homeassistant/components/device_tracker/netgear.py +++ b/homeassistant/components/device_tracker/netgear.py @@ -4,30 +4,8 @@ homeassistant.components.device_tracker.netgear Device tracker platform that supports scanning a Netgear router for device presence. -Configuration: - -To use the Netgear tracker you will need to add something like the following -to your configuration.yaml file. - -device_tracker: - platform: netgear - host: YOUR_ROUTER_IP - username: YOUR_ADMIN_USERNAME - password: YOUR_ADMIN_PASSWORD - -Variables: - -host -*Required -The IP address of your router, e.g. 192.168.1.1. - -username -*Required -The username of an user with administrative privileges, usually 'admin'. - -password -*Required -The password for your given admin account. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.netgear.html """ import logging from datetime import timedelta From 6ca50d8b5c208a2063910832df5d9a07301b6893 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:55:15 +0200 Subject: [PATCH 048/226] Move configuration details to docs --- homeassistant/components/device_tracker/owntracks.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/device_tracker/owntracks.py b/homeassistant/components/device_tracker/owntracks.py index 505fd6b7ad2..78fd42f1566 100644 --- a/homeassistant/components/device_tracker/owntracks.py +++ b/homeassistant/components/device_tracker/owntracks.py @@ -1,11 +1,10 @@ """ homeassistant.components.device_tracker.owntracks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - OwnTracks platform for the device tracker. -device_tracker: - platform: owntracks +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.owntracks.html """ import json import logging From 403889bbebe4d10e686c428881082639b690ba5a Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 20:55:45 +0200 Subject: [PATCH 049/226] Move configuration details to docs --- .../components/device_tracker/nmap_tracker.py | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/device_tracker/nmap_tracker.py b/homeassistant/components/device_tracker/nmap_tracker.py index 6f993f0fc7e..fe6b814b96f 100644 --- a/homeassistant/components/device_tracker/nmap_tracker.py +++ b/homeassistant/components/device_tracker/nmap_tracker.py @@ -3,26 +3,8 @@ homeassistant.components.device_tracker.nmap ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Device tracker platform that supports scanning a network with nmap. -Configuration: - -To use the nmap tracker you will need to add something like the following -to your configuration.yaml file. - -device_tracker: - platform: nmap_tracker - hosts: 192.168.1.1/24 - -Variables: - -hosts -*Required -The IP addresses to scan in the network-prefix notation (192.168.1.1/24) or -the range notation (192.168.1.1-255). - -home_interval -*Optional -Number of minutes it will not scan devices that it found in previous results. -This is to save battery. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/device_tracker.nmap_scanner.html """ import logging from datetime import timedelta From 44418b509c7a5c32bf8a3c9ccd5aac2bb3b76194 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:00:28 +0200 Subject: [PATCH 050/226] Move configuration details to docs --- homeassistant/components/camera/generic.py | 39 ++-------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/homeassistant/components/camera/generic.py b/homeassistant/components/camera/generic.py index 7e4a24ffdfe..74d2d0102d3 100644 --- a/homeassistant/components/camera/generic.py +++ b/homeassistant/components/camera/generic.py @@ -3,43 +3,8 @@ homeassistant.components.camera.generic ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Support for IP Cameras. -This component provides basic support for IP cameras. For the basic support to -work you camera must support accessing a JPEG snapshot via a URL and you will -need to specify the "still_image_url" parameter which should be the location of -the JPEG image. - -As part of the basic support the following features will be provided: -- MJPEG video streaming -- Saving a snapshot -- Recording(JPEG frame capture) - -To use this component, add the following to your configuration.yaml file. - -camera: - platform: generic - name: Door Camera - username: YOUR_USERNAME - password: YOUR_PASSWORD - still_image_url: http://YOUR_CAMERA_IP_AND_PORT/image.jpg - -Variables: - -still_image_url -*Required -The URL your camera serves the image on, eg. http://192.168.1.21:2112/ - -name -*Optional -This parameter allows you to override the name of your camera in Home -Assistant. - -username -*Optional -The username for accessing your camera. - -password -*Optional -The password for accessing your camera. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/camera.generic.html """ import logging from requests.auth import HTTPBasicAuth From 0874cb364fb99bb39c32af8aec763393b1997bff Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:00:44 +0200 Subject: [PATCH 051/226] Move configuration details to docs --- homeassistant/components/camera/foscam.py | 36 ----------------------- 1 file changed, 36 deletions(-) diff --git a/homeassistant/components/camera/foscam.py b/homeassistant/components/camera/foscam.py index 78fd0f4d2e1..24a42cbf883 100644 --- a/homeassistant/components/camera/foscam.py +++ b/homeassistant/components/camera/foscam.py @@ -3,42 +3,6 @@ homeassistant.components.camera.foscam ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This component provides basic support for Foscam IP cameras. -As part of the basic support the following features will be provided: --MJPEG video streaming - -To use this component, add the following to your configuration.yaml file. - -camera: - platform: foscam - name: Door Camera - ip: 192.168.0.123 - port: 88 - username: YOUR_USERNAME - password: YOUR_PASSWORD - -Variables: - -ip -*Required -The IP address of your Foscam device. - -username -*Required -The username of a visitor or operator of your camera. Oddly admin accounts -don't seem to have access to take snapshots. - -password -*Required -The password for accessing your camera. - -name -*Optional -This parameter allows you to override the name of your camera in homeassistant. - -port -*Optional -The port that the camera is running on. The default is 88. - For more details about this platform, please refer to the documentation at https://home-assistant.io/components/camera.foscam.html """ From c5c2f0c5f3f3039441b6817b548c4a593276cd4a Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:07:24 +0200 Subject: [PATCH 052/226] Add link to docs --- homeassistant/components/automation/event.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/event.py b/homeassistant/components/automation/event.py index c5b0ee47923..c172b8e0e11 100644 --- a/homeassistant/components/automation/event.py +++ b/homeassistant/components/automation/event.py @@ -1,8 +1,10 @@ """ homeassistant.components.automation.event ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Offers event listening automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/components/automation.html#event-trigger """ import logging From 241ff45c5eb6345ad720ddbb0f4c00db2b62359f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:07:40 +0200 Subject: [PATCH 053/226] Add link to docs --- homeassistant/components/automation/mqtt.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/mqtt.py b/homeassistant/components/automation/mqtt.py index 3f85792f907..706d97824b4 100644 --- a/homeassistant/components/automation/mqtt.py +++ b/homeassistant/components/automation/mqtt.py @@ -1,8 +1,10 @@ """ homeassistant.components.automation.mqtt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Offers MQTT listening automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/components/automation.html#mqtt-trigger """ import logging From cb69ac30ec09bf12eae6d138835ea6beaff944f3 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:07:53 +0200 Subject: [PATCH 054/226] Add link to docs --- homeassistant/components/automation/numeric_state.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/numeric_state.py b/homeassistant/components/automation/numeric_state.py index 7e014213d62..1ddfb91a334 100644 --- a/homeassistant/components/automation/numeric_state.py +++ b/homeassistant/components/automation/numeric_state.py @@ -1,8 +1,10 @@ """ homeassistant.components.automation.numeric_state ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Offers numeric state listening automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/components/automation.html#numeric-state-trigger """ import logging From e06739813453fa1f06c5bb2755b4f1746d9f3663 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:08:18 +0200 Subject: [PATCH 055/226] Add link to docs --- homeassistant/components/automation/state.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/state.py b/homeassistant/components/automation/state.py index 5fc36300ed0..52379355d6b 100644 --- a/homeassistant/components/automation/state.py +++ b/homeassistant/components/automation/state.py @@ -1,8 +1,10 @@ """ homeassistant.components.automation.state ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Offers state listening automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/components/automation.html#state-trigger """ import logging From 17d9df0da5ec724aab3bc9b830b77b7a6f7fd27e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:08:34 +0200 Subject: [PATCH 056/226] Add link to docs --- homeassistant/components/automation/sun.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/sun.py b/homeassistant/components/automation/sun.py index 103df6c9b39..c72474ae4dd 100644 --- a/homeassistant/components/automation/sun.py +++ b/homeassistant/components/automation/sun.py @@ -1,8 +1,10 @@ """ homeassistant.components.automation.sun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Offers sun based automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/components/automation.html#sun-trigger """ import logging from datetime import timedelta From 771118caaf59d0f64ffb6a8a57f0a4da8b4f71cc Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:08:51 +0200 Subject: [PATCH 057/226] Add link to docs --- homeassistant/components/automation/time.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/time.py b/homeassistant/components/automation/time.py index 1d97ccc135d..2f05c6f4390 100644 --- a/homeassistant/components/automation/time.py +++ b/homeassistant/components/automation/time.py @@ -1,8 +1,10 @@ """ homeassistant.components.automation.time ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Offers time listening automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/components/automation.html#time-trigger """ import logging From 185ba000dd103ee5fc4ae8808b8602f4aba0c88f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 21:09:11 +0200 Subject: [PATCH 058/226] Add link to docs --- homeassistant/components/automation/zone.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/automation/zone.py b/homeassistant/components/automation/zone.py index f62aec8bf2a..28d1c8456f0 100644 --- a/homeassistant/components/automation/zone.py +++ b/homeassistant/components/automation/zone.py @@ -1,8 +1,10 @@ """ homeassistant.components.automation.zone ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Offers zone automation rules. + +For more details about this automation rule, please refer to the documentation +at https://home-assistant.io/components/automation.html#zone-trigger """ import logging From 893b9fc8ac2d7341a65097ceaa78916074dd0370 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:06:29 +0200 Subject: [PATCH 059/226] Move configuration details to docs --- homeassistant/components/notify/xmpp.py | 27 ++----------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/notify/xmpp.py b/homeassistant/components/notify/xmpp.py index 1d72f6a262b..d4f5a7336a6 100644 --- a/homeassistant/components/notify/xmpp.py +++ b/homeassistant/components/notify/xmpp.py @@ -3,31 +3,8 @@ homeassistant.components.notify.xmpp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Jabber (XMPP) notification service. -Configuration: - -To use the Jabber notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: xmpp - sender: YOUR_JID - password: YOUR_JABBER_ACCOUNT_PASSWORD - recipient: YOUR_RECIPIENT - -Variables: - -sender -*Required -The Jabber ID (JID) that will act as origin of the messages. Add your JID -including the domain, e.g. your_name@jabber.org. - -password -*Required -The password for your given Jabber account. - -recipient -*Required -The Jabber ID (JID) that will receive the messages. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.xmpp.html """ import logging From 91138b8679c99c4fb6ed923bfbacd2b578db5eba Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:16:26 +0200 Subject: [PATCH 060/226] Move configuration details to docs --- homeassistant/components/notify/syslog.py | 27 ++--------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/notify/syslog.py b/homeassistant/components/notify/syslog.py index 5d246f2fd0d..7881e68476d 100644 --- a/homeassistant/components/notify/syslog.py +++ b/homeassistant/components/notify/syslog.py @@ -3,31 +3,8 @@ homeassistant.components.notify.syslog ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Syslog notification service. -Configuration: - -To use the Syslog notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: syslog - facility: SYSLOG_FACILITY - option: SYSLOG_LOG_OPTION - priority: SYSLOG_PRIORITY - -Variables: - -facility -*Optional -Facility according to RFC 3164 (http://tools.ietf.org/html/rfc3164). Default -is 'syslog' if no value is given. - -option -*Option -Log option. Default is 'pid' if no value is given. - -priority -*Optional -Priority of the messages. Default is 'info' if no value is given. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.syslog.html """ import logging import syslog From 912ddbb4fc8e27062a548e14d94872adfe4bcd4f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:25:41 +0200 Subject: [PATCH 061/226] Add link to docs --- homeassistant/components/notify/file.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/file.py b/homeassistant/components/notify/file.py index 9c0beca14ac..f2fd66d4202 100644 --- a/homeassistant/components/notify/file.py +++ b/homeassistant/components/notify/file.py @@ -17,12 +17,14 @@ Variables: filename *Required -Name of the file to use. The file will be created if it doesn't exist and saved -in your config/ folder. + timestamp *Required Add a timestamp to the entry, valid entries are 1 or 0. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.file.html """ import logging import os From 405025a00b10bbba08e90fc4649c5e7d87983362 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:26:32 +0200 Subject: [PATCH 062/226] Remove configuration details --- homeassistant/components/notify/file.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/homeassistant/components/notify/file.py b/homeassistant/components/notify/file.py index f2fd66d4202..3fe6d555524 100644 --- a/homeassistant/components/notify/file.py +++ b/homeassistant/components/notify/file.py @@ -3,26 +3,6 @@ homeassistant.components.notify.file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ File notification service. -Configuration: - -To use the File notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: file - filename: FILENAME - timestamp: 1 or 0 - -Variables: - -filename -*Required - - -timestamp -*Required -Add a timestamp to the entry, valid entries are 1 or 0. - For more details about this platform, please refer to the documentation at https://home-assistant.io/components/notify.file.html """ From fd382871a15aee8f938956d09cbfec361a23af1a Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:30:21 +0200 Subject: [PATCH 063/226] Move configuration details to docs --- homeassistant/components/notify/pushbullet.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/notify/pushbullet.py b/homeassistant/components/notify/pushbullet.py index 76eaf5c0c37..49aaccd3004 100644 --- a/homeassistant/components/notify/pushbullet.py +++ b/homeassistant/components/notify/pushbullet.py @@ -3,21 +3,8 @@ homeassistant.components.notify.pushbullet ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PushBullet platform for notify component. -Configuration: - -To use the PushBullet notifier you will need to add something like the -following to your configuration.yaml file. - -notify: - platform: pushbullet - api_key: YOUR_API_KEY - -Variables: - -api_key -*Required -Enter the API key for PushBullet. Go to https://www.pushbullet.com/ to retrieve -your API key. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.pushbullet.html """ import logging From fb84c0ce6b7fd5440b2bb275908abc8969fc92ac Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:41:53 +0200 Subject: [PATCH 064/226] Move configuration details to docs --- homeassistant/components/notify/nma.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/notify/nma.py b/homeassistant/components/notify/nma.py index bf8fb2162a8..a9fa6559e71 100644 --- a/homeassistant/components/notify/nma.py +++ b/homeassistant/components/notify/nma.py @@ -3,23 +3,8 @@ homeassistant.components.notify.nma ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NMA (Notify My Android) notification service. -Configuration: - -To use the NMA notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: nma - api_key: YOUR_API_KEY - -Variables: - -api_key -*Required -Enter the API key for NMA. Go to https://www.notifymyandroid.com and create a -new API key to use with Home Assistant. - -Details for the API : https://www.notifymyandroid.com/api.jsp +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.nma.html """ import logging import xml.etree.ElementTree as ET From e353dae3a6744b037c3c64aed09e1ac646ea172e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:45:36 +0200 Subject: [PATCH 065/226] Move vonfiguration details to docs --- homeassistant/components/notify/slack.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/notify/slack.py b/homeassistant/components/notify/slack.py index bd3a2b71c0c..0b168ed5075 100644 --- a/homeassistant/components/notify/slack.py +++ b/homeassistant/components/notify/slack.py @@ -3,27 +3,8 @@ homeassistant.components.notify.slack ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Slack platform for notify component. -Configuration: - -To use the Slack notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: slack - api_key: ABCDEFGHJKLMNOPQRSTUVXYZ - default_channel: '#general' - -Variables: - -api_key -*Required -The slack API token to use for sending slack messages. -You can get your slack API token here https://api.slack.com/web?sudo=1 - -default_channel -*Required -The default channel to post to if no channel is explicitly specified when -sending the notification message. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.slack.html """ import logging From f019b4f6976c57eb7ab3359ec7b6da0aa9cdb748 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 22:56:12 +0200 Subject: [PATCH 066/226] Move configuration details to docs --- homeassistant/components/notify/smtp.py | 50 +------------------------ 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/homeassistant/components/notify/smtp.py b/homeassistant/components/notify/smtp.py index fbddd8d1d26..758e7839e50 100644 --- a/homeassistant/components/notify/smtp.py +++ b/homeassistant/components/notify/smtp.py @@ -3,54 +3,8 @@ homeassistant.components.notify.smtp ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mail (SMTP) notification service. -Configuration: - -To use the smtp notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: smtp - server: MAIL_SERVER - port: YOUR_SMTP_PORT - sender: SENDER_EMAIL_ADDRESS - starttls: 1 or 0 - username: YOUR_SMTP_USERNAME - password: YOUR_SMTP_PASSWORD - recipient: YOUR_RECIPIENT - -Variables: - -server -*Required -SMTP server which is used to end the notifications. For Google Mail, eg. -smtp.gmail.com. Keep in mind that Google has some extra layers of protection -which need special attention (Hint: 'Less secure apps'). - -port -*Required -The port that the SMTP server is using, eg. 587 for Google Mail and STARTTLS -or 465/993 depending on your SMTP servers. - -sender -*Required -E-Mail address of the sender. - -starttls -*Optional -Enables STARTTLS, eg. 1 or 0. - -username -*Required -Username for the SMTP account. - -password -*Required -Password for the SMTP server that belongs to the given username. If the -password contains a colon it need to be wrapped in apostrophes. - -recipient -*Required -Recipient of the notification. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.smtp.html """ import logging import smtplib From a44a39003db387823b8a01e77c65212d5bff9f7e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 23:07:26 +0200 Subject: [PATCH 067/226] Move configuration description to docs --- homeassistant/components/notify/pushover.py | 31 ++------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/homeassistant/components/notify/pushover.py b/homeassistant/components/notify/pushover.py index c52e430ac9f..e2b4b4c4b40 100644 --- a/homeassistant/components/notify/pushover.py +++ b/homeassistant/components/notify/pushover.py @@ -3,35 +3,8 @@ homeassistant.components.notify.pushover ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pushover platform for notify component. -Configuration: - -To use the Pushover notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: pushover - api_key: ABCDEFGHJKLMNOPQRSTUVXYZ - user_key: ABCDEFGHJKLMNOPQRSTUVXYZ - -Variables: - -api_key -*Required -This parameter is optional but should be configured, in order to get an API -key you should go to https://pushover.net and register a new application. - -This is a quote from the pushover website regarding free/open source apps: -"If you are creating a client-side library, application, or open source project -that will be redistributed and installed by end-users, you may want to require -each of your users to register their own application rather than including your -own API token with the software." - -When setting up the application I recommend using the icon located here: -https://home-assistant.io/images/favicon-192x192.png - -user_key -*Required -To retrieve this value log into your account at https://pushover.net +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.pushover.html """ import logging From 24e4b9e012b1b6aac86530b5286f79be740b4a62 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 23:08:56 +0200 Subject: [PATCH 068/226] Move configuration description to docs --- homeassistant/components/notify/instapush.py | 48 +------------------- 1 file changed, 2 insertions(+), 46 deletions(-) diff --git a/homeassistant/components/notify/instapush.py b/homeassistant/components/notify/instapush.py index 95ff0d41435..839eac24a0d 100644 --- a/homeassistant/components/notify/instapush.py +++ b/homeassistant/components/notify/instapush.py @@ -3,52 +3,8 @@ homeassistant.components.notify.instapush ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Instapush notification service. -Configuration: - -To use the Instapush notifier you will need to add something like the following -to your configuration.yaml file. - -notify: - platform: instapush - api_key: YOUR_APP_KEY - app_secret: YOUR_APP_SECRET - event: YOUR_EVENT - tracker: YOUR_TRACKER - -Variables: - -api_key -*Required -To retrieve this value log into your account at https://instapush.im and go -to 'APPS', choose an app, and check 'Basic Info'. - -app_secret -*Required -To get this value log into your account at https://instapush.im and go to -'APPS'. The 'Application ID' can be found under 'Basic Info'. - -event -*Required -To retrieve a valid event log into your account at https://instapush.im and go -to 'APPS'. If you have no events to use with Home Assistant, create one event -for your app. - -tracker -*Required -To retrieve the tracker value log into your account at https://instapush.im and -go to 'APPS', choose the app, and check the event entries. - -Example usage of Instapush if you have an event 'notification' and a tracker -'home-assistant'. - -curl -X POST \ - -H "x-instapush-appid: YOUR_APP_KEY" \ - -H "x-instapush-appsecret: YOUR_APP_SECRET" \ - -H "Content-Type: application/json" \ - -d '{"event":"notification","trackers":{"home-assistant":"Switch 1"}}' \ - https://api.instapush.im/v1/post - -Details for the API : https://instapush.im/developer/rest +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.instapush.html """ import logging import json From 64a78d7b4f528bade42457f428bfb79029cae5e8 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 23:41:46 +0200 Subject: [PATCH 069/226] Upgrade psutil to 3.2.2 --- homeassistant/components/sensor/systemmonitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 82f62da10e0..f585cfa18bd 100644 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -64,7 +64,7 @@ import homeassistant.util.dt as dt_util from homeassistant.helpers.entity import Entity from homeassistant.const import STATE_ON, STATE_OFF -REQUIREMENTS = ['psutil==3.0.0'] +REQUIREMENTS = ['psutil==3.2.2'] SENSOR_TYPES = { 'disk_use_percent': ['Disk Use', '%'], 'disk_use': ['Disk Use', 'GiB'], From fe032be35201a03a447fc264d1abbbb5c130ce4f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 23:42:27 +0200 Subject: [PATCH 070/226] Upgrade psutil to 3.2.2 --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index 12797da4e5a..57f117ec3cd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -41,7 +41,7 @@ pydispatcher==2.0.5 PyISY==1.0.5 # PSutil (sensor.systemmonitor) -psutil==3.0.0 +psutil==3.2.2 # Pushover (notify.pushover) python-pushover==0.2 From 0e89418cbeaed079379d0602c4cdca079320b250 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 23:44:27 +0200 Subject: [PATCH 071/226] Move configuration desciption to docs --- .../components/sensor/systemmonitor.py | 56 +------------------ 1 file changed, 2 insertions(+), 54 deletions(-) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index f585cfa18bd..1fee6a6328c 100644 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -3,60 +3,8 @@ homeassistant.components.sensor.systemmonitor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Shows system monitor values such as: disk, memory, and processor use. -Configuration: - -To use the System monitor sensor you will need to add something like the -following to your configuration.yaml file. - -sensor: - platform: systemmonitor - resources: - - type: 'disk_use_percent' - arg: '/' - - type: 'disk_use' - arg: '/home' - - type: 'disk_free' - arg: '/' - - type: 'memory_use_percent' - - type: 'memory_use' - - type: 'memory_free' - - type: 'swap_use_percent' - - type: 'swap_use' - - type: 'swap_free' - - type: 'network_in' - arg: 'eth0' - - type: 'network_out' - arg: 'eth0' - - type: 'packets_in' - arg: 'eth0' - - type: 'packets_out' - arg: 'eth0' - - type: 'ipv4_address' - arg: 'eth0' - - type: 'ipv6_address' - arg: 'eth0' - - type: 'processor_use' - - type: 'process' - arg: 'octave-cli' - - type: 'last_boot' - - type: 'since_last_boot' - -Variables: - -resources -*Required -An array specifying the variables to monitor. - -These are the variables for the resources array: - -type -*Required -The variable you wish to monitor, see the configuration example above for a -sample list of variables. - -arg -*Optional -Additional details for the type, eg. path, binary name, etc. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.systemmonitor.html """ import logging From 32bb950b5f4e0cac647353c2b4a7940f908fc73f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Oct 2015 22:36:21 -0700 Subject: [PATCH 072/226] Add tests for manual alarm control panel platform --- .../components/alarm_control_panel/manual.py | 99 ++++--- tests/__init__.py | 2 - .../alarm_control_panel/test_manual.py | 258 ++++++++++++++++++ 3 files changed, 305 insertions(+), 54 deletions(-) create mode 100644 tests/components/alarm_control_panel/test_manual.py diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index 2aee8b89e17..63370de352c 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -46,11 +46,10 @@ class ManualAlarm(alarm.AlarmControlPanel): self._state = STATE_ALARM_DISARMED self._hass = hass self._name = name - self._code = code + self._code = str(code) if code else None self._pending_time = datetime.timedelta(seconds=pending_time) self._trigger_time = datetime.timedelta(seconds=trigger_time) self._state_ts = None - self._pending_to = None @property def should_poll(self): @@ -65,6 +64,15 @@ class ManualAlarm(alarm.AlarmControlPanel): @property def state(self): """ Returns the state of the device. """ + if self._state in (STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY) and \ + self._pending_time and self._state_ts + self._pending_time > \ + dt_util.utcnow(): + return STATE_ALARM_PENDING + + if self._state == STATE_ALARM_TRIGGERED and self._trigger_time and \ + self._state_ts + self._trigger_time > dt_util.utcnow(): + return STATE_ALARM_PENDING + return self._state @property @@ -72,70 +80,57 @@ class ManualAlarm(alarm.AlarmControlPanel): """ One or more characters. """ return None if self._code is None else '.+' - def update_state(self, state, pending_to): - """ Changes between state with delay. """ - self._state = state - self._state_ts = dt_util.utcnow() - self._pending_to = pending_to - self.update_ha_state() - def alarm_disarm(self, code=None): """ Send disarm command. """ - if code == str(self._code) or self.code_format is None: - self.update_state(STATE_ALARM_DISARMED, None) - else: - _LOGGER.warning("Wrong code entered while disarming!") + if not self._validate_code(code, STATE_ALARM_DISARMED): + return + + self._state = STATE_ALARM_DISARMED + self._state_ts = dt_util.utcnow() + self.update_ha_state() def alarm_arm_home(self, code=None): """ Send arm home command. """ - if code == str(self._code) or self.code_format is None: - self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_HOME) + if not self._validate_code(code, STATE_ALARM_ARMED_HOME): + return - def delayed_alarm_arm_home(event_time): - """ Callback for delayed action. """ - if self._pending_to == STATE_ALARM_ARMED_HOME and \ - dt_util.utcnow() - self._state_ts >= self._pending_time: - self.update_state(STATE_ALARM_ARMED_HOME, None) + self._state = STATE_ALARM_ARMED_HOME + self._state_ts = dt_util.utcnow() + self.update_ha_state() + + if self._pending_time: track_point_in_time( - self._hass, delayed_alarm_arm_home, - dt_util.utcnow() + self._pending_time) - else: - _LOGGER.warning("Wrong code entered while arming home!") + self._hass, self.update_ha_state, + self._state_ts + self._pending_time) def alarm_arm_away(self, code=None): """ Send arm away command. """ - if code == str(self._code) or self.code_format is None: - self.update_state(STATE_ALARM_PENDING, STATE_ALARM_ARMED_AWAY) + if not self._validate_code(code, STATE_ALARM_ARMED_AWAY): + return - def delayed_alarm_arm_away(event_time): - """ Callback for delayed action. """ - if self._pending_to == STATE_ALARM_ARMED_AWAY and \ - dt_util.utcnow() - self._state_ts >= self._pending_time: - self.update_state(STATE_ALARM_ARMED_AWAY, None) + self._state = STATE_ALARM_ARMED_AWAY + self._state_ts = dt_util.utcnow() + self.update_ha_state() + + if self._pending_time: track_point_in_time( - self._hass, delayed_alarm_arm_away, - dt_util.utcnow() + self._pending_time) - else: - _LOGGER.warning("Wrong code entered while arming away!") + self._hass, self.update_ha_state, + self._state_ts + self._pending_time) def alarm_trigger(self, code=None): """ Send alarm trigger command. No code needed. """ - self.update_state(STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) + self._state = STATE_ALARM_TRIGGERED + self._state_ts = dt_util.utcnow() + self.update_ha_state() - def delayed_alarm_trigger(event_time): - """ callback for delayed action """ - if self._pending_to == STATE_ALARM_TRIGGERED and \ - dt_util.utcnow() - self._state_ts >= self._pending_time: - self.update_state(STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED) + if self._trigger_time: + track_point_in_time( + self._hass, self.update_ha_state, + self._state_ts + self._trigger_time) - def delayed_alarm_disarm(event_time): - """ Callback for delayed action. """ - if self._pending_to == STATE_ALARM_DISARMED and \ - dt_util.utcnow() - self._state_ts >= self._trigger_time: - self.update_state(STATE_ALARM_DISARMED, None) - track_point_in_time( - self._hass, delayed_alarm_disarm, - dt_util.utcnow() + self._trigger_time) - track_point_in_time( - self._hass, delayed_alarm_trigger, - dt_util.utcnow() + self._pending_time) + def _validate_code(self, code, state): + """ Validate given code. """ + check = self._code is None or code == self._code + if not check: + _LOGGER.warning('Invalid code given for %s', state) + return check diff --git a/tests/__init__.py b/tests/__init__.py index c39a22e0b57..e69de29bb2d 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,2 +0,0 @@ -import logging -logging.disable(logging.CRITICAL) diff --git a/tests/components/alarm_control_panel/test_manual.py b/tests/components/alarm_control_panel/test_manual.py new file mode 100644 index 00000000000..69514babb35 --- /dev/null +++ b/tests/components/alarm_control_panel/test_manual.py @@ -0,0 +1,258 @@ +""" +tests.components.alarm_control_panel.test_manual +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests manual alarm control panel component. +""" +from datetime import timedelta +import unittest +from unittest.mock import patch + +import homeassistant.core as ha +from homeassistant.const import ( + STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) +from homeassistant.components import alarm_control_panel +import homeassistant.util.dt as dt_util + +from tests.common import fire_time_changed + +CODE = 'HELLO_CODE' + + +class TestAlarmControlPanelManual(unittest.TestCase): + """ Test the demo module. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = ha.HomeAssistant() + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_arm_home_no_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 0 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_HOME, + self.hass.states.get(entity_id).state) + + def test_arm_home_with_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE, entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_HOME, + self.hass.states.get(entity_id).state) + + def test_arm_home_with_invalid_code(self): + """ Attempt to arm home without a valid code. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE + '2') + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_arm_away_no_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 0 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE, entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_AWAY, + self.hass.states.get(entity_id).state) + + def test_arm_away_with_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_AWAY, + self.hass.states.get(entity_id).state) + + def test_arm_away_with_invalid_code(self): + """ Attempt to arm away without a valid code. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'code': CODE, + 'pending_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE + '2') + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_trigger_no_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'trigger_time': 0 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + def test_trigger_with_pending(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'trigger_time': 1 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + def test_disarm_while_pending_trigger(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'trigger_time': 5 + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_disarm(self.hass, entity_id=entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=5) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) From d37b70556d23ddc5a00afc484078ff042ffdcaad Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Oct 2015 22:41:35 -0700 Subject: [PATCH 073/226] manual alarm: Test disarm with invalid code --- .../alarm_control_panel/test_manual.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/components/alarm_control_panel/test_manual.py b/tests/components/alarm_control_panel/test_manual.py index 69514babb35..2b5e2d9f337 100644 --- a/tests/components/alarm_control_panel/test_manual.py +++ b/tests/components/alarm_control_panel/test_manual.py @@ -256,3 +256,38 @@ class TestAlarmControlPanelManual(unittest.TestCase): self.assertEqual(STATE_ALARM_DISARMED, self.hass.states.get(entity_id).state) + + def test_disarm_during_trigger_with_invalid_code(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'manual', + 'name': 'test', + 'trigger_time': 5, + 'code': CODE + '2' + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_disarm(self.hass, entity_id=entity_id) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=5) + with patch(('homeassistant.components.alarm_control_panel.manual.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.pool.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) From 716376081ddcc386367a64f0f6b9dde8e3aff0ed Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Oct 2015 23:08:12 -0700 Subject: [PATCH 074/226] Add tests for MQTT alarm --- .../components/alarm_control_panel/mqtt.py | 45 +++-- tests/common.py | 6 +- .../alarm_control_panel/test_manual.py | 2 +- .../alarm_control_panel/test_mqtt.py | 178 ++++++++++++++++++ 4 files changed, 209 insertions(+), 22 deletions(-) create mode 100644 tests/components/alarm_control_panel/test_mqtt.py diff --git a/homeassistant/components/alarm_control_panel/mqtt.py b/homeassistant/components/alarm_control_panel/mqtt.py index 3b2f745693d..e070babd080 100644 --- a/homeassistant/components/alarm_control_panel/mqtt.py +++ b/homeassistant/components/alarm_control_panel/mqtt.py @@ -10,7 +10,9 @@ import logging import homeassistant.components.mqtt as mqtt import homeassistant.components.alarm_control_panel as alarm -from homeassistant.const import (STATE_UNKNOWN) +from homeassistant.const import ( + STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN) _LOGGER = logging.getLogger(__name__) @@ -62,10 +64,15 @@ class MqttAlarm(alarm.AlarmControlPanel): self._payload_disarm = payload_disarm self._payload_arm_home = payload_arm_home self._payload_arm_away = payload_arm_away - self._code = code + self._code = str(code) if code else None def message_received(topic, payload, qos): """ A new MQTT message has been received. """ + if payload not in (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_AWAY, STATE_ALARM_PENDING, + STATE_ALARM_TRIGGERED): + _LOGGER.warning('Received unexpected payload: %s', payload) + return self._state = payload self.update_ha_state() @@ -93,24 +100,28 @@ class MqttAlarm(alarm.AlarmControlPanel): def alarm_disarm(self, code=None): """ Send disarm command. """ - if code == str(self._code) or self.code_format is None: - mqtt.publish(self.hass, self._command_topic, - self._payload_disarm, self._qos) - else: - _LOGGER.warning("Wrong code entered while disarming!") + if not self._validate_code(code, 'disarming'): + return + mqtt.publish(self.hass, self._command_topic, + self._payload_disarm, self._qos) def alarm_arm_home(self, code=None): """ Send arm home command. """ - if code == str(self._code) or self.code_format is None: - mqtt.publish(self.hass, self._command_topic, - self._payload_arm_home, self._qos) - else: - _LOGGER.warning("Wrong code entered while arming home!") + if not self._validate_code(code, 'arming home'): + return + mqtt.publish(self.hass, self._command_topic, + self._payload_arm_home, self._qos) def alarm_arm_away(self, code=None): """ Send arm away command. """ - if code == str(self._code) or self.code_format is None: - mqtt.publish(self.hass, self._command_topic, - self._payload_arm_away, self._qos) - else: - _LOGGER.warning("Wrong code entered while arming away!") + if not self._validate_code(code, 'arming away'): + return + mqtt.publish(self.hass, self._command_topic, + self._payload_arm_away, self._qos) + + def _validate_code(self, code, state): + """ Validate given code. """ + check = self._code is None or code == self._code + if not check: + _LOGGER.warning('Wrong code entered for %s', state) + return check diff --git a/tests/common.py b/tests/common.py index 9263cae04e3..b8108c673fd 100644 --- a/tests/common.py +++ b/tests/common.py @@ -125,16 +125,14 @@ def mock_http_component(hass): @mock.patch('homeassistant.components.mqtt.MQTT') -@mock.patch('homeassistant.components.mqtt.MQTT.publish') -def mock_mqtt_component(hass, mock_mqtt, mock_mqtt_publish): +def mock_mqtt_component(hass, mock_mqtt): mqtt.setup(hass, { mqtt.DOMAIN: { mqtt.CONF_BROKER: 'mock-broker', } }) hass.config.components.append(mqtt.DOMAIN) - - return mock_mqtt_publish + return mock_mqtt class MockHTTP(object): diff --git a/tests/components/alarm_control_panel/test_manual.py b/tests/components/alarm_control_panel/test_manual.py index 2b5e2d9f337..d823bfe6ccc 100644 --- a/tests/components/alarm_control_panel/test_manual.py +++ b/tests/components/alarm_control_panel/test_manual.py @@ -21,7 +21,7 @@ CODE = 'HELLO_CODE' class TestAlarmControlPanelManual(unittest.TestCase): - """ Test the demo module. """ + """ Test the manual alarm module. """ def setUp(self): # pylint: disable=invalid-name self.hass = ha.HomeAssistant() diff --git a/tests/components/alarm_control_panel/test_mqtt.py b/tests/components/alarm_control_panel/test_mqtt.py new file mode 100644 index 00000000000..6cba26c15a6 --- /dev/null +++ b/tests/components/alarm_control_panel/test_mqtt.py @@ -0,0 +1,178 @@ +""" +tests.components.alarm_control_panel.test_manual +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests manual alarm control panel component. +""" +import unittest +from unittest.mock import patch + +import homeassistant.core as ha +from homeassistant.const import ( + STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN) +from homeassistant.components import alarm_control_panel + +from tests.common import mock_mqtt_component, fire_mqtt_message + +CODE = 'HELLO_CODE' + + +class TestAlarmControlPanelMQTT(unittest.TestCase): + """ Test the manual alarm module. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = ha.HomeAssistant() + self.mock_publish = mock_mqtt_component(self.hass) + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + @patch('homeassistant.components.alarm_control_panel.mqtt._LOGGER.error') + def test_fail_setup_without_state_topic(self, mock_error): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'command_topic': 'alarm/command' + }})) + + self.assertEqual(1, mock_error.call_count) + + @patch('homeassistant.components.alarm_control_panel.mqtt._LOGGER.error') + def test_fail_setup_without_command_topic(self, mock_error): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'state_topic': 'alarm/state' + }})) + + self.assertEqual(1, mock_error.call_count) + + def test_update_state_via_state_topic(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_UNKNOWN, + self.hass.states.get(entity_id).state) + + for state in (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_AWAY, STATE_ALARM_PENDING, + STATE_ALARM_TRIGGERED): + fire_mqtt_message(self.hass, 'alarm/state', state) + self.hass.pool.block_till_done() + self.assertEqual(state, self.hass.states.get(entity_id).state) + + def test_ignore_update_state_if_unknown_via_state_topic(self): + """ Test arm home method. """ + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_UNKNOWN, + self.hass.states.get(entity_id).state) + + fire_mqtt_message(self.hass, 'alarm/state', 'unsupported state') + self.hass.pool.block_till_done() + self.assertEqual(STATE_UNKNOWN, self.hass.states.get(entity_id).state) + + def test_arm_home_publishes_mqtt(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + }})) + + alarm_control_panel.alarm_arm_home(self.hass) + self.hass.pool.block_till_done() + self.assertEqual(('alarm/command', 'ARM_HOME', 0), + self.mock_publish.mock_calls[-1][1]) + + def test_arm_home_not_publishes_mqtt_with_invalid_code(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + 'code': '1234' + }})) + + call_count = self.mock_publish.call_count + alarm_control_panel.alarm_arm_home(self.hass, 'abcd') + self.hass.pool.block_till_done() + self.assertEqual(call_count, self.mock_publish.call_count) + + def test_arm_away_publishes_mqtt(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + }})) + + alarm_control_panel.alarm_arm_away(self.hass) + self.hass.pool.block_till_done() + self.assertEqual(('alarm/command', 'ARM_AWAY', 0), + self.mock_publish.mock_calls[-1][1]) + + def test_arm_away_not_publishes_mqtt_with_invalid_code(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + 'code': '1234' + }})) + + call_count = self.mock_publish.call_count + alarm_control_panel.alarm_arm_away(self.hass, 'abcd') + self.hass.pool.block_till_done() + self.assertEqual(call_count, self.mock_publish.call_count) + + def test_disarm_publishes_mqtt(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + }})) + + alarm_control_panel.alarm_disarm(self.hass) + self.hass.pool.block_till_done() + self.assertEqual(('alarm/command', 'DISARM', 0), + self.mock_publish.mock_calls[-1][1]) + + def test_disarm_not_publishes_mqtt_with_invalid_code(self): + self.assertTrue(alarm_control_panel.setup(self.hass, { + 'alarm_control_panel': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + 'code': '1234' + }})) + + call_count = self.mock_publish.call_count + alarm_control_panel.alarm_disarm(self.hass, 'abcd') + self.hass.pool.block_till_done() + self.assertEqual(call_count, self.mock_publish.call_count) From 49de153ecf40c2da03a9b9dc8c86c6342b55a841 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Oct 2015 23:21:47 -0700 Subject: [PATCH 075/226] Add alarm component to demo component --- homeassistant/components/demo.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index f22135ec5bc..388a869ae0c 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -63,6 +63,14 @@ def setup(hass, config): 'still_image_url': 'http://home-assistant.io/demo/webcam.jpg', }}) + # Setup alarm_control_panel + bootstrap.setup_component( + hass, 'alarm_control_panel', + {'alarm_control_panel': { + 'platform': 'manual', + 'name': 'Test Alarm', + }}) + # Setup scripts bootstrap.setup_component( hass, 'script', From 7da354c4c5931de8ccf10372ce3ade9c1fbb1586 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 13 Oct 2015 23:49:28 +0200 Subject: [PATCH 076/226] Move configuration details to docs --- homeassistant/components/sensor/bitcoin.py | 61 +--------------------- 1 file changed, 2 insertions(+), 59 deletions(-) diff --git a/homeassistant/components/sensor/bitcoin.py b/homeassistant/components/sensor/bitcoin.py index 60a8a9172b7..803b9dbb9d4 100644 --- a/homeassistant/components/sensor/bitcoin.py +++ b/homeassistant/components/sensor/bitcoin.py @@ -3,65 +3,8 @@ homeassistant.components.sensor.bitcoin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Bitcoin information service that uses blockchain.info and its online wallet. -Configuration: - -You need to enable the API access for your online wallet to get the balance. -To do that log in and move to 'Account Setting', choose 'IP Restrictions', and -check 'Enable Api Access'. You will get an email message from blockchain.info -where you must authorize the API access. - -To use the Bitcoin sensor you will need to add something like the following -to your configuration.yaml file. - -sensor: - platform: bitcoin - wallet: 'YOUR WALLET_ID' - password: YOUR_ACCOUNT_PASSWORD - currency: YOUR CURRENCY - display_options: - - exchangerate - - trade_volume_btc - - miners_revenue_usd - - btc_mined - - trade_volume_usd - - difficulty - - minutes_between_blocks - - number_of_transactions - - hash_rate - - timestamp - - mined_blocks - - blocks_size - - total_fees_btc - - total_btc_sent - - estimated_btc_sent - - total_btc - - total_blocks - - next_retarget - - estimated_transaction_volume_usd - - miners_revenue_btc - - market_price_usd - -Variables: - -wallet -*Optional -This is your wallet identifier from https://blockchain.info to access the -online wallet. - -password -*Optional -Password your your online wallet. - -currency -*Optional -The currency to exchange to, eg. CHF, USD, EUR,etc. Default is USD. - -display_options -*Optional -An array specifying the variables to display. - -These are the variables for the display_options array. See the configuration -example above for a list of all available variables. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.bitcoin.html """ import logging from datetime import timedelta From 6064fffc8e6bca0190a3c97768eaa4f6f98fc060 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 14 Oct 2015 08:35:47 +0200 Subject: [PATCH 077/226] Move configuration details to docs --- homeassistant/components/sensor/sabnzbd.py | 43 ++-------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/homeassistant/components/sensor/sabnzbd.py b/homeassistant/components/sensor/sabnzbd.py index b372e777478..7aeb14b27f5 100644 --- a/homeassistant/components/sensor/sabnzbd.py +++ b/homeassistant/components/sensor/sabnzbd.py @@ -1,47 +1,10 @@ """ homeassistant.components.sensor.sabnzbd ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Monitors SABnzbd NZB client API +Monitors SABnzbd NZB client API. -Configuration: - -To use the SABnzbd sensor you will need to add something like the following to -your configuration.yaml file. - -sensor: - platform: sabnzbd - name: SAB - api_key: YOUR_API_KEY - base_url: YOUR_SABNZBD_BASE_URL - monitored_variables: - - type: 'current_status' - - type: 'speed' - - type: 'queue_size' - - type: 'queue_remaining' - - type: 'disk_size' - - type: 'disk_free' - -Variables: - -base_url -*Required -This is the base URL of your SABnzbd instance including the port number if not -running on 80, e.g. http://192.168.1.32:8124/ - -name -*Optional -The name to use when displaying this SABnzbd instance. - -monitored_variables -*Required -An array specifying the variables to monitor. - -These are the variables for the monitored_variables array: - -type -*Required -The variable you wish to monitor, see the configuration example above for a -list of all available variables. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/light.sabnzbd.html """ from homeassistant.util import Throttle from datetime import timedelta From 80e4f2f51fa42b07483e5dc7d3671fe91a507c7c Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 14 Oct 2015 08:45:29 +0200 Subject: [PATCH 078/226] Add link to doc --- homeassistant/components/simple_alarm.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/simple_alarm.py b/homeassistant/components/simple_alarm.py index 46cb52fa950..9eb9e542cf4 100644 --- a/homeassistant/components/simple_alarm.py +++ b/homeassistant/components/simple_alarm.py @@ -1,10 +1,10 @@ """ homeassistant.components.simple_alarm ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Intruder alerts component. -Provides a simple alarm feature: - - flash a light when a known device comes home - - flash a light red if a light turns on while there is no one home. +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/simple_alarm.html """ import logging @@ -17,7 +17,7 @@ DOMAIN = "simple_alarm" DEPENDENCIES = ['group', 'device_tracker', 'light'] # Attribute to tell which light has to flash whem a known person comes home -# If ommitted will flash all. +# If omitted will flash all. CONF_KNOWN_LIGHT = "known_light" # Attribute to tell which light has to flash whem an unknown person comes home From 8d99c4a0cc756c2a3ba1f4f1b620708741aed0a6 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 14 Oct 2015 10:38:08 +0200 Subject: [PATCH 079/226] Move configuration details to docs --- homeassistant/components/sun.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py index ce4dbd1e937..7765f1b7276 100644 --- a/homeassistant/components/sun.py +++ b/homeassistant/components/sun.py @@ -1,23 +1,10 @@ """ homeassistant.components.sun ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Provides functionality to keep track of the sun. -Event listener --------------- -The suns event listener will call the service when the sun rises or sets with -an offset. - -The sun event need to have the type 'sun', which service to call, which event -(sunset or sunrise) and the offset. - -{ - "type": "sun", - "service": "switch.turn_on", - "event": "sunset", - "offset": "-01:00:00" -} +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/sun.html """ import logging from datetime import timedelta From b2e39884f90ccfbe965ddece44d04c4457916633 Mon Sep 17 00:00:00 2001 From: Todd Ingarfield Date: Wed, 14 Oct 2015 11:02:07 -0500 Subject: [PATCH 080/226] Removed name and netdisco functions, implemented update method to caches values, radiotherm lib to coveragerc and requirements_all.txt --- .coveragerc | 1 + .../components/thermostat/radiotherm.py | 69 ++++++++----------- requirements_all.txt | 3 + 3 files changed, 33 insertions(+), 40 deletions(-) diff --git a/.coveragerc b/.coveragerc index 1ff145e2de3..e44a905a0ab 100644 --- a/.coveragerc +++ b/.coveragerc @@ -88,6 +88,7 @@ omit = homeassistant/components/switch/transmission.py homeassistant/components/switch/wemo.py homeassistant/components/thermostat/nest.py + homeassistant/components/thermostat/radiotherm.py [report] diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index e11f845b0b4..3acd3ef8986 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -9,33 +9,23 @@ from urllib.error import URLError from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) -from homeassistant.const import (CONF_HOST, CONF_NAME, TEMP_FAHRENHEIT) +from homeassistant.const import (CONF_HOST, TEMP_FAHRENHEIT) REQUIREMENTS = ['radiotherm==1.2'] def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the Radio Thermostat. """ + import radiotherm + logger = logging.getLogger(__name__) - try: - import radiotherm - except ImportError: - logger.exception( - "Error while importing dependency radiotherm. " - "Did you maybe not install the radiotherm dependency?") - return - - # Detect hosts with hass discovery, config or radiotherm discovery hosts = [] - if discovery_info: - logger.info('hass radiotherm discovery', discovery_info) - elif CONF_HOST in config: + if CONF_HOST in config: hosts = [config[CONF_HOST]] else: hosts.append(radiotherm.discover.discover_address()) - name = config.get(CONF_NAME) if hosts is None: logger.error("no radiotherm thermostats detected") return @@ -48,7 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): tstats.append(RadioThermostat(tstat)) except (URLError, OSError): logger.exception( - "Unable to connect to Radio Thermostat @{}".format(host)) + "Unable to connect to Radio Thermostat: %s", host) add_devices(tstats) @@ -56,16 +46,19 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class RadioThermostat(ThermostatDevice): """ Represent a Radio Thermostat. """ - def __init__(self, device, name=None): + def __init__(self, device): self.device = device - if name: - self.set_name(name) self.set_time() + self._target_temperature = None + self._current_temperature = None + self._operation = STATE_IDLE + self._name = None + self.update() @property def name(self): """ Returns the name of the Radio Thermostat. """ - return self.device.name['raw'] + return self._name @property def unit_of_measurement(self): @@ -75,10 +68,7 @@ class RadioThermostat(ThermostatDevice): @property def device_state_attributes(self): """ Returns device specific state attributes. """ - # Move these to Thermostat Device and make them global return { - "humidity": None, - "target_humidity": None, "fan": self.device.fmode['human'], "mode": self.device.tmode['human'] } @@ -86,39 +76,38 @@ class RadioThermostat(ThermostatDevice): @property def current_temperature(self): """ Returns the current temperature. """ - return self.device.temp['raw'] + return round(self._current_temperature, 1) @property def operation(self): """ Returns current operation. head, cool idle """ - if self.device.tmode['human'] == 'Cool': - return STATE_COOL - elif self.device.tmode['human'] == 'Heat': - return STATE_HEAT - else: - return STATE_IDLE + return self._operation @property def target_temperature(self): """ Returns the temperature we try to reach. """ - if self.operation == STATE_COOL: - temp = self.device.t_cool['raw'] - elif self.operation == STATE_HEAT: - temp = self.device.t_heat['raw'] + return round(self._target_temperature, 1) - return round(temp, 1) + def update(self): + self._current_temperature = self.device.temp['raw'] + self._name = self.device.name['raw'] + if self.device.tmode['human'] == 'Cool': + self._target_temperature = self.device.t_cool['raw'] + self._operation = STATE_COOL + elif self.device.tmode['human'] == 'Heat': + self._target_temperature = self.device.t_heat['raw'] + self._operation = STATE_HEAT + else: + self._operation = STATE_IDLE def set_temperature(self, temperature): """ Set new target temperature """ - if self.operation == STATE_COOL: + if self._operation == STATE_COOL: self.device.t_cool = temperature - elif self.operation == STATE_HEAT: + elif self._operation == STATE_HEAT: self.device.t_heat = temperature - - def set_name(self, name): - """ Set thermostat name """ - self.device.name = name + self.device.hold = 1 def set_time(self): """ Set device time """ diff --git a/requirements_all.txt b/requirements_all.txt index 2b7074d91cd..668cedf65b2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -137,3 +137,6 @@ SoCo==0.11.1 # PlexAPI (media_player.plex) https://github.com/adrienbrault/python-plexapi/archive/df2d0847e801d6d5cda920326d693cf75f304f1a.zip#python-plexapi==1.0.2 + +# Radio Thermostat (thermostat.radiotherm) +radiotherm=1.2 From 347597ebdc20707451d3469b20ffc0307032c482 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 14 Oct 2015 23:09:52 -0700 Subject: [PATCH 081/226] Base Script on entity --- homeassistant/components/script.py | 240 +++++++++++++++++------------ tests/components/test_script.py | 217 ++++++++++++++++++++++++++ 2 files changed, 359 insertions(+), 98 deletions(-) create mode 100644 tests/components/test_script.py diff --git a/homeassistant/components/script.py b/homeassistant/components/script.py index c4f70b6d6d3..c5b1d4872de 100644 --- a/homeassistant/components/script.py +++ b/homeassistant/components/script.py @@ -8,154 +8,198 @@ by the user or automatically based upon automation events, etc. import logging from datetime import timedelta import homeassistant.util.dt as date_util +from itertools import islice import threading -from homeassistant.helpers.event import track_point_in_time +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.entity import ToggleEntity +from homeassistant.helpers.event import track_point_in_utc_time from homeassistant.util import split_entity_id from homeassistant.const import ( - STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF, EVENT_TIME_CHANGED) + ATTR_ENTITY_ID, EVENT_TIME_CHANGED, STATE_ON, SERVICE_TURN_ON, + SERVICE_TURN_OFF) DOMAIN = "script" +ENTITY_ID_FORMAT = DOMAIN + '.{}' DEPENDENCIES = ["group"] +STATE_NOT_RUNNING = 'Not Running' + CONF_ALIAS = "alias" -CONF_SERVICE = "execute_service" +CONF_SERVICE = "service" +CONF_SERVICE_OLD = "execute_service" CONF_SERVICE_DATA = "service_data" CONF_SEQUENCE = "sequence" CONF_EVENT = "event" CONF_EVENT_DATA = "event_data" CONF_DELAY = "delay" -ATTR_ENTITY_ID = "entity_id" + +ATTR_LAST_ACTION = 'last_action' _LOGGER = logging.getLogger(__name__) +def is_on(hass, entity_id): + """ Returns if the switch is on based on the statemachine. """ + return hass.states.is_state(entity_id, STATE_ON) + + +def turn_on(hass, entity_id): + """ Turn script on. """ + _, object_id = split_entity_id(entity_id) + + hass.services.call(DOMAIN, object_id) + + +def turn_off(hass, entity_id): + """ Turn script on. """ + hass.services.call(DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}) + + def setup(hass, config): """ Load the scripts from the configuration. """ - scripts = [] + component = EntityComponent(_LOGGER, DOMAIN, hass) + + def service_handler(service): + """ Execute a service call to script. - - - - - \ No newline at end of file + } \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 055403f9d38..ac34b5fc269 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 055403f9d3892118243c8a64a341bce5b74ce8aa +Subproject commit ac34b5fc26928238343f34f334a6f6f1a19d5442 From f1aa685cf2b1c33ea79aa5289c7f7b30c9f92494 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 25 Oct 2015 21:00:22 -0700 Subject: [PATCH 216/226] Add version to config API --- homeassistant/core.py | 3 ++- tests/test_core.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/core.py b/homeassistant/core.py index b834efce406..fc1ff2e8cbe 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -17,7 +17,7 @@ import functools as ft from collections import namedtuple from homeassistant.const import ( - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, + __version__, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_STOP, EVENT_TIME_CHANGED, EVENT_STATE_CHANGED, EVENT_CALL_SERVICE, ATTR_NOW, ATTR_DOMAIN, ATTR_SERVICE, MATCH_ALL, EVENT_SERVICE_EXECUTED, ATTR_SERVICE_CALL_ID, EVENT_SERVICE_REGISTERED, @@ -741,6 +741,7 @@ class Config(object): 'location_name': self.location_name, 'time_zone': time_zone.zone, 'components': self.components, + 'version': __version__ } diff --git a/tests/test_core.py b/tests/test_core.py index 01ede9e138e..bb59aac03fa 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -21,7 +21,7 @@ from homeassistant.exceptions import ( import homeassistant.util.dt as dt_util from homeassistant.helpers.event import track_state_change from homeassistant.const import ( - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, + __version__, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, ATTR_FRIENDLY_NAME, TEMP_CELCIUS, TEMP_FAHRENHEIT) @@ -555,6 +555,7 @@ class TestConfig(unittest.TestCase): 'location_name': None, 'time_zone': 'UTC', 'components': [], + 'version': __version__, } self.assertEqual(expected, self.config.as_dict()) From 06c8c1b168d7c7a494de6ff3054e5d0fd65da87f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 25 Oct 2015 23:11:50 -0700 Subject: [PATCH 217/226] Update to latest version frontend --- homeassistant/components/frontend/version.py | 2 +- .../components/frontend/www_static/frontend.html | 16 ++++++++-------- .../frontend/www_static/home-assistant-polymer | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 758c92dc3e9..1c753d1638e 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -1,2 +1,2 @@ """ DO NOT MODIFY. Auto-generated by build_frontend script """ -VERSION = "231652c54795bcc542269ff03ec2e9b2" +VERSION = "beb922c55bb26ea576581b453f6d7c04" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index f17de5a2781..7343bd3afd0 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -5993,12 +5993,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN font-weight: 300; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; - } \ No newline at end of file +console.group&&(console.groupCollapsed("Dispatch: %s",t),console.group("payload"),console.debug(e),console.groupEnd())},e.dispatchError=function(t){console.group&&(console.debug("Dispatch error: "+t),console.groupEnd())},e.storeHandled=function(t,e,n){console.group&&e!==n&&console.debug("Store "+t+" handled action")},e.dispatchEnd=function(t){console.group&&(console.debug("Dispatch done, new state: ",t.toJS()),console.groupEnd())}},function(t,e,n){function r(t,e){this.__prevState=t,this.__evaluator=e,this.__prevValues=i.Map(),this.__observers=[]}var i=n(2),o=n(7),u=n(8);Object.defineProperty(r.prototype,"notifyObservers",{writable:!0,configurable:!0,value:function(t){if(this.__observers.length>0){var e=i.Map();this.__observers.forEach(function(n){var r,i=n.getter,a=o(i),s=this.__prevState;this.__prevValues.has(a)?r=this.__prevValues.get(a):(r=this.__evaluator.evaluate(s,i),this.__prevValues=this.__prevValues.set(a,r));var c=this.__evaluator.evaluate(t,i);u(r,c)||(n.handler.call(null,c),e=e.set(a,c))}.bind(this)),this.__prevValues=e}this.__prevState=t}}),Object.defineProperty(r.prototype,"onChange",{writable:!0,configurable:!0,value:function(t,e){var n={getter:t,handler:e};return this.__observers.push(n),function(){var t=this.__observers.indexOf(n);t>-1&&this.__observers.splice(t,1)}.bind(this)}}),Object.defineProperty(r.prototype,"reset",{writable:!0,configurable:!0,value:function(t){this.__prevState=t,this.__prevValues=i.Map(),this.__observers=[]}}),t.exports=r},function(t,e,n){var r=n(2);t.exports=function(t,e){if(t.hasOwnProperty("__hashCode"))return t.__hashCode;var n=r.fromJS(t).hashCode();return e||(Object.defineProperty(t,"__hashCode",{enumerable:!1,configurable:!1,writable:!1,value:n}),Object.freeze(t)),n}},function(t,e,n){var r=n(2);t.exports=function(t,e){return r.is(t,e)}},function(t,e,n){function r(t){return s(t)&&a(t[t.length-1])}function i(t){return t[t.length-1]}function o(t){return t.slice(0,t.length-1)}function u(t){if(!c(t))throw new Error("Cannot create Getter from KeyPath: "+t);return[t,l]}var a=n(3).isFunction,s=n(3).isArray,c=n(10).isKeyPath,l=function(t){return t};t.exports={isGetter:r,getComputeFn:i,getDeps:o,fromKeyPath:u}},function(t,e,n){var r=n(3).isArray,i=n(3).isFunction;e.isKeyPath=function(t){return r(t)&&!i(t[t.length-1])}},function(t,e,n){function r(){this.__cachedGetters=i.Map({})}var i=n(2),o=n(1).toImmutable,u=n(7),a=n(8),s=n(9).getComputeFn,c=n(9).getDeps,l=n(10).isKeyPath,f=n(9).isGetter,d=!1;Object.defineProperty(r.prototype,"evaluate",{writable:!0,configurable:!0,value:function(t,e){if(l(e))return t.getIn(e);if(!f(e))throw new Error("evaluate must be passed a keyPath or Getter");var n=u(e);if(this.__isCached(t,e))return this.__cachedGetters.getIn([n,"value"]);var r=c(e).map(function(e){return this.evaluate(t,e)}.bind(this));if(this.__hasStaleValue(t,e)){var i=this.__cachedGetters.getIn([n,"args"]);if(a(i,o(r))){var p=this.__cachedGetters.getIn([n,"value"]);return this.__cacheValue(t,e,i,p),p}}if(d===!0)throw d=!1,new Error("Evaluate may not be called within a Getters computeFn");var h;d=!0;try{h=s(e).apply(null,r),d=!1}catch(_){throw d=!1,_}return this.__cacheValue(t,e,r,h),h}}),Object.defineProperty(r.prototype,"__hasStaleValue",{writable:!0,configurable:!0,value:function(t,e){var n=u(e),r=this.__cachedGetters;return r.has(n)&&r.getIn([n,"stateHashCode"])!==t.hashCode()}}),Object.defineProperty(r.prototype,"__cacheValue",{writable:!0,configurable:!0,value:function(t,e,n,r){var a=u(e);this.__cachedGetters=this.__cachedGetters.set(a,i.Map({value:r,args:o(n),stateHashCode:t.hashCode()}))}}),Object.defineProperty(r.prototype,"__isCached",{writable:!0,configurable:!0,value:function(t,e){var n=u(e);return this.__cachedGetters.hasIn([n,"value"])&&this.__cachedGetters.getIn([n,"stateHashCode"])===t.hashCode()}}),Object.defineProperty(r.prototype,"untrack",{writable:!0,configurable:!0,value:function(t){}}),Object.defineProperty(r.prototype,"reset",{writable:!0,configurable:!0,value:function(){this.__cachedGetters=i.Map({})}}),t.exports=r},function(t,e,n){function r(t,e){var n={};return i(e,function(e,r){n[r]=t.evaluate(e)}),n}var i=n(3).each;t.exports=function(t){return{getInitialState:function(){return r(t,this.getDataBindings())},componentDidMount:function(){var e=this;e.__unwatchFns=[],i(this.getDataBindings(),function(n,r){var i=t.observe(n,function(t){var n={};n[r]=t,e.setState(n)});e.__unwatchFns.push(i)})},componentWillUnmount:function(){for(;this.__unwatchFns.length;)this.__unwatchFns.shift()()}}}},function(t,e,n){function r(t){return this instanceof r?(this.__handlers=o({}),t&&u(this,t),void this.initialize()):new r(t)}function i(t){return t instanceof r}var o=n(2).Map,u=n(3).extend,a=n(1).toJS,s=n(1).toImmutable;Object.defineProperty(r.prototype,"initialize",{writable:!0,configurable:!0,value:function(){}}),Object.defineProperty(r.prototype,"getInitialState",{writable:!0,configurable:!0,value:function(){return o()}}),Object.defineProperty(r.prototype,"handle",{writable:!0,configurable:!0,value:function(t,e,n){var r=this.__handlers.get(e);return"function"==typeof r?r.call(this,t,n,e):t}}),Object.defineProperty(r.prototype,"handleReset",{writable:!0,configurable:!0,value:function(t){return this.getInitialState()}}),Object.defineProperty(r.prototype,"on",{writable:!0,configurable:!0,value:function(t,e){this.__handlers=this.__handlers.set(t,e)}}),Object.defineProperty(r.prototype,"serialize",{writable:!0,configurable:!0,value:function(t){return a(t)}}),Object.defineProperty(r.prototype,"deserialize",{writable:!0,configurable:!0,value:function(t){return s(t)}}),t.exports=r,t.exports.isStore=i}])})},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(121),u=r(o);e["default"]=u["default"](i.reactor),t.exports=e["default"]},function(t,e){"use strict";var n=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};t.exports=n},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(130),o=r(i);e.callApi=o["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(146),u=i(o),a=n(147),s=r(a),c=u["default"];e.actions=c;var l=s;e.getters=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){t.registerStores({restApiCache:l["default"]})}function o(t){return[["restApiCache",t.entity],function(t){return!!t}]}function u(t){return[["restApiCache",t.entity],function(t){return t||s.toImmutable({})}]}function a(t){return function(e){return["restApiCache",t.entity,e]}}Object.defineProperty(e,"__esModule",{value:!0}),e.register=i,e.createHasDataGetter=o,e.createEntityMapGetter=u,e.createByIdGetter=a;var s=n(3),c=n(170),l=r(c),f=n(169),d=r(f);e.createApiActions=d["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(80),n(37),e["default"]=new o["default"]({is:"state-info",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"partial-base",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1}},computeMenuButtonClass:function(t,e){return!t&&e?"invisible":""},toggleMenu:function(){this.fire("open-menu")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({ENTITY_HISTORY_DATE_SELECTED:null,ENTITY_HISTORY_FETCH_START:null,ENTITY_HISTORY_FETCH_ERROR:null,ENTITY_HISTORY_FETCH_SUCCESS:null,RECENT_ENTITY_HISTORY_FETCH_START:null,RECENT_ENTITY_HISTORY_FETCH_ERROR:null,RECENT_ENTITY_HISTORY_FETCH_SUCCESS:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({LOGBOOK_DATE_SELECTED:null,LOGBOOK_ENTRIES_FETCH_START:null,LOGBOOK_ENTRIES_FETCH_ERROR:null,LOGBOOK_ENTRIES_FETCH_SUCCESS:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(171),u=i(o),a=n(57),s=r(a),c=u["default"];e.actions=c;var l=s;e.getters=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({VALIDATING_AUTH_TOKEN:null,VALID_AUTH_TOKEN:null,INVALID_AUTH_TOKEN:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({authAttempt:a["default"],authCurrent:c["default"],rememberAuth:f["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(133),a=i(u),s=n(134),c=i(s),l=n(135),f=i(l),d=n(131),p=r(d),h=n(132),_=r(h),v=p;e.actions=v;var y=_;e.getters=y},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=t[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!e||n.length!==e);r=!0);}catch(s){i=!0,o=s}finally{try{!r&&a["return"]&&a["return"]()}finally{if(i)throw o}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),a=function(){function t(t,e){for(var n=0;n5?"value big":"value"}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"loading-box"}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(122),a=r(u);n(39),n(120),n(119),n(116),n(118),n(117),e["default"]=new o["default"]({is:"state-card-content",properties:{stateObj:{type:Object,observer:"stateObjChanged"}},stateObjChanged:function(t,e){var n=o["default"].dom(this);if(!t)return void(n.lastChild&&n.removeChild(n.lastChild));var r=a["default"](t);if(e&&a["default"](e)===r)n.lastChild.stateObj=t;else{n.lastChild&&n.removeChild(n.lastChild);var i=document.createElement("state-card-"+r);i.stateObj=t,n.appendChild(i)}}}),t.exports=e["default"]},function(t,e){"use strict";function n(t,e){return t?e.map(function(e){return e in t.attributes?"has-"+e:""}).join(" "):""}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return i.reactor.evaluate(i.serviceGetters.canToggleEntity(t))}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=r;var i=n(2);t.exports=e["default"]},function(t,e,n){"use strict";function r(t,e,n){function r(){y&&clearTimeout(y),p&&clearTimeout(p),g=0,p=y=m=void 0}function s(e,n){n&&clearTimeout(n),p=y=m=void 0,e&&(g=o(),h=t.apply(v,d),y||p||(d=v=void 0))}function c(){var t=e-(o()-_);0>=t||t>e?s(m,p):y=setTimeout(c,t)}function l(){s(O,y)}function f(){if(d=arguments,_=o(),v=this,m=O&&(y||!w),b===!1)var n=w&&!y;else{p||w||(g=_);var r=b-(_-g),i=0>=r||r>b;i?(p&&(p=clearTimeout(p)),g=_,h=t.apply(v,d)):p||(p=setTimeout(l,r))}return i&&y?y=clearTimeout(y):y||e===b||(y=setTimeout(c,e)),n&&(i=!0,h=t.apply(v,d)),!i||y||p||(d=v=void 0),h}var d,p,h,_,v,y,m,g=0,b=!1,O=!0;if("function"!=typeof t)throw new TypeError(u);if(e=0>e?0:+e||0,n===!0){var w=!0;O=!1}else i(n)&&(w=!!n.leading,b="maxWait"in n&&a(+n.maxWait||0,e),O="trailing"in n?!!n.trailing:O);return f.cancel=r,f}var i=n(46),o=n(126),u="Expected a function",a=Math.max;t.exports=r},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({SERVER_CONFIG_LOADED:null,COMPONENT_LOADED:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({serverComponent:a["default"],serverConfig:c["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(138),a=i(u),s=n(139),c=i(s),l=n(136),f=r(l),d=n(137),p=r(d),h=f;e.actions=h;var _=p;e.getters=_},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(148),u=i(o),a=n(149),s=r(a),c=u["default"];e.actions=c;var l=s;e.getters=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({NAVIGATE:null,SHOW_SIDEBAR:null,LOG_OUT:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({notifications:a["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(166),a=i(u),s=n(164),c=r(s),l=n(165),f=r(l),d=c;e.actions=d;var p=f;e.getters=p},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({streamStatus:a["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(178),a=i(u),s=n(174),c=r(s),l=n(175),f=r(l),d=c;e.actions=d;var p=f;e.getters=p},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(5),o=r(i);e["default"]=o["default"]({API_FETCH_ALL_START:null,API_FETCH_ALL_SUCCESS:null,API_FETCH_ALL_FAIL:null,SYNC_SCHEDULED:null,SYNC_SCHEDULE_CANCELLED:null}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({isFetchingData:a["default"],isSyncScheduled:c["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(180),a=i(u),s=n(181),c=i(s),l=n(179),f=r(l),d=n(60),p=r(d),h=f;e.actions=h;var _=p;e.getters=_},function(t,e){"use strict";function n(t){return t.getFullYear()+"-"+(t.getMonth()+1)+"-"+t.getDate()}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e){"use strict";function n(t){var e=t.split(" "),n=r(e,2),i=n[0],o=n[1],u=i.split(":"),a=r(u,3),s=a[0],c=a[1],l=a[2],f=o.split("-"),d=r(f,3),p=d[0],h=d[1],_=d[2];return new Date(Date.UTC(_,parseInt(h,10)-1,p,s,c,l))}Object.defineProperty(e,"__esModule",{value:!0});var r=function(){function t(t,e){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=t[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!e||n.length!==e);r=!0);}catch(s){i=!0,o=s}finally{try{!r&&a["return"]&&a["return"]()}finally{if(i)throw o}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();e["default"]=n,t.exports=e["default"]},function(t,e,n){(function(t){"use strict";!function(e,n){t.exports=n()}(void 0,function(){function e(){return Ln.apply(null,arguments)}function n(t){Ln=t}function r(t){return"[object Array]"===Object.prototype.toString.call(t)}function i(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function o(t,e){var n,r=[];for(n=0;n0)for(n in zn)r=zn[n],i=e[r],"undefined"!=typeof i&&(t[r]=i);return t}function h(t){p(this,t),this._d=new Date(null!=t._d?t._d.getTime():NaN),Rn===!1&&(Rn=!0,e.updateOffset(this),Rn=!1)}function _(t){return t instanceof h||null!=t&&null!=t._isAMomentObject}function v(t){return 0>t?Math.ceil(t):Math.floor(t)}function y(t){var e=+t,n=0;return 0!==e&&isFinite(e)&&(n=v(e)),n}function m(t,e,n){var r,i=Math.min(t.length,e.length),o=Math.abs(t.length-e.length),u=0;for(r=0;i>r;r++)(n&&t[r]!==e[r]||!n&&y(t[r])!==y(e[r]))&&u++;return u+o}function g(){}function b(t){return t?t.toLowerCase().replace("_","-"):t}function O(t){for(var e,n,r,i,o=0;o0;){if(r=w(i.slice(0,e).join("-")))return r;if(n&&n.length>=e&&m(i,n,!0)>=e-1)break;e--}o++}return null}function w(e){var n=null;if(!Hn[e]&&"undefined"!=typeof t&&t&&t.exports)try{n=Nn._abbr,!function(){var t=new Error('Cannot find module "./locale"');throw t.code="MODULE_NOT_FOUND",t}(),S(n)}catch(r){}return Hn[e]}function S(t,e){var n;return t&&(n="undefined"==typeof e?T(t):M(t,e),n&&(Nn=n)),Nn._abbr}function M(t,e){return null!==e?(e.abbr=t,Hn[t]=Hn[t]||new g,Hn[t].set(e),S(t),Hn[t]):(delete Hn[t],null)}function T(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Nn;if(!r(t)){if(e=w(t))return e;t=[t]}return O(t)}function E(t,e){var n=t.toLowerCase();Yn[n]=Yn[n+"s"]=Yn[e]=t}function j(t){return"string"==typeof t?Yn[t]||Yn[t.toLowerCase()]:void 0}function I(t){var e,n,r={};for(n in t)u(t,n)&&(e=j(n),e&&(r[e]=t[n]));return r}function P(t,n){return function(r){return null!=r?(C(this,t,r),e.updateOffset(this,n),this):D(this,t)}}function D(t,e){return t._d["get"+(t._isUTC?"UTC":"")+e]()}function C(t,e,n){return t._d["set"+(t._isUTC?"UTC":"")+e](n)}function A(t,e){var n;if("object"==typeof t)for(n in t)this.set(n,t[n]);else if(t=j(t),"function"==typeof this[t])return this[t](e);return this}function k(t,e,n){var r=""+Math.abs(t),i=e-r.length,o=t>=0;return(o?n?"+":"":"-")+Math.pow(10,Math.max(0,i)).toString().substr(1)+r}function x(t,e,n,r){var i=r;"string"==typeof r&&(i=function(){return this[r]()}),t&&(Bn[t]=i),e&&(Bn[e[0]]=function(){return k(i.apply(this,arguments),e[1],e[2])}),n&&(Bn[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),t)})}function L(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function N(t){var e,n,r=t.match(Gn);for(e=0,n=r.length;n>e;e++)Bn[r[e]]?r[e]=Bn[r[e]]:r[e]=L(r[e]);return function(i){var o="";for(e=0;n>e;e++)o+=r[e]instanceof Function?r[e].call(i,t):r[e];return o}}function z(t,e){return t.isValid()?(e=R(e,t.localeData()),Un[e]=Un[e]||N(e),Un[e](t)):t.localeData().invalidDate()}function R(t,e){function n(t){return e.longDateFormat(t)||t}var r=5;for(Fn.lastIndex=0;r>=0&&Fn.test(t);)t=t.replace(Fn,n),Fn.lastIndex=0,r-=1;return t}function H(t){return"function"==typeof t&&"[object Function]"===Object.prototype.toString.call(t)}function Y(t,e,n){or[t]=H(e)?e:function(t){return t&&n?n:e}}function G(t,e){return u(or,t)?or[t](e._strict,e._locale):new RegExp(F(t))}function F(t){return t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,n,r,i){return e||n||r||i}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function U(t,e){var n,r=e;for("string"==typeof t&&(t=[t]),"number"==typeof e&&(r=function(t,n){n[e]=y(t)}),n=0;nr;r++){if(i=s([2e3,r]),n&&!this._longMonthsParse[r]&&(this._longMonthsParse[r]=new RegExp("^"+this.months(i,"").replace(".","")+"$","i"),this._shortMonthsParse[r]=new RegExp("^"+this.monthsShort(i,"").replace(".","")+"$","i")),n||this._monthsParse[r]||(o="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[r]=new RegExp(o.replace(".",""),"i")),n&&"MMMM"===e&&this._longMonthsParse[r].test(t))return r;if(n&&"MMM"===e&&this._shortMonthsParse[r].test(t))return r;if(!n&&this._monthsParse[r].test(t))return r}}function $(t,e){var n;return"string"==typeof e&&(e=t.localeData().monthsParse(e),"number"!=typeof e)?t:(n=Math.min(t.date(),q(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,n),t)}function Z(t){return null!=t?($(this,t),e.updateOffset(this,!0),this):D(this,"Month")}function X(){return q(this.year(),this.month())}function Q(t){var e,n=t._a;return n&&-2===l(t).overflow&&(e=n[sr]<0||n[sr]>11?sr:n[cr]<1||n[cr]>q(n[ar],n[sr])?cr:n[lr]<0||n[lr]>24||24===n[lr]&&(0!==n[fr]||0!==n[dr]||0!==n[pr])?lr:n[fr]<0||n[fr]>59?fr:n[dr]<0||n[dr]>59?dr:n[pr]<0||n[pr]>999?pr:-1,l(t)._overflowDayOfYear&&(ar>e||e>cr)&&(e=cr),l(t).overflow=e),t}function tt(t){e.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+t)}function et(t,e){var n=!0;return a(function(){return n&&(tt(t+"\n"+(new Error).stack),n=!1),e.apply(this,arguments)},e)}function nt(t,e){vr[t]||(tt(e),vr[t]=!0)}function rt(t){var e,n,r=t._i,i=yr.exec(r);if(i){for(l(t).iso=!0,e=0,n=mr.length;n>e;e++)if(mr[e][1].exec(r)){t._f=mr[e][0];break}for(e=0,n=gr.length;n>e;e++)if(gr[e][1].exec(r)){t._f+=(i[6]||" ")+gr[e][0];break}r.match(nr)&&(t._f+="Z"),wt(t)}else t._isValid=!1}function it(t){var n=br.exec(t._i);return null!==n?void(t._d=new Date(+n[1])):(rt(t),void(t._isValid===!1&&(delete t._isValid,e.createFromInputFallback(t))))}function ot(t,e,n,r,i,o,u){var a=new Date(t,e,n,r,i,o,u);return 1970>t&&a.setFullYear(t),a}function ut(t){var e=new Date(Date.UTC.apply(null,arguments));return 1970>t&&e.setUTCFullYear(t),e}function at(t){return st(t)?366:365}function st(t){return t%4===0&&t%100!==0||t%400===0}function ct(){return st(this.year())}function lt(t,e,n){var r,i=n-e,o=n-t.day();return o>i&&(o-=7),i-7>o&&(o+=7),r=Dt(t).add(o,"d"),{week:Math.ceil(r.dayOfYear()/7),year:r.year()}}function ft(t){return lt(t,this._week.dow,this._week.doy).week}function dt(){return this._week.dow}function pt(){return this._week.doy}function ht(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")}function _t(t){var e=lt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")}function vt(t,e,n,r,i){var o,u=6+i-r,a=ut(t,0,1+u),s=a.getUTCDay();return i>s&&(s+=7),n=null!=n?1*n:i,o=1+u+7*(e-1)-s+n,{year:o>0?t:t-1,dayOfYear:o>0?o:at(t-1)+o}}function yt(t){var e=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")}function mt(t,e,n){return null!=t?t:null!=e?e:n}function gt(t){var e=new Date;return t._useUTC?[e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()]:[e.getFullYear(),e.getMonth(),e.getDate()]}function bt(t){var e,n,r,i,o=[];if(!t._d){for(r=gt(t),t._w&&null==t._a[cr]&&null==t._a[sr]&&Ot(t),t._dayOfYear&&(i=mt(t._a[ar],r[ar]),t._dayOfYear>at(i)&&(l(t)._overflowDayOfYear=!0),n=ut(i,0,t._dayOfYear),t._a[sr]=n.getUTCMonth(),t._a[cr]=n.getUTCDate()),e=0;3>e&&null==t._a[e];++e)t._a[e]=o[e]=r[e];for(;7>e;e++)t._a[e]=o[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[lr]&&0===t._a[fr]&&0===t._a[dr]&&0===t._a[pr]&&(t._nextDay=!0,t._a[lr]=0),t._d=(t._useUTC?ut:ot).apply(null,o),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[lr]=24)}}function Ot(t){var e,n,r,i,o,u,a;e=t._w,null!=e.GG||null!=e.W||null!=e.E?(o=1,u=4,n=mt(e.GG,t._a[ar],lt(Dt(),1,4).year),r=mt(e.W,1),i=mt(e.E,1)):(o=t._locale._week.dow,u=t._locale._week.doy,n=mt(e.gg,t._a[ar],lt(Dt(),o,u).year),r=mt(e.w,1),null!=e.d?(i=e.d,o>i&&++r):i=null!=e.e?e.e+o:o),a=vt(n,r,i,u,o),t._a[ar]=a.year,t._dayOfYear=a.dayOfYear}function wt(t){if(t._f===e.ISO_8601)return void rt(t);t._a=[],l(t).empty=!0;var n,r,i,o,u,a=""+t._i,s=a.length,c=0;for(i=R(t._f,t._locale).match(Gn)||[],n=0;n0&&l(t).unusedInput.push(u),a=a.slice(a.indexOf(r)+r.length),c+=r.length),Bn[o]?(r?l(t).empty=!1:l(t).unusedTokens.push(o),V(o,r,t)):t._strict&&!r&&l(t).unusedTokens.push(o);l(t).charsLeftOver=s-c,a.length>0&&l(t).unusedInput.push(a),l(t).bigHour===!0&&t._a[lr]<=12&&t._a[lr]>0&&(l(t).bigHour=void 0),t._a[lr]=St(t._locale,t._a[lr],t._meridiem),bt(t),Q(t)}function St(t,e,n){var r;return null==n?e:null!=t.meridiemHour?t.meridiemHour(e,n):null!=t.isPM?(r=t.isPM(n),r&&12>e&&(e+=12),r||12!==e||(e=0),e):e}function Mt(t){var e,n,r,i,o;if(0===t._f.length)return l(t).invalidFormat=!0,void(t._d=new Date(NaN));for(i=0;io)&&(r=o,n=e));a(t,n||e)}function Tt(t){if(!t._d){var e=I(t._i);t._a=[e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],bt(t)}}function Et(t){var e=new h(Q(jt(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function jt(t){var e=t._i,n=t._f;return t._locale=t._locale||T(t._l),null===e||void 0===n&&""===e?d({nullInput:!0}):("string"==typeof e&&(t._i=e=t._locale.preparse(e)),_(e)?new h(Q(e)):(r(n)?Mt(t):n?wt(t):i(e)?t._d=e:It(t),t))}function It(t){var n=t._i;void 0===n?t._d=new Date:i(n)?t._d=new Date(+n):"string"==typeof n?it(t):r(n)?(t._a=o(n.slice(0),function(t){return parseInt(t,10)}),bt(t)):"object"==typeof n?Tt(t):"number"==typeof n?t._d=new Date(n):e.createFromInputFallback(t)}function Pt(t,e,n,r,i){var o={};return"boolean"==typeof n&&(r=n,n=void 0),o._isAMomentObject=!0,o._useUTC=o._isUTC=i,o._l=n,o._i=t,o._f=e,o._strict=r,Et(o)}function Dt(t,e,n,r){return Pt(t,e,n,r,!1)}function Ct(t,e){var n,i;if(1===e.length&&r(e[0])&&(e=e[0]),!e.length)return Dt();for(n=e[0],i=1;it&&(t=-t,n="-"),n+k(~~(t/60),2)+e+k(~~t%60,2)})}function zt(t){var e=(t||"").match(nr)||[],n=e[e.length-1]||[],r=(n+"").match(Tr)||["-",0,0],i=+(60*r[1])+y(r[2]);return"+"===r[0]?i:-i}function Rt(t,n){var r,o;return n._isUTC?(r=n.clone(),o=(_(t)||i(t)?+t:+Dt(t))-+r,r._d.setTime(+r._d+o),e.updateOffset(r,!1),r):Dt(t).local()}function Ht(t){return 15*-Math.round(t._d.getTimezoneOffset()/15)}function Yt(t,n){var r,i=this._offset||0;return null!=t?("string"==typeof t&&(t=zt(t)),Math.abs(t)<16&&(t=60*t),!this._isUTC&&n&&(r=Ht(this)),this._offset=t,this._isUTC=!0,null!=r&&this.add(r,"m"),i!==t&&(!n||this._changeInProgress?ne(this,Zt(t-i,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,e.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?i:Ht(this)}function Gt(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}function Ft(t){return this.utcOffset(0,t)}function Ut(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(Ht(this),"m")),this}function Bt(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(zt(this._i)),this}function Vt(t){return t=t?Dt(t).utcOffset():0,(this.utcOffset()-t)%60===0}function qt(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Wt(){if("undefined"!=typeof this._isDSTShifted)return this._isDSTShifted;var t={};if(p(t,this),t=jt(t),t._a){var e=t._isUTC?s(t._a):Dt(t._a);this._isDSTShifted=this.isValid()&&m(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Kt(){return!this._isUTC}function Jt(){return this._isUTC}function $t(){return this._isUTC&&0===this._offset}function Zt(t,e){var n,r,i,o=t,a=null;return Lt(t)?o={ms:t._milliseconds,d:t._days,M:t._months}:"number"==typeof t?(o={},e?o[e]=t:o.milliseconds=t):(a=Er.exec(t))?(n="-"===a[1]?-1:1,o={y:0,d:y(a[cr])*n,h:y(a[lr])*n,m:y(a[fr])*n,s:y(a[dr])*n,ms:y(a[pr])*n}):(a=jr.exec(t))?(n="-"===a[1]?-1:1,o={y:Xt(a[2],n),M:Xt(a[3],n),d:Xt(a[4],n),h:Xt(a[5],n),m:Xt(a[6],n),s:Xt(a[7],n),w:Xt(a[8],n)}):null==o?o={}:"object"==typeof o&&("from"in o||"to"in o)&&(i=te(Dt(o.from),Dt(o.to)),o={},o.ms=i.milliseconds,o.M=i.months),r=new xt(o),Lt(t)&&u(t,"_locale")&&(r._locale=t._locale),r}function Xt(t,e){var n=t&&parseFloat(t.replace(",","."));return(isNaN(n)?0:n)*e}function Qt(t,e){var n={milliseconds:0,months:0};return n.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(n.months,"M").isAfter(e)&&--n.months,n.milliseconds=+e-+t.clone().add(n.months,"M"),n}function te(t,e){var n;return e=Rt(e,t),t.isBefore(e)?n=Qt(t,e):(n=Qt(e,t),n.milliseconds=-n.milliseconds,n.months=-n.months),n}function ee(t,e){return function(n,r){var i,o;return null===r||isNaN(+r)||(nt(e,"moment()."+e+"(period, number) is deprecated. Please use moment()."+e+"(number, period)."),o=n,n=r,r=o),n="string"==typeof n?+n:n,i=Zt(n,r),ne(this,i,t),this}}function ne(t,n,r,i){var o=n._milliseconds,u=n._days,a=n._months;i=null==i?!0:i,o&&t._d.setTime(+t._d+o*r),u&&C(t,"Date",D(t,"Date")+u*r),a&&$(t,D(t,"Month")+a*r),i&&e.updateOffset(t,u||a)}function re(t,e){var n=t||Dt(),r=Rt(n,this).startOf("day"),i=this.diff(r,"days",!0),o=-6>i?"sameElse":-1>i?"lastWeek":0>i?"lastDay":1>i?"sameDay":2>i?"nextDay":7>i?"nextWeek":"sameElse";return this.format(e&&e[o]||this.localeData().calendar(o,this,Dt(n)))}function ie(){return new h(this)}function oe(t,e){var n;return e=j("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=_(t)?t:Dt(t),+this>+t):(n=_(t)?+t:+Dt(t),n<+this.clone().startOf(e))}function ue(t,e){var n;return e=j("undefined"!=typeof e?e:"millisecond"),"millisecond"===e?(t=_(t)?t:Dt(t),+t>+this):(n=_(t)?+t:+Dt(t),+this.clone().endOf(e)e-o?(n=t.clone().add(i-1,"months"),r=(e-o)/(o-n)):(n=t.clone().add(i+1,"months"),r=(e-o)/(n-o)),-(i+r)}function fe(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function de(){var t=this.clone().utc();return 0e;e++)if(this._weekdaysParse[e]||(n=Dt([2e3,1]).day(e),r="^"+this.weekdays(n,"")+"|^"+this.weekdaysShort(n,"")+"|^"+this.weekdaysMin(n,""),this._weekdaysParse[e]=new RegExp(r.replace(".",""),"i")),this._weekdaysParse[e].test(t))return e}function Fe(t){var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=ze(t,this.localeData()),this.add(t-e,"d")):e}function Ue(t){var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")}function Be(t){return null==t?this.day()||7:this.day(this.day()%7?t:t-7)}function Ve(t,e){x(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function qe(t,e){return e._meridiemParse}function We(t){return"p"===(t+"").toLowerCase().charAt(0)}function Ke(t,e,n){return t>11?n?"pm":"PM":n?"am":"AM"}function Je(t,e){e[pr]=y(1e3*("0."+t))}function $e(){return this._isUTC?"UTC":""}function Ze(){return this._isUTC?"Coordinated Universal Time":""}function Xe(t){return Dt(1e3*t)}function Qe(){return Dt.apply(null,arguments).parseZone()}function tn(t,e,n){var r=this._calendar[t];return"function"==typeof r?r.call(e,n):r}function en(t){var e=this._longDateFormat[t],n=this._longDateFormat[t.toUpperCase()];return e||!n?e:(this._longDateFormat[t]=n.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])}function nn(){return this._invalidDate}function rn(t){return this._ordinal.replace("%d",t)}function on(t){return t}function un(t,e,n,r){var i=this._relativeTime[n];return"function"==typeof i?i(t,e,n,r):i.replace(/%d/i,t)}function an(t,e){var n=this._relativeTime[t>0?"future":"past"];return"function"==typeof n?n(e):n.replace(/%s/i,e)}function sn(t){var e,n;for(n in t)e=t[n],"function"==typeof e?this[n]=e:this["_"+n]=e;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function cn(t,e,n,r){var i=T(),o=s().set(r,e);return i[n](o,t)}function ln(t,e,n,r,i){if("number"==typeof t&&(e=t,t=void 0),t=t||"",null!=e)return cn(t,e,n,i);var o,u=[];for(o=0;r>o;o++)u[o]=cn(t,o,n,i);return u}function fn(t,e){return ln(t,e,"months",12,"month")}function dn(t,e){return ln(t,e,"monthsShort",12,"month")}function pn(t,e){return ln(t,e,"weekdays",7,"day")}function hn(t,e){return ln(t,e,"weekdaysShort",7,"day")}function _n(t,e){return ln(t,e,"weekdaysMin",7,"day")}function vn(){var t=this._data;return this._milliseconds=$r(this._milliseconds),this._days=$r(this._days),this._months=$r(this._months),t.milliseconds=$r(t.milliseconds),t.seconds=$r(t.seconds),t.minutes=$r(t.minutes),t.hours=$r(t.hours),t.months=$r(t.months),t.years=$r(t.years),this}function yn(t,e,n,r){var i=Zt(e,n);return t._milliseconds+=r*i._milliseconds,t._days+=r*i._days,t._months+=r*i._months,t._bubble()}function mn(t,e){return yn(this,t,e,1)}function gn(t,e){return yn(this,t,e,-1)}function bn(t){return 0>t?Math.floor(t):Math.ceil(t)}function On(){var t,e,n,r,i,o=this._milliseconds,u=this._days,a=this._months,s=this._data;return o>=0&&u>=0&&a>=0||0>=o&&0>=u&&0>=a||(o+=864e5*bn(Sn(a)+u),u=0,a=0),s.milliseconds=o%1e3,t=v(o/1e3),s.seconds=t%60,e=v(t/60),s.minutes=e%60,n=v(e/60),s.hours=n%24,u+=v(n/24),i=v(wn(u)),a+=i,u-=bn(Sn(i)),r=v(a/12),a%=12,s.days=u,s.months=a,s.years=r,this}function wn(t){return 4800*t/146097}function Sn(t){return 146097*t/4800}function Mn(t){var e,n,r=this._milliseconds;if(t=j(t),"month"===t||"year"===t)return e=this._days+r/864e5,n=this._months+wn(e),"month"===t?n:n/12;switch(e=this._days+Math.round(Sn(this._months)),t){case"week":return e/7+r/6048e5;case"day":return e+r/864e5;case"hour":return 24*e+r/36e5;case"minute":return 1440*e+r/6e4;case"second":return 86400*e+r/1e3;case"millisecond":return Math.floor(864e5*e)+r;default:throw new Error("Unknown unit "+t)}}function Tn(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*y(this._months/12)}function En(t){return function(){return this.as(t)}}function jn(t){return t=j(t),this[t+"s"]()}function In(t){return function(){return this._data[t]}}function Pn(){return v(this.days()/7)}function Dn(t,e,n,r,i){return i.relativeTime(e||1,!!n,t,r)}function Cn(t,e,n){var r=Zt(t).abs(),i=di(r.as("s")),o=di(r.as("m")),u=di(r.as("h")),a=di(r.as("d")),s=di(r.as("M")),c=di(r.as("y")),l=i0,l[4]=n,Dn.apply(null,l)}function An(t,e){return void 0===pi[t]?!1:void 0===e?pi[t]:(pi[t]=e,!0)}function kn(t){var e=this.localeData(),n=Cn(this,!t,e);return t&&(n=e.pastFuture(+this,n)),e.postformat(n)}function xn(){var t,e,n,r=hi(this._milliseconds)/1e3,i=hi(this._days),o=hi(this._months);t=v(r/60),e=v(t/60),r%=60,t%=60,n=v(o/12),o%=12;var u=n,a=o,s=i,c=e,l=t,f=r,d=this.asSeconds();return d?(0>d?"-":"")+"P"+(u?u+"Y":"")+(a?a+"M":"")+(s?s+"D":"")+(c||l||f?"T":"")+(c?c+"H":"")+(l?l+"M":"")+(f?f+"S":""):"P0D"}var Ln,Nn,zn=e.momentProperties=[],Rn=!1,Hn={},Yn={},Gn=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Fn=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Un={},Bn={},Vn=/\d/,qn=/\d\d/,Wn=/\d{3}/,Kn=/\d{4}/,Jn=/[+-]?\d{6}/,$n=/\d\d?/,Zn=/\d{1,3}/,Xn=/\d{1,4}/,Qn=/[+-]?\d{1,6}/,tr=/\d+/,er=/[+-]?\d+/,nr=/Z|[+-]\d\d:?\d\d/gi,rr=/[+-]?\d+(\.\d{1,3})?/,ir=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,or={},ur={},ar=0,sr=1,cr=2,lr=3,fr=4,dr=5,pr=6;x("M",["MM",2],"Mo",function(){return this.month()+1}),x("MMM",0,0,function(t){return this.localeData().monthsShort(this,t)}),x("MMMM",0,0,function(t){return this.localeData().months(this,t)}),E("month","M"),Y("M",$n),Y("MM",$n,qn),Y("MMM",ir),Y("MMMM",ir),U(["M","MM"],function(t,e){e[sr]=y(t)-1}),U(["MMM","MMMM"],function(t,e,n,r){var i=n._locale.monthsParse(t,r,n._strict);null!=i?e[sr]=i:l(n).invalidMonth=t});var hr="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),_r="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),vr={};e.suppressDeprecationWarnings=!1;var yr=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,mr=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],gr=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],br=/^\/?Date\((\-?\d+)/i;e.createFromInputFallback=et("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),x(0,["YY",2],0,function(){return this.year()%100}),x(0,["YYYY",4],0,"year"),x(0,["YYYYY",5],0,"year"),x(0,["YYYYYY",6,!0],0,"year"),E("year","y"),Y("Y",er),Y("YY",$n,qn),Y("YYYY",Xn,Kn),Y("YYYYY",Qn,Jn),Y("YYYYYY",Qn,Jn),U(["YYYYY","YYYYYY"],ar),U("YYYY",function(t,n){n[ar]=2===t.length?e.parseTwoDigitYear(t):y(t)}),U("YY",function(t,n){n[ar]=e.parseTwoDigitYear(t)}),e.parseTwoDigitYear=function(t){return y(t)+(y(t)>68?1900:2e3)};var Or=P("FullYear",!1);x("w",["ww",2],"wo","week"),x("W",["WW",2],"Wo","isoWeek"),E("week","w"),E("isoWeek","W"),Y("w",$n),Y("ww",$n,qn),Y("W",$n),Y("WW",$n,qn),B(["w","ww","W","WW"],function(t,e,n,r){e[r.substr(0,1)]=y(t)});var wr={dow:0,doy:6};x("DDD",["DDDD",3],"DDDo","dayOfYear"),E("dayOfYear","DDD"),Y("DDD",Zn),Y("DDDD",Wn),U(["DDD","DDDD"],function(t,e,n){n._dayOfYear=y(t)}),e.ISO_8601=function(){};var Sr=et("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var t=Dt.apply(null,arguments);return this>t?this:t}),Mr=et("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var t=Dt.apply(null,arguments);return t>this?this:t});Nt("Z",":"),Nt("ZZ",""),Y("Z",nr),Y("ZZ",nr),U(["Z","ZZ"],function(t,e,n){n._useUTC=!0,n._tzm=zt(t)});var Tr=/([\+\-]|\d\d)/gi;e.updateOffset=function(){};var Er=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,jr=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Zt.fn=xt.prototype;var Ir=ee(1,"add"),Pr=ee(-1,"subtract");e.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Dr=et("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return void 0===t?this.localeData():this.locale(t)});x(0,["gg",2],0,function(){return this.weekYear()%100}),x(0,["GG",2],0,function(){return this.isoWeekYear()%100}),De("gggg","weekYear"),De("ggggg","weekYear"),De("GGGG","isoWeekYear"),De("GGGGG","isoWeekYear"),E("weekYear","gg"),E("isoWeekYear","GG"),Y("G",er),Y("g",er),Y("GG",$n,qn),Y("gg",$n,qn),Y("GGGG",Xn,Kn),Y("gggg",Xn,Kn),Y("GGGGG",Qn,Jn),Y("ggggg",Qn,Jn),B(["gggg","ggggg","GGGG","GGGGG"],function(t,e,n,r){e[r.substr(0,2)]=y(t)}),B(["gg","GG"],function(t,n,r,i){n[i]=e.parseTwoDigitYear(t)}),x("Q",0,0,"quarter"),E("quarter","Q"),Y("Q",Vn),U("Q",function(t,e){e[sr]=3*(y(t)-1)}),x("D",["DD",2],"Do","date"),E("date","D"),Y("D",$n),Y("DD",$n,qn),Y("Do",function(t,e){return t?e._ordinalParse:e._ordinalParseLenient}),U(["D","DD"],cr),U("Do",function(t,e){e[cr]=y(t.match($n)[0],10)});var Cr=P("Date",!0);x("d",0,"do","day"),x("dd",0,0,function(t){return this.localeData().weekdaysMin(this,t)}),x("ddd",0,0,function(t){return this.localeData().weekdaysShort(this,t)}),x("dddd",0,0,function(t){return this.localeData().weekdays(this,t)}),x("e",0,0,"weekday"),x("E",0,0,"isoWeekday"),E("day","d"),E("weekday","e"),E("isoWeekday","E"),Y("d",$n),Y("e",$n),Y("E",$n),Y("dd",ir),Y("ddd",ir),Y("dddd",ir),B(["dd","ddd","dddd"],function(t,e,n){var r=n._locale.weekdaysParse(t);null!=r?e.d=r:l(n).invalidWeekday=t}),B(["d","e","E"],function(t,e,n,r){e[r]=y(t)});var Ar="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),kr="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),xr="Su_Mo_Tu_We_Th_Fr_Sa".split("_");x("H",["HH",2],0,"hour"),x("h",["hh",2],0,function(){return this.hours()%12||12}),Ve("a",!0),Ve("A",!1),E("hour","h"),Y("a",qe),Y("A",qe),Y("H",$n),Y("h",$n),Y("HH",$n,qn),Y("hh",$n,qn),U(["H","HH"],lr),U(["a","A"],function(t,e,n){n._isPm=n._locale.isPM(t),n._meridiem=t}),U(["h","hh"],function(t,e,n){e[lr]=y(t),l(n).bigHour=!0});var Lr=/[ap]\.?m?\.?/i,Nr=P("Hours",!0);x("m",["mm",2],0,"minute"),E("minute","m"),Y("m",$n),Y("mm",$n,qn),U(["m","mm"],fr);var zr=P("Minutes",!1);x("s",["ss",2],0,"second"),E("second","s"),Y("s",$n),Y("ss",$n,qn),U(["s","ss"],dr);var Rr=P("Seconds",!1);x("S",0,0,function(){return~~(this.millisecond()/100)}),x(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),x(0,["SSS",3],0,"millisecond"),x(0,["SSSS",4],0,function(){return 10*this.millisecond()}),x(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),x(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),x(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),x(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),x(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),E("millisecond","ms"),Y("S",Zn,Vn),Y("SS",Zn,qn),Y("SSS",Zn,Wn);var Hr;for(Hr="SSSS";Hr.length<=9;Hr+="S")Y(Hr,tr);for(Hr="S";Hr.length<=9;Hr+="S")U(Hr,Je);var Yr=P("Milliseconds",!1);x("z",0,0,"zoneAbbr"),x("zz",0,0,"zoneName");var Gr=h.prototype;Gr.add=Ir,Gr.calendar=re,Gr.clone=ie,Gr.diff=ce,Gr.endOf=Oe,Gr.format=pe,Gr.from=he,Gr.fromNow=_e,Gr.to=ve,Gr.toNow=ye,Gr.get=A,Gr.invalidAt=Pe,Gr.isAfter=oe,Gr.isBefore=ue,Gr.isBetween=ae,Gr.isSame=se,Gr.isValid=je,Gr.lang=Dr,Gr.locale=me,Gr.localeData=ge,Gr.max=Mr,Gr.min=Sr,Gr.parsingFlags=Ie,Gr.set=A,Gr.startOf=be,Gr.subtract=Pr,Gr.toArray=Te,Gr.toObject=Ee,Gr.toDate=Me,Gr.toISOString=de,Gr.toJSON=de,Gr.toString=fe,Gr.unix=Se,Gr.valueOf=we,Gr.year=Or,Gr.isLeapYear=ct,Gr.weekYear=Ae,Gr.isoWeekYear=ke,Gr.quarter=Gr.quarters=Ne,Gr.month=Z,Gr.daysInMonth=X,Gr.week=Gr.weeks=ht,Gr.isoWeek=Gr.isoWeeks=_t,Gr.weeksInYear=Le,Gr.isoWeeksInYear=xe,Gr.date=Cr,Gr.day=Gr.days=Fe,Gr.weekday=Ue,Gr.isoWeekday=Be,Gr.dayOfYear=yt,Gr.hour=Gr.hours=Nr,Gr.minute=Gr.minutes=zr,Gr.second=Gr.seconds=Rr,Gr.millisecond=Gr.milliseconds=Yr,Gr.utcOffset=Yt,Gr.utc=Ft,Gr.local=Ut,Gr.parseZone=Bt,Gr.hasAlignedHourOffset=Vt,Gr.isDST=qt,Gr.isDSTShifted=Wt,Gr.isLocal=Kt,Gr.isUtcOffset=Jt,Gr.isUtc=$t,Gr.isUTC=$t,Gr.zoneAbbr=$e,Gr.zoneName=Ze,Gr.dates=et("dates accessor is deprecated. Use date instead.",Cr),Gr.months=et("months accessor is deprecated. Use month instead",Z),Gr.years=et("years accessor is deprecated. Use year instead",Or),Gr.zone=et("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Gt);var Fr=Gr,Ur={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Br={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Vr="Invalid date",qr="%d",Wr=/\d{1,2}/,Kr={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Jr=g.prototype;Jr._calendar=Ur,Jr.calendar=tn,Jr._longDateFormat=Br,Jr.longDateFormat=en,Jr._invalidDate=Vr,Jr.invalidDate=nn,Jr._ordinal=qr,Jr.ordinal=rn,Jr._ordinalParse=Wr,Jr.preparse=on,Jr.postformat=on,Jr._relativeTime=Kr,Jr.relativeTime=un,Jr.pastFuture=an,Jr.set=sn,Jr.months=W,Jr._months=hr,Jr.monthsShort=K,Jr._monthsShort=_r,Jr.monthsParse=J,Jr.week=ft,Jr._week=wr,Jr.firstDayOfYear=pt,Jr.firstDayOfWeek=dt,Jr.weekdays=Re,Jr._weekdays=Ar,Jr.weekdaysMin=Ye,Jr._weekdaysMin=xr,Jr.weekdaysShort=He,Jr._weekdaysShort=kr,Jr.weekdaysParse=Ge,Jr.isPM=We,Jr._meridiemParse=Lr,Jr.meridiem=Ke,S("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,n=1===y(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+n}}),e.lang=et("moment.lang is deprecated. Use moment.locale instead.",S),e.langData=et("moment.langData is deprecated. Use moment.localeData instead.",T);var $r=Math.abs,Zr=En("ms"),Xr=En("s"),Qr=En("m"),ti=En("h"),ei=En("d"),ni=En("w"),ri=En("M"),ii=En("y"),oi=In("milliseconds"),ui=In("seconds"),ai=In("minutes"),si=In("hours"),ci=In("days"),li=In("months"),fi=In("years"),di=Math.round,pi={s:45,m:45,h:22,d:26,M:11},hi=Math.abs,_i=xt.prototype;_i.abs=vn,_i.add=mn,_i.subtract=gn,_i.as=Mn,_i.asMilliseconds=Zr,_i.asSeconds=Xr,_i.asMinutes=Qr,_i.asHours=ti,_i.asDays=ei,_i.asWeeks=ni,_i.asMonths=ri,_i.asYears=ii,_i.valueOf=Tn,_i._bubble=On,_i.get=jn,_i.milliseconds=oi,_i.seconds=ui,_i.minutes=ai,_i.hours=si,_i.days=ci,_i.weeks=Pn,_i.months=li,_i.years=fi,_i.humanize=kn,_i.toISOString=xn,_i.toString=xn,_i.toJSON=xn,_i.locale=me,_i.localeData=ge,_i.toIsoString=et("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",xn),_i.lang=Dr,x("X",0,0,"unix"),x("x",0,0,"valueOf"),Y("x",er),Y("X",rr),U("X",function(t,e,n){n._d=new Date(1e3*parseFloat(t,10))}),U("x",function(t,e,n){n._d=new Date(y(t))}),e.version="2.10.6",n(Dt),e.fn=Fr,e.min=At,e.max=kt,e.utc=s,e.unix=Xe,e.months=fn,e.isDate=i,e.locale=S,e.invalid=d,e.duration=Zt,e.isMoment=_,e.weekdays=pn,e.parseZone=Qe,e.localeData=T,e.isDuration=Lt,e.monthsShort=dn,e.weekdaysMin=_n,e.defineLocale=M,e.weekdaysShort=hn,e.normalizeUnits=j,e.relativeTimeThreshold=An;var vi=e;return vi})}).call(e,n(72)(t))},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);e["default"]=new u["default"]({is:"ha-entity-toggle",properties:{stateObj:{type:Object,observer:"stateObjChanged"},toggleChecked:{type:Boolean,value:!1}},ready:function(){this.forceStateChange()},toggleChanged:function(t){var e=t.target.checked;e&&"off"===this.stateObj.state?this.turn_on():e||"off"===this.stateObj.state||this.turn_off()},stateObjChanged:function(t){t&&this.updateToggle(t)},updateToggle:function(t){this.toggleChecked=t&&"off"!==t.state},forceStateChange:function(){this.updateToggle(this.stateObj)},turn_on:function(){var t=this;i.serviceActions.callTurnOn(this.stateObj.entityId).then(function(){return t.forceStateChange()})},turn_off:function(){var t=this;i.serviceActions.callTurnOff(this.stateObj.entityId).then(function(){return t.forceStateChange()})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"ha-card",properties:{title:{type:String},header:{type:String}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(34),o=r(i),u=n(2),a=n(1),s=r(a),c=6e4,l=u.util.parseDateTime;e["default"]=new s["default"]({is:"relative-ha-datetime",properties:{datetime:{type:String,observer:"datetimeChanged"},datetimeObj:{type:Object,observer:"datetimeObjChanged"},parsedDateTime:{type:Object},relativeTime:{type:String,value:"not set"}},created:function(){this.updateRelative=this.updateRelative.bind(this)},attached:function(){this._interval=setInterval(this.updateRelative,c)},detached:function(){clearInterval(this._interval)},datetimeChanged:function(t){this.parsedDateTime=t?l(t):null,this.updateRelative()},datetimeObjChanged:function(t){this.parsedDateTime=t,this.updateRelative()},updateRelative:function(){this.relativeTime=this.parsedDateTime?o["default"](this.parsedDateTime).fromNow():""}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(19),n(91),n(90),e["default"]=new o["default"]({is:"state-history-charts",properties:{stateHistory:{type:Object},isLoadingData:{type:Boolean,value:!1},apiLoaded:{type:Boolean,value:!1},isLoading:{type:Boolean,computed:"computeIsLoading(isLoadingData, apiLoaded)"},groupedStateHistory:{type:Object,computed:"computeGroupedStateHistory(isLoading, stateHistory)"},isSingleDevice:{type:Boolean,computed:"computeIsSingleDevice(stateHistory)"}},computeIsSingleDevice:function(t){return t&&1===t.size},computeGroupedStateHistory:function(t,e){if(t||!e)return{line:[],timeline:[]};var n={},r=[];e.forEach(function(t){if(t&&0!==t.size){var e=t.find(function(t){return"unit_of_measurement"in t.attributes}),i=e?e.attributes.unit_of_measurement:!1;i?i in n?n[i].push(t.toArray()):n[i]=[t.toArray()]:r.push(t.toArray())}}),r=r.length>0&&r;var i=Object.keys(n).map(function(t){return[t,n[t]]});return{line:i,timeline:r}},googleApiLoaded:function(){var t=this;window.google.load("visualization","1",{packages:["timeline","corechart"],callback:function(){return t.apiLoaded=!0}})},computeContentClasses:function(t){return t?"loading":""},computeIsLoading:function(t,e){return t||!e},computeIsEmpty:function(t){return t&&0===t.size},extractUnit:function(t){return t[0]},extractData:function(t){return t[1]}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(9),e["default"]=new o["default"]({is:"state-card-display",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e){"use strict";function n(t,e){switch(t){case"homeassistant":return"home";case"group":return"homeassistant-24:group";case"device_tracker":return"social:person";case"switch":return"image:flash-on";case"alarm_control_panel":return e&&"disarmed"===e?"icons:lock-open":"icons:lock";case"media_player":var n="hardware:cast";return e&&"off"!==e&&"idle"!==e&&(n+="-connected"),n;case"sun":return"image:wb-sunny";case"light":return"image:wb-incandescent";case"simple_alarm":return"social:notifications";case"notify":return"announcement";case"thermostat":return"homeassistant-100:thermostat";case"sensor":return"visibility";case"configurator":return"settings";case"conversation":return"av:hearing";case"script":return"description";case"scene":return"social:pages";case"updater":return"update_available"===e?"icons:cloud-download":"icons:cloud-done";default:return"bookmark"}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return u["default"](t).format("LT")}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(34),u=r(o);t.exports=e["default"]},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(2);e["default"]=function(t,e){r.authActions.validate(t,{rememberAuth:e,useStreaming:r.localStoragePreferences.useStreaming})},t.exports=e["default"]},function(t,e,n){"use strict";function r(t,e){var n=null==t?void 0:t[e];return i(n)?n:void 0}var i=n(129);t.exports=r},function(t,e){"use strict";function n(t){return!!t&&"object"==typeof t}t.exports=n},function(t,e,n){"use strict";function r(t){return i(t)&&a.call(t)==o}var i=n(46),o="[object Function]",u=Object.prototype,a=u.toString;t.exports=r},function(t,e){"use strict";function n(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}t.exports=n},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(3),i=["isLoadingEntityHistory"];e.isLoadingEntityHistory=i;var o=["currentEntityHistoryDate"];e.currentDate=o;var u=["entityHistory"];e.entityHistoryMap=u;var a=[o,u,function(t,e){return e.get(t)||r.toImmutable({})}];e.entityHistoryForCurrentDate=a;var s=[o,u,function(t,e){return!!e.get(t)}];e.hasDataForCurrentDate=s;var c=["recentEntityHistory"];e.recentEntityHistoryMap=c;var l=["recentEntityHistory"];e.recentEntityHistoryUpdatedMap=l},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({currentEntityHistoryDate:a["default"],entityHistory:c["default"],isLoadingEntityHistory:f["default"],recentEntityHistory:p["default"],recentEntityHistoryUpdated:_["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(141),a=i(u),s=n(142),c=i(s),l=n(143),f=i(l),d=n(144),p=i(d),h=n(145),_=i(h),v=n(140),y=r(v),m=n(47),g=r(m),b=y;e.actions=b;var O=g;e.getters=O},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var o=function(){function t(t,e){for(var n=0;n6e4}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var u=n(167),a=n(187),s=i(a),c=n(189),l=i(c),f=n(191),d=i(f),p=n(15),h=r(p),_=n(25),v=r(_),y=n(7),m=r(y),g=n(48),b=r(g),O=n(26),w=r(O),S=n(152),M=r(S),T=n(51),E=r(T),j=n(54),I=r(j),P=n(28),D=r(P),C=n(13),A=r(C),k=n(29),x=r(k),L=n(31),N=r(L),z=n(184),R=r(z),H=n(8),Y=r(H),G=function F(){o(this,F);var t=s["default"]();Object.defineProperties(this,{demo:{value:!1,enumerable:!0},localStoragePreferences:{value:u.localStoragePreferences,enumerable:!0},reactor:{value:t,enumerable:!0},util:{value:d["default"],enumerable:!0},startLocalStoragePreferencesSync:{value:u.localStoragePreferences.startSync.bind(u.localStoragePreferences,t)},startUrlSync:{value:I.urlSync.startSync.bind(null,t)},stopUrlSync:{value:I.urlSync.stopSync.bind(null,t)}}),l["default"](this,t,{auth:h,config:v,entity:m,entityHistory:b,event:w,logbook:M,moreInfo:E,navigation:I,notification:D,service:A,stream:x,sync:N,voice:R,restApi:Y})};e["default"]=G,t.exports=e["default"]},function(t,e){"use strict";function n(t){return function(e){return null==e?void 0:e[t]}}t.exports=n},function(t,e,n){"use strict";var r=n(64),i=r("length");t.exports=i},function(t,e,n){"use strict";function r(t){return null!=t&&o(i(t))}var i=n(65),o=n(69);t.exports=r},function(t,e){"use strict";function n(t,e){return t="number"==typeof t||r.test(t)?+t:-1,e=null==e?i:e,t>-1&&t%1==0&&e>t}var r=/^\d+$/,i=9007199254740991;t.exports=n},function(t,e,n){"use strict";function r(t,e,n){if(!u(n))return!1;var r=typeof e;if("number"==r?i(n)&&o(e,n.length):"string"==r&&e in n){var a=n[e];return t===t?t===a:a!==a}return!1}var i=n(66),o=n(67),u=n(70);t.exports=r},function(t,e){"use strict";function n(t){return"number"==typeof t&&t>-1&&t%1==0&&r>=t}var r=9007199254740991;t.exports=n},function(t,e){"use strict";function n(t){var e=typeof t;return!!t&&("object"==e||"function"==e)}t.exports=n},function(t,e,n){"use strict";function r(t,e,n){n&&i(t,e,n)&&(e=n=void 0),t=+t||0,n=null==n?1:+n||0,null==e?(e=t,t=0):e=+e||0;for(var r=-1,a=u(o((e-t)/(n||1)),0),s=Array(a);++r1}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(36),e["default"]=new o["default"]({is:"ha-introduction-card",properties:{showInstallInstruction:{type:Boolean,value:!1},showHideInstruction:{type:Boolean,value:!0}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(41),a=r(u);e["default"]=new o["default"]({is:"display-time",properties:{dateObj:{type:Object}},computeTime:function(t){return t?a["default"](t):""}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"entity-list",behaviors:[s["default"]],properties:{entities:{type:Array,bindNuclear:[i.entityGetters.entityMap,function(t){return t.valueSeq().sortBy(function(t){return t.entityId}).toArray()}]}},entitySelected:function(t){t.preventDefault(),this.fire("entity-selected",{entityId:t.model.entity.entityId})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2);n(18),e["default"]=new o["default"]({is:"ha-entity-marker",properties:{entityId:{type:String,value:""},state:{type:Object,computed:"computeState(entityId)"},icon:{type:Object,computed:"computeIcon(state)"},image:{type:Object,computed:"computeImage(state)"},value:{type:String,computed:"computeValue(state)"}},listeners:{click:"badgeTap"},badgeTap:function(t){var e=this;t.stopPropagation(),this.entityId&&this.async(function(){return u.moreInfoActions.selectEntity(e.entityId)},1)},computeState:function(t){return t&&u.reactor.evaluate(u.entityGetters.byId(t))},computeIcon:function(t){return!t&&"home"},computeImage:function(t){return t&&t.attributes.entity_picture},computeValue:function(t){return t&&t.entityDisplay.split(" ").map(function(t){return t.substr(0,1)}).join("")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2),a=n(40),s=r(a),c=n(22),l=r(c);n(18),e["default"]=new o["default"]({is:"ha-state-label-badge",properties:{state:{type:Object,observer:"stateChanged"}},listeners:{click:"badgeTap"},badgeTap:function(t){var e=this;return t.stopPropagation(),l["default"](this.state.entityId)?void("scene"===this.state.domain?u.serviceActions.callTurnOn(this.state.entityId):"off"===this.state.state?u.serviceActions.callTurnOn(this.state.entityId):u.serviceActions.callTurnOff(this.state.entityId)):void this.async(function(){return u.moreInfoActions.selectEntity(e.state.entityId)},1)},computeClasses:function(t){switch(t.domain){case"scene":return"green";case"script":return"on"===t.state?"blue":"grey";default:return""}},computeGlow:function(t){switch(t.domain){case"scene":case"script":return"on"===t.state;default:return!1}},computeValue:function(t){switch(t.domain){case"device_tracker":case"sun":case"scene":case"script":case"alarm_control_panel":return void 0;case"sensor":return t.attributes.unit_of_measurement&&t.state;default:return t.state}},computeIcon:function(t){switch(t.domain){case"device_tracker":case"alarm_control_panel":case"scene":case"script":return s["default"](t.domain,t.state);case"sensor":return!t.attributes.unit_of_measurement&&s["default"](t.domain);case"sun":return"above_horizon"===t.state?"image:wb-sunny":"image:brightness-3";default:return void 0}},computeImage:function(t){return t.attributes.entity_picture},computeLabel:function(t){switch(t.domain){case"scene":case"script":return t.domain;case"sensor":return t.attributes.unit_of_measurement||t.state;case"device_tracker":return"not_home"===t.state?"Away":t.state;case"alarm_control_panel":return t.state;default:return t.attributes.unit_of_measurement}},computeDescription:function(t){return t.entityDisplay},stateChanged:function(){this.updateStyles()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(124),a=r(u);n(17),e["default"]=new o["default"]({is:"state-badge",properties:{stateObj:{type:Object,observer:"updateIconColor"}},updateIconColor:function(t){if("light"===t.domain&&"on"===t.state&&t.attributes.brightness&&t.attributes.xy_color){var e=a["default"](t.attributes.xy_color[0],t.attributes.xy_color[1],t.attributes.brightness);this.$.icon.style.color="rgb("+e.map(Math.floor).join(",")+")"}else this.$.icon.style.color=null}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"events-list",behaviors:[s["default"]],properties:{events:{type:Array,bindNuclear:[i.eventGetters.entityMap,function(t){return t.valueSeq().sortBy(function(t){return t.event}).toArray()}]}},eventSelected:function(t){t.preventDefault(),this.fire("event-selected",{eventType:t.model.event.event})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function o(t){return"#"+i(t.r)+i(t.g)+i(t.b)}Object.defineProperty(e,"__esModule",{value:!0});var u=n(1),a=r(u);e["default"]=new a["default"]({is:"ha-color-picker",properties:{width:{type:Number,value:300},height:{type:Number,value:300},color:{type:Object}},listeners:{mousedown:"onMouseDown",mouseup:"onMouseUp",touchstart:"onTouchStart",touchend:"onTouchEnd",tap:"onTap"},onMouseDown:function(t){this.onMouseMove(t),this.addEventListener("mousemove",this.onMouseMove)},onMouseUp:function(){this.removeEventListener("mousemove",this.onMouseMove)},onTouchStart:function(t){this.onTouchMove(t),this.addEventListener("touchmove",this.onTouchMove)},onTouchEnd:function(){this.removeEventListener("touchmove",this.onTouchMove)},onTap:function(t){t.stopPropagation()},onTouchMove:function(t){var e=t.touches[0];this.onColorSelect(t,{x:e.clientX,y:e.clientY})},onMouseMove:function(t){var e=this;t.preventDefault(),this.mouseMoveIsThrottled&&(this.mouseMoveIsThrottled=!1,this.onColorSelect(t),this.async(function(){return e.mouseMoveIsThrottled=!0},100))},onColorSelect:function(t,e){if(this.context){var n=e||this.relativeMouseCoordinates(t),r=this.context.getImageData(n.x,n.y,1,1).data;this.setColor({r:r[0],g:r[1],b:r[2]})}},setColor:function(t){this.color={hex:o(t),rgb:t},this.fire("colorselected",{rgb:this.color.rgb,hex:this.color.hex})},relativeMouseCoordinates:function(t){var e=0,n=0;if(this.canvas){var r=this.canvas.getBoundingClientRect();e=t.clientX-r.left,n=t.clientY-r.top}return{x:e,y:n}},ready:function(){this.setColor=this.setColor.bind(this),this.mouseMoveIsThrottled=!0,this.canvas=this.children[0],this.context=this.canvas.getContext("2d");var t=this.context.createLinearGradient(0,0,this.width,0);t.addColorStop(0,"rgb(255,0,0)"),t.addColorStop(.16,"rgb(255,0,255)"),t.addColorStop(.32,"rgb(0,0,255)"),t.addColorStop(.48,"rgb(0,255,255)"),t.addColorStop(.64,"rgb(0,255,0)"),t.addColorStop(.8,"rgb(255,255,0)"),t.addColorStop(1,"rgb(255,0,0)"),this.context.fillStyle=t,this.context.fillRect(0,0,this.width,this.height);var e=this.context.createLinearGradient(0,0,0,this.height);e.addColorStop(0,"rgba(255,255,255,1)"),e.addColorStop(.5,"rgba(255,255,255,0)"),e.addColorStop(.5,"rgba(0,0,0,0)"),e.addColorStop(1,"rgba(0,0,0,1)"),this.context.fillStyle=e,this.context.fillRect(0,0,this.width,this.height)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(18),e["default"]=new o["default"]({is:"ha-demo-badge"}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(88),e["default"]=new o["default"]({is:"ha-logbook",properties:{entries:{type:Object,value:[]}},noEntries:function(t){return!t.length}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(92),e["default"]=new u["default"]({is:"ha-sidebar",behaviors:[s["default"]],properties:{menuShown:{type:Boolean},menuSelected:{type:String},selected:{type:String,bindNuclear:i.navigationGetters.activePane,observer:"selectedChanged"},hasHistoryComponent:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("history")},hasLogbookComponent:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("logbook")}},selectedChanged:function(t){for(var e=this.querySelectorAll(".menu [data-panel]"),n=0;nd;d++)f._columns[d]=[];var p=0;return n&&u(),c.keySeq().sortBy(function(t){return i(t)}).forEach(function(t){if("a"===t)return void(f._demo=!0);var n=i(t);n>=0&&10>n?f._badges.push.apply(f._badges,r(c.get(t)).sortBy(o).toArray()):"group"===t?c.get(t).filter(function(t){return!t.attributes.auto}).sortBy(o).forEach(function(t){var n=s.util.expandGroup(t,e);n.forEach(function(t){return l[t.entityId]=!0}),a(t.entityDisplay,n.toArray(),t)}):a(t,r(c.get(t)).sortBy(o).toArray())}),f},computeShouldRenderColumn:function(t,e){return 0===t||e.length},computeShowIntroduction:function(t,e,n){return 0===t&&(e||n._demo)},computeShowHideInstruction:function(t,e){return t.size>0&&!0&&!e._demo},computeGroupEntityOfCard:function(t,e){return t[e].groupEntity},computeStatesOfCard:function(t,e){return t[e].entities}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(17),n(76),n(37),e["default"]=new u["default"]({is:"logbook-entry",entityClicked:function(t){t.preventDefault(),i.moreInfoActions.selectEntity(this.entryObj.entityId)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(17),e["default"]=new u["default"]({is:"services-list",behaviors:[s["default"]],properties:{serviceDomains:{type:Array,bindNuclear:i.serviceGetters.entityMap}},computeDomains:function(t){return t.valueSeq().map(function(t){return t.domain}).sort().toJS()},computeServices:function(t,e){return t.get(e).get("services").keySeq().toArray()},serviceClicked:function(t){t.preventDefault(),this.fire("service-selected",{domain:t.model.domain,service:t.model.service})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){var e=parseFloat(t);return!isNaN(e)&&isFinite(e)?e:null}Object.defineProperty(e,"__esModule",{value:!0});var o=n(71),u=r(o),a=n(1),s=r(a);e["default"]=new s["default"]({is:"state-history-chart-line",properties:{data:{type:Object,observer:"dataChanged"},unit:{type:String},isSingleDevice:{type:Boolean,value:!1},isAttached:{type:Boolean,value:!1,observer:"dataChanged"},chartEngine:{type:Object}},created:function(){this.style.display="block"},attached:function(){this.isAttached=!0},dataChanged:function(){this.drawChart()},drawChart:function(){if(this.isAttached){this.chartEngine||(this.chartEngine=new window.google.visualization.LineChart(this));var t=this.unit,e=this.data;if(0!==e.length){var n={legend:{position:"top"},interpolateNulls:!0,titlePosition:"none",vAxes:{0:{title:t}},hAxis:{format:"H:mm"},chartArea:{left:"60",width:"95%"},explorer:{actions:["dragToZoom","rightClickToReset","dragToPan"],keepInBounds:!0,axis:"horizontal",maxZoomIn:.1}};this.isSingleDevice&&(n.legend.position="none",n.vAxes[0].title=null,n.chartArea.left=40,n.chartArea.height="80%",n.chartArea.top=5,n.enableInteractivity=!1);var r=new Date(Math.min.apply(null,e.map(function(t){return t[0].lastChangedAsDate}))),o=new Date(r);o.setDate(o.getDate()+1),o>new Date&&(o=new Date);var a=e.map(function(t){function e(t,e){c&&e&&s.push([t[0]].concat(c.slice(1).map(function(t,n){return e[n]?t:null}))),s.push(t),c=t}var n=t[t.length-1],r=n.domain,u=n.entityDisplay,a=new window.google.visualization.DataTable;a.addColumn({type:"datetime",id:"Time"});var s=[],c=void 0;if("thermostat"===r){var l=t.reduce(function(t,e){return t||e.attributes.target_temp_high!==e.attributes.target_temp_low},!1);a.addColumn("number",u+" current temperature");var f=void 0;l?!function(){a.addColumn("number",u+" target temperature high"),a.addColumn("number",u+" target temperature low");var t=[!1,!0,!0];f=function(n){var r=i(n.attributes.current_temperature),o=i(n.attributes.target_temp_high),u=i(n.attributes.target_temp_low);e([n.lastChangedAsDate,r,o,u],t)}}():!function(){a.addColumn("number",u+" target temperature");var t=[!1,!0];f=function(n){var r=i(n.attributes.current_temperature),o=i(n.attributes.temperature);e([n.lastChangedAsDate,r,o],t)}}(),t.forEach(f)}else!function(){a.addColumn("number",u);var n="sensor"!==r&&[!0];t.forEach(function(t){var r=i(t.state);e([t.lastChangedAsDate,r],n)})}();return e([o].concat(c.slice(1)),!1),a.addRows(s),a}),s=void 0;s=1===a.length?a[0]:a.slice(1).reduce(function(t,e){return window.google.visualization.data.join(t,e,"full",[[0,0]],u["default"](1,t.getNumberOfColumns()),u["default"](1,e.getNumberOfColumns()))},a[0]),this.chartEngine.draw(s,n)}}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"state-history-chart-timeline",properties:{data:{type:Object,observer:"dataChanged"},isAttached:{type:Boolean,value:!1,observer:"dataChanged"}},attached:function(){this.isAttached=!0},dataChanged:function(){this.drawChart()},drawChart:function(){function t(t,e,n,r){var o=e.replace(/_/g," ");i.addRow([t,o,n,r])}if(this.isAttached){for(var e=o["default"].dom(this),n=this.data;e.node.lastChild;)e.node.removeChild(e.node.lastChild);if(n&&0!==n.length){var r=new window.google.visualization.Timeline(this),i=new window.google.visualization.DataTable;i.addColumn({type:"string",id:"Entity"}),i.addColumn({type:"string",id:"State"}),i.addColumn({type:"date",id:"Start"}),i.addColumn({type:"date",id:"End"});var u=new Date(n.reduce(function(t,e){return Math.min(t,e[0].lastChangedAsDate)},new Date)),a=new Date(u);a.setDate(a.getDate()+1),a>new Date&&(a=new Date);var s=0;n.forEach(function(e){if(0!==e.length){var n=e[0].entityDisplay,r=void 0,i=null,o=null;e.forEach(function(e){null!==i&&e.state!==i?(r=e.lastChangedAsDate,t(n,i,o,r),i=e.state,o=r):null===i&&(i=e.state,o=e.lastChangedAsDate)}),t(n,i,o,a),s++}}),r.draw(i,{height:55+42*s,timeline:{showRowLabels:n.length>1},hAxis:{format:"H:mm"}})}}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"stream-status",behaviors:[s["default"]],properties:{isStreaming:{type:Boolean,bindNuclear:i.streamGetters.isStreamingEvents},hasError:{type:Boolean,bindNuclear:i.streamGetters.hasStreamingEventsError}},toggleChanged:function(){this.isStreaming?i.streamActions.stop():i.streamActions.start()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(20),n(38),n(107);var c=["camera","configurator","scene"];e["default"]=new u["default"]({is:"more-info-dialog",behaviors:[s["default"]],properties:{stateObj:{type:Object,bindNuclear:i.moreInfoGetters.currentEntity,observer:"stateObjChanged"},stateHistory:{type:Object,bindNuclear:[i.moreInfoGetters.currentEntityHistory,function(t){return t?[t]:!1}]},isLoadingHistoryData:{type:Boolean,computed:"computeIsLoadingHistoryData(_delayedDialogOpen, _isLoadingHistoryData)"},_isLoadingHistoryData:{type:Boolean,bindNuclear:i.entityHistoryGetters.isLoadingEntityHistory},hasHistoryComponent:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("history"),observer:"fetchHistoryData"},shouldFetchHistory:{type:Boolean,bindNuclear:i.moreInfoGetters.isCurrentEntityHistoryStale,observer:"fetchHistoryData"},showHistoryComponent:{type:Boolean,value:!1},dialogOpen:{type:Boolean,value:!1,observer:"dialogOpenChanged"},_delayedDialogOpen:{type:Boolean,value:!1},_boundOnBackdropTap:{type:Function,value:function(){return this._onBackdropTap.bind(this)}}},computeIsLoadingHistoryData:function(t,e){return!t||e},fetchHistoryData:function(){this.stateObj&&this.hasHistoryComponent&&this.shouldFetchHistory&&i.entityHistoryActions.fetchRecent(this.stateObj.entityId)},stateObjChanged:function(t){var e=this;return t?(this.showHistoryComponent=this.hasHistoryComponent&&-1===c.indexOf(this.stateObj.domain),void this.async(function(){e.fetchHistoryData(),e.dialogOpen=!0},10)):void(this.dialogOpen=!1)},dialogOpenChanged:function(t){var e=this;t?(this.$.dialog.backdropElement.addEventListener("click",this._boundOnBackdropTap),this.async(function(){return e._delayedDialogOpen=!0},10)):!t&&this.stateObj&&(i.moreInfoActions.deselectEntity(),this._delayedDialogOpen=!1)},_onBackdropTap:function(){this.$.dialog.backdropElement.removeEventListener("click",this._boundOnBackdropTap),this.dialogOpen=!1}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2),a=n(4),s=r(a);n(85),n(102),n(100),n(99),n(101),n(96),n(97),n(98),n(103),n(93),e["default"]=new o["default"]({is:"home-assistant-main",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},activePane:{type:String,bindNuclear:u.navigationGetters.activePane,observer:"activePaneChanged"},isSelectedStates:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("states")},isSelectedHistory:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("history")},isSelectedMap:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("map")},isSelectedLogbook:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("logbook")},isSelectedDevEvent:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("devEvent")},isSelectedDevState:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("devState")},isSelectedDevService:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("devService")},showSidebar:{type:Boolean,bindNuclear:u.navigationGetters.showSidebar}},listeners:{"open-menu":"openMenu","close-menu":"closeMenu"},openMenu:function(){this.narrow?this.$.drawer.openDrawer():u.navigationActions.showSidebar(!0)},closeMenu:function(){this.$.drawer.closeDrawer(),this.showSidebar&&u.navigationActions.showSidebar(!1)},activePaneChanged:function(){this.narrow&&this.$.drawer.closeDrawer()},attached:function(){u.startUrlSync()},computeForceNarrow:function(t,e){return t||!e},detached:function(){u.stopUrlSync()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2),a=n(4),s=r(a),c=n(42),l=r(c);e["default"]=new o["default"]({is:"login-form",behaviors:[s["default"]],properties:{isValidating:{type:Boolean,observer:"isValidatingChanged",bindNuclear:u.authGetters.isValidating},isInvalid:{type:Boolean,bindNuclear:u.authGetters.isInvalidAttempt},errorMessage:{type:String,bindNuclear:u.authGetters.attemptErrorMessage}},listeners:{keydown:"passwordKeyDown","loginButton.click":"validatePassword"},observers:["validatingChanged(isValidating, isInvalid)"],validatingChanged:function(t,e){t||e||(this.$.passwordInput.value="")},isValidatingChanged:function(t){var e=this;t||this.async(function(){return e.$.passwordInput.focus()},10)},passwordKeyDown:function(t){13===t.keyCode?(this.validatePassword(),t.preventDefault()):this.isInvalid&&(this.isInvalid=!1)},validatePassword:function(){this.$.hideKeyboardOnFocus.focus(),l["default"](this.$.passwordInput.value,this.$.rememberLogin.checked)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(10),n(89),e["default"]=new u["default"]({is:"partial-dev-call-service",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},domain:{type:String,value:""},service:{type:String,value:""},serviceData:{type:String,value:""},description:{type:String,computed:"computeDescription(domain, service)"}},computeDescription:function(t,e){return i.reactor.evaluate([i.serviceGetters.entityMap,function(n){return n.has(t)&&n.get(t).get("services").has(e)?JSON.stringify(n.get(t).get("services").get(e).toJS(),null,2):"No description available"; +}])},serviceSelected:function(t){this.domain=t.detail.domain,this.service=t.detail.service},callService:function(){var t=void 0;try{t=this.serviceData?JSON.parse(this.serviceData):{}}catch(e){return void alert("Error parsing JSON: "+e)}i.serviceActions.callService(this.domain,this.service,t)},computeFormClasses:function(t){return"layout "+(t?"vertical":"horizontal")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(10),n(81),e["default"]=new u["default"]({is:"partial-dev-fire-event",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},eventType:{type:String,value:""},eventData:{type:String,value:""}},eventSelected:function(t){this.eventType=t.detail.eventType},fireEvent:function(){var t=void 0;try{t=this.eventData?JSON.parse(this.eventData):{}}catch(e){return void alert("Error parsing JSON: "+e)}i.eventActions.fireEvent(this.eventType,t)},computeFormClasses:function(t){return"layout "+(t?"vertical":"horizontal")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);n(10),n(77),e["default"]=new u["default"]({is:"partial-dev-set-state",properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},entityId:{type:String,value:""},state:{type:String,value:""},stateAttributes:{type:String,value:""}},setStateData:function(t){var e=t?JSON.stringify(t,null," "):"";this.$.inputData.value=e,this.$.inputDataWrapper.update(this.$.inputData)},entitySelected:function(t){var e=i.reactor.evaluate(i.entityGetters.byId(t.detail.entityId));this.entityId=e.entityId,this.state=e.state,this.stateAttributes=JSON.stringify(e.attributes,null," ")},handleSetState:function(){var t=void 0;try{t=this.stateAttributes?JSON.parse(this.stateAttributes):{}}catch(e){return void alert("Error parsing JSON: "+e)}i.entityActions.save({entityId:this.entityId,state:this.state,attributes:t})},computeFormClasses:function(t){return"layout "+(t?"vertical":"horizontal")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(10),n(38),e["default"]=new u["default"]({is:"partial-history",behaviors:[s["default"]],properties:{narrow:{type:Boolean},showMenu:{type:Boolean,value:!1},isDataLoaded:{type:Boolean,bindNuclear:i.entityHistoryGetters.hasDataForCurrentDate,observer:"isDataLoadedChanged"},stateHistory:{type:Object,bindNuclear:i.entityHistoryGetters.entityHistoryForCurrentDate},isLoadingData:{type:Boolean,bindNuclear:i.entityHistoryGetters.isLoadingEntityHistory},selectedDate:{type:String,value:null,bindNuclear:i.entityHistoryGetters.currentDate}},isDataLoadedChanged:function(t){t||this.async(function(){return i.entityHistoryActions.fetchSelectedDate()},1)},handleRefreshClick:function(){i.entityHistoryActions.fetchSelectedDate()},datepickerFocus:function(){this.datePicker.adjustPosition()},attached:function(){this.datePicker=new window.Pikaday({field:this.$.datePicker.inputElement,onSelect:i.entityHistoryActions.changeCurrentDate})},detached:function(){this.datePicker.destroy()},computeContentClasses:function(t){return"flex content "+(t?"narrow":"wide")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(10),n(84),n(19),e["default"]=new u["default"]({is:"partial-logbook",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},selectedDate:{type:String,bindNuclear:i.logbookGetters.currentDate},isLoading:{type:Boolean,bindNuclear:i.logbookGetters.isLoadingEntries},isStale:{type:Boolean,bindNuclear:i.logbookGetters.isCurrentStale,observer:"isStaleChanged"},entries:{type:Array,bindNuclear:[i.logbookGetters.currentEntries,function(t){return t.reverse().toArray()}]},datePicker:{type:Object}},isStaleChanged:function(t){var e=this;t&&this.async(function(){return i.logbookActions.fetchDate(e.selectedDate)},1)},handleRefresh:function(){i.logbookActions.fetchDate(this.selectedDate)},datepickerFocus:function(){this.datePicker.adjustPosition()},attached:function(){this.datePicker=new window.Pikaday({field:this.$.datePicker.inputElement,onSelect:i.logbookActions.changeCurrentDate})},detached:function(){this.datePicker.destroy()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(78),window.L.Icon.Default.imagePath="/static/images/leaflet",e["default"]=new u["default"]({is:"partial-map",behaviors:[s["default"]],properties:{locationGPS:{type:Number,bindNuclear:i.configGetters.locationGPS},locationName:{type:String,bindNuclear:i.configGetters.locationName},locationEntities:{type:Array,bindNuclear:[i.entityGetters.visibleEntityMap,function(t){return t.valueSeq().filter(function(t){return t.attributes.latitude&&"home"!==t.state}).toArray()}]},zoneEntities:{type:Array,bindNuclear:[i.entityGetters.entityMap,function(t){return t.valueSeq().filter(function(t){return"zone"===t.domain}).toArray()}]},narrow:{type:Boolean},showMenu:{type:Boolean,value:!1}},attached:function(){var t=this;window.L.Browser.mobileWebkit&&this.async(function(){var e=t.$.map,n=e.style.display;e.style.display="none",t.async(function(){e.style.display=n},1)},1)},computeMenuButtonClass:function(t,e){return!t&&e?"invisible":""},toggleMenu:function(){this.fire("open-menu")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(10),n(86),n(87),e["default"]=new u["default"]({is:"partial-zone",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},isFetching:{type:Boolean,bindNuclear:i.syncGetters.isFetching},isStreaming:{type:Boolean,bindNuclear:i.streamGetters.isStreamingEvents},canListen:{type:Boolean,bindNuclear:[i.voiceGetters.isVoiceSupported,i.configGetters.isComponentLoaded("conversation"),function(t,e){return t&&e}]},isListening:{type:Boolean,bindNuclear:i.voiceGetters.isListening},showListenInterface:{type:Boolean,bindNuclear:[i.voiceGetters.isListening,i.voiceGetters.isTransmitting,function(t,e){return t||e}]},introductionLoaded:{type:Boolean,bindNuclear:i.configGetters.isComponentLoaded("introduction")},locationName:{type:String,bindNuclear:i.configGetters.locationName},showMenu:{type:Boolean,value:!1,observer:"windowChange"},states:{type:Object,bindNuclear:i.entityGetters.visibleEntityMap},columns:{type:Number}},created:function(){var t=this;this.windowChange=this.windowChange.bind(this);for(var e=[],n=0;5>n;n++)e.push(278+278*n);this.mqls=e.map(function(e){var n=window.matchMedia("(min-width: "+e+"px)");return n.addListener(t.windowChange),n})},detached:function(){var t=this;this.mqls.forEach(function(e){return e.removeListener(t.windowChange)})},windowChange:function(){var t=this.mqls.reduce(function(t,e){return t+e.matches},0);this.columns=Math.max(1,t-this.showMenu)},handleRefresh:function(){i.syncActions.fetchAll()},handleListenClick:function(){this.isListening?i.voiceActions.stop():i.voiceActions.listen()},computeDomains:function(t){return t.keySeq().toArray()},computeMenuButtonClass:function(t,e){return!t&&e?"invisible":""},computeStatesOfDomain:function(t,e){return t.get(e).toArray()},computeListenButtonIcon:function(t){return t?"av:mic-off":"av:mic"},computeRefreshButtonClass:function(t){return t?"ha-spin":void 0},computeShowIntroduction:function(t,e){return t||0===e.size},toggleMenu:function(){this.fire("open-menu")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);e["default"]=new u["default"]({is:"notification-manager",behaviors:[s["default"]],properties:{text:{type:String,bindNuclear:i.notificationGetters.lastNotificationMessage,observer:"showNotification"}},showNotification:function(t){t&&this.$.toast.show()}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o);e["default"]=new u["default"]({is:"more-info-alarm_control_panel",handleDisarmTap:function(){this.callService("alarm_disarm",{code:this.enteredCode})},handleHomeTap:function(){this.callService("alarm_arm_home",{code:this.enteredCode})},handleAwayTap:function(){this.callService("alarm_arm_away",{code:this.enteredCode})},properties:{stateObj:{type:Object,observer:"stateObjChanged"},enteredCode:{type:String,value:""},disarmButtonVisible:{type:Boolean,value:!1},armHomeButtonVisible:{type:Boolean,value:!1},armAwayButtonVisible:{type:Boolean,value:!1},codeInputVisible:{type:Boolean,value:!1},codeInputEnabled:{type:Boolean,value:!1},codeFormat:{type:String,value:""},codeValid:{type:Boolean,computed:"validateCode(enteredCode, codeFormat)"}},validateCode:function(t,e){var n=new RegExp(e);return null===e?!0:n.test(t)},stateObjChanged:function(t){var e=this;t&&(this.codeFormat=t.attributes.code_format,this.codeInputVisible=null!==this.codeFormat,this.codeInputEnabled="armed_home"===t.state||"armed_away"===t.state||"disarmed"===t.state||"pending"===t.state||"triggered"===t.state,this.disarmButtonVisible="armed_home"===t.state||"armed_away"===t.state||"pending"===t.state||"triggered"===t.state,this.armHomeButtonVisible="disarmed"===t.state,this.armAwayButtonVisible="disarmed"===t.state),this.async(function(){return e.fire("iron-resize")},500)},callService:function(t,e){var n=e||{};n.entity_id=this.stateObj.entityId,i.serviceActions.callService("alarm_control_panel",t,n)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"more-info-camera",properties:{stateObj:{type:Object},dialogOpen:{type:Boolean}},imageLoaded:function(){this.fire("iron-resize")},computeCameraImageUrl:function(t){return t?"/api/camera_proxy_stream/"+this.stateObj.entityId:"data:image/gif;base64,R0lGODlhAQABAAAAACw="}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(19),e["default"]=new u["default"]({is:"more-info-configurator",behaviors:[s["default"]],properties:{stateObj:{type:Object},action:{type:String,value:"display"},isStreaming:{type:Boolean,bindNuclear:i.streamGetters.isStreamingEvents},isConfigurable:{type:Boolean,computed:"computeIsConfigurable(stateObj)"},isConfiguring:{type:Boolean,value:!1},submitCaption:{type:String,computed:"computeSubmitCaption(stateObj)"},fieldInput:{type:Object,value:{}}},computeIsConfigurable:function(t){return"configure"===t.state},computeSubmitCaption:function(t){return t.attributes.submit_caption||"Set configuration"},fieldChanged:function(t){var e=t.target;this.fieldInput[e.id]=e.value},submitClicked:function(){var t=this;this.isConfiguring=!0;var e={configure_id:this.stateObj.attributes.configure_id,fields:this.fieldInput};i.serviceActions.callService("configurator","configure",e).then(function(){t.isConfiguring=!1,t.isStreaming||i.syncActions.fetchAll()},function(){t.isConfiguring=!1})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(123),a=r(u);n(108),n(109),n(113),n(106),n(114),n(112),n(110),n(111),n(105),n(115),n(104),e["default"]=new o["default"]({is:"more-info-content",properties:{stateObj:{type:Object,observer:"stateObjChanged"},dialogOpen:{type:Boolean,value:!1,observer:"dialogOpenChanged"}},dialogOpenChanged:function(t){var e=o["default"].dom(this);e.lastChild&&(e.lastChild.dialogOpen=t)},stateObjChanged:function(t,e){var n=o["default"].dom(this);if(!t)return void(n.lastChild&&n.removeChild(n.lastChild));var r=a["default"](t);if(e&&a["default"](e)===r)n.lastChild.dialogOpen=this.dialogOpen,n.lastChild.stateObj=t;else{n.lastChild&&n.removeChild(n.lastChild);var i=document.createElement("more-info-"+r);i.stateObj=t,i.dialogOpen=this.dialogOpen,n.appendChild(i)}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=["entity_picture","friendly_name","unit_of_measurement"];e["default"]=new o["default"]({is:"more-info-default",properties:{stateObj:{type:Object}},computeDisplayAttributes:function(t){return t?Object.keys(t.attributes).filter(function(t){return-1===u.indexOf(t)}):[]},getAttributeValue:function(t,e){return t.attributes[e]}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(4),s=r(a);n(20),e["default"]=new u["default"]({is:"more-info-group",behaviors:[s["default"]],properties:{stateObj:{type:Object},states:{type:Array,bindNuclear:[i.moreInfoGetters.currentEntity,i.entityGetters.entityMap,function(t,e){return t?t.attributes.entity_id.map(e.get.bind(e)):[]}]}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(21),s=r(a);n(82);var c=["brightness","xy_color"];e["default"]=new u["default"]({is:"more-info-light",properties:{stateObj:{type:Object,observer:"stateObjChanged"},brightnessSliderValue:{type:Number,value:0}},stateObjChanged:function(t){var e=this;t&&"on"===t.state&&(this.brightnessSliderValue=t.attributes.brightness),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return s["default"](t,c)},brightnessSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||(0===e?i.serviceActions.callTurnOff(this.stateObj.entityId):i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,brightness:e}))},colorPicked:function(t){var e=t.detail.rgb;i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,rgb_color:[e.r,e.g,e.b]})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(21),s=r(a),c=["volume_level"];e["default"]=new u["default"]({is:"more-info-media_player",properties:{stateObj:{type:Object,observer:"stateObjChanged"},isOff:{type:Boolean,value:!1},isPlaying:{type:Boolean,value:!1},isMuted:{type:Boolean,value:!1},volumeSliderValue:{type:Number,value:0},supportsPause:{type:Boolean,value:!1},supportsVolumeSet:{type:Boolean,value:!1},supportsVolumeMute:{type:Boolean,value:!1},supportsPreviousTrack:{type:Boolean,value:!1},supportsNextTrack:{type:Boolean,value:!1},supportsTurnOn:{type:Boolean,value:!1},supportsTurnOff:{type:Boolean,value:!1}},stateObjChanged:function(t){var e=this;t&&(this.isOff="off"===t.state,this.isPlaying="playing"===t.state,this.volumeSliderValue=100*t.attributes.volume_level,this.isMuted=t.attributes.is_volume_muted,this.supportsPause=0!==(1&t.attributes.supported_media_commands),this.supportsVolumeSet=0!==(4&t.attributes.supported_media_commands),this.supportsVolumeMute=0!==(8&t.attributes.supported_media_commands),this.supportsPreviousTrack=0!==(16&t.attributes.supported_media_commands),this.supportsNextTrack=0!==(32&t.attributes.supported_media_commands),this.supportsTurnOn=0!==(128&t.attributes.supported_media_commands),this.supportsTurnOff=0!==(256&t.attributes.supported_media_commands)),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return s["default"](t,c)},computeIsOff:function(t){return"off"===t.state},computeMuteVolumeIcon:function(t){return t?"av:volume-off":"av:volume-up"},computePlaybackControlIcon:function(){return this.isPlaying?this.supportsPause?"av:pause":"av:stop":"av:play-arrow"},computeHidePowerButton:function(t,e,n){return t?!e:!n},handleTogglePower:function(){this.callService(this.isOff?"turn_on":"turn_off")},handlePrevious:function(){this.callService("media_previous_track")},handlePlaybackControl:function(){this.callService("media_play_pause")},handleNext:function(){this.callService("media_next_track")},handleVolumeTap:function(){this.supportsVolumeMute&&this.callService("volume_mute",{is_volume_muted:!this.isMuted})},volumeSliderChanged:function(t){var e=parseFloat(t.target.value),n=e>0?e/100:0;this.callService("volume_set",{volume_level:n})},callService:function(t,e){var n=e||{};n.entity_id=this.stateObj.entityId,i.serviceActions.callService("media_player",t,n)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);e["default"]=new o["default"]({is:"more-info-script",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2),a=n(41),s=r(a),c=u.util.parseDateTime;e["default"]=new o["default"]({is:"more-info-sun",properties:{stateObj:{type:Object},risingDate:{type:Object,computed:"computeRising(stateObj)"},settingDate:{type:Object,computed:"computeSetting(stateObj)"}},computeRising:function(t){return c(t.attributes.next_rising)},computeSetting:function(t){return c(t.attributes.next_setting)},computeOrder:function(t,e){return t>e?["set","ris"]:["ris","set"]},itemCaption:function(t){return"ris"===t?"Rising ":"Setting "},itemDate:function(t){return"ris"===t?this.risingDate:this.settingDate},itemValue:function(t){return s["default"](this.itemDate(t))}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(2),o=n(1),u=r(o),a=n(21),s=r(a),c=["away_mode"];e["default"]=new u["default"]({is:"more-info-thermostat",properties:{stateObj:{type:Object,observer:"stateObjChanged"},tempMin:{type:Number},tempMax:{type:Number},targetTemperatureSliderValue:{type:Number},awayToggleChecked:{type:Boolean}},stateObjChanged:function(t){this.targetTemperatureSliderValue=t.attributes.temperature,this.awayToggleChecked="on"===t.attributes.away_mode,this.tempMin=t.attributes.min_temp,this.tempMax=t.attributes.max_temp},computeClassNames:function(t){return s["default"](t,c)},targetTemperatureSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||i.serviceActions.callService("thermostat","set_temperature",{entity_id:this.stateObj.entityId,temperature:e})},toggleChanged:function(t){var e=t.target.checked;e&&"off"===this.stateObj.attributes.away_mode?this.service_set_away(!0):e||"on"!==this.stateObj.attributes.away_mode||this.service_set_away(!1)},service_set_away:function(t){var e=this;i.serviceActions.callService("thermostat","set_away_mode",{away_mode:t,entity_id:this.stateObj.entityId}).then(function(){return e.stateObjChanged(e.stateObj)})}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2);e["default"]=new o["default"]({is:"more-info-updater",properties:{stateObj:{type:Object}},updateTapped:function(){u.serviceActions.callService("updater","update",{})},linkTapped:function(){window.open(this.stateObj.attributes.link,"_blank")}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(9),n(39),e["default"]=new o["default"]({is:"state-card-configurator",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(9);var u=["playing","paused"];e["default"]=new o["default"]({is:"state-card-media_player",properties:{stateObj:{type:Object},isPlaying:{type:Boolean,computed:"computeIsPlaying(stateObj)"}},computeIsPlaying:function(t){return-1!==u.indexOf(t.state)},computePrimaryText:function(t,e){return e?t.attributes.media_title:t.stateDisplay},computeSecondaryText:function(t){var e=void 0;return"music"===t.attributes.media_content_type?t.attributes.media_artist:"tvshow"===t.attributes.media_content_type?(e=t.attributes.media_series_title,t.attributes.media_season&&t.attributes.media_episode&&(e+=" S"+t.attributes.media_season+"E"+t.attributes.media_episode),e):t.attributes.app_name?t.attributes.app_name:""}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i),u=n(2);n(9),e["default"]=new o["default"]({is:"state-card-scene",properties:{stateObj:{type:Object}},activateScene:function(){u.serviceActions.callTurnOn(this.stateObj.entityId)}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(9),e["default"]=new o["default"]({is:"state-card-thermostat",properties:{stateObj:{type:Object}},computeTargetTemperature:function(t){return t.attributes.temperature+" "+t.attributes.unit_of_measurement}}),t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),o=r(i);n(9),n(35),e["default"]=new o["default"]({is:"state-card-toggle"}),t.exports=e["default"]},function(t,e){"use strict";function n(t){return{attached:function(){var e=this;this.__unwatchFns=Object.keys(this.properties).reduce(function(n,r){if(!("bindNuclear"in e.properties[r]))return n;var i=e.properties[r].bindNuclear;if(!i)throw new Error("Undefined getter specified for key "+r);return e[r]=t.evaluate(i),n.concat(t.observe(i,function(t){e[r]=t}))},[])},detached:function(){for(;this.__unwatchFns.length;)this.__unwatchFns.shift()()}}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return-1!==a.indexOf(t.domain)?t.domain:u["default"](t.entityId)?"toggle":"display"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(22),u=r(o),a=["thermostat","configurator","scene","media_player"];t.exports=e["default"]},function(t,e){"use strict";function n(t){return-1!==r.indexOf(t.domain)?t.domain:"default"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n;var r=["light","group","sun","configurator","thermostat","script","media_player","camera","updater","alarm_control_panel"];t.exports=e["default"]},function(t,e){"use strict";function n(t,e,n){var r=1-t-e,i=n/255,o=i/e*t,u=i/e*r,a=1.612*o-.203*i-.302*u,s=.509*-o+1.412*i+.066*u,c=.026*o-.072*i+.962*u;a=.0031308>=a?12.92*a:1.055*Math.pow(a,1/2.4)-.055,s=.0031308>=s?12.92*s:1.055*Math.pow(s,1/2.4)-.055,c=.0031308>=c?12.92*c:1.055*Math.pow(c,1/2.4)-.055;var l=Math.max(a,s,c);return a/=l,s/=l,c/=l,a=255*a,0>a&&(a=255),s=255*s,0>s&&(s=255),c=255*c,0>c&&(c=255),[a,s,c]}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=n,t.exports=e["default"]},function(t,e,n){var r;(function(t,i,o){"use strict";(function(){function u(t){return"function"==typeof t||"object"==typeof t&&null!==t}function a(t){return"function"==typeof t}function s(t){return"object"==typeof t&&null!==t}function c(t){W=t}function l(t){Z=t}function f(){return function(){t.nextTick(v)}}function d(){return function(){q(v)}}function p(){var t=0,e=new tt(v),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function h(){var t=new MessageChannel;return t.port1.onmessage=v,function(){t.port2.postMessage(0)}}function _(){return function(){setTimeout(v,1)}}function v(){for(var t=0;$>t;t+=2){var e=rt[t],n=rt[t+1];e(n),rt[t]=void 0,rt[t+1]=void 0}$=0}function y(){try{var t=n(196);return q=t.runOnLoop||t.runOnContext,d()}catch(e){return _()}}function m(){}function g(){return new TypeError("You cannot resolve a promise with itself")}function b(){return new TypeError("A promises callback cannot return that same promise.")}function O(t){try{return t.then}catch(e){return at.error=e,at}}function w(t,e,n,r){try{t.call(e,n,r)}catch(i){return i}}function S(t,e,n){Z(function(t){var r=!1,i=w(n,e,function(n){r||(r=!0,e!==n?E(t,n):I(t,n))},function(e){r||(r=!0,P(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&i&&(r=!0,P(t,i))},t)}function M(t,e){e._state===ot?I(t,e._result):e._state===ut?P(t,e._result):D(e,void 0,function(e){E(t,e)},function(e){P(t,e)})}function T(t,e){if(e.constructor===t.constructor)M(t,e);else{var n=O(e);n===at?P(t,at.error):void 0===n?I(t,e):a(n)?S(t,e,n):I(t,e)}}function E(t,e){t===e?P(t,g()):u(e)?T(t,e):I(t,e)}function j(t){t._onerror&&t._onerror(t._result),C(t)}function I(t,e){t._state===it&&(t._result=e,t._state=ot,0!==t._subscribers.length&&Z(C,t))}function P(t,e){t._state===it&&(t._state=ut,t._result=e,Z(j,t))}function D(t,e,n,r){var i=t._subscribers,o=i.length;t._onerror=null,i[o]=e,i[o+ot]=n,i[o+ut]=r,0===o&&t._state&&Z(C,t)}function C(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r,i,o=t._result,u=0;uu;u++)D(r.resolve(t[u]),void 0,e,n);return i}function H(t){var e=this;if(t&&"object"==typeof t&&t.constructor===e)return t;var n=new e(m);return E(n,t),n}function Y(t){var e=this,n=new e(m);return P(n,t),n}function G(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function F(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function U(t){this._id=ht++,this._state=void 0,this._result=void 0,this._subscribers=[],m!==t&&(a(t)||G(),this instanceof U||F(),L(this,t))}function B(){var t;if("undefined"!=typeof i)t=i;else if("undefined"!=typeof self)t=self;else try{t=Function("return this")()}catch(e){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=t.Promise;(!n||"[object Promise]"!==Object.prototype.toString.call(n.resolve())||n.cast)&&(t.Promise=_t)}var V;V=Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)};var q,W,K,J=V,$=0,Z=({}.toString,function(t,e){rt[$]=t,rt[$+1]=e,$+=2,2===$&&(W?W(v):K())}),X="undefined"!=typeof window?window:void 0,Q=X||{},tt=Q.MutationObserver||Q.WebKitMutationObserver,et="undefined"!=typeof t&&"[object process]"==={}.toString.call(t),nt="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,rt=new Array(1e3);K=et?f():tt?p():nt?h():void 0===X?y():_();var it=void 0,ot=1,ut=2,at=new A,st=new A;N.prototype._validateInput=function(t){return J(t)},N.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},N.prototype._init=function(){this._result=new Array(this.length)};var ct=N;N.prototype._enumerate=function(){for(var t=this,e=t.length,n=t.promise,r=t._input,i=0;n._state===it&&e>i;i++)t._eachEntry(r[i],i)},N.prototype._eachEntry=function(t,e){var n=this,r=n._instanceConstructor;s(t)?t.constructor===r&&t._state!==it?(t._onerror=null,n._settledAt(t._state,e,t._result)):n._willSettleAt(r.resolve(t),e):(n._remaining--,n._result[e]=t)},N.prototype._settledAt=function(t,e,n){var r=this,i=r.promise;i._state===it&&(r._remaining--,t===ut?P(i,n):r._result[e]=n),0===r._remaining&&I(i,r._result)},N.prototype._willSettleAt=function(t,e){var n=this;D(t,void 0,function(t){n._settledAt(ot,e,t)},function(t){n._settledAt(ut,e,t)})};var lt=z,ft=R,dt=H,pt=Y,ht=0,_t=U;U.all=lt,U.race=ft,U.resolve=dt,U.reject=pt,U._setScheduler=c,U._setAsap=l,U._asap=Z,U.prototype={constructor:U,then:function(t,e){var n=this,r=n._state;if(r===ot&&!t||r===ut&&!e)return this;var i=new this.constructor(m),o=n._result;if(r){var u=arguments[r-1];Z(function(){x(r,i,u,o)})}else D(n,i,t,e);return i},"catch":function(t){return this.then(null,t)}};var vt=B,yt={Promise:_t,polyfill:vt};n(195).amd?(r=function(){return yt}.call(e,n,e,o),!(void 0!==r&&(o.exports=r))):"undefined"!=typeof o&&o.exports?o.exports=yt:"undefined"!=typeof this&&(this.ES6Promise=yt),vt()}).call(void 0)}).call(e,n(193),function(){return this}(),n(192)(t))},function(t,e,n){"use strict";var r=n(43),i=r(Date,"now"),o=i||function(){return(new Date).getTime()};t.exports=o},function(t,e){"use strict";function n(t){return"number"==typeof t&&t>-1&&t%1==0&&r>=t}var r=9007199254740991;t.exports=n},function(t,e,n){"use strict";var r=n(43),i=n(127),o=n(44),u="[object Array]",a=Object.prototype,s=a.toString,c=r(Array,"isArray"),l=c||function(t){return o(t)&&i(t.length)&&s.call(t)==u};t.exports=l},function(t,e,n){"use strict";function r(t){return null==t?!1:i(t)?l.test(s.call(t)):o(t)&&u.test(t)}var i=n(45),o=n(44),u=/^\[object .+?Constructor\]$/,a=Object.prototype,s=Function.prototype.toString,c=a.hasOwnProperty,l=RegExp("^"+s.call(c).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.exports=r},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(125),i=n(15),o=function(t,e,n){var o=arguments.length<=3||void 0===arguments[3]?null:arguments[3],u=t.evaluate(i.getters.authInfo),a=u.host+"/api/"+n;return new r.Promise(function(t,n){var r=new XMLHttpRequest;r.open(e,a,!0),r.setRequestHeader("X-HA-access",u.authToken),r.onload=function(){if(r.status>199&&r.status<300)t(JSON.parse(r.responseText));else try{n(JSON.parse(r.responseText))}catch(e){n({})}},r.onerror=function(){return n({})},o?r.send(JSON.stringify(o)):r.send()})};e["default"]=o,t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){var n=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],r=n.useStreaming,i=void 0===r?t.evaluate(s.getters.isSupported):r,o=n.rememberAuth,u=void 0===o?!1:o,f=n.host,d=void 0===f?"":f;t.dispatch(a["default"].VALIDATING_AUTH_TOKEN,{authToken:e,host:d}),c.actions.fetchAll(t).then(function(){t.dispatch(a["default"].VALID_AUTH_TOKEN,{authToken:e,host:d,rememberAuth:u}),i?s.actions.start(t,{syncOnInitialConnect:!1}):c.actions.start(t,{skipInitialSync:!0})},function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=e.message,r=void 0===n?l:n;t.dispatch(a["default"].INVALID_AUTH_TOKEN,{errorMessage:r +})})}function o(t){t.dispatch(a["default"].LOG_OUT,{})}Object.defineProperty(e,"__esModule",{value:!0}),e.validate=i,e.logOut=o;var u=n(14),a=r(u),s=n(29),c=n(31),l="Unexpected result from API"},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=[["authAttempt","isValidating"],function(t){return!!t}];e.isValidating=n;var r=[["authAttempt","isInvalid"],function(t){return!!t}];e.isInvalidAttempt=r;var i=["authAttempt","errorMessage"];e.attemptErrorMessage=i;var o=["rememberAuth"];e.rememberAuth=o;var u=[["authAttempt","authToken"],["authAttempt","host"],function(t,e){return{authToken:t,host:e}}];e.attemptAuthInfo=u;var a=["authCurrent","authToken"];e.currentAuthToken=a;var s=[a,["authCurrent","host"],function(t,e){return{authToken:t,host:e}}];e.currentAuthInfo=s;var c=[n,["authAttempt","authToken"],["authCurrent","authToken"],function(t,e,n){return t?e:n}];e.authToken=c;var l=[n,u,s,function(t,e,n){return t?e:n}];e.authInfo=l},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){if(null==t)throw new TypeError("Cannot destructure undefined")}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t,e){var n=e.authToken,r=e.host;return d.toImmutable({authToken:n,host:r,isValidating:"true",isInvalid:!1,errorMessage:""})}function s(t,e){return i(e),v.getInitialState()}function c(t,e){var n=e.errorMessage;return t.withMutations(function(t){return t.set("isValidating",!1).set("isInvalid","true").set("errorMessage",n)})}Object.defineProperty(e,"__esModule",{value:!0});var l=function(){function t(t,e){for(var n=0;n1&&t.set(p,r)})}function a(){return _.getInitialState()}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function t(t,e){for(var n=0;no}Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),o=6e4,u=["currentLogbookDate"];e.currentDate=u;var a=[u,["logbookEntriesUpdated"],function(t,e){return r(e.get(t))}];e.isCurrentStale=a;var s=[u,["logbookEntries"],function(t,e){return e.get(t)||i.toImmutable([])}];e.currentEntries=s;var c=["isLoadingLogbookEntries"];e.isLoadingEntries=c},function(t,e,n){"use strict";function r(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e["default"]=t,e}function i(t){return t&&t.__esModule?t:{"default":t}}function o(t){t.registerStores({currentLogbookDate:a["default"],isLoadingLogbookEntries:c["default"],logbookEntries:f["default"],logbookEntriesUpdated:p["default"]})}Object.defineProperty(e,"__esModule",{value:!0}),e.register=o;var u=n(154),a=i(u),s=n(155),c=i(s),l=n(156),f=i(l),d=n(157),p=i(d),h=n(150),_=r(h),v=n(151),y=r(v),m=_;e.actions=m;var g=y;e.getters=g},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n1)for(var n=1;n \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index ac34b5fc269..24623ff26ab 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit ac34b5fc26928238343f34f334a6f6f1a19d5442 +Subproject commit 24623ff26ab8cbf7b39f0a25c26d9d991063b61a From 18747f8ae1ef3958c0c25b0b7b19b7d17e31d798 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 25 Oct 2015 23:12:00 -0700 Subject: [PATCH 218/226] Update some docs --- homeassistant/components/light/hue.py | 2 ++ homeassistant/components/light/hyperion.py | 12 +----------- homeassistant/components/light/limitlessled.py | 17 +---------------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index b438d7b92b1..eff9aef4f36 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -2,6 +2,8 @@ homeassistant.components.light.hue ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Support for Hue lights. + +https://home-assistant.io/components/light.hue.html """ import logging import socket diff --git a/homeassistant/components/light/hyperion.py b/homeassistant/components/light/hyperion.py index fe48d58f945..d5fa3f9f2ce 100644 --- a/homeassistant/components/light/hyperion.py +++ b/homeassistant/components/light/hyperion.py @@ -3,17 +3,7 @@ homeassistant.components.light.hyperion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Support for Hyperion remotes. -Configuration: - -To connect to [a Hyperion server](https://github.com/tvdzwan/hyperion) you -will need to add something like the following to your configuration.yaml file: - -light: - platform: hyperion - host: 192.168.1.98 - port: 19444 - -The JSON server port is 19444 by default. +https://home-assistant.io/components/light.hyperion.html """ import logging import socket diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index ba8b8235260..b35ed379047 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -12,22 +12,7 @@ Support for LimitlessLED bulbs, also known as... - dekolight - iLight -Configuration: - -To use limitlessled you will need to add the following to your -configuration.yaml file. - -light: - platform: limitlessled - bridges: - - host: 192.168.1.10 - group_1_name: Living Room - group_2_name: Bedroom - group_3_name: Office - group_3_type: white - group_4_name: Kitchen - - host: 192.168.1.11 - group_2_name: Basement +https://home-assistant.io/components/light.limitlessled.html """ import logging From 0826ae2742f08faac8fb879b01ea7369dc782228 Mon Sep 17 00:00:00 2001 From: pavoni Date: Mon, 26 Oct 2015 08:37:13 +0000 Subject: [PATCH 219/226] Revise pywemo version, update discovery.device_from_description parameters --- homeassistant/components/switch/wemo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index b598af04946..5cc3be0dbe9 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -11,7 +11,7 @@ import logging from homeassistant.components.switch import SwitchDevice from homeassistant.const import STATE_ON, STATE_OFF, STATE_STANDBY -REQUIREMENTS = ['pywemo==0.3.1'] +REQUIREMENTS = ['pywemo==0.3.2'] _LOGGER = logging.getLogger(__name__) @@ -22,7 +22,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): import pywemo.discovery as discovery if discovery_info is not None: - device = discovery.device_from_description(discovery_info[2]) + device = discovery.device_from_description(discovery_info[2], discovery_info[3]) if device: add_devices_callback([WemoSwitch(device)]) From ef6c209c6f28a753b660de80a4a136d16e933d6a Mon Sep 17 00:00:00 2001 From: pavoni Date: Mon, 26 Oct 2015 09:03:57 +0000 Subject: [PATCH 220/226] Revise for clarity, disable pylink check --- homeassistant/components/switch/wemo.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index 5cc3be0dbe9..820c0736c87 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -22,7 +22,10 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): import pywemo.discovery as discovery if discovery_info is not None: - device = discovery.device_from_description(discovery_info[2], discovery_info[3]) + location = discovery_info[2] + mac = discovery_info[3] + # pylint: disable=too-many-function-args + device = discovery.device_from_description(location, mac) if device: add_devices_callback([WemoSwitch(device)]) From c9f1dce6a2e6b0669f9775fd6973d1b886f2b6b1 Mon Sep 17 00:00:00 2001 From: Krzysztof Koziarek Date: Mon, 26 Oct 2015 11:32:00 +0100 Subject: [PATCH 221/226] Coding style fixes --- homeassistant/components/device_tracker/ubus.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/device_tracker/ubus.py b/homeassistant/components/device_tracker/ubus.py index a231af02be7..3135993e91b 100644 --- a/homeassistant/components/device_tracker/ubus.py +++ b/homeassistant/components/device_tracker/ubus.py @@ -124,8 +124,7 @@ class UbusDeviceScanner(object): if not self.hostapd: hostapd = _req_json_rpc(self.url, self.session_id, 'list', 'hostapd.*', '') - for key in hostapd.keys(): - self.hostapd.append(key) + self.hostapd.extend(hostapd.keys()) self.last_results = [] results = 0 @@ -135,14 +134,9 @@ class UbusDeviceScanner(object): if result: results = results + 1 - for key in result["clients"].keys(): - self.last_results.append(key) - - if results: - return True - else: - return False + self.last_results.extend(result['clients'].keys()) + return bool(results) def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params): """ Perform one JSON RPC operation. """ From fbb73dd5da7ade81683fc404c8e66ae78211b4c3 Mon Sep 17 00:00:00 2001 From: Krzysztof Koziarek Date: Mon, 26 Oct 2015 11:50:09 +0100 Subject: [PATCH 222/226] fixed pylint warnings --- homeassistant/components/device_tracker/ubus.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/device_tracker/ubus.py b/homeassistant/components/device_tracker/ubus.py index 3135993e91b..195ed33e77b 100644 --- a/homeassistant/components/device_tracker/ubus.py +++ b/homeassistant/components/device_tracker/ubus.py @@ -89,8 +89,8 @@ class UbusDeviceScanner(object): 'call', 'uci', 'get', config="dhcp", type="dnsmasq") if result: - self.leasefile = next(iter(result["values"]. - values()))["leasefile"] + values = result["values"].values() + self.leasefile = next(iter(values))["leasefile"] else: return @@ -101,8 +101,8 @@ class UbusDeviceScanner(object): if result: self.mac2name = dict() for line in result["data"].splitlines(): - [time, mac, ip, name, lid] = line.split(" ") - self.mac2name[mac.upper()] = name + hosts = line.split(" ") + self.mac2name[hosts[1].upper()] = hosts[3] else: # Error, handled in the _req_json_rpc return @@ -138,6 +138,7 @@ class UbusDeviceScanner(object): return bool(results) + def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params): """ Perform one JSON RPC operation. """ @@ -147,8 +148,7 @@ def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params): "params": [session_id, subsystem, method, - params] - }) + params]}) try: res = requests.post(url, data=data, timeout=5) @@ -159,7 +159,7 @@ def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params): if res.status_code == 200: response = res.json() - if (rpcmethod == "call"): + if rpcmethod == "call": return response["result"][1] else: return response["result"] From 649124d16217a744e53d6e7dfaf82933169fa3e0 Mon Sep 17 00:00:00 2001 From: Krzysztof Koziarek Date: Mon, 26 Oct 2015 11:55:20 +0100 Subject: [PATCH 223/226] Added ubus.py to .coveragerc --- .coveragerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.coveragerc b/.coveragerc index 7e474d287c2..b1ec9681fef 100644 --- a/.coveragerc +++ b/.coveragerc @@ -37,6 +37,7 @@ omit = homeassistant/components/device_tracker/asuswrt.py homeassistant/components/device_tracker/ddwrt.py homeassistant/components/device_tracker/luci.py + homeassistant/components/device_tracker/ubus.py homeassistant/components/device_tracker/netgear.py homeassistant/components/device_tracker/nmap_tracker.py homeassistant/components/device_tracker/thomson.py From dbc05450a0a2cbc57ea4eb90c89340114ec9f3c9 Mon Sep 17 00:00:00 2001 From: pavoni Date: Mon, 26 Oct 2015 16:32:12 +0000 Subject: [PATCH 224/226] Bump requirements_all.txt version, remove pylint disable --- homeassistant/components/switch/wemo.py | 1 - requirements_all.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index 820c0736c87..c710a914d80 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -24,7 +24,6 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): if discovery_info is not None: location = discovery_info[2] mac = discovery_info[3] - # pylint: disable=too-many-function-args device = discovery.device_from_description(location, mac) if device: diff --git a/requirements_all.txt b/requirements_all.txt index 11d91043d12..2ec0fb339bb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -90,7 +90,7 @@ pynetgear==0.3 netdisco==0.5 # Wemo (switch.wemo) -pywemo==0.3.1 +pywemo==0.3.2 # Wink (*.wink) https://github.com/balloob/python-wink/archive/c2b700e8ca866159566ecf5e644d9c297f69f257.zip#python-wink==0.1 From 9ab9d0e383b61c301e2ae59da8dab4e6570ac387 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 26 Oct 2015 20:49:20 -0700 Subject: [PATCH 225/226] Update netdisco requirement --- 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 b75abc32e4b..f61d792bc60 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -19,7 +19,7 @@ from homeassistant.const import ( DOMAIN = "discovery" DEPENDENCIES = [] -REQUIREMENTS = ['netdisco==0.5'] +REQUIREMENTS = ['netdisco==0.5.1'] SCAN_INTERVAL = 300 # seconds diff --git a/requirements_all.txt b/requirements_all.txt index 2ec0fb339bb..0a26e15ecc6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -87,7 +87,7 @@ https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b pynetgear==0.3 # Netdisco (discovery) -netdisco==0.5 +netdisco==0.5.1 # Wemo (switch.wemo) pywemo==0.3.2 From 55c0ee6b32fd8e797b3c64518d175e10ee37118d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 26 Oct 2015 21:27:42 -0700 Subject: [PATCH 226/226] Version bump to 0.7.6 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 4d5f68e24c5..07eee5c793b 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """ Constants used by Home Assistant components. """ -__version__ = "0.7.6.dev0" +__version__ = "0.7.6" # Can be used to specify a catch all when registering state or event listeners. MATCH_ALL = '*'