diff --git a/.gitmodules b/.gitmodules index 12316f30e72..8ea8376a6a4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "homeassistant/external/pywemo"] path = homeassistant/external/pywemo url = https://github.com/balloob/pywemo.git -[submodule "homeassistant/external/phue"] - path = homeassistant/external/phue - url = https://github.com/studioimaginaire/phue.git diff --git a/.travis.yml b/.travis.yml index fa81e929d7b..ff38ef3ced1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,10 @@ python: - "3.4" install: - pip install -r requirements.txt - - pip install pep8 pylint + - pip install flake8 pylint coveralls script: - - pep8 homeassistant --exclude bower_components,external + - flake8 homeassistant --exclude bower_components,external - pylint homeassistant - - python -m homeassistant -t test + - coverage run --source=homeassistant -m unittest discover test +after_success: + - coveralls diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f30ebf040d4..1d8ef8016e1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,15 +13,17 @@ Contains the code to interact with WeMo switches. Called if type=wemo in switch **homeassistant/components/switch/tellstick.py** Contains the code to interact with Tellstick switches. Called if type=tellstick in switch config. -If a component exists, your job is easy. Have a look at how the component works with other platforms and create a similar file for the platform that you would like to add.If you cannot find a suitable component, you'll have to add it yourself. When writing a component try to structure it after the Switch component to maximize reusability. +If a component exists, your job is easy. Have a look at how the component works with other platforms and create a similar file for the platform that you would like to add. If you cannot find a suitable component, you'll have to add it yourself. When writing a component try to structure it after the Switch component to maximize reusability. Communication between Home Assistant and devices should happen via third-party libraries that implement the device API. This will make sure the platform support code stays as small as possible. +For help on building your component, please see the See the documentation on [further customizing Home Assistant](https://github.com/balloob/home-assistant#further-customizing-home-assistant). + 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 and PEP8 validation. To generate reports, run `pylint homeassistant > pylint.txt` and `pep8 homeassistant --exclude bower_components,external > pep8.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`. If you've added a component: diff --git a/README.md b/README.md index a9205efe722..956176e4962 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Home Assistant [![Build Status](https://travis-ci.org/balloob/home-assistant.svg?branch=master)](https://travis-ci.org/balloob/home-assistant) +# 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) 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. @@ -27,9 +27,11 @@ Home Assistant also includes functionality for controlling HTPCs: The system is built modular so support for other devices or actions can be implemented easily. See also the [section on architecture](#architecture) and the [section on customizing](#customizing). +If you run into issues while using Home Assistant or during development of a component, reach out to the [Home Assistant developer community](https://groups.google.com/forum/#!forum/home-assistant-dev). + ## Installation instructions / Quick-start guide -Running Home Assistant requires that python3 and the packages pyephem and requests are installed. +Running Home Assistant requires that python3 and the package requests are installed. Run the following code to get up and running with the minimum setup: @@ -51,13 +53,15 @@ docker run -d --name="home-assistant" -v /path/to/homeassistant/config:/config - After you got the demo mode running it is time to enable some real components and get started. An example configuration file has been provided in [/config/home-assistant.conf.example](https://github.com/balloob/home-assistant/blob/master/config/home-assistant.conf.example). +*Note:* you can append `?api_password=YOUR_PASSWORD` to the url of the web interface to log in automatically. + ### Philips Hue To get Philips Hue working you will have to connect Home Assistant to the Hue bridge. Run the following command from your config dir and follow the instructions: ```bash -python -m phue --host HUE_BRIDGE_IP_ADDRESS --config-file-path phue.conf +python3 -m phue --host HUE_BRIDGE_IP_ADDRESS --config-file-path phue.conf ``` After that add the following lines to your `home-assistant.conf`: @@ -88,21 +92,17 @@ Once tracking the `device_tracker` component will maintain a file in your config ## Further customizing Home Assistant -If you run into issues while developing your component, reach out to the [Home Assistant developer community](https://groups.google.com/forum/#!forum/home-assistant-dev). - Home Assistant can be extended by components. Components can listen for- or trigger events and offer services. Components are written in Python and can do all the goodness that Python has to offer. Home Assistant offers [built-in components](#components) but it is easy to built your own. An example component can be found in [`/config/custom_components/example.py`](https://github.com/balloob/home-assistant/blob/master/config/custom_components/example.py). -*Note:* Home Assistant will use the directory that contains your config file as the directory that holds your customizations. By default this is the `./config` folder but this can be placed anywhere on the filesystem. +*Note:* Home Assistant will use the directory that contains your config file as the directory that holds your customizations. By default this is the `./config` folder but this can be pointed anywhere on the filesystem by using the `--config /YOUR/CONFIG/PATH/` argument. A component will be loaded on start if a section (ie. `[light]`) for it exists in the config file or a module that depends on the component is loaded. When loading a component Home Assistant will check the following paths: * <config file directory>/custom_components/<component name>.py * homeassistant/components/<component name>.py (built-in components) -Upon loading of a component it will be validated to see if the required fields (`DOMAIN`, `DEPENDENCIES`) and required method ( `setup(hass, config)` ) are available. - Once loaded, a component will only be setup if all dependencies can be loaded and are able to setup. Keep an eye on the logs to see if loading and setup of your component went well. *Warning:* You can override a built-in component by offering a component with the same name in your custom_components folder. This is not recommended and may lead to unexpected behavior! @@ -133,6 +133,8 @@ host=paulusschoutsen.nl Then in the setup-method of your component you will be able to refer to `config[example][host]` to get the value `paulusschoutsen.nl`. +If you want to get your component included with the Home Assistant distribution, please take a look at the [contributing page](https://github.com/balloob/home-assistant/blob/master/CONTRIBUTING.md). + ## Architecture diff --git a/build_frontend b/build_frontend index 4266f4ddd20..415ee2e894d 100755 --- a/build_frontend +++ b/build_frontend @@ -9,7 +9,8 @@ cp polymer/bower_components/webcomponentsjs/webcomponents.min.js . # Let Polymer refer to the minified JS version before we compile sed -i.bak 's/polymer\.js/polymer\.min\.js/' polymer/bower_components/polymer/polymer.html -vulcanize -o frontend.html --inline polymer/splash-login.html + +vulcanize -o frontend.html --inline --strip polymer/splash-login.html # Revert back the change to the Polymer component rm polymer/bower_components/polymer/polymer.html diff --git a/docs/screenshots.png b/docs/screenshots.png index 8b73211bfcd..09dff77c894 100644 Binary files a/docs/screenshots.png and b/docs/screenshots.png differ diff --git a/homeassistant/__init__.py b/homeassistant/__init__.py index 5e50380b7d6..7b836af8d05 100644 --- a/homeassistant/__init__.py +++ b/homeassistant/__init__.py @@ -6,7 +6,6 @@ Home Assistant is a Home Automation framework for observing the state of entities and react to changes. """ -import sys import os import time import logging @@ -25,6 +24,7 @@ DOMAIN = "homeassistant" SERVICE_HOMEASSISTANT_STOP = "stop" EVENT_HOMEASSISTANT_START = "homeassistant_start" +EVENT_HOMEASSISTANT_STOP = "homeassistant_stop" EVENT_STATE_CHANGED = "state_changed" EVENT_TIME_CHANGED = "time_changed" EVENT_CALL_SERVICE = "call_service" @@ -63,7 +63,7 @@ class HomeAssistant(object): self.services = ServiceRegistry(self.bus, pool) self.states = StateMachine(self.bus) - self.config_dir = os.getcwd() + self.config_dir = os.path.join(os.getcwd(), 'config') def get_config_path(self, path): """ Returns path to the file within the config dir. """ @@ -90,6 +90,8 @@ class HomeAssistant(object): except KeyboardInterrupt: break + self.stop() + def call_service(self, domain, service, service_data=None): """ Fires event to call specified service. """ event_data = service_data or {} @@ -108,7 +110,11 @@ class HomeAssistant(object): def track_state_change(self, entity_ids, action, from_state=None, to_state=None): - """ Track specific state changes. """ + """ + Track specific state changes. + entity_ids, from_state and to_state can be string or list. + Use list to match multiple. + """ from_state = _process_match_param(from_state) to_state = _process_match_param(to_state) @@ -131,14 +137,16 @@ class HomeAssistant(object): self.bus.listen(EVENT_STATE_CHANGED, state_listener) def track_point_in_time(self, action, point_in_time): - """ Adds a listener that fires once after a spefic point in time. """ + """ + Adds a listener that fires once at or after a spefic point in time. + """ @ft.wraps(action) def point_in_time_listener(event): """ Listens for matching time_changed events. """ now = event.data[ATTR_NOW] - if now > point_in_time and \ + if now >= point_in_time and \ not hasattr(point_in_time_listener, 'run'): # Set variable so that we will never run twice. @@ -219,10 +227,21 @@ class HomeAssistant(object): self.bus.listen(event_type, onetime_listener) + def stop(self): + """ Stops Home Assistant and shuts down all threads. """ + _LOGGER.info("Stopping") + + self.bus.fire(EVENT_HOMEASSISTANT_STOP) + + # Wait till all responses to homeassistant_stop are done + self._pool.block_till_done() + + self._pool.stop() + def _process_match_param(parameter): """ Wraps parameter in a list if it is not one and returns it. """ - if not parameter: + if not parameter or parameter == MATCH_ALL: return MATCH_ALL elif isinstance(parameter, list): return parameter @@ -240,7 +259,7 @@ def _matcher(subject, pattern): class JobPriority(util.OrderedEnum): """ Provides priorities for bus events. """ - # pylint: disable=no-init + # pylint: disable=no-init,too-few-public-methods EVENT_SERVICE = 1 EVENT_STATE = 2 @@ -289,7 +308,7 @@ def create_worker_pool(thread_count=POOL_NUM_THREAD): class EventOrigin(enum.Enum): """ Distinguish between origin of event. """ - # pylint: disable=no-init + # pylint: disable=no-init,too-few-public-methods local = "LOCAL" remote = "REMOTE" @@ -313,11 +332,11 @@ class Event(object): # pylint: disable=maybe-no-member if self.data: return "".format( - self.event_type, self.origin.value[0], + self.event_type, str(self.origin)[0], util.repr_helper(self.data)) else: return "".format(self.event_type, - self.origin.value[0]) + str(self.origin)[0]) class EventBus(object): @@ -381,9 +400,9 @@ class EventBus(object): if not self._listeners[event_type]: self._listeners.pop(event_type) - except (KeyError, AttributeError): + except (KeyError, ValueError): # KeyError is key event_type listener did not exist - # AttributeError if listener did not exist within event_type + # ValueError if listener did not exist within event_type pass @@ -593,6 +612,7 @@ class Timer(threading.Thread): self.daemon = True self._bus = hass.bus self.interval = interval or TIMER_INTERVAL + self._stop = threading.Event() # We want to be able to fire every time a minute starts (seconds=0). # We want this so other modules can use that to make sure they fire @@ -602,6 +622,9 @@ class Timer(threading.Thread): hass.listen_once_event(EVENT_HOMEASSISTANT_START, lambda event: self.start()) + hass.listen_once_event(EVENT_HOMEASSISTANT_STOP, + lambda event: self._stop.set()) + def run(self): """ Start the timer. """ @@ -612,7 +635,7 @@ class Timer(threading.Thread): calc_now = dt.datetime.now interval = self.interval - while True: + while not self._stop.isSet(): now = calc_now() # First check checks if we are not on a second matching the diff --git a/homeassistant/__main__.py b/homeassistant/__main__.py index 7e8952f55eb..c8d50151cea 100644 --- a/homeassistant/__main__.py +++ b/homeassistant/__main__.py @@ -20,7 +20,6 @@ except ImportError: def main(): """ Starts Home Assistant. Will create demo config if no config found. """ - tasks = ['serve', 'test'] parser = argparse.ArgumentParser() parser.add_argument( @@ -29,64 +28,49 @@ def main(): default="config", help="Directory that contains the Home Assistant configuration") - parser.add_argument( - '-t', '--task', - default=tasks[0], - choices=tasks, - help="Task to execute. Defaults to serve.") - args = parser.parse_args() - if args.task == tasks[1]: - # unittest does not like our command line arguments, remove them - sys.argv[1:] = [] + # Validate that all core dependencies are installed + import_fail = False - import unittest + for module in ['requests']: + try: + importlib.import_module(module) + except ImportError: + import_fail = True + print( + 'Fatal Error: Unable to find dependency {}'.format(module)) - unittest.main(module='homeassistant.test') + if import_fail: + print(("Install dependencies by running: " + "pip3 install -r requirements.txt")) + exit() - else: - # Validate that all core dependencies are installed - import_fail = False + # Test if configuration directory exists + config_dir = os.path.join(os.getcwd(), args.config) - for module in ['requests']: - try: - importlib.import_module(module) - except ImportError: - import_fail = True - print( - 'Fatal Error: Unable to find dependency {}'.format(module)) + if not os.path.isdir(config_dir): + print(('Fatal Error: Unable to find specified configuration ' + 'directory {} ').format(config_dir)) + sys.exit() - if import_fail: - print(("Install dependencies by running: " - "pip3 install -r requirements.txt")) - exit() + config_path = os.path.join(config_dir, 'home-assistant.conf') - # Test if configuration directory exists - config_dir = os.path.join(os.getcwd(), args.config) - - if not os.path.isdir(config_dir): - print(('Fatal Error: Unable to find specified configuration ' - 'directory {} ').format(config_dir)) + # Ensure a config file exists to make first time usage easier + if not os.path.isfile(config_path): + try: + with open(config_path, 'w') as conf: + conf.write("[http]\n") + conf.write("api_password=password\n\n") + conf.write("[demo]\n") + except IOError: + print(('Fatal Error: No configuration file found and unable ' + 'to write a default one to {}').format(config_path)) sys.exit() - config_path = os.path.join(config_dir, 'home-assistant.conf') - - # Ensure a config file exists to make first time usage easier - if not os.path.isfile(config_path): - try: - with open(config_path, 'w') as conf: - conf.write("[http]\n") - conf.write("api_password=password\n\n") - conf.write("[demo]\n") - except IOError: - print(('Fatal Error: No configuration file found and unable ' - 'to write a default one to {}').format(config_path)) - sys.exit() - - hass = bootstrap.from_config_file(config_path) - hass.start() - hass.block_till_stopped() + hass = bootstrap.from_config_file(config_path) + hass.start() + hass.block_till_stopped() if __name__ == "__main__": main() diff --git a/homeassistant/components/__init__.py b/homeassistant/components/__init__.py index 7d7ccca3f8b..a7eeadabc69 100644 --- a/homeassistant/components/__init__.py +++ b/homeassistant/components/__init__.py @@ -16,7 +16,6 @@ Each component should publish services only under its own domain. """ import itertools as it import logging -import importlib import homeassistant as ha import homeassistant.util as util @@ -60,7 +59,7 @@ def is_on(hass, entity_id=None): if entity_id: group = get_component('group') - entity_ids = group.expand_entity_ids([entity_id]) + entity_ids = group.expand_entity_ids(hass, [entity_id]) else: entity_ids = hass.states.entity_ids @@ -81,13 +80,19 @@ def is_on(hass, entity_id=None): return False -def turn_on(hass, **service_data): +def turn_on(hass, entity_id=None, **service_data): """ Turns specified entity on if possible. """ + if entity_id is not None: + service_data[ATTR_ENTITY_ID] = entity_id + hass.call_service(ha.DOMAIN, SERVICE_TURN_ON, service_data) -def turn_off(hass, **service_data): +def turn_off(hass, entity_id=None, **service_data): """ Turns specified entity off. """ + if entity_id is not None: + service_data[ATTR_ENTITY_ID] = entity_id + hass.call_service(ha.DOMAIN, SERVICE_TURN_OFF, service_data) @@ -140,7 +145,7 @@ class ToggleDevice(object): def get_state_attributes(self): """ Returns optional state attributes. """ - return None + return {} def update(self): """ Retrieve latest state from the real device. """ @@ -170,7 +175,6 @@ def setup(hass, config): def handle_turn_service(service): """ Method to handle calls to homeassistant.turn_on/off. """ - entity_ids = extract_entity_ids(hass, service) # Generic turn on/off method requires entity id diff --git a/homeassistant/components/chromecast.py b/homeassistant/components/chromecast.py index 1604e72f950..c5b0c180d99 100644 --- a/homeassistant/components/chromecast.py +++ b/homeassistant/components/chromecast.py @@ -6,6 +6,7 @@ Provides functionality to interact with Chromecasts. """ import logging +import homeassistant as ha import homeassistant.util as util import homeassistant.components as components @@ -113,8 +114,8 @@ def setup(hass, config): return False - if 'hosts' in config[DOMAIN]: - hosts = config[DOMAIN]['hosts'].split(",") + if ha.CONF_HOSTS in config[DOMAIN]: + hosts = config[DOMAIN][ha.CONF_HOSTS].split(",") # If no hosts given, scan for chromecasts else: diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 1b5cf1d9a6c..67127f7e3cd 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -111,7 +111,9 @@ def setup(hass, config): # Setup chromecast hass.states.set("chromecast.Living_Rm", "Netflix", - {'friendly_name': 'Living Room'}) + {'friendly_name': 'Living Room', + ATTR_ENTITY_PICTURE: + 'http://graph.facebook.com/KillBillMovie/picture'}) # Setup tellstick sensors hass.states.set("tellstick_sensor.Outside_temperature", "15.6", diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 1d5036fc1e4..85e7d206e3e 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -10,8 +10,6 @@ import os import csv from datetime import datetime, timedelta -import requests - import homeassistant as ha from homeassistant.loader import get_component import homeassistant.util as util @@ -176,10 +174,9 @@ class DeviceTracker(object): is_new_file = not os.path.isfile(known_dev_path) with open(known_dev_path, 'a') as outp: - _LOGGER.info(( - "Found {} new devices," - " updating {}").format(len(unknown_devices), - known_dev_path)) + _LOGGER.info( + "Found %d new devices, updating %s", + len(unknown_devices), known_dev_path) writer = csv.writer(outp) @@ -199,10 +196,9 @@ class DeviceTracker(object): 'picture': ""} except IOError: - _LOGGER.exception(( - "Error updating {}" - "with {} new devices").format(known_dev_path, - len(unknown_devices))) + _LOGGER.exception( + "Error updating %s with %d new devices", + known_dev_path, len(unknown_devices)) self.lock.release() @@ -268,9 +264,9 @@ class DeviceTracker(object): self.path_known_devices_file) # Remove entities that are no longer maintained - new_entity_ids = set([known_devices[device]['entity_id'] - for device in known_devices - if known_devices[device]['track']]) + new_entity_ids = set([known_devices[dev]['entity_id'] + for dev in known_devices + if known_devices[dev]['track']]) for entity_id in \ self.device_entity_ids - new_entity_ids: diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py index 7880e197d28..8c0ff0b763a 100644 --- a/homeassistant/components/group.py +++ b/homeassistant/components/group.py @@ -80,8 +80,8 @@ def get_entity_ids(hass, entity_id, domain_filter=None): entity_ids = hass.states.get(entity_id).attributes[ATTR_ENTITY_ID] if domain_filter: - return [entity_id for entity_id in entity_ids - if entity_id.startswith(domain_filter)] + return [ent_id for ent_id in entity_ids + if ent_id.startswith(domain_filter)] else: return entity_ids diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index 11e08ecdc62..8c6ddc1e5e0 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -85,8 +85,6 @@ from urllib.parse import urlparse, parse_qs import homeassistant as ha import homeassistant.remote as rem import homeassistant.util as util -from homeassistant.components import (STATE_ON, STATE_OFF, - SERVICE_TURN_ON, SERVICE_TURN_OFF) from . import frontend DOMAIN = "http" @@ -138,6 +136,10 @@ def setup(hass, config): lambda event: threading.Thread(target=server.start, daemon=True).start()) + hass.listen_once_event( + ha.EVENT_HOMEASSISTANT_STOP, + lambda event: server.shutdown()) + # If no local api set, set one with known information if isinstance(hass, rem.HomeAssistant) and hass.local_api is None: hass.local_api = \ @@ -148,6 +150,10 @@ def setup(hass, config): class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer): """ Handle HTTP requests in a threaded fashion. """ + # pylint: disable=too-few-public-methods + + allow_reuse_address = True + daemon_threads = True # pylint: disable=too-many-arguments def __init__(self, server_address, RequestHandlerClass, @@ -348,7 +354,8 @@ class RequestHandler(SimpleHTTPRequestHandler): else: app_url = "frontend-{}.html".format(frontend.VERSION) - write(("" + write(("" + "" "Home Assistant" "" "" diff --git a/homeassistant/components/http/frontend.py b/homeassistant/components/http/frontend.py index cf4e0b55d63..0392f4b5c78 100644 --- a/homeassistant/components/http/frontend.py +++ b/homeassistant/components/http/frontend.py @@ -1,2 +1,2 @@ """ DO NOT MODIFY. Auto-generated by build_frontend script """ -VERSION = "d23de9af256f9c1ab74fc3969fa410d3" +VERSION = "12ba7bca8ad0c196cb04ada4fe85a76b" diff --git a/homeassistant/components/http/www_static/frontend.html b/homeassistant/components/http/www_static/frontend.html index fb5d51f9546..322cba2605f 100644 --- a/homeassistant/components/http/www_static/frontend.html +++ b/homeassistant/components/http/www_static/frontend.html @@ -1,3112 +1,11 @@ - - + + - - - - - - - - + diff --git a/homeassistant/components/http/www_static/polymer/bower.json b/homeassistant/components/http/www_static/polymer/bower.json index a79b33b1381..7ed42ce8926 100644 --- a/homeassistant/components/http/www_static/polymer/bower.json +++ b/homeassistant/components/http/www_static/polymer/bower.json @@ -4,15 +4,11 @@ "authors": [ "Paulus Schoutsen " ], - "main": "index.htm", + "main": "splash-login.html", "license": "MIT", "private": true, "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" + "bower_components" ], "dependencies": { "webcomponentsjs": "Polymer/webcomponentsjs#~0.5.1", @@ -24,6 +20,7 @@ "core-item": "Polymer/core-item#~0.5.1", "core-input": "Polymer/core-input#~0.5.1", "core-icons": "polymer/core-icons#~0.5.1", + "core-image": "polymer/core-image#~0.5.1", "paper-toast": "Polymer/paper-toast#~0.5.1", "paper-dialog": "Polymer/paper-dialog#~0.5.1", "paper-spinner": "Polymer/paper-spinner#~0.5.1", diff --git a/homeassistant/components/http/www_static/polymer/event-fire-dialog.html b/homeassistant/components/http/www_static/polymer/event-fire-dialog.html index 10958a62f4a..db3b5a9653d 100644 --- a/homeassistant/components/http/www_static/polymer/event-fire-dialog.html +++ b/homeassistant/components/http/www_static/polymer/event-fire-dialog.html @@ -29,6 +29,13 @@ } @media all and (max-width: 620px) { + paper-action-dialog { + margin: 0; + width: 100%; + height: calc(100% - 64px); + top: 64px; + } + .eventContainer { display: none; } diff --git a/homeassistant/components/http/www_static/polymer/home-assistant-main.html b/homeassistant/components/http/www_static/polymer/home-assistant-main.html index a2b9138e8a0..cc89ed736ff 100644 --- a/homeassistant/components/http/www_static/polymer/home-assistant-main.html +++ b/homeassistant/components/http/www_static/polymer/home-assistant-main.html @@ -12,59 +12,83 @@