diff --git a/.coveragerc b/.coveragerc index 00e10da8110..ee40c987ea2 100644 --- a/.coveragerc +++ b/.coveragerc @@ -36,11 +36,14 @@ omit = homeassistant/components/notify/nma.py homeassistant/components/notify/pushbullet.py homeassistant/components/notify/pushover.py + homeassistant/components/notify/smtp.py + homeassistant/components/notify/syslog.py homeassistant/components/notify/xmpp.py homeassistant/components/sensor/bitcoin.py homeassistant/components/sensor/mysensors.py homeassistant/components/sensor/openweathermap.py homeassistant/components/sensor/sabnzbd.py + homeassistant/components/sensor/swiss_public_transport.py homeassistant/components/sensor/systemmonitor.py homeassistant/components/sensor/time_date.py homeassistant/components/sensor/transmission.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48523c1a4fe..3f2fd110a1d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,24 +1,41 @@ -# Adding support for a new device +# Contributing to Home Assistant -For help on building your component, please see the See the [developer documentation on home-assistant.io](https://home-assistant.io/developers/). +Everybody is invited and welcome to contribute to Home Assistant. There is a lot to do...if you are not a developer perhaps you would like to help with the documentation on [home-assistant.io](https://home-assistant.io/)? If you are a developer and have devices in your home which aren't working with Home Assistant yet, why not spent a couple of hours and help to integrate them? + +The process is straight-forward. + + - Fork the Home Assistant [git repository](https://github.com/balloob/home-assistant). + - Write the code for your device, notification service, sensor, or IoT thing. + - Check it with ``pylint`` and ``flake8``. + - Create a Pull Request against the [**dev**](https://github.com/balloob/home-assistant/tree/dev) branch of Home Assistant. + +Still interested? Then you should read the next sections and get more details. + +## Adding support for a new device + +For help on building your component, please see the [developer documentation](https://home-assistant.io/developers/) on [home-assistant.io](https://home-assistant.io/). After you finish adding support for your device: - - update the supported devices in README.md. - - add any new dependencies to requirements.txt. - - Make sure all your code passes Pylint, flake8 (PEP8 and some more) validation. To generate reports, run `pylint homeassistant > pylint.txt` and `flake8 homeassistant --exclude bower_components,external > flake8.txt`. + - Update the supported devices in the `README.md` file. + - Add any new dependencies to `requirements.txt`. + - Update the `.coveragerc` file. + - Provide some documentation for [home-assistant.io](https://home-assistant.io/). The documentation is handled in a separate [git repository](https://github.com/balloob/home-assistant.io). + - Make sure all your code passes Pylint and flake8 (PEP8 and some more) validation. To generate reports, run `pylint homeassistant > pylint.txt` and `flake8 homeassistant --exclude bower_components,external > flake8.txt`. + - Create a Pull Request against the [**dev**](https://github.com/balloob/home-assistant/tree/dev) branch of Home Assistant. + - Check for comments and suggestions on your Pull Request and keep an eye on the [Travis output](https://travis-ci.org/balloob/home-assistant/). If you've added a component: - - update the file [`domain-icon.html`](https://github.com/balloob/home-assistant/blob/master/homeassistant/components/http/www_static/polymer/domain-icon.html) with an icon for your domain ([pick from this list](https://www.polymer-project.org/0.5/components/core-elements/demo.html#core-icon)) - - update the demo component with two states that it provides + - Update the file [`home-assistant-icons.html`](https://github.com/balloob/home-assistant/blob/master/homeassistant/components/frontend/www_static/polymer/resources/home-assistant-icons.html) with an icon for your domain ([pick one from this list](https://www.polymer-project.org/1.0/components/core-elements/demo.html#core-icon)). + - Update the demo component with two states that it provides - Add your component to home-assistant.conf.example -Since you've updated domain-icon.html, you've made changes to the frontend: +Since you've updated `home-assistant-icons.html`, you've made changes to the frontend: - - run `build_frontend`. This will build a new version of the frontend. Make sure you add the changed files `frontend.py` and `frontend.html` to the commit. + - Run `build_frontend`. This will build a new version of the frontend. Make sure you add the changed files `frontend.py` and `frontend.html` to the commit. -## Setting states +### Setting states It is the responsibility of the component to maintain the states of the devices in your domain. Each device should be a single state and, if possible, a group should be provided that tracks the combined state of the devices. @@ -31,9 +48,9 @@ A state can have several attributes that will help the frontend in displaying yo These attributes are defined in [homeassistant.components](https://github.com/balloob/home-assistant/blob/master/homeassistant/components/__init__.py#L25). -## Proper Visibility Handling ## +### Proper Visibility Handling -Generally, when creating a new entity for Home Assistant you will want it to be a class that inherits the [homeassistant.helpers.entity.Entity](https://github.com/balloob/home-assistant/blob/master/homeassistant/helpers/entity.py) Class. If this is done, visibility will be handled for you. +Generally, when creating a new entity for Home Assistant you will want it to be a class that inherits the [homeassistant.helpers.entity.Entity](https://github.com/balloob/home-assistant/blob/master/homeassistant/helpers/entity.py) class. If this is done, visibility will be handled for you. You can set a suggestion for your entity's visibility by setting the hidden property by doing something similar to the following. ```python @@ -44,12 +61,12 @@ This will SUGGEST that the active frontend hides the entity. This requires that Remember: The suggestion set by your component's code will always be overwritten by user settings in the configuration.yaml file. This is why you may set hidden to be False, but the property may remain True (or vice-versa). -## Working on the frontend +### Working on the frontend -The frontend is composed of Polymer web-components and compiled into the file `frontend.html`. During development you do not want to work with the compiled version but with the seperate files. To have Home Assistant serve the seperate files, set `development=1` for the http-component in your config. +The frontend is composed of [Polymer](https://www.polymer-project.org) web-components and compiled into the file `frontend.html`. During development you do not want to work with the compiled version but with the seperate files. To have Home Assistant serve the seperate files, set `development=1` for the *http-component* in your config. When you are done with development and ready to commit your changes, run `build_frontend`, set `development=0` in your config and validate that everything still works. -## Notes on PyLint and PEP8 validation +### Notes on PyLint and PEP8 validation In case a PyLint warning cannot be avoided, add a comment to disable the PyLint check for that line. This can be done using the format `# pylint: disable=YOUR-ERROR-NAME`. Example of an unavoidable PyLint warning is if you do not use the passed in datetime if you're listening for time change. diff --git a/README.md b/README.md index 1648b526332..05fe01340bc 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,11 @@ Home Assistant is a home automation platform running on Python 3. The goal of Ho It offers the following functionality through built-in components: - * Track if devices are home by monitoring connected devices to a wireless router (supporting [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), [DD-WRT](http://www.dd-wrt.com/site/index)) - * Track and control [Philips Hue](http://meethue.com) lights - * Track and control [WeMo switches](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) - * Track and control [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast) - * Track running services by monitoring `ps` output - * Track and control [Tellstick devices and sensors](http://www.telldus.se/products/tellstick) + * Track if devices are home by monitoring connected devices to a wireless router (supporting [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), and [DD-WRT](http://www.dd-wrt.com/site/index)) + * Track and control [Philips Hue](http://meethue.com) lights, [WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) switches, and [Tellstick](http://www.telldus.se/products/tellstick) devices and sensors + * Track and control [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast) and [Music Player Daemon](http://www.musicpd.org/) + * 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/), and [Modbus](http://www.modbus.org/) + * Track running system services and monitoring your system stats (Memory, disk usage, and more) * Control low-cost 433 MHz remote control wall-socket devices (https://github.com/r10r/rcswitch-pi) and other switches that can be turned on/off with shell commands * Turn on the lights when people get home after sun set * Turn on lights slowly during sun set to compensate for light loss @@ -19,6 +18,8 @@ It offers the following functionality through built-in components: * Offers web interface to monitor and control Home Assistant * Offers a [REST API](https://home-assistant.io/developers/api.html) for easy integration with other projects * [Ability to have multiple instances of Home Assistant work together](https://home-assistant.io/developers/architecture.html) + * 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/), and [Jabber (XMPP)](http://xmpp.org) + * Allow to display details about a running [Transmission](http://www.transmissionbt.com/) client, the [Bitcoin](https://bitcoin.org) network, local meteorological data from [OpenWeatherMap](http://openweathermap.org/), the time, the date, and the downloads from [SABnzbd](http://sabnzbd.org) Home Assistant also includes functionality for controlling HTPCs: @@ -34,16 +35,16 @@ If you run into issues while using Home Assistant or during development of a com ## Installation instructions / Quick-start guide -Running Home Assistant requires that python 3.4 and the package requests are installed. Run the following code to install and start Home Assistant: +Running Home Assistant requires that [Python](https://www.python.org/) 3.4 and the package [requests](http://docs.python-requests.org/en/latest/) are installed. Run the following code to install and start Home Assistant: ```python git clone --recursive https://github.com/balloob/home-assistant.git cd home-assistant -pip3 install -r requirements.txt +python3 -m pip install --user -r requirements.txt python3 -m homeassistant --open-ui ``` -The last command will start the Home Assistant server and launch its webinterface. By default Home Assistant looks for the configuration file `config/home-assistant.conf`. A standard configuration file will be written if none exists. +The last command will start the Home Assistant server and launch its web interface. By default Home Assistant looks for the configuration file `config/home-assistant.conf`. A standard configuration file will be written if none exists. If you are still exploring if you want to use Home Assistant in the first place, you can enable the demo mode by adding the `--demo-mode` argument to the last command. diff --git a/config/custom_components/example.py b/config/custom_components/example.py index dc18aae4b98..5bfb03353e0 100644 --- a/config/custom_components/example.py +++ b/config/custom_components/example.py @@ -8,6 +8,22 @@ Example component to target an entity_id to: - turn it off if all lights are turned off - turn it off if all people leave the house - offer a service to turn it on for 10 seconds + +Configuration: + +To use the Example custom component you will need to add the following to +your config/configuration.yaml + +example: + target: TARGET_ENTITY + +Variable: + +target +*Required +TARGET_ENTITY should be one of your devices that can be turned on and off, +ie a light or a switch. Example value could be light.Ceiling or switch.AC +(if you have these devices with those names). """ import time import logging @@ -31,6 +47,7 @@ CONF_TARGET = 'target' # Name of the service that we expose SERVICE_FLASH = 'flash' +# Shortcut for the logger _LOGGER = logging.getLogger(__name__) diff --git a/config/custom_components/hello_world.py b/config/custom_components/hello_world.py index be1b935c8ad..96d9a788b6b 100644 --- a/config/custom_components/hello_world.py +++ b/config/custom_components/hello_world.py @@ -3,6 +3,14 @@ custom_components.hello_world ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Implements the bare minimum that a component should implement. + +Configuration: + +To use the hello_word component you will need to add the following to your +config/configuration.yaml + +hello_world: + """ # The domain of your component. Should be equal to the name of your component diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 787e0f80562..f8c595255d9 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -186,6 +186,24 @@ def from_config_file(config_path, hass=None): def enable_logging(hass): """ Setup the logging for home assistant. """ logging.basicConfig(level=logging.INFO) + fmt = ("%(log_color)s%(asctime)s %(levelname)s (%(threadName)s) " + "[%(name)s] %(message)s%(reset)s") + try: + from colorlog import ColoredFormatter + logging.getLogger().handlers[0].setFormatter(ColoredFormatter( + fmt, + datefmt='%y-%m-%d %H:%M:%S', + reset=True, + log_colors={ + 'DEBUG': 'cyan', + 'INFO': 'green', + 'WARNING': 'yellow', + 'ERROR': 'red', + 'CRITICAL': 'red', + } + )) + except ImportError: + _LOGGER.warn("Colorlog package not found, console coloring disabled") # Log errors to a file if we have write access to file or config dir err_log_path = hass.config.path('home-assistant.log') @@ -202,7 +220,7 @@ def enable_logging(hass): err_handler.setLevel(logging.WARNING) err_handler.setFormatter( logging.Formatter('%(asctime)s %(name)s: %(message)s', - datefmt='%H:%M %d-%m-%y')) + datefmt='%y-%m-%d %H:%M:%S')) logging.getLogger('').addHandler(err_handler) else: @@ -235,8 +253,13 @@ def process_ha_core_config(hass, config): set_time_zone(config.get(CONF_TIME_ZONE)) - for entity_id, attrs in config.get(CONF_CUSTOMIZE, {}).items(): - Entity.overwrite_attribute(entity_id, attrs.keys(), attrs.values()) + customize = config.get(CONF_CUSTOMIZE) + + if isinstance(customize, dict): + for entity_id, attrs in config.get(CONF_CUSTOMIZE, {}).items(): + if not isinstance(attrs, dict): + continue + Entity.overwrite_attribute(entity_id, attrs.keys(), attrs.values()) if CONF_TEMPERATURE_UNIT in config: unit = config[CONF_TEMPERATURE_UNIT] diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 2abae8095d6..a4eb9481873 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -93,10 +93,10 @@ def setup(hass, config): # Setup fake device tracker hass.states.set("device_tracker.paulus", "home", {ATTR_ENTITY_PICTURE: - "http://graph.facebook.com/schoutsen/picture"}) + "http://graph.facebook.com/297400035/picture"}) hass.states.set("device_tracker.anne_therese", "not_home", {ATTR_ENTITY_PICTURE: - "http://graph.facebook.com/anne.t.frederiksen/picture"}) + "http://graph.facebook.com/621994601/picture"}) hass.states.set("group.all_devices", "home", { diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 5cefed5c5c8..611136aac5b 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -17,7 +17,7 @@ import homeassistant.util.dt as dt_util from homeassistant.const import ( STATE_HOME, STATE_NOT_HOME, ATTR_ENTITY_PICTURE, ATTR_FRIENDLY_NAME, - CONF_PLATFORM) + CONF_PLATFORM, DEVICE_DEFAULT_NAME) from homeassistant.components import group DOMAIN = "device_tracker" @@ -169,66 +169,28 @@ class DeviceTracker(object): if not self.lock.acquire(False): return - found_devices = set(dev.upper() for dev in - self.device_scanner.scan_devices()) + try: + found_devices = set(dev.upper() for dev in + self.device_scanner.scan_devices()) - for device in self.tracked: - is_home = device in found_devices + for device in self.tracked: + is_home = device in found_devices - self._update_state(now, device, is_home) + self._update_state(now, device, is_home) - if is_home: - found_devices.remove(device) + if is_home: + found_devices.remove(device) - # Did we find any devices that we didn't know about yet? - new_devices = found_devices - self.untracked_devices + # Did we find any devices that we didn't know about yet? + new_devices = found_devices - self.untracked_devices - if new_devices: - if not self.track_new_devices: - self.untracked_devices.update(new_devices) + if new_devices: + if not self.track_new_devices: + self.untracked_devices.update(new_devices) - # Write new devices to known devices file - if not self.invalid_known_devices_file: - - known_dev_path = self.hass.config.path(KNOWN_DEVICES_FILE) - - try: - # If file does not exist we will write the header too - is_new_file = not os.path.isfile(known_dev_path) - - with open(known_dev_path, 'a') as outp: - _LOGGER.info( - "Found %d new devices, updating %s", - len(new_devices), known_dev_path) - - writer = csv.writer(outp) - - if is_new_file: - writer.writerow(( - "device", "name", "track", "picture")) - - for device in new_devices: - # See if the device scanner knows the name - # else defaults to unknown device - dname = self.device_scanner.get_device_name(device) - name = dname or "unknown device" - - track = 0 - if self.track_new_devices: - self._track_device(device, name) - track = 1 - - writer.writerow((device, name, track, "")) - - if self.track_new_devices: - self._generate_entity_ids(new_devices) - - except IOError: - _LOGGER.exception( - "Error updating %s with %d new devices", - known_dev_path, len(new_devices)) - - self.lock.release() + self._update_known_devices_file(new_devices) + finally: + self.lock.release() # pylint: disable=too-many-branches def _read_known_devices_file(self): @@ -309,6 +271,44 @@ class DeviceTracker(object): finally: self.lock.release() + def _update_known_devices_file(self, new_devices): + """ Add new devices to known devices file. """ + if not self.invalid_known_devices_file: + known_dev_path = self.hass.config.path(KNOWN_DEVICES_FILE) + + try: + # If file does not exist we will write the header too + is_new_file = not os.path.isfile(known_dev_path) + + with open(known_dev_path, 'a') as outp: + _LOGGER.info("Found %d new devices, updating %s", + len(new_devices), known_dev_path) + + writer = csv.writer(outp) + + if is_new_file: + writer.writerow(("device", "name", "track", "picture")) + + for device in new_devices: + # See if the device scanner knows the name + # else defaults to unknown device + name = self.device_scanner.get_device_name(device) or \ + DEVICE_DEFAULT_NAME + + track = 0 + if self.track_new_devices: + self._track_device(device, name) + track = 1 + + writer.writerow((device, name, track, "")) + + if self.track_new_devices: + self._generate_entity_ids(new_devices) + + except IOError: + _LOGGER.exception("Error updating %s with %d new devices", + known_dev_path, len(new_devices)) + def _track_device(self, device, name): """ Add a device to the list of tracked devices. diff --git a/homeassistant/components/frontend/index.html.template b/homeassistant/components/frontend/index.html.template index b9126ed25e2..f84c8653b31 100644 --- a/homeassistant/components/frontend/index.html.template +++ b/homeassistant/components/frontend/index.html.template @@ -15,8 +15,8 @@ - + diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index c419cca2942..ededf05d5ed 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 = "2d15135e9bfd0ee5b023d9abb79be62d" +VERSION = "010d9683fa9d210abd199b3cde4edbc0" diff --git a/homeassistant/components/frontend/www_static/favicon-apple-180x180.png b/homeassistant/components/frontend/www_static/favicon-apple-180x180.png new file mode 100644 index 00000000000..20117d00f22 Binary files /dev/null and b/homeassistant/components/frontend/www_static/favicon-apple-180x180.png differ diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 7ec670dacf0..808617e8af5 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -22,29 +22,32 @@ The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 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 ---> @@ -5863,43 +5876,64 @@ this._removeChildren(); - - - + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -16202,8 +16409,8 @@ document.registerElement('color-picker', { prototype: colorPickerPrototype }); fill: currentcolor; - width: var(--iron-icon-width); - height: var(--iron-icon-height); + width: var(--iron-icon-width, 24px); + height: var(--iron-icon-height, 24px); } @@ -16292,7 +16499,6 @@ document.registerElement('color-picker', { prototype: colorPickerPrototype }); - @@ -16887,7 +17093,7 @@ window.hass.uiUtil.domainIcon = function(domain, state) { case "media_player": var icon = "hardware:cast"; - if (state && state !== "idle") { + if (state && state !== "off" && state !== 'idle') { icon += "-connected"; } @@ -17247,6 +17453,7 @@ window.hass.uiUtil.domainIcon = function(domain, state) { this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)'; }, + /** @param {Event=} event */ downAction: function(event) { var xCenter = this.containerMetrics.width / 2; var yCenter = this.containerMetrics.height / 2; @@ -17291,6 +17498,7 @@ window.hass.uiUtil.domainIcon = function(domain, state) { this.waveContainer.style.height = this.containerMetrics.size + 'px'; }, + /** @param {Event=} event */ upAction: function(event) { if (!this.isMouseDown) { return; @@ -17414,11 +17622,9 @@ window.hass.uiUtil.domainIcon = function(domain, state) { var ownerRoot = Polymer.dom(this).getOwnerRoot(); var target; - if (ownerRoot) { + if (this.parentNode.nodeType == 11) { // DOCUMENT_FRAGMENT_NODE target = ownerRoot.host; - } - - if (!target) { + } else { target = this.parentNode; } @@ -17432,8 +17638,8 @@ window.hass.uiUtil.domainIcon = function(domain, state) { }, attached: function() { - this._listen(this.target, 'up', this.upAction.bind(this)); - this._listen(this.target, 'down', this.downAction.bind(this)); + this.listen(this.target, 'up', 'upAction'); + this.listen(this.target, 'down', 'downAction'); if (!this.target.hasAttribute('noink')) { this.keyEventTarget = this.target; @@ -17459,6 +17665,7 @@ window.hass.uiUtil.domainIcon = function(domain, state) { }, 1); }, + /** @param {Event=} event */ downAction: function(event) { if (this.holdDown && this.ripples.length > 0) { return; @@ -17473,6 +17680,7 @@ window.hass.uiUtil.domainIcon = function(domain, state) { } }, + /** @param {Event=} event */ upAction: function(event) { if (this.holdDown) { return; @@ -17608,12 +17816,12 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN left: -15px; width: 48px; height: 48px; - color: var(--paper-checkbox-unchecked-ink-color); + color: var(--paper-checkbox-unchecked-ink-color, --primary-text-color); opacity: 0.6; } :host #ink[checked] { - color: var(--paper-checkbox-checked-ink-color); + color: var(--paper-checkbox-checked-ink-color, --default-primary-color); } :host #checkbox { @@ -17621,7 +17829,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN box-sizing: border-box; height: 100%; border: solid 2px; - border-color: var(--paper-checkbox-unchecked-color); + border-color: var(--paper-checkbox-unchecked-color, --primary-text-color); border-radius: 2px; pointer-events: none; -webkit-transition: background-color 140ms, border-color 140ms; @@ -17665,8 +17873,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } :host #checkbox.checked { - background-color: var(--paper-checkbox-checked-color); - border-color: var(--paper-checkbox-checked-color); + background-color: var(--paper-checkbox-checked-color, --default-primary-color); + border-color: var(--paper-checkbox-checked-color, --default-primary-color); } :host #checkmark { @@ -17693,7 +17901,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN padding-left: 8px; white-space: normal; pointer-events: none; - color: var(--paper-checkbox-label-color); + color: var(--paper-checkbox-label-color, --primary-text-color); } #checkboxLabel[hidden] { @@ -17707,11 +17915,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN :host([disabled]) #checkbox { opacity: 0.5; - border-color: var(--paper-checkbox-unchecked-color); + border-color: var(--paper-checkbox-unchecked-color, --primary-text-color); } :host([disabled][checked]) #checkbox { - background-color: var(--paper-checkbox-unchecked-color); + background-color: var(--paper-checkbox-unchecked-color, --primary-text-color); opacity: 0.5; } @@ -17739,7 +17947,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN is: 'paper-checkbox', behaviors: [ - Polymer.PaperRadioButtonBehavior + Polymer.PaperInkyFocusBehavior ], hostAttributes: { @@ -17812,12 +18020,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN if (checked) { return 'checked'; } + return ''; }, _computeCheckmarkClass: function(checked) { if (!checked) { return 'hidden'; } + return ''; } }) @@ -18040,7 +18250,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN background: var(--paper-input-container-focus-color, --default-primary-color); } - .is-highlighted .focused-line { + .underline.is-highlighted .focused-line { -webkit-transform: none; transform: none; -webkit-transition: -webkit-transform 0.25s; @@ -18049,7 +18259,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN @apply(--paper-transition-easing); } - .is-invalid .focused-line { + .underline.is-invalid .focused-line { background: var(--paper-input-container-invalid-color, --google-red-500); -webkit-transform: none; @@ -18236,10 +18446,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _addons: { - type: Array, - value: function() { - return []; - } + type: Array + // do not set a default value here intentionally - it will be initialized lazily when a + // distributed child is attached, which may occur before configuration for this element + // in polyfill. }, _inputHasContent: { @@ -18269,7 +18479,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN _boundOnInput: { type: Function, value: function() { - this._onInput.bind(this) + return this._onInput.bind(this); } }, @@ -18300,6 +18510,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, ready: function() { + if (!this._addons) { + this._addons = []; + } this.addEventListener('focus', this._boundOnFocus, true); this.addEventListener('blur', this._boundOnBlur, true); if (this.attrForValue) { @@ -18314,8 +18527,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }, _onAddonAttached: function(event) { - this._addons.push(event.target); - this._handleValue(this._inputElement); + if (!this._addons) { + this._addons = []; + } + var target = event.target; + if (this._addons.indexOf(target) === -1) { + this._addons.push(target); + if (this.isAttached) { + this._handleValue(this._inputElement); + } + } }, _onFocus: function() { @@ -19379,7 +19600,9 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { */ dragging: { type: Boolean, - value: false + value: false, + readOnly: true, + notify: true }, /** @@ -19435,6 +19658,7 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { reflectToAttribute: true, type: Boolean, value: false, + readOnly: true, notify: true }, @@ -19443,7 +19667,9 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { */ peeking: { type: Boolean, - value: false + value: false, + readOnly: true, + notify: true }, /** @@ -19468,6 +19694,7 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { */ selected: { reflectToAttribute: true, + notify: true, type: String, value: null }, @@ -19594,7 +19821,7 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { }, _responsiveChange: function(narrow) { - this.narrow = narrow; + this._setNarrow(narrow); if (this.narrow) { this.selected = this.defaultSelected; @@ -19625,12 +19852,12 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { this.width = this.$.drawer.offsetWidth; this._moveDrawer(this._translateXForDeltaX(this.rightDrawer ? -this.edgeSwipeSensitivity : this.edgeSwipeSensitivity)); - this.peeking = true; + this._setPeeking(true); }, _stopEdgePeek: function() { if (this.peeking) { - this.peeking = false; + this._setPeeking(false); this._moveDrawer(null); } }, @@ -19669,13 +19896,13 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { x <= this.edgeSwipeSensitivity); }, - _trackStart: function() { + _trackStart: function(event) { if (this._swipeAllowed()) { sharedPanel = this; - this.dragging = true; + this._setDragging(true); if (this._isMainSelected()) { - this.dragging = this.peeking || this._isEdgeTouch(event); + this._setDragging(this.peeking || this._isEdgeTouch(event)); } if (this.dragging) { @@ -19704,7 +19931,7 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { // Ignore trackx until we move past the edge peek. return; } - this.peeking = false; + this._setPeeking(false); } this._moveDrawer(this._translateXForDeltaX(dx)); @@ -19715,7 +19942,7 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { if (this.dragging) { var xDirection = e.detail.dx > 0; - this.dragging = false; + this._setDragging(false); this.transition = true; sharedPanel = null; this._moveDrawer(null); @@ -19767,6 +19994,17 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { z-index: 0; } + :root { + /** + * Default paper header panel shadow + */ + --paper-header-panel-shadow: { + height: 6px; + bottom: -6px; + box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4); + }; + } + #mainContainer { @apply(--layout-flex); @@ -19870,19 +20108,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { - -
+
@@ -21163,10 +21403,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { properties: { /** * The URL of an image. - * - * @attribute src - * @type string - * @default '' */ src: { observer: '_srcChanged', @@ -21178,10 +21414,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { * When true, the image is prevented from loading and any placeholder is * shown. This may be useful when a binding to the src property is known to * be invalid, to prevent 404 requests. - * - * @attribute preventLoad - * @type boolean - * @default false */ preventLoad: { type: Boolean, @@ -21193,10 +21425,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { * aspect ratio of the image is contained within the element and * letterboxed) or `cover` (image is cropped in order to fully cover the * bounds of the element), or `null` (default: image takes natural size). - * - * @attribute sizing - * @type string - * @default null */ sizing: { type: String, @@ -21206,10 +21434,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { /** * When a sizing option is uzed (`cover` or `contain`), this determines * how the image is aligned within the element bounds. - * - * @attribute position - * @type string - * @default 'center' */ position: { type: String, @@ -21219,10 +21443,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { /** * When `true`, any change to the `src` property will cause the `placeholder` * image to be shown until the - * - * @attribute preload - * @type boolean - * @default false */ preload: { type: Boolean, @@ -21232,10 +21452,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { /** * This image will be used as a background/placeholder until the src image has * loaded. Use of a data-URI for placeholder is encouraged for instant rendering. - * - * @attribute placeholder - * @type string - * @default null */ placeholder: { type: String, @@ -21245,10 +21461,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { /** * When `preload` is true, setting `fade` to true will cause the image to * fade into place. - * - * @attribute fade - * @type boolean - * @default false */ fade: { type: Boolean, @@ -21257,10 +21469,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { /** * Read-only value that is true when the image is loaded. - * - * @attribute preloaded - * @type boolean - * @default false */ loaded: { notify: true, @@ -21271,10 +21479,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { /** * Read-only value that tracks the loading state of the image when the `preload` * option is used. - * - * @attribute loading - * @type boolean - * @default false */ loading: { notify: true, @@ -21285,10 +21489,6 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { /** * Can be used to set the width of image (e.g. via binding); size may also be * set via CSS. - * - * @attribute width - * @type number - * @default null */ width: { observer: '_widthChanged', @@ -21403,11 +21603,11 @@ iron-selector:not(.narrow-layout) #main ::content [paper-drawer-toggle] { this.style.backgroundPosition = placeholderStyle.backgroundPosition = - this.sizing ? this.position : null; + this.sizing ? this.position : ''; this.style.backgroundRepeat = placeholderStyle.backgroundRepeat = - this.sizing ? 'no-repeat' : null; + this.sizing ? 'no-repeat' : ''; }, _loadBehaviorChanged: function() { @@ -21770,27 +21970,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } :host .toggle-bar { - background-color: var(--paper-toggle-button-unchecked-bar-color); + background-color: var(--paper-toggle-button-unchecked-bar-color, #000000); } :host .toggle-button { - background-color: var(--paper-toggle-button-unchecked-button-color); + background-color: var(--paper-toggle-button-unchecked-button-color, --paper-grey-50); } :host([checked]) .toggle-bar { - background-color: var(--paper-toggle-button-checked-bar-color); + background-color: var(--paper-toggle-button-checked-bar-color, --google-green-500); } :host([checked]) .toggle-button { - background-color: var(--paper-toggle-button-checked-button-color); + background-color: var(--paper-toggle-button-checked-button-color, --google-green-500); } :host .toggle-ink { - color: var(--paper-toggle-button-unchecked-ink-color); + color: var(--paper-toggle-button-unchecked-ink-color, --primary-text-color); } :host([checked]) .toggle-ink { - color: var(--paper-toggle-button-checked-ink-color); + color: var(--paper-toggle-button-checked-ink-color, --google-green-500); } /* ID selectors should not be overriden by users. */ @@ -21874,7 +22074,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN is: 'paper-toggle-button', behaviors: [ - Polymer.PaperRadioButtonBehavior + Polymer.PaperInkyFocusBehavior ], hostAttributes: { @@ -21995,7 +22195,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
- +
@@ -22026,6 +22226,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN this.forceStateChange(); }, + toggleTapped: function(ev) { + ev.stopPropagation(); + }, + toggleChanged: function(ev) { var newVal = ev.target.checked; @@ -22187,6 +22391,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN .state { margin-left: 16px; text-align: right; + overflow-x: hidden; } .main-text { @@ -22208,8 +22413,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
-
[[computePrimaryText(stateObj)]]
-
[[computeSecondaryText(stateObj)]]
+
[[computePrimaryText(stateObj, isPlaying)]]
+
[[computeSecondaryText(stateObj, isPlaying)]]
@@ -22217,6 +22422,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - -
- - + Log Out diff --git a/homeassistant/components/frontend/www_static/polymer/bower.json b/homeassistant/components/frontend/www_static/polymer/bower.json index b5ee548776c..a431eabb905 100644 --- a/homeassistant/components/frontend/www_static/polymer/bower.json +++ b/homeassistant/components/frontend/www_static/polymer/bower.json @@ -31,12 +31,13 @@ "paper-slider": "PolymerElements/paper-slider#^1.0.0", "paper-checkbox": "PolymerElements/paper-checkbox#^1.0.0", "paper-drawer-panel": "PolymerElements/paper-drawer-panel#^1.0.0", - "paper-scroll-header-panel": "polymerelements/paper-scroll-header-panel#~1.0", + "paper-scroll-header-panel": "polymerelements/paper-scroll-header-panel#^1.0.0", "google-apis": "GoogleWebComponents/google-apis#0.8-preview", "moment": "^2.10.3", "layout": "Polymer/layout", "color-picker-element": "~0.0.3", - "paper-styles": "polymerelements/paper-styles#~1.0" + "paper-styles": "polymerelements/paper-styles#^1.0.0", + "paper-date-picker": "vsimonian/paper-date-picker#master" }, "resolutions": { "polymer": "^1.0.0", diff --git a/homeassistant/components/frontend/www_static/polymer/cards/state-card-content.html b/homeassistant/components/frontend/www_static/polymer/cards/state-card-content.html index 0feed86de00..e5b929b0804 100644 --- a/homeassistant/components/frontend/www_static/polymer/cards/state-card-content.html +++ b/homeassistant/components/frontend/www_static/polymer/cards/state-card-content.html @@ -7,14 +7,6 @@ - - - - diff --git a/homeassistant/components/frontend/www_static/polymer/more-infos/more-info-media_player.html b/homeassistant/components/frontend/www_static/polymer/more-infos/more-info-media_player.html index 0d97752714d..2f10a0897a4 100644 --- a/homeassistant/components/frontend/www_static/polymer/more-infos/more-info-media_player.html +++ b/homeassistant/components/frontend/www_static/polymer/more-infos/more-info-media_player.html @@ -8,8 +8,7 @@ text-transform: capitalize; } - /* Accent the power button because the user should use that first */ - paper-icon-button[focus] { + paper-icon-button[highlight] { color: var(--accent-color); } @@ -21,7 +20,7 @@ transition: max-height .5s ease-in; } - .has-media_volume .volume { + .has-volume_level .volume { max-height: 40px; } @@ -29,25 +28,26 @@
- +
-