From 573dfb648fd8a2a4768ce2e13ae9b4bea04a9831 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 16 Nov 2015 00:03:37 -0800 Subject: [PATCH 001/166] Version bump to 0.9.0.dev0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index af95153f217..da1e424718f 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """ Constants used by Home Assistant components. """ -__version__ = "0.8.0" +__version__ = "0.9.0.dev0" # Can be used to specify a catch all when registering state or event listeners. MATCH_ALL = '*' From 8be53af78f67198a531502eeb42dd5e8df81e96d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 16 Nov 2015 22:00:21 -0800 Subject: [PATCH 002/166] Convert README to RST format --- README.md | 38 --------------------- README.rst | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 38 deletions(-) delete mode 100644 README.md create mode 100644 README.rst diff --git a/README.md b/README.md deleted file mode 100644 index e1528e393bd..00000000000 --- a/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Home Assistant [![Build Status](https://travis-ci.org/balloob/home-assistant.svg?branch=master)](https://travis-ci.org/balloob/home-assistant) [![Coverage Status](https://img.shields.io/coveralls/balloob/home-assistant.svg)](https://coveralls.io/r/balloob/home-assistant?branch=master) [![Join the chat at https://gitter.im/balloob/home-assistant](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/balloob/home-assistant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -[demo]: https://home-assistant.io/demo/ - -Home Assistant is a home automation platform running on Python 3. The goal of Home Assistant is to be able to track and control all devices at home and offer a platform for automating control. - -To get started: -```bash -python3 -m pip install homeassistant -hass --open-ui -``` - -Check out [the website](https://home-assistant.io) for [a demo][demo], installation instructions, tutorials and documentation. - -[![screenshot-states](https://raw.github.com/balloob/home-assistant/master/docs/screenshots.png)][demo] - -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 Linksys 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, 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), [Plex](https://plex.tv/), [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/), [RFXtrx](http://www.rfxcom.com/), [Arduino](https://www.arduino.cc/), [Raspberry Pi](https://www.raspberrypi.org/), and [Modbus](http://www.modbus.org/) - * Interaction with [IFTTT](https://ifttt.com/) - * 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/) - -Built home automation on top of your devices: - - * Keep a precise history of every change to the state of your house - * Turn on the lights when people get home after sun set - * Turn on lights slowly during sun set to compensate for less light - * Turn off all lights and devices when everybody leaves the house - * Offers a [REST API](https://home-assistant.io/developers/api.html) and can interface with MQTT for easy integration with other projects like [OwnTracks](http://owntracks.org/) - * Allow sending notifications using [Instapush](https://instapush.im), [Notify My Android (NMA)](http://www.notifymyandroid.com/), [PushBullet](https://www.pushbullet.com/), [PushOver](https://pushover.net/), [Slack](https://slack.com/), [Telegram](https://telegram.org/), and [Jabber (XMPP)](http://xmpp.org) - -The system is built modular so support for other devices or actions can be implemented easily. See also the [section on architecture](https://home-assistant.io/developers/architecture.html) and the [section on creating your own components](https://home-assistant.io/developers/creating_components.html). - -If you run into issues while using Home Assistant or during development of a component, check the [Home Assistant help section](https://home-assistant.io/help/) how to reach us. diff --git a/README.rst b/README.rst new file mode 100644 index 00000000000..c66b3670f32 --- /dev/null +++ b/README.rst @@ -0,0 +1,98 @@ +Home Assistant |Build Status| |Coverage Status| |Join the chat at https://gitter.im/balloob/home-assistant| +=========================================================================================================== + +Home Assistant is a home automation platform running on Python 3. The +goal of Home Assistant is to be able to track and control all devices at +home and offer a platform for automating control. + +To get started: + +.. code:: bash + + python3 -m pip install homeassistant + hass --open-ui + +Check out `the website `__ for `a +demo `__, installation instructions, +tutorials and documentation. + +|screenshot-states| + +Examples of devices it can interface it: + +- Monitoring connected devices to a wireless router: + `OpenWrt `__, + `Tomato `__, + `Netgear `__, + `DD-WRT `__, + `TPLink `__, + `ASUSWRT `__ and any SNMP + capable Linksys WAP/WRT +- `Philips Hue `__ lights, + `WeMo `__ + switches, `Edimax `__ switches, + `Efergy `__ energy monitoring, and + `Tellstick `__ devices and + sensors +- `Google + Chromecasts `__, + `Music Player Daemon `__, `Logitech + Squeezebox `__, + `Plex `__, `Kodi (XBMC) `__, + iTunes (by way of + `itunes-api `__), and Amazon + Fire TV (by way of + `python-firetv `__) +- Support for + `ISY994 `__ + (Insteon and X10 devices), `Z-Wave `__, `Nest + Thermostats `__, + `RFXtrx `__, + `Arduino `__, `Raspberry + Pi `__, and + `Modbus `__ +- Interaction with `IFTTT `__ +- Integrate data from the `Bitcoin `__ network, + meteorological data from + `OpenWeatherMap `__ and + `Forecast.io `__, + `Transmission `__, or + `SABnzbd `__. +- `See full list of supported + devices `__ + +Built home automation on top of your devices: + +- Keep a precise history of every change to the state of your house +- Turn on the lights when people get home after sun set +- Turn on lights slowly during sun set to compensate for less light +- Turn off all lights and devices when everybody leaves the house +- Offers a `REST API `__ + and can interface with MQTT for easy integration with other projects + like `OwnTracks `__ +- Allow sending notifications using + `Instapush `__, `Notify My Android + (NMA) `__, + `PushBullet `__, + `PushOver `__, `Slack `__, + `Telegram `__, and `Jabber + (XMPP) `__ + +The system is built modular so support for other devices or actions can +be implemented easily. See also the `section on +architecture `__ +and the `section on creating your own +components `__. + +If you run into issues while using Home Assistant or during development +of a component, check the `Home Assistant help +section `__ how to reach us. + +.. |Build Status| image:: https://travis-ci.org/balloob/home-assistant.svg?branch=master + :target: https://travis-ci.org/balloob/home-assistant +.. |Coverage Status| image:: https://img.shields.io/coveralls/balloob/home-assistant.svg + :target: https://coveralls.io/r/balloob/home-assistant?branch=master +.. |Join the chat at https://gitter.im/balloob/home-assistant| image:: https://badges.gitter.im/Join%20Chat.svg + :target: https://gitter.im/balloob/home-assistant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +.. |screenshot-states| image:: https://raw.github.com/balloob/home-assistant/master/docs/screenshots.png + :target: https://home-assistant.io/demo/ From 377d2c6e5a3e8e6a153ea91f27fb88f450afe3d1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 17 Nov 2015 00:18:42 -0800 Subject: [PATCH 003/166] Allow generating requirements_all.txt --- MANIFEST.in | 2 +- .../components/light/blinksticklight.py | 6 +- homeassistant/components/light/rfxtrx.py | 3 +- homeassistant/components/light/tellstick.py | 28 +- homeassistant/components/light/zwave.py | 6 +- homeassistant/components/sensor/rfxtrx.py | 2 +- homeassistant/components/sensor/tellstick.py | 6 +- .../components/sensor/transmission.py | 9 +- homeassistant/components/sensor/zwave.py | 5 +- .../components/switch/hikvisioncam.py | 15 +- homeassistant/components/switch/orvibo.py | 13 +- homeassistant/components/switch/rfxtrx.py | 2 +- homeassistant/components/switch/tellstick.py | 19 +- .../components/switch/transmission.py | 6 +- homeassistant/components/switch/zwave.py | 6 +- requirements_all.txt | 285 +++++++++--------- script/gen_requirements_all.py | 76 +++++ 17 files changed, 283 insertions(+), 206 deletions(-) create mode 100755 script/gen_requirements_all.py diff --git a/MANIFEST.in b/MANIFEST.in index 8233015e646..d04d86bae58 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include README.md +include README.rst include LICENSE graft homeassistant prune homeassistant/components/frontend/www_static/home-assistant-polymer diff --git a/homeassistant/components/light/blinksticklight.py b/homeassistant/components/light/blinksticklight.py index 086a004eba2..5cc14a9034b 100644 --- a/homeassistant/components/light/blinksticklight.py +++ b/homeassistant/components/light/blinksticklight.py @@ -8,9 +8,7 @@ https://home-assistant.io/components/light.blinksticklight/ """ import logging -from blinkstick import blinkstick - -from homeassistant.components.light import (Light, ATTR_RGB_COLOR) +from homeassistant.components.light import Light, ATTR_RGB_COLOR _LOGGER = logging.getLogger(__name__) @@ -22,6 +20,8 @@ DEPENDENCIES = [] # pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Add device specified by serial number. """ + from blinkstick import blinkstick + stick = blinkstick.find_by_serial(config['serial']) add_devices_callback([BlinkStickLight(stick, config['name'])]) diff --git a/homeassistant/components/light/rfxtrx.py b/homeassistant/components/light/rfxtrx.py index ff52001353b..8d6a2b86217 100644 --- a/homeassistant/components/light/rfxtrx.py +++ b/homeassistant/components/light/rfxtrx.py @@ -8,7 +8,6 @@ https://home-assistant.io/components/light.rfxtrx/ """ import logging import homeassistant.components.rfxtrx as rfxtrx -import RFXtrx as rfxtrxmod from homeassistant.components.light import Light from homeassistant.util import slugify @@ -20,6 +19,8 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup the RFXtrx platform. """ + import RFXtrx as rfxtrxmod + lights = [] devices = config.get('devices', None) if devices: diff --git a/homeassistant/components/light/tellstick.py b/homeassistant/components/light/tellstick.py index 9a22a4dcdc0..24d86c47c51 100644 --- a/homeassistant/components/light/tellstick.py +++ b/homeassistant/components/light/tellstick.py @@ -6,13 +6,9 @@ Support for Tellstick lights. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.tellstick/ """ -import logging -# pylint: disable=no-name-in-module, import-error from homeassistant.components.light import Light, ATTR_BRIGHTNESS from homeassistant.const import (EVENT_HOMEASSISTANT_STOP, ATTR_FRIENDLY_NAME) -import tellcore.constants as tellcore_constants -from tellcore.library import DirectCallbackDispatcher REQUIREMENTS = ['tellcore-py==1.1.2'] @@ -20,12 +16,9 @@ REQUIREMENTS = ['tellcore-py==1.1.2'] def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Find and return Tellstick lights. """ - try: - import tellcore.telldus as telldus - except ImportError: - logging.getLogger(__name__).exception( - "Failed to import tellcore") - return [] + import tellcore.telldus as telldus + from tellcore.library import DirectCallbackDispatcher + import tellcore.constants as tellcore_constants core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher()) @@ -58,17 +51,20 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): class TellstickLight(Light): """ Represents a Tellstick light. """ - last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON | - tellcore_constants.TELLSTICK_TURNOFF | - tellcore_constants.TELLSTICK_DIM | - tellcore_constants.TELLSTICK_UP | - tellcore_constants.TELLSTICK_DOWN) def __init__(self, tellstick_device): + import tellcore.constants as tellcore_constants + self.tellstick_device = tellstick_device self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name} self._brightness = 0 + self.last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON | + tellcore_constants.TELLSTICK_TURNOFF | + tellcore_constants.TELLSTICK_DIM | + tellcore_constants.TELLSTICK_UP | + tellcore_constants.TELLSTICK_DOWN) + @property def name(self): """ Returns the name of the switch if any. """ @@ -104,6 +100,8 @@ class TellstickLight(Light): def update(self): """ Update state of the light. """ + import tellcore.constants as tellcore_constants + last_command = self.tellstick_device.last_sent_command( self.last_sent_command_mask) diff --git a/homeassistant/components/light/zwave.py b/homeassistant/components/light/zwave.py index f1cd6f57fc0..31cd64d2530 100644 --- a/homeassistant/components/light/zwave.py +++ b/homeassistant/components/light/zwave.py @@ -7,9 +7,6 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.zwave/ """ # pylint: disable=import-error -from openzwave.network import ZWaveNetwork -from pydispatch import dispatcher - import homeassistant.components.zwave as zwave from homeassistant.const import STATE_ON, STATE_OFF @@ -51,6 +48,9 @@ class ZwaveDimmer(Light): """ Provides a Z-Wave dimmer. """ # pylint: disable=too-many-arguments def __init__(self, value): + from openzwave.network import ZWaveNetwork + from pydispatch import dispatcher + self._value = value self._node = value.node diff --git a/homeassistant/components/sensor/rfxtrx.py b/homeassistant/components/sensor/rfxtrx.py index 0118c30ceb6..c67810c86eb 100644 --- a/homeassistant/components/sensor/rfxtrx.py +++ b/homeassistant/components/sensor/rfxtrx.py @@ -11,7 +11,6 @@ from collections import OrderedDict from homeassistant.const import (TEMP_CELCIUS) from homeassistant.helpers.entity import Entity -from RFXtrx import SensorEvent import homeassistant.components.rfxtrx as rfxtrx from homeassistant.util import slugify @@ -28,6 +27,7 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup the RFXtrx platform. """ + from RFXtrx import SensorEvent def sensor_update(event): """ Callback for sensor updates from the RFXtrx gateway. """ diff --git a/homeassistant/components/sensor/tellstick.py b/homeassistant/components/sensor/tellstick.py index b6eb42f6dbb..c6993de462d 100644 --- a/homeassistant/components/sensor/tellstick.py +++ b/homeassistant/components/sensor/tellstick.py @@ -9,9 +9,6 @@ https://home-assistant.io/components/sensor.tellstick/ import logging from collections import namedtuple -import tellcore.telldus as telldus -import tellcore.constants as tellcore_constants - from homeassistant.const import TEMP_CELCIUS from homeassistant.helpers.entity import Entity import homeassistant.util as util @@ -24,6 +21,9 @@ REQUIREMENTS = ['tellcore-py==1.1.2'] # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up Tellstick sensors. """ + import tellcore.telldus as telldus + import tellcore.constants as tellcore_constants + sensor_value_descriptions = { tellcore_constants.TELLSTICK_TEMPERATURE: DatatypeDescription( diff --git a/homeassistant/components/sensor/transmission.py b/homeassistant/components/sensor/transmission.py index c4a40e64470..484b045f295 100644 --- a/homeassistant/components/sensor/transmission.py +++ b/homeassistant/components/sensor/transmission.py @@ -11,10 +11,6 @@ from datetime import timedelta from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD from homeassistant.helpers.entity import Entity -# pylint: disable=no-name-in-module, import-error -import transmissionrpc - -from transmissionrpc.error import TransmissionError import logging @@ -33,6 +29,9 @@ _THROTTLED_REFRESH = None # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the Transmission sensors. """ + import transmissionrpc + from transmissionrpc.error import TransmissionError + host = config.get(CONF_HOST) username = config.get(CONF_USERNAME, None) password = config.get(CONF_PASSWORD, None) @@ -97,6 +96,8 @@ class TransmissionSensor(Entity): def refresh_transmission_data(self): """ Calls the throttled Transmission refresh method. """ + from transmissionrpc.error import TransmissionError + if _THROTTLED_REFRESH is not None: try: _THROTTLED_REFRESH() diff --git a/homeassistant/components/sensor/zwave.py b/homeassistant/components/sensor/zwave.py index 0a9b3e8290f..23d2f8948f8 100644 --- a/homeassistant/components/sensor/zwave.py +++ b/homeassistant/components/sensor/zwave.py @@ -8,8 +8,6 @@ at https://home-assistant.io/components/zwave/ """ # pylint: disable=import-error from homeassistant.helpers.event import track_point_in_time -from openzwave.network import ZWaveNetwork -from pydispatch import dispatcher import datetime import homeassistant.util.dt as dt_util import homeassistant.components.zwave as zwave @@ -79,6 +77,9 @@ class ZWaveSensor(Entity): """ Represents a Z-Wave sensor. """ def __init__(self, sensor_value): + from openzwave.network import ZWaveNetwork + from pydispatch import dispatcher + self._value = sensor_value self._node = sensor_value.node diff --git a/homeassistant/components/switch/hikvisioncam.py b/homeassistant/components/switch/hikvisioncam.py index ec74a83dbc2..2d91acdf361 100644 --- a/homeassistant/components/switch/hikvisioncam.py +++ b/homeassistant/components/switch/hikvisioncam.py @@ -11,12 +11,6 @@ from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD import logging -try: - import hikvision.api - from hikvision.error import HikvisionError, MissingParamError -except ImportError: - hikvision.api = None - _LOGGING = logging.getLogger(__name__) REQUIREMENTS = ['hikvision==0.4'] # pylint: disable=too-many-arguments @@ -25,6 +19,8 @@ REQUIREMENTS = ['hikvision==0.4'] def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup Hikvision camera. """ + import hikvision.api + from hikvision.error import HikvisionError, MissingParamError host = config.get(CONF_HOST, None) port = config.get('port', "80") @@ -32,13 +28,6 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): username = config.get(CONF_USERNAME, "admin") password = config.get(CONF_PASSWORD, "12345") - if hikvision.api is None: - _LOGGING.error(( - "Failed to import hikvision. Did you maybe not install the " - "'hikvision' dependency?")) - - return False - try: hikvision_cam = hikvision.api.CreateDevice( host, port=port, username=username, diff --git a/homeassistant/components/switch/orvibo.py b/homeassistant/components/switch/orvibo.py index 04864e13fdd..b9469d15df0 100644 --- a/homeassistant/components/switch/orvibo.py +++ b/homeassistant/components/switch/orvibo.py @@ -10,8 +10,6 @@ import logging from homeassistant.components.switch import SwitchDevice -from orvibo.s20 import S20, S20Exception - DEFAULT_NAME = "Orvibo S20 Switch" REQUIREMENTS = ['orvibo==1.0.0'] _LOGGER = logging.getLogger(__name__) @@ -20,6 +18,8 @@ _LOGGER = logging.getLogger(__name__) # pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Find and return S20 switches. """ + from orvibo.s20 import S20, S20Exception + if config.get('host') is None: _LOGGER.error("Missing required variable: host") return @@ -34,9 +34,12 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): class S20Switch(SwitchDevice): """ Represents an S20 switch. """ def __init__(self, name, s20): + from orvibo.s20 import S20Exception + self._name = name self._s20 = s20 self._state = False + self._exc = S20Exception @property def should_poll(self): @@ -57,19 +60,19 @@ class S20Switch(SwitchDevice): """ Update device state. """ try: self._state = self._s20.on - except S20Exception: + except self._exc: _LOGGER.exception("Error while fetching S20 state") def turn_on(self, **kwargs): """ Turn the device on. """ try: self._s20.on = True - except S20Exception: + except self._exc: _LOGGER.exception("Error while turning on S20") def turn_off(self, **kwargs): """ Turn the device off. """ try: self._s20.on = False - except S20Exception: + except self._exc: _LOGGER.exception("Error while turning off S20") diff --git a/homeassistant/components/switch/rfxtrx.py b/homeassistant/components/switch/rfxtrx.py index 83100598245..86bcf580f41 100644 --- a/homeassistant/components/switch/rfxtrx.py +++ b/homeassistant/components/switch/rfxtrx.py @@ -8,7 +8,6 @@ https://home-assistant.io/components/switch.rfxtrx/ """ import logging import homeassistant.components.rfxtrx as rfxtrx -from RFXtrx import LightingDevice from homeassistant.components.switch import SwitchDevice from homeassistant.util import slugify @@ -20,6 +19,7 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup the RFXtrx platform. """ + from RFXtrx import LightingDevice # Add switch from config file switchs = [] diff --git a/homeassistant/components/switch/tellstick.py b/homeassistant/components/switch/tellstick.py index 2966673520f..61edbed0af4 100644 --- a/homeassistant/components/switch/tellstick.py +++ b/homeassistant/components/switch/tellstick.py @@ -11,8 +11,6 @@ import logging from homeassistant.const import (EVENT_HOMEASSISTANT_STOP, ATTR_FRIENDLY_NAME) from homeassistant.helpers.entity import ToggleEntity -import tellcore.constants as tellcore_constants -from tellcore.library import DirectCallbackDispatcher SIGNAL_REPETITIONS = 1 REQUIREMENTS = ['tellcore-py==1.1.2'] @@ -22,11 +20,9 @@ _LOGGER = logging.getLogger(__name__) # pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Find and return Tellstick switches. """ - try: - import tellcore.telldus as telldus - except ImportError: - _LOGGER.exception("Failed to import tellcore") - return + import tellcore.telldus as telldus + import tellcore.constants as tellcore_constants + from tellcore.library import DirectCallbackDispatcher core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher()) @@ -62,14 +58,17 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): class TellstickSwitchDevice(ToggleEntity): """ Represents a Tellstick switch. """ - last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON | - tellcore_constants.TELLSTICK_TURNOFF) def __init__(self, tellstick_device, signal_repetitions): + import tellcore.constants as tellcore_constants + self.tellstick_device = tellstick_device self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name} self.signal_repetitions = signal_repetitions + self.last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON | + tellcore_constants.TELLSTICK_TURNOFF) + @property def should_poll(self): """ Tells Home Assistant not to poll this entity. """ @@ -88,6 +87,8 @@ class TellstickSwitchDevice(ToggleEntity): @property def is_on(self): """ True if switch is on. """ + import tellcore.constants as tellcore_constants + last_command = self.tellstick_device.last_sent_command( self.last_sent_command_mask) diff --git a/homeassistant/components/switch/transmission.py b/homeassistant/components/switch/transmission.py index bb4f6616975..f3f6a9a8765 100644 --- a/homeassistant/components/switch/transmission.py +++ b/homeassistant/components/switch/transmission.py @@ -10,9 +10,6 @@ from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.helpers.entity import ToggleEntity -# pylint: disable=no-name-in-module, import-error -import transmissionrpc -from transmissionrpc.error import TransmissionError import logging _LOGGING = logging.getLogger(__name__) @@ -22,6 +19,9 @@ REQUIREMENTS = ['transmissionrpc==0.11'] # pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Sets up the transmission sensor. """ + import transmissionrpc + from transmissionrpc.error import TransmissionError + host = config.get(CONF_HOST) username = config.get(CONF_USERNAME, None) password = config.get(CONF_PASSWORD, None) diff --git a/homeassistant/components/switch/zwave.py b/homeassistant/components/switch/zwave.py index 7d86605c646..493e2234bcf 100644 --- a/homeassistant/components/switch/zwave.py +++ b/homeassistant/components/switch/zwave.py @@ -5,8 +5,6 @@ homeassistant.components.switch.zwave Zwave platform that handles simple binary switches. """ # pylint: disable=import-error -from openzwave.network import ZWaveNetwork -from pydispatch import dispatcher import homeassistant.components.zwave as zwave @@ -36,11 +34,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class ZwaveSwitch(SwitchDevice): """ Provides a zwave switch. """ def __init__(self, value): + from openzwave.network import ZWaveNetwork + from pydispatch import dispatcher + self._value = value self._node = value.node self._state = value.data - dispatcher.connect( self._value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED) diff --git a/requirements_all.txt b/requirements_all.txt index ce6cbfabc96..081c8235b12 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1,161 +1,168 @@ -# Required for Home Assistant core +# Home Assistant core requests>=2,<3 pyyaml>=3.11,<4 pytz>=2015.4 pip>=7.0.0 vincenty==0.1.3 -# Optional, needed for specific components - -# Sun (sun) -astral==0.8.1 - -# Philips Hue (lights.hue) -phue==0.8 - -# Limitlessled/Easybulb/Milight (lights.limitlessled) -ledcontroller==1.1.0 - -# Chromecast (media_player.cast) -pychromecast==0.6.12 - -# Keyboard (keyboard) -pyuserinput==0.1.9 - -# Tellstick (*.tellstick) -tellcore-py==1.1.2 - -# Nmap (device_tracker.nmap) -python-nmap==0.4.3 - -# PushBullet (notify.pushbullet) -pushbullet.py==0.9.0 - -# Nest Thermostat (thermostat.nest) -python-nest==2.6.0 - -# Z-Wave (*.zwave) -pydispatcher==2.0.5 - -# ISY994 (isy994) -PyISY==1.0.5 - -# PSutil (sensor.systemmonitor) -psutil==3.2.2 - -# Pushover (notify.pushover) -python-pushover==0.2 - -# Transmission Torrent Client (*.transmission) -transmissionrpc==0.11 - -# OpenWeatherMap (sensor.openweathermap) -pyowm==2.2.1 - -# XMPP (notify.xmpp) -sleekxmpp==1.3.1 -dnspython3==1.12.0 - -# Blockchain (sensor.bitcoin) -blockchain==1.1.2 - -# Music Player Daemon (media_player.mpd) -python-mpd2==0.5.4 - -# Hikvision (switch.hikvisioncam) -hikvision==0.4 - -# Console log coloring -colorlog==2.6.0 - -# JSON-RPC interface (media_player.kodi) -jsonrpc-requests==0.1 - -# Forecast.io (sensor.forecast) -python-forecastio==1.3.3 - -# Firmata (*.arduino) +# homeassistant.components.arduino PyMata==2.07a -# Rfxtrx (rfxtrx) -https://github.com/Danielhiversen/pyRFXtrx/archive/ec7a1aaddf8270db6e5da1c13d58c1547effd7cf.zip#RFXtrx==0.15 - -# Mysensors (sensor.mysensors) -https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3 - -# Netgear (device_tracker.netgear) +# homeassistant.components.device_tracker.netgear pynetgear==0.3 -# Netdisco (discovery) -netdisco==0.5.1 +# homeassistant.components.device_tracker.nmap_tracker +python-nmap==0.4.3 -# Wemo (switch.wemo) -pywemo==0.3.2 - -# Wink (*.wink) -https://github.com/balloob/python-wink/archive/9eb39eaba0717922815e673ad1114c685839d890.zip#python-wink==0.1.1 - -# Slack notifier (notify.slack) -slacker==0.6.8 - -# Temper sensors (sensor.temper) -https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3 - -# PyEdimax (switch.edimax) -https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip#pyedimax==0.1 - -# RPI-GPIO platform (*.rpi_gpio) -# Uncomment for Raspberry Pi -# RPi.GPIO==0.5.11 - -# Adafruit temperature/humidity sensor (sensor.dht) -# Uncomment on a Raspberry Pi / Beaglebone -# http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0 - -# PAHO MQTT (mqtt) -paho-mqtt==1.1 - -# PyModbus (modbus) -https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0 - -# Verisure (verisure) -https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60f7f35854390d59be.zip#python-verisure==0.2.6 - -# IFTTT Maker Channel (ifttt) -pyfttt==0.3 - -# SABnzbd (sensor.sabnzbd) -https://github.com/balloob/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1 - -# Vera (*.vera) -https://github.com/pavoni/home-assistant-vera-api/archive/efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip#python-vera==0.1.1 - -# Sonos (media_player.sonos) -SoCo==0.11.1 - -# PlexAPI (media_player.plex) -plexapi==1.1.0 - -# SNMP (device_tracker.snmp) +# homeassistant.components.device_tracker.snmp pysnmp==4.2.5 -# Blinkstick (light.blinksticklight) +# homeassistant.components.discovery +netdisco==0.5.1 + +# homeassistant.components.ifttt +pyfttt==0.3 + +# homeassistant.components.isy994 +PyISY==1.0.5 + +# homeassistant.components.keyboard +pyuserinput==0.1.9 + +# homeassistant.components.light.blinksticklight blinkstick==1.1.7 -# Telegram (notify.telegram) -python-telegram-bot==2.8.7 +# homeassistant.components.light.hue +phue==0.8 -# CPUinfo (sensor.cpuinfo) -py-cpuinfo==0.1.6 +# homeassistant.components.light.limitlessled +ledcontroller==1.1.0 -# Radio Thermostat (thermostat.radiotherm) -radiotherm==1.2 +# homeassistant.components.light.tellstick +# homeassistant.components.sensor.tellstick +# homeassistant.components.switch.tellstick +tellcore-py==1.1.2 -# Honeywell Evo Home Client (thermostat.honeywell) -evohomeclient==0.2.3 +# homeassistant.components.light.vera +# homeassistant.components.switch.vera +https://github.com/pavoni/home-assistant-vera-api/archive/efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip#python-vera==0.1.1 -# Pushetta (notify.pushetta) +# homeassistant.components.wink +# homeassistant.components.light.wink +# homeassistant.components.sensor.wink +# homeassistant.components.switch.wink +https://github.com/balloob/python-wink/archive/9eb39eaba0717922815e673ad1114c685839d890.zip#python-wink==0.1.1 + +# homeassistant.components.media_player.cast +pychromecast==0.6.12 + +# homeassistant.components.media_player.kodi +jsonrpc-requests==0.1 + +# homeassistant.components.media_player.mpd +python-mpd2==0.5.4 + +# homeassistant.components.media_player.plex +plexapi==1.1.0 + +# homeassistant.components.media_player.sonos +SoCo==0.11.1 + +# homeassistant.components.modbus +https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0 + +# homeassistant.components.mqtt +paho-mqtt==1.1 + +# homeassistant.components.notify.pushbullet +pushbullet.py==0.9.0 + +# homeassistant.components.notify.pushetta pushetta==1.0.15 -# Orvibo S10 +# homeassistant.components.notify.pushover +python-pushover==0.2 + +# homeassistant.components.notify.slack +slacker==0.6.8 + +# homeassistant.components.notify.telegram +python-telegram-bot==2.8.7 + +# homeassistant.components.notify.xmpp +sleekxmpp==1.3.1 + +# homeassistant.components.notify.xmpp +dnspython3==1.12.0 + +# homeassistant.components.rfxtrx +https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip#RFXtrx==0.2 + +# homeassistant.components.sensor.bitcoin +blockchain==1.1.2 + +# homeassistant.components.sensor.cpuspeed +py-cpuinfo==0.1.6 + +# homeassistant.components.sensor.dht +http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0 + +# homeassistant.components.sensor.forecast +python-forecastio==1.3.3 + +# homeassistant.components.sensor.mysensors +https://github.com/theolind/pymysensors/archive/d4b809c2167650691058d1e29bfd2c4b1792b4b0.zip#pymysensors==0.3 + +# homeassistant.components.sensor.openweathermap +pyowm==2.2.1 + +# homeassistant.components.sensor.rpi_gpio +# homeassistant.components.switch.rpi_gpio +RPi.GPIO==0.5.11 + +# homeassistant.components.sensor.sabnzbd +https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1 + +# homeassistant.components.sensor.systemmonitor +psutil==3.2.2 + +# homeassistant.components.sensor.temper +https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip#temperusb==1.2.3 + +# homeassistant.components.sensor.transmission +# homeassistant.components.switch.transmission +transmissionrpc==0.11 + +# homeassistant.components.sensor.vera +https://github.com/balloob/home-assistant-vera-api/archive/a8f823066ead6c7da6fb5e7abaf16fef62e63364.zip#python-vera==0.1 + +# homeassistant.components.sun +astral==0.8.1 + +# homeassistant.components.switch.edimax +https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip#pyedimax==0.1 + +# homeassistant.components.switch.hikvisioncam +hikvision==0.4 + +# homeassistant.components.switch.orvibo orvibo==1.0.0 + +# homeassistant.components.switch.wemo +pywemo==0.3.2 + +# homeassistant.components.thermostat.honeywell +evohomeclient==0.2.3 + +# homeassistant.components.thermostat.nest +python-nest==2.6.0 + +# homeassistant.components.thermostat.radiotherm +radiotherm==1.2 + +# homeassistant.components.verisure +https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60f7f35854390d59be.zip#python-verisure==0.2.6 + +# homeassistant.components.zwave +pydispatcher==2.0.5 + diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py new file mode 100755 index 00000000000..15b11063efa --- /dev/null +++ b/script/gen_requirements_all.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +""" +Generate an updated requirements_all.txt +""" + +from collections import OrderedDict +import importlib +import os +import pkgutil +import re + + +def explore_module(package, explore_children): + module = importlib.import_module(package) + + found = [] + + if not hasattr(module, '__path__'): + return found + + for _, name, ispkg in pkgutil.iter_modules(module.__path__, package + '.'): + found.append(name) + + if explore_children: + found.extend(explore_module(name, False)) + + return found + + +def core_requirements(): + with open('setup.py') as inp: + reqs_raw = re.search( + r'REQUIRES = \[(.*?)\]', inp.read(), re.S).group(1) + + return re.findall(r"'(.*?)'", reqs_raw) + + +def main(): + if not os.path.isfile('requirements_all.txt'): + print('Run this from HA root dir') + return + + reqs = OrderedDict() + + errors = [] + for package in sorted(explore_module('homeassistant.components', True)): + try: + module = importlib.import_module(package) + except ImportError: + errors.append(package) + continue + + if not getattr(module, 'REQUIREMENTS', None): + continue + + for req in module.REQUIREMENTS: + reqs.setdefault(req, []).append(package) + + if errors: + print("Found errors") + print('\n'.join(errors)) + return + + print('# Home Assistant core') + print('\n'.join(core_requirements())) + print() + + for pkg, requirements in reqs.items(): + for req in sorted(requirements, + key=lambda name: (len(name.split('.')), name)): + print('#', req) + print(pkg) + print() + +if __name__ == '__main__': + main() From e92fe149febaee281e612dde0b34293ca8395baa Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 17 Nov 2015 00:28:22 -0800 Subject: [PATCH 004/166] Comment out requirements that break on certain platforms --- requirements_all.txt | 4 ++-- script/gen_requirements_all.py | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/requirements_all.txt b/requirements_all.txt index 081c8235b12..7df9584e7fa 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -105,7 +105,7 @@ blockchain==1.1.2 py-cpuinfo==0.1.6 # homeassistant.components.sensor.dht -http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0 +# http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip#Adafruit_DHT==1.1.0 # homeassistant.components.sensor.forecast python-forecastio==1.3.3 @@ -118,7 +118,7 @@ pyowm==2.2.1 # homeassistant.components.sensor.rpi_gpio # homeassistant.components.switch.rpi_gpio -RPi.GPIO==0.5.11 +# RPi.GPIO==0.5.11 # homeassistant.components.sensor.sabnzbd https://github.com/jamespcole/home-assistant-nzb-clients/archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip#python-sabnzbd==0.1 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 15b11063efa..b10c0f38ed8 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -9,6 +9,11 @@ import os import pkgutil import re +COMMENT_REQUIREMENTS = [ + 'RPi.GPIO', + 'Adafruit_Python_DHT' +] + def explore_module(package, explore_children): module = importlib.import_module(package) @@ -35,6 +40,11 @@ def core_requirements(): return re.findall(r"'(.*?)'", reqs_raw) +def comment_requirement(req): + """ Some requirements don't install on all systems. """ + return any(ign in req for ign in COMMENT_REQUIREMENTS) + + def main(): if not os.path.isfile('requirements_all.txt'): print('Run this from HA root dir') @@ -69,7 +79,11 @@ def main(): for req in sorted(requirements, key=lambda name: (len(name.split('.')), name)): print('#', req) - print(pkg) + + if comment_requirement(pkg): + print('#', pkg) + else: + print(pkg) print() if __name__ == '__main__': From bca65b620afeb6be9829af203ca90903d93901e1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 17 Nov 2015 00:34:14 -0800 Subject: [PATCH 005/166] Update Vera sensor dependency --- homeassistant/components/sensor/vera.py | 6 +++--- requirements_all.txt | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py index 00ad9336705..1848c680517 100644 --- a/homeassistant/components/sensor/vera.py +++ b/homeassistant/components/sensor/vera.py @@ -15,9 +15,9 @@ from homeassistant.const import ( ATTR_BATTERY_LEVEL, ATTR_TRIPPED, ATTR_ARMED, ATTR_LAST_TRIP_TIME, TEMP_CELCIUS, TEMP_FAHRENHEIT) -REQUIREMENTS = ['https://github.com/balloob/home-assistant-vera-api/archive/' - 'a8f823066ead6c7da6fb5e7abaf16fef62e63364.zip' - '#python-vera==0.1'] +REQUIREMENTS = ['https://github.com/pavoni/home-assistant-vera-api/archive/' + 'efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip' + '#python-vera==0.1.1'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 7df9584e7fa..c6b4ae81721 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -44,6 +44,7 @@ ledcontroller==1.1.0 tellcore-py==1.1.2 # homeassistant.components.light.vera +# homeassistant.components.sensor.vera # homeassistant.components.switch.vera https://github.com/pavoni/home-assistant-vera-api/archive/efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip#python-vera==0.1.1 @@ -133,9 +134,6 @@ https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc7045 # homeassistant.components.switch.transmission transmissionrpc==0.11 -# homeassistant.components.sensor.vera -https://github.com/balloob/home-assistant-vera-api/archive/a8f823066ead6c7da6fb5e7abaf16fef62e63364.zip#python-vera==0.1 - # homeassistant.components.sun astral==0.8.1 From c78899c4f305101cce19c23058e35ccc181fb7c0 Mon Sep 17 00:00:00 2001 From: miniconfig Date: Tue, 17 Nov 2015 10:17:57 -0500 Subject: [PATCH 006/166] Added support for Locks, including those connected through a wink hub. --- homeassistant/components/lock/__init__.py | 124 ++++++++++++++++++++ homeassistant/components/lock/demo.py | 56 +++++++++ homeassistant/components/lock/services.yaml | 0 homeassistant/components/lock/wink.py | 73 ++++++++++++ homeassistant/components/wink.py | 4 +- homeassistant/const.py | 8 ++ 6 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/lock/__init__.py create mode 100644 homeassistant/components/lock/demo.py create mode 100644 homeassistant/components/lock/services.yaml create mode 100644 homeassistant/components/lock/wink.py diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py new file mode 100644 index 00000000000..88768208c1e --- /dev/null +++ b/homeassistant/components/lock/__init__.py @@ -0,0 +1,124 @@ +""" +homeassistant.components.lock +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Component to interface with various locks that can be controlled remotely. + +For more details about this component, please refer to the documentation +at https://home-assistant.io/components/lock/ +""" +from datetime import timedelta +import logging +import os + +from homeassistant.config import load_yaml_config_file +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.entity import ToggleEntity + +from homeassistant.const import ( + STATE_LOCKED, SERVICE_LOCK, SERVICE_UNLOCK, ATTR_ENTITY_ID) +from homeassistant.components import ( + group, wink) + +DOMAIN = 'lock' +DEPENDENCIES = [] +SCAN_INTERVAL = 30 + +GROUP_NAME_ALL_LOCKS = 'all locks' +ENTITY_ID_ALL_LOCKS = group.ENTITY_ID_FORMAT.format('all_locks') + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + +ATTR_LOCKED = "locked" + +MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) + +# Maps discovered services to their platforms +DISCOVERY_PLATFORMS = { + wink.DISCOVER_LOCKS: 'wink' +} + +PROP_TO_ATTR = { + 'locked': ATTR_LOCKED +} + +_LOGGER = logging.getLogger(__name__) + + +def is_locked(hass, entity_id=None): + """ Returns if the lock is locked based on the statemachine. """ + entity_id = entity_id or ENTITY_ID_ALL_LOCKS + return hass.states.is_state(entity_id, STATE_LOCKED) + + +def do_lock(hass, entity_id=None): + """ Locks all or specified locks. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_LOCK, data) + + +def do_unlock(hass, entity_id=None): + """ Unlocks all or specified locks. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_UNLOCK, data) + + +def setup(hass, config): + """ Track states and offer events for locks. """ + component = EntityComponent( + _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, + GROUP_NAME_ALL_LOCKS) + component.setup(config) + + def handle_lock_service(service): + """ Handles calls to the lock services. """ + target_locks = component.extract_from_service(service) + + for lock in target_locks: + if service.service == SERVICE_LOCK: + lock.do_lock() + else: + lock.do_unlock() + + if lock.should_poll: + lock.update_ha_state(True) + + descriptions = load_yaml_config_file( + os.path.join(os.path.dirname(__file__), 'services.yaml')) + hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service, + descriptions.get(SERVICE_UNLOCK)) + hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service, + descriptions.get(SERVICE_LOCK)) + + return True + + +class LockDevice(ToggleEntity): + """ Represents a lock within Home Assistant. """ + # pylint: disable=no-self-use + + @property + def locked(self): + """ Is the lock locked or unlocked. """ + return None + + @property + def device_state_attributes(self): + """ Returns device specific state attributes. """ + return None + + @property + def state_attributes(self): + """ Returns optional state attributes. """ + data = {} + + for prop, attr in PROP_TO_ATTR.items(): + value = getattr(self, prop) + if value: + data[attr] = value + + device_attr = self.device_state_attributes + + if device_attr is not None: + data.update(device_attr) + + return data diff --git a/homeassistant/components/lock/demo.py b/homeassistant/components/lock/demo.py new file mode 100644 index 00000000000..76eea0104fb --- /dev/null +++ b/homeassistant/components/lock/demo.py @@ -0,0 +1,56 @@ +""" +homeassistant.components.lock.demo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Demo platform that has two fake locks. +""" +from homeassistant.components.lock import LockDevice +from homeassistant.const import ( + DEVICE_DEFAULT_NAME, STATE_LOCKED, STATE_UNLOCKED) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices_callback, discovery_info=None): + """ Find and return demo locks. """ + add_devices_callback([ + DemoLock('Left Door', STATE_LOCKED, None), + DemoLock('Right Door', STATE_UNLOCKED, None) + ]) + + +class DemoLock(LockDevice): + """ Provides a demo lock. """ + def __init__(self, name, state, icon): + self._name = name or DEVICE_DEFAULT_NAME + self._state = state + self._icon = icon + + @property + def should_poll(self): + """ No polling needed for a demo lock. """ + return False + + @property + def name(self): + """ Returns the name of the device if any. """ + return self._name + + @property + def icon(self): + """ Returns the icon to use for device if any. """ + return self._icon + + @property + def is_locked(self): + """ True if device is locked. """ + return self._state + + def do_lock(self, **kwargs): + """ Lock the device. """ + self._state = STATE_LOCKED + self.update_ha_state() + + def do_unlock(self, **kwargs): + """ Unlock the device. """ + self._state = STATE_UNLOCKED + self.update_ha_state() diff --git a/homeassistant/components/lock/services.yaml b/homeassistant/components/lock/services.yaml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/homeassistant/components/lock/wink.py b/homeassistant/components/lock/wink.py new file mode 100644 index 00000000000..059c3a56611 --- /dev/null +++ b/homeassistant/components/lock/wink.py @@ -0,0 +1,73 @@ +""" +homeassistant.components.lock.wink +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for Wink locks. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/lock.wink/ +""" +import logging + +from homeassistant.helpers.entity import Entity +from homeassistant.const import CONF_ACCESS_TOKEN, STATE_LOCKED, STATE_UNLOCKED + +REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' + '9eb39eaba0717922815e673ad1114c685839d890.zip' + '#python-wink==0.1.1'] + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Wink platform. """ + import pywink + + if discovery_info is None: + token = config.get(CONF_ACCESS_TOKEN) + + if token is None: + logging.getLogger(__name__).error( + "Missing wink access_token. " + "Get one at https://winkbearertoken.appspot.com/") + return + + pywink.set_bearer_token(token) + + add_devices(WinkLockDevice(lock) for lock in pywink.get_locks()) + + +class WinkLockDevice(Entity): + """ Represents a Wink lock. """ + + def __init__(self, wink): + self.wink = wink + + @property + def state(self): + """ Returns the state. """ + return STATE_LOCKED if self.is_locked else STATE_UNLOCKED + + @property + def unique_id(self): + """ Returns the id of this wink lock """ + return "{}.{}".format(self.__class__, self.wink.deviceId()) + + @property + def name(self): + """ Returns the name of the lock if any. """ + return self.wink.name() + + def update(self): + """ Update the state of the lock. """ + self.wink.updateState() + + @property + def is_locked(self): + """ True if device is locked. """ + return self.wink.state() + + def do_lock(self): + """ Lock the device. """ + self.wink.setState(True) + + def do_unlock(self): + """ Unlock the device. """ + self.wink.setState(False) diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 03601f1d958..66ea29ff4dd 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -25,6 +25,7 @@ REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' DISCOVER_LIGHTS = "wink.lights" DISCOVER_SWITCHES = "wink.switches" DISCOVER_SENSORS = "wink.sensors" +DISCOVER_LOCKS = "wink.locks" def setup(hass, config): @@ -41,7 +42,8 @@ def setup(hass, config): for component_name, func_exists, discovery_type in ( ('light', pywink.get_bulbs, DISCOVER_LIGHTS), ('switch', pywink.get_switches, DISCOVER_SWITCHES), - ('sensor', pywink.get_sensors, DISCOVER_SENSORS)): + ('sensor', pywink.get_sensors, DISCOVER_SENSORS), + ('lock', pywink.get_locks, DISCOVER_LOCKS)): if func_exists(): component = get_component(component_name) diff --git a/homeassistant/const.py b/homeassistant/const.py index da1e424718f..5b0b5a5e214 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -53,6 +53,8 @@ STATE_ALARM_ARMED_HOME = 'armed_home' STATE_ALARM_ARMED_AWAY = 'armed_away' STATE_ALARM_PENDING = 'pending' STATE_ALARM_TRIGGERED = 'triggered' +STATE_LOCKED = 'locked' +STATE_UNLOCKED = 'unlocked' # #### STATE AND EVENT ATTRIBUTES #### # Contains current time for a TIME_CHANGED event @@ -96,6 +98,9 @@ ATTR_BATTERY_LEVEL = "battery_level" # For devices which support an armed state ATTR_ARMED = "device_armed" +# For devices which support a locked state +ATTR_LOCKED = "locked" + # For sensors that support 'tripping', eg. motion and door sensors ATTR_TRIPPED = "device_tripped" @@ -135,6 +140,9 @@ SERVICE_ALARM_ARM_HOME = "alarm_arm_home" SERVICE_ALARM_ARM_AWAY = "alarm_arm_away" SERVICE_ALARM_TRIGGER = "alarm_trigger" +SERVICE_LOCK = "lock" +SERVICE_UNLOCK = "unlock" + # #### API / REMOTE #### SERVER_PORT = 8123 From e317e0798b3814f9adf4ac514f0b04c20b0da9ff Mon Sep 17 00:00:00 2001 From: Nolan Gilley Date: Tue, 17 Nov 2015 19:14:29 -0500 Subject: [PATCH 007/166] initial commit for ecobee thermostat component. --- homeassistant/components/sensor/ecobee.py | 101 +++++++ homeassistant/components/thermostat/ecobee.py | 263 ++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 367 insertions(+) create mode 100644 homeassistant/components/sensor/ecobee.py create mode 100644 homeassistant/components/thermostat/ecobee.py diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py new file mode 100644 index 00000000000..ba4db55b842 --- /dev/null +++ b/homeassistant/components/sensor/ecobee.py @@ -0,0 +1,101 @@ +""" +homeassistant.components.sensor.ecobee +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This sensor component requires that the Ecobee Thermostat +component be setup first. This component shows remote +ecobee sensor data. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.ecobee/ +""" +from homeassistant.helpers.entity import Entity +import json +import logging +import os + +SENSOR_TYPES = { + 'temperature': ['Temperature', '°F'], + 'humidity': ['Humidity', '%'], + 'occupancy': ['Occupancy', ''] +} + +_LOGGER = logging.getLogger(__name__) + +ECOBEE_CONFIG_FILE = 'ecobee.conf' + + +def config_from_file(filename, config=None): + ''' Small configuration file management function ''' + if config: + # We're writing configuration + try: + with open(filename, 'w') as fdesc: + fdesc.write(json.dumps(config)) + except IOError as error: + print(error) + return False + return True + else: + # We're reading config + if os.path.isfile(filename): + try: + with open(filename, 'r') as fdesc: + return json.loads(fdesc.read()) + except IOError as error: + return False + else: + return {} + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the sensors. """ + config = config_from_file(hass.config.path(ECOBEE_CONFIG_FILE)) + dev = list() + for name, data in config['sensors'].items(): + if 'temp' in data: + dev.append(EcobeeSensor(name, 'temperature', hass)) + if 'humidity' in data: + dev.append(EcobeeSensor(name, 'humidity', hass)) + if 'occupancy' in data: + dev.append(EcobeeSensor(name, 'occupancy', hass)) + + add_devices(dev) + + +class EcobeeSensor(Entity): + """ An ecobee sensor. """ + + def __init__(self, sensor_name, sensor_type, hass): + self._name = sensor_name + ' ' + SENSOR_TYPES[sensor_type][0] + self.sensor_name = sensor_name + self.hass = hass + self.type = sensor_type + self._state = None + self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] + self.update() + + @property + def name(self): + return self._name.rstrip() + + @property + def state(self): + """ Returns the state of the device. """ + return self._state + + @property + def unit_of_measurement(self): + return self._unit_of_measurement + + def update(self): + config = config_from_file(self.hass.config.path(ECOBEE_CONFIG_FILE)) + try: + data = config['sensors'][self.sensor_name] + if self.type == 'temperature': + self._state = data['temp'] + elif self.type == 'humidity': + self._state = data['humidity'] + elif self.type == 'occupancy': + self._state = data['occupancy'] + except KeyError: + print("Error updating ecobee sensors.") diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py new file mode 100644 index 00000000000..6792c34a421 --- /dev/null +++ b/homeassistant/components/thermostat/ecobee.py @@ -0,0 +1,263 @@ +#!/usr/local/bin/python3 +""" +homeassistant.components.thermostat.ecobee +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Ecobee Thermostat Component + +This component adds support for Ecobee3 Wireless Thermostats. +You will need to setup developer access to your thermostat, +and create and API key on the ecobee website. + +The first time you run this component you will see a configuration +component card in Home Assistant. This card will contain a PIN code +that you will need to use to authorize access to your thermostat. You +can do this at https://www.ecobee.com/consumerportal/index.html +Click My Apps, Add application, Enter Pin and click Authorize. + +After authorizing the application click the button in the configuration +card. Now your thermostat should shown in home-assistant. You will need +to restart home assistant to get rid of the configuration card. Once the +thermostat has been added you can add the ecobee sensor component +to your configuration.yaml. + +thermostat: + platform: ecobee + api_key: asdfasdfasdfasdfasdfaasdfasdfasdfasdf +""" +from homeassistant.loader import get_component +from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, + STATE_IDLE, STATE_HEAT) +from homeassistant.const import ( + CONF_API_KEY, TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) +import logging +import os + +REQUIREMENTS = [ + 'https://github.com/nkgilley/home-assistant-ecobee-api/archive/' + 'c61ee6d456bb5f4ab0c9598804aa9231c3d06f8e.zip#python-ecobee==0.1.1'] + +_LOGGER = logging.getLogger(__name__) + +ECOBEE_CONFIG_FILE = 'ecobee.conf' +_CONFIGURING = {} + + +def setup_platform(hass, config, add_devices_callback, discovery_info=None): + """ Setup Platform """ + # Only act if we are not already configuring this host + if 'ecobee' in _CONFIGURING: + return + + setup_ecobee(hass, config, add_devices_callback) + + +def setup_ecobee(hass, config, add_devices_callback): + """ Setup ecobee thermostat """ + from pyecobee import Ecobee, config_from_file + # Create ecobee.conf if it doesn't exist + if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)): + jsonconfig = {"API_KEY": config[CONF_API_KEY]} + config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig) + + ecobee = Ecobee(hass.config.path(ECOBEE_CONFIG_FILE)) + + # If ecobee has a PIN then it needs to be configured. + if ecobee.pin is not None: + # ecobee.request_pin() + request_configuration(ecobee, hass, add_devices_callback) + return + + if 'ecobee' in _CONFIGURING: + _CONFIGURING.pop('ecobee') + configurator = get_component('configurator') + configurator.request_done('ecobee') + + devices = [] + for index in range(0, len(ecobee.thermostats)): + devices.append(Thermostat(ecobee, index)) + + add_devices_callback(devices) + + +def request_configuration(ecobee, hass, add_devices_callback): + """ Request configuration steps from the user. """ + configurator = get_component('configurator') + if 'ecobee' in _CONFIGURING: + configurator.notify_errors( + _CONFIGURING['ecobee'], "Failed to register, please try again.") + + return + + # pylint: disable=unused-argument + def ecobee_configuration_callback(data): + """ Actions to do when our configuration callback is called. """ + ecobee.request_tokens() + ecobee.update() + setup_ecobee(hass, None, add_devices_callback) + + _CONFIGURING['ecobee'] = configurator.request_config( + hass, "Ecobee", ecobee_configuration_callback, + description=( + 'Please authorize this app at https://www.ecobee.com/consumer' + 'portal/index.html with pin code: ' + ecobee.pin), + description_image='https://goo.gl/6tBkbH', + submit_caption="I have authorized the app." + ) + + +class Thermostat(ThermostatDevice): + """docstring for Thermostat""" + + def __init__(self, ecobee, thermostat_index): + self.ecobee = ecobee + self.thermostat_index = thermostat_index + self.thermostat_data = self.ecobee.get_thermostat( + self.thermostat_index) + self._name = self.thermostat_data['name'] + if 'away' in self.thermostat_data['program']['currentClimateRef']: + self._away = True + else: + self._away = False + + def update(self): + self.thermostat_data = self.ecobee.get_thermostat( + self.thermostat_index) + _LOGGER.info("ecobee data updated successfully.") + + @property + def name(self): + """ Returns the name of the Ecobee Thermostat. """ + return self.thermostat_data['name'] + + @property + def unit_of_measurement(self): + """ Unit of measurement this thermostat expresses itself in. """ + return TEMP_FAHRENHEIT + + @property + def current_temperature(self): + """ Returns the current temperature. """ + return self.thermostat_data['runtime']['actualTemperature'] / 10 + + @property + def target_temperature(self): + """ Returns the temperature we try to reach. """ + return (self.target_temperature_low + self.target_temperature_high) / 2 + + @property + def target_temperature_low(self): + """ Returns the lower bound temperature we try to reach. """ + return int(self.thermostat_data['runtime']['desiredHeat'] / 10) + + @property + def target_temperature_high(self): + """ Returns the upper bound temperature we try to reach. """ + return int(self.thermostat_data['runtime']['desiredCool'] / 10) + + @property + def humidity(self): + """ Returns the current humidity. """ + return self.thermostat_data['runtime']['actualHumidity'] + + @property + def desired_fan_mode(self): + """ Returns the desired fan mode of operation. """ + return self.thermostat_data['runtime']['desiredFanMode'] + + @property + def fan(self): + """ Returns the current fan state. """ + if 'fan' in self.thermostat_data['equipmentStatus']: + return STATE_ON + else: + return STATE_OFF + + @property + def operation(self): + """ Returns current operation ie. heat, cool, idle """ + status = self.thermostat_data['equipmentStatus'] + if status == '': + return STATE_IDLE + elif 'Cool' in status: + return STATE_COOL + elif 'auxHeat' in status: + return STATE_HEAT + elif 'heatPump' in status: + return STATE_HEAT + else: + return status + + @property + def mode(self): + """ Returns current mode ie. home, away, sleep """ + mode = self.thermostat_data['program']['currentClimateRef'] + if 'away' in mode: + self._away = True + else: + self._away = False + return mode + + @property + def hvac_mode(self): + """ Return current hvac mode ie. auto, auxHeatOnly, cool, heat, off """ + return self.thermostat_data['settings']['hvacMode'] + + @property + def device_state_attributes(self): + """ Returns device specific state attributes. """ + # Move these to Thermostat Device and make them global + return { + "humidity": self.humidity, + "fan": self.fan, + "mode": self.mode, + "hvac_mode": self.hvac_mode + } + + @property + def is_away_mode_on(self): + """ Returns if away mode is on. """ + return self._away + + def turn_away_mode_on(self): + """ Turns away on. """ + self._away = True + self.ecobee.set_climate_hold("away") + + def turn_away_mode_off(self): + """ Turns away off. """ + self._away = False + self.ecobee.resume_program() + + def set_temperature(self, temperature): + """ Set new target temperature """ + temperature = int(temperature) + low_temp = temperature - 1 + high_temp = temperature + 1 + self.ecobee.set_hold_temp(low_temp, high_temp) + + def set_hvac_mode(self, mode): + """ Set HVAC mode (auto, auxHeatOnly, cool, heat, off) """ + self.ecobee.set_hvac_mode(mode) + + # Home and Sleep mode aren't used in UI yet: + + # def turn_home_mode_on(self): + # """ Turns home mode on. """ + # self._away = False + # self.ecobee.set_climate_hold("home") + + # def turn_home_mode_off(self): + # """ Turns home mode off. """ + # self._away = False + # self.ecobee.resume_program() + + # def turn_sleep_mode_on(self): + # """ Turns sleep mode on. """ + # self._away = False + # self.ecobee.set_climate_hold("sleep") + + # def turn_sleep_mode_off(self): + # """ Turns sleep mode off. """ + # self._away = False + # self.ecobee.resume_program() diff --git a/requirements_all.txt b/requirements_all.txt index ce6cbfabc96..db7ca1ada2d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -159,3 +159,6 @@ pushetta==1.0.15 # Orvibo S10 orvibo==1.0.0 + +# Ecobee (*.ecobee) +https://github.com/nkgilley/home-assistant-ecobee-api/archive/e0388659a0f2fc7266485affbd398350cc0b5c58.zip#python-ecobee==0.1.1 From 22fcbc67cfa61ca8f372a4ce978c687c19d5346d Mon Sep 17 00:00:00 2001 From: Nolan Gilley Date: Tue, 17 Nov 2015 19:20:56 -0500 Subject: [PATCH 008/166] fix req --- homeassistant/components/thermostat/ecobee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 6792c34a421..cbdd52ba7e9 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -35,7 +35,7 @@ import os REQUIREMENTS = [ 'https://github.com/nkgilley/home-assistant-ecobee-api/archive/' - 'c61ee6d456bb5f4ab0c9598804aa9231c3d06f8e.zip#python-ecobee==0.1.1'] + 'e0388659a0f2fc7266485affbd398350cc0b5c58.zip#python-ecobee==0.1.1'] _LOGGER = logging.getLogger(__name__) From ab9e173179fc7a9e890f7df81088a095ffa3ec21 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 18 Nov 2015 08:42:49 +0100 Subject: [PATCH 009/166] Update docstrings --- homeassistant/components/camera/__init__.py | 15 ++++++++------- homeassistant/components/camera/generic.py | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index ff5198b7ab1..ae5fe28beac 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -58,7 +58,7 @@ MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n' # pylint: disable=too-many-branches def setup(hass, config): - """ Track states and offer events for sensors. """ + """ Track states and offer events for cameras. """ component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL, @@ -101,7 +101,8 @@ def setup(hass, config): # pylint: disable=unused-argument def _proxy_camera_mjpeg_stream(handler, path_match, data): - """ Proxies the camera image as an mjpeg stream via the HA server. + """ + Proxies the camera image as an mjpeg stream via the HA server. This function takes still images from the IP camera and turns them into an MJPEG stream. This means that HA can return a live video stream even with only a still image URL available. @@ -163,7 +164,7 @@ def setup(hass, config): class Camera(Entity): - """ The base class for camera components """ + """ The base class for camera components. """ def __init__(self): self.is_streaming = False @@ -171,23 +172,23 @@ class Camera(Entity): @property # pylint: disable=no-self-use def is_recording(self): - """ Returns true if the device is recording """ + """ Returns true if the device is recording. """ return False @property # pylint: disable=no-self-use def brand(self): - """ Should return a string of the camera brand """ + """ Should return a string of the camera brand. """ return None @property # pylint: disable=no-self-use def model(self): - """ Returns string of camera model """ + """ Returns string of camera model. """ return None def camera_image(self): - """ Return bytes of camera image """ + """ Return bytes of camera image. """ raise NotImplementedError() @property diff --git a/homeassistant/components/camera/generic.py b/homeassistant/components/camera/generic.py index b8be51292bf..7e9542908d5 100644 --- a/homeassistant/components/camera/generic.py +++ b/homeassistant/components/camera/generic.py @@ -40,7 +40,7 @@ class GenericCamera(Camera): self._still_image_url = device_info['still_image_url'] def camera_image(self): - """ Return a still image reponse from the camera. """ + """ Return a still image response from the camera. """ if self._username and self._password: try: response = requests.get( From c6d1a4bdaf572407cfbfe79dd5a259c6290a3780 Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Wed, 18 Nov 2015 10:13:46 -0500 Subject: [PATCH 010/166] Fix configurator, rename repo, cleanup code. --- homeassistant/components/sensor/ecobee.py | 26 ++++----- homeassistant/components/thermostat/ecobee.py | 53 ++++++++----------- requirements_all.txt | 2 +- 3 files changed, 32 insertions(+), 49 deletions(-) diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py index ba4db55b842..a8d9e41acb1 100644 --- a/homeassistant/components/sensor/ecobee.py +++ b/homeassistant/components/sensor/ecobee.py @@ -13,6 +13,8 @@ import json import logging import os +DEPENDENCIES = ['thermostat'] + SENSOR_TYPES = { 'temperature': ['Temperature', '°F'], 'humidity': ['Humidity', '%'], @@ -24,27 +26,17 @@ _LOGGER = logging.getLogger(__name__) ECOBEE_CONFIG_FILE = 'ecobee.conf' -def config_from_file(filename, config=None): - ''' Small configuration file management function ''' - if config: - # We're writing configuration +def config_from_file(filename): + ''' Small configuration file reading function ''' + if os.path.isfile(filename): try: - with open(filename, 'w') as fdesc: - fdesc.write(json.dumps(config)) + with open(filename, 'r') as fdesc: + return json.loads(fdesc.read()) except IOError as error: - print(error) + _LOGGER.error("ecobee sensor couldn't read config file: " + error) return False - return True else: - # We're reading config - if os.path.isfile(filename): - try: - with open(filename, 'r') as fdesc: - return json.loads(fdesc.read()) - except IOError as error: - return False - else: - return {} + return {} def setup_platform(hass, config, add_devices, discovery_info=None): diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index cbdd52ba7e9..0c00fb0de46 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -16,8 +16,7 @@ can do this at https://www.ecobee.com/consumerportal/index.html Click My Apps, Add application, Enter Pin and click Authorize. After authorizing the application click the button in the configuration -card. Now your thermostat should shown in home-assistant. You will need -to restart home assistant to get rid of the configuration card. Once the +card. Now your thermostat should shown in home-assistant. Once the thermostat has been added you can add the ecobee sensor component to your configuration.yaml. @@ -34,8 +33,8 @@ import logging import os REQUIREMENTS = [ - 'https://github.com/nkgilley/home-assistant-ecobee-api/archive/' - 'e0388659a0f2fc7266485affbd398350cc0b5c58.zip#python-ecobee==0.1.1'] + 'https://github.com/nkgilley/python-ecobee-api/archive/' + '824a7dfabe7ef6975b2864f33e6ae0b48fb6ea3f.zip#python-ecobee==0.0.1'] _LOGGER = logging.getLogger(__name__) @@ -64,20 +63,15 @@ def setup_ecobee(hass, config, add_devices_callback): # If ecobee has a PIN then it needs to be configured. if ecobee.pin is not None: - # ecobee.request_pin() request_configuration(ecobee, hass, add_devices_callback) return if 'ecobee' in _CONFIGURING: - _CONFIGURING.pop('ecobee') configurator = get_component('configurator') - configurator.request_done('ecobee') + configurator.request_done(_CONFIGURING.pop('ecobee')) - devices = [] - for index in range(0, len(ecobee.thermostats)): - devices.append(Thermostat(ecobee, index)) - - add_devices_callback(devices) + add_devices_callback(Thermostat(ecobee, index) + for index in range(len(ecobee.thermostats))) def request_configuration(ecobee, hass, add_devices_callback): @@ -101,34 +95,31 @@ def request_configuration(ecobee, hass, add_devices_callback): description=( 'Please authorize this app at https://www.ecobee.com/consumer' 'portal/index.html with pin code: ' + ecobee.pin), - description_image='https://goo.gl/6tBkbH', + description_image="/static/images/config_ecobee_thermostat.png", submit_caption="I have authorized the app." ) class Thermostat(ThermostatDevice): - """docstring for Thermostat""" + """ Thermostat class for Ecobee """ def __init__(self, ecobee, thermostat_index): self.ecobee = ecobee self.thermostat_index = thermostat_index - self.thermostat_data = self.ecobee.get_thermostat( + self.thermostat = self.ecobee.get_thermostat( self.thermostat_index) - self._name = self.thermostat_data['name'] - if 'away' in self.thermostat_data['program']['currentClimateRef']: - self._away = True - else: - self._away = False + self._name = self.thermostat['name'] + self._away = 'away' in self.thermostat['program']['currentClimateRef'] def update(self): - self.thermostat_data = self.ecobee.get_thermostat( + self.thermostat = self.ecobee.get_thermostat( self.thermostat_index) _LOGGER.info("ecobee data updated successfully.") @property def name(self): """ Returns the name of the Ecobee Thermostat. """ - return self.thermostat_data['name'] + return self.thermostat['name'] @property def unit_of_measurement(self): @@ -138,7 +129,7 @@ class Thermostat(ThermostatDevice): @property def current_temperature(self): """ Returns the current temperature. """ - return self.thermostat_data['runtime']['actualTemperature'] / 10 + return self.thermostat['runtime']['actualTemperature'] / 10 @property def target_temperature(self): @@ -148,27 +139,27 @@ class Thermostat(ThermostatDevice): @property def target_temperature_low(self): """ Returns the lower bound temperature we try to reach. """ - return int(self.thermostat_data['runtime']['desiredHeat'] / 10) + return int(self.thermostat['runtime']['desiredHeat'] / 10) @property def target_temperature_high(self): """ Returns the upper bound temperature we try to reach. """ - return int(self.thermostat_data['runtime']['desiredCool'] / 10) + return int(self.thermostat['runtime']['desiredCool'] / 10) @property def humidity(self): """ Returns the current humidity. """ - return self.thermostat_data['runtime']['actualHumidity'] + return self.thermostat['runtime']['actualHumidity'] @property def desired_fan_mode(self): """ Returns the desired fan mode of operation. """ - return self.thermostat_data['runtime']['desiredFanMode'] + return self.thermostat['runtime']['desiredFanMode'] @property def fan(self): """ Returns the current fan state. """ - if 'fan' in self.thermostat_data['equipmentStatus']: + if 'fan' in self.thermostat['equipmentStatus']: return STATE_ON else: return STATE_OFF @@ -176,7 +167,7 @@ class Thermostat(ThermostatDevice): @property def operation(self): """ Returns current operation ie. heat, cool, idle """ - status = self.thermostat_data['equipmentStatus'] + status = self.thermostat['equipmentStatus'] if status == '': return STATE_IDLE elif 'Cool' in status: @@ -191,7 +182,7 @@ class Thermostat(ThermostatDevice): @property def mode(self): """ Returns current mode ie. home, away, sleep """ - mode = self.thermostat_data['program']['currentClimateRef'] + mode = self.thermostat['program']['currentClimateRef'] if 'away' in mode: self._away = True else: @@ -201,7 +192,7 @@ class Thermostat(ThermostatDevice): @property def hvac_mode(self): """ Return current hvac mode ie. auto, auxHeatOnly, cool, heat, off """ - return self.thermostat_data['settings']['hvacMode'] + return self.thermostat['settings']['hvacMode'] @property def device_state_attributes(self): diff --git a/requirements_all.txt b/requirements_all.txt index db7ca1ada2d..4e34b6029ac 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -161,4 +161,4 @@ pushetta==1.0.15 orvibo==1.0.0 # Ecobee (*.ecobee) -https://github.com/nkgilley/home-assistant-ecobee-api/archive/e0388659a0f2fc7266485affbd398350cc0b5c58.zip#python-ecobee==0.1.1 +https://github.com/nkgilley/python-ecobee-api/archive/824a7dfabe7ef6975b2864f33e6ae0b48fb6ea3f.zip#python-ecobee==0.0.1 From 18d0f4461f0fade2e919f16ae18c826932b9e749 Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Wed, 18 Nov 2015 10:16:16 -0500 Subject: [PATCH 011/166] add config png to images dir. --- .../images/config_ecobee_thermostat.png | Bin 0 -> 31083 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 homeassistant/components/frontend/www_static/images/config_ecobee_thermostat.png diff --git a/homeassistant/components/frontend/www_static/images/config_ecobee_thermostat.png b/homeassistant/components/frontend/www_static/images/config_ecobee_thermostat.png new file mode 100644 index 0000000000000000000000000000000000000000..e62a4165c9becb8c974faa54523cd1bad9b4ef32 GIT binary patch literal 31083 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 xU6?KYcZ>A7BL5HbU&-%mneX{5e$8K|?t}7cwC# Date: Wed, 18 Nov 2015 10:43:52 -0500 Subject: [PATCH 012/166] point to updated python-ecobee library --- homeassistant/components/thermostat/ecobee.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 0c00fb0de46..472c0e60b60 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -34,7 +34,7 @@ import os REQUIREMENTS = [ 'https://github.com/nkgilley/python-ecobee-api/archive/' - '824a7dfabe7ef6975b2864f33e6ae0b48fb6ea3f.zip#python-ecobee==0.0.1'] + '730009b9593899d42e98c81a0544f91e65b2bc15.zip#python-ecobee==0.0.1'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 4e34b6029ac..3a930c145dd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -161,4 +161,4 @@ pushetta==1.0.15 orvibo==1.0.0 # Ecobee (*.ecobee) -https://github.com/nkgilley/python-ecobee-api/archive/824a7dfabe7ef6975b2864f33e6ae0b48fb6ea3f.zip#python-ecobee==0.0.1 +https://github.com/nkgilley/python-ecobee-api/archive/730009b9593899d42e98c81a0544f91e65b2bc15.zip#python-ecobee==0.0.1 From f1fed789927e416b1b82d955af80bd563701e1bd Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 18 Nov 2015 19:19:27 +0100 Subject: [PATCH 013/166] Fix issue with older glances releases #637 (thanks @jdotbdot) --- homeassistant/components/sensor/glances.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/glances.py b/homeassistant/components/sensor/glances.py index 176081336df..1c7bfa8dbd9 100644 --- a/homeassistant/components/sensor/glances.py +++ b/homeassistant/components/sensor/glances.py @@ -116,7 +116,11 @@ class GlancesSensor(Entity): elif self.type == 'disk_use': return round(value['fs'][0]['used'] / 1024**3, 1) elif self.type == 'disk_free': - return round(value['fs'][0]['free'] / 1024**3, 1) + try: + return round(value['fs'][0]['free'] / 1024**3, 1) + except KeyError: + return round((value['fs'][0]['size'] - + value['fs'][0]['used']) /1024**3, 1) elif self.type == 'memory_use_percent': return value['mem']['percent'] elif self.type == 'memory_use': From d05af626802231bf1398298a5e1cb9d0753a1820 Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Wed, 18 Nov 2015 14:57:27 -0500 Subject: [PATCH 014/166] use Throttle like the BitCoin component. --- .coveragerc | 1 + homeassistant/components/thermostat/ecobee.py | 82 +++++++++++-------- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/.coveragerc b/.coveragerc index f19e37d00a1..9fafe443dcf 100644 --- a/.coveragerc +++ b/.coveragerc @@ -16,6 +16,7 @@ omit = homeassistant/components/*/tellstick.py homeassistant/components/*/vera.py + homeassistant/components/*/ecobee.py homeassistant/components/verisure.py homeassistant/components/*/verisure.py diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 472c0e60b60..7258a3b65a1 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -29,18 +29,23 @@ from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) from homeassistant.const import ( CONF_API_KEY, TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) +from homeassistant.util import Throttle +from datetime import timedelta import logging import os REQUIREMENTS = [ 'https://github.com/nkgilley/python-ecobee-api/archive/' - '730009b9593899d42e98c81a0544f91e65b2bc15.zip#python-ecobee==0.0.1'] + '790c20d820dbb727af2dbfb3ef0f79231e19a503.zip#python-ecobee==0.0.1'] _LOGGER = logging.getLogger(__name__) ECOBEE_CONFIG_FILE = 'ecobee.conf' _CONFIGURING = {} +# Return cached results if last scan was less then this time ago +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180) + def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup Platform """ @@ -48,33 +53,32 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): if 'ecobee' in _CONFIGURING: return - setup_ecobee(hass, config, add_devices_callback) + from pyecobee import config_from_file - -def setup_ecobee(hass, config, add_devices_callback): - """ Setup ecobee thermostat """ - from pyecobee import Ecobee, config_from_file # Create ecobee.conf if it doesn't exist if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)): jsonconfig = {"API_KEY": config[CONF_API_KEY]} config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig) + data = EcobeeData(hass.config.path(ECOBEE_CONFIG_FILE)) + setup_ecobee(hass, data, config, add_devices_callback) - ecobee = Ecobee(hass.config.path(ECOBEE_CONFIG_FILE)) +def setup_ecobee(hass, data, config, add_devices_callback): + """ Setup ecobee thermostat """ # If ecobee has a PIN then it needs to be configured. - if ecobee.pin is not None: - request_configuration(ecobee, hass, add_devices_callback) + if data.ecobee.pin is not None: + request_configuration(data, hass, add_devices_callback) return if 'ecobee' in _CONFIGURING: configurator = get_component('configurator') configurator.request_done(_CONFIGURING.pop('ecobee')) - add_devices_callback(Thermostat(ecobee, index) - for index in range(len(ecobee.thermostats))) + add_devices_callback(Thermostat(data, index) + for index in range(len(data.ecobee.thermostats))) -def request_configuration(ecobee, hass, add_devices_callback): +def request_configuration(data, hass, add_devices_callback): """ Request configuration steps from the user. """ configurator = get_component('configurator') if 'ecobee' in _CONFIGURING: @@ -84,35 +88,50 @@ def request_configuration(ecobee, hass, add_devices_callback): return # pylint: disable=unused-argument - def ecobee_configuration_callback(data): + def ecobee_configuration_callback(callback_data): """ Actions to do when our configuration callback is called. """ - ecobee.request_tokens() - ecobee.update() - setup_ecobee(hass, None, add_devices_callback) + data.ecobee.request_tokens() + data.ecobee.update() + setup_ecobee(hass, data, None, add_devices_callback) _CONFIGURING['ecobee'] = configurator.request_config( hass, "Ecobee", ecobee_configuration_callback, description=( 'Please authorize this app at https://www.ecobee.com/consumer' - 'portal/index.html with pin code: ' + ecobee.pin), + 'portal/index.html with pin code: ' + data.ecobee.pin), description_image="/static/images/config_ecobee_thermostat.png", submit_caption="I have authorized the app." ) +# pylint: disable=too-few-public-methods +class EcobeeData(object): + """ Gets the latest data and update the states. """ + + def __init__(self, config_filename): + from pyecobee import Ecobee + self.ecobee = Ecobee(config_filename) + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """ Get the latest data from pyecobee. """ + self.ecobee.update() + + class Thermostat(ThermostatDevice): """ Thermostat class for Ecobee """ - def __init__(self, ecobee, thermostat_index): - self.ecobee = ecobee + def __init__(self, data, thermostat_index): + self.data = data self.thermostat_index = thermostat_index - self.thermostat = self.ecobee.get_thermostat( + self.thermostat = self.data.ecobee.get_thermostat( self.thermostat_index) self._name = self.thermostat['name'] self._away = 'away' in self.thermostat['program']['currentClimateRef'] def update(self): - self.thermostat = self.ecobee.get_thermostat( + self.data.update() + self.thermostat = self.data.ecobee.get_thermostat( self.thermostat_index) _LOGGER.info("ecobee data updated successfully.") @@ -183,10 +202,7 @@ class Thermostat(ThermostatDevice): def mode(self): """ Returns current mode ie. home, away, sleep """ mode = self.thermostat['program']['currentClimateRef'] - if 'away' in mode: - self._away = True - else: - self._away = False + self._away = 'away' in mode return mode @property @@ -213,42 +229,42 @@ class Thermostat(ThermostatDevice): def turn_away_mode_on(self): """ Turns away on. """ self._away = True - self.ecobee.set_climate_hold("away") + self.data.ecobee.set_climate_hold("away") def turn_away_mode_off(self): """ Turns away off. """ self._away = False - self.ecobee.resume_program() + self.data.ecobee.resume_program() def set_temperature(self, temperature): """ Set new target temperature """ temperature = int(temperature) low_temp = temperature - 1 high_temp = temperature + 1 - self.ecobee.set_hold_temp(low_temp, high_temp) + self.data.ecobee.set_hold_temp(low_temp, high_temp) def set_hvac_mode(self, mode): """ Set HVAC mode (auto, auxHeatOnly, cool, heat, off) """ - self.ecobee.set_hvac_mode(mode) + self.data.ecobee.set_hvac_mode(mode) # Home and Sleep mode aren't used in UI yet: # def turn_home_mode_on(self): # """ Turns home mode on. """ # self._away = False - # self.ecobee.set_climate_hold("home") + # self.data.ecobee.set_climate_hold("home") # def turn_home_mode_off(self): # """ Turns home mode off. """ # self._away = False - # self.ecobee.resume_program() + # self.data.ecobee.resume_program() # def turn_sleep_mode_on(self): # """ Turns sleep mode on. """ # self._away = False - # self.ecobee.set_climate_hold("sleep") + # self.data.ecobee.set_climate_hold("sleep") # def turn_sleep_mode_off(self): # """ Turns sleep mode off. """ # self._away = False - # self.ecobee.resume_program() + # self.data.ecobee.resume_program() From 4eacea32da47d605edf09dd1720a244a2ae41e88 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 19 Nov 2015 18:07:54 +0100 Subject: [PATCH 015/166] Fix pylint issue --- homeassistant/components/sensor/glances.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/glances.py b/homeassistant/components/sensor/glances.py index 1c7bfa8dbd9..092e4c75733 100644 --- a/homeassistant/components/sensor/glances.py +++ b/homeassistant/components/sensor/glances.py @@ -120,7 +120,7 @@ class GlancesSensor(Entity): return round(value['fs'][0]['free'] / 1024**3, 1) except KeyError: return round((value['fs'][0]['size'] - - value['fs'][0]['used']) /1024**3, 1) + value['fs'][0]['used']) / 1024**3, 1) elif self.type == 'memory_use_percent': return value['mem']['percent'] elif self.type == 'memory_use': From 5f89db59577b78e0f3117cf10d5cdcf2480b1641 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 19 Nov 2015 19:00:22 +0100 Subject: [PATCH 016/166] Binary sensor component --- .../components/binary_sensor/__init__.py | 44 +++++++++++++++++ .../components/binary_sensor/demo.py | 49 +++++++++++++++++++ homeassistant/components/demo.py | 2 +- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/binary_sensor/__init__.py create mode 100644 homeassistant/components/binary_sensor/demo.py diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py new file mode 100644 index 00000000000..b02d38a9f81 --- /dev/null +++ b/homeassistant/components/binary_sensor/__init__.py @@ -0,0 +1,44 @@ +""" +homeassistant.components.binary_sensor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Component to interface with binary sensors (sensors which only know two states) +that can be monitored. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/binary_sensor/ +""" +import logging + +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.entity import Entity + +DOMAIN = 'binary_sensor' +DEPENDENCIES = [] +SCAN_INTERVAL = 30 + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + + +def setup(hass, config): + """ Track states and offer events for binary sensors. """ + component = EntityComponent( + logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) + + component.setup(config) + + return True + + +# pylint: disable=no-self-use +class BinarySensorDevice(Entity): + """ Represents a binary sensor.. """ + + @property + def is_on(self): + """ True if the binary sensor is on. """ + return False + + @property + def friendly_state(self): + """ Returns the friendly state of the binary sensor. """ + return None diff --git a/homeassistant/components/binary_sensor/demo.py b/homeassistant/components/binary_sensor/demo.py new file mode 100644 index 00000000000..266b46b7e17 --- /dev/null +++ b/homeassistant/components/binary_sensor/demo.py @@ -0,0 +1,49 @@ +""" +homeassistant.components.binary_sensor.demo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Demo platform that has two fake binary sensors. +""" +from homeassistant.components.binary_sensor import BinarySensorDevice +from homeassistant.const import (STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Demo binary sensors. """ + add_devices([ + DemoBinarySensor('Window Bathroom', True, None), + DemoBinarySensor('Floor Basement', False, None), + ]) + + +class DemoBinarySensor(BinarySensorDevice): + """ A Demo binary sensor. """ + + def __init__(self, name, state, icon=None): + self._name = name or DEVICE_DEFAULT_NAME + self._state = state + self._icon = icon + + @property + def should_poll(self): + """ No polling needed for a demo binary sensor. """ + return False + + @property + def name(self): + """ Returns the name of the binary sensor. """ + return self._name + + @property + def icon(self): + """ Returns the icon to use for device if any. """ + return self._icon + + @property + def is_on(self): + """ True if the sensor is on. """ + return self._state + + @property + def state(self): + """ Returns the state of the binary sensor. """ + return STATE_ON if self.is_on else STATE_OFF diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 7c873e834bd..3022a0e9393 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone'] COMPONENTS_WITH_DEMO_PLATFORM = [ 'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor', - 'thermostat'] + 'thermostat', 'binary_sensor'] def setup(hass, config): From ca32c81612d2c31f0cda34319fad2011fdbac515 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 19 Nov 2015 19:27:10 +0100 Subject: [PATCH 017/166] Camera demo --- homeassistant/components/camera/demo.py | 37 +++++++++++++++++++++ homeassistant/components/camera/demo_1.png | Bin 0 -> 9772 bytes homeassistant/components/camera/demo_2.png | Bin 0 -> 9667 bytes homeassistant/components/camera/demo_3.png | Bin 0 -> 9595 bytes homeassistant/components/camera/demo_4.png | Bin 0 -> 9906 bytes homeassistant/components/camera/demo_5.png | Bin 0 -> 9699 bytes 6 files changed, 37 insertions(+) create mode 100644 homeassistant/components/camera/demo.py create mode 100644 homeassistant/components/camera/demo_1.png create mode 100644 homeassistant/components/camera/demo_2.png create mode 100644 homeassistant/components/camera/demo_3.png create mode 100644 homeassistant/components/camera/demo_4.png create mode 100644 homeassistant/components/camera/demo_5.png diff --git a/homeassistant/components/camera/demo.py b/homeassistant/components/camera/demo.py new file mode 100644 index 00000000000..fc3ec263143 --- /dev/null +++ b/homeassistant/components/camera/demo.py @@ -0,0 +1,37 @@ +""" +homeassistant.components.camera.demo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Demo platform that has a fake camera. +""" +import os +from random import randint +from homeassistant.components.camera import Camera + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Demo camera. """ + add_devices([ + DemoCamera('Demo camera') + ]) + + +class DemoCamera(Camera): + """ A Demo camera. """ + + def __init__(self, name): + super().__init__() + self._name = name + + def camera_image(self): + """ Return a faked still image response. """ + + image_path = os.path.join(os.path.dirname(__file__), + 'demo_{}.png'.format(randint(1, 5))) + with open(image_path, 'rb') as file: + output = file.read() + return output + + @property + def name(self): + """ Return the name of this device. """ + return self._name diff --git a/homeassistant/components/camera/demo_1.png b/homeassistant/components/camera/demo_1.png new file mode 100644 index 0000000000000000000000000000000000000000..fc681fccecd69fb91801a6ecad8cd28454cae278 GIT binary patch literal 9772 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 NgQu&X%Q~loCIAIg5cmK9 literal 0 HcmV?d00001 diff --git a/homeassistant/components/camera/demo_2.png b/homeassistant/components/camera/demo_2.png new file mode 100644 index 0000000000000000000000000000000000000000..255cd5c45d4510cdc5853f22080017af1fad0e68 GIT binary patch literal 9667 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 literal 0 HcmV?d00001 diff --git a/homeassistant/components/camera/demo_3.png b/homeassistant/components/camera/demo_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b54c1ffb57c97644426efae5950dcf47e8c70031 GIT binary patch literal 9595 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

bv~b* z3&mb5r&cP(wXrSp^Fp-4LB&e`;dMv-vSc zYCfg>-1&LcKeIg9XC1rV>|!{lzkO4}9^;kWs?!|o<6m~o`m$FyuH#aOx0}q|gR!FX zELE#aSRL*&wJukGVz??=-Gp7(?Dm-h-?i4x3C(&qS<3$Qp`_bFbIoMWO_{uMnbYio zuX4S!!*>4oTA^P1$VY9yUSY|v^1vTwkJwz3`?&d6$Na@|y-u?eayGVd-qqDSZ#T=^ zqcZ8jQK<;~=X*@jT7AP7lyom%+~JV5u4H}Bb*Un$GMSQX7n?GCEn*j3n^kb}h~yl$ zLY0jZKh0>+TpIQ+tKDJak;<5^$$@9o{nNLwTUfU_l&>k3{AT^+(h>``gEgO0b~8k( z%yMu)R3s)-CYinHoKm0U{<$xooDA8rF%q;QK;O;c(W|3UVJkj7`O&A(=W@^GOvB43 zoV_{k*35}cd-`sJlm;lc`}>M7EuE}l_+yV=X<_TiLnWVTqFz7$zI%_L<}@qm^yyJM zi(Q^1tW{7rx8B+@nD@bq@W`iA<%RV^xxUn=C;G-KVfi5^9)I2WKOp{-P5 z^{{!n)a6oTW>`b=P4Jo)6OD|Tsc(ZkRCcy+^A_Boc>CxCkD>{^U2LZ}#d3A3T)!Y7 zuOWB!zuBhC4oaE)aO2Zs4*uevT!f4(eJWzrnSj{W~$-#KK(>JWS+`KDgK%Oq`% zsmC8YQF!V8{7F6Eqw_a)C%GimvFQAJu%~INfKcLsm5ohe|M`>m*Y8j0$c-+G`xno0>+4MY=`KlCd9h`62k$$@ zcX06hO~|_L%JG)%K+VoNl}Tq7E6&)RlQliQeZQdb$Lo>rP2*NA+}q(+San)$;*4ok zA%&$Cy^Dp5y$-QI7u%z%b1I{y!nQVbvd5XuhNE`AJzc8jPS)Ofwx(QKJ%ele;!JVo zz9~}!lnll59;{!bB=`5loTjU}Z||(DS-brI-;9lqHq?bL@MUvre!(xobneJ0t%)hT x;ujch=`Gyo=d2@a_TJvkVz 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 literal 0 HcmV?d00001 From 685964785d6a2da7a9f47d69cd921034749dcb10 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 19 Nov 2015 19:35:51 +0100 Subject: [PATCH 018/166] Add camera to demos --- homeassistant/components/demo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 7c873e834bd..c8888a71c1b 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone'] COMPONENTS_WITH_DEMO_PLATFORM = [ 'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor', - 'thermostat'] + 'thermostat', 'camera'] def setup(hass, config): From fa7391cdf684bb643bba77fbeb79ef0691fa37c0 Mon Sep 17 00:00:00 2001 From: miniconfig Date: Thu, 19 Nov 2015 16:54:55 -0500 Subject: [PATCH 019/166] Changed do_lock and do_unlock methods to lock and unlock. Implemented state method. Fixed locked method for demo interface. Changed LockDevice to extend Entity instead of ToggleEntity --- homeassistant/components/lock/__init__.py | 51 ++++++++--------------- homeassistant/components/lock/demo.py | 11 +++-- homeassistant/components/lock/wink.py | 17 +++----- 3 files changed, 31 insertions(+), 48 deletions(-) diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index 88768208c1e..613410dfd07 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -12,12 +12,12 @@ import os from homeassistant.config import load_yaml_config_file from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.helpers.entity import ToggleEntity +from homeassistant.helpers.entity import Entity from homeassistant.const import ( - STATE_LOCKED, SERVICE_LOCK, SERVICE_UNLOCK, ATTR_ENTITY_ID) -from homeassistant.components import ( - group, wink) + STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN, SERVICE_LOCK, SERVICE_UNLOCK, + ATTR_ENTITY_ID) +from homeassistant.components import (group, wink) DOMAIN = 'lock' DEPENDENCIES = [] @@ -44,19 +44,19 @@ PROP_TO_ATTR = { _LOGGER = logging.getLogger(__name__) -def is_locked(hass, entity_id=None): +def locked(hass, entity_id=None): """ Returns if the lock is locked based on the statemachine. """ entity_id = entity_id or ENTITY_ID_ALL_LOCKS return hass.states.is_state(entity_id, STATE_LOCKED) -def do_lock(hass, entity_id=None): +def lock(hass, entity_id=None): """ Locks all or specified locks. """ data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_LOCK, data) -def do_unlock(hass, entity_id=None): +def unlock(hass, entity_id=None): """ Unlocks all or specified locks. """ data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_UNLOCK, data) @@ -73,14 +73,14 @@ def setup(hass, config): """ Handles calls to the lock services. """ target_locks = component.extract_from_service(service) - for lock in target_locks: + for item in target_locks: if service.service == SERVICE_LOCK: - lock.do_lock() + item.lock() else: - lock.do_unlock() + item.unlock() - if lock.should_poll: - lock.update_ha_state(True) + if item.should_poll: + item.update_ha_state(True) descriptions = load_yaml_config_file( os.path.join(os.path.dirname(__file__), 'services.yaml')) @@ -92,7 +92,7 @@ def setup(hass, config): return True -class LockDevice(ToggleEntity): +class LockDevice(Entity): """ Represents a lock within Home Assistant. """ # pylint: disable=no-self-use @@ -102,23 +102,8 @@ class LockDevice(ToggleEntity): return None @property - def device_state_attributes(self): - """ Returns device specific state attributes. """ - return None - - @property - def state_attributes(self): - """ Returns optional state attributes. """ - data = {} - - for prop, attr in PROP_TO_ATTR.items(): - value = getattr(self, prop) - if value: - data[attr] = value - - device_attr = self.device_state_attributes - - if device_attr is not None: - data.update(device_attr) - - return data + def state(self): + is_locked = self.locked + if is_locked is None: + return STATE_UNKNOWN + return STATE_LOCKED if is_locked else STATE_UNLOCKED diff --git a/homeassistant/components/lock/demo.py b/homeassistant/components/lock/demo.py index 76eea0104fb..67e7032849f 100644 --- a/homeassistant/components/lock/demo.py +++ b/homeassistant/components/lock/demo.py @@ -41,16 +41,19 @@ class DemoLock(LockDevice): return self._icon @property - def is_locked(self): + def locked(self): """ True if device is locked. """ - return self._state + if self._state == STATE_LOCKED: + return True + else: + return False - def do_lock(self, **kwargs): + def lock(self, **kwargs): """ Lock the device. """ self._state = STATE_LOCKED self.update_ha_state() - def do_unlock(self, **kwargs): + def unlock(self, **kwargs): """ Unlock the device. """ self._state = STATE_UNLOCKED self.update_ha_state() diff --git a/homeassistant/components/lock/wink.py b/homeassistant/components/lock/wink.py index 059c3a56611..5e463f49a8d 100644 --- a/homeassistant/components/lock/wink.py +++ b/homeassistant/components/lock/wink.py @@ -8,8 +8,8 @@ https://home-assistant.io/components/lock.wink/ """ import logging -from homeassistant.helpers.entity import Entity -from homeassistant.const import CONF_ACCESS_TOKEN, STATE_LOCKED, STATE_UNLOCKED +from homeassistant.components.lock import LockDevice +from homeassistant.const import CONF_ACCESS_TOKEN REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' '9eb39eaba0717922815e673ad1114c685839d890.zip' @@ -34,17 +34,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): add_devices(WinkLockDevice(lock) for lock in pywink.get_locks()) -class WinkLockDevice(Entity): +class WinkLockDevice(LockDevice): """ Represents a Wink lock. """ def __init__(self, wink): self.wink = wink - @property - def state(self): - """ Returns the state. """ - return STATE_LOCKED if self.is_locked else STATE_UNLOCKED - @property def unique_id(self): """ Returns the id of this wink lock """ @@ -60,14 +55,14 @@ class WinkLockDevice(Entity): self.wink.updateState() @property - def is_locked(self): + def locked(self): """ True if device is locked. """ return self.wink.state() - def do_lock(self): + def lock(self): """ Lock the device. """ self.wink.setState(True) - def do_unlock(self): + def unlock(self): """ Unlock the device. """ self.wink.setState(False) From 77a1a1529c4ec978fc248666973f3ee2a93802cb Mon Sep 17 00:00:00 2001 From: Tom Duijf Date: Thu, 19 Nov 2015 22:14:41 +0000 Subject: [PATCH 020/166] Added support for email, removed 'device/' hack to send to all own devices, as own email address does the same --- homeassistant/components/notify/pushbullet.py | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/notify/pushbullet.py b/homeassistant/components/notify/pushbullet.py index 9e9b941394e..16c4e4192eb 100644 --- a/homeassistant/components/notify/pushbullet.py +++ b/homeassistant/components/notify/pushbullet.py @@ -48,20 +48,22 @@ class PushBulletNotificationService(BaseNotificationService): def refresh(self): ''' - Refresh devices, contacts, channels, etc + Refresh devices, contacts, etc pbtargets stores all targets available from this pushbullet instance into a dict. These are PB objects!. It sacrifices a bit of memory for faster processing at send_message + + As of sept 2015, contacts were replaced by chats. This is not + implemented in the module yet ''' self.pushbullet.refresh() self.pbtargets = { - 'device': - {tgt.nickname: tgt for tgt in self.pushbullet.devices}, - 'contact': - {tgt.email: tgt for tgt in self.pushbullet.contacts}, - 'channel': - {tgt.channel_tag: tgt for tgt in self.pushbullet.channels}, + 'device': { + tgt.nickname.lower(): tgt for tgt in self.pushbullet.devices}, + 'channel': { + tgt.channel_tag.lower(): tgt for + tgt in self.pushbullet.channels}, } def send_message(self, message=None, **kwargs): @@ -69,6 +71,8 @@ class PushBulletNotificationService(BaseNotificationService): Send a message to a specified target. If no target specified, a 'normal' push will be sent to all devices linked to the PB account. + Email is special, these are assumed to always exist. We use a special + call which doesn't require a push object """ targets = kwargs.get(ATTR_TARGET) title = kwargs.get(ATTR_TITLE) @@ -86,36 +90,36 @@ class PushBulletNotificationService(BaseNotificationService): # Main loop, Process all targets specified for target in targets: - - # Allow for untargeted push, combined with other types - if target in ['device', 'device/']: - self.pushbullet.push_note(title, message) - _LOGGER.info('Sent notification to self') - continue - try: ttype, tname = target.split('/', 1) except ValueError: _LOGGER.error('Invalid target syntax: %s', target) continue + # Target is email, send directly, don't use a target object + # This also seems works to send to all devices in own account + if ttype == 'email': + self.pushbullet.push_note(title, message, email=tname) + _LOGGER.info('Sent notification to self') + continue + # Refresh if name not found. While awaiting periodic refresh # solution in component, poor mans refresh ;) if ttype not in self.pbtargets: _LOGGER.error('Invalid target syntax: %s', target) continue - if tname not in self.pbtargets[ttype] and not refreshed: + if tname.lower() not in self.pbtargets[ttype] and not refreshed: self.refresh() refreshed = True # Attempt push_note on a dict value. Keys are types & target # name. Dict pbtargets has all *actual* targets. try: - self.pbtargets[ttype][tname].push_note(title, message) + self.pbtargets[ttype][tname.lower()].push_note(title, message) except KeyError: - _LOGGER.error('No such target: %s.%s', ttype, tname) + _LOGGER.error('No such target: %s/%s', ttype, tname) continue except self.pushbullet.errors.PushError: - _LOGGER.error('Notify failed to: %s.%s', ttype, tname) + _LOGGER.error('Notify failed to: %s/%s', ttype, tname) continue - _LOGGER.info('Sent notification to %s.%s', ttype, tname) + _LOGGER.info('Sent notification to %s/%s', ttype, tname) From b9730e6914f4dfece1656bb587492545640e3ead Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 19 Nov 2015 19:00:22 +0100 Subject: [PATCH 021/166] Binary sensor component --- .../components/binary_sensor/__init__.py | 44 +++++++++++++++++ .../components/binary_sensor/demo.py | 49 +++++++++++++++++++ homeassistant/components/demo.py | 2 +- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/binary_sensor/__init__.py create mode 100644 homeassistant/components/binary_sensor/demo.py diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py new file mode 100644 index 00000000000..b02d38a9f81 --- /dev/null +++ b/homeassistant/components/binary_sensor/__init__.py @@ -0,0 +1,44 @@ +""" +homeassistant.components.binary_sensor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Component to interface with binary sensors (sensors which only know two states) +that can be monitored. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/binary_sensor/ +""" +import logging + +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.entity import Entity + +DOMAIN = 'binary_sensor' +DEPENDENCIES = [] +SCAN_INTERVAL = 30 + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + + +def setup(hass, config): + """ Track states and offer events for binary sensors. """ + component = EntityComponent( + logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) + + component.setup(config) + + return True + + +# pylint: disable=no-self-use +class BinarySensorDevice(Entity): + """ Represents a binary sensor.. """ + + @property + def is_on(self): + """ True if the binary sensor is on. """ + return False + + @property + def friendly_state(self): + """ Returns the friendly state of the binary sensor. """ + return None diff --git a/homeassistant/components/binary_sensor/demo.py b/homeassistant/components/binary_sensor/demo.py new file mode 100644 index 00000000000..266b46b7e17 --- /dev/null +++ b/homeassistant/components/binary_sensor/demo.py @@ -0,0 +1,49 @@ +""" +homeassistant.components.binary_sensor.demo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Demo platform that has two fake binary sensors. +""" +from homeassistant.components.binary_sensor import BinarySensorDevice +from homeassistant.const import (STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Demo binary sensors. """ + add_devices([ + DemoBinarySensor('Window Bathroom', True, None), + DemoBinarySensor('Floor Basement', False, None), + ]) + + +class DemoBinarySensor(BinarySensorDevice): + """ A Demo binary sensor. """ + + def __init__(self, name, state, icon=None): + self._name = name or DEVICE_DEFAULT_NAME + self._state = state + self._icon = icon + + @property + def should_poll(self): + """ No polling needed for a demo binary sensor. """ + return False + + @property + def name(self): + """ Returns the name of the binary sensor. """ + return self._name + + @property + def icon(self): + """ Returns the icon to use for device if any. """ + return self._icon + + @property + def is_on(self): + """ True if the sensor is on. """ + return self._state + + @property + def state(self): + """ Returns the state of the binary sensor. """ + return STATE_ON if self.is_on else STATE_OFF diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index c8888a71c1b..547a1d54a03 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone'] COMPONENTS_WITH_DEMO_PLATFORM = [ 'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor', - 'thermostat', 'camera'] + 'thermostat', 'camera', 'binary_sensor'] def setup(hass, config): From a6006b1835d53292c48050f32ec61118369ece86 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 20 Nov 2015 14:58:49 +0100 Subject: [PATCH 022/166] Move state --- homeassistant/components/binary_sensor/__init__.py | 10 ++++++++-- homeassistant/components/binary_sensor/demo.py | 10 ++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py index b02d38a9f81..2ef9e83cc30 100644 --- a/homeassistant/components/binary_sensor/__init__.py +++ b/homeassistant/components/binary_sensor/__init__.py @@ -11,6 +11,7 @@ import logging from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import Entity +from homeassistant.const import (STATE_ON, STATE_OFF) DOMAIN = 'binary_sensor' DEPENDENCIES = [] @@ -31,12 +32,17 @@ def setup(hass, config): # pylint: disable=no-self-use class BinarySensorDevice(Entity): - """ Represents a binary sensor.. """ + """ Represents a binary sensor. """ @property def is_on(self): """ True if the binary sensor is on. """ - return False + return None + + @property + def state(self): + """ Returns the state of the binary sensor. """ + return STATE_ON if self.is_on else STATE_OFF @property def friendly_state(self): diff --git a/homeassistant/components/binary_sensor/demo.py b/homeassistant/components/binary_sensor/demo.py index 266b46b7e17..a24b893c610 100644 --- a/homeassistant/components/binary_sensor/demo.py +++ b/homeassistant/components/binary_sensor/demo.py @@ -4,7 +4,6 @@ homeassistant.components.binary_sensor.demo Demo platform that has two fake binary sensors. """ from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.const import (STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME) def setup_platform(hass, config, add_devices, discovery_info=None): @@ -19,7 +18,7 @@ class DemoBinarySensor(BinarySensorDevice): """ A Demo binary sensor. """ def __init__(self, name, state, icon=None): - self._name = name or DEVICE_DEFAULT_NAME + self._name = name self._state = state self._icon = icon @@ -40,10 +39,5 @@ class DemoBinarySensor(BinarySensorDevice): @property def is_on(self): - """ True if the sensor is on. """ + """ True if the binary sensor is on. """ return self._state - - @property - def state(self): - """ Returns the state of the binary sensor. """ - return STATE_ON if self.is_on else STATE_OFF From d254e7e9e50271442f5c680cc5ff1b957ac96639 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 20 Nov 2015 15:29:36 +0100 Subject: [PATCH 023/166] Fix pylint issue --- homeassistant/components/binary_sensor/demo.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/binary_sensor/demo.py b/homeassistant/components/binary_sensor/demo.py index 22eeaa7b8a5..a24b893c610 100644 --- a/homeassistant/components/binary_sensor/demo.py +++ b/homeassistant/components/binary_sensor/demo.py @@ -41,4 +41,3 @@ class DemoBinarySensor(BinarySensorDevice): def is_on(self): """ True if the binary sensor is on. """ return self._state - From 3df6c584c0c8458ce7c92634f2f8c2399cbb59d2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 20 Nov 2015 08:38:56 -0800 Subject: [PATCH 024/166] Update frontend --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 62 +++++++++---------- .../www_static/home-assistant-polymer | 2 +- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 1435fe16c5c..0199b05156e 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 = "b75e3c9ebd3de2dae0912a89499127a9" +VERSION = "dff74f773ea8b0356b0bd8130ed6f0cf" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 5157f4dd5a6..b2a2eb97b3e 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -839,7 +839,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --google-grey-300: #e0e0e0; --google-grey-500: #9e9e9e; --google-grey-700: #616161; - + /* Material Design color palette from online spec document */ --paper-red-50: #ffebee; @@ -856,7 +856,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-red-a200: #ff5252; --paper-red-a400: #ff1744; --paper-red-a700: #d50000; - + --paper-pink-50: #fce4ec; --paper-pink-100: #f8bbd0; --paper-pink-200: #f48fb1; @@ -871,7 +871,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-pink-a200: #ff4081; --paper-pink-a400: #f50057; --paper-pink-a700: #c51162; - + --paper-purple-50: #f3e5f5; --paper-purple-100: #e1bee7; --paper-purple-200: #ce93d8; @@ -886,7 +886,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-purple-a200: #e040fb; --paper-purple-a400: #d500f9; --paper-purple-a700: #aa00ff; - + --paper-deep-purple-50: #ede7f6; --paper-deep-purple-100: #d1c4e9; --paper-deep-purple-200: #b39ddb; @@ -901,7 +901,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-deep-purple-a200: #7c4dff; --paper-deep-purple-a400: #651fff; --paper-deep-purple-a700: #6200ea; - + --paper-indigo-50: #e8eaf6; --paper-indigo-100: #c5cae9; --paper-indigo-200: #9fa8da; @@ -916,7 +916,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-indigo-a200: #536dfe; --paper-indigo-a400: #3d5afe; --paper-indigo-a700: #304ffe; - + --paper-blue-50: #e3f2fd; --paper-blue-100: #bbdefb; --paper-blue-200: #90caf9; @@ -931,7 +931,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-blue-a200: #448aff; --paper-blue-a400: #2979ff; --paper-blue-a700: #2962ff; - + --paper-light-blue-50: #e1f5fe; --paper-light-blue-100: #b3e5fc; --paper-light-blue-200: #81d4fa; @@ -946,7 +946,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-light-blue-a200: #40c4ff; --paper-light-blue-a400: #00b0ff; --paper-light-blue-a700: #0091ea; - + --paper-cyan-50: #e0f7fa; --paper-cyan-100: #b2ebf2; --paper-cyan-200: #80deea; @@ -961,7 +961,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-cyan-a200: #18ffff; --paper-cyan-a400: #00e5ff; --paper-cyan-a700: #00b8d4; - + --paper-teal-50: #e0f2f1; --paper-teal-100: #b2dfdb; --paper-teal-200: #80cbc4; @@ -976,7 +976,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-teal-a200: #64ffda; --paper-teal-a400: #1de9b6; --paper-teal-a700: #00bfa5; - + --paper-green-50: #e8f5e9; --paper-green-100: #c8e6c9; --paper-green-200: #a5d6a7; @@ -991,7 +991,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-green-a200: #69f0ae; --paper-green-a400: #00e676; --paper-green-a700: #00c853; - + --paper-light-green-50: #f1f8e9; --paper-light-green-100: #dcedc8; --paper-light-green-200: #c5e1a5; @@ -1006,7 +1006,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-light-green-a200: #b2ff59; --paper-light-green-a400: #76ff03; --paper-light-green-a700: #64dd17; - + --paper-lime-50: #f9fbe7; --paper-lime-100: #f0f4c3; --paper-lime-200: #e6ee9c; @@ -1021,7 +1021,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-lime-a200: #eeff41; --paper-lime-a400: #c6ff00; --paper-lime-a700: #aeea00; - + --paper-yellow-50: #fffde7; --paper-yellow-100: #fff9c4; --paper-yellow-200: #fff59d; @@ -1036,7 +1036,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-yellow-a200: #ffff00; --paper-yellow-a400: #ffea00; --paper-yellow-a700: #ffd600; - + --paper-amber-50: #fff8e1; --paper-amber-100: #ffecb3; --paper-amber-200: #ffe082; @@ -1051,7 +1051,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-amber-a200: #ffd740; --paper-amber-a400: #ffc400; --paper-amber-a700: #ffab00; - + --paper-orange-50: #fff3e0; --paper-orange-100: #ffe0b2; --paper-orange-200: #ffcc80; @@ -1066,7 +1066,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-orange-a200: #ffab40; --paper-orange-a400: #ff9100; --paper-orange-a700: #ff6500; - + --paper-deep-orange-50: #fbe9e7; --paper-deep-orange-100: #ffccbc; --paper-deep-orange-200: #ffab91; @@ -1081,7 +1081,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-deep-orange-a200: #ff6e40; --paper-deep-orange-a400: #ff3d00; --paper-deep-orange-a700: #dd2c00; - + --paper-brown-50: #efebe9; --paper-brown-100: #d7ccc8; --paper-brown-200: #bcaaa4; @@ -1092,7 +1092,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-brown-700: #5d4037; --paper-brown-800: #4e342e; --paper-brown-900: #3e2723; - + --paper-grey-50: #fafafa; --paper-grey-100: #f5f5f5; --paper-grey-200: #eeeeee; @@ -1103,7 +1103,7 @@ var a=i[o];r&&"#"==a[0]?s=Polymer.Collection.get(r).getItem(a):(s=s[a],n&&r&&par --paper-grey-700: #616161; --paper-grey-800: #424242; --paper-grey-900: #212121; - + --paper-blue-grey-50: #eceff1; --paper-blue-grey-100: #cfd8dc; --paper-blue-grey-200: #b0bec5; @@ -2176,7 +2176,7 @@ case"touchend":return this.addPointerListenerEnd(t,e,i,n);case"touchmove":return } + } \ 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 99af263595d..39e09d85b74 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 99af263595dbbf057d26bb266101fa1e386442c6 +Subproject commit 39e09d85b74afb332ad2872b5aa556c9c9d113c3 From b4cf0e874afeca102780b0936faefd290b72585d Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Fri, 20 Nov 2015 22:03:17 +0100 Subject: [PATCH 025/166] Support parsing mqtt messages via jsonpath --- homeassistant/components/mqtt/__init__.py | 11 +++++++++++ homeassistant/components/sensor/mqtt.py | 15 ++++++++++++--- homeassistant/components/switch/mqtt.py | 13 +++++++++++-- requirements_all.txt | 1 + 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index cd5b5370175..24a19494d41 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -9,6 +9,8 @@ https://home-assistant.io/components/mqtt/ import logging import os import socket +import json +import jsonpath_rw from homeassistant.exceptions import HomeAssistantError import homeassistant.util as util @@ -127,6 +129,15 @@ def setup(hass, config): return True +class JsonFmtParser(object): + """ Implements a json parser on xpath""" + def __init__(self, jsonpath): + self._expr = jsonpath_rw.parse(jsonpath) + def __call__(self, payload): + match = self._expr.find(json.loads(payload)) + return match[0].value if len(match) > 0 else None + + # This is based on one of the paho-mqtt examples: # http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/tree/examples/sub-class.py # pylint: disable=too-many-arguments diff --git a/homeassistant/components/sensor/mqtt.py b/homeassistant/components/sensor/mqtt.py index 2623d2fdcce..f2608bd1657 100644 --- a/homeassistant/components/sensor/mqtt.py +++ b/homeassistant/components/sensor/mqtt.py @@ -7,6 +7,8 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.mqtt/ """ import logging +import json +import jsonpath_rw from homeassistant.helpers.entity import Entity import homeassistant.components.mqtt as mqtt @@ -31,23 +33,30 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): config.get('name', DEFAULT_NAME), config.get('state_topic'), config.get('qos', DEFAULT_QOS), - config.get('unit_of_measurement'))]) + config.get('unit_of_measurement'), + config.get('state_format'))]) # pylint: disable=too-many-arguments, too-many-instance-attributes class MqttSensor(Entity): """ Represents a sensor that can be updated using MQTT. """ - def __init__(self, hass, name, state_topic, qos, unit_of_measurement): + def __init__(self, hass, name, state_topic, qos, unit_of_measurement,state_format): self._state = "-" self._hass = hass self._name = name self._state_topic = state_topic self._qos = qos self._unit_of_measurement = unit_of_measurement + self._state_format = state_format + + if self._state_format.startswith('json:'): + self._parser = mqtt.JsonFmtParser(self._state_format[5:]) + else: + self._parser = lambda x: x def message_received(topic, payload, qos): """ A new MQTT message has been received. """ - self._state = payload + self._state = self._parser(payload) self.update_ha_state() mqtt.subscribe(hass, self._state_topic, message_received, self._qos) diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index 12d3f486323..a94ebe6b6b1 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -37,14 +37,15 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): config.get('qos', DEFAULT_QOS), config.get('payload_on', DEFAULT_PAYLOAD_ON), config.get('payload_off', DEFAULT_PAYLOAD_OFF), - config.get('optimistic', DEFAULT_OPTIMISTIC))]) + config.get('optimistic', DEFAULT_OPTIMISTIC), + config.get('state_format'))]) # pylint: disable=too-many-arguments, too-many-instance-attributes class MqttSwitch(SwitchDevice): """ Represents a switch that can be togggled using MQTT. """ def __init__(self, hass, name, state_topic, command_topic, qos, - payload_on, payload_off, optimistic): + payload_on, payload_off, optimistic, state_format): self._state = False self._hass = hass self._name = name @@ -54,9 +55,17 @@ class MqttSwitch(SwitchDevice): self._payload_on = payload_on self._payload_off = payload_off self._optimistic = optimistic + + self._state_format = state_format + + if self._state_format.startswith('json:'): + self._parser = mqtt.JsonFmtParser(self._state_format[5:]) + else: + self._parser = lambda x: x def message_received(topic, payload, qos): """ A new MQTT message has been received. """ + payload = self._parser(payload) if payload == self._payload_on: self._state = True self.update_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index c6b4ae81721..7e15e594313 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -74,6 +74,7 @@ https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b6 # homeassistant.components.mqtt paho-mqtt==1.1 +jsonpath-rw==1.4.0 # homeassistant.components.notify.pushbullet pushbullet.py==0.9.0 From 105dc2847e9c57429afd8b79304f9a7c046b0570 Mon Sep 17 00:00:00 2001 From: miniconfig Date: Fri, 20 Nov 2015 16:34:27 -0500 Subject: [PATCH 026/166] Changed locked method of lock support to "is_locked". Added lock and unlock methods Updated wink components to use the new version of the wink library. --- homeassistant/components/light/wink.py | 4 ++-- homeassistant/components/lock/__init__.py | 18 +++++++++++++----- homeassistant/components/lock/demo.py | 2 +- homeassistant/components/lock/wink.py | 6 +++--- homeassistant/components/sensor/wink.py | 4 ++-- homeassistant/components/switch/wink.py | 4 ++-- homeassistant/components/wink.py | 4 ++-- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py index 4fbf87aea2d..eaa703799f7 100644 --- a/homeassistant/components/light/wink.py +++ b/homeassistant/components/light/wink.py @@ -13,8 +13,8 @@ from homeassistant.components.wink import WinkToggleDevice from homeassistant.const import CONF_ACCESS_TOKEN REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' - '9eb39eaba0717922815e673ad1114c685839d890.zip' - '#python-wink==0.1.1'] + '42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip' + '#python-wink==0.2'] def setup_platform(hass, config, add_devices_callback, discovery_info=None): diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index 613410dfd07..2cbd3a40872 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -44,7 +44,7 @@ PROP_TO_ATTR = { _LOGGER = logging.getLogger(__name__) -def locked(hass, entity_id=None): +def is_locked(hass, entity_id=None): """ Returns if the lock is locked based on the statemachine. """ entity_id = entity_id or ENTITY_ID_ALL_LOCKS return hass.states.is_state(entity_id, STATE_LOCKED) @@ -97,13 +97,21 @@ class LockDevice(Entity): # pylint: disable=no-self-use @property - def locked(self): + def is_locked(self): """ Is the lock locked or unlocked. """ return None + def lock(self): + """ Locks the lock. """ + raise NotImplementedError() + + def unlock(self): + """ Unlocks the lock. """ + raise NotImplementedError() + @property def state(self): - is_locked = self.locked - if is_locked is None: + locked = self.is_locked + if locked is None: return STATE_UNKNOWN - return STATE_LOCKED if is_locked else STATE_UNLOCKED + return STATE_LOCKED if locked else STATE_UNLOCKED diff --git a/homeassistant/components/lock/demo.py b/homeassistant/components/lock/demo.py index 67e7032849f..ac7bbed3dc2 100644 --- a/homeassistant/components/lock/demo.py +++ b/homeassistant/components/lock/demo.py @@ -41,7 +41,7 @@ class DemoLock(LockDevice): return self._icon @property - def locked(self): + def is_locked(self): """ True if device is locked. """ if self._state == STATE_LOCKED: return True diff --git a/homeassistant/components/lock/wink.py b/homeassistant/components/lock/wink.py index 5e463f49a8d..27f602d65fa 100644 --- a/homeassistant/components/lock/wink.py +++ b/homeassistant/components/lock/wink.py @@ -12,8 +12,8 @@ from homeassistant.components.lock import LockDevice from homeassistant.const import CONF_ACCESS_TOKEN REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' - '9eb39eaba0717922815e673ad1114c685839d890.zip' - '#python-wink==0.1.1'] + '42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip' + '#python-wink==0.2'] def setup_platform(hass, config, add_devices, discovery_info=None): @@ -55,7 +55,7 @@ class WinkLockDevice(LockDevice): self.wink.updateState() @property - def locked(self): + def is_locked(self): """ True if device is locked. """ return self.wink.state() diff --git a/homeassistant/components/sensor/wink.py b/homeassistant/components/sensor/wink.py index 8bfdb9205fa..26fe6538e05 100644 --- a/homeassistant/components/sensor/wink.py +++ b/homeassistant/components/sensor/wink.py @@ -12,8 +12,8 @@ from homeassistant.helpers.entity import Entity from homeassistant.const import CONF_ACCESS_TOKEN, STATE_OPEN, STATE_CLOSED REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' - '9eb39eaba0717922815e673ad1114c685839d890.zip' - '#python-wink==0.1.1'] + '42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip' + '#python-wink==0.2'] def setup_platform(hass, config, add_devices, discovery_info=None): diff --git a/homeassistant/components/switch/wink.py b/homeassistant/components/switch/wink.py index b022d8cbf72..f0dc18003c6 100644 --- a/homeassistant/components/switch/wink.py +++ b/homeassistant/components/switch/wink.py @@ -12,8 +12,8 @@ from homeassistant.components.wink import WinkToggleDevice from homeassistant.const import CONF_ACCESS_TOKEN REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' - '9eb39eaba0717922815e673ad1114c685839d890.zip' - '#python-wink==0.1.1'] + '42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip' + '#python-wink==0.2'] def setup_platform(hass, config, add_devices, discovery_info=None): diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 66ea29ff4dd..bd79210bf75 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -19,8 +19,8 @@ from homeassistant.const import ( DOMAIN = "wink" DEPENDENCIES = [] REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' - '9eb39eaba0717922815e673ad1114c685839d890.zip' - '#python-wink==0.1.1'] + '42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip' + '#python-wink==0.2'] DISCOVER_LIGHTS = "wink.lights" DISCOVER_SWITCHES = "wink.switches" From 799043dc0a2031318b235d4a78f0c6d1178e7dca Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Fri, 20 Nov 2015 22:45:09 +0100 Subject: [PATCH 027/166] refactor format mqtt format parser --- homeassistant/components/mqtt/__init__.py | 23 +++++++++++++++++------ homeassistant/components/sensor/mqtt.py | 7 +------ homeassistant/components/switch/mqtt.py | 8 +------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 24a19494d41..b2884a0ff34 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -129,13 +129,24 @@ def setup(hass, config): return True -class JsonFmtParser(object): - """ Implements a json parser on xpath""" - def __init__(self, jsonpath): - self._expr = jsonpath_rw.parse(jsonpath) +class FmtParser(object): + """ wrapper for all supported formats """ + + class _JsonFmtParser(object): + """ Implements a json parser on xpath""" + def __init__(self, jsonpath): + self._expr = jsonpath_rw.parse(jsonpath) + def __call__(self, payload): + match = self._expr.find(json.loads(payload)) + return match[0].value if len(match) > 0 else None + + def __init__(self, fmt): + if fmt.startswith('json:'): + self._parser = FmtParser._JsonFmtParser(fmt[5:]) + else: + self._parser = lambda x: x def __call__(self, payload): - match = self._expr.find(json.loads(payload)) - return match[0].value if len(match) > 0 else None + return self._parser(payload) # This is based on one of the paho-mqtt examples: diff --git a/homeassistant/components/sensor/mqtt.py b/homeassistant/components/sensor/mqtt.py index f2608bd1657..64a8852d06e 100644 --- a/homeassistant/components/sensor/mqtt.py +++ b/homeassistant/components/sensor/mqtt.py @@ -47,12 +47,7 @@ class MqttSensor(Entity): self._state_topic = state_topic self._qos = qos self._unit_of_measurement = unit_of_measurement - self._state_format = state_format - - if self._state_format.startswith('json:'): - self._parser = mqtt.JsonFmtParser(self._state_format[5:]) - else: - self._parser = lambda x: x + self._parser = mqtt.FmtParser(state_format) def message_received(topic, payload, qos): """ A new MQTT message has been received. """ diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index a94ebe6b6b1..eeb4551b921 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -55,13 +55,7 @@ class MqttSwitch(SwitchDevice): self._payload_on = payload_on self._payload_off = payload_off self._optimistic = optimistic - - self._state_format = state_format - - if self._state_format.startswith('json:'): - self._parser = mqtt.JsonFmtParser(self._state_format[5:]) - else: - self._parser = lambda x: x + self._parser = mqtt.FmtParser(state_format) def message_received(topic, payload, qos): """ A new MQTT message has been received. """ From 030686a978225255d386fe3b9b6925744514f2f6 Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Fri, 20 Nov 2015 22:55:52 +0100 Subject: [PATCH 028/166] fix flak8 warnings --- homeassistant/components/mqtt/__init__.py | 32 ++++++++++++----------- homeassistant/components/sensor/mqtt.py | 5 ++-- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index b2884a0ff34..b5b8ca9cca7 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -129,24 +129,26 @@ def setup(hass, config): return True -class FmtParser(object): - """ wrapper for all supported formats """ - - class _JsonFmtParser(object): +class _JsonFmtParser(object): """ Implements a json parser on xpath""" def __init__(self, jsonpath): - self._expr = jsonpath_rw.parse(jsonpath) + self._expr = jsonpath_rw.parse(jsonpath) + def __call__(self, payload): - match = self._expr.find(json.loads(payload)) - return match[0].value if len(match) > 0 else None - - def __init__(self, fmt): - if fmt.startswith('json:'): - self._parser = FmtParser._JsonFmtParser(fmt[5:]) - else: - self._parser = lambda x: x - def __call__(self, payload): - return self._parser(payload) + match = self._expr.find(json.loads(payload)) + return match[0].value if len(match) > 0 else payload + + +class FmtParser(object): + """ wrapper for all supported formats """ + def __init__(self, fmt): + if fmt.startswith('json:'): + self._parser = _JsonFmtParser(fmt[5:]) + else: + self._parser = lambda x: x + + def __call__(self, payload): + return self._parser(payload) # This is based on one of the paho-mqtt examples: diff --git a/homeassistant/components/sensor/mqtt.py b/homeassistant/components/sensor/mqtt.py index 64a8852d06e..384d0f8a48a 100644 --- a/homeassistant/components/sensor/mqtt.py +++ b/homeassistant/components/sensor/mqtt.py @@ -7,8 +7,6 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.mqtt/ """ import logging -import json -import jsonpath_rw from homeassistant.helpers.entity import Entity import homeassistant.components.mqtt as mqtt @@ -40,7 +38,8 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): # pylint: disable=too-many-arguments, too-many-instance-attributes class MqttSensor(Entity): """ Represents a sensor that can be updated using MQTT. """ - def __init__(self, hass, name, state_topic, qos, unit_of_measurement,state_format): + def __init__(self, hass, name, state_topic, qos, unit_of_measurement, + state_format): self._state = "-" self._hass = hass self._name = name From 065f4b7c20d7cf1da468c4227337be94b8527e40 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 20 Nov 2015 23:39:39 +0100 Subject: [PATCH 029/166] Add binary sensor for aREST --- .../components/binary_sensor/arest.py | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 homeassistant/components/binary_sensor/arest.py diff --git a/homeassistant/components/binary_sensor/arest.py b/homeassistant/components/binary_sensor/arest.py new file mode 100644 index 00000000000..3077fe40bdb --- /dev/null +++ b/homeassistant/components/binary_sensor/arest.py @@ -0,0 +1,106 @@ +""" +homeassistant.components.binary_sensor.arest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The arest sensor will consume an exposed aREST API of a device. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.arest/ +""" +import logging +import requests +from datetime import timedelta + +from homeassistant.util import Throttle +from homeassistant.components.binary_sensor import BinarySensorDevice + +_LOGGER = logging.getLogger(__name__) + +# Return cached results if last scan was less then this time ago +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30) + +CONF_RESOURCE = 'resource' +CONF_PIN = 'pin' + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Get the aREST binary sensor. """ + + resource = config.get(CONF_RESOURCE) + pin = config.get(CONF_PIN) + + if None in (resource, pin): + _LOGGER.error('Not all required config keys present: %s', + ', '.join((CONF_RESOURCE, CONF_PIN))) + return False + + try: + response = requests.get(resource, timeout=10).json() + except requests.exceptions.MissingSchema: + _LOGGER.error('Missing resource or schema in configuration. ' + 'Add http:// to your URL.') + return False + except requests.exceptions.ConnectionError: + _LOGGER.error('No route to device at %s. ' + 'Please check the IP address in the configuration file.', + resource) + return False + + arest = ArestData(resource, pin) + + add_devices([ArestBinarySensor(arest, + resource, + config.get('name', response['name']), + pin)]) + + +# pylint: disable=too-many-instance-attributes, too-many-arguments +class ArestBinarySensor(BinarySensorDevice): + """ Implements an aREST binary sensor for a pin. """ + + def __init__(self, arest, resource, name, pin): + self.arest = arest + self._resource = resource + self._name = name + self._pin = pin + self.update() + + if self._pin is not None: + request = requests.get('{}/mode/{}/i'.format + (self._resource, self._pin), timeout=10) + if request.status_code is not 200: + _LOGGER.error("Can't set mode. Is device offline?") + + @property + def name(self): + """ The name of the binary sensor. """ + return self._name + + @property + def is_on(self): + """ True if the binary sensor is on. """ + return bool(self.arest.data.get('state')) + + def update(self): + """ Gets the latest data from aREST API. """ + self.arest.update() + + +# pylint: disable=too-few-public-methods +class ArestData(object): + """ Class for handling the data retrieval for pins. """ + + def __init__(self, resource, pin): + self._resource = resource + self._pin = pin + self.data = {} + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """ Gets the latest data from aREST device. """ + try: + response = requests.get('{}/digital/{}'.format( + self._resource, self._pin), timeout=10) + self.data = {'state': response.json()['return_value']} + except requests.exceptions.ConnectionError: + _LOGGER.error("No route to device '%s'. Is device offline?", + self._resource) From 44714614ada3b5974c706235811c53f7709ff162 Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Fri, 20 Nov 2015 23:42:22 +0100 Subject: [PATCH 030/166] Fix unit tests for mqtt --- homeassistant/components/mqtt/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index b5b8ca9cca7..5b92da90d0a 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -142,10 +142,10 @@ class _JsonFmtParser(object): class FmtParser(object): """ wrapper for all supported formats """ def __init__(self, fmt): - if fmt.startswith('json:'): - self._parser = _JsonFmtParser(fmt[5:]) - else: - self._parser = lambda x: x + self._parser = lambda x: x + if fmt: + if fmt.startswith('json:'): + self._parser = _JsonFmtParser(fmt[5:]) def __call__(self, payload): return self._parser(payload) From 08d29d3630f498932a00fde2187a1cfe40c3a6d0 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 20 Nov 2015 23:43:59 +0100 Subject: [PATCH 031/166] Add MQTT binary sensor --- .../components/binary_sensor/mqtt.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 homeassistant/components/binary_sensor/mqtt.py diff --git a/homeassistant/components/binary_sensor/mqtt.py b/homeassistant/components/binary_sensor/mqtt.py new file mode 100644 index 00000000000..cac991d4eb2 --- /dev/null +++ b/homeassistant/components/binary_sensor/mqtt.py @@ -0,0 +1,76 @@ +""" +homeassistant.components.binary_sensor.mqtt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Allows to configure a MQTT binary sensor. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.mqtt/ +""" +import logging +from homeassistant.components.binary_sensor import BinarySensorDevice +import homeassistant.components.mqtt as mqtt + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'MQTT Binary sensor' +DEFAULT_QOS = 0 +DEFAULT_PAYLOAD_ON = 'ON' +DEFAULT_PAYLOAD_OFF = 'OFF' + +DEPENDENCIES = ['mqtt'] + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Add MQTT binary sensor. """ + + if config.get('state_topic') is None: + _LOGGER.error('Missing required variable: state_topic') + return False + + add_devices([MqttBinarySensor( + hass, + config.get('name', DEFAULT_NAME), + config.get('state_topic', None), + config.get('qos', DEFAULT_QOS), + config.get('payload_on', DEFAULT_PAYLOAD_ON), + config.get('payload_off', DEFAULT_PAYLOAD_OFF))]) + + +# pylint: disable=too-many-arguments, too-many-instance-attributes +class MqttBinarySensor(BinarySensorDevice): + """ Represents a binary sensor that is updated by MQTT. """ + def __init__(self, hass, name, state_topic, qos, payload_on, payload_off): + self._hass = hass + self._name = name + self._state = False + self._state_topic = state_topic + self._payload_on = payload_on + self._payload_off = payload_off + self._qos = qos + + def message_received(topic, payload, qos): + """ A new MQTT message has been received. """ + if payload == self._payload_on: + self._state = True + self.update_ha_state() + elif payload == self._payload_off: + self._state = False + self.update_ha_state() + + mqtt.subscribe(hass, self._state_topic, message_received, self._qos) + + @property + def should_poll(self): + """ No polling needed. """ + return False + + @property + def name(self): + """ The name of the binary sensor. """ + return self._name + + @property + def is_on(self): + """ True if the binary sensor is on. """ + return self._state From 820b2a31b3745e2dbd162565915fba2ce23592b3 Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Fri, 20 Nov 2015 23:44:46 +0100 Subject: [PATCH 032/166] Add additional unit tests for mqtt state format parsing --- tests/components/sensor/test_mqtt.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/components/sensor/test_mqtt.py b/tests/components/sensor/test_mqtt.py index b59ea867c58..8d1aef4d57f 100644 --- a/tests/components/sensor/test_mqtt.py +++ b/tests/components/sensor/test_mqtt.py @@ -39,3 +39,22 @@ class TestSensorMQTT(unittest.TestCase): self.assertEqual('100', state.state) self.assertEqual('fav unit', state.attributes.get('unit_of_measurement')) + + def test_setting_sensor_value_via_mqtt_json_message(self): + self.assertTrue(sensor.setup(self.hass, { + 'sensor': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'test-topic', + 'unit_of_measurement': 'fav unit', + 'state_format': 'json:val' + } + })) + + fire_mqtt_message(self.hass, 'test-topic', '{ "val": "100" }') + self.hass.pool.block_till_done() + state = self.hass.states.get('sensor.test') + + self.assertEqual('100', state.state) + self.assertEqual('fav unit', + state.attributes.get('unit_of_measurement')) From 44abc31057c174968939beb940d48e55b326895c Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Fri, 20 Nov 2015 17:47:25 -0500 Subject: [PATCH 033/166] work in progress: configurator is now in it's own component. configurator seems to work but the thermostat is now broken. --- .coveragerc | 2 + homeassistant/components/ecobee.py | 127 ++++++++++++++++++ homeassistant/components/thermostat/ecobee.py | 72 ++-------- requirements_all.txt | 2 +- 4 files changed, 142 insertions(+), 61 deletions(-) create mode 100644 homeassistant/components/ecobee.py diff --git a/.coveragerc b/.coveragerc index 9fafe443dcf..b8016fa7624 100644 --- a/.coveragerc +++ b/.coveragerc @@ -16,6 +16,8 @@ omit = homeassistant/components/*/tellstick.py homeassistant/components/*/vera.py + + homeassistant/components/ecobee.py homeassistant/components/*/ecobee.py homeassistant/components/verisure.py diff --git a/homeassistant/components/ecobee.py b/homeassistant/components/ecobee.py new file mode 100644 index 00000000000..99db73b6a90 --- /dev/null +++ b/homeassistant/components/ecobee.py @@ -0,0 +1,127 @@ +""" +homeassistant.components.zwave +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Connects Home Assistant to the Ecobee API and maintains tokens. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/ecobee/ + +[ecobee] +api_key: asdflaksf +""" + +from homeassistant.loader import get_component +from homeassistant import bootstrap +from homeassistant.const import ( + EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, + EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, CONF_API_KEY) +from datetime import timedelta +import logging +import os + +DOMAIN = "ecobee" +DISCOVER_THERMOSTAT = "ecobee.thermostat" +DEPENDENCIES = [] +NETWORK = None + +REQUIREMENTS = [ + 'https://github.com/nkgilley/python-ecobee-api/archive/' + 'd35596b67c75451fa47001c493a15eebee195e93.zip#python-ecobee==0.0.1'] + +_LOGGER = logging.getLogger(__name__) + +ECOBEE_CONFIG_FILE = 'ecobee.conf' +_CONFIGURING = {} + +# Return cached results if last scan was less then this time ago +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180) + + +def request_configuration(network, hass): + """ Request configuration steps from the user. """ + configurator = get_component('configurator') + if 'ecobee' in _CONFIGURING: + configurator.notify_errors( + _CONFIGURING['ecobee'], "Failed to register, please try again.") + + return + + # pylint: disable=unused-argument + def ecobee_configuration_callback(callback_data): + """ Actions to do when our configuration callback is called. """ + network.request_tokens() + network.update() + setup_ecobee(hass, network) + + _CONFIGURING['ecobee'] = configurator.request_config( + hass, "Ecobee", ecobee_configuration_callback, + description=( + 'Please authorize this app at https://www.ecobee.com/consumer' + 'portal/index.html with pin code: ' + NETWORK.pin), + description_image="/static/images/config_ecobee_thermostat.png", + submit_caption="I have authorized the app." + ) + + +def setup_ecobee(hass, network): + """ Setup ecobee thermostat """ + # If ecobee has a PIN then it needs to be configured. + if network.pin is not None: + request_configuration(network, hass) + return + + if 'ecobee' in _CONFIGURING: + configurator = get_component('configurator') + configurator.request_done(_CONFIGURING.pop('ecobee')) + + +def setup(hass, config): + """ + Setup Ecobee. + Will automatically load thermostat and sensor components to support + devices discovered on the network. + """ + # pylint: disable=global-statement, import-error + global NETWORK + + if 'ecobee' in _CONFIGURING: + return + + from pyecobee import Ecobee, config_from_file + + # Create ecobee.conf if it doesn't exist + if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)): + if config[DOMAIN].get(CONF_API_KEY) is None: + _LOGGER.error("No ecobee api_key found in config.") + return + jsonconfig = {"API_KEY": config[DOMAIN].get(CONF_API_KEY)} + config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig) + + NETWORK = Ecobee(hass.config.path(ECOBEE_CONFIG_FILE)) + + setup_ecobee(hass, NETWORK) + + # Ensure component is loaded + bootstrap.setup_component(hass, 'thermostat', config) + + # Fire discovery event + hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { + ATTR_SERVICE: DISCOVER_THERMOSTAT, + ATTR_DISCOVERED: { + 'network': NETWORK, + } + }) + + def stop_ecobee(event): + """ Stop Ecobee. """ + + pass + + def start_ecobee(event): + """ Called when Home Assistant starts up. """ + + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_ecobee) + + hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_ecobee) + + return True diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 7258a3b65a1..5b377be4907 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -1,4 +1,3 @@ -#!/usr/local/bin/python3 """ homeassistant.components.thermostat.ecobee ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -24,19 +23,14 @@ thermostat: platform: ecobee api_key: asdfasdfasdfasdfasdfaasdfasdfasdfasdf """ -from homeassistant.loader import get_component from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) -from homeassistant.const import ( - CONF_API_KEY, TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) +from homeassistant.const import (TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) from homeassistant.util import Throttle from datetime import timedelta import logging -import os -REQUIREMENTS = [ - 'https://github.com/nkgilley/python-ecobee-api/archive/' - '790c20d820dbb727af2dbfb3ef0f79231e19a503.zip#python-ecobee==0.0.1'] +DEPENDENCIES = ['ecobee'] _LOGGER = logging.getLogger(__name__) @@ -47,70 +41,28 @@ _CONFIGURING = {} MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_devices, discovery_info=None): """ Setup Platform """ - # Only act if we are not already configuring this host - if 'ecobee' in _CONFIGURING: + _LOGGER.error("ecobee !!!!") + if discovery_info is None: return - - from pyecobee import config_from_file - - # Create ecobee.conf if it doesn't exist - if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)): - jsonconfig = {"API_KEY": config[CONF_API_KEY]} - config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig) - data = EcobeeData(hass.config.path(ECOBEE_CONFIG_FILE)) - setup_ecobee(hass, data, config, add_devices_callback) + data = EcobeeData(discovery_info[0]) + setup_ecobee(hass, data, add_devices) -def setup_ecobee(hass, data, config, add_devices_callback): +def setup_ecobee(hass, data, add_devices): """ Setup ecobee thermostat """ - # If ecobee has a PIN then it needs to be configured. - if data.ecobee.pin is not None: - request_configuration(data, hass, add_devices_callback) - return - if 'ecobee' in _CONFIGURING: - configurator = get_component('configurator') - configurator.request_done(_CONFIGURING.pop('ecobee')) - - add_devices_callback(Thermostat(data, index) - for index in range(len(data.ecobee.thermostats))) - - -def request_configuration(data, hass, add_devices_callback): - """ Request configuration steps from the user. """ - configurator = get_component('configurator') - if 'ecobee' in _CONFIGURING: - configurator.notify_errors( - _CONFIGURING['ecobee'], "Failed to register, please try again.") - - return - - # pylint: disable=unused-argument - def ecobee_configuration_callback(callback_data): - """ Actions to do when our configuration callback is called. """ - data.ecobee.request_tokens() - data.ecobee.update() - setup_ecobee(hass, data, None, add_devices_callback) - - _CONFIGURING['ecobee'] = configurator.request_config( - hass, "Ecobee", ecobee_configuration_callback, - description=( - 'Please authorize this app at https://www.ecobee.com/consumer' - 'portal/index.html with pin code: ' + data.ecobee.pin), - description_image="/static/images/config_ecobee_thermostat.png", - submit_caption="I have authorized the app." - ) + add_devices(Thermostat(data, index) + for index in range(len(data.ecobee.thermostats))) # pylint: disable=too-few-public-methods class EcobeeData(object): """ Gets the latest data and update the states. """ - def __init__(self, config_filename): - from pyecobee import Ecobee - self.ecobee = Ecobee(config_filename) + def __init__(self, network): + self.ecobee = network @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): diff --git a/requirements_all.txt b/requirements_all.txt index 3a930c145dd..b74226f4991 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -161,4 +161,4 @@ pushetta==1.0.15 orvibo==1.0.0 # Ecobee (*.ecobee) -https://github.com/nkgilley/python-ecobee-api/archive/730009b9593899d42e98c81a0544f91e65b2bc15.zip#python-ecobee==0.0.1 +https://github.com/nkgilley/python-ecobee-api/archive/d35596b67c75451fa47001c493a15eebee195e93.zip#python-ecobee==0.0.1 From b4ee3f73b46aed0f36bc660db80487869c739863 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 20 Nov 2015 23:47:49 +0100 Subject: [PATCH 034/166] Add aREST binary sensor and fix ordering --- .coveragerc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.coveragerc b/.coveragerc index f19e37d00a1..07d4a8dd4bc 100644 --- a/.coveragerc +++ b/.coveragerc @@ -29,7 +29,7 @@ omit = homeassistant/components/rfxtrx.py homeassistant/components/*/rfxtrx.py - homeassistant/components/ifttt.py + homeassistant/components/binary_sensor/arest.py homeassistant/components/browser.py homeassistant/components/camera/* homeassistant/components/device_tracker/actiontec.py @@ -48,6 +48,7 @@ omit = homeassistant/components/device_tracker/snmp.py homeassistant/components/discovery.py homeassistant/components/downloader.py + homeassistant/components/ifttt.py homeassistant/components/keyboard.py homeassistant/components/light/hue.py homeassistant/components/light/mqtt.py @@ -84,7 +85,6 @@ omit = homeassistant/components/sensor/glances.py homeassistant/components/sensor/mysensors.py homeassistant/components/sensor/openweathermap.py - homeassistant/components/switch/orvibo.py homeassistant/components/sensor/rest.py homeassistant/components/sensor/rpi_gpio.py homeassistant/components/sensor/sabnzbd.py @@ -98,6 +98,7 @@ omit = homeassistant/components/switch/command_switch.py homeassistant/components/switch/edimax.py homeassistant/components/switch/hikvisioncam.py + homeassistant/components/switch/orvibo.py homeassistant/components/switch/rest.py homeassistant/components/switch/rpi_gpio.py homeassistant/components/switch/transmission.py From 422a93e73599f661b9c6be2f2b6a7bdc6b28bdeb Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 20 Nov 2015 23:48:59 +0100 Subject: [PATCH 035/166] Add tests for MQTT binary sensor --- tests/components/binary_sensor/__init__.py | 0 tests/components/binary_sensor/test_mqtt.py | 48 +++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/components/binary_sensor/__init__.py create mode 100644 tests/components/binary_sensor/test_mqtt.py diff --git a/tests/components/binary_sensor/__init__.py b/tests/components/binary_sensor/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/components/binary_sensor/test_mqtt.py b/tests/components/binary_sensor/test_mqtt.py new file mode 100644 index 00000000000..83fa532d051 --- /dev/null +++ b/tests/components/binary_sensor/test_mqtt.py @@ -0,0 +1,48 @@ +""" +tests.components.binary_sensor.test_mqtt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests MQTT binary sensor. +""" +import unittest + +import homeassistant.core as ha +import homeassistant.components.binary_sensor as binary_sensor +from tests.common import mock_mqtt_component, fire_mqtt_message +from homeassistant.const import (STATE_OFF, STATE_ON) + + +class TestSensorMQTT(unittest.TestCase): + """ Test the MQTT sensor. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = ha.HomeAssistant() + mock_mqtt_component(self.hass) + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_setting_sensor_value_via_mqtt_message(self): + self.assertTrue(binary_sensor.setup(self.hass, { + 'binary_sensor': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'test-topic', + 'payload_on': 'ON', + 'payload_off': 'OFF', + } + })) + + state = self.hass.states.get('binary_sensor.test') + self.assertEqual(STATE_OFF, state.state) + + fire_mqtt_message(self.hass, 'test-topic', 'ON') + self.hass.pool.block_till_done() + state = self.hass.states.get('binary_sensor.test') + self.assertEqual(STATE_ON, state.state) + + fire_mqtt_message(self.hass, 'test-topic', 'OFF') + self.hass.pool.block_till_done() + state = self.hass.states.get('binary_sensor.test') + self.assertEqual(STATE_OFF, state.state) From 427944cc4491225bc043b43175d81fce6fd44e27 Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Fri, 20 Nov 2015 23:50:46 +0100 Subject: [PATCH 036/166] add test for mqtt+json switch --- tests/components/sensor/test_mqtt.py | 3 +-- tests/components/switch/test_mqtt.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/components/sensor/test_mqtt.py b/tests/components/sensor/test_mqtt.py index 8d1aef4d57f..0c17b95e212 100644 --- a/tests/components/sensor/test_mqtt.py +++ b/tests/components/sensor/test_mqtt.py @@ -56,5 +56,4 @@ class TestSensorMQTT(unittest.TestCase): state = self.hass.states.get('sensor.test') self.assertEqual('100', state.state) - self.assertEqual('fav unit', - state.attributes.get('unit_of_measurement')) + diff --git a/tests/components/switch/test_mqtt.py b/tests/components/switch/test_mqtt.py index a09fcf86c58..4754e64e575 100644 --- a/tests/components/switch/test_mqtt.py +++ b/tests/components/switch/test_mqtt.py @@ -80,3 +80,31 @@ class TestSensorMQTT(unittest.TestCase): self.mock_publish.mock_calls[-1][1]) state = self.hass.states.get('switch.test') self.assertEqual(STATE_OFF, state.state) + + def test_controlling_state_via_topic_and_json_message(self): + self.assertTrue(switch.setup(self.hass, { + 'switch': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'payload_on': 'beer on', + 'payload_off': 'beer off', + 'state_format': 'json:val' + } + })) + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_OFF, state.state) + + fire_mqtt_message(self.hass, 'state-topic', '{"val":"beer on"}') + self.hass.pool.block_till_done() + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_ON, state.state) + + fire_mqtt_message(self.hass, 'state-topic', '{"val":"beer off"}') + self.hass.pool.block_till_done() + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_OFF, state.state) \ No newline at end of file From 06212604356216b45905d64c434bcaf83a6a5b15 Mon Sep 17 00:00:00 2001 From: Brad Buran Date: Thu, 19 Nov 2015 20:35:18 -0800 Subject: [PATCH 037/166] Fix issue with finding location of OpenZWave conf Under some install scenarios, it may be possible that OpenZWave can't automatically discover the location of the vendor-specific XML config files. In this event, we need to specify the location in the Home Assistant configuration.yaml file. --- homeassistant/components/zwave.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/zwave.py b/homeassistant/components/zwave.py index 06f471cd692..11515e4031d 100644 --- a/homeassistant/components/zwave.py +++ b/homeassistant/components/zwave.py @@ -6,6 +6,9 @@ Connects Home Assistant to a Z-Wave network. For more details about this component, please refer to the documentation at https://home-assistant.io/components/zwave/ """ +import sys +import os.path + from pprint import pprint from homeassistant import bootstrap @@ -21,6 +24,8 @@ CONF_USB_STICK_PATH = "usb_path" DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick" CONF_DEBUG = "debug" CONF_POLLING_INTERVAL = "polling_interval" +DEFAULT_ZWAVE_CONFIG_PATH = os.path.join(sys.prefix, 'share', + 'python-openzwave', 'config') DISCOVER_SENSORS = "zwave.sensors" DISCOVER_SWITCHES = "zwave.switch" @@ -120,7 +125,9 @@ def setup(hass, config): # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH, DEFAULT_CONF_USB_STICK_PATH), - user_path=hass.config.config_dir) + user_path=hass.config.config_dir, + config_path=config[DOMAIN].get('config_path', + DEFAULT_ZWAVE_CONFIG_PATH),) options.set_console_output(use_debug) options.lock() From f37d0d1c20d4bfa204a16d99f1f00d92bca769d9 Mon Sep 17 00:00:00 2001 From: miniconfig Date: Sat, 21 Nov 2015 09:52:43 -0500 Subject: [PATCH 038/166] Updated wink library version in requirements_all.txt --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index ce6cbfabc96..97d08d97c58 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -93,7 +93,7 @@ netdisco==0.5.1 pywemo==0.3.2 # Wink (*.wink) -https://github.com/balloob/python-wink/archive/9eb39eaba0717922815e673ad1114c685839d890.zip#python-wink==0.1.1 +https://github.com/balloob/python-wink/archive/42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip#python-wink==0.2 # Slack notifier (notify.slack) slacker==0.6.8 From 715abf241e732d69c43798493b134ca51cae9194 Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Sat, 21 Nov 2015 17:57:15 +0100 Subject: [PATCH 039/166] Disable pylint warning for callable classes --- homeassistant/components/mqtt/__init__.py | 8 +++++--- homeassistant/components/sensor/mqtt.py | 4 ++-- homeassistant/components/switch/mqtt.py | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 5b92da90d0a..c27abbebe58 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -129,6 +129,7 @@ def setup(hass, config): return True +# pylint: disable=too-few-public-methods class _JsonFmtParser(object): """ Implements a json parser on xpath""" def __init__(self, jsonpath): @@ -139,16 +140,17 @@ class _JsonFmtParser(object): return match[0].value if len(match) > 0 else payload +# pylint: disable=too-few-public-methods class FmtParser(object): """ wrapper for all supported formats """ def __init__(self, fmt): - self._parser = lambda x: x + self._parse = lambda x: x if fmt: if fmt.startswith('json:'): - self._parser = _JsonFmtParser(fmt[5:]) + self._parse = _JsonFmtParser(fmt[5:]) def __call__(self, payload): - return self._parser(payload) + return self._parse(payload) # This is based on one of the paho-mqtt examples: diff --git a/homeassistant/components/sensor/mqtt.py b/homeassistant/components/sensor/mqtt.py index 384d0f8a48a..2bbed97e40c 100644 --- a/homeassistant/components/sensor/mqtt.py +++ b/homeassistant/components/sensor/mqtt.py @@ -46,11 +46,11 @@ class MqttSensor(Entity): self._state_topic = state_topic self._qos = qos self._unit_of_measurement = unit_of_measurement - self._parser = mqtt.FmtParser(state_format) + self._parse = mqtt.FmtParser(state_format) def message_received(topic, payload, qos): """ A new MQTT message has been received. """ - self._state = self._parser(payload) + self._state = self._parse(payload) self.update_ha_state() mqtt.subscribe(hass, self._state_topic, message_received, self._qos) diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index eeb4551b921..ed99a87868a 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -55,11 +55,11 @@ class MqttSwitch(SwitchDevice): self._payload_on = payload_on self._payload_off = payload_off self._optimistic = optimistic - self._parser = mqtt.FmtParser(state_format) + self._parse = mqtt.FmtParser(state_format) def message_received(topic, payload, qos): """ A new MQTT message has been received. """ - payload = self._parser(payload) + payload = self._parse(payload) if payload == self._payload_on: self._state = True self.update_ha_state() From 8dc0de1d05cda0f218b882ccf4013bbfa405824d Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Sat, 21 Nov 2015 12:24:06 -0500 Subject: [PATCH 040/166] move EcobeeData class and Throttle to the main ecobee component, this way the sensor and thermostat will use the same throttled updating object. --- homeassistant/components/ecobee.py | 25 ++++++++++++++---- homeassistant/components/thermostat/ecobee.py | 26 +------------------ 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/ecobee.py b/homeassistant/components/ecobee.py index 99db73b6a90..ef982a15e63 100644 --- a/homeassistant/components/ecobee.py +++ b/homeassistant/components/ecobee.py @@ -1,5 +1,5 @@ """ -homeassistant.components.zwave +homeassistant.components.ecobee ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Connects Home Assistant to the Ecobee API and maintains tokens. @@ -12,6 +12,7 @@ api_key: asdflaksf from homeassistant.loader import get_component from homeassistant import bootstrap +from homeassistant.util import Throttle from homeassistant.const import ( EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, CONF_API_KEY) @@ -57,7 +58,7 @@ def request_configuration(network, hass): hass, "Ecobee", ecobee_configuration_callback, description=( 'Please authorize this app at https://www.ecobee.com/consumer' - 'portal/index.html with pin code: ' + NETWORK.pin), + 'portal/index.html with pin code: ' + network.pin), description_image="/static/images/config_ecobee_thermostat.png", submit_caption="I have authorized the app." ) @@ -75,6 +76,20 @@ def setup_ecobee(hass, network): configurator.request_done(_CONFIGURING.pop('ecobee')) +# pylint: disable=too-few-public-methods +class EcobeeData(object): + """ Gets the latest data and update the states. """ + + def __init__(self, config_file): + from pyecobee import Ecobee + self.ecobee = Ecobee(config_file) + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """ Get the latest data from pyecobee. """ + self.ecobee.update() + + def setup(hass, config): """ Setup Ecobee. @@ -87,7 +102,7 @@ def setup(hass, config): if 'ecobee' in _CONFIGURING: return - from pyecobee import Ecobee, config_from_file + from pyecobee import config_from_file # Create ecobee.conf if it doesn't exist if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)): @@ -97,9 +112,9 @@ def setup(hass, config): jsonconfig = {"API_KEY": config[DOMAIN].get(CONF_API_KEY)} config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig) - NETWORK = Ecobee(hass.config.path(ECOBEE_CONFIG_FILE)) + NETWORK = EcobeeData(hass.config.path(ECOBEE_CONFIG_FILE)) - setup_ecobee(hass, NETWORK) + setup_ecobee(hass, NETWORK.ecobee) # Ensure component is loaded bootstrap.setup_component(hass, 'thermostat', config) diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 5b377be4907..7f95aa7d1c6 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -26,8 +26,6 @@ thermostat: from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) from homeassistant.const import (TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) -from homeassistant.util import Throttle -from datetime import timedelta import logging DEPENDENCIES = ['ecobee'] @@ -37,39 +35,17 @@ _LOGGER = logging.getLogger(__name__) ECOBEE_CONFIG_FILE = 'ecobee.conf' _CONFIGURING = {} -# Return cached results if last scan was less then this time ago -MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180) - def setup_platform(hass, config, add_devices, discovery_info=None): """ Setup Platform """ _LOGGER.error("ecobee !!!!") if discovery_info is None: return - data = EcobeeData(discovery_info[0]) - setup_ecobee(hass, data, add_devices) - - -def setup_ecobee(hass, data, add_devices): - """ Setup ecobee thermostat """ - + data = discovery_info[0] add_devices(Thermostat(data, index) for index in range(len(data.ecobee.thermostats))) -# pylint: disable=too-few-public-methods -class EcobeeData(object): - """ Gets the latest data and update the states. """ - - def __init__(self, network): - self.ecobee = network - - @Throttle(MIN_TIME_BETWEEN_UPDATES) - def update(self): - """ Get the latest data from pyecobee. """ - self.ecobee.update() - - class Thermostat(ThermostatDevice): """ Thermostat class for Ecobee """ From dbcd055cfecb4c0757f3d4d42826b2638f3fc52c Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Sun, 22 Nov 2015 16:18:05 +0100 Subject: [PATCH 041/166] move import of jsonpath-rw to c'tor of _JsonFmtParser --- homeassistant/components/mqtt/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index c27abbebe58..f729d02af8a 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -10,7 +10,6 @@ import logging import os import socket import json -import jsonpath_rw from homeassistant.exceptions import HomeAssistantError import homeassistant.util as util @@ -32,7 +31,8 @@ SERVICE_PUBLISH = 'publish' EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED' DEPENDENCIES = [] -REQUIREMENTS = ['paho-mqtt==1.1'] +REQUIREMENTS = ['paho-mqtt==1.1' + 'jsonpath-rw==1.4.0'] CONF_BROKER = 'broker' CONF_PORT = 'port' @@ -133,6 +133,7 @@ def setup(hass, config): class _JsonFmtParser(object): """ Implements a json parser on xpath""" def __init__(self, jsonpath): + import jsonpath_rw self._expr = jsonpath_rw.parse(jsonpath) def __call__(self, payload): From 90681c2dc97fdddf9dee418ddb0b6e2981e26c62 Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Sun, 22 Nov 2015 16:19:08 +0100 Subject: [PATCH 042/166] fix incorrect requirements --- homeassistant/components/mqtt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index f729d02af8a..24c30c5eca6 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -31,7 +31,7 @@ SERVICE_PUBLISH = 'publish' EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED' DEPENDENCIES = [] -REQUIREMENTS = ['paho-mqtt==1.1' +REQUIREMENTS = ['paho-mqtt==1.1', 'jsonpath-rw==1.4.0'] CONF_BROKER = 'broker' From 100400f14940bfade04ed29c51434ec55f3ac83d Mon Sep 17 00:00:00 2001 From: Oliver van Porten Date: Sun, 22 Nov 2015 16:28:21 +0100 Subject: [PATCH 043/166] move requirements to single line to not to affect coverage --- homeassistant/components/mqtt/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 24c30c5eca6..9ec5169c729 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -31,8 +31,7 @@ SERVICE_PUBLISH = 'publish' EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED' DEPENDENCIES = [] -REQUIREMENTS = ['paho-mqtt==1.1', - 'jsonpath-rw==1.4.0'] +REQUIREMENTS = ['paho-mqtt==1.1', 'jsonpath-rw==1.4.0'] CONF_BROKER = 'broker' CONF_PORT = 'port' From d4f0f0ffd331461efe1c86c873b880257e2b229a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 22 Nov 2015 15:10:24 -0800 Subject: [PATCH 044/166] Update automation url in warning --- homeassistant/components/automation/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index d3ef80d7192..23d83f554ca 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -123,7 +123,7 @@ def _migrate_old_config(config): _LOGGER.warning( 'You are using an old configuration format. Please upgrade: ' - 'https://home-assistant.io/components/automation.html') + 'https://home-assistant.io/components/automation/') new_conf = { CONF_TRIGGER: dict(config), From f17079918233350fe23e1ff43202f376259302cb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 22 Nov 2015 15:09:56 -0800 Subject: [PATCH 045/166] Reconnect when disconnected from MQTT --- homeassistant/components/mqtt/__init__.py | 146 ++++++++++++++-------- 1 file changed, 93 insertions(+), 53 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 9ec5169c729..30f7dc71b41 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -6,10 +6,12 @@ MQTT component, using paho-mqtt. For more details about this component, please refer to the documentation at https://home-assistant.io/components/mqtt/ """ +import json import logging import os import socket -import json +import time + from homeassistant.exceptions import HomeAssistantError import homeassistant.util as util @@ -45,6 +47,8 @@ ATTR_TOPIC = 'topic' ATTR_PAYLOAD = 'payload' ATTR_QOS = 'qos' +MAX_RECONNECT_WAIT = 300 # seconds + def publish(hass, topic, payload, qos=None): """ Send an MQTT message. """ @@ -66,9 +70,7 @@ def subscribe(hass, topic, callback, qos=DEFAULT_QOS): event.data[ATTR_QOS]) hass.bus.listen(EVENT_MQTT_MESSAGE_RECEIVED, mqtt_topic_subscriber) - - if topic not in MQTT_CLIENT.topics: - MQTT_CLIENT.subscribe(topic, qos) + MQTT_CLIENT.subscribe(topic, qos) def setup(hass, config): @@ -162,24 +164,30 @@ class MQTT(object): # pragma: no cover password, certificate): import paho.mqtt.client as mqtt - self.hass = hass - self._progress = {} - self.topics = {} + self.userdata = { + 'hass': hass, + 'topics': {}, + 'progress': {}, + } if client_id is None: self._mqttc = mqtt.Client() else: self._mqttc = mqtt.Client(client_id) + self._mqttc.user_data_set(self.userdata) + if username is not None: self._mqttc.username_pw_set(username, password) if certificate is not None: self._mqttc.tls_set(certificate) - self._mqttc.on_subscribe = self._mqtt_on_subscribe - self._mqttc.on_unsubscribe = self._mqtt_on_unsubscribe - self._mqttc.on_connect = self._mqtt_on_connect - self._mqttc.on_message = self._mqtt_on_message + self._mqttc.on_subscribe = _mqtt_on_subscribe + self._mqttc.on_unsubscribe = _mqtt_on_unsubscribe + self._mqttc.on_connect = _mqtt_on_connect + self._mqttc.on_disconnect = _mqtt_on_disconnect + self._mqttc.on_message = _mqtt_on_message + self._mqttc.connect(broker, port, keepalive) def publish(self, topic, payload, qos): @@ -190,7 +198,7 @@ class MQTT(object): # pragma: no cover """ Unsubscribe from topic. """ result, mid = self._mqttc.unsubscribe(topic) _raise_on_error(result) - self._progress[mid] = topic + self.userdata['progress'][mid] = topic def start(self): """ Run the MQTT client. """ @@ -202,55 +210,87 @@ class MQTT(object): # pragma: no cover def subscribe(self, topic, qos): """ Subscribe to a topic. """ - if topic in self.topics: + if topic in self.userdata['topics']: return result, mid = self._mqttc.subscribe(topic, qos) _raise_on_error(result) - self._progress[mid] = topic - self.topics[topic] = None + self.userdata['progress'][mid] = topic + self.userdata['topics'][topic] = None - def _mqtt_on_connect(self, mqttc, obj, flags, result_code): - """ On connect, resubscribe to all topics we were subscribed to. """ - if result_code != 0: - _LOGGER.error('Unable to connect to the MQTT broker: %s', { - 1: 'Incorrect protocol version', - 2: 'Invalid client identifier', - 3: 'Server unavailable', - 4: 'Bad username or password', - 5: 'Not authorised' - }.get(result_code)) - self._mqttc.disconnect() - return - old_topics = self.topics - self._progress = {} - self.topics = {} - for topic, qos in old_topics.items(): - # qos is None if we were in process of subscribing - if qos is not None: - self._mqttc.subscribe(topic, qos) +def _mqtt_on_message(mqttc, userdata, msg): + """ Message callback """ + userdata['hass'].bus.fire(EVENT_MQTT_MESSAGE_RECEIVED, { + ATTR_TOPIC: msg.topic, + ATTR_QOS: msg.qos, + ATTR_PAYLOAD: msg.payload.decode('utf-8'), + }) - def _mqtt_on_subscribe(self, mqttc, obj, mid, granted_qos): - """ Called when subscribe succesfull. """ - topic = self._progress.pop(mid, None) - if topic is None: - return - self.topics[topic] = granted_qos - def _mqtt_on_unsubscribe(self, mqttc, obj, mid, granted_qos): - """ Called when subscribe succesfull. """ - topic = self._progress.pop(mid, None) - if topic is None: - return - self.topics.pop(topic, None) +def _mqtt_on_connect(mqttc, userdata, flags, result_code): + """ On connect, resubscribe to all topics we were subscribed to. """ + if result_code != 0: + _LOGGER.error('Unable to connect to the MQTT broker: %s', { + 1: 'Incorrect protocol version', + 2: 'Invalid client identifier', + 3: 'Server unavailable', + 4: 'Bad username or password', + 5: 'Not authorised' + }.get(result_code)) + mqttc.disconnect() + return - def _mqtt_on_message(self, mqttc, obj, msg): - """ Message callback """ - self.hass.bus.fire(EVENT_MQTT_MESSAGE_RECEIVED, { - ATTR_TOPIC: msg.topic, - ATTR_QOS: msg.qos, - ATTR_PAYLOAD: msg.payload.decode('utf-8'), - }) + old_topics = userdata['topics'] + + userdata['topics'] = {} + userdata['progress'] = {} + + for topic, qos in old_topics.items(): + # qos is None if we were in process of subscribing + if qos is not None: + mqttc.subscribe(topic, qos) + + +def _mqtt_on_subscribe(mqttc, userdata, mid, granted_qos): + """ Called when subscribe successfull. """ + topic = userdata['progress'].pop(mid, None) + if topic is None: + return + userdata['topics'][topic] = granted_qos + + +def _mqtt_on_unsubscribe(mqttc, userdata, mid, granted_qos): + """ Called when subscribe successfull. """ + topic = userdata['progress'].pop(mid, None) + if topic is None: + return + userdata['topics'].pop(topic, None) + + +def _mqtt_on_disconnect(mqttc, userdata, result_code): + """ Called when being disconnected. """ + # When disconnected because of calling disconnect() + if result_code == 0: + return + + tries = 0 + wait_time = 0 + + while True: + try: + if mqttc.reconnect() == 0: + _LOGGER.info('Successfully reconnected to the MQTT server') + break + except socket.error: + pass + + wait_time = min(2**tries, MAX_RECONNECT_WAIT) + _LOGGER.warning( + 'Disconnected from MQTT (%s). Trying to reconnect in %ss', + result_code, wait_time) + # It is ok to sleep here as we are in the MQTT thread. + time.sleep(wait_time) + tries += 1 def _raise_on_error(result): # pragma: no cover From 1bda0bd73bc34f0bb90b71c08f9f688bf852475b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 22 Nov 2015 16:04:16 -0800 Subject: [PATCH 046/166] Add some MQTT tests --- homeassistant/components/mqtt/__init__.py | 18 +++--- tests/components/test_mqtt.py | 74 ++++++++++++++++++++++- 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 30f7dc71b41..7f4ff030d36 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -158,7 +158,7 @@ class FmtParser(object): # This is based on one of the paho-mqtt examples: # http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/tree/examples/sub-class.py # pylint: disable=too-many-arguments -class MQTT(object): # pragma: no cover +class MQTT(object): """ Implements messaging service for MQTT. """ def __init__(self, hass, broker, port, client_id, keepalive, username, password, certificate): @@ -194,12 +194,6 @@ class MQTT(object): # pragma: no cover """ Publish a MQTT message. """ self._mqttc.publish(topic, payload, qos) - def unsubscribe(self, topic): - """ Unsubscribe from topic. """ - result, mid = self._mqttc.unsubscribe(topic) - _raise_on_error(result) - self.userdata['progress'][mid] = topic - def start(self): """ Run the MQTT client. """ self._mqttc.loop_start() @@ -217,6 +211,12 @@ class MQTT(object): # pragma: no cover self.userdata['progress'][mid] = topic self.userdata['topics'][topic] = None + def unsubscribe(self, topic): + """ Unsubscribe from topic. """ + result, mid = self._mqttc.unsubscribe(topic) + _raise_on_error(result) + self.userdata['progress'][mid] = topic + def _mqtt_on_message(mqttc, userdata, msg): """ Message callback """ @@ -236,7 +236,7 @@ def _mqtt_on_connect(mqttc, userdata, flags, result_code): 3: 'Server unavailable', 4: 'Bad username or password', 5: 'Not authorised' - }.get(result_code)) + }.get(result_code, 'Unknown reason')) mqttc.disconnect() return @@ -293,7 +293,7 @@ def _mqtt_on_disconnect(mqttc, userdata, result_code): tries += 1 -def _raise_on_error(result): # pragma: no cover +def _raise_on_error(result): """ Raise error if error result. """ if result != 0: raise HomeAssistantError('Error talking to MQTT: {}'.format(result)) diff --git a/tests/components/test_mqtt.py b/tests/components/test_mqtt.py index 4c3dbb1d20a..47a5ac7b4e1 100644 --- a/tests/components/test_mqtt.py +++ b/tests/components/test_mqtt.py @@ -4,6 +4,7 @@ tests.test_component_mqtt Tests MQTT component. """ +from collections import namedtuple import unittest from unittest import mock import socket @@ -17,8 +18,8 @@ from tests.common import ( get_test_home_assistant, mock_mqtt_component, fire_mqtt_message) -class TestDemo(unittest.TestCase): - """ Test the demo module. """ +class TestMQTT(unittest.TestCase): + """ Test the MQTT module. """ def setUp(self): # pylint: disable=invalid-name self.hass = get_test_home_assistant(1) @@ -136,3 +137,72 @@ class TestDemo(unittest.TestCase): self.hass.pool.block_till_done() self.assertEqual(0, len(self.calls)) + + +class TestMQTTCallbacks(unittest.TestCase): + """ Test the MQTT callbacks. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = get_test_home_assistant(1) + mock_mqtt_component(self.hass) + self.calls = [] + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_receiving_mqtt_message_fires_hass_event(self): + calls = [] + + def record(event): + calls.append(event) + + self.hass.bus.listen_once(mqtt.EVENT_MQTT_MESSAGE_RECEIVED, record) + + MQTTMessage = namedtuple('MQTTMessage', ['topic', 'qos', 'payload']) + message = MQTTMessage('test_topic', 1, 'Hello World!'.encode('utf-8')) + + mqtt._mqtt_on_message(None, {'hass': self.hass}, message) + self.hass.pool.block_till_done() + + self.assertEqual(1, len(calls)) + last_event = calls[0] + self.assertEqual('Hello World!', last_event.data['payload']) + self.assertEqual(message.topic, last_event.data['topic']) + self.assertEqual(message.qos, last_event.data['qos']) + + def test_mqtt_failed_connection_results_in_disconnect(self): + for result_code in range(1, 6): + mqttc = mock.MagicMock() + mqtt._mqtt_on_connect(mqttc, {'topics': {}}, 0, result_code) + self.assertTrue(mqttc.disconnect.called) + + def test_mqtt_subscribes_topics_on_connect(self): + prev_topics = { + 'topic/test': 1, + 'home/sensor': 2, + 'still/pending': None + } + mqttc = mock.MagicMock() + mqtt._mqtt_on_connect(mqttc, {'topics': prev_topics}, 0, 0) + self.assertFalse(mqttc.disconnect.called) + + expected = [(topic, qos) for topic, qos in prev_topics.items() + if qos is not None] + self.assertEqual(expected, [call[1] for call + in mqttc.subscribe.mock_calls]) + + def test_mqtt_disconnect_tries_no_reconnect_on_stop(self): + mqttc = mock.MagicMock() + mqtt._mqtt_on_disconnect(mqttc, {}, 0) + self.assertFalse(mqttc.reconnect.called) + + @mock.patch('homeassistant.components.mqtt.time.sleep') + def test_mqtt_disconnect_tries_reconnect(self, mock_sleep): + mqttc = mock.MagicMock() + mqttc.reconnect.side_effect = [1, 1, 1, 0] + mqtt._mqtt_on_disconnect(mqttc, {}, 1) + self.assertTrue(mqttc.reconnect.called) + self.assertEqual(4, len(mqttc.reconnect.mock_calls)) + self.assertEqual([1, 2, 4], + [call[1][0] for call in mock_sleep.mock_calls]) From 8269e843f2a38ea9bf6da904e7a60d559ee29ba6 Mon Sep 17 00:00:00 2001 From: sfam Date: Mon, 23 Nov 2015 00:22:43 +0000 Subject: [PATCH 047/166] Initial commit for rollershutter component --- .../components/rollershutter/__init__.py | 116 +++++++++++++++++ .../components/rollershutter/mqtt.py | 119 ++++++++++++++++++ .../components/rollershutter/services.yaml | 0 tests/components/rollershutter/test_mqtt.py | 116 +++++++++++++++++ 4 files changed, 351 insertions(+) create mode 100644 homeassistant/components/rollershutter/__init__.py create mode 100644 homeassistant/components/rollershutter/mqtt.py create mode 100644 homeassistant/components/rollershutter/services.yaml create mode 100644 tests/components/rollershutter/test_mqtt.py diff --git a/homeassistant/components/rollershutter/__init__.py b/homeassistant/components/rollershutter/__init__.py new file mode 100644 index 00000000000..461a34200b2 --- /dev/null +++ b/homeassistant/components/rollershutter/__init__.py @@ -0,0 +1,116 @@ +""" +homeassistant.components.rollershutter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Rollershutter component. + +""" +import os +import logging + +from homeassistant.config import load_yaml_config_file +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.entity import Entity +from homeassistant.components import group +from homeassistant.const import ( + SERVICE_MOVE_UP, SERVICE_MOVE_DOWN, SERVICE_MOVE_STOP, + STATE_OPEN, ATTR_ENTITY_ID) + + +DOMAIN = 'rollershutter' +DEPENDENCIES = [] +SCAN_INTERVAL = 15 + +GROUP_NAME_ALL_ROLLERSHUTTERS = 'all rollershutters' +ENTITY_ID_ALL_ROLLERSHUTTERS = group.ENTITY_ID_FORMAT.format( + 'all_rollershutters') + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + +# Maps discovered services to their platforms +DISCOVERY_PLATFORMS = {} + +_LOGGER = logging.getLogger(__name__) + + +def is_open(hass, entity_id=None): + """ Returns if the rollershutter is open based on the statemachine. """ + entity_id = entity_id or ENTITY_ID_ALL_ROLLERSHUTTERS + return hass.states.is_state(entity_id, STATE_OPEN) + + +def move_up(hass, entity_id=None): + """ Moves all or specified rollershutter up. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_MOVE_UP, data) + + +def move_down(hass, entity_id=None): + """ Moves all or specified rollershutter down. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_MOVE_DOWN, data) + + +def move_stop(hass, entity_id=None): + """ Stops all or specified rollershutter. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_MOVE_STOP, data) + + +def setup(hass, config): + """ Track states and offer events for rollershutters. """ + component = EntityComponent( + _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, + GROUP_NAME_ALL_ROLLERSHUTTERS) + component.setup(config) + + def handle_rollershutter_service(service): + """ Handles calls to the rollershutter services. """ + target_rollershutters = component.extract_from_service(service) + + for rollershutter in target_rollershutters: + if service.service == SERVICE_MOVE_UP: + rollershutter.move_up() + elif service.service == SERVICE_MOVE_DOWN: + rollershutter.move_down() + elif service.service == SERVICE_MOVE_STOP: + rollershutter.move_stop() + + if rollershutter.should_poll: + rollershutter.update_ha_state(True) + + descriptions = load_yaml_config_file( + os.path.join(os.path.dirname(__file__), 'services.yaml')) + + hass.services.register(DOMAIN, SERVICE_MOVE_UP, + handle_rollershutter_service, + descriptions.get(SERVICE_MOVE_UP)) + hass.services.register(DOMAIN, SERVICE_MOVE_DOWN, + handle_rollershutter_service, + descriptions.get(SERVICE_MOVE_DOWN)) + hass.services.register(DOMAIN, SERVICE_MOVE_STOP, + handle_rollershutter_service, + descriptions.get(SERVICE_MOVE_STOP)) + + return True + + +class RollershutterDevice(Entity): + """ Represents a rollershutter within Home Assistant. """ + # pylint: disable=no-self-use + + @property + def state_attributes(self): + """ Returns optional state attributes. """ + return None + + def move_up(self, **kwargs): + """ Moves the device UP. """ + raise NotImplementedError() + + def move_down(self, **kwargs): + """ Moves the device DOWN. """ + raise NotImplementedError() + + def move_stop(self, **kwargs): + """ Moves the device to STOP. """ + raise NotImplementedError() diff --git a/homeassistant/components/rollershutter/mqtt.py b/homeassistant/components/rollershutter/mqtt.py new file mode 100644 index 00000000000..ad5a4346bc9 --- /dev/null +++ b/homeassistant/components/rollershutter/mqtt.py @@ -0,0 +1,119 @@ +""" +homeassistant.components.rollershutter.mqtt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Allows to configure a MQTT rollershutter. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/rollershutter.mqtt/ +""" +import logging +import homeassistant.components.mqtt as mqtt +from homeassistant.components.rollershutter import RollershutterDevice +from homeassistant.const import (STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN) +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['mqtt'] + +DEFAULT_NAME = "MQTT Shutter" +DEFAULT_QOS = 0 +DEFAULT_PAYLOAD_UP = "UP" +DEFAULT_PAYLOAD_DOWN = "DOWN" +DEFAULT_PAYLOAD_STOP = "STOP" + +ATTR_CURRENT_POSITION = 'current_position' + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices_callback, discovery_info=None): + """ Add MQTT Roller Shutter """ + + if config.get('command_topic') is None: + _LOGGER.error("Missing required variable: command_topic") + return False + + add_devices_callback([MqttRollershutter( + hass, + config.get('name', DEFAULT_NAME), + config.get('state_topic'), + config.get('command_topic'), + config.get('qos', DEFAULT_QOS), + config.get('payload_up', DEFAULT_PAYLOAD_UP), + config.get('payload_down', DEFAULT_PAYLOAD_DOWN), + config.get('payload_stop', DEFAULT_PAYLOAD_STOP), + config.get('state_format'))]) + + +# pylint: disable=too-many-arguments, too-many-instance-attributes +class MqttRollershutter(RollershutterDevice): + """ Represents a rollershutter that can be togggled using MQTT """ + def __init__(self, hass, name, state_topic, command_topic, qos, + payload_up, payload_down, payload_stop, state_format): + self._state = -1 + self._hass = hass + self._name = name + self._state_topic = state_topic + self._command_topic = command_topic + self._qos = qos + self._payload_up = payload_up + self._payload_down = payload_down + self._payload_stop = payload_stop + self._parse = mqtt.FmtParser(state_format) + + if self._state_topic: + def message_received(topic, payload, qos): + """ A new MQTT message has been received. """ + value = self._parse(payload) + if value.isnumeric(): + if 0 <= int(value) <= 100: + self._state = int(value) + self.update_ha_state() + + mqtt.subscribe(hass, self._state_topic, message_received, + self._qos) + + @property + def should_poll(self): + """ No polling needed """ + return False + + @property + def name(self): + """ The name of the rollershutter """ + return self._name + + @property + def state(self): + """ Returns the state of the device. """ + if self._state == -1: + return STATE_UNKNOWN + elif self._state == 0: + return STATE_CLOSED + else: + return STATE_OPEN + + @property + def is_open(self): + """ True if device is open. """ + return self.state == STATE_OPEN + + def move_up(self, **kwargs): + """ Moves the device UP. """ + mqtt.publish(self.hass, self._command_topic, self._payload_up, + self._qos) + + def move_down(self, **kwargs): + """ Moves the device DOWN. """ + mqtt.publish(self.hass, self._command_topic, self._payload_down, + self._qos) + + def move_stop(self, **kwargs): + """ Moves the device to STOP. """ + mqtt.publish(self.hass, self._command_topic, self._payload_stop, + self._qos) + + @property + def state_attributes(self): + """ Return the state attributes. """ + state_attr = { + ATTR_CURRENT_POSITION: self._state, + } + return state_attr diff --git a/homeassistant/components/rollershutter/services.yaml b/homeassistant/components/rollershutter/services.yaml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/components/rollershutter/test_mqtt.py b/tests/components/rollershutter/test_mqtt.py new file mode 100644 index 00000000000..099d8fad1ea --- /dev/null +++ b/tests/components/rollershutter/test_mqtt.py @@ -0,0 +1,116 @@ +""" +tests.components.rollershutter.test_mqtt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests mqtt rollershutter. +""" +import unittest + +from homeassistant.const import STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN +import homeassistant.core as ha +import homeassistant.components.rollershutter as rollershutter +from tests.common import mock_mqtt_component, fire_mqtt_message + + +class TestRollershutterMQTT(unittest.TestCase): + """ Test the MQTT rollershutter. """ + + 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() + + def test_controlling_state_via_topic(self): + self.assertTrue(rollershutter.setup(self.hass, { + 'rollershutter': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'qos': 0, + 'payload_up': 'UP', + 'payload_down': 'DOWN', + 'payload_stop': 'STOP' + } + })) + + state = self.hass.states.get('rollershutter.test') + self.assertEqual(STATE_UNKNOWN, state.state) + + fire_mqtt_message(self.hass, 'state-topic', '0') + self.hass.pool.block_till_done() + + state = self.hass.states.get('rollershutter.test') + self.assertEqual(STATE_CLOSED, state.state) + + fire_mqtt_message(self.hass, 'state-topic', '50') + self.hass.pool.block_till_done() + + state = self.hass.states.get('rollershutter.test') + self.assertEqual(STATE_OPEN, state.state) + + fire_mqtt_message(self.hass, 'state-topic', '100') + self.hass.pool.block_till_done() + + state = self.hass.states.get('rollershutter.test') + self.assertEqual(STATE_OPEN, state.state) + + def test_sending_mqtt_commands(self): + self.assertTrue(rollershutter.setup(self.hass, { + 'rollershutter': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'qos': 2 + } + })) + + state = self.hass.states.get('rollershutter.test') + self.assertEqual(STATE_UNKNOWN, state.state) + + rollershutter.move_up(self.hass, 'rollershutter.test') + self.hass.pool.block_till_done() + + self.assertEqual(('command-topic', 'UP', 2), + self.mock_publish.mock_calls[-1][1]) + state = self.hass.states.get('rollershutter.test') + self.assertEqual(STATE_UNKNOWN, state.state) + + def test_state_attributes_current_position(self): + self.assertTrue(rollershutter.setup(self.hass, { + 'rollershutter': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'payload_up': 'UP', + 'payload_down': 'DOWN', + 'payload_stop': 'STOP' + } + })) + + current_position = self.hass.states.get( + 'rollershutter.test').attributes['current_position'] + self.assertEqual(-1, current_position) + + fire_mqtt_message(self.hass, 'state-topic', '0') + self.hass.pool.block_till_done() + current_position = self.hass.states.get( + 'rollershutter.test').attributes['current_position'] + self.assertEqual(0, current_position) + + fire_mqtt_message(self.hass, 'state-topic', '50') + self.hass.pool.block_till_done() + current_position = self.hass.states.get( + 'rollershutter.test').attributes['current_position'] + self.assertEqual(50, current_position) + + fire_mqtt_message(self.hass, 'state-topic', '101') + self.hass.pool.block_till_done() + current_position = self.hass.states.get( + 'rollershutter.test').attributes['current_position'] + self.assertEqual(50, current_position) From d4b3af327d0dfab571df7c411e26f95a4612fa2f Mon Sep 17 00:00:00 2001 From: sfam Date: Mon, 23 Nov 2015 00:25:10 +0000 Subject: [PATCH 048/166] Initial commit for rollershutter component --- homeassistant/const.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 5b0b5a5e214..047f66ef924 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -53,8 +53,6 @@ STATE_ALARM_ARMED_HOME = 'armed_home' STATE_ALARM_ARMED_AWAY = 'armed_away' STATE_ALARM_PENDING = 'pending' STATE_ALARM_TRIGGERED = 'triggered' -STATE_LOCKED = 'locked' -STATE_UNLOCKED = 'unlocked' # #### STATE AND EVENT ATTRIBUTES #### # Contains current time for a TIME_CHANGED event @@ -98,9 +96,6 @@ ATTR_BATTERY_LEVEL = "battery_level" # For devices which support an armed state ATTR_ARMED = "device_armed" -# For devices which support a locked state -ATTR_LOCKED = "locked" - # For sensors that support 'tripping', eg. motion and door sensors ATTR_TRIPPED = "device_tripped" @@ -140,8 +135,9 @@ SERVICE_ALARM_ARM_HOME = "alarm_arm_home" SERVICE_ALARM_ARM_AWAY = "alarm_arm_away" SERVICE_ALARM_TRIGGER = "alarm_trigger" -SERVICE_LOCK = "lock" -SERVICE_UNLOCK = "unlock" +SERVICE_MOVE_UP = 'move_up' +SERVICE_MOVE_DOWN = 'move_down' +SERVICE_MOVE_STOP = 'move_stop' # #### API / REMOTE #### SERVER_PORT = 8123 From 68ff9dd74f61fce99adfeaba3dc4519bbc0dc997 Mon Sep 17 00:00:00 2001 From: sfam Date: Mon, 23 Nov 2015 00:35:22 +0000 Subject: [PATCH 049/166] rollershutter component - fix const --- homeassistant/const.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/homeassistant/const.py b/homeassistant/const.py index 047f66ef924..add1848b72c 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -53,6 +53,8 @@ STATE_ALARM_ARMED_HOME = 'armed_home' STATE_ALARM_ARMED_AWAY = 'armed_away' STATE_ALARM_PENDING = 'pending' STATE_ALARM_TRIGGERED = 'triggered' +STATE_LOCKED = 'locked' +STATE_UNLOCKED = 'unlocked' # #### STATE AND EVENT ATTRIBUTES #### # Contains current time for a TIME_CHANGED event @@ -96,6 +98,9 @@ ATTR_BATTERY_LEVEL = "battery_level" # For devices which support an armed state ATTR_ARMED = "device_armed" +# For devices which support a locked state +ATTR_LOCKED = "locked" + # For sensors that support 'tripping', eg. motion and door sensors ATTR_TRIPPED = "device_tripped" @@ -135,6 +140,9 @@ SERVICE_ALARM_ARM_HOME = "alarm_arm_home" SERVICE_ALARM_ARM_AWAY = "alarm_arm_away" SERVICE_ALARM_TRIGGER = "alarm_trigger" +SERVICE_LOCK = "lock" +SERVICE_UNLOCK = "unlock" + SERVICE_MOVE_UP = 'move_up' SERVICE_MOVE_DOWN = 'move_down' SERVICE_MOVE_STOP = 'move_stop' From cc196d988867fe7e7d08c062c3ca06bf3383bdcf Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Mon, 23 Nov 2015 11:15:19 -0500 Subject: [PATCH 050/166] fixed sensors and thermostat. discovery working for both now. --- homeassistant/components/ecobee.py | 70 ++++++++++++------ homeassistant/components/sensor/__init__.py | 5 +- homeassistant/components/sensor/ecobee.py | 73 ++++++++++--------- .../components/thermostat/__init__.py | 8 +- homeassistant/components/thermostat/ecobee.py | 35 ++++++--- 5 files changed, 118 insertions(+), 73 deletions(-) diff --git a/homeassistant/components/ecobee.py b/homeassistant/components/ecobee.py index ef982a15e63..8b73a9969ef 100644 --- a/homeassistant/components/ecobee.py +++ b/homeassistant/components/ecobee.py @@ -1,13 +1,29 @@ """ homeassistant.components.ecobee -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Connects Home Assistant to the Ecobee API and maintains tokens. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/ecobee/ +Ecobee Component + +This component adds support for Ecobee3 Wireless Thermostats. +You will need to setup developer access to your thermostat, +and create and API key on the ecobee website. + +The first time you run this component you will see a configuration +component card in Home Assistant. This card will contain a PIN code +that you will need to use to authorize access to your thermostat. You +can do this at https://www.ecobee.com/consumerportal/index.html +Click My Apps, Add application, Enter Pin and click Authorize. + +After authorizing the application click the button in the configuration +card. Now your thermostat and sensors should shown in home-assistant. + +You can use the optional hold_temp parameter to set whether or not holds +are set indefintely or until the next scheduled event. + +ecobee: + api_key: asdfasdfasdfasdfasdfaasdfasdfasdfasdf + hold_temp: True -[ecobee] -api_key: asdflaksf """ from homeassistant.loader import get_component @@ -22,8 +38,10 @@ import os DOMAIN = "ecobee" DISCOVER_THERMOSTAT = "ecobee.thermostat" +DISCOVER_SENSORS = "ecobee.sensor" DEPENDENCIES = [] NETWORK = None +HOLD_TEMP = 'hold_temp' REQUIREMENTS = [ 'https://github.com/nkgilley/python-ecobee-api/archive/' @@ -38,7 +56,7 @@ _CONFIGURING = {} MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180) -def request_configuration(network, hass): +def request_configuration(network, hass, config): """ Request configuration steps from the user. """ configurator = get_component('configurator') if 'ecobee' in _CONFIGURING: @@ -52,7 +70,7 @@ def request_configuration(network, hass): """ Actions to do when our configuration callback is called. """ network.request_tokens() network.update() - setup_ecobee(hass, network) + setup_ecobee(hass, network, config) _CONFIGURING['ecobee'] = configurator.request_config( hass, "Ecobee", ecobee_configuration_callback, @@ -64,17 +82,35 @@ def request_configuration(network, hass): ) -def setup_ecobee(hass, network): +def setup_ecobee(hass, network, config): """ Setup ecobee thermostat """ # If ecobee has a PIN then it needs to be configured. if network.pin is not None: - request_configuration(network, hass) + request_configuration(network, hass, config) return if 'ecobee' in _CONFIGURING: configurator = get_component('configurator') configurator.request_done(_CONFIGURING.pop('ecobee')) + # Ensure component is loaded + bootstrap.setup_component(hass, 'thermostat') + bootstrap.setup_component(hass, 'sensor') + + hold_temp = config[DOMAIN].get(HOLD_TEMP, False) + + # Fire thermostat discovery event + hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { + ATTR_SERVICE: DISCOVER_THERMOSTAT, + ATTR_DISCOVERED: {'hold_temp': hold_temp} + }) + + # Fire sensor discovery event + hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { + ATTR_SERVICE: DISCOVER_SENSORS, + ATTR_DISCOVERED: {} + }) + # pylint: disable=too-few-public-methods class EcobeeData(object): @@ -88,6 +124,7 @@ class EcobeeData(object): def update(self): """ Get the latest data from pyecobee. """ self.ecobee.update() + _LOGGER.info("ecobee data updated successfully.") def setup(hass, config): @@ -114,18 +151,7 @@ def setup(hass, config): NETWORK = EcobeeData(hass.config.path(ECOBEE_CONFIG_FILE)) - setup_ecobee(hass, NETWORK.ecobee) - - # Ensure component is loaded - bootstrap.setup_component(hass, 'thermostat', config) - - # Fire discovery event - hass.bus.fire(EVENT_PLATFORM_DISCOVERED, { - ATTR_SERVICE: DISCOVER_THERMOSTAT, - ATTR_DISCOVERED: { - 'network': NETWORK, - } - }) + setup_ecobee(hass, NETWORK.ecobee, config) def stop_ecobee(event): """ Stop Ecobee. """ diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 32ee59a6fa9..0d214475358 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -9,7 +9,7 @@ https://home-assistant.io/components/sensor/ import logging from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.components import wink, zwave, isy994, verisure +from homeassistant.components import wink, zwave, isy994, verisure, ecobee DOMAIN = 'sensor' DEPENDENCIES = [] @@ -22,7 +22,8 @@ DISCOVERY_PLATFORMS = { wink.DISCOVER_SENSORS: 'wink', zwave.DISCOVER_SENSORS: 'zwave', isy994.DISCOVER_SENSORS: 'isy994', - verisure.DISCOVER_SENSORS: 'verisure' + verisure.DISCOVER_SENSORS: 'verisure', + ecobee.DISCOVER_SENSORS: 'ecobee' } diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py index a8d9e41acb1..b7663a70d6a 100644 --- a/homeassistant/components/sensor/ecobee.py +++ b/homeassistant/components/sensor/ecobee.py @@ -1,22 +1,39 @@ """ homeassistant.components.sensor.ecobee -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This sensor component requires that the Ecobee Thermostat -component be setup first. This component shows remote -ecobee sensor data. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Ecobee Thermostat Component + +This component adds support for Ecobee3 Wireless Thermostats. +You will need to setup developer access to your thermostat, +and create and API key on the ecobee website. + +The first time you run this component you will see a configuration +component card in Home Assistant. This card will contain a PIN code +that you will need to use to authorize access to your thermostat. You +can do this at https://www.ecobee.com/consumerportal/index.html +Click My Apps, Add application, Enter Pin and click Authorize. + +After authorizing the application click the button in the configuration +card. Now your thermostat and sensors should shown in home-assistant. + +You can use the optional hold_temp parameter to set whether or not holds +are set indefintely or until the next scheduled event. + +ecobee: + api_key: asdfasdfasdfasdfasdfaasdfasdfasdfasdf + hold_temp: True -For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/sensor.ecobee/ """ from homeassistant.helpers.entity import Entity -import json +from homeassistant.components.ecobee import NETWORK +from homeassistant.const import TEMP_FAHRENHEIT import logging -import os -DEPENDENCIES = ['thermostat'] +DEPENDENCIES = ['ecobee'] SENSOR_TYPES = { - 'temperature': ['Temperature', '°F'], + 'temperature': ['Temperature', TEMP_FAHRENHEIT], 'humidity': ['Humidity', '%'], 'occupancy': ['Occupancy', ''] } @@ -26,24 +43,12 @@ _LOGGER = logging.getLogger(__name__) ECOBEE_CONFIG_FILE = 'ecobee.conf' -def config_from_file(filename): - ''' Small configuration file reading function ''' - if os.path.isfile(filename): - try: - with open(filename, 'r') as fdesc: - return json.loads(fdesc.read()) - except IOError as error: - _LOGGER.error("ecobee sensor couldn't read config file: " + error) - return False - else: - return {} - - def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the sensors. """ - config = config_from_file(hass.config.path(ECOBEE_CONFIG_FILE)) + if discovery_info is None: + return dev = list() - for name, data in config['sensors'].items(): + for name, data in NETWORK.ecobee.sensors.items(): if 'temp' in data: dev.append(EcobeeSensor(name, 'temperature', hass)) if 'humidity' in data: @@ -80,14 +85,10 @@ class EcobeeSensor(Entity): return self._unit_of_measurement def update(self): - config = config_from_file(self.hass.config.path(ECOBEE_CONFIG_FILE)) - try: - data = config['sensors'][self.sensor_name] - if self.type == 'temperature': - self._state = data['temp'] - elif self.type == 'humidity': - self._state = data['humidity'] - elif self.type == 'occupancy': - self._state = data['occupancy'] - except KeyError: - print("Error updating ecobee sensors.") + data = NETWORK.ecobee.sensors[self.sensor_name] + if self.type == 'temperature': + self._state = data['temp'] + elif self.type == 'humidity': + self._state = data['humidity'] + elif self.type == 'occupancy': + self._state = data['occupancy'] diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py index 480e3e4805e..f1a82a4c989 100644 --- a/homeassistant/components/thermostat/__init__.py +++ b/homeassistant/components/thermostat/__init__.py @@ -15,6 +15,7 @@ from homeassistant.config import load_yaml_config_file import homeassistant.util as util from homeassistant.helpers.entity import Entity from homeassistant.helpers.temperature import convert +from homeassistant.components import ecobee from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF, STATE_UNKNOWN, TEMP_CELCIUS) @@ -42,6 +43,10 @@ ATTR_OPERATION = "current_operation" _LOGGER = logging.getLogger(__name__) +DISCOVERY_PLATFORMS = { + ecobee.DISCOVER_THERMOSTAT: 'ecobee', +} + def set_away_mode(hass, away_mode, entity_id=None): """ Turn all or specified thermostat away mode on. """ @@ -67,7 +72,8 @@ def set_temperature(hass, temperature, entity_id=None): def setup(hass, config): """ Setup thermostats. """ - component = EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) + component = EntityComponent(_LOGGER, DOMAIN, hass, + SCAN_INTERVAL, DISCOVERY_PLATFORMS) component.setup(config) def thermostat_service(service): diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 7f95aa7d1c6..51d21cb9991 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -15,17 +15,20 @@ can do this at https://www.ecobee.com/consumerportal/index.html Click My Apps, Add application, Enter Pin and click Authorize. After authorizing the application click the button in the configuration -card. Now your thermostat should shown in home-assistant. Once the -thermostat has been added you can add the ecobee sensor component -to your configuration.yaml. +card. Now your thermostat and sensors should shown in home-assistant. -thermostat: - platform: ecobee +You can use the optional hold_temp parameter to set whether or not holds +are set indefintely or until the next scheduled event. + +ecobee: api_key: asdfasdfasdfasdfasdfaasdfasdfasdfasdf + hold_temp: True + """ from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) from homeassistant.const import (TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) +from homeassistant.components.ecobee import NETWORK import logging DEPENDENCIES = ['ecobee'] @@ -38,30 +41,32 @@ _CONFIGURING = {} def setup_platform(hass, config, add_devices, discovery_info=None): """ Setup Platform """ - _LOGGER.error("ecobee !!!!") if discovery_info is None: return - data = discovery_info[0] - add_devices(Thermostat(data, index) + data = NETWORK + hold_temp = discovery_info['hold_temp'] + _LOGGER.info("Loading ecobee thermostat component with hold_temp set to " + + str(hold_temp)) + add_devices(Thermostat(data, index, hold_temp) for index in range(len(data.ecobee.thermostats))) class Thermostat(ThermostatDevice): """ Thermostat class for Ecobee """ - def __init__(self, data, thermostat_index): + def __init__(self, data, thermostat_index, hold_temp): self.data = data self.thermostat_index = thermostat_index self.thermostat = self.data.ecobee.get_thermostat( self.thermostat_index) self._name = self.thermostat['name'] self._away = 'away' in self.thermostat['program']['currentClimateRef'] + self.hold_temp = hold_temp def update(self): self.data.update() self.thermostat = self.data.ecobee.get_thermostat( self.thermostat_index) - _LOGGER.info("ecobee data updated successfully.") @property def name(self): @@ -157,7 +162,10 @@ class Thermostat(ThermostatDevice): def turn_away_mode_on(self): """ Turns away on. """ self._away = True - self.data.ecobee.set_climate_hold("away") + if self.hold_temp: + self.data.ecobee.set_climate_hold("away", "indefinite") + else: + self.data.ecobee.set_climate_hold("away") def turn_away_mode_off(self): """ Turns away off. """ @@ -169,7 +177,10 @@ class Thermostat(ThermostatDevice): temperature = int(temperature) low_temp = temperature - 1 high_temp = temperature + 1 - self.data.ecobee.set_hold_temp(low_temp, high_temp) + if self.hold_temp: + self.data.ecobee.set_hold_temp(low_temp, high_temp, "indefinite") + else: + self.data.ecobee.set_hold_temp(low_temp, high_temp) def set_hvac_mode(self, mode): """ Set HVAC mode (auto, auxHeatOnly, cool, heat, off) """ From 27bc4c582bc2fa7ce3b7467f2823525879d5ee12 Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Mon, 23 Nov 2015 11:40:54 -0500 Subject: [PATCH 051/166] update network data before sensor setup. --- homeassistant/components/sensor/ecobee.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py index b7663a70d6a..1ef40bcca89 100644 --- a/homeassistant/components/sensor/ecobee.py +++ b/homeassistant/components/sensor/ecobee.py @@ -48,13 +48,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if discovery_info is None: return dev = list() + NETWORK.update() for name, data in NETWORK.ecobee.sensors.items(): if 'temp' in data: - dev.append(EcobeeSensor(name, 'temperature', hass)) + dev.append(EcobeeSensor(name, 'temperature')) if 'humidity' in data: - dev.append(EcobeeSensor(name, 'humidity', hass)) + dev.append(EcobeeSensor(name, 'humidity')) if 'occupancy' in data: - dev.append(EcobeeSensor(name, 'occupancy', hass)) + dev.append(EcobeeSensor(name, 'occupancy')) add_devices(dev) @@ -62,10 +63,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class EcobeeSensor(Entity): """ An ecobee sensor. """ - def __init__(self, sensor_name, sensor_type, hass): + def __init__(self, sensor_name, sensor_type): self._name = sensor_name + ' ' + SENSOR_TYPES[sensor_type][0] self.sensor_name = sensor_name - self.hass = hass self.type = sensor_type self._state = None self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] @@ -85,6 +85,7 @@ class EcobeeSensor(Entity): return self._unit_of_measurement def update(self): + NETWORK.update() data = NETWORK.ecobee.sensors[self.sensor_name] if self.type == 'temperature': self._state = data['temp'] From 80e829f53a1482757be9671b3ac864e2ced0f5ab Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Mon, 23 Nov 2015 11:52:02 -0500 Subject: [PATCH 052/166] was getting errors for NETWORK being None. looked like it was being loaded too early, so this will wait until it's ready --- homeassistant/components/sensor/ecobee.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py index 1ef40bcca89..524ac912405 100644 --- a/homeassistant/components/sensor/ecobee.py +++ b/homeassistant/components/sensor/ecobee.py @@ -48,7 +48,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if discovery_info is None: return dev = list() - NETWORK.update() + while NETWORK is None: + continue for name, data in NETWORK.ecobee.sensors.items(): if 'temp' in data: dev.append(EcobeeSensor(name, 'temperature')) From 09a82dedf058a7a44105ea577a7211bbf3c5242e Mon Sep 17 00:00:00 2001 From: Allan Glen Date: Mon, 23 Nov 2015 11:57:46 -0700 Subject: [PATCH 053/166] Re-order Dockerfile for faster rebuild on code changes --- Dockerfile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9344ec65245..82e334504d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,27 @@ -FROM python:3-onbuild +FROM python:3 MAINTAINER Paulus Schoutsen VOLUME /config -RUN pip3 install --no-cache-dir -r requirements_all.txt +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app # For the nmap tracker RUN apt-get update && \ apt-get install -y --no-install-recommends nmap net-tools && \ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* +COPY script/build_python_openzwave script/build_python_openzwave RUN apt-get update && \ apt-get install -y cython3 libudev-dev && \ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ pip3 install "cython<0.23" && \ script/build_python_openzwave +COPY requirements_all.txt requirements_all.txt +RUN pip3 install --no-cache-dir -r requirements_all.txt + +# Copy source +COPY . . + CMD [ "python", "-m", "homeassistant", "--config", "/config" ] From 0d3a099926f37b36ac34147a4f8cd921fd08c9a8 Mon Sep 17 00:00:00 2001 From: Pascal Bach Date: Mon, 23 Nov 2015 21:46:47 +0100 Subject: [PATCH 054/166] arest: fix order argument order of log messages --- homeassistant/components/switch/arest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/arest.py b/homeassistant/components/switch/arest.py index c7bf1b34e4a..92bd70cb734 100644 --- a/homeassistant/components/switch/arest.py +++ b/homeassistant/components/switch/arest.py @@ -76,7 +76,7 @@ class ArestSwitch(SwitchDevice): self._state = True else: _LOGGER.error("Can't turn on pin %s at %s. Is device offline?", - self._resource, self._pin) + self._pin, self._resource) def turn_off(self, **kwargs): """ Turn the device off. """ @@ -86,7 +86,7 @@ class ArestSwitch(SwitchDevice): self._state = False else: _LOGGER.error("Can't turn off pin %s at %s. Is device offline?", - self._resource, self._pin) + self._pin, self._resource) def update(self): """ Gets the latest data from aREST API and updates the state. """ From d141306493e9a206dc7d8ce57cdb572706e5a991 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 23 Nov 2015 20:42:32 -0800 Subject: [PATCH 055/166] Update Dockerfile to depend on Python 3.4 instead of latest --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 82e334504d5..a1f9d459295 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3 +FROM python:3.4 MAINTAINER Paulus Schoutsen VOLUME /config From e001ea913a6132571a1b79cad50e07ac6d288190 Mon Sep 17 00:00:00 2001 From: sfam Date: Tue, 24 Nov 2015 08:03:02 +0000 Subject: [PATCH 056/166] add __init__.py to test folder --- tests/components/alarm_control_panel/__init__.py | 0 tests/components/rollershutter/__init__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/components/alarm_control_panel/__init__.py create mode 100644 tests/components/rollershutter/__init__.py diff --git a/tests/components/alarm_control_panel/__init__.py b/tests/components/alarm_control_panel/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/components/rollershutter/__init__.py b/tests/components/rollershutter/__init__.py new file mode 100644 index 00000000000..e69de29bb2d From 351430c1b38415ec790701b7c303d2a8ad1d3a04 Mon Sep 17 00:00:00 2001 From: sfam Date: Tue, 24 Nov 2015 10:41:39 +0000 Subject: [PATCH 057/166] move current_position to RollershutterDevice class --- .../components/rollershutter/__init__.py | 17 ++++++- .../components/rollershutter/mqtt.py | 46 +++++++++---------- tests/components/rollershutter/test_mqtt.py | 12 +++-- 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/rollershutter/__init__.py b/homeassistant/components/rollershutter/__init__.py index 461a34200b2..5ebcf8a3d21 100644 --- a/homeassistant/components/rollershutter/__init__.py +++ b/homeassistant/components/rollershutter/__init__.py @@ -13,7 +13,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.components import group from homeassistant.const import ( SERVICE_MOVE_UP, SERVICE_MOVE_DOWN, SERVICE_MOVE_STOP, - STATE_OPEN, ATTR_ENTITY_ID) + STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN, ATTR_ENTITY_ID) DOMAIN = 'rollershutter' @@ -98,6 +98,21 @@ class RollershutterDevice(Entity): """ Represents a rollershutter within Home Assistant. """ # pylint: disable=no-self-use + @property + def current_position(self): + """ Return current position of rollershutter. + None is unknown, 0 is closed, 100 is fully open. """ + raise NotImplementedError() + + @property + def state(self): + current = self.current_position + + if current is None: + return STATE_UNKNOWN + + return STATE_CLOSED if current == 0 else STATE_OPEN + @property def state_attributes(self): """ Returns optional state attributes. """ diff --git a/homeassistant/components/rollershutter/mqtt.py b/homeassistant/components/rollershutter/mqtt.py index ad5a4346bc9..6128a4d9819 100644 --- a/homeassistant/components/rollershutter/mqtt.py +++ b/homeassistant/components/rollershutter/mqtt.py @@ -8,7 +8,6 @@ https://home-assistant.io/components/rollershutter.mqtt/ import logging import homeassistant.components.mqtt as mqtt from homeassistant.components.rollershutter import RollershutterDevice -from homeassistant.const import (STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN) _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['mqtt'] @@ -47,7 +46,7 @@ class MqttRollershutter(RollershutterDevice): """ Represents a rollershutter that can be togggled using MQTT """ def __init__(self, hass, name, state_topic, command_topic, qos, payload_up, payload_down, payload_stop, state_format): - self._state = -1 + self._state = None self._hass = hass self._name = name self._state_topic = state_topic @@ -58,17 +57,20 @@ class MqttRollershutter(RollershutterDevice): self._payload_stop = payload_stop self._parse = mqtt.FmtParser(state_format) - if self._state_topic: - def message_received(topic, payload, qos): - """ A new MQTT message has been received. """ - value = self._parse(payload) - if value.isnumeric(): - if 0 <= int(value) <= 100: - self._state = int(value) - self.update_ha_state() + if self._state_topic is None: + return - mqtt.subscribe(hass, self._state_topic, message_received, - self._qos) + def message_received(topic, payload, qos): + """ A new MQTT message has been received. """ + value = self._parse(payload) + if value.isnumeric() and 0 <= int(value) <= 100: + self._state = int(value) + self.update_ha_state() + else: + _LOGGER.warning( + "Payload is expected to be an integer between 0 and 100") + + mqtt.subscribe(hass, self._state_topic, message_received, self._qos) @property def should_poll(self): @@ -81,19 +83,15 @@ class MqttRollershutter(RollershutterDevice): return self._name @property - def state(self): - """ Returns the state of the device. """ - if self._state == -1: - return STATE_UNKNOWN - elif self._state == 0: - return STATE_CLOSED - else: - return STATE_OPEN + def current_position(self): + """ Return current position of rollershutter. + None is unknown, 0 is closed, 100 is fully open. """ + return self._state @property def is_open(self): """ True if device is open. """ - return self.state == STATE_OPEN + return self._state > 0 def move_up(self, **kwargs): """ Moves the device UP. """ @@ -113,7 +111,7 @@ class MqttRollershutter(RollershutterDevice): @property def state_attributes(self): """ Return the state attributes. """ - state_attr = { - ATTR_CURRENT_POSITION: self._state, - } + state_attr = {} + if self._state is not None: + state_attr[ATTR_CURRENT_POSITION] = self._state return state_attr diff --git a/tests/components/rollershutter/test_mqtt.py b/tests/components/rollershutter/test_mqtt.py index 099d8fad1ea..2a71163c50f 100644 --- a/tests/components/rollershutter/test_mqtt.py +++ b/tests/components/rollershutter/test_mqtt.py @@ -93,9 +93,9 @@ class TestRollershutterMQTT(unittest.TestCase): } })) - current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] - self.assertEqual(-1, current_position) + state_attributes_dict = self.hass.states.get( + 'rollershutter.test').attributes + self.assertFalse('current_position' in state_attributes_dict) fire_mqtt_message(self.hass, 'state-topic', '0') self.hass.pool.block_till_done() @@ -114,3 +114,9 @@ class TestRollershutterMQTT(unittest.TestCase): current_position = self.hass.states.get( 'rollershutter.test').attributes['current_position'] self.assertEqual(50, current_position) + + fire_mqtt_message(self.hass, 'state-topic', 'non-numeric') + self.hass.pool.block_till_done() + current_position = self.hass.states.get( + 'rollershutter.test').attributes['current_position'] + self.assertEqual(50, current_position) From 067b5862c01731df43093085bbee2a514ff96667 Mon Sep 17 00:00:00 2001 From: "nkgilley@gmail.com" Date: Tue, 24 Nov 2015 09:29:33 -0500 Subject: [PATCH 058/166] bug fixes --- homeassistant/components/ecobee.py | 13 ------------- homeassistant/components/sensor/ecobee.py | 10 ++++------ homeassistant/components/thermostat/ecobee.py | 4 ++-- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/ecobee.py b/homeassistant/components/ecobee.py index 8b73a9969ef..03f17133501 100644 --- a/homeassistant/components/ecobee.py +++ b/homeassistant/components/ecobee.py @@ -30,7 +30,6 @@ from homeassistant.loader import get_component from homeassistant import bootstrap from homeassistant.util import Throttle from homeassistant.const import ( - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, CONF_API_KEY) from datetime import timedelta import logging @@ -153,16 +152,4 @@ def setup(hass, config): setup_ecobee(hass, NETWORK.ecobee, config) - def stop_ecobee(event): - """ Stop Ecobee. """ - - pass - - def start_ecobee(event): - """ Called when Home Assistant starts up. """ - - hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_ecobee) - - hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_ecobee) - return True diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py index 524ac912405..a6499949015 100644 --- a/homeassistant/components/sensor/ecobee.py +++ b/homeassistant/components/sensor/ecobee.py @@ -26,7 +26,7 @@ ecobee: """ from homeassistant.helpers.entity import Entity -from homeassistant.components.ecobee import NETWORK +from homeassistant.components import ecobee from homeassistant.const import TEMP_FAHRENHEIT import logging @@ -48,9 +48,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if discovery_info is None: return dev = list() - while NETWORK is None: - continue - for name, data in NETWORK.ecobee.sensors.items(): + for name, data in ecobee.NETWORK.ecobee.sensors.items(): if 'temp' in data: dev.append(EcobeeSensor(name, 'temperature')) if 'humidity' in data: @@ -86,8 +84,8 @@ class EcobeeSensor(Entity): return self._unit_of_measurement def update(self): - NETWORK.update() - data = NETWORK.ecobee.sensors[self.sensor_name] + ecobee.NETWORK.update() + data = ecobee.NETWORK.ecobee.sensors[self.sensor_name] if self.type == 'temperature': self._state = data['temp'] elif self.type == 'humidity': diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 51d21cb9991..78f4d555c9c 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -28,7 +28,7 @@ ecobee: from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) from homeassistant.const import (TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) -from homeassistant.components.ecobee import NETWORK +from homeassistant.components import ecobee import logging DEPENDENCIES = ['ecobee'] @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """ Setup Platform """ if discovery_info is None: return - data = NETWORK + data = ecobee.NETWORK hold_temp = discovery_info['hold_temp'] _LOGGER.info("Loading ecobee thermostat component with hold_temp set to " + str(hold_temp)) From b0fa80ad4c5b84f77432c6fb06253383a7694571 Mon Sep 17 00:00:00 2001 From: Goir Date: Mon, 23 Nov 2015 19:52:08 +0100 Subject: [PATCH 059/166] Added support for Homematic thermostat --- .coveragerc | 1 + .../components/thermostat/homematic.py | 141 ++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 homeassistant/components/thermostat/homematic.py diff --git a/.coveragerc b/.coveragerc index 07d4a8dd4bc..8efc162b3eb 100644 --- a/.coveragerc +++ b/.coveragerc @@ -103,6 +103,7 @@ omit = homeassistant/components/switch/rpi_gpio.py homeassistant/components/switch/transmission.py homeassistant/components/switch/wemo.py + homeassistant/components/thermostat/homematic.py homeassistant/components/thermostat/honeywell.py homeassistant/components/thermostat/nest.py homeassistant/components/thermostat/radiotherm.py diff --git a/homeassistant/components/thermostat/homematic.py b/homeassistant/components/thermostat/homematic.py new file mode 100644 index 00000000000..aea3e34f8c8 --- /dev/null +++ b/homeassistant/components/thermostat/homematic.py @@ -0,0 +1,141 @@ +""" +homeassistant.components.thermostat.homematic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Adds support for Homematic (HM-TC-IT-WM-W-EU, HM-CC-RT-DN) +thermostats using Homegear or Homematic central (CCU1/CCU2). + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/thermostat.homematic/ + +Configuration example: + +thermostat: + platform: homematic + address: HOMEGEAR/CCU ADDRESS (e.g. http://localhost:2001) + devices: + Livingroom 1: + id: DEVICE_SERIAL_NO (e.g. MEQ0791521) + Livingroom 2: + id: DEVICE_SERIAL_NO + +""" +import logging +import socket +from xmlrpc.client import ServerProxy + +from homeassistant.components.thermostat import ThermostatDevice +from homeassistant.const import TEMP_CELCIUS + +REQUIREMENTS = [] + +CONF_ADDRESS = 'address' +CONF_DEVICES = 'devices' +CONF_ID = 'id' +PROPERTY_SET_TEMPERATURE = 'SET_TEMPERATURE' +PROPERTY_VALVE_STATE = 'VALVE_STATE' +PROPERTY_ACTUAL_TEMPERATURE = 'ACTUAL_TEMPERATURE' +PROPERTY_BATTERY_STATE = 'BATTERY_STATE' +PROPERTY_CONTROL_MODE = 'CONTROL_MODE' + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Homematic thermostat. """ + + devices = [] + try: + homegear = ServerProxy(config[CONF_ADDRESS]) + for name, device_cfg in config[CONF_DEVICES].items(): + # get device description to detect the type + device_type = homegear.getDeviceDescription( + device_cfg[CONF_ID] + ':-1')['TYPE'] + + if device_type in ['HM-CC-RT-DN', 'HM-CC-RT-DN-BoM']: + devices.append(HomematicThermostat(homegear, + device_cfg[CONF_ID], + name, 4)) + elif device_type == 'HM-TC-IT-WM-W-EU': + devices.append(HomematicThermostat(homegear, + device_cfg[CONF_ID], + name, 2)) + else: + raise ValueError( + "Device Type '{}' currently not supported".format( + device_type)) + except socket.error: + _LOGGER.exception("Connection error to homematic web service") + return False + + add_devices(devices) + + return True + + +# pylint: disable=too-many-instance-attributes +class HomematicThermostat(ThermostatDevice): + """ Represents a Homematic thermostat. """ + + def __init__(self, device, _id, name, channel): + self.device = device + self._id = _id + self._channel = channel + self._name = name + self._full_device_name = '{}:{}'.format(self._id, self._channel) + + self._current_temperature = None + self._target_temperature = None + self._valve = None + self._battery = None + self._mode = None + self.update() + + @property + def name(self): + """ Returns the name of the Homematic device. """ + return self._name + + @property + def unit_of_measurement(self): + """ Unit of measurement this thermostat expresses itself in. """ + return TEMP_CELCIUS + + @property + def current_temperature(self): + """ Returns the current temperature. """ + return self._current_temperature + + @property + def target_temperature(self): + """ Returns the temperature we try to reach. """ + return self._target_temperature + + def set_temperature(self, temperature): + """ Set new target temperature """ + self.device.setValue(self._full_device_name, + PROPERTY_SET_TEMPERATURE, + temperature) + + @property + def device_state_attributes(self): + return {"valve": self._valve, + "battery": self._battery, + "mode": self._mode} + + def update(self): + try: + self._current_temperature = self.device.getValue( + self._full_device_name, + PROPERTY_ACTUAL_TEMPERATURE) + self._target_temperature = self.device.getValue( + self._full_device_name, + PROPERTY_SET_TEMPERATURE) + self._valve = self.device.getValue(self._full_device_name, + PROPERTY_VALVE_STATE) + self._battery = self.device.getValue(self._full_device_name, + PROPERTY_BATTERY_STATE) + self._mode = self.device.getValue(self._full_device_name, + PROPERTY_CONTROL_MODE) + except socket.error: + _LOGGER.exception("Did not receive any temperature data from the " + "homematic API.") From bc106bcb108476eb1e575854b3b2ea6374c427ca Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 08:48:27 +0100 Subject: [PATCH 060/166] Move configuration details to docs --- .../components/thermostat/homematic.py | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/thermostat/homematic.py b/homeassistant/components/thermostat/homematic.py index aea3e34f8c8..ab81e368589 100644 --- a/homeassistant/components/thermostat/homematic.py +++ b/homeassistant/components/thermostat/homematic.py @@ -1,23 +1,11 @@ """ homeassistant.components.thermostat.homematic ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Adds support for Homematic (HM-TC-IT-WM-W-EU, HM-CC-RT-DN) -thermostats using Homegear or Homematic central (CCU1/CCU2). +Adds support for Homematic (HM-TC-IT-WM-W-EU, HM-CC-RT-DN) thermostats using +Homegear or Homematic central (CCU1/CCU2). For more details about this platform, please refer to the documentation at https://home-assistant.io/components/thermostat.homematic/ - -Configuration example: - -thermostat: - platform: homematic - address: HOMEGEAR/CCU ADDRESS (e.g. http://localhost:2001) - devices: - Livingroom 1: - id: DEVICE_SERIAL_NO (e.g. MEQ0791521) - Livingroom 2: - id: DEVICE_SERIAL_NO - """ import logging import socket @@ -111,18 +99,20 @@ class HomematicThermostat(ThermostatDevice): return self._target_temperature def set_temperature(self, temperature): - """ Set new target temperature """ + """ Set new target temperature. """ self.device.setValue(self._full_device_name, PROPERTY_SET_TEMPERATURE, temperature) @property def device_state_attributes(self): + """ Returns device specific state attributes. """ return {"valve": self._valve, "battery": self._battery, "mode": self._mode} def update(self): + """ Update the data from the thermostat. """ try: self._current_temperature = self.device.getValue( self._full_device_name, From 3e60c4801c74f02fe8257c9cd9815b191c9017f6 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 08:56:50 +0100 Subject: [PATCH 061/166] Update docstrings --- homeassistant/components/ifttt.py | 4 +-- homeassistant/components/mqtt/__init__.py | 8 +++--- homeassistant/components/notify/pushbullet.py | 10 ++++---- homeassistant/components/recorder.py | 25 +++++++++++-------- homeassistant/components/switch/mqtt.py | 2 +- .../components/thermostat/honeywell.py | 1 + .../components/thermostat/radiotherm.py | 1 + homeassistant/components/zwave.py | 4 +-- 8 files changed, 30 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/ifttt.py b/homeassistant/components/ifttt.py index 246265a5268..da1b377b078 100644 --- a/homeassistant/components/ifttt.py +++ b/homeassistant/components/ifttt.py @@ -28,7 +28,7 @@ REQUIREMENTS = ['pyfttt==0.3'] def trigger(hass, event, value1=None, value2=None, value3=None): - """ Trigger a Maker IFTTT recipe """ + """ Trigger a Maker IFTTT recipe. """ data = { ATTR_EVENT: event, ATTR_VALUE1: value1, @@ -39,7 +39,7 @@ def trigger(hass, event, value1=None, value2=None, value3=None): def setup(hass, config): - """ Setup the ifttt service component """ + """ Setup the ifttt service component. """ if not validate_config(config, {DOMAIN: ['key']}, _LOGGER): return False diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 7f4ff030d36..b8dc8909887 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -132,7 +132,7 @@ def setup(hass, config): # pylint: disable=too-few-public-methods class _JsonFmtParser(object): - """ Implements a json parser on xpath""" + """ Implements a json parser on xpath. """ def __init__(self, jsonpath): import jsonpath_rw self._expr = jsonpath_rw.parse(jsonpath) @@ -144,7 +144,7 @@ class _JsonFmtParser(object): # pylint: disable=too-few-public-methods class FmtParser(object): - """ wrapper for all supported formats """ + """ Wrapper for all supported formats. """ def __init__(self, fmt): self._parse = lambda x: x if fmt: @@ -252,7 +252,7 @@ def _mqtt_on_connect(mqttc, userdata, flags, result_code): def _mqtt_on_subscribe(mqttc, userdata, mid, granted_qos): - """ Called when subscribe successfull. """ + """ Called when subscribe successful. """ topic = userdata['progress'].pop(mid, None) if topic is None: return @@ -260,7 +260,7 @@ def _mqtt_on_subscribe(mqttc, userdata, mid, granted_qos): def _mqtt_on_unsubscribe(mqttc, userdata, mid, granted_qos): - """ Called when subscribe successfull. """ + """ Called when subscribe successful. """ topic = userdata['progress'].pop(mid, None) if topic is None: return diff --git a/homeassistant/components/notify/pushbullet.py b/homeassistant/components/notify/pushbullet.py index 16c4e4192eb..5dc97a399b5 100644 --- a/homeassistant/components/notify/pushbullet.py +++ b/homeassistant/components/notify/pushbullet.py @@ -47,16 +47,16 @@ class PushBulletNotificationService(BaseNotificationService): self.refresh() def refresh(self): - ''' + """ Refresh devices, contacts, etc pbtargets stores all targets available from this pushbullet instance into a dict. These are PB objects!. It sacrifices a bit of memory - for faster processing at send_message + for faster processing at send_message. As of sept 2015, contacts were replaced by chats. This is not - implemented in the module yet - ''' + implemented in the module yet. + """ self.pushbullet.refresh() self.pbtargets = { 'device': { @@ -72,7 +72,7 @@ class PushBulletNotificationService(BaseNotificationService): If no target specified, a 'normal' push will be sent to all devices linked to the PB account. Email is special, these are assumed to always exist. We use a special - call which doesn't require a push object + call which doesn't require a push object. """ targets = kwargs.get(ATTR_TARGET) title = kwargs.get(ATTR_TITLE) diff --git a/homeassistant/components/recorder.py b/homeassistant/components/recorder.py index b09e10f7d92..f654f035857 100644 --- a/homeassistant/components/recorder.py +++ b/homeassistant/components/recorder.py @@ -59,7 +59,7 @@ def query_events(event_query, arguments=None): def row_to_state(row): - """ Convert a databsae row to a state. """ + """ Convert a database row to a state. """ try: return State( row[1], row[2], json.loads(row[3]), @@ -83,8 +83,9 @@ def row_to_event(row): def run_information(point_in_time=None): - """ Returns information about current run or the run that - covers point_in_time. """ + """ + Returns information about current run or the run that covers point_in_time. + """ _verify_instance() if point_in_time is None or point_in_time > _INSTANCE.recording_start: @@ -142,8 +143,10 @@ class RecorderRun(object): @property def where_after_start_run(self): - """ Returns SQL WHERE clause to select rows - created after the start of the run. """ + """ + Returns SQL WHERE clause to select rows created after the start of the + run. + """ return "created >= {} ".format(_adapt_datetime(self.start)) @property @@ -158,9 +161,7 @@ class RecorderRun(object): class Recorder(threading.Thread): - """ - Threaded recorder - """ + """ Threaded recorder class """ def __init__(self, hass): threading.Thread.__init__(self) @@ -208,8 +209,10 @@ class Recorder(threading.Thread): self.queue.task_done() def event_listener(self, event): - """ Listens for new events on the EventBus and puts them - in the process queue. """ + """ + Listens for new events on the EventBus and puts them in the process + queue. + """ self.queue.put(event) def shutdown(self, event): @@ -433,6 +436,6 @@ def _adapt_datetime(datetimestamp): def _verify_instance(): - """ throws error if recorder not initialized. """ + """ Throws error if recorder not initialized. """ if _INSTANCE is None: raise RuntimeError("Recorder not initialized.") diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index ed99a87868a..43bceab69a5 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): # pylint: disable=too-many-arguments, too-many-instance-attributes class MqttSwitch(SwitchDevice): - """ Represents a switch that can be togggled using MQTT. """ + """ Represents a switch that can be toggled using MQTT. """ def __init__(self, hass, name, state_topic, command_topic, qos, payload_on, payload_off, optimistic, state_format): self._state = False diff --git a/homeassistant/components/thermostat/honeywell.py b/homeassistant/components/thermostat/honeywell.py index 56880c4eded..2d724502d85 100644 --- a/homeassistant/components/thermostat/honeywell.py +++ b/homeassistant/components/thermostat/honeywell.py @@ -74,6 +74,7 @@ class RoundThermostat(ThermostatDevice): self.device.set_temperature(self._name, temperature) def update(self): + """ Update the data from the thermostat. """ try: # Only take first thermostat data from API for now data = next(self.device.temperatures(force_refresh=True)) diff --git a/homeassistant/components/thermostat/radiotherm.py b/homeassistant/components/thermostat/radiotherm.py index 748d0421acd..051a2a6413e 100644 --- a/homeassistant/components/thermostat/radiotherm.py +++ b/homeassistant/components/thermostat/radiotherm.py @@ -101,6 +101,7 @@ class RadioThermostat(ThermostatDevice): return round(self._target_temperature, 1) def update(self): + """ Update the data from the thermostat. """ self._current_temperature = self.device.temp['raw'] self._name = self.device.name['raw'] if self.device.tmode['human'] == 'Cool': diff --git a/homeassistant/components/zwave.py b/homeassistant/components/zwave.py index 11515e4031d..e21c339fb23 100644 --- a/homeassistant/components/zwave.py +++ b/homeassistant/components/zwave.py @@ -83,7 +83,7 @@ def _obj_to_dict(obj): def nice_print_node(node): - """ Prints a nice formatted node to the output (debug method) """ + """ Prints a nice formatted node to the output (debug method). """ node_dict = _obj_to_dict(node) node_dict['values'] = {value_id: _obj_to_dict(value) for value_id, value in node.values.items()} @@ -95,7 +95,7 @@ def nice_print_node(node): def get_config_value(node, value_index): - """ Returns the current config value for a specific index """ + """ Returns the current config value for a specific index. """ try: for value in node.values.values(): From a8ddae9343683ca69067eecbece5ecff6d4e5d1d Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 17:21:11 +0100 Subject: [PATCH 062/166] Add myStrom switch platform --- homeassistant/components/switch/mystrom.py | 103 +++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 homeassistant/components/switch/mystrom.py diff --git a/homeassistant/components/switch/mystrom.py b/homeassistant/components/switch/mystrom.py new file mode 100644 index 00000000000..86cd6686f1e --- /dev/null +++ b/homeassistant/components/switch/mystrom.py @@ -0,0 +1,103 @@ +""" +homeassistant.components.switch.mystrom +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for myStrom switches. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/switch.mystrom/ +""" +import logging +import requests + +from homeassistant.components.switch import SwitchDevice +from homeassistant.const import STATE_UNKNOWN + +DEFAULT_NAME = 'myStrom Switch' + +_LOGGER = logging.getLogger(__name__) + + +# pylint: disable=unused-argument, too-many-function-args +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Find and return myStrom switches. """ + resource = config.get('resource') + + if resource is None: + _LOGGER.error('Missing required variable: resource') + return False + + try: + requests.get(resource, timeout=10) + except requests.exceptions.MissingSchema: + _LOGGER.error("Missing resource or schema in configuration. " + "Add http:// to your URL.") + return False + except requests.exceptions.ConnectionError: + _LOGGER.error("No route to device. " + "Please check the IP address in the configuration file.") + return False + + add_devices([MyStromSwitch( + config.get('name', DEFAULT_NAME), + config.get('resource'))]) + + +class MyStromSwitch(SwitchDevice): + """ Represents a myStrom switch. """ + def __init__(self, name, resource): + self._state = STATE_UNKNOWN + self._name = name + self._resource = resource + self.consumption = 0 + + @property + def name(self): + """ The name of the switch. """ + return self._name + + @property + def is_on(self): + """ True if switch is on. """ + return self._state + + @property + def current_power_mwh(self): + """ Current power consumption in mwh. """ + return self.consumption + + def turn_on(self, **kwargs): + """ Turn the switch on. """ + request = requests.get('{}/relay'.format(self._resource), + params={'state': '1'}, + timeout=10) + if request.status_code == 200: + self._state = True + else: + _LOGGER.error("Can't turn on %s. Is device offline?", + self._resource) + + def turn_off(self, **kwargs): + """ Turn the switch off. """ + request = requests.get('{}/relay'.format(self._resource), + params={'state': '0'}, + timeout=10) + if request.status_code == 200: + self._state = False + else: + _LOGGER.error("Can't turn off %s. Is device offline?", + self._resource) + + def update(self): + """ Gets the latest data from REST API and updates the state. """ + try: + request = requests.get('{}/report'.format(self._resource), + timeout=10) + if request.json()['relay'] is True: + self._state = True + else: + self._state = False + + self.consumption = request.json()['power'] + except requests.exceptions.ConnectionError: + _LOGGER.error("No route to device '%s'. Is device offline?", + self._resource) From 9dfa4ea2339c0ff4303ddbd8540d56984f918b02 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 17:21:31 +0100 Subject: [PATCH 063/166] Add mystrom switch --- .coveragerc | 1 + 1 file changed, 1 insertion(+) diff --git a/.coveragerc b/.coveragerc index 8efc162b3eb..22e8116693c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -98,6 +98,7 @@ omit = homeassistant/components/switch/command_switch.py homeassistant/components/switch/edimax.py homeassistant/components/switch/hikvisioncam.py + homeassistant/components/switch/mystrom.py homeassistant/components/switch/orvibo.py homeassistant/components/switch/rest.py homeassistant/components/switch/rpi_gpio.py From e45ef0013b3c7f551e84200c5f12e3b5b5d2229e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 18:07:29 +0100 Subject: [PATCH 064/166] Catch connection timeout --- homeassistant/components/switch/mystrom.py | 37 +++++++++++++--------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/switch/mystrom.py b/homeassistant/components/switch/mystrom.py index 86cd6686f1e..48f47b41ed6 100644 --- a/homeassistant/components/switch/mystrom.py +++ b/homeassistant/components/switch/mystrom.py @@ -10,7 +10,6 @@ import logging import requests from homeassistant.components.switch import SwitchDevice -from homeassistant.const import STATE_UNKNOWN DEFAULT_NAME = 'myStrom Switch' @@ -45,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class MyStromSwitch(SwitchDevice): """ Represents a myStrom switch. """ def __init__(self, name, resource): - self._state = STATE_UNKNOWN + self._state = False self._name = name self._resource = resource self.consumption = 0 @@ -67,24 +66,32 @@ class MyStromSwitch(SwitchDevice): def turn_on(self, **kwargs): """ Turn the switch on. """ - request = requests.get('{}/relay'.format(self._resource), - params={'state': '1'}, - timeout=10) - if request.status_code == 200: - self._state = True - else: + try: + request = requests.get('{}/relay'.format(self._resource), + params={'state': '1'}, + timeout=10) + if request.status_code == 200: + self._state = True + else: + raise requests.exceptions.ConnectionError + + except requests.exceptions.ConnectionError: _LOGGER.error("Can't turn on %s. Is device offline?", self._resource) def turn_off(self, **kwargs): """ Turn the switch off. """ - request = requests.get('{}/relay'.format(self._resource), - params={'state': '0'}, - timeout=10) - if request.status_code == 200: - self._state = False - else: - _LOGGER.error("Can't turn off %s. Is device offline?", + try: + request = requests.get('{}/relay'.format(self._resource), + params={'state': '0'}, + timeout=10) + if request.status_code == 200: + self._state = False + else: + raise requests.exceptions.ConnectionError + + except requests.exceptions.ConnectionError: + _LOGGER.error("Can't turn on %s. Is device offline?", self._resource) def update(self): From 1bebb17e9ff5dc9b67a173b80bc76237a8273841 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 18:14:19 +0100 Subject: [PATCH 065/166] Not need to raise exception --- homeassistant/components/switch/mystrom.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/homeassistant/components/switch/mystrom.py b/homeassistant/components/switch/mystrom.py index 48f47b41ed6..3acbfb24ce6 100644 --- a/homeassistant/components/switch/mystrom.py +++ b/homeassistant/components/switch/mystrom.py @@ -72,9 +72,6 @@ class MyStromSwitch(SwitchDevice): timeout=10) if request.status_code == 200: self._state = True - else: - raise requests.exceptions.ConnectionError - except requests.exceptions.ConnectionError: _LOGGER.error("Can't turn on %s. Is device offline?", self._resource) @@ -87,9 +84,6 @@ class MyStromSwitch(SwitchDevice): timeout=10) if request.status_code == 200: self._state = False - else: - raise requests.exceptions.ConnectionError - except requests.exceptions.ConnectionError: _LOGGER.error("Can't turn on %s. Is device offline?", self._resource) From 08ba71a35931f4f37ae3a094dcf3623c65c5b9da Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 25 Nov 2015 18:13:39 +0000 Subject: [PATCH 066/166] rename component to motor and services to open/close/stop --- homeassistant/components/motor/__init__.py | 130 +++++++++++++++++ .../{rollershutter => motor}/mqtt.py | 52 +++---- .../{rollershutter => motor}/services.yaml | 0 .../components/rollershutter/__init__.py | 131 ------------------ .../{rollershutter => motor}/__init__.py | 0 .../{rollershutter => motor}/test_mqtt.py | 56 ++++---- 6 files changed, 184 insertions(+), 185 deletions(-) create mode 100644 homeassistant/components/motor/__init__.py rename homeassistant/components/{rollershutter => motor}/mqtt.py (71%) rename homeassistant/components/{rollershutter => motor}/services.yaml (100%) delete mode 100644 homeassistant/components/rollershutter/__init__.py rename tests/components/{rollershutter => motor}/__init__.py (100%) rename tests/components/{rollershutter => motor}/test_mqtt.py (67%) diff --git a/homeassistant/components/motor/__init__.py b/homeassistant/components/motor/__init__.py new file mode 100644 index 00000000000..feea836a0dd --- /dev/null +++ b/homeassistant/components/motor/__init__.py @@ -0,0 +1,130 @@ +""" +homeassistant.components.motor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Motor component. + +""" +import os +import logging + +from homeassistant.config import load_yaml_config_file +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.entity import Entity +from homeassistant.components import group +from homeassistant.const import ( + SERVICE_OPEN, SERVICE_CLOSE, SERVICE_STOP, + STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN, ATTR_ENTITY_ID) + + +DOMAIN = 'motor' +DEPENDENCIES = [] +SCAN_INTERVAL = 15 + +GROUP_NAME_ALL_MOTORS = 'all motors' +ENTITY_ID_ALL_MOTORS = group.ENTITY_ID_FORMAT.format('all_motors') + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + +# Maps discovered services to their platforms +DISCOVERY_PLATFORMS = {} + +_LOGGER = logging.getLogger(__name__) + + +def is_open(hass, entity_id=None): + """ Returns if the motor is open based on the statemachine. """ + entity_id = entity_id or ENTITY_ID_ALL_MOTORS + return hass.states.is_state(entity_id, STATE_OPEN) + + +def call_open(hass, entity_id=None): + """ Open all or specified motor. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_OPEN, data) + + +def call_close(hass, entity_id=None): + """ Close all or specified motor. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_CLOSE, data) + + +def call_stop(hass, entity_id=None): + """ Stops all or specified motor. """ + data = {ATTR_ENTITY_ID: entity_id} if entity_id else None + hass.services.call(DOMAIN, SERVICE_STOP, data) + + +def setup(hass, config): + """ Track states and offer events for motors. """ + component = EntityComponent( + _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, + GROUP_NAME_ALL_MOTORS) + component.setup(config) + + def handle_motor_service(service): + """ Handles calls to the motor services. """ + target_motors = component.extract_from_service(service) + + for motor in target_motors: + if service.service == SERVICE_OPEN: + motor.open() + elif service.service == SERVICE_CLOSE: + motor.close() + elif service.service == SERVICE_STOP: + motor.stop() + + if motor.should_poll: + motor.update_ha_state(True) + + descriptions = load_yaml_config_file( + os.path.join(os.path.dirname(__file__), 'services.yaml')) + + hass.services.register(DOMAIN, SERVICE_OPEN, + handle_motor_service, + descriptions.get(SERVICE_OPEN)) + hass.services.register(DOMAIN, SERVICE_CLOSE, + handle_motor_service, + descriptions.get(SERVICE_CLOSE)) + hass.services.register(DOMAIN, SERVICE_STOP, + handle_motor_service, + descriptions.get(SERVICE_STOP)) + + return True + + +class MotorDevice(Entity): + """ Represents a motor within Home Assistant. """ + # pylint: disable=no-self-use + + @property + def current_position(self): + """ Return current position of motor. + None is unknown, 0 is closed, 100 is fully open. """ + raise NotImplementedError() + + @property + def state(self): + current = self.current_position + + if current is None: + return STATE_UNKNOWN + + return STATE_CLOSED if current == 0 else STATE_OPEN + + @property + def state_attributes(self): + """ Returns optional state attributes. """ + return None + + def open(self, **kwargs): + """ Open the device. """ + raise NotImplementedError() + + def close(self, **kwargs): + """ Close the device. """ + raise NotImplementedError() + + def stop(self, **kwargs): + """ Stop the device. """ + raise NotImplementedError() diff --git a/homeassistant/components/rollershutter/mqtt.py b/homeassistant/components/motor/mqtt.py similarity index 71% rename from homeassistant/components/rollershutter/mqtt.py rename to homeassistant/components/motor/mqtt.py index 6128a4d9819..48a20d5a3b6 100644 --- a/homeassistant/components/rollershutter/mqtt.py +++ b/homeassistant/components/motor/mqtt.py @@ -1,21 +1,21 @@ """ -homeassistant.components.rollershutter.mqtt +homeassistant.components.motor.mqtt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Allows to configure a MQTT rollershutter. +Allows to configure a MQTT motor. For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/rollershutter.mqtt/ +https://home-assistant.io/components/motor.mqtt/ """ import logging import homeassistant.components.mqtt as mqtt -from homeassistant.components.rollershutter import RollershutterDevice +from homeassistant.components.motor import MotorDevice _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['mqtt'] -DEFAULT_NAME = "MQTT Shutter" +DEFAULT_NAME = "MQTT Motor" DEFAULT_QOS = 0 -DEFAULT_PAYLOAD_UP = "UP" -DEFAULT_PAYLOAD_DOWN = "DOWN" +DEFAULT_PAYLOAD_OPEN = "OPEN" +DEFAULT_PAYLOAD_CLOSE = "CLOSE" DEFAULT_PAYLOAD_STOP = "STOP" ATTR_CURRENT_POSITION = 'current_position' @@ -23,37 +23,37 @@ ATTR_CURRENT_POSITION = 'current_position' # pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """ Add MQTT Roller Shutter """ + """ Add MQTT Motor """ if config.get('command_topic') is None: _LOGGER.error("Missing required variable: command_topic") return False - add_devices_callback([MqttRollershutter( + add_devices_callback([MqttMotor( hass, config.get('name', DEFAULT_NAME), config.get('state_topic'), config.get('command_topic'), config.get('qos', DEFAULT_QOS), - config.get('payload_up', DEFAULT_PAYLOAD_UP), - config.get('payload_down', DEFAULT_PAYLOAD_DOWN), + config.get('payload_open', DEFAULT_PAYLOAD_OPEN), + config.get('payload_close', DEFAULT_PAYLOAD_CLOSE), config.get('payload_stop', DEFAULT_PAYLOAD_STOP), config.get('state_format'))]) # pylint: disable=too-many-arguments, too-many-instance-attributes -class MqttRollershutter(RollershutterDevice): - """ Represents a rollershutter that can be togggled using MQTT """ +class MqttMotor(MotorDevice): + """ Represents a motor that can be controlled using MQTT """ def __init__(self, hass, name, state_topic, command_topic, qos, - payload_up, payload_down, payload_stop, state_format): + payload_open, payload_close, payload_stop, state_format): self._state = None self._hass = hass self._name = name self._state_topic = state_topic self._command_topic = command_topic self._qos = qos - self._payload_up = payload_up - self._payload_down = payload_down + self._payload_open = payload_open + self._payload_close = payload_close self._payload_stop = payload_stop self._parse = mqtt.FmtParser(state_format) @@ -79,12 +79,12 @@ class MqttRollershutter(RollershutterDevice): @property def name(self): - """ The name of the rollershutter """ + """ The name of the motor """ return self._name @property def current_position(self): - """ Return current position of rollershutter. + """ Return current position of motor. None is unknown, 0 is closed, 100 is fully open. """ return self._state @@ -93,18 +93,18 @@ class MqttRollershutter(RollershutterDevice): """ True if device is open. """ return self._state > 0 - def move_up(self, **kwargs): - """ Moves the device UP. """ - mqtt.publish(self.hass, self._command_topic, self._payload_up, + def open(self, **kwargs): + """ Close the device. """ + mqtt.publish(self.hass, self._command_topic, self._payload_open, self._qos) - def move_down(self, **kwargs): - """ Moves the device DOWN. """ - mqtt.publish(self.hass, self._command_topic, self._payload_down, + def close(self, **kwargs): + """ Open the device. """ + mqtt.publish(self.hass, self._command_topic, self._payload_close, self._qos) - def move_stop(self, **kwargs): - """ Moves the device to STOP. """ + def stop(self, **kwargs): + """ Stop the device. """ mqtt.publish(self.hass, self._command_topic, self._payload_stop, self._qos) diff --git a/homeassistant/components/rollershutter/services.yaml b/homeassistant/components/motor/services.yaml similarity index 100% rename from homeassistant/components/rollershutter/services.yaml rename to homeassistant/components/motor/services.yaml diff --git a/homeassistant/components/rollershutter/__init__.py b/homeassistant/components/rollershutter/__init__.py deleted file mode 100644 index 5ebcf8a3d21..00000000000 --- a/homeassistant/components/rollershutter/__init__.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -homeassistant.components.rollershutter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Rollershutter component. - -""" -import os -import logging - -from homeassistant.config import load_yaml_config_file -from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.helpers.entity import Entity -from homeassistant.components import group -from homeassistant.const import ( - SERVICE_MOVE_UP, SERVICE_MOVE_DOWN, SERVICE_MOVE_STOP, - STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN, ATTR_ENTITY_ID) - - -DOMAIN = 'rollershutter' -DEPENDENCIES = [] -SCAN_INTERVAL = 15 - -GROUP_NAME_ALL_ROLLERSHUTTERS = 'all rollershutters' -ENTITY_ID_ALL_ROLLERSHUTTERS = group.ENTITY_ID_FORMAT.format( - 'all_rollershutters') - -ENTITY_ID_FORMAT = DOMAIN + '.{}' - -# Maps discovered services to their platforms -DISCOVERY_PLATFORMS = {} - -_LOGGER = logging.getLogger(__name__) - - -def is_open(hass, entity_id=None): - """ Returns if the rollershutter is open based on the statemachine. """ - entity_id = entity_id or ENTITY_ID_ALL_ROLLERSHUTTERS - return hass.states.is_state(entity_id, STATE_OPEN) - - -def move_up(hass, entity_id=None): - """ Moves all or specified rollershutter up. """ - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_MOVE_UP, data) - - -def move_down(hass, entity_id=None): - """ Moves all or specified rollershutter down. """ - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_MOVE_DOWN, data) - - -def move_stop(hass, entity_id=None): - """ Stops all or specified rollershutter. """ - data = {ATTR_ENTITY_ID: entity_id} if entity_id else None - hass.services.call(DOMAIN, SERVICE_MOVE_STOP, data) - - -def setup(hass, config): - """ Track states and offer events for rollershutters. """ - component = EntityComponent( - _LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS, - GROUP_NAME_ALL_ROLLERSHUTTERS) - component.setup(config) - - def handle_rollershutter_service(service): - """ Handles calls to the rollershutter services. """ - target_rollershutters = component.extract_from_service(service) - - for rollershutter in target_rollershutters: - if service.service == SERVICE_MOVE_UP: - rollershutter.move_up() - elif service.service == SERVICE_MOVE_DOWN: - rollershutter.move_down() - elif service.service == SERVICE_MOVE_STOP: - rollershutter.move_stop() - - if rollershutter.should_poll: - rollershutter.update_ha_state(True) - - descriptions = load_yaml_config_file( - os.path.join(os.path.dirname(__file__), 'services.yaml')) - - hass.services.register(DOMAIN, SERVICE_MOVE_UP, - handle_rollershutter_service, - descriptions.get(SERVICE_MOVE_UP)) - hass.services.register(DOMAIN, SERVICE_MOVE_DOWN, - handle_rollershutter_service, - descriptions.get(SERVICE_MOVE_DOWN)) - hass.services.register(DOMAIN, SERVICE_MOVE_STOP, - handle_rollershutter_service, - descriptions.get(SERVICE_MOVE_STOP)) - - return True - - -class RollershutterDevice(Entity): - """ Represents a rollershutter within Home Assistant. """ - # pylint: disable=no-self-use - - @property - def current_position(self): - """ Return current position of rollershutter. - None is unknown, 0 is closed, 100 is fully open. """ - raise NotImplementedError() - - @property - def state(self): - current = self.current_position - - if current is None: - return STATE_UNKNOWN - - return STATE_CLOSED if current == 0 else STATE_OPEN - - @property - def state_attributes(self): - """ Returns optional state attributes. """ - return None - - def move_up(self, **kwargs): - """ Moves the device UP. """ - raise NotImplementedError() - - def move_down(self, **kwargs): - """ Moves the device DOWN. """ - raise NotImplementedError() - - def move_stop(self, **kwargs): - """ Moves the device to STOP. """ - raise NotImplementedError() diff --git a/tests/components/rollershutter/__init__.py b/tests/components/motor/__init__.py similarity index 100% rename from tests/components/rollershutter/__init__.py rename to tests/components/motor/__init__.py diff --git a/tests/components/rollershutter/test_mqtt.py b/tests/components/motor/test_mqtt.py similarity index 67% rename from tests/components/rollershutter/test_mqtt.py rename to tests/components/motor/test_mqtt.py index 2a71163c50f..4d7af04ae6c 100644 --- a/tests/components/rollershutter/test_mqtt.py +++ b/tests/components/motor/test_mqtt.py @@ -1,19 +1,19 @@ """ -tests.components.rollershutter.test_mqtt +tests.components.motor.test_mqtt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Tests mqtt rollershutter. +Tests mqtt motor. """ import unittest from homeassistant.const import STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN import homeassistant.core as ha -import homeassistant.components.rollershutter as rollershutter +import homeassistant.components.motor as motor from tests.common import mock_mqtt_component, fire_mqtt_message -class TestRollershutterMQTT(unittest.TestCase): - """ Test the MQTT rollershutter. """ +class TestMotorMQTT(unittest.TestCase): + """ Test the MQTT motor. """ def setUp(self): # pylint: disable=invalid-name self.hass = ha.HomeAssistant() @@ -24,43 +24,43 @@ class TestRollershutterMQTT(unittest.TestCase): self.hass.stop() def test_controlling_state_via_topic(self): - self.assertTrue(rollershutter.setup(self.hass, { - 'rollershutter': { + self.assertTrue(motor.setup(self.hass, { + 'motor': { 'platform': 'mqtt', 'name': 'test', 'state_topic': 'state-topic', 'command_topic': 'command-topic', 'qos': 0, - 'payload_up': 'UP', - 'payload_down': 'DOWN', + 'payload_open': 'OPEN', + 'payload_close': 'CLOSE', 'payload_stop': 'STOP' } })) - state = self.hass.states.get('rollershutter.test') + state = self.hass.states.get('motor.test') self.assertEqual(STATE_UNKNOWN, state.state) fire_mqtt_message(self.hass, 'state-topic', '0') self.hass.pool.block_till_done() - state = self.hass.states.get('rollershutter.test') + state = self.hass.states.get('motor.test') self.assertEqual(STATE_CLOSED, state.state) fire_mqtt_message(self.hass, 'state-topic', '50') self.hass.pool.block_till_done() - state = self.hass.states.get('rollershutter.test') + state = self.hass.states.get('motor.test') self.assertEqual(STATE_OPEN, state.state) fire_mqtt_message(self.hass, 'state-topic', '100') self.hass.pool.block_till_done() - state = self.hass.states.get('rollershutter.test') + state = self.hass.states.get('motor.test') self.assertEqual(STATE_OPEN, state.state) def test_sending_mqtt_commands(self): - self.assertTrue(rollershutter.setup(self.hass, { - 'rollershutter': { + self.assertTrue(motor.setup(self.hass, { + 'motor': { 'platform': 'mqtt', 'name': 'test', 'state_topic': 'state-topic', @@ -69,54 +69,54 @@ class TestRollershutterMQTT(unittest.TestCase): } })) - state = self.hass.states.get('rollershutter.test') + state = self.hass.states.get('motor.test') self.assertEqual(STATE_UNKNOWN, state.state) - rollershutter.move_up(self.hass, 'rollershutter.test') + motor.call_open(self.hass, 'motor.test') self.hass.pool.block_till_done() - self.assertEqual(('command-topic', 'UP', 2), + self.assertEqual(('command-topic', 'OPEN', 2), self.mock_publish.mock_calls[-1][1]) - state = self.hass.states.get('rollershutter.test') + state = self.hass.states.get('motor.test') self.assertEqual(STATE_UNKNOWN, state.state) def test_state_attributes_current_position(self): - self.assertTrue(rollershutter.setup(self.hass, { - 'rollershutter': { + self.assertTrue(motor.setup(self.hass, { + 'motor': { 'platform': 'mqtt', 'name': 'test', 'state_topic': 'state-topic', 'command_topic': 'command-topic', - 'payload_up': 'UP', - 'payload_down': 'DOWN', + 'payload_open': 'OPEN', + 'payload_close': 'CLOSE', 'payload_stop': 'STOP' } })) state_attributes_dict = self.hass.states.get( - 'rollershutter.test').attributes + 'motor.test').attributes self.assertFalse('current_position' in state_attributes_dict) fire_mqtt_message(self.hass, 'state-topic', '0') self.hass.pool.block_till_done() current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] + 'motor.test').attributes['current_position'] self.assertEqual(0, current_position) fire_mqtt_message(self.hass, 'state-topic', '50') self.hass.pool.block_till_done() current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] + 'motor.test').attributes['current_position'] self.assertEqual(50, current_position) fire_mqtt_message(self.hass, 'state-topic', '101') self.hass.pool.block_till_done() current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] + 'motor.test').attributes['current_position'] self.assertEqual(50, current_position) fire_mqtt_message(self.hass, 'state-topic', 'non-numeric') self.hass.pool.block_till_done() current_position = self.hass.states.get( - 'rollershutter.test').attributes['current_position'] + 'motor.test').attributes['current_position'] self.assertEqual(50, current_position) From 0dbf4b3c10e92ec207c3e5288646186b12196b90 Mon Sep 17 00:00:00 2001 From: sfam Date: Wed, 25 Nov 2015 18:20:16 +0000 Subject: [PATCH 067/166] add const.py changes to commit --- homeassistant/const.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index add1848b72c..1513c188cc2 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -143,9 +143,9 @@ SERVICE_ALARM_TRIGGER = "alarm_trigger" SERVICE_LOCK = "lock" SERVICE_UNLOCK = "unlock" -SERVICE_MOVE_UP = 'move_up' -SERVICE_MOVE_DOWN = 'move_down' -SERVICE_MOVE_STOP = 'move_stop' +SERVICE_OPEN = 'open' +SERVICE_CLOSE = 'close' +SERVICE_STOP = 'stop' # #### API / REMOTE #### SERVER_PORT = 8123 From 76ac913fc0862421b7e4ef1f32994c8084a21f86 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 21 Nov 2015 19:01:47 +0100 Subject: [PATCH 068/166] Add influx component --- homeassistant/components/influx.py | 143 +++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 homeassistant/components/influx.py diff --git a/homeassistant/components/influx.py b/homeassistant/components/influx.py new file mode 100644 index 00000000000..ef28308d77e --- /dev/null +++ b/homeassistant/components/influx.py @@ -0,0 +1,143 @@ +""" +homeassistant.components.influx +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +InfluxDB component which allows you to send data to an Influx database. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/influx/ + +Configuration: + +influx: + host: localhost + port: 8086 + dbname: home_assistant + dbuser: DB_USER + dbuser_password: DB_USER_PASSWORD +""" +import logging +import requests +import socket + +import homeassistant.util as util +from homeassistant.helpers import validate_config +from homeassistant.const import (MATCH_ALL) + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = "influx" +DEPENDENCIES = ['recorder'] + +INFLUX_CLIENT = None + +DEFAULT_HOST = 'localhost' +DEFAULT_PORT = 8086 +DEFAULT_DATABASE = 'home_assistant' + +REQUIREMENTS = ['influxdb==2.10.0'] + +CONF_HOST = 'host' +CONF_PORT = 'port' +CONF_DB_NAME = 'database' +CONF_USERNAME = 'username' +CONF_PASSWORD = 'password' + + +def setup(hass, config): + """ Setup the Influx component. """ + + from influxdb import exceptions + + if not validate_config(config, {DOMAIN: ['host']}, _LOGGER): + return False + + conf = config[DOMAIN] + + host = conf[CONF_HOST] + port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT) + dbname = util.convert(conf.get(CONF_DB_NAME), str, DEFAULT_DATABASE) + username = util.convert(conf.get(CONF_USERNAME), str) + password = util.convert(conf.get(CONF_PASSWORD), str) + + global INFLUX_CLIENT + + try: + INFLUX_CLIENT = Influx(host, port, username, password, dbname) + except (socket.gaierror, requests.exceptions.ConnectionError): + _LOGGER.error("Database is not accessible. " + "Please check your entries in the configuration file.") + return False + + try: + INFLUX_CLIENT.create_database(dbname) + except exceptions.InfluxDBClientError: + _LOGGER.info("Database '%s' already exists", dbname) + + INFLUX_CLIENT.switch_user(username, password) + INFLUX_CLIENT.switch_database(dbname) + + def event_listener(event): + """ Listen for new messages on the bus and sends them to Influx. """ + event_data = event.as_dict() + json_body = [] + + if event_data['event_type'] is not 'time_changed': + try: + entity_id = event_data['data']['entity_id'] + new_state = event_data['data']['new_state'] + + json_body = [ + { + "measurement": entity_id.split('.')[1], + "tags": { + "type": entity_id.split('.')[0], + }, + "time": event_data['time_fired'], + "fields": { + "value": new_state.state + } + } + ] + except KeyError: + pass + + if json_body: + INFLUX_CLIENT.write_data(json_body) + + hass.bus.listen(MATCH_ALL, event_listener) + + return True + + +# pylint: disable=too-many-arguments +class Influx(object): + """ Implements the handling of an connection to an Influx database.. """ + + def __init__(self, host, port, username, password, dbname): + + from influxdb import InfluxDBClient + + self._host = host + self._port = port + self._username = username + self._password = password + self._dbname = dbname + + self.client = InfluxDBClient(self._host, self._port, self._username, + self._password, self._dbname) + + def switch_user(self, username, password): + """ Switch the user to the given one. """ + self.client.switch_user(username, password) + + def create_database(self, dbname): + """ Creates a new Influx database. """ + self.client.create_database(dbname) + + def switch_database(self, dbname): + """ Switch the user to the given one. """ + return self.client.switch_database(dbname) + + def write_data(self, data): + """ Writes data to Influx database. """ + self.client.write_points(data) From 38b564e4137784bd3941ac7ccc2ccb189532dc0c Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 22:47:00 +0100 Subject: [PATCH 069/166] Remove class, just use state_changed, and update the export data --- homeassistant/components/influx.py | 123 ++++++++++++----------------- 1 file changed, 50 insertions(+), 73 deletions(-) diff --git a/homeassistant/components/influx.py b/homeassistant/components/influx.py index ef28308d77e..78c3d15787e 100644 --- a/homeassistant/components/influx.py +++ b/homeassistant/components/influx.py @@ -16,20 +16,19 @@ influx: dbuser_password: DB_USER_PASSWORD """ import logging -import requests -import socket import homeassistant.util as util from homeassistant.helpers import validate_config -from homeassistant.const import (MATCH_ALL) +from homeassistant.const import (EVENT_STATE_CHANGED, STATE_ON, STATE_OFF, + STATE_UNLOCKED, STATE_LOCKED, STATE_UNKNOWN) +from homeassistant.components.sun import (STATE_ABOVE_HORIZON, + STATE_BELOW_HORIZON) _LOGGER = logging.getLogger(__name__) DOMAIN = "influx" DEPENDENCIES = ['recorder'] -INFLUX_CLIENT = None - DEFAULT_HOST = 'localhost' DEFAULT_PORT = 8086 DEFAULT_DATABASE = 'home_assistant' @@ -46,7 +45,7 @@ CONF_PASSWORD = 'password' def setup(hass, config): """ Setup the Influx component. """ - from influxdb import exceptions + from influxdb import InfluxDBClient, exceptions if not validate_config(config, {DOMAIN: ['host']}, _LOGGER): return False @@ -59,85 +58,63 @@ def setup(hass, config): username = util.convert(conf.get(CONF_USERNAME), str) password = util.convert(conf.get(CONF_PASSWORD), str) - global INFLUX_CLIENT - try: - INFLUX_CLIENT = Influx(host, port, username, password, dbname) - except (socket.gaierror, requests.exceptions.ConnectionError): - _LOGGER.error("Database is not accessible. " + influx = InfluxDBClient(host=host, port=port, username=username, + password=password, database=dbname) + databases = [i['name'] for i in influx.get_list_database()] + except exceptions.InfluxDBClientError: + _LOGGER.error("Database host is not accessible. " "Please check your entries in the configuration file.") return False - try: - INFLUX_CLIENT.create_database(dbname) - except exceptions.InfluxDBClientError: - _LOGGER.info("Database '%s' already exists", dbname) - - INFLUX_CLIENT.switch_user(username, password) - INFLUX_CLIENT.switch_database(dbname) + if dbname not in databases: + _LOGGER.error("Database %s doesn't exist", dbname) + return False def event_listener(event): """ Listen for new messages on the bus and sends them to Influx. """ event_data = event.as_dict() - json_body = [] - if event_data['event_type'] is not 'time_changed': - try: - entity_id = event_data['data']['entity_id'] - new_state = event_data['data']['new_state'] + if event_data['event_type'] is not EVENT_STATE_CHANGED: + return - json_body = [ - { - "measurement": entity_id.split('.')[1], - "tags": { - "type": entity_id.split('.')[0], - }, - "time": event_data['time_fired'], - "fields": { - "value": new_state.state - } - } - ] - except KeyError: - pass + state = event_data['data']['new_state'] + + if state.state == STATE_ON or state.state == STATE_LOCKED or \ + state.state == STATE_ABOVE_HORIZON: + _state = 1 + elif state.state == STATE_OFF or state.state == STATE_UNLOCKED or \ + state.state == STATE_UNKNOWN or \ + state.state == STATE_BELOW_HORIZON: + _state = 0 + else: + _state = state.state + + try: + measurement = state.attributes['unit_of_measurement'] + except KeyError: + measurement = '{}'.format(state.domain) + + json_body = [ + { + 'measurement': measurement, + 'tags': { + 'domain': state.domain, + 'entity_id': state.object_id, + }, + 'time': event_data['time_fired'], + 'fields': { + 'value': _state, + } + } + ] if json_body: - INFLUX_CLIENT.write_data(json_body) + try: + influx.write_points(json_body) + except exceptions.InfluxDBClientError: + _LOGGER.error("Field type conflict") - hass.bus.listen(MATCH_ALL, event_listener) + hass.bus.listen(EVENT_STATE_CHANGED, event_listener) return True - - -# pylint: disable=too-many-arguments -class Influx(object): - """ Implements the handling of an connection to an Influx database.. """ - - def __init__(self, host, port, username, password, dbname): - - from influxdb import InfluxDBClient - - self._host = host - self._port = port - self._username = username - self._password = password - self._dbname = dbname - - self.client = InfluxDBClient(self._host, self._port, self._username, - self._password, self._dbname) - - def switch_user(self, username, password): - """ Switch the user to the given one. """ - self.client.switch_user(username, password) - - def create_database(self, dbname): - """ Creates a new Influx database. """ - self.client.create_database(dbname) - - def switch_database(self, dbname): - """ Switch the user to the given one. """ - return self.client.switch_database(dbname) - - def write_data(self, data): - """ Writes data to Influx database. """ - self.client.write_points(data) From e60ab8f4c2a6aa327b3d57bb0b220f2063341e2e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 25 Nov 2015 23:31:04 +0100 Subject: [PATCH 070/166] Add possibility to write data to file --- script/gen_requirements_all.py | 68 +++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index b10c0f38ed8..a5f3c347fa4 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -8,6 +8,7 @@ import importlib import os import pkgutil import re +import argparse COMMENT_REQUIREMENTS = [ 'RPi.GPIO', @@ -16,6 +17,7 @@ COMMENT_REQUIREMENTS = [ def explore_module(package, explore_children): + """ Explore the modules. """ module = importlib.import_module(package) found = [] @@ -33,10 +35,10 @@ def explore_module(package, explore_children): def core_requirements(): + """ Gather core requirements out of setup.py. """ with open('setup.py') as inp: reqs_raw = re.search( r'REQUIRES = \[(.*?)\]', inp.read(), re.S).group(1) - return re.findall(r"'(.*?)'", reqs_raw) @@ -45,20 +47,23 @@ def comment_requirement(req): return any(ign in req for ign in COMMENT_REQUIREMENTS) -def main(): - if not os.path.isfile('requirements_all.txt'): - print('Run this from HA root dir') - return - +def gather_modules(): + """ Collect the information and construct the output. """ reqs = OrderedDict() errors = [] + output = [] + for package in sorted(explore_module('homeassistant.components', True)): try: module = importlib.import_module(package) except ImportError: errors.append(package) continue + # For catching the error by RPi.GPIO + # RuntimeError: This module can only be run on a Raspberry Pi! + except RuntimeError: + continue if not getattr(module, 'REQUIREMENTS', None): continue @@ -71,20 +76,55 @@ def main(): print('\n'.join(errors)) return - print('# Home Assistant core') - print('\n'.join(core_requirements())) - print() - + output.append('# Home Assistant core') + output.append('\n') + output.append('\n'.join(core_requirements())) + output.append('\n') for pkg, requirements in reqs.items(): for req in sorted(requirements, key=lambda name: (len(name.split('.')), name)): - print('#', req) + output.append('\n# {}'.format(req)) if comment_requirement(pkg): - print('#', pkg) + output.append('\n# {}\n'.format(pkg)) else: - print(pkg) - print() + output.append('\n{}\n'.format(pkg)) + + return ''.join(output) + + +def write_file(data): + """ Writes the modules to the requirements_all.txt. """ + with open('requirements_all.txt', 'w+') as req_file: + req_file.write(data) + + +def display(data): + """ Prints the output to command line. """ + print(data) + + +def argparsing(): + """ Parsing the command line arguments. """ + parser = argparse.ArgumentParser( + description='Generate a requirements_all.txt') + parser.add_argument('file', nargs='?', + help='create new requirements_all.txt file') + return parser.parse_args() + + +def main(): + """ Main """ + if not os.path.isfile('requirements_all.txt'): + print('Run this from HA root dir') + return + args = argparsing() + data = gather_modules() + + if args.file: + write_file(data) + else: + display(data) if __name__ == '__main__': main() From 4bd0db30c988da8c1110df504ab29d3e20f69adb Mon Sep 17 00:00:00 2001 From: badele Date: Thu, 26 Nov 2015 07:52:37 +0100 Subject: [PATCH 071/166] Add should_fire_event in rfxtrx component --- homeassistant/components/light/rfxtrx.py | 60 ++++++++++++++++------ homeassistant/components/rfxtrx.py | 22 +++++--- homeassistant/components/switch/rfxtrx.py | 61 +++++++++++++++++------ 3 files changed, 107 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/light/rfxtrx.py b/homeassistant/components/light/rfxtrx.py index 8d6a2b86217..e5ff38241d9 100644 --- a/homeassistant/components/light/rfxtrx.py +++ b/homeassistant/components/light/rfxtrx.py @@ -8,10 +8,16 @@ https://home-assistant.io/components/light.rfxtrx/ """ import logging import homeassistant.components.rfxtrx as rfxtrx +import RFXtrx as rfxtrxmod from homeassistant.components.light import Light from homeassistant.util import slugify +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.components.rfxtrx import ATTR_STATE, ATTR_FIREEVENT, ATTR_PACKETID, \ + ATTR_NAME, EVENT_BUTTON_PRESSED + + DEPENDENCIES = ['rfxtrx'] _LOGGER = logging.getLogger(__name__) @@ -19,16 +25,22 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup the RFXtrx platform. """ - import RFXtrx as rfxtrxmod - lights = [] devices = config.get('devices', None) + if devices: for entity_id, entity_info in devices.items(): if entity_id not in rfxtrx.RFX_DEVICES: - _LOGGER.info("Add %s rfxtrx.light", entity_info['name']) - rfxobject = rfxtrx.get_rfx_object(entity_info['packetid']) - new_light = RfxtrxLight(entity_info['name'], rfxobject, False) + _LOGGER.info("Add %s rfxtrx.light", entity_info[ATTR_NAME]) + + # Check if i must fire event + fire_event = entity_info.get(ATTR_FIREEVENT, False) + datas = {ATTR_STATE: False, ATTR_FIREEVENT: fire_event} + + rfxobject = rfxtrx.get_rfx_object(entity_info[ATTR_PACKETID]) + new_light = RfxtrxLight( + entity_info[ATTR_NAME], rfxobject, datas + ) rfxtrx.RFX_DEVICES[entity_id] = new_light lights.append(new_light) @@ -54,12 +66,14 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): ) pkt_id = "".join("{0:02x}".format(x) for x in event.data) entity_name = "%s : %s" % (entity_id, pkt_id) - new_light = RfxtrxLight(entity_name, event, False) + datas = {ATTR_STATE: False, ATTR_FIREEVENT: False} + new_light = RfxtrxLight(entity_name, event, datas) rfxtrx.RFX_DEVICES[entity_id] = new_light add_devices_callback([new_light]) # Check if entity exists or previously added automatically - if entity_id in rfxtrx.RFX_DEVICES: + if entity_id in rfxtrx.RFX_DEVICES \ + and isinstance(rfxtrx.RFX_DEVICES[entity_id], RfxtrxLight): _LOGGER.debug( "EntityID: %s light_update. Command: %s", entity_id, @@ -67,10 +81,22 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): ) if event.values['Command'] == 'On'\ or event.values['Command'] == 'Off': - if event.values['Command'] == 'On': - rfxtrx.RFX_DEVICES[entity_id].turn_on() - else: - rfxtrx.RFX_DEVICES[entity_id].turn_off() + + # Update the rfxtrx device state + is_on = event.values['Command'] == 'On' + # pylint: disable=protected-access + rfxtrx.RFX_DEVICES[entity_id]._state = is_on + rfxtrx.RFX_DEVICES[entity_id].update_ha_state() + + # Fire event + if rfxtrx.RFX_DEVICES[entity_id].should_fire_event: + rfxtrx.RFX_DEVICES[entity_id].hass.bus.fire( + EVENT_BUTTON_PRESSED, { + ATTR_ENTITY_ID: + rfxtrx.RFX_DEVICES[entity_id].entity_id, + ATTR_STATE: event.values['Command'].lower() + } + ) # Subscribe to main rfxtrx events if light_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS: @@ -79,10 +105,11 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): class RfxtrxLight(Light): """ Provides a RFXtrx light. """ - def __init__(self, name, event, state): + def __init__(self, name, event, datas): self._name = name self._event = event - self._state = state + self._state = datas[ATTR_STATE] + self._should_fire_event = datas[ATTR_FIREEVENT] @property def should_poll(self): @@ -94,6 +121,11 @@ class RfxtrxLight(Light): """ Returns the name of the light if any. """ return self._name + @property + def should_fire_event(self): + """ Returns is the device must fire event""" + return self._should_fire_event + @property def is_on(self): """ True if light is on. """ @@ -115,4 +147,4 @@ class RfxtrxLight(Light): self._event.device.send_off(rfxtrx.RFXOBJECT.transport) self._state = False - self.update_ha_state() + self.update_ha_state() \ No newline at end of file diff --git a/homeassistant/components/rfxtrx.py b/homeassistant/components/rfxtrx.py index 3c4675d806d..e02a56d3c7a 100644 --- a/homeassistant/components/rfxtrx.py +++ b/homeassistant/components/rfxtrx.py @@ -4,7 +4,7 @@ homeassistant.components.rfxtrx Provides support for RFXtrx components. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/rfxtrx/ +https://home-assistant.io/components/rfxtrx.html """ import logging from homeassistant.util import slugify @@ -14,8 +14,16 @@ REQUIREMENTS = ['https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip' + '#RFXtrx==0.2'] DOMAIN = "rfxtrx" -CONF_DEVICE = 'device' -CONF_DEBUG = 'debug' + +ATTR_DEVICE = 'device' +ATTR_DEBUG = 'debug' +ATTR_STATE = 'state' +ATTR_NAME = 'name' +ATTR_PACKETID = 'packetid' +ATTR_FIREEVENT = 'fire_event' + +EVENT_BUTTON_PRESSED = 'button_pressed' + RECEIVED_EVT_SUBSCRIBERS = [] RFX_DEVICES = {} _LOGGER = logging.getLogger(__name__) @@ -50,15 +58,15 @@ def setup(hass, config): # Init the rfxtrx module global RFXOBJECT - if CONF_DEVICE not in config[DOMAIN]: + if ATTR_DEVICE not in config[DOMAIN]: _LOGGER.exception( "can found device parameter in %s YAML configuration section", DOMAIN ) return False - device = config[DOMAIN][CONF_DEVICE] - debug = config[DOMAIN].get(CONF_DEBUG, False) + device = config[DOMAIN][ATTR_DEVICE] + debug = config[DOMAIN].get(ATTR_DEBUG, False) RFXOBJECT = rfxtrxmod.Core(device, handle_receive, debug=debug) @@ -86,4 +94,4 @@ def get_rfx_object(packetid): return obj - return None + return None \ No newline at end of file diff --git a/homeassistant/components/switch/rfxtrx.py b/homeassistant/components/switch/rfxtrx.py index 86bcf580f41..e4400bdf86f 100644 --- a/homeassistant/components/switch/rfxtrx.py +++ b/homeassistant/components/switch/rfxtrx.py @@ -8,10 +8,16 @@ https://home-assistant.io/components/switch.rfxtrx/ """ import logging import homeassistant.components.rfxtrx as rfxtrx +import RFXtrx as rfxtrxmod from homeassistant.components.switch import SwitchDevice from homeassistant.util import slugify +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.components.rfxtrx import ATTR_STATE, ATTR_FIREEVENT, ATTR_PACKETID, \ + ATTR_NAME, EVENT_BUTTON_PRESSED + + DEPENDENCIES = ['rfxtrx'] _LOGGER = logging.getLogger(__name__) @@ -19,7 +25,6 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup the RFXtrx platform. """ - from RFXtrx import LightingDevice # Add switch from config file switchs = [] @@ -27,9 +32,15 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): if devices: for entity_id, entity_info in devices.items(): if entity_id not in rfxtrx.RFX_DEVICES: - _LOGGER.info("Add %s rfxtrx.switch", entity_info['name']) - rfxobject = rfxtrx.get_rfx_object(entity_info['packetid']) - newswitch = RfxtrxSwitch(entity_info['name'], rfxobject, False) + _LOGGER.info("Add %s rfxtrx.switch", entity_info[ATTR_NAME]) + + # Check if i must fire event + fire_event = entity_info.get(ATTR_FIREEVENT, False) + datas = {ATTR_STATE: False, ATTR_FIREEVENT: fire_event} + + rfxobject = rfxtrx.get_rfx_object(entity_info[ATTR_PACKETID]) + newswitch = RfxtrxSwitch( + entity_info[ATTR_NAME], rfxobject, datas) rfxtrx.RFX_DEVICES[entity_id] = newswitch switchs.append(newswitch) @@ -37,7 +48,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): def switch_update(event): """ Callback for sensor updates from the RFXtrx gateway. """ - if isinstance(event.device, LightingDevice): + if not isinstance(event.device, rfxtrxmod.LightingDevice): return # Add entity if not exist and the automatic_add is True @@ -55,12 +66,14 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): ) pkt_id = "".join("{0:02x}".format(x) for x in event.data) entity_name = "%s : %s" % (entity_id, pkt_id) - new_switch = RfxtrxSwitch(entity_name, event, False) + datas = {ATTR_STATE: False, ATTR_FIREEVENT: False} + new_switch = RfxtrxSwitch(entity_name, event, datas) rfxtrx.RFX_DEVICES[entity_id] = new_switch add_devices_callback([new_switch]) # Check if entity exists or previously added automatically - if entity_id in rfxtrx.RFX_DEVICES: + if entity_id in rfxtrx.RFX_DEVICES \ + and isinstance(rfxtrx.RFX_DEVICES[entity_id], RfxtrxSwitch): _LOGGER.debug( "EntityID: %s switch_update. Command: %s", entity_id, @@ -68,10 +81,22 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): ) if event.values['Command'] == 'On'\ or event.values['Command'] == 'Off': - if event.values['Command'] == 'On': - rfxtrx.RFX_DEVICES[entity_id].turn_on() - else: - rfxtrx.RFX_DEVICES[entity_id].turn_off() + + # Update the rfxtrx device state + is_on = event.values['Command'] == 'On' + # pylint: disable=protected-access + rfxtrx.RFX_DEVICES[entity_id]._state = is_on + rfxtrx.RFX_DEVICES[entity_id].update_ha_state() + + # Fire event + if rfxtrx.RFX_DEVICES[entity_id].should_fire_event: + rfxtrx.RFX_DEVICES[entity_id].hass.bus.fire( + EVENT_BUTTON_PRESSED, { + ATTR_ENTITY_ID: + rfxtrx.RFX_DEVICES[entity_id].entity_id, + ATTR_STATE: event.values['Command'].lower() + } + ) # Subscribe to main rfxtrx events if switch_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS: @@ -80,10 +105,11 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): class RfxtrxSwitch(SwitchDevice): """ Provides a RFXtrx switch. """ - def __init__(self, name, event, state): + def __init__(self, name, event, datas): self._name = name self._event = event - self._state = state + self._state = datas[ATTR_STATE] + self._should_fire_event = datas[ATTR_FIREEVENT] @property def should_poll(self): @@ -95,9 +121,14 @@ class RfxtrxSwitch(SwitchDevice): """ Returns the name of the device if any. """ return self._name + @property + def should_fire_event(self): + """ Returns is the device must fire event""" + return self._should_fire_event + @property def is_on(self): - """ True if device is on. """ + """ True if light is on. """ return self._state def turn_on(self, **kwargs): @@ -114,4 +145,4 @@ class RfxtrxSwitch(SwitchDevice): self._event.device.send_off(rfxtrx.RFXOBJECT.transport) self._state = False - self.update_ha_state() + self.update_ha_state() \ No newline at end of file From a33220db7f49962a97c58181582f0437723752f1 Mon Sep 17 00:00:00 2001 From: badele Date: Thu, 26 Nov 2015 08:12:04 +0100 Subject: [PATCH 072/166] Fix pylint style --- homeassistant/components/light/rfxtrx.py | 2 +- homeassistant/components/rfxtrx.py | 2 +- homeassistant/components/switch/rfxtrx.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/light/rfxtrx.py b/homeassistant/components/light/rfxtrx.py index e5ff38241d9..9da69300623 100644 --- a/homeassistant/components/light/rfxtrx.py +++ b/homeassistant/components/light/rfxtrx.py @@ -147,4 +147,4 @@ class RfxtrxLight(Light): self._event.device.send_off(rfxtrx.RFXOBJECT.transport) self._state = False - self.update_ha_state() \ No newline at end of file + self.update_ha_state() diff --git a/homeassistant/components/rfxtrx.py b/homeassistant/components/rfxtrx.py index e02a56d3c7a..bcdbec5327b 100644 --- a/homeassistant/components/rfxtrx.py +++ b/homeassistant/components/rfxtrx.py @@ -94,4 +94,4 @@ def get_rfx_object(packetid): return obj - return None \ No newline at end of file + return None diff --git a/homeassistant/components/switch/rfxtrx.py b/homeassistant/components/switch/rfxtrx.py index e4400bdf86f..24bd2f2fd6d 100644 --- a/homeassistant/components/switch/rfxtrx.py +++ b/homeassistant/components/switch/rfxtrx.py @@ -145,4 +145,4 @@ class RfxtrxSwitch(SwitchDevice): self._event.device.send_off(rfxtrx.RFXOBJECT.transport) self._state = False - self.update_ha_state() \ No newline at end of file + self.update_ha_state() From 128e3bb762b2cb6900ee09f4650405e2cb9609b4 Mon Sep 17 00:00:00 2001 From: badele Date: Thu, 26 Nov 2015 08:27:31 +0100 Subject: [PATCH 073/166] Move import module --- homeassistant/components/light/rfxtrx.py | 3 ++- homeassistant/components/rfxtrx.py | 2 +- homeassistant/components/switch/rfxtrx.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/light/rfxtrx.py b/homeassistant/components/light/rfxtrx.py index 9da69300623..6132c10a99c 100644 --- a/homeassistant/components/light/rfxtrx.py +++ b/homeassistant/components/light/rfxtrx.py @@ -8,7 +8,6 @@ https://home-assistant.io/components/light.rfxtrx/ """ import logging import homeassistant.components.rfxtrx as rfxtrx -import RFXtrx as rfxtrxmod from homeassistant.components.light import Light from homeassistant.util import slugify @@ -25,6 +24,8 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup the RFXtrx platform. """ + import RFXtrx as rfxtrxmod + lights = [] devices = config.get('devices', None) diff --git a/homeassistant/components/rfxtrx.py b/homeassistant/components/rfxtrx.py index bcdbec5327b..38aa785e7ad 100644 --- a/homeassistant/components/rfxtrx.py +++ b/homeassistant/components/rfxtrx.py @@ -4,7 +4,7 @@ homeassistant.components.rfxtrx Provides support for RFXtrx components. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/rfxtrx.html +https://home-assistant.io/components/rfxtrx/ """ import logging from homeassistant.util import slugify diff --git a/homeassistant/components/switch/rfxtrx.py b/homeassistant/components/switch/rfxtrx.py index 24bd2f2fd6d..69e08e7d129 100644 --- a/homeassistant/components/switch/rfxtrx.py +++ b/homeassistant/components/switch/rfxtrx.py @@ -8,7 +8,6 @@ https://home-assistant.io/components/switch.rfxtrx/ """ import logging import homeassistant.components.rfxtrx as rfxtrx -import RFXtrx as rfxtrxmod from homeassistant.components.switch import SwitchDevice from homeassistant.util import slugify @@ -25,6 +24,7 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Setup the RFXtrx platform. """ + import RFXtrx as rfxtrxmod # Add switch from config file switchs = [] From 4f75286f64dde2cbfa429eb19167169f88c2baa1 Mon Sep 17 00:00:00 2001 From: sfam Date: Thu, 26 Nov 2015 09:38:25 +0000 Subject: [PATCH 074/166] fix some comments --- homeassistant/components/motor/mqtt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/motor/mqtt.py b/homeassistant/components/motor/mqtt.py index 48a20d5a3b6..2aac5e37c16 100644 --- a/homeassistant/components/motor/mqtt.py +++ b/homeassistant/components/motor/mqtt.py @@ -90,16 +90,16 @@ class MqttMotor(MotorDevice): @property def is_open(self): - """ True if device is open. """ + """ True if device is current position is not zero. """ return self._state > 0 def open(self, **kwargs): - """ Close the device. """ + """ Open the device. """ mqtt.publish(self.hass, self._command_topic, self._payload_open, self._qos) def close(self, **kwargs): - """ Open the device. """ + """ Close the device. """ mqtt.publish(self.hass, self._command_topic, self._payload_close, self._qos) From f2f598bd264bb9536065058a65f49c49153f2920 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 26 Nov 2015 16:37:00 +0100 Subject: [PATCH 075/166] Use host as config var instead of resource --- homeassistant/components/switch/mystrom.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/switch/mystrom.py b/homeassistant/components/switch/mystrom.py index 3acbfb24ce6..36a62fe33e4 100644 --- a/homeassistant/components/switch/mystrom.py +++ b/homeassistant/components/switch/mystrom.py @@ -16,29 +16,27 @@ DEFAULT_NAME = 'myStrom Switch' _LOGGER = logging.getLogger(__name__) -# pylint: disable=unused-argument, too-many-function-args def setup_platform(hass, config, add_devices, discovery_info=None): """ Find and return myStrom switches. """ - resource = config.get('resource') + host = config.get('host') - if resource is None: - _LOGGER.error('Missing required variable: resource') + if host is None: + _LOGGER.error('Missing required variable: host') return False + resource = 'http://{}'.format(host) + try: requests.get(resource, timeout=10) - except requests.exceptions.MissingSchema: - _LOGGER.error("Missing resource or schema in configuration. " - "Add http:// to your URL.") - return False except requests.exceptions.ConnectionError: - _LOGGER.error("No route to device. " - "Please check the IP address in the configuration file.") + _LOGGER.error("No route to device %s. " + "Please check the IP address in the configuration file", + host) return False add_devices([MyStromSwitch( config.get('name', DEFAULT_NAME), - config.get('resource'))]) + resource)]) class MyStromSwitch(SwitchDevice): From 067011af1563ee67441292c496ed7feee39e136b Mon Sep 17 00:00:00 2001 From: Pascal Bach Date: Thu, 26 Nov 2015 20:45:07 +0100 Subject: [PATCH 076/166] function support for aREST backend The implementation sends /?params=1 for turn_on and /?params=0 for turn_off It uses the return value of the function to determine the current state. 0=Off, 1=On --- homeassistant/components/switch/arest.py | 95 ++++++++++++++++++++---- 1 file changed, 82 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/switch/arest.py b/homeassistant/components/switch/arest.py index 92bd70cb734..c42295660d4 100644 --- a/homeassistant/components/switch/arest.py +++ b/homeassistant/components/switch/arest.py @@ -34,30 +34,33 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False dev = [] - pins = config.get('pins') + pins = config.get('pins', {}) for pinnum, pin in pins.items(): - dev.append(ArestSwitch(resource, - config.get('name', response.json()['name']), - pin.get('name'), - pinnum)) + dev.append(ArestSwitchPin(resource, + config.get('name', response.json()['name']), + pin.get('name'), + pinnum)) + + functions = config.get('functions', {}) + for funcname, func in functions.items(): + dev.append(ArestSwitchFunction(resource, + config.get('name', + response.json()['name']), + func.get('name'), + funcname)) + add_devices(dev) -class ArestSwitch(SwitchDevice): +class ArestSwitchBase(SwitchDevice): """ Implements an aREST switch. """ - def __init__(self, resource, location, name, pin): + def __init__(self, resource, location, name): self._resource = resource self._name = '{} {}'.format(location.title(), name.title()) \ or DEVICE_DEFAULT_NAME - self._pin = pin self._state = None - request = requests.get('{}/mode/{}/o'.format(self._resource, - self._pin), timeout=10) - if request.status_code is not 200: - _LOGGER.error("Can't set mode. Is device offline?") - @property def name(self): """ The name of the switch. """ @@ -68,6 +71,72 @@ class ArestSwitch(SwitchDevice): """ True if device is on. """ return self._state + +class ArestSwitchFunction(ArestSwitchBase): + """ Implements an aREST switch. Based on functions. """ + + def __init__(self, resource, location, name, func): + super().__init__(resource, location, name) + self._func = func + + request = requests.get('{}/{}'.format(self._resource, self._func), + timeout=10) + + if request.status_code is not 200: + _LOGGER.error("Can't find function. Is device offline?") + return + + try: + request.json()['return_value'] + except KeyError: + _LOGGER.error("No return_value received. " + "Is the function name correct.") + except ValueError: + _LOGGER.error("Response invalid. Is the function name correct.") + + def turn_on(self, **kwargs): + """ Turn the device on. """ + request = requests.get('{}/{}'.format(self._resource, self._func), + timeout=10, params={"params": "1"}) + + if request.status_code == 200: + self._state = True + else: + _LOGGER.error("Can't turn on function %s at %s. " + "Is device offline?", + self._func, self._resource) + + def turn_off(self, **kwargs): + """ Turn the device off. """ + request = requests.get('{}/{}'.format(self._resource, self._func), + timeout=10, params={"params": "0"}) + + if request.status_code == 200: + self._state = False + else: + _LOGGER.error("Can't turn off function %s at %s. " + "Is device offline?", + self._func, self._resource) + + def update(self): + """ Gets the latest data from aREST API and updates the state. """ + request = requests.get('{}/{}'.format(self._resource, + self._func), timeout=10) + self._state = request.json()['return_value'] != 0 + + +class ArestSwitchPin(ArestSwitchBase): + """ Implements an aREST switch. Based on digital I/O """ + + def __init__(self, resource, location, name, pin): + super().__init__(resource, location, name) + self._pin = pin + + request = requests.get('{}/mode/{}/o'.format(self._resource, + self._pin), timeout=10) + if request.status_code is not 200: + _LOGGER.error("Can't set mode. Is device offline?") + def turn_on(self, **kwargs): """ Turn the device on. """ request = requests.get('{}/digital/{}/1'.format(self._resource, From 69e9d39690e4ba6c35f8d905040ec0194b0fb22c Mon Sep 17 00:00:00 2001 From: Pascal Bach Date: Tue, 24 Nov 2015 21:30:06 +0100 Subject: [PATCH 077/166] Allow setting the retain flag for mqtt switch. Some devices can read the initial value on startup. If the retain flag is set they always receive the value as last set by home assistant. --- homeassistant/components/mqtt/__init__.py | 15 +++++++++++---- homeassistant/components/switch/mqtt.py | 9 ++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index b8dc8909887..65db49f8636 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -28,6 +28,7 @@ MQTT_CLIENT = None DEFAULT_PORT = 1883 DEFAULT_KEEPALIVE = 60 DEFAULT_QOS = 0 +DEFAULT_RETAIN = False SERVICE_PUBLISH = 'publish' EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED' @@ -46,11 +47,12 @@ CONF_CERTIFICATE = 'certificate' ATTR_TOPIC = 'topic' ATTR_PAYLOAD = 'payload' ATTR_QOS = 'qos' +ATTR_RETAIN = 'retain' MAX_RECONNECT_WAIT = 300 # seconds -def publish(hass, topic, payload, qos=None): +def publish(hass, topic, payload, qos=None, retain=None): """ Send an MQTT message. """ data = { ATTR_TOPIC: topic, @@ -58,6 +60,10 @@ def publish(hass, topic, payload, qos=None): } if qos is not None: data[ATTR_QOS] = qos + + if retain is not None: + data[ATTR_RETAIN] = retain + hass.services.call(DOMAIN, SERVICE_PUBLISH, data) @@ -119,9 +125,10 @@ def setup(hass, config): msg_topic = call.data.get(ATTR_TOPIC) payload = call.data.get(ATTR_PAYLOAD) qos = call.data.get(ATTR_QOS, DEFAULT_QOS) + retain = call.data.get(ATTR_RETAIN, DEFAULT_RETAIN) if msg_topic is None or payload is None: return - MQTT_CLIENT.publish(msg_topic, payload, qos) + MQTT_CLIENT.publish(msg_topic, payload, qos, retain) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_mqtt) @@ -190,9 +197,9 @@ class MQTT(object): self._mqttc.connect(broker, port, keepalive) - def publish(self, topic, payload, qos): + def publish(self, topic, payload, qos, retain): """ Publish a MQTT message. """ - self._mqttc.publish(topic, payload, qos) + self._mqttc.publish(topic, payload, qos, retain) def start(self): """ Run the MQTT client. """ diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index 43bceab69a5..7b973799eed 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -17,6 +17,7 @@ DEFAULT_QOS = 0 DEFAULT_PAYLOAD_ON = "ON" DEFAULT_PAYLOAD_OFF = "OFF" DEFAULT_OPTIMISTIC = False +DEFAULT_RETAIN = False DEPENDENCIES = ['mqtt'] @@ -35,6 +36,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): config.get('state_topic'), config.get('command_topic'), config.get('qos', DEFAULT_QOS), + config.get('retain', DEFAULT_RETAIN), config.get('payload_on', DEFAULT_PAYLOAD_ON), config.get('payload_off', DEFAULT_PAYLOAD_OFF), config.get('optimistic', DEFAULT_OPTIMISTIC), @@ -44,7 +46,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): # pylint: disable=too-many-arguments, too-many-instance-attributes class MqttSwitch(SwitchDevice): """ Represents a switch that can be toggled using MQTT. """ - def __init__(self, hass, name, state_topic, command_topic, qos, + def __init__(self, hass, name, state_topic, command_topic, qos, retain, payload_on, payload_off, optimistic, state_format): self._state = False self._hass = hass @@ -52,6 +54,7 @@ class MqttSwitch(SwitchDevice): self._state_topic = state_topic self._command_topic = command_topic self._qos = qos + self._retain = retain self._payload_on = payload_on self._payload_off = payload_off self._optimistic = optimistic @@ -93,7 +96,7 @@ class MqttSwitch(SwitchDevice): def turn_on(self, **kwargs): """ Turn the device on. """ mqtt.publish(self.hass, self._command_topic, self._payload_on, - self._qos) + self._qos, self._retain) if self._optimistic: # optimistically assume that switch has changed state self._state = True @@ -102,7 +105,7 @@ class MqttSwitch(SwitchDevice): def turn_off(self, **kwargs): """ Turn the device off. """ mqtt.publish(self.hass, self._command_topic, self._payload_off, - self._qos) + self._qos, self._retain) if self._optimistic: # optimistically assume that switch has changed state self._state = False From 341c3a8fcda4c514edd3ae5b3de0b0d17270109e Mon Sep 17 00:00:00 2001 From: Pascal Bach Date: Thu, 26 Nov 2015 20:55:26 +0100 Subject: [PATCH 078/166] Fix tests for mqtt publish with retain. --- tests/components/alarm_control_panel/test_mqtt.py | 6 +++--- tests/components/light/test_mqtt.py | 4 ++-- tests/components/switch/test_mqtt.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/components/alarm_control_panel/test_mqtt.py b/tests/components/alarm_control_panel/test_mqtt.py index 6cba26c15a6..58c55350cd2 100644 --- a/tests/components/alarm_control_panel/test_mqtt.py +++ b/tests/components/alarm_control_panel/test_mqtt.py @@ -101,7 +101,7 @@ class TestAlarmControlPanelMQTT(unittest.TestCase): alarm_control_panel.alarm_arm_home(self.hass) self.hass.pool.block_till_done() - self.assertEqual(('alarm/command', 'ARM_HOME', 0), + self.assertEqual(('alarm/command', 'ARM_HOME', 0, False), self.mock_publish.mock_calls[-1][1]) def test_arm_home_not_publishes_mqtt_with_invalid_code(self): @@ -130,7 +130,7 @@ class TestAlarmControlPanelMQTT(unittest.TestCase): alarm_control_panel.alarm_arm_away(self.hass) self.hass.pool.block_till_done() - self.assertEqual(('alarm/command', 'ARM_AWAY', 0), + self.assertEqual(('alarm/command', 'ARM_AWAY', 0, False), self.mock_publish.mock_calls[-1][1]) def test_arm_away_not_publishes_mqtt_with_invalid_code(self): @@ -159,7 +159,7 @@ class TestAlarmControlPanelMQTT(unittest.TestCase): alarm_control_panel.alarm_disarm(self.hass) self.hass.pool.block_till_done() - self.assertEqual(('alarm/command', 'DISARM', 0), + self.assertEqual(('alarm/command', 'DISARM', 0, False), self.mock_publish.mock_calls[-1][1]) def test_disarm_not_publishes_mqtt_with_invalid_code(self): diff --git a/tests/components/light/test_mqtt.py b/tests/components/light/test_mqtt.py index 39c81ee0a04..fdebb0c1ef5 100644 --- a/tests/components/light/test_mqtt.py +++ b/tests/components/light/test_mqtt.py @@ -139,7 +139,7 @@ class TestLightMQTT(unittest.TestCase): light.turn_on(self.hass, 'light.test') self.hass.pool.block_till_done() - self.assertEqual(('test_light_rgb/set', 'on', 2), + self.assertEqual(('test_light_rgb/set', 'on', 2, False), self.mock_publish.mock_calls[-1][1]) state = self.hass.states.get('light.test') self.assertEqual(STATE_ON, state.state) @@ -147,7 +147,7 @@ class TestLightMQTT(unittest.TestCase): light.turn_off(self.hass, 'light.test') self.hass.pool.block_till_done() - self.assertEqual(('test_light_rgb/set', 'off', 2), + self.assertEqual(('test_light_rgb/set', 'off', 2, False), self.mock_publish.mock_calls[-1][1]) state = self.hass.states.get('light.test') self.assertEqual(STATE_OFF, state.state) diff --git a/tests/components/switch/test_mqtt.py b/tests/components/switch/test_mqtt.py index 4754e64e575..2cfe29c2910 100644 --- a/tests/components/switch/test_mqtt.py +++ b/tests/components/switch/test_mqtt.py @@ -68,7 +68,7 @@ class TestSensorMQTT(unittest.TestCase): switch.turn_on(self.hass, 'switch.test') self.hass.pool.block_till_done() - self.assertEqual(('command-topic', 'beer on', 2), + self.assertEqual(('command-topic', 'beer on', 2, False), self.mock_publish.mock_calls[-1][1]) state = self.hass.states.get('switch.test') self.assertEqual(STATE_ON, state.state) @@ -76,7 +76,7 @@ class TestSensorMQTT(unittest.TestCase): switch.turn_off(self.hass, 'switch.test') self.hass.pool.block_till_done() - self.assertEqual(('command-topic', 'beer off', 2), + self.assertEqual(('command-topic', 'beer off', 2, False), self.mock_publish.mock_calls[-1][1]) state = self.hass.states.get('switch.test') self.assertEqual(STATE_OFF, state.state) From 2861bbb02c1c06b80473176edb7f6e85a5473806 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 26 Nov 2015 13:08:13 -0800 Subject: [PATCH 079/166] Warn if config invalid shape for script --- homeassistant/components/script.py | 5 +++-- tests/components/test_script.py | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/script.py b/homeassistant/components/script.py index 2b18a5143fd..f8240bbf7f5 100644 --- a/homeassistant/components/script.py +++ b/homeassistant/components/script.py @@ -76,8 +76,9 @@ def setup(hass, config): _LOGGER.warn("Found invalid key for script: %s. Use %s instead.", object_id, slugify(object_id)) continue - if not cfg.get(CONF_SEQUENCE): - _LOGGER.warn("Missing key 'sequence' for script %s", object_id) + if not isinstance(cfg.get(CONF_SEQUENCE), list): + _LOGGER.warn("Key 'sequence' for script %s should be a list", + object_id) continue alias = cfg.get(CONF_ALIAS, object_id) script = Script(hass, object_id, alias, cfg[CONF_SEQUENCE]) diff --git a/tests/components/test_script.py b/tests/components/test_script.py index 50cfba55ec5..30b7e4e3c8f 100644 --- a/tests/components/test_script.py +++ b/tests/components/test_script.py @@ -27,23 +27,10 @@ class TestScript(unittest.TestCase): """ Stop down stuff we started. """ self.hass.stop() - def test_setup_with_empty_sequence(self): - self.assertTrue(script.setup(self.hass, { - 'script': { - 'test': { - 'sequence': [] - } - } - })) - - self.assertIsNone(self.hass.states.get(ENTITY_ID)) - def test_setup_with_missing_sequence(self): self.assertTrue(script.setup(self.hass, { 'script': { - 'test': { - 'sequence': [] - } + 'test': {} } })) @@ -60,6 +47,19 @@ class TestScript(unittest.TestCase): self.assertEqual(0, len(self.hass.states.entity_ids('script'))) + def test_setup_with_dict_as_sequence(self): + self.assertTrue(script.setup(self.hass, { + 'script': { + 'test': { + 'sequence': { + 'event': 'test_event' + } + } + } + })) + + self.assertEqual(0, len(self.hass.states.entity_ids('script'))) + def test_firing_event(self): event = 'test_event' calls = [] From fabd0ced3fe96839b93a9f790fb498a69c996222 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 26 Nov 2015 13:11:59 -0800 Subject: [PATCH 080/166] Make DEPENDENCIES optional for components --- homeassistant/bootstrap.py | 19 +++++++++---------- .../alarm_control_panel/__init__.py | 1 - .../components/alarm_control_panel/manual.py | 2 -- homeassistant/components/arduino.py | 1 - .../components/binary_sensor/__init__.py | 1 - homeassistant/components/browser.py | 1 - homeassistant/components/configurator.py | 1 - homeassistant/components/conversation.py | 1 - homeassistant/components/discovery.py | 1 - homeassistant/components/downloader.py | 1 - homeassistant/components/group.py | 1 - homeassistant/components/http.py | 1 - homeassistant/components/ifttt.py | 2 -- homeassistant/components/introduction.py | 1 - homeassistant/components/isy994.py | 1 - homeassistant/components/keyboard.py | 1 - homeassistant/components/light/__init__.py | 1 - .../components/light/blinksticklight.py | 1 - homeassistant/components/lock/__init__.py | 1 - homeassistant/components/logger.py | 1 - .../components/media_player/__init__.py | 1 - homeassistant/components/modbus.py | 1 - homeassistant/components/mqtt/__init__.py | 1 - homeassistant/components/notify/__init__.py | 1 - homeassistant/components/recorder.py | 1 - homeassistant/components/rfxtrx.py | 1 - homeassistant/components/sensor/__init__.py | 1 - homeassistant/components/shell_command.py | 1 - homeassistant/components/sun.py | 1 - homeassistant/components/switch/__init__.py | 1 - .../components/thermostat/__init__.py | 1 - homeassistant/components/updater.py | 1 - homeassistant/components/wink.py | 1 - homeassistant/components/zone.py | 1 - homeassistant/components/zwave.py | 1 - homeassistant/loader.py | 2 +- 36 files changed, 10 insertions(+), 47 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 4d68227d4d0..41377aadebf 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -82,7 +82,7 @@ def _setup_component(hass, domain, config): return True component = loader.get_component(domain) - missing_deps = [dep for dep in component.DEPENDENCIES + missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', []) if dep not in hass.config.components] if missing_deps: @@ -106,7 +106,7 @@ def _setup_component(hass, domain, config): # Assumption: if a component does not depend on groups # it communicates with devices - if group.DOMAIN not in component.DEPENDENCIES: + if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []): hass.pool.add_worker() hass.bus.fire( @@ -133,14 +133,13 @@ def prepare_setup_platform(hass, config, domain, platform_name): return platform # Load dependencies - if hasattr(platform, 'DEPENDENCIES'): - for component in platform.DEPENDENCIES: - if not setup_component(hass, component, config): - _LOGGER.error( - 'Unable to prepare setup for platform %s because ' - 'dependency %s could not be initialized', platform_path, - component) - return None + for component in getattr(platform, 'DEPENDENCIES', []): + if not setup_component(hass, component, config): + _LOGGER.error( + 'Unable to prepare setup for platform %s because ' + 'dependency %s could not be initialized', platform_path, + component) + return None if not _handle_requirements(hass, platform, platform_path): return None diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index d3289e08e62..3f5e6362fb6 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -15,7 +15,6 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent DOMAIN = 'alarm_control_panel' -DEPENDENCIES = [] SCAN_INTERVAL = 30 ENTITY_ID_FORMAT = DOMAIN + '.{}' diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index ca1816db9e6..63bc989f3df 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -18,8 +18,6 @@ from homeassistant.const import ( _LOGGER = logging.getLogger(__name__) -DEPENDENCIES = [] - DEFAULT_ALARM_NAME = 'HA Alarm' DEFAULT_PENDING_TIME = 60 DEFAULT_TRIGGER_TIME = 120 diff --git a/homeassistant/components/arduino.py b/homeassistant/components/arduino.py index 0c278ceee63..88967ec1f74 100644 --- a/homeassistant/components/arduino.py +++ b/homeassistant/components/arduino.py @@ -19,7 +19,6 @@ from homeassistant.const import (EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) DOMAIN = "arduino" -DEPENDENCIES = [] REQUIREMENTS = ['PyMata==2.07a'] BOARD = None _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py index 2ef9e83cc30..ccfd57aff8c 100644 --- a/homeassistant/components/binary_sensor/__init__.py +++ b/homeassistant/components/binary_sensor/__init__.py @@ -14,7 +14,6 @@ from homeassistant.helpers.entity import Entity from homeassistant.const import (STATE_ON, STATE_OFF) DOMAIN = 'binary_sensor' -DEPENDENCIES = [] SCAN_INTERVAL = 30 ENTITY_ID_FORMAT = DOMAIN + '.{}' diff --git a/homeassistant/components/browser.py b/homeassistant/components/browser.py index db0f3710158..88548e2a1b3 100644 --- a/homeassistant/components/browser.py +++ b/homeassistant/components/browser.py @@ -8,7 +8,6 @@ https://home-assistant.io/components/browser/ """ DOMAIN = "browser" -DEPENDENCIES = [] SERVICE_BROWSE_URL = "browse_url" diff --git a/homeassistant/components/configurator.py b/homeassistant/components/configurator.py index 8bec580abf9..515daffc71c 100644 --- a/homeassistant/components/configurator.py +++ b/homeassistant/components/configurator.py @@ -15,7 +15,6 @@ from homeassistant.helpers import generate_entity_id from homeassistant.const import EVENT_TIME_CHANGED DOMAIN = "configurator" -DEPENDENCIES = [] ENTITY_ID_FORMAT = DOMAIN + ".{}" SERVICE_CONFIGURE = "configure" diff --git a/homeassistant/components/conversation.py b/homeassistant/components/conversation.py index d9cba832df7..7cd1193448c 100644 --- a/homeassistant/components/conversation.py +++ b/homeassistant/components/conversation.py @@ -14,7 +14,6 @@ from homeassistant.const import ( ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF) DOMAIN = "conversation" -DEPENDENCIES = [] SERVICE_PROCESS = "process" diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 3a43c86f58a..807f1fe3944 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -17,7 +17,6 @@ from homeassistant.const import ( ATTR_SERVICE, ATTR_DISCOVERED) DOMAIN = "discovery" -DEPENDENCIES = [] REQUIREMENTS = ['netdisco==0.5.1'] SCAN_INTERVAL = 300 # seconds diff --git a/homeassistant/components/downloader.py b/homeassistant/components/downloader.py index a69a6ca1517..655bf7d4eb6 100644 --- a/homeassistant/components/downloader.py +++ b/homeassistant/components/downloader.py @@ -15,7 +15,6 @@ from homeassistant.helpers import validate_config from homeassistant.util import sanitize_filename DOMAIN = "downloader" -DEPENDENCIES = [] SERVICE_DOWNLOAD_FILE = "download_file" diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py index 9ae83cb734a..52ffe824e42 100644 --- a/homeassistant/components/group.py +++ b/homeassistant/components/group.py @@ -17,7 +17,6 @@ from homeassistant.const import ( STATE_UNKNOWN) DOMAIN = "group" -DEPENDENCIES = [] ENTITY_ID_FORMAT = DOMAIN + ".{}" diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index a7ae0c5af6e..88392ed3fe4 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -34,7 +34,6 @@ import homeassistant.util.dt as date_util import homeassistant.bootstrap as bootstrap DOMAIN = "http" -DEPENDENCIES = [] CONF_API_PASSWORD = "api_password" CONF_SERVER_HOST = "server_host" diff --git a/homeassistant/components/ifttt.py b/homeassistant/components/ifttt.py index 246265a5268..3721f5b1d33 100644 --- a/homeassistant/components/ifttt.py +++ b/homeassistant/components/ifttt.py @@ -22,8 +22,6 @@ ATTR_VALUE1 = 'value1' ATTR_VALUE2 = 'value2' ATTR_VALUE3 = 'value3' -DEPENDENCIES = [] - REQUIREMENTS = ['pyfttt==0.3'] diff --git a/homeassistant/components/introduction.py b/homeassistant/components/introduction.py index 08a71b27292..540d928f7f5 100644 --- a/homeassistant/components/introduction.py +++ b/homeassistant/components/introduction.py @@ -9,7 +9,6 @@ https://home-assistant.io/components/introduction/ import logging DOMAIN = 'introduction' -DEPENDENCIES = [] def setup(hass, config=None): diff --git a/homeassistant/components/isy994.py b/homeassistant/components/isy994.py index 427ef4f048e..2a36f2060fc 100644 --- a/homeassistant/components/isy994.py +++ b/homeassistant/components/isy994.py @@ -20,7 +20,6 @@ from homeassistant.const import ( ATTR_FRIENDLY_NAME) DOMAIN = "isy994" -DEPENDENCIES = [] REQUIREMENTS = ['PyISY==1.0.5'] DISCOVER_LIGHTS = "isy994.lights" DISCOVER_SWITCHES = "isy994.switches" diff --git a/homeassistant/components/keyboard.py b/homeassistant/components/keyboard.py index ea650d8b421..c772d1c6e74 100644 --- a/homeassistant/components/keyboard.py +++ b/homeassistant/components/keyboard.py @@ -15,7 +15,6 @@ from homeassistant.const import ( DOMAIN = "keyboard" -DEPENDENCIES = [] REQUIREMENTS = ['pyuserinput==0.1.9'] diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index d7f8746de5a..1b80035fb0d 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -21,7 +21,6 @@ import homeassistant.util.color as color_util DOMAIN = "light" -DEPENDENCIES = [] SCAN_INTERVAL = 30 GROUP_NAME_ALL_LIGHTS = 'all lights' diff --git a/homeassistant/components/light/blinksticklight.py b/homeassistant/components/light/blinksticklight.py index 5cc14a9034b..fae9890c93d 100644 --- a/homeassistant/components/light/blinksticklight.py +++ b/homeassistant/components/light/blinksticklight.py @@ -14,7 +14,6 @@ _LOGGER = logging.getLogger(__name__) REQUIREMENTS = ["blinkstick==1.1.7"] -DEPENDENCIES = [] # pylint: disable=unused-argument diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index 2cbd3a40872..fdc2da3e8d4 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -20,7 +20,6 @@ from homeassistant.const import ( from homeassistant.components import (group, wink) DOMAIN = 'lock' -DEPENDENCIES = [] SCAN_INTERVAL = 30 GROUP_NAME_ALL_LOCKS = 'all locks' diff --git a/homeassistant/components/logger.py b/homeassistant/components/logger.py index a6dafa56005..9a5d1c59d1a 100644 --- a/homeassistant/components/logger.py +++ b/homeassistant/components/logger.py @@ -10,7 +10,6 @@ import logging from collections import OrderedDict DOMAIN = 'logger' -DEPENDENCIES = [] LOGSEVERITY = { 'CRITICAL': 50, diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 8140bbb2af9..8204052b4a9 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -22,7 +22,6 @@ from homeassistant.const import ( SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK) DOMAIN = 'media_player' -DEPENDENCIES = [] SCAN_INTERVAL = 10 ENTITY_ID_FORMAT = DOMAIN + '.{}' diff --git a/homeassistant/components/modbus.py b/homeassistant/components/modbus.py index 099801eb7cf..6f53c89835a 100644 --- a/homeassistant/components/modbus.py +++ b/homeassistant/components/modbus.py @@ -13,7 +13,6 @@ from homeassistant.const import (EVENT_HOMEASSISTANT_START, DOMAIN = "modbus" -DEPENDENCIES = [] REQUIREMENTS = ['https://github.com/bashwork/pymodbus/archive/' 'd7fc4f1cc975631e0a9011390e8017f64b612661.zip#pymodbus==1.2.0'] diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 9ec5169c729..7ce9340b27e 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -30,7 +30,6 @@ DEFAULT_QOS = 0 SERVICE_PUBLISH = 'publish' EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED' -DEPENDENCIES = [] REQUIREMENTS = ['paho-mqtt==1.1', 'jsonpath-rw==1.4.0'] CONF_BROKER = 'broker' diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index 6cd7a2196cf..9182f1dbf3a 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -17,7 +17,6 @@ from homeassistant.helpers import config_per_platform from homeassistant.const import CONF_NAME DOMAIN = "notify" -DEPENDENCIES = [] # Title of notification ATTR_TITLE = "title" diff --git a/homeassistant/components/recorder.py b/homeassistant/components/recorder.py index b09e10f7d92..6b2557dd1d6 100644 --- a/homeassistant/components/recorder.py +++ b/homeassistant/components/recorder.py @@ -23,7 +23,6 @@ from homeassistant.const import ( EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) DOMAIN = "recorder" -DEPENDENCIES = [] DB_FILE = 'home-assistant.db' diff --git a/homeassistant/components/rfxtrx.py b/homeassistant/components/rfxtrx.py index 3c4675d806d..894634c8fc2 100644 --- a/homeassistant/components/rfxtrx.py +++ b/homeassistant/components/rfxtrx.py @@ -9,7 +9,6 @@ https://home-assistant.io/components/rfxtrx/ import logging from homeassistant.util import slugify -DEPENDENCIES = [] REQUIREMENTS = ['https://github.com/Danielhiversen/pyRFXtrx/archive/0.2.zip' + '#RFXtrx==0.2'] diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 32ee59a6fa9..95cb331b91f 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -12,7 +12,6 @@ from homeassistant.helpers.entity_component import EntityComponent from homeassistant.components import wink, zwave, isy994, verisure DOMAIN = 'sensor' -DEPENDENCIES = [] SCAN_INTERVAL = 30 ENTITY_ID_FORMAT = DOMAIN + '.{}' diff --git a/homeassistant/components/shell_command.py b/homeassistant/components/shell_command.py index 61c9add3f23..5e12c8bfd6e 100644 --- a/homeassistant/components/shell_command.py +++ b/homeassistant/components/shell_command.py @@ -12,7 +12,6 @@ import subprocess from homeassistant.util import slugify DOMAIN = 'shell_command' -DEPENDENCIES = [] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py index a5b83e76929..efe0a7dec2b 100644 --- a/homeassistant/components/sun.py +++ b/homeassistant/components/sun.py @@ -15,7 +15,6 @@ import homeassistant.util.dt as dt_util from homeassistant.helpers.event import track_point_in_utc_time from homeassistant.helpers.entity import Entity -DEPENDENCIES = [] REQUIREMENTS = ['astral==0.8.1'] DOMAIN = "sun" ENTITY_ID = "sun.sun" diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index 9a0abb4ce7a..e7b3c629f39 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -20,7 +20,6 @@ from homeassistant.components import ( group, discovery, wink, isy994, verisure, zwave) DOMAIN = 'switch' -DEPENDENCIES = [] SCAN_INTERVAL = 30 GROUP_NAME_ALL_SWITCHES = 'all switches' diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py index 480e3e4805e..b475fce39d8 100644 --- a/homeassistant/components/thermostat/__init__.py +++ b/homeassistant/components/thermostat/__init__.py @@ -20,7 +20,6 @@ from homeassistant.const import ( TEMP_CELCIUS) DOMAIN = "thermostat" -DEPENDENCIES = [] ENTITY_ID_FORMAT = DOMAIN + ".{}" SCAN_INTERVAL = 60 diff --git a/homeassistant/components/updater.py b/homeassistant/components/updater.py index 803cfa609ca..a020a6c0abb 100644 --- a/homeassistant/components/updater.py +++ b/homeassistant/components/updater.py @@ -16,7 +16,6 @@ from homeassistant.helpers import event _LOGGER = logging.getLogger(__name__) PYPI_URL = 'https://pypi.python.org/pypi/homeassistant/json' -DEPENDENCIES = [] DOMAIN = 'updater' ENTITY_ID = 'updater.updater' diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index bd79210bf75..1ab82236596 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -17,7 +17,6 @@ from homeassistant.const import ( ATTR_SERVICE, ATTR_DISCOVERED, ATTR_FRIENDLY_NAME) DOMAIN = "wink" -DEPENDENCIES = [] REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' '42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip' '#python-wink==0.2'] diff --git a/homeassistant/components/zone.py b/homeassistant/components/zone.py index a32a297caeb..da0341129f7 100644 --- a/homeassistant/components/zone.py +++ b/homeassistant/components/zone.py @@ -15,7 +15,6 @@ from homeassistant.helpers.entity import Entity from homeassistant.util.location import distance DOMAIN = "zone" -DEPENDENCIES = [] ENTITY_ID_FORMAT = 'zone.{}' ENTITY_ID_HOME = ENTITY_ID_FORMAT.format('home') STATE = 'zoning' diff --git a/homeassistant/components/zwave.py b/homeassistant/components/zwave.py index 11515e4031d..5d526293083 100644 --- a/homeassistant/components/zwave.py +++ b/homeassistant/components/zwave.py @@ -17,7 +17,6 @@ from homeassistant.const import ( EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED) DOMAIN = "zwave" -DEPENDENCIES = [] REQUIREMENTS = ['pydispatcher==2.0.5'] CONF_USB_STICK_PATH = "usb_path" diff --git a/homeassistant/loader.py b/homeassistant/loader.py index b05083b4abd..8b38f5e0966 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -193,7 +193,7 @@ def _load_order_component(comp_name, load_order, loading): loading.add(comp_name) - for dependency in component.DEPENDENCIES: + for dependency in getattr(component, 'DEPENDENCIES', []): # Check not already loaded if dependency in load_order: continue From 08da1e6f8d8c07b1d79131103916560d14ed35ac Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 26 Nov 2015 23:57:34 +0100 Subject: [PATCH 081/166] Add influx component --- .coveragerc | 1 + requirements_all.txt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.coveragerc b/.coveragerc index 8efc162b3eb..e41d31b2830 100644 --- a/.coveragerc +++ b/.coveragerc @@ -49,6 +49,7 @@ omit = homeassistant/components/discovery.py homeassistant/components/downloader.py homeassistant/components/ifttt.py + homeassistant/components/influx.py homeassistant/components/keyboard.py homeassistant/components/light/hue.py homeassistant/components/light/mqtt.py diff --git a/requirements_all.txt b/requirements_all.txt index a9f24cdb65f..e8281efcfd6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -23,6 +23,9 @@ netdisco==0.5.1 # homeassistant.components.ifttt pyfttt==0.3 +# homeassistant.components.influx +influxdb==2.10.0 + # homeassistant.components.isy994 PyISY==1.0.5 @@ -165,4 +168,3 @@ https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60 # homeassistant.components.zwave pydispatcher==2.0.5 - From 74b37bd61b2db9a4be25b9d7a9d10455f3697821 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 26 Nov 2015 23:57:57 +0100 Subject: [PATCH 082/166] Change to exception instead of error --- homeassistant/components/influx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/influx.py b/homeassistant/components/influx.py index 78c3d15787e..5de2f3bdd73 100644 --- a/homeassistant/components/influx.py +++ b/homeassistant/components/influx.py @@ -113,7 +113,7 @@ def setup(hass, config): try: influx.write_points(json_body) except exceptions.InfluxDBClientError: - _LOGGER.error("Field type conflict") + _LOGGER.exception('Error saving event to Influx') hass.bus.listen(EVENT_STATE_CHANGED, event_listener) From 67bcb00c9e28c546a17bc91862d74c41705b4672 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 26 Nov 2015 19:09:32 +0100 Subject: [PATCH 083/166] Add demo platform for alarm control panel --- .../components/alarm_control_panel/demo.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 homeassistant/components/alarm_control_panel/demo.py diff --git a/homeassistant/components/alarm_control_panel/demo.py b/homeassistant/components/alarm_control_panel/demo.py new file mode 100644 index 00000000000..c20a0462540 --- /dev/null +++ b/homeassistant/components/alarm_control_panel/demo.py @@ -0,0 +1,74 @@ +""" +homeassistant.components.alarm_control_panel.demo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Demo platform that has two fake alarm control panels. +""" +import homeassistant.components.alarm_control_panel as Alarm +from homeassistant.const import (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_AWAY) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """ Sets up the Demo alarm control panels. """ + add_devices([ + DemoAlarmControlPanel('Front door', '1234', STATE_ALARM_ARMED_HOME), + DemoAlarmControlPanel('Safe', '1234', STATE_ALARM_ARMED_AWAY), + ]) + + +class DemoAlarmControlPanel(Alarm.AlarmControlPanel): + """ A Demo alarm control panel. """ + + def __init__(self, name, code, state): + self._state = state + self._name = name + self._code = str(code) if code else 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 alarm_disarm(self, code=None): + """ Send disarm command. """ + if not self._validate_code(code, STATE_ALARM_DISARMED): + return + self._state = STATE_ALARM_DISARMED + self.update_ha_state() + + def alarm_arm_home(self, code=None): + """ Send arm home command. """ + if not self._validate_code(code, STATE_ALARM_ARMED_HOME): + return + self._state = STATE_ALARM_ARMED_HOME + self.update_ha_state() + + def alarm_arm_away(self, code=None): + """ Send arm away command. """ + if not self._validate_code(code, STATE_ALARM_ARMED_AWAY): + return + self._state = STATE_ALARM_ARMED_AWAY + self.update_ha_state() + + def alarm_trigger(self, code=None): + """ Send alarm trigger command. No code needed. """ + pass + + def _validate_code(self, code, state): + """ Validate given code. """ + return self._code is None or code == self._code From 60460e82174c16625dd11966df70a8157b24777d Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 26 Nov 2015 19:10:06 +0100 Subject: [PATCH 084/166] Add alarm control panel as platform and remove camera/acp entries --- homeassistant/components/demo.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 547a1d54a03..261c0e1b6a9 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone'] COMPONENTS_WITH_DEMO_PLATFORM = [ 'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor', - 'thermostat', 'camera', 'binary_sensor'] + 'thermostat', 'camera', 'binary_sensor', 'alarm_control_panel'] def setup(hass, config): @@ -55,23 +55,6 @@ def setup(hass, config): group.setup_group(hass, 'bedroom', [lights[0], switches[1], media_players[0]]) - # Setup IP Camera - bootstrap.setup_component( - hass, 'camera', - {'camera': { - 'platform': 'generic', - 'name': 'IP Camera', - '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 7224775aa87e2abf60a0424aacf9a563821e4e7e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 27 Nov 2015 00:40:51 +0100 Subject: [PATCH 085/166] Use manual alarm control panel as base for demo --- .../components/alarm_control_panel/demo.py | 60 ++++--------------- 1 file changed, 12 insertions(+), 48 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/demo.py b/homeassistant/components/alarm_control_panel/demo.py index c20a0462540..2d2e36d03bc 100644 --- a/homeassistant/components/alarm_control_panel/demo.py +++ b/homeassistant/components/alarm_control_panel/demo.py @@ -3,72 +3,36 @@ homeassistant.components.alarm_control_panel.demo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Demo platform that has two fake alarm control panels. """ -import homeassistant.components.alarm_control_panel as Alarm -from homeassistant.const import (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, +import homeassistant.components.alarm_control_panel.manual as Alarm +from homeassistant.const import (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_AWAY) def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the Demo alarm control panels. """ add_devices([ - DemoAlarmControlPanel('Front door', '1234', STATE_ALARM_ARMED_HOME), - DemoAlarmControlPanel('Safe', '1234', STATE_ALARM_ARMED_AWAY), + + DemoAlarmControlPanel(hass, 'Front door', '1234', 2, 4, + STATE_ALARM_DISARMED), + DemoAlarmControlPanel(hass, 'Safe', '1234', 2, 4, + STATE_ALARM_ARMED_AWAY), ]) -class DemoAlarmControlPanel(Alarm.AlarmControlPanel): +# pylint: disable=too-many-arguments +class DemoAlarmControlPanel(Alarm.ManualAlarm): """ A Demo alarm control panel. """ - def __init__(self, name, code, state): + def __init__(self, hass, name, code, pending_time, trigger_time, state): + super().__init__(hass, name, code, pending_time, trigger_time) self._state = state - self._name = name - self._code = str(code) if code else None @property def should_poll(self): - """ No polling needed. """ + """ No polling needed for a demo panel. """ 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 alarm_disarm(self, code=None): - """ Send disarm command. """ - if not self._validate_code(code, STATE_ALARM_DISARMED): - return - self._state = STATE_ALARM_DISARMED - self.update_ha_state() - - def alarm_arm_home(self, code=None): - """ Send arm home command. """ - if not self._validate_code(code, STATE_ALARM_ARMED_HOME): - return - self._state = STATE_ALARM_ARMED_HOME - self.update_ha_state() - - def alarm_arm_away(self, code=None): - """ Send arm away command. """ - if not self._validate_code(code, STATE_ALARM_ARMED_AWAY): - return - self._state = STATE_ALARM_ARMED_AWAY - self.update_ha_state() - - def alarm_trigger(self, code=None): - """ Send alarm trigger command. No code needed. """ - pass - - def _validate_code(self, code, state): - """ Validate given code. """ - return self._code is None or code == self._code From 7204bc018fc127a9f2b677a1f184a25b9454b26a Mon Sep 17 00:00:00 2001 From: pavoni Date: Fri, 27 Nov 2015 11:43:43 +0000 Subject: [PATCH 086/166] Add exception handler for vera timeout --- homeassistant/components/switch/vera.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index 80724f92757..14983919c64 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -126,5 +126,8 @@ class VeraSwitch(ToggleEntity): def update(self): # We need to debounce the status call after turning switch on or off # because the vera has some lag in updating the device status - if (self.last_command_send + 5) < time.time(): - self.is_on_status = self.vera_device.is_switched_on() + try: + if (self.last_command_send + 5) < time.time(): + self.is_on_status = self.vera_device.is_switched_on() + except RequestException: + _LOGGER.warning('Could not update status for %s', self.name) From 00f0dfb97104d465c90942fb0e2190bc99742c90 Mon Sep 17 00:00:00 2001 From: pavoni Date: Fri, 27 Nov 2015 18:21:26 +0000 Subject: [PATCH 087/166] Trap and trace error rather than throwing exception when efergy server --- homeassistant/components/sensor/efergy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/efergy.py b/homeassistant/components/sensor/efergy.py index 99140b5b2a9..447903a714e 100644 --- a/homeassistant/components/sensor/efergy.py +++ b/homeassistant/components/sensor/efergy.py @@ -97,5 +97,5 @@ class EfergySensor(Entity): self._state = response.json()['sum'] else: self._state = 'Unknown' - except RequestException: + except (RequestException, ValueError): _LOGGER.warning('Could not update status for %s', self.name) From bbf73e0bae587583bc16c0e87942e29cb4787566 Mon Sep 17 00:00:00 2001 From: pavoni Date: Fri, 27 Nov 2015 19:05:15 +0000 Subject: [PATCH 088/166] Bump pywemo version - fixed scan device = None bug --- homeassistant/components/switch/wemo.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index 1d701bf88cc..bad471ce437 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.2'] +REQUIREMENTS = ['pywemo==0.3.3'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index a9f24cdb65f..982cf125572 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -149,7 +149,7 @@ hikvision==0.4 orvibo==1.0.0 # homeassistant.components.switch.wemo -pywemo==0.3.2 +pywemo==0.3.3 # homeassistant.components.thermostat.honeywell evohomeclient==0.2.3 From d91fe792c56d872e9054fd608978fd51a99142dd Mon Sep 17 00:00:00 2001 From: happyleaves Date: Sat, 14 Nov 2015 12:56:18 -0500 Subject: [PATCH 089/166] limitlessled improvements --- .../components/light/limitlessled.py | 348 +++++++++++------- requirements_all.txt | 2 +- 2 files changed, 226 insertions(+), 124 deletions(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index ad5f8487a2a..8700dd85bf2 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -8,171 +8,273 @@ https://home-assistant.io/components/light.limitlessled/ """ import logging -from homeassistant.const import DEVICE_DEFAULT_NAME from homeassistant.components.light import (Light, ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_EFFECT, + ATTR_COLOR_TEMP, ATTR_TRANSITION, + ATTR_FLASH, FLASH_LONG, EFFECT_COLORLOOP, EFFECT_WHITE) +from limitlessled import Color +from limitlessled.bridge import Bridge +from limitlessled.group.rgbw import RgbwGroup +from limitlessled.group.white import WhiteGroup +from limitlessled.pipeline import Pipeline +from limitlessled.presets import COLORLOOP + + _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['ledcontroller==1.1.0'] - -COLOR_TABLE = { - 'white': [0xFF, 0xFF, 0xFF], - 'violet': [0xEE, 0x82, 0xEE], - 'royal_blue': [0x41, 0x69, 0xE1], - 'baby_blue': [0x87, 0xCE, 0xFA], - 'aqua': [0x00, 0xFF, 0xFF], - 'royal_mint': [0x7F, 0xFF, 0xD4], - 'seafoam_green': [0x2E, 0x8B, 0x57], - 'green': [0x00, 0x80, 0x00], - 'lime_green': [0x32, 0xCD, 0x32], - 'yellow': [0xFF, 0xFF, 0x00], - 'yellow_orange': [0xDA, 0xA5, 0x20], - 'orange': [0xFF, 0xA5, 0x00], - 'red': [0xFF, 0x00, 0x00], - 'pink': [0xFF, 0xC0, 0xCB], - 'fusia': [0xFF, 0x00, 0xFF], - 'lilac': [0xDA, 0x70, 0xD6], - 'lavendar': [0xE6, 0xE6, 0xFA], -} +REQUIREMENTS = ['limitlessled==1.0.0'] +RGB_BOUNDARY = 40 +DEFAULT_TRANSITION = 0 +DEFAULT_PORT = 8899 +DEFAULT_VERSION = 5 +DEFAULT_LED_TYPE = 'rgbw' +WHITE = [255, 255, 255] -def _distance_squared(rgb1, rgb2): - """ Return sum of squared distances of each color part. """ - return sum((val1-val2)**2 for val1, val2 in zip(rgb1, rgb2)) - - -def _rgb_to_led_color(rgb_color): - """ Convert an RGB color to the closest color string and color. """ - return sorted((_distance_squared(rgb_color, color), name) - for name, color in COLOR_TABLE.items())[0][1] +def legacy_setup(config, add_devices_callback): + """ Perform setup using legacy format. """ + bridges = config.get('bridges', [config]) + lights = [] + for bridge_conf in bridges: + bridge = Bridge(bridge_conf.get('host')) + for i in range(1, 5): + name_key = 'group_%d_name' % i + if name_key in bridge_conf: + group_type = bridge_conf.get('group_%d_type' % i, + DEFAULT_LED_TYPE) + group = bridge.add_group(i, + bridge_conf.get(name_key), + group_type) + lights.append(LimitlessLEDGroup.factory(group)) + add_devices_callback(lights) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Gets the LimitlessLED lights. """ - import ledcontroller - # Handle old configuration format: - bridges = config.get('bridges', [config]) - - for bridge_id, bridge in enumerate(bridges): - bridge['id'] = bridge_id - - pool = ledcontroller.LedControllerPool([x['host'] for x in bridges]) + # Two legacy configuration formats are supported to + # maintain backwards compatibility. + legacy_setup(config, add_devices_callback) + # Use the expanded configuration format. + if 'bridges' not in config: + return lights = [] - for bridge in bridges: - for i in range(1, 5): - name_key = 'group_%d_name' % i - if name_key in bridge: - group_type = bridge.get('group_%d_type' % i, 'rgbw') - lights.append(LimitlessLED.factory(pool, bridge['id'], i, - bridge[name_key], - group_type)) - + for bridge_conf in config.get('bridges'): + if 'groups' not in bridge_conf: + continue + bridge = Bridge(bridge_conf.get('host'), + port=bridge_conf.get('port', DEFAULT_PORT), + version=bridge_conf.get('version', DEFAULT_VERSION)) + for group_conf in bridge_conf.get('groups'): + group = bridge.add_group(group_conf.get('number'), + group_conf.get('name'), + group_conf.get('type', DEFAULT_LED_TYPE)) + lights.append(LimitlessLEDGroup.factory(group)) add_devices_callback(lights) -class LimitlessLED(Light): - """ Represents a LimitlessLED light """ +def state(new_state): + """ State decorator. + + Specify True (turn on) or False (turn off). + """ + def decorator(function): + """ Decorator function. """ + # pylint: disable=no-member + def wrapper(self, **kwargs): + """ Wrap a group state change. """ + pipeline = Pipeline() + transition_time = DEFAULT_TRANSITION + # Stop any repeating pipeline. + if self.repeating: + self.repeating = False + self.group.stop() + # Not on? Turn on. + if not self.is_on: + pipeline.on() + # Set transition time. + if ATTR_TRANSITION in kwargs: + transition_time = kwargs[ATTR_TRANSITION] + # Do group type-specific work. + function(self, transition_time, pipeline, **kwargs) + # Update state. + self.on_state = new_state + self.group.enqueue(pipeline) + self.update_ha_state() + return wrapper + return decorator + + +class LimitlessLEDGroup(Light): + """ LimitessLED group. """ + def __init__(self, group): + """ Initialize a group. """ + self.group = group + self.repeating = False + self.on_state = False + self._brightness = None @staticmethod - def factory(pool, controller_id, group, name, group_type): - ''' Construct a Limitless LED of the appropriate type ''' - if group_type == 'white': - return WhiteLimitlessLED(pool, controller_id, group, name) - elif group_type == 'rgbw': - return RGBWLimitlessLED(pool, controller_id, group, name) - - # pylint: disable=too-many-arguments - def __init__(self, pool, controller_id, group, name, group_type): - self.pool = pool - self.controller_id = controller_id - self.group = group - - self.pool.execute(self.controller_id, "set_group_type", self.group, - group_type) - - # LimitlessLEDs don't report state, we have track it ourselves. - self.pool.execute(self.controller_id, "off", self.group) - - self._name = name or DEVICE_DEFAULT_NAME - self._state = False + def factory(group): + """ Produce LimitlessLEDGroup objects. """ + if isinstance(group, WhiteGroup): + return LimitlessLEDWhiteGroup(group) + elif isinstance(group, RgbwGroup): + return LimitlessLEDRGBWGroup(group) @property def should_poll(self): - """ No polling needed. """ + """ No polling needed. + + LimitlessLED state cannot be fetched. + """ return False @property def name(self): - """ Returns the name of the device if any. """ - return self._name + """ Returns the name of the group. """ + return self.group.name @property def is_on(self): """ True if device is on. """ - return self._state - - def turn_off(self, **kwargs): - """ Turn the device off. """ - self._state = False - self.pool.execute(self.controller_id, "off", self.group) - self.update_ha_state() - - -class RGBWLimitlessLED(LimitlessLED): - """ Represents a RGBW LimitlessLED light """ - - def __init__(self, pool, controller_id, group, name): - super().__init__(pool, controller_id, group, name, 'rgbw') - - self._brightness = 100 - self._led_color = 'white' + return self.on_state @property def brightness(self): + """ Brightness property. """ return self._brightness + @state(False) + def turn_off(self, transition_time, pipeline, **kwargs): + """ Turn off a group. """ + pipeline.transition(transition_time, brightness=0.0).off() + + +class LimitlessLEDWhiteGroup(LimitlessLEDGroup): + """ LimitlessLED White group. """ + def __init__(self, group): + """ Initialize White group. """ + super().__init__(group) + # Initialize group with known values. + self.group.on = True + self.group.temperature = 1.0 + self.group.brightness = 0.0 + self._brightness = _to_hass_brightness(1.0) + self._temperature = _to_hass_temperature(self.group.temperature) + self.group.on = False + + @property + def color_temp(self): + """ Temperature property. """ + return self._temperature + + @state(True) + def turn_on(self, transition_time, pipeline, **kwargs): + """ Turn on (or adjust property of) a group. """ + # Check arguments. + if ATTR_BRIGHTNESS in kwargs: + self._brightness = kwargs[ATTR_BRIGHTNESS] + if ATTR_COLOR_TEMP in kwargs: + self._temperature = kwargs[ATTR_COLOR_TEMP] + # Set up transition. + pipeline.transition(transition_time, + brightness=_from_hass_brightness( + self._brightness), + temperature=_from_hass_temperature( + self._temperature)) + + +class LimitlessLEDRGBWGroup(LimitlessLEDGroup): + """ LimitlessLED RGBW group. """ + def __init__(self, group): + """ Initialize RGBW group. """ + super().__init__(group) + # Initialize group with known values. + self.group.on = True + self.group.white() + self._color = WHITE + self.group.brightness = 0.0 + self._brightness = _to_hass_brightness(1.0) + self.group.on = False + @property def rgb_color(self): - return COLOR_TABLE[self._led_color] - - def turn_on(self, **kwargs): - """ Turn the device on. """ - self._state = True + """ Color property. """ + return self._color + @state(True) + def turn_on(self, transition_time, pipeline, **kwargs): + """ Turn on (or adjust property of) a group. """ + # Check arguments. if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] - if ATTR_RGB_COLOR in kwargs: - self._led_color = _rgb_to_led_color(kwargs[ATTR_RGB_COLOR]) - - effect = kwargs.get(ATTR_EFFECT) - - if effect == EFFECT_COLORLOOP: - self.pool.execute(self.controller_id, "disco", self.group) - elif effect == EFFECT_WHITE: - self.pool.execute(self.controller_id, "white", self.group) - else: - self.pool.execute(self.controller_id, "set_color", - self._led_color, self.group) - - # Brightness can be set independently of color - self.pool.execute(self.controller_id, "set_brightness", - self._brightness / 255.0, self.group) - - self.update_ha_state() + self._color = kwargs[ATTR_RGB_COLOR] + # White is a special case. + if min(self._color) > 256 - RGB_BOUNDARY: + pipeline.white() + self._color = WHITE + # Set up transition. + pipeline.transition(transition_time, + brightness=_from_hass_brightness( + self._brightness), + color=_from_hass_color(self._color)) + # Flash. + if ATTR_FLASH in kwargs: + duration = 0 + if kwargs[ATTR_FLASH] == FLASH_LONG: + duration = 1 + pipeline.flash(duration=duration) + # Add effects. + if ATTR_EFFECT in kwargs: + if kwargs[ATTR_EFFECT] == EFFECT_COLORLOOP: + self.repeating = True + pipeline.append(COLORLOOP) + if kwargs[ATTR_EFFECT] == EFFECT_WHITE: + pipeline.white() + self._color = WHITE -class WhiteLimitlessLED(LimitlessLED): - """ Represents a White LimitlessLED light """ +def _from_hass_temperature(temperature): + """ Convert Home Assistant color temperature + units to percentage. + """ + return (temperature - 154) / 346 - def __init__(self, pool, controller_id, group, name): - super().__init__(pool, controller_id, group, name, 'white') - def turn_on(self, **kwargs): - """ Turn the device on. """ - self._state = True - self.pool.execute(self.controller_id, "on", self.group) - self.update_ha_state() +def _to_hass_temperature(temperature): + """ Convert percentage to Home Assistant + color temperature units. + """ + return int(temperature * 346) + 154 + + +def _from_hass_brightness(brightness): + """ Convert Home Assistant brightness units + to percentage. + """ + return brightness / 255 + + +def _to_hass_brightness(brightness): + """ Convert percentage to Home Assistant + brightness units. + """ + return int(brightness * 255) + + +def _from_hass_color(color): + """ Convert Home Assistant RGB list + to Color tuple. + """ + return Color(*tuple(color)) + + +def _to_hass_color(color): + """ Convert from Color tuple to + Home Assistant RGB list. + """ + return list([int(c) for c in color]) diff --git a/requirements_all.txt b/requirements_all.txt index a9f24cdb65f..e563895d94b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -36,7 +36,7 @@ blinkstick==1.1.7 phue==0.8 # homeassistant.components.light.limitlessled -ledcontroller==1.1.0 +limitlessled==1.0.0 # homeassistant.components.light.tellstick # homeassistant.components.sensor.tellstick From 6809a881faf0cf2a4e2036805a1327ff39b48d29 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 01:02:35 -0800 Subject: [PATCH 090/166] Tweak MQTT Motor component --- homeassistant/components/motor/__init__.py | 20 ++++++--- homeassistant/components/motor/mqtt.py | 16 -------- tests/components/motor/test_mqtt.py | 48 +++++++++++++++++++++- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/homeassistant/components/motor/__init__.py b/homeassistant/components/motor/__init__.py index feea836a0dd..806dd9e0eb1 100644 --- a/homeassistant/components/motor/__init__.py +++ b/homeassistant/components/motor/__init__.py @@ -17,7 +17,6 @@ from homeassistant.const import ( DOMAIN = 'motor' -DEPENDENCIES = [] SCAN_INTERVAL = 15 GROUP_NAME_ALL_MOTORS = 'all motors' @@ -30,6 +29,8 @@ DISCOVERY_PLATFORMS = {} _LOGGER = logging.getLogger(__name__) +ATTR_CURRENT_POSITION = 'current_position' + def is_open(hass, entity_id=None): """ Returns if the motor is open based on the statemachine. """ @@ -114,17 +115,24 @@ class MotorDevice(Entity): @property def state_attributes(self): - """ Returns optional state attributes. """ - return None + """ Return the state attributes. """ + current = self.current_position + + if current is None: + return None + + return { + ATTR_CURRENT_POSITION: current + } def open(self, **kwargs): - """ Open the device. """ + """ Open the motor. """ raise NotImplementedError() def close(self, **kwargs): - """ Close the device. """ + """ Close the motor. """ raise NotImplementedError() def stop(self, **kwargs): - """ Stop the device. """ + """ Stop the motor. """ raise NotImplementedError() diff --git a/homeassistant/components/motor/mqtt.py b/homeassistant/components/motor/mqtt.py index 2aac5e37c16..1075030fc37 100644 --- a/homeassistant/components/motor/mqtt.py +++ b/homeassistant/components/motor/mqtt.py @@ -18,10 +18,7 @@ DEFAULT_PAYLOAD_OPEN = "OPEN" DEFAULT_PAYLOAD_CLOSE = "CLOSE" DEFAULT_PAYLOAD_STOP = "STOP" -ATTR_CURRENT_POSITION = 'current_position' - -# pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Add MQTT Motor """ @@ -88,11 +85,6 @@ class MqttMotor(MotorDevice): None is unknown, 0 is closed, 100 is fully open. """ return self._state - @property - def is_open(self): - """ True if device is current position is not zero. """ - return self._state > 0 - def open(self, **kwargs): """ Open the device. """ mqtt.publish(self.hass, self._command_topic, self._payload_open, @@ -107,11 +99,3 @@ class MqttMotor(MotorDevice): """ Stop the device. """ mqtt.publish(self.hass, self._command_topic, self._payload_stop, self._qos) - - @property - def state_attributes(self): - """ Return the state attributes. """ - state_attr = {} - if self._state is not None: - state_attr[ATTR_CURRENT_POSITION] = self._state - return state_attr diff --git a/tests/components/motor/test_mqtt.py b/tests/components/motor/test_mqtt.py index 4d7af04ae6c..1638e830f2d 100644 --- a/tests/components/motor/test_mqtt.py +++ b/tests/components/motor/test_mqtt.py @@ -58,7 +58,7 @@ class TestMotorMQTT(unittest.TestCase): state = self.hass.states.get('motor.test') self.assertEqual(STATE_OPEN, state.state) - def test_sending_mqtt_commands(self): + def test_send_open_command(self): self.assertTrue(motor.setup(self.hass, { 'motor': { 'platform': 'mqtt', @@ -75,7 +75,51 @@ class TestMotorMQTT(unittest.TestCase): motor.call_open(self.hass, 'motor.test') self.hass.pool.block_till_done() - self.assertEqual(('command-topic', 'OPEN', 2), + self.assertEqual(('command-topic', 'OPEN', 2, False), + self.mock_publish.mock_calls[-1][1]) + state = self.hass.states.get('motor.test') + self.assertEqual(STATE_UNKNOWN, state.state) + + def test_send_close_command(self): + self.assertTrue(motor.setup(self.hass, { + 'motor': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'qos': 2 + } + })) + + state = self.hass.states.get('motor.test') + self.assertEqual(STATE_UNKNOWN, state.state) + + motor.call_close(self.hass, 'motor.test') + self.hass.pool.block_till_done() + + self.assertEqual(('command-topic', 'CLOSE', 2, False), + self.mock_publish.mock_calls[-1][1]) + state = self.hass.states.get('motor.test') + self.assertEqual(STATE_UNKNOWN, state.state) + + def test_send_stop_command(self): + self.assertTrue(motor.setup(self.hass, { + 'motor': { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'qos': 2 + } + })) + + state = self.hass.states.get('motor.test') + self.assertEqual(STATE_UNKNOWN, state.state) + + motor.call_stop(self.hass, 'motor.test') + self.hass.pool.block_till_done() + + self.assertEqual(('command-topic', 'STOP', 2, False), self.mock_publish.mock_calls[-1][1]) state = self.hass.states.get('motor.test') self.assertEqual(STATE_UNKNOWN, state.state) From 1146d6e58d4187da0300ddd08d9b3cc5459bb006 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 01:18:02 -0800 Subject: [PATCH 091/166] Allow thermostat temperatures with decimal numbers --- homeassistant/components/frontend/version.py | 2 +- .../components/frontend/www_static/frontend.html | 6 +++--- .../frontend/www_static/home-assistant-polymer | 2 +- homeassistant/components/thermostat/__init__.py | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 0199b05156e..ed954909e66 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 = "dff74f773ea8b0356b0bd8130ed6f0cf" +VERSION = "c90d40a0240cc1feec791ee820d928b3" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index b2a2eb97b3e..73b2ac1b7dd 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -5838,7 +5838,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN .has-away_mode .away-mode-toggle { display: block; - }

- -
Initializing
+ +
diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index ed954909e66..7e957562bba 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 = "c90d40a0240cc1feec791ee820d928b3" +VERSION = "c1df3a08faa4a9978b25639ca0fd63cd" diff --git a/homeassistant/components/frontend/www_static/favicon-384x384.png b/homeassistant/components/frontend/www_static/favicon-384x384.png new file mode 100644 index 0000000000000000000000000000000000000000..51f67770790077d5e271231ebeadf09a08feb52c GIT binary patch literal 19825 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
)*=#XTG%lIsERmIq&*q^1o-@c$g^87+q{t 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 literal 0 HcmV?d00001 diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 73b2ac1b7dd..cf19d314f24 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -1,6 +1,6 @@ -
\ 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 62e494bd045..f29b1062b30 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 62e494bd04509e8d9b73354b0e17d3381955e0c8 +Subproject commit f29b1062b30c76ceeea87fd426a042d98358394a diff --git a/homeassistant/components/frontend/www_static/manifest.json b/homeassistant/components/frontend/www_static/manifest.json index 69143ce5179..3d0eb5fa443 100644 --- a/homeassistant/components/frontend/www_static/manifest.json +++ b/homeassistant/components/frontend/www_static/manifest.json @@ -5,10 +5,14 @@ "display": "standalone", "icons": [ { - "src": "\/static\/favicon-192x192.png", + "src": "/static/favicon-192x192.png", "sizes": "192x192", - "type": "image\/png", - "density": "4.0" + "type": "image/png", + }, + { + "src": "/static/favicon-384x384.png", + "sizes": "384x384", + "type": "image/png", } ] } diff --git a/homeassistant/components/frontend/www_static/webcomponents-lite.min.js b/homeassistant/components/frontend/www_static/webcomponents-lite.min.js index 3a3fd4e8564..4f8af01fd15 100644 --- a/homeassistant/components/frontend/www_static/webcomponents-lite.min.js +++ b/homeassistant/components/frontend/www_static/webcomponents-lite.min.js @@ -7,6 +7,6 @@ * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt */ -// @version 0.7.17 -!function(){window.WebComponents=window.WebComponents||{flags:{}};var e="webcomponents-lite.js",t=document.querySelector('script[src*="'+e+'"]'),n={};if(!n.noOpts){if(location.search.slice(1).split("&").forEach(function(e){var t,r=e.split("=");r[0]&&(t=r[0].match(/wc-(.+)/))&&(n[t[1]]=r[1]||!0)}),t)for(var r,o=0;r=t.attributes[o];o++)"src"!==r.name&&(n[r.name]=r.value||!0);if(n.log&&n.log.split){var i=n.log.split(",");n.log={},i.forEach(function(e){n.log[e]=!0})}else n.log={}}n.register&&(window.CustomElements=window.CustomElements||{flags:{}},window.CustomElements.flags.register=n.register),WebComponents.flags=n}(),function(e){"use strict";function t(e){return void 0!==h[e]}function n(){s.call(this),this._isInvalid=!0}function r(e){return""==e&&n.call(this),e.toLowerCase()}function o(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,63,96].indexOf(t)?e:encodeURIComponent(e)}function i(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,96].indexOf(t)?e:encodeURIComponent(e)}function a(e,a,s){function c(e){g.push(e)}var d=a||"scheme start",u=0,l="",_=!1,w=!1,g=[];e:for(;(e[u-1]!=p||0==u)&&!this._isInvalid;){var b=e[u];switch(d){case"scheme start":if(!b||!m.test(b)){if(a){c("Invalid scheme.");break e}l="",d="no scheme";continue}l+=b.toLowerCase(),d="scheme";break;case"scheme":if(b&&v.test(b))l+=b.toLowerCase();else{if(":"!=b){if(a){if(p==b)break e;c("Code point not allowed in scheme: "+b);break e}l="",u=0,d="no scheme";continue}if(this._scheme=l,l="",a)break e;t(this._scheme)&&(this._isRelative=!0),d="file"==this._scheme?"relative":this._isRelative&&s&&s._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==b?(this._query="?",d="query"):"#"==b?(this._fragment="#",d="fragment"):p!=b&&" "!=b&&"\n"!=b&&"\r"!=b&&(this._schemeData+=o(b));break;case"no scheme":if(s&&t(s._scheme)){d="relative";continue}c("Missing scheme."),n.call(this);break;case"relative or authority":if("/"!=b||"/"!=e[u+1]){c("Expected /, got: "+b),d="relative";continue}d="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=s._scheme),p==b){this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._username=s._username,this._password=s._password;break e}if("/"==b||"\\"==b)"\\"==b&&c("\\ is an invalid code point."),d="relative slash";else if("?"==b)this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query="?",this._username=s._username,this._password=s._password,d="query";else{if("#"!=b){var y=e[u+1],E=e[u+2];("file"!=this._scheme||!m.test(b)||":"!=y&&"|"!=y||p!=E&&"/"!=E&&"\\"!=E&&"?"!=E&&"#"!=E)&&(this._host=s._host,this._port=s._port,this._username=s._username,this._password=s._password,this._path=s._path.slice(),this._path.pop()),d="relative path";continue}this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._fragment="#",this._username=s._username,this._password=s._password,d="fragment"}break;case"relative slash":if("/"!=b&&"\\"!=b){"file"!=this._scheme&&(this._host=s._host,this._port=s._port,this._username=s._username,this._password=s._password),d="relative path";continue}"\\"==b&&c("\\ is an invalid code point."),d="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=b){c("Expected '/', got: "+b),d="authority ignore slashes";continue}d="authority second slash";break;case"authority second slash":if(d="authority ignore slashes","/"!=b){c("Expected '/', got: "+b);continue}break;case"authority ignore slashes":if("/"!=b&&"\\"!=b){d="authority";continue}c("Expected authority, got: "+b);break;case"authority":if("@"==b){_&&(c("@ already seen."),l+="%40"),_=!0;for(var L=0;L>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),function(e){function t(e){b.push(e),g||(g=!0,m(r))}function n(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function r(){g=!1;var e=b;b=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var n=e.takeRecords();o(e),n.length&&(e.callback_(n,e),t=!0)}),t&&r()}function o(e){e.nodes_.forEach(function(t){var n=v.get(t);n&&n.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var n=e;n;n=n.parentNode){var r=v.get(n);if(r)for(var o=0;o0){var o=n[r-1],i=f(o,e);if(i)return void(n[r-1]=i)}else t(this.observer);n[r]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),n=0;n":return">";case" ":return" "}}function t(t){return t.replace(a,e)}var n="template",r=document.implementation.createHTMLDocument("template"),o=!0;HTMLTemplateElement=function(){},HTMLTemplateElement.prototype=Object.create(HTMLElement.prototype),HTMLTemplateElement.decorate=function(e){e.content||(e.content=r.createDocumentFragment());for(var n;n=e.firstChild;)e.content.appendChild(n);if(o)try{Object.defineProperty(e,"innerHTML",{get:function(){for(var e="",n=this.content.firstChild;n;n=n.nextSibling)e+=n.outerHTML||t(n.data);return e},set:function(e){for(r.body.innerHTML=e,HTMLTemplateElement.bootstrap(r);this.content.firstChild;)this.content.removeChild(this.content.firstChild);for(;r.body.firstChild;)this.content.appendChild(r.body.firstChild)},configurable:!0})}catch(i){o=!1}},HTMLTemplateElement.bootstrap=function(e){for(var t,r=e.querySelectorAll(n),o=0,i=r.length;i>o&&(t=r[o]);o++)HTMLTemplateElement.decorate(t)},document.addEventListener("DOMContentLoaded",function(){HTMLTemplateElement.bootstrap(document)});var i=document.createElement;document.createElement=function(){"use strict";var e=i.apply(document,arguments);return"template"==e.localName&&HTMLTemplateElement.decorate(e),e};var a=/[&\u00A0<>]/g}(),function(e){"use strict";if(!window.performance){var t=Date.now();window.performance={now:function(){return Date.now()-t}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var e=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return e?function(t){return e(function(){t(performance.now())})}:function(e){return window.setTimeout(e,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(e){clearTimeout(e)}}());var n=function(){var e=document.createEvent("Event");return e.initEvent("foo",!0,!0),e.preventDefault(),e.defaultPrevented}();if(!n){var r=Event.prototype.preventDefault;Event.prototype.preventDefault=function(){this.cancelable&&(r.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0}}))}}var o=/Trident/.test(navigator.userAgent);if((!window.CustomEvent||o&&"function"!=typeof window.CustomEvent)&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),!window.Event||o&&"function"!=typeof window.Event){var i=window.Event;window.Event=function(e,t){t=t||{};var n=document.createEvent("Event");return n.initEvent(e,Boolean(t.bubbles),Boolean(t.cancelable)),n},window.Event.prototype=i.prototype}}(window.WebComponents),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||p,r(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===_}function r(e,t){if(n(t))e&&e();else{var o=function(){("complete"===t.readyState||t.readyState===_)&&(t.removeEventListener(w,o),r(e,t))};t.addEventListener(w,o)}}function o(e){e.target.__loaded=!0}function i(e,t){function n(){c==d&&e&&e({allImports:s,loadedImports:u,errorImports:l})}function r(e){o(e),u.push(this),c++,n()}function i(e){l.push(this),c++,n()}var s=t.querySelectorAll("link[rel=import]"),c=0,d=s.length,u=[],l=[];if(d)for(var h,f=0;d>f&&(h=s[f]);f++)a(h)?(c++,n()):(h.addEventListener("load",r),h.addEventListener("error",i));else n()}function a(e){return l?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)c(t)&&d(t)}function c(e){return"link"===e.localName&&"import"===e.rel}function d(e){var t=e["import"];t?o({target:e}):(e.addEventListener("load",o),e.addEventListener("error",o))}var u="import",l=Boolean(u in document.createElement("link")),h=Boolean(window.ShadowDOMPolyfill),f=function(e){return h?window.ShadowDOMPolyfill.wrapIfNeeded(e):e},p=f(document),m={get:function(){var e=window.HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return f(e)},configurable:!0};Object.defineProperty(document,"_currentScript",m),Object.defineProperty(p,"_currentScript",m);var v=/Trident/.test(navigator.userAgent),_=v?"complete":"interactive",w="readystatechange";l&&(new MutationObserver(function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,r=t.length;r>n&&(e=t[n]);n++)d(e)}()),t(function(e){window.HTMLImports.ready=!0,window.HTMLImports.readyTime=(new Date).getTime();var t=p.createEvent("CustomEvent");t.initCustomEvent("HTMLImportsLoaded",!0,!0,e),p.dispatchEvent(t)}),e.IMPORT_LINK_TYPE=u,e.useNative=l,e.rootDocument=p,e.whenReady=t,e.isIE=v}(window.HTMLImports),function(e){var t=[],n=function(e){t.push(e)},r=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=r}(window.HTMLImports),window.HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,r={resolveUrlsInStyle:function(e,t){var n=e.ownerDocument,r=n.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,t,r),e},resolveUrlsInCssText:function(e,r,o){var i=this.replaceUrls(e,o,r,t);return i=this.replaceUrls(i,o,r,n)},replaceUrls:function(e,t,n,r){return e.replace(r,function(e,r,o,i){var a=o.replace(/["']/g,"");return n&&(a=new URL(a,n).href),t.href=a,a=t.href,r+"'"+a+"'"+i})}};e.path=r}),window.HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(n,r,o){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(e){if(4===i.readyState){var n=null;try{var a=i.getResponseHeader("Location");a&&(n="/"===a.substr(0,1)?location.origin+a:a)}catch(e){console.error(e.message)}r.call(o,!t.ok(i)&&i,i.response||i.responseText,n)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),window.HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,r=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};r.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,r){if(n.load&&console.log("fetch",e,r),e)if(e.match(/^data:/)){var o=e.split(","),i=o[0],a=o[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,r,null,a)}.bind(this),0)}else{var s=function(t,n,o){this.receive(e,r,t,n,o)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,r,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,r,o){this.cache[e]=r;for(var i,a=this.pending[e],s=0,c=a.length;c>s&&(i=a[s]);s++)this.onload(e,i,r,n,o),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=r}),window.HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),window.HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===u}function n(e){var t=r(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function r(e){return e.textContent+o(e)}function o(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,r=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+r+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,c=e.flags,d=e.isIE,u=e.IMPORT_LINK_TYPE,l="link[rel="+u+"]",h={documentSelectors:l,importsSelectors:[l,"link[rel=stylesheet]:not([type])","style:not([type])","script:not([type])",'script[type="application/javascript"]','script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(c.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){c.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,c.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(e["import"]=e.__doc,window.HTMLImports.__importsParsingHook&&window.HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.__resource&&!e.__error?e.dispatchEvent(new CustomEvent("load",{bubbles:!1})):e.dispatchEvent(new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),t.__appliedElement=e,e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,r=function(o){e.removeEventListener("load",r),e.removeEventListener("error",r),t&&t(o),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",r),e.addEventListener("error",r),d&&"style"===e.localName){var o=!1;if(-1==e.textContent.indexOf("@import"))o=!0;else if(e.sheet){o=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;s>c&&(i=a[c]);c++)i.type===CSSRule.IMPORT_RULE&&(o=o&&Boolean(i.styleSheet))}o&&setTimeout(function(){e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))})}},parseScript:function(t){var r=document.createElement("script");r.__importElement=t,r.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(r,function(t){r.parentNode&&r.parentNode.removeChild(r),e.currentScript=null}),this.addElementToDocument(r)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var r,o=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=o.length;a>i&&(r=o[i]);i++)if(!this.isParsed(r))return this.hasResource(r)?t(r)?this.nextToParseInDoc(r.__doc,r):r:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e.__doc?!1:!0}};e.parser=h,e.IMPORT_SELECTOR=l}),window.HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function r(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function o(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var o=n.createElement("base");o.setAttribute("href",t),n.baseURI||r(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(o),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,c=e.rootDocument,d=e.Loader,u=e.Observer,l=e.parser,h={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){f.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);f.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===c?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,r,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=r,n.__error=a,t(n)){var c=this.documents[e];void 0===c&&(c=a?null:o(r,s||e),c&&(c.__importLink=n,this.bootDocument(c)),this.documents[e]=c),n.__doc=c}l.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),l.parseNext()},loadedAll:function(){l.parseNext()}},f=new d(h.loaded.bind(h),h.loadedAll.bind(h));if(h.observer=new u,!document.baseURI){var p={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",p),Object.defineProperty(c,"baseURI",p)}e.importer=h,e.importLoader=f}),window.HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,r={added:function(e){for(var r,o,i,a,s=0,c=e.length;c>s&&(a=e[s]);s++)r||(r=a.ownerDocument,o=t.isParsed(r)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&o&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&o.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&o.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=r.added.bind(r);var o=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){window.HTMLImports.importer.bootDocument(r)}var n=e.initializeModules;e.isIE;if(!e.useNative){n();var r=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(window.HTMLImports),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],r=function(e){n.push(e)},o=function(){n.forEach(function(t){t(e)})};e.addModule=r,e.initializeModules=o,e.hasNative=Boolean(document.registerElement),e.isIE=/Trident/.test(navigator.userAgent),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||window.HTMLImports.useNative)}(window.CustomElements),window.CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void r(e,t)}),r(e,t)}function n(e,t,r){var o=e.firstElementChild;if(!o)for(o=e.firstChild;o&&o.nodeType!==Node.ELEMENT_NODE;)o=o.nextSibling;for(;o;)t(o,r)!==!0&&n(o,t,r),o=o.nextElementSibling;return null}function r(e,n){for(var r=e.shadowRoot;r;)t(r,n),r=r.olderShadowRoot}function o(e,t){i(e,t,[])}function i(e,t,n){if(e=window.wrap(e),!(n.indexOf(e)>=0)){n.push(e);for(var r,o=e.querySelectorAll("link[rel="+a+"]"),s=0,c=o.length;c>s&&(r=o[s]);s++)r["import"]&&i(r["import"],t,n);t(e)}}var a=window.HTMLImports?window.HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=o,e.forSubtree=t}),window.CustomElements.addModule(function(e){function t(e,t){return n(e,t)||r(e,t)}function n(t,n){return e.upgrade(t,n)?!0:void(n&&a(t))}function r(e,t){b(e,function(e){return n(e,t)?!0:void 0})}function o(e){T.push(e),L||(L=!0,setTimeout(i))}function i(){L=!1;for(var e,t=T,n=0,r=t.length;r>n&&(e=t[n]);n++)e();T=[]}function a(e){E?o(function(){s(e)}):s(e)}function s(e){e.__upgraded__&&!e.__attached&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function c(e){d(e),b(e,function(e){d(e)})}function d(e){E?o(function(){u(e)}):u(e)}function u(e){e.__upgraded__&&e.__attached&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function l(e){for(var t=e,n=window.wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&t.host}}function h(e){if(e.shadowRoot&&!e.shadowRoot.__watched){g.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)m(t),t=t.olderShadowRoot}}function f(e,n){if(g.dom){var r=n[0];if(r&&"childList"===r.type&&r.addedNodes&&r.addedNodes){for(var o=r.addedNodes[0];o&&o!==document&&!o.host;)o=o.parentNode;var i=o&&(o.URL||o._URL||o.host&&o.host.localName)||"";i=i.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",n.length,i||"")}var a=l(e);n.forEach(function(e){"childList"===e.type&&(M(e.addedNodes,function(e){e.localName&&t(e,a)}),M(e.removedNodes,function(e){e.localName&&c(e)}))}),g.dom&&console.groupEnd()}function p(e){for(e=window.wrap(e),e||(e=window.wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(f(e,t.takeRecords()),i())}function m(e){if(!e.__observer){var t=new MutationObserver(f.bind(this,e));t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function v(e){e=window.wrap(e),g.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop());var n=e===window.wrap(document); -t(e,n),m(e),g.dom&&console.groupEnd()}function _(e){y(e,v)}function w(e){HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(e),t(e)}var g=e.flags,b=e.forSubtree,y=e.forDocumentTree,E=window.MutationObserver._isPolyfilled&&g["throttle-attached"];e.hasPolyfillMutations=E,e.hasThrottledAttached=E;var L=!1,T=[],M=Array.prototype.forEach.call.bind(Array.prototype.forEach),N=Element.prototype.createShadowRoot;N&&(Element.prototype.createShadowRoot=function(){var e=N.call(this);return window.CustomElements.watchShadow(this),e}),e.watchShadow=h,e.upgradeDocumentTree=_,e.upgradeDocument=v,e.upgradeSubtree=r,e.upgradeAll=w,e.attached=a,e.takeRecords=p}),window.CustomElements.addModule(function(e){function t(t,r){if(!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var o=t.getAttribute("is"),i=e.getRegisteredDefinition(t.localName)||e.getRegisteredDefinition(o);if(i&&(o&&i.tag==t.localName||!o&&!i["extends"]))return n(t,i,r)}}function n(t,n,o){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),r(t,n),t.__upgraded__=!0,i(t),o&&e.attached(t),e.upgradeSubtree(t,o),a.upgrade&&console.groupEnd(),t}function r(e,t){Object.__proto__?e.__proto__=t.prototype:(o(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function o(e,t,n){for(var r={},o=t;o!==n&&o!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(o),s=0;i=a[s];s++)r[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(o,i)),r[i]=1);o=Object.getPrototypeOf(o)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=r}),window.CustomElements.addModule(function(e){function t(t,r){var c=r||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(o(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(d(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return c.prototype||(c.prototype=Object.create(HTMLElement.prototype)),c.__name=t.toLowerCase(),c.lifecycle=c.lifecycle||{},c.ancestry=i(c["extends"]),a(c),s(c),n(c.prototype),u(c.__name,c),c.ctor=l(c),c.ctor.prototype=c.prototype,c.prototype.constructor=c.ctor,e.ready&&_(document),c.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){r.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){r.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function r(e,t,n){e=e.toLowerCase();var r=this.getAttribute(e);n.apply(this,arguments);var o=this.getAttribute(e);this.attributeChangedCallback&&o!==r&&this.attributeChangedCallback(e,r,o)}function o(e){for(var t=0;t=0&&b(r,HTMLElement),r)}function p(e,t){var n=e[t];e[t]=function(){var e=n.apply(this,arguments);return w(e),e}}var m,v=e.isIE,_=e.upgradeDocumentTree,w=e.upgradeAll,g=e.upgradeWithDefinition,b=e.implementPrototype,y=e.useNative,E=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],L={},T="http://www.w3.org/1999/xhtml",M=document.createElement.bind(document),N=document.createElementNS.bind(document);m=Object.__proto__||y?function(e,t){return e instanceof t}:function(e,t){if(e instanceof t)return!0;for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},p(Node.prototype,"cloneNode"),p(document,"importNode"),v&&!function(){var e=document.importNode;document.importNode=function(){var t=e.apply(document,arguments);if(t.nodeType==t.DOCUMENT_FRAGMENT_NODE){var n=document.createDocumentFragment();return n.appendChild(t),n}return t}}(),document.registerElement=t,document.createElement=f,document.createElementNS=h,e.registry=L,e["instanceof"]=m,e.reservedTagList=E,e.getRegisteredDefinition=d,document.register=document.registerElement}),function(e){function t(){i(window.wrap(document)),window.CustomElements.ready=!0;var e=window.requestAnimationFrame||function(e){setTimeout(e,16)};e(function(){setTimeout(function(){window.CustomElements.readyTime=Date.now(),window.HTMLImports&&(window.CustomElements.elapsed=window.CustomElements.readyTime-window.HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})})}var n=e.useNative,r=e.initializeModules;e.isIE;if(n){var o=function(){};e.watchShadow=o,e.upgrade=o,e.upgradeAll=o,e.upgradeDocumentTree=o,e.upgradeSubtree=o,e.takeRecords=o,e["instanceof"]=function(e,t){return e instanceof t}}else r();var i=e.upgradeDocumentTree,a=e.upgradeDocument;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=window.ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=window.ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),window.HTMLImports&&(window.HTMLImports.__importsParsingHook=function(e){e["import"]&&a(wrap(e["import"]))}),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!window.HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t()}(window.CustomElements),function(e){var t=document.createElement("style");t.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var n=document.querySelector("head");n.insertBefore(t,n.firstChild)}(window.WebComponents); \ No newline at end of file +// @version 0.7.18 +!function(){window.WebComponents=window.WebComponents||{flags:{}};var e="webcomponents-lite.js",t=document.querySelector('script[src*="'+e+'"]'),n={};if(!n.noOpts){if(location.search.slice(1).split("&").forEach(function(e){var t,r=e.split("=");r[0]&&(t=r[0].match(/wc-(.+)/))&&(n[t[1]]=r[1]||!0)}),t)for(var r,o=0;r=t.attributes[o];o++)"src"!==r.name&&(n[r.name]=r.value||!0);if(n.log&&n.log.split){var i=n.log.split(",");n.log={},i.forEach(function(e){n.log[e]=!0})}else n.log={}}n.register&&(window.CustomElements=window.CustomElements||{flags:{}},window.CustomElements.flags.register=n.register),WebComponents.flags=n}(),function(e){"use strict";function t(e){return void 0!==h[e]}function n(){s.call(this),this._isInvalid=!0}function r(e){return""==e&&n.call(this),e.toLowerCase()}function o(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,63,96].indexOf(t)?e:encodeURIComponent(e)}function i(e){var t=e.charCodeAt(0);return t>32&&127>t&&-1==[34,35,60,62,96].indexOf(t)?e:encodeURIComponent(e)}function a(e,a,s){function c(e){g.push(e)}var d=a||"scheme start",u=0,l="",w=!1,_=!1,g=[];e:for(;(e[u-1]!=p||0==u)&&!this._isInvalid;){var b=e[u];switch(d){case"scheme start":if(!b||!m.test(b)){if(a){c("Invalid scheme.");break e}l="",d="no scheme";continue}l+=b.toLowerCase(),d="scheme";break;case"scheme":if(b&&v.test(b))l+=b.toLowerCase();else{if(":"!=b){if(a){if(p==b)break e;c("Code point not allowed in scheme: "+b);break e}l="",u=0,d="no scheme";continue}if(this._scheme=l,l="",a)break e;t(this._scheme)&&(this._isRelative=!0),d="file"==this._scheme?"relative":this._isRelative&&s&&s._scheme==this._scheme?"relative or authority":this._isRelative?"authority first slash":"scheme data"}break;case"scheme data":"?"==b?(this._query="?",d="query"):"#"==b?(this._fragment="#",d="fragment"):p!=b&&" "!=b&&"\n"!=b&&"\r"!=b&&(this._schemeData+=o(b));break;case"no scheme":if(s&&t(s._scheme)){d="relative";continue}c("Missing scheme."),n.call(this);break;case"relative or authority":if("/"!=b||"/"!=e[u+1]){c("Expected /, got: "+b),d="relative";continue}d="authority ignore slashes";break;case"relative":if(this._isRelative=!0,"file"!=this._scheme&&(this._scheme=s._scheme),p==b){this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._username=s._username,this._password=s._password;break e}if("/"==b||"\\"==b)"\\"==b&&c("\\ is an invalid code point."),d="relative slash";else if("?"==b)this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query="?",this._username=s._username,this._password=s._password,d="query";else{if("#"!=b){var y=e[u+1],E=e[u+2];("file"!=this._scheme||!m.test(b)||":"!=y&&"|"!=y||p!=E&&"/"!=E&&"\\"!=E&&"?"!=E&&"#"!=E)&&(this._host=s._host,this._port=s._port,this._username=s._username,this._password=s._password,this._path=s._path.slice(),this._path.pop()),d="relative path";continue}this._host=s._host,this._port=s._port,this._path=s._path.slice(),this._query=s._query,this._fragment="#",this._username=s._username,this._password=s._password,d="fragment"}break;case"relative slash":if("/"!=b&&"\\"!=b){"file"!=this._scheme&&(this._host=s._host,this._port=s._port,this._username=s._username,this._password=s._password),d="relative path";continue}"\\"==b&&c("\\ is an invalid code point."),d="file"==this._scheme?"file host":"authority ignore slashes";break;case"authority first slash":if("/"!=b){c("Expected '/', got: "+b),d="authority ignore slashes";continue}d="authority second slash";break;case"authority second slash":if(d="authority ignore slashes","/"!=b){c("Expected '/', got: "+b);continue}break;case"authority ignore slashes":if("/"!=b&&"\\"!=b){d="authority";continue}c("Expected authority, got: "+b);break;case"authority":if("@"==b){w&&(c("@ already seen."),l+="%40"),w=!0;for(var L=0;L>>0)+(t++ +"__")};n.prototype={set:function(t,n){var r=t[this.name];return r&&r[0]===t?r[1]=n:e(t,this.name,{value:[t,n],writable:!0}),this},get:function(e){var t;return(t=e[this.name])&&t[0]===e?t[1]:void 0},"delete":function(e){var t=e[this.name];return t&&t[0]===e?(t[0]=t[1]=void 0,!0):!1},has:function(e){var t=e[this.name];return t?t[0]===e:!1}},window.WeakMap=n}(),function(e){function t(e){b.push(e),g||(g=!0,m(r))}function n(e){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(e)||e}function r(){g=!1;var e=b;b=[],e.sort(function(e,t){return e.uid_-t.uid_});var t=!1;e.forEach(function(e){var n=e.takeRecords();o(e),n.length&&(e.callback_(n,e),t=!0)}),t&&r()}function o(e){e.nodes_.forEach(function(t){var n=v.get(t);n&&n.forEach(function(t){t.observer===e&&t.removeTransientObservers()})})}function i(e,t){for(var n=e;n;n=n.parentNode){var r=v.get(n);if(r)for(var o=0;o0){var o=n[r-1],i=f(o,e);if(i)return void(n[r-1]=i)}else t(this.observer);n[r]=e},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(e){var t=this.options;t.attributes&&e.addEventListener("DOMAttrModified",this,!0),t.characterData&&e.addEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.addEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(e){var t=this.options;t.attributes&&e.removeEventListener("DOMAttrModified",this,!0),t.characterData&&e.removeEventListener("DOMCharacterDataModified",this,!0),t.childList&&e.removeEventListener("DOMNodeInserted",this,!0),(t.childList||t.subtree)&&e.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(e){if(e!==this.target){this.addListeners_(e),this.transientObservedNodes.push(e);var t=v.get(e);t||v.set(e,t=[]),t.push(this)}},removeTransientObservers:function(){var e=this.transientObservedNodes;this.transientObservedNodes=[],e.forEach(function(e){this.removeListeners_(e);for(var t=v.get(e),n=0;n":return">";case" ":return" "}}function t(t){return t.replace(a,e)}var n="template",r=document.implementation.createHTMLDocument("template"),o=!0;HTMLTemplateElement=function(){},HTMLTemplateElement.prototype=Object.create(HTMLElement.prototype),HTMLTemplateElement.decorate=function(e){if(!e.content){e.content=r.createDocumentFragment();for(var n;n=e.firstChild;)e.content.appendChild(n);if(o)try{Object.defineProperty(e,"innerHTML",{get:function(){for(var e="",n=this.content.firstChild;n;n=n.nextSibling)e+=n.outerHTML||t(n.data);return e},set:function(e){for(r.body.innerHTML=e,HTMLTemplateElement.bootstrap(r);this.content.firstChild;)this.content.removeChild(this.content.firstChild);for(;r.body.firstChild;)this.content.appendChild(r.body.firstChild)},configurable:!0})}catch(i){o=!1}HTMLTemplateElement.bootstrap(e.content)}},HTMLTemplateElement.bootstrap=function(e){for(var t,r=e.querySelectorAll(n),o=0,i=r.length;i>o&&(t=r[o]);o++)HTMLTemplateElement.decorate(t)},document.addEventListener("DOMContentLoaded",function(){HTMLTemplateElement.bootstrap(document)});var i=document.createElement;document.createElement=function(){"use strict";var e=i.apply(document,arguments);return"template"==e.localName&&HTMLTemplateElement.decorate(e),e};var a=/[&\u00A0<>]/g}(),function(e){"use strict";if(!window.performance){var t=Date.now();window.performance={now:function(){return Date.now()-t}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var e=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return e?function(t){return e(function(){t(performance.now())})}:function(e){return window.setTimeout(e,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(e){clearTimeout(e)}}());var n=function(){var e=document.createEvent("Event");return e.initEvent("foo",!0,!0),e.preventDefault(),e.defaultPrevented}();if(!n){var r=Event.prototype.preventDefault;Event.prototype.preventDefault=function(){this.cancelable&&(r.call(this),Object.defineProperty(this,"defaultPrevented",{get:function(){return!0},configurable:!0}))}}var o=/Trident/.test(navigator.userAgent);if((!window.CustomEvent||o&&"function"!=typeof window.CustomEvent)&&(window.CustomEvent=function(e,t){t=t||{};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,Boolean(t.bubbles),Boolean(t.cancelable),t.detail),n},window.CustomEvent.prototype=window.Event.prototype),!window.Event||o&&"function"!=typeof window.Event){var i=window.Event;window.Event=function(e,t){t=t||{};var n=document.createEvent("Event");return n.initEvent(e,Boolean(t.bubbles),Boolean(t.cancelable)),n},window.Event.prototype=i.prototype}}(window.WebComponents),window.HTMLImports=window.HTMLImports||{flags:{}},function(e){function t(e,t){t=t||p,r(function(){i(e,t)},t)}function n(e){return"complete"===e.readyState||e.readyState===w}function r(e,t){if(n(t))e&&e();else{var o=function(){("complete"===t.readyState||t.readyState===w)&&(t.removeEventListener(_,o),r(e,t))};t.addEventListener(_,o)}}function o(e){e.target.__loaded=!0}function i(e,t){function n(){c==d&&e&&e({allImports:s,loadedImports:u,errorImports:l})}function r(e){o(e),u.push(this),c++,n()}function i(e){l.push(this),c++,n()}var s=t.querySelectorAll("link[rel=import]"),c=0,d=s.length,u=[],l=[];if(d)for(var h,f=0;d>f&&(h=s[f]);f++)a(h)?(c++,n()):(h.addEventListener("load",r),h.addEventListener("error",i));else n()}function a(e){return l?e.__loaded||e["import"]&&"loading"!==e["import"].readyState:e.__importParsed}function s(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)c(t)&&d(t)}function c(e){return"link"===e.localName&&"import"===e.rel}function d(e){var t=e["import"];t?o({target:e}):(e.addEventListener("load",o),e.addEventListener("error",o))}var u="import",l=Boolean(u in document.createElement("link")),h=Boolean(window.ShadowDOMPolyfill),f=function(e){return h?window.ShadowDOMPolyfill.wrapIfNeeded(e):e},p=f(document),m={get:function(){var e=window.HTMLImports.currentScript||document.currentScript||("complete"!==document.readyState?document.scripts[document.scripts.length-1]:null);return f(e)},configurable:!0};Object.defineProperty(document,"_currentScript",m),Object.defineProperty(p,"_currentScript",m);var v=/Trident/.test(navigator.userAgent),w=v?"complete":"interactive",_="readystatechange";l&&(new MutationObserver(function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.addedNodes&&s(t.addedNodes)}).observe(document.head,{childList:!0}),function(){if("loading"===document.readyState)for(var e,t=document.querySelectorAll("link[rel=import]"),n=0,r=t.length;r>n&&(e=t[n]);n++)d(e)}()),t(function(e){window.HTMLImports.ready=!0,window.HTMLImports.readyTime=(new Date).getTime();var t=p.createEvent("CustomEvent");t.initCustomEvent("HTMLImportsLoaded",!0,!0,e),p.dispatchEvent(t)}),e.IMPORT_LINK_TYPE=u,e.useNative=l,e.rootDocument=p,e.whenReady=t,e.isIE=v}(window.HTMLImports),function(e){var t=[],n=function(e){t.push(e)},r=function(){t.forEach(function(t){t(e)})};e.addModule=n,e.initializeModules=r}(window.HTMLImports),window.HTMLImports.addModule(function(e){var t=/(url\()([^)]*)(\))/g,n=/(@import[\s]+(?!url\())([^;]*)(;)/g,r={resolveUrlsInStyle:function(e,t){var n=e.ownerDocument,r=n.createElement("a");return e.textContent=this.resolveUrlsInCssText(e.textContent,t,r),e},resolveUrlsInCssText:function(e,r,o){var i=this.replaceUrls(e,o,r,t);return i=this.replaceUrls(i,o,r,n)},replaceUrls:function(e,t,n,r){return e.replace(r,function(e,r,o,i){var a=o.replace(/["']/g,"");return n&&(a=new URL(a,n).href),t.href=a,a=t.href,r+"'"+a+"'"+i})}};e.path=r}),window.HTMLImports.addModule(function(e){var t={async:!0,ok:function(e){return e.status>=200&&e.status<300||304===e.status||0===e.status},load:function(n,r,o){var i=new XMLHttpRequest;return(e.flags.debug||e.flags.bust)&&(n+="?"+Math.random()),i.open("GET",n,t.async),i.addEventListener("readystatechange",function(e){if(4===i.readyState){var n=null;try{var a=i.getResponseHeader("Location");a&&(n="/"===a.substr(0,1)?location.origin+a:a)}catch(e){console.error(e.message)}r.call(o,!t.ok(i)&&i,i.response||i.responseText,n)}}),i.send(),i},loadDocument:function(e,t,n){this.load(e,t,n).responseType="document"}};e.xhr=t}),window.HTMLImports.addModule(function(e){var t=e.xhr,n=e.flags,r=function(e,t){this.cache={},this.onload=e,this.oncomplete=t,this.inflight=0,this.pending={}};r.prototype={addNodes:function(e){this.inflight+=e.length;for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)this.require(t);this.checkDone()},addNode:function(e){this.inflight++,this.require(e),this.checkDone()},require:function(e){var t=e.src||e.href;e.__nodeUrl=t,this.dedupe(t,e)||this.fetch(t,e)},dedupe:function(e,t){if(this.pending[e])return this.pending[e].push(t),!0;return this.cache[e]?(this.onload(e,t,this.cache[e]),this.tail(),!0):(this.pending[e]=[t],!1)},fetch:function(e,r){if(n.load&&console.log("fetch",e,r),e)if(e.match(/^data:/)){var o=e.split(","),i=o[0],a=o[1];a=i.indexOf(";base64")>-1?atob(a):decodeURIComponent(a),setTimeout(function(){this.receive(e,r,null,a)}.bind(this),0)}else{var s=function(t,n,o){this.receive(e,r,t,n,o)}.bind(this);t.load(e,s)}else setTimeout(function(){this.receive(e,r,{error:"href must be specified"},null)}.bind(this),0)},receive:function(e,t,n,r,o){this.cache[e]=r;for(var i,a=this.pending[e],s=0,c=a.length;c>s&&(i=a[s]);s++)this.onload(e,i,r,n,o),this.tail();this.pending[e]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}},e.Loader=r}),window.HTMLImports.addModule(function(e){var t=function(e){this.addCallback=e,this.mo=new MutationObserver(this.handler.bind(this))};t.prototype={handler:function(e){for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)"childList"===t.type&&t.addedNodes.length&&this.addedNodes(t.addedNodes)},addedNodes:function(e){this.addCallback&&this.addCallback(e);for(var t,n=0,r=e.length;r>n&&(t=e[n]);n++)t.children&&t.children.length&&this.addedNodes(t.children)},observe:function(e){this.mo.observe(e,{childList:!0,subtree:!0})}},e.Observer=t}),window.HTMLImports.addModule(function(e){function t(e){return"link"===e.localName&&e.rel===u}function n(e){var t=r(e);return"data:text/javascript;charset=utf-8,"+encodeURIComponent(t)}function r(e){return e.textContent+o(e)}function o(e){var t=e.ownerDocument;t.__importedScripts=t.__importedScripts||0;var n=e.ownerDocument.baseURI,r=t.__importedScripts?"-"+t.__importedScripts:"";return t.__importedScripts++,"\n//# sourceURL="+n+r+".js\n"}function i(e){var t=e.ownerDocument.createElement("style");return t.textContent=e.textContent,a.resolveUrlsInStyle(t),t}var a=e.path,s=e.rootDocument,c=e.flags,d=e.isIE,u=e.IMPORT_LINK_TYPE,l="link[rel="+u+"]",h={documentSelectors:l,importsSelectors:[l,"link[rel=stylesheet]:not([type])","style:not([type])","script:not([type])",'script[type="application/javascript"]','script[type="text/javascript"]'].join(","),map:{link:"parseLink",script:"parseScript",style:"parseStyle"},dynamicElements:[],parseNext:function(){var e=this.nextToParse();e&&this.parse(e)},parse:function(e){if(this.isParsed(e))return void(c.parse&&console.log("[%s] is already parsed",e.localName));var t=this[this.map[e.localName]];t&&(this.markParsing(e),t.call(this,e))},parseDynamic:function(e,t){this.dynamicElements.push(e),t||this.parseNext()},markParsing:function(e){c.parse&&console.log("parsing",e),this.parsingElement=e},markParsingComplete:function(e){e.__importParsed=!0,this.markDynamicParsingComplete(e),e.__importElement&&(e.__importElement.__importParsed=!0,this.markDynamicParsingComplete(e.__importElement)),this.parsingElement=null,c.parse&&console.log("completed",e)},markDynamicParsingComplete:function(e){var t=this.dynamicElements.indexOf(e);t>=0&&this.dynamicElements.splice(t,1)},parseImport:function(e){if(e["import"]=e.__doc,window.HTMLImports.__importsParsingHook&&window.HTMLImports.__importsParsingHook(e),e["import"]&&(e["import"].__importParsed=!0),this.markParsingComplete(e),e.__resource&&!e.__error?e.dispatchEvent(new CustomEvent("load",{bubbles:!1})):e.dispatchEvent(new CustomEvent("error",{bubbles:!1})),e.__pending)for(var t;e.__pending.length;)t=e.__pending.shift(),t&&t({target:e});this.parseNext()},parseLink:function(e){t(e)?this.parseImport(e):(e.href=e.href,this.parseGeneric(e))},parseStyle:function(e){var t=e;e=i(e),t.__appliedElement=e,e.__importElement=t,this.parseGeneric(e)},parseGeneric:function(e){this.trackElement(e),this.addElementToDocument(e)},rootImportForElement:function(e){for(var t=e;t.ownerDocument.__importLink;)t=t.ownerDocument.__importLink;return t},addElementToDocument:function(e){var t=this.rootImportForElement(e.__importElement||e);t.parentNode.insertBefore(e,t)},trackElement:function(e,t){var n=this,r=function(o){e.removeEventListener("load",r),e.removeEventListener("error",r),t&&t(o),n.markParsingComplete(e),n.parseNext()};if(e.addEventListener("load",r),e.addEventListener("error",r),d&&"style"===e.localName){var o=!1;if(-1==e.textContent.indexOf("@import"))o=!0;else if(e.sheet){o=!0;for(var i,a=e.sheet.cssRules,s=a?a.length:0,c=0;s>c&&(i=a[c]);c++)i.type===CSSRule.IMPORT_RULE&&(o=o&&Boolean(i.styleSheet))}o&&setTimeout(function(){e.dispatchEvent(new CustomEvent("load",{bubbles:!1}))})}},parseScript:function(t){var r=document.createElement("script");r.__importElement=t,r.src=t.src?t.src:n(t),e.currentScript=t,this.trackElement(r,function(t){r.parentNode&&r.parentNode.removeChild(r),e.currentScript=null}),this.addElementToDocument(r)},nextToParse:function(){return this._mayParse=[],!this.parsingElement&&(this.nextToParseInDoc(s)||this.nextToParseDynamic())},nextToParseInDoc:function(e,n){if(e&&this._mayParse.indexOf(e)<0){this._mayParse.push(e);for(var r,o=e.querySelectorAll(this.parseSelectorsForNode(e)),i=0,a=o.length;a>i&&(r=o[i]);i++)if(!this.isParsed(r))return this.hasResource(r)?t(r)?this.nextToParseInDoc(r.__doc,r):r:void 0}return n},nextToParseDynamic:function(){return this.dynamicElements[0]},parseSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===s?this.documentSelectors:this.importsSelectors},isParsed:function(e){return e.__importParsed},needsDynamicParsing:function(e){return this.dynamicElements.indexOf(e)>=0},hasResource:function(e){return t(e)&&void 0===e.__doc?!1:!0}};e.parser=h,e.IMPORT_SELECTOR=l}),window.HTMLImports.addModule(function(e){function t(e){return n(e,a)}function n(e,t){return"link"===e.localName&&e.getAttribute("rel")===t}function r(e){return!!Object.getOwnPropertyDescriptor(e,"baseURI")}function o(e,t){var n=document.implementation.createHTMLDocument(a);n._URL=t;var o=n.createElement("base");o.setAttribute("href",t),n.baseURI||r(n)||Object.defineProperty(n,"baseURI",{value:t});var i=n.createElement("meta");return i.setAttribute("charset","utf-8"),n.head.appendChild(i),n.head.appendChild(o),n.body.innerHTML=e,window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(n),n}var i=e.flags,a=e.IMPORT_LINK_TYPE,s=e.IMPORT_SELECTOR,c=e.rootDocument,d=e.Loader,u=e.Observer,l=e.parser,h={documents:{},documentPreloadSelectors:s,importsPreloadSelectors:[s].join(","),loadNode:function(e){f.addNode(e)},loadSubtree:function(e){var t=this.marshalNodes(e);f.addNodes(t)},marshalNodes:function(e){return e.querySelectorAll(this.loadSelectorsForNode(e))},loadSelectorsForNode:function(e){var t=e.ownerDocument||e;return t===c?this.documentPreloadSelectors:this.importsPreloadSelectors},loaded:function(e,n,r,a,s){if(i.load&&console.log("loaded",e,n),n.__resource=r,n.__error=a,t(n)){var c=this.documents[e];void 0===c&&(c=a?null:o(r,s||e),c&&(c.__importLink=n,this.bootDocument(c)),this.documents[e]=c),n.__doc=c}l.parseNext()},bootDocument:function(e){this.loadSubtree(e),this.observer.observe(e),l.parseNext()},loadedAll:function(){l.parseNext()}},f=new d(h.loaded.bind(h),h.loadedAll.bind(h));if(h.observer=new u,!document.baseURI){var p={get:function(){var e=document.querySelector("base");return e?e.href:window.location.href},configurable:!0};Object.defineProperty(document,"baseURI",p),Object.defineProperty(c,"baseURI",p)}e.importer=h,e.importLoader=f}),window.HTMLImports.addModule(function(e){var t=e.parser,n=e.importer,r={added:function(e){for(var r,o,i,a,s=0,c=e.length;c>s&&(a=e[s]);s++)r||(r=a.ownerDocument,o=t.isParsed(r)),i=this.shouldLoadNode(a),i&&n.loadNode(a),this.shouldParseNode(a)&&o&&t.parseDynamic(a,i)},shouldLoadNode:function(e){return 1===e.nodeType&&o.call(e,n.loadSelectorsForNode(e))},shouldParseNode:function(e){return 1===e.nodeType&&o.call(e,t.parseSelectorsForNode(e))}};n.observer.addCallback=r.added.bind(r);var o=HTMLElement.prototype.matches||HTMLElement.prototype.matchesSelector||HTMLElement.prototype.webkitMatchesSelector||HTMLElement.prototype.mozMatchesSelector||HTMLElement.prototype.msMatchesSelector}),function(e){function t(){window.HTMLImports.importer.bootDocument(r)}var n=e.initializeModules;e.isIE;if(!e.useNative){n();var r=e.rootDocument;"complete"===document.readyState||"interactive"===document.readyState&&!window.attachEvent?t():document.addEventListener("DOMContentLoaded",t)}}(window.HTMLImports),window.CustomElements=window.CustomElements||{flags:{}},function(e){var t=e.flags,n=[],r=function(e){n.push(e)},o=function(){n.forEach(function(t){t(e)})};e.addModule=r,e.initializeModules=o,e.hasNative=Boolean(document.registerElement),e.isIE=/Trident/.test(navigator.userAgent),e.useNative=!t.register&&e.hasNative&&!window.ShadowDOMPolyfill&&(!window.HTMLImports||window.HTMLImports.useNative)}(window.CustomElements),window.CustomElements.addModule(function(e){function t(e,t){n(e,function(e){return t(e)?!0:void r(e,t)}),r(e,t)}function n(e,t,r){var o=e.firstElementChild;if(!o)for(o=e.firstChild;o&&o.nodeType!==Node.ELEMENT_NODE;)o=o.nextSibling;for(;o;)t(o,r)!==!0&&n(o,t,r),o=o.nextElementSibling;return null}function r(e,n){for(var r=e.shadowRoot;r;)t(r,n),r=r.olderShadowRoot}function o(e,t){i(e,t,[])}function i(e,t,n){if(e=window.wrap(e),!(n.indexOf(e)>=0)){n.push(e);for(var r,o=e.querySelectorAll("link[rel="+a+"]"),s=0,c=o.length;c>s&&(r=o[s]);s++)r["import"]&&i(r["import"],t,n);t(e)}}var a=window.HTMLImports?window.HTMLImports.IMPORT_LINK_TYPE:"none";e.forDocumentTree=o,e.forSubtree=t}),window.CustomElements.addModule(function(e){function t(e,t){return n(e,t)||r(e,t)}function n(t,n){return e.upgrade(t,n)?!0:void(n&&a(t))}function r(e,t){g(e,function(e){return n(e,t)?!0:void 0})}function o(e){L.push(e),E||(E=!0,setTimeout(i))}function i(){E=!1;for(var e,t=L,n=0,r=t.length;r>n&&(e=t[n]);n++)e();L=[]}function a(e){y?o(function(){s(e)}):s(e)}function s(e){e.__upgraded__&&!e.__attached&&(e.__attached=!0,e.attachedCallback&&e.attachedCallback())}function c(e){d(e),g(e,function(e){d(e)})}function d(e){y?o(function(){u(e)}):u(e)}function u(e){e.__upgraded__&&e.__attached&&(e.__attached=!1,e.detachedCallback&&e.detachedCallback())}function l(e){for(var t=e,n=window.wrap(document);t;){if(t==n)return!0;t=t.parentNode||t.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&t.host}}function h(e){if(e.shadowRoot&&!e.shadowRoot.__watched){_.dom&&console.log("watching shadow-root for: ",e.localName);for(var t=e.shadowRoot;t;)m(t),t=t.olderShadowRoot}}function f(e,n){if(_.dom){var r=n[0];if(r&&"childList"===r.type&&r.addedNodes&&r.addedNodes){for(var o=r.addedNodes[0];o&&o!==document&&!o.host;)o=o.parentNode;var i=o&&(o.URL||o._URL||o.host&&o.host.localName)||"";i=i.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",n.length,i||"")}var a=l(e);n.forEach(function(e){"childList"===e.type&&(T(e.addedNodes,function(e){e.localName&&t(e,a)}),T(e.removedNodes,function(e){e.localName&&c(e)}))}),_.dom&&console.groupEnd()}function p(e){for(e=window.wrap(e),e||(e=window.wrap(document));e.parentNode;)e=e.parentNode;var t=e.__observer;t&&(f(e,t.takeRecords()),i())}function m(e){if(!e.__observer){var t=new MutationObserver(f.bind(this,e));t.observe(e,{childList:!0,subtree:!0}),e.__observer=t}}function v(e){e=window.wrap(e),_.dom&&console.group("upgradeDocument: ",e.baseURI.split("/").pop()); +var n=e===window.wrap(document);t(e,n),m(e),_.dom&&console.groupEnd()}function w(e){b(e,v)}var _=e.flags,g=e.forSubtree,b=e.forDocumentTree,y=window.MutationObserver._isPolyfilled&&_["throttle-attached"];e.hasPolyfillMutations=y,e.hasThrottledAttached=y;var E=!1,L=[],T=Array.prototype.forEach.call.bind(Array.prototype.forEach),M=Element.prototype.createShadowRoot;M&&(Element.prototype.createShadowRoot=function(){var e=M.call(this);return window.CustomElements.watchShadow(this),e}),e.watchShadow=h,e.upgradeDocumentTree=w,e.upgradeDocument=v,e.upgradeSubtree=r,e.upgradeAll=t,e.attached=a,e.takeRecords=p}),window.CustomElements.addModule(function(e){function t(t,r){if("template"===t.localName&&window.HTMLTemplateElement&&HTMLTemplateElement.decorate&&HTMLTemplateElement.decorate(t),!t.__upgraded__&&t.nodeType===Node.ELEMENT_NODE){var o=t.getAttribute("is"),i=e.getRegisteredDefinition(t.localName)||e.getRegisteredDefinition(o);if(i&&(o&&i.tag==t.localName||!o&&!i["extends"]))return n(t,i,r)}}function n(t,n,o){return a.upgrade&&console.group("upgrade:",t.localName),n.is&&t.setAttribute("is",n.is),r(t,n),t.__upgraded__=!0,i(t),o&&e.attached(t),e.upgradeSubtree(t,o),a.upgrade&&console.groupEnd(),t}function r(e,t){Object.__proto__?e.__proto__=t.prototype:(o(e,t.prototype,t["native"]),e.__proto__=t.prototype)}function o(e,t,n){for(var r={},o=t;o!==n&&o!==HTMLElement.prototype;){for(var i,a=Object.getOwnPropertyNames(o),s=0;i=a[s];s++)r[i]||(Object.defineProperty(e,i,Object.getOwnPropertyDescriptor(o,i)),r[i]=1);o=Object.getPrototypeOf(o)}}function i(e){e.createdCallback&&e.createdCallback()}var a=e.flags;e.upgrade=t,e.upgradeWithDefinition=n,e.implementPrototype=r}),window.CustomElements.addModule(function(e){function t(t,r){var c=r||{};if(!t)throw new Error("document.registerElement: first argument `name` must not be empty");if(t.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(t)+"'.");if(o(t))throw new Error("Failed to execute 'registerElement' on 'Document': Registration failed for type '"+String(t)+"'. The type name is invalid.");if(d(t))throw new Error("DuplicateDefinitionError: a type with name '"+String(t)+"' is already registered");return c.prototype||(c.prototype=Object.create(HTMLElement.prototype)),c.__name=t.toLowerCase(),c.lifecycle=c.lifecycle||{},c.ancestry=i(c["extends"]),a(c),s(c),n(c.prototype),u(c.__name,c),c.ctor=l(c),c.ctor.prototype=c.prototype,c.prototype.constructor=c.ctor,e.ready&&w(document),c.ctor}function n(e){if(!e.setAttribute._polyfilled){var t=e.setAttribute;e.setAttribute=function(e,n){r.call(this,e,n,t)};var n=e.removeAttribute;e.removeAttribute=function(e){r.call(this,e,null,n)},e.setAttribute._polyfilled=!0}}function r(e,t,n){e=e.toLowerCase();var r=this.getAttribute(e);n.apply(this,arguments);var o=this.getAttribute(e);this.attributeChangedCallback&&o!==r&&this.attributeChangedCallback(e,r,o)}function o(e){for(var t=0;t=0&&b(r,HTMLElement),r)}function p(e,t){var n=e[t];e[t]=function(){var e=n.apply(this,arguments);return _(e),e}}var m,v=e.isIE,w=e.upgradeDocumentTree,_=e.upgradeAll,g=e.upgradeWithDefinition,b=e.implementPrototype,y=e.useNative,E=["annotation-xml","color-profile","font-face","font-face-src","font-face-uri","font-face-format","font-face-name","missing-glyph"],L={},T="http://www.w3.org/1999/xhtml",M=document.createElement.bind(document),N=document.createElementNS.bind(document);m=Object.__proto__||y?function(e,t){return e instanceof t}:function(e,t){if(e instanceof t)return!0;for(var n=e;n;){if(n===t.prototype)return!0;n=n.__proto__}return!1},p(Node.prototype,"cloneNode"),p(document,"importNode"),v&&!function(){var e=document.importNode;document.importNode=function(){var t=e.apply(document,arguments);if(t.nodeType==t.DOCUMENT_FRAGMENT_NODE){var n=document.createDocumentFragment();return n.appendChild(t),n}return t}}(),document.registerElement=t,document.createElement=f,document.createElementNS=h,e.registry=L,e["instanceof"]=m,e.reservedTagList=E,e.getRegisteredDefinition=d,document.register=document.registerElement}),function(e){function t(){i(window.wrap(document)),window.CustomElements.ready=!0;var e=window.requestAnimationFrame||function(e){setTimeout(e,16)};e(function(){setTimeout(function(){window.CustomElements.readyTime=Date.now(),window.HTMLImports&&(window.CustomElements.elapsed=window.CustomElements.readyTime-window.HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})})}var n=e.useNative,r=e.initializeModules;e.isIE;if(n){var o=function(){};e.watchShadow=o,e.upgrade=o,e.upgradeAll=o,e.upgradeDocumentTree=o,e.upgradeSubtree=o,e.takeRecords=o,e["instanceof"]=function(e,t){return e instanceof t}}else r();var i=e.upgradeDocumentTree,a=e.upgradeDocument;if(window.wrap||(window.ShadowDOMPolyfill?(window.wrap=window.ShadowDOMPolyfill.wrapIfNeeded,window.unwrap=window.ShadowDOMPolyfill.unwrapIfNeeded):window.wrap=window.unwrap=function(e){return e}),window.HTMLImports&&(window.HTMLImports.__importsParsingHook=function(e){e["import"]&&a(wrap(e["import"]))}),"complete"===document.readyState||e.flags.eager)t();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var s=window.HTMLImports&&!window.HTMLImports.ready?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(s,t)}else t()}(window.CustomElements),function(e){var t=document.createElement("style");t.textContent="body {transition: opacity ease-in 0.2s; } \nbody[unresolved] {opacity: 0; display: block; overflow: hidden; position: relative; } \n";var n=document.querySelector("head");n.insertBefore(t,n.firstChild)}(window.WebComponents); \ No newline at end of file From 0df39b4df57be3681e041a5fd4e7f905fa567902 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 18:32:15 -0800 Subject: [PATCH 104/166] Remove no password set boolean --- homeassistant/components/frontend/__init__.py | 2 +- homeassistant/components/http.py | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 9bc46f86023..dac2041fa56 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -65,7 +65,7 @@ def _handle_get_root(handler, path_match, data): app_url = "frontend-{}.html".format(version.VERSION) # auto login if no password was set, else check api_password param - auth = ('no_password_set' if handler.server.no_password_set + auth = ('no_password_set' if handler.server.api_password is None else data.get('api_password', '')) with open(INDEX_PATH) as template_file: diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index 33290a159fa..5e8332e283a 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -53,10 +53,6 @@ def setup(hass, config): conf = config[DOMAIN] api_password = util.convert(conf.get(CONF_API_PASSWORD), str) - no_password_set = api_password is None - - if no_password_set: - api_password = util.get_random_string() # If no server host is given, accept all incoming requests server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0') @@ -66,7 +62,7 @@ def setup(hass, config): try: server = HomeAssistantHTTPServer( (server_host, server_port), RequestHandler, hass, api_password, - development, no_password_set) + development) except OSError: # If address already in use _LOGGER.exception("Error setting up HTTP server") @@ -93,14 +89,13 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): # pylint: disable=too-many-arguments def __init__(self, server_address, request_handler_class, - hass, api_password, development, no_password_set): + hass, api_password, development): super().__init__(server_address, request_handler_class) self.server_address = server_address self.hass = hass self.api_password = api_password self.development = development - self.no_password_set = no_password_set self.paths = [] self.sessions = SessionStore() @@ -157,7 +152,7 @@ class RequestHandler(SimpleHTTPRequestHandler): def log_message(self, fmt, *arguments): """ Redirect built-in log to HA logging """ - if self.server.no_password_set: + if self.server.api_password is None: _LOGGER.info(fmt, *arguments) else: _LOGGER.info( @@ -192,8 +187,7 @@ class RequestHandler(SimpleHTTPRequestHandler): "Error parsing JSON", HTTP_UNPROCESSABLE_ENTITY) return - if self.server.no_password_set: - _LOGGER.warning('NO PASSWORD SET') + if self.server.api_password is None: self.authenticated = True elif HTTP_HEADER_HA_AUTH in self.headers: api_password = self.headers.get(HTTP_HEADER_HA_AUTH) From 546377e80a7104805cb94400612f6439e8a2cb83 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 18:59:59 -0800 Subject: [PATCH 105/166] Throttle camera stream to 2fps --- homeassistant/components/camera/__init__.py | 37 ++++++++++----------- homeassistant/components/camera/demo.py | 4 +-- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index ae5fe28beac..e63665230ca 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -19,6 +19,7 @@ from homeassistant.const import ( ) from homeassistant.helpers.entity_component import EntityComponent +import homeassistant.util.dt as dt_util DOMAIN = 'camera' @@ -80,19 +81,21 @@ def setup(hass, config): def _proxy_camera_image(handler, path_match, data): """ Proxies the camera image via the HA server. """ entity_id = path_match.group(ATTR_ENTITY_ID) + camera = component.entities.get(entity_id) - camera = None - if entity_id in component.entities.keys(): - camera = component.entities[entity_id] - - if camera: - response = camera.camera_image() - if response is not None: - handler.wfile.write(response) - else: - handler.send_response(HTTP_NOT_FOUND) - else: + if camera is None: handler.send_response(HTTP_NOT_FOUND) + handler.end_headers() + return + + response = camera.camera_image() + + if response is None: + handler.send_response(HTTP_NOT_FOUND) + handler.end_headers() + return + + handler.wfile.write(response) hass.http.register_path( 'GET', @@ -108,12 +111,9 @@ def setup(hass, config): stream even with only a still image URL available. """ entity_id = path_match.group(ATTR_ENTITY_ID) + camera = component.entities.get(entity_id) - camera = None - if entity_id in component.entities.keys(): - camera = component.entities[entity_id] - - if not camera: + if camera is None: handler.send_response(HTTP_NOT_FOUND) handler.end_headers() return @@ -131,7 +131,6 @@ def setup(hass, config): # MJPEG_START_HEADER.format() while True: - img_bytes = camera.camera_image() if img_bytes is None: continue @@ -148,12 +147,12 @@ def setup(hass, config): handler.request.sendall( bytes('--jpgboundary\r\n', 'utf-8')) + time.sleep(0.5) + except (requests.RequestException, IOError): camera.is_streaming = False camera.update_ha_state() - camera.is_streaming = False - hass.http.register_path( 'GET', re.compile( diff --git a/homeassistant/components/camera/demo.py b/homeassistant/components/camera/demo.py index fc3ec263143..fd79bc3ce82 100644 --- a/homeassistant/components/camera/demo.py +++ b/homeassistant/components/camera/demo.py @@ -24,12 +24,10 @@ class DemoCamera(Camera): def camera_image(self): """ Return a faked still image response. """ - image_path = os.path.join(os.path.dirname(__file__), 'demo_{}.png'.format(randint(1, 5))) with open(image_path, 'rb') as file: - output = file.read() - return output + return file.read() @property def name(self): From e67732b4f85820d71d9bbb14b1b6de3014bfda7a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 19:12:42 -0800 Subject: [PATCH 106/166] Remove no longer needed image --- .../components/frontend/www_static/splash.png | Bin 51901 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 homeassistant/components/frontend/www_static/splash.png diff --git a/homeassistant/components/frontend/www_static/splash.png b/homeassistant/components/frontend/www_static/splash.png deleted file mode 100644 index 582140a2bc35f598fc227782ff06039759b39fe5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51901 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 z 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 From 733de6b3576c0c4982cb4998ef37cf255aaa6ed5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 22:14:40 -0800 Subject: [PATCH 107/166] Streaming API will keep session alive --- homeassistant/components/api.py | 3 +++ homeassistant/components/http.py | 43 +++++++++++++++++++------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/api.py b/homeassistant/components/api.py index a81c0f3227f..1e6e66baee0 100644 --- a/homeassistant/components/api.py +++ b/homeassistant/components/api.py @@ -106,6 +106,7 @@ def _handle_get_api_stream(handler, path_match, data): wfile = handler.wfile write_lock = threading.Lock() block = threading.Event() + session_id = None restrict = data.get('restrict') if restrict: @@ -119,6 +120,7 @@ def _handle_get_api_stream(handler, path_match, data): try: wfile.write(msg.encode("UTF-8")) wfile.flush() + handler.server.sessions.extend_validation(session_id) except IOError: block.set() @@ -138,6 +140,7 @@ def _handle_get_api_stream(handler, path_match, data): handler.send_response(HTTP_OK) handler.send_header('Content-type', 'text/event-stream') + session_id = handler.set_session_cookie_header() handler.end_headers() hass.bus.listen(MATCH_ALL, forward_events) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index 5e8332e283a..81965179afe 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -337,26 +337,28 @@ class RequestHandler(SimpleHTTPRequestHandler): def set_cache_header(self): """ Add cache headers if not in development """ - if not self.server.development: - # 1 year in seconds - cache_time = 365 * 86400 + if self.server.development: + return - self.send_header( - HTTP_HEADER_CACHE_CONTROL, - "public, max-age={}".format(cache_time)) - self.send_header( - HTTP_HEADER_EXPIRES, - self.date_time_string(time.time()+cache_time)) + # 1 year in seconds + cache_time = 365 * 86400 + + self.send_header( + HTTP_HEADER_CACHE_CONTROL, + "public, max-age={}".format(cache_time)) + self.send_header( + HTTP_HEADER_EXPIRES, + self.date_time_string(time.time()+cache_time)) def set_session_cookie_header(self): - """ Add the header for the session cookie. """ + """ Add the header for the session cookie and return session id. """ if not self.authenticated: return - current = self.get_cookie_session_id() + session_id = self.get_cookie_session_id() - if current is not None: - self.server.sessions.extend_validation(current) + if session_id is not None: + self.server.sessions.extend_validation(session_id) return self.send_header( @@ -364,6 +366,8 @@ class RequestHandler(SimpleHTTPRequestHandler): '{}={}'.format(SESSION_KEY, self.server.sessions.create()) ) + return session_id + def verify_session(self): """ Verify that we are in a valid session. """ return self.get_cookie_session_id() is not None @@ -387,19 +391,22 @@ class RequestHandler(SimpleHTTPRequestHandler): if morsel is None: return None - current = cookie[SESSION_KEY].value + session_id = cookie[SESSION_KEY].value - return current if self.server.sessions.is_valid(current) else None + if self.server.sessions.is_valid(session_id): + return session_id + + return None def destroy_session(self): """ Destroys session. """ - current = self.get_cookie_session_id() + session_id = self.get_cookie_session_id() - if current is None: + if session_id is None: return self.send_header('Set-Cookie', '') - self.server.sessions.destroy(current) + self.server.sessions.destroy(session_id) def session_valid_time(): From f76edf0ed94469afcda4657c6aeaf772c93b6e6c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 22:15:11 -0800 Subject: [PATCH 108/166] Tweak manifest and frontend index --- .../components/frontend/index.html.template | 19 +++++-------------- .../frontend/www_static/manifest.json | 1 + 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/frontend/index.html.template b/homeassistant/components/frontend/index.html.template index 533fc43ac4e..87c5f6638a7 100644 --- a/homeassistant/components/frontend/index.html.template +++ b/homeassistant/components/frontend/index.html.template @@ -4,18 +4,13 @@ Home Assistant - - - - + + + href='/static/favicon-apple-180x180.png'> - + -
- -
-
+
diff --git a/homeassistant/components/frontend/www_static/manifest.json b/homeassistant/components/frontend/www_static/manifest.json index 3d0eb5fa443..3767a4b1c5b 100644 --- a/homeassistant/components/frontend/www_static/manifest.json +++ b/homeassistant/components/frontend/www_static/manifest.json @@ -3,6 +3,7 @@ "short_name": "Assistant", "start_url": "/", "display": "standalone", + "theme_color": "#03A9F4", "icons": [ { "src": "/static/favicon-192x192.png", From 286299c4c9716d41c059145b8391de714c37c68d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 22:19:34 -0800 Subject: [PATCH 109/166] update frontend --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 18 +++++++++--------- .../frontend/www_static/home-assistant-polymer | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 7e957562bba..04ccb720f6b 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 = "c1df3a08faa4a9978b25639ca0fd63cd" +VERSION = "36df87bb6c219a2ee59adf416e3abdfa" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index cf19d314f24..e600c4c5583 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -6052,12 +6052,12 @@ case"touchend":return this.addPointerListenerEnd(t,e,i,n);case"touchmove":return font-weight: 300; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; - } \ 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 f29b1062b30..33124030f6d 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit f29b1062b30c76ceeea87fd426a042d98358394a +Subproject commit 33124030f6d119ad3a58cb520062f2aa58022c6d From 70698f7ab09d487ea994b76bac575aa7f80aa8bb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 28 Nov 2015 23:16:20 -0800 Subject: [PATCH 110/166] Update demo camera images --- homeassistant/components/camera/__init__.py | 1 - homeassistant/components/camera/demo.py | 6 ++++-- homeassistant/components/camera/demo_0.jpg | Bin 0 -> 43574 bytes homeassistant/components/camera/demo_1.jpg | Bin 0 -> 44897 bytes homeassistant/components/camera/demo_1.png | Bin 9772 -> 0 bytes homeassistant/components/camera/demo_2.jpg | Bin 0 -> 44535 bytes homeassistant/components/camera/demo_2.png | Bin 9667 -> 0 bytes homeassistant/components/camera/demo_3.jpg | Bin 0 -> 44897 bytes homeassistant/components/camera/demo_3.png | Bin 9595 -> 0 bytes homeassistant/components/camera/demo_4.png | Bin 9906 -> 0 bytes homeassistant/components/camera/demo_5.png | Bin 9699 -> 0 bytes 11 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 homeassistant/components/camera/demo_0.jpg create mode 100644 homeassistant/components/camera/demo_1.jpg delete mode 100644 homeassistant/components/camera/demo_1.png create mode 100644 homeassistant/components/camera/demo_2.jpg delete mode 100644 homeassistant/components/camera/demo_2.png create mode 100644 homeassistant/components/camera/demo_3.jpg delete mode 100644 homeassistant/components/camera/demo_3.png delete mode 100644 homeassistant/components/camera/demo_4.png delete mode 100644 homeassistant/components/camera/demo_5.png diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index e63665230ca..169c97595af 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -19,7 +19,6 @@ from homeassistant.const import ( ) from homeassistant.helpers.entity_component import EntityComponent -import homeassistant.util.dt as dt_util DOMAIN = 'camera' diff --git a/homeassistant/components/camera/demo.py b/homeassistant/components/camera/demo.py index fd79bc3ce82..0ad992db86d 100644 --- a/homeassistant/components/camera/demo.py +++ b/homeassistant/components/camera/demo.py @@ -4,8 +4,8 @@ homeassistant.components.camera.demo Demo platform that has a fake camera. """ import os -from random import randint from homeassistant.components.camera import Camera +import homeassistant.util.dt as dt_util def setup_platform(hass, config, add_devices, discovery_info=None): @@ -24,8 +24,10 @@ class DemoCamera(Camera): def camera_image(self): """ Return a faked still image response. """ + now = dt_util.utcnow() + image_path = os.path.join(os.path.dirname(__file__), - 'demo_{}.png'.format(randint(1, 5))) + 'demo_{}.jpg'.format(now.second % 4)) with open(image_path, 'rb') as file: return file.read() diff --git a/homeassistant/components/camera/demo_0.jpg b/homeassistant/components/camera/demo_0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ff87d5179f8364d86acf3a875e374741c5285bcb GIT binary patch literal 43574 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%0DH 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 literal 0 HcmV?d00001 diff --git a/homeassistant/components/camera/demo_1.jpg b/homeassistant/components/camera/demo_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..06166fffa859d9fdccf1fc89a563cd6574319d42 GIT binary patch literal 44897 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

SRA^Sy-HeIiGTl4YPvhL`x+uUjH-c_;| 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 X#STjDOT{=W?XLf4nCiOn?*E$r*w#h! literal 0 HcmV?d00001 diff --git a/homeassistant/components/camera/demo_1.png b/homeassistant/components/camera/demo_1.png deleted file mode 100644 index fc681fccecd69fb91801a6ecad8cd28454cae278..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9772 zcmeAS@N?(olHy`uVBq!ia0y~yU^vgfz;Ka+je&t7JNDTY1_lO}VkgfK4h{~E8jh3> z1_lPs0*}aI1_oAF5N6EbymmtT}V z`<;yx1A_vCr;B4q#hkZuD-%Rq|GlukTCCQXU?Jqe@qKDRM^i<21AEi!jU8)N+kMrw zDRpIGEwue`C^RNNcK+(u@6J~{#zxNDEvL~XzD}lS@d?Fn0S*BsmEyAf_HFZg&ihO{ zImgzs_TQ;5CCjp_eq9cY{kk@vbJl^C@^V?P19Xy27S3I&$j14C?+Np{Wi@>+NlY;g zTiK#nZ)N#*9F3d*zgczhZJCa*%q}|CbAM)@H8{HdtV4!4>uJGVv zN=GMp%xb#3TJyO!Q(O8j6(P@UiWkm>U67dYvdKdw@&p5`<946vPD&^3T=-cnw<%9N z;=GT^!YG!jQ-%9vr&Or!L=P$VQ_2&MbWU+s>J--OcM(z#lIv9QTVf;RIme??Ws=3j zPaZ0TN>3+xJUTM#C6kAe<H4{) zOSe7PX3VWSW$Vd@>q7PF)`S^{TX?c;x|t@#Qs8aB*uv_qY*TvsvjRW&%Js&=L2|+i zICiW(b5M1z^3jVMwF|B@u!oneu9x?$n)oS2V(-ebM9;@tyBO5IZYr+Lx6HoB<56kU z!LaPxX7h;0E|0s`nJxRe`Sg}`l5VFaE0z@ME6WS-tdw=7}gbWTvhZcX#KS zVz0^1p6uHzv z)A7{glru_w=RP=TfA?q%YMP?nIm1^*Rx==L!Y38Z&0Qcn?1JX0B$O4FEO9vLdTO#l zSHsLmg}y!!jY^M7AqVm2e{=*vcFQcWDV((S(F>18A@@_l>|G7^DH|=U4s)-)W9i_x zqFY?kUpSEEPT;!-cXY(v(^Do+t!6vn(NZztlL=$&oX@j5Ev%Hg)|}CpZW<6g@zW8H zVo~?>5_RqEr{{3^I-L?`J{v1D_u|p8W!{ZRZl^ADR6Tbn7I#ng**Nv~FUypu)e;jv znKbD66~C0}n7UClOzr#BPEl#+Q^EYYp)zv|mzt@4pU7m|GDV$BH&$lu>0LK|>=juN zx5OsVqp&CD-qB;dM&@N9Peg^9Tv@`DBqCM(y)}e)-CFTA`_Fl?{4@VA8@d~8yK$`W z+mGFHCJA31?YqDI2=JY8Auvw$_=HC$XSUkD`C(d-oBf!n^o-yh3!V0w=ts3>;!`6u z^A~?O(?74pUi;>WH0hu@5kF)7t;0)lZT5dtotx_^=>9xh)l5chPmpiKk}pYu1=~f` z)7HJuef~+0m)m54Z;`(CY^Ge%=)Qd{{){3ZqeUa!pi&L2~ z$aVAnS!ntXx zv$vn6e*4JhRXn*kG~Z^;rw3Bz)>$Ekzp+}^mK0RXxOxBJg>BQ8$Y@K6F;?oT%n#jM z`)niEj{Jl)W%fND%?a2h8#;5_9oMDSA9sH}mNixLbe8gwi#MNNoAGn+>Vuy= zl9orFN)|16?~s0Mb{2P8Wn^q<`NC(BtjS$#W1_MapNK3kUssa7=Rvjy4aUT{J5Lhd zZF6ub*&6=%{_Yx|4#g9}LH1`?Ju{qa(Y|Na!k;Cn=E=E_wYolq>G=iP~&5n=bZNZ^Z~eq@+^n&BzausHGTB0tNC%Xe8Ek2o#!?b!V( zx8AS(eP3?vl#V!4#xJMC7roQ(>`znd4?R%Zd`6kip)pqC)BLq7yY^gOztZTMiR_$@ z--BAu&A%DC*llj*&bKS1O6xsqQuf;HvPds6=(k|76g${pR+>6%``y!z_LiP^u$K+1 ze8s*!@&6~YkM-@2$FKfOw_QK``~Krg4JXX5+HF7f_WtgQFD&Vk*(J5_N*V7f7qr{3 z|L2BN&kj$VE3p6l;{~-m#>T5{q~hOv{d_smK2Ox@DTiNv{!;(CYvvJ?nk4pp@VI7c zsTMtFYx|!&n@^oRSS7c}`Wc6uxa7JHjpXFl!QVrL%v(|7Gc z?Rz{ab8XC6-$}oC@-TQHK#zeKS#zmdV4W4^*G@L&CWwd9vm0H`+JFQQ1+p&4j{d76XEgk;nZyMv z`fUw={JOUE(VS}s4{dfX-m&G%u^)P7aT3#<|4;BS;4c5|;Tm#!NnF{wH)(qwn1`*t z^KGy8s~i5Sjxhc>Zk8V)W2^M{?B(K$#0b9i^QUD?Wc=N5$UT%>PX82FWsoADK#tSP zn7e25UL^pmOOdn+&_%z`}Gq-n6 z+ksn3%O8CEv}@L}^#{MRN9QeRdim6Iss+P41O6!Yo!>qk-nKL7M$wEL#=9IYhqJKU zdVX!jt~;q2`#2svQ|Vw1czl_sap~VhPvT!sUoVko@O!cV@4U4$cCEIW`iP-~OZwvf zs`>LdW2biHT6Hz_ak?-bIdo)RHO=t^z6^vefIS21jAX4$0IKl zZS;AQ`P@8F@O*UN3c*J{o{KC5c36Jl@3i^xoKJqX)3MGwS~jB7jH?p3`$7y-&raqm zELrzD^KqkTqk&{USN*LA&pyiE$(U8h<0e=T+yABY!~F}l`+Pg+MZ}7$i+Zx_zs=$G zn{4sw@{Ynx-R0Z1UpmEgn(xQW*Q>0xmv7mALDT)3&9Z~b4m3AkQsz5wLP>ji>(jWf z=0{gzHH52gNybdLxBJces#`l3MK4iUDa4*oF>&fc#mO9dwQ4qAKVGj@!&Z3f221eo zWy@zv89bF*xondA`a-|V`S-d@isY@0Psxh7@HB9B&1qt1v;2`erQ1R_=JH*ObyqfT zRb85y$J!{Wd`u+z_1*;UV$pe0kCr4$WzW^DWj5V7)4;bdhwIM#Wy_*Wj)_HAe*O}3 zcw1g&({{h}XMdEu3n;o=Q1yoEPTac(KPML{IZgT(UT$4)Z+hI|-ekVEt(y&gS1e!2 zV&ocFQs{U3!cN>C9}l10 zVUs54K1p^?WJcmO2lhgio$7OYPAMOqc;s+oYgjPHl#R#s_%^b$Sz4N&oy)xP$m&Dt z`+r0Py-c6)eKb*U%2Vwgy=|9F`(E-)`Xw2c@pK;JhX+yRM{JgrOcbn~wb)`d-|90_ zZ6RQ zkZrl%*3;7#Ub~X;`qtEI$;T#`7o`OC7ne;G?QL+F8KGqKHMpO^YgHLK);M( z&i(&C9zU5^sW$h1jd1kybDq}sI+V2YMCD@V*EL?cH7%p>5rfUPgUJHRPiRWqJ$dTF zHZf=4&-eK93%=N0T_JU6_pzh)+k{Z!Lgu{Axrb>7;Zz>D5mfB$5sAKvViys+%1(YJH6Qg1xd&{u!| zW^>@DPffS?SeFG9KJMj|*Pp}PwbsXfvqR=YcmAE3d5;*{X1NF!WZSnpP7}TzwL>B0 z;_{52w zmA}ER6_+MtY(3StAtaRZY;cfBv&1`IX{EA{p&<|KOEiAmy0owM&++cY!lh<;uO{D` zcXrB&#{mx}9=xf`cR*17&fZg37dR~4*`?@|DP-ld6iv`ZTs^+No7s@o7X$t{JO31)7vgFmM@)7+P+@%;6D5Rf8~93|0+LheO44$ zc$jy=wYewm7@zlfQL(Wga{3jnDPIcZ+L`KQ-uRrBHMWaV!>#`>=(&s81`J%d<^q{*IeYfv#aA@^AXzV=qj*OUN zfm36vx&Qfxi_X2|eO3_l;G^)IIRb~@T-WM9wpKglkBsxFdj(oqp?Ps(r}ei=ea@@u zX%$|!Q1fE{%NMt&=XHxGzrVWrt7l+ z%30lud_U>U-ovv}ZKE^`^{39zIDV7WpQrFs?$Y_^zx`+`DmfdhQNr;o?=ze6Q<*O; zm!fP77fqHk^eegjn9E~%d3SbKE9+#rln1@n4IkLA58hpp8Jlza#>Oo>A91zl7JFO9 z-9Fsbc1$~3NM58(<;3GH2ju(9i;|25-QC4K805_Y6^s=df^SDJ;tTkGHoPLC*IHvj z9P?473;J87g2P#|WMo}g(iZf+G7)Gy@A>Syht&128y<%~JUd@lTw~$PUYq+;8ZA@R#c7)SDJS`^88Sau={cy`;B42 zPM_9TT(B{EvU=62Yipw;w`Pe>ojUdFJ8_W}JDzepS@&Fh-Fk2P*(*E?{*^g>I&=SJ z>f42HL|=S(c=%57dD|&drd(L;&d`QOHip9;QoKU*~E1ykkhg$@r* z*b8IoD$1*qZ1Xs4tJiaF*C{Uas^*R@68-e*WN}*ffk6LN!pm8m+8x=%BOb-=+MxO7 z&d$jf7rSrHyK8m0%=dD{t`g1ZaaEd=)%~B%OrPh-kzC1Qu=Wfilh_-RvgCGqq7o$g)_eN#ez_u` z-u!mu+k>Bf*2EN@R26*G^7&5j`HOq2%k%brz1H!a#b9lGf`Vzt0{PWv!@pknVOpf) zJDY1Ecgb_D$0l#Hci+CO$9Ld6`=39h#h)Hu7CKmRxaQ@K{QbXPt=5U(XY*s%o;`ES z?^QJG@BcID_xt_w%P&jTyx;fx-Qx!bn*;6L#Wn6OG~c*kW7N||)4XGKaffG|&$4)a zd9hF2vqy{X?we68Hs{j4Ll-uDm^XQ|O_1Hp8SlccUrIP1oxfM~&+a8lTGsFT)zy^z zIq;mtW1dr|PfOa@*$7nV?fP@``wQ!5+j;BKqT3%hOi6Q4E9yFX_t{hZ**0vRf27u| z{j_=8sq=^K+P#y1(vhk9dXdPN=*^%p<EGeV=UN)19+zrQ+mG zIe|=~tpX8i6~Bv`{(HXDYx}7)Q}qr<&0o3b+Iq<&fi4QG&&d9jjk$g}??p#s&`Wb2 z$;`4APVEC?n*Q_cYMbi!e?Dh@<;oR_d+|F86h%cv4_@E7wAP~~l>P6Sn3s#pj^^%A zomzKT zQsd>9DF>TaOY&6GKmGXlc<1+f)sL;(81i1GKc95&*zW(Un(NZ)-urn9>y;GVy}MOv z_Tfc~{z|p|;W-+4WpdiFNwfUsm3)2k?d|R9si&tI7Cv$*Dk|c6U;6S=t9V>Ra}Y1YE50;rF-_+D5(Q=t}RUw3k|}Vk^GpDxUuBqo2&O-BCu}Fa6w&%h^5FJ8WE()wql3-@m^%uUyk3e`{;R*i-9PukRC37pV^wwLaE+cyp?^)A3J1r{(IFbj4=4 z@Xx=<%2m(i#TM0dw6bt=JNvaA%10U<{~AQ zcdtBsylz+5I{A8^>EG`!|9WHN!MFcbX?;64OZ2+owhy}JjoP9!4(t3foP6%g0^#>Y z&5LC^Zp7EKNli~_+;{7__e_iV{~l$R+~iv?74gAhp6iw~9^HA{D$CzJd9hJ)DFf^E zc>j;w`YiF=<&4|jipL&#`29ZngAdj37w(MVNPp95EcTHnzgRmfB5wELH&2u0k}dO# zjpZ+N8Xf-4G~>?ozIbD{$!bnN{>&5R((%zR4tRWd#meXPNsh_^uV37la==JVxqHoy zzf$@6-&yxJySIjKtJqnd@X9(VsQ2X)PxW_SU-P~_vd#Q%${k0JTlXrG1LU?YV>>@h z*W%RaZ zdN6c9Yw+)zE5BvwSY1nr4tjZbwUw05%h|j$*8Rw=efCj0n>n$!NT2icy2U?}U;hpI zXxty&{D_0)@Xm>vH3wAwIfl2fd|#WQJ^w?>mGhoU*3MsPxLGi8+C0gt8}nwL_CK^T z?`*@*C!UWtzN!5!6&JquThtM|_PAQpAKMEoHhg~}csV`)X|&eL*9kjjwExgOe|i2z zo>V5|ACt~q(Ov#8{$57bM`@R<59W$|yl&bzV9jo0D(tn~ABo3w={%uxd z(cJl`S(D*SvT$6?4G$Z^g{ux8etmZhk9W_!eBm#dYh8SKCUNNPKlWMzm@T-0`|d{1VD{f4#cR)#sG%N&^}ttZ9XIl1TEi?$s*`!_N__-t$U zF7oZ8g`N7Z-%r zyEg~kcq`k~&Tf5q)4w1qgV@cw!LvcQX4sUTFa{>Ap=yYhmw z+KR4uYCLcC_X@vHI~&VSE>DhmYT9jKwR9&}Ie)=}%S_$>qg)m=FZihu z-2QV`?#yk=<&I5@*tvH8;SUR>y@lVI+nj!1(af}UdE)L1Iy{fU@0<+!RZtd_YBbwo zVFYVQ0ZY}@S&J=Wm85rC zGxVHna9F6lzfnYe@{D&=(kI(YkZdeDr?q8SDnp2n?B%)NawfAIDPM?e4NK!K5jdRn z;VhGJo$uw+(Ah`lJ!St>v*q@2|Mt)tt&%f>bM75H#Cmkw3Pp|NF6QN*Hg3p!lX*J3 zvdE)odXE2gi{E#oxXY@3{#$U0al2ci?S`a7>%DReSx=gU`>6Xb`@HSyFH^a==MTI0 z9&7(3Yr3Ii|NQ!#&z~MBsPBz-mkOEh5IlYNj5s;TP+9(;W)s5-|HVFhJX8M84(GIj z@GFOQIcw$Te{VZ0l^b~?Et+E$+xN9)?j6FX^tVcFUt8dMR)CqYF|Eb);kR8T&(?f) zxx0U5$;seLYUhscuKkm_H*ikC9xa>g7Y|oU&MKLnc}Crz?d{JW;`0CR#+xrcmf85( zDpE2$Yq3g-@9eDgo0i}H!oa{f7qk}OSg`#S{llz*EVt$_$vpltOC_}0bl%U4KV7_@*$M3pw_wK&){V}KPWUz$zx0qtbjZ;~z_vToXox2wHvvHbg|Ib;ul2&=W z{>E1XWEX!?Dm~?S@8zwCwby>%nZomL+s(t;(L&&By8f zK32Ua$-B~`mj$r!9b@T}zp+4k0zzAu(VR~{l7=yTV!o#yxd|HAA{venAi)6uH8OFpG+`m}%1?B4uuKQFF`_I>d5tXxzi>+S3i z=gsdP2}!5^^xd7X>zU@3at^tu*KYM~_n-UCbExkQdi*7C?S~(o=hXb`-(B>2csSOs zOlGyD{q4ueo=f}nc5+!~n;c#gEi2PhY(48;keB7M)!D|H=Nrt#*1b)XIkToD`%ldk z4Zry{t)6=yNq>=vOnJJFk`wK1HqQ}=A zSkuTiM|b@r!-Y1Ib?^2pYwvxT+PC8LI_?L5{KDo*J@R>xw9^N}f z!nSE?6ZaUzEwTA};gpue`pHv2TP=Mj(aAL>tFT0bQGMIif~4DLt{N0cmGNxZayDW{bgr6H~`b8Pex6!>Q$CQ1`MfgSE)MHzN zzV9&6?DI63Z!=TRfvr>R!odx5SgT`?&04XvBl%ce;R(cGLcH<8Gn&h_p-dm~bR za{2RQ{(I!`#PdbSd!}Bm%Oq2dkL&%< zpS-`GA)~9pvd`;cG|J-*41SNj`+_`qXbH;XtXQ#g^Ph29;d+^NB=i91`{`6J}*U$ZX z@}jrNmi-F@C*0cPsj}=T!>S!-dyZXPS?+b{`ST}d#l=zuoc7G!waHWEnahEg`D$#} z)X#0Km3scBzn|}_NS^y;Jti4X?S(E$dUp=&4{<&7vnb?V*Ris^pncbj@2%Ggkh#Xq za;qRgphM2V?m^G`HA0@p3K*|0$Q6`YZE_?j@pIjWpB+sz+Oz-J&k+y07Wes<4FdxM NgQu&X%Q~loCIAIg5cmK9 diff --git a/homeassistant/components/camera/demo_2.jpg b/homeassistant/components/camera/demo_2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..71356479ab08c00a17ec0e09c9198714154f85d2 GIT binary patch literal 44535 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 S&b>lU|9$xLV%GQi|2F}=zPe%n literal 0 HcmV?d00001 diff --git a/homeassistant/components/camera/demo_2.png b/homeassistant/components/camera/demo_2.png deleted file mode 100644 index 255cd5c45d4510cdc5853f22080017af1fad0e68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9667 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 diff --git a/homeassistant/components/camera/demo_3.jpg b/homeassistant/components/camera/demo_3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..06166fffa859d9fdccf1fc89a563cd6574319d42 GIT binary patch literal 44897 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

SRA^Sy-HeIiGTl4YPvhL`x+uUjH-c_;| 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 X#STjDOT{=W?XLf4nCiOn?*E$r*w#h! literal 0 HcmV?d00001 diff --git a/homeassistant/components/camera/demo_3.png b/homeassistant/components/camera/demo_3.png deleted file mode 100644 index b54c1ffb57c97644426efae5950dcf47e8c70031..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9595 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

bv~b* z3&mb5r&cP(wXrSp^Fp-4LB&e`;dMv-vSc zYCfg>-1&LcKeIg9XC1rV>|!{lzkO4}9^;kWs?!|o<6m~o`m$FyuH#aOx0}q|gR!FX zELE#aSRL*&wJukGVz??=-Gp7(?Dm-h-?i4x3C(&qS<3$Qp`_bFbIoMWO_{uMnbYio zuX4S!!*>4oTA^P1$VY9yUSY|v^1vTwkJwz3`?&d6$Na@|y-u?eayGVd-qqDSZ#T=^ zqcZ8jQK<;~=X*@jT7AP7lyom%+~JV5u4H}Bb*Un$GMSQX7n?GCEn*j3n^kb}h~yl$ zLY0jZKh0>+TpIQ+tKDJak;<5^$$@9o{nNLwTUfU_l&>k3{AT^+(h>``gEgO0b~8k( z%yMu)R3s)-CYinHoKm0U{<$xooDA8rF%q;QK;O;c(W|3UVJkj7`O&A(=W@^GOvB43 zoV_{k*35}cd-`sJlm;lc`}>M7EuE}l_+yV=X<_TiLnWVTqFz7$zI%_L<}@qm^yyJM zi(Q^1tW{7rx8B+@nD@bq@W`iA<%RV^xxUn=C;G-KVfi5^9)I2WKOp{-P5 z^{{!n)a6oTW>`b=P4Jo)6OD|Tsc(ZkRCcy+^A_Boc>CxCkD>{^U2LZ}#d3A3T)!Y7 zuOWB!zuBhC4oaE)aO2Zs4*uevT!f4(eJWzrnSj{W~$-#KK(>JWS+`KDgK%Oq`% zsmC8YQF!V8{7F6Eqw_a)C%GimvFQAJu%~INfKcLsm5ohe|M`>m*Y8j0$c-+G`xno0>+4MY=`KlCd9h`62k$$@ zcX06hO~|_L%JG)%K+VoNl}Tq7E6&)RlQliQeZQdb$Lo>rP2*NA+}q(+San)$;*4ok zA%&$Cy^Dp5y$-QI7u%z%b1I{y!nQVbvd5XuhNE`AJzc8jPS)Ofwx(QKJ%ele;!JVo zz9~}!lnll59;{!bB=`5loTjU}Z||(DS-brI-;9lqHq?bL@MUvre!(xobneJ0t%)hT x;ujch=`Gyo=d2@a_TJvkVz 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 From 41a0f2c198722c683045bc26d9436b254ce7f8a6 Mon Sep 17 00:00:00 2001 From: pavoni Date: Sun, 29 Nov 2015 10:47:20 +0000 Subject: [PATCH 111/166] Add elevation attribute --- homeassistant/components/sun.py | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py index efe0a7dec2b..687c0856e5f 100644 --- a/homeassistant/components/sun.py +++ b/homeassistant/components/sun.py @@ -12,12 +12,14 @@ import urllib import homeassistant.util as util import homeassistant.util.dt as dt_util -from homeassistant.helpers.event import track_point_in_utc_time +from homeassistant.helpers.event import ( + track_point_in_utc_time, track_utc_time_change) from homeassistant.helpers.entity import Entity REQUIREMENTS = ['astral==0.8.1'] DOMAIN = "sun" ENTITY_ID = "sun.sun" +ENTITY_ID_ELEVATION = "sun.elevation" CONF_ELEVATION = 'elevation' @@ -26,6 +28,7 @@ STATE_BELOW_HORIZON = "below_horizon" STATE_ATTR_NEXT_RISING = "next_rising" STATE_ATTR_NEXT_SETTING = "next_setting" +STATE_ATTR_ELEVATION = "elevation" _LOGGER = logging.getLogger(__name__) @@ -139,11 +142,13 @@ class Sun(Entity): self.hass = hass self.location = location self._state = self.next_rising = self.next_setting = None + track_utc_time_change(hass, self.timer_update, second=30) @property def should_poll(self): - """ We trigger updates ourselves after sunset/sunrise """ - return False + """ We trigger updates ourselves after sunset/sunrise, + but sun angle requires poll """ + return True @property def name(self): @@ -159,8 +164,11 @@ class Sun(Entity): @property def state_attributes(self): return { - STATE_ATTR_NEXT_RISING: dt_util.datetime_to_str(self.next_rising), - STATE_ATTR_NEXT_SETTING: dt_util.datetime_to_str(self.next_setting) + STATE_ATTR_NEXT_RISING: + dt_util.datetime_to_str(self.next_rising), + STATE_ATTR_NEXT_SETTING: + dt_util.datetime_to_str(self.next_setting), + STATE_ATTR_ELEVATION: round(self.solar_elevation, 2) } @property @@ -168,6 +176,15 @@ class Sun(Entity): """ Returns the datetime when the next change to the state is. """ return min(self.next_rising, self.next_setting) + @property + def solar_elevation(self): + """ Returns the angle the sun is above the horizon""" + from astral import Astral + return Astral().solar_elevation( + dt_util.utcnow(), + self.location.latitude, + self.location.longitude) + def update_as_of(self, utc_point_in_time): """ Calculate sun state at a point in UTC time. """ mod = -1 @@ -198,3 +215,7 @@ class Sun(Entity): track_point_in_utc_time( self.hass, self.point_in_time_listener, self.next_change + timedelta(seconds=1)) + + def timer_update(self, time): + """ Needed to update solar elevation. """ + self.update_ha_state() From f4c3fbe8fde415c23bedbb714402f694b1bfbcfa Mon Sep 17 00:00:00 2001 From: pavoni Date: Sun, 29 Nov 2015 11:56:47 +0000 Subject: [PATCH 112/166] Add attribuet config to numeric state platform to allow trigger based in attributes rather than states. --- .../components/automation/numeric_state.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/automation/numeric_state.py b/homeassistant/components/automation/numeric_state.py index ab3529235d6..fe0a4f98bd9 100644 --- a/homeassistant/components/automation/numeric_state.py +++ b/homeassistant/components/automation/numeric_state.py @@ -14,6 +14,7 @@ from homeassistant.helpers.event import track_state_change CONF_ENTITY_ID = "entity_id" CONF_BELOW = "below" CONF_ABOVE = "above" +CONF_ATTRIBUTE = "attribute" _LOGGER = logging.getLogger(__name__) @@ -28,6 +29,7 @@ def trigger(hass, config, action): below = config.get(CONF_BELOW) above = config.get(CONF_ABOVE) + attribute = config.get(CONF_ATTRIBUTE) if below is None and above is None: _LOGGER.error("Missing configuration key." @@ -40,8 +42,8 @@ def trigger(hass, config, action): """ Listens for state changes and calls action. """ # Fire action if we go from outside range into range - if _in_range(to_s.state, above, below) and \ - (from_s is None or not _in_range(from_s.state, above, below)): + if _in_range(to_s, above, below, attribute) and \ + (from_s is None or not _in_range(from_s, above, below, attribute)): action() track_state_change( @@ -61,6 +63,7 @@ def if_action(hass, config): below = config.get(CONF_BELOW) above = config.get(CONF_ABOVE) + attribute = config.get(CONF_ABOVE) if below is None and above is None: _LOGGER.error("Missing configuration key." @@ -71,14 +74,15 @@ def if_action(hass, config): def if_numeric_state(): """ Test numeric state condition. """ state = hass.states.get(entity_id) - return state is not None and _in_range(state.state, above, below) + return state is not None and _in_range(state, above, below, attribute) return if_numeric_state -def _in_range(value, range_start, range_end): +def _in_range(state, range_start, range_end, attribute): """ Checks if value is inside the range """ - + value = (state.state if attribute is None + else state.attributes.get(attribute)) try: value = float(value) except ValueError: From 73e3ce504479172eaee245793a9ca0a7c878e6b1 Mon Sep 17 00:00:00 2001 From: pavoni Date: Sun, 29 Nov 2015 12:18:54 +0000 Subject: [PATCH 113/166] Fix bug --- homeassistant/components/automation/numeric_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/automation/numeric_state.py b/homeassistant/components/automation/numeric_state.py index fe0a4f98bd9..9c9215cacb5 100644 --- a/homeassistant/components/automation/numeric_state.py +++ b/homeassistant/components/automation/numeric_state.py @@ -63,7 +63,7 @@ def if_action(hass, config): below = config.get(CONF_BELOW) above = config.get(CONF_ABOVE) - attribute = config.get(CONF_ABOVE) + attribute = config.get(CONF_ATTRIBUTE) if below is None and above is None: _LOGGER.error("Missing configuration key." From 7d503e3f8b668748c6db64377b9e0395a600d32e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 29 Nov 2015 15:52:44 +0100 Subject: [PATCH 114/166] Update docstrings --- homeassistant/components/motor/__init__.py | 11 ++++++++--- homeassistant/components/motor/mqtt.py | 13 ++++++++----- homeassistant/components/mqtt/__init__.py | 2 +- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/motor/__init__.py b/homeassistant/components/motor/__init__.py index 806dd9e0eb1..dda7c52c05d 100644 --- a/homeassistant/components/motor/__init__.py +++ b/homeassistant/components/motor/__init__.py @@ -1,8 +1,10 @@ """ homeassistant.components.motor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Motor component. +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/motor/ """ import os import logging @@ -100,12 +102,15 @@ class MotorDevice(Entity): @property def current_position(self): - """ Return current position of motor. - None is unknown, 0 is closed, 100 is fully open. """ + """ + Return current position of motor. + None is unknown, 0 is closed, 100 is fully open. + """ raise NotImplementedError() @property def state(self): + """ Returns the state of the motor. """ current = self.current_position if current is None: diff --git a/homeassistant/components/motor/mqtt.py b/homeassistant/components/motor/mqtt.py index 1075030fc37..7c25e382f84 100644 --- a/homeassistant/components/motor/mqtt.py +++ b/homeassistant/components/motor/mqtt.py @@ -1,7 +1,8 @@ """ homeassistant.components.motor.mqtt -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Allows to configure a MQTT motor. + For more details about this platform, please refer to the documentation at https://home-assistant.io/components/motor.mqtt/ """ @@ -40,7 +41,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): # pylint: disable=too-many-arguments, too-many-instance-attributes class MqttMotor(MotorDevice): - """ Represents a motor that can be controlled using MQTT """ + """ Represents a motor that can be controlled using MQTT. """ def __init__(self, hass, name, state_topic, command_topic, qos, payload_open, payload_close, payload_stop, state_format): self._state = None @@ -76,13 +77,15 @@ class MqttMotor(MotorDevice): @property def name(self): - """ The name of the motor """ + """ The name of the motor. """ return self._name @property def current_position(self): - """ Return current position of motor. - None is unknown, 0 is closed, 100 is fully open. """ + """ + Return current position of motor. + None is unknown, 0 is closed, 100 is fully open. + """ return self._state def open(self, **kwargs): diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 0e8506523d2..2c5dbf82923 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -138,7 +138,7 @@ def setup(hass, config): # pylint: disable=too-few-public-methods class _JsonFmtParser(object): - """ Implements a json parser on xpath. """ + """ Implements a JSON parser on xpath. """ def __init__(self, jsonpath): import jsonpath_rw self._expr = jsonpath_rw.parse(jsonpath) From 8841eef2b7f039d36dd8b795273d861ad28c67a2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 11:44:27 -0800 Subject: [PATCH 115/166] Add tests for lock component --- homeassistant/components/lock/__init__.py | 4 -- homeassistant/components/lock/demo.py | 22 +++------- tests/components/lock/__init__.py | 0 tests/components/lock/test_demo.py | 51 +++++++++++++++++++++++ 4 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 tests/components/lock/__init__.py create mode 100644 tests/components/lock/test_demo.py diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index fdc2da3e8d4..0d67679e82c 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -36,10 +36,6 @@ DISCOVERY_PLATFORMS = { wink.DISCOVER_LOCKS: 'wink' } -PROP_TO_ATTR = { - 'locked': ATTR_LOCKED -} - _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/lock/demo.py b/homeassistant/components/lock/demo.py index ac7bbed3dc2..472b17f46bf 100644 --- a/homeassistant/components/lock/demo.py +++ b/homeassistant/components/lock/demo.py @@ -5,25 +5,23 @@ homeassistant.components.lock.demo Demo platform that has two fake locks. """ from homeassistant.components.lock import LockDevice -from homeassistant.const import ( - DEVICE_DEFAULT_NAME, STATE_LOCKED, STATE_UNLOCKED) +from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED # pylint: disable=unused-argument def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Find and return demo locks. """ add_devices_callback([ - DemoLock('Left Door', STATE_LOCKED, None), - DemoLock('Right Door', STATE_UNLOCKED, None) + DemoLock('Front Door', STATE_LOCKED), + DemoLock('Kitchen Door', STATE_UNLOCKED) ]) class DemoLock(LockDevice): """ Provides a demo lock. """ - def __init__(self, name, state, icon): - self._name = name or DEVICE_DEFAULT_NAME + def __init__(self, name, state): + self._name = name self._state = state - self._icon = icon @property def should_poll(self): @@ -35,18 +33,10 @@ class DemoLock(LockDevice): """ Returns the name of the device if any. """ return self._name - @property - def icon(self): - """ Returns the icon to use for device if any. """ - return self._icon - @property def is_locked(self): """ True if device is locked. """ - if self._state == STATE_LOCKED: - return True - else: - return False + return self._state == STATE_LOCKED def lock(self, **kwargs): """ Lock the device. """ diff --git a/tests/components/lock/__init__.py b/tests/components/lock/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/components/lock/test_demo.py b/tests/components/lock/test_demo.py new file mode 100644 index 00000000000..7320b1aa69a --- /dev/null +++ b/tests/components/lock/test_demo.py @@ -0,0 +1,51 @@ +""" +tests.components.lock.test_demo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tests demo lock component. +""" +import unittest + +import homeassistant.core as ha +from homeassistant.components import lock + + +FRONT = 'lock.front_door' +KITCHEN = 'lock.kitchen_door' + + +class TestLockDemo(unittest.TestCase): + """ Test the demo lock. """ + + def setUp(self): # pylint: disable=invalid-name + self.hass = ha.HomeAssistant() + self.assertTrue(lock.setup(self.hass, { + 'lock': { + 'platform': 'demo' + } + })) + + def tearDown(self): # pylint: disable=invalid-name + """ Stop down stuff we started. """ + self.hass.stop() + + def test_is_locked(self): + self.assertTrue(lock.is_locked(self.hass, FRONT)) + self.hass.states.is_state(FRONT, 'locked') + + self.assertFalse(lock.is_locked(self.hass, KITCHEN)) + self.hass.states.is_state(KITCHEN, 'unlocked') + + def test_locking(self): + lock.lock(self.hass, KITCHEN) + + self.hass.pool.block_till_done() + + self.assertTrue(lock.is_locked(self.hass, KITCHEN)) + + def test_unlocking(self): + lock.unlock(self.hass, FRONT) + + self.hass.pool.block_till_done() + + self.assertFalse(lock.is_locked(self.hass, FRONT)) From 01203c7c4c17c788f8544bda6e9452631c88ecdd Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 12:13:06 -0800 Subject: [PATCH 116/166] Add updater tests --- tests/components/test_updater.py | 74 ++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/components/test_updater.py diff --git a/tests/components/test_updater.py b/tests/components/test_updater.py new file mode 100644 index 00000000000..3e5cf55e0b0 --- /dev/null +++ b/tests/components/test_updater.py @@ -0,0 +1,74 @@ +""" +tests.test_updater +~~~~~~~~~~~~~~~~~~ + +Tests updater component. +""" +import unittest +from unittest.mock import patch + +import requests + +import homeassistant.core as ha +from homeassistant.const import __version__ as CURRENT_VERSION +from homeassistant.components import updater +import homeassistant.util.dt as dt_util +from tests.common import fire_time_changed + +NEW_VERSION = '10000.0' + + +class TestUpdater(unittest.TestCase): + """ Test the demo lock. """ + + 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() + + @patch('homeassistant.components.updater.get_newest_version') + def test_new_version_shows_entity_on_start(self, mock_get_newest_version): + mock_get_newest_version.return_value = NEW_VERSION + + self.assertTrue(updater.setup(self.hass, { + 'updater': None + })) + + self.assertTrue(self.hass.states.is_state(updater.ENTITY_ID, + NEW_VERSION)) + + @patch('homeassistant.components.updater.get_newest_version') + def test_no_entity_on_same_version(self, mock_get_newest_version): + mock_get_newest_version.return_value = CURRENT_VERSION + + self.assertTrue(updater.setup(self.hass, { + 'updater': None + })) + + self.assertIsNone(self.hass.states.get(updater.ENTITY_ID)) + + mock_get_newest_version.return_value = NEW_VERSION + + fire_time_changed(self.hass, + dt_util.utcnow().replace(hour=0, minute=0, second=0)) + + self.hass.pool.block_till_done() + + self.assertTrue(self.hass.states.is_state(updater.ENTITY_ID, + NEW_VERSION)) + + @patch('homeassistant.components.updater.requests.get') + def test_errors_while_fetching_new_version(self, mock_get): + mock_get.side_effect = requests.RequestException + + self.assertIsNone(updater.get_newest_version()) + + mock_get.side_effect = ValueError + + self.assertIsNone(updater.get_newest_version()) + + mock_get.side_effect = KeyError + + self.assertIsNone(updater.get_newest_version()) From aff1c273725be75426bfa790a3b33f4198ed8773 Mon Sep 17 00:00:00 2001 From: pavoni Date: Sun, 29 Nov 2015 20:45:03 +0000 Subject: [PATCH 117/166] Remove unused and potentially confusing property --- homeassistant/components/sun.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py index 687c0856e5f..2e1c0c9b377 100644 --- a/homeassistant/components/sun.py +++ b/homeassistant/components/sun.py @@ -144,12 +144,6 @@ class Sun(Entity): self._state = self.next_rising = self.next_setting = None track_utc_time_change(hass, self.timer_update, second=30) - @property - def should_poll(self): - """ We trigger updates ourselves after sunset/sunrise, - but sun angle requires poll """ - return True - @property def name(self): return "Sun" From 18ca7b4f9e3d3186384a5b95a1ba0be7ea1d87a9 Mon Sep 17 00:00:00 2001 From: happyleaves Date: Sun, 29 Nov 2015 15:52:16 -0500 Subject: [PATCH 118/166] bump requirement version; support multiple switches per platform --- homeassistant/components/switch/orvibo.py | 28 +++++++++++++++-------- requirements_all.txt | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/switch/orvibo.py b/homeassistant/components/switch/orvibo.py index b9469d15df0..c636a7f3f55 100644 --- a/homeassistant/components/switch/orvibo.py +++ b/homeassistant/components/switch/orvibo.py @@ -11,7 +11,7 @@ import logging from homeassistant.components.switch import SwitchDevice DEFAULT_NAME = "Orvibo S20 Switch" -REQUIREMENTS = ['orvibo==1.0.0'] +REQUIREMENTS = ['orvibo==1.0.1'] _LOGGER = logging.getLogger(__name__) @@ -20,15 +20,23 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Find and return S20 switches. """ from orvibo.s20 import S20, S20Exception - if config.get('host') is None: - _LOGGER.error("Missing required variable: host") - return - try: - s20 = S20(config.get('host')) - add_devices_callback([S20Switch(config.get('name', DEFAULT_NAME), - s20)]) - except S20Exception: - _LOGGER.exception("S20 couldn't be initialized") + switches = [] + switch_conf = config.get('switches', [config]) + + for switch in switch_conf: + if switch.get('host') is None: + _LOGGER.error("Missing required variable: host") + continue + host = switch.get('host') + try: + switches.append(S20Switch(switch.get('name', DEFAULT_NAME), + S20(host))) + _LOGGER.info("Initialized S20 at %s", host) + except S20Exception: + _LOGGER.exception("S20 at %s couldn't be initialized", + host) + + add_devices_callback(switches) class S20Switch(SwitchDevice): diff --git a/requirements_all.txt b/requirements_all.txt index a9f24cdb65f..7dd5dc8996a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -146,7 +146,7 @@ https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f hikvision==0.4 # homeassistant.components.switch.orvibo -orvibo==1.0.0 +orvibo==1.0.1 # homeassistant.components.switch.wemo pywemo==0.3.2 From cb0eb2df7dc788ee7a9cf37b9e2ec080f936186b Mon Sep 17 00:00:00 2001 From: pavoni Date: Sun, 29 Nov 2015 21:37:08 +0000 Subject: [PATCH 119/166] Add tests --- .../automation/test_numeric_state.py | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/tests/components/automation/test_numeric_state.py b/tests/components/automation/test_numeric_state.py index a04b8d01f4e..8280f396f93 100644 --- a/tests/components/automation/test_numeric_state.py +++ b/tests/components/automation/test_numeric_state.py @@ -253,6 +253,156 @@ class TestAutomationNumericState(unittest.TestCase): self.hass.pool.block_till_done() self.assertEqual(0, len(self.calls)) + def test_if_fires_on_entity_change_below_with_attribute(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 9 is below 10 + self.hass.states.set('test.entity', 9, { 'test_attribute': 11 }) + self.hass.pool.block_till_done() + self.assertEqual(1, len(self.calls)) + + def test_if_not_fires_on_entity_change_not_below_with_attribute(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 11 is not below 10 + self.hass.states.set('test.entity', 11, { 'test_attribute': 9 }) + self.hass.pool.block_till_done() + self.assertEqual(0, len(self.calls)) + + def test_if_fires_on_attribute_change_with_attribute_below(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'attribute': 'test_attribute', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 9 is below 10 + self.hass.states.set('test.entity', 'entity', { 'test_attribute': 9 }) + self.hass.pool.block_till_done() + self.assertEqual(1, len(self.calls)) + + def test_if_not_fires_on_attribute_change_with_attribute_not_below(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'attribute': 'test_attribute', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 11 is not below 10 + self.hass.states.set('test.entity', 'entity', { 'test_attribute': 11 }) + self.hass.pool.block_till_done() + self.assertEqual(0, len(self.calls)) + + def test_if_not_fires_on_entity_change_with_attribute_below(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'attribute': 'test_attribute', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 11 is not below 10, entity state value should not be tested + self.hass.states.set('test.entity', '9', { 'test_attribute': 11 }) + self.hass.pool.block_till_done() + self.assertEqual(0, len(self.calls)) + + def test_if_not_fires_on_entity_change_with_not_attribute_below(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'attribute': 'test_attribute', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 11 is not below 10, entity state value should not be tested + self.hass.states.set('test.entity', 'entity') + self.hass.pool.block_till_done() + self.assertEqual(0, len(self.calls)) + + def test_if_fires_on_attribute_change_with_attribute_below_multiple_attributes(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'attribute': 'test_attribute', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 9 is not below 10 + self.hass.states.set('test.entity', 'entity', { 'test_attribute': 9, 'not_test_attribute': 11 }) + self.hass.pool.block_till_done() + self.assertEqual(1, len(self.calls)) + + def test_if_not_fires_on_attribute_change_with_attribute_not_below_multiple_attributes(self): + self.assertTrue(automation.setup(self.hass, { + automation.DOMAIN: { + 'trigger': { + 'platform': 'numeric_state', + 'entity_id': 'test.entity', + 'attribute': 'test_attribute', + 'below': 10, + }, + 'action': { + 'service': 'test.automation' + } + } + })) + # 11 is not below 10 + self.hass.states.set('test.entity', 'entity', { 'test_attribute': 11, 'not_test_attribute': 9 }) + self.hass.pool.block_till_done() + self.assertEqual(0, len(self.calls)) + def test_if_action(self): entity_id = 'domain.test_entity' test_state = 10 From a301d869d7824c796ce6606af462bcf696927498 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 13:49:05 -0800 Subject: [PATCH 120/166] PyLint 1.5 fixes --- .../components/automation/numeric_state.py | 2 +- homeassistant/components/automation/zone.py | 1 + homeassistant/components/binary_sensor/arest.py | 5 +++-- homeassistant/components/camera/__init__.py | 9 +++++---- homeassistant/components/camera/generic.py | 9 +++++---- homeassistant/components/camera/mjpeg.py | 13 +++++++------ homeassistant/components/ecobee.py | 7 ++++--- homeassistant/components/light/zwave.py | 5 +++-- homeassistant/components/media_player/firetv.py | 2 +- homeassistant/components/notify/xmpp.py | 4 ++-- homeassistant/components/recorder.py | 2 +- homeassistant/components/script.py | 10 +++++----- homeassistant/components/sensor/arest.py | 9 +++++---- homeassistant/components/sensor/ecobee.py | 3 ++- homeassistant/components/sensor/forecast.py | 16 ++++------------ homeassistant/components/sensor/glances.py | 5 +++-- homeassistant/components/sensor/rest.py | 7 ++++--- homeassistant/components/sensor/rpi_gpio.py | 11 +++-------- homeassistant/components/sensor/sabnzbd.py | 5 ++--- homeassistant/components/sensor/transmission.py | 9 ++++----- homeassistant/components/sensor/vera.py | 2 +- homeassistant/components/sensor/zwave.py | 4 +++- homeassistant/components/switch/hikvisioncam.py | 7 ++++--- homeassistant/components/switch/mystrom.py | 9 +++------ homeassistant/components/switch/transmission.py | 8 ++++---- homeassistant/components/switch/zwave.py | 2 +- homeassistant/components/thermostat/ecobee.py | 5 +++-- homeassistant/components/updater.py | 6 +++--- homeassistant/config.py | 2 +- homeassistant/helpers/event.py | 1 + homeassistant/util/package.py | 6 ++++-- pylintrc | 4 +++- 32 files changed, 96 insertions(+), 94 deletions(-) diff --git a/homeassistant/components/automation/numeric_state.py b/homeassistant/components/automation/numeric_state.py index ab3529235d6..115f351a4f9 100644 --- a/homeassistant/components/automation/numeric_state.py +++ b/homeassistant/components/automation/numeric_state.py @@ -82,7 +82,7 @@ def _in_range(value, range_start, range_end): try: value = float(value) except ValueError: - _LOGGER.warn("Missing value in numeric check") + _LOGGER.warning("Missing value in numeric check") return False if range_start is not None and range_end is not None: diff --git a/homeassistant/components/automation/zone.py b/homeassistant/components/automation/zone.py index 4bf7eccf41e..f0f800bd313 100644 --- a/homeassistant/components/automation/zone.py +++ b/homeassistant/components/automation/zone.py @@ -46,6 +46,7 @@ def trigger(hass, config, action): from_match = _in_zone(hass, zone_entity_id, from_s) if from_s else None to_match = _in_zone(hass, zone_entity_id, to_s) + # pylint: disable=too-many-boolean-expressions if event == EVENT_ENTER and not from_match and to_match or \ event == EVENT_LEAVE and from_match and not to_match: action() diff --git a/homeassistant/components/binary_sensor/arest.py b/homeassistant/components/binary_sensor/arest.py index 3077fe40bdb..7eafca9f2ae 100644 --- a/homeassistant/components/binary_sensor/arest.py +++ b/homeassistant/components/binary_sensor/arest.py @@ -6,9 +6,10 @@ The arest sensor will consume an exposed aREST API of a device. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/binary_sensor.arest/ """ -import logging -import requests from datetime import timedelta +import logging + +import requests from homeassistant.util import Throttle from homeassistant.components.binary_sensor import BinarySensorDevice diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 169c97595af..fc5c739c888 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -7,19 +7,20 @@ Component to interface with various cameras. For more details about this component, please refer to the documentation at https://home-assistant.io/components/camera/ """ -import requests import logging -import time import re +import time + +import requests + from homeassistant.helpers.entity import Entity +from homeassistant.helpers.entity_component import EntityComponent from homeassistant.const import ( ATTR_ENTITY_PICTURE, HTTP_NOT_FOUND, ATTR_ENTITY_ID, ) -from homeassistant.helpers.entity_component import EntityComponent - DOMAIN = 'camera' DEPENDENCIES = ['http'] diff --git a/homeassistant/components/camera/generic.py b/homeassistant/components/camera/generic.py index 7e9542908d5..c81febccc86 100644 --- a/homeassistant/components/camera/generic.py +++ b/homeassistant/components/camera/generic.py @@ -7,11 +7,12 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/camera.generic/ """ import logging -from requests.auth import HTTPBasicAuth -from homeassistant.helpers import validate_config -from homeassistant.components.camera import DOMAIN -from homeassistant.components.camera import Camera + import requests +from requests.auth import HTTPBasicAuth + +from homeassistant.helpers import validate_config +from homeassistant.components.camera import DOMAIN, Camera _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/camera/mjpeg.py b/homeassistant/components/camera/mjpeg.py index 1e643304add..0d59c8d60c7 100644 --- a/homeassistant/components/camera/mjpeg.py +++ b/homeassistant/components/camera/mjpeg.py @@ -6,13 +6,14 @@ Support for IP Cameras. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/camera.mjpeg/ """ -import logging -from requests.auth import HTTPBasicAuth -from homeassistant.helpers import validate_config -from homeassistant.components.camera import DOMAIN -from homeassistant.components.camera import Camera -import requests from contextlib import closing +import logging + +import requests +from requests.auth import HTTPBasicAuth + +from homeassistant.helpers import validate_config +from homeassistant.components.camera import DOMAIN, Camera _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/ecobee.py b/homeassistant/components/ecobee.py index a41bf7f25cc..03a678f5c49 100644 --- a/homeassistant/components/ecobee.py +++ b/homeassistant/components/ecobee.py @@ -26,14 +26,15 @@ ecobee: """ +from datetime import timedelta +import logging +import os + from homeassistant.loader import get_component from homeassistant import bootstrap from homeassistant.util import Throttle from homeassistant.const import ( EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, CONF_API_KEY) -from datetime import timedelta -import logging -import os DOMAIN = "ecobee" DISCOVER_THERMOSTAT = "ecobee.thermostat" diff --git a/homeassistant/components/light/zwave.py b/homeassistant/components/light/zwave.py index 31cd64d2530..02664ed896c 100644 --- a/homeassistant/components/light/zwave.py +++ b/homeassistant/components/light/zwave.py @@ -6,12 +6,13 @@ Support for Z-Wave lights. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.zwave/ """ +# Because we do not compile openzwave on CI # pylint: disable=import-error -import homeassistant.components.zwave as zwave +from threading import Timer from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.components.light import (Light, ATTR_BRIGHTNESS) -from threading import Timer +import homeassistant.components.zwave as zwave def setup_platform(hass, config, add_devices, discovery_info=None): diff --git a/homeassistant/components/media_player/firetv.py b/homeassistant/components/media_player/firetv.py index 1b2c921e3d4..e5f9885f86e 100644 --- a/homeassistant/components/media_player/firetv.py +++ b/homeassistant/components/media_player/firetv.py @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.info( 'Device %s accessible and ready for control', device_id) else: - _LOGGER.warn( + _LOGGER.warning( '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) diff --git a/homeassistant/components/notify/xmpp.py b/homeassistant/components/notify/xmpp.py index 016e0a949fd..4b688fb7a79 100644 --- a/homeassistant/components/notify/xmpp.py +++ b/homeassistant/components/notify/xmpp.py @@ -8,14 +8,14 @@ https://home-assistant.io/components/notify.xmpp/ """ import logging -_LOGGER = logging.getLogger(__name__) - from homeassistant.helpers import validate_config from homeassistant.components.notify import ( DOMAIN, ATTR_TITLE, BaseNotificationService) REQUIREMENTS = ['sleekxmpp==1.3.1', 'dnspython3==1.12.0'] +_LOGGER = logging.getLogger(__name__) + def get_service(hass, config): """ Get the Jabber (XMPP) notification service. """ diff --git a/homeassistant/components/recorder.py b/homeassistant/components/recorder.py index acda166e12a..126d8c9f40e 100644 --- a/homeassistant/components/recorder.py +++ b/homeassistant/components/recorder.py @@ -73,7 +73,7 @@ def row_to_state(row): def row_to_event(row): """ Convert a databse row to an event. """ try: - return Event(row[1], json.loads(row[2]), EventOrigin[row[3].lower()], + return Event(row[1], json.loads(row[2]), EventOrigin(row[3]), date_util.utc_from_timestamp(row[5])) except ValueError: # When json.loads fails diff --git a/homeassistant/components/script.py b/homeassistant/components/script.py index f8240bbf7f5..bf7c51fe3fb 100644 --- a/homeassistant/components/script.py +++ b/homeassistant/components/script.py @@ -9,7 +9,6 @@ https://home-assistant.io/components/script/ """ import logging from datetime import timedelta -import homeassistant.util.dt as date_util from itertools import islice import threading @@ -17,6 +16,7 @@ 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 slugify, split_entity_id +import homeassistant.util.dt as date_util from homeassistant.const import ( ATTR_ENTITY_ID, EVENT_TIME_CHANGED, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF) @@ -73,12 +73,12 @@ def setup(hass, config): for object_id, cfg in config[DOMAIN].items(): if object_id != slugify(object_id): - _LOGGER.warn("Found invalid key for script: %s. Use %s instead.", - object_id, slugify(object_id)) + _LOGGER.warning("Found invalid key for script: %s. Use %s instead", + object_id, slugify(object_id)) continue if not isinstance(cfg.get(CONF_SEQUENCE), list): - _LOGGER.warn("Key 'sequence' for script %s should be a list", - object_id) + _LOGGER.warning("Key 'sequence' for script %s should be a list", + object_id) continue alias = cfg.get(CONF_ALIAS, object_id) script = Script(hass, object_id, alias, cfg[CONF_SEQUENCE]) diff --git a/homeassistant/components/sensor/arest.py b/homeassistant/components/sensor/arest.py index 332725102dd..f1faa7cc932 100644 --- a/homeassistant/components/sensor/arest.py +++ b/homeassistant/components/sensor/arest.py @@ -6,13 +6,14 @@ The arest sensor will consume an exposed aREST API of a device. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.arest/ """ -import logging -import requests from datetime import timedelta +import logging + +import requests -from homeassistant.util import Throttle -from homeassistant.helpers.entity import Entity from homeassistant.const import DEVICE_DEFAULT_NAME +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py index a6499949015..5950b5deccb 100644 --- a/homeassistant/components/sensor/ecobee.py +++ b/homeassistant/components/sensor/ecobee.py @@ -25,10 +25,11 @@ ecobee: hold_temp: True """ +import logging + from homeassistant.helpers.entity import Entity from homeassistant.components import ecobee from homeassistant.const import TEMP_FAHRENHEIT -import logging DEPENDENCIES = ['ecobee'] diff --git a/homeassistant/components/sensor/forecast.py b/homeassistant/components/sensor/forecast.py index aa3dd3d3d04..c024c19b5f7 100644 --- a/homeassistant/components/sensor/forecast.py +++ b/homeassistant/components/sensor/forecast.py @@ -9,17 +9,11 @@ https://home-assistant.io/components/sensor.forecast/ import logging from datetime import timedelta -REQUIREMENTS = ['python-forecastio==1.3.3'] - -try: - import forecastio -except ImportError: - forecastio = None - from homeassistant.util import Throttle from homeassistant.const import (CONF_API_KEY, TEMP_CELCIUS) from homeassistant.helpers.entity import Entity +REQUIREMENTS = ['python-forecastio==1.3.3'] _LOGGER = logging.getLogger(__name__) # Sensor types are defined like so: @@ -53,11 +47,7 @@ MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=120) def setup_platform(hass, config, add_devices, discovery_info=None): """ Get the Forecast.io sensor. """ - - global forecastio # pylint: disable=invalid-name - if forecastio is None: - import forecastio as forecastio_ - forecastio = forecastio_ + import forecastio if None in (hass.config.latitude, hass.config.longitude): _LOGGER.error("Latitude or longitude not set in Home Assistant config") @@ -141,6 +131,7 @@ class ForeCastSensor(Entity): # pylint: disable=too-many-branches def update(self): """ Gets the latest data from Forecast.io and updates the states. """ + import forecastio self.forecast_client.update() data = self.forecast_client.data @@ -209,6 +200,7 @@ class ForeCastData(object): @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """ Gets the latest data from Forecast.io. """ + import forecastio forecast = forecastio.load_forecast(self._api_key, self.latitude, diff --git a/homeassistant/components/sensor/glances.py b/homeassistant/components/sensor/glances.py index 092e4c75733..7938ae7e659 100644 --- a/homeassistant/components/sensor/glances.py +++ b/homeassistant/components/sensor/glances.py @@ -6,9 +6,10 @@ Gathers system information of hosts which running glances. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.glances/ """ -import logging -import requests from datetime import timedelta +import logging + +import requests from homeassistant.util import Throttle from homeassistant.helpers.entity import Entity diff --git a/homeassistant/components/sensor/rest.py b/homeassistant/components/sensor/rest.py index 7fe3a583b08..53609dbb237 100644 --- a/homeassistant/components/sensor/rest.py +++ b/homeassistant/components/sensor/rest.py @@ -6,10 +6,11 @@ The rest sensor will consume JSON responses sent by an exposed REST API. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.rest/ """ -import logging -import requests -from json import loads from datetime import timedelta +from json import loads +import logging + +import requests from homeassistant.util import Throttle from homeassistant.helpers.entity import Entity diff --git a/homeassistant/components/sensor/rpi_gpio.py b/homeassistant/components/sensor/rpi_gpio.py index 2e2746fe9d4..ef7ea8c33c1 100644 --- a/homeassistant/components/sensor/rpi_gpio.py +++ b/homeassistant/components/sensor/rpi_gpio.py @@ -6,13 +6,10 @@ Allows to configure a binary state sensor using RPi GPIO. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.rpi_gpio/ """ +# pylint: disable=import-error import logging from homeassistant.helpers.entity import Entity -try: - import RPi.GPIO as GPIO -except ImportError: - GPIO = None from homeassistant.const import (DEVICE_DEFAULT_NAME, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) @@ -29,10 +26,7 @@ _LOGGER = logging.getLogger(__name__) # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the Raspberry PI GPIO ports. """ - if GPIO is None: - _LOGGER.error('RPi.GPIO not available. rpi_gpio ports ignored.') - return - # pylint: disable=no-member + import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) sensors = [] @@ -65,6 +59,7 @@ class RPiGPIOSensor(Entity): def __init__(self, port_name, port_num, pull_mode, value_high, value_low, bouncetime): # pylint: disable=no-member + import RPi.GPIO as GPIO self._name = port_name or DEVICE_DEFAULT_NAME self._port = port_num self._pull = GPIO.PUD_DOWN if pull_mode == "DOWN" else GPIO.PUD_UP diff --git a/homeassistant/components/sensor/sabnzbd.py b/homeassistant/components/sensor/sabnzbd.py index e478daac2f9..98d76a302dd 100644 --- a/homeassistant/components/sensor/sabnzbd.py +++ b/homeassistant/components/sensor/sabnzbd.py @@ -6,12 +6,11 @@ Monitors SABnzbd NZB client API. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.sabnzbd/ """ -from homeassistant.util import Throttle from datetime import timedelta +import logging from homeassistant.helpers.entity import Entity - -import logging +from homeassistant.util import Throttle REQUIREMENTS = ['https://github.com/jamespcole/home-assistant-nzb-clients/' 'archive/616cad59154092599278661af17e2a9f2cf5e2a9.zip' diff --git a/homeassistant/components/sensor/transmission.py b/homeassistant/components/sensor/transmission.py index 484b045f295..62afdd39bf4 100644 --- a/homeassistant/components/sensor/transmission.py +++ b/homeassistant/components/sensor/transmission.py @@ -6,14 +6,13 @@ Monitors Transmission BitTorrent client API. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.transmission/ """ -from homeassistant.util import Throttle from datetime import timedelta -from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD - -from homeassistant.helpers.entity import Entity - import logging +from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD +from homeassistant.util import Throttle +from homeassistant.helpers.entity import Entity + REQUIREMENTS = ['transmissionrpc==0.11'] SENSOR_TYPES = { 'current_status': ['Status', ''], diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py index 1848c680517..7fb72fd91b7 100644 --- a/homeassistant/components/sensor/vera.py +++ b/homeassistant/components/sensor/vera.py @@ -95,7 +95,7 @@ class VeraSensor(Entity): @property def state_attributes(self): - attr = super().state_attributes + attr = {} if self.vera_device.has_battery: attr[ATTR_BATTERY_LEVEL] = self.vera_device.battery_level + '%' diff --git a/homeassistant/components/sensor/zwave.py b/homeassistant/components/sensor/zwave.py index 23d2f8948f8..1ed831b286d 100644 --- a/homeassistant/components/sensor/zwave.py +++ b/homeassistant/components/sensor/zwave.py @@ -6,9 +6,11 @@ Interfaces with Z-Wave sensors. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/zwave/ """ +# Because we do not compile openzwave on CI # pylint: disable=import-error -from homeassistant.helpers.event import track_point_in_time import datetime + +from homeassistant.helpers.event import track_point_in_time import homeassistant.util.dt as dt_util import homeassistant.components.zwave as zwave from homeassistant.helpers.entity import Entity diff --git a/homeassistant/components/switch/hikvisioncam.py b/homeassistant/components/switch/hikvisioncam.py index 2d91acdf361..c85aae4a7f0 100644 --- a/homeassistant/components/switch/hikvisioncam.py +++ b/homeassistant/components/switch/hikvisioncam.py @@ -6,11 +6,12 @@ Support turning on/off motion detection on Hikvision cameras. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.hikvision/ """ -from homeassistant.helpers.entity import ToggleEntity -from homeassistant.const import STATE_ON, STATE_OFF -from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD import logging +from homeassistant.helpers.entity import ToggleEntity +from homeassistant.const import (STATE_ON, STATE_OFF, + CONF_HOST, CONF_USERNAME, CONF_PASSWORD) + _LOGGING = logging.getLogger(__name__) REQUIREMENTS = ['hikvision==0.4'] # pylint: disable=too-many-arguments diff --git a/homeassistant/components/switch/mystrom.py b/homeassistant/components/switch/mystrom.py index 36a62fe33e4..919ff28e4ef 100644 --- a/homeassistant/components/switch/mystrom.py +++ b/homeassistant/components/switch/mystrom.py @@ -91,12 +91,9 @@ class MyStromSwitch(SwitchDevice): try: request = requests.get('{}/report'.format(self._resource), timeout=10) - if request.json()['relay'] is True: - self._state = True - else: - self._state = False - - self.consumption = request.json()['power'] + data = request.json() + self._state = bool(data['relay']) + self.consumption = data['power'] except requests.exceptions.ConnectionError: _LOGGER.error("No route to device '%s'. Is device offline?", self._resource) diff --git a/homeassistant/components/switch/transmission.py b/homeassistant/components/switch/transmission.py index f3f6a9a8765..1f0da4a00e0 100644 --- a/homeassistant/components/switch/transmission.py +++ b/homeassistant/components/switch/transmission.py @@ -6,12 +6,12 @@ Enable or disable Transmission BitTorrent client Turtle Mode. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.transmission/ """ -from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD -from homeassistant.const import STATE_ON, STATE_OFF - -from homeassistant.helpers.entity import ToggleEntity import logging +from homeassistant.const import (CONF_HOST, CONF_USERNAME, CONF_PASSWORD, + STATE_ON, STATE_OFF) +from homeassistant.helpers.entity import ToggleEntity + _LOGGING = logging.getLogger(__name__) REQUIREMENTS = ['transmissionrpc==0.11'] diff --git a/homeassistant/components/switch/zwave.py b/homeassistant/components/switch/zwave.py index 493e2234bcf..f4777340445 100644 --- a/homeassistant/components/switch/zwave.py +++ b/homeassistant/components/switch/zwave.py @@ -4,8 +4,8 @@ homeassistant.components.switch.zwave Zwave platform that handles simple binary switches. """ +# Because we do not compile openzwave on CI # pylint: disable=import-error - import homeassistant.components.zwave as zwave from homeassistant.components.switch import SwitchDevice diff --git a/homeassistant/components/thermostat/ecobee.py b/homeassistant/components/thermostat/ecobee.py index 78f4d555c9c..66117954a51 100644 --- a/homeassistant/components/thermostat/ecobee.py +++ b/homeassistant/components/thermostat/ecobee.py @@ -25,11 +25,12 @@ ecobee: hold_temp: True """ +import logging + +from homeassistant.components import ecobee from homeassistant.components.thermostat import (ThermostatDevice, STATE_COOL, STATE_IDLE, STATE_HEAT) from homeassistant.const import (TEMP_FAHRENHEIT, STATE_ON, STATE_OFF) -from homeassistant.components import ecobee -import logging DEPENDENCIES = ['ecobee'] diff --git a/homeassistant/components/updater.py b/homeassistant/components/updater.py index a020a6c0abb..d4eb97f5ec5 100644 --- a/homeassistant/components/updater.py +++ b/homeassistant/components/updater.py @@ -47,10 +47,10 @@ def get_newest_version(): return req.json()['info']['version'] except requests.RequestException: _LOGGER.exception('Could not contact PyPI to check for updates') - return + return None except ValueError: _LOGGER.exception('Received invalid response from PyPI') - return + return None except KeyError: _LOGGER.exception('Response from PyPI did not include version') - return + return None diff --git a/homeassistant/config.py b/homeassistant/config.py index 2c2152df7a0..3d17fce5e17 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -67,7 +67,7 @@ def create_default_config(config_dir, detect_location=True): Returns path to new config file if success, None if failed. """ config_path = os.path.join(config_dir, YAML_CONFIG_FILE) - info = {attr: default for attr, default, *_ in DEFAULT_CONFIG} + info = {attr: default for attr, default, _, _ in DEFAULT_CONFIG} location_info = detect_location and loc_util.detect_location_info() diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index 60377fd1f5d..3934a6c52ef 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -124,6 +124,7 @@ def track_utc_time_change(hass, action, year=None, month=None, day=None, mat = _matcher + # pylint: disable=too-many-boolean-expressions if mat(now.year, year) and \ mat(now.month, month) and \ mat(now.day, day) and \ diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index fdfbc133944..fd320090736 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -1,12 +1,13 @@ """Helpers to install PyPi packages.""" import logging import os -import pkg_resources import subprocess import sys import threading from urllib.parse import urlparse +import pkg_resources + _LOGGER = logging.getLogger(__name__) INSTALL_LOCK = threading.Lock() @@ -27,7 +28,7 @@ def install_package(package, upgrade=True, target=None): args += ['--target', os.path.abspath(target)] try: - return 0 == subprocess.call(args) + return subprocess.call(args) == 0 except subprocess.SubprocessError: _LOGGER.exception('Unable to install pacakge %s', package) return False @@ -50,4 +51,5 @@ def check_package_exists(package, lib_dir): return True # Check packages from global + virtual environment + # pylint: disable=not-an-iterable return any(dist in req for dist in pkg_resources.working_set) diff --git a/pylintrc b/pylintrc index e8455cf4245..768cd3d46ff 100644 --- a/pylintrc +++ b/pylintrc @@ -9,6 +9,7 @@ reports=no # abstract-class-not-used - is flaky, should not show up but does # unused-argument - generic callbacks and setup methods create a lot of warnings # global-statement - used for the on-demand requirement installation +# redefined-variable-type - this is Python, we're duck typing! disable= locally-disabled, duplicate-code, @@ -16,7 +17,8 @@ disable= abstract-class-little-used, abstract-class-not-used, unused-argument, - global-statement + global-statement, + redefined-variable-type [EXCEPTIONS] overgeneral-exceptions=Exception,HomeAssistantError From 5023772b3eba14112c8e6f30cff30eeddca44234 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 13:55:46 -0800 Subject: [PATCH 121/166] Fix gen_requirements_all.py and add updated requirements_all.txt --- requirements_all.txt | 1 - script/gen_requirements_all.py | 31 ++++++------------------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/requirements_all.txt b/requirements_all.txt index bf07dd4dfcf..01af666b720 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -170,4 +170,3 @@ https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60 # homeassistant.components.zwave pydispatcher==2.0.5 - diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index a5f3c347fa4..730886075ec 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -8,7 +8,6 @@ import importlib import os import pkgutil import re -import argparse COMMENT_REQUIREMENTS = [ 'RPi.GPIO', @@ -60,10 +59,6 @@ def gather_modules(): except ImportError: errors.append(package) continue - # For catching the error by RPi.GPIO - # RuntimeError: This module can only be run on a Raspberry Pi! - except RuntimeError: - continue if not getattr(module, 'REQUIREMENTS', None): continue @@ -74,7 +69,7 @@ def gather_modules(): if errors: print("Found errors") print('\n'.join(errors)) - return + return None output.append('# Home Assistant core') output.append('\n') @@ -99,32 +94,18 @@ def write_file(data): req_file.write(data) -def display(data): - """ Prints the output to command line. """ - print(data) - - -def argparsing(): - """ Parsing the command line arguments. """ - parser = argparse.ArgumentParser( - description='Generate a requirements_all.txt') - parser.add_argument('file', nargs='?', - help='create new requirements_all.txt file') - return parser.parse_args() - - def main(): """ Main """ if not os.path.isfile('requirements_all.txt'): print('Run this from HA root dir') return - args = argparsing() + data = gather_modules() - if args.file: - write_file(data) - else: - display(data) + if data is None: + return + + write_file(data) if __name__ == '__main__': main() From 7ba9fb90f1782c6c77561e2d73456146e1e2a291 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 14:04:44 -0800 Subject: [PATCH 122/166] More PyLint fixes --- homeassistant/components/camera/foscam.py | 7 ++++--- homeassistant/components/media_player/itunes.py | 4 ++-- homeassistant/components/media_player/kodi.py | 12 ++---------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/camera/foscam.py b/homeassistant/components/camera/foscam.py index d4d707c790f..b210e1a2f1b 100644 --- a/homeassistant/components/camera/foscam.py +++ b/homeassistant/components/camera/foscam.py @@ -7,11 +7,12 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/camera.foscam/ """ import logging -from homeassistant.helpers import validate_config -from homeassistant.components.camera import DOMAIN -from homeassistant.components.camera import Camera + import requests +from homeassistant.helpers import validate_config +from homeassistant.components.camera import DOMAIN, Camera + _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/media_player/itunes.py b/homeassistant/components/media_player/itunes.py index 275e7d96dee..5d08a7e95d4 100644 --- a/homeassistant/components/media_player/itunes.py +++ b/homeassistant/components/media_player/itunes.py @@ -8,6 +8,8 @@ https://home-assistant.io/components/media_player.itunes/ """ import logging +import requests + from homeassistant.components.media_player import ( MediaPlayerDevice, MEDIA_TYPE_MUSIC, MEDIA_TYPE_PLAYLIST, SUPPORT_PAUSE, SUPPORT_SEEK, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_MUTE, @@ -17,8 +19,6 @@ from homeassistant.components.media_player import ( from homeassistant.const import ( STATE_IDLE, STATE_PLAYING, STATE_PAUSED, STATE_OFF, STATE_ON) -import requests - _LOGGER = logging.getLogger(__name__) SUPPORT_ITUNES = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index eda143b6cce..6fe6be554c6 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -15,11 +15,6 @@ from homeassistant.components.media_player import ( from homeassistant.const import ( STATE_IDLE, STATE_PLAYING, STATE_PAUSED, STATE_OFF) -try: - import jsonrpc_requests -except ImportError: - jsonrpc_requests = None - _LOGGER = logging.getLogger(__name__) REQUIREMENTS = ['jsonrpc-requests==0.1'] @@ -31,11 +26,6 @@ SUPPORT_KODI = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the kodi platform. """ - global jsonrpc_requests # pylint: disable=invalid-name - if jsonrpc_requests is None: - import jsonrpc_requests as jsonrpc_requests_ - jsonrpc_requests = jsonrpc_requests_ - add_devices([ KodiDevice( config.get('name', 'Kodi'), @@ -60,6 +50,7 @@ class KodiDevice(MediaPlayerDevice): # pylint: disable=too-many-public-methods def __init__(self, name, url, auth=None): + import jsonrpc_requests self._name = name self._url = url self._server = jsonrpc_requests.Server(url, auth=auth) @@ -77,6 +68,7 @@ class KodiDevice(MediaPlayerDevice): def _get_players(self): """ Returns the active player objects or None """ + import jsonrpc_requests try: return self._server.Player.GetActivePlayers() except jsonrpc_requests.jsonrpc.TransportError: From 5fba67f6c37a7c36935e4f9cb227b21f1b7a1c7b Mon Sep 17 00:00:00 2001 From: happyleaves Date: Sat, 14 Nov 2015 12:56:18 -0500 Subject: [PATCH 123/166] limitlessled improvements --- .../components/light/limitlessled.py | 348 +++++++++++------- requirements_all.txt | 2 +- 2 files changed, 226 insertions(+), 124 deletions(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index ad5f8487a2a..8700dd85bf2 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -8,171 +8,273 @@ https://home-assistant.io/components/light.limitlessled/ """ import logging -from homeassistant.const import DEVICE_DEFAULT_NAME from homeassistant.components.light import (Light, ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_EFFECT, + ATTR_COLOR_TEMP, ATTR_TRANSITION, + ATTR_FLASH, FLASH_LONG, EFFECT_COLORLOOP, EFFECT_WHITE) +from limitlessled import Color +from limitlessled.bridge import Bridge +from limitlessled.group.rgbw import RgbwGroup +from limitlessled.group.white import WhiteGroup +from limitlessled.pipeline import Pipeline +from limitlessled.presets import COLORLOOP + + _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['ledcontroller==1.1.0'] - -COLOR_TABLE = { - 'white': [0xFF, 0xFF, 0xFF], - 'violet': [0xEE, 0x82, 0xEE], - 'royal_blue': [0x41, 0x69, 0xE1], - 'baby_blue': [0x87, 0xCE, 0xFA], - 'aqua': [0x00, 0xFF, 0xFF], - 'royal_mint': [0x7F, 0xFF, 0xD4], - 'seafoam_green': [0x2E, 0x8B, 0x57], - 'green': [0x00, 0x80, 0x00], - 'lime_green': [0x32, 0xCD, 0x32], - 'yellow': [0xFF, 0xFF, 0x00], - 'yellow_orange': [0xDA, 0xA5, 0x20], - 'orange': [0xFF, 0xA5, 0x00], - 'red': [0xFF, 0x00, 0x00], - 'pink': [0xFF, 0xC0, 0xCB], - 'fusia': [0xFF, 0x00, 0xFF], - 'lilac': [0xDA, 0x70, 0xD6], - 'lavendar': [0xE6, 0xE6, 0xFA], -} +REQUIREMENTS = ['limitlessled==1.0.0'] +RGB_BOUNDARY = 40 +DEFAULT_TRANSITION = 0 +DEFAULT_PORT = 8899 +DEFAULT_VERSION = 5 +DEFAULT_LED_TYPE = 'rgbw' +WHITE = [255, 255, 255] -def _distance_squared(rgb1, rgb2): - """ Return sum of squared distances of each color part. """ - return sum((val1-val2)**2 for val1, val2 in zip(rgb1, rgb2)) - - -def _rgb_to_led_color(rgb_color): - """ Convert an RGB color to the closest color string and color. """ - return sorted((_distance_squared(rgb_color, color), name) - for name, color in COLOR_TABLE.items())[0][1] +def legacy_setup(config, add_devices_callback): + """ Perform setup using legacy format. """ + bridges = config.get('bridges', [config]) + lights = [] + for bridge_conf in bridges: + bridge = Bridge(bridge_conf.get('host')) + for i in range(1, 5): + name_key = 'group_%d_name' % i + if name_key in bridge_conf: + group_type = bridge_conf.get('group_%d_type' % i, + DEFAULT_LED_TYPE) + group = bridge.add_group(i, + bridge_conf.get(name_key), + group_type) + lights.append(LimitlessLEDGroup.factory(group)) + add_devices_callback(lights) def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Gets the LimitlessLED lights. """ - import ledcontroller - # Handle old configuration format: - bridges = config.get('bridges', [config]) - - for bridge_id, bridge in enumerate(bridges): - bridge['id'] = bridge_id - - pool = ledcontroller.LedControllerPool([x['host'] for x in bridges]) + # Two legacy configuration formats are supported to + # maintain backwards compatibility. + legacy_setup(config, add_devices_callback) + # Use the expanded configuration format. + if 'bridges' not in config: + return lights = [] - for bridge in bridges: - for i in range(1, 5): - name_key = 'group_%d_name' % i - if name_key in bridge: - group_type = bridge.get('group_%d_type' % i, 'rgbw') - lights.append(LimitlessLED.factory(pool, bridge['id'], i, - bridge[name_key], - group_type)) - + for bridge_conf in config.get('bridges'): + if 'groups' not in bridge_conf: + continue + bridge = Bridge(bridge_conf.get('host'), + port=bridge_conf.get('port', DEFAULT_PORT), + version=bridge_conf.get('version', DEFAULT_VERSION)) + for group_conf in bridge_conf.get('groups'): + group = bridge.add_group(group_conf.get('number'), + group_conf.get('name'), + group_conf.get('type', DEFAULT_LED_TYPE)) + lights.append(LimitlessLEDGroup.factory(group)) add_devices_callback(lights) -class LimitlessLED(Light): - """ Represents a LimitlessLED light """ +def state(new_state): + """ State decorator. + + Specify True (turn on) or False (turn off). + """ + def decorator(function): + """ Decorator function. """ + # pylint: disable=no-member + def wrapper(self, **kwargs): + """ Wrap a group state change. """ + pipeline = Pipeline() + transition_time = DEFAULT_TRANSITION + # Stop any repeating pipeline. + if self.repeating: + self.repeating = False + self.group.stop() + # Not on? Turn on. + if not self.is_on: + pipeline.on() + # Set transition time. + if ATTR_TRANSITION in kwargs: + transition_time = kwargs[ATTR_TRANSITION] + # Do group type-specific work. + function(self, transition_time, pipeline, **kwargs) + # Update state. + self.on_state = new_state + self.group.enqueue(pipeline) + self.update_ha_state() + return wrapper + return decorator + + +class LimitlessLEDGroup(Light): + """ LimitessLED group. """ + def __init__(self, group): + """ Initialize a group. """ + self.group = group + self.repeating = False + self.on_state = False + self._brightness = None @staticmethod - def factory(pool, controller_id, group, name, group_type): - ''' Construct a Limitless LED of the appropriate type ''' - if group_type == 'white': - return WhiteLimitlessLED(pool, controller_id, group, name) - elif group_type == 'rgbw': - return RGBWLimitlessLED(pool, controller_id, group, name) - - # pylint: disable=too-many-arguments - def __init__(self, pool, controller_id, group, name, group_type): - self.pool = pool - self.controller_id = controller_id - self.group = group - - self.pool.execute(self.controller_id, "set_group_type", self.group, - group_type) - - # LimitlessLEDs don't report state, we have track it ourselves. - self.pool.execute(self.controller_id, "off", self.group) - - self._name = name or DEVICE_DEFAULT_NAME - self._state = False + def factory(group): + """ Produce LimitlessLEDGroup objects. """ + if isinstance(group, WhiteGroup): + return LimitlessLEDWhiteGroup(group) + elif isinstance(group, RgbwGroup): + return LimitlessLEDRGBWGroup(group) @property def should_poll(self): - """ No polling needed. """ + """ No polling needed. + + LimitlessLED state cannot be fetched. + """ return False @property def name(self): - """ Returns the name of the device if any. """ - return self._name + """ Returns the name of the group. """ + return self.group.name @property def is_on(self): """ True if device is on. """ - return self._state - - def turn_off(self, **kwargs): - """ Turn the device off. """ - self._state = False - self.pool.execute(self.controller_id, "off", self.group) - self.update_ha_state() - - -class RGBWLimitlessLED(LimitlessLED): - """ Represents a RGBW LimitlessLED light """ - - def __init__(self, pool, controller_id, group, name): - super().__init__(pool, controller_id, group, name, 'rgbw') - - self._brightness = 100 - self._led_color = 'white' + return self.on_state @property def brightness(self): + """ Brightness property. """ return self._brightness + @state(False) + def turn_off(self, transition_time, pipeline, **kwargs): + """ Turn off a group. """ + pipeline.transition(transition_time, brightness=0.0).off() + + +class LimitlessLEDWhiteGroup(LimitlessLEDGroup): + """ LimitlessLED White group. """ + def __init__(self, group): + """ Initialize White group. """ + super().__init__(group) + # Initialize group with known values. + self.group.on = True + self.group.temperature = 1.0 + self.group.brightness = 0.0 + self._brightness = _to_hass_brightness(1.0) + self._temperature = _to_hass_temperature(self.group.temperature) + self.group.on = False + + @property + def color_temp(self): + """ Temperature property. """ + return self._temperature + + @state(True) + def turn_on(self, transition_time, pipeline, **kwargs): + """ Turn on (or adjust property of) a group. """ + # Check arguments. + if ATTR_BRIGHTNESS in kwargs: + self._brightness = kwargs[ATTR_BRIGHTNESS] + if ATTR_COLOR_TEMP in kwargs: + self._temperature = kwargs[ATTR_COLOR_TEMP] + # Set up transition. + pipeline.transition(transition_time, + brightness=_from_hass_brightness( + self._brightness), + temperature=_from_hass_temperature( + self._temperature)) + + +class LimitlessLEDRGBWGroup(LimitlessLEDGroup): + """ LimitlessLED RGBW group. """ + def __init__(self, group): + """ Initialize RGBW group. """ + super().__init__(group) + # Initialize group with known values. + self.group.on = True + self.group.white() + self._color = WHITE + self.group.brightness = 0.0 + self._brightness = _to_hass_brightness(1.0) + self.group.on = False + @property def rgb_color(self): - return COLOR_TABLE[self._led_color] - - def turn_on(self, **kwargs): - """ Turn the device on. """ - self._state = True + """ Color property. """ + return self._color + @state(True) + def turn_on(self, transition_time, pipeline, **kwargs): + """ Turn on (or adjust property of) a group. """ + # Check arguments. if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] - if ATTR_RGB_COLOR in kwargs: - self._led_color = _rgb_to_led_color(kwargs[ATTR_RGB_COLOR]) - - effect = kwargs.get(ATTR_EFFECT) - - if effect == EFFECT_COLORLOOP: - self.pool.execute(self.controller_id, "disco", self.group) - elif effect == EFFECT_WHITE: - self.pool.execute(self.controller_id, "white", self.group) - else: - self.pool.execute(self.controller_id, "set_color", - self._led_color, self.group) - - # Brightness can be set independently of color - self.pool.execute(self.controller_id, "set_brightness", - self._brightness / 255.0, self.group) - - self.update_ha_state() + self._color = kwargs[ATTR_RGB_COLOR] + # White is a special case. + if min(self._color) > 256 - RGB_BOUNDARY: + pipeline.white() + self._color = WHITE + # Set up transition. + pipeline.transition(transition_time, + brightness=_from_hass_brightness( + self._brightness), + color=_from_hass_color(self._color)) + # Flash. + if ATTR_FLASH in kwargs: + duration = 0 + if kwargs[ATTR_FLASH] == FLASH_LONG: + duration = 1 + pipeline.flash(duration=duration) + # Add effects. + if ATTR_EFFECT in kwargs: + if kwargs[ATTR_EFFECT] == EFFECT_COLORLOOP: + self.repeating = True + pipeline.append(COLORLOOP) + if kwargs[ATTR_EFFECT] == EFFECT_WHITE: + pipeline.white() + self._color = WHITE -class WhiteLimitlessLED(LimitlessLED): - """ Represents a White LimitlessLED light """ +def _from_hass_temperature(temperature): + """ Convert Home Assistant color temperature + units to percentage. + """ + return (temperature - 154) / 346 - def __init__(self, pool, controller_id, group, name): - super().__init__(pool, controller_id, group, name, 'white') - def turn_on(self, **kwargs): - """ Turn the device on. """ - self._state = True - self.pool.execute(self.controller_id, "on", self.group) - self.update_ha_state() +def _to_hass_temperature(temperature): + """ Convert percentage to Home Assistant + color temperature units. + """ + return int(temperature * 346) + 154 + + +def _from_hass_brightness(brightness): + """ Convert Home Assistant brightness units + to percentage. + """ + return brightness / 255 + + +def _to_hass_brightness(brightness): + """ Convert percentage to Home Assistant + brightness units. + """ + return int(brightness * 255) + + +def _from_hass_color(color): + """ Convert Home Assistant RGB list + to Color tuple. + """ + return Color(*tuple(color)) + + +def _to_hass_color(color): + """ Convert from Color tuple to + Home Assistant RGB list. + """ + return list([int(c) for c in color]) diff --git a/requirements_all.txt b/requirements_all.txt index 8ce63e99a01..1ff81bcc64a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -39,7 +39,7 @@ blinkstick==1.1.7 phue==0.8 # homeassistant.components.light.limitlessled -ledcontroller==1.1.0 +limitlessled==1.0.0 # homeassistant.components.light.tellstick # homeassistant.components.sensor.tellstick From 32003daf3f99f1ea636c9361b5d77e79564e09ca Mon Sep 17 00:00:00 2001 From: happyleaves Date: Sat, 28 Nov 2015 12:21:00 -0500 Subject: [PATCH 124/166] refactor legacy; move imports --- .../components/light/limitlessled.py | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index 8700dd85bf2..4952a3144ba 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -14,13 +14,6 @@ from homeassistant.components.light import (Light, ATTR_BRIGHTNESS, ATTR_FLASH, FLASH_LONG, EFFECT_COLORLOOP, EFFECT_WHITE) -from limitlessled import Color -from limitlessled.bridge import Bridge -from limitlessled.group.rgbw import RgbwGroup -from limitlessled.group.white import WhiteGroup -from limitlessled.pipeline import Pipeline -from limitlessled.presets import COLORLOOP - _LOGGER = logging.getLogger(__name__) REQUIREMENTS = ['limitlessled==1.0.0'] @@ -32,38 +25,43 @@ DEFAULT_LED_TYPE = 'rgbw' WHITE = [255, 255, 255] -def legacy_setup(config, add_devices_callback): - """ Perform setup using legacy format. """ +def rewrite_legacy(config): + """ Rewrite legacy configuration to new format. """ bridges = config.get('bridges', [config]) - lights = [] + new_bridges = [] for bridge_conf in bridges: - bridge = Bridge(bridge_conf.get('host')) - for i in range(1, 5): - name_key = 'group_%d_name' % i - if name_key in bridge_conf: - group_type = bridge_conf.get('group_%d_type' % i, - DEFAULT_LED_TYPE) - group = bridge.add_group(i, - bridge_conf.get(name_key), - group_type) - lights.append(LimitlessLEDGroup.factory(group)) - add_devices_callback(lights) + groups = [] + if 'groups' in bridge_conf: + groups = bridge_conf['groups'] + else: + _LOGGER.warn("Legacy configuration format detected") + for i in range(1, 5): + name_key = 'group_%d_name' % i + if name_key in bridge_conf: + groups.append({ + 'number': i, + 'type': bridge_conf.get('group_%d_type' % i, + DEFAULT_LED_TYPE), + 'name': bridge_conf.get(name_key) + }) + new_bridges.append({ + 'host': bridge_conf.get('host'), + 'groups': groups + }) + return {'bridges': new_bridges} def setup_platform(hass, config, add_devices_callback, discovery_info=None): """ Gets the LimitlessLED lights. """ + from limitlessled.bridge import Bridge # Two legacy configuration formats are supported to # maintain backwards compatibility. - legacy_setup(config, add_devices_callback) + config = rewrite_legacy(config) # Use the expanded configuration format. - if 'bridges' not in config: - return lights = [] for bridge_conf in config.get('bridges'): - if 'groups' not in bridge_conf: - continue bridge = Bridge(bridge_conf.get('host'), port=bridge_conf.get('port', DEFAULT_PORT), version=bridge_conf.get('version', DEFAULT_VERSION)) @@ -82,9 +80,10 @@ def state(new_state): """ def decorator(function): """ Decorator function. """ - # pylint: disable=no-member + # pylint: disable=no-member,protected-access def wrapper(self, **kwargs): """ Wrap a group state change. """ + from limitlessled.pipeline import Pipeline pipeline = Pipeline() transition_time = DEFAULT_TRANSITION # Stop any repeating pipeline. @@ -100,7 +99,7 @@ def state(new_state): # Do group type-specific work. function(self, transition_time, pipeline, **kwargs) # Update state. - self.on_state = new_state + self._is_on = new_state self.group.enqueue(pipeline) self.update_ha_state() return wrapper @@ -113,12 +112,14 @@ class LimitlessLEDGroup(Light): """ Initialize a group. """ self.group = group self.repeating = False - self.on_state = False + self._is_on = False self._brightness = None @staticmethod def factory(group): """ Produce LimitlessLEDGroup objects. """ + from limitlessled.group.rgbw import RgbwGroup + from limitlessled.group.white import WhiteGroup if isinstance(group, WhiteGroup): return LimitlessLEDWhiteGroup(group) elif isinstance(group, RgbwGroup): @@ -140,7 +141,7 @@ class LimitlessLEDGroup(Light): @property def is_on(self): """ True if device is on. """ - return self.on_state + return self._is_on @property def brightness(self): @@ -208,6 +209,7 @@ class LimitlessLEDRGBWGroup(LimitlessLEDGroup): @state(True) def turn_on(self, transition_time, pipeline, **kwargs): """ Turn on (or adjust property of) a group. """ + from limitlessled.presets import COLORLOOP # Check arguments. if ATTR_BRIGHTNESS in kwargs: self._brightness = kwargs[ATTR_BRIGHTNESS] @@ -270,6 +272,7 @@ def _from_hass_color(color): """ Convert Home Assistant RGB list to Color tuple. """ + from limitlessled import Color return Color(*tuple(color)) From 6e0c30d9f7fe89f8bcdd698df70a27b5be0b25e8 Mon Sep 17 00:00:00 2001 From: happyleaves Date: Sun, 29 Nov 2015 18:29:37 -0500 Subject: [PATCH 125/166] warn -> warning --- homeassistant/components/light/limitlessled.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index 4952a3144ba..4cc7b1ab3b7 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -34,7 +34,7 @@ def rewrite_legacy(config): if 'groups' in bridge_conf: groups = bridge_conf['groups'] else: - _LOGGER.warn("Legacy configuration format detected") + _LOGGER.warning("Legacy configuration format detected") for i in range(1, 5): name_key = 'group_%d_name' % i if name_key in bridge_conf: From 72ebb22eba1345013bcea1d77a6d6383eb119a88 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 17:59:59 -0800 Subject: [PATCH 126/166] Update demo entities --- .../components/alarm_control_panel/demo.py | 31 ++----------------- .../components/binary_sensor/demo.py | 12 ++----- homeassistant/components/demo.py | 2 +- 3 files changed, 7 insertions(+), 38 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/demo.py b/homeassistant/components/alarm_control_panel/demo.py index 2d2e36d03bc..0ace53167de 100644 --- a/homeassistant/components/alarm_control_panel/demo.py +++ b/homeassistant/components/alarm_control_panel/demo.py @@ -3,36 +3,11 @@ homeassistant.components.alarm_control_panel.demo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Demo platform that has two fake alarm control panels. """ -import homeassistant.components.alarm_control_panel.manual as Alarm -from homeassistant.const import (STATE_ALARM_DISARMED, - STATE_ALARM_ARMED_AWAY) +import homeassistant.components.alarm_control_panel.manual as manual def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the Demo alarm control panels. """ add_devices([ - - DemoAlarmControlPanel(hass, 'Front door', '1234', 2, 4, - STATE_ALARM_DISARMED), - DemoAlarmControlPanel(hass, 'Safe', '1234', 2, 4, - STATE_ALARM_ARMED_AWAY), - ]) - - -# pylint: disable=too-many-arguments -class DemoAlarmControlPanel(Alarm.ManualAlarm): - """ A Demo alarm control panel. """ - - def __init__(self, hass, name, code, pending_time, trigger_time, state): - super().__init__(hass, name, code, pending_time, trigger_time) - self._state = state - - @property - def should_poll(self): - """ No polling needed for a demo panel. """ - return False - - @property - def state(self): - """ Returns the state of the device. """ - return self._state + manual.ManualAlarm(hass, 'Alarm', '1234', 5, 10), + ]) diff --git a/homeassistant/components/binary_sensor/demo.py b/homeassistant/components/binary_sensor/demo.py index a24b893c610..087d7405d9b 100644 --- a/homeassistant/components/binary_sensor/demo.py +++ b/homeassistant/components/binary_sensor/demo.py @@ -9,18 +9,17 @@ from homeassistant.components.binary_sensor import BinarySensorDevice def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the Demo binary sensors. """ add_devices([ - DemoBinarySensor('Window Bathroom', True, None), - DemoBinarySensor('Floor Basement', False, None), + DemoBinarySensor('Basement Floor Wet', False), + DemoBinarySensor('Movement Backyard', True), ]) class DemoBinarySensor(BinarySensorDevice): """ A Demo binary sensor. """ - def __init__(self, name, state, icon=None): + def __init__(self, name, state): self._name = name self._state = state - self._icon = icon @property def should_poll(self): @@ -32,11 +31,6 @@ class DemoBinarySensor(BinarySensorDevice): """ Returns the name of the binary sensor. """ return self._name - @property - def icon(self): - """ Returns the icon to use for device if any. """ - return self._icon - @property def is_on(self): """ True if the binary sensor is on. """ diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 261c0e1b6a9..de87bfc9fb1 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone'] COMPONENTS_WITH_DEMO_PLATFORM = [ 'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor', - 'thermostat', 'camera', 'binary_sensor', 'alarm_control_panel'] + 'thermostat', 'camera', 'binary_sensor', 'alarm_control_panel', 'lock'] def setup(hass, config): From 5b4f607da19244f7eefc9350352475f9fb347a4e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 22:49:54 -0800 Subject: [PATCH 127/166] Upgrade frontend with lock support --- homeassistant/components/frontend/version.py | 2 +- .../components/frontend/www_static/frontend.html | 14 +++++++------- .../frontend/www_static/home-assistant-polymer | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 04ccb720f6b..a3c09fc4149 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 = "36df87bb6c219a2ee59adf416e3abdfa" +VERSION = "a07269fd3559611af16a4204b7645a64" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index e600c4c5583..36921057fca 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -6054,10 +6054,10 @@ case"touchend":return this.addPointerListenerEnd(t,e,i,n);case"touchmove":return text-rendering: optimizeLegibility; } \ No newline at end of file +}},{key:"batch",value:function(t){this.batchStart(),t(),this.batchEnd()}},{key:"registerStore",value:function(t,e){console.warn("Deprecation warning: `registerStore` will no longer be supported in 1.1, use `registerStores` instead"),this.registerStores(i({},t,e))}},{key:"registerStores",value:function(t){this.reactorState=d["default"].registerStores(this.reactorState,t),this.__notify()}},{key:"serialize",value:function(){return d["default"].serialize(this.reactorState)}},{key:"loadState",value:function(t){this.reactorState=d["default"].loadState(this.reactorState,t),this.__notify()}},{key:"reset",value:function(){var t=d["default"].reset(this.reactorState);this.reactorState=t,this.prevReactorState=t,this.observerState=new y.ObserverState}},{key:"__notify",value:function(){var t=this;if(!(this.__batchDepth>0)){var e=this.reactorState.get("dirtyStores");if(0!==e.size){var n=s["default"].Set().withMutations(function(n){n.union(t.observerState.get("any")),e.forEach(function(e){var r=t.observerState.getIn(["stores",e]);r&&n.union(r)})});n.forEach(function(e){var n=t.observerState.getIn(["observersMap",e]);if(n){var r=n.get("getter"),i=n.get("handler"),o=d["default"].evaluate(t.prevReactorState,r),u=d["default"].evaluate(t.reactorState,r);t.prevReactorState=o.reactorState,t.reactorState=u.reactorState;var a=o.result,c=u.result;s["default"].is(a,c)||i.call(null,c)}});var r=d["default"].resetDirtyStores(this.reactorState);this.prevReactorState=r,this.reactorState=r}}}},{key:"batchStart",value:function(){this.__batchDepth++}},{key:"batchEnd",value:function(){if(this.__batchDepth--,this.__batchDepth<=0){this.__isDispatching=!0;try{this.__notify()}catch(t){throw this.__isDispatching=!1,t}this.__isDispatching=!1}}}]),t}();e["default"]=(0,_.toFactory)(m),t.exports=e["default"]},function(t,e,n){function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n={};return(0,o.each)(e,function(e,r){n[r]=t.evaluate(e)}),n}Object.defineProperty(e,"__esModule",{value:!0});var o=n(4);e["default"]=function(t){return{getInitialState:function(){return i(t,this.getDataBindings())},componentDidMount:function(){var e=this;this.__unwatchFns=[],(0,o.each)(this.getDataBindings(),function(n,i){var o=t.observe(n,function(t){e.setState(r({},i,t))});e.__unwatchFns.push(o)})},componentWillUnmount:function(){for(;this.__unwatchFns.length;)this.__unwatchFns.shift()()}}},t.exports=e["default"]},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){return new b({result:t,reactorState:e})}function o(t){return t}function u(t,e){var n=o(e);return t.getIn(["cache",n])}function a(t,e){var n=u(t,e);if(!n)return!1;var r=n.get("storeStates");return 0===r.size?!1:r.every(function(e,n){return t.getIn(["storeStates",n])===e})}function s(t,e,n){var r=o(e),i=t.get("dispatchId"),u=(0,y.getStoreDeps)(e),a=(0,_.toImmutable)({}).withMutations(function(e){u.forEach(function(n){var r=t.getIn(["storeStates",n]);e.set(n,r)})});return t.setIn(["cache",r],p["default"].Map({value:n,storeStates:a,dispatchId:i}))}function c(t,e){var n=o(e);return t.getIn(["cache",n,"value"])}function l(t){return t.update("dispatchId",function(t){return t+1})}function f(t,e){return t.withMutations(function(t){e.forEach(function(e){var n=t.has(e)?t.get(e)+1:1;t.set(e,n)})})}var d=n(3),p=r(d),h=n(9),v=r(h),_=n(5),y=n(10),m=n(11),g=n(4),b=p["default"].Record({result:null,reactorState:null});e.registerStores=function(t,e){var n=t.get("debug");return t.withMutations(function(t){(0,g.each)(e,function(e,r){t.getIn(["stores",r])&&console.warn("Store already defined for id = "+r);var i=e.getInitialState();if(n&&!(0,_.isImmutableValue)(i))throw new Error("Store getInitialState() must return an immutable value, did you forget to call toImmutable");t.update("stores",function(t){return t.set(r,e)}).update("state",function(t){return t.set(r,i)}).update("dirtyStores",function(t){return t.add(r)}).update("storeStates",function(t){return f(t,[r])})}),l(t)})},e.dispatch=function(t,e,n){var r=t.get("state"),i=t.get("debug"),o=t.get("dirtyStores"),u=r.withMutations(function(r){i&&v["default"].dispatchStart(e,n),t.get("stores").forEach(function(t,u){var a=r.get(u),s=void 0;try{s=t.handle(a,e,n)}catch(c){throw v["default"].dispatchError(c.message),c}if(i&&void 0===s){var l="Store handler must return a value, did you forget a return statement";throw v["default"].dispatchError(l),new Error(l)}r.set(u,s),a!==s&&(o=o.add(u)),i&&v["default"].storeHandled(u,a,s)}),i&&v["default"].dispatchEnd(r)}),a=t.set("state",u).set("dirtyStores",o).update("storeStates",function(t){return f(t,o)});return l(a)},e.loadState=function(t,e){var n=[],r=(0,_.toImmutable)({}).withMutations(function(r){(0,g.each)(e,function(e,i){var o=t.getIn(["stores",i]);if(o){var u=o.deserialize(e);void 0!==u&&(r.set(i,u),n.push(i))}})}),i=p["default"].Set(n);return t.update("state",function(t){return t.merge(r)}).update("dirtyStores",function(t){return t.union(i)}).update("storeStates",function(t){return f(t,n)})},e.addObserver=function(t,e,n){var r=e;(0,m.isKeyPath)(e)&&(e=(0,y.fromKeyPath)(e));var i=t.get("nextId"),o=(0,y.getStoreDeps)(e),u=p["default"].Map({id:i,storeDeps:o,getterKey:r,getter:e,handler:n}),a=void 0;return a=0===o.size?t.update("any",function(t){return t.add(i)}):t.withMutations(function(t){o.forEach(function(e){var n=["stores",e];t.hasIn(n)||t.setIn(n,p["default"].Set([])),t.updateIn(["stores",e],function(t){return t.add(i)})})}),a=a.set("nextId",i+1).setIn(["observersMap",i],u),{observerState:a,entry:u}},e.removeObserver=function(t,n,r){var i=t.get("observersMap").filter(function(t){var e=t.get("getterKey"),i=!r||t.get("handler")===r;return i?(0,m.isKeyPath)(n)&&(0,m.isKeyPath)(e)?(0,m.isEqual)(n,e):n===e:!1});return t.withMutations(function(t){i.forEach(function(n){return e.removeObserverByEntry(t,n)})})},e.removeObserverByEntry=function(t,e){return t.withMutations(function(t){var n=e.get("id"),r=e.get("storeDeps");0===r.size?t.update("any",function(t){return t.remove(n)}):r.forEach(function(e){t.updateIn(["stores",e],function(t){return t?t.remove(n):t})}),t.removeIn(["observersMap",n])})},e.reset=function(t){var n=t.get("debug"),r=t.get("state");return t.withMutations(function(t){var i=t.get("stores"),o=i.keySeq().toJS();i.forEach(function(e,i){var o=r.get(i),u=e.handleReset(o);if(n&&void 0===u)throw new Error("Store handleReset() must return a value, did you forget a return statement");if(n&&!(0,_.isImmutableValue)(u))throw new Error("Store reset state must be an immutable value, did you forget to call toImmutable");t.setIn(["state",i],u)}),t.update("storeStates",function(t){return f(t,o)}),e.resetDirtyStores(t)})},e.evaluate=function O(t,e){var n=t.get("state");if((0,m.isKeyPath)(e))return i(n.getIn(e),t);if(!(0,y.isGetter)(e))throw new Error("evaluate must be passed a keyPath or Getter");if(a(t,e))return i(c(t,e),t);var r=(0,y.getDeps)(e).map(function(e){return O(t,e).result}),o=(0,y.getComputeFn)(e).apply(null,r);return i(o,s(t,e,o))},e.serialize=function(t){var e={};return t.get("stores").forEach(function(n,r){var i=t.getIn(["state",r]),o=n.serialize(i);void 0!==o&&(e[r]=o)}),e},e.resetDirtyStores=function(t){return t.set("dirtyStores",p["default"].Set())}},function(t,e){e.dispatchStart=function(t,e){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){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,d.isArray)(t)&&(0,d.isFunction)(t[t.length-1])}function o(t){return t[t.length-1]}function u(t){return t.slice(0,t.length-1)}function a(t,e){e||(e=f["default"].Set());var n=f["default"].Set().withMutations(function(e){if(!i(t))throw new Error("getFlattenedDeps must be passed a Getter");u(t).forEach(function(t){if((0,p.isKeyPath)(t))e.add((0,l.List)(t));else{if(!i(t))throw new Error("Invalid getter, each dependency must be a KeyPath or Getter");e.union(a(t))}})});return e.union(n)}function s(t){if(!(0,p.isKeyPath)(t))throw new Error("Cannot create Getter from KeyPath: "+t);return[t,h]}function c(t){if(t.hasOwnProperty("__storeDeps"))return t.__storeDeps;var e=a(t).map(function(t){return t.first()}).filter(function(t){return!!t});return Object.defineProperty(t,"__storeDeps",{enumerable:!1,configurable:!1,writable:!1,value:e}),e}Object.defineProperty(e,"__esModule",{value:!0});var l=n(3),f=r(l),d=n(4),p=n(11),h=function(t){return t};e["default"]={isGetter:i,getComputeFn:o,getFlattenedDeps:a,getStoreDeps:c,getDeps:u,fromKeyPath:s},t.exports=e["default"]},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,s.isArray)(t)&&!(0,s.isFunction)(t[t.length-1])}function o(t,e){var n=a["default"].List(t),r=a["default"].List(e);return a["default"].is(n,r)}Object.defineProperty(e,"__esModule",{value:!0}),e.isKeyPath=i,e.isEqual=o;var u=n(3),a=r(u),s=n(4)},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),o=r(i),u=o["default"].Record({dispatchId:0,state:o["default"].Map(),stores:o["default"].Map(),cache:o["default"].Map(),storeStates:o["default"].Map(),dirtyStores:o["default"].Set(),debug:!1}),a=o["default"].Record({any:o["default"].Set([]),stores:o["default"].Map({}),observersMap:o["default"].Map({}),nextId:1});e["default"]={ReactorState:u,ObserverState:a},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(124),u=r(o);e["default"]=(0,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(133),o=r(i);e.callApi=o["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){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(149),u=i(o),a=n(150),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||(0,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(175),l=r(c),f=n(174),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(82),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(5),o=r(i);e["default"]=(0,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"]=(0,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(176),u=i(o),a=n(58),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"]=(0,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(136),a=i(u),s=n(137),c=i(s),l=n(138),f=i(l),d=n(134),p=r(d),h=n(135),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;n4?"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(125),a=r(u);n(39),n(123),n(122),n(119),n(121),n(120),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=(0,a["default"])(t);if(e&&(0,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){return t&&t.__esModule?t:{"default":t}}function i(t,e){switch(t){case"alarm_control_panel":return e&&"disarmed"===e?"mdi:bell-outline":"mdi:bell";case"binary_sensor":return e&&"off"===e?"mdi:radiobox-blank":"mdi:checkbox-marked-circle";case"camera":return"mdi:video";case"configurator":return"mdi:settings";case"conversation":return"mdi:text-to-speech";case"device_tracker":return"mdi:account";case"group":return"mdi:google-circles-communities";case"homeassistant":return"mdi:home";case"light":return"mdi:lightbulb";case"lock":return e&&"unlocked"===e?"mdi:lock-open":"mdi:lock";case"media_player":var n="mdi:cast";return e&&"off"!==e&&"idle"!==e&&(n+="-connected"),n;case"notify":return"mdi:comment-alert";case"updater":return"mdi:cloud-upload";case"scene":return"mdi:google-pages";case"script":return"mdi:file-document";case"sensor":return"mdi:eye";case"simple_alarm":return"mdi:bell";case"sun":return"mdi:white-balance-sunny";case"switch":return"mdi:flash";case"thermostat":return"mdi:nest-thermostat";default:return console.warn("Unable to find icon for domain "+t+" ("+e+")"),u["default"]}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(40),u=r(o);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"]=(0,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(141),a=i(u),s=n(142),c=i(s),l=n(139),f=r(l),d=n(140),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(153),u=i(o),a=n(154),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"]=(0,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(171),a=i(u),s=n(169),c=r(s),l=n(170),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(183),a=i(u),s=n(179),c=r(s),l=n(180),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"]=(0,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(185),a=i(u),s=n(186),c=i(s),l=n(184),f=r(l),d=n(61),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){(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=S(i.slice(0,e).join("-")))return r;if(n&&n.length>=e&&m(i,n,!0)>=e-1)break;e--}o++}return null}function S(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}(),w(n)}catch(r){}return Hn[e]}function w(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),w(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=S(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 I(t){return"string"==typeof t?Yn[t]||Yn[t.toLowerCase()]:void 0}function j(t){var e,n,r={};for(n in t)u(t,n)&&(e=I(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=I(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 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"),St(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 St(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]=wt(t._locale,t._a[lr],t._meridiem),bt(t),Q(t)}function wt(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=j(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(It(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function It(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)),v(e)?new h(Q(e)):(r(n)?Mt(t):n?St(t):i(e)?t._d=e:jt(t),t))}function jt(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 Rt(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 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=It(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=Ir.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=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=I("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=I("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){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 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(wn(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=_(Sn(u)),a+=i,u-=bn(wn(i)),r=_(a/12),a%=12,s.days=u,s.months=a,s.years=r,this}function Sn(t){return 4800*t/146097}function wn(t){return 146097*t/4800}function Mn(t){var e,n,r=this._milliseconds;if(t=I(t),"month"===t||"year"===t)return e=this._days+r/864e5,n=this._months+Sn(e),"month"===t?n:n/12;switch(e=this._days+Math.round(wn(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 In(t){return t=I(t),this[t+"s"]()}function jn(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 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=_(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;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("_"),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":""))}),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 Sr={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 wr=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 Tr=/([\+\-]|\d\d)/gi;e.updateOffset=function(){};var Er=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ir=/^(-)?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 jr=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 Rr=P("Minutes",!1);x("s",["ss",2],0,"second"),E("second","s"),Y("s",$n),Y("ss",$n,qn),U(["s","ss"],dr);var zr=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=jr,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=Ie,Gr.lang=Dr,Gr.locale=me,Gr.localeData=ge,Gr.max=Mr,Gr.min=wr,Gr.parsingFlags=je,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=we,Gr.valueOf=Se,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=vt,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=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=Sr,Jr.firstDayOfYear=pt,Jr.firstDayOfWeek=dt,Jr.weekdays=ze,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,w("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.",w),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=jn("milliseconds"),ui=jn("seconds"),ai=jn("minutes"),si=jn("hours"),ci=jn("days"),li=jn("months"),fi=jn("years"),di=Math.round,pi={s:45,m:45,h:22,d:26,M:11},hi=Math.abs,vi=xt.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=Tn,vi._bubble=On,vi.get=In,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=kn,vi.toISOString=xn,vi.toString=xn,vi.toJSON=xn,vi.locale=me,vi.localeData=ge,vi.toIsoString=et("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",xn),vi.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=w,e.invalid=d,e.duration=Zt,e.isMoment=v,e.weekdays=pn,e.parseZone=Qe,e.localeData=T,e.isDuration=Lt,e.monthsShort=dn,e.weekdaysMin=vn,e.defineLocale=M,e.weekdaysShort=hn,e.normalizeUnits=I,e.relativeTimeThreshold=An;var _i=e;return _i})}).call(e,n(73)(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(1),o=r(i),u=n(22),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(0,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(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,n=this._checkToggle(this.stateObj);e&&!n?this._call_service(!0):!e&&n&&this._call_service(!1)},stateObjChanged:function(t){t&&this.updateToggle(t)},updateToggle:function(t){this.toggleChecked=this._checkToggle(t)},forceStateChange:function(){var t=this._checkToggle(this.stateObj);this.toggleChecked===t&&(this.toggleChecked=!this.toggleChecked),this.toggleChecked=t},_checkToggle:function(t){return t&&"off"!==t.state&&"unlocked"!==t.state},_call_service:function(t){var e=this,n=void 0,r=void 0;"lock"===this.stateObj.domain?(n="lock",r=t?"lock":"unlock"):(n="homeassistant",r=t?"turn_on":"turn_off"),i.serviceActions.callService(n,r,{entity_id:this.stateObj.entityId}).then(function(){return e.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:{header:{type:String},elevation:{type:Number,value:1,reflectToAttribute:!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(33),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?(0,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(18),n(92),n(91),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(10),e["default"]=new o["default"]({is:"state-card-display",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e["default"]="bookmark",t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,u["default"])(t).format("LT")}Object.defineProperty(e,"__esModule",{value:!0}), +e["default"]=i;var o=n(33),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,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||!S),b===!1)var n=S&&!y;else{p||S||(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 S=!0;O=!1}else i(n)&&(S=!!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(47),o=n(129),u="Expected a function",a=Math.max;t.exports=r},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(132);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(47),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)||(0,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(144),a=i(u),s=n(145),c=i(s),l=n(146),f=i(l),d=n(147),p=i(d),h=n(148),v=i(h),_=n(143),y=r(_),m=n(48),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(172),a=n(192),s=i(a),c=n(194),l=i(c),f=n(196),d=i(f),p=n(15),h=r(p),v=n(24),_=r(v),y=n(8),m=r(y),g=n(49),b=r(g),O=n(152),S=r(O),w=n(25),M=r(w),T=n(157),E=r(T),I=n(52),j=r(I),P=n(55),D=r(P),C=n(27),A=r(C),k=n(13),x=r(k),L=n(28),N=r(L),R=n(30),z=r(R),H=n(189),Y=r(H),G=n(9),F=r(G),U=function B(){o(this,B);var t=(0,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:D.urlSync.startSync.bind(null,t)},stopUrlSync:{value:D.urlSync.stopSync.bind(null,t)}}),(0,l["default"])(this,t,{auth:h,config:_,entity:m,entityHistory:b,errorLog:S,event:M,logbook:E,moreInfo:j,navigation:D,notification:A,service:x,stream:N,sync:z,voice:Y,restApi:F})};e["default"]=U,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(65),i=r("length");t.exports=i},function(t,e,n){"use strict";function r(t){return null!=t&&o(i(t))}var i=n(66),o=n(70);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(67),o=n(68),u=n(71);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?(0,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(17),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(126),a=r(u);e["default"]=new o["default"]({is:"ha-state-icon",properties:{stateObj:{type:Object}},computeIcon:function(t){return(0,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(1),o=r(i),u=n(2),a=n(22),s=r(a),c=n(21),l=r(c);n(17),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(),(0,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"binary_sensor":case"script":return"on"===t.state?"blue":"grey";case"updater":return"blue";default:return""}},computeValue:function(t){switch(t.domain){case"binary_sensor":case"device_tracker":case"updater":case"sun":case"scene":case"script":case"alarm_control_panel":return;case"sensor":return t.state;default:return t.state}},computeIcon:function(t){switch(t.domain){case"alarm_control_panel":return"pending"===t.state?"mdi:clock-fast":"armed_away"===t.state?"mdi:nature":"armed_home"===t.state?"mdi:home-variant":(0,s["default"])(t.domain,t.state);case"binary_sensor":case"device_tracker":case"scene":case"updater":case"script":return(0,s["default"])(t.domain,t.state);case"sun":return"above_horizon"===t.state?(0,s["default"])(t.domain):"mdi:brightness-3";default:return}},computeImage:function(t){return t.attributes.entity_picture},computeLabel:function(t){switch(t.domain){case"scene":case"script":return t.domain;case"device_tracker":return"not_home"===t.state?"Away":t.state;case"alarm_control_panel":return"pending"===t.state?"pend":"armed_away"===t.state||"armed_home"===t.state?"armed":"disarm";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);n(80),e["default"]=new o["default"]({is:"state-badge",properties:{stateObj:{type:Object,observer:"updateIconColor"}},updateIconColor:function(t){"light"===t.domain&&"on"===t.state&&t.attributes.rgb_color&&t.attributes.rgb_color.reduce(function(t,e){return t+e},0)<730?this.$.icon.style.color="rgb("+t.attributes.rgb_color.join(",")+")":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"},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)},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(17),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(89),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(93),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 e in t&&t[e].groupEntity},computeStatesOfCard:function(t,e){return e in t&&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(34),n(77),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(34),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(72),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]],(0,u["default"])(1,t.getNumberOfColumns()),(0,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);e["default"]=new u["default"]({is:"ha-voice-command-dialog",behaviors:[s["default"]],properties:{dialogOpen:{type:Boolean,value:!1,observer:"dialogOpenChanged"},finalTranscript:{type:String,bindNuclear:i.voiceGetters.finalTranscript},interimTranscript:{type:String,bindNuclear:i.voiceGetters.extraInterimTranscript},isTransmitting:{type:Boolean,bindNuclear:i.voiceGetters.isTransmitting},isListening:{type:Boolean,bindNuclear:i.voiceGetters.isListening},showListenInterface:{type:Boolean,computed:"computeShowListenInterface(isListening, isTransmitting)", +observer:"showListenInterfaceChanged"},_boundOnBackdropTap:{type:Function,value:function(){return this._onBackdropTap.bind(this)}}},computeShowListenInterface:function(t,e){return t||e},dialogOpenChanged:function(t){t?this.$.dialog.backdropElement.addEventListener("click",this._boundOnBackdropTap):!t&&this.isListening&&i.voiceActions.stop()},showListenInterfaceChanged:function(t){!t&&this.dialogOpen?this.dialogOpen=!1:t&&(this.dialogOpen=!0)},_onBackdropTap:function(){this.$.dialog.backdropElement.removeEventListener("click",this._boundOnBackdropTap),this.isListening&&i.voiceActions.stop()}}),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),n(38),n(110);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(87),n(105),n(103),n(102),n(104),n(98),n(99),n(101),n(100),n(106),n(95),n(94),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")},isSelectedDevInfo:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("devInfo")},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(){(0,u.startUrlSync)()},computeForceNarrow:function(t,e){return t||!e},detached:function(){(0,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:{errorMessage:{type:String,bindNuclear:u.authGetters.attemptErrorMessage},isInvalid:{type:Boolean,bindNuclear:u.authGetters.isInvalidAttempt},isValidating:{type:Boolean,observer:"isValidatingChanged",bindNuclear:u.authGetters.isValidating},loadingResources:{type:Boolean,value:!1},forceShowLoading:{type:Boolean,value:!1},showLoading:{type:Boolean,computed:"computeShowSpinner(forceShowLoading, isValidating)"}},listeners:{keydown:"passwordKeyDown","loginButton.click":"validatePassword"},observers:["validatingChanged(isValidating, isInvalid)"],computeShowSpinner:function(t,e){return t||e},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(),(0,l["default"])(this.$.passwordInput.value,this.$.rememberLogin.checked)},attached:function(){var t=document.getElementById("init");t.parentElement.removeChild(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);n(7),n(90),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(7),n(83),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),a=n(4),s=r(a);n(7),e["default"]=new u["default"]({is:"partial-dev-info",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},hassVersion:{type:String,bindNuclear:i.configGetters.serverVersion},polymerVersion:{type:String,value:u["default"].version},nuclearVersion:{type:String,value:"1.2.1"},errorLog:{type:String,value:""}},attached:function(){this.refreshErrorLog()},refreshErrorLog:function(t){var e=this;t&&t.preventDefault(),this.errorLog="Loading error log…",i.errorLogActions.fetchErrorLog().then(function(t){return e.errorLog=t||"No errors have been reported."})}}),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(7),n(78),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(7),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(7),n(86),n(18),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(79),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(7),n(88),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}]},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(){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()},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(18),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(127),a=r(u);n(111),n(112),n(116),n(109),n(117),n(115),n(113),n(114),n(108),n(118),n(107),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=(0,a["default"])(t);if(e&&(0,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","icon","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(19),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(20),s=r(a);n(84);var c=["brightness","rgb_color","color_temp"];e["default"]=new u["default"]({is:"more-info-light",properties:{stateObj:{type:Object,observer:"stateObjChanged"},brightnessSliderValue:{type:Number,value:0},ctSliderValue:{type:Number,value:0}},stateObjChanged:function(t){var e=this;t&&"on"===t.state&&(this.brightnessSliderValue=t.attributes.brightness,this.ctSliderValue=t.attributes.color_temp),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return(0,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}))},ctSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,color_temp: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(20),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(0,s["default"])(t,c)},computeIsOff:function(t){return"off"===t.state},computeMuteVolumeIcon:function(t){return t?"mdi:volume-off":"mdi:volume-high"},computePlaybackControlIcon:function(){return this.isPlaying?this.supportsPause?"mdi:pause":"mdi:stop":"mdi:play"},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(0,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(20),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(0,s["default"])(t,c)},targetTemperatureSliderChanged:function(t){i.serviceActions.callService("thermostat","set_temperature",{entity_id:this.stateObj.entityId,temperature:t.target.value})},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);e["default"]=new o["default"]({is:"more-info-updater",properties:{}}),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(10),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(10);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(10),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(10),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(10),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:(0,u["default"])(t.entityId)?"toggle":"display"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(21),u=r(o),a=["thermostat","configurator","scene","media_player"];t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){if(!t)return u["default"];if(t.attributes.icon)return t.attributes.icon;var e=t.attributes.unit_of_measurement;return!e||"sensor"!==t.domain||e!==c.util.temperatureUnits.UNIT_TEMP_C&&e!==c.util.temperatureUnits.UNIT_TEMP_F?(0,s["default"])(t.domain,t.state):"mdi:thermometer"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(40),u=r(o),a=n(22),s=r(a),c=n(2);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,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(201);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 S(t,e,n,r){try{t.call(e,n,r); +}catch(i){return i}}function w(t,e,n){Z(function(t){var r=!1,i=S(n,e,function(n){r||(r=!0,e!==n?E(t,n):j(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?j(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?j(t,e):a(n)?w(t,e,n):j(t,e)}}function E(t,e){t===e?P(t,g()):u(e)?T(t,e):j(t,e)}function I(t){t._onerror&&t._onerror(t._result),C(t)}function j(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(I,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=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&&j(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(){x(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(200).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(198),function(){return this}(),n(197)(t))},function(t,e,n){"use strict";var r=n(44),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(44),i=n(130),o=n(45),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(46),o=n(45),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(128),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(){var e=void 0;try{e="application/json"===r.getResponseHeader("content-type")?JSON.parse(r.responseText):r.responseText}catch(i){e=r.responseText}r.status>199&&r.status<300?t(e):n(e)},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(c.getters.isSupported):r,o=n.rememberAuth,u=void 0===o?!1:o,s=n.host,d=void 0===s?"":s;t.dispatch(a["default"].VALIDATING_AUTH_TOKEN,{authToken:e,host:d}),l.actions.fetchAll(t).then(function(){t.dispatch(a["default"].VALID_AUTH_TOKEN,{authToken:e,host:d,rememberAuth:u}),i?c.actions.start(t,{syncOnInitialConnect:!1}):l.actions.start(t,{skipInitialSync:!0})},function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=e.message,r=void 0===n?f:n;t.dispatch(a["default"].INVALID_AUTH_TOKEN,{errorMessage:r})})}function o(t){(0,s.callApi)(t,"POST","log_out"),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(6),c=n(28),l=n(30),f="Unexpected result from API"},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=["authAttempt","isValidating"];e.isValidating=n;var r=["authAttempt","isInvalid"];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(0,d.toImmutable)({authToken:n,host:r,isValidating:!0,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",!0).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)||(0,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(159),a=i(u),s=n(160),c=i(s),l=n(161),f=i(l),d=n(162),p=i(d),h=n(155),v=r(h),_=n(156),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 33124030f6d..300f3582a61 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 33124030f6d119ad3a58cb520062f2aa58022c6d +Subproject commit 300f3582a61b5781431778cd2f44bef05d49baf3 From 90eab17ea6acb26bb2824584c2d64b27343922de Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 23:23:27 -0800 Subject: [PATCH 128/166] Fix MQTT light bugs --- homeassistant/components/light/mqtt.py | 8 ++++---- tests/components/light/test_mqtt.py | 25 +++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/light/mqtt.py b/homeassistant/components/light/mqtt.py index 97624ec72f9..30f968d758f 100644 --- a/homeassistant/components/light/mqtt.py +++ b/homeassistant/components/light/mqtt.py @@ -18,7 +18,6 @@ DEFAULT_NAME = "MQTT Light" DEFAULT_QOS = 0 DEFAULT_PAYLOAD_ON = "on" DEFAULT_PAYLOAD_OFF = "off" -DEFAULT_RGB_PATTERN = "%d,%d,%d" DEFAULT_OPTIMISTIC = False DEPENDENCIES = ['mqtt'] @@ -137,9 +136,8 @@ class MqttLight(Light): if ATTR_RGB_COLOR in kwargs and \ self._topic["rgb_command_topic"] is not None: - rgb = DEFAULT_RGB_PATTERN % tuple(self._rgb) mqtt.publish(self._hass, self._topic["rgb_command_topic"], - rgb, self._qos) + "{},{},{}".format(*kwargs[ATTR_RGB_COLOR]), self._qos) if self._optimistic_rgb: self._rgb = kwargs[ATTR_RGB_COLOR] @@ -147,8 +145,10 @@ class MqttLight(Light): if ATTR_BRIGHTNESS in kwargs and \ self._topic["brightness_command_topic"] is not None: + mqtt.publish(self._hass, self._topic["brightness_command_topic"], - self._brightness, self._qos) + kwargs[ATTR_BRIGHTNESS], self._qos) + if self._optimistic_brightness: self._brightness = kwargs[ATTR_BRIGHTNESS] should_update = True diff --git a/tests/components/light/test_mqtt.py b/tests/components/light/test_mqtt.py index bc0195feff1..8172a6c7c63 100644 --- a/tests/components/light/test_mqtt.py +++ b/tests/components/light/test_mqtt.py @@ -149,9 +149,7 @@ class TestLightMQTT(unittest.TestCase): 'platform': 'mqtt', 'name': 'test', 'command_topic': 'test_light_rgb/set', - 'brightness_state_topic': 'test_light_rgb/brightness/status', 'brightness_command_topic': 'test_light_rgb/brightness/set', - 'rgb_state_topic': 'test_light_rgb/rgb/status', 'rgb_command_topic': 'test_light_rgb/rgb/set', 'qos': 2, 'payload_on': 'on', @@ -177,3 +175,26 @@ class TestLightMQTT(unittest.TestCase): self.mock_publish.mock_calls[-1][1]) state = self.hass.states.get('light.test') self.assertEqual(STATE_OFF, state.state) + + light.turn_on(self.hass, 'light.test', rgb_color=[75, 75, 75], + brightness=50) + self.hass.pool.block_till_done() + + # Calls are threaded so we need to reorder them + bright_call, rgb_call, state_call = \ + sorted((call[1] for call in self.mock_publish.mock_calls[-3:]), + key=lambda call: call[0]) + + self.assertEqual(('test_light_rgb/set', 'on', 2, False), + state_call) + + self.assertEqual(('test_light_rgb/rgb/set', '75,75,75', 2, False), + rgb_call) + + self.assertEqual(('test_light_rgb/brightness/set', 50, 2, False), + bright_call) + + state = self.hass.states.get('light.test') + self.assertEqual(STATE_ON, state.state) + self.assertEqual([75, 75, 75], state.attributes['rgb_color']) + self.assertEqual(50, state.attributes['brightness']) From b53993e8c07611befb0b1001eb9dc2f1d2df1393 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 29 Nov 2015 23:55:37 -0800 Subject: [PATCH 129/166] Update Travis to test on Python 3.5 too --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index da3516554ef..f12d318b5d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,10 @@ sudo: false language: python cache: directories: - - $HOME/virtualenv/python3.4.2/ + - $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/ python: - - "3.4" + - 3.4.2 + - 3.5.0 install: - script/bootstrap_server script: From ac598471209a96f980460036df9ca625eee3feed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 30 Nov 2015 09:14:32 +0100 Subject: [PATCH 130/166] Update heat_control.py --- .../components/thermostat/heat_control.py | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/thermostat/heat_control.py b/homeassistant/components/thermostat/heat_control.py index 7080528fd17..66992e223a0 100644 --- a/homeassistant/components/thermostat/heat_control.py +++ b/homeassistant/components/thermostat/heat_control.py @@ -24,6 +24,9 @@ CONF_NAME = 'name' DEFAULT_NAME = 'Heat Control' CONF_HEATER = 'heater' CONF_SENSOR = 'target_sensor' +CONF_MIN_TEMP = 'min_temp' +CONF_MAX_TEMP = 'max_temp' +CONF_TARGET_TEMP = 'target_temp' _LOGGER = logging.getLogger(__name__) @@ -34,27 +37,32 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = config.get(CONF_NAME, DEFAULT_NAME) heater_entity_id = config.get(CONF_HEATER) sensor_entity_id = config.get(CONF_SENSOR) + min_temp = util.convert(config.get(CONF_MIN_TEMP), float, None) + max_temp = util.convert(config.get(CONF_MAX_TEMP), float, None) + target_temp = util.convert(config.get(CONF_TARGET_TEMP), float, None) if None in (heater_entity_id, sensor_entity_id): _LOGGER.error('Missing required key %s or %s', CONF_HEATER, CONF_SENSOR) return False - add_devices([HeatControl(hass, name, heater_entity_id, sensor_entity_id)]) + add_devices([HeatControl(hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp)]) # pylint: disable=too-many-instance-attributes class HeatControl(ThermostatDevice): """ Represents a HeatControl device. """ - def __init__(self, hass, name, heater_entity_id, sensor_entity_id): + def __init__(self, hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp): self.hass = hass self._name = name self.heater_entity_id = heater_entity_id self._active = False self._cur_temp = None - self._target_temp = None + self._min_temp = min_temp + self._max_temp = max_temp + self._target_temp = target_temp self._unit = None track_state_change(hass, sensor_entity_id, self._sensor_changed) @@ -97,6 +105,22 @@ class HeatControl(ThermostatDevice): self._control_heating() self.update_ha_state() + @property + def min_temp(self): + """ Return minimum temperature. """ + if self._min_temp: + return self._min_temp + else: + return ThermostatDevice.min_temp.fget(self) + + @property + def max_temp(self): + """ Return maximum temperature. """ + if self._min_temp: + return self._max_temp + else: + return ThermostatDevice.max_temp.fget(self) + def _sensor_changed(self, entity_id, old_state, new_state): """ Called when temperature changes. """ if new_state is None: From 2732b2030545a857e3e419051b8832c9c2b3e789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 30 Nov 2015 09:22:04 +0100 Subject: [PATCH 131/166] style fix in heatcontrol --- homeassistant/components/thermostat/heat_control.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/thermostat/heat_control.py b/homeassistant/components/thermostat/heat_control.py index 66992e223a0..93326be384a 100644 --- a/homeassistant/components/thermostat/heat_control.py +++ b/homeassistant/components/thermostat/heat_control.py @@ -46,14 +46,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None): CONF_SENSOR) return False - add_devices([HeatControl(hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp)]) + add_devices([HeatControl(hass, name, heater_entity_id, sensor_entity_id, + min_temp, max_temp, target_temp)]) # pylint: disable=too-many-instance-attributes class HeatControl(ThermostatDevice): """ Represents a HeatControl device. """ - def __init__(self, hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp): + def __init__(self, hass, name, heater_entity_id, sensor_entity_id, + min_temp, max_temp, target_temp): self.hass = hass self._name = name self.heater_entity_id = heater_entity_id @@ -111,6 +113,7 @@ class HeatControl(ThermostatDevice): if self._min_temp: return self._min_temp else: + # pylint: disable=no-member return ThermostatDevice.min_temp.fget(self) @property @@ -119,6 +122,7 @@ class HeatControl(ThermostatDevice): if self._min_temp: return self._max_temp else: + # pylint: disable=no-member return ThermostatDevice.max_temp.fget(self) def _sensor_changed(self, entity_id, old_state, new_state): From 48a424e86fb372732e0977a1eb777c7a344c202d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 30 Nov 2015 00:48:39 -0800 Subject: [PATCH 132/166] Frontend upgrade --- homeassistant/components/frontend/version.py | 2 +- homeassistant/components/frontend/www_static/frontend.html | 2 +- .../components/frontend/www_static/home-assistant-polymer | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index a3c09fc4149..789efa8988c 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 = "a07269fd3559611af16a4204b7645a64" +VERSION = "ece94598f1575599c5aefa7322b1423b" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 36921057fca..32df087296c 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -6052,7 +6052,7 @@ case"touchend":return this.addPointerListenerEnd(t,e,i,n);case"touchmove":return font-weight: 300; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; - } \ 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 c130933f452..2e8ad266eeb 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit c130933f45262dd1c7b4fd75d23a90c132fb271f +Subproject commit 2e8ad266eeb8cd0136df498b995f584e01338000 From 705e3e4fbb6cd872e0737371725991b7346c52ae Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 5 Dec 2015 13:20:00 -0800 Subject: [PATCH 155/166] Update material design icons --- homeassistant/components/frontend/mdi_version.py | 2 +- .../components/frontend/www_static/mdi.html | 2 +- script/update_mdi.py | 15 ++++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/frontend/mdi_version.py b/homeassistant/components/frontend/mdi_version.py index c9d06a4b300..a8106ecd77e 100644 --- a/homeassistant/components/frontend/mdi_version.py +++ b/homeassistant/components/frontend/mdi_version.py @@ -1,2 +1,2 @@ """ DO NOT MODIFY. Auto-generated by update_mdi script """ -VERSION = "38EF63D0474411E4B3CF842B2B6CFE1B" +VERSION = "7d76081c37634d36af21f5cc1ca79408" diff --git a/homeassistant/components/frontend/www_static/mdi.html b/homeassistant/components/frontend/www_static/mdi.html index 42212a3a301..13b003806b3 100644 --- a/homeassistant/components/frontend/www_static/mdi.html +++ b/homeassistant/components/frontend/www_static/mdi.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/script/update_mdi.py b/script/update_mdi.py index f7899be3964..c61a3808b39 100755 --- a/script/update_mdi.py +++ b/script/update_mdi.py @@ -2,7 +2,7 @@ """ Downloads the latest Polymer v1 iconset version for materialdesignicons.com """ - +import hashlib import os import re import requests @@ -75,17 +75,18 @@ def main(): print("materialdesignicons.com icon updater") local_version = get_local_version() - remote_version, remote_url = get_remote_version() - print('Local version:', local_version) - print('Remote version:', remote_version) + # The remote version is not reliable. + _, remote_url = get_remote_version() - if local_version == remote_version: + source = clean_component(requests.get(remote_url).text) + new_version = hashlib.md5(source.encode('utf-8')).hexdigest() + + if local_version == new_version: print('Already on the latest version.') sys.exit() - write_component(remote_version, - clean_component(requests.get(remote_url).text)) + write_component(new_version, source) print('Updated to latest version') if __name__ == '__main__': From c4fe480b7b1700df6720b447f8223e51e6a5f843 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 5 Dec 2015 13:44:50 -0800 Subject: [PATCH 156/166] HTTP will not fail if no config --- homeassistant/components/http.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index 81965179afe..f5e337ccf9c 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -50,7 +50,7 @@ _LOGGER = logging.getLogger(__name__) def setup(hass, config): """ Sets up the HTTP API and debug interface. """ - conf = config[DOMAIN] + conf = config.get(DOMAIN, {}) api_password = util.convert(conf.get(CONF_API_PASSWORD), str) From 03962ab6ae33e7e1e59626bd6befd524313712a2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 09:08:34 -0800 Subject: [PATCH 157/166] Fix demo component messing up the config Could cause HTTP to be initialised in production mode. --- homeassistant/components/demo.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 8a8c5ed31e5..8b4b3fcce6c 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -53,9 +53,10 @@ def setup(hass, config): bootstrap.setup_component(hass, 'sun') # Setup demo platforms + demo_config = config.copy() for component in COMPONENTS_WITH_DEMO_PLATFORM: - bootstrap.setup_component( - hass, component, {component: {CONF_PLATFORM: 'demo'}}) + demo_config[component] = {CONF_PLATFORM: 'demo'} + bootstrap.setup_component(hass, component, demo_config) # Setup room groups lights = sorted(hass.states.entity_ids('light')) From f8668075d0e8447a44e51d2b2fa12a6ba797920c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 09:09:18 -0800 Subject: [PATCH 158/166] Fix State.copy() --- homeassistant/core.py | 3 ++- tests/test_core.py | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/homeassistant/core.py b/homeassistant/core.py index d7ec3abe458..85b16f07b83 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -381,7 +381,8 @@ class State(object): def copy(self): """ Creates a copy of itself. """ return State(self.entity_id, self.state, - dict(self.attributes), self.last_changed) + dict(self.attributes), self.last_changed, + self.last_updated) def as_dict(self): """ Converts State to a dict to be used within JSON. diff --git a/tests/test_core.py b/tests/test_core.py index bb59aac03fa..fee46fe2dd4 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -268,7 +268,15 @@ class TestState(unittest.TestCase): def test_copy(self): state = ha.State('domain.hello', 'world', {'some': 'attr'}) - self.assertEqual(state, state.copy()) + # Patch dt_util.utcnow() so we know last_updated got copied too + with patch('homeassistant.core.dt_util.utcnow', + return_value=dt_util.utcnow() + timedelta(seconds=10)): + copy = state.copy() + self.assertEqual(state.entity_id, copy.entity_id) + self.assertEqual(state.state, copy.state) + self.assertEqual(state.attributes, copy.attributes) + self.assertEqual(state.last_changed, copy.last_changed) + self.assertEqual(state.last_updated, copy.last_updated) def test_dict_conversion(self): state = ha.State('domain.hello', 'world', {'some': 'attr'}) From 934b097bc7e611349450924b785c7f4225b32eac Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 09:12:19 -0800 Subject: [PATCH 159/166] Rename date_util to dt_util Follows the rest of Home Assistant --- homeassistant/core.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/homeassistant/core.py b/homeassistant/core.py index 85b16f07b83..8ea55c653e3 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -25,7 +25,7 @@ from homeassistant.const import ( from homeassistant.exceptions import ( HomeAssistantError, InvalidEntityFormatError) import homeassistant.util as util -import homeassistant.util.dt as date_util +import homeassistant.util.dt as dt_util import homeassistant.util.location as location import homeassistant.helpers.temperature as temp_helper from homeassistant.config import get_default_config_dir @@ -196,8 +196,8 @@ class Event(object): self.event_type = event_type self.data = data or {} self.origin = origin - self.time_fired = date_util.strip_microseconds( - time_fired or date_util.utcnow()) + self.time_fired = dt_util.strip_microseconds( + time_fired or dt_util.utcnow()) def as_dict(self): """ Returns a dict representation of this Event. """ @@ -205,7 +205,7 @@ class Event(object): 'event_type': self.event_type, 'data': dict(self.data), 'origin': str(self.origin), - 'time_fired': date_util.datetime_to_str(self.time_fired), + 'time_fired': dt_util.datetime_to_str(self.time_fired), } def __repr__(self): @@ -351,14 +351,14 @@ class State(object): self.entity_id = entity_id.lower() self.state = state self.attributes = attributes or {} - self.last_updated = date_util.strip_microseconds( - last_updated or date_util.utcnow()) + self.last_updated = dt_util.strip_microseconds( + last_updated or dt_util.utcnow()) # Strip microsecond from last_changed else we cannot guarantee # state == State.from_dict(state.as_dict()) # This behavior occurs because to_dict uses datetime_to_str # which does not preserve microseconds - self.last_changed = date_util.strip_microseconds( + self.last_changed = dt_util.strip_microseconds( last_changed or self.last_updated) @property @@ -391,8 +391,8 @@ class State(object): return {'entity_id': self.entity_id, 'state': self.state, 'attributes': self.attributes, - 'last_changed': date_util.datetime_to_str(self.last_changed), - 'last_updated': date_util.datetime_to_str(self.last_updated)} + 'last_changed': dt_util.datetime_to_str(self.last_changed), + 'last_updated': dt_util.datetime_to_str(self.last_updated)} @classmethod def from_dict(cls, json_dict): @@ -407,12 +407,12 @@ class State(object): last_changed = json_dict.get('last_changed') if last_changed: - last_changed = date_util.str_to_datetime(last_changed) + last_changed = dt_util.str_to_datetime(last_changed) last_updated = json_dict.get('last_updated') if last_updated: - last_updated = date_util.str_to_datetime(last_updated) + last_updated = dt_util.str_to_datetime(last_updated) return cls(json_dict['entity_id'], json_dict['state'], json_dict.get('attributes'), last_changed, last_updated) @@ -429,7 +429,7 @@ class State(object): return "".format( self.entity_id, self.state, attr, - date_util.datetime_to_local_str(self.last_changed)) + dt_util.datetime_to_local_str(self.last_changed)) class StateMachine(object): @@ -733,7 +733,7 @@ class Config(object): def as_dict(self): """ Converts config to a dictionary. """ - time_zone = self.time_zone or date_util.UTC + time_zone = self.time_zone or dt_util.UTC return { 'latitude': self.latitude, @@ -767,7 +767,7 @@ def create_timer(hass, interval=TIMER_INTERVAL): last_fired_on_second = -1 - calc_now = date_util.utcnow + calc_now = dt_util.utcnow while not stop_event.isSet(): now = calc_now() @@ -833,6 +833,6 @@ def create_worker_pool(worker_count=None): for start, job in current_jobs: _LOGGER.warning("WorkerPool:Current job from %s: %s", - date_util.datetime_to_local_str(start), job) + dt_util.datetime_to_local_str(start), job) return util.ThreadPool(job_handler, worker_count, busy_callback) From a833e8b4138f599acbbfd42dca4392b6b18c62e1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 09:38:49 -0800 Subject: [PATCH 160/166] Update requirements_all.txt --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index 7bb549ca579..965b615f95f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -160,7 +160,7 @@ orvibo==1.0.1 pywemo==0.3.3 # homeassistant.components.thermostat.honeywell -evohomeclient==0.2.3 +evohomeclient==0.2.4 # homeassistant.components.thermostat.nest python-nest==2.6.0 From b7712ac682b1da4b3c511ad3f9edab51cdb34191 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 09:45:58 -0800 Subject: [PATCH 161/166] Clean up influx component --- homeassistant/components/influx.py | 35 ++++++++++++------------------ 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/influx.py b/homeassistant/components/influx.py index e8b458892cc..a65126f8102 100644 --- a/homeassistant/components/influx.py +++ b/homeassistant/components/influx.py @@ -71,29 +71,23 @@ def setup(hass, config): _LOGGER.error("Database %s doesn't exist", dbname) return False - def event_listener(event): + def influx_event_listener(event): """ Listen for new messages on the bus and sends them to Influx. """ - event_data = event.as_dict() - if event_data['event_type'] is not EVENT_STATE_CHANGED: + state = event.data.get('new_state') + + if state is None: return - state = event_data['data']['new_state'] - - if state.state == STATE_ON or state.state == STATE_LOCKED or \ - state.state == STATE_ABOVE_HORIZON: + if state.state in (STATE_ON, STATE_LOCKED, STATE_ABOVE_HORIZON): _state = 1 - elif state.state == STATE_OFF or state.state == STATE_UNLOCKED or \ - state.state == STATE_UNKNOWN or \ - state.state == STATE_BELOW_HORIZON: + elif state.state in (STATE_OFF, STATE_UNLOCKED, STATE_UNKNOWN, + STATE_BELOW_HORIZON): _state = 0 else: _state = state.state - try: - measurement = state.attributes['unit_of_measurement'] - except KeyError: - measurement = '{}'.format(state.domain) + measurement = state.attributes.get('unit_of_measurement', state.domain) json_body = [ { @@ -102,19 +96,18 @@ def setup(hass, config): 'domain': state.domain, 'entity_id': state.object_id, }, - 'time': event_data['time_fired'], + 'time': event.time_fired, 'fields': { 'value': _state, } } ] - if json_body: - try: - influx.write_points(json_body) - except exceptions.InfluxDBClientError: - _LOGGER.exception('Error saving event to Influx') + try: + influx.write_points(json_body) + except exceptions.InfluxDBClientError: + _LOGGER.exception('Error saving event to Influx') - hass.bus.listen(EVENT_STATE_CHANGED, event_listener) + hass.bus.listen(EVENT_STATE_CHANGED, influx_event_listener) return True From 1cb4d40bbba26f029d23613ad5865769b2b6719e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 10:00:10 -0800 Subject: [PATCH 162/166] Update frontend --- homeassistant/components/frontend/version.py | 2 +- .../frontend/www_static/frontend.html | 26 +++++++++---------- .../www_static/home-assistant-polymer | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 5c9371f67e4..bbc0264f751 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 = "33a9830ccda8000eb88700de9d4cd03b" +VERSION = "6f4dc002423ec8acfb1c4063e708a8b1" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 6e46b80ef88..bbf0d00bc7c 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -3718,7 +3718,7 @@ case"touchend":return this.addPointerListenerEnd(t,e,i,n);case"touchmove":return text-align: right; white-space: nowrap; width: 127px; - } \ No newline at end of file +}catch(n){throw this.__isDispatching=!1,n}try{this.__notify()}finally{this.__isDispatching=!1}}},{key:"batch",value:function(t){this.batchStart(),t(),this.batchEnd()}},{key:"registerStore",value:function(t,e){console.warn("Deprecation warning: `registerStore` will no longer be supported in 1.1, use `registerStores` instead"),this.registerStores(i({},t,e))}},{key:"registerStores",value:function(t){this.reactorState=d["default"].registerStores(this.reactorState,t),this.__notify()}},{key:"serialize",value:function(){return d["default"].serialize(this.reactorState)}},{key:"loadState",value:function(t){this.reactorState=d["default"].loadState(this.reactorState,t),this.__notify()}},{key:"reset",value:function(){var t=d["default"].reset(this.reactorState);this.reactorState=t,this.prevReactorState=t,this.observerState=new y.ObserverState}},{key:"__notify",value:function(){var t=this;if(!(this.__batchDepth>0)){var e=this.reactorState.get("dirtyStores");if(0!==e.size){var n=s["default"].Set().withMutations(function(n){n.union(t.observerState.get("any")),e.forEach(function(e){var r=t.observerState.getIn(["stores",e]);r&&n.union(r)})});n.forEach(function(e){var n=t.observerState.getIn(["observersMap",e]);if(n){var r=n.get("getter"),i=n.get("handler"),o=d["default"].evaluate(t.prevReactorState,r),u=d["default"].evaluate(t.reactorState,r);t.prevReactorState=o.reactorState,t.reactorState=u.reactorState;var a=o.result,c=u.result;s["default"].is(a,c)||i.call(null,c)}});var r=d["default"].resetDirtyStores(this.reactorState);this.prevReactorState=r,this.reactorState=r}}}},{key:"batchStart",value:function(){this.__batchDepth++}},{key:"batchEnd",value:function(){if(this.__batchDepth--,this.__batchDepth<=0){this.__isDispatching=!0;try{this.__notify()}catch(t){throw this.__isDispatching=!1,t}this.__isDispatching=!1}}}]),t}();e["default"]=(0,_.toFactory)(m),t.exports=e["default"]},function(t,e,n){function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n={};return(0,o.each)(e,function(e,r){n[r]=t.evaluate(e)}),n}Object.defineProperty(e,"__esModule",{value:!0});var o=n(4);e["default"]=function(t){return{getInitialState:function(){return i(t,this.getDataBindings())},componentDidMount:function(){var e=this;this.__unwatchFns=[],(0,o.each)(this.getDataBindings(),function(n,i){var o=t.observe(n,function(t){e.setState(r({},i,t))});e.__unwatchFns.push(o)})},componentWillUnmount:function(){for(;this.__unwatchFns.length;)this.__unwatchFns.shift()()}}},t.exports=e["default"]},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){return new b({result:t,reactorState:e})}function o(t){return t}function u(t,e){var n=o(e);return t.getIn(["cache",n])}function a(t,e){var n=u(t,e);if(!n)return!1;var r=n.get("storeStates");return 0===r.size?!1:r.every(function(e,n){return t.getIn(["storeStates",n])===e})}function s(t,e,n){var r=o(e),i=t.get("dispatchId"),u=(0,y.getStoreDeps)(e),a=(0,_.toImmutable)({}).withMutations(function(e){u.forEach(function(n){var r=t.getIn(["storeStates",n]);e.set(n,r)})});return t.setIn(["cache",r],p["default"].Map({value:n,storeStates:a,dispatchId:i}))}function c(t,e){var n=o(e);return t.getIn(["cache",n,"value"])}function l(t){return t.update("dispatchId",function(t){return t+1})}function f(t,e){return t.withMutations(function(t){e.forEach(function(e){var n=t.has(e)?t.get(e)+1:1;t.set(e,n)})})}var d=n(3),p=r(d),h=n(9),v=r(h),_=n(5),y=n(10),m=n(11),g=n(4),b=p["default"].Record({result:null,reactorState:null});e.registerStores=function(t,e){var n=t.get("debug");return t.withMutations(function(t){(0,g.each)(e,function(e,r){t.getIn(["stores",r])&&console.warn("Store already defined for id = "+r);var i=e.getInitialState();if(n&&!(0,_.isImmutableValue)(i))throw new Error("Store getInitialState() must return an immutable value, did you forget to call toImmutable");t.update("stores",function(t){return t.set(r,e)}).update("state",function(t){return t.set(r,i)}).update("dirtyStores",function(t){return t.add(r)}).update("storeStates",function(t){return f(t,[r])})}),l(t)})},e.dispatch=function(t,e,n){var r=t.get("state"),i=t.get("debug"),o=t.get("dirtyStores"),u=r.withMutations(function(r){i&&v["default"].dispatchStart(e,n),t.get("stores").forEach(function(t,u){var a=r.get(u),s=void 0;try{s=t.handle(a,e,n)}catch(c){throw v["default"].dispatchError(c.message),c}if(i&&void 0===s){var l="Store handler must return a value, did you forget a return statement";throw v["default"].dispatchError(l),new Error(l)}r.set(u,s),a!==s&&(o=o.add(u)),i&&v["default"].storeHandled(u,a,s)}),i&&v["default"].dispatchEnd(r)}),a=t.set("state",u).set("dirtyStores",o).update("storeStates",function(t){return f(t,o)});return l(a)},e.loadState=function(t,e){var n=[],r=(0,_.toImmutable)({}).withMutations(function(r){(0,g.each)(e,function(e,i){var o=t.getIn(["stores",i]);if(o){var u=o.deserialize(e);void 0!==u&&(r.set(i,u),n.push(i))}})}),i=p["default"].Set(n);return t.update("state",function(t){return t.merge(r)}).update("dirtyStores",function(t){return t.union(i)}).update("storeStates",function(t){return f(t,n)})},e.addObserver=function(t,e,n){var r=e;(0,m.isKeyPath)(e)&&(e=(0,y.fromKeyPath)(e));var i=t.get("nextId"),o=(0,y.getStoreDeps)(e),u=p["default"].Map({id:i,storeDeps:o,getterKey:r,getter:e,handler:n}),a=void 0;return a=0===o.size?t.update("any",function(t){return t.add(i)}):t.withMutations(function(t){o.forEach(function(e){var n=["stores",e];t.hasIn(n)||t.setIn(n,p["default"].Set([])),t.updateIn(["stores",e],function(t){return t.add(i)})})}),a=a.set("nextId",i+1).setIn(["observersMap",i],u),{observerState:a,entry:u}},e.removeObserver=function(t,n,r){var i=t.get("observersMap").filter(function(t){var e=t.get("getterKey"),i=!r||t.get("handler")===r;return i?(0,m.isKeyPath)(n)&&(0,m.isKeyPath)(e)?(0,m.isEqual)(n,e):n===e:!1});return t.withMutations(function(t){i.forEach(function(n){return e.removeObserverByEntry(t,n)})})},e.removeObserverByEntry=function(t,e){return t.withMutations(function(t){var n=e.get("id"),r=e.get("storeDeps");0===r.size?t.update("any",function(t){return t.remove(n)}):r.forEach(function(e){t.updateIn(["stores",e],function(t){return t?t.remove(n):t})}),t.removeIn(["observersMap",n])})},e.reset=function(t){var n=t.get("debug"),r=t.get("state");return t.withMutations(function(t){var i=t.get("stores"),o=i.keySeq().toJS();i.forEach(function(e,i){var o=r.get(i),u=e.handleReset(o);if(n&&void 0===u)throw new Error("Store handleReset() must return a value, did you forget a return statement");if(n&&!(0,_.isImmutableValue)(u))throw new Error("Store reset state must be an immutable value, did you forget to call toImmutable");t.setIn(["state",i],u)}),t.update("storeStates",function(t){return f(t,o)}),e.resetDirtyStores(t)})},e.evaluate=function O(t,e){var n=t.get("state");if((0,m.isKeyPath)(e))return i(n.getIn(e),t);if(!(0,y.isGetter)(e))throw new Error("evaluate must be passed a keyPath or Getter");if(a(t,e))return i(c(t,e),t);var r=(0,y.getDeps)(e).map(function(e){return O(t,e).result}),o=(0,y.getComputeFn)(e).apply(null,r);return i(o,s(t,e,o))},e.serialize=function(t){var e={};return t.get("stores").forEach(function(n,r){var i=t.getIn(["state",r]),o=n.serialize(i);void 0!==o&&(e[r]=o)}),e},e.resetDirtyStores=function(t){return t.set("dirtyStores",p["default"].Set())}},function(t,e){e.dispatchStart=function(t,e){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){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,d.isArray)(t)&&(0,d.isFunction)(t[t.length-1])}function o(t){return t[t.length-1]}function u(t){return t.slice(0,t.length-1)}function a(t,e){e||(e=f["default"].Set());var n=f["default"].Set().withMutations(function(e){if(!i(t))throw new Error("getFlattenedDeps must be passed a Getter");u(t).forEach(function(t){if((0,p.isKeyPath)(t))e.add((0,l.List)(t));else{if(!i(t))throw new Error("Invalid getter, each dependency must be a KeyPath or Getter");e.union(a(t))}})});return e.union(n)}function s(t){if(!(0,p.isKeyPath)(t))throw new Error("Cannot create Getter from KeyPath: "+t);return[t,h]}function c(t){if(t.hasOwnProperty("__storeDeps"))return t.__storeDeps;var e=a(t).map(function(t){return t.first()}).filter(function(t){return!!t});return Object.defineProperty(t,"__storeDeps",{enumerable:!1,configurable:!1,writable:!1,value:e}),e}Object.defineProperty(e,"__esModule",{value:!0});var l=n(3),f=r(l),d=n(4),p=n(11),h=function(t){return t};e["default"]={isGetter:i,getComputeFn:o,getFlattenedDeps:a,getStoreDeps:c,getDeps:u,fromKeyPath:s},t.exports=e["default"]},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,s.isArray)(t)&&!(0,s.isFunction)(t[t.length-1])}function o(t,e){var n=a["default"].List(t),r=a["default"].List(e);return a["default"].is(n,r)}Object.defineProperty(e,"__esModule",{value:!0}),e.isKeyPath=i,e.isEqual=o;var u=n(3),a=r(u),s=n(4)},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),o=r(i),u=o["default"].Record({dispatchId:0,state:o["default"].Map(),stores:o["default"].Map(),cache:o["default"].Map(),storeStates:o["default"].Map(),dirtyStores:o["default"].Set(),debug:!1}),a=o["default"].Record({any:o["default"].Set([]),stores:o["default"].Map({}),observersMap:o["default"].Map({}),nextId:1});e["default"]={ReactorState:u,ObserverState:a},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(125),u=r(o);e["default"]=(0,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(134),o=r(i);e.callApi=o["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(82),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){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(150),u=i(o),a=n(151),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||(0,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(176),l=r(c),f=n(175),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(5),o=r(i);e["default"]=(0,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"]=(0,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(177),u=i(o),a=n(58),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"]=(0,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(137),a=i(u),s=n(138),c=i(s),l=n(139),f=i(l),d=n(135),p=r(d),h=n(136),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;n4?"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(126),a=r(u);n(39),n(124),n(123),n(119),n(122),n(120),n(121),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=(0,a["default"])(t);if(e&&(0,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){return t&&t.__esModule?t:{"default":t}}function i(t,e){switch(t){case"alarm_control_panel":return e&&"disarmed"===e?"mdi:bell-outline":"mdi:bell";case"binary_sensor":return e&&"off"===e?"mdi:radiobox-blank":"mdi:checkbox-marked-circle";case"camera":return"mdi:video";case"configurator":return"mdi:settings";case"conversation":return"mdi:text-to-speech";case"device_tracker":return"mdi:account";case"group":return"mdi:google-circles-communities";case"homeassistant":return"mdi:home";case"light":return"mdi:lightbulb";case"lock":return e&&"unlocked"===e?"mdi:lock-open":"mdi:lock";case"media_player":var n="mdi:cast";return e&&"off"!==e&&"idle"!==e&&(n+="-connected"),n;case"notify":return"mdi:comment-alert";case"updater":return"mdi:cloud-upload";case"rollershutter":return e&&"open"===e?"mdi:window-open":"mdi:window-closed";case"scene":return"mdi:google-pages";case"script":return"mdi:file-document";case"sensor":return"mdi:eye";case"simple_alarm":return"mdi:bell";case"sun":return"mdi:white-balance-sunny";case"switch":return"mdi:flash";case"thermostat":return"mdi:nest-thermostat";default:return console.warn("Unable to find icon for domain "+t+" ("+e+")"),u["default"]}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(40),u=r(o);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"]=(0,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(142),a=i(u),s=n(143),c=i(s),l=n(140),f=r(l),d=n(141),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(154),u=i(o),a=n(155),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"]=(0,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(172),a=i(u),s=n(170),c=r(s),l=n(171),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(184),a=i(u),s=n(180),c=r(s),l=n(181),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"]=(0,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(186),a=i(u),s=n(187),c=i(s),l=n(185),f=r(l),d=n(61),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){(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=S(i.slice(0,e).join("-")))return r;if(n&&n.length>=e&&m(i,n,!0)>=e-1)break;e--}o++}return null}function S(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}(),w(n)}catch(r){}return Hn[e]}function w(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),w(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=S(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 I(t){return"string"==typeof t?Yn[t]||Yn[t.toLowerCase()]:void 0}function j(t){var e,n,r={};for(n in t)u(t,n)&&(e=I(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=I(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 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"),St(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 St(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]=wt(t._locale,t._a[lr],t._meridiem),bt(t),Q(t)}function wt(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=j(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(It(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function It(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)),v(e)?new h(Q(e)):(r(n)?Mt(t):n?St(t):i(e)?t._d=e:jt(t),t))}function jt(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 Rt(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 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=It(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=Ir.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=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=I("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=I("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){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 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(wn(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=_(Sn(u)),a+=i,u-=bn(wn(i)),r=_(a/12),a%=12,s.days=u,s.months=a,s.years=r,this}function Sn(t){return 4800*t/146097}function wn(t){return 146097*t/4800}function Mn(t){var e,n,r=this._milliseconds;if(t=I(t),"month"===t||"year"===t)return e=this._days+r/864e5,n=this._months+Sn(e),"month"===t?n:n/12;switch(e=this._days+Math.round(wn(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 In(t){return t=I(t),this[t+"s"]()}function jn(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 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=_(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;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("_"),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":""))}),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 Sr={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 wr=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 Tr=/([\+\-]|\d\d)/gi;e.updateOffset=function(){};var Er=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ir=/^(-)?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 jr=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 Rr=P("Minutes",!1);x("s",["ss",2],0,"second"),E("second","s"),Y("s",$n),Y("ss",$n,qn),U(["s","ss"],dr);var zr=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=jr,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=Ie,Gr.lang=Dr,Gr.locale=me,Gr.localeData=ge,Gr.max=Mr,Gr.min=wr,Gr.parsingFlags=je,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=we,Gr.valueOf=Se,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=vt,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=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=Sr,Jr.firstDayOfYear=pt,Jr.firstDayOfWeek=dt,Jr.weekdays=ze,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,w("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.",w),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=jn("milliseconds"),ui=jn("seconds"),ai=jn("minutes"),si=jn("hours"),ci=jn("days"),li=jn("months"),fi=jn("years"),di=Math.round,pi={s:45,m:45,h:22,d:26,M:11},hi=Math.abs,vi=xt.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=Tn,vi._bubble=On,vi.get=In,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=kn,vi.toISOString=xn,vi.toString=xn,vi.toJSON=xn,vi.locale=me,vi.localeData=ge,vi.toIsoString=et("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",xn),vi.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=w,e.invalid=d,e.duration=Zt,e.isMoment=v,e.weekdays=pn,e.parseZone=Qe,e.localeData=T,e.isDuration=Lt,e.monthsShort=dn,e.weekdaysMin=vn,e.defineLocale=M,e.weekdaysShort=hn,e.normalizeUnits=I,e.relativeTimeThreshold=An;var _i=e;return _i})}).call(e,n(73)(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(1),o=r(i),u=n(22),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(0,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(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,n=this._checkToggle(this.stateObj);e&&!n?this._call_service(!0):!e&&n&&this._call_service(!1)},stateObjChanged:function(t){t&&this.updateToggle(t)},updateToggle:function(t){this.toggleChecked=this._checkToggle(t)},forceStateChange:function(){var t=this._checkToggle(this.stateObj);this.toggleChecked===t&&(this.toggleChecked=!this.toggleChecked),this.toggleChecked=t},_checkToggle:function(t){return t&&"off"!==t.state&&"unlocked"!==t.state},_call_service:function(t){var e=this,n=void 0,r=void 0;"lock"===this.stateObj.domain?(n="lock",r=t?"lock":"unlock"):(n="homeassistant",r=t?"turn_on":"turn_off"),i.serviceActions.callService(n,r,{entity_id:this.stateObj.entityId}).then(function(){return e.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:{header:{type:String},elevation:{type:Number,value:1,reflectToAttribute:!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(33),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?(0,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(18),n(92),n(91),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(7),e["default"]=new o["default"]({is:"state-card-display",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e["default"]="bookmark",t.exports=e["default"]},function(t,e,n){ +"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,u["default"])(t).format("LT")}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(33),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,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||!S),b===!1)var n=S&&!y;else{p||S||(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 S=!0;O=!1}else i(n)&&(S=!!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(47),o=n(130),u="Expected a function",a=Math.max;t.exports=r},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(133);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(47),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)||(0,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(145),a=i(u),s=n(146),c=i(s),l=n(147),f=i(l),d=n(148),p=i(d),h=n(149),v=i(h),_=n(144),y=r(_),m=n(48),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(173),a=n(193),s=i(a),c=n(195),l=i(c),f=n(197),d=i(f),p=n(15),h=r(p),v=n(24),_=r(v),y=n(9),m=r(y),g=n(49),b=r(g),O=n(153),S=r(O),w=n(25),M=r(w),T=n(158),E=r(T),I=n(52),j=r(I),P=n(55),D=r(P),C=n(27),A=r(C),k=n(13),x=r(k),L=n(28),N=r(L),R=n(30),z=r(R),H=n(190),Y=r(H),G=n(10),F=r(G),U=function B(){o(this,B);var t=(0,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:D.urlSync.startSync.bind(null,t)},stopUrlSync:{value:D.urlSync.stopSync.bind(null,t)}}),(0,l["default"])(this,t,{auth:h,config:_,entity:m,entityHistory:b,errorLog:S,event:M,logbook:E,moreInfo:j,navigation:D,notification:A,service:x,stream:N,sync:z,voice:Y,restApi:F})};e["default"]=U,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(65),i=r("length");t.exports=i},function(t,e,n){"use strict";function r(t){return null!=t&&o(i(t))}var i=n(66),o=n(70);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(67),o=n(68),u=n(71);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?(0,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(17),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(127),a=r(u);e["default"]=new o["default"]({is:"ha-state-icon",properties:{stateObj:{type:Object}},computeIcon:function(t){return(0,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(1),o=r(i),u=n(2),a=n(22),s=r(a),c=n(21),l=r(c);n(17),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(),(0,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"binary_sensor":case"script":return"on"===t.state?"blue":"grey";case"updater":return"blue";default:return""}},computeValue:function(t){switch(t.domain){case"binary_sensor":case"device_tracker":case"updater":case"sun":case"scene":case"script":case"alarm_control_panel":return;case"sensor":return t.state;default:return t.state}},computeIcon:function(t){switch(t.domain){case"alarm_control_panel":return"pending"===t.state?"mdi:clock-fast":"armed_away"===t.state?"mdi:nature":"armed_home"===t.state?"mdi:home-variant":(0,s["default"])(t.domain,t.state);case"binary_sensor":case"device_tracker":case"scene":case"updater":case"script":return(0,s["default"])(t.domain,t.state);case"sun":return"above_horizon"===t.state?(0,s["default"])(t.domain):"mdi:brightness-3";default:return}},computeImage:function(t){return t.attributes.entity_picture},computeLabel:function(t){switch(t.domain){case"scene":case"script":return t.domain;case"device_tracker":return"not_home"===t.state?"Away":t.state;case"alarm_control_panel":return"pending"===t.state?"pend":"armed_away"===t.state||"armed_home"===t.state?"armed":"disarm";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);n(80),e["default"]=new o["default"]({is:"state-badge",properties:{stateObj:{type:Object,observer:"updateIconColor"}},updateIconColor:function(t){"light"===t.domain&&"on"===t.state&&t.attributes.rgb_color&&t.attributes.rgb_color.reduce(function(t,e){return t+e},0)<730?this.$.icon.style.color="rgb("+t.attributes.rgb_color.join(",")+")":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"},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)},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(17),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(89),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(93),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 e in t&&t[e].groupEntity},computeStatesOfCard:function(t,e){return e in t&&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(34),n(77),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(34),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(72),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]],(0,u["default"])(1,t.getNumberOfColumns()),(0,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);e["default"]=new u["default"]({is:"ha-voice-command-dialog",behaviors:[s["default"]],properties:{dialogOpen:{type:Boolean,value:!1,observer:"dialogOpenChanged"},finalTranscript:{type:String,bindNuclear:i.voiceGetters.finalTranscript},interimTranscript:{type:String,bindNuclear:i.voiceGetters.extraInterimTranscript},isTransmitting:{type:Boolean,bindNuclear:i.voiceGetters.isTransmitting +},isListening:{type:Boolean,bindNuclear:i.voiceGetters.isListening},showListenInterface:{type:Boolean,computed:"computeShowListenInterface(isListening, isTransmitting)",observer:"showListenInterfaceChanged"},_boundOnBackdropTap:{type:Function,value:function(){return this._onBackdropTap.bind(this)}}},computeShowListenInterface:function(t,e){return t||e},dialogOpenChanged:function(t){t?this.$.dialog.backdropElement.addEventListener("click",this._boundOnBackdropTap):!t&&this.isListening&&i.voiceActions.stop()},showListenInterfaceChanged:function(t){!t&&this.dialogOpen?this.dialogOpen=!1:t&&(this.dialogOpen=!0)},_onBackdropTap:function(){this.$.dialog.backdropElement.removeEventListener("click",this._boundOnBackdropTap),this.isListening&&i.voiceActions.stop()}}),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),n(38),n(110);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(87),n(105),n(103),n(102),n(104),n(98),n(99),n(101),n(100),n(106),n(95),n(94),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")},isSelectedDevInfo:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("devInfo")},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(){(0,u.startUrlSync)()},computeForceNarrow:function(t,e){return t||!e},detached:function(){(0,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:{errorMessage:{type:String,bindNuclear:u.authGetters.attemptErrorMessage},isInvalid:{type:Boolean,bindNuclear:u.authGetters.isInvalidAttempt},isValidating:{type:Boolean,observer:"isValidatingChanged",bindNuclear:u.authGetters.isValidating},loadingResources:{type:Boolean,value:!1},forceShowLoading:{type:Boolean,value:!1},showLoading:{type:Boolean,computed:"computeShowSpinner(forceShowLoading, isValidating)"}},listeners:{keydown:"passwordKeyDown","loginButton.click":"validatePassword"},observers:["validatingChanged(isValidating, isInvalid)"],computeShowSpinner:function(t,e){return t||e},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(),(0,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(8),n(90),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(8),n(83),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),a=n(4),s=r(a);n(8),e["default"]=new u["default"]({is:"partial-dev-info",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},hassVersion:{type:String,bindNuclear:i.configGetters.serverVersion},polymerVersion:{type:String,value:u["default"].version},nuclearVersion:{type:String,value:"1.2.1"},errorLog:{type:String,value:""}},attached:function(){this.refreshErrorLog()},refreshErrorLog:function(t){var e=this;t&&t.preventDefault(),this.errorLog="Loading error log…",i.errorLogActions.fetchErrorLog().then(function(t){return e.errorLog=t||"No errors have been reported."})}}),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(8),n(78),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(8),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(8),n(86),n(18),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(79),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(8),n(88),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}]},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(300+300*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(){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()},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(18),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(128),a=r(u);n(111),n(112),n(116),n(109),n(117),n(115),n(113),n(114),n(108),n(118),n(107),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=(0,a["default"])(t);if(e&&(0,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","icon","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(19),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(20),s=r(a);n(84);var c=["brightness","rgb_color","color_temp"];e["default"]=new u["default"]({is:"more-info-light",properties:{stateObj:{type:Object,observer:"stateObjChanged"},brightnessSliderValue:{type:Number,value:0},ctSliderValue:{type:Number,value:0}},stateObjChanged:function(t){var e=this;t&&"on"===t.state&&(this.brightnessSliderValue=t.attributes.brightness,this.ctSliderValue=t.attributes.color_temp),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return(0,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}))},ctSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,color_temp: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(20),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(0,s["default"])(t,c)},computeIsOff:function(t){return"off"===t.state},computeMuteVolumeIcon:function(t){return t?"mdi:volume-off":"mdi:volume-high"},computePlaybackControlIcon:function(){return this.isPlaying?this.supportsPause?"mdi:pause":"mdi:stop":"mdi:play"},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(0,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(20),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(0,s["default"])(t,c)},targetTemperatureSliderChanged:function(t){i.serviceActions.callService("thermostat","set_temperature",{entity_id:this.stateObj.entityId,temperature:t.target.value})},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);e["default"]=new o["default"]({is:"more-info-updater",properties:{}}),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(7),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(7);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(2),o=n(1),u=r(o);n(7),e["default"]=new u["default"]({is:"state-card-rollershutter",properties:{stateObj:{type:Object}},computeIsFullyOpen:function(t){return 100===t.attributes.current_position},computeIsFullyClosed:function(t){return 0===t.attributes.current_position},onMoveUpTap:function(){i.serviceActions.callService("rollershutter","move_up",{entity_id:this.stateObj.entityId})},onMoveDownTap:function(){i.serviceActions.callService("rollershutter","move_down",{entity_id:this.stateObj.entityId})},onStopTap:function(){i.serviceActions.callService("rollershutter","stop",{entity_id: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),u=n(2);n(7),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(7),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(7),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:(0,u["default"])(t.entityId)?"toggle":"display"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(21),u=r(o),a=["thermostat","configurator","scene","media_player","rollershutter"];t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){if(!t)return u["default"];if(t.attributes.icon)return t.attributes.icon;var e=t.attributes.unit_of_measurement;return!e||"sensor"!==t.domain||e!==c.util.temperatureUnits.UNIT_TEMP_C&&e!==c.util.temperatureUnits.UNIT_TEMP_F?(0,s["default"])(t.domain,t.state):"mdi:thermometer"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(40),u=r(o),a=n(22),s=r(a),c=n(2);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,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(202);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 S(t,e,n,r){try{t.call(e,n,r)}catch(i){return i}}function w(t,e,n){Z(function(t){var r=!1,i=S(n,e,function(n){r||(r=!0,e!==n?E(t,n):j(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?j(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?j(t,e):a(n)?w(t,e,n):j(t,e)}}function E(t,e){t===e?P(t,g()):u(e)?T(t,e):j(t,e)}function I(t){t._onerror&&t._onerror(t._result),C(t)}function j(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(I,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=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&&j(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(){x(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(201).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(199),function(){return this}(),n(198)(t))},function(t,e,n){"use strict";var r=n(44),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(44),i=n(131),o=n(45),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(46),o=n(45),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(129),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(){var e=void 0;try{e="application/json"===r.getResponseHeader("content-type")?JSON.parse(r.responseText):r.responseText}catch(i){e=r.responseText}r.status>199&&r.status<300?t(e):n(e)},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(c.getters.isSupported):r,o=n.rememberAuth,u=void 0===o?!1:o,s=n.host,d=void 0===s?"":s;t.dispatch(a["default"].VALIDATING_AUTH_TOKEN,{authToken:e,host:d}),l.actions.fetchAll(t).then(function(){t.dispatch(a["default"].VALID_AUTH_TOKEN,{authToken:e,host:d,rememberAuth:u}),i?c.actions.start(t,{syncOnInitialConnect:!1}):l.actions.start(t,{skipInitialSync:!0})},function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=e.message,r=void 0===n?f:n;t.dispatch(a["default"].INVALID_AUTH_TOKEN,{errorMessage:r})})}function o(t){(0,s.callApi)(t,"POST","log_out"),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(6),c=n(28),l=n(30),f="Unexpected result from API"},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=["authAttempt","isValidating"];e.isValidating=n;var r=["authAttempt","isInvalid"];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(0,d.toImmutable)({authToken:n,host:r,isValidating:!0,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",!0).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)||(0,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(160),a=i(u),s=n(161),c=i(s),l=n(162),f=i(l),d=n(163),p=i(d),h=n(156),v=r(h),_=n(157),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 2e8ad266eeb..41dbd6abc34 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 2e8ad266eeb8cd0136df498b995f584e01338000 +Subproject commit 41dbd6abc34473113ba9c9380d9d5e10dff3d623 From b2ae3655587c5c28d73eaba41cf59e94c7708a7b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 11:03:31 -0800 Subject: [PATCH 163/166] Scripts call services in blocking manner --- homeassistant/components/script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/script.py b/homeassistant/components/script.py index bf7c51fe3fb..3e13db66699 100644 --- a/homeassistant/components/script.py +++ b/homeassistant/components/script.py @@ -201,7 +201,7 @@ class Script(ToggleEntity): self._last_action) domain, service = split_entity_id(conf_service) data = action.get(CONF_SERVICE_DATA, {}) - self.hass.services.call(domain, service, data) + self.hass.services.call(domain, service, data, True) def _fire_event(self, action): """ Fires an event. """ From d9b8ab88514480ba5a6971f9cbf2b391aaf14391 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 11:34:53 -0800 Subject: [PATCH 164/166] Update frontend --- homeassistant/components/frontend/version.py | 2 +- .../components/frontend/www_static/frontend.html | 8 ++++---- .../components/frontend/www_static/home-assistant-polymer | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index bbc0264f751..042d3e31b11 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 = "6f4dc002423ec8acfb1c4063e708a8b1" +VERSION = "8470cd10f28b20eae9022fa4c8f40c1b" diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index bbf0d00bc7c..c67acda405e 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -6085,7 +6085,7 @@ return t._iter.toSeq().reverse()}),e},st.prototype.map=function(t,e){var n=this, }catch(n){throw this.__isDispatching=!1,n}try{this.__notify()}finally{this.__isDispatching=!1}}},{key:"batch",value:function(t){this.batchStart(),t(),this.batchEnd()}},{key:"registerStore",value:function(t,e){console.warn("Deprecation warning: `registerStore` will no longer be supported in 1.1, use `registerStores` instead"),this.registerStores(i({},t,e))}},{key:"registerStores",value:function(t){this.reactorState=d["default"].registerStores(this.reactorState,t),this.__notify()}},{key:"serialize",value:function(){return d["default"].serialize(this.reactorState)}},{key:"loadState",value:function(t){this.reactorState=d["default"].loadState(this.reactorState,t),this.__notify()}},{key:"reset",value:function(){var t=d["default"].reset(this.reactorState);this.reactorState=t,this.prevReactorState=t,this.observerState=new y.ObserverState}},{key:"__notify",value:function(){var t=this;if(!(this.__batchDepth>0)){var e=this.reactorState.get("dirtyStores");if(0!==e.size){var n=s["default"].Set().withMutations(function(n){n.union(t.observerState.get("any")),e.forEach(function(e){var r=t.observerState.getIn(["stores",e]);r&&n.union(r)})});n.forEach(function(e){var n=t.observerState.getIn(["observersMap",e]);if(n){var r=n.get("getter"),i=n.get("handler"),o=d["default"].evaluate(t.prevReactorState,r),u=d["default"].evaluate(t.reactorState,r);t.prevReactorState=o.reactorState,t.reactorState=u.reactorState;var a=o.result,c=u.result;s["default"].is(a,c)||i.call(null,c)}});var r=d["default"].resetDirtyStores(this.reactorState);this.prevReactorState=r,this.reactorState=r}}}},{key:"batchStart",value:function(){this.__batchDepth++}},{key:"batchEnd",value:function(){if(this.__batchDepth--,this.__batchDepth<=0){this.__isDispatching=!0;try{this.__notify()}catch(t){throw this.__isDispatching=!1,t}this.__isDispatching=!1}}}]),t}();e["default"]=(0,_.toFactory)(m),t.exports=e["default"]},function(t,e,n){function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n={};return(0,o.each)(e,function(e,r){n[r]=t.evaluate(e)}),n}Object.defineProperty(e,"__esModule",{value:!0});var o=n(4);e["default"]=function(t){return{getInitialState:function(){return i(t,this.getDataBindings())},componentDidMount:function(){var e=this;this.__unwatchFns=[],(0,o.each)(this.getDataBindings(),function(n,i){var o=t.observe(n,function(t){e.setState(r({},i,t))});e.__unwatchFns.push(o)})},componentWillUnmount:function(){for(;this.__unwatchFns.length;)this.__unwatchFns.shift()()}}},t.exports=e["default"]},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}function i(t,e){return new b({result:t,reactorState:e})}function o(t){return t}function u(t,e){var n=o(e);return t.getIn(["cache",n])}function a(t,e){var n=u(t,e);if(!n)return!1;var r=n.get("storeStates");return 0===r.size?!1:r.every(function(e,n){return t.getIn(["storeStates",n])===e})}function s(t,e,n){var r=o(e),i=t.get("dispatchId"),u=(0,y.getStoreDeps)(e),a=(0,_.toImmutable)({}).withMutations(function(e){u.forEach(function(n){var r=t.getIn(["storeStates",n]);e.set(n,r)})});return t.setIn(["cache",r],p["default"].Map({value:n,storeStates:a,dispatchId:i}))}function c(t,e){var n=o(e);return t.getIn(["cache",n,"value"])}function l(t){return t.update("dispatchId",function(t){return t+1})}function f(t,e){return t.withMutations(function(t){e.forEach(function(e){var n=t.has(e)?t.get(e)+1:1;t.set(e,n)})})}var d=n(3),p=r(d),h=n(9),v=r(h),_=n(5),y=n(10),m=n(11),g=n(4),b=p["default"].Record({result:null,reactorState:null});e.registerStores=function(t,e){var n=t.get("debug");return t.withMutations(function(t){(0,g.each)(e,function(e,r){t.getIn(["stores",r])&&console.warn("Store already defined for id = "+r);var i=e.getInitialState();if(n&&!(0,_.isImmutableValue)(i))throw new Error("Store getInitialState() must return an immutable value, did you forget to call toImmutable");t.update("stores",function(t){return t.set(r,e)}).update("state",function(t){return t.set(r,i)}).update("dirtyStores",function(t){return t.add(r)}).update("storeStates",function(t){return f(t,[r])})}),l(t)})},e.dispatch=function(t,e,n){var r=t.get("state"),i=t.get("debug"),o=t.get("dirtyStores"),u=r.withMutations(function(r){i&&v["default"].dispatchStart(e,n),t.get("stores").forEach(function(t,u){var a=r.get(u),s=void 0;try{s=t.handle(a,e,n)}catch(c){throw v["default"].dispatchError(c.message),c}if(i&&void 0===s){var l="Store handler must return a value, did you forget a return statement";throw v["default"].dispatchError(l),new Error(l)}r.set(u,s),a!==s&&(o=o.add(u)),i&&v["default"].storeHandled(u,a,s)}),i&&v["default"].dispatchEnd(r)}),a=t.set("state",u).set("dirtyStores",o).update("storeStates",function(t){return f(t,o)});return l(a)},e.loadState=function(t,e){var n=[],r=(0,_.toImmutable)({}).withMutations(function(r){(0,g.each)(e,function(e,i){var o=t.getIn(["stores",i]);if(o){var u=o.deserialize(e);void 0!==u&&(r.set(i,u),n.push(i))}})}),i=p["default"].Set(n);return t.update("state",function(t){return t.merge(r)}).update("dirtyStores",function(t){return t.union(i)}).update("storeStates",function(t){return f(t,n)})},e.addObserver=function(t,e,n){var r=e;(0,m.isKeyPath)(e)&&(e=(0,y.fromKeyPath)(e));var i=t.get("nextId"),o=(0,y.getStoreDeps)(e),u=p["default"].Map({id:i,storeDeps:o,getterKey:r,getter:e,handler:n}),a=void 0;return a=0===o.size?t.update("any",function(t){return t.add(i)}):t.withMutations(function(t){o.forEach(function(e){var n=["stores",e];t.hasIn(n)||t.setIn(n,p["default"].Set([])),t.updateIn(["stores",e],function(t){return t.add(i)})})}),a=a.set("nextId",i+1).setIn(["observersMap",i],u),{observerState:a,entry:u}},e.removeObserver=function(t,n,r){var i=t.get("observersMap").filter(function(t){var e=t.get("getterKey"),i=!r||t.get("handler")===r;return i?(0,m.isKeyPath)(n)&&(0,m.isKeyPath)(e)?(0,m.isEqual)(n,e):n===e:!1});return t.withMutations(function(t){i.forEach(function(n){return e.removeObserverByEntry(t,n)})})},e.removeObserverByEntry=function(t,e){return t.withMutations(function(t){var n=e.get("id"),r=e.get("storeDeps");0===r.size?t.update("any",function(t){return t.remove(n)}):r.forEach(function(e){t.updateIn(["stores",e],function(t){return t?t.remove(n):t})}),t.removeIn(["observersMap",n])})},e.reset=function(t){var n=t.get("debug"),r=t.get("state");return t.withMutations(function(t){var i=t.get("stores"),o=i.keySeq().toJS();i.forEach(function(e,i){var o=r.get(i),u=e.handleReset(o);if(n&&void 0===u)throw new Error("Store handleReset() must return a value, did you forget a return statement");if(n&&!(0,_.isImmutableValue)(u))throw new Error("Store reset state must be an immutable value, did you forget to call toImmutable");t.setIn(["state",i],u)}),t.update("storeStates",function(t){return f(t,o)}),e.resetDirtyStores(t)})},e.evaluate=function O(t,e){var n=t.get("state");if((0,m.isKeyPath)(e))return i(n.getIn(e),t);if(!(0,y.isGetter)(e))throw new Error("evaluate must be passed a keyPath or Getter");if(a(t,e))return i(c(t,e),t);var r=(0,y.getDeps)(e).map(function(e){return O(t,e).result}),o=(0,y.getComputeFn)(e).apply(null,r);return i(o,s(t,e,o))},e.serialize=function(t){var e={};return t.get("stores").forEach(function(n,r){var i=t.getIn(["state",r]),o=n.serialize(i);void 0!==o&&(e[r]=o)}),e},e.resetDirtyStores=function(t){return t.set("dirtyStores",p["default"].Set())}},function(t,e){e.dispatchStart=function(t,e){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){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,d.isArray)(t)&&(0,d.isFunction)(t[t.length-1])}function o(t){return t[t.length-1]}function u(t){return t.slice(0,t.length-1)}function a(t,e){e||(e=f["default"].Set());var n=f["default"].Set().withMutations(function(e){if(!i(t))throw new Error("getFlattenedDeps must be passed a Getter");u(t).forEach(function(t){if((0,p.isKeyPath)(t))e.add((0,l.List)(t));else{if(!i(t))throw new Error("Invalid getter, each dependency must be a KeyPath or Getter");e.union(a(t))}})});return e.union(n)}function s(t){if(!(0,p.isKeyPath)(t))throw new Error("Cannot create Getter from KeyPath: "+t);return[t,h]}function c(t){if(t.hasOwnProperty("__storeDeps"))return t.__storeDeps;var e=a(t).map(function(t){return t.first()}).filter(function(t){return!!t});return Object.defineProperty(t,"__storeDeps",{enumerable:!1,configurable:!1,writable:!1,value:e}),e}Object.defineProperty(e,"__esModule",{value:!0});var l=n(3),f=r(l),d=n(4),p=n(11),h=function(t){return t};e["default"]={isGetter:i,getComputeFn:o,getFlattenedDeps:a,getStoreDeps:c,getDeps:u,fromKeyPath:s},t.exports=e["default"]},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,s.isArray)(t)&&!(0,s.isFunction)(t[t.length-1])}function o(t,e){var n=a["default"].List(t),r=a["default"].List(e);return a["default"].is(n,r)}Object.defineProperty(e,"__esModule",{value:!0}),e.isKeyPath=i,e.isEqual=o;var u=n(3),a=r(u),s=n(4)},function(t,e,n){function r(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=n(3),o=r(i),u=o["default"].Record({dispatchId:0,state:o["default"].Map(),stores:o["default"].Map(),cache:o["default"].Map(),storeStates:o["default"].Map(),dirtyStores:o["default"].Set(),debug:!1}),a=o["default"].Record({any:o["default"].Set([]),stores:o["default"].Map({}),observersMap:o["default"].Map({}),nextId:1});e["default"]={ReactorState:u,ObserverState:a},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(125),u=r(o);e["default"]=(0,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(134),o=r(i);e.callApi=o["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(82),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){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(150),u=i(o),a=n(151),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||(0,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(176),l=r(c),f=n(175),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(5),o=r(i);e["default"]=(0,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"]=(0,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(177),u=i(o),a=n(58),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"]=(0,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(137),a=i(u),s=n(138),c=i(s),l=n(139),f=i(l),d=n(135),p=r(d),h=n(136),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;n4?"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(126),a=r(u);n(39),n(124),n(123),n(119),n(122),n(120),n(121),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=(0,a["default"])(t);if(e&&(0,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){return t&&t.__esModule?t:{"default":t}}function i(t,e){switch(t){case"alarm_control_panel":return e&&"disarmed"===e?"mdi:bell-outline":"mdi:bell";case"binary_sensor":return e&&"off"===e?"mdi:radiobox-blank":"mdi:checkbox-marked-circle";case"camera":return"mdi:video";case"configurator":return"mdi:settings";case"conversation":return"mdi:text-to-speech";case"device_tracker":return"mdi:account";case"group":return"mdi:google-circles-communities";case"homeassistant":return"mdi:home";case"light":return"mdi:lightbulb";case"lock":return e&&"unlocked"===e?"mdi:lock-open":"mdi:lock";case"media_player":var n="mdi:cast";return e&&"off"!==e&&"idle"!==e&&(n+="-connected"),n;case"notify":return"mdi:comment-alert";case"updater":return"mdi:cloud-upload";case"rollershutter":return e&&"open"===e?"mdi:window-open":"mdi:window-closed";case"scene":return"mdi:google-pages";case"script":return"mdi:file-document";case"sensor":return"mdi:eye";case"simple_alarm":return"mdi:bell";case"sun":return"mdi:white-balance-sunny";case"switch":return"mdi:flash";case"thermostat":return"mdi:nest-thermostat";default:return console.warn("Unable to find icon for domain "+t+" ("+e+")"),u["default"]}}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(40),u=r(o);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"]=(0,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(142),a=i(u),s=n(143),c=i(s),l=n(140),f=r(l),d=n(141),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(154),u=i(o),a=n(155),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"]=(0,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(172),a=i(u),s=n(170),c=r(s),l=n(171),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(184),a=i(u),s=n(180),c=r(s),l=n(181),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"]=(0,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(186),a=i(u),s=n(187),c=i(s),l=n(185),f=r(l),d=n(61),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){(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=S(i.slice(0,e).join("-")))return r;if(n&&n.length>=e&&m(i,n,!0)>=e-1)break;e--}o++}return null}function S(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}(),w(n)}catch(r){}return Hn[e]}function w(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),w(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=S(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 I(t){return"string"==typeof t?Yn[t]||Yn[t.toLowerCase()]:void 0}function j(t){var e,n,r={};for(n in t)u(t,n)&&(e=I(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=I(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 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"),St(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 St(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]=wt(t._locale,t._a[lr],t._meridiem),bt(t),Q(t)}function wt(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=j(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(It(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function It(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)),v(e)?new h(Q(e)):(r(n)?Mt(t):n?St(t):i(e)?t._d=e:jt(t),t))}function jt(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 Rt(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 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=It(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=Ir.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=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=I("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=I("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){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 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(wn(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=_(Sn(u)),a+=i,u-=bn(wn(i)),r=_(a/12),a%=12,s.days=u,s.months=a,s.years=r,this}function Sn(t){return 4800*t/146097}function wn(t){return 146097*t/4800}function Mn(t){var e,n,r=this._milliseconds;if(t=I(t),"month"===t||"year"===t)return e=this._days+r/864e5,n=this._months+Sn(e),"month"===t?n:n/12;switch(e=this._days+Math.round(wn(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 In(t){return t=I(t),this[t+"s"]()}function jn(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 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=_(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;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("_"),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":""))}),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 Sr={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 wr=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 Tr=/([\+\-]|\d\d)/gi;e.updateOffset=function(){};var Er=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ir=/^(-)?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 jr=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 Rr=P("Minutes",!1);x("s",["ss",2],0,"second"),E("second","s"),Y("s",$n),Y("ss",$n,qn),U(["s","ss"],dr);var zr=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=jr,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=Ie,Gr.lang=Dr,Gr.locale=me,Gr.localeData=ge,Gr.max=Mr,Gr.min=wr,Gr.parsingFlags=je,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=we,Gr.valueOf=Se,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=vt,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=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=Sr,Jr.firstDayOfYear=pt,Jr.firstDayOfWeek=dt,Jr.weekdays=ze,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,w("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.",w),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=jn("milliseconds"),ui=jn("seconds"),ai=jn("minutes"),si=jn("hours"),ci=jn("days"),li=jn("months"),fi=jn("years"),di=Math.round,pi={s:45,m:45,h:22,d:26,M:11},hi=Math.abs,vi=xt.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=Tn,vi._bubble=On,vi.get=In,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=kn,vi.toISOString=xn,vi.toString=xn,vi.toJSON=xn,vi.locale=me,vi.localeData=ge,vi.toIsoString=et("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",xn),vi.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=w,e.invalid=d,e.duration=Zt,e.isMoment=v,e.weekdays=pn,e.parseZone=Qe,e.localeData=T,e.isDuration=Lt,e.monthsShort=dn,e.weekdaysMin=vn,e.defineLocale=M,e.weekdaysShort=hn,e.normalizeUnits=I,e.relativeTimeThreshold=An;var _i=e;return _i})}).call(e,n(73)(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(1),o=r(i),u=n(22),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(0,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(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,n=this._checkToggle(this.stateObj);e&&!n?this._call_service(!0):!e&&n&&this._call_service(!1)},stateObjChanged:function(t){t&&this.updateToggle(t)},updateToggle:function(t){this.toggleChecked=this._checkToggle(t)},forceStateChange:function(){var t=this._checkToggle(this.stateObj);this.toggleChecked===t&&(this.toggleChecked=!this.toggleChecked),this.toggleChecked=t},_checkToggle:function(t){return t&&"off"!==t.state&&"unlocked"!==t.state},_call_service:function(t){var e=this,n=void 0,r=void 0;"lock"===this.stateObj.domain?(n="lock",r=t?"lock":"unlock"):(n="homeassistant",r=t?"turn_on":"turn_off"),i.serviceActions.callService(n,r,{entity_id:this.stateObj.entityId}).then(function(){return e.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:{header:{type:String},elevation:{type:Number,value:1,reflectToAttribute:!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(33),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?(0,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(18),n(92),n(91),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(7),e["default"]=new o["default"]({is:"state-card-display",properties:{stateObj:{type:Object}}}),t.exports=e["default"]},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e["default"]="bookmark",t.exports=e["default"]},function(t,e,n){ "use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){return(0,u["default"])(t).format("LT")}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(33),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,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||!S),b===!1)var n=S&&!y;else{p||S||(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 S=!0;O=!1}else i(n)&&(S=!!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(47),o=n(130),u="Expected a function",a=Math.max;t.exports=r},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(133);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(47),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)||(0,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(145),a=i(u),s=n(146),c=i(s),l=n(147),f=i(l),d=n(148),p=i(d),h=n(149),v=i(h),_=n(144),y=r(_),m=n(48),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(173),a=n(193),s=i(a),c=n(195),l=i(c),f=n(197),d=i(f),p=n(15),h=r(p),v=n(24),_=r(v),y=n(9),m=r(y),g=n(49),b=r(g),O=n(153),S=r(O),w=n(25),M=r(w),T=n(158),E=r(T),I=n(52),j=r(I),P=n(55),D=r(P),C=n(27),A=r(C),k=n(13),x=r(k),L=n(28),N=r(L),R=n(30),z=r(R),H=n(190),Y=r(H),G=n(10),F=r(G),U=function B(){o(this,B);var t=(0,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:D.urlSync.startSync.bind(null,t)},stopUrlSync:{value:D.urlSync.stopSync.bind(null,t)}}),(0,l["default"])(this,t,{auth:h,config:_,entity:m,entityHistory:b,errorLog:S,event:M,logbook:E,moreInfo:j,navigation:D,notification:A,service:x,stream:N,sync:z,voice:Y,restApi:F})};e["default"]=U,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(65),i=r("length");t.exports=i},function(t,e,n){"use strict";function r(t){return null!=t&&o(i(t))}var i=n(66),o=n(70);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(67),o=n(68),u=n(71);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?(0,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(17),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(127),a=r(u);e["default"]=new o["default"]({is:"ha-state-icon",properties:{stateObj:{type:Object}},computeIcon:function(t){return(0,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(1),o=r(i),u=n(2),a=n(22),s=r(a),c=n(21),l=r(c);n(17),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(),(0,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"binary_sensor":case"script":return"on"===t.state?"blue":"grey";case"updater":return"blue";default:return""}},computeValue:function(t){switch(t.domain){case"binary_sensor":case"device_tracker":case"updater":case"sun":case"scene":case"script":case"alarm_control_panel":return;case"sensor":return t.state;default:return t.state}},computeIcon:function(t){switch(t.domain){case"alarm_control_panel":return"pending"===t.state?"mdi:clock-fast":"armed_away"===t.state?"mdi:nature":"armed_home"===t.state?"mdi:home-variant":(0,s["default"])(t.domain,t.state);case"binary_sensor":case"device_tracker":case"scene":case"updater":case"script":return(0,s["default"])(t.domain,t.state);case"sun":return"above_horizon"===t.state?(0,s["default"])(t.domain):"mdi:brightness-3";default:return}},computeImage:function(t){return t.attributes.entity_picture},computeLabel:function(t){switch(t.domain){case"scene":case"script":return t.domain;case"device_tracker":return"not_home"===t.state?"Away":t.state;case"alarm_control_panel":return"pending"===t.state?"pend":"armed_away"===t.state||"armed_home"===t.state?"armed":"disarm";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);n(80),e["default"]=new o["default"]({is:"state-badge",properties:{stateObj:{type:Object,observer:"updateIconColor"}},updateIconColor:function(t){"light"===t.domain&&"on"===t.state&&t.attributes.rgb_color&&t.attributes.rgb_color.reduce(function(t,e){return t+e},0)<730?this.$.icon.style.color="rgb("+t.attributes.rgb_color.join(",")+")":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"},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)},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(17),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(89),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(93),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 e in t&&t[e].groupEntity},computeStatesOfCard:function(t,e){return e in t&&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(34),n(77),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(34),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(72),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]],(0,u["default"])(1,t.getNumberOfColumns()),(0,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);e["default"]=new u["default"]({is:"ha-voice-command-dialog",behaviors:[s["default"]],properties:{dialogOpen:{type:Boolean,value:!1,observer:"dialogOpenChanged"},finalTranscript:{type:String,bindNuclear:i.voiceGetters.finalTranscript},interimTranscript:{type:String,bindNuclear:i.voiceGetters.extraInterimTranscript},isTransmitting:{type:Boolean,bindNuclear:i.voiceGetters.isTransmitting -},isListening:{type:Boolean,bindNuclear:i.voiceGetters.isListening},showListenInterface:{type:Boolean,computed:"computeShowListenInterface(isListening, isTransmitting)",observer:"showListenInterfaceChanged"},_boundOnBackdropTap:{type:Function,value:function(){return this._onBackdropTap.bind(this)}}},computeShowListenInterface:function(t,e){return t||e},dialogOpenChanged:function(t){t?this.$.dialog.backdropElement.addEventListener("click",this._boundOnBackdropTap):!t&&this.isListening&&i.voiceActions.stop()},showListenInterfaceChanged:function(t){!t&&this.dialogOpen?this.dialogOpen=!1:t&&(this.dialogOpen=!0)},_onBackdropTap:function(){this.$.dialog.backdropElement.removeEventListener("click",this._boundOnBackdropTap),this.isListening&&i.voiceActions.stop()}}),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),n(38),n(110);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(87),n(105),n(103),n(102),n(104),n(98),n(99),n(101),n(100),n(106),n(95),n(94),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")},isSelectedDevInfo:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("devInfo")},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(){(0,u.startUrlSync)()},computeForceNarrow:function(t,e){return t||!e},detached:function(){(0,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:{errorMessage:{type:String,bindNuclear:u.authGetters.attemptErrorMessage},isInvalid:{type:Boolean,bindNuclear:u.authGetters.isInvalidAttempt},isValidating:{type:Boolean,observer:"isValidatingChanged",bindNuclear:u.authGetters.isValidating},loadingResources:{type:Boolean,value:!1},forceShowLoading:{type:Boolean,value:!1},showLoading:{type:Boolean,computed:"computeShowSpinner(forceShowLoading, isValidating)"}},listeners:{keydown:"passwordKeyDown","loginButton.click":"validatePassword"},observers:["validatingChanged(isValidating, isInvalid)"],computeShowSpinner:function(t,e){return t||e},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(),(0,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(8),n(90),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(8),n(83),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),a=n(4),s=r(a);n(8),e["default"]=new u["default"]({is:"partial-dev-info",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},hassVersion:{type:String,bindNuclear:i.configGetters.serverVersion},polymerVersion:{type:String,value:u["default"].version},nuclearVersion:{type:String,value:"1.2.1"},errorLog:{type:String,value:""}},attached:function(){this.refreshErrorLog()},refreshErrorLog:function(t){var e=this;t&&t.preventDefault(),this.errorLog="Loading error log…",i.errorLogActions.fetchErrorLog().then(function(t){return e.errorLog=t||"No errors have been reported."})}}),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(8),n(78),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(8),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(8),n(86),n(18),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(79),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(8),n(88),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}]},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(300+300*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(){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()},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(18),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(128),a=r(u);n(111),n(112),n(116),n(109),n(117),n(115),n(113),n(114),n(108),n(118),n(107),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=(0,a["default"])(t);if(e&&(0,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","icon","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(19),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(20),s=r(a);n(84);var c=["brightness","rgb_color","color_temp"];e["default"]=new u["default"]({is:"more-info-light",properties:{stateObj:{type:Object,observer:"stateObjChanged"},brightnessSliderValue:{type:Number,value:0},ctSliderValue:{type:Number,value:0}},stateObjChanged:function(t){var e=this;t&&"on"===t.state&&(this.brightnessSliderValue=t.attributes.brightness,this.ctSliderValue=t.attributes.color_temp),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return(0,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}))},ctSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,color_temp: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(20),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(0,s["default"])(t,c)},computeIsOff:function(t){return"off"===t.state},computeMuteVolumeIcon:function(t){return t?"mdi:volume-off":"mdi:volume-high"},computePlaybackControlIcon:function(){return this.isPlaying?this.supportsPause?"mdi:pause":"mdi:stop":"mdi:play"},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(0,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(20),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(0,s["default"])(t,c)},targetTemperatureSliderChanged:function(t){i.serviceActions.callService("thermostat","set_temperature",{entity_id:this.stateObj.entityId,temperature:t.target.value})},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);e["default"]=new o["default"]({is:"more-info-updater",properties:{}}),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(7),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(7);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(2),o=n(1),u=r(o);n(7),e["default"]=new u["default"]({is:"state-card-rollershutter",properties:{stateObj:{type:Object}},computeIsFullyOpen:function(t){return 100===t.attributes.current_position},computeIsFullyClosed:function(t){return 0===t.attributes.current_position},onMoveUpTap:function(){i.serviceActions.callService("rollershutter","move_up",{entity_id:this.stateObj.entityId})},onMoveDownTap:function(){i.serviceActions.callService("rollershutter","move_down",{entity_id:this.stateObj.entityId})},onStopTap:function(){i.serviceActions.callService("rollershutter","stop",{entity_id: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),u=n(2);n(7),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(7),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(7),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:(0,u["default"])(t.entityId)?"toggle":"display"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(21),u=r(o),a=["thermostat","configurator","scene","media_player","rollershutter"];t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){if(!t)return u["default"];if(t.attributes.icon)return t.attributes.icon;var e=t.attributes.unit_of_measurement;return!e||"sensor"!==t.domain||e!==c.util.temperatureUnits.UNIT_TEMP_C&&e!==c.util.temperatureUnits.UNIT_TEMP_F?(0,s["default"])(t.domain,t.state):"mdi:thermometer"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(40),u=r(o),a=n(22),s=r(a),c=n(2);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,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(202);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 S(t,e,n,r){try{t.call(e,n,r)}catch(i){return i}}function w(t,e,n){Z(function(t){var r=!1,i=S(n,e,function(n){r||(r=!0,e!==n?E(t,n):j(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?j(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?j(t,e):a(n)?w(t,e,n):j(t,e)}}function E(t,e){t===e?P(t,g()):u(e)?T(t,e):j(t,e)}function I(t){t._onerror&&t._onerror(t._result),C(t)}function j(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(I,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=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&&j(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(){x(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(201).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(199),function(){return this}(),n(198)(t))},function(t,e,n){"use strict";var r=n(44),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(44),i=n(131),o=n(45),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(46),o=n(45),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(129),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(){var e=void 0;try{e="application/json"===r.getResponseHeader("content-type")?JSON.parse(r.responseText):r.responseText}catch(i){e=r.responseText}r.status>199&&r.status<300?t(e):n(e)},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(c.getters.isSupported):r,o=n.rememberAuth,u=void 0===o?!1:o,s=n.host,d=void 0===s?"":s;t.dispatch(a["default"].VALIDATING_AUTH_TOKEN,{authToken:e,host:d}),l.actions.fetchAll(t).then(function(){t.dispatch(a["default"].VALID_AUTH_TOKEN,{authToken:e,host:d,rememberAuth:u}),i?c.actions.start(t,{syncOnInitialConnect:!1}):l.actions.start(t,{skipInitialSync:!0})},function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=e.message,r=void 0===n?f:n;t.dispatch(a["default"].INVALID_AUTH_TOKEN,{errorMessage:r})})}function o(t){(0,s.callApi)(t,"POST","log_out"),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(6),c=n(28),l=n(30),f="Unexpected result from API"},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=["authAttempt","isValidating"];e.isValidating=n;var r=["authAttempt","isInvalid"];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(0,d.toImmutable)({authToken:n,host:r,isValidating:!0,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",!0).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)||(0,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(160),a=i(u),s=n(161),c=i(s),l=n(162),f=i(l),d=n(163),p=i(d),h=n(156),v=r(h),_=n(157),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 +},isListening:{type:Boolean,bindNuclear:i.voiceGetters.isListening},showListenInterface:{type:Boolean,computed:"computeShowListenInterface(isListening, isTransmitting)",observer:"showListenInterfaceChanged"},_boundOnBackdropTap:{type:Function,value:function(){return this._onBackdropTap.bind(this)}}},computeShowListenInterface:function(t,e){return t||e},dialogOpenChanged:function(t){t?this.$.dialog.backdropElement.addEventListener("click",this._boundOnBackdropTap):!t&&this.isListening&&i.voiceActions.stop()},showListenInterfaceChanged:function(t){!t&&this.dialogOpen?this.dialogOpen=!1:t&&(this.dialogOpen=!0)},_onBackdropTap:function(){this.$.dialog.backdropElement.removeEventListener("click",this._boundOnBackdropTap),this.isListening&&i.voiceActions.stop()}}),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),n(38),n(110);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}},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.async(function(){return e._delayedDialogOpen=!0},10):!t&&this.stateObj&&(i.moreInfoActions.deselectEntity(),this._delayedDialogOpen=!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(87),n(105),n(103),n(102),n(104),n(98),n(99),n(101),n(100),n(106),n(95),n(94),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")},isSelectedDevInfo:{type:Boolean,bindNuclear:u.navigationGetters.isActivePane("devInfo")},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(){(0,u.startUrlSync)()},computeForceNarrow:function(t,e){return t||!e},detached:function(){(0,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:{errorMessage:{type:String,bindNuclear:u.authGetters.attemptErrorMessage},isInvalid:{type:Boolean,bindNuclear:u.authGetters.isInvalidAttempt},isValidating:{type:Boolean,observer:"isValidatingChanged",bindNuclear:u.authGetters.isValidating},loadingResources:{type:Boolean,value:!1},forceShowLoading:{type:Boolean,value:!1},showLoading:{type:Boolean,computed:"computeShowSpinner(forceShowLoading, isValidating)"}},listeners:{keydown:"passwordKeyDown","loginButton.click":"validatePassword"},observers:["validatingChanged(isValidating, isInvalid)"],computeShowSpinner:function(t,e){return t||e},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(),(0,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(8),n(90),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(8),n(83),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),a=n(4),s=r(a);n(8),e["default"]=new u["default"]({is:"partial-dev-info",behaviors:[s["default"]],properties:{narrow:{type:Boolean,value:!1},showMenu:{type:Boolean,value:!1},hassVersion:{type:String,bindNuclear:i.configGetters.serverVersion},polymerVersion:{type:String,value:u["default"].version},nuclearVersion:{type:String,value:"1.2.1"},errorLog:{type:String,value:""}},attached:function(){this.refreshErrorLog()},refreshErrorLog:function(t){var e=this;t&&t.preventDefault(),this.errorLog="Loading error log…",i.errorLogActions.fetchErrorLog().then(function(t){return e.errorLog=t||"No errors have been reported."})}}),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(8),n(78),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(8),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(8),n(86),n(18),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(79),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(8),n(88),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}]},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(300+300*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(){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()},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(18),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(128),a=r(u);n(111),n(112),n(116),n(109),n(117),n(115),n(113),n(114),n(108),n(118),n(107),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=(0,a["default"])(t);if(e&&(0,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","icon","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(19),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(20),s=r(a);n(84);var c=["brightness","rgb_color","color_temp"];e["default"]=new u["default"]({is:"more-info-light",properties:{stateObj:{type:Object,observer:"stateObjChanged"},brightnessSliderValue:{type:Number,value:0},ctSliderValue:{type:Number,value:0}},stateObjChanged:function(t){var e=this;t&&"on"===t.state&&(this.brightnessSliderValue=t.attributes.brightness,this.ctSliderValue=t.attributes.color_temp),this.async(function(){return e.fire("iron-resize")},500)},computeClassNames:function(t){return(0,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}))},ctSliderChanged:function(t){var e=parseInt(t.target.value,10);isNaN(e)||i.serviceActions.callService("light","turn_on",{entity_id:this.stateObj.entityId,color_temp: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(20),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(0,s["default"])(t,c)},computeIsOff:function(t){return"off"===t.state},computeMuteVolumeIcon:function(t){return t?"mdi:volume-off":"mdi:volume-high"},computePlaybackControlIcon:function(){return this.isPlaying?this.supportsPause?"mdi:pause":"mdi:stop":"mdi:play"},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(0,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(20),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(0,s["default"])(t,c)},targetTemperatureSliderChanged:function(t){i.serviceActions.callService("thermostat","set_temperature",{entity_id:this.stateObj.entityId,temperature:t.target.value})},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);e["default"]=new o["default"]({is:"more-info-updater",properties:{}}),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(7),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(7);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(2),o=n(1),u=r(o);n(7),e["default"]=new u["default"]({is:"state-card-rollershutter",properties:{stateObj:{type:Object}},computeIsFullyOpen:function(t){return 100===t.attributes.current_position},computeIsFullyClosed:function(t){return 0===t.attributes.current_position},onMoveUpTap:function(){i.serviceActions.callService("rollershutter","move_up",{entity_id:this.stateObj.entityId})},onMoveDownTap:function(){i.serviceActions.callService("rollershutter","move_down",{entity_id:this.stateObj.entityId})},onStopTap:function(){i.serviceActions.callService("rollershutter","stop",{entity_id: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),u=n(2);n(7),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(7),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(7),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:(0,u["default"])(t.entityId)?"toggle":"display"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(21),u=r(o),a=["thermostat","configurator","scene","media_player","rollershutter"];t.exports=e["default"]},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function i(t){if(!t)return u["default"];if(t.attributes.icon)return t.attributes.icon;var e=t.attributes.unit_of_measurement;return!e||"sensor"!==t.domain||e!==c.util.temperatureUnits.UNIT_TEMP_C&&e!==c.util.temperatureUnits.UNIT_TEMP_F?(0,s["default"])(t.domain,t.state):"mdi:thermometer"}Object.defineProperty(e,"__esModule",{value:!0}),e["default"]=i;var o=n(40),u=r(o),a=n(22),s=r(a),c=n(2);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,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(202);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 S(t,e,n,r){try{t.call(e,n,r)}catch(i){return i}}function w(t,e,n){Z(function(t){var r=!1,i=S(n,e,function(n){r||(r=!0,e!==n?E(t,n):j(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?j(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?j(t,e):a(n)?w(t,e,n):j(t,e)}}function E(t,e){t===e?P(t,g()):u(e)?T(t,e):j(t,e)}function I(t){t._onerror&&t._onerror(t._result),C(t)}function j(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(I,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=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&&j(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(){x(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(201).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(199),function(){return this}(),n(198)(t))},function(t,e,n){"use strict";var r=n(44),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(44),i=n(131),o=n(45),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(46),o=n(45),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(129),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(){var e=void 0;try{e="application/json"===r.getResponseHeader("content-type")?JSON.parse(r.responseText):r.responseText}catch(i){e=r.responseText}r.status>199&&r.status<300?t(e):n(e)},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(c.getters.isSupported):r,o=n.rememberAuth,u=void 0===o?!1:o,s=n.host,d=void 0===s?"":s;t.dispatch(a["default"].VALIDATING_AUTH_TOKEN,{authToken:e,host:d}),l.actions.fetchAll(t).then(function(){t.dispatch(a["default"].VALID_AUTH_TOKEN,{authToken:e,host:d,rememberAuth:u}),i?c.actions.start(t,{syncOnInitialConnect:!1}):l.actions.start(t,{skipInitialSync:!0})},function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=e.message,r=void 0===n?f:n;t.dispatch(a["default"].INVALID_AUTH_TOKEN,{errorMessage:r})})}function o(t){(0,s.callApi)(t,"POST","log_out"),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(6),c=n(28),l=n(30),f="Unexpected result from API"},function(t,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=["authAttempt","isValidating"];e.isValidating=n;var r=["authAttempt","isInvalid"];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(0,d.toImmutable)({authToken:n,host:r,isValidating:!0,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",!0).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)||(0,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(160),a=i(u),s=n(161),c=i(s),l=n(162),f=i(l),d=n(163),p=i(d),h=n(156),v=r(h),_=n(157),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 41dbd6abc34..feb776ec89d 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 41dbd6abc34473113ba9c9380d9d5e10dff3d623 +Subproject commit feb776ec89d6872dad2203b352cc6d652c46356d From e0c4c8d7dd54b245977fbdd6ae95e83f42ce85eb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 11:41:43 -0800 Subject: [PATCH 165/166] Remove unused constant in HTTP --- homeassistant/components/http.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index f5e337ccf9c..f76e7e16b11 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -36,7 +36,6 @@ CONF_API_PASSWORD = "api_password" CONF_SERVER_HOST = "server_host" CONF_SERVER_PORT = "server_port" CONF_DEVELOPMENT = "development" -CONF_SESSIONS_ENABLED = "sessions_enabled" DATA_API_PASSWORD = 'api_password' From 535a3c399ef2bb55d55fb993e3d8e4f7941199c1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Dec 2015 11:44:38 -0800 Subject: [PATCH 166/166] Version bump to 0.9.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 2a1b7108cdd..eeb57050d90 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """ Constants used by Home Assistant components. """ -__version__ = "0.9.0.dev0" +__version__ = "0.9.0" # Can be used to specify a catch all when registering state or event listeners. MATCH_ALL = '*'