From 5581c6295e0e8d34b40cfa5d2ebec0b8b4711c3d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 13 Jul 2017 10:19:59 -0700 Subject: [PATCH 001/118] Fix iFrame panel test --- tests/components/test_panel_iframe.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/components/test_panel_iframe.py b/tests/components/test_panel_iframe.py index ec1e5bf365075..5f9cdcfa57ceb 100644 --- a/tests/components/test_panel_iframe.py +++ b/tests/components/test_panel_iframe.py @@ -53,9 +53,7 @@ def test_correct_config(self): }, }) - # 5 dev tools + map are automatically loaded + 2 iframe panels - assert len(self.hass.data[frontend.DATA_PANELS]) == 8 - assert self.hass.data[frontend.DATA_PANELS]['router'] == { + assert self.hass.data[frontend.DATA_PANELS].get('router') == { 'component_name': 'iframe', 'config': {'url': 'http://192.168.1.1'}, 'icon': 'mdi:network-wireless', @@ -64,7 +62,7 @@ def test_correct_config(self): 'url_path': 'router' } - assert self.hass.data[frontend.DATA_PANELS]['weather'] == { + assert self.hass.data[frontend.DATA_PANELS].get('weather') == { 'component_name': 'iframe', 'config': {'url': 'https://www.wunderground.com/us/ca/san-diego'}, 'icon': 'mdi:weather', From ba019c799a5807049e5143da3b6a0645131eae7e Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Fri, 14 Jul 2017 04:26:21 +0200 Subject: [PATCH 002/118] Make deps directory persistent over upgrades (#7801) * Use pip install --user if venv not active * Set PYTHONUSERBASE to deps directory, when installing with --user option. * Reset --prefix option to workaround incompatability when installing with --user option. This requires pip version 8.0.0 or greater. * Require pip version 8.0.3. * Do not delete deps directory on home assistant upgrade. * Fix local lib mount and check package exist. * Update and add tests * Fix upgrade from before version 0.46 * Extract function to get user site * Add function(s) to package util to get user site. * Use async subprocess for one of the functions to get user site. * Add function to package util to check if virtual environment is active. * Add and update tests. * Update version for last removal of deps dir * Address comments * Rewrite package util tests with pytest * Rewrite all existing unittest class based tests for package util as test functions, and capitalize pytest fixtures. * Add test for installing with target inside venv. --- homeassistant/bootstrap.py | 24 +- homeassistant/config.py | 10 +- homeassistant/package_constraints.txt | 2 +- homeassistant/scripts/__init__.py | 12 +- homeassistant/setup.py | 4 + homeassistant/util/package.py | 70 ++++-- requirements_all.txt | 2 +- setup.py | 2 +- tests/test_config.py | 52 ++-- tests/test_setup.py | 37 ++- tests/util/test_package.py | 330 ++++++++++++++++---------- 11 files changed, 371 insertions(+), 174 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 5f64fd447a6e6..a90a96e4fa006 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -19,6 +19,7 @@ from homeassistant.setup import async_setup_component import homeassistant.loader as loader from homeassistant.util.logging import AsyncHandler +from homeassistant.util.package import async_get_user_site, get_user_site from homeassistant.util.yaml import clear_secret_cache from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.signal import async_register_signal_handling @@ -48,7 +49,8 @@ def from_config_dict(config: Dict[str, Any], if config_dir is not None: config_dir = os.path.abspath(config_dir) hass.config.config_dir = config_dir - mount_local_lib_path(config_dir) + hass.loop.run_until_complete( + async_mount_local_lib_path(config_dir, hass.loop)) # run task hass = hass.loop.run_until_complete( @@ -183,7 +185,7 @@ def async_from_config_file(config_path: str, # Set config dir to directory holding config file config_dir = os.path.abspath(os.path.dirname(config_path)) hass.config.config_dir = config_dir - yield from hass.async_add_job(mount_local_lib_path, config_dir) + yield from async_mount_local_lib_path(config_dir, hass.loop) async_enable_logging(hass, verbose, log_rotate_days) @@ -276,11 +278,23 @@ def async_stop_async_handler(event): def mount_local_lib_path(config_dir: str) -> str: + """Add local library to Python Path.""" + deps_dir = os.path.join(config_dir, 'deps') + lib_dir = get_user_site(deps_dir) + if lib_dir not in sys.path: + sys.path.insert(0, lib_dir) + return deps_dir + + +@asyncio.coroutine +def async_mount_local_lib_path(config_dir: str, + loop: asyncio.AbstractEventLoop) -> str: """Add local library to Python Path. - Async friendly. + This function is a coroutine. """ deps_dir = os.path.join(config_dir, 'deps') - if deps_dir not in sys.path: - sys.path.insert(0, os.path.join(config_dir, 'deps')) + lib_dir = yield from async_get_user_site(deps_dir, loop=loop) + if lib_dir not in sys.path: + sys.path.insert(0, lib_dir) return deps_dir diff --git a/homeassistant/config.py b/homeassistant/config.py index d91854c516214..cb8d0b442c168 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -1,6 +1,8 @@ """Module to help with parsing and generating configuration files.""" import asyncio from collections import OrderedDict +# pylint: disable=no-name-in-module +from distutils.version import LooseVersion # pylint: disable=import-error import logging import os import re @@ -295,9 +297,11 @@ def process_ha_config_upgrade(hass): _LOGGER.info('Upgrading config directory from %s to %s', conf_version, __version__) - lib_path = hass.config.path('deps') - if os.path.isdir(lib_path): - shutil.rmtree(lib_path) + if LooseVersion(conf_version) < LooseVersion('0.49'): + # 0.49 introduced persistent deps dir. + lib_path = hass.config.path('deps') + if os.path.isdir(lib_path): + shutil.rmtree(lib_path) with open(version_path, 'wt') as outp: outp.write(__version__) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 1de3671a2962a..9414bc98dc861 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -1,7 +1,7 @@ requests==2.14.2 pyyaml>=3.11,<4 pytz>=2017.02 -pip>=7.1.0 +pip>=8.0.3 jinja2>=2.9.5 voluptuous==0.10.5 typing>=3,<4 diff --git a/homeassistant/scripts/__init__.py b/homeassistant/scripts/__init__.py index af9e00626dd7a..2324613acfb83 100644 --- a/homeassistant/scripts/__init__.py +++ b/homeassistant/scripts/__init__.py @@ -7,7 +7,8 @@ from typing import List from homeassistant.config import get_default_config_dir -from homeassistant.util.package import install_package +from homeassistant.const import CONSTRAINT_FILE +from homeassistant.util.package import install_package, is_virtual_env from homeassistant.bootstrap import mount_local_lib_path @@ -40,7 +41,14 @@ def run(args: List) -> int: logging.basicConfig(stream=sys.stdout, level=logging.INFO) for req in getattr(script, 'REQUIREMENTS', []): - if not install_package(req, target=deps_dir): + if is_virtual_env(): + returncode = install_package(req, constraints=os.path.join( + os.path.dirname(__file__), os.pardir, CONSTRAINT_FILE)) + else: + returncode = install_package( + req, target=deps_dir, constraints=os.path.join( + os.path.dirname(__file__), os.pardir, CONSTRAINT_FILE)) + if not returncode: print('Aborting scipt, could not install dependency', req) return 1 diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 285a575514513..3594399281ffb 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -77,6 +77,10 @@ def _async_process_requirements(hass: core.HomeAssistant, name: str, def pip_install(mod): """Install packages.""" + if pkg_util.is_virtual_env(): + return pkg_util.install_package( + mod, constraints=os.path.join( + os.path.dirname(__file__), CONSTRAINT_FILE)) return pkg_util.install_package( mod, target=hass.config.path('deps'), constraints=os.path.join( diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index a5a863b088080..4736c1acc1a32 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -1,4 +1,5 @@ """Helpers to install PyPi packages.""" +import asyncio import logging import os import sys @@ -24,20 +25,26 @@ def install_package(package: str, upgrade: bool=True, """ # Not using 'import pip; pip.main([])' because it breaks the logger with INSTALL_LOCK: - if check_package_exists(package, target): + if check_package_exists(package): return True - _LOGGER.info("Attempting install of %s", package) + _LOGGER.info('Attempting install of %s', package) + env = os.environ.copy() args = [sys.executable, '-m', 'pip', 'install', '--quiet', package] if upgrade: args.append('--upgrade') - if target: - args += ['--target', os.path.abspath(target)] - if constraints is not None: args += ['--constraint', constraints] - - process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) + if target: + assert not is_virtual_env() + # This only works if not running in venv + args += ['--user'] + env['PYTHONUSERBASE'] = os.path.abspath(target) + if sys.platform != 'win32': + # Workaround for incompatible prefix setting + # See http://stackoverflow.com/a/4495175 + args += ['--prefix='] + process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) _, stderr = process.communicate() if process.returncode != 0: _LOGGER.error("Unable to install package %s: %s", @@ -47,7 +54,7 @@ def install_package(package: str, upgrade: bool=True, return True -def check_package_exists(package: str, lib_dir: str) -> bool: +def check_package_exists(package: str) -> bool: """Check if a package is installed globally or in lib_dir. Returns True when the requirement is met. @@ -59,12 +66,43 @@ def check_package_exists(package: str, lib_dir: str) -> bool: # This is a zip file req = pkg_resources.Requirement.parse(urlparse(package).fragment) - # Check packages from lib dir - if lib_dir is not None: - if any(dist in req for dist in - pkg_resources.find_distributions(lib_dir)): - return True + env = pkg_resources.Environment() + return any(dist in req for dist in env[req.project_name]) + + +def is_virtual_env() -> bool: + """Return true if environment is a virtual environment.""" + return hasattr(sys, 'real_prefix') - # Check packages from global + virtual environment - # pylint: disable=not-an-iterable - return any(dist in req for dist in pkg_resources.working_set) + +def _get_user_site(deps_dir: str) -> tuple: + """Get arguments and environment for subprocess used in get_user_site.""" + env = os.environ.copy() + env['PYTHONUSERBASE'] = os.path.abspath(deps_dir) + args = [sys.executable, '-m', 'site', '--user-site'] + return args, env + + +def get_user_site(deps_dir: str) -> str: + """Return user local library path.""" + args, env = _get_user_site(deps_dir) + process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) + stdout, _ = process.communicate() + lib_dir = stdout.decode().strip() + return lib_dir + + +@asyncio.coroutine +def async_get_user_site(deps_dir: str, loop: asyncio.AbstractEventLoop) -> str: + """Return user local library path. + + This function is a coroutine. + """ + args, env = _get_user_site(deps_dir) + process = yield from asyncio.create_subprocess_exec( + *args, loop=loop, stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL, + env=env) + stdout, _ = yield from process.communicate() + lib_dir = stdout.decode().strip() + return lib_dir diff --git a/requirements_all.txt b/requirements_all.txt index d4e4a30add725..60d25a4104949 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2,7 +2,7 @@ requests==2.14.2 pyyaml>=3.11,<4 pytz>=2017.02 -pip>=7.1.0 +pip>=8.0.3 jinja2>=2.9.5 voluptuous==0.10.5 typing>=3,<4 diff --git a/setup.py b/setup.py index 4476bc2f9f02b..d19a074889a90 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ 'requests==2.14.2', 'pyyaml>=3.11,<4', 'pytz>=2017.02', - 'pip>=7.1.0', + 'pip>=8.0.3', 'jinja2>=2.9.5', 'voluptuous==0.10.5', 'typing>=3,<4', diff --git a/tests/test_config.py b/tests/test_config.py index 00b631a2f788a..eba98795fe922 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -260,40 +260,30 @@ def test_entity_customization(self): @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') def test_remove_lib_on_upgrade(self, mock_os, mock_shutil): - """Test removal of library on upgrade.""" - ha_version = '0.7.0' - + """Test removal of library on upgrade from before 0.49.""" + ha_version = '0.48.0' mock_os.path.isdir = mock.Mock(return_value=True) - mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): opened_file = mock_open.return_value # pylint: disable=no-member opened_file.readline.return_value = ha_version - self.hass.config.path = mock.Mock() - config_util.process_ha_config_upgrade(self.hass) - hass_path = self.hass.config.path.return_value self.assertEqual(mock_os.path.isdir.call_count, 1) self.assertEqual( mock_os.path.isdir.call_args, mock.call(hass_path) ) - self.assertEqual(mock_shutil.rmtree.call_count, 1) self.assertEqual( mock_shutil.rmtree.call_args, mock.call(hass_path) ) - @mock.patch('homeassistant.config.shutil') - @mock.patch('homeassistant.config.os') - def test_not_remove_lib_if_not_upgrade(self, mock_os, mock_shutil): - """Test removal of library with no upgrade.""" - ha_version = __version__ - - mock_os.path.isdir = mock.Mock(return_value=True) + def test_process_config_upgrade(self): + """Test update of version on upgrade.""" + ha_version = '0.8.0' mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): @@ -301,12 +291,38 @@ def test_not_remove_lib_if_not_upgrade(self, mock_os, mock_shutil): # pylint: disable=no-member opened_file.readline.return_value = ha_version - self.hass.config.path = mock.Mock() + config_util.process_ha_config_upgrade(self.hass) + + self.assertEqual(opened_file.write.call_count, 1) + self.assertEqual( + opened_file.write.call_args, mock.call(__version__) + ) + + def test_config_upgrade_same_version(self): + """Test no update of version on no upgrade.""" + ha_version = __version__ + + mock_open = mock.mock_open() + with mock.patch('homeassistant.config.open', mock_open, create=True): + opened_file = mock_open.return_value + # pylint: disable=no-member + opened_file.readline.return_value = ha_version config_util.process_ha_config_upgrade(self.hass) - assert mock_os.path.isdir.call_count == 0 - assert mock_shutil.rmtree.call_count == 0 + assert opened_file.write.call_count == 0 + + def test_config_upgrade_no_file(self): + """Test update of version on upgrade, with no version file.""" + mock_open = mock.mock_open() + mock_open.side_effect = [FileNotFoundError(), mock.DEFAULT] + with mock.patch('homeassistant.config.open', mock_open, create=True): + opened_file = mock_open.return_value + # pylint: disable=no-member + config_util.process_ha_config_upgrade(self.hass) + self.assertEqual(opened_file.write.call_count, 1) + self.assertEqual( + opened_file.write.call_args, mock.call(__version__)) @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') diff --git a/tests/test_setup.py b/tests/test_setup.py index 291dfdd741fc1..742df86242f21 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -9,7 +9,7 @@ import voluptuous as vol from homeassistant.core import callback -from homeassistant.const import EVENT_HOMEASSISTANT_START +from homeassistant.const import EVENT_HOMEASSISTANT_START, CONSTRAINT_FILE import homeassistant.config as config_util from homeassistant import setup, loader import homeassistant.util.dt as dt_util @@ -203,6 +203,41 @@ def test_component_not_installed_if_requirement_fails(self, mock_install): assert not setup.setup_component(self.hass, 'comp') assert 'comp' not in self.hass.config.components + @mock.patch('homeassistant.setup.os.path.dirname') + @mock.patch('homeassistant.util.package.sys') + @mock.patch('homeassistant.util.package.install_package', + return_value=True) + def test_requirement_installed_in_venv( + self, mock_install, mock_sys, mock_dirname): + """Test requirement installed in virtual environment.""" + mock_sys.real_prefix = 'pythonpath' + mock_dirname.return_value = 'ha_package_path' + self.hass.config.skip_pip = False + loader.set_component( + 'comp', MockModule('comp', requirements=['package==0.0.1'])) + assert setup.setup_component(self.hass, 'comp') + assert 'comp' in self.hass.config.components + assert mock_install.call_args == mock.call( + 'package==0.0.1', + constraints=os.path.join('ha_package_path', CONSTRAINT_FILE)) + + @mock.patch('homeassistant.setup.os.path.dirname') + @mock.patch('homeassistant.util.package.sys', spec=object()) + @mock.patch('homeassistant.util.package.install_package', + return_value=True) + def test_requirement_installed_in_deps( + self, mock_install, mock_sys, mock_dirname): + """Test requirement installed in deps directory.""" + mock_dirname.return_value = 'ha_package_path' + self.hass.config.skip_pip = False + loader.set_component( + 'comp', MockModule('comp', requirements=['package==0.0.1'])) + assert setup.setup_component(self.hass, 'comp') + assert 'comp' in self.hass.config.components + assert mock_install.call_args == mock.call( + 'package==0.0.1', target=self.hass.config.path('deps'), + constraints=os.path.join('ha_package_path', CONSTRAINT_FILE)) + def test_component_not_setup_twice_if_loaded_during_other_setup(self): """Test component setup while waiting for lock is not setup twice.""" result = [] diff --git a/tests/util/test_package.py b/tests/util/test_package.py index e0682d79f57be..7ca1315c2e1e3 100644 --- a/tests/util/test_package.py +++ b/tests/util/test_package.py @@ -1,11 +1,13 @@ """Test Home Assistant package util methods.""" +import asyncio +import logging import os -import pkg_resources -import unittest - +import sys from subprocess import PIPE -from distutils.sysconfig import get_python_lib -from unittest.mock import call, patch, Mock +from unittest.mock import MagicMock, call, patch + +import pkg_resources +import pytest import homeassistant.util.package as package @@ -18,124 +20,200 @@ .format(os.path.join(RESOURCE_DIR, 'pyhelloworld3.zip'), TEST_NEW_REQ) -@patch('homeassistant.util.package.Popen') -@patch('homeassistant.util.package.check_package_exists') -class TestPackageUtilInstallPackage(unittest.TestCase): - """Test for homeassistant.util.package module.""" - - def setUp(self): - """Setup the tests.""" - self.mock_process = Mock() - self.mock_process.communicate.return_value = (b'message', b'error') - self.mock_process.returncode = 0 - - def test_install_existing_package(self, mock_exists, mock_popen): - """Test an install attempt on an existing package.""" - mock_popen.return_value = self.mock_process - mock_exists.return_value = True - - self.assertTrue(package.install_package(TEST_EXIST_REQ)) - - self.assertEqual(mock_exists.call_count, 1) - self.assertEqual(mock_exists.call_args, call(TEST_EXIST_REQ, None)) - - self.assertEqual(self.mock_process.communicate.call_count, 0) - - @patch('homeassistant.util.package.sys') - def test_install(self, mock_sys, mock_exists, mock_popen): - """Test an install attempt on a package that doesn't exist.""" - mock_exists.return_value = False - mock_popen.return_value = self.mock_process - - self.assertTrue(package.install_package(TEST_NEW_REQ, False)) - - self.assertEqual(mock_exists.call_count, 1) - - self.assertEqual(self.mock_process.communicate.call_count, 1) - self.assertEqual(mock_popen.call_count, 1) - self.assertEqual( - mock_popen.call_args, - call([ - mock_sys.executable, '-m', 'pip', 'install', '--quiet', - TEST_NEW_REQ - ], stdin=PIPE, stdout=PIPE, stderr=PIPE) - ) - - @patch('homeassistant.util.package.sys') - def test_install_upgrade(self, mock_sys, mock_exists, mock_popen): - """Test an upgrade attempt on a package.""" - mock_exists.return_value = False - mock_popen.return_value = self.mock_process - - self.assertTrue(package.install_package(TEST_NEW_REQ)) - - self.assertEqual(mock_exists.call_count, 1) - - self.assertEqual(self.mock_process.communicate.call_count, 1) - self.assertEqual(mock_popen.call_count, 1) - self.assertEqual( - mock_popen.call_args, - call([ - mock_sys.executable, '-m', 'pip', 'install', '--quiet', - TEST_NEW_REQ, '--upgrade' - ], stdin=PIPE, stdout=PIPE, stderr=PIPE) - ) - - @patch('homeassistant.util.package.sys') - def test_install_target(self, mock_sys, mock_exists, mock_popen): - """Test an install with a target.""" - target = 'target_folder' - mock_exists.return_value = False - mock_popen.return_value = self.mock_process - - self.assertTrue( - package.install_package(TEST_NEW_REQ, False, target=target) - ) - - self.assertEqual(mock_exists.call_count, 1) - - self.assertEqual(self.mock_process.communicate.call_count, 1) - self.assertEqual(mock_popen.call_count, 1) - self.assertEqual( - mock_popen.call_args, - call([ - mock_sys.executable, '-m', 'pip', 'install', '--quiet', - TEST_NEW_REQ, '--target', os.path.abspath(target) - ], stdin=PIPE, stdout=PIPE, stderr=PIPE) - ) - - @patch('homeassistant.util.package._LOGGER') - @patch('homeassistant.util.package.sys') - def test_install_error(self, mock_sys, mock_logger, mock_exists, - mock_popen): - """Test an install with a target.""" - mock_exists.return_value = False - mock_popen.return_value = self.mock_process - self.mock_process.returncode = 1 - - self.assertFalse(package.install_package(TEST_NEW_REQ)) - - self.assertEqual(mock_logger.error.call_count, 1) - - -class TestPackageUtilCheckPackageExists(unittest.TestCase): - """Test for homeassistant.util.package module.""" - - def test_check_package_global(self): - """Test for a globally-installed package.""" - installed_package = list(pkg_resources.working_set)[0].project_name - - self.assertTrue(package.check_package_exists(installed_package, None)) - - def test_check_package_local(self): - """Test for a locally-installed package.""" - lib_dir = get_python_lib() - installed_package = list(pkg_resources.working_set)[0].project_name - - self.assertTrue( - package.check_package_exists(installed_package, lib_dir) - ) - - def test_check_package_zip(self): - """Test for an installed zip package.""" - self.assertFalse(package.check_package_exists(TEST_ZIP_REQ, None)) +@pytest.fixture +def mock_sys(): + """Mock sys.""" + with patch('homeassistant.util.package.sys', spec=object) as sys_mock: + sys_mock.executable = 'python3' + yield sys_mock + + +@pytest.fixture +def mock_exists(): + """Mock check_package_exists.""" + with patch('homeassistant.util.package.check_package_exists') as mock: + mock.return_value = False + yield mock + + +@pytest.fixture +def deps_dir(): + """Return path to deps directory.""" + return os.path.abspath('/deps_dir') + + +@pytest.fixture +def lib_dir(deps_dir): + """Return path to lib directory.""" + return os.path.join(deps_dir, 'lib_dir') + + +@pytest.fixture +def mock_popen(lib_dir): + """Return a Popen mock.""" + with patch('homeassistant.util.package.Popen') as popen_mock: + popen_mock.return_value.communicate.return_value = ( + bytes(lib_dir, 'utf-8'), b'error') + popen_mock.return_value.returncode = 0 + yield popen_mock + + +@pytest.fixture +def mock_env_copy(): + """Mock os.environ.copy.""" + with patch('homeassistant.util.package.os.environ.copy') as env_copy: + env_copy.return_value = {} + yield env_copy + + +@asyncio.coroutine +def mock_async_subprocess(): + """Return an async Popen mock.""" + async_popen = MagicMock() + + @asyncio.coroutine + def communicate(input=None): + """Communicate mock.""" + stdout = bytes('/deps_dir/lib_dir', 'utf-8') + return (stdout, None) + + async_popen.communicate = communicate + return async_popen + + +def test_install_existing_package(mock_exists, mock_popen): + """Test an install attempt on an existing package.""" + mock_exists.return_value = True + assert package.install_package(TEST_EXIST_REQ) + assert mock_exists.call_count == 1 + assert mock_exists.call_args == call(TEST_EXIST_REQ) + assert mock_popen.return_value.communicate.call_count == 0 + + +def test_install(mock_sys, mock_exists, mock_popen, mock_env_copy): + """Test an install attempt on a package that doesn't exist.""" + env = mock_env_copy() + assert package.install_package(TEST_NEW_REQ, False) + assert mock_exists.call_count == 1 + assert mock_popen.call_count == 1 + assert ( + mock_popen.call_args == + call([ + mock_sys.executable, '-m', 'pip', 'install', '--quiet', + TEST_NEW_REQ + ], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) + ) + assert mock_popen.return_value.communicate.call_count == 1 + + +def test_install_upgrade(mock_sys, mock_exists, mock_popen, mock_env_copy): + """Test an upgrade attempt on a package.""" + env = mock_env_copy() + assert package.install_package(TEST_NEW_REQ) + assert mock_exists.call_count == 1 + assert mock_popen.call_count == 1 + assert ( + mock_popen.call_args == + call([ + mock_sys.executable, '-m', 'pip', 'install', '--quiet', + TEST_NEW_REQ, '--upgrade' + ], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) + ) + assert mock_popen.return_value.communicate.call_count == 1 + + +def test_install_target(mock_sys, mock_exists, mock_popen, mock_env_copy): + """Test an install with a target.""" + target = 'target_folder' + env = mock_env_copy() + env['PYTHONUSERBASE'] = os.path.abspath(target) + mock_sys.platform = 'linux' + args = [ + mock_sys.executable, '-m', 'pip', 'install', '--quiet', + TEST_NEW_REQ, '--user', '--prefix='] + + assert package.install_package(TEST_NEW_REQ, False, target=target) + assert mock_exists.call_count == 1 + assert mock_popen.call_count == 1 + assert ( + mock_popen.call_args == + call(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) + ) + assert mock_popen.return_value.communicate.call_count == 1 + + +def test_install_target_venv(mock_sys, mock_exists, mock_popen, mock_env_copy): + """Test an install with a target in a virtual environment.""" + target = 'target_folder' + mock_sys.real_prefix = '/usr' + with pytest.raises(AssertionError): + package.install_package(TEST_NEW_REQ, False, target=target) + + +def test_install_error(caplog, mock_sys, mock_exists, mock_popen): + """Test an install with a target.""" + caplog.set_level(logging.WARNING) + mock_popen.return_value.returncode = 1 + assert not package.install_package(TEST_NEW_REQ) + assert len(caplog.records) == 1 + for record in caplog.records: + assert record.levelname == 'ERROR' + + +def test_install_constraint(mock_sys, mock_exists, mock_popen, mock_env_copy): + """Test install with constraint file on not installed package.""" + env = mock_env_copy() + constraints = 'constraints_file.txt' + assert package.install_package( + TEST_NEW_REQ, False, constraints=constraints) + assert mock_exists.call_count == 1 + assert mock_popen.call_count == 1 + assert ( + mock_popen.call_args == + call([ + mock_sys.executable, '-m', 'pip', 'install', '--quiet', + TEST_NEW_REQ, '--constraint', constraints + ], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) + ) + assert mock_popen.return_value.communicate.call_count == 1 + + +def test_check_package_global(): + """Test for an installed package.""" + installed_package = list(pkg_resources.working_set)[0].project_name + assert package.check_package_exists(installed_package) + + +def test_check_package_zip(): + """Test for an installed zip package.""" + assert not package.check_package_exists(TEST_ZIP_REQ) + + +def test_get_user_site(deps_dir, lib_dir, mock_popen, mock_env_copy): + """Test get user site directory.""" + env = mock_env_copy() + env['PYTHONUSERBASE'] = os.path.abspath(deps_dir) + args = [sys.executable, '-m', 'site', '--user-site'] + ret = package.get_user_site(deps_dir) + assert mock_popen.call_count == 1 + assert mock_popen.call_args == call( + args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) + assert ret == lib_dir + + +@asyncio.coroutine +def test_async_get_user_site(hass, mock_env_copy): + """Test async get user site directory.""" + deps_dir = '/deps_dir' + env = mock_env_copy() + env['PYTHONUSERBASE'] = os.path.abspath(deps_dir) + args = [sys.executable, '-m', 'site', '--user-site'] + with patch('homeassistant.util.package.asyncio.create_subprocess_exec', + return_value=mock_async_subprocess()) as popen_mock: + ret = yield from package.async_get_user_site(deps_dir, hass.loop) + assert popen_mock.call_count == 1 + assert popen_mock.call_args == call( + *args, loop=hass.loop, stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL, + env=env) + assert ret == os.path.join(deps_dir, 'lib_dir') From 4fde0ffe9c1aa246ca4689aa9b239a991c012448 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Fri, 14 Jul 2017 04:38:36 +0200 Subject: [PATCH 003/118] LIFX: support for multizone (#8399) * Make aiolifx modules easily available * Use aiolifx features_map for deciding bulb features Also move the feature detection out of Light so it is available even during the initial detection. * Move each LIFX light type to a separate class * Simplify AwaitAioLIFX This has become possible with recent aiolifx that calls the callback even when a message is lost. Now the wrapper can be used also before a Light is added though the register callback then has to become a coroutine. * Refactor send_color * Add support for multizone This lets lifx_set_state work on individual zones. Also update to aiolifx_effects 0.1.1 that restores the state for individual zones. --- homeassistant/components/light/lifx.py | 269 ++++++++++++------- homeassistant/components/light/services.yaml | 4 + requirements_all.txt | 2 +- 3 files changed, 181 insertions(+), 94 deletions(-) diff --git a/homeassistant/components/light/lifx.py b/homeassistant/components/light/lifx.py index 0c5535ea8eaea..a32aa0c4a6b6f 100644 --- a/homeassistant/components/light/lifx.py +++ b/homeassistant/components/light/lifx.py @@ -33,7 +33,7 @@ _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['aiolifx==0.5.2', 'aiolifx_effects==0.1.0'] +REQUIREMENTS = ['aiolifx==0.5.2', 'aiolifx_effects==0.1.1'] UDP_BROADCAST_PORT = 56700 @@ -53,10 +53,12 @@ SERVICE_LIFX_SET_STATE = 'lifx_set_state' ATTR_INFRARED = 'infrared' +ATTR_ZONES = 'zones' ATTR_POWER = 'power' LIFX_SET_STATE_SCHEMA = LIGHT_TURN_ON_SCHEMA.extend({ ATTR_INFRARED: vol.All(vol.Coerce(int), vol.Clamp(min=0, max=255)), + ATTR_ZONES: vol.All(cv.ensure_list, [cv.positive_int]), ATTR_POWER: cv.boolean, }) @@ -112,11 +114,21 @@ }) +def aiolifx(): + """Return the aiolifx module.""" + import aiolifx as aiolifx_module + return aiolifx_module + + +def aiolifx_effects(): + """Return the aiolifx_effects module.""" + import aiolifx_effects as aiolifx_effects_module + return aiolifx_effects_module + + @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the LIFX platform.""" - import aiolifx - if sys.platform == 'win32': _LOGGER.warning("The lifx platform is known to not work on Windows. " "Consider using the lifx_legacy platform instead") @@ -124,7 +136,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): server_addr = config.get(CONF_SERVER) lifx_manager = LIFXManager(hass, async_add_devices) - lifx_discovery = aiolifx.LifxDiscovery( + lifx_discovery = aiolifx().LifxDiscovery( hass.loop, lifx_manager, discovery_interval=DISCOVERY_INTERVAL, @@ -145,6 +157,16 @@ def cleanup(event): return True +def lifxwhite(device): + """Return whether this is a white-only bulb.""" + return not aiolifx().products.features_map[device.product]["color"] + + +def lifxmultizone(device): + """Return whether this is a multizone bulb/strip.""" + return aiolifx().products.features_map[device.product]["multizone"] + + def find_hsbk(**kwargs): """Find the desired color from a number of possible inputs.""" hue, saturation, brightness, kelvin = [None]*4 @@ -187,11 +209,10 @@ class LIFXManager(object): def __init__(self, hass, async_add_devices): """Initialize the light.""" - import aiolifx_effects self.entities = {} self.hass = hass self.async_add_devices = async_add_devices - self.effects_conductor = aiolifx_effects.Conductor(loop=hass.loop) + self.effects_conductor = aiolifx_effects().Conductor(loop=hass.loop) descriptions = load_yaml_config_file( path.join(path.dirname(__file__), 'services.yaml')) @@ -245,11 +266,10 @@ def async_service_handle(service): @asyncio.coroutine def start_effect(self, entities, service, **kwargs): """Start a light effect on entities.""" - import aiolifx_effects devices = list(map(lambda l: l.device, entities)) if service == SERVICE_EFFECT_PULSE: - effect = aiolifx_effects.EffectPulse( + effect = aiolifx_effects().EffectPulse( power_on=kwargs.get(ATTR_POWER_ON), period=kwargs.get(ATTR_PERIOD), cycles=kwargs.get(ATTR_CYCLES), @@ -264,7 +284,7 @@ def start_effect(self, entities, service, **kwargs): if ATTR_BRIGHTNESS in kwargs: brightness = convert_8_to_16(kwargs[ATTR_BRIGHTNESS]) - effect = aiolifx_effects.EffectColorloop( + effect = aiolifx_effects().EffectColorloop( power_on=kwargs.get(ATTR_POWER_ON), period=kwargs.get(ATTR_PERIOD), change=kwargs.get(ATTR_CHANGE), @@ -289,32 +309,39 @@ def service_to_entities(self, service): @callback def register(self, device): - """Handle for newly detected bulb.""" + """Handler for newly detected bulb.""" + self.hass.async_add_job(self.async_register(device)) + + @asyncio.coroutine + def async_register(self, device): + """Handler for newly detected bulb.""" if device.mac_addr in self.entities: entity = self.entities[device.mac_addr] - entity.device = device entity.registered = True _LOGGER.debug("%s register AGAIN", entity.who) - self.hass.async_add_job(entity.async_update_ha_state()) + yield from entity.async_update() + yield from entity.async_update_ha_state() else: _LOGGER.debug("%s register NEW", device.ip_addr) device.timeout = MESSAGE_TIMEOUT device.retry_count = MESSAGE_RETRIES device.unregister_timeout = UNAVAILABLE_GRACE - device.get_version(self.got_version) - @callback - def got_version(self, device, msg): - """Request current color setting once we have the product version.""" - device.get_color(self.ready) + ack = AwaitAioLIFX().wait + yield from ack(device.get_version) + yield from ack(device.get_color) - @callback - def ready(self, device, msg): - """Handle the device once all data is retrieved.""" - entity = LIFXLight(device, self.effects_conductor) - _LOGGER.debug("%s register READY", entity.who) - self.entities[device.mac_addr] = entity - self.async_add_devices([entity]) + if lifxwhite(device): + entity = LIFXWhite(device, self.effects_conductor) + elif lifxmultizone(device): + yield from ack(partial(device.get_color_zones, start_index=0)) + entity = LIFXStrip(device, self.effects_conductor) + else: + entity = LIFXColor(device, self.effects_conductor) + + _LOGGER.debug("%s register READY", entity.who) + self.entities[device.mac_addr] = entity + self.async_add_devices([entity]) @callback def unregister(self, device): @@ -329,9 +356,8 @@ def unregister(self, device): class AwaitAioLIFX: """Wait for an aiolifx callback and return the message.""" - def __init__(self, light): + def __init__(self): """Initialize the wrapper.""" - self.light = light self.device = None self.message = None self.event = asyncio.Event() @@ -373,15 +399,8 @@ def __init__(self, device, effects_conductor): self.device = device self.effects_conductor = effects_conductor self.registered = True - self.product = device.product self.postponed_update = None - @property - def lifxwhite(self): - """Return whether this is a white-only bulb.""" - # https://lan.developer.lifx.com/docs/lifx-products - return self.product in [10, 11, 18] - @property def available(self): """Return the availability of the device.""" @@ -397,14 +416,6 @@ def who(self): """Return a string identifying the device.""" return "%s (%s)" % (self.device.ip_addr, self.name) - @property - def rgb_color(self): - """Return the RGB value.""" - hue, sat, bri, _ = self.device.color - - return color_util.color_hsv_to_RGB( - hue, convert_16_to_8(sat), convert_16_to_8(bri)) - @property def brightness(self): """Return the brightness of this light between 0..255.""" @@ -421,26 +432,6 @@ def color_temp(self): _LOGGER.debug("color_temp: %d", temperature) return temperature - @property - def min_mireds(self): - """Return the coldest color_temp that this light supports.""" - # The 3 LIFX "White" products supported a limited temperature range - if self.lifxwhite: - kelvin = 6500 - else: - kelvin = 9000 - return math.floor(color_util.color_temperature_kelvin_to_mired(kelvin)) - - @property - def max_mireds(self): - """Return the warmest color_temp that this light supports.""" - # The 3 LIFX "White" products supported a limited temperature range - if self.lifxwhite: - kelvin = 2700 - else: - kelvin = 2500 - return math.ceil(color_util.color_temperature_kelvin_to_mired(kelvin)) - @property def is_on(self): """Return true if device is on.""" @@ -454,32 +445,6 @@ def effect(self): return 'lifx_effect_' + effect.name return None - @property - def supported_features(self): - """Flag supported features.""" - features = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | - SUPPORT_TRANSITION | SUPPORT_EFFECT) - - if not self.lifxwhite: - features |= SUPPORT_RGB_COLOR | SUPPORT_XY_COLOR - - return features - - @property - def effect_list(self): - """Return the list of supported effects for this light.""" - if self.lifxwhite: - return [ - SERVICE_EFFECT_PULSE, - SERVICE_EFFECT_STOP, - ] - - return [ - SERVICE_EFFECT_COLORLOOP, - SERVICE_EFFECT_PULSE, - SERVICE_EFFECT_STOP, - ] - @asyncio.coroutine def update_after_transition(self, now): """Request new status after completion of the last transition.""" @@ -530,30 +495,36 @@ def async_set_state(self, **kwargs): power_on = kwargs.get(ATTR_POWER, False) power_off = not kwargs.get(ATTR_POWER, True) - hsbk = merge_hsbk(self.device.color, find_hsbk(**kwargs)) + hsbk = find_hsbk(**kwargs) # Send messages, waiting for ACK each time - ack = AwaitAioLIFX(self).wait + ack = AwaitAioLIFX().wait bulb = self.device if not self.is_on: if power_off: yield from ack(partial(bulb.set_power, False)) if hsbk: - yield from ack(partial(bulb.set_color, hsbk)) + yield from self.send_color(ack, hsbk, kwargs, duration=0) if power_on: yield from ack(partial(bulb.set_power, True, duration=fade)) else: if power_on: yield from ack(partial(bulb.set_power, True)) if hsbk: - yield from ack(partial(bulb.set_color, hsbk, duration=fade)) + yield from self.send_color(ack, hsbk, kwargs, duration=fade) if power_off: yield from ack(partial(bulb.set_power, False, duration=fade)) # Schedule an update when the transition is complete self.update_later(fade) + @asyncio.coroutine + def send_color(self, ack, hsbk, kwargs, duration): + """Send a color change to the device.""" + hsbk = merge_hsbk(self.device.color, hsbk) + yield from ack(partial(self.device.set_color, hsbk, duration=duration)) + @asyncio.coroutine def default_effect(self, **kwargs): """Start an effect with default parameters.""" @@ -569,5 +540,117 @@ def async_update(self): _LOGGER.debug("%s async_update", self.who) if self.available: # Avoid state ping-pong by holding off updates as the state settles - yield from asyncio.sleep(0.25) - yield from AwaitAioLIFX(self).wait(self.device.get_color) + yield from asyncio.sleep(0.3) + yield from AwaitAioLIFX().wait(self.device.get_color) + + +class LIFXWhite(LIFXLight): + """Representation of a white-only LIFX light.""" + + @property + def min_mireds(self): + """Return the coldest color_temp that this light supports.""" + return math.floor(color_util.color_temperature_kelvin_to_mired(6500)) + + @property + def max_mireds(self): + """Return the warmest color_temp that this light supports.""" + return math.ceil(color_util.color_temperature_kelvin_to_mired(2700)) + + @property + def supported_features(self): + """Flag supported features.""" + return (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_TRANSITION | + SUPPORT_EFFECT) + + @property + def effect_list(self): + """Return the list of supported effects for this light.""" + return [ + SERVICE_EFFECT_PULSE, + SERVICE_EFFECT_STOP, + ] + + +class LIFXColor(LIFXLight): + """Representation of a color LIFX light.""" + + @property + def min_mireds(self): + """Return the coldest color_temp that this light supports.""" + return math.floor(color_util.color_temperature_kelvin_to_mired(9000)) + + @property + def max_mireds(self): + """Return the warmest color_temp that this light supports.""" + return math.ceil(color_util.color_temperature_kelvin_to_mired(2500)) + + @property + def supported_features(self): + """Flag supported features.""" + return (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_TRANSITION | + SUPPORT_EFFECT | SUPPORT_RGB_COLOR | SUPPORT_XY_COLOR) + + @property + def effect_list(self): + """Return the list of supported effects for this light.""" + return [ + SERVICE_EFFECT_COLORLOOP, + SERVICE_EFFECT_PULSE, + SERVICE_EFFECT_STOP, + ] + + @property + def rgb_color(self): + """Return the RGB value.""" + hue, sat, bri, _ = self.device.color + + return color_util.color_hsv_to_RGB( + hue, convert_16_to_8(sat), convert_16_to_8(bri)) + + +class LIFXStrip(LIFXColor): + """Representation of a LIFX light strip with multiple zones.""" + + @asyncio.coroutine + def send_color(self, ack, hsbk, kwargs, duration): + """Send a color change to the device.""" + bulb = self.device + num_zones = len(bulb.color_zones) + + # Zone brightness is not reported when powered off + if not self.is_on and hsbk[2] is None: + yield from ack(partial(bulb.set_power, True)) + yield from self.async_update() + yield from ack(partial(bulb.set_power, False)) + + zones = kwargs.get(ATTR_ZONES, None) + if zones is None: + zones = list(range(0, num_zones)) + else: + zones = list(filter(lambda x: x < num_zones, set(zones))) + + # Send new color to each zone + for index, zone in enumerate(zones): + zone_hsbk = merge_hsbk(bulb.color_zones[zone], hsbk) + apply = 1 if (index == len(zones)-1) else 0 + set_zone = partial(bulb.set_color_zones, + start_index=zone, + end_index=zone, + color=zone_hsbk, + duration=duration, + apply=apply) + yield from ack(set_zone) + + @asyncio.coroutine + def async_update(self): + """Update strip status.""" + if self.available: + yield from super().async_update() + + ack = AwaitAioLIFX().wait + bulb = self.device + + # Each get_color_zones returns the next 8 zones + for zone in range(0, len(bulb.color_zones), 8): + yield from ack(partial(bulb.get_color_zones, start_index=zone)) diff --git a/homeassistant/components/light/services.yaml b/homeassistant/components/light/services.yaml index ef99f18fb427f..782d449644239 100644 --- a/homeassistant/components/light/services.yaml +++ b/homeassistant/components/light/services.yaml @@ -117,6 +117,10 @@ lifx_set_state: description: Automatic infrared level (0..255) when light brightness is low example: 255 + zones: + description: List of zone numbers to affect (8 per LIFX Z, starts at 0) + example: '[0,5]' + transition: description: Duration in seconds it takes to get to the final state example: 10 diff --git a/requirements_all.txt b/requirements_all.txt index 60d25a4104949..86258306da23a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -52,7 +52,7 @@ aiohttp_cors==0.5.3 aiolifx==0.5.2 # homeassistant.components.light.lifx -aiolifx_effects==0.1.0 +aiolifx_effects==0.1.1 # homeassistant.components.scene.hunterdouglas_powerview aiopvapi==1.4 From d8abef9210d63b91b8e55d37bfffe2d96edf0fab Mon Sep 17 00:00:00 2001 From: Dougal Matthews Date: Fri, 14 Jul 2017 04:53:19 +0200 Subject: [PATCH 004/118] Add RGB support to switch.flux (#8417) --- homeassistant/components/switch/flux.py | 20 +++++++++-- tests/components/switch/test_flux.py | 47 +++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/switch/flux.py b/homeassistant/components/switch/flux.py index daa4d1f8cd1b8..dea4285e3a90d 100644 --- a/homeassistant/components/switch/flux.py +++ b/homeassistant/components/switch/flux.py @@ -37,6 +37,7 @@ MODE_XY = 'xy' MODE_MIRED = 'mired' +MODE_RGB = 'rgb' DEFAULT_MODE = MODE_XY PLATFORM_SCHEMA = vol.Schema({ @@ -55,7 +56,7 @@ vol.All(vol.Coerce(int), vol.Range(min=0, max=255)), vol.Optional(CONF_DISABLE_BRIGTNESS_ADJUST): cv.boolean, vol.Optional(CONF_MODE, default=DEFAULT_MODE): - vol.Any(MODE_XY, MODE_MIRED) + vol.Any(MODE_XY, MODE_MIRED, MODE_RGB) }) @@ -79,6 +80,15 @@ def set_lights_temp(hass, lights, mired, brightness): transition=30) +def set_lights_rgb(hass, lights, rgb): + """Set color of array of lights.""" + for light in lights: + if is_on(hass, light): + turn_on(hass, light, + rgb_color=rgb, + transition=30) + + # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Flux switches.""" @@ -194,7 +204,8 @@ def flux_update(self, now=None): temp = self._sunset_colortemp - temp_offset else: temp = self._sunset_colortemp + temp_offset - x_val, y_val, b_val = color_RGB_to_xy(*color_temperature_to_rgb(temp)) + rgb = color_temperature_to_rgb(temp) + x_val, y_val, b_val = color_RGB_to_xy(*rgb) brightness = self._brightness if self._brightness else b_val if self._disable_brightness_adjust: brightness = None @@ -205,6 +216,11 @@ def flux_update(self, now=None): "of %s cycle complete at %s", x_val, y_val, brightness, round( percentage_complete * 100), time_state, now) + elif self._mode == MODE_RGB: + set_lights_rgb(self.hass, self._lights, rgb) + _LOGGER.info("Lights updated to rgb:%s, %s%% " + "of %s cycle complete at %s", rgb, + round(percentage_complete * 100), time_state, now) else: # Convert to mired and clamp to allowed values mired = color_temperature_kelvin_to_mired(temp) diff --git a/tests/components/switch/test_flux.py b/tests/components/switch/test_flux.py index 2422f0ea3347c..d529e8c3f56ec 100644 --- a/tests/components/switch/test_flux.py +++ b/tests/components/switch/test_flux.py @@ -557,3 +557,50 @@ def event_date(hass, event, now=None): self.hass.block_till_done() call = turn_on_calls[-1] self.assertEqual(call.data[light.ATTR_COLOR_TEMP], 269) + + def test_flux_with_rgb(self): + """Test the flux switch´s mode rgb.""" + platform = loader.get_component('light.test') + platform.init() + self.assertTrue( + setup_component(self.hass, light.DOMAIN, + {light.DOMAIN: {CONF_PLATFORM: 'test'}})) + + dev1 = platform.DEVICES[0] + + # Verify initial state of light + state = self.hass.states.get(dev1.entity_id) + self.assertEqual(STATE_ON, state.state) + self.assertIsNone(state.attributes.get('color_temp')) + + test_time = dt_util.now().replace(hour=8, minute=30, second=0) + sunset_time = test_time.replace(hour=17, minute=0, second=0) + sunrise_time = test_time.replace(hour=5, minute=0, second=0) + + def event_date(hass, event, now=None): + if event == 'sunrise': + return sunrise_time + else: + return sunset_time + + with patch('homeassistant.util.dt.now', return_value=test_time): + with patch('homeassistant.helpers.sun.get_astral_event_date', + side_effect=event_date): + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'flux', + 'name': 'flux', + 'lights': [dev1.entity_id], + 'mode': 'rgb' + } + }) + turn_on_calls = mock_service( + self.hass, light.DOMAIN, SERVICE_TURN_ON) + switch.turn_on(self.hass, 'switch.flux') + self.hass.block_till_done() + fire_time_changed(self.hass, test_time) + self.hass.block_till_done() + call = turn_on_calls[-1] + rgb = (255, 198, 152) + rounded_call = tuple(map(round, call.data[light.ATTR_RGB_COLOR])) + self.assertEqual(rounded_call, rgb) From 9373d5e9012a77d59f4e782eaf618e6ae0b4be07 Mon Sep 17 00:00:00 2001 From: dersger Date: Fri, 14 Jul 2017 05:00:23 +0200 Subject: [PATCH 005/118] Fix media_position for cast component (#8452) * Make it available during state paused. * Don't adjust for media_position_updated_at. I.e. do as vlc, sonos etc so that returned position is the position at the time of media_position_updated_at, not now. --- homeassistant/components/media_player/cast.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 418d35767505f..51acf68d819e2 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -234,18 +234,13 @@ def supported_features(self): @property def media_position(self): """Position of current playing media in seconds.""" - if self.media_status is None or self.media_status_received is None or \ + if self.media_status is None or \ not (self.media_status.player_is_playing or + self.media_status.player_is_paused or self.media_status.player_is_idle): return None - position = self.media_status.current_time - - if self.media_status.player_is_playing: - position += (dt_util.utcnow() - - self.media_status_received).total_seconds() - - return position + return self.media_status.current_time @property def media_position_updated_at(self): From d473f3407bea9e7065704361f9e2edb90f735607 Mon Sep 17 00:00:00 2001 From: Sean Gollschewsky Date: Fri, 14 Jul 2017 04:01:25 +0100 Subject: [PATCH 006/118] Remove km from visibility, add visibility_distance (#8454) * Remove km from visibility, add visibility_distance * Fix line length * Fix trailing space and line break indentation * Indentation * More whitespace --- homeassistant/components/sensor/metoffice.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/metoffice.py b/homeassistant/components/sensor/metoffice.py index a20ec8fdd5a7a..25516eda5b1b8 100644 --- a/homeassistant/components/sensor/metoffice.py +++ b/homeassistant/components/sensor/metoffice.py @@ -40,6 +40,15 @@ 'exceptional': [], } +VISIBILTY_CLASSES = { + 'VP': '<1', + 'PO': '1-4', + 'MO': '4-10', + 'GO': '10-20', + 'VG': '20-40', + 'EX': '>40' +} + SCAN_INTERVAL = timedelta(minutes=35) # Sensor types are defined like: Name, units @@ -51,7 +60,8 @@ 'wind_speed': ['Wind Speed', 'm/s'], 'wind_direction': ['Wind Direction', None], 'wind_gust': ['Wind Gust', 'm/s'], - 'visibility': ['Visibility', 'km'], + 'visibility': ['Visibility', None], + 'visibility_distance': ['Visibility Distance', 'km'], 'uv': ['UV', None], 'precipitation': ['Probability of Precipitation', '%'], 'humidity': ['Humidity', '%'] @@ -119,6 +129,9 @@ def name(self): @property def state(self): """Return the state of the sensor.""" + if (self._condition == 'visibility_distance' and + 'visibility' in self.data.data.__dict__.keys()): + return VISIBILTY_CLASSES.get(self.data.data.visibility.value) if self._condition in self.data.data.__dict__.keys(): variable = getattr(self.data.data, self._condition) if self._condition == "weather": From 5829cdfdf191d2b6db67eafaf28c46e92791c2b6 Mon Sep 17 00:00:00 2001 From: Bryce Edwards Date: Thu, 13 Jul 2017 22:02:07 -0500 Subject: [PATCH 007/118] Radarr sensor fix for issue #8250 (#8456) * Radarr sensor fix for issue #8250 * Radarr sensor fix for issue #8250 --- homeassistant/components/sensor/radarr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/radarr.py b/homeassistant/components/sensor/radarr.py index f5efe12c449cb..59408b4f96ba1 100644 --- a/homeassistant/components/sensor/radarr.py +++ b/homeassistant/components/sensor/radarr.py @@ -216,9 +216,9 @@ def get_date(zone, offset=0): def get_release_date(data): """Get release date.""" - date = data['physicalRelease'] + date = data.get('physicalRelease') if not date: - date = data['inCinemas'] + date = data.get('inCinemas') return date From 87b83f36023c329b0990d8bae05853aabbe37589 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Fri, 14 Jul 2017 05:04:23 +0200 Subject: [PATCH 008/118] Accept transition for light.toggle (#8466) --- homeassistant/helpers/entity.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index da177bc43315f..49f250c65fa9d 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -378,18 +378,18 @@ def async_turn_off(self, **kwargs): return self.hass.async_add_job( ft.partial(self.turn_off, **kwargs)) - def toggle(self) -> None: + def toggle(self, **kwargs) -> None: """Toggle the entity.""" if self.is_on: - self.turn_off() + self.turn_off(**kwargs) else: - self.turn_on() + self.turn_on(**kwargs) - def async_toggle(self): + def async_toggle(self, **kwargs): """Toggle the entity. This method must be run in the event loop and returns a coroutine. """ if self.is_on: - return self.async_turn_off() - return self.async_turn_on() + return self.async_turn_off(**kwargs) + return self.async_turn_on(**kwargs) From 6ca828fd146fe1a5b466a030ee501e3c7e19e49f Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 14 Jul 2017 21:26:26 +0300 Subject: [PATCH 009/118] Make themes API work even when themes are not defined. (#8473) --- homeassistant/components/frontend/__init__.py | 11 +++++++---- tests/components/test_frontend.py | 10 ++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 4184feabaebd5..443ff6f38520c 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -212,17 +212,20 @@ def setup(hass, config): register_built_in_panel(hass, panel) themes = config.get(DOMAIN, {}).get(ATTR_THEMES) - if themes: - setup_themes(hass, themes) + setup_themes(hass, themes) return True def setup_themes(hass, themes): """Set up themes data and services.""" - hass.data[DATA_THEMES] = themes - hass.data[DATA_DEFAULT_THEME] = DEFAULT_THEME hass.http.register_view(ThemesView) + hass.data[DATA_DEFAULT_THEME] = DEFAULT_THEME + if themes is None: + hass.data[DATA_THEMES] = {} + return + + hass.data[DATA_THEMES] = themes @callback def update_theme_and_fire_event(): diff --git a/tests/components/test_frontend.py b/tests/components/test_frontend.py index d1e2e5d434631..3682e0a2c1412 100644 --- a/tests/components/test_frontend.py +++ b/tests/components/test_frontend.py @@ -133,3 +133,13 @@ def test_themes_reload_themes(hass, mock_http_client_with_themes): json = yield from resp.json() assert json['themes'] == {'sad': {'primary-color': 'blue'}} assert json['default_theme'] == 'default' + + +@asyncio.coroutine +def test_missing_themes(mock_http_client): + """Test that themes API works when themes are not defined.""" + resp = yield from mock_http_client.get('/api/themes') + assert resp.status == 200 + json = yield from resp.json() + assert json['default_theme'] == 'default' + assert json['themes'] == {} From 543e8bb62ed8e8f91d38d486ad2d0cc0727c8ced Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sat, 15 Jul 2017 16:25:02 +0200 Subject: [PATCH 010/118] Fix check for running inside venv (#8481) * Import and use the function from pip instead of defining it ourselves. * Fix tests. --- homeassistant/scripts/__init__.py | 10 ++++++---- homeassistant/setup.py | 2 +- homeassistant/util/package.py | 10 +++------- tests/test_setup.py | 12 +++++++----- tests/util/test_package.py | 26 +++++++++++++++++++------- 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/homeassistant/scripts/__init__.py b/homeassistant/scripts/__init__.py index 2324613acfb83..f6934aef8f659 100644 --- a/homeassistant/scripts/__init__.py +++ b/homeassistant/scripts/__init__.py @@ -1,15 +1,17 @@ """Home Assistant command line scripts.""" import argparse import importlib +import logging import os import sys -import logging + from typing import List +from homeassistant.bootstrap import mount_local_lib_path from homeassistant.config import get_default_config_dir from homeassistant.const import CONSTRAINT_FILE -from homeassistant.util.package import install_package, is_virtual_env -from homeassistant.bootstrap import mount_local_lib_path +from homeassistant.util.package import ( + install_package, running_under_virtualenv) def run(args: List) -> int: @@ -41,7 +43,7 @@ def run(args: List) -> int: logging.basicConfig(stream=sys.stdout, level=logging.INFO) for req in getattr(script, 'REQUIREMENTS', []): - if is_virtual_env(): + if running_under_virtualenv(): returncode = install_package(req, constraints=os.path.join( os.path.dirname(__file__), os.pardir, CONSTRAINT_FILE)) else: diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 3594399281ffb..a7083d010e6d8 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -77,7 +77,7 @@ def _async_process_requirements(hass: core.HomeAssistant, name: str, def pip_install(mod): """Install packages.""" - if pkg_util.is_virtual_env(): + if pkg_util.running_under_virtualenv(): return pkg_util.install_package( mod, constraints=os.path.join( os.path.dirname(__file__), CONSTRAINT_FILE)) diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index 4736c1acc1a32..a82a50f4e0265 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -2,11 +2,12 @@ import asyncio import logging import os +from subprocess import PIPE, Popen import sys import threading -from subprocess import Popen, PIPE from urllib.parse import urlparse +from pip.locations import running_under_virtualenv from typing import Optional import pkg_resources @@ -36,7 +37,7 @@ def install_package(package: str, upgrade: bool=True, if constraints is not None: args += ['--constraint', constraints] if target: - assert not is_virtual_env() + assert not running_under_virtualenv() # This only works if not running in venv args += ['--user'] env['PYTHONUSERBASE'] = os.path.abspath(target) @@ -70,11 +71,6 @@ def check_package_exists(package: str) -> bool: return any(dist in req for dist in env[req.project_name]) -def is_virtual_env() -> bool: - """Return true if environment is a virtual environment.""" - return hasattr(sys, 'real_prefix') - - def _get_user_site(deps_dir: str) -> tuple: """Get arguments and environment for subprocess used in get_user_site.""" env = os.environ.copy() diff --git a/tests/test_setup.py b/tests/test_setup.py index 742df86242f21..9a0f85874ad27 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -204,13 +204,14 @@ def test_component_not_installed_if_requirement_fails(self, mock_install): assert 'comp' not in self.hass.config.components @mock.patch('homeassistant.setup.os.path.dirname') - @mock.patch('homeassistant.util.package.sys') + @mock.patch('homeassistant.util.package.running_under_virtualenv', + return_value=True) @mock.patch('homeassistant.util.package.install_package', return_value=True) def test_requirement_installed_in_venv( - self, mock_install, mock_sys, mock_dirname): + self, mock_install, mock_venv, mock_dirname): """Test requirement installed in virtual environment.""" - mock_sys.real_prefix = 'pythonpath' + mock_venv.return_value = True mock_dirname.return_value = 'ha_package_path' self.hass.config.skip_pip = False loader.set_component( @@ -222,11 +223,12 @@ def test_requirement_installed_in_venv( constraints=os.path.join('ha_package_path', CONSTRAINT_FILE)) @mock.patch('homeassistant.setup.os.path.dirname') - @mock.patch('homeassistant.util.package.sys', spec=object()) + @mock.patch('homeassistant.util.package.running_under_virtualenv', + return_value=False) @mock.patch('homeassistant.util.package.install_package', return_value=True) def test_requirement_installed_in_deps( - self, mock_install, mock_sys, mock_dirname): + self, mock_install, mock_venv, mock_dirname): """Test requirement installed in deps directory.""" mock_dirname.return_value = 'ha_package_path' self.hass.config.skip_pip = False diff --git a/tests/util/test_package.py b/tests/util/test_package.py index 7ca1315c2e1e3..ade374dad3347 100644 --- a/tests/util/test_package.py +++ b/tests/util/test_package.py @@ -66,6 +66,14 @@ def mock_env_copy(): yield env_copy +@pytest.fixture +def mock_venv(): + """Mock homeassistant.util.package.running_under_virtualenv.""" + with patch('homeassistant.util.package.running_under_virtualenv') as mock: + mock.return_value = True + yield mock + + @asyncio.coroutine def mock_async_subprocess(): """Return an async Popen mock.""" @@ -90,7 +98,7 @@ def test_install_existing_package(mock_exists, mock_popen): assert mock_popen.return_value.communicate.call_count == 0 -def test_install(mock_sys, mock_exists, mock_popen, mock_env_copy): +def test_install(mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): """Test an install attempt on a package that doesn't exist.""" env = mock_env_copy() assert package.install_package(TEST_NEW_REQ, False) @@ -106,7 +114,8 @@ def test_install(mock_sys, mock_exists, mock_popen, mock_env_copy): assert mock_popen.return_value.communicate.call_count == 1 -def test_install_upgrade(mock_sys, mock_exists, mock_popen, mock_env_copy): +def test_install_upgrade( + mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): """Test an upgrade attempt on a package.""" env = mock_env_copy() assert package.install_package(TEST_NEW_REQ) @@ -122,11 +131,13 @@ def test_install_upgrade(mock_sys, mock_exists, mock_popen, mock_env_copy): assert mock_popen.return_value.communicate.call_count == 1 -def test_install_target(mock_sys, mock_exists, mock_popen, mock_env_copy): +def test_install_target( + mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): """Test an install with a target.""" target = 'target_folder' env = mock_env_copy() env['PYTHONUSERBASE'] = os.path.abspath(target) + mock_venv.return_value = False mock_sys.platform = 'linux' args = [ mock_sys.executable, '-m', 'pip', 'install', '--quiet', @@ -142,15 +153,15 @@ def test_install_target(mock_sys, mock_exists, mock_popen, mock_env_copy): assert mock_popen.return_value.communicate.call_count == 1 -def test_install_target_venv(mock_sys, mock_exists, mock_popen, mock_env_copy): +def test_install_target_venv( + mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): """Test an install with a target in a virtual environment.""" target = 'target_folder' - mock_sys.real_prefix = '/usr' with pytest.raises(AssertionError): package.install_package(TEST_NEW_REQ, False, target=target) -def test_install_error(caplog, mock_sys, mock_exists, mock_popen): +def test_install_error(caplog, mock_sys, mock_exists, mock_popen, mock_venv): """Test an install with a target.""" caplog.set_level(logging.WARNING) mock_popen.return_value.returncode = 1 @@ -160,7 +171,8 @@ def test_install_error(caplog, mock_sys, mock_exists, mock_popen): assert record.levelname == 'ERROR' -def test_install_constraint(mock_sys, mock_exists, mock_popen, mock_env_copy): +def test_install_constraint( + mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): """Test install with constraint file on not installed package.""" env = mock_env_copy() constraints = 'constraints_file.txt' From 23b65bfb3044b719d68325dad97a284dbafcd601 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 15 Jul 2017 21:07:15 -0700 Subject: [PATCH 011/118] Version bump to 0.50.0dev0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index f7df04be7f1a6..b4b2aac52e300 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 -MINOR_VERSION = 49 +MINOR_VERSION = 50 PATCH_VERSION = '0.dev0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) From bffa0d2b041531ebe9847a7beb6ae707f6a4e7a8 Mon Sep 17 00:00:00 2001 From: Open Home Automation Date: Sun, 16 Jul 2017 13:34:13 +0200 Subject: [PATCH 012/118] Bump to KNXIP 0.5 (#8492) * Bump to KNXIP 0.5 * Updated requirements file --- homeassistant/components/knx.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/knx.py b/homeassistant/components/knx.py index ec533a7850ba1..9772c19ff78ce 100644 --- a/homeassistant/components/knx.py +++ b/homeassistant/components/knx.py @@ -13,7 +13,7 @@ EVENT_HOMEASSISTANT_STOP, CONF_HOST, CONF_PORT) from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['knxip==0.4'] +REQUIREMENTS = ['knxip==0.5'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 86258306da23a..e07cc8de84c53 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -338,7 +338,7 @@ jsonrpc-websocket==0.5 keyring>=9.3,<10.0 # homeassistant.components.knx -knxip==0.4 +knxip==0.5 # homeassistant.components.device_tracker.owntracks libnacl==1.5.1 From d3be056d1567e5792a4b215ddd0d5eb17c90bfa1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 16 Jul 2017 09:23:06 -0700 Subject: [PATCH 013/118] Expose all components on hass [Concept] (#8490) * Add components concept * Lint * Raise ImportError if component not found --- homeassistant/components/light/__init__.py | 2 + homeassistant/core.py | 2 + homeassistant/loader.py | 44 ++++++++++++++++++++++ tests/test_loader.py | 32 +++++++++++++++- 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 1dbd07f943912..5f3caff511aa0 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -13,6 +13,7 @@ import voluptuous as vol from homeassistant.core import callback +from homeassistant.loader import bind_hass from homeassistant.components import group from homeassistant.config import load_yaml_config_file from homeassistant.const import ( @@ -165,6 +166,7 @@ def turn_on(hass, entity_id=None, transition=None, brightness=None, @callback +@bind_hass def async_turn_on(hass, entity_id=None, transition=None, brightness=None, brightness_pct=None, rgb_color=None, xy_color=None, color_temp=None, kelvin=None, white_value=None, diff --git a/homeassistant/core.py b/homeassistant/core.py index d1779fe420ddf..496bb018fbdd6 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -30,6 +30,7 @@ EVENT_SERVICE_EXECUTED, EVENT_SERVICE_REGISTERED, EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL, EVENT_HOMEASSISTANT_CLOSE, EVENT_SERVICE_REMOVED, __version__) +from homeassistant.loader import Components from homeassistant.exceptions import ( HomeAssistantError, InvalidEntityFormatError) from homeassistant.util.async import ( @@ -128,6 +129,7 @@ def __init__(self, loop=None): self.services = ServiceRegistry(self) self.states = StateMachine(self.bus, self.loop) self.config = Config() # type: Config + self.components = Components(self) # This is a dictionary that any component can store any data on. self.data = {} self.state = CoreState.not_running diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 586988a343692..566cdd4fb1527 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -10,6 +10,7 @@ is checked to see if it contains a user provided version. If not available it will check the built-in components and platforms. """ +import functools as ft import importlib import logging import os @@ -170,6 +171,49 @@ def get_component(comp_name) -> Optional[ModuleType]: return None +class Components: + """Helper to load components.""" + + def __init__(self, hass): + """Initialize the Components class.""" + self._hass = hass + + def __getattr__(self, comp_name): + """Fetch a component.""" + component = get_component(comp_name) + if component is None: + raise ImportError('Unable to load {}'.format(comp_name)) + wrapped = ComponentWrapper(self._hass, component) + setattr(self, comp_name, wrapped) + return wrapped + + +class ComponentWrapper: + """Class to wrap a component and auto fill in hass argument.""" + + def __init__(self, hass, component): + """Initialize the component wrapper.""" + self._hass = hass + self._component = component + + def __getattr__(self, attr): + """Fetch an attribute.""" + value = getattr(self._component, attr) + + if hasattr(value, '__bind_hass'): + value = ft.partial(value, self._hass) + + setattr(self, attr, value) + return value + + +def bind_hass(func): + """Decorator to indicate that first argument is hass.""" + # pylint: disable=protected-access + func.__bind_hass = True + return func + + def load_order_component(comp_name: str) -> OrderedSet: """Return an OrderedSet of components in the correct order of loading. diff --git a/tests/test_loader.py b/tests/test_loader.py index 0b3f9653faae9..6081b061ed29b 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -1,11 +1,15 @@ """Test to verify that we can load components.""" # pylint: disable=protected-access +import asyncio import unittest +import pytest + import homeassistant.loader as loader import homeassistant.components.http as http -from tests.common import get_test_home_assistant, MockModule +from tests.common import ( + get_test_home_assistant, MockModule, async_mock_service) class TestLoader(unittest.TestCase): @@ -54,3 +58,29 @@ def test_load_order_component(self): # Try to get load order for non-existing component self.assertEqual([], loader.load_order_component('mod1')) + + +def test_component_loader(hass): + """Test loading components.""" + components = loader.Components(hass) + assert components.http.CONFIG_SCHEMA is http.CONFIG_SCHEMA + assert hass.components.http.CONFIG_SCHEMA is http.CONFIG_SCHEMA + + +def test_component_loader_non_existing(hass): + """Test loading components.""" + components = loader.Components(hass) + with pytest.raises(ImportError): + components.non_existing + + +@asyncio.coroutine +def test_component_wrapper(hass): + """Test component wrapper.""" + calls = async_mock_service(hass, 'light', 'turn_on') + + components = loader.Components(hass) + components.light.async_turn_on('light.test') + yield from hass.async_block_till_done() + + assert len(calls) == 1 From d29bdddaa790908fbe611e65eab33a2bc61a4b9f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 16 Jul 2017 10:14:46 -0700 Subject: [PATCH 014/118] Add bind_hass to components (#8502) * Add bind_hass to components * Add bind_hass to group --- .../alarm_control_panel/__init__.py | 5 +++++ .../components/automation/__init__.py | 8 ++++++++ homeassistant/components/camera/__init__.py | 3 +++ homeassistant/components/climate/__init__.py | 9 +++++++++ homeassistant/components/cover/__init__.py | 10 ++++++++++ .../components/device_tracker/__init__.py | 2 ++ homeassistant/components/fan/__init__.py | 8 ++++++++ homeassistant/components/group.py | 11 ++++++++++ .../components/image_processing/__init__.py | 2 ++ homeassistant/components/input_boolean.py | 5 +++++ homeassistant/components/input_select.py | 5 +++++ homeassistant/components/input_slider.py | 2 ++ homeassistant/components/light/__init__.py | 5 +++++ homeassistant/components/lock/__init__.py | 4 ++++ .../components/media_player/__init__.py | 20 +++++++++++++++++++ homeassistant/components/mqtt/__init__.py | 6 ++++++ homeassistant/components/notify/__init__.py | 2 ++ .../components/persistent_notification.py | 5 +++++ homeassistant/components/python_script.py | 3 +++ homeassistant/components/remote/__init__.py | 5 +++++ homeassistant/components/scene/__init__.py | 2 ++ homeassistant/components/script.py | 6 ++++++ homeassistant/components/switch/__init__.py | 7 +++++++ homeassistant/components/zone.py | 3 +++ 24 files changed, 138 insertions(+) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 80c5e0ad1ccbb..39c86f3215f8c 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -15,6 +15,7 @@ ATTR_CODE, ATTR_CODE_FORMAT, ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER, SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY) from homeassistant.config import load_yaml_config_file +from homeassistant.loader import bind_hass from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity @@ -44,6 +45,7 @@ }) +@bind_hass def alarm_disarm(hass, code=None, entity_id=None): """Send the alarm the command for disarm.""" data = {} @@ -55,6 +57,7 @@ def alarm_disarm(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_DISARM, data) +@bind_hass def alarm_arm_home(hass, code=None, entity_id=None): """Send the alarm the command for arm home.""" data = {} @@ -66,6 +69,7 @@ def alarm_arm_home(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_ARM_HOME, data) +@bind_hass def alarm_arm_away(hass, code=None, entity_id=None): """Send the alarm the command for arm away.""" data = {} @@ -77,6 +81,7 @@ def alarm_arm_away(hass, code=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data) +@bind_hass def alarm_trigger(hass, code=None, entity_id=None): """Send the alarm the command for trigger.""" data = {} diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index 09f0e2867555f..27332bfaa9fbb 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -13,6 +13,7 @@ from homeassistant.setup import async_prepare_setup_platform from homeassistant.core import CoreState +from homeassistant.loader import bind_hass from homeassistant import config as conf_util from homeassistant.const import ( ATTR_ENTITY_ID, CONF_PLATFORM, STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, @@ -105,6 +106,7 @@ def _platform_validator(config): RELOAD_SERVICE_SCHEMA = vol.Schema({}) +@bind_hass def is_on(hass, entity_id): """ Return true if specified automation entity_id is on. @@ -114,35 +116,41 @@ def is_on(hass, entity_id): return hass.states.is_state(entity_id, STATE_ON) +@bind_hass def turn_on(hass, entity_id=None): """Turn on specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TURN_ON, data) +@bind_hass def turn_off(hass, entity_id=None): """Turn off specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) +@bind_hass def toggle(hass, entity_id=None): """Toggle specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TOGGLE, data) +@bind_hass def trigger(hass, entity_id=None): """Trigger specified automation or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TRIGGER, data) +@bind_hass def reload(hass): """Reload the automation from config.""" hass.services.call(DOMAIN, SERVICE_RELOAD) +@bind_hass def async_reload(hass): """Reload the automation from config. diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 5b97e102d8ded..a7d778d99aa79 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -23,6 +23,7 @@ from homeassistant.const import (ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE) from homeassistant.config import load_yaml_config_file from homeassistant.exceptions import HomeAssistantError +from homeassistant.loader import bind_hass from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent @@ -55,6 +56,7 @@ }) +@bind_hass def enable_motion_detection(hass, entity_id=None): """Enable Motion Detection.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None @@ -62,6 +64,7 @@ def enable_motion_detection(hass, entity_id=None): DOMAIN, SERVICE_EN_MOTION, data)) +@bind_hass def disable_motion_detection(hass, entity_id=None): """Disable Motion Detection.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 5b6c025b3e3e2..6dd66817d43ed 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -14,6 +14,7 @@ import voluptuous as vol from homeassistant.config import load_yaml_config_file +from homeassistant.loader import bind_hass from homeassistant.util.temperature import convert as convert_temperature from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import Entity @@ -114,6 +115,7 @@ }) +@bind_hass def set_away_mode(hass, away_mode, entity_id=None): """Turn all or specified climate devices away mode on.""" data = { @@ -126,6 +128,7 @@ def set_away_mode(hass, away_mode, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_AWAY_MODE, data) +@bind_hass def set_hold_mode(hass, hold_mode, entity_id=None): """Set new hold mode.""" data = { @@ -138,6 +141,7 @@ def set_hold_mode(hass, hold_mode, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_HOLD_MODE, data) +@bind_hass def set_aux_heat(hass, aux_heat, entity_id=None): """Turn all or specified climate devices auxillary heater on.""" data = { @@ -150,6 +154,7 @@ def set_aux_heat(hass, aux_heat, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_AUX_HEAT, data) +@bind_hass def set_temperature(hass, temperature=None, entity_id=None, target_temp_high=None, target_temp_low=None, operation_mode=None): @@ -167,6 +172,7 @@ def set_temperature(hass, temperature=None, entity_id=None, hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, kwargs) +@bind_hass def set_humidity(hass, humidity, entity_id=None): """Set new target humidity.""" data = {ATTR_HUMIDITY: humidity} @@ -177,6 +183,7 @@ def set_humidity(hass, humidity, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_HUMIDITY, data) +@bind_hass def set_fan_mode(hass, fan, entity_id=None): """Set all or specified climate devices fan mode on.""" data = {ATTR_FAN_MODE: fan} @@ -187,6 +194,7 @@ def set_fan_mode(hass, fan, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_FAN_MODE, data) +@bind_hass def set_operation_mode(hass, operation_mode, entity_id=None): """Set new target operation mode.""" data = {ATTR_OPERATION_MODE: operation_mode} @@ -197,6 +205,7 @@ def set_operation_mode(hass, operation_mode, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_OPERATION_MODE, data) +@bind_hass def set_swing_mode(hass, swing_mode, entity_id=None): """Set new target swing mode.""" data = {ATTR_SWING_MODE: swing_mode} diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index d323ad324c700..df096c9ba8087 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -13,6 +13,7 @@ import voluptuous as vol from homeassistant.config import load_yaml_config_file +from homeassistant.loader import bind_hass from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import Entity from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa @@ -86,24 +87,28 @@ } +@bind_hass def is_closed(hass, entity_id=None): """Return if the cover is closed based on the statemachine.""" entity_id = entity_id or ENTITY_ID_ALL_COVERS return hass.states.is_state(entity_id, STATE_CLOSED) +@bind_hass def open_cover(hass, entity_id=None): """Open all or specified cover.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_OPEN_COVER, data) +@bind_hass def close_cover(hass, entity_id=None): """Close all or specified cover.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_CLOSE_COVER, data) +@bind_hass def set_cover_position(hass, position, entity_id=None): """Move to specific position all or specified cover.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} @@ -111,24 +116,28 @@ def set_cover_position(hass, position, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_COVER_POSITION, data) +@bind_hass def stop_cover(hass, entity_id=None): """Stop all or specified cover.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_STOP_COVER, data) +@bind_hass def open_cover_tilt(hass, entity_id=None): """Open all or specified cover tilt.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_OPEN_COVER_TILT, data) +@bind_hass def close_cover_tilt(hass, entity_id=None): """Close all or specified cover tilt.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_CLOSE_COVER_TILT, data) +@bind_hass def set_cover_tilt_position(hass, tilt_position, entity_id=None): """Move to specific tilt position all or specified cover.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} @@ -136,6 +145,7 @@ def set_cover_tilt_position(hass, tilt_position, entity_id=None): hass.services.call(DOMAIN, SERVICE_SET_COVER_TILT_POSITION, data) +@bind_hass def stop_cover_tilt(hass, entity_id=None): """Stop all or specified cover tilt.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 017bb723ee560..8192dfa751de9 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -16,6 +16,7 @@ from homeassistant.setup import async_prepare_setup_platform from homeassistant.core import callback +from homeassistant.loader import bind_hass from homeassistant.components import group, zone from homeassistant.components.discovery import SERVICE_NETGEAR from homeassistant.config import load_yaml_config_file, async_log_exception @@ -93,6 +94,7 @@ } +@bind_hass def is_on(hass: HomeAssistantType, entity_id: str=None): """Return the state if any or a specified device is home.""" entity = entity_id or ENTITY_ID_ALL_DEVICES diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index 4642017ce32bb..fd12529cb486d 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -17,6 +17,7 @@ from homeassistant.const import (SERVICE_TURN_ON, SERVICE_TOGGLE, SERVICE_TURN_OFF, ATTR_ENTITY_ID, STATE_UNKNOWN) +from homeassistant.loader import bind_hass from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa @@ -118,6 +119,7 @@ } +@bind_hass def is_on(hass, entity_id: str=None) -> bool: """Return if the fans are on based on the statemachine.""" entity_id = entity_id or ENTITY_ID_ALL_FANS @@ -125,6 +127,7 @@ def is_on(hass, entity_id: str=None) -> bool: return state.attributes[ATTR_SPEED] not in [SPEED_OFF, STATE_UNKNOWN] +@bind_hass def turn_on(hass, entity_id: str=None, speed: str=None) -> None: """Turn all or specified fan on.""" data = { @@ -137,6 +140,7 @@ def turn_on(hass, entity_id: str=None, speed: str=None) -> None: hass.services.call(DOMAIN, SERVICE_TURN_ON, data) +@bind_hass def turn_off(hass, entity_id: str=None) -> None: """Turn all or specified fan off.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} @@ -144,6 +148,7 @@ def turn_off(hass, entity_id: str=None) -> None: hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) +@bind_hass def toggle(hass, entity_id: str=None) -> None: """Toggle all or specified fans.""" data = { @@ -153,6 +158,7 @@ def toggle(hass, entity_id: str=None) -> None: hass.services.call(DOMAIN, SERVICE_TOGGLE, data) +@bind_hass def oscillate(hass, entity_id: str=None, should_oscillate: bool=True) -> None: """Set oscillation on all or specified fan.""" data = { @@ -165,6 +171,7 @@ def oscillate(hass, entity_id: str=None, should_oscillate: bool=True) -> None: hass.services.call(DOMAIN, SERVICE_OSCILLATE, data) +@bind_hass def set_speed(hass, entity_id: str=None, speed: str=None) -> None: """Set speed for all or specified fan.""" data = { @@ -177,6 +184,7 @@ def set_speed(hass, entity_id: str=None, speed: str=None) -> None: hass.services.call(DOMAIN, SERVICE_SET_SPEED, data) +@bind_hass def set_direction(hass, entity_id: str=None, direction: str=None) -> None: """Set direction for all or specified fan.""" data = { diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py index d07e506e8971a..9985d129a3a3e 100644 --- a/homeassistant/components/group.py +++ b/homeassistant/components/group.py @@ -17,6 +17,7 @@ STATE_UNLOCKED, STATE_OK, STATE_PROBLEM, STATE_UNKNOWN, ATTR_ASSUMED_STATE, SERVICE_RELOAD) from homeassistant.core import callback +from homeassistant.loader import bind_hass from homeassistant.helpers.entity import Entity, async_generate_entity_id from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.event import async_track_state_change @@ -108,6 +109,7 @@ def _get_group_on_off(state): return None, None +@bind_hass def is_on(hass, entity_id): """Test if the group state is in its ON-state.""" state = hass.states.get(entity_id) @@ -121,23 +123,27 @@ def is_on(hass, entity_id): return False +@bind_hass def reload(hass): """Reload the automation from config.""" hass.add_job(async_reload, hass) @callback +@bind_hass def async_reload(hass): """Reload the automation from config.""" hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_RELOAD)) +@bind_hass def set_visibility(hass, entity_id=None, visible=True): """Hide or shows a group.""" data = {ATTR_ENTITY_ID: entity_id, ATTR_VISIBLE: visible} hass.services.call(DOMAIN, SERVICE_SET_VISIBILITY, data) +@bind_hass def set_group(hass, object_id, name=None, entity_ids=None, visible=None, icon=None, view=None, control=None, add=None): """Create a new user group.""" @@ -147,6 +153,7 @@ def set_group(hass, object_id, name=None, entity_ids=None, visible=None, @callback +@bind_hass def async_set_group(hass, object_id, name=None, entity_ids=None, visible=None, icon=None, view=None, control=None, add=None): """Create a new user group.""" @@ -166,18 +173,21 @@ def async_set_group(hass, object_id, name=None, entity_ids=None, visible=None, hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_SET, data)) +@bind_hass def remove(hass, name): """Remove a user group.""" hass.add_job(async_remove, hass, name) @callback +@bind_hass def async_remove(hass, object_id): """Remove a user group.""" data = {ATTR_OBJECT_ID: object_id} hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_REMOVE, data)) +@bind_hass def expand_entity_ids(hass, entity_ids): """Return entity_ids with group entity ids replaced by their members. @@ -215,6 +225,7 @@ def expand_entity_ids(hass, entity_ids): return found_ids +@bind_hass def get_entity_ids(hass, entity_id, domain_filter=None): """Get members of this group. diff --git a/homeassistant/components/image_processing/__init__.py b/homeassistant/components/image_processing/__init__.py index fb1cddcad6160..e6979087b6f5b 100644 --- a/homeassistant/components/image_processing/__init__.py +++ b/homeassistant/components/image_processing/__init__.py @@ -16,6 +16,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, CONF_NAME, CONF_ENTITY_ID) from homeassistant.exceptions import HomeAssistantError +from homeassistant.loader import bind_hass from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.loader import get_component @@ -59,6 +60,7 @@ }) +@bind_hass def scan(hass, entity_id=None): """Force process a image.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None diff --git a/homeassistant/components/input_boolean.py b/homeassistant/components/input_boolean.py index e975e42bcdcb7..3c4efdce17547 100644 --- a/homeassistant/components/input_boolean.py +++ b/homeassistant/components/input_boolean.py @@ -12,6 +12,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, CONF_ICON, CONF_NAME, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_TOGGLE, STATE_ON) +from homeassistant.loader import bind_hass import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent @@ -41,21 +42,25 @@ }, extra=vol.ALLOW_EXTRA) +@bind_hass def is_on(hass, entity_id): """Test if input_boolean is True.""" return hass.states.is_state(entity_id, STATE_ON) +@bind_hass def turn_on(hass, entity_id): """Set input_boolean to True.""" hass.services.call(DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: entity_id}) +@bind_hass def turn_off(hass, entity_id): """Set input_boolean to False.""" hass.services.call(DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}) +@bind_hass def toggle(hass, entity_id): """Set input_boolean to False.""" hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id}) diff --git a/homeassistant/components/input_select.py b/homeassistant/components/input_select.py index c7f3a7f22364e..f16b029c1d71c 100644 --- a/homeassistant/components/input_select.py +++ b/homeassistant/components/input_select.py @@ -10,6 +10,7 @@ import voluptuous as vol from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON, CONF_NAME +from homeassistant.loader import bind_hass import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent @@ -77,6 +78,7 @@ def _cv_input_select(cfg): }, required=True, extra=vol.ALLOW_EXTRA) +@bind_hass def select_option(hass, entity_id, option): """Set value of input_select.""" hass.services.call(DOMAIN, SERVICE_SELECT_OPTION, { @@ -85,6 +87,7 @@ def select_option(hass, entity_id, option): }) +@bind_hass def select_next(hass, entity_id): """Set next value of input_select.""" hass.services.call(DOMAIN, SERVICE_SELECT_NEXT, { @@ -92,6 +95,7 @@ def select_next(hass, entity_id): }) +@bind_hass def select_previous(hass, entity_id): """Set previous value of input_select.""" hass.services.call(DOMAIN, SERVICE_SELECT_PREVIOUS, { @@ -99,6 +103,7 @@ def select_previous(hass, entity_id): }) +@bind_hass def set_options(hass, entity_id, options): """Set options of input_select.""" hass.services.call(DOMAIN, SERVICE_SET_OPTIONS, { diff --git a/homeassistant/components/input_slider.py b/homeassistant/components/input_slider.py index bd17376b2efd8..5357878a0cef4 100644 --- a/homeassistant/components/input_slider.py +++ b/homeassistant/components/input_slider.py @@ -12,6 +12,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_NAME) +from homeassistant.loader import bind_hass from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import async_get_last_state @@ -69,6 +70,7 @@ def _cv_input_slider(cfg): }, required=True, extra=vol.ALLOW_EXTRA) +@bind_hass def select_value(hass, entity_id, value): """Set input_slider to value.""" hass.services.call(DOMAIN, SERVICE_SELECT_VALUE, { diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 5f3caff511aa0..4e9fbbf81ab86 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -148,12 +148,14 @@ def extract_info(state): return params +@bind_hass def is_on(hass, entity_id=None): """Return if the lights are on based on the statemachine.""" entity_id = entity_id or ENTITY_ID_ALL_LIGHTS return hass.states.is_state(entity_id, STATE_ON) +@bind_hass def turn_on(hass, entity_id=None, transition=None, brightness=None, brightness_pct=None, rgb_color=None, xy_color=None, color_temp=None, kelvin=None, white_value=None, @@ -193,12 +195,14 @@ def async_turn_on(hass, entity_id=None, transition=None, brightness=None, hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data)) +@bind_hass def turn_off(hass, entity_id=None, transition=None): """Turn all or specified light off.""" hass.add_job(async_turn_off, hass, entity_id, transition) @callback +@bind_hass def async_turn_off(hass, entity_id=None, transition=None): """Turn all or specified light off.""" data = { @@ -212,6 +216,7 @@ def async_turn_off(hass, entity_id=None, transition=None): DOMAIN, SERVICE_TURN_OFF, data)) +@bind_hass def toggle(hass, entity_id=None, transition=None): """Toggle all or specified light.""" data = { diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index 369f0c93b858d..c64f77b3bd6ae 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -13,6 +13,7 @@ import voluptuous as vol from homeassistant.config import load_yaml_config_file +from homeassistant.loader import bind_hass from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import Entity from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa @@ -43,12 +44,14 @@ _LOGGER = logging.getLogger(__name__) +@bind_hass def is_locked(hass, entity_id=None): """Return 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) +@bind_hass def lock(hass, entity_id=None, code=None): """Lock all or specified locks.""" data = {} @@ -60,6 +63,7 @@ def lock(hass, entity_id=None, code=None): hass.services.call(DOMAIN, SERVICE_LOCK, data) +@bind_hass def unlock(hass, entity_id=None, code=None): """Unlock all or specified locks.""" data = {} diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 35981d89d6d6e..a53f7f1367a1d 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -17,6 +17,7 @@ import voluptuous as vol from homeassistant.config import load_yaml_config_file +from homeassistant.loader import bind_hass from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa @@ -199,6 +200,7 @@ ] +@bind_hass def is_on(hass, entity_id=None): """ Return true if specified media player entity_id is on. @@ -210,36 +212,42 @@ def is_on(hass, entity_id=None): for entity_id in entity_ids) +@bind_hass def turn_on(hass, entity_id=None): """Turn on specified media player or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TURN_ON, data) +@bind_hass def turn_off(hass, entity_id=None): """Turn off specified media player or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) +@bind_hass def toggle(hass, entity_id=None): """Toggle specified media player or all.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_TOGGLE, data) +@bind_hass def volume_up(hass, entity_id=None): """Send the media player the command for volume up.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_VOLUME_UP, data) +@bind_hass def volume_down(hass, entity_id=None): """Send the media player the command for volume down.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_VOLUME_DOWN, data) +@bind_hass def mute_volume(hass, mute, entity_id=None): """Send the media player the command for muting the volume.""" data = {ATTR_MEDIA_VOLUME_MUTED: mute} @@ -250,6 +258,7 @@ def mute_volume(hass, mute, entity_id=None): hass.services.call(DOMAIN, SERVICE_VOLUME_MUTE, data) +@bind_hass def set_volume_level(hass, volume, entity_id=None): """Send the media player the command for setting the volume.""" data = {ATTR_MEDIA_VOLUME_LEVEL: volume} @@ -260,42 +269,49 @@ def set_volume_level(hass, volume, entity_id=None): hass.services.call(DOMAIN, SERVICE_VOLUME_SET, data) +@bind_hass def media_play_pause(hass, entity_id=None): """Send the media player the command for play/pause.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY_PAUSE, data) +@bind_hass def media_play(hass, entity_id=None): """Send the media player the command for play/pause.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PLAY, data) +@bind_hass def media_pause(hass, entity_id=None): """Send the media player the command for pause.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PAUSE, data) +@bind_hass def media_stop(hass, entity_id=None): """Send the media player the stop command.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_STOP, data) +@bind_hass def media_next_track(hass, entity_id=None): """Send the media player the command for next track.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_NEXT_TRACK, data) +@bind_hass def media_previous_track(hass, entity_id=None): """Send the media player the command for prev track.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_MEDIA_PREVIOUS_TRACK, data) +@bind_hass def media_seek(hass, position, entity_id=None): """Send the media player the command to seek in current playing media.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} @@ -303,6 +319,7 @@ def media_seek(hass, position, entity_id=None): hass.services.call(DOMAIN, SERVICE_MEDIA_SEEK, data) +@bind_hass def play_media(hass, media_type, media_id, entity_id=None, enqueue=None): """Send the media player the command for playing media.""" data = {ATTR_MEDIA_CONTENT_TYPE: media_type, @@ -317,6 +334,7 @@ def play_media(hass, media_type, media_id, entity_id=None, enqueue=None): hass.services.call(DOMAIN, SERVICE_PLAY_MEDIA, data) +@bind_hass def select_source(hass, source, entity_id=None): """Send the media player the command to select input source.""" data = {ATTR_INPUT_SOURCE: source} @@ -327,12 +345,14 @@ def select_source(hass, source, entity_id=None): hass.services.call(DOMAIN, SERVICE_SELECT_SOURCE, data) +@bind_hass def clear_playlist(hass, entity_id=None): """Send the media player the command for clear playlist.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else {} hass.services.call(DOMAIN, SERVICE_CLEAR_PLAYLIST, data) +@bind_hass def set_shuffle(hass, shuffle, entity_id=None): """Send the media player the command to enable/disable shuffle mode.""" data = {ATTR_MEDIA_SHUFFLE: shuffle} diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index f5a664129623a..3c75648892b4a 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -19,6 +19,7 @@ from homeassistant.setup import async_prepare_setup_platform from homeassistant.config import load_yaml_config_file from homeassistant.exceptions import HomeAssistantError +from homeassistant.loader import bind_hass from homeassistant.helpers import template, config_validation as cv from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, dispatcher_send) @@ -180,12 +181,14 @@ def _build_publish_data(topic, qos, retain): return data +@bind_hass def publish(hass, topic, payload, qos=None, retain=None): """Publish message to an MQTT topic.""" hass.add_job(async_publish, hass, topic, payload, qos, retain) @callback +@bind_hass def async_publish(hass, topic, payload, qos=None, retain=None): """Publish message to an MQTT topic.""" data = _build_publish_data(topic, qos, retain) @@ -193,6 +196,7 @@ def async_publish(hass, topic, payload, qos=None, retain=None): hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_PUBLISH, data)) +@bind_hass def publish_template(hass, topic, payload_template, qos=None, retain=None): """Publish message to an MQTT topic using a template payload.""" data = _build_publish_data(topic, qos, retain) @@ -201,6 +205,7 @@ def publish_template(hass, topic, payload_template, qos=None, retain=None): @asyncio.coroutine +@bind_hass def async_subscribe(hass, topic, msg_callback, qos=DEFAULT_QOS, encoding='utf-8'): """Subscribe to an MQTT topic.""" @@ -232,6 +237,7 @@ def async_mqtt_topic_subscriber(dp_topic, dp_payload, dp_qos): return async_remove +@bind_hass def subscribe(hass, topic, msg_callback, qos=DEFAULT_QOS, encoding='utf-8'): """Subscribe to an MQTT topic.""" diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index f9f9d04c05c48..1c17d1a795ad8 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -13,6 +13,7 @@ from homeassistant.setup import async_prepare_setup_platform from homeassistant.exceptions import HomeAssistantError +from homeassistant.loader import bind_hass import homeassistant.helpers.config_validation as cv from homeassistant.config import load_yaml_config_file from homeassistant.const import CONF_NAME, CONF_PLATFORM @@ -51,6 +52,7 @@ }) +@bind_hass def send_message(hass, message, title=None, data=None): """Send a notification message.""" info = { diff --git a/homeassistant/components/persistent_notification.py b/homeassistant/components/persistent_notification.py index 212b2e7e7dad6..5e68aeee3abc7 100644 --- a/homeassistant/components/persistent_notification.py +++ b/homeassistant/components/persistent_notification.py @@ -12,6 +12,7 @@ from homeassistant.core import callback from homeassistant.exceptions import TemplateError +from homeassistant.loader import bind_hass from homeassistant.helpers import config_validation as cv from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.util import slugify @@ -43,17 +44,20 @@ _LOGGER = logging.getLogger(__name__) +@bind_hass def create(hass, message, title=None, notification_id=None): """Generate a notification.""" hass.add_job(async_create, hass, message, title, notification_id) +@bind_hass def dismiss(hass, notification_id): """Remove a notification.""" hass.add_job(async_dismiss, hass, notification_id) @callback +@bind_hass def async_create(hass, message, title=None, notification_id=None): """Generate a notification.""" data = { @@ -68,6 +72,7 @@ def async_create(hass, message, title=None, notification_id=None): @callback +@bind_hass def async_dismiss(hass, notification_id): """Remove a notification.""" data = {ATTR_NOTIFICATION_ID: notification_id} diff --git a/homeassistant/components/python_script.py b/homeassistant/components/python_script.py index c159bec0f7589..66b9bd0112a07 100644 --- a/homeassistant/components/python_script.py +++ b/homeassistant/components/python_script.py @@ -6,6 +6,7 @@ import voluptuous as vol from homeassistant.exceptions import HomeAssistantError +from homeassistant.loader import bind_hass from homeassistant.util import sanitize_filename DOMAIN = 'python_script' @@ -49,6 +50,7 @@ def python_script_service_handler(call): return True +@bind_hass def execute_script(hass, name, data=None): """Execute a script.""" filename = '{}.py'.format(name) @@ -57,6 +59,7 @@ def execute_script(hass, name, data=None): execute(hass, filename, source, data) +@bind_hass def execute(hass, filename, source, data=None): """Execute Python source.""" from RestrictedPython import compile_restricted_exec diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index 4e00a053cf923..bec4adcaa7ed1 100755 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -13,6 +13,7 @@ import voluptuous as vol from homeassistant.config import load_yaml_config_file +from homeassistant.loader import bind_hass from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import ToggleEntity import homeassistant.helpers.config_validation as cv @@ -62,12 +63,14 @@ }) +@bind_hass def is_on(hass, entity_id=None): """Return if the remote is on based on the statemachine.""" entity_id = entity_id or ENTITY_ID_ALL_REMOTES return hass.states.is_state(entity_id, STATE_ON) +@bind_hass def turn_on(hass, activity=None, entity_id=None): """Turn all or specified remote on.""" data = {ATTR_ACTIVITY: activity} @@ -76,12 +79,14 @@ def turn_on(hass, activity=None, entity_id=None): hass.services.call(DOMAIN, SERVICE_TURN_ON, data) +@bind_hass def turn_off(hass, entity_id=None): """Turn all or specified remote off.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.services.call(DOMAIN, SERVICE_TURN_OFF, data) +@bind_hass def send_command(hass, device, command, entity_id=None, num_repeats=None, delay_secs=None): """Send a command to a device.""" diff --git a/homeassistant/components/scene/__init__.py b/homeassistant/components/scene/__init__.py index dd46f469a558b..fbfe2b6959a8c 100644 --- a/homeassistant/components/scene/__init__.py +++ b/homeassistant/components/scene/__init__.py @@ -11,6 +11,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, CONF_PLATFORM, SERVICE_TURN_ON) +from homeassistant.loader import bind_hass import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent @@ -56,6 +57,7 @@ def _platform_validator(config): }) +@bind_hass def activate(hass, entity_id=None): """Activate a scene.""" data = {} diff --git a/homeassistant/components/script.py b/homeassistant/components/script.py index 996cef10d7790..62edb11b7784e 100644 --- a/homeassistant/components/script.py +++ b/homeassistant/components/script.py @@ -16,6 +16,7 @@ ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_TOGGLE, SERVICE_RELOAD, STATE_ON, CONF_ALIAS) from homeassistant.core import split_entity_id +from homeassistant.loader import bind_hass from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent import homeassistant.helpers.config_validation as cv @@ -55,16 +56,19 @@ RELOAD_SERVICE_SCHEMA = vol.Schema({}) +@bind_hass def is_on(hass, entity_id): """Return if the script is on based on the statemachine.""" return hass.states.is_state(entity_id, STATE_ON) +@bind_hass def reload(hass): """Reload script component.""" hass.services.call(DOMAIN, SERVICE_RELOAD) +@bind_hass def turn_on(hass, entity_id, variables=None): """Turn script on.""" _, object_id = split_entity_id(entity_id) @@ -72,11 +76,13 @@ def turn_on(hass, entity_id, variables=None): hass.services.call(DOMAIN, object_id, variables) +@bind_hass def turn_off(hass, entity_id): """Turn script on.""" hass.services.call(DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: entity_id}) +@bind_hass def toggle(hass, entity_id): """Toggle the script.""" hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id}) diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index 2af79a5431359..a53c6c5c01f21 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -13,6 +13,7 @@ from homeassistant.core import callback from homeassistant.config import load_yaml_config_file +from homeassistant.loader import bind_hass from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa @@ -48,6 +49,7 @@ _LOGGER = logging.getLogger(__name__) +@bind_hass def is_on(hass, entity_id=None): """Return if the switch is on based on the statemachine. @@ -57,24 +59,28 @@ def is_on(hass, entity_id=None): return hass.states.is_state(entity_id, STATE_ON) +@bind_hass def turn_on(hass, entity_id=None): """Turn all or specified switch on.""" hass.add_job(async_turn_on, hass, entity_id) @callback +@bind_hass def async_turn_on(hass, entity_id=None): """Turn all or specified switch on.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_TURN_ON, data)) +@bind_hass def turn_off(hass, entity_id=None): """Turn all or specified switch off.""" hass.add_job(async_turn_off, hass, entity_id) @callback +@bind_hass def async_turn_off(hass, entity_id=None): """Turn all or specified switch off.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None @@ -82,6 +88,7 @@ def async_turn_off(hass, entity_id=None): hass.services.async_call(DOMAIN, SERVICE_TURN_OFF, data)) +@bind_hass def toggle(hass, entity_id=None): """Toggle all or specified switch.""" data = {ATTR_ENTITY_ID: entity_id} if entity_id else None diff --git a/homeassistant/components/zone.py b/homeassistant/components/zone.py index e1a8b8e721bf5..712abfb1b6e30 100644 --- a/homeassistant/components/zone.py +++ b/homeassistant/components/zone.py @@ -12,6 +12,7 @@ from homeassistant.const import ( ATTR_HIDDEN, ATTR_LATITUDE, ATTR_LONGITUDE, CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, CONF_ICON) +from homeassistant.loader import bind_hass from homeassistant.helpers import config_per_platform from homeassistant.helpers.entity import Entity, async_generate_entity_id from homeassistant.util.async import run_callback_threadsafe @@ -50,6 +51,7 @@ }, extra=vol.ALLOW_EXTRA) +@bind_hass def active_zone(hass, latitude, longitude, radius=0): """Find the active zone for given latitude, longitude.""" return run_callback_threadsafe( @@ -57,6 +59,7 @@ def active_zone(hass, latitude, longitude, radius=0): ).result() +@bind_hass def async_active_zone(hass, latitude, longitude, radius=0): """Find the active zone for given latitude, longitude. From f6c3832e90ec83e63b4032750acad24549586401 Mon Sep 17 00:00:00 2001 From: Maikel Wever Date: Sun, 16 Jul 2017 19:27:48 +0200 Subject: [PATCH 015/118] Fix TP-Link device tracker regression since 0.49 (#8497) * Fix TP-Link device tracker regression since 0.49 This regression was introduced by #8322. Fix is to utf encode the password like the other TP-Link backends do. * Fix linting issue introduced in previous commit Commit in question: 677f3fbb7f821ee925364c8260d235dce4f0ddbe --- homeassistant/components/device_tracker/tplink.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 88b0abe8ce4d9..ccf0c2d01afb3 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -391,7 +391,8 @@ def _update_info(self): "Cache-Control": "no-cache" } - password_md5 = hashlib.md5(self.password).hexdigest().upper() + password_md5 = hashlib.md5( + self.password.encode('utf')).hexdigest().upper() # create a session to handle cookie easier session = requests.session() From d0275c80754ac4a73d453d4fce0ad6d755d46e3a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 16 Jul 2017 12:39:38 -0700 Subject: [PATCH 016/118] Persistent notification import (#8507) * Rewrite persistent notification creation * Update components.is_on to use auto loading * Fix two hass parameters --- homeassistant/components/__init__.py | 30 ++++++++--------- .../alarm_control_panel/simplisafe.py | 6 ++-- homeassistant/components/amcrest.py | 6 ++-- homeassistant/components/apple_tv.py | 14 +++----- homeassistant/components/arlo.py | 6 ++-- homeassistant/components/axis.py | 14 ++++---- homeassistant/components/configurator.py | 2 ++ homeassistant/components/cover/myq.py | 6 ++-- homeassistant/components/demo.py | 9 +++--- .../components/device_tracker/unifi.py | 6 ++-- homeassistant/components/google.py | 32 +++++++++---------- homeassistant/components/media_player/roku.py | 6 ++-- homeassistant/components/ring.py | 6 ++-- homeassistant/components/sensor/qnap.py | 9 +++--- homeassistant/components/switch/broadlink.py | 11 +++---- homeassistant/components/upnp.py | 8 ++--- 16 files changed, 70 insertions(+), 101 deletions(-) diff --git a/homeassistant/components/__init__.py b/homeassistant/components/__init__.py index ecbb803646471..1d437d35da7b8 100644 --- a/homeassistant/components/__init__.py +++ b/homeassistant/components/__init__.py @@ -15,7 +15,6 @@ import homeassistant.config as conf_util from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.service import extract_entity_ids -from homeassistant.loader import get_component from homeassistant.const import ( ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE, SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART, @@ -33,25 +32,27 @@ def is_on(hass, entity_id=None): If there is no entity id given we will check all. """ if entity_id: - group = get_component('group') - - entity_ids = group.expand_entity_ids(hass, [entity_id]) + entity_ids = hass.components.group.expand_entity_ids([entity_id]) else: entity_ids = hass.states.entity_ids() for ent_id in entity_ids: domain = ha.split_entity_id(ent_id)[0] - module = get_component(domain) - try: - if module.is_on(hass, ent_id): - return True + component = getattr(hass.components, domain) + + except ImportError: + _LOGGER.error('Failed to call %s.is_on: component not found', + domain) + continue + + if not hasattr(component, 'is_on'): + _LOGGER.warning("Component %s has no is_on method.", domain) + continue - except AttributeError: - # module is None or method is_on does not exist - _LOGGER.exception("Failed to call %s.is_on for %s", - module, ent_id) + if component.is_on(ent_id): + return True return False @@ -161,10 +162,9 @@ def async_handle_core_service(call): return if errors: - notif = get_component('persistent_notification') _LOGGER.error(errors) - notif.async_create( - hass, "Config error. See dev-info panel for details.", + hass.components.persistent_notification.async_create( + "Config error. See dev-info panel for details.", "Config validating", "{0}.check_config".format(ha.DOMAIN)) return diff --git a/homeassistant/components/alarm_control_panel/simplisafe.py b/homeassistant/components/alarm_control_panel/simplisafe.py index fadfbc41a6fde..913a3abb616b5 100644 --- a/homeassistant/components/alarm_control_panel/simplisafe.py +++ b/homeassistant/components/alarm_control_panel/simplisafe.py @@ -15,7 +15,6 @@ STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, EVENT_HOMEASSISTANT_STOP) import homeassistant.helpers.config_validation as cv -import homeassistant.loader as loader REQUIREMENTS = ['simplisafe-python==1.0.2'] @@ -42,7 +41,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) - persistent_notification = loader.get_component('persistent_notification') simplisafe = SimpliSafeApiInterface() status = simplisafe.set_credentials(username, password) if status: @@ -53,8 +51,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): else: message = 'Failed to log into SimpliSafe. Check credentials.' _LOGGER.error(message) - persistent_notification.create( - hass, message, + hass.components.persistent_notification.create( + message, title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) return False diff --git a/homeassistant/components/amcrest.py b/homeassistant/components/amcrest.py index 8a40c790c1262..9760ee5d60773 100644 --- a/homeassistant/components/amcrest.py +++ b/homeassistant/components/amcrest.py @@ -11,7 +11,6 @@ import voluptuous as vol from requests.exceptions import HTTPError, ConnectTimeout -import homeassistant.loader as loader from homeassistant.const import ( CONF_NAME, CONF_HOST, CONF_PORT, CONF_USERNAME, CONF_PASSWORD, CONF_SENSORS, CONF_SCAN_INTERVAL, HTTP_BASIC_AUTHENTICATION) @@ -92,7 +91,6 @@ def setup(hass, config): amcrest_cams = config[DOMAIN] - persistent_notification = loader.get_component('persistent_notification') for device in amcrest_cams: camera = AmcrestCamera(device.get(CONF_HOST), device.get(CONF_PORT), @@ -103,8 +101,8 @@ def setup(hass, config): except (ConnectTimeout, HTTPError) as ex: _LOGGER.error("Unable to connect to Amcrest camera: %s", str(ex)) - persistent_notification.create( - hass, 'Error: {}
' + hass.components.persistent_notification.create( + 'Error: {}
' 'You will need to restart hass after fixing.' ''.format(ex), title=NOTIFICATION_TITLE, diff --git a/homeassistant/components/apple_tv.py b/homeassistant/components/apple_tv.py index 17cc46f33187f..948caa27538cc 100644 --- a/homeassistant/components/apple_tv.py +++ b/homeassistant/components/apple_tv.py @@ -15,7 +15,6 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers import discovery from homeassistant.components.discovery import SERVICE_APPLE_TV -from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['pyatv==0.3.2'] @@ -66,27 +65,24 @@ def request_configuration(hass, config, atv, credentials): """Request configuration steps from the user.""" - configurator = get_component('configurator') + configurator = hass.components.configurator @asyncio.coroutine def configuration_callback(callback_data): """Handle the submitted configuration.""" from pyatv import exceptions pin = callback_data.get('pin') - notification = get_component('persistent_notification') try: yield from atv.airplay.finish_authentication(pin) - notification.async_create( - hass, + hass.components.persistent_notification.async_create( 'Authentication succeeded!

Add the following ' 'to credentials: in your apple_tv configuration:

' '{0}'.format(credentials), title=NOTIFICATION_AUTH_TITLE, notification_id=NOTIFICATION_AUTH_ID) except exceptions.DeviceAuthenticationError as ex: - notification.async_create( - hass, + hass.components.persistent_notification.async_create( 'Authentication failed! Did you enter correct PIN?

' 'Details: {0}'.format(ex), title=NOTIFICATION_AUTH_TITLE, @@ -119,9 +115,7 @@ def scan_for_apple_tvs(hass): if not devices: devices = ['No device(s) found'] - notification = get_component('persistent_notification') - notification.async_create( - hass, + hass.components.persistent_notification.async_create( 'The following devices were found:

' + '

'.join(devices), title=NOTIFICATION_SCAN_TITLE, diff --git a/homeassistant/components/arlo.py b/homeassistant/components/arlo.py index 630420bd3e5ad..1ba2acb4fe073 100644 --- a/homeassistant/components/arlo.py +++ b/homeassistant/components/arlo.py @@ -9,7 +9,6 @@ import voluptuous as vol from requests.exceptions import HTTPError, ConnectTimeout -import homeassistant.loader as loader from homeassistant.helpers import config_validation as cv from homeassistant.const import CONF_USERNAME, CONF_PASSWORD @@ -40,7 +39,6 @@ def setup(hass, config): username = conf.get(CONF_USERNAME) password = conf.get(CONF_PASSWORD) - persistent_notification = loader.get_component('persistent_notification') try: from pyarlo import PyArlo @@ -50,8 +48,8 @@ def setup(hass, config): hass.data[DATA_ARLO] = arlo except (ConnectTimeout, HTTPError) as ex: _LOGGER.error("Unable to connect to Netgar Arlo: %s", str(ex)) - persistent_notification.create( - hass, 'Error: {}
' + hass.components.persistent_notification.create( + 'Error: {}
' 'You will need to restart hass after fixing.' ''.format(ex), title=NOTIFICATION_TITLE, diff --git a/homeassistant/components/axis.py b/homeassistant/components/axis.py index bb1ec05496a4f..d83e07989e60d 100644 --- a/homeassistant/components/axis.py +++ b/homeassistant/components/axis.py @@ -21,7 +21,6 @@ from homeassistant.helpers import discovery from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.entity import Entity -from homeassistant.loader import get_component REQUIREMENTS = ['axis==8'] @@ -79,7 +78,7 @@ def request_configuration(hass, name, host, serialnumber): """Request configuration steps from the user.""" - configurator = get_component('configurator') + configurator = hass.components.configurator def configuration_callback(callback_data): """Called when config is submitted.""" @@ -242,12 +241,11 @@ def setup_device(hass, config): if enable_metadatastream: device.initialize_new_event = event_initialized if not device.initiate_metadatastream(): - notification = get_component('persistent_notification') - notification.create(hass, - 'Dependency missing for sensors, ' - 'please check documentation', - title=DOMAIN, - notification_id='axis_notification') + hass.components.persistent_notification.create( + 'Dependency missing for sensors, ' + 'please check documentation', + title=DOMAIN, + notification_id='axis_notification') AXIS_DEVICES[device.serial_number] = device diff --git a/homeassistant/components/configurator.py b/homeassistant/components/configurator.py index e502e0a0253a8..660a62a5b895e 100644 --- a/homeassistant/components/configurator.py +++ b/homeassistant/components/configurator.py @@ -12,6 +12,7 @@ from homeassistant.core import callback as async_callback from homeassistant.const import EVENT_TIME_CHANGED, ATTR_FRIENDLY_NAME, \ ATTR_ENTITY_PICTURE +from homeassistant.loader import bind_hass from homeassistant.helpers.entity import generate_entity_id from homeassistant.util.async import run_callback_threadsafe @@ -37,6 +38,7 @@ STATE_CONFIGURED = 'configured' +@bind_hass def request_config( hass, name, callback, description=None, description_image=None, submit_caption=None, fields=None, link_name=None, link_url=None, diff --git a/homeassistant/components/cover/myq.py b/homeassistant/components/cover/myq.py index 4c862f8c8b87a..8d59a90278c69 100644 --- a/homeassistant/components/cover/myq.py +++ b/homeassistant/components/cover/myq.py @@ -12,7 +12,6 @@ from homeassistant.const import ( CONF_USERNAME, CONF_PASSWORD, CONF_TYPE, STATE_CLOSED) import homeassistant.helpers.config_validation as cv -import homeassistant.loader as loader REQUIREMENTS = ['pymyq==0.0.8'] @@ -37,7 +36,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) brand = config.get(CONF_TYPE) - persistent_notification = loader.get_component('persistent_notification') myq = pymyq(username, password, brand) try: @@ -52,8 +50,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except (TypeError, KeyError, NameError, ValueError) as ex: _LOGGER.error("%s", ex) - persistent_notification.create( - hass, 'Error: {}
' + hass.components.persistent_notification.create( + 'Error: {}
' 'You will need to restart hass after fixing.' ''.format(ex), title=NOTIFICATION_TITLE, diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 222a031d38077..27bb1bbb8d125 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -9,7 +9,6 @@ import homeassistant.bootstrap as bootstrap import homeassistant.core as ha -import homeassistant.loader as loader from homeassistant.const import ATTR_ENTITY_ID, CONF_PLATFORM DEPENDENCIES = ['conversation', 'introduction', 'zone'] @@ -38,9 +37,9 @@ @asyncio.coroutine def async_setup(hass, config): """Set up the demo environment.""" - group = loader.get_component('group') - configurator = loader.get_component('configurator') - persistent_notification = loader.get_component('persistent_notification') + group = hass.components.group + configurator = hass.components.configurator + persistent_notification = hass.components.persistent_notification config.setdefault(ha.DOMAIN, {}) config.setdefault(DOMAIN, {}) @@ -206,7 +205,7 @@ def hue_configuration_callback(data): def setup_configurator(): """Set up a configurator.""" request_id = configurator.request_config( - hass, "Philips Hue", hue_configuration_callback, + "Philips Hue", hue_configuration_callback, description=("Press the button on the bridge to register Philips " "Hue with Home Assistant."), description_image="/static/images/config_philips_hue.jpg", diff --git a/homeassistant/components/device_tracker/unifi.py b/homeassistant/components/device_tracker/unifi.py index 29c997b4dac68..a471ca5c96a10 100644 --- a/homeassistant/components/device_tracker/unifi.py +++ b/homeassistant/components/device_tracker/unifi.py @@ -8,7 +8,6 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv -import homeassistant.loader as loader from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD @@ -48,14 +47,13 @@ def get_scanner(hass, config): port = config[DOMAIN].get(CONF_PORT) verify_ssl = config[DOMAIN].get(CONF_VERIFY_SSL) - persistent_notification = loader.get_component('persistent_notification') try: ctrl = Controller(host, username, password, port, version='v4', site_id=site_id, ssl_verify=verify_ssl) except APIError as ex: _LOGGER.error("Failed to connect to Unifi: %s", ex) - persistent_notification.create( - hass, 'Failed to connect to Unifi. ' + hass.components.persistent_notification.create( + 'Failed to connect to Unifi. ' 'Error: {}
' 'You will need to restart hass after fixing.' ''.format(ex), diff --git a/homeassistant/components/google.py b/homeassistant/components/google.py index f7f8e63167f09..e99c4095f220a 100644 --- a/homeassistant/components/google.py +++ b/homeassistant/components/google.py @@ -17,7 +17,6 @@ from voluptuous.error import Error as VoluptuousError import homeassistant.helpers.config_validation as cv -import homeassistant.loader as loader from homeassistant.setup import setup_component from homeassistant.helpers import discovery from homeassistant.helpers.entity import generate_entity_id @@ -106,32 +105,31 @@ def do_authentication(hass, config): 'Home-Assistant.io', ) - persistent_notification = loader.get_component('persistent_notification') try: dev_flow = oauth.step1_get_device_and_user_codes() except OAuth2DeviceCodeError as err: - persistent_notification.create( - hass, 'Error: {}
You will need to restart hass after fixing.' - ''.format(err), + hass.components.persistent_notification.create( + 'Error: {}
You will need to restart hass after fixing.' + ''.format(err), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) return False - persistent_notification.create( - hass, 'In order to authorize Home-Assistant to view your calendars ' - 'you must visit: {} and enter ' - 'code: {}'.format(dev_flow.verification_url, - dev_flow.verification_url, - dev_flow.user_code), + hass.components.persistent_notification.create( + 'In order to authorize Home-Assistant to view your calendars ' + 'you must visit: {} and enter ' + 'code: {}'.format(dev_flow.verification_url, + dev_flow.verification_url, + dev_flow.user_code), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID ) def step2_exchange(now): """Keep trying to validate the user_code until it expires.""" if now >= dt.as_local(dev_flow.user_code_expiry): - persistent_notification.create( - hass, 'Authenication code expired, please restart ' - 'Home-Assistant and try again', + hass.components.persistent_notification.create( + 'Authenication code expired, please restart ' + 'Home-Assistant and try again', title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) listener() @@ -146,9 +144,9 @@ def step2_exchange(now): storage.put(credentials) do_setup(hass, config) listener() - persistent_notification.create( - hass, 'We are all setup now. Check {} for calendars that have ' - 'been found'.format(YAML_DEVICES), + hass.components.persistent_notification.create( + 'We are all setup now. Check {} for calendars that have ' + 'been found'.format(YAML_DEVICES), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) listener = track_time_change(hass, step2_exchange, diff --git a/homeassistant/components/media_player/roku.py b/homeassistant/components/media_player/roku.py index aac6b1a228db0..5917f1e308344 100644 --- a/homeassistant/components/media_player/roku.py +++ b/homeassistant/components/media_player/roku.py @@ -15,7 +15,6 @@ from homeassistant.const import ( CONF_HOST, STATE_IDLE, STATE_PLAYING, STATE_UNKNOWN, STATE_HOME) import homeassistant.helpers.config_validation as cv -import homeassistant.loader as loader REQUIREMENTS = ['python-roku==3.1.3'] @@ -52,7 +51,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): elif CONF_HOST in config: hosts.append(config.get(CONF_HOST)) - persistent_notification = loader.get_component('persistent_notification') rokus = [] for host in hosts: new_roku = RokuDevice(host) @@ -66,8 +64,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except AttributeError: _LOGGER.error("Unable to initialize roku at %s", host) - persistent_notification.create( - hass, 'Error: Unable to initialize roku at {}
' + hass.components.persistent_notification.create( + 'Error: Unable to initialize roku at {}
' 'Check its network connection or consider ' 'using auto discovery.
' 'You will need to restart hass after fixing.' diff --git a/homeassistant/components/ring.py b/homeassistant/components/ring.py index 450ef6b197865..a1529fddbd60c 100644 --- a/homeassistant/components/ring.py +++ b/homeassistant/components/ring.py @@ -9,7 +9,6 @@ import homeassistant.helpers.config_validation as cv from homeassistant.const import CONF_USERNAME, CONF_PASSWORD -import homeassistant.loader as loader from requests.exceptions import HTTPError, ConnectTimeout @@ -40,7 +39,6 @@ def setup(hass, config): username = conf.get(CONF_USERNAME) password = conf.get(CONF_PASSWORD) - persistent_notification = loader.get_component('persistent_notification') try: from ring_doorbell import Ring @@ -51,8 +49,8 @@ def setup(hass, config): hass.data['ring'] = ring except (ConnectTimeout, HTTPError) as ex: _LOGGER.error("Unable to connect to Ring service: %s", str(ex)) - persistent_notification.create( - hass, 'Error: {}
' + hass.components.persistent_notification.create( + 'Error: {}
' 'You will need to restart hass after fixing.' ''.format(ex), title=NOTIFICATION_TITLE, diff --git a/homeassistant/components/sensor/qnap.py b/homeassistant/components/sensor/qnap.py index 42f68a1967a0f..20460f9063c05 100644 --- a/homeassistant/components/sensor/qnap.py +++ b/homeassistant/components/sensor/qnap.py @@ -110,11 +110,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): api.update() if not api.data: - import homeassistant.loader as loader - loader.get_component('persistent_notification').create( - hass, 'Error: Failed to set up QNAP sensor.
' - 'Check the logs for additional information. ' - 'You will need to restart hass after fixing.', + hass.components.persistent_notification.create( + 'Error: Failed to set up QNAP sensor.
' + 'Check the logs for additional information. ' + 'You will need to restart hass after fixing.', title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) return False diff --git a/homeassistant/components/switch/broadlink.py b/homeassistant/components/switch/broadlink.py index 3a7f3ee0c80fa..6ea738d82bc19 100644 --- a/homeassistant/components/switch/broadlink.py +++ b/homeassistant/components/switch/broadlink.py @@ -13,7 +13,6 @@ import voluptuous as vol -import homeassistant.loader as loader from homeassistant.util.dt import utcnow from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA) from homeassistant.const import ( @@ -67,8 +66,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): config.get(CONF_MAC).encode().replace(b':', b'')) switch_type = config.get(CONF_TYPE) - persistent_notification = loader.get_component('persistent_notification') - @asyncio.coroutine def _learn_command(call): try: @@ -91,13 +88,13 @@ def _learn_command(call): log_msg = "Recieved packet is: {}".\ format(b64encode(packet).decode('utf8')) _LOGGER.info(log_msg) - persistent_notification.async_create( - hass, log_msg, title='Broadlink switch') + hass.components.persistent_notification.async_create( + log_msg, title='Broadlink switch') return yield from asyncio.sleep(1, loop=hass.loop) _LOGGER.error("Did not received any signal") - persistent_notification.async_create( - hass, "Did not received any signal", title='Broadlink switch') + hass.components.persistent_notification.async_create( + "Did not received any signal", title='Broadlink switch') @asyncio.coroutine def _send_packet(call): diff --git a/homeassistant/components/upnp.py b/homeassistant/components/upnp.py index 355a6d0a64805..9e45def63dbc3 100644 --- a/homeassistant/components/upnp.py +++ b/homeassistant/components/upnp.py @@ -9,8 +9,6 @@ import voluptuous as vol -import homeassistant.loader as loader - from homeassistant.const import (EVENT_HOMEASSISTANT_STOP) from homeassistant.helpers import config_validation as cv from homeassistant.helpers import discovery @@ -78,8 +76,6 @@ def setup(hass, config): if external_port == 0: external_port = internal_port - persistent_notification = loader.get_component('persistent_notification') - try: upnp.addportmapping( external_port, 'TCP', host, internal_port, 'Home Assistant', '') @@ -92,8 +88,8 @@ def deregister_port(event): except Exception as ex: _LOGGER.error("UPnP failed to configure port mapping: %s", str(ex)) - persistent_notification.create( - hass, 'ERROR: tcp port {} is already mapped in your router.' + hass.components.persistent_notification.create( + 'ERROR: tcp port {} is already mapped in your router.' '
Please disable port_mapping in the upnp ' 'configuration section.
' 'You will need to restart hass after fixing.' From ffd3081743e5e0d0ba2051aa0d93e6a648fdd3ca Mon Sep 17 00:00:00 2001 From: Alexander Rust Date: Sun, 16 Jul 2017 21:43:47 +0200 Subject: [PATCH 017/118] Added additional attributes to OwnTracks device_tracker (#8503) * Added additional attributes to OwnTracks device_tracker * Added missing space after : --- homeassistant/components/device_tracker/owntracks.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/owntracks.py b/homeassistant/components/device_tracker/owntracks.py index f88fda03cf7df..ab4ba315c0245 100644 --- a/homeassistant/components/device_tracker/owntracks.py +++ b/homeassistant/components/device_tracker/owntracks.py @@ -353,12 +353,20 @@ def _parse_see_args(topic, data): kwargs = { 'dev_id': dev_id, 'host_name': host_name, - 'gps': (data[WAYPOINT_LAT_KEY], data[WAYPOINT_LON_KEY]) + 'gps': (data[WAYPOINT_LAT_KEY], data[WAYPOINT_LON_KEY]), + 'attributes': {} } if 'acc' in data: kwargs['gps_accuracy'] = data['acc'] if 'batt' in data: kwargs['battery'] = data['batt'] + if 'vel' in data: + kwargs['attributes']['velocity'] = data['vel'] + if 'tid' in data: + kwargs['attributes']['tid'] = data['tid'] + if 'addr' in data: + kwargs['attributes']['address'] = data['addr'] + return dev_id, kwargs From 8c9557401fc11790ab5ddf08c1e09e3ba3d56743 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 17 Jul 2017 11:03:16 +0200 Subject: [PATCH 018/118] Update dlib_face_detect.py (#8516) --- homeassistant/components/image_processing/dlib_face_detect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/image_processing/dlib_face_detect.py b/homeassistant/components/image_processing/dlib_face_detect.py index 7c0c0e2664906..b4ad10934f2d2 100644 --- a/homeassistant/components/image_processing/dlib_face_detect.py +++ b/homeassistant/components/image_processing/dlib_face_detect.py @@ -68,4 +68,4 @@ def process_image(self, image): image = face_recognition.load_image_file(fak_file) face_locations = face_recognition.face_locations(image) - self.process_faces(face_locations, len(face_locations)) + self.process_faces(list(face_locations), len(face_locations)) From 40aafcdf5df2abb10dd9ae08ecc6b9349f6d0244 Mon Sep 17 00:00:00 2001 From: Russell Cloran Date: Mon, 17 Jul 2017 02:25:20 -0700 Subject: [PATCH 019/118] prometheus: Convert fahrenheit to celsius (#8511) --- homeassistant/components/prometheus.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/prometheus.py b/homeassistant/components/prometheus.py index 4ed6028ac568d..18a3a932d36ab 100644 --- a/homeassistant/components/prometheus.py +++ b/homeassistant/components/prometheus.py @@ -17,6 +17,7 @@ TEMP_CELSIUS, TEMP_FAHRENHEIT) from homeassistant import core as hacore from homeassistant.helpers import state as state_helper +from homeassistant.util.temperature import fahrenheit_to_celsius _LOGGER = logging.getLogger(__name__) @@ -198,6 +199,8 @@ def _handle_sensor(self, state): metric = self._metric(*metric) try: value = state_helper.state_as_number(state) + if unit == TEMP_FAHRENHEIT: + value = fahrenheit_to_celsius(value) metric.labels(**self._labels(state)).set(value) except ValueError: pass From f0479855bdfff3140ccf761fcb8c9ac247691157 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 17 Jul 2017 12:09:42 +0200 Subject: [PATCH 020/118] Realfix for dlib (#8517) * Update dlib_face_detect.py * fix lint * Update dlib_face_detect.py --- .../components/image_processing/dlib_face_detect.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/image_processing/dlib_face_detect.py b/homeassistant/components/image_processing/dlib_face_detect.py index b4ad10934f2d2..1c999782ec78a 100644 --- a/homeassistant/components/image_processing/dlib_face_detect.py +++ b/homeassistant/components/image_processing/dlib_face_detect.py @@ -19,6 +19,8 @@ _LOGGER = logging.getLogger(__name__) +ATTR_LOCATION = 'location' + def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Dlib Face detection platform.""" @@ -68,4 +70,7 @@ def process_image(self, image): image = face_recognition.load_image_file(fak_file) face_locations = face_recognition.face_locations(image) - self.process_faces(list(face_locations), len(face_locations)) + face_locations = [{ATTR_LOCATION: location} + for location in face_locations] + + self.process_faces(face_locations, len(face_locations)) From cca0d3ed446e0e9842390cdb18207d121a0a4210 Mon Sep 17 00:00:00 2001 From: Eugenio Panadero Date: Mon, 17 Jul 2017 13:47:28 +0200 Subject: [PATCH 021/118] Attach the `chat_id` for a callback query from a chat group (fixes #8461) (#8523) --- homeassistant/components/telegram_bot/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/telegram_bot/__init__.py b/homeassistant/components/telegram_bot/__init__.py index 3d16252120bf3..6d9f43e2425ef 100644 --- a/homeassistant/components/telegram_bot/__init__.py +++ b/homeassistant/components/telegram_bot/__init__.py @@ -581,6 +581,8 @@ def _get_message_data(self, msg_data): data[ATTR_FROM_LAST] = msg_data['from']['last_name'] if 'chat' in msg_data: data[ATTR_CHAT_ID] = msg_data['chat']['id'] + elif ATTR_MESSAGE in msg_data and 'chat' in msg_data[ATTR_MESSAGE]: + data[ATTR_CHAT_ID] = msg_data[ATTR_MESSAGE]['chat']['id'] return True, data From 1a1571cd520f7bd8192b443625d8887d7e1f3ce6 Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Mon, 17 Jul 2017 13:21:41 -0400 Subject: [PATCH 022/118] Added sensor state rounding (#8499) --- homeassistant/components/sensor/pi_hole.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/pi_hole.py b/homeassistant/components/sensor/pi_hole.py index bacb25ce2c4c4..f788fc8fd173d 100644 --- a/homeassistant/components/sensor/pi_hole.py +++ b/homeassistant/components/sensor/pi_hole.py @@ -104,7 +104,10 @@ def unit_of_measurement(self): @property def state(self): """Return the state of the device.""" - return self._api.data[self._var_id] + try: + return round(self._api.data[self._var_id], 2) + except TypeError: + return self._api.data[self._var_id] # pylint: disable=no-member @property From c67c20f75205ad6da5c120a3736847a2eb9e9c1e Mon Sep 17 00:00:00 2001 From: Mike Christianson Date: Mon, 17 Jul 2017 10:45:42 -0700 Subject: [PATCH 023/118] fix for a bug introduced with media support in #8282 (#8513) data may be None if twitter data property unconfigured: File "/opt/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/notify/twitter.py", line 63, in send_message media = data.get(ATTR_MEDIA) --- homeassistant/components/notify/twitter.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/notify/twitter.py b/homeassistant/components/notify/twitter.py index 6d74f86132aef..43efd2c2732ca 100644 --- a/homeassistant/components/notify/twitter.py +++ b/homeassistant/components/notify/twitter.py @@ -60,10 +60,13 @@ def __init__(self, hass, consumer_key, consumer_secret, access_token_key, def send_message(self, message="", **kwargs): """Tweet a message, optionally with media.""" data = kwargs.get(ATTR_DATA) - media = data.get(ATTR_MEDIA) - if not self.hass.config.is_allowed_path(media): - _LOGGER.warning("'%s' is not in a whitelisted area.", media) - return + + media = None + if data: + media = data.get(ATTR_MEDIA) + if not self.hass.config.is_allowed_path(media): + _LOGGER.warning("'%s' is not in a whitelisted area.", media) + return media_id = self.upload_media(media) From 95e00279240e282c9a060d230ef2aaea33646a6d Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 17 Jul 2017 20:21:16 +0200 Subject: [PATCH 024/118] Fix KeyError --- homeassistant/components/notify/twitter.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/notify/twitter.py b/homeassistant/components/notify/twitter.py index 43efd2c2732ca..74002b89c7642 100644 --- a/homeassistant/components/notify/twitter.py +++ b/homeassistant/components/notify/twitter.py @@ -65,7 +65,7 @@ def send_message(self, message="", **kwargs): if data: media = data.get(ATTR_MEDIA) if not self.hass.config.is_allowed_path(media): - _LOGGER.warning("'%s' is not in a whitelisted area.", media) + _LOGGER.warning("'%s' is not a whitelisted directory", media) return media_id = self.upload_media(media) @@ -97,8 +97,7 @@ def upload_media(self, media_path=None): return None media_id = resp.json()['media_id'] - media_id = self.upload_media_chunked(file, total_bytes, - media_id) + media_id = self.upload_media_chunked(file, total_bytes, media_id) resp = self.upload_media_finalize(media_id) if 199 > resp.status_code < 300: @@ -150,8 +149,8 @@ def log_bytes_sent(bytes_sent, total_bytes): def log_error_resp(resp): """Log error response.""" obj = json.loads(resp.text) - error_message = obj['error'] - _LOGGER.error("Error %s : %s", resp.status_code, error_message) + error_message = obj['errors'] + _LOGGER.error("Error %s: %s", resp.status_code, error_message) @staticmethod def log_error_resp_append(resp): @@ -159,5 +158,5 @@ def log_error_resp_append(resp): obj = json.loads(resp.text) error_message = obj['errors'][0]['message'] error_code = obj['errors'][0]['code'] - _LOGGER.error("Error %s : %s (Code %s)", resp.status_code, + _LOGGER.error("Error %s: %s (Code %s)", resp.status_code, error_message, error_code) From 8c9b3898fcda136a7ead6c81143894bc6007fc20 Mon Sep 17 00:00:00 2001 From: Eugenio Panadero Date: Mon, 17 Jul 2017 22:16:18 +0200 Subject: [PATCH 025/118] handle timeout errors without logging.exception when updating hue lights; double quotes in log msgs (#8524) --- homeassistant/components/light/hue.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 3344de02e75f9..cdbea7d2194ea 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -115,7 +115,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if discovery_info is not None: if "HASS Bridge" in discovery_info.get('name', ''): - _LOGGER.info('Emulated hue found, will not add') + _LOGGER.info("Emulated hue found, will not add") return False host = discovery_info.get('host') @@ -126,7 +126,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): host = _find_host_from_config(hass, filename) if host is None: - _LOGGER.error('No host found in configuration') + _LOGGER.error("No host found in configuration") return False # Only act if we are not already configuring this host @@ -180,6 +180,12 @@ def update_lights(): try: api = bridge.get_api() + except phue.PhueRequestTimeout: + _LOGGER.warning("Timeout trying to reach the bridge") + return + except ConnectionRefusedError: + _LOGGER.error("The bridge refused the connection") + return except socket.error: # socket.error when we cannot reach Hue _LOGGER.exception("Cannot reach the bridge") @@ -221,8 +227,8 @@ def update_lights(): for lightgroup_id, info in api_groups.items(): if 'state' not in info: - _LOGGER.warning('Group info does not contain state. ' - 'Please update your hub.') + _LOGGER.warning("Group info does not contain state. " + "Please update your hub.") skip_groups = True break From b83ff739bc20e1e43486a0d4186446a19896272a Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Mon, 17 Jul 2017 22:24:05 +0200 Subject: [PATCH 026/118] Remove deprecated automation keywords (#8510) * Remove deprecated automation keywords * Remove retired test case * Remove retired keyword --- homeassistant/components/automation/state.py | 8 ++------ homeassistant/components/automation/time.py | 11 ++--------- tests/components/automation/test_state.py | 19 ------------------- 3 files changed, 4 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/automation/state.py b/homeassistant/components/automation/state.py index fbd1570a1e0cf..8ad5c40bb80d2 100644 --- a/homeassistant/components/automation/state.py +++ b/homeassistant/components/automation/state.py @@ -12,13 +12,11 @@ from homeassistant.const import MATCH_ALL, CONF_PLATFORM from homeassistant.helpers.event import ( async_track_state_change, async_track_point_in_utc_time) -from homeassistant.helpers.deprecation import get_deprecated import homeassistant.helpers.config_validation as cv CONF_ENTITY_ID = 'entity_id' CONF_FROM = 'from' CONF_TO = 'to' -CONF_STATE = 'state' CONF_FOR = 'for' TRIGGER_SCHEMA = vol.All( @@ -28,11 +26,9 @@ # These are str on purpose. Want to catch YAML conversions CONF_FROM: str, CONF_TO: str, - CONF_STATE: str, CONF_FOR: vol.All(cv.time_period, cv.positive_timedelta), }), - vol.Any(cv.key_dependency(CONF_FOR, CONF_TO), - cv.key_dependency(CONF_FOR, CONF_STATE)) + cv.key_dependency(CONF_FOR, CONF_TO), ) @@ -41,7 +37,7 @@ def async_trigger(hass, config, action): """Listen for state changes based on configuration.""" entity_id = config.get(CONF_ENTITY_ID) from_state = config.get(CONF_FROM, MATCH_ALL) - to_state = get_deprecated(config, CONF_TO, CONF_STATE, MATCH_ALL) + to_state = config.get(CONF_TO, MATCH_ALL) time_delta = config.get(CONF_FOR) async_remove_state_for_cancel = None async_remove_state_for_listener = None diff --git a/homeassistant/components/automation/time.py b/homeassistant/components/automation/time.py index 8ba082e3331ec..a3a8496c3c52c 100644 --- a/homeassistant/components/automation/time.py +++ b/homeassistant/components/automation/time.py @@ -10,7 +10,7 @@ import voluptuous as vol from homeassistant.core import callback -from homeassistant.const import CONF_AT, CONF_PLATFORM, CONF_AFTER +from homeassistant.const import CONF_AT, CONF_PLATFORM from homeassistant.helpers import config_validation as cv from homeassistant.helpers.event import async_track_time_change @@ -23,12 +23,10 @@ TRIGGER_SCHEMA = vol.All(vol.Schema({ vol.Required(CONF_PLATFORM): 'time', CONF_AT: cv.time, - CONF_AFTER: cv.time, CONF_HOURS: vol.Any(vol.Coerce(int), vol.Coerce(str)), CONF_MINUTES: vol.Any(vol.Coerce(int), vol.Coerce(str)), CONF_SECONDS: vol.Any(vol.Coerce(int), vol.Coerce(str)), -}), cv.has_at_least_one_key(CONF_HOURS, CONF_MINUTES, - CONF_SECONDS, CONF_AT, CONF_AFTER)) +}), cv.has_at_least_one_key(CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AT)) @asyncio.coroutine @@ -37,11 +35,6 @@ def async_trigger(hass, config, action): if CONF_AT in config: at_time = config.get(CONF_AT) hours, minutes, seconds = at_time.hour, at_time.minute, at_time.second - elif CONF_AFTER in config: - _LOGGER.warning("'after' is deprecated for the time trigger. Please " - "rename 'after' to 'at' in your configuration file.") - at_time = config.get(CONF_AFTER) - hours, minutes, seconds = at_time.hour, at_time.minute, at_time.second else: hours = config.get(CONF_HOURS) minutes = config.get(CONF_MINUTES) diff --git a/tests/components/automation/test_state.py b/tests/components/automation/test_state.py index 28473511e2999..2fd6c8415db57 100644 --- a/tests/components/automation/test_state.py +++ b/tests/components/automation/test_state.py @@ -130,25 +130,6 @@ def test_if_fires_on_attribute_change_with_to_filter(self): self.hass.block_till_done() self.assertEqual(1, len(self.calls)) - def test_if_fires_on_entity_change_with_state_filter(self): - """Test for firing on entity change with state filter.""" - assert setup_component(self.hass, automation.DOMAIN, { - automation.DOMAIN: { - 'trigger': { - 'platform': 'state', - 'entity_id': 'test.entity', - 'state': 'world' - }, - 'action': { - 'service': 'test.automation' - } - } - }) - - self.hass.states.set('test.entity', 'world') - self.hass.block_till_done() - self.assertEqual(1, len(self.calls)) - def test_if_fires_on_entity_change_with_both_filters(self): """Test for firing if both filters are a non match.""" assert setup_component(self.hass, automation.DOMAIN, { From fde4a7d029bd5983ae6dbb9541082c5a88cd82e3 Mon Sep 17 00:00:00 2001 From: Jan Losinski Date: Mon, 17 Jul 2017 22:50:55 +0200 Subject: [PATCH 027/118] Citybikes: Allow None as result for empty slots (#8528) The citibykes API returns "null" as value for empty_slots on some stations (see #8527). This causes the component to not process the data. This is fixed by accepting None as valid data. The row in the frontend is left empty if "null" was returned by the service. fixes #8527 --- homeassistant/components/sensor/citybikes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/citybikes.py b/homeassistant/components/sensor/citybikes.py index 15046897732a1..4cb532d26eb15 100644 --- a/homeassistant/components/sensor/citybikes.py +++ b/homeassistant/components/sensor/citybikes.py @@ -82,7 +82,7 @@ STATION_SCHEMA = vol.Schema({ vol.Required(ATTR_FREE_BIKES): cv.positive_int, - vol.Required(ATTR_EMPTY_SLOTS): cv.positive_int, + vol.Required(ATTR_EMPTY_SLOTS): vol.Any(cv.positive_int, None), vol.Required(ATTR_LATITUDE): cv.latitude, vol.Required(ATTR_LONGITUDE): cv.latitude, vol.Required(ATTR_ID): cv.string, From dcd6f7a29e96d2335c8f0c19774b78697e2fe7af Mon Sep 17 00:00:00 2001 From: Phil Lavin Date: Mon, 17 Jul 2017 22:34:38 +0100 Subject: [PATCH 028/118] Return a 0 temperature value when none is found (#8518) * Return a 0 temperature value when none is found It's well documented that these TRVs will only return the current temperature for a short time after the actuator has moved. This means that, usually, they will not return the current temperature. Setting a non-value here causes errors in the logs and for the TRV to not show on the dashboard at all * Fix lint issue --- homeassistant/components/climate/maxcube.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/climate/maxcube.py b/homeassistant/components/climate/maxcube.py index 9d6c1bbab5bec..271616daf8b04 100644 --- a/homeassistant/components/climate/maxcube.py +++ b/homeassistant/components/climate/maxcube.py @@ -10,7 +10,6 @@ from homeassistant.components.climate import ClimateDevice, STATE_AUTO from homeassistant.components.maxcube import MAXCUBE_HANDLE from homeassistant.const import TEMP_CELSIUS, ATTR_TEMPERATURE -from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) @@ -140,7 +139,7 @@ def update(self): def map_temperature_max_hass(temperature): """Map Temperature from MAX! to HASS.""" if temperature is None: - return STATE_UNKNOWN + return 0.0 return temperature From 4ae11c009dadfcdd9609d4e1b92441e8657fece1 Mon Sep 17 00:00:00 2001 From: Thibault Cohen Date: Tue, 18 Jul 2017 10:23:39 -0400 Subject: [PATCH 029/118] Fix #6469 and #6828 (#8537) --- homeassistant/components/sensor/hydroquebec.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/sensor/hydroquebec.py b/homeassistant/components/sensor/hydroquebec.py index 45a7b812039b8..884f101c03328 100644 --- a/homeassistant/components/sensor/hydroquebec.py +++ b/homeassistant/components/sensor/hydroquebec.py @@ -39,21 +39,21 @@ 'balance': ['Balance', PRICE, 'mdi:square-inc-cash'], 'period_total_bill': - ['Current period bill', PRICE, 'mdi:square-inc-cash'], + ['Period total bill', PRICE, 'mdi:square-inc-cash'], 'period_length': - ['Current period length', DAYS, 'mdi:calendar-today'], + ['Period length', DAYS, 'mdi:calendar-today'], 'period_total_days': - ['Total number of days in this period', DAYS, 'mdi:calendar-today'], + ['Period total days', DAYS, 'mdi:calendar-today'], 'period_mean_daily_bill': - ['Period daily average bill', PRICE, 'mdi:square-inc-cash'], + ['Period mean daily bill', PRICE, 'mdi:square-inc-cash'], 'period_mean_daily_consumption': - ['Period daily average consumption', KILOWATT_HOUR, 'mdi:flash'], + ['Period mean daily consumption', KILOWATT_HOUR, 'mdi:flash'], 'period_total_consumption': - ['Total Consumption', KILOWATT_HOUR, 'mdi:flash'], + ['Period total consumption', KILOWATT_HOUR, 'mdi:flash'], 'period_lower_price_consumption': - ['Period Lower price consumption', KILOWATT_HOUR, 'mdi:flash'], + ['Period lower price consumption', KILOWATT_HOUR, 'mdi:flash'], 'period_higher_price_consumption': - ['Period Higher price consumption', KILOWATT_HOUR, 'mdi:flash'], + ['Period higher price consumption', KILOWATT_HOUR, 'mdi:flash'], 'yesterday_total_consumption': ['Yesterday total consumption', KILOWATT_HOUR, 'mdi:flash'], 'yesterday_lower_price_consumption': @@ -125,7 +125,6 @@ def __init__(self, hydroquebec_data, sensor_type, name): """Initialize the sensor.""" self.client_name = name self.type = sensor_type - self.entity_id = "sensor.{}_{}".format(name, sensor_type) self._name = SENSOR_TYPES[sensor_type][0] self._unit_of_measurement = SENSOR_TYPES[sensor_type][1] self._icon = SENSOR_TYPES[sensor_type][2] From 879c816f5c20681c92838ffbec33c418129a0370 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 18 Jul 2017 16:23:57 +0200 Subject: [PATCH 030/118] Update docstrings (#8536) --- homeassistant/bootstrap.py | 18 +++++----- homeassistant/config.py | 74 +++++++++++++++++++------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index a90a96e4fa006..7831036ff597e 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -40,7 +40,7 @@ def from_config_dict(config: Dict[str, Any], skip_pip: bool=False, log_rotate_days: Any=None) \ -> Optional[core.HomeAssistant]: - """Try to configure Home Assistant from a config dict. + """Try to configure Home Assistant from a configuration dictionary. Dynamically loads required components and its dependencies. """ @@ -71,7 +71,7 @@ def async_from_config_dict(config: Dict[str, Any], skip_pip: bool=False, log_rotate_days: Any=None) \ -> Optional[core.HomeAssistant]: - """Try to configure Home Assistant from a config dict. + """Try to configure Home Assistant from a configuration dictionary. Dynamically loads required components and its dependencies. This method is a coroutine. @@ -92,8 +92,8 @@ def async_from_config_dict(config: Dict[str, Any], hass.config.skip_pip = skip_pip if skip_pip: - _LOGGER.warning('Skipping pip installation of required modules. ' - 'This may cause issues.') + _LOGGER.warning("Skipping pip installation of required modules. " + "This may cause issues") if not loader.PREPARED: yield from hass.async_add_job(loader.prepare, hass) @@ -118,13 +118,13 @@ def async_from_config_dict(config: Dict[str, Any], # pylint: disable=not-an-iterable res = yield from core_components.async_setup(hass, config) if not res: - _LOGGER.error('Home Assistant core failed to initialize. ' - 'Further initialization aborted.') + _LOGGER.error("Home Assistant core failed to initialize. " + "further initialization aborted") return hass yield from persistent_notification.async_setup(hass, config) - _LOGGER.info('Home Assistant core initialized') + _LOGGER.info("Home Assistant core initialized") # stage 1 for component in components: @@ -143,7 +143,7 @@ def async_from_config_dict(config: Dict[str, Any], yield from hass.async_block_till_done() stop = time() - _LOGGER.info('Home Assistant initialized in %.2fs', stop-start) + _LOGGER.info("Home Assistant initialized in %.2fs", stop-start) async_register_signal_handling(hass) return hass @@ -193,7 +193,7 @@ def async_from_config_file(config_path: str, config_dict = yield from hass.async_add_job( conf_util.load_yaml_config_file, config_path) except HomeAssistantError as err: - _LOGGER.error('Error loading %s: %s', config_path, err) + _LOGGER.error("Error loading %s: %s", config_path, err) return None finally: clear_secret_cache() diff --git a/homeassistant/config.py b/homeassistant/config.py index cb8d0b442c168..003e64816856a 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -40,7 +40,7 @@ DATA_CUSTOMIZE = 'hass_customize' FILE_MIGRATION = [ - ["ios.conf", ".ios.conf"], + ['ios.conf', '.ios.conf'], ] DEFAULT_CORE_CONFIG = ( @@ -71,7 +71,7 @@ http: # Uncomment this to add a password (recommended!) # api_password: PASSWORD - # Uncomment this if you are using SSL or running in Docker etc + # Uncomment this if you are using SSL/TLS, running in Docker container, etc. # base_url: example.duckdns.org:8123 # Checks for available updates @@ -89,7 +89,7 @@ # Allows you to issue voice commands from the frontend in enabled browsers conversation: -# Enables support for tracking state changes over time. +# Enables support for tracking state changes over time history: # View all events in a logbook @@ -98,13 +98,13 @@ # Track the sun sun: -# Weather Prediction +# Weather prediction sensor: - platform: yr + - platform: yr # Text to speech tts: - platform: google + - platform: google group: !include groups.yaml automation: !include automations.yaml @@ -141,17 +141,17 @@ def get_default_config_dir() -> str: - """Put together the default configuration directory based on OS.""" + """Put together the default configuration directory based on the OS.""" data_dir = os.getenv('APPDATA') if os.name == "nt" \ else os.path.expanduser('~') return os.path.join(data_dir, CONFIG_DIR_NAME) def ensure_config_exists(config_dir: str, detect_location: bool=True) -> str: - """Ensure a config file exists in given configuration directory. + """Ensure a configuration file exists in given configuration directory. Creating a default one if needed. - Return path to the config file. + Return path to the configuration file. """ config_path = find_config_file(config_dir) @@ -195,8 +195,8 @@ def create_default_config(config_dir, detect_location=True): info[attr] = getattr(location_info, prop) or default if location_info.latitude and location_info.longitude: - info[CONF_ELEVATION] = loc_util.elevation(location_info.latitude, - location_info.longitude) + info[CONF_ELEVATION] = loc_util.elevation( + location_info.latitude, location_info.longitude) # Writing files with YAML does not create the most human readable results # So we're hard coding a YAML template. @@ -225,16 +225,16 @@ def create_default_config(config_dir, detect_location=True): return config_path except IOError: - print('Unable to create default configuration file', config_path) + print("Unable to create default configuration file", config_path) return None @asyncio.coroutine def async_hass_config_yaml(hass): - """Load YAML from hass config File. + """Load YAML from a Home Assistant configuration file. - This function allow component inside asyncio loop to reload his config by - self. + This function allow a component inside the asyncio loop to reload its + configuration by itself. This method is a coroutine. """ @@ -269,7 +269,7 @@ def load_yaml_config_file(config_path): getattr(err, 'filename', err))) if not isinstance(conf_dict, dict): - msg = 'The configuration file {} does not contain a dictionary'.format( + msg = "The configuration file {} does not contain a dictionary".format( os.path.basename(config_path)) _LOGGER.error(msg) raise HomeAssistantError(msg) @@ -278,7 +278,7 @@ def load_yaml_config_file(config_path): def process_ha_config_upgrade(hass): - """Upgrade config if necessary. + """Upgrade configuration if necessary. This method needs to run in an executor. """ @@ -294,8 +294,8 @@ def process_ha_config_upgrade(hass): if conf_version == __version__: return - _LOGGER.info('Upgrading config directory from %s to %s', conf_version, - __version__) + _LOGGER.info("Upgrading configuration directory from %s to %s", + conf_version, __version__) if LooseVersion(conf_version) < LooseVersion('0.49'): # 0.49 introduced persistent deps dir. @@ -306,20 +306,20 @@ def process_ha_config_upgrade(hass): with open(version_path, 'wt') as outp: outp.write(__version__) - _LOGGER.info('Migrating old system config files to new locations') + _LOGGER.info("Migrating old system configuration files to new locations") for oldf, newf in FILE_MIGRATION: if os.path.isfile(hass.config.path(oldf)): - _LOGGER.info('Migrating %s to %s', oldf, newf) + _LOGGER.info("Migrating %s to %s", oldf, newf) os.rename(hass.config.path(oldf), hass.config.path(newf)) @callback def async_log_exception(ex, domain, config, hass): - """Generate log exception for config validation. + """Generate log exception for configuration validation. This method must be run in the event loop. """ - message = 'Invalid config for [{}]: '.format(domain) + message = "Invalid config for [{}]: ".format(domain) if hass is not None: async_notify_setup_error(hass, domain, True) @@ -344,7 +344,7 @@ def async_log_exception(ex, domain, config, hass): @asyncio.coroutine def async_process_ha_core_config(hass, config): - """Process the [homeassistant] section from the config. + """Process the [homeassistant] section from the configuration. This method is a coroutine. """ @@ -362,7 +362,7 @@ def set_time_zone(time_zone_str): hac.time_zone = time_zone date_util.set_default_time_zone(time_zone) else: - _LOGGER.error('Received invalid time zone %s', time_zone_str) + _LOGGER.error("Received invalid time zone %s", time_zone_str) for key, attr in ((CONF_LATITUDE, 'latitude'), (CONF_LONGITUDE, 'longitude'), @@ -374,7 +374,7 @@ def set_time_zone(time_zone_str): if CONF_TIME_ZONE in config: set_time_zone(config.get(CONF_TIME_ZONE)) - # init whitelist external dir + # Init whitelist external dir hac.whitelist_external_dirs = set((hass.config.path('www'),)) if CONF_WHITELIST_EXTERNAL_DIRS in config: hac.whitelist_external_dirs.update( @@ -394,7 +394,7 @@ def set_time_zone(time_zone_str): try: pkg_cust = CUSTOMIZE_CONFIG_SCHEMA(pkg_cust) except vol.Invalid: - _LOGGER.warning('Package %s contains invalid customize', name) + _LOGGER.warning("Package %s contains invalid customize", name) continue cust_exact.update(pkg_cust[CONF_CUSTOMIZE]) @@ -415,9 +415,9 @@ def set_time_zone(time_zone_str): hac.units = METRIC_SYSTEM else: hac.units = IMPERIAL_SYSTEM - _LOGGER.warning("Found deprecated temperature unit in core config, " - "expected unit system. Replace '%s: %s' with " - "'%s: %s'", CONF_TEMPERATURE_UNIT, unit, + _LOGGER.warning("Found deprecated temperature unit in core " + "configuration expected unit system. Replace '%s: %s' " + "with '%s: %s'", CONF_TEMPERATURE_UNIT, unit, CONF_UNIT_SYSTEM, hac.units.name) # Shortcut if no auto-detection necessary @@ -434,7 +434,7 @@ def set_time_zone(time_zone_str): loc_util.detect_location_info) if info is None: - _LOGGER.error('Could not detect location information') + _LOGGER.error("Could not detect location information") return if hac.latitude is None and hac.longitude is None: @@ -463,8 +463,8 @@ def set_time_zone(time_zone_str): if discovered: _LOGGER.warning( - 'Incomplete core config. Auto detected %s', - ', '.join('{}: {}'.format(key, val) for key, val in discovered)) + "Incomplete core configuration. Auto detected %s", + ", ".join('{}: {}'.format(key, val) for key, val in discovered)) def _log_pkg_error(package, component, config, message): @@ -495,7 +495,7 @@ def _identify_config_schema(module): def merge_packages_config(config, packages): - """Merge packages into the top-level config. Mutate config.""" + """Merge packages into the top-level configuration. Mutate config.""" # pylint: disable=too-many-nested-blocks PACKAGES_CONFIG_SCHEMA(packages) for pack_name, pack_conf in packages.items(): @@ -549,7 +549,7 @@ def merge_packages_config(config, packages): if comp_name in config: _log_pkg_error( pack_name, comp_name, config, "may occur only once" - " and it already exist in your main config") + " and it already exist in your main configuration") continue config[comp_name] = comp_conf @@ -558,7 +558,7 @@ def merge_packages_config(config, packages): @callback def async_process_component_config(hass, config, domain): - """Check component config and return processed config. + """Check component configuration and return processed configuration. Raise a vol.Invalid exception on error. @@ -619,7 +619,7 @@ def async_process_component_config(hass, config, domain): @asyncio.coroutine def async_check_ha_config_file(hass): - """Check if HA config file valid. + """Check if Home Assistant configuration file is valid. This method is a coroutine. """ From 2aa89cfe07792dabc18e4888aa6ba16c59e287cf Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 18 Jul 2017 16:24:32 +0200 Subject: [PATCH 031/118] Upgrade TwitterAPI to 2.4.6 (#8535) --- homeassistant/components/notify/twitter.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/twitter.py b/homeassistant/components/notify/twitter.py index 74002b89c7642..9d2a8c079322b 100644 --- a/homeassistant/components/notify/twitter.py +++ b/homeassistant/components/notify/twitter.py @@ -16,7 +16,7 @@ ATTR_DATA, PLATFORM_SCHEMA, BaseNotificationService) from homeassistant.const import CONF_ACCESS_TOKEN, CONF_USERNAME -REQUIREMENTS = ['TwitterAPI==2.4.5'] +REQUIREMENTS = ['TwitterAPI==2.4.6'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index e07cc8de84c53..5cb1e676b27ea 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -36,7 +36,7 @@ PyMata==2.14 SoCo==0.12 # homeassistant.components.notify.twitter -TwitterAPI==2.4.5 +TwitterAPI==2.4.6 # homeassistant.components.device_tracker.automatic aioautomatic==0.4.0 From 29266213a0ea0c9b21a167f40b9f1f7e31f0ef8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20St=C3=A5hl?= Date: Tue, 18 Jul 2017 20:19:36 +0200 Subject: [PATCH 032/118] Fix support for multiple Apple TVs (#8539) --- homeassistant/components/apple_tv.py | 2 +- homeassistant/components/remote/apple_tv.py | 5 +++++ requirements_all.txt | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/apple_tv.py b/homeassistant/components/apple_tv.py index 948caa27538cc..c5f40ca5db87f 100644 --- a/homeassistant/components/apple_tv.py +++ b/homeassistant/components/apple_tv.py @@ -17,7 +17,7 @@ from homeassistant.components.discovery import SERVICE_APPLE_TV import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['pyatv==0.3.2'] +REQUIREMENTS = ['pyatv==0.3.4'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/remote/apple_tv.py b/homeassistant/components/remote/apple_tv.py index a7ea113c2db15..e89234c60ac90 100644 --- a/homeassistant/components/remote/apple_tv.py +++ b/homeassistant/components/remote/apple_tv.py @@ -44,6 +44,11 @@ def name(self): """Return the name of the device.""" return self._name + @property + def unique_id(self): + """Return an unique ID.""" + return self._atv.metadata.device_id + @property def is_on(self): """Return true if device is on.""" diff --git a/requirements_all.txt b/requirements_all.txt index 5cb1e676b27ea..0eccc3c0aa257 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -519,7 +519,7 @@ pyasn1-modules==0.0.9 pyasn1==0.2.3 # homeassistant.components.apple_tv -pyatv==0.3.2 +pyatv==0.3.4 # homeassistant.components.device_tracker.bbox # homeassistant.components.sensor.bbox From 5e1ff20b09cd38ba7fa47b39d3ac9f2440628591 Mon Sep 17 00:00:00 2001 From: Thibault Cohen Date: Tue, 18 Jul 2017 18:02:42 -0400 Subject: [PATCH 033/118] Decora: Fix set brightness and improve reconnection (#8522) --- homeassistant/components/light/decora.py | 10 +++++++--- requirements_all.txt | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/light/decora.py b/homeassistant/components/light/decora.py index bc45870f5f268..17cc741c59317 100644 --- a/homeassistant/components/light/decora.py +++ b/homeassistant/components/light/decora.py @@ -16,7 +16,7 @@ PLATFORM_SCHEMA) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['decora==0.6'] +REQUIREMENTS = ['decora==0.6', 'bluepy==1.1.1'] _LOGGER = logging.getLogger(__name__) @@ -39,6 +39,7 @@ def wrapper_retry(device, *args, **kwds): """Try send command and retry on error.""" # pylint: disable=import-error import decora + import bluepy initial = time.monotonic() while True: @@ -46,7 +47,10 @@ def wrapper_retry(device, *args, **kwds): return None try: return method(device, *args, **kwds) - except (decora.decoraException, AttributeError): + except (decora.decoraException, AttributeError, + bluepy.btle.BTLEException): + _LOGGER.warning("Decora connect error for device %s. " + "Reconnecting...", device.name) # pylint: disable=protected-access device._switch.connect() return wrapper_retry @@ -119,7 +123,7 @@ def assumed_state(self): @retry def set_state(self, brightness): """Set the state of this lamp to the provided brightness.""" - self._switch.set_brightness(brightness / 2.55) + self._switch.set_brightness(int(brightness / 2.55)) self._brightness = brightness @retry diff --git a/requirements_all.txt b/requirements_all.txt index 0eccc3c0aa257..c11959387b16f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -106,6 +106,9 @@ blinkstick==1.1.8 # homeassistant.components.sensor.bitcoin blockchain==1.3.3 +# homeassistant.components.light.decora +# bluepy==1.1.1 + # homeassistant.components.notify.aws_lambda # homeassistant.components.notify.aws_sns # homeassistant.components.notify.aws_sqs From d54a634f112f347262ef342e2d3e21c5f6eb4b8e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 18 Jul 2017 15:11:17 -0700 Subject: [PATCH 034/118] Update demo.py --- 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 27bb1bbb8d125..187e899aacdcd 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -107,7 +107,7 @@ def async_setup(hass, config): # Set up example persistent notification persistent_notification.async_create( - hass, 'This is an example of a persistent notification.', + 'This is an example of a persistent notification.', title='Example Notification') # Set up room groups From 1a86fa5a02e950d36f8e5c8474f47ccd53816926 Mon Sep 17 00:00:00 2001 From: Kevin Fronczak Date: Tue, 18 Jul 2017 18:16:32 -0400 Subject: [PATCH 035/118] Initial support for Google Wifi/OnHub (#8485) * Initial support for Google Wifi/OnHub * Moved state logic to update function of API class - Throttle added to update - State logic implementation is cleaner - Modified tests to work with the new throttle on update --- .../components/sensor/google_wifi.py | 201 +++++++++++++++++ tests/components/sensor/test_google_wifi.py | 203 ++++++++++++++++++ 2 files changed, 404 insertions(+) create mode 100644 homeassistant/components/sensor/google_wifi.py create mode 100644 tests/components/sensor/test_google_wifi.py diff --git a/homeassistant/components/sensor/google_wifi.py b/homeassistant/components/sensor/google_wifi.py new file mode 100644 index 0000000000000..d878f4f8d20b3 --- /dev/null +++ b/homeassistant/components/sensor/google_wifi.py @@ -0,0 +1,201 @@ +""" +Support for retreiving status info from Google Wifi/OnHub routers. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.google_wifi/ +""" +import logging +from datetime import timedelta + +import voluptuous as vol +import requests + +import homeassistant.util.dt as dt +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.util import Throttle +from homeassistant.const import ( + CONF_NAME, CONF_HOST, CONF_MONITORED_CONDITIONS, + STATE_UNKNOWN) + +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=1) + +_LOGGER = logging.getLogger(__name__) + +ENDPOINT = '/api/v1/status' + +ATTR_CURRENT_VERSION = 'current_version' +ATTR_NEW_VERSION = 'new_version' +ATTR_UPTIME = 'uptime' +ATTR_LAST_RESTART = 'last_restart' +ATTR_LOCAL_IP = 'local_ip' +ATTR_STATUS = 'status' + +DEFAULT_NAME = 'google_wifi' +DEFAULT_HOST = 'testwifi.here' + +MONITORED_CONDITIONS = { + ATTR_CURRENT_VERSION: [ + 'Current Version', + None, + 'mdi:checkbox-marked-circle-outline' + ], + ATTR_NEW_VERSION: [ + 'New Version', + None, + 'mdi:update' + ], + ATTR_UPTIME: [ + 'Uptime', + 'days', + 'mdi:timelapse' + ], + ATTR_LAST_RESTART: [ + 'Last Network Restart', + None, + 'mdi:restart' + ], + ATTR_LOCAL_IP: [ + 'Local IP Address', + None, + 'mdi:access-point-network' + ], + ATTR_STATUS: [ + 'Status', + None, + 'mdi:google' + ] +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Optional(CONF_MONITORED_CONDITIONS, default=MONITORED_CONDITIONS): + vol.All(cv.ensure_list, [vol.In(MONITORED_CONDITIONS)]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the Google Wifi sensor.""" + name = config.get(CONF_NAME) + host = config.get(CONF_HOST) + + api = GoogleWifiAPI(host) + + sensors = [GoogleWifiSensor(hass, api, name, condition) + for condition in config[CONF_MONITORED_CONDITIONS]] + + add_devices(sensors, True) + + +class GoogleWifiSensor(Entity): + """Representation of a Google Wifi sensor.""" + + def __init__(self, hass, api, name, variable): + """Initialize a Pi-Hole sensor.""" + self._hass = hass + self._api = api + self._name = name + self._state = STATE_UNKNOWN + + variable_info = MONITORED_CONDITIONS[variable] + self._var_name = variable + self._var_units = variable_info[1] + self._var_icon = variable_info[2] + + @property + def name(self): + """Return the name of the sensor.""" + return "{}_{}".format(self._name, self._var_name) + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return self._var_icon + + @property + def unit_of_measurement(self): + """Return the unit the value is expressed in.""" + return self._var_units + + @property + def availiable(self): + """Return availiability of goole wifi api.""" + return self._api.availiable + + @property + def state(self): + """Return the state of the device.""" + return self._state + + def update(self): + """Get the latest data from the Google Wifi API.""" + self._api.update() + if self.availiable: + self._state = self._api.data[self._var_name] + else: + self._state = STATE_UNKNOWN + + +class GoogleWifiAPI(object): + """Get the latest data and update the states.""" + + def __init__(self, host): + """Initialize the data object.""" + uri = 'http://' + resource = "{}{}{}".format(uri, host, ENDPOINT) + + self._request = requests.Request('GET', resource).prepare() + self.raw_data = None + self.data = { + ATTR_CURRENT_VERSION: STATE_UNKNOWN, + ATTR_NEW_VERSION: STATE_UNKNOWN, + ATTR_UPTIME: STATE_UNKNOWN, + ATTR_LAST_RESTART: STATE_UNKNOWN, + ATTR_LOCAL_IP: STATE_UNKNOWN, + ATTR_STATUS: STATE_UNKNOWN + } + self.availiable = True + self.update() + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Get the latest data from the router.""" + try: + _LOGGER.error("Before request") + with requests.Session() as sess: + response = sess.send( + self._request, timeout=10) + self.raw_data = response.json() + _LOGGER.error(self.raw_data) + self.data_format() + self.availiable = True + except ValueError: + _LOGGER.error("Unable to fetch data from Google Wifi") + self.availiable = False + self.raw_data = None + + def data_format(self): + """Format raw data into easily accessible dict.""" + for key, value in self.raw_data.items(): + if key == 'software': + self.data[ATTR_CURRENT_VERSION] = value['softwareVersion'] + if value['updateNewVersion'] == '0.0.0.0': + self.data[ATTR_NEW_VERSION] = 'Latest' + else: + self.data[ATTR_NEW_VERSION] = value['updateNewVersion'] + elif key == 'system': + self.data[ATTR_UPTIME] = value['uptime'] / (3600 * 24) + last_restart = dt.now() - timedelta(seconds=value['uptime']) + self.data[ATTR_LAST_RESTART] = \ + last_restart.strftime("%Y-%m-%d %H:%M:%S") + elif key == 'wan': + if value['online']: + self.data[ATTR_STATUS] = 'Online' + else: + self.data[ATTR_STATUS] = 'Offline' + if not value['ipAddress']: + self.data[ATTR_LOCAL_IP] = STATE_UNKNOWN + else: + self.data[ATTR_LOCAL_IP] = value['localIpAddress'] diff --git a/tests/components/sensor/test_google_wifi.py b/tests/components/sensor/test_google_wifi.py new file mode 100644 index 0000000000000..978ec99236c22 --- /dev/null +++ b/tests/components/sensor/test_google_wifi.py @@ -0,0 +1,203 @@ +"""The tests for the Google Wifi platform.""" +import unittest +from unittest.mock import patch, Mock +from datetime import datetime, timedelta +import requests_mock + +from homeassistant import core as ha +from homeassistant.setup import setup_component +import homeassistant.components.sensor.google_wifi as google_wifi +from homeassistant.const import STATE_UNKNOWN +from homeassistant.util import dt as dt_util + +from tests.common import get_test_home_assistant, assert_setup_component + +NAME = 'foo' + +MOCK_DATA = ('{"software": {"softwareVersion":"initial",' + '"updateNewVersion":"initial"},' + '"system": {"uptime":86400},' + '"wan": {"localIpAddress":"initial", "online":true,' + '"ipAddress":true}}') + +MOCK_DATA_NEXT = ('{"software": {"softwareVersion":"next",' + '"updateNewVersion":"0.0.0.0"},' + '"system": {"uptime":172800},' + '"wan": {"localIpAddress":"next", "online":false,' + '"ipAddress":false}}') + + +class TestGoogleWifiSetup(unittest.TestCase): + """Tests for setting up the Google Wifi switch platform.""" + + def setUp(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + + @requests_mock.Mocker() + def test_setup_minimum(self, mock_req): + """Test setup with minimum configuration.""" + resource = '{}{}{}'.format('http://', + google_wifi.DEFAULT_HOST, + google_wifi.ENDPOINT) + mock_req.get(resource, status_code=200) + self.assertTrue(setup_component(self.hass, 'sensor', { + 'sensor': { + 'platform': 'google_wifi' + } + })) + + @requests_mock.Mocker() + def test_setup_get(self, mock_req): + """Test setup with full configuration.""" + resource = '{}{}{}'.format('http://', + 'localhost', + google_wifi.ENDPOINT) + mock_req.get(resource, status_code=200) + self.assertTrue(setup_component(self.hass, 'sensor', { + 'sensor': { + 'platform': 'google_wifi', + 'host': 'localhost', + 'name': 'Test Wifi', + 'monitored_conditions': ['current_version', + 'new_version', + 'uptime', + 'last_restart', + 'local_ip', + 'status'] + } + })) + assert_setup_component(6, 'sensor') + + +class TestGoogleWifiSensor(unittest.TestCase): + """Tests for Google Wifi sensor platform.""" + + def setUp(self): + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + with requests_mock.Mocker() as mock_req: + self.setup_api(MOCK_DATA, mock_req) + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + + def setup_api(self, data, mock_req): + """Setup API with fake data.""" + resource = '{}{}{}'.format('http://', + 'localhost', + google_wifi.ENDPOINT) + now = datetime(1970, month=1, day=1) + with patch('homeassistant.util.dt.now', return_value=now): + mock_req.get(resource, text=data, status_code=200) + self.api = google_wifi.GoogleWifiAPI("localhost") + self.name = NAME + self.sensor_dict = dict() + for condition, cond_list in google_wifi.MONITORED_CONDITIONS.items(): + sensor = google_wifi.GoogleWifiSensor(self.hass, self.api, + self.name, condition) + name = '{}_{}'.format(self.name, condition) + units = cond_list[1] + icon = cond_list[2] + self.sensor_dict[condition] = {'sensor': sensor, + 'name': name, + 'units': units, + 'icon': icon} + + def fake_delay(self, ha_delay): + """Fake delay to prevent update throttle.""" + hass_now = dt_util.utcnow() + shifted_time = hass_now + timedelta(seconds=ha_delay) + self.hass.bus.fire(ha.EVENT_TIME_CHANGED, + {ha.ATTR_NOW: shifted_time}) + + def test_name(self): + """Test the name.""" + for name in self.sensor_dict: + sensor = self.sensor_dict[name]['sensor'] + test_name = self.sensor_dict[name]['name'] + self.assertEqual(test_name, sensor.name) + + def test_unit_of_measurement(self): + """Test the unit of measurement.""" + for name in self.sensor_dict: + sensor = self.sensor_dict[name]['sensor'] + self.assertEqual(self.sensor_dict[name]['units'], + sensor.unit_of_measurement) + + def test_icon(self): + """Test the icon.""" + for name in self.sensor_dict: + sensor = self.sensor_dict[name]['sensor'] + self.assertEqual(self.sensor_dict[name]['icon'], sensor.icon) + + @requests_mock.Mocker() + def test_state(self, mock_req): + """Test the initial state.""" + self.setup_api(MOCK_DATA, mock_req) + now = datetime(1970, month=1, day=1) + with patch('homeassistant.util.dt.now', return_value=now): + for name in self.sensor_dict: + sensor = self.sensor_dict[name]['sensor'] + self.fake_delay(2) + sensor.update() + if name == google_wifi.ATTR_LAST_RESTART: + self.assertEqual('1969-12-31 00:00:00', sensor.state) + elif name == google_wifi.ATTR_UPTIME: + self.assertEqual(1, sensor.state) + elif name == google_wifi.ATTR_STATUS: + self.assertEqual('Online', sensor.state) + else: + self.assertEqual('initial', sensor.state) + + @requests_mock.Mocker() + def test_update_when_value_is_none(self, mock_req): + """Test state gets updated to unknown when sensor returns no data.""" + self.setup_api(None, mock_req) + for name in self.sensor_dict: + sensor = self.sensor_dict[name]['sensor'] + self.fake_delay(2) + sensor.update() + self.assertEqual(STATE_UNKNOWN, sensor.state) + + @requests_mock.Mocker() + def test_update_when_value_changed(self, mock_req): + """Test state gets updated when sensor returns a new status.""" + self.setup_api(MOCK_DATA_NEXT, mock_req) + now = datetime(1970, month=1, day=1) + with patch('homeassistant.util.dt.now', return_value=now): + for name in self.sensor_dict: + sensor = self.sensor_dict[name]['sensor'] + self.fake_delay(2) + sensor.update() + if name == google_wifi.ATTR_LAST_RESTART: + self.assertEqual('1969-12-30 00:00:00', sensor.state) + elif name == google_wifi.ATTR_UPTIME: + self.assertEqual(2, sensor.state) + elif name == google_wifi.ATTR_STATUS: + self.assertEqual('Offline', sensor.state) + elif name == google_wifi.ATTR_NEW_VERSION: + self.assertEqual('Latest', sensor.state) + elif name == google_wifi.ATTR_LOCAL_IP: + self.assertEqual(STATE_UNKNOWN, sensor.state) + else: + self.assertEqual('next', sensor.state) + + def test_update_when_unavailiable(self): + """Test state updates when Google Wifi unavailiable.""" + self.api.update = Mock('google_wifi.GoogleWifiAPI.update', + side_effect=self.update_side_effect()) + for name in self.sensor_dict: + sensor = self.sensor_dict[name]['sensor'] + sensor.update() + self.assertEqual(STATE_UNKNOWN, sensor.state) + + def update_side_effect(self): + """Mock representation of update function.""" + self.api.data = None + self.api.availiable = False From 4ece4bf241629189eb911a390208b7e24af5110b Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Wed, 19 Jul 2017 03:04:01 -0400 Subject: [PATCH 036/118] Fix exception dlib_face_identify when image is not recognized by face_recognition module (#8552) * Some images are not supported by face_recognition, so this patch treats the error messages instead throwing a traceback. Fixes #7867 * Makes lint happy --- .../components/image_processing/dlib_face_identify.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/image_processing/dlib_face_identify.py b/homeassistant/components/image_processing/dlib_face_identify.py index 8df6de91da4e6..ec98d5bdcff84 100644 --- a/homeassistant/components/image_processing/dlib_face_identify.py +++ b/homeassistant/components/image_processing/dlib_face_identify.py @@ -58,8 +58,12 @@ def __init__(self, camera_entity, faces, name=None): self._faces = {} for face_name, face_file in faces.items(): - image = face_recognition.load_image_file(face_file) - self._faces[face_name] = face_recognition.face_encodings(image)[0] + try: + image = face_recognition.load_image_file(face_file) + self._faces[face_name] = \ + face_recognition.face_encodings(image)[0] + except IndexError as err: + _LOGGER.error("Failed to parse %s. Error: %s", face_file, err) @property def camera_entity(self): From 6bc07298d3131c9aa10c9513b04a9020eaa14eb1 Mon Sep 17 00:00:00 2001 From: Aliaksandr Date: Wed, 19 Jul 2017 10:14:48 +0300 Subject: [PATCH 037/118] [media_extractor] Add support for custom stream queries for media_extractor (#8538) * Add support for different stream formats * Encapsulate logic inside MediaExtractor class * Add CONFIG_SCHEMA * Fix for cases when youtube-dl returns content of playlist as list --- homeassistant/components/media_extractor.py | 198 ++++++++++++++------ 1 file changed, 143 insertions(+), 55 deletions(-) diff --git a/homeassistant/components/media_extractor.py b/homeassistant/components/media_extractor.py index c7d019973a34f..559af46e9f681 100644 --- a/homeassistant/components/media_extractor.py +++ b/homeassistant/components/media_extractor.py @@ -6,11 +6,14 @@ """ import logging import os +import voluptuous as vol from homeassistant.components.media_player import ( - ATTR_MEDIA_CONTENT_ID, DOMAIN as MEDIA_PLAYER_DOMAIN, - MEDIA_PLAYER_PLAY_MEDIA_SCHEMA, SERVICE_PLAY_MEDIA) + ATTR_ENTITY_ID, ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_CONTENT_TYPE, + DOMAIN as MEDIA_PLAYER_DOMAIN, MEDIA_PLAYER_PLAY_MEDIA_SCHEMA, + SERVICE_PLAY_MEDIA) from homeassistant.config import load_yaml_config_file +from homeassistant.helpers import config_validation as cv REQUIREMENTS = ['youtube_dl==2017.7.9'] @@ -19,6 +22,18 @@ DOMAIN = 'media_extractor' DEPENDENCIES = ['media_player'] +CONF_CUSTOMIZE_ENTITIES = 'customize' +CONF_DEFAULT_STREAM_QUERY = 'default_query' +DEFAULT_STREAM_QUERY = 'best' + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Optional(CONF_DEFAULT_STREAM_QUERY): cv.string, + vol.Optional(CONF_CUSTOMIZE_ENTITIES): + vol.Schema({cv.entity_id: vol.Schema({cv.string: cv.string})}), + }), +}, extra=vol.ALLOW_EXTRA) + def setup(hass, config): """Set up the media extractor service.""" @@ -28,23 +43,7 @@ def setup(hass, config): def play_media(call): """Get stream URL and send it to the media_player.play_media.""" - media_url = call.data.get(ATTR_MEDIA_CONTENT_ID) - - try: - stream_url = get_media_stream_url(media_url) - except YDException: - _LOGGER.error("Could not retrieve data for the URL: %s", - media_url) - return - else: - data = {k: v for k, v in call.data.items() - if k != ATTR_MEDIA_CONTENT_ID} - data[ATTR_MEDIA_CONTENT_ID] = stream_url - - hass.async_add_job( - hass.services.async_call( - MEDIA_PLAYER_DOMAIN, SERVICE_PLAY_MEDIA, data) - ) + MediaExtractor(hass, config[DOMAIN], call.data).extract_and_send() hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, @@ -55,47 +54,136 @@ def play_media(call): return True -class YDException(Exception): - """General service exception.""" +class MEDownloadException(Exception): + """Media extractor download exception.""" + + pass + + +class MEQueryException(Exception): + """Media extractor query exception.""" pass -def get_media_stream_url(media_url): - """Extract stream URL from the media URL.""" - from youtube_dl import YoutubeDL - from youtube_dl.utils import DownloadError, ExtractorError +class MediaExtractor: + """Class which encapsulates all extraction logic.""" + + def __init__(self, hass, component_config, call_data): + """Initialize media extractor.""" + self.hass = hass + self.config = component_config + self.call_data = call_data + + def get_media_url(self): + """Return media content url.""" + return self.call_data.get(ATTR_MEDIA_CONTENT_ID) + + def get_entities(self): + """Return list of entities.""" + return self.call_data.get(ATTR_ENTITY_ID, []) + + def extract_and_send(self): + """Extract exact stream format for each entity_id and play it.""" + try: + stream_selector = self.get_stream_selector() + except MEDownloadException: + _LOGGER.error("Could not retrieve data for the URL: %s", + self.get_media_url()) + else: + entities = self.get_entities() + + if len(entities) == 0: + self.call_media_player_service(stream_selector, None) + + for entity_id in entities: + self.call_media_player_service(stream_selector, entity_id) + + def get_stream_selector(self): + """Return format selector for the media URL.""" + from youtube_dl import YoutubeDL + from youtube_dl.utils import DownloadError, ExtractorError - ydl = YoutubeDL({'quiet': True, 'logger': _LOGGER}) + ydl = YoutubeDL({'quiet': True, 'logger': _LOGGER}) - try: - all_media_streams = ydl.extract_info(media_url, process=False) - except DownloadError: - # This exception will be logged by youtube-dl itself - raise YDException() + try: + all_media = ydl.extract_info(self.get_media_url(), + process=False) + except DownloadError: + # This exception will be logged by youtube-dl itself + raise MEDownloadException() + + if 'entries' in all_media: + _LOGGER.warning("Playlists are not supported, " + "looking for the first video") + entries = list(all_media['entries']) + if len(entries) > 0: + selected_media = entries[0] + else: + _LOGGER.error("Playlist is empty") + raise MEDownloadException() + else: + selected_media = all_media - if 'entries' in all_media_streams: - _LOGGER.warning("Playlists are not supported, " - "looking for the first video") try: - selected_stream = next(all_media_streams['entries']) - except StopIteration: - _LOGGER.error("Playlist is empty") - raise YDException() - else: - selected_stream = all_media_streams - - try: - media_info = ydl.process_ie_result(selected_stream, download=False) - except (ExtractorError, DownloadError): - # This exception will be logged by youtube-dl itself - raise YDException() - - format_selector = ydl.build_format_selector('best') - - try: - best_quality_stream = next(format_selector(media_info)) - except (KeyError, StopIteration): - best_quality_stream = media_info - - return best_quality_stream['url'] + media_info = ydl.process_ie_result(selected_media, + download=False) + except (ExtractorError, DownloadError): + # This exception will be logged by youtube-dl itself + raise MEDownloadException() + + def stream_selector(query): + """Find stream url that matches query.""" + try: + format_selector = ydl.build_format_selector(query) + except (SyntaxError, ValueError, AttributeError) as ex: + _LOGGER.error(ex) + raise MEQueryException() + + try: + requested_stream = next(format_selector(media_info)) + except (KeyError, StopIteration): + _LOGGER.error("Could not extract stream for the query: %s", + query) + raise MEQueryException() + + return requested_stream['url'] + + return stream_selector + + def call_media_player_service(self, stream_selector, entity_id): + """Call media_player.play_media service.""" + stream_query = self.get_stream_query_for_entity(entity_id) + + try: + stream_url = stream_selector(stream_query) + except MEQueryException: + _LOGGER.error("Wrong query format: %s", stream_query) + return + else: + data = {k: v for k, v in self.call_data.items() + if k != ATTR_ENTITY_ID} + data[ATTR_MEDIA_CONTENT_ID] = stream_url + + if entity_id: + data[ATTR_ENTITY_ID] = entity_id + + self.hass.async_add_job( + self.hass.services.async_call( + MEDIA_PLAYER_DOMAIN, SERVICE_PLAY_MEDIA, data) + ) + + def get_stream_query_for_entity(self, entity_id): + """Get stream format query for entity.""" + default_stream_query = self.config.get(CONF_DEFAULT_STREAM_QUERY, + DEFAULT_STREAM_QUERY) + + if entity_id: + media_content_type = self.call_data.get(ATTR_MEDIA_CONTENT_TYPE) + + return self.config \ + .get(CONF_CUSTOMIZE_ENTITIES, {}) \ + .get(entity_id, {}) \ + .get(media_content_type, default_stream_query) + + return default_stream_query From 42699b7a60779ba9d56b4b8a600595b6c759fea7 Mon Sep 17 00:00:00 2001 From: Jeff Wilson Date: Wed, 19 Jul 2017 06:20:45 -0400 Subject: [PATCH 038/118] Report Harmony remote off if state is unknown (#8547) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/remote/harmony.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/remote/harmony.py b/homeassistant/components/remote/harmony.py index 165bd0b911480..cdc6a7ac61f37 100755 --- a/homeassistant/components/remote/harmony.py +++ b/homeassistant/components/remote/harmony.py @@ -174,7 +174,7 @@ def device_state_attributes(self): @property def is_on(self): """Return False if PowerOff is the current activity, otherwise True.""" - return self._current_activity != 'PowerOff' + return self._current_activity not in [None, 'PowerOff'] def update(self): """Return current activity.""" From c8bfcd2ed4c94e863332eb308ad63d406017eb19 Mon Sep 17 00:00:00 2001 From: viswa-swami Date: Wed, 19 Jul 2017 06:21:39 -0400 Subject: [PATCH 039/118] Upgrade the alarmdecoder dependency library from 0.12.1 to 0.12.3. (#8542) * Upgrade the alarmdecoder dependency library from 0.12.1 to 0.12.3. Nutech software who owns this library have upgraded this library with some fixes regarding arming it to home/away and then disarming the alarm. Without this upgraded library, HASS is having a problem when we try to disarm an armed alarm after around 8 hours or so. * Updated the requirements_all.txt by running the script gen_requirements_all.py --- homeassistant/components/alarmdecoder.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/alarmdecoder.py b/homeassistant/components/alarmdecoder.py index d4948429b811a..011cc3ad21d61 100644 --- a/homeassistant/components/alarmdecoder.py +++ b/homeassistant/components/alarmdecoder.py @@ -15,7 +15,7 @@ from homeassistant.helpers.discovery import async_load_platform from homeassistant.helpers.dispatcher import async_dispatcher_send -REQUIREMENTS = ['alarmdecoder==0.12.1.0'] +REQUIREMENTS = ['alarmdecoder==0.12.3'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index c11959387b16f..a6e559377e9b1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -58,7 +58,7 @@ aiolifx_effects==0.1.1 aiopvapi==1.4 # homeassistant.components.alarmdecoder -alarmdecoder==0.12.1.0 +alarmdecoder==0.12.3 # homeassistant.components.amcrest amcrest==1.2.0 From c27074e6f7b1a4eab75e15c055b29b4d4f1125a0 Mon Sep 17 00:00:00 2001 From: Eugenio Panadero Date: Wed, 19 Jul 2017 19:33:16 +0200 Subject: [PATCH 040/118] turn_on_action and turn_off_action with script syntax (#8558) --- homeassistant/components/media_player/kodi.py | 94 +++++++++++++++---- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index f484c04a05841..3764677c84732 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -5,6 +5,7 @@ https://home-assistant.io/components/media_player.kodi/ """ import asyncio +from collections import OrderedDict from functools import wraps import logging import urllib @@ -20,15 +21,18 @@ SUPPORT_PLAY_MEDIA, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_STOP, SUPPORT_TURN_OFF, SUPPORT_PLAY, SUPPORT_VOLUME_STEP, SUPPORT_SHUFFLE_SET, MediaPlayerDevice, PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, - MEDIA_TYPE_VIDEO, MEDIA_TYPE_PLAYLIST, MEDIA_PLAYER_SCHEMA, DOMAIN) + MEDIA_TYPE_VIDEO, MEDIA_TYPE_PLAYLIST, MEDIA_PLAYER_SCHEMA, DOMAIN, + SUPPORT_TURN_ON) from homeassistant.const import ( STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING, CONF_HOST, CONF_NAME, CONF_PORT, CONF_SSL, CONF_PROXY_SSL, CONF_USERNAME, CONF_PASSWORD, CONF_TIMEOUT, EVENT_HOMEASSISTANT_STOP) from homeassistant.core import callback from homeassistant.helpers.aiohttp_client import async_get_clientsession -import homeassistant.helpers.config_validation as cv +from homeassistant.helpers import script, config_validation as cv from homeassistant.helpers.deprecation import get_deprecated +from homeassistant.helpers.template import Template +from homeassistant.util.yaml import dump REQUIREMENTS = ['jsonrpc-async==0.6', 'jsonrpc-websocket==0.5'] @@ -37,6 +41,7 @@ EVENT_KODI_CALL_METHOD_RESULT = 'kodi_call_method_result' CONF_TCP_PORT = 'tcp_port' +CONF_TURN_ON_ACTION = 'turn_on_action' CONF_TURN_OFF_ACTION = 'turn_off_action' CONF_ENABLE_WEBSOCKET = 'enable_websocket' @@ -47,7 +52,14 @@ DEFAULT_PROXY_SSL = False DEFAULT_ENABLE_WEBSOCKET = True -TURN_OFF_ACTION = [None, 'quit', 'hibernate', 'suspend', 'reboot', 'shutdown'] +DEPRECATED_TURN_OFF_ACTIONS = { + None: None, + 'quit': 'Application.Quit', + 'hibernate': 'System.Hibernate', + 'suspend': 'System.Suspend', + 'reboot': 'System.Reboot', + 'shutdown': 'System.Shutdown' +} # https://github.com/xbmc/xbmc/blob/master/xbmc/media/MediaType.h MEDIA_TYPES = { @@ -75,7 +87,9 @@ vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_TCP_PORT, default=DEFAULT_TCP_PORT): cv.port, vol.Optional(CONF_PROXY_SSL, default=DEFAULT_PROXY_SSL): cv.boolean, - vol.Optional(CONF_TURN_OFF_ACTION, default=None): vol.In(TURN_OFF_ACTION), + vol.Optional(CONF_TURN_ON_ACTION, default=None): cv.SCRIPT_SCHEMA, + vol.Optional(CONF_TURN_OFF_ACTION): + vol.Any(cv.SCRIPT_SCHEMA, vol.In(DEPRECATED_TURN_OFF_ACTIONS)), vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int, vol.Inclusive(CONF_USERNAME, 'auth'): cv.string, vol.Inclusive(CONF_PASSWORD, 'auth'): cv.string, @@ -114,11 +128,36 @@ } +def _check_deprecated_turn_off(hass, turn_off_action): + """Create an equivalent script for old turn off actions.""" + if isinstance(turn_off_action, str): + method = DEPRECATED_TURN_OFF_ACTIONS[turn_off_action] + new_config = OrderedDict( + [('service', '{}.{}'.format(DOMAIN, SERVICE_CALL_METHOD)), + ('data_template', OrderedDict( + [('entity_id', '{{ entity_id }}'), + ('method', method)]))]) + example_conf = dump(OrderedDict( + [(CONF_TURN_OFF_ACTION, new_config)])) + _LOGGER.warning( + "The '%s' action for turn off Kodi is deprecated and " + "will cease to function in a future release. You need to " + "change it for a generic Home Assistant script sequence, " + "which is, for this turn_off action, like this:\n%s", + turn_off_action, example_conf) + new_config['data_template'] = OrderedDict( + [(key, Template(value, hass)) + for key, value in new_config['data_template'].items()]) + turn_off_action = [new_config] + return turn_off_action + + @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the Kodi platform.""" if DATA_KODI not in hass.data: hass.data[DATA_KODI] = [] + name = config.get(CONF_NAME) host = config.get(CONF_HOST) port = config.get(CONF_PORT) tcp_port = config.get(CONF_TCP_PORT) @@ -134,10 +173,11 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): entity = KodiDevice( hass, - name=config.get(CONF_NAME), + name=name, host=host, port=port, tcp_port=tcp_port, encryption=encryption, username=config.get(CONF_USERNAME), password=config.get(CONF_PASSWORD), + turn_on_action=config.get(CONF_TURN_ON_ACTION), turn_off_action=config.get(CONF_TURN_OFF_ACTION), timeout=config.get(CONF_TIMEOUT), websocket=websocket) @@ -210,7 +250,8 @@ class KodiDevice(MediaPlayerDevice): """Representation of a XBMC/Kodi device.""" def __init__(self, hass, name, host, port, tcp_port, encryption=False, - username=None, password=None, turn_off_action=None, + username=None, password=None, + turn_on_action=None, turn_off_action=None, timeout=DEFAULT_TIMEOUT, websocket=True): """Initialize the Kodi device.""" import jsonrpc_async @@ -262,6 +303,17 @@ def on_hass_stop(event): else: self._ws_server = None + # Script creation for the turn on/off config options + if turn_on_action is not None: + turn_on_action = script.Script( + self.hass, turn_on_action, + "{} turn ON script".format(self.name), + self.async_update_ha_state(True)) + if turn_off_action is not None: + turn_off_action = script.Script( + self.hass, _check_deprecated_turn_off(hass, turn_off_action), + "{} turn OFF script".format(self.name)) + self._turn_on_action = turn_on_action self._turn_off_action = turn_off_action self._enable_websocket = websocket self._players = list() @@ -304,7 +356,7 @@ def async_on_volume_changed(self, sender, data): @callback def async_on_quit(self, sender, data): - """Handle the muted volume.""" + """Reset the player state on quit action.""" self._players = None self._properties = {} self._item = {} @@ -520,25 +572,31 @@ def supported_features(self): """Flag media player features that are supported.""" supported_features = SUPPORT_KODI - if self._turn_off_action in TURN_OFF_ACTION: + if self._turn_on_action is not None: + supported_features |= SUPPORT_TURN_ON + + if self._turn_off_action is not None: supported_features |= SUPPORT_TURN_OFF return supported_features + @cmd + @asyncio.coroutine + def async_turn_on(self): + """Execute turn_on_action to turn on media player.""" + if self._turn_on_action is not None: + yield from self._turn_on_action.async_run( + variables={"entity_id": self.entity_id}) + else: + _LOGGER.warning("turn_on requested but turn_on_action is none") + @cmd @asyncio.coroutine def async_turn_off(self): """Execute turn_off_action to turn off media player.""" - if self._turn_off_action == 'quit': - yield from self.server.Application.Quit() - elif self._turn_off_action == 'hibernate': - yield from self.server.System.Hibernate() - elif self._turn_off_action == 'suspend': - yield from self.server.System.Suspend() - elif self._turn_off_action == 'reboot': - yield from self.server.System.Reboot() - elif self._turn_off_action == 'shutdown': - yield from self.server.System.Shutdown() + if self._turn_off_action is not None: + yield from self._turn_off_action.async_run( + variables={"entity_id": self.entity_id}) else: _LOGGER.warning("turn_off requested but turn_off_action is none") From f1280d3edb35b12fcfcfee433cc4149e45c1068c Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Wed, 19 Jul 2017 13:45:53 -0400 Subject: [PATCH 041/118] Extends Pi-hole sensor to support the new sensors: (#8549) - domains_being_blocked - queries_cached - queries_forwarded - unique_clients - unique_domains --- homeassistant/components/sensor/pi_hole.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/pi_hole.py b/homeassistant/components/sensor/pi_hole.py index f788fc8fd173d..13421aca61d3f 100644 --- a/homeassistant/components/sensor/pi_hole.py +++ b/homeassistant/components/sensor/pi_hole.py @@ -36,11 +36,21 @@ MONITORED_CONDITIONS = { 'dns_queries_today': ['DNS Queries Today', - None, 'mdi:network-question'], + None, 'mdi:comment-question-outline'], 'ads_blocked_today': ['Ads Blocked Today', None, 'mdi:close-octagon-outline'], 'ads_percentage_today': ['Ads Percentage Blocked Today', '%', 'mdi:close-octagon-outline'], + 'domains_being_blocked': ['Domains Blocked', + None, 'mdi:block-helper'], + 'queries_cached': ['DNS Queries Cached', + None, 'mdi:comment-question-outline'], + 'queries_forwarded': ['DNS Queries Forwarded', + None, 'mdi:comment-question-outline'], + 'unique_clients': ['DNS Unique Clients', + None, 'mdi:account-outline'], + 'unique_domains': ['DNS Unique Domains', + None, 'mdi:domain'], } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ From 84ebcd8a592d4661e1bf44619104512c7cd7c15c Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Wed, 19 Jul 2017 18:27:39 -0400 Subject: [PATCH 042/118] Support for Wink Switch and Light groups also fix fan speed selection (#8501) * Support for Switch and Light groups, fix fan speed * Fixed hound violations --- homeassistant/components/fan/wink.py | 14 +++++++++++--- homeassistant/components/light/wink.py | 6 +++++- homeassistant/components/switch/wink.py | 4 ++++ homeassistant/components/wink.py | 5 +++-- requirements_all.txt | 2 +- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/fan/wink.py b/homeassistant/components/fan/wink.py index c649009b23002..3920e606d906c 100644 --- a/homeassistant/components/fan/wink.py +++ b/homeassistant/components/fan/wink.py @@ -9,7 +9,8 @@ from homeassistant.components.fan import (FanEntity, SPEED_HIGH, SPEED_LOW, SPEED_MEDIUM, - STATE_UNKNOWN) + STATE_UNKNOWN, SUPPORT_SET_SPEED, + SUPPORT_DIRECTION) from homeassistant.helpers.entity import ToggleEntity from homeassistant.components.wink import WinkDevice, DOMAIN @@ -20,6 +21,8 @@ SPEED_LOWEST = 'lowest' SPEED_AUTO = 'auto' +SUPPORTED_FEATURES = SUPPORT_DIRECTION + SUPPORT_SET_SPEED + def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Wink platform.""" @@ -44,11 +47,11 @@ def set_direction(self: ToggleEntity, direction: str) -> None: def set_speed(self: ToggleEntity, speed: str) -> None: """Set the speed of the fan.""" - self.wink.set_fan_speed(speed) + self.wink.set_state(True, speed) def turn_on(self: ToggleEntity, speed: str=None, **kwargs) -> None: """Turn on the fan.""" - self.wink.set_state(True) + self.wink.set_state(True, speed) def turn_off(self: ToggleEntity, **kwargs) -> None: """Turn off the fan.""" @@ -96,3 +99,8 @@ def speed_list(self: ToggleEntity) -> list: if SPEED_HIGH in wink_supported_speeds: supported_speeds.append(SPEED_HIGH) return supported_speeds + + @property + def supported_features(self: ToggleEntity) -> int: + """Flag supported features.""" + return SUPPORTED_FEATURES diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py index 93b23a9d7bab3..445fe8ceb25f2 100644 --- a/homeassistant/components/light/wink.py +++ b/homeassistant/components/light/wink.py @@ -28,6 +28,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _id = light.object_id() + light.name() if _id not in hass.data[DOMAIN]['unique_ids']: add_devices([WinkLight(light, hass)]) + for light in pywink.get_light_groups(): + _id = light.object_id() + light.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkLight(light, hass)]) class WinkLight(WinkDevice, Light): @@ -101,7 +105,7 @@ def turn_on(self, **kwargs): xyb = color_util.color_RGB_to_xy(*rgb_color) state_kwargs['color_xy'] = xyb[0], xyb[1] state_kwargs['brightness'] = xyb[2] - elif self.wink.supports_hue_saturation(): + if self.wink.supports_hue_saturation(): hsv = colorsys.rgb_to_hsv( rgb_color[0], rgb_color[1], rgb_color[2]) state_kwargs['color_hue_saturation'] = hsv[0], hsv[1] diff --git a/homeassistant/components/switch/wink.py b/homeassistant/components/switch/wink.py index 0076355665cee..ec9311ac9e901 100644 --- a/homeassistant/components/switch/wink.py +++ b/homeassistant/components/switch/wink.py @@ -32,6 +32,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _id = sprinkler.object_id() + sprinkler.name() if _id not in hass.data[DOMAIN]['unique_ids']: add_devices([WinkToggleDevice(sprinkler, hass)]) + for switch in pywink.get_binary_switch_groups(): + _id = switch.object_id() + switch.name() + if _id not in hass.data[DOMAIN]['unique_ids']: + add_devices([WinkToggleDevice(switch, hass)]) class WinkToggleDevice(WinkDevice, ToggleEntity): diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 1c0410a4aa0f0..7024291e7fe44 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -19,7 +19,7 @@ from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['python-wink==1.2.4', 'pubnubsub-handler==1.0.2'] +REQUIREMENTS = ['python-wink==1.3.1', 'pubnubsub-handler==1.0.2'] _LOGGER = logging.getLogger(__name__) @@ -105,7 +105,8 @@ def _get_wink_token_from_web(): password = config[DOMAIN][CONF_PASSWORD] client_id = config[DOMAIN]['client_id'] client_secret = config[DOMAIN]['client_secret'] - pywink.set_wink_credentials(email, password, client_id, client_secret) + pywink.legacy_set_wink_credentials(email, password, + client_id, client_secret) hass.data[DOMAIN]['oath'] = {"email": email, "password": password, "client_id": client_id, diff --git a/requirements_all.txt b/requirements_all.txt index a6e559377e9b1..aee9aec89fadf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -755,7 +755,7 @@ python-twitch==1.3.0 python-vlc==1.1.2 # homeassistant.components.wink -python-wink==1.2.4 +python-wink==1.3.1 # homeassistant.components.zwave python_openzwave==0.4.0.31 From 54755df9eac7409c191cdafb874235ca4a4d6e16 Mon Sep 17 00:00:00 2001 From: Open Home Automation Date: Thu, 20 Jul 2017 07:01:05 +0200 Subject: [PATCH 043/118] Added a service to write to KNX group addressed including documentation (#8491) * Added a service to write to KNX group addressed including documentation * Define parameters as required * Reformating * Moved service documentation to service.yaml * Moved service documentation to services.yaml * Update knx.py --- homeassistant/components/knx.py | 71 ++++++++++++++------------ homeassistant/components/services.yaml | 13 +++++ 2 files changed, 50 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/knx.py b/homeassistant/components/knx.py index 9772c19ff78ce..9530becb6cea1 100644 --- a/homeassistant/components/knx.py +++ b/homeassistant/components/knx.py @@ -5,6 +5,7 @@ https://home-assistant.io/components/knx/ """ import logging +import os import voluptuous as vol @@ -12,6 +13,7 @@ from homeassistant.const import ( EVENT_HOMEASSISTANT_STOP, CONF_HOST, CONF_PORT) from homeassistant.helpers.entity import Entity +from homeassistant.config import load_yaml_config_file REQUIREMENTS = ['knxip==0.5'] @@ -25,6 +27,9 @@ EVENT_KNX_FRAME_SEND = 'knx_frame_send' KNXTUNNEL = None +KNX_ADDRESS = "address" +KNX_DATA = "data" +KNX_GROUP_WRITE = "group_write" CONF_LISTEN = "listen" CONFIG_SCHEMA = vol.Schema({ @@ -36,6 +41,11 @@ }), }, extra=vol.ALLOW_EXTRA) +KNX_WRITE_SCHEMA = vol.Schema({ + vol.Required(KNX_ADDRESS): vol.All(cv.ensure_list, [cv.string]), + vol.Required(KNX_DATA): vol.All(cv.ensure_list, [cv.byte]) +}) + def setup(hass, config): """Set up the connection to the KNX IP interface.""" @@ -65,6 +75,9 @@ def setup(hass, config): _LOGGER.info("KNX IP tunnel to %s:%i established", host, port) + descriptions = load_yaml_config_file( + os.path.join(os.path.dirname(__file__), 'services.yaml')) + def received_knx_event(address, data): """Process received KNX message.""" if len(data) == 1: @@ -86,47 +99,37 @@ def received_knx_event(address, data): hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, close_tunnel) # Listen to KNX events and send them to the bus - def handle_knx_send(event): + def handle_group_write(call): """Bridge knx_frame_send events to the KNX bus.""" - try: - addr = event.data["address"] - except KeyError: - _LOGGER.error("KNX group address is missing") - return - - try: - data = event.data["data"] - except KeyError: - _LOGGER.error("KNX data block missing") - return - - knxaddr = None - try: - addr = int(addr) - except ValueError: - pass + # parameters are pre-validated using KNX_WRITE_SCHEMA + addrlist = call.data.get("address") + knxdata = call.data.get("data") - if knxaddr is None: - try: - knxaddr = parse_group_address(addr) - except KNXException: - _LOGGER.error("KNX address format incorrect") - return - - knxdata = None - if isinstance(data, list): - knxdata = data - else: + knxaddrlist = [] + for addr in addrlist: try: - knxdata = [int(data) & 0xff] + _LOGGER.debug("Found %s", addr) + knxaddr = int(addr) except ValueError: - _LOGGER.error("KNX data format incorrect") - return + knxaddr = None + + if knxaddr is None: + try: + knxaddr = parse_group_address(addr) + except KNXException: + _LOGGER.error("KNX address format incorrect: %s", addr) + + knxaddrlist.append(knxaddr) - KNXTUNNEL.group_write(knxaddr, knxdata) + for addr in knxaddrlist: + KNXTUNNEL.group_write(addr, knxdata) # Listen for when knx_frame_send event is fired - hass.bus.listen(EVENT_KNX_FRAME_SEND, handle_knx_send) + hass.services.register(DOMAIN, + KNX_GROUP_WRITE, + handle_group_write, + descriptions[DOMAIN][KNX_GROUP_WRITE], + schema=KNX_WRITE_SCHEMA) return True diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index eefcff5bd17f9..880a539927a7a 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -520,3 +520,16 @@ wake_on_lan: broadcast_address: description: Optional broadcast IP where to send the magic packet. example: '192.168.255.255' + +knx: + group_write: + description: Turn a light on + + fields: + address: + description: Group address(es) to write to + example: '1/1/0' + + data: + description: KNX data to send + example: 1 From 9cc3e7e47b3cbfa18783e2842f924624c10ef850 Mon Sep 17 00:00:00 2001 From: Jeff Wilson Date: Thu, 20 Jul 2017 01:51:50 -0400 Subject: [PATCH 044/118] Handle manual edits to emulated_hue_ids.json (#8560) --- homeassistant/components/emulated_hue/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/emulated_hue/__init__.py b/homeassistant/components/emulated_hue/__init__.py index b0b6ec0324f9c..315fc56499974 100644 --- a/homeassistant/components/emulated_hue/__init__.py +++ b/homeassistant/components/emulated_hue/__init__.py @@ -193,7 +193,7 @@ def entity_id_to_number(self, entity_id): if entity_id == ent_id: return number - number = str(len(self.numbers) + 1) + number = str(max(int(k) for k in self.numbers) + 1) self.numbers[number] = entity_id self._save_numbers_json() return number From 8a42e1551a54fd6c1e1e383dd63a050d09e889ef Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Thu, 20 Jul 2017 07:54:46 +0200 Subject: [PATCH 045/118] LIFX: assume default features for unknown products (#8553) This makes the detection work for prototypes as well. --- homeassistant/components/light/lifx.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/lifx.py b/homeassistant/components/light/lifx.py index a32aa0c4a6b6f..a6c5f8558755e 100644 --- a/homeassistant/components/light/lifx.py +++ b/homeassistant/components/light/lifx.py @@ -159,12 +159,18 @@ def cleanup(event): def lifxwhite(device): """Return whether this is a white-only bulb.""" - return not aiolifx().products.features_map[device.product]["color"] + features = aiolifx().products.features_map.get(device.product, None) + if features: + return not features["color"] + return False def lifxmultizone(device): """Return whether this is a multizone bulb/strip.""" - return aiolifx().products.features_map[device.product]["multizone"] + features = aiolifx().products.features_map.get(device.product, None) + if features: + return features["multizone"] + return False def find_hsbk(**kwargs): From ee05a4ab892ac6faf396fe90a9ae61f0cba318e8 Mon Sep 17 00:00:00 2001 From: Yannick POLLART Date: Thu, 20 Jul 2017 07:56:11 +0200 Subject: [PATCH 046/118] Fix broken status update for lighting4 devices (#8543) * Fix broken status update for lighting4 devices * Fixed indentation --- .../components/binary_sensor/rfxtrx.py | 20 +++++++++---------- homeassistant/components/rfxtrx.py | 11 ++-------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/binary_sensor/rfxtrx.py b/homeassistant/components/binary_sensor/rfxtrx.py index 9a2c23206c189..b70169dc5948f 100644 --- a/homeassistant/components/binary_sensor/rfxtrx.py +++ b/homeassistant/components/binary_sensor/rfxtrx.py @@ -62,6 +62,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): entity[CONF_COMMAND_ON], entity[CONF_COMMAND_OFF]) device.hass = hass + device.is_lighting4 = (packet_id[2:4] == '13') sensors.append(device) rfxtrx.RFX_DEVICES[device_id] = device @@ -94,6 +95,8 @@ def binary_sensor_update(event): pkt_id = "".join("{0:02x}".format(x) for x in event.data) sensor = RfxtrxBinarySensor(event, pkt_id) + sensor.hass = hass + sensor.is_lighting4 = (pkt_id[2:4] == '13') rfxtrx.RFX_DEVICES[device_id] = sensor add_devices_callback([sensor]) _LOGGER.info("Added binary sensor %s " @@ -111,12 +114,12 @@ def binary_sensor_update(event): slugify(event.device.id_string.lower()), event.device.__class__.__name__, event.device.subtype) - - if sensor.is_pt2262: - cmd = rfxtrx.get_pt2262_cmd(device_id, sensor.data_bits) - _LOGGER.info("applying cmd %s to device_id: %s)", - cmd, sensor.masked_id) - sensor.apply_cmd(int(cmd, 16)) + if sensor.is_lighting4: + if sensor.data_bits is not None: + cmd = rfxtrx.get_pt2262_cmd(device_id, sensor.data_bits) + sensor.apply_cmd(int(cmd, 16)) + else: + sensor.update_state(True) else: rfxtrx.apply_received_command(event) @@ -170,11 +173,6 @@ def name(self): """Return the device name.""" return self._name - @property - def is_pt2262(self): - """Return true if the device is PT2262-based.""" - return self._data_bits is not None - @property def masked_id(self): """Return the masked device id (isolated address bits).""" diff --git a/homeassistant/components/rfxtrx.py b/homeassistant/components/rfxtrx.py index b6e4d3415f4e9..e3ffc2f24a87d 100644 --- a/homeassistant/components/rfxtrx.py +++ b/homeassistant/components/rfxtrx.py @@ -247,10 +247,8 @@ def get_pt2262_device(device_id): """Look for the device which id matches the given device_id parameter.""" for dev_id, device in RFX_DEVICES.items(): try: - if (device.is_pt2262 and - device.masked_id == get_pt2262_deviceid( - device_id, - device.data_bits)): + if device.masked_id == get_pt2262_deviceid(device_id, + device.data_bits): _LOGGER.info("rfxtrx: found matching device %s for %s", device_id, get_pt2262_deviceid(device_id, device.data_bits)) @@ -414,11 +412,6 @@ def should_fire_event(self): """Return is the device must fire event.""" return self._should_fire_event - @property - def is_pt2262(self): - """Return true if the device is PT2262-based.""" - return False - @property def is_on(self): """Return true if device is on.""" From 8d1999dc1205fb8c2156b0a3ed66f1320574b7ed Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Thu, 20 Jul 2017 01:56:24 -0400 Subject: [PATCH 047/118] Enhance python_script to support "_getitem_" (#8541) * Enhance python_script to support "_getitem_" In order to use dict / list structures in python scripts we need _getitem_ allowed in the RestrictedPython environment. There is a default_guarded_getitem included with RestrictedPython, which is a pass through used in the Eval code paths. * Add tests for dict/list support in python_scripts * Lint --- homeassistant/components/python_script.py | 2 ++ tests/components/test_python_script.py | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/homeassistant/components/python_script.py b/homeassistant/components/python_script.py index 66b9bd0112a07..386abba59aed2 100644 --- a/homeassistant/components/python_script.py +++ b/homeassistant/components/python_script.py @@ -65,6 +65,7 @@ def execute(hass, filename, source, data=None): from RestrictedPython import compile_restricted_exec from RestrictedPython.Guards import safe_builtins, full_write_guard from RestrictedPython.Utilities import utility_builtins + from RestrictedPython.Eval import default_guarded_getitem compiled = compile_restricted_exec(source, filename=filename) @@ -99,6 +100,7 @@ def protected_getattr(obj, name, default=None): '_getattr_': protected_getattr, '_write_': full_write_guard, '_getiter_': iter, + '_getitem_': default_guarded_getitem } logger = logging.getLogger('{}.{}'.format(__name__, filename)) local = { diff --git a/tests/components/test_python_script.py b/tests/components/test_python_script.py index 78142e06cf3a3..62c1b67eba994 100644 --- a/tests/components/test_python_script.py +++ b/tests/components/test_python_script.py @@ -137,6 +137,22 @@ def test_accessing_async_methods(hass, caplog): assert "Not allowed to access async methods" in caplog.text +@asyncio.coroutine +def test_using_complex_structures(hass, caplog): + """Test that dicts and lists work.""" + caplog.set_level(logging.INFO) + source = """ +mydict = {"a": 1, "b": 2} +mylist = [1, 2, 3, 4] +logger.info('Logging from inside script: %s %s' % (mydict["a"], mylist[2])) + """ + + hass.async_add_job(execute, hass, 'test.py', source, {}) + yield from hass.async_block_till_done() + + assert "Logging from inside script: 1 3" in caplog.text + + @asyncio.coroutine def test_accessing_forbidden_methods(hass, caplog): """Test compile error logs error.""" From 49c399c358bbe45b034f6e013233dc906d47ef0a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 19 Jul 2017 22:59:21 -0700 Subject: [PATCH 048/118] Update persistent deps dir version in config.py (#8479) * Update persistent deps dir version in config.py * Update last version to remove deps dir in tests --- homeassistant/config.py | 4 ++-- tests/test_config.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/config.py b/homeassistant/config.py index 003e64816856a..a4b7bce5dc0cc 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -297,8 +297,8 @@ def process_ha_config_upgrade(hass): _LOGGER.info("Upgrading configuration directory from %s to %s", conf_version, __version__) - if LooseVersion(conf_version) < LooseVersion('0.49'): - # 0.49 introduced persistent deps dir. + if LooseVersion(conf_version) < LooseVersion('0.50'): + # 0.50 introduced persistent deps dir. lib_path = hass.config.path('deps') if os.path.isdir(lib_path): shutil.rmtree(lib_path) diff --git a/tests/test_config.py b/tests/test_config.py index eba98795fe922..8c889979a823e 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -260,8 +260,8 @@ def test_entity_customization(self): @mock.patch('homeassistant.config.shutil') @mock.patch('homeassistant.config.os') def test_remove_lib_on_upgrade(self, mock_os, mock_shutil): - """Test removal of library on upgrade from before 0.49.""" - ha_version = '0.48.0' + """Test removal of library on upgrade from before 0.50.""" + ha_version = '0.49.0' mock_os.path.isdir = mock.Mock(return_value=True) mock_open = mock.mock_open() with mock.patch('homeassistant.config.open', mock_open, create=True): From fde291f8666594e61d7fd02b5bdfc648042e9af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Thu, 20 Jul 2017 11:12:42 +0200 Subject: [PATCH 049/118] Add is_lighting4 to RfxtrxBinarySensor (#8563) --- homeassistant/components/binary_sensor/rfxtrx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/binary_sensor/rfxtrx.py b/homeassistant/components/binary_sensor/rfxtrx.py index b70169dc5948f..e86c948e1917a 100644 --- a/homeassistant/components/binary_sensor/rfxtrx.py +++ b/homeassistant/components/binary_sensor/rfxtrx.py @@ -154,6 +154,7 @@ def __init__(self, event, name, device_class=None, self._device_class = device_class self._off_delay = off_delay self._state = False + self.is_lighting4 = False self.delay_listener = None self._data_bits = data_bits self._cmd_on = cmd_on From bc27d173d010179b34be8b2f23c746ab2fbbedd5 Mon Sep 17 00:00:00 2001 From: pavoni Date: Thu, 20 Jul 2017 10:21:08 +0100 Subject: [PATCH 050/118] Bump pyver to fix exception in fetching colours. --- homeassistant/components/vera.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/vera.py b/homeassistant/components/vera.py index b43cea3fcea6d..2183e20188f24 100644 --- a/homeassistant/components/vera.py +++ b/homeassistant/components/vera.py @@ -20,7 +20,7 @@ EVENT_HOMEASSISTANT_STOP) from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['pyvera==0.2.34'] +REQUIREMENTS = ['pyvera==0.2.35'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index aee9aec89fadf..1adc4778ebabe 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -773,7 +773,7 @@ pyunifi==2.13 # pyuserinput==0.1.11 # homeassistant.components.vera -pyvera==0.2.34 +pyvera==0.2.35 # homeassistant.components.media_player.vizio pyvizio==0.0.2 From 90639d33ab6b574abfec71b8ebbdd86cefff9081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Thu, 20 Jul 2017 15:20:00 +0200 Subject: [PATCH 051/118] Xiaomi gw support (#8555) * xiaomi support * xiaomi support * style * style * style * style * style * coveragerc * Update xiaomi.py * Update xiaomi.py * Update xiaomi.py * refactorization * refactorization * config validation * style * package * refactorization * refactorization * refactorization * HA integration --- .coveragerc | 4 +- .../components/binary_sensor/xiaomi.py | 316 ++++++++++++++++++ homeassistant/components/cover/xiaomi.py | 66 ++++ homeassistant/components/light/xiaomi.py | 103 ++++++ homeassistant/components/sensor/xiaomi.py | 77 +++++ homeassistant/components/switch/xiaomi.py | 111 ++++++ homeassistant/components/xiaomi.py | 195 +++++++++++ requirements_all.txt | 3 + 8 files changed, 874 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/binary_sensor/xiaomi.py create mode 100644 homeassistant/components/cover/xiaomi.py create mode 100755 homeassistant/components/light/xiaomi.py create mode 100644 homeassistant/components/sensor/xiaomi.py create mode 100644 homeassistant/components/switch/xiaomi.py create mode 100644 homeassistant/components/xiaomi.py diff --git a/.coveragerc b/.coveragerc index 2d1bff462b963..3ec0b119cb8e9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -193,6 +193,9 @@ omit = homeassistant/components/wink.py homeassistant/components/*/wink.py + homeassistant/components/xiaomi.py + homeassistant/components/*/xiaomi.py + homeassistant/components/zabbix.py homeassistant/components/*/zabbix.py @@ -274,7 +277,6 @@ omit = homeassistant/components/device_tracker/tplink.py homeassistant/components/device_tracker/trackr.py homeassistant/components/device_tracker/ubus.py - homeassistant/components/device_tracker/xiaomi.py homeassistant/components/downloader.py homeassistant/components/emoncms_history.py homeassistant/components/emulated_hue/upnp.py diff --git a/homeassistant/components/binary_sensor/xiaomi.py b/homeassistant/components/binary_sensor/xiaomi.py new file mode 100644 index 0000000000000..14d2ef9b308e1 --- /dev/null +++ b/homeassistant/components/binary_sensor/xiaomi.py @@ -0,0 +1,316 @@ +"""Support for Xiaomi binary sensors.""" +import logging + +from homeassistant.components.binary_sensor import BinarySensorDevice +from homeassistant.components.xiaomi import (PY_XIAOMI_GATEWAY, XiaomiDevice) + +_LOGGER = logging.getLogger(__name__) + +NO_CLOSE = 'no_close' +ATTR_OPEN_SINCE = 'Open since' + +MOTION = 'motion' +NO_MOTION = 'no_motion' +ATTR_NO_MOTION_SINCE = 'No motion since' + +DENSITY = 'density' +ATTR_DENSITY = 'Density' + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Perform the setup for Xiaomi devices.""" + devices = [] + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + for device in gateway.devices['binary_sensor']: + model = device['model'] + if model == 'motion': + devices.append(XiaomiMotionSensor(device, hass, gateway)) + elif model == 'magnet': + devices.append(XiaomiDoorSensor(device, gateway)) + elif model == 'smoke': + devices.append(XiaomiSmokeSensor(device, gateway)) + elif model == 'natgas': + devices.append(XiaomiNatgasSensor(device, gateway)) + elif model == 'switch': + devices.append(XiaomiButton(device, 'Switch', 'status', + hass, gateway)) + elif model == 'sensor_switch.aq2': + devices.append(XiaomiButton(device, 'Switch', 'status', + hass, gateway)) + elif model == '86sw1': + devices.append(XiaomiButton(device, 'Wall Switch', 'channel_0', + hass, gateway)) + elif model == '86sw2': + devices.append(XiaomiButton(device, 'Wall Switch (Left)', + 'channel_0', hass, gateway)) + devices.append(XiaomiButton(device, 'Wall Switch (Right)', + 'channel_1', hass, gateway)) + devices.append(XiaomiButton(device, 'Wall Switch (Both)', + 'dual_channel', hass, gateway)) + elif model == 'cube': + devices.append(XiaomiCube(device, hass, gateway)) + add_devices(devices) + + +class XiaomiBinarySensor(XiaomiDevice, BinarySensorDevice): + """Representation of a base XiaomiBinarySensor.""" + + def __init__(self, device, name, xiaomi_hub): + """Initialize the XiaomiSmokeSensor.""" + self._data_key = None + self._device_class = None + self._should_poll = False + self._density = 0 + XiaomiDevice.__init__(self, device, name, xiaomi_hub) + + @property + def should_poll(self): + """Return True if entity has to be polled for state.""" + return self._should_poll + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def device_class(self): + """Return the class of binary sensor.""" + return self._device_class + + def update(self): + """Update the sensor state.""" + _LOGGER.debug('Updating xiaomi sensor by polling') + self._get_from_hub(self._sid) + + +class XiaomiNatgasSensor(XiaomiBinarySensor): + """Representation of a XiaomiNatgasSensor.""" + + def __init__(self, device, xiaomi_hub): + """Initialize the XiaomiSmokeSensor.""" + self._data_key = 'alarm' + self._density = None + self._device_class = 'gas' + XiaomiBinarySensor.__init__(self, device, 'Natgas Sensor', xiaomi_hub) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attrs = {ATTR_DENSITY: self._density} + attrs.update(super().device_state_attributes) + return attrs + + def parse_data(self, data): + """Parse data sent by gateway.""" + if DENSITY in data: + self._density = int(data.get(DENSITY)) + + value = data.get(self._data_key) + if value is None: + return False + + if value == '1': + if self._state: + return False + self._state = True + return True + elif value == '0': + if self._state: + self._state = False + return True + return False + + +class XiaomiMotionSensor(XiaomiBinarySensor): + """Representation of a XiaomiMotionSensor.""" + + def __init__(self, device, hass, xiaomi_hub): + """Initialize the XiaomiMotionSensor.""" + self._hass = hass + self._data_key = 'status' + self._no_motion_since = 0 + self._device_class = 'motion' + XiaomiBinarySensor.__init__(self, device, 'Motion Sensor', xiaomi_hub) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attrs = {ATTR_NO_MOTION_SINCE: self._no_motion_since} + attrs.update(super().device_state_attributes) + return attrs + + def parse_data(self, data): + """Parse data sent by gateway.""" + self._should_poll = False + if NO_MOTION in data: # handle push from the hub + self._no_motion_since = data[NO_MOTION] + self._state = False + return True + + value = data.get(self._data_key) + if value is None: + return False + + if value == MOTION: + self._should_poll = True + if self.entity_id is not None: + self._hass.bus.fire('motion', { + 'entity_id': self.entity_id + }) + + self._no_motion_since = 0 + if self._state: + return False + self._state = True + return True + elif value == NO_MOTION: + if not self._state: + return False + self._state = False + return True + + +class XiaomiDoorSensor(XiaomiBinarySensor): + """Representation of a XiaomiDoorSensor.""" + + def __init__(self, device, xiaomi_hub): + """Initialize the XiaomiDoorSensor.""" + self._data_key = 'status' + self._open_since = 0 + self._device_class = 'opening' + XiaomiBinarySensor.__init__(self, device, 'Door Window Sensor', + xiaomi_hub) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attrs = {ATTR_OPEN_SINCE: self._open_since} + attrs.update(super().device_state_attributes) + return attrs + + def parse_data(self, data): + """Parse data sent by gateway.""" + self._should_poll = False + if NO_CLOSE in data: # handle push from the hub + self._open_since = data[NO_CLOSE] + return True + + value = data.get(self._data_key) + if value is None: + return False + + if value == 'open': + self._should_poll = True + if self._state: + return False + self._state = True + return True + elif value == 'close': + self._open_since = 0 + if self._state: + self._state = False + return True + return False + + +class XiaomiSmokeSensor(XiaomiBinarySensor): + """Representation of a XiaomiSmokeSensor.""" + + def __init__(self, device, xiaomi_hub): + """Initialize the XiaomiSmokeSensor.""" + self._data_key = 'alarm' + self._density = 0 + self._device_class = 'smoke' + XiaomiBinarySensor.__init__(self, device, 'Smoke Sensor', xiaomi_hub) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attrs = {ATTR_DENSITY: self._density} + attrs.update(super().device_state_attributes) + return attrs + + def parse_data(self, data): + """Parse data sent by gateway.""" + if DENSITY in data: + self._density = int(data.get(DENSITY)) + value = data.get(self._data_key) + if value is None: + return False + + if value == '1': + if self._state: + return False + self._state = True + return True + elif value == '0': + if self._state: + self._state = False + return True + return False + + +class XiaomiButton(XiaomiBinarySensor): + """Representation of a Xiaomi Button.""" + + def __init__(self, device, name, data_key, hass, xiaomi_hub): + """Initialize the XiaomiButton.""" + self._hass = hass + self._data_key = data_key + XiaomiBinarySensor.__init__(self, device, name, xiaomi_hub) + + def parse_data(self, data): + """Parse data sent by gateway.""" + value = data.get(self._data_key) + if value is None: + return False + + if value == 'long_click_press': + self._state = True + click_type = 'long_click_press' + elif value == 'long_click_release': + self._state = False + click_type = 'hold' + elif value == 'click': + click_type = 'single' + elif value == 'double_click': + click_type = 'double' + elif value == 'both_click': + click_type = 'both' + else: + return False + + self._hass.bus.fire('click', { + 'entity_id': self.entity_id, + 'click_type': click_type + }) + if value in ['long_click_press', 'long_click_release']: + return True + return False + + +class XiaomiCube(XiaomiBinarySensor): + """Representation of a Xiaomi Cube.""" + + def __init__(self, device, hass, xiaomi_hub): + """Initialize the Xiaomi Cube.""" + self._hass = hass + self._state = False + XiaomiBinarySensor.__init__(self, device, 'Cube', xiaomi_hub) + + def parse_data(self, data): + """Parse data sent by gateway.""" + if 'status' in data: + self._hass.bus.fire('cube_action', { + 'entity_id': self.entity_id, + 'action_type': data['status'] + }) + + if 'rotate' in data: + self._hass.bus.fire('cube_action', { + 'entity_id': self.entity_id, + 'action_type': 'rotate', + 'action_value': float(data['rotate'].replace(",", ".")) + }) + return False diff --git a/homeassistant/components/cover/xiaomi.py b/homeassistant/components/cover/xiaomi.py new file mode 100644 index 0000000000000..7e3b0b7044d82 --- /dev/null +++ b/homeassistant/components/cover/xiaomi.py @@ -0,0 +1,66 @@ +"""Support for Xiaomi curtain.""" +import logging + +from homeassistant.components.cover import CoverDevice +from homeassistant.components.xiaomi import (PY_XIAOMI_GATEWAY, XiaomiDevice) + +_LOGGER = logging.getLogger(__name__) + +ATTR_CURTAIN_LEVEL = 'curtain_level' + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Perform the setup for Xiaomi devices.""" + devices = [] + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + for device in gateway.devices['cover']: + model = device['model'] + if model == 'curtain': + devices.append(XiaomiGenericCover(device, "Curtain", + {'status': 'status', + 'pos': 'curtain_level'}, + gateway)) + add_devices(devices) + + +class XiaomiGenericCover(XiaomiDevice, CoverDevice): + """Representation of a XiaomiPlug.""" + + def __init__(self, device, name, data_key, xiaomi_hub): + """Initialize the XiaomiPlug.""" + self._data_key = data_key + self._pos = 0 + XiaomiDevice.__init__(self, device, name, xiaomi_hub) + + @property + def current_cover_position(self): + """Return the current position of the cover.""" + return self._pos + + @property + def is_closed(self): + """Return if the cover is closed.""" + return self.current_cover_position < 0 + + def close_cover(self, **kwargs): + """Close the cover.""" + self._write_to_hub(self._sid, self._data_key['status'], 'close') + + def open_cover(self, **kwargs): + """Open the cover.""" + self._write_to_hub(self._sid, self._data_key['status'], 'open') + + def stop_cover(self, **kwargs): + """Stop the cover.""" + self._write_to_hub(self._sid, self._data_key['status'], 'stop') + + def set_cover_position(self, position, **kwargs): + """Move the cover to a specific position.""" + self._write_to_hub(self._sid, self._data_key['pos'], str(position)) + + def parse_data(self, data): + """Parse data sent by gateway.""" + if ATTR_CURTAIN_LEVEL in data: + self._pos = int(data[ATTR_CURTAIN_LEVEL]) + return True + return False diff --git a/homeassistant/components/light/xiaomi.py b/homeassistant/components/light/xiaomi.py new file mode 100755 index 0000000000000..d8a70b726f47b --- /dev/null +++ b/homeassistant/components/light/xiaomi.py @@ -0,0 +1,103 @@ +"""Support for Xiaomi Gateway Light.""" +import logging +import struct +import binascii +from homeassistant.components.xiaomi import (PY_XIAOMI_GATEWAY, XiaomiDevice) +from homeassistant.components.light import (ATTR_BRIGHTNESS, ATTR_RGB_COLOR, + SUPPORT_BRIGHTNESS, + SUPPORT_RGB_COLOR, Light) + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Perform the setup for Xiaomi devices.""" + devices = [] + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + for device in gateway.devices['light']: + model = device['model'] + if model == 'gateway': + devices.append(XiaomiGatewayLight(device, 'Gateway Light', + gateway)) + add_devices(devices) + + +class XiaomiGatewayLight(XiaomiDevice, Light): + """Representation of a XiaomiGatewayLight.""" + + def __init__(self, device, name, xiaomi_hub): + """Initialize the XiaomiGatewayLight.""" + self._data_key = 'rgb' + self._rgb = (255, 255, 255) + self._brightness = 180 + + XiaomiDevice.__init__(self, device, name, xiaomi_hub) + + @property + def is_on(self): + """Return true if it is on.""" + return self._state + + def parse_data(self, data): + """Parse data sent by gateway.""" + value = data.get(self._data_key) + if value is None: + return False + + if value == 0: + if self._state: + self._state = False + return True + + rgbhexstr = "%x" % value + if len(rgbhexstr) == 7: + rgbhexstr = '0' + rgbhexstr + elif len(rgbhexstr) != 8: + _LOGGER.error('Light RGB data error.' + ' Must be 8 characters. Received: %s', rgbhexstr) + return False + + rgbhex = bytes.fromhex(rgbhexstr) + rgba = struct.unpack('BBBB', rgbhex) + brightness = rgba[0] + rgb = rgba[1:] + + self._brightness = int(255 * brightness / 100) + self._rgb = rgb + self._state = True + return True + + @property + def brightness(self): + """Return the brightness of this light between 0..255.""" + return self._brightness + + @property + def rgb_color(self): + """Return the RBG color value.""" + return self._rgb + + @property + def supported_features(self): + """Return the supported features.""" + return SUPPORT_BRIGHTNESS | SUPPORT_RGB_COLOR + + def turn_on(self, **kwargs): + """Turn the light on.""" + if ATTR_RGB_COLOR in kwargs: + self._rgb = kwargs[ATTR_RGB_COLOR] + + if ATTR_BRIGHTNESS in kwargs: + self._brightness = int(100 * kwargs[ATTR_BRIGHTNESS] / 255) + + rgba = (self._brightness,) + self._rgb + rgbhex = binascii.hexlify(struct.pack('BBBB', *rgba)).decode("ASCII") + rgbhex = int(rgbhex, 16) + + if self._write_to_hub(self._sid, **{self._data_key: rgbhex}): + self._state = True + + def turn_off(self, **kwargs): + """Turn the light off.""" + if self._write_to_hub(self._sid, **{self._data_key: 0}): + self._state = False diff --git a/homeassistant/components/sensor/xiaomi.py b/homeassistant/components/sensor/xiaomi.py new file mode 100644 index 0000000000000..b1fcd8beb1f0f --- /dev/null +++ b/homeassistant/components/sensor/xiaomi.py @@ -0,0 +1,77 @@ +"""Support for Xiaomi sensors.""" +import logging + +from homeassistant.components.xiaomi import (PY_XIAOMI_GATEWAY, XiaomiDevice) +from homeassistant.const import TEMP_CELSIUS + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Perform the setup for Xiaomi devices.""" + devices = [] + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + for device in gateway.devices['sensor']: + if device['model'] == 'sensor_ht': + devices.append(XiaomiSensor(device, 'Temperature', + 'temperature', gateway)) + devices.append(XiaomiSensor(device, 'Humidity', + 'humidity', gateway)) + if device['model'] == 'weather.v1': + devices.append(XiaomiSensor(device, 'Temperature', + 'temperature', gateway)) + devices.append(XiaomiSensor(device, 'Humidity', + 'humidity', gateway)) + devices.append(XiaomiSensor(device, 'Pressure', + 'pressure', gateway)) + elif device['model'] == 'gateway': + devices.append(XiaomiSensor(device, 'Illumination', + 'illumination', gateway)) + add_devices(devices) + + +class XiaomiSensor(XiaomiDevice): + """Representation of a XiaomiSensor.""" + + def __init__(self, device, name, data_key, xiaomi_hub): + """Initialize the XiaomiSensor.""" + self._data_key = data_key + XiaomiDevice.__init__(self, device, name, xiaomi_hub) + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity, if any.""" + if self._data_key == 'temperature': + return TEMP_CELSIUS + elif self._data_key == 'humidity': + return '%' + elif self._data_key == 'illumination': + return 'lm' + elif self._data_key == 'pressure': + return 'hPa' + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + def parse_data(self, data): + """Parse data sent by gateway.""" + value = data.get(self._data_key) + if value is None: + return False + value = float(value) + if self._data_key == 'temperature' and value == 10000: + return False + elif self._data_key == 'humidity' and value == 0: + return False + elif self._data_key == 'illumination' and value == 0: + return False + elif self._data_key == 'pressure' and value == 0: + return False + if self._data_key in ['temperature', 'humidity']: + value /= 100 + elif self._data_key in ['illumination']: + value = max(value - 300, 0) + self._state = round(value, 2) + return True diff --git a/homeassistant/components/switch/xiaomi.py b/homeassistant/components/switch/xiaomi.py new file mode 100644 index 0000000000000..fa472136bb504 --- /dev/null +++ b/homeassistant/components/switch/xiaomi.py @@ -0,0 +1,111 @@ +"""Support for Xiaomi binary sensors.""" +import logging + +from homeassistant.components.switch import SwitchDevice +from homeassistant.components.xiaomi import (PY_XIAOMI_GATEWAY, XiaomiDevice) + +_LOGGER = logging.getLogger(__name__) + +ATTR_LOAD_POWER = 'Load power' # Load power in watts (W) +ATTR_POWER_CONSUMED = 'Power consumed' +ATTR_IN_USE = 'In use' +LOAD_POWER = 'load_power' +POWER_CONSUMED = 'power_consumed' +IN_USE = 'inuse' + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Perform the setup for Xiaomi devices.""" + devices = [] + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + for device in gateway.devices['switch']: + model = device['model'] + if model == 'plug': + devices.append(XiaomiGenericSwitch(device, "Plug", 'status', + True, gateway)) + elif model == 'ctrl_neutral1': + devices.append(XiaomiGenericSwitch(device, 'Wall Switch', + 'channel_0', + False, gateway)) + elif model == 'ctrl_neutral2': + devices.append(XiaomiGenericSwitch(device, 'Wall Switch Left', + 'channel_0', + False, gateway)) + devices.append(XiaomiGenericSwitch(device, 'Wall Switch Right', + 'channel_1', + False, gateway)) + elif model == '86plug': + devices.append(XiaomiGenericSwitch(device, 'Wall Plug', + 'status', True, gateway)) + add_devices(devices) + + +class XiaomiGenericSwitch(XiaomiDevice, SwitchDevice): + """Representation of a XiaomiPlug.""" + + def __init__(self, device, name, data_key, supports_power_consumption, + xiaomi_hub): + """Initialize the XiaomiPlug.""" + self._data_key = data_key + self._in_use = None + self._load_power = None + self._power_consumed = None + self._supports_power_consumption = supports_power_consumption + XiaomiDevice.__init__(self, device, name, xiaomi_hub) + + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + if self._data_key == 'status': + return 'mdi:power-plug' + return 'mdi:power-socket' + + @property + def is_on(self): + """Return true if it is on.""" + return self._state + + @property + def device_state_attributes(self): + """Return the state attributes.""" + if self._supports_power_consumption: + attrs = {ATTR_IN_USE: self._in_use, + ATTR_LOAD_POWER: self._load_power, + ATTR_POWER_CONSUMED: self._power_consumed} + else: + attrs = {} + attrs.update(super().device_state_attributes) + return attrs + + def turn_on(self, **kwargs): + """Turn the switch on.""" + if self._write_to_hub(self._sid, **{self._data_key: 'on'}): + self._state = True + self.schedule_update_ha_state() + + def turn_off(self): + """Turn the switch off.""" + if self._write_to_hub(self._sid, **{self._data_key: 'off'}): + self._state = False + self.schedule_update_ha_state() + + def parse_data(self, data): + """Parse data sent by gateway.""" + if IN_USE in data: + self._in_use = int(data[IN_USE]) + if not self._in_use: + self._load_power = 0 + if POWER_CONSUMED in data: + self._power_consumed = round(float(data[POWER_CONSUMED]), 2) + if LOAD_POWER in data: + self._load_power = round(float(data[LOAD_POWER]), 2) + + value = data.get(self._data_key) + if value is None: + return False + + state = value == 'on' + if self._state == state: + return False + self._state = state + return True diff --git a/homeassistant/components/xiaomi.py b/homeassistant/components/xiaomi.py new file mode 100644 index 0000000000000..e4a9698c71f70 --- /dev/null +++ b/homeassistant/components/xiaomi.py @@ -0,0 +1,195 @@ +"""Support for Xiaomi Gateways.""" +import logging +import voluptuous as vol +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers import discovery +from homeassistant.helpers.entity import Entity +from homeassistant.const import (ATTR_BATTERY_LEVEL, EVENT_HOMEASSISTANT_STOP, + CONF_MAC) + + +REQUIREMENTS = ['https://github.com/Danielhiversen/PyXiaomiGateway/archive/' + '877faec36e1bfa4177cae2a0d4f49570af083e1d.zip#' + 'PyXiaomiGateway==0.1.0'] + +ATTR_GW_SID = 'gw_sid' +ATTR_RINGTONE_ID = 'ringtone_id' +ATTR_RINGTONE_VOL = 'ringtone_vol' +CONF_DISCOVERY_RETRY = 'discovery_retry' +CONF_GATEWAYS = 'gateways' +CONF_INTERFACE = 'interface' +DOMAIN = 'xiaomi' +PY_XIAOMI_GATEWAY = "xiaomi_gw" + + +def _validate_conf(config): + """Validate a list of devices definitions.""" + res_config = [] + for gw_conf in config: + res_gw_conf = {'sid': gw_conf.get(CONF_MAC)} + if res_gw_conf['sid'] is not None: + res_gw_conf['sid'] = res_gw_conf['sid'].replace(":", "").lower() + if len(res_gw_conf['sid']) != 12: + raise vol.Invalid('Invalid mac address', gw_conf.get(CONF_MAC)) + key = gw_conf.get('key') + if key is None: + _LOGGER.warning( + 'Gateway Key is not provided.' + ' Controlling gateway device will not be possible.') + elif len(key) != 16: + raise vol.Invalid('Invalid key %s.' + ' Key must be 16 characters', key) + res_gw_conf['key'] = key + res_config.append(res_gw_conf) + return res_config + + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Optional(CONF_GATEWAYS, default=[{CONF_MAC: None, "key": None}]): + vol.All(cv.ensure_list, _validate_conf), + vol.Optional(CONF_INTERFACE, default='any'): cv.string, + vol.Optional(CONF_DISCOVERY_RETRY, default=3): cv.positive_int + }) +}, extra=vol.ALLOW_EXTRA) + +_LOGGER = logging.getLogger(__name__) + + +def setup(hass, config): + """Set up the Xiaomi component.""" + gateways = config[DOMAIN][CONF_GATEWAYS] + interface = config[DOMAIN][CONF_INTERFACE] + discovery_retry = config[DOMAIN][CONF_DISCOVERY_RETRY] + + from PyXiaomiGateway import PyXiaomiGateway + hass.data[PY_XIAOMI_GATEWAY] = PyXiaomiGateway(hass.add_job, gateways, + interface) + + _LOGGER.debug("Expecting %s gateways", len(gateways)) + for _ in range(discovery_retry): + _LOGGER.info('Discovering Xiaomi Gateways (Try %s)', _ + 1) + hass.data[PY_XIAOMI_GATEWAY].discover_gateways() + if len(hass.data[PY_XIAOMI_GATEWAY].gateways) >= len(gateways): + break + + if not hass.data[PY_XIAOMI_GATEWAY].gateways: + _LOGGER.error("No gateway discovered") + return False + hass.data[PY_XIAOMI_GATEWAY].listen() + _LOGGER.debug("Listening for broadcast") + + for component in ['binary_sensor', 'sensor', 'switch', 'light', 'cover']: + discovery.load_platform(hass, component, DOMAIN, {}, config) + + def stop_xiaomi(event): + """Stop Xiaomi Socket.""" + _LOGGER.info("Shutting down Xiaomi Hub.") + hass.data[PY_XIAOMI_GATEWAY].stop_listen() + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_xiaomi) + + def play_ringtone_service(call): + """Service to play ringtone through Gateway.""" + if call.data.get(ATTR_RINGTONE_ID) is None \ + or call.data.get(ATTR_GW_SID) is None: + _LOGGER.error("Mandatory parameters is not specified.") + return + + ring_id = int(call.data.get(ATTR_RINGTONE_ID)) + if ring_id in [9, 14-19]: + _LOGGER.error('Specified mid: %s is not defined in gateway.', + ring_id) + return + + ring_vol = call.data.get(ATTR_RINGTONE_VOL) + if ring_vol is None: + ringtone = {'mid': ring_id} + else: + ringtone = {'mid': ring_id, 'vol': int(ring_vol)} + + gw_sid = call.data.get(ATTR_GW_SID) + + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + if gateway.sid == gw_sid: + gateway.write_to_hub(gateway.sid, **ringtone) + break + else: + _LOGGER.error('Unknown gateway sid: %s was specified.', gw_sid) + + def stop_ringtone_service(call): + """Service to stop playing ringtone on Gateway.""" + gw_sid = call.data.get(ATTR_GW_SID) + if gw_sid is None: + _LOGGER.error("Mandatory parameter (%s) is not specified.", + ATTR_GW_SID) + return + + for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): + if gateway.sid == gw_sid: + ringtone = {'mid': 10000} + gateway.write_to_hub(gateway.sid, **ringtone) + break + else: + _LOGGER.error('Unknown gateway sid: %s was specified.', gw_sid) + + hass.services.async_register(DOMAIN, 'play_ringtone', + play_ringtone_service, + description=None, schema=None) + hass.services.async_register(DOMAIN, 'stop_ringtone', + stop_ringtone_service, + description=None, schema=None) + return True + + +class XiaomiDevice(Entity): + """Representation a base Xiaomi device.""" + + def __init__(self, device, name, xiaomi_hub): + """Initialize the xiaomi device.""" + self._state = None + self._sid = device['sid'] + self._name = '{}_{}'.format(name, self._sid) + self._write_to_hub = xiaomi_hub.write_to_hub + self._get_from_hub = xiaomi_hub.get_from_hub + xiaomi_hub.callbacks[self._sid].append(self.push_data) + self._device_state_attributes = {} + self.parse_data(device['data']) + self.parse_voltage(device['data']) + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def should_poll(self): + """Poll update device status.""" + return False + + @property + def device_state_attributes(self): + """Return the state attributes.""" + return self._device_state_attributes + + def push_data(self, data): + """Push from Hub.""" + _LOGGER.debug("PUSH >> %s: %s", self, data) + if self.parse_data(data) or self.parse_voltage(data): + self.schedule_update_ha_state() + + def parse_voltage(self, data): + """Parse battery level data sent by gateway.""" + if 'voltage' not in data: + return False + max_volt = 3300 + min_volt = 2800 + voltage = data['voltage'] + voltage = min(voltage, max_volt) + voltage = max(voltage, min_volt) + percent = ((voltage - min_volt) / (max_volt - min_volt)) * 100 + self._device_state_attributes[ATTR_BATTERY_LEVEL] = round(percent, 1) + return True + + def parse_data(self, data): + """Parse data sent by gateway.""" + raise NotImplementedError() diff --git a/requirements_all.txt b/requirements_all.txt index 1adc4778ebabe..8199348b82468 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -276,6 +276,9 @@ holidays==0.8.1 # homeassistant.components.camera.onvif http://github.com/tgaugry/suds-passworddigest-py3/archive/86fc50e39b4d2b8997481967d6a7fe1c57118999.zip#suds-passworddigest-py3==0.1.2a +# homeassistant.components.xiaomi +https://github.com/Danielhiversen/PyXiaomiGateway/archive/877faec36e1bfa4177cae2a0d4f49570af083e1d.zip#PyXiaomiGateway==0.1.0 + # homeassistant.components.sensor.dht # https://github.com/adafruit/Adafruit_Python_DHT/archive/da8cddf7fb629c1ef4f046ca44f42523c9cf2d11.zip#Adafruit_DHT==1.3.0 From 718949481f56ebe8c9f5f67b0f57bdf2bdcb1c3c Mon Sep 17 00:00:00 2001 From: namadori Date: Thu, 20 Jul 2017 15:53:06 +0200 Subject: [PATCH 052/118] fix #8263 corrected Adafruit DHT library version from 1.3.0 to 1.3.2 (#8562) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/sensor/dht.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/dht.py b/homeassistant/components/sensor/dht.py index 1f24a0ee667ca..6056322cc2452 100644 --- a/homeassistant/components/sensor/dht.py +++ b/homeassistant/components/sensor/dht.py @@ -20,7 +20,7 @@ # Update this requirement to upstream as soon as it supports Python 3. REQUIREMENTS = ['https://github.com/adafruit/Adafruit_Python_DHT/archive/' 'da8cddf7fb629c1ef4f046ca44f42523c9cf2d11.zip' - '#Adafruit_DHT==1.3.0'] + '#Adafruit_DHT==1.3.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 8199348b82468..86d3d8d60ac0d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -280,7 +280,7 @@ http://github.com/tgaugry/suds-passworddigest-py3/archive/86fc50e39b4d2b89974819 https://github.com/Danielhiversen/PyXiaomiGateway/archive/877faec36e1bfa4177cae2a0d4f49570af083e1d.zip#PyXiaomiGateway==0.1.0 # homeassistant.components.sensor.dht -# https://github.com/adafruit/Adafruit_Python_DHT/archive/da8cddf7fb629c1ef4f046ca44f42523c9cf2d11.zip#Adafruit_DHT==1.3.0 +# https://github.com/adafruit/Adafruit_Python_DHT/archive/da8cddf7fb629c1ef4f046ca44f42523c9cf2d11.zip#Adafruit_DHT==1.3.2 # homeassistant.components.media_player.braviatv https://github.com/aparraga/braviarc/archive/0.3.7.zip#braviarc==0.3.7 From a5c0831dc19382a47381d927e6a2210703020be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Thu, 20 Jul 2017 23:04:21 +0200 Subject: [PATCH 053/118] xiaomi bug fix (#8576) --- .../components/binary_sensor/xiaomi.py | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/binary_sensor/xiaomi.py b/homeassistant/components/binary_sensor/xiaomi.py index 14d2ef9b308e1..216329da9c8b6 100644 --- a/homeassistant/components/binary_sensor/xiaomi.py +++ b/homeassistant/components/binary_sensor/xiaomi.py @@ -55,10 +55,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class XiaomiBinarySensor(XiaomiDevice, BinarySensorDevice): """Representation of a base XiaomiBinarySensor.""" - def __init__(self, device, name, xiaomi_hub): + def __init__(self, device, name, xiaomi_hub, data_key, device_class): """Initialize the XiaomiSmokeSensor.""" - self._data_key = None - self._device_class = None + self._data_key = data_key + self._device_class = device_class self._should_poll = False self._density = 0 XiaomiDevice.__init__(self, device, name, xiaomi_hub) @@ -89,10 +89,9 @@ class XiaomiNatgasSensor(XiaomiBinarySensor): def __init__(self, device, xiaomi_hub): """Initialize the XiaomiSmokeSensor.""" - self._data_key = 'alarm' self._density = None - self._device_class = 'gas' - XiaomiBinarySensor.__init__(self, device, 'Natgas Sensor', xiaomi_hub) + XiaomiBinarySensor.__init__(self, device, 'Natgas Sensor', xiaomi_hub, + 'alarm', 'gas') @property def device_state_attributes(self): @@ -128,10 +127,9 @@ class XiaomiMotionSensor(XiaomiBinarySensor): def __init__(self, device, hass, xiaomi_hub): """Initialize the XiaomiMotionSensor.""" self._hass = hass - self._data_key = 'status' self._no_motion_since = 0 - self._device_class = 'motion' - XiaomiBinarySensor.__init__(self, device, 'Motion Sensor', xiaomi_hub) + XiaomiBinarySensor.__init__(self, device, 'Motion Sensor', xiaomi_hub, + 'status', 'motion') @property def device_state_attributes(self): @@ -176,11 +174,9 @@ class XiaomiDoorSensor(XiaomiBinarySensor): def __init__(self, device, xiaomi_hub): """Initialize the XiaomiDoorSensor.""" - self._data_key = 'status' self._open_since = 0 - self._device_class = 'opening' XiaomiBinarySensor.__init__(self, device, 'Door Window Sensor', - xiaomi_hub) + xiaomi_hub, 'status', 'opening') @property def device_state_attributes(self): @@ -219,10 +215,9 @@ class XiaomiSmokeSensor(XiaomiBinarySensor): def __init__(self, device, xiaomi_hub): """Initialize the XiaomiSmokeSensor.""" - self._data_key = 'alarm' self._density = 0 - self._device_class = 'smoke' - XiaomiBinarySensor.__init__(self, device, 'Smoke Sensor', xiaomi_hub) + XiaomiBinarySensor.__init__(self, device, 'Smoke Sensor', xiaomi_hub, + 'alarm', 'smoke') @property def device_state_attributes(self): @@ -257,8 +252,8 @@ class XiaomiButton(XiaomiBinarySensor): def __init__(self, device, name, data_key, hass, xiaomi_hub): """Initialize the XiaomiButton.""" self._hass = hass - self._data_key = data_key - XiaomiBinarySensor.__init__(self, device, name, xiaomi_hub) + XiaomiBinarySensor.__init__(self, device, name, xiaomi_hub, + data_key, None) def parse_data(self, data): """Parse data sent by gateway.""" @@ -297,7 +292,8 @@ def __init__(self, device, hass, xiaomi_hub): """Initialize the Xiaomi Cube.""" self._hass = hass self._state = False - XiaomiBinarySensor.__init__(self, device, 'Cube', xiaomi_hub) + XiaomiBinarySensor.__init__(self, device, 'Cube', xiaomi_hub, + None, None) def parse_data(self, data): """Parse data sent by gateway.""" From e63a96cf53ec6f0ed0fad7bf362e262c9943cecb Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Thu, 20 Jul 2017 16:59:41 -0600 Subject: [PATCH 054/118] Bumped python-simplisafe version (#8578) * Bumped python-simplisafe version --- homeassistant/components/alarm_control_panel/simplisafe.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/simplisafe.py b/homeassistant/components/alarm_control_panel/simplisafe.py index 913a3abb616b5..a600a01fcfdb8 100644 --- a/homeassistant/components/alarm_control_panel/simplisafe.py +++ b/homeassistant/components/alarm_control_panel/simplisafe.py @@ -16,7 +16,7 @@ EVENT_HOMEASSISTANT_STOP) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['simplisafe-python==1.0.2'] +REQUIREMENTS = ['simplisafe-python==1.0.3'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 86d3d8d60ac0d..9110795275d34 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -843,7 +843,7 @@ sense-hat==2.2.0 sharp_aquos_rc==0.3.2 # homeassistant.components.alarm_control_panel.simplisafe -simplisafe-python==1.0.2 +simplisafe-python==1.0.3 # homeassistant.components.notify.slack slacker==0.9.50 From 4f8d2ec31717305f242ed7d8dfdd76af34ab86dd Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Fri, 21 Jul 2017 03:40:07 -0400 Subject: [PATCH 055/118] Added Time Remaining and Time Elapsed sensors for octoprint (#8581) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/sensor/octoprint.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/sensor/octoprint.py b/homeassistant/components/sensor/octoprint.py index 150a97288cca2..035799429f537 100644 --- a/homeassistant/components/sensor/octoprint.py +++ b/homeassistant/components/sensor/octoprint.py @@ -25,6 +25,8 @@ 'Temperatures': ['printer', 'temperature', '*', TEMP_CELSIUS], 'Current State': ['printer', 'state', 'text', None], 'Job Percentage': ['job', 'progress', 'completion', '%'], + 'Time Remaining': ['job', 'progress', 'printTimeLeft', 'seconds'], + 'Time Elapsed': ['job', 'progress', 'printTime', 'seconds'], } PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ From f6a5e0887da10418f73bc7df0a76d307e3a9b76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Fri, 21 Jul 2017 10:10:03 +0200 Subject: [PATCH 056/118] upgade xiaomi lib to 0.2 (#8584) --- homeassistant/components/xiaomi.py | 4 ++-- requirements_all.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/xiaomi.py b/homeassistant/components/xiaomi.py index e4a9698c71f70..59fe120ccaf2a 100644 --- a/homeassistant/components/xiaomi.py +++ b/homeassistant/components/xiaomi.py @@ -9,8 +9,8 @@ REQUIREMENTS = ['https://github.com/Danielhiversen/PyXiaomiGateway/archive/' - '877faec36e1bfa4177cae2a0d4f49570af083e1d.zip#' - 'PyXiaomiGateway==0.1.0'] + 'aa9325fe6fdd62a8ef8c9ca1dce31d3292f484bb.zip#' + 'PyXiaomiGateway==0.2.0'] ATTR_GW_SID = 'gw_sid' ATTR_RINGTONE_ID = 'ringtone_id' diff --git a/requirements_all.txt b/requirements_all.txt index 9110795275d34..9275e5ed33271 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -277,7 +277,7 @@ holidays==0.8.1 http://github.com/tgaugry/suds-passworddigest-py3/archive/86fc50e39b4d2b8997481967d6a7fe1c57118999.zip#suds-passworddigest-py3==0.1.2a # homeassistant.components.xiaomi -https://github.com/Danielhiversen/PyXiaomiGateway/archive/877faec36e1bfa4177cae2a0d4f49570af083e1d.zip#PyXiaomiGateway==0.1.0 +https://github.com/Danielhiversen/PyXiaomiGateway/archive/aa9325fe6fdd62a8ef8c9ca1dce31d3292f484bb.zip#PyXiaomiGateway==0.2.0 # homeassistant.components.sensor.dht # https://github.com/adafruit/Adafruit_Python_DHT/archive/da8cddf7fb629c1ef4f046ca44f42523c9cf2d11.zip#Adafruit_DHT==1.3.2 From fada6d3f493ebf39732834a62bc86e281e3d6d6f Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Fri, 21 Jul 2017 10:13:42 +0200 Subject: [PATCH 057/118] Device support for different new sensors of the xiaomi aqara gateway (#8577) * The gateway configuration accepts a MAC address or a SID value in uppercase already. The ringtone services accepts the same values now. I hope it will avoid confusion. * Device support for the new wall switches with neutral lead (ctrl_ln1, ctrl_ln2) added. * Measurement unit from pressure of weather.v1 fixed. * Device support for sensor_magnet.aq2 added. * Device support for sensor_motion.aq2 (motion and lux) added. * Code reformatted. * The ringtone service (start/stop) uses the parameter gw_mac instead of gw_sid now. * Version of the required library updated. --- homeassistant/components/binary_sensor/xiaomi.py | 4 ++++ homeassistant/components/sensor/xiaomi.py | 9 +++++++-- homeassistant/components/switch/xiaomi.py | 13 +++++++++++++ homeassistant/components/xiaomi.py | 16 +++++++++------- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/binary_sensor/xiaomi.py b/homeassistant/components/binary_sensor/xiaomi.py index 216329da9c8b6..2f9d91655b68a 100644 --- a/homeassistant/components/binary_sensor/xiaomi.py +++ b/homeassistant/components/binary_sensor/xiaomi.py @@ -25,8 +25,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): model = device['model'] if model == 'motion': devices.append(XiaomiMotionSensor(device, hass, gateway)) + elif model == 'sensor_motion.aq2': + devices.append(XiaomiMotionSensor(device, hass, gateway)) elif model == 'magnet': devices.append(XiaomiDoorSensor(device, gateway)) + elif model == 'sensor_magnet.aq2': + devices.append(XiaomiDoorSensor(device, gateway)) elif model == 'smoke': devices.append(XiaomiSmokeSensor(device, gateway)) elif model == 'natgas': diff --git a/homeassistant/components/sensor/xiaomi.py b/homeassistant/components/sensor/xiaomi.py index b1fcd8beb1f0f..994a6789bbf12 100644 --- a/homeassistant/components/sensor/xiaomi.py +++ b/homeassistant/components/sensor/xiaomi.py @@ -17,13 +17,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None): 'temperature', gateway)) devices.append(XiaomiSensor(device, 'Humidity', 'humidity', gateway)) - if device['model'] == 'weather.v1': + elif device['model'] == 'weather.v1': devices.append(XiaomiSensor(device, 'Temperature', 'temperature', gateway)) devices.append(XiaomiSensor(device, 'Humidity', 'humidity', gateway)) devices.append(XiaomiSensor(device, 'Pressure', 'pressure', gateway)) + elif device['model'] == 'sensor_motion.aq2': + devices.append(XiaomiSensor(device, 'Illumination', + 'lux', gateway)) elif device['model'] == 'gateway': devices.append(XiaomiSensor(device, 'Illumination', 'illumination', gateway)) @@ -47,6 +50,8 @@ def unit_of_measurement(self): return '%' elif self._data_key == 'illumination': return 'lm' + elif self._data_key == 'lux': + return 'lx' elif self._data_key == 'pressure': return 'hPa' @@ -69,7 +74,7 @@ def parse_data(self, data): return False elif self._data_key == 'pressure' and value == 0: return False - if self._data_key in ['temperature', 'humidity']: + if self._data_key in ['temperature', 'humidity', 'pressure']: value /= 100 elif self._data_key in ['illumination']: value = max(value - 300, 0) diff --git a/homeassistant/components/switch/xiaomi.py b/homeassistant/components/switch/xiaomi.py index fa472136bb504..3e4ea4f6d72b6 100644 --- a/homeassistant/components/switch/xiaomi.py +++ b/homeassistant/components/switch/xiaomi.py @@ -27,6 +27,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(XiaomiGenericSwitch(device, 'Wall Switch', 'channel_0', False, gateway)) + elif model == 'ctrl_ln1': + devices.append(XiaomiGenericSwitch(device, 'Wall Switch LN', + 'channel_0', + False, gateway)) elif model == 'ctrl_neutral2': devices.append(XiaomiGenericSwitch(device, 'Wall Switch Left', 'channel_0', @@ -34,6 +38,15 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(XiaomiGenericSwitch(device, 'Wall Switch Right', 'channel_1', False, gateway)) + elif model == 'ctrl_ln2': + devices.append(XiaomiGenericSwitch(device, + 'Wall Switch LN Left', + 'channel_0', + False, gateway)) + devices.append(XiaomiGenericSwitch(device, + 'Wall Switch LN Right', + 'channel_1', + False, gateway)) elif model == '86plug': devices.append(XiaomiGenericSwitch(device, 'Wall Plug', 'status', True, gateway)) diff --git a/homeassistant/components/xiaomi.py b/homeassistant/components/xiaomi.py index 59fe120ccaf2a..377446a66c8f4 100644 --- a/homeassistant/components/xiaomi.py +++ b/homeassistant/components/xiaomi.py @@ -12,7 +12,7 @@ 'aa9325fe6fdd62a8ef8c9ca1dce31d3292f484bb.zip#' 'PyXiaomiGateway==0.2.0'] -ATTR_GW_SID = 'gw_sid' +ATTR_GW_MAC = 'gw_mac' ATTR_RINGTONE_ID = 'ringtone_id' ATTR_RINGTONE_VOL = 'ringtone_vol' CONF_DISCOVERY_RETRY = 'discovery_retry' @@ -90,12 +90,13 @@ def stop_xiaomi(event): def play_ringtone_service(call): """Service to play ringtone through Gateway.""" - if call.data.get(ATTR_RINGTONE_ID) is None \ - or call.data.get(ATTR_GW_SID) is None: + ring_id = call.data.get(ATTR_RINGTONE_ID) + gw_sid = call.data.get(ATTR_GW_MAC) + if ring_id is None or gw_sid is None: _LOGGER.error("Mandatory parameters is not specified.") return - ring_id = int(call.data.get(ATTR_RINGTONE_ID)) + ring_id = int(ring_id) if ring_id in [9, 14-19]: _LOGGER.error('Specified mid: %s is not defined in gateway.', ring_id) @@ -107,7 +108,7 @@ def play_ringtone_service(call): else: ringtone = {'mid': ring_id, 'vol': int(ring_vol)} - gw_sid = call.data.get(ATTR_GW_SID) + gw_sid = gw_sid.replace(":", "").lower() for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): if gateway.sid == gw_sid: @@ -118,12 +119,13 @@ def play_ringtone_service(call): def stop_ringtone_service(call): """Service to stop playing ringtone on Gateway.""" - gw_sid = call.data.get(ATTR_GW_SID) + gw_sid = call.data.get(ATTR_GW_MAC) if gw_sid is None: _LOGGER.error("Mandatory parameter (%s) is not specified.", - ATTR_GW_SID) + ATTR_GW_MAC) return + gw_sid = gw_sid.replace(":", "").lower() for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): if gateway.sid == gw_sid: ringtone = {'mid': 10000} From ee153062ab3b3d41576ac86ca4d142dd5cb14c58 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Fri, 21 Jul 2017 04:19:26 -0400 Subject: [PATCH 058/118] Extends Fitbit sensors to track the device battery level (#8583) * Extends Fitbit sensors to track the device battery level * cleanup old stuff * remove update from init --- homeassistant/components/sensor/fitbit.py | 73 +++++++++++++++++------ 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/sensor/fitbit.py b/homeassistant/components/sensor/fitbit.py index 80e452e7b3738..0c10d2159eac3 100644 --- a/homeassistant/components/sensor/fitbit.py +++ b/homeassistant/components/sensor/fitbit.py @@ -15,9 +15,9 @@ from homeassistant.core import callback from homeassistant.components.http import HomeAssistantView from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ATTR_ATTRIBUTION from homeassistant.helpers.entity import Entity from homeassistant.loader import get_component -from homeassistant.util import Throttle import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['fitbit==0.2.3'] @@ -32,6 +32,7 @@ ATTR_LAST_SAVED_AT = 'last_saved_at' CONF_MONITORED_RESOURCES = 'monitored_resources' +CONF_ATTRIBUTION = 'Data provided by Fitbit.com' DEPENDENCIES = ['http'] @@ -40,9 +41,7 @@ FITBIT_CONFIG_FILE = 'fitbit.conf' FITBIT_DEFAULT_RESOURCES = ['activities/steps'] -ICON = 'mdi:walk' - -MIN_TIME_BETWEEN_UPDATES = datetime.timedelta(minutes=30) +SCAN_INTERVAL = datetime.timedelta(minutes=30) DEFAULT_CONFIG = { 'client_id': 'CLIENT_ID_HERE', @@ -74,6 +73,7 @@ 'activities/tracker/steps': 'steps', 'body/bmi': 'BMI', 'body/fat': '%', + 'devices/battery': 'level', 'sleep/awakeningsCount': 'times awaken', 'sleep/efficiency': '%', 'sleep/minutesAfterWakeup': 'minutes', @@ -95,6 +95,7 @@ 'body': 'in', 'liquids': 'fl. oz.', 'blood glucose': 'mg/dL', + 'battery': '', }, 'en_GB': { 'duration': 'milliseconds', @@ -104,7 +105,8 @@ 'weight': 'stone', 'body': 'centimeters', 'liquids': 'milliliters', - 'blood glucose': 'mmol/L' + 'blood glucose': 'mmol/L', + 'battery': '', }, 'metric': { 'duration': 'milliseconds', @@ -114,7 +116,8 @@ 'weight': 'kilograms', 'body': 'centimeters', 'liquids': 'milliliters', - 'blood glucose': 'mmol/L' + 'blood glucose': 'mmol/L', + 'battery': '', } } @@ -253,11 +256,20 @@ def setup_platform(hass, config, add_devices, discovery_info=None): authd_client.system = 'en_US' dev = [] + registered_devs = authd_client.get_devices() for resource in config.get(CONF_MONITORED_RESOURCES): - dev.append(FitbitSensor( - authd_client, config_path, resource, - hass.config.units.is_metric)) - add_devices(dev) + + # monitor battery for all linked FitBit devices + if resource == 'devices/battery': + for dev_extra in registered_devs: + dev.append(FitbitSensor( + authd_client, config_path, resource, + hass.config.units.is_metric, dev_extra)) + else: + dev.append(FitbitSensor( + authd_client, config_path, resource, + hass.config.units.is_metric)) + add_devices(dev, True) else: oauth = fitbit.api.FitbitOauth2Client( @@ -348,11 +360,13 @@ def get(self, request): class FitbitSensor(Entity): """Implementation of a Fitbit sensor.""" - def __init__(self, client, config_path, resource_type, is_metric): + def __init__(self, client, config_path, resource_type, + is_metric, extra=None): """Initialize the Fitbit sensor.""" self.client = client self.config_path = config_path self.resource_type = resource_type + self.extra = extra pretty_resource = self.resource_type.replace('activities/', '') pretty_resource = pretty_resource.replace('/', ' ') pretty_resource = pretty_resource.title() @@ -360,6 +374,13 @@ def __init__(self, client, config_path, resource_type, is_metric): pretty_resource = 'BMI' elif pretty_resource == 'Heart': pretty_resource = 'Resting Heart Rate' + elif pretty_resource == 'Devices Battery': + if self.extra: + pretty_resource = \ + '{0} Battery'.format(self.extra.get('deviceVersion')) + else: + pretty_resource = 'Battery' + self._name = pretty_resource unit_type = FITBIT_RESOURCES_LIST[self.resource_type] if unit_type == "": @@ -374,7 +395,6 @@ def __init__(self, client, config_path, resource_type, is_metric): unit_type = measurement_system[split_resource[-1]] self._unit_of_measurement = unit_type self._state = 0 - self.update() @property def name(self): @@ -394,14 +414,33 @@ def unit_of_measurement(self): @property def icon(self): """Icon to use in the frontend, if any.""" - return ICON + if self.resource_type == 'devices/battery': + return 'mdi:battery-50' + return 'mdi:walk' + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attrs = {} + + attrs[ATTR_ATTRIBUTION] = CONF_ATTRIBUTION + + if self.extra: + attrs['model'] = self.extra.get('deviceVersion') + attrs['type'] = self.extra.get('type') + + return attrs - @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Get the latest data from the Fitbit API and update the states.""" - container = self.resource_type.replace("/", "-") - response = self.client.time_series(self.resource_type, period='7d') - self._state = response[container][-1].get('value') + if self.resource_type == 'devices/battery': + response = self.client.get_devices() + self._state = response[0].get('battery') + else: + container = self.resource_type.replace("/", "-") + response = self.client.time_series(self.resource_type, period='7d') + self._state = response[container][-1].get('value') + if self.resource_type == 'activities/heart': self._state = response[container][-1]. \ get('value').get('restingHeartRate') From 4359e0babf74aa6c40a3c6354e6b0d67180f3497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Fri, 21 Jul 2017 12:39:25 +0200 Subject: [PATCH 059/118] xiaomi binary sensor bug fix (#8586) * xiaomi binary sensor bug fig * Is not need on binary_sensor --- homeassistant/components/binary_sensor/xiaomi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/binary_sensor/xiaomi.py b/homeassistant/components/binary_sensor/xiaomi.py index 2f9d91655b68a..fafdc098c5d1a 100644 --- a/homeassistant/components/binary_sensor/xiaomi.py +++ b/homeassistant/components/binary_sensor/xiaomi.py @@ -73,8 +73,8 @@ def should_poll(self): return self._should_poll @property - def state(self): - """Return the state of the sensor.""" + def is_on(self): + """Return true if sensor is on.""" return self._state @property From 06ceadfd543d619bef4fa0aaed5ea1a0c9ff9414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Osb=C3=A4ck?= Date: Fri, 21 Jul 2017 22:35:19 +0200 Subject: [PATCH 060/118] upgrade pywebpush and PyJWT (#8588) --- homeassistant/components/notify/html5.py | 2 +- requirements_all.txt | 4 ++-- requirements_test_all.txt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/notify/html5.py b/homeassistant/components/notify/html5.py index 1fcd2e03898a2..7151b41824845 100644 --- a/homeassistant/components/notify/html5.py +++ b/homeassistant/components/notify/html5.py @@ -25,7 +25,7 @@ from homeassistant.components.frontend import add_manifest_json_key from homeassistant.helpers import config_validation as cv -REQUIREMENTS = ['pywebpush==1.0.5', 'PyJWT==1.5.0'] +REQUIREMENTS = ['pywebpush==1.0.6', 'PyJWT==1.5.2'] DEPENDENCIES = ['frontend'] diff --git a/requirements_all.txt b/requirements_all.txt index 9275e5ed33271..4c9a05aafb34b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -21,7 +21,7 @@ astral==1.4 PyISY==1.0.7 # homeassistant.components.notify.html5 -PyJWT==1.5.0 +PyJWT==1.5.2 # homeassistant.components.sensor.mvglive PyMVGLive==1.1.4 @@ -785,7 +785,7 @@ pyvizio==0.0.2 pyvlx==0.1.3 # homeassistant.components.notify.html5 -pywebpush==1.0.5 +pywebpush==1.0.6 # homeassistant.components.wemo pywemo==0.4.19 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 58fdcecf63c38..491f5574b3221 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -21,7 +21,7 @@ freezegun>=0.3.8 # homeassistant.components.notify.html5 -PyJWT==1.5.0 +PyJWT==1.5.2 # homeassistant.components.media_player.sonos SoCo==0.12 @@ -108,7 +108,7 @@ python-forecastio==1.3.5 pyunifi==2.13 # homeassistant.components.notify.html5 -pywebpush==1.0.5 +pywebpush==1.0.6 # homeassistant.components.python_script restrictedpython==4.0a3 From dc42b6358aa84a8ec7a856c57fd5b01922d5d791 Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Fri, 21 Jul 2017 20:18:57 -0400 Subject: [PATCH 061/118] Support for Wink oauth application authorization (#8208) --- .../www_static/images/config_wink.png | Bin 0 -> 8174 bytes homeassistant/components/wink.py | 321 ++++++++++++++---- 2 files changed, 262 insertions(+), 59 deletions(-) create mode 100644 homeassistant/components/frontend/www_static/images/config_wink.png diff --git a/homeassistant/components/frontend/www_static/images/config_wink.png b/homeassistant/components/frontend/www_static/images/config_wink.png new file mode 100644 index 0000000000000000000000000000000000000000..6b91f8cb58ee80f95c0e2277940b629e23a2cfd3 GIT binary patch literal 8174 zcmcJURZtwfx4_#{ibGo*%2Eo&ip%2A;;_Ktl;RG>-L1GTQhaf1>Egv*7m7o1ch|)i z*vt2y`|_W;5BKHELz0u6WX_zN$;tc@p{yi>hfRU~cfN{o9E8ra_X3m#RtK@R;MSpdos}|HLLmz&<^`8>Gytwa*>AVew zdzwL~opL!0G<S4T=TQ_O!MIe8%4I8)*8qylA&5ZJ2B0kAHTn4Kmfn&%`Z>565rF zkBgu6{Gc3~BlmIYW`MQpPm^Ii?O^8CWX|j~qri;&1a04El&7(x}VRMl48Z zZ;?pkD{)L3p0{W6S|2fKg6nnZ&VyfyTZRT_y%fhBiW?;q$IK;v?e&k2ggE$7!(4U; zizav!7fXaD_+>gxF2kcb_rJ49Qg0VKJi>WrH1~rZI!$ouU%K-$P8<@J`f-hy;^A_j zM!t}L!BpL%Q8la5Yj@RS1Hi_%x6ghA>CK|bNbq-;vzTI8-<;?!=A7D-zi0#67opzb zQ@*0`<)53=_H|>v{h)NilEld7H`tdhQ1{x{B8smRbIS14)^O~V1&xm?LEh23fg@i& zob~;(#8b`6*h()YBHgIuVhBs}46#|97;LEFO{sbmp`3n^hbFdx^6(DqNF1mBer-AZ zRn1F&399^cZF;CJZtYMZ(N-xP14GzCO^-THObvVQvfC36D38qtV_Umn2klQ+-WB(5 zj?!;Ti~z-?8l*L8<4FQUM=b%H3*JnF{bttIKU#o+hxxTtywl~Z&x+^2e$GggDMYM| z3?s0;=NVE4?hJ5x5?jof`v0sHlsGl!hcr%8GO@bkstb1|>@!pei$v5dce*+@M(A3- zWQO~pu-UU>8IW1e^Vl7&QnKZ}C5SbaJh-@DD@!XH;F2o3q3wdAO%#IWrao#&FtkRG zT{vlyR8|g4`Ru7`nq{2K?f+bAcvbApouQSk@|sJ#rt=%0p&X<-YtB~?Rod{_8LcH_wZwd?_0)PrX)W@ZODoQPY|Q*uVeNt3LZdAa z8&510X*`F|hcOVvSht&&QWI%rPBmQgb?;AlpHIO?QwJxYS4%4z9{+ zqnnP3u%qVGPZ2m*Snvf4MoGWvNHZO}I30>PM(nBZfy%PmgTy%#4el1YOTh}wKuWjw znd0j^RyD4qg~WJo1g5Y8L>;ujIFlD_=RfzEm@15)^!2sp=?wJF$sf%2u<(3oV4oLs z5~ztuXZXcwmK2xt^0z9_!SB@?*w%K))hmoR^WHi)!buJMD(u7{-C%gN0@*zO*QXeh zu8$j1e$Gx2t{>9GMHkB{nTz!{deQ4JMX5CJiLYvgFzRP7WHfQWC>#!~0jp|R!>c)B zoGVG|smlvar=&QmtA1=Gs9UMlKzbD;IYrDG@_&$}mzNLFsjAstB0)4LJ$?P`dTef3R%8uO_ELe?V$4=(qUdi)~&MJrv zbt>^Chv^vMKRjQxE9ys2hJ|eJh0sL6h(ubqe4iikQjBn|+Rz3bZb@7O4qF;}xS`Rb ztsrpSg_I=cZ`y^~lLqP9KGYa@+dNmNekh&`zu$5kS5_IETL?UwhAuplXC}aR&%k%1 zCE<#*HF%w-CJ%Em?`}7ccZ)2`iGDJpJkd~;e>iRX!wuuWi8(Ec|81P1&CW(Zb|8V zPY|bkNJ^jG6r%SY9c><}^|7A~xl^_uw;BAynrvQlR(ER@G3NS5VtThDTg@)k-*mm_ zOj?w?2+_BYI{_|q-JTFuuZ2w1u@&w_$n-VzODWDy2tU+XJ0t`B^sadd+uY;puU|!K zE`!$KLf0L!CN$QLcQx5(gHKc2t|@&c$)vUGJ&QLS0VrFch%4d2UIu_^yghXx`p8)m zSkcthD=SZ+U6DXd`?Rgz{kG7u3G}PQoNyj$UWLdubk%&l7tbvJAzdYcHs6E$hUBdy zafW|uU|9A=Hru-koF|9s_H*Kd{VW3pLsh2KwIwk`>euMm9ST+Nv7#IqzY10y2Ju+y zj#|B^iFrReYs#+E2{nX#EK&eApFF!ELG7qo+1p_#bYnFAa^q8}tj60fAs!^pA5l1T zSP=&|_qQpd=g(s5Gq5dpvk*=JJNw+!SXksBh1IPIja&G_0KVZ+Y-TF2Ewf@M&H|QI zQ!tW|k@+nxzOqQY5R~V*)O4DYN)D7jW~Yz3-zu`QezkdFH%R`WZ^U3o^;c|iBkT82 zkt|}5LE?A{p_7bC$V7Xi54m+D7PQux?@bvAhJO3@?^RWdy6LU%VlX|g-vPe5g)0+r ztVi+&@mY7thO=4hum~SU9kGfz$WW@^>j;GD25l1f{H48U&h0gqW~JRC7i>?|O}HUG z(7PkTQY=7;LLM|*Tu|}OpLZZ(RrZh`yA~hakAE|`#F~Fz^hS58ED$4$HkYn>Sf=k+iW@8wg|IxbaL@_0ma3IC zV`2T2l#Q3Dro_rK=HYbaSTb%;qtzb<_=tv6qjpO&&ozqZ7aw~FS=xK66;hwg52b4j zV#7_;ZSS6H1ZD3|OsmDcBK1N4q~&E~JFR&|2hqS=c)q7L6~i*%-}V!*kSaHHmBBzu z{suC(vh#6>Ba~Ov0+WA>$n`|rr*+*$QjbW1Np8pbaAr;;VMr7T#8x z(5QF_G~QTBRD`Ds8i&!(wKjza>R?=%-O?A_Kk-TSk;k5RHVoI}DXnnI=8V24Dk-xv zvO&_hq)D*H^X^l3u1znFPhJApk1Y!de#hTrjHh9__%}n$6*hcm$JjqcFWd~#@gL;e z5b3&Km;Y!Kx*mRqDofGnYxt1dST|x2WfgVw-jl45LE*P7p&SlUr0UD$1v4gd_upIrA=Ho>b0KMPtivgZ9slHJ-fE1+kr zKk%N>Xo`5(AcEL5;Epi6fK@r?J{atZlPsME=4R2B#32-ow1jH1{#iu`spDE z<(c2FY*=~cgn}x=cf%X$3gThb-Aj9+9;CHE+2Mg+HT}?`U89JOh*GM-fkEgt31$l~ zF$&{Tz6ya7>hN?8#%68;5=yP=tBBUk@XuVp7h+?9Ro&`=aB;Lz0|sjomyJyT^)2D&@X^-{7&z5I!7W@GqWoFYK z_D@ZbDWy$b&zf+_JZpC$utW8_aA^)9W@2u$-Y!{Lc$|U;yAzg70i=RF`SY!wt7ISE?eec4q}oX-zc0OA84dLk{^?B-ly3yf=W!ISzI#g-eJsV) z73Q#0Mf8`S>RM1hWX-F{=`6p^NkPu^0WanD!>g1IDf@4vT88zWb0>LSWFAvb>NBhy zbo!|pL-3*aiA_JF83t^~R1uyuVnLN*ujgj8rej6lLkeC#E$G(f7?W)pfS}TkRi`hHkPPW<#uf?%}B;7 z{o`uog43(b^&r<2M78vH62>k|E6~y2KAT}4yN5*9+2M#Xr<>6~` z$bfxbi@r`!^soh{LgOLCY>!+F+s1a}n#Pa006`8CuR zlrU@sx%(SK9cvA8Do5b_`E0O%!Zq~eyr`UFWF4Q1OTZsF*Bk=I+fX8wddK>h!G>Ak zYeMk(*fit)aFEYo@L~nSKIPR*{znoZymSgD-*0@7<;2vE ze(YEwFQw;qV+3{KHaz@y_H-h@=jJ|Te{A+U_fwlcd_$WBBfi4ZmwgHrihWxg0pG0C zcjv|%J}D7RHiRqdRuLyoD=C%|X3j=pg$CZm|k8N?}(@v)StwLBDlH|S4LsYS7Yxd*hX~%xKLjYYQ34?=Od(pb@ z(#>dh-u%!YwC^&FMbKs@eZ7Jn4uJw1e>s0w`@BXc#0to6i7oNX>@FgW>BN<&$n%F{- ziTIK~nRv^HmoBc7Ib@I3?7OUGk|Fe-orlL+E zES3}WgOy^PjH}QvrnGPgJ()O2uWpNI@Stn#C++)-&e(>yHLgCLF9V4+n}1n6@j-^j z)N1WCb+D)QtHR;J0{UyqS+$;534J39A5TNZ{EUuF^ak2*>RDI;DJ`*czL}|2*m9hq z4cX#U(+1=IeW~OqdBlULMQQzBc zUQ-GSnlHFugk)$EJfM@K53G4tes7VItBi^f%A!Fq-_3Q-5DliK(Iro-wf6Tk+V;>P z!Kgm$?t}+PK<_Pc$-w?eZ!fp~?u)6ibMLO9^@7>4Z>JNQ&1^WJFePkAkThzS!&A@p zI>02RCi)>yUikJq&mfw?n|#-0P7YQx*eWF?A6+IYBNqT%?{xjXp{1;?)|2c-O&^s+ zOnKI)lsaS9$@SOHjyRmw?lw)clm<#Eph4cXi#Xv}3UG5Q;49cPK(V`T6+V|v%vSg(wDI>gE_-)Gqv44I~o zbF4Ow52@7%Ir|ye!%NiG2MgAXXvQwt-doa9tt2&#wji$Z*qLr3P5VB|>#vwbzn3E& z_Tu|W@Id^UdJ-C*RIM|Ts+uA)4+$NlnVk#Z?b7`p#o#vEa?7{X8=~~ zvfxy*FnlWGj&JBGZ7a1DQ=+vP`&+gfisMZ}G{FJ=Tt)xDFx?mbh0FRS`WMT&`Xwnl!^LXm?-w^-g7x~>tt=~eUjwIFwO&8L7#({0AV^ssVXND978FYH1wr2aR~ z;l2*bXCEz&vGH3BLZ^m)&9&Rsfwt}&wK`Yd-OD{Jrwez2$Q;1FT=cPW2UKc=`Q1AMz73BzVt7PUjiPID;cW0Hz-0%7Ym~`6N z$1+(>@QC#eoW<@HCkcrv8>m%$Jv=P&9}0cobw>i>X<86M-Y3xbj^*zcQ0AsmBR}vK+ai{a7P22wit)LG&ImqvL({ z)A@1K+ifofcKch-azC!Df0oxLlvRzYrHY6Fgn{}Z2l&^S8EECR{EEU+c9`53L{vFW zs(2K+P@iq>BkvvUJ@8YqR9|c68|&n=_j9u-s}r-w=vL6z(!1I^@YYO3%%j#O6~#7Y zGOwJD4^J8QIPu#S`WpKc-nV1Eg9Qxtvyj@F#%cH&f`qXzKqvoIsedM*1Wd1Hk7>9-S5X2yDlLb%tBrj+30!i>REx23*DB0dt*9Itwuj_OhmRey)W<8ualFMdM!<0)>OwdWW7M-MqrA2J zEM*Btrw&Q2Z+z*e)a}j8(5brxL*n)>dt32?wO0qZbFvpPL>Y{acc`lmS$Hkzw;pWO zeH%4k_L=6$G%Ri3)LW}-Z@#1~<@vt@6URQW4X!ThnfHUBL4ATIU)pI(Kg!FA6FAQN zvbciVYp>}9JL-m^7MEN9qMhqPjgb!q*fW!v7X7xzO#w+))u>|;7c`d}k7{I|wUA#W z=bce}AOQ*awP9|S*aBe4R*xC=RqJM;kdd7$VS#M@KI1UkAaBy(2uNg{ z5XaeK-Dfb@bd%lwrb!8YR?nzh^b%Ru`YO<41?6f2$)?cfD=tqtWLTYIXX?IFG((Er z_9@nLT`7#o(?zv%n0e@qlZ7M!iu`v>{M~u#q`(e=jf~h^x;n*w%9Rv>LWtliy9nrBJnj$*JO`WP6ZyLfY( zn-98XH{N>P2lr6zW6vPBkr3{YkjSy8lF>e&;L}}G1WMfdr6UnD^F4WDKWBnmazkNY z!>ghZcwU{7+D+P@GZa#w4&9A4RPBhI8oib++FOjFs6)a|hrO#QFJ*iA^dzy`VWo>L z+JBE`aM4BOTW#*k=~V0eON{|9pul|YQw2QNb;cwf3AyI^F$Rr;V!C} zcTV@W+y1tNRXD$CcDocnKuqOdZ^Az~?6;&?X@T8z9BEXEZ-|{_u-oP1VEWlW!8ba> z%Z(uxx4_|#YxY4=6?b@RIzVt+?-q8NvHAc7mZ)bp3&Tl8-JJex}cnwc9orndy4Gj02V ztJ5w3>!ma$wj*o8Xp^~QLj238u^p$3H7Rq10bnC!j6-cx$|8f;v!#P*W6!={I$}r& zUUQ9hZCex<${SVWXDyDMh{p*AGxCm`(zWWvo29<>uqZo{WOR^DLwE;_?*8gJt zkfa+-f4vb(19d_M^hHn#afe>}RycKjm7pp6boOq5ccb>2tQAl%)8un-w3E9f*{($% z;Aw!rj|6fj)Ktvp2^~k>nu@+@#=n_ z*qoWnkXncjAs5uM*9?1fBCN@NWtmetr1%2RYAu9Tx66U_@_6_WDWU|KW#3_F6kYu; zv>!F*L&-jXno-=zju$rCDy_F(3Ic2wO0J(1$H9xUF)Bv~$T*ng;I5&R2B z@JSoR9>D#?H+L`nTC;@tHOXTG{u7X3ujy3n>WjPg0+HQ_K|&$!bb_PsOG-EeNDL{q zn=2$O(?R;I@vKPl%+lxiVzD|!C>QUS)u9kh7EO(0>hpwoe6UV_!z79k$0ExyT;*Lu zmVOorJ~|C7I&q22q6Qxpu2iIy^CBJKiiN9F0jDKcskX)qr0&i2>FC=FDe`IDmy=2E_|~X zDz59jVQ;VhYlA=uho+nHf1khq&hPC1m1+N-oPOtTNJE{Y!iSiA{J?)AC#57=CT{rc Fe*h|;;rsvq literal 0 HcmV?d00001 diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 7024291e7fe44..58a6f51b67b95 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -7,15 +7,21 @@ import logging import time import json +import os from datetime import timedelta import voluptuous as vol +import requests +from homeassistant.loader import get_component +from homeassistant.core import callback +from homeassistant.components.http import HomeAssistantView from homeassistant.helpers import discovery from homeassistant.helpers.event import track_time_interval from homeassistant.const import ( - CONF_ACCESS_TOKEN, ATTR_BATTERY_LEVEL, CONF_EMAIL, CONF_PASSWORD, - EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) + ATTR_BATTERY_LEVEL, CONF_EMAIL, CONF_PASSWORD, + EVENT_HOMEASSISTANT_START, + EVENT_HOMEASSISTANT_STOP, __version__) from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv @@ -23,11 +29,10 @@ _LOGGER = logging.getLogger(__name__) -CHANNELS = [] - DOMAIN = 'wink' SUBSCRIPTION_HANDLER = None + CONF_CLIENT_ID = 'client_id' CONF_CLIENT_SECRET = 'client_secret' CONF_USER_AGENT = 'user_agent' @@ -37,8 +42,24 @@ CONF_MISSING_OATH_MSG = 'Missing oath2 credentials.' CONF_TOKEN_URL = "https://winkbearertoken.appspot.com/token" +ATTR_ACCESS_TOKEN = 'access_token' +ATTR_REFRESH_TOKEN = 'refresh_token' +ATTR_CLIENT_ID = 'client_id' +ATTR_CLIENT_SECRET = 'client_secret' + +WINK_AUTH_CALLBACK_PATH = '/auth/wink/callback' +WINK_AUTH_START = '/auth/wink' +WINK_CONFIG_FILE = '.wink.conf' +USER_AGENT = "Manufacturer/Home-Assistant%s python/3 Wink/3" % (__version__) + +DEFAULT_CONFIG = { + 'client_id': 'CLIENT_ID_HERE', + 'client_secret': 'CLIENT_SECRET_HERE' +} + SERVICE_ADD_NEW_DEVICES = 'add_new_devices' SERVICE_REFRESH_STATES = 'refresh_state_from_wink' +SERVICE_KEEP_ALIVE = 'keep_pubnub_updates_flowing' CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -52,11 +73,6 @@ msg=CONF_MISSING_OATH_MSG): cv.string, vol.Exclusive(CONF_EMAIL, CONF_OATH, msg=CONF_DEFINED_BOTH_MSG): cv.string, - vol.Exclusive(CONF_ACCESS_TOKEN, CONF_OATH, - msg=CONF_DEFINED_BOTH_MSG): cv.string, - vol.Exclusive(CONF_ACCESS_TOKEN, CONF_APPSPOT, - msg=CONF_DEFINED_BOTH_MSG): cv.string, - vol.Optional(CONF_USER_AGENT, default=None): cv.string }) }, extra=vol.ALLOW_EXTRA) @@ -66,30 +82,118 @@ ] +def _write_config_file(file_path, config): + try: + with open(file_path, 'w') as conf_file: + conf_file.write(json.dumps(config, sort_keys=True, indent=4)) + except IOError as error: + _LOGGER.error("Saving config file failed: %s", error) + raise IOError("Saving Wink config file failed") + return config + + +def _read_config_file(file_path): + try: + with open(file_path, 'r') as conf_file: + return json.loads(conf_file.read()) + except IOError as error: + _LOGGER.error("Reading config file failed: %s", error) + raise IOError("Reading Wink config file failed") + + +def _request_app_setup(hass, config): + """Assist user with configuring the Wink dev application.""" + hass.data['configurator'] = True + configurator = get_component('configurator') + + # pylint: disable=unused-argument + def wink_configuration_callback(callback_data): + """Handle configuration updates.""" + _config_path = hass.config.path(WINK_CONFIG_FILE) + if not os.path.isfile(_config_path): + setup(hass, config) + return + + client_id = callback_data.get('client_id') + client_secret = callback_data.get('client_secret') + if None not in (client_id, client_secret): + _write_config_file(_config_path, + {ATTR_CLIENT_ID: client_id, + ATTR_CLIENT_SECRET: client_secret}) + setup(hass, config) + return + else: + error_msg = ("Your input was invalid. Please try again.") + _configurator = hass.data[DOMAIN]['configuring'][DOMAIN] + configurator.notify_errors(_configurator, error_msg) + + start_url = "{}{}".format(hass.config.api.base_url, + WINK_AUTH_CALLBACK_PATH) + + description = """Please create a Wink developer app at + https://developer.wink.com. + Add a Redirect URI of {}. + They will provide you a Client ID and secret + after reviewing your request. + (This can take several days). + """.format(start_url) + + hass.data[DOMAIN]['configuring'][DOMAIN] = configurator.request_config( + hass, DOMAIN, wink_configuration_callback, + description=description, submit_caption="submit", + description_image="/static/images/config_wink.png", + fields=[{'id': 'client_id', 'name': 'Client ID', 'type': 'string'}, + {'id': 'client_secret', + 'name': 'Client secret', + 'type': 'string'}] + ) + + +def _request_oauth_completion(hass, config): + """Request user complete Wink OAuth2 flow.""" + hass.data['configurator'] = True + configurator = get_component('configurator') + if DOMAIN in hass.data[DOMAIN]['configuring']: + configurator.notify_errors( + hass.data[DOMAIN]['configuring'][DOMAIN], + "Failed to register, please try again.") + return + + # pylint: disable=unused-argument + def wink_configuration_callback(callback_data): + """Call setup again.""" + setup(hass, config) + + start_url = '{}{}'.format(hass.config.api.base_url, WINK_AUTH_START) + + description = "Please authorize Wink by visiting {}".format(start_url) + + hass.data[DOMAIN]['configuring'][DOMAIN] = configurator.request_config( + hass, DOMAIN, wink_configuration_callback, + description=description + ) + + def setup(hass, config): """Set up the Wink component.""" import pywink - import requests from pubnubsubhandler import PubNubSubscriptionHandler - hass.data[DOMAIN] = {} - hass.data[DOMAIN]['entities'] = [] - hass.data[DOMAIN]['unique_ids'] = [] - hass.data[DOMAIN]['entities'] = {} - - user_agent = config[DOMAIN].get(CONF_USER_AGENT) - - if user_agent: - pywink.set_user_agent(user_agent) - - access_token = config[DOMAIN].get(CONF_ACCESS_TOKEN) - client_id = config[DOMAIN].get('client_id') + if hass.data.get(DOMAIN) is None: + hass.data[DOMAIN] = { + 'unique_ids': [], + 'entities': {}, + 'oauth': {}, + 'configuring': {}, + 'pubnub': None, + 'configurator': False + } def _get_wink_token_from_web(): - email = hass.data[DOMAIN]["oath"]["email"] - password = hass.data[DOMAIN]["oath"]["password"] + _email = hass.data[DOMAIN]["oauth"]["email"] + _password = hass.data[DOMAIN]["oauth"]["password"] - payload = {'username': email, 'password': password} + payload = {'username': _email, 'password': _password} token_response = requests.post(CONF_TOKEN_URL, data=payload) try: token = token_response.text.split(':')[1].split()[0].rstrip('Wink Auth +

{}

""" + + if data.get('code') is not None: + response = self.request_token(data.get('code'), + self.config_file["client_secret"]) + + config_contents = { + ATTR_ACCESS_TOKEN: response['access_token'], + ATTR_REFRESH_TOKEN: response['refresh_token'], + ATTR_CLIENT_ID: self.config_file["client_id"], + ATTR_CLIENT_SECRET: self.config_file["client_secret"] + } + _write_config_file(hass.config.path(WINK_CONFIG_FILE), + config_contents) + + hass.async_add_job(setup, hass, self.config) + + return web.Response(text=html_response.format(response_message), + content_type='text/html') + + error_msg = "No code returned from Wink API" + _LOGGER.error(error_msg) + return web.Response(text=html_response.format(error_msg), + content_type='text/html') + + class WinkDevice(Entity): """Representation a base Wink device.""" From 8d31c5fbf63cff82baf2a0f509ffebd0556199ae Mon Sep 17 00:00:00 2001 From: Russell Cloran Date: Fri, 21 Jul 2017 21:22:43 -0700 Subject: [PATCH 062/118] zha: Update to bellows 0.3.4 (#8594) --- homeassistant/components/zha/__init__.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index e397b7d042a3b..1b2d46ee72b03 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -14,7 +14,7 @@ from homeassistant.helpers import discovery, entity from homeassistant.util import slugify -REQUIREMENTS = ['bellows==0.3.2'] +REQUIREMENTS = ['bellows==0.3.4'] DOMAIN = 'zha' diff --git a/requirements_all.txt b/requirements_all.txt index 4c9a05aafb34b..6bfc3a70ee63f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -92,7 +92,7 @@ batinfo==0.4.2 beautifulsoup4==4.6.0 # homeassistant.components.zha -bellows==0.3.2 +bellows==0.3.4 # homeassistant.components.blink blinkpy==0.6.0 From 7bea69ce83c1bec8f25d9cb86780906598c0e7c5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 21 Jul 2017 21:29:58 -0700 Subject: [PATCH 063/118] update frontend --- homeassistant/components/frontend/version.py | 13 +++++++------ .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 138122 -> 138190 bytes .../www_static/home-assistant-polymer | 2 +- .../www_static/panels/ha-panel-config.html | 2 +- .../www_static/panels/ha-panel-config.html.gz | Bin 15104 -> 15074 bytes .../www_static/panels/ha-panel-hassio.html | 2 +- .../www_static/panels/ha-panel-hassio.html.gz | Bin 378 -> 409 bytes .../www_static/panels/ha-panel-iframe.html | 2 +- .../www_static/panels/ha-panel-iframe.html.gz | Bin 403 -> 407 bytes .../www_static/panels/ha-panel-map.html | 2 +- .../www_static/panels/ha-panel-map.html.gz | Bin 44245 -> 44197 bytes .../panels/ha-panel-shopping-list.html | 1 + .../panels/ha-panel-shopping-list.html.gz | Bin 0 -> 5303 bytes .../www_static/panels/ha-panel-zwave.html | 2 +- .../www_static/panels/ha-panel-zwave.html.gz | Bin 10611 -> 10543 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2484 -> 2485 bytes 18 files changed, 16 insertions(+), 14 deletions(-) create mode 100644 homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html create mode 100644 homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 67c8bbac8170b..6ab94fe5a789a 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -3,21 +3,22 @@ FINGERPRINTS = { "compatibility.js": "8e4c44b5f4288cc48ec1ba94a9bec812", "core.js": "d4a7cb8c80c62b536764e0e81385f6aa", - "frontend.html": "a7d4cb8260e8094342b5bd8c36c4bf5b", + "frontend.html": "7bd9aa75b2602768e66cf7e20845d7c4", "mdi.html": "e91f61a039ed0a9936e7ee5360da3870", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-automation.html": "72a5c1856cece8d9246328e84185ab0b", - "panels/ha-panel-config.html": "76853de505d173e82249bf605eb73505", + "panels/ha-panel-config.html": "c0e043028cfa75d6d4dc5e0de0bb6dc1", "panels/ha-panel-dev-event.html": "4886c821235492b1b92739b580d21c61", "panels/ha-panel-dev-info.html": "24e888ec7a8acd0c395b34396e9001bc", "panels/ha-panel-dev-service.html": "ac2c50e486927dc4443e93d79f08c06e", "panels/ha-panel-dev-state.html": "8f1a27c04db6329d31cfcc7d0d6a0869", "panels/ha-panel-dev-template.html": "82cd543177c417e5c6612e07df851e6b", - "panels/ha-panel-hassio.html": "262d31efd9add719e0325da5cf79a096", + "panels/ha-panel-hassio.html": "96d563215cf7bf7b0eeaf8625bafa4ef", "panels/ha-panel-history.html": "35177e2046c9a4191c8f51f8160255ce", - "panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab", + "panels/ha-panel-iframe.html": "238189f21e670b6dcfac937e5ebd7d3b", "panels/ha-panel-kiosk.html": "2ac2df41bd447600692a0054892fc094", "panels/ha-panel-logbook.html": "7c45bd41c146ec38b9938b8a5188bb0d", - "panels/ha-panel-map.html": "d3dae1400ec4e4cd7681d2aa79131d55", - "panels/ha-panel-zwave.html": "2ea2223339d1d2faff478751c2927d11" + "panels/ha-panel-map.html": "b4923812c695dd8a69ad3da380ffe7b4", + "panels/ha-panel-shopping-list.html": "75602d06b41702c8093bd91c10374101", + "panels/ha-panel-zwave.html": "8c8e7844d33163f560e1f691550a8369" } diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 41e9975e8b3a3..3205a1d7d4f40 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -2,4 +2,4 @@ this._useContent&&u.Logical.saveChildNodes(this)},_setupRoot:function(){this._useContent&&(this._createLocalRoot(),this.dataHost||l(u.Logical.getChildNodes(this)))},_createLocalRoot:function(){this.shadyRoot=this.root,this.shadyRoot._distributionClean=!1,this.shadyRoot._hasDistributed=!1,this.shadyRoot._isShadyRoot=!0,this.shadyRoot._dirtyRoots=[];var e=this.shadyRoot._insertionPoints=!this._notes||this._notes._hasContent?this.shadyRoot.querySelectorAll("content"):[];u.Logical.saveChildNodes(this.shadyRoot);for(var t,o=0;o0?~setTimeout(e,t):(this._twiddle.textContent=this._twiddleContent++,this._callbacks.push(e),this._currVal++)},cancel:function(e){if(e<0)clearTimeout(~e);else{var t=e-this._lastVal;if(t>=0){if(!this._callbacks[t])throw"invalid async handle: "+e;this._callbacks[t]=null}}},_atEndOfMicrotask:function(){for(var e=this._callbacks.length,t=0;t \ No newline at end of file +return performance.now()};else var t=function(){return Date.now()};var e=function(t,e,i){this.target=t,this.currentTime=e,this.timelineTime=i,this.type="cancel",this.bubbles=!1,this.cancelable=!1,this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},i=window.Element.prototype.animate;window.Element.prototype.animate=function(n,r){var o=i.call(this,n,r);o._cancelHandlers=[],o.oncancel=null;var a=o.cancel;o.cancel=function(){a.call(this);var i=new e(this,null,t()),n=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){n.forEach(function(t){t.call(i.target,i)})},0)};var s=o.addEventListener;o.addEventListener=function(t,e){"function"==typeof e&&"cancel"==t?this._cancelHandlers.push(e):s.call(this,t,e)};var u=o.removeEventListener;return o.removeEventListener=function(t,e){if("cancel"==t){var i=this._cancelHandlers.indexOf(e);i>=0&&this._cancelHandlers.splice(i,1)}else u.call(this,t,e)},o}}}(),function(t){var e=document.documentElement,i=null,n=!1;try{var r=getComputedStyle(e).getPropertyValue("opacity"),o="0"==r?"1":"0";i=e.animate({opacity:[o,o]},{duration:1}),i.currentTime=0,n=getComputedStyle(e).getPropertyValue("opacity")==o}catch(t){}finally{i&&i.cancel()}if(!n){var a=window.Element.prototype.animate;window.Element.prototype.animate=function(e,i){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&e[Symbol.iterator]&&(e=Array.from(e)),Array.isArray(e)||null===e||(e=t.convertToArrayForm(e)),a.call(this,e,i)}}}(c),function(t,e,i){function n(t){var i=e.timeline;i.currentTime=t,i._discardAnimations(),0==i._animations.length?o=!1:requestAnimationFrame(n)}var r=window.requestAnimationFrame;window.requestAnimationFrame=function(t){return r(function(i){e.timeline._updateAnimationsPromises(),t(i),e.timeline._updateAnimationsPromises()})},e.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},e.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){e.animationsWithPromises=e.animationsWithPromises.filter(function(t){return t._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(t){return"finished"!=t.playState&&"idle"!=t.playState})},_play:function(t){var i=new e.Animation(t,this);return this._animations.push(i),e.restartWebAnimationsNextTick(),i._updatePromises(),i._animation.play(),i._updatePromises(),i},play:function(t){return t&&t.remove(),this._play(t)}};var o=!1;e.restartWebAnimationsNextTick=function(){o||(o=!0,requestAnimationFrame(n))};var a=new e.AnimationTimeline;e.timeline=a;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return a}})}catch(t){}try{window.document.timeline=a}catch(t){}}(0,e),function(t,e,i){e.animationsWithPromises=[],e.Animation=function(e,i){if(this.id="",e&&e._id&&(this.id=e._id),this.effect=e,e&&(e._animation=this),!i)throw new Error("Animation with null timeline is not supported");this._timeline=i,this._sequenceNumber=t.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},e.Animation.prototype={_updatePromises:function(){var t=this._oldPlayState,e=this.playState;return this._readyPromise&&e!==t&&("idle"==e?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==t?this._resolveReadyPromise():"pending"==e&&(this._readyPromise=void 0)),this._finishedPromise&&e!==t&&("idle"==e?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==e?this._resolveFinishedPromise():"finished"==t&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var t,i,n,r,o=!!this._animation;o&&(t=this.playbackRate,i=this._paused,n=this.startTime,r=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=e.newUnderlyingAnimationForKeyframeEffect(this.effect),e.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=e.newUnderlyingAnimationForGroup(this.effect),e.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&e.bindAnimationForCustomEffect(this),o&&(1!=t&&(this.playbackRate=t),null!==n?this.startTime=n:null!==r?this.currentTime=r:null!==this._holdTime&&(this.currentTime=this._holdTime),i&&this.pause()),this._updatePromises()},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var t=this.effect._timing.delay;this._childAnimations.forEach(function(i){this._arrangeChildren(i,t),this.effect instanceof window.SequenceEffect&&(t+=e.groupChildDuration(i.effect))}.bind(this))}},_setExternalAnimation:function(t){if(this.effect&&this._isGroup)for(var e=0;e \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index c04830c01a9ce36c9f3097e754d9c329a70302df..baceb29a98504762bb696a9090a16641c8b8df42 100644 GIT binary patch delta 68674 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Ξ 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 7c079dc01f03d..c7be840a9d73b 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 7c079dc01f03d7599762df1ac8c6eab8e4b90004 +Subproject commit c7be840a9d73b6a32a0d74b1a5c0fb4475018d75 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html index 5e6cf7b6483a1..e54ba31fb3e47 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html.gz index 8c4cf065663ca29a6f33975991002d845e796bcc..a0745b91349ec77b3bb8846abb57ad2bba6a624f 100644 GIT binary patch delta 1068 zcmV+{1k?L~cH(skABzY8000000t2xhq&6_BVSPI&z8(=-OP5bq=_W5qeYeKO2HsBY zO5vd1EI%rblH+4u$M71NwZ6P7LwT%|@-`@c3U$kL61CbdWaERZoma}dp}Yk{-q%jI zqwA}L>9m@pVoQabiWeoW!D73V>us<^M05vY6ItULN*5m%dRRx+B~R6S%EnmYjmBSo8{GsOr_^$qSC^D zE@fF~pEk-`V=t$-Em}=3mH?)>yJvda7G7h1Z-M~IzFdP{yD2GBGrqxB%etGcQz<1KK4V$YzN&|ulhRcU z1GN1*r-z580OojoU%Rm}&xAuf4&JYM>r@GJ7tFGUz~;bWg)H%`QDW0-lm2b>|%a|%j&;>tCNaH?f)Mql`XOUNMDufc<#o1uAmJU2>*ZRw6Yyh zydg{)*jT`v#p~`(fdBhWD!J~rWCKhJdeIw)_R*dwxmN3~a_M~f?ip^D^RBxJ8NoCM z{c&}`fO1tWiy0VB;+vj|TKK+?IJ3B*J$j8>0sKJuTGb+ICt{q$J&KiocIe;8^(ILs zOE`?vcR8;|j|T|a0!1mu``}GH55)ZJuRkoud;tGHjf-U!fOagmjAhgXN~j*kMq(cq z;+)R6xhAMBfE~I`PJ>h+2B1QceW-`j+v3=nDAD)}rCbSS00EJA3Vz^gnp(&irCEo> z$=0jTsKVMaxdEO<8)$V>f zV}zR{PezNSAL2LKFO^^OEof9?%yPE5$IU#h-#B0Hl6gA83d2LU#x?!_M&bTd#MAQd zbjqoCmv5{!eIC8;S`zWT^_FK&%iAR<&eC=Gy2C|g$cAQC=c?XgTDJEI%2SmGj)9SX z;F1_v&_={%kQ;|;#ZEq`-6nEU4my@YvEwR>ZJ@rSWO0qUY=-Yb)LhV$a#tx8lF@|H mjzjH?^o=SEp8Q(;tZOwEP`pzUd9j+L+y4i=*;upR&;S6rnjgLZ delta 1098 zcmV-Q1hxC(b%1ssABzYGxHVW=0t0AaEpTCOWo#{DZ*FF3XD(=TZEOIs3ZynKD*ZM< zNw+pe*3#wERl3OweJg0Pv4OXfyHYr)H_MOk#erj9$NW3M)R%WAa ztZ@yci<2xHbQ&n~uJ3-Z)w~D1s_y}}>1Z-4kwBO7VOWdq8hwNO=E)}CH?J>`US6r_ zsubi+XPq*TM%O4SFb9M$Sa!32ygHGo^x#Y+EbLO6b@pnbtTp;_g4@E?BUe?brgk- zVeNif;li=jZ=T8AwiE4t$T2Lijs-mlt@cEfydQBqpTlyla+?jJtKBH+L^JDr-e273 zCzH5MpO>sSXyG$~S`7POuhx=2>GGRB+TlgG@0D|3VZHsk_b)(qzm3Ll4!5#&&m47%$~n9crBGH^>EKyWhh7pS_Z1j)=K>8kWhN$7b?cme7xagn%#Uzd{daX! z@u>a(quL=c;f#_jD#x9g4KKsrEsVUF9M6uf6Z)c2fd*sPzvGhYcNBgDnY`z7JN{m^~ zHg~z1$Mq}c%bhY$Cs<*4=;pYl|KBLwzlwNT9-dA)74PznwWiOb*Ii2@-nZWJ%xU?% zY zawv9OWw8y^my|57QJ2l|U5J_sdQ$Exr9v{AP}*^*-I2agg~5|wi=TC^#sZ4BY9cRI QlXUz40Ow(HP~p%30IMo5l>h($ diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html b/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html index f339403019b8f..2ec3ee876b9dc 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html.gz index 6a1c2905cf0087ed1d383c04a1cd8ff53c21f228..03b8a09f320d02b2f305c7298c4a974c64d689d7 100644 GIT binary patch literal 409 zcmV;K0cQRmiwFP!0000217%XdZrd;n{S{TG1h8Z5HW-e94O@}Rumat734(yN7)XO8 zdJ^5tNd51V?4~KOlc-1X@jXh7W@p<*BdE4<$RIimAtG<(&mZ^YN7**jl6)dHwv8fJ zI#Pp0VboS?D0}c|OARp^O4W?6x4_sokw=T|UK^#*A1=zolo)GI9`B6nDKL1Rnrf+Q z7KYM+@gm1tx!>pWaFD`72z1WK5@jrEI+qUpkl}p!mg1ZUG%#jx4ib_r+{n}Irm?#D zNrJmzdTt-cjt;}>Vq*QD!J-e;V_<`^zGSTa{`4C=E*4?+XCjN>i>shFU=~wfc> zY{;+Hm$UJT&YRt*$H(KBufJYiSev+6USOAIuVe+id7WO(Ze`&IYm0XzV3X;Uya!`Z z2_})12-YZesc&OQ%#Gp{$cZ?l6+N3sVI$YmdYabhm6zo<)$)(3`QQBm?Ez(aegXgh Dn#jvt literal 378 zcmV-=0fqh_iwFP!0000217%XdYTPgo{S`&0U9i{W7L3=>(uTc+1k(1hEM;QNA_Ylf zq;VGG_}?qpO}5aJX5PFR-WyG$+1a+y2&!!yGKfw?h{${S^T&O8C)=i4i!Y?cwo&9t zM{2MrjM_^LWe*;0sUb!~iOuMG3yf_Od9>IbwNVQFX;LPp!dQFqcw<~ofx+|KR4cDp zCzKA17dhU`<1xRdlN268pi4&9C}UC6rF7_r4Cmw_#kmk@V9ekWBqUq74o}%tV|DeD z1b4yo+&+;V9fr+hV*Q`Nq7T$#V1u!qGFCsnykf`2Dy;rWWD$JvA?OoW#C(t~fkIVJ zJofm>cmq3NeRDg{1u#RW6XQJijt%+EcDfj^=(0O}d4B%=?fb9ych)BE)9f`yHPw0!)p9<60L~?vHbnve055p9ga7~l diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html b/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html index ff2cdbfe4b4b1..7e7c2afd61aa0 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-iframe.html.gz index ef8727a2ea39a8df7dc1bd2a637ca81ccf735756..afa1e40bf9d16e54864d7f0ac4ae47beeb6ec8db 100644 GIT binary patch literal 407 zcmV;I0cidoiwFP!0000219ei%Zrd;r{1t*gfdnuk7buECp?K&ax1c?=C&LGdTw84T z0=cT=8v6HAWCA07+;(SXwL2Q}37r*u0;vUefRd<5rVKdH@82HSCn|W?$T8@%;5s%ap=tpu1hG_Ipb5 z6i!vN!fW$b>O!o(-b@#7<|lE|c!maTxtNOGuDZLcz<$rWA}ND!ZfI^uPHNrI^eXs+ zIo{35))S=HV|X5@w6+{`2+3vA>KNi2uZ{5tiP@l@UZ7k)%|bFq<6jY#OvFrEdzh^) z2!J0brWq(X!T4nGKcox4{>>Cq%||J&33k`COPqDF_!{ilLAtq^-2WB-CZ-S}p@H0A zD$`%^9HIX*{s4u`rseVielEWdq+d3#vHXEA%Wa9ht>s;Ne_egAzX26DNJh2-001~t B#c%)s literal 403 zcmV;E0c`#siwFoNO`})>1889_aA9s`Y%OVKa$#*{E@*UZYyf3a!D<^Z5d9UgP)NYa zx=>2l$U5YZTWJsN$@rj^#$L6OMo6=DjM;y$R!T5wZ!>S+Xx^KVn8-URCQwES52To$ zRLVfR?&ptZ{-u+mZ^aSKMGAwSdo;5HX3egf6pt!^j8ed~L+S9|FT$P}L8S!P;Dd&oqBPO3&izCK4-Vz%K5_hP7 zze2e@%`w@N4R44}Hd0>ox5*{A?YzI;ryQVC<#%)!59#h|^YGunHZfs@L>BUJt(Dthis.options.maxZoom?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,z(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},invalidateSize:function(t){if(!this._loaded)return this;t=i({animate:!1,pan:!0},!0===t?{animate:!0}:t);var n=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var o=this.getSize(),s=n.divideBy(2).round(),r=o.divideBy(2).round(),a=s.subtract(r);return a.x||a.y?(t.animate&&t.pan?this.panBy(a):(t.pan&&this._rawPanBy(a),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(e(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:n,newSize:o})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){if(t=this._locateOptions=i({timeout:1e4,watch:!1},t),!("geolocation"in navigator))return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var n=e(this._handleGeolocationResponse,this),o=e(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(n,o,t):navigator.geolocation.getCurrentPosition(n,o,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var i=t.code,e=t.message||(1===i?"permission denied":2===i?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:i,message:"Geolocation error: "+e+"."})},_handleGeolocationResponse:function(t){var i=t.coords.latitude,e=t.coords.longitude,n=new M(i,e),o=n.toBounds(t.coords.accuracy),s=this._locateOptions;if(s.setView){var r=this.getBoundsZoom(o);this.setView(n,s.maxZoom?Math.min(r,s.maxZoom):r)}var a={latlng:n,bounds:o,timestamp:t.timestamp};for(var h in t.coords)"number"==typeof t.coords[h]&&(a[h]=t.coords[h]);this.fire("locationfound",a)},addHandler:function(t,i){if(!i)return this;var e=this[t]=new i(this);return this._handlers.push(e),this.options[t]&&e.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}ut(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this._loaded&&this.fire("unload");var t;for(t in this._layers)this._layers[t].remove();for(t in this._panes)ut(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,i){var e="leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),n=ht("div",e,i||this._mapPane);return t&&(this._panes[t]=n),n},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new T(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,i,e){t=z(t),e=w(e||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),a=t.getSouthEast(),h=this.getSize().subtract(e),u=b(this.project(a,n),this.project(r,n)).getSize(),l=Ki?this.options.zoomSnap:1,c=h.x/u.x,_=h.y/u.y,d=i?Math.max(c,_):Math.min(c,_);return n=this.getScaleZoom(d,n),l&&(n=Math.round(n/(l/100))*(l/100),n=i?Math.ceil(n/l)*l:Math.floor(n/l)*l),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new x(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,i){var e=this._getTopLeftPoint(t,i);return new P(e,e.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,i){var e=this.options.crs;return i=void 0===i?this._zoom:i,e.scale(t)/e.scale(i)},getScaleZoom:function(t,i){var e=this.options.crs;i=void 0===i?this._zoom:i;var n=e.zoom(t*e.scale(i));return isNaN(n)?1/0:n},project:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.latLngToPoint(C(t),i)},unproject:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.pointToLatLng(w(t),i)},layerPointToLatLng:function(t){var i=w(t).add(this.getPixelOrigin());return this.unproject(i)},latLngToLayerPoint:function(t){return this.project(C(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(C(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(z(t))},distance:function(t,i){return this.options.crs.distance(C(t),C(i))},containerPointToLayerPoint:function(t){return w(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return w(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var i=this.containerPointToLayerPoint(w(t));return this.layerPointToLatLng(i)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(C(t)))},mouseEventToContainerPoint:function(t){return tt(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var i=this._container=rt(t);if(!i)throw new Error("Map container not found.");if(i._leaflet_id)throw new Error("Map container is already initialized.");V(i,"scroll",this._onScroll,this),this._containerId=n(i)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&Ki,pt(t,"leaflet-container"+(te?" leaflet-touch":"")+(ne?" leaflet-retina":"")+(Bi?" leaflet-oldie":"")+(Wi?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var i=at(t,"position");"absolute"!==i&&"relative"!==i&&"fixed"!==i&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Lt(this._mapPane,new x(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(pt(t.markerPane,"leaflet-zoom-hide"),pt(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,i){Lt(this._mapPane,new x(0,0));var e=!this._loaded;this._loaded=!0,i=this._limitZoom(i),this.fire("viewprereset");var n=this._zoom!==i;this._moveStart(n)._move(t,i)._moveEnd(n),this.fire("viewreset"),e&&this.fire("load")},_moveStart:function(t){return t&&this.fire("zoomstart"),this.fire("movestart")},_move:function(t,i,e){void 0===i&&(i=this._zoom);var n=this._zoom!==i;return this._zoom=i,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(n||e&&e.pinch)&&this.fire("zoom",e),this.fire("move",e)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return g(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Lt(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={},this._targets[n(this._container)]=this;var i=t?G:V;i(this._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress",this._handleDOMEvent,this),this.options.trackResize&&i(window,"resize",this._onResize,this),Ki&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){g(this._resizeRequest),this._resizeRequest=f(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,o=[],s="mouseout"===i||"mouseover"===i,r=t.target||t.srcElement,a=!1;r;){if((e=this._targets[n(r)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){a=!0;break}if(e&&e.listens(i,!0)){if(s&&!ot(r,t))break;if(o.push(e),s)break}if(r===this._container)break;r=r.parentNode}return o.length||a||s||!ot(r,t)||(o=[this]),o},_handleDOMEvent:function(t){if(this._loaded&&!nt(t)){var i=t.type;"mousedown"!==i&&"keypress"!==i||zt(t.target||t.srcElement),this._fireDOMEvent(t,i)}},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,n){if("click"===t.type){var o=i({},t);o.type="preclick",this._fireDOMEvent(o,o.type,n)}if(!t._stopped&&(n=(n||[]).concat(this._findEventTargets(t,e)),n.length)){var s=n[0];"contextmenu"===e&&s.listens(e,!0)&&$(t);var r={originalEvent:t};if("keypress"!==t.type){var a=s.options&&"icon"in s.options;r.containerPoint=a?this.latLngToContainerPoint(s.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=a?s.getLatLng():this.layerPointToLatLng(r.layerPoint)}for(var h=0;h0?Math.round(t-i)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(i))},_limitZoom:function(t){var i=this.getMinZoom(),e=this.getMaxZoom(),n=Ki?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(i,Math.min(e,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){mt(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,i){var e=this._getCenterOffset(t)._floor();return!(!0!==(i&&i.animate)&&!this.getSize().contains(e)||(this.panBy(e,i),0))},_createAnimProxy:function(){var t=this._proxy=ht("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(t){var i=Pe,e=this._proxy.style[i];wt(this._proxy,this.project(t.center,t.zoom),this.getZoomScale(t.zoom,1)),e===this._proxy.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",function(){var t=this.getCenter(),i=this.getZoom();wt(this._proxy,this.project(t,i),this.getZoomScale(i,1))},this),this._on("unload",this._destroyAnimProxy,this)},_destroyAnimProxy:function(){ut(this._proxy),delete this._proxy},_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,i,e){if(this._animatingZoom)return!0;if(e=e||{},!this._zoomAnimated||!1===e.animate||this._nothingToAnimate()||Math.abs(i-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o)||(f(function(){this._moveStart(!0)._animateZoom(t,i,!0)},this),0))},_animateZoom:function(t,i,n,o){n&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,pt(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:o}),setTimeout(e(this._onZoomTransitionEnd,this),250)},_onZoomTransitionEnd:function(){this._animatingZoom&&(mt(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),f(function(){this._moveEnd(!0)},this))}}),ke=v.extend({options:{position:"topright"},initialize:function(t){l(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return pt(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this},remove:function(){return this._map?(ut(this._container),this.onRemove&&this.onRemove(this._map),this._map=null,this):this},_refocusOnMap:function(t){this._map&&t&&t.screenX>0&&t.screenY>0&&this._map.getContainer().focus()}}),Be=function(t){return new ke(t)};Se.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){function t(t,o){var s=e+t+" "+e+o;i[t+o]=ht("div",s,n)}var i=this._controlCorners={},e="leaflet-",n=this._controlContainer=ht("div",e+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){for(var t in this._controlCorners)ut(this._controlCorners[t]);ut(this._controlContainer),delete this._controlCorners,delete this._controlContainer}});var Ie=ke.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,i,e,n){return e1,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=i&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var i=this._getLayer(n(t.target)),e=i.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;e&&this._map.fire(e,i)},_createRadioElement:function(t,i){var e='",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),o=this._map.hasLayer(t.layer);t.overlay?(i=document.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=o):i=this._createRadioElement("leaflet-base-layers",o),this._layerControlInputs.push(i),i.layerId=n(t.layer),V(i,"click",this._onInputClick,this);var s=document.createElement("span");s.innerHTML=" "+t.name;var r=document.createElement("div");return e.appendChild(r),r.appendChild(i),r.appendChild(s),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e,n=this._layerControlInputs,o=[],s=[];this._handlingClick=!0;for(var r=n.length-1;r>=0;r--)t=n[r],i=this._getLayer(t.layerId).layer,e=this._map.hasLayer(i),t.checked&&!e?o.push(i):!t.checked&&e&&s.push(i);for(r=0;r=0;o--)t=e[o],i=this._getLayer(t.layerId).layer,t.disabled=void 0!==i.options.minZoom&&ni.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),Ae=function(t,i,e){return new Ie(t,i,e)},Oe=ke.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=ht("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=ht("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),J(s),V(s,"click",Q),V(s,"click",o,this),V(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";mt(this._zoomInButton,i),mt(this._zoomOutButton,i),(this._disabled||t._zoom===t.getMinZoom())&&pt(this._zoomOutButton,i),(this._disabled||t._zoom===t.getMaxZoom())&&pt(this._zoomInButton,i)}});Se.mergeOptions({zoomControl:!0}),Se.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new Oe,this.addControl(this.zoomControl))});var Re=function(t){return new Oe(t)},De=ke.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=ht("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=ht("div",i,e)),t.imperial&&(this._iScale=ht("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;o>5280?(i=o/5280,e=this._getRoundNum(i),this._updateScale(this._iScale,e+" mi",e/i)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,i,e){t.style.width=Math.round(this.options.maxWidth*e)+"px",t.innerHTML=i},_getRoundNum:function(t){var i=Math.pow(10,(Math.floor(t)+"").length-1),e=t/i;return e=e>=10?10:e>=5?5:e>=3?3:e>=2?2:1,i*e}}),Ne=function(t){return new De(t)},je=ke.extend({options:{position:"bottomright",prefix:'Leaflet'},initialize:function(t){l(this,t),this._attributions={}},onAdd:function(t){t.attributionControl=this,this._container=ht("div","leaflet-control-attribution"),J(this._container);for(var i in t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Se.mergeOptions({attributionControl:!0}),Se.addInitHook(function(){this.options.attributionControl&&(new je).addTo(this)});var We=function(t){return new je(t)};ke.Layers=Ie,ke.Zoom=Oe,ke.Scale=De,ke.Attribution=je,Be.layers=Ae,Be.zoom=Re,Be.scale=Ne,Be.attribution=We;var He,Fe=v.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled?this:(this._enabled=!0,this.addHooks(),this)},disable:function(){return this._enabled?(this._enabled=!1,this.removeHooks(),this):this},enabled:function(){return!!this._enabled}}),Ue={Events:xi},Ve=!1,Ge=te?"touchstart mousedown":"mousedown",qe={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},Ke={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},Ye=wi.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){l(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(V(this._dragStartTarget,Ge,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(L.Draggable._dragging===this&&this.finishDrag(),G(this._dragStartTarget,Ge,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!dt(this._element,"leaflet-zoom-anim")&&!(Ve||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||(Ve=this,this._preventOutline&&zt(this._element),bt(),zi(),this._moving)))){this.fire("down");var i=t.touches?t.touches[0]:t;this._startPoint=new x(i.clientX,i.clientY),V(document,Ke[t.type],this._onMove,this),V(document,qe[t.type],this._onUp,this)}},_onMove:function(t){if(!t._simulated&&this._enabled){if(t.touches&&t.touches.length>1)return void(this._moved=!0);var i=t.touches&&1===t.touches.length?t.touches[0]:t,e=new x(i.clientX,i.clientY),n=e.subtract(this._startPoint);(n.x||n.y)&&(Math.abs(n.x)+Math.abs(n.y)1e-7;h++)i=s*Math.sin(a),i=Math.pow((1-i)/(1+i),s/2),u=Math.PI/2-2*Math.atan(r*i)-a,a+=u;return new M(a*e,t.x*e/n)}},tn=(Object.freeze||Object)({LonLat:$e,Mercator:Qe,SphericalMercator:bi}),en=i({},Pi,{code:"EPSG:3395",projection:Qe,transformation:function(){var t=.5/(Math.PI*Qe.R);return E(t,.5,-t,.5)}()}),nn=i({},Pi,{code:"EPSG:4326",projection:$e,transformation:E(1/180,1,-1/180,.5)}),on=i({},Li,{projection:$e,transformation:E(1,0,-1,0),scale:function(t){return Math.pow(2,t)},zoom:function(t){return Math.log(t)/Math.LN2},distance:function(t,i){var e=i.lng-t.lng,n=i.lat-t.lat;return Math.sqrt(e*e+n*n)},infinite:!0});Li.Earth=Pi,Li.EPSG3395=en,Li.EPSG3857=Zi,Li.EPSG900913=Ei,Li.EPSG4326=nn,Li.Simple=on;var sn=wi.extend({options:{pane:"overlayPane",attribution:null,bubblingMouseEvents:!0},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[n(t)]=this,this}, removeInteractiveTarget:function(t){return delete this._map._targets[n(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var i=t.target;if(i.hasLayer(this)){if(this._map=i,this._zoomAnimated=i._zoomAnimated,this.getEvents){var e=this.getEvents();i.on(e,this),this.once("remove",function(){i.off(e,this)},this)}this.onAdd(i),this.getAttribution&&i.attributionControl&&i.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),i.fire("layeradd",{layer:this})}}});Se.include({addLayer:function(t){var i=n(t);return this._layers[i]?this:(this._layers[i]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this)},removeLayer:function(t){var i=n(t);return this._layers[i]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[i],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null,this):this},hasLayer:function(t){return!!t&&n(t)in this._layers},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},_addLayers:function(t){t=t?pi(t)?t:[t]:[];for(var i=0,e=t.length;ithis._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()i)return r=(n-i)/e,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,i){return i=i||this._defaultShape(),t=C(t),i.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new T,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return jt(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var i=[],e=jt(t),n=0,o=t.length;n=2&&i[0]instanceof M&&i[0].equals(i[e-1])&&i.pop(),i},_setLatLngs:function(t){gn.prototype._setLatLngs.call(this,t),jt(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return jt(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,i=this.options.weight,e=new x(i,i);if(t=new P(t.min.subtract(e),t.max.add(e)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t)){if(this.options.noClip)return void(this._parts=this._rings);for(var n,o=0,s=this._rings.length;ot.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||gn.prototype._containsPoint.call(this,t,!0)}}),yn=hn.extend({initialize:function(t,i){l(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=pi(t)?t:t.features;if(o){for(i=0,e=o.length;io?(i.height=o+"px",pt(t,s)):mt(t,s),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),e=this._getAnchor();Lt(this._container,i.add(e))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,i=parseInt(at(this._container,"marginBottom"),10)||0,e=this._container.offsetHeight+i,n=this._containerWidth,o=new x(this._containerLeft,-e-this._containerBottom);o._add(Pt(this._container));var s=t.layerPointToContainerPoint(o),r=w(this.options.autoPanPadding),a=w(this.options.autoPanPaddingTopLeft||r),h=w(this.options.autoPanPaddingBottomRight||r),u=t.getSize(),l=0,c=0;s.x+n+h.x>u.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c])}},_onCloseButtonClick:function(t){this._close(),Q(t)},_getAnchor:function(){return w(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}}),Mn=function(t,i){return new zn(t,i)};Se.mergeOptions({closePopupOnClick:!0}),Se.include({openPopup:function(t,i,e){return t instanceof zn||(t=new zn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),sn.include({bindPopup:function(t,i){return t instanceof zn?(l(t,i),this._popup=t,t._source=this):(this._popup&&!i||(this._popup=new zn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){if(t instanceof sn||(i=t,t=this),t instanceof hn)for(var e in this._layers){t=this._layers[e];break}return i||(i=t.getCenter?t.getCenter():t.getLatLng()),this._popup&&this._map&&(this._popup._source=t,this._popup.update(),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;if(this._popup&&this._map)return Q(t),i instanceof pn?void this.openPopup(t.layer||t.target,t.latlng):void(this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var Cn=Tn.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Tn.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Tn.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Tn.prototype.getEvents.call(this);return te&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=ht("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i=this._map,e=this._container,n=i.latLngToContainerPoint(i.getCenter()),o=i.layerPointToContainerPoint(t),s=this.options.direction,r=e.offsetWidth,a=e.offsetHeight,h=w(this.options.offset),u=this._getAnchor();"top"===s?t=t.add(w(-r/2+h.x,-a+h.y+u.y,!0)):"bottom"===s?t=t.subtract(w(r/2-h.x,-h.y,!0)):"center"===s?t=t.subtract(w(r/2+h.x,a/2-u.y+h.y,!0)):"right"===s||"auto"===s&&o.xthis.options.maxZoom||en&&this._retainParent(o,s,r,n))},_retainChildren:function(t,i,e,n){for(var o=2*t;o<2*t+2;o++)for(var s=2*i;s<2*i+2;s++){var r=new x(o,s);r.z=e+1;var a=this._tileCoordsToKey(r),h=this._tiles[a];h&&h.active?h.retain=!0:(h&&h.loaded&&(h.retain=!0),e+1this.options.maxZoom||void 0!==this.options.minZoom&&o1)return void this._setView(t,e);for(var c=o.min.y;c<=o.max.y;c++)for(var _=o.min.x;_<=o.max.x;_++){var d=new x(_,c);d.z=this._tileZoom,this._isValidTile(d)&&(this._tiles[this._tileCoordsToKey(d)]||r.push(d))}if(r.sort(function(t,i){return t.distanceTo(s)-i.distanceTo(s)}),0!==r.length){this._loading||(this._loading=!0,this.fire("loading"));var p=document.createDocumentFragment();for(_=0;_e.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return z(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToBounds:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e),s=i.unproject(n,t.z),r=i.unproject(o,t.z),a=new T(s,r);return this.options.noWrap||i.wrapLatLngBounds(a),a},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new x(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ut(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){pt(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=r,t.onmousemove=r,Bi&&this.options.opacity<1&&vt(t,this.options.opacity),Oi&&!Ri&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var n=this._getTilePos(t),o=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),e(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&f(e(this._tileReady,this,t,null,s)),Lt(s,n),this._tiles[o]={el:s,coords:t,current:!0},i.appendChild(s),this.fire("tileloadstart",{tile:s,coords:t})},_tileReady:function(t,i,n){if(this._map){i&&this.fire("tileerror",{error:i,tile:n,coords:t});var o=this._tileCoordsToKey(t);(n=this._tiles[o])&&(n.loaded=+new Date,this._map._fadeAnimated?(vt(n.el,0),g(this._fadeFrame),this._fadeFrame=f(this._updateOpacity,this)):(n.active=!0,this._pruneTiles()),i||(pt(n.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:n.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),Bi||!this._map._fadeAnimated?f(this._pruneTiles,this):setTimeout(e(this._pruneTiles,this),250)))}},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new x(this._wrapX?s(t.x,this._wrapX):t.x,this._wrapY?s(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new P(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}}),kn=Sn.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,i=l(this,i),i.detectRetina&&ne&&i.maxZoom>0&&(i.tileSize=Math.floor(i.tileSize/2),i.zoomReverse?(i.zoomOffset--,i.minZoom++):(i.zoomOffset++,i.maxZoom--),i.minZoom=Math.max(0,i.minZoom)),"string"==typeof i.subdomains&&(i.subdomains=i.subdomains.split("")),Oi||this.on("tileunload",this._onTileRemove)},setUrl:function(t,i){return this._url=t,i||this.redraw(),this},createTile:function(t,i){var n=document.createElement("img");return V(n,"load",e(this._tileOnLoad,this,i,n)),V(n,"error",e(this._tileOnError,this,i,n)),this.options.crossOrigin&&(n.crossOrigin=""),n.alt="",n.setAttribute("role","presentation"),n.src=this.getTileUrl(t),n},getTileUrl:function(t){var e={r:ne?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var n=this._globalTileRange.max.y-t.y;this.options.tms&&(e.y=n),e["-y"]=n}return _(this._url,i(e,this.options))},_tileOnLoad:function(t,i){Bi?setTimeout(e(t,this,null,i),0):t(null,i)},_tileOnError:function(t,i,e){var n=this.options.errorTileUrl;n&&i.src!==n&&(i.src=n),t(e,i)},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,i=this.options.maxZoom,e=this.options.zoomReverse,n=this.options.zoomOffset;return e&&(t=i-t),t+n},_getSubdomain:function(t){var i=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[i]},_abortLoading:function(){var t,i;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&(i=this._tiles[t].el,i.onload=r,i.onerror=r,i.complete||(i.src=mi,ut(i)))}}),Bn=kn.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var n=i({},this.defaultWmsParams);for(var o in e)o in this.options||(n[o]=e[o]);e=l(this,e),n.width=n.height=e.tileSize*(e.detectRetina&&ne?2:1),this.wmsParams=n},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var i=this._wmsVersion>=1.3?"crs":"srs";this.wmsParams[i]=this._crs.code,kn.prototype.onAdd.call(this,t)},getTileUrl:function(t){var i=this._tileCoordsToBounds(t),e=this._crs.project(i.getNorthWest()),n=this._crs.project(i.getSouthEast()),o=(this._wmsVersion>=1.3&&this._crs===nn?[n.y,e.x,e.y,n.x]:[e.x,n.y,n.x,e.y]).join(","),s=kn.prototype.getTileUrl.call(this,t);return s+c(this.wmsParams,s,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+o},setParams:function(t,e){return i(this.wmsParams,t),e||this.redraw(),this}});kn.WMS=Bn,si.wms=ri;var In=sn.extend({options:{padding:.1},initialize:function(t){l(this,t),n(this),this._layers=this._layers||{}},onAdd:function(){this._container||(this._initContainer(),this._zoomAnimated&&pt(this._container,"leaflet-zoom-animated")),this.getPane().appendChild(this._container),this._update(),this.on("update",this._updatePaths,this)},onRemove:function(){this.off("update",this._updatePaths,this),this._destroyContainer()},getEvents:function(){var t={viewreset:this._reset,zoom:this._onZoom,moveend:this._update,zoomend:this._onZoomEnd};return this._zoomAnimated&&(t.zoomanim=this._onAnimZoom),t},_onAnimZoom:function(t){this._updateTransform(t.center,t.zoom)},_onZoom:function(){this._updateTransform(this._map.getCenter(),this._map.getZoom())},_updateTransform:function(t,i){var e=this._map.getZoomScale(i,this._zoom),n=Pt(this._container),o=this._map.getSize().multiplyBy(.5+this.options.padding),s=this._map.project(this._center,i),r=this._map.project(t,i),a=r.subtract(s),h=o.multiplyBy(-e).add(n).add(o).subtract(a);Ki?wt(this._container,h,e):Lt(this._container,h)},_reset:function(){this._update(),this._updateTransform(this._center,this._zoom);for(var t in this._layers)this._layers[t]._reset()},_onZoomEnd:function(){for(var t in this._layers)this._layers[t]._project()},_updatePaths:function(){for(var t in this._layers)this._layers[t]._update()},_update:function(){var t=this.options.padding,i=this._map.getSize(),e=this._map.containerPointToLayerPoint(i.multiplyBy(-t)).round();this._bounds=new P(e,e.add(i.multiplyBy(1+2*t)).round()),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}}),An=In.extend({getEvents:function(){var t=In.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){In.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=document.createElement("canvas");V(t,"mousemove",o(this._onMouseMove,32,this),this),V(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this),V(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_destroyContainer:function(){delete this._ctx,ut(this._container),G(this._container),delete this._container},_updatePaths:function(){if(!this._postponeUpdatePaths){var t;this._redrawBounds=null;for(var i in this._layers)t=this._layers[i],t._update();this._redraw()}},_update:function(){if(!this._map._animatingZoom||!this._bounds){this._drawnLayers={},In.prototype._update.call(this);var t=this._bounds,i=this._container,e=t.getSize(),n=ne?2:1;Lt(i,t.min),i.width=n*e.x,i.height=n*e.y,i.style.width=e.x+"px",i.style.height=e.y+"px",ne&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_reset:function(){In.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t),this._layers[n(t)]=t;var i=t._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=i),this._drawLast=i,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var i=t._order,e=i.next,n=i.prev;e?e.prev=n:this._drawLast=n,n?n.next=e:this._drawFirst=e,delete t._order,delete this._layers[L.stamp(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if(t.options.dashArray){var i,e=t.options.dashArray.split(","),n=[];for(i=0;i')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),Rn={_initContainer:function(){this._container=ht("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(In.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=On("shape");pt(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=On("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[n(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ut(i),t.removeInteractiveTarget(i),delete this._layers[n(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i||(i=t._stroke=On("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=pi(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e||(e=t._fill=On("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){ct(t._container)},_bringToBack:function(t){_t(t._container)}},Dn=re?On:S,Nn=In.extend({getEvents:function(){var t=In.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=Dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=Dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ut(this._container),G(this._container),delete this._container,delete this._rootGroup},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){In.prototype._update.call(this);var t=this._bounds,i=t.getSize(),e=this._container;this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),Lt(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update")}},_initPath:function(t){var i=t._path=Dn("path");t.options.className&&pt(i,t.options.className),t.options.interactive&&pt(i,"leaflet-interactive"),this._updateStyle(t),this._layers[n(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ut(t._path),t.removeInteractiveTarget(t._path),delete this._layers[n(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,k(t._parts,i))},_updateCircle:function(t){var i=t._point,e=t._radius,n=t._radiusY||e,o="a"+e+","+n+" 0 1,0 ",s=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+o+2*e+",0 "+o+2*-e+",0 ";this._setPath(t,s)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){ct(t._path)},_bringToBack:function(t){_t(t._path)}});re&&Nn.include(Rn),Se.include({getRenderer:function(t){var i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return i||(i=this._renderer=this.options.preferCanvas&&ai()||hi()),this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=Nn&&hi({pane:t})||An&&ai({pane:t}),this._paneRenderers[t]=i),i}});var jn=vn.extend({initialize:function(t,i){vn.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return t=z(t),[t.getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Nn.create=Dn,Nn.pointsToPath=k,yn.geometryToLayer=Kt,yn.coordsToLatLng=Yt,yn.coordsToLatLngs=Xt,yn.latLngToCoords=Jt,yn.latLngsToCoords=$t,yn.getFeature=Qt,yn.asFeature=ti,Se.mergeOptions({boxZoom:!0});var Wn=Fe.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){V(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){G(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ut(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){return!(!t.shiftKey||1!==t.which&&1!==t.button)&&(this._clearDeferredResetState(),this._resetState(),zi(),bt(),this._startPoint=this._map.mouseEventToContainerPoint(t),void V(document,{contextmenu:Q,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this))},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=ht("div","leaflet-zoom-box",this._container),pt(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new P(this._point,this._startPoint),e=i.getSize();Lt(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ut(this._box),mt(this._container,"leaflet-crosshair")),Mi(),Tt(),G(document,{contextmenu:Q,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(e(this._resetState,this),0);var i=new T(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Se.addInitHook("addHandler","boxZoom",Wn),Se.mergeOptions({doubleClickZoom:!0});var Hn=Fe.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Se.addInitHook("addHandler","doubleClickZoom",Hn),Se.mergeOptions({dragging:!0,inertia:!Ri,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var Fn=Fe.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new Ye(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}pt(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){mt(this._map._container,"leaflet-grab"),mt(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t=this._map;if(t._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var i=z(this._map.options.maxBounds);this._offsetLimit=b(this._map.latLngToContainerPoint(i.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(i.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(i),i-this._times[0]>50&&(this._positions.shift(),this._times.shift())}this._map.fire("move",t).fire("drag",t)},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),i=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=i.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,i){return t-(t-i)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),i=this._offsetLimit;t.xi.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){ -var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)0?s:-s))-i;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(i+r):t.setZoomAround(this._lastMousePos,i+r))}});Se.addInitHook("addHandler","scrollWheelZoom",Vn),Se.mergeOptions({tap:!0,tapTolerance:15});var Gn=Fe.extend({addHooks:function(){V(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){G(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if($(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new x(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&pt(n,"leaflet-active"),this._holdTimeout=setTimeout(e(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),V(document,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),G(document,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],e=i.target;e&&e.tagName&&"a"===e.tagName.toLowerCase()&&mt(e,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var i=t.touches[0];this._newPos=new x(i.clientX,i.clientY),this._simulateEvent("mousemove",i)},_simulateEvent:function(t,i){var e=document.createEvent("MouseEvents");e._simulated=!0,i.target._simulatedClick=!0,e.initMouseEvent(t,!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),i.target.dispatchEvent(e)}});te&&!Qi&&Se.addInitHook("addHandler","tap",Gn),Se.mergeOptions({touchZoom:te&&!Ri,bounceAtZoomLimits:!0});var qn=Fe.extend({addHooks:function(){pt(this._map._container,"leaflet-touch-zoom"),V(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){mt(this._map._container,"leaflet-touch-zoom"),G(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(e.add(n)._divideBy(2))),this._startDist=e.distanceTo(n),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),V(document,"touchmove",this._onTouchMove,this),V(document,"touchend",this._onTouchEnd,this),$(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var i=this._map,n=i.mouseEventToContainerPoint(t.touches[0]),o=i.mouseEventToContainerPoint(t.touches[1]),s=n.distanceTo(o)/this._startDist;if(this._zoom=i.getScaleZoom(s,this._startZoom),!i.options.bounceAtZoomLimits&&(this._zoomi.getMaxZoom()&&s>1)&&(this._zoom=i._limitZoom(this._zoom)),"center"===i.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=n._add(o)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=i.unproject(i.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(i._moveStart(!0),this._moved=!0),g(this._animRequest);var a=e(i._move,i,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=f(a,this,!0),$(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,g(this._animRequest),G(document,"touchmove",this._onTouchMove),G(document,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}});Se.addInitHook("addHandler","touchZoom",qn),Se.BoxZoom=Wn,Se.DoubleClickZoom=Hn,Se.Drag=Fn,Se.Keyboard=Un,Se.ScrollWheelZoom=Vn,Se.Tap=Gn,Se.TouchZoom=qn;var Kn=window.L;window.L=t,t.version="1.1.0",t.noConflict=li,t.Control=ke,t.control=Be,t.Browser=ae,t.Evented=wi,t.Mixin=Ue,t.Util=yi,t.Class=v,t.Handler=Fe,t.extend=i,t.bind=e,t.stamp=n,t.setOptions=l,t.DomEvent=Le,t.DomUtil=Ze,t.PosAnimation=Ee,t.Draggable=Ye,t.LineUtil=Xe,t.PolyUtil=Je,t.Point=x,t.point=w,t.Bounds=P,t.bounds=b,t.Transformation=Z,t.transformation=E,t.Projection=tn,t.LatLng=M,t.latLng=C,t.LatLngBounds=T,t.latLngBounds=z,t.CRS=Li,t.GeoJSON=yn,t.geoJSON=ii,t.geoJson=wn,t.Layer=sn,t.LayerGroup=rn,t.layerGroup=an,t.FeatureGroup=hn,t.featureGroup=un,t.ImageOverlay=Ln,t.imageOverlay=Pn,t.VideoOverlay=bn,t.videoOverlay=ei,t.DivOverlay=Tn,t.Popup=zn,t.popup=Mn,t.Tooltip=Cn,t.tooltip=Zn,t.Icon=ln,t.icon=Ht,t.DivIcon=En,t.divIcon=ni,t.Marker=dn,t.marker=Ft,t.TileLayer=kn,t.tileLayer=si,t.GridLayer=Sn,t.gridLayer=oi,t.SVG=Nn,t.svg=hi,t.Renderer=In,t.Canvas=An,t.canvas=ai,t.Path=pn,t.CircleMarker=mn,t.circleMarker=Ut,t.Circle=fn,t.circle=Vt,t.Polyline=gn,t.polyline=Gt,t.Polygon=vn,t.polygon=qt,t.Rectangle=jn,t.rectangle=ui,t.Map=Se,t.map=Ct}) \ No newline at end of file +var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)0?s:-s))-i;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(i+r):t.setZoomAround(this._lastMousePos,i+r))}});Se.addInitHook("addHandler","scrollWheelZoom",Vn),Se.mergeOptions({tap:!0,tapTolerance:15});var Gn=Fe.extend({addHooks:function(){V(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){G(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if($(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new x(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&pt(n,"leaflet-active"),this._holdTimeout=setTimeout(e(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),V(document,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),G(document,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],e=i.target;e&&e.tagName&&"a"===e.tagName.toLowerCase()&&mt(e,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var i=t.touches[0];this._newPos=new x(i.clientX,i.clientY),this._simulateEvent("mousemove",i)},_simulateEvent:function(t,i){var e=document.createEvent("MouseEvents");e._simulated=!0,i.target._simulatedClick=!0,e.initMouseEvent(t,!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),i.target.dispatchEvent(e)}});te&&!Qi&&Se.addInitHook("addHandler","tap",Gn),Se.mergeOptions({touchZoom:te&&!Ri,bounceAtZoomLimits:!0});var qn=Fe.extend({addHooks:function(){pt(this._map._container,"leaflet-touch-zoom"),V(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){mt(this._map._container,"leaflet-touch-zoom"),G(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(e.add(n)._divideBy(2))),this._startDist=e.distanceTo(n),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),V(document,"touchmove",this._onTouchMove,this),V(document,"touchend",this._onTouchEnd,this),$(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var i=this._map,n=i.mouseEventToContainerPoint(t.touches[0]),o=i.mouseEventToContainerPoint(t.touches[1]),s=n.distanceTo(o)/this._startDist;if(this._zoom=i.getScaleZoom(s,this._startZoom),!i.options.bounceAtZoomLimits&&(this._zoomi.getMaxZoom()&&s>1)&&(this._zoom=i._limitZoom(this._zoom)),"center"===i.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=n._add(o)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=i.unproject(i.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(i._moveStart(!0),this._moved=!0),g(this._animRequest);var a=e(i._move,i,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=f(a,this,!0),$(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,g(this._animRequest),G(document,"touchmove",this._onTouchMove),G(document,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}});Se.addInitHook("addHandler","touchZoom",qn),Se.BoxZoom=Wn,Se.DoubleClickZoom=Hn,Se.Drag=Fn,Se.Keyboard=Un,Se.ScrollWheelZoom=Vn,Se.Tap=Gn,Se.TouchZoom=qn;var Kn=window.L;window.L=t,t.version="1.1.0",t.noConflict=li,t.Control=ke,t.control=Be,t.Browser=ae,t.Evented=wi,t.Mixin=Ue,t.Util=yi,t.Class=v,t.Handler=Fe,t.extend=i,t.bind=e,t.stamp=n,t.setOptions=l,t.DomEvent=Le,t.DomUtil=Ze,t.PosAnimation=Ee,t.Draggable=Ye,t.LineUtil=Xe,t.PolyUtil=Je,t.Point=x,t.point=w,t.Bounds=P,t.bounds=b,t.Transformation=Z,t.transformation=E,t.Projection=tn,t.LatLng=M,t.latLng=C,t.LatLngBounds=T,t.latLngBounds=z,t.CRS=Li,t.GeoJSON=yn,t.geoJSON=ii,t.geoJson=wn,t.Layer=sn,t.LayerGroup=rn,t.layerGroup=an,t.FeatureGroup=hn,t.featureGroup=un,t.ImageOverlay=Ln,t.imageOverlay=Pn,t.VideoOverlay=bn,t.videoOverlay=ei,t.DivOverlay=Tn,t.Popup=zn,t.popup=Mn,t.Tooltip=Cn,t.tooltip=Zn,t.Icon=ln,t.icon=Ht,t.DivIcon=En,t.divIcon=ni,t.Marker=dn,t.marker=Ft,t.TileLayer=kn,t.tileLayer=si,t.GridLayer=Sn,t.gridLayer=oi,t.SVG=Nn,t.svg=hi,t.Renderer=In,t.Canvas=An,t.canvas=ai,t.Path=pn,t.CircleMarker=mn,t.circleMarker=Ut,t.Circle=fn,t.circle=Vt,t.Polyline=gn,t.polyline=Gt,t.Polygon=vn,t.polygon=qt,t.Rectangle=jn,t.rectangle=ui,t.Map=Se,t.map=Ct}) \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-map.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-map.html.gz index a5e2b5e4fffcc75f69471635ef30940c2c52c673..ac93508be615c5d062f3bfa51d06e61d0114c23d 100644 GIT binary patch delta 34 scmV+-0Nwx9*#f260q0+FqOV>*R#VsH<@CVTRK0lrJe=$l{y0FNFg9{>OV diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html new file mode 100644 index 0000000000000..99d4b1db86e35 --- /dev/null +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz new file mode 100644 index 0000000000000000000000000000000000000000..f80112f596de006935b9393f102991d2ac6264aa GIT binary patch literal 5303 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 z \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html.gz index 93eae9a0374bdf58940cb490fd95d44f96d29186..271ecd66614574e05e16afc3d92badd497f1a482 100644 GIT binary patch delta 9752 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 m?@35PaXkL-AAkl(yr_rAo}{jJ zeV38Y=m#2&Mx*i2>#OQ|b^7`WqvZ7UHLj2oU!kJJ)zbZc^}}ELp?muJ1b|VV+@HQq zvRmgWOA@?Zx~>!5_it}jFKFJHlMw+J zICH&jd^3DzfON!maE|QW0}Pi)}!OZ7V;Hzk^wXt2>jc0zv_mlkNg}KHg?!7Olu= zVIQ(pR^88GrG1oLZ}Or-YuWG$yh2rWOX_d(GJ~ZYFOnmntdc6As3eOW(&j4P%)LdC zU0zj_r2`=(<-E#oh&K>`xxS3JS*=K;XfIr&;xbzkE?1cG^*!(QN)h!Flj;K_fARGR z&yJj^$&!S8yv~ywnlVY1ZdT+ZjJigb*mY1@;%bActED>_oRI&E@;h8y#5u8xHL&x%6+e6K4p;F4OFV(@ZVz|qa>S}(AicY`Zw6D*Kd(_Ul!jz0UP!5$IS?fDz zL{wt0=Uqn;S{;u@Raq*KlYETvRlZ7aad3+x;(9K@ImP)ZFGyEh;UcRRIq?~Ey!%aP zBeh0isqi19C?VEI?C_zJ?gSZst_qwk-EU~l4?(JrR+7}^I%L>mVw~5PE>8pgY3ZJw zF;gV%hgyGUfDUM}dwxy~xX4hywfmO1Ih3@S_CDVX%kDo2FJ1!3~j`bYAAnHA!q$O}>W z7y89*)F^eFRgj+>I2UL`#vmcxb7(*J9Qv6E2p@0)g06^fXe09-1-?Vqcn?ZKdnc0b zh>L7fo&KD!?yqstdC1DS?3H?(BHz%Y9WLh&qz~o~)%^y~-;;TjkiJE$8$5U2#~x9= z4YVdR!(&fUYCZVaL$v0#j{L_SbY2^c9x?0{j;jy(+ltTo^COQ? z76aHOJ48D!f?PyEc+*p+aX3v>NLjHbs;jIV zTojnN_*t^U1b^kOVumPdITrL%4g4U__+Rt6Dx<>Nt#R?nF*(~i^m(c zo|IkY{%liYTYJE6b)05;H1S+lbTDzVZ``W5!S4Jv&l1Ofvyox5rlp~DR2@l##D{r9 zpBTd%*PXW;6R{uW**Yg@Z$5u>KKSpG%bx3Y2PAmPs*Za?K5p_&r>n@-st-*evO_V9 z9n6tcS!Sd!-+@r9p!=rzJa0a}ayOr7=P3TBg)r2SDMJY-&ApiPSr9ioPQw8As_p{` zTb;}tp18Yz$d0sOOWn@1k5<;X`19xLP3Or2mw2Li$Mld{Pjf>?mHj3C_NG{M+;3kQ zBwl^%cE7dw9B*&YsWF<(m^;d5 z2uR}u6j3dC6gv0?D*all21Wgm4kyrtvY;8z^-OocJ>>~=WoO^D2w|M{w*Vs%OL1^y}_{OcWEwy6N25^2Cv?e<#4>hx2!4sVX{#w zdd_h3iT%Il6qga|cs=?z@Pls8b9_=hHeo{w8E%xP|k` z#yPNa4h+tLy0@(u58%^n}XJ2ZHQg11fqxU(J&xH*{o z$AbT8KmNXHYd)pyPg*5l%!j;tO$jLClu8inDS@ee#(ZdPWFT0KJl;}Mf?9+9@qQu< zP2*$SN1?5iOoSP=u?e?-Qv{zG3G0ZdMTUKoj2lE&@cnBNq7)fgL8Wq^d?O%2{S(rE z&}&jEzP2SGd))7-OtqBw!kW$2vJdL6d=^)0+OJ~VA)Ip4w7lmFRY2hBP=>8jjs4m7~ zG&Eq0TRM%SATeNLPO_nO8JnnPG@L_lyVShJRLFPY03krKOT)ejV)72Kzdavp8%cF zY&2HNnfS?Qm=05=JOo17W8UkQE9IGux0Ra4I5U2o< zX-v;U)__g6{s=maae!mB9C(LOlxPURI|$RrR{>yE-efo%ssPYy9C%Zt^QM5Ak0&D) zz%-kLel*dT!zdp5;W$zOOt&cUgYi@aFy)4!hl5lF)Y|osMoXwS@ItMBiCn)#Zk-L{ z{>AqvQtNMu%?g8xM;OM20%0OxpBVI12Qe99JR2pU4q}Rq&?Jlv5R(r@!8D3ZDd=#E zhttT@K}_8t9tH^MpeeXOKSf5fn93)}k7foIQ+j~>AT-1PwPRw^sR@G->jhpK8L&WD za5^(!OiF|Ztm)(gyX)aI%baDgfr2n z#N))n7V)Siry~?it#H;qV>}v5Lr#XX=8wrj3WZiU>#1NooFdN(XWcdONl)74gFcH! zVc4Qy=(uSdByAO#3MOMeZL0u2pU}aLHD&80yUd~YLX4!|;}DpCy2mk+I*x;wM6(oy zi9rvh^;tNHBOS!V9LJL=_Dm_LlG3psjdc*~pV2IsA%h@<1Kuc|r8blA(G=?-=!-C(;nbiA-7p?alGMawO&cX+WPx!hgH(d?IEScyL?*ICEeC^$5-bf= z1^~5tF_K1U6H85hf@m!DA_D{vN+H=jHZj)FpH0${3SjE?aTsC^gEhmSO(#+yzyM6u z{&+H$x|IQ#qP--TB3}h?H4lmBOEm~=p27Mokcb#DmnAxH5IRl*6#!k~p*Yq^iDpdER0V+g zy>Jw!DgYFJ?@hdk#)GSzC^XejK-qq1fp9ew^VK0-vM7|=Qem>Ve<$*N0( zz*HKI@lfZ(qncSdiFM()vS+D>unrRDJef{(5Lb5`jz^k9X_TJ&X(%aO216Jc<3x(< zWjHK<3C7q*V=J6>1H#ET^sVp!RseB48MlZ>yD^GK0kXm;5adOpU}%Ly2p7)MkzIb) zN#k)C4O1(8##1N6;acI)VR4+MGtXWD0(COUj_n$T&YMos)U)>x4?~GZ_T|~~nlIvJ zX@s?MSVeki5RX&JE@Uv%*72u?8dGE*~VN)6vAUw_o(x42O38ijJG$prry=!6<3z zA)d5OhO#w9MSjP_SGp50(*O`dO-YawY7mGGVuVnjK_G7O!%!Oc0AUh_$wW?23jtUT zX*>>eKCELVNf1kuB0wNbM`Hee(Nu##f)10w3TqIEiSTeb9Ldqk96C(lm zWKI940@NKE3BXz(CG=0{E$`e&0EiIB^iKuYc61m3T0W$IDqsfLANr@}QtH;@m_!~n zAcTo&5+<<)3U=T{I38P|kjnK?fUpG$;bS=SX0cT$+DLDjgpmabN!(z6f~8%M20Dcl z?HEZ*?gq-VG@1s}Ahke2Rg=+>#oY-iKK7IBHcO~86!&@t^nC*XD^awfCy;AkgIMA? zUz1Pw5_B90=%&c7Rai((86xNwo&snxt${YC4PBk7Kk!;luN<_|EC^TlQ^l`a!96kH zTU}uiur|Q%qCqk4X_<(BdKHS^G;}M^rdo|z>u)P!T}#4)PHD%G;1q#f?@+4S9kZ+r zvv!j+?;8EsTHA-(ilwzy<|3e&Uc#|dt9SAm0d~}t+3%ckd8yS(EGoeB zG>bNSQ}~L3uCvulg?OhC-`8%p3*z7+`nT9(3iJ>K{SyjlX=Iy!hzd^A;#wsVTxzft zZnQ9pBM8c*N_qn)0sYhKDD4}?^p8|w0@&=$DkN(iPSMS(#iHf1?qSF5VpJsipRJ>{ zEl25`Y#py|65MunZ`)m8<7nN29Z7_nb5UMU_0h-Dw%P%e%dnK5svW~Qb{Cv{fs*W| zoDVmj7TVFHG-o4!^7=YoGo#Ysl<(si+?zaC?&M0>;|KJqI{9L*)KbR3$~Ww`wh%;I zz?H!4@~#fouSr{k>jQ5ggVS7hT8{x@x0MQ?T*ixGj_syNpnF9~v{6(*w9f`Ydti z?lt*a2)1K>ym?R7oVd7q{*+UcChFejB2Co2Pdb{Yd!Jo2Q4c?jNbgm%>(5IUEQC1A zW;Dq+tdCfKiS-_OR`R>ntO~nQO>Zj^P=m9oq#NYYbsJhLef>co@C$A#|oOdgHc@&lV7J8c_%j6k~V-Ha-yx%d5dsK>4|Hmx~5JF5wZ8{X`{)WFGS{?GPH z-_rD@T>9pe?H9j$%B^0It-kHdxasUi&3if_8s#6~a#9_Yb=Q5Q*Mm#_b|tPad}4Y} zbyZ?_4tGY`RYGlIhu9E@`v#)IrC`h~9Jj z{28u)g|(sfuykisHuIK-In7j~UcnXGvf{O0>e7O_D@5X)oP@(=*(b7A`PvfH5hrpY zg>+EQdNpD|ryfLtG+WeS3*#Pnf`E~fZ;YYU%JIv`L3u-#H)ZK4^_md8Exgl@C3hDR zZFZGxz*dh>q|1-mnp9qpuG@v%36QkqT`Di4UY*#98XD zT4vZ-6H9|oL(NhmV+wN*kY-bi)EH4-3ty5|FKLWJ1Cd*J#`#2nSl$M)6i6e+Hi=k& zhK)Lz&;bn|@u%qD#1T@r5A|C;DdCB8&sXY*fDSD-i-D8h7 zSMxlTc2l>ujR8~lk6BqQ@PI^yor>Q;M&A)fdDnfJvo*~RR_0-{UX;BI+-0%E)KjL}rD%D1R-P}iv~yH+#mgoO z2s?|j?0g|y#+z!8NVG|Gx5a_vzuom$`K6PO7#k&dY?eh@f=9e`2rsN(qfb1wGx0ov zRtFdjzQg0_rTf$W{LA@~lg}6}1S`h)7m^tj0mqXT86ZQrJ@>aebc;_&RVtls?zu)f ze;h>FI$>kE+ude*jBJ06tGm4T_y;pUC8ssGL&chE%RU1DKzTk`+(|3y^byaSVY z87Y4!*_;iFI4feRB#}gksj*6Psci-2Dx-vJ*FDuFrsYMxDhE49mtA$v6@qAj{!1eX zaQ@sjTrqVoUDDKxb)Mjh62~_Mg^+2kFS)svkl}5TIPVCa^Pb_cD8wSiv&na`U@s;S z#LI^X^$WwsxSmbiaL>tydHe8xVt~!5c(vI|6KK*OW;X(9ai&oe?`h%pMy`yO^4-KcAzyPw<$f-R%P_Rdd*nu&|MW>COU9Xe()soeexx zGKX1VwXJpc(Im$Pt;uSG)uL++_I-bQqCpu{2PX+zOjQ|U6el5 zvuztWeSa@hrZJh}V^8e`bxc13*tU;C*0*f%vL+lK_x+>gQr%u*kTaeVXhb+4Ah9)4 z_VVS~`2yU_;3K{-J5_f;boCb$Uv*?|`CxNXUUl#*ckZ~asxy2}mghZ#Hfw+0G9Q$A zQFX|oW~V1%$}9h9i<$&8AHT`skGRlx38bIa+r41`OAl~c?4X1wfxQByh;JK!=d0K0 z5Btz~s+amFs9!--8ebzPWYi?|m@!#)-8gJBZRs-fdIdy#rLIr2&Qbo!p-D|bQ(z03 z9AP!o4~fr=+@5X-3`h7LT3mm#re99$jgt3__;(00o)pFsoKjVb&*9S7-<8(y^sHxR zN8(l5lC|kQZ(v7hX;>fGf8-@*4fM-JchsRa`s zSfOks61eijvLLSdLw1dczmv1M)qp3|z^Qa9WoGC;_QrHOs@~60#-()^eZZPGU`GGS zbvi$+N$@~ct#k$wz>I&Fy>fdb%(!I97#G`hy*=3z29r+VyBk2J@7gg$hgvH4Hv^LvFpO#M{(d7L3J39AYJEYrJ1Sx|ziL?2w9JT&8jukn9ndF#quu*_J;BKB*$FVP z5AFrV;(5D5Lfe0D@v8faW*<394cdIU^G#I~k zHcM{FA?Qbmwn_O9^vQWE4SFG*BZw1^D8uzsMSHluO~dP4ruidrXH1=6n)+w6>xJaQ zT7zoFUJj_0&h0tJ|9g{H3*ubiLsx9Qe8?SEV@q_coQr??Lp2AscBB^ZeVe})`Ss3b zy~v`0&-qVSGyvwoi-yLTwyYd_isp7^wv^gUic1@}N=B`w(i}PFpMFxYG>1dTYGbkG zaJWJDA1azj*Bp-aRJv!<))5Wjf2gGx6KdyD%uq&4z>WFoYOPyD#H|^@V1?J0)m6lMA3z@dLD*e&F9;;a?Tf{gH&y+pZa4gsE#U~G-u^O~z>WBYOC%c5JpkhRGm^Y7LI z@HW4x=7u0U*SmLQIh5bAh2F0f>285XCp(s%!CkrvW@DMIam|Ga0c(K&y}`x(1(`1| zv9b;}0}uNOoGfS{Kwv+=<{#g*-Gx-2UcyRJTWA@cDLRqPCHnI;I zyyt&>OYgya`z5&{-egw%U73slsVeS65BDDTbI5kpq7peE|~TD+sZV;nMxQE03ZBr6yOq<+f;W^2}^ zsyBRb^^pau^JnJL{xc+guOYE5-zYpXlkR`-^jIDN>Pf|yGYUr?Uyj{(KJS@cI)y`{ zFQjR)WilsIwb4K`ttS~tJ;8I6t?|BgE>8}*4^HT5hsDY-IA|u}f;5)woAH~-XXlR% zE3E_eP6BFpx*W3KY|B2HPIP-sWf<+75ByF=Z5ugVw^bz{D4&)mCM-6(Q-k{$f4hG) z|1=JeJf)lK>9MV0hNo}q8Y%qN($LK^r~Rz*A1GZ4ZEa1L%A?IVTFuX4@}CQ@+r9Ke zCTX8s5yiW>*<56NRmT&qPeJWzf)LTZNR&4cJ=WDr@eA&9*^|jjXF$}&s5KdVWXaAQ zAGhYI>}}bn=G?tme_WHfzsa2%%TIrcgkN~pgq|Pi*`3$c1a^JTmGJ_P+2oXHY@(&g z9a_d7|3SB8%+L$=O3HeRd$J0$*NGh6?P|$)`f85&ooxtQSPVm=7k9ujS7m1#LF%l# z?1#BY_)%hl*ug#D>vnst6d4^%Y+J2=iX&r$2Mw{@9c`vm4Rb4v}`s*L5?d2g3q?Z!`MpPmGfgA+RjSp(V;vULlB zxQ%Z%&RU;F!ZHUXwrL;2y)PUUTk6yyLA$^gY#G*T?O?kCzHI32VHWNO`tnrI{VRKj z>b%z~|C^Q`0s`|kD9{z7``Lfx-=S_gIkqkYTlTi(k!TwXOZHmU(NU!}##UFFoVR5S z58FdjVy-7`P=Tl~vq6Q_4JuS`P$6l93IxzMsO*k%s~L0;d<@`*gupRv?|(LX^v#|p zZr)IhI-t_0=ga?Te{Z_rvolO#I$5wGj4uh){`eYRX0JSm~1(!^MAO`$b*}wwAn(>5AHt4%i+C)hrH+fLfGouB`QR zhd@xT{g%yom({Kb5toCx-t#A;F;w zzDV$XLB2E+twU+M8E);W1sKlmSi5#_FB5K8big*@c2$Sll@xB*cDd9RpxOZHSbubDeap*y%{{vAvp)Vfg2NpD>=#!4gS1U#bU$Q4!T)8Tbq4`to zPMUpUPh~)rD$jpc5h_^7LSs=8s;p5_(uqkQzKk zLNii-h_}@E8N0TJ)DFC`S3ch=?f>EhJ?quH<~-nz2Wfw)&9uKnTmQNRvz$|45_;wjZGM%P@=_9q zRS@8XAJ04NVZCPvq3nO}?QMNEl10NxSS-l0%KCGI%JN4e z_S^xX{K%6r6Wm+JevweP`qDT9%z1_Qm#{P%oS)m0``sD-EE`liHuv@(CpE*i6YGuZw8_6rvj``La<*h%9e+2rz|Ww zuIxIN9t9LS##?pl+~!&0cyvF`!uj~PWA6l)S8y|`f7Ye~?H-d1QAl=te6+RaTDp#E zFI(>M%0#c+U8}0!yvSacwA-`OQgpG!8=4zZ`UoXqdvDwE(fX*=UI#^uO6>N1UHURd z%9JBv^z%g?{rf}CoJ&XBe(Js8qmIg>j9)0nm%IU?yy38~9Ez8vKQF}@S6O=hGperG zuSF@9f83po_`h04cMLGKEOLbb^dLiIl?trJLBSz(lfQUI% zT@c55c5Zc*_Q%09>*L^=cm@2A{{jwC=K=D3&k`<7n1TCh522;UZtO4RsPE6pFS;AE znnX*D%UU08QX-DSudP@|$)kK(NBHq4-_&V>Uxe*^+0&|U7qBgb`mA?x#8a-l9RY8v z>e+)qb?fHFkgGxT_dx5-R_m{JP=NGv9rWvCPx3Y1LOovlBWO^rybq;A^ng0r(d zac)6c&TZ?0FUyPGyc=(>7gc;A*EU%0?Sk~YQJ2=Mmv7!$?wq)yw!1Xm{rfPsZ>?ud zt>Me@TWr?4w39>uDt~h78LSwBcE#J#vL$Jd0}Vwvn|}CUU0AN=E0HNBid=*wGnNtw zu4IxW3D2WESJp=t9~NzImbzH-nyT(X(bbqt%*RodB{BQXZ-_FZ@jU z32ihn#fwa`I9CBw_+e6{ejW**(l9L;_aD)uxu$W3kAhVCkrGK5tN1{67Cf$wKLV-%-MoYtdhv8;MkfmCr6vNV+uA{@&kVFCH6DzcbS zA~vcrCSi??BOf7D648=j46|YcOq^7OvN9HkeVDO8COKl8@g(OeR6NZ5qM%en8x07e zWHKydg4fuph!ZBs=d6eY@gg2H7zdT|LN<#f2BNG=eSb5~C_*qqTtoqc$OvFy0vP4F zFu)DG&m9y*sgIc~<|>GD3WG?7FvsVSUnD9I(+3J#8mow>Qe-moWfF)uOwuGGp8%mO zE)vcMxnW9SL=w+_!C4$5Pyh)m2?a4E@1ER^hsHp6&UqS(An}7V$tX!=ky7AiQLGS* zZH(hcC4UeX#HsHm8L}cMq7YUAc(8om>V+!Dl(QlM$ikeI&+|M?2$>7xedF}h-w2K= z&X5CHkg{B)5&Tg2X`ZD)z_XAO^@2B6!|3j!ZA7D+i`V_n_~)ilp4J6KDS%YU3|W@| ziHyO`aRfP>D<=FT{GO=i$W| zR+`3eQSd7>7_&V1ia&2z&kPV*p8KK5;362r5%kQ*4h8BJV=RqN%JJ~eKq5j#6^f_O zN`GcsB$yNw2&5Q5wCAF7!DrN=)3oZ-0tusYZ&{98&T8Z+sLm_iLZU{G ze8JIZ(c7jUE`DF>#ixspE?4TW==i2T-~3uD`Z~QQF{bgG?pIGupMCfGIU3?*;5F!f zXy>(uA~UZc-Rsb5$sRN3?99HOKA&pG1p{f`^gY#f?p#?BuU}IKCv`ME%Bfn!!GD-U z>Zxs+zHF74e)_6y7G-B%cTIIgU>xS1bBW)o5w`P?gy}sJwoz$o_jW@c(2$0aYvQ*u z6T@Kr{Fc7z?VNcqRPXY@4zsJ4&@Fm)`A@pp^PyY2eDI?@^y7%1oymJIE=+)I?tJ@Z zORobxk@NHEcKFmfvrK5usg{kRcYm*ceYOD`HhXSOtz&O$$8qIe2+Hmi6uzGWo)wTo z>OsuQ!Zz%V)?CgROnu@{_Q9Z?t>Kex?7C(_M|tpiZ#|`Q4aHji+5=SWA@q--57GvY zOgDoy{+Q!+Abr|~r<~KIef`bUGR(awD`-CUq4vPj+M6SYdV*?99a#Mb|9_*?^Z%2& zJ~w5(Q8kQV+Jl^!^KRbzU`YK>JGpPUIAL^en+>$O-WxBVZJ(1K7+_qdr^Z0H#t%cP z-$%~v3rE!q>=^i%?gQB7`!)f?PuRx$ANY>(uKalCIFnu;YDs^Xd2T>e!>7nwx=X8rhZTJy8 z2l>qxN6*{ly01~cv~2^gtu>5_#vD%Sb89pRBQ@d}4s~pFUF!L0D1S}n2(zwITg7{I z*5v9bN0GN&nce6f$aje5kpt~c1Q6)%OSycH7!L3?3)~X`Fvry^0Baus12#8DWgtZ zpu!tY!fPiYw@=nm`+t57w(uAqa3*^CFbV_kCmOA&o*u9S;04Kz!N8Us_mlu<@&xC7 zs|G=v8650y1-VN(3fE*g&L-{l6TlC>N z1fRCBn+!!_T_E1hY1FG!_vJv(xgK5fZbV;~J$D+F-3SQpurbdXpelO{j?@4{qMOR3 zTU*;dK5JH$s{i$)9vOery^g*h{m@w>Q%VO5E=NDS{Bhsks3hwvo$Yjw{L|21uDbb= z3Nab(hY&tAvVZl>Q)hC_-7O49IPko={%z-)%SN{@b!8aEp_>oy+WNaP3uveEij=j! zQZu(`>svSTW3JNfZ_k{^5_|W?4F$nmXB}?!^o^j^uQ7&@+4$c5ova!Z_k-!dYeyzc zc-HPb`pz+{c53dreD%ov359a)n`@+gb8Q{F_Usv(%T_0V3X;yB)PLE~$Vq*E?f}#r zY@`MoG5SyqOm!$4x#|qb=NrItub;D>307>(Fsb&wSM6+@+`~7ve!R-=2Ls;Q55}Wm Tz}I~g(B1zFLGxW}V-^4aO{B!D delta 2401 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 T1HSIPfa?BV4*tX%V-^4a(LutC From 7edf14e55f521f9e187bce1f565f4a2ed1237a5a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 21 Jul 2017 21:38:53 -0700 Subject: [PATCH 064/118] Add Intent component (#8434) * Add intent component * Add intent script component * Add shopping list component * Convert Snips to use intent component * Convert Alexa to use intent component * Lint * Fix Alexa tests * Update snips test * Add intent support to conversation * Add API to view shopping list contents * Lint * Fix demo test * Lint * lint * Remove type from slot schema * Add dependency to conversation * Move intent to be a helper * Fix conversation * Clean up intent helper * Fix Alexa * Snips to use new hass.components * Allow registering intents with conversation at any point in time * Shopping list to register sentences * Add HTTP endpoint to Conversation * Add async action option to intent_script * Update API.ai to use intents * Cleanup Alexa * Shopping list component to register built-in panel * Rename shopping list intent to inlude Hass name --- homeassistant/components/alexa.py | 109 +++++----- homeassistant/components/apiai.py | 115 ++++------- homeassistant/components/conversation.py | 195 +++++++++++++----- homeassistant/components/frontend/__init__.py | 3 + homeassistant/components/intent_script.py | 100 +++++++++ homeassistant/components/shopping_list.py | 90 ++++++++ homeassistant/components/snips.py | 86 ++------ homeassistant/helpers/intent.py | 165 +++++++++++++++ tests/common.py | 34 ++- tests/components/test_alexa.py | 17 +- tests/components/test_apiai.py | 50 +++-- tests/components/test_conversation.py | 178 ++++++++++++---- tests/components/test_demo.py | 78 ++++--- tests/components/test_intent_script.py | 45 ++++ tests/components/test_shopping_list.py | 61 ++++++ tests/components/test_snips.py | 30 +-- 16 files changed, 965 insertions(+), 391 deletions(-) create mode 100644 homeassistant/components/intent_script.py create mode 100644 homeassistant/components/shopping_list.py create mode 100644 homeassistant/helpers/intent.py create mode 100644 tests/components/test_intent_script.py create mode 100644 tests/components/test_shopping_list.py diff --git a/homeassistant/components/alexa.py b/homeassistant/components/alexa.py index 1a3708fb74626..c121268f93d55 100644 --- a/homeassistant/components/alexa.py +++ b/homeassistant/components/alexa.py @@ -15,8 +15,8 @@ from homeassistant.core import callback from homeassistant.const import HTTP_BAD_REQUEST -from homeassistant.helpers import template, script, config_validation as cv -from homeassistant.components.http import HomeAssistantView +from homeassistant.helpers import intent, template, config_validation as cv +from homeassistant.components import http _LOGGER = logging.getLogger(__name__) @@ -60,6 +60,12 @@ class SpeechType(enum.Enum): ssml = "SSML" +SPEECH_MAPPINGS = { + 'plain': SpeechType.plaintext, + 'ssml': SpeechType.ssml, +} + + class CardType(enum.Enum): """The Alexa card types.""" @@ -69,20 +75,6 @@ class CardType(enum.Enum): CONFIG_SCHEMA = vol.Schema({ DOMAIN: { - CONF_INTENTS: { - cv.string: { - vol.Optional(CONF_ACTION): cv.SCRIPT_SCHEMA, - vol.Optional(CONF_CARD): { - vol.Required(CONF_TYPE): cv.enum(CardType), - vol.Required(CONF_TITLE): cv.template, - vol.Required(CONF_CONTENT): cv.template, - }, - vol.Optional(CONF_SPEECH): { - vol.Required(CONF_TYPE): cv.enum(SpeechType), - vol.Required(CONF_TEXT): cv.template, - } - } - }, CONF_FLASH_BRIEFINGS: { cv.string: vol.All(cv.ensure_list, [{ vol.Required(CONF_UID, default=str(uuid.uuid4())): cv.string, @@ -96,40 +88,27 @@ class CardType(enum.Enum): }, extra=vol.ALLOW_EXTRA) -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Activate Alexa component.""" - intents = config[DOMAIN].get(CONF_INTENTS, {}) flash_briefings = config[DOMAIN].get(CONF_FLASH_BRIEFINGS, {}) - hass.http.register_view(AlexaIntentsView(hass, intents)) + hass.http.register_view(AlexaIntentsView) hass.http.register_view(AlexaFlashBriefingView(hass, flash_briefings)) return True -class AlexaIntentsView(HomeAssistantView): +class AlexaIntentsView(http.HomeAssistantView): """Handle Alexa requests.""" url = INTENTS_API_ENDPOINT name = 'api:alexa' - def __init__(self, hass, intents): - """Initialize Alexa view.""" - super().__init__() - - intents = copy.deepcopy(intents) - template.attach(hass, intents) - - for name, intent in intents.items(): - if CONF_ACTION in intent: - intent[CONF_ACTION] = script.Script( - hass, intent[CONF_ACTION], "Alexa intent {}".format(name)) - - self.intents = intents - @asyncio.coroutine def post(self, request): """Handle Alexa.""" + hass = request.app['hass'] data = yield from request.json() _LOGGER.debug('Received Alexa request: %s', data) @@ -146,14 +125,14 @@ def post(self, request): if req_type == 'SessionEndedRequest': return None - intent = req.get('intent') - response = AlexaResponse(request.app['hass'], intent) + alexa_intent_info = req.get('intent') + alexa_response = AlexaResponse(hass, alexa_intent_info) if req_type == 'LaunchRequest': - response.add_speech( + alexa_response.add_speech( SpeechType.plaintext, "Hello, and welcome to the future. How may I help?") - return self.json(response) + return self.json(alexa_response) if req_type != 'IntentRequest': _LOGGER.warning('Received unsupported request: %s', req_type) @@ -161,38 +140,47 @@ def post(self, request): 'Received unsupported request: {}'.format(req_type), HTTP_BAD_REQUEST) - intent_name = intent['name'] - config = self.intents.get(intent_name) + intent_name = alexa_intent_info['name'] - if config is None: + try: + intent_response = yield from intent.async_handle( + hass, DOMAIN, intent_name, + {key: {'value': value} for key, value + in alexa_response.variables.items()}) + except intent.UnknownIntent as err: _LOGGER.warning('Received unknown intent %s', intent_name) - response.add_speech( + alexa_response.add_speech( SpeechType.plaintext, "This intent is not yet configured within Home Assistant.") - return self.json(response) + return self.json(alexa_response) - speech = config.get(CONF_SPEECH) - card = config.get(CONF_CARD) - action = config.get(CONF_ACTION) - - if action is not None: - yield from action.async_run(response.variables) + except intent.InvalidSlotInfo as err: + _LOGGER.error('Received invalid slot data from Alexa: %s', err) + return self.json_message('Invalid slot data received', + HTTP_BAD_REQUEST) + except intent.IntentError: + _LOGGER.exception('Error handling request for %s', intent_name) + return self.json_message('Error handling intent', HTTP_BAD_REQUEST) - # pylint: disable=unsubscriptable-object - if speech is not None: - response.add_speech(speech[CONF_TYPE], speech[CONF_TEXT]) + for intent_speech, alexa_speech in SPEECH_MAPPINGS.items(): + if intent_speech in intent_response.speech: + alexa_response.add_speech( + alexa_speech, + intent_response.speech[intent_speech]['speech']) + break - if card is not None: - response.add_card(card[CONF_TYPE], card[CONF_TITLE], - card[CONF_CONTENT]) + if 'simple' in intent_response.card: + alexa_response.add_card( + 'simple', intent_response.card['simple']['title'], + intent_response.card['simple']['content']) - return self.json(response) + return self.json(alexa_response) class AlexaResponse(object): """Help generating the response for Alexa.""" - def __init__(self, hass, intent=None): + def __init__(self, hass, intent_info): """Initialize the response.""" self.hass = hass self.speech = None @@ -201,8 +189,9 @@ def __init__(self, hass, intent=None): self.session_attributes = {} self.should_end_session = True self.variables = {} - if intent is not None and 'slots' in intent: - for key, value in intent['slots'].items(): + # Intent is None if request was a LaunchRequest or SessionEndedRequest + if intent_info is not None: + for key, value in intent_info.get('slots', {}).items(): if 'value' in value: underscored_key = key.replace('.', '_') self.variables[underscored_key] = value['value'] @@ -272,7 +261,7 @@ def as_dict(self): } -class AlexaFlashBriefingView(HomeAssistantView): +class AlexaFlashBriefingView(http.HomeAssistantView): """Handle Alexa Flash Briefing skill requests.""" url = FLASH_BRIEFINGS_API_ENDPOINT diff --git a/homeassistant/components/apiai.py b/homeassistant/components/apiai.py index 989c1a596f331..eb6cd0027f7e8 100644 --- a/homeassistant/components/apiai.py +++ b/homeassistant/components/apiai.py @@ -5,13 +5,12 @@ https://home-assistant.io/components/apiai/ """ import asyncio -import copy import logging import voluptuous as vol from homeassistant.const import PROJECT_NAME, HTTP_BAD_REQUEST -from homeassistant.helpers import template, script, config_validation as cv +from homeassistant.helpers import intent, template from homeassistant.components.http import HomeAssistantView _LOGGER = logging.getLogger(__name__) @@ -29,24 +28,14 @@ DEPENDENCIES = ['http'] CONFIG_SCHEMA = vol.Schema({ - DOMAIN: { - CONF_INTENTS: { - cv.string: { - vol.Optional(CONF_SPEECH): cv.template, - vol.Optional(CONF_ACTION): cv.SCRIPT_SCHEMA, - vol.Optional(CONF_ASYNC_ACTION, - default=DEFAULT_CONF_ASYNC_ACTION): cv.boolean - } - } - } + DOMAIN: {} }, extra=vol.ALLOW_EXTRA) -def setup(hass, config): +@asyncio.coroutine +def async_setup(hass, config): """Activate API.AI component.""" - intents = config[DOMAIN].get(CONF_INTENTS, {}) - - hass.http.register_view(ApiaiIntentsView(hass, intents)) + hass.http.register_view(ApiaiIntentsView) return True @@ -57,24 +46,10 @@ class ApiaiIntentsView(HomeAssistantView): url = INTENTS_API_ENDPOINT name = 'api:apiai' - def __init__(self, hass, intents): - """Initialize API.AI view.""" - super().__init__() - - self.hass = hass - intents = copy.deepcopy(intents) - template.attach(hass, intents) - - for name, intent in intents.items(): - if CONF_ACTION in intent: - intent[CONF_ACTION] = script.Script( - hass, intent[CONF_ACTION], "Apiai intent {}".format(name)) - - self.intents = intents - @asyncio.coroutine def post(self, request): """Handle API.AI.""" + hass = request.app['hass'] data = yield from request.json() _LOGGER.debug("Received api.ai request: %s", data) @@ -91,55 +66,41 @@ def post(self, request): if action_incomplete: return None - # use intent to no mix HASS actions with this parameter - intent = req.get('action') + action = req.get('action') parameters = req.get('parameters') - # contexts = req.get('contexts') - response = ApiaiResponse(parameters) - - # Default Welcome Intent - # Maybe is better to handle this in api.ai directly? - # - # if intent == 'input.welcome': - # response.add_speech( - # "Hello, and welcome to the future. How may I help?") - # return self.json(response) - - if intent == "": + apiai_response = ApiaiResponse(parameters) + + if action == "": _LOGGER.warning("Received intent with empty action") - response.add_speech( + apiai_response.add_speech( "You have not defined an action in your api.ai intent.") - return self.json(response) - - config = self.intents.get(intent) - - if config is None: - _LOGGER.warning("Received unknown intent %s", intent) - response.add_speech( - "Intent '%s' is not yet configured within Home Assistant." % - intent) - return self.json(response) - - speech = config.get(CONF_SPEECH) - action = config.get(CONF_ACTION) - async_action = config.get(CONF_ASYNC_ACTION) - - if action is not None: - # API.AI expects a response in less than 5s - if async_action: - # Do not wait for the action to be executed. - # Needed if the action will take longer than 5s to execute - self.hass.async_add_job(action.async_run(response.parameters)) - else: - # Wait for the action to be executed so we can use results to - # render the answer - yield from action.async_run(response.parameters) - - # pylint: disable=unsubscriptable-object - if speech is not None: - response.add_speech(speech) - - return self.json(response) + return self.json(apiai_response) + + try: + intent_response = yield from intent.async_handle( + hass, DOMAIN, action, + {key: {'value': value} for key, value + in parameters.items()}) + + except intent.UnknownIntent as err: + _LOGGER.warning('Received unknown intent %s', action) + apiai_response.add_speech( + "This intent is not yet configured within Home Assistant.") + return self.json(apiai_response) + + except intent.InvalidSlotInfo as err: + _LOGGER.error('Received invalid slot data: %s', err) + return self.json_message('Invalid slot data received', + HTTP_BAD_REQUEST) + except intent.IntentError: + _LOGGER.exception('Error handling request for %s', action) + return self.json_message('Error handling intent', HTTP_BAD_REQUEST) + + if 'plain' in intent_response.speech: + apiai_response.add_speech( + intent_response.speech['plain']['speech']) + + return self.json(apiai_response) class ApiaiResponse(object): diff --git a/homeassistant/components/conversation.py b/homeassistant/components/conversation.py index 591190383a074..b682b318c7b90 100644 --- a/homeassistant/components/conversation.py +++ b/homeassistant/components/conversation.py @@ -4,6 +4,7 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/conversation/ """ +import asyncio import logging import re import warnings @@ -11,16 +12,17 @@ import voluptuous as vol from homeassistant import core +from homeassistant.loader import bind_hass from homeassistant.const import ( - ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON) -import homeassistant.helpers.config_validation as cv -from homeassistant.helpers import script + ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON, HTTP_BAD_REQUEST) +from homeassistant.helpers import intent, config_validation as cv +from homeassistant.components import http REQUIREMENTS = ['fuzzywuzzy==0.15.0'] +DEPENDENCIES = ['http'] ATTR_TEXT = 'text' -ATTR_SENTENCE = 'sentence' DOMAIN = 'conversation' REGEX_TURN_COMMAND = re.compile(r'turn (?P(?: |\w)+) (?P\w+)') @@ -28,79 +30,168 @@ SERVICE_PROCESS = 'process' SERVICE_PROCESS_SCHEMA = vol.Schema({ - vol.Required(ATTR_TEXT): vol.All(cv.string, vol.Lower), + vol.Required(ATTR_TEXT): cv.string, }) CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({ - cv.string: vol.Schema({ - vol.Required(ATTR_SENTENCE): cv.string, - vol.Required('action'): cv.SCRIPT_SCHEMA, + vol.Optional('intents'): vol.Schema({ + cv.string: vol.All(cv.ensure_list, [cv.string]) }) })}, extra=vol.ALLOW_EXTRA) +_LOGGER = logging.getLogger(__name__) -def setup(hass, config): + +@core.callback +@bind_hass +def async_register(hass, intent_type, utterances): + """Register an intent. + + Registrations don't require conversations to be loaded. They will become + active once the conversation component is loaded. + """ + intents = hass.data.get(DOMAIN) + + if intents is None: + intents = hass.data[DOMAIN] = {} + + conf = intents.get(intent_type) + + if conf is None: + conf = intents[intent_type] = [] + + conf.extend(_create_matcher(utterance) for utterance in utterances) + + +@asyncio.coroutine +def async_setup(hass, config): """Register the process service.""" warnings.filterwarnings('ignore', module='fuzzywuzzy') - from fuzzywuzzy import process as fuzzyExtract - logger = logging.getLogger(__name__) config = config.get(DOMAIN, {}) + intents = hass.data.get(DOMAIN) - choices = {attrs[ATTR_SENTENCE]: script.Script( - hass, - attrs['action'], - name) - for name, attrs in config.items()} + if intents is None: + intents = hass.data[DOMAIN] = {} + for intent_type, utterances in config.get('intents', {}).items(): + conf = intents.get(intent_type) + + if conf is None: + conf = intents[intent_type] = [] + + conf.extend(_create_matcher(utterance) for utterance in utterances) + + @asyncio.coroutine def process(service): """Parse text into commands.""" - # if actually configured - if choices: - text = service.data[ATTR_TEXT] - match = fuzzyExtract.extractOne(text, choices.keys()) - scorelimit = 60 # arbitrary value - logging.info( - 'matched up text %s and found %s', - text, - [match[0] if match[1] > scorelimit else 'nothing'] - ) - if match[1] > scorelimit: - choices[match[0]].run() # run respective script - return - text = service.data[ATTR_TEXT] - match = REGEX_TURN_COMMAND.match(text) + yield from _process(hass, text) + + hass.services.async_register( + DOMAIN, SERVICE_PROCESS, process, schema=SERVICE_PROCESS_SCHEMA) + + hass.http.register_view(ConversationProcessView) + + return True - if not match: - logger.error("Unable to process: %s", text) - return - name, command = match.groups() - entities = {state.entity_id: state.name for state in hass.states.all()} - entity_ids = fuzzyExtract.extractOne( - name, entities, score_cutoff=65)[2] +def _create_matcher(utterance): + """Create a regex that matches the utterance.""" + parts = re.split(r'({\w+})', utterance) + group_matcher = re.compile(r'{(\w+)}') - if not entity_ids: - logger.error( - "Could not find entity id %s from text %s", name, text) - return + pattern = ['^'] - if command == 'on': - hass.services.call(core.DOMAIN, SERVICE_TURN_ON, { + for part in parts: + match = group_matcher.match(part) + + if match is None: + pattern.append(part) + continue + + pattern.append('(?P<{}>{})'.format(match.groups()[0], r'[\w ]+')) + + pattern.append('$') + return re.compile(''.join(pattern), re.I) + + +@asyncio.coroutine +def _process(hass, text): + """Process a line of text.""" + intents = hass.data.get(DOMAIN, {}) + + for intent_type, matchers in intents.items(): + for matcher in matchers: + match = matcher.match(text) + + if not match: + continue + + response = yield from intent.async_handle( + hass, DOMAIN, intent_type, + {key: {'value': value} for key, value + in match.groupdict().items()}, text) + return response + + from fuzzywuzzy import process as fuzzyExtract + text = text.lower() + match = REGEX_TURN_COMMAND.match(text) + + if not match: + _LOGGER.error("Unable to process: %s", text) + return None + + name, command = match.groups() + entities = {state.entity_id: state.name for state + in hass.states.async_all()} + entity_ids = fuzzyExtract.extractOne( + name, entities, score_cutoff=65)[2] + + if not entity_ids: + _LOGGER.error( + "Could not find entity id %s from text %s", name, text) + return + + if command == 'on': + yield from hass.services.async_call( + core.DOMAIN, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity_ids, }, blocking=True) - elif command == 'off': - hass.services.call(core.DOMAIN, SERVICE_TURN_OFF, { + elif command == 'off': + yield from hass.services.async_call( + core.DOMAIN, SERVICE_TURN_OFF, { ATTR_ENTITY_ID: entity_ids, }, blocking=True) - else: - logger.error('Got unsupported command %s from text %s', - command, text) + else: + _LOGGER.error('Got unsupported command %s from text %s', + command, text) - hass.services.register( - DOMAIN, SERVICE_PROCESS, process, schema=SERVICE_PROCESS_SCHEMA) - return True +class ConversationProcessView(http.HomeAssistantView): + """View to retrieve shopping list content.""" + + url = '/api/conversation/process' + name = "api:conversation:process" + + @asyncio.coroutine + def post(self, request): + """Send a request for processing.""" + hass = request.app['hass'] + try: + data = yield from request.json() + except ValueError: + return self.json_message('Invalid JSON specified', + HTTP_BAD_REQUEST) + + text = data.get('text') + + if text is None: + return self.json_message('Missing "text" key in JSON.', + HTTP_BAD_REQUEST) + + intent_result = yield from _process(hass, text) + + return self.json(intent_result) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 443ff6f38520c..2674eb062a8a7 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -12,6 +12,7 @@ from homeassistant.config import find_config_file, load_yaml_config_file from homeassistant.const import CONF_NAME, EVENT_THEMES_UPDATED from homeassistant.core import callback +from homeassistant.loader import bind_hass from homeassistant.components import api from homeassistant.components.http import HomeAssistantView from homeassistant.components.http.auth import is_trusted_ip @@ -75,6 +76,7 @@ }) +@bind_hass def register_built_in_panel(hass, component_name, sidebar_title=None, sidebar_icon=None, url_path=None, config=None): """Register a built-in panel.""" @@ -96,6 +98,7 @@ def register_built_in_panel(hass, component_name, sidebar_title=None, sidebar_icon, url_path, url, config) +@bind_hass def register_panel(hass, component_name, path, md5=None, sidebar_title=None, sidebar_icon=None, url_path=None, url=None, config=None): """Register a panel for the frontend. diff --git a/homeassistant/components/intent_script.py b/homeassistant/components/intent_script.py new file mode 100644 index 0000000000000..91489e188c534 --- /dev/null +++ b/homeassistant/components/intent_script.py @@ -0,0 +1,100 @@ +"""Handle intents with scripts.""" +import asyncio +import copy +import logging + +import voluptuous as vol + +from homeassistant.helpers import ( + intent, template, script, config_validation as cv) + +DOMAIN = 'intent_script' + +CONF_INTENTS = 'intents' +CONF_SPEECH = 'speech' + +CONF_ACTION = 'action' +CONF_CARD = 'card' +CONF_TYPE = 'type' +CONF_TITLE = 'title' +CONF_CONTENT = 'content' +CONF_TEXT = 'text' +CONF_ASYNC_ACTION = 'async_action' + +DEFAULT_CONF_ASYNC_ACTION = False + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: { + cv.string: { + vol.Optional(CONF_ACTION): cv.SCRIPT_SCHEMA, + vol.Optional(CONF_ASYNC_ACTION, + default=DEFAULT_CONF_ASYNC_ACTION): cv.boolean, + vol.Optional(CONF_CARD): { + vol.Optional(CONF_TYPE, default='simple'): cv.string, + vol.Required(CONF_TITLE): cv.template, + vol.Required(CONF_CONTENT): cv.template, + }, + vol.Optional(CONF_SPEECH): { + vol.Optional(CONF_TYPE, default='plain'): cv.string, + vol.Required(CONF_TEXT): cv.template, + } + } + } +}, extra=vol.ALLOW_EXTRA) + +_LOGGER = logging.getLogger(__name__) + + +@asyncio.coroutine +def async_setup(hass, config): + """Activate Alexa component.""" + intents = copy.deepcopy(config[DOMAIN]) + template.attach(hass, intents) + + for intent_type, conf in intents.items(): + if CONF_ACTION in conf: + conf[CONF_ACTION] = script.Script( + hass, conf[CONF_ACTION], + "Intent Script {}".format(intent_type)) + intent.async_register(hass, ScriptIntentHandler(intent_type, conf)) + + return True + + +class ScriptIntentHandler(intent.IntentHandler): + """Respond to an intent with a script.""" + + def __init__(self, intent_type, config): + """Initialize the script intent handler.""" + self.intent_type = intent_type + self.config = config + + @asyncio.coroutine + def async_handle(self, intent_obj): + """Handle the intent.""" + speech = self.config.get(CONF_SPEECH) + card = self.config.get(CONF_CARD) + action = self.config.get(CONF_ACTION) + is_async_action = self.config.get(CONF_ASYNC_ACTION) + slots = {key: value['value'] for key, value + in intent_obj.slots.items()} + + if action is not None: + if is_async_action: + intent_obj.hass.async_add_job(action.async_run(slots)) + else: + yield from action.async_run(slots) + + response = intent_obj.create_response() + + if speech is not None: + response.async_set_speech(speech[CONF_TEXT].async_render(slots), + speech[CONF_TYPE]) + + if card is not None: + response.async_set_card( + card[CONF_TITLE].async_render(slots), + card[CONF_CONTENT].async_render(slots), + card[CONF_TYPE]) + + return response diff --git a/homeassistant/components/shopping_list.py b/homeassistant/components/shopping_list.py new file mode 100644 index 0000000000000..7247579fa39b4 --- /dev/null +++ b/homeassistant/components/shopping_list.py @@ -0,0 +1,90 @@ +"""Component to manage a shoppling list.""" +import asyncio +import logging + +import voluptuous as vol + +from homeassistant.core import callback +from homeassistant.components import http +from homeassistant.helpers import intent +import homeassistant.helpers.config_validation as cv + + +DOMAIN = 'shopping_list' +DEPENDENCIES = ['http'] +_LOGGER = logging.getLogger(__name__) +CONFIG_SCHEMA = vol.Schema({DOMAIN: {}}, extra=vol.ALLOW_EXTRA) +EVENT = 'shopping_list_updated' +INTENT_ADD_ITEM = 'HassShoppingListAddItem' +INTENT_LAST_ITEMS = 'HassShoppingListLastItems' + + +@asyncio.coroutine +def async_setup(hass, config): + """Initialize the shopping list.""" + hass.data[DOMAIN] = [] + intent.async_register(hass, AddItemIntent()) + intent.async_register(hass, ListTopItemsIntent()) + hass.http.register_view(ShoppingListView) + hass.components.conversation.async_register(INTENT_ADD_ITEM, [ + 'Add {item} to my shopping list', + ]) + hass.components.conversation.async_register(INTENT_LAST_ITEMS, [ + 'What is on my shopping list' + ]) + hass.components.frontend.register_built_in_panel( + 'shopping-list', 'Shopping List', 'mdi:cart') + return True + + +class AddItemIntent(intent.IntentHandler): + """Handle AddItem intents.""" + + intent_type = INTENT_ADD_ITEM + slot_schema = { + 'item': cv.string + } + + @asyncio.coroutine + def async_handle(self, intent_obj): + """Handle the intent.""" + slots = self.async_validate_slots(intent_obj.slots) + item = slots['item']['value'] + intent_obj.hass.data[DOMAIN].append(item) + + response = intent_obj.create_response() + response.async_set_speech( + "I've added {} to your shopping list".format(item)) + intent_obj.hass.bus.async_fire(EVENT) + return response + + +class ListTopItemsIntent(intent.IntentHandler): + """Handle AddItem intents.""" + + intent_type = INTENT_LAST_ITEMS + slot_schema = { + 'item': cv.string + } + + @asyncio.coroutine + def async_handle(self, intent_obj): + """Handle the intent.""" + response = intent_obj.create_response() + response.async_set_speech( + "These are the top 5 items in your shopping list: {}".format( + ', '.join(reversed(intent_obj.hass.data[DOMAIN][-5:])))) + intent_obj.hass.bus.async_fire(EVENT) + return response + + +class ShoppingListView(http.HomeAssistantView): + """View to retrieve shopping list content.""" + + url = '/api/shopping_list' + name = "api:shopping_list" + + @callback + def get(self, request): + """Retrieve if API is running.""" + return self.json(request.app['hass'].data[DOMAIN]) diff --git a/homeassistant/components/snips.py b/homeassistant/components/snips.py index b123de4815896..6243de0b2d609 100644 --- a/homeassistant/components/snips.py +++ b/homeassistant/components/snips.py @@ -5,12 +5,10 @@ https://home-assistant.io/components/snips/ """ import asyncio -import copy import json import logging import voluptuous as vol -from homeassistant.helpers import template, script, config_validation as cv -import homeassistant.loader as loader +from homeassistant.helpers import intent, config_validation as cv DOMAIN = 'snips' DEPENDENCIES = ['mqtt'] @@ -19,16 +17,10 @@ INTENT_TOPIC = 'hermes/nlu/intentParsed' -LOGGER = logging.getLogger(__name__) +_LOGGER = logging.getLogger(__name__) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: { - CONF_INTENTS: { - cv.string: { - vol.Optional(CONF_ACTION): cv.SCRIPT_SCHEMA, - } - } - } + DOMAIN: {} }, extra=vol.ALLOW_EXTRA) INTENT_SCHEMA = vol.Schema({ @@ -49,74 +41,34 @@ @asyncio.coroutine def async_setup(hass, config): """Activate Snips component.""" - mqtt = loader.get_component('mqtt') - intents = config[DOMAIN].get(CONF_INTENTS, {}) - handler = IntentHandler(hass, intents) - @asyncio.coroutine def message_received(topic, payload, qos): """Handle new messages on MQTT.""" - LOGGER.debug("New intent: %s", payload) - yield from handler.handle_intent(payload) - - yield from mqtt.async_subscribe(hass, INTENT_TOPIC, message_received) - - return True - - -class IntentHandler(object): - """Help handling intents.""" - - def __init__(self, hass, intents): - """Initialize the intent handler.""" - self.hass = hass - intents = copy.deepcopy(intents) - template.attach(hass, intents) - - for name, intent in intents.items(): - if CONF_ACTION in intent: - intent[CONF_ACTION] = script.Script( - hass, intent[CONF_ACTION], "Snips intent {}".format(name)) + _LOGGER.debug("New intent: %s", payload) - self.intents = intents - - @asyncio.coroutine - def handle_intent(self, payload): - """Handle an intent.""" try: - response = json.loads(payload) + request = json.loads(payload) except TypeError: - LOGGER.error('Received invalid JSON: %s', payload) + _LOGGER.error('Received invalid JSON: %s', payload) return try: - response = INTENT_SCHEMA(response) + request = INTENT_SCHEMA(request) except vol.Invalid as err: - LOGGER.error('Intent has invalid schema: %s. %s', err, response) - return - - intent = response['intent']['intentName'].split('__')[-1] - config = self.intents.get(intent) - - if config is None: - LOGGER.warning("Received unknown intent %s. %s", intent, response) + _LOGGER.error('Intent has invalid schema: %s. %s', err, request) return - action = config.get(CONF_ACTION) - - if action is not None: - slots = self.parse_slots(response) - yield from action.async_run(slots) + intent_type = request['intent']['intentName'].split('__')[-1] + slots = {slot['slotName']: {'value': slot['value']['value']} + for slot in request.get('slots', [])} - # pylint: disable=no-self-use - def parse_slots(self, response): - """Parse the intent slots.""" - parameters = {} + try: + yield from intent.async_handle( + hass, DOMAIN, intent_type, slots, request['input']) + except intent.IntentError: + _LOGGER.exception("Error while handling intent.") - for slot in response.get('slots', []): - key = slot['slotName'] - value = slot['value']['value'] - if value is not None: - parameters[key] = value + yield from hass.components.mqtt.async_subscribe( + INTENT_TOPIC, message_received) - return parameters + return True diff --git a/homeassistant/helpers/intent.py b/homeassistant/helpers/intent.py new file mode 100644 index 0000000000000..459d89a83ce23 --- /dev/null +++ b/homeassistant/helpers/intent.py @@ -0,0 +1,165 @@ +"""Module to coordinate user intentions.""" +import asyncio +import logging + +import voluptuous as vol + +from homeassistant.core import callback +from homeassistant.exceptions import HomeAssistantError + + +DATA_KEY = 'intent' +_LOGGER = logging.getLogger(__name__) + +SLOT_SCHEMA = vol.Schema({ +}, extra=vol.ALLOW_EXTRA) + +SPEECH_TYPE_PLAIN = 'plain' +SPEECH_TYPE_SSML = 'ssml' + + +@callback +def async_register(hass, handler): + """Register an intent with Home Assistant.""" + intents = hass.data.get(DATA_KEY) + if intents is None: + intents = hass.data[DATA_KEY] = {} + + if handler.intent_type in intents: + _LOGGER.warning('Intent %s is being overwritten by %s.', + handler.intent_type, handler) + + intents[handler.intent_type] = handler + + +@asyncio.coroutine +def async_handle(hass, platform, intent_type, slots=None, text_input=None): + """Handle an intent.""" + handler = hass.data.get(DATA_KEY, {}).get(intent_type) + + if handler is None: + raise UnknownIntent() + + intent = Intent(hass, platform, intent_type, slots or {}, text_input) + + try: + _LOGGER.info("Triggering intent handler %s", handler) + result = yield from handler.async_handle(intent) + return result + except vol.Invalid as err: + raise InvalidSlotInfo from err + except Exception as err: + raise IntentHandleError from err + + +class IntentError(HomeAssistantError): + """Base class for intent related errors.""" + + pass + + +class UnknownIntent(IntentError): + """When the intent is not registered.""" + + pass + + +class InvalidSlotInfo(IntentError): + """When the slot data is invalid.""" + + pass + + +class IntentHandleError(IntentError): + """Error while handling intent.""" + + pass + + +class IntentHandler: + """Intent handler registration.""" + + intent_type = None + slot_schema = None + _slot_schema = None + platforms = None + + @callback + def async_can_handle(self, intent_obj): + """Test if an intent can be handled.""" + return self.platforms is None or intent_obj.platform in self.platforms + + @callback + def async_validate_slots(self, slots): + """Validate slot information.""" + if self.slot_schema is None: + return slots + + if self._slot_schema is None: + self._slot_schema = vol.Schema({ + key: SLOT_SCHEMA.extend({'value': validator}) + for key, validator in self.slot_schema.items()}) + + return self._slot_schema(slots) + + @asyncio.coroutine + def async_handle(self, intent_obj): + """Handle the intent.""" + raise NotImplementedError() + + def __repr__(self): + """String representation of intent handler.""" + return '<{} - {}>'.format(self.__class__.__name__, self.intent_type) + + +class Intent: + """Hold the intent.""" + + __slots__ = ['hass', 'platform', 'intent_type', 'slots', 'text_input'] + + def __init__(self, hass, platform, intent_type, slots, text_input): + """Initialize an intent.""" + self.hass = hass + self.platform = platform + self.intent_type = intent_type + self.slots = slots + self.text_input = text_input + + @callback + def create_response(self): + """Create a response.""" + return IntentResponse(self) + + +class IntentResponse: + """Response to an intent.""" + + def __init__(self, intent): + """Initialize an IntentResponse.""" + self.intent = intent + self.speech = {} + self.card = {} + + @callback + def async_set_speech(self, speech, speech_type='plain', extra_data=None): + """Set speech response.""" + self.speech[speech_type] = { + 'speech': speech, + 'extra_data': extra_data, + } + + @callback + def async_set_card(self, title, content, card_type='simple'): + """Set speech response.""" + self.card[card_type] = { + 'title': title, + 'content': content, + } + + @callback + def as_dict(self): + """Return a dictionary representation of an intent response.""" + return { + 'speech': self.speech, + 'card': self.card, + } diff --git a/tests/common.py b/tests/common.py index b2001a3c83723..5e328959a7ae2 100644 --- a/tests/common.py +++ b/tests/common.py @@ -14,9 +14,7 @@ from homeassistant import core as ha, loader from homeassistant.setup import setup_component, async_setup_component from homeassistant.config import async_process_component_config -from homeassistant.helpers.dispatcher import async_dispatcher_send -from homeassistant.helpers.entity import ToggleEntity -from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE +from homeassistant.helpers import intent, dispatcher, entity, restore_state from homeassistant.util.unit_system import METRIC_SYSTEM import homeassistant.util.dt as date_util import homeassistant.util.yaml as yaml @@ -193,12 +191,31 @@ def mock_service_log(call): # pylint: disable=unnecessary-lambda mock_service = threadsafe_callback_factory(async_mock_service) +@ha.callback +def async_mock_intent(hass, intent_typ): + """Set up a fake intent handler.""" + intents = [] + + class MockIntentHandler(intent.IntentHandler): + intent_type = intent_typ + + @asyncio.coroutine + def async_handle(self, intent): + """Handle the intent.""" + intents.append(intent) + return intent.create_response() + + intent.async_register(hass, MockIntentHandler()) + + return intents + + @ha.callback def async_fire_mqtt_message(hass, topic, payload, qos=0): """Fire the MQTT message.""" if isinstance(payload, str): payload = payload.encode('utf-8') - async_dispatcher_send( + dispatcher.async_dispatcher_send( hass, mqtt.SIGNAL_MQTT_MESSAGE_RECEIVED, topic, payload, qos) @@ -352,7 +369,7 @@ def setup_platform(self, hass, config, add_devices, discovery_info=None): self._setup_platform(hass, config, add_devices, discovery_info) -class MockToggleDevice(ToggleEntity): +class MockToggleDevice(entity.ToggleEntity): """Provide a mock toggle device.""" def __init__(self, name, state): @@ -506,10 +523,11 @@ def init_recorder_component(hass, add_config=None): def mock_restore_cache(hass, states): """Mock the DATA_RESTORE_CACHE.""" - hass.data[DATA_RESTORE_CACHE] = { + key = restore_state.DATA_RESTORE_CACHE + hass.data[key] = { state.entity_id: state for state in states} - _LOGGER.debug('Restore cache: %s', hass.data[DATA_RESTORE_CACHE]) - assert len(hass.data[DATA_RESTORE_CACHE]) == len(states), \ + _LOGGER.debug('Restore cache: %s', hass.data[key]) + assert len(hass.data[key]) == len(states), \ "Duplicate entity_id? {}".format(states) hass.state = ha.CoreState.starting mock_component(hass, recorder.DOMAIN) diff --git a/tests/components/test_alexa.py b/tests/components/test_alexa.py index 47a3e086d2939..eb8391c3e0d04 100644 --- a/tests/components/test_alexa.py +++ b/tests/components/test_alexa.py @@ -47,10 +47,14 @@ def mock_service(call): "uid": "uuid" } }, - "intents": { + } + })) + assert loop.run_until_complete(async_setup_component( + hass, 'intent_script', { + 'intent_script': { "WhereAreWeIntent": { "speech": { - "type": "plaintext", + "type": "plain", "text": """ {%- if is_state("device_tracker.paulus", "home") @@ -69,19 +73,19 @@ def mock_service(call): }, "GetZodiacHoroscopeIntent": { "speech": { - "type": "plaintext", + "type": "plain", "text": "You told us your sign is {{ ZodiacSign }}.", } }, "AMAZON.PlaybackAction": { "speech": { - "type": "plaintext", + "type": "plain", "text": "Playing {{ object_byArtist_name }}.", } }, "CallServiceIntent": { "speech": { - "type": "plaintext", + "type": "plain", "text": "Service called", }, "action": { @@ -93,8 +97,7 @@ def mock_service(call): } } } - } - })) + })) return loop.run_until_complete(test_client(hass.http.app)) diff --git a/tests/components/test_apiai.py b/tests/components/test_apiai.py index f5624f3c20960..0c15326bbfc0e 100644 --- a/tests/components/test_apiai.py +++ b/tests/components/test_apiai.py @@ -57,14 +57,15 @@ def mock_service(call): hass.services.register("test", "apiai", mock_service) - setup.setup_component(hass, apiai.DOMAIN, { - # Key is here to verify we allow other keys in config too - "homeassistant": {}, - "apiai": { - "intents": { - "WhereAreWeIntent": { - "speech": - """ + assert setup.setup_component(hass, apiai.DOMAIN, { + "apiai": {}, + }) + assert setup.setup_component(hass, "intent_script", { + "intent_script": { + "WhereAreWeIntent": { + "speech": { + "type": "plain", + "text": """ {%- if is_state("device_tracker.paulus", "home") and is_state("device_tracker.anne_therese", "home") -%} @@ -77,19 +78,25 @@ def mock_service(call): }} {% endif %} """, + } + }, + "GetZodiacHoroscopeIntent": { + "speech": { + "type": "plain", + "text": "You told us your sign is {{ ZodiacSign }}.", + } + }, + "CallServiceIntent": { + "speech": { + "type": "plain", + "text": "Service called", }, - "GetZodiacHoroscopeIntent": { - "speech": "You told us your sign is {{ ZodiacSign }}.", - }, - "CallServiceIntent": { - "speech": "Service called", - "action": { - "service": "test.apiai", - "data_template": { - "hello": "{{ ZodiacSign }}" - }, - "entity_id": "switch.test", - } + "action": { + "service": "test.apiai", + "data_template": { + "hello": "{{ ZodiacSign }}" + }, + "entity_id": "switch.test", } } } @@ -509,5 +516,4 @@ def test_intent_with_unknown_action(self): self.assertEqual(200, req.status_code) text = req.json().get("speech") self.assertEqual( - "Intent 'unknown' is not yet configured within Home Assistant.", - text) + "This intent is not yet configured within Home Assistant.", text) diff --git a/tests/components/test_conversation.py b/tests/components/test_conversation.py index 65ce95ee8e99b..138ae1668f8f5 100644 --- a/tests/components/test_conversation.py +++ b/tests/components/test_conversation.py @@ -1,16 +1,18 @@ """The tests for the Conversation component.""" # pylint: disable=protected-access +import asyncio import unittest from unittest.mock import patch from homeassistant.core import callback -from homeassistant.setup import setup_component +from homeassistant.setup import setup_component, async_setup_component import homeassistant.components as core_components from homeassistant.components import conversation from homeassistant.const import ATTR_ENTITY_ID from homeassistant.util.async import run_coroutine_threadsafe +from homeassistant.helpers import intent -from tests.common import get_test_home_assistant, assert_setup_component +from tests.common import get_test_home_assistant, async_mock_intent class TestConversation(unittest.TestCase): @@ -25,10 +27,9 @@ def setUp(self): self.assertTrue(run_coroutine_threadsafe( core_components.async_setup(self.hass, {}), self.hass.loop ).result()) - with assert_setup_component(0): - self.assertTrue(setup_component(self.hass, conversation.DOMAIN, { - conversation.DOMAIN: {} - })) + self.assertTrue(setup_component(self.hass, conversation.DOMAIN, { + conversation.DOMAIN: {} + })) # pylint: disable=invalid-name def tearDown(self): @@ -119,44 +120,131 @@ def test_bad_request_notext(self, mock_logger, mock_call): self.assertFalse(mock_call.called) -class TestConfiguration(unittest.TestCase): - """Test the conversation configuration component.""" +@asyncio.coroutine +def test_calling_intent(hass): + """Test calling an intent from a conversation.""" + intents = async_mock_intent(hass, 'OrderBeer') - # pylint: disable=invalid-name - def setUp(self): - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - self.assertTrue(setup_component(self.hass, conversation.DOMAIN, { - conversation.DOMAIN: { - 'test_2': { - 'sentence': 'switch boolean', - 'action': { - 'service': 'input_boolean.toggle' - } - } + result = yield from async_setup_component(hass, 'conversation', { + 'conversation': { + 'intents': { + 'OrderBeer': [ + 'I would like the {type} beer' + ] } - })) - - # pylint: disable=invalid-name - def tearDown(self): - """Stop everything that was started.""" - self.hass.stop() - - def test_custom(self): - """Setup and perform good turn on requests.""" - calls = [] - - @callback - def record_call(service): - """Recorder for a call.""" - calls.append(service) - - self.hass.services.register('input_boolean', 'toggle', record_call) - - event_data = {conversation.ATTR_TEXT: 'switch boolean'} - self.assertTrue(self.hass.services.call( - conversation.DOMAIN, 'process', event_data, True)) - - call = calls[-1] - self.assertEqual('input_boolean', call.domain) - self.assertEqual('toggle', call.service) + } + }) + assert result + + yield from hass.services.async_call( + 'conversation', 'process', { + conversation.ATTR_TEXT: 'I would like the Grolsch beer' + }) + yield from hass.async_block_till_done() + + assert len(intents) == 1 + intent = intents[0] + assert intent.platform == 'conversation' + assert intent.intent_type == 'OrderBeer' + assert intent.slots == {'type': {'value': 'Grolsch'}} + assert intent.text_input == 'I would like the Grolsch beer' + + +@asyncio.coroutine +def test_register_before_setup(hass): + """Test calling an intent from a conversation.""" + intents = async_mock_intent(hass, 'OrderBeer') + + hass.components.conversation.async_register('OrderBeer', [ + 'A {type} beer, please' + ]) + + result = yield from async_setup_component(hass, 'conversation', { + 'conversation': { + 'intents': { + 'OrderBeer': [ + 'I would like the {type} beer' + ] + } + } + }) + assert result + + yield from hass.services.async_call( + 'conversation', 'process', { + conversation.ATTR_TEXT: 'A Grolsch beer, please' + }) + yield from hass.async_block_till_done() + + assert len(intents) == 1 + intent = intents[0] + assert intent.platform == 'conversation' + assert intent.intent_type == 'OrderBeer' + assert intent.slots == {'type': {'value': 'Grolsch'}} + assert intent.text_input == 'A Grolsch beer, please' + + yield from hass.services.async_call( + 'conversation', 'process', { + conversation.ATTR_TEXT: 'I would like the Grolsch beer' + }) + yield from hass.async_block_till_done() + + assert len(intents) == 2 + intent = intents[1] + assert intent.platform == 'conversation' + assert intent.intent_type == 'OrderBeer' + assert intent.slots == {'type': {'value': 'Grolsch'}} + assert intent.text_input == 'I would like the Grolsch beer' + + +@asyncio.coroutine +def test_http_processing_intent(hass, test_client): + """Test processing intent via HTTP API.""" + class TestIntentHandler(intent.IntentHandler): + intent_type = 'OrderBeer' + + @asyncio.coroutine + def async_handle(self, intent): + """Handle the intent.""" + response = intent.create_response() + response.async_set_speech( + "I've ordered a {}!".format(intent.slots['type']['value'])) + response.async_set_card( + "Beer ordered", + "You chose a {}.".format(intent.slots['type']['value'])) + return response + + intent.async_register(hass, TestIntentHandler()) + + result = yield from async_setup_component(hass, 'conversation', { + 'conversation': { + 'intents': { + 'OrderBeer': [ + 'I would like the {type} beer' + ] + } + } + }) + assert result + + client = yield from test_client(hass.http.app) + resp = yield from client.post('/api/conversation/process', json={ + 'text': 'I would like the Grolsch beer' + }) + + assert resp.status == 200 + data = yield from resp.json() + + assert data == { + 'card': { + 'simple': { + 'content': 'You chose a Grolsch.', + 'title': 'Beer ordered' + }}, + 'speech': { + 'plain': { + 'extra_data': None, + 'speech': "I've ordered a Grolsch!" + } + } + } diff --git a/tests/components/test_demo.py b/tests/components/test_demo.py index 1bb39b053a51a..93aac65ecb560 100644 --- a/tests/components/test_demo.py +++ b/tests/components/test_demo.py @@ -1,52 +1,62 @@ """The tests for the Demo component.""" +import asyncio import json import os -import unittest -from homeassistant.setup import setup_component +import pytest + +from homeassistant.setup import async_setup_component from homeassistant.components import demo, device_tracker from homeassistant.remote import JSONEncoder -from tests.common import mock_http_component, get_test_home_assistant + +@pytest.fixture +def minimize_demo_platforms(hass): + """Cleanup demo component for tests.""" + orig = demo.COMPONENTS_WITH_DEMO_PLATFORM + demo.COMPONENTS_WITH_DEMO_PLATFORM = [ + 'switch', 'light', 'media_player'] + + yield + + demo.COMPONENTS_WITH_DEMO_PLATFORM = orig -class TestDemo(unittest.TestCase): - """Test the Demo component.""" +@pytest.fixture(autouse=True) +def demo_cleanup(hass): + """Clean up device tracker demo file.""" + yield + try: + os.remove(hass.config.path(device_tracker.YAML_DEVICES)) + except FileNotFoundError: + pass - def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" - self.hass = get_test_home_assistant() - mock_http_component(self.hass) - def tearDown(self): # pylint: disable=invalid-name - """Stop everything that was started.""" - self.hass.stop() +@asyncio.coroutine +def test_if_demo_state_shows_by_default(hass, minimize_demo_platforms): + """Test if demo state shows if we give no configuration.""" + yield from async_setup_component(hass, demo.DOMAIN, {demo.DOMAIN: {}}) - try: - os.remove(self.hass.config.path(device_tracker.YAML_DEVICES)) - except FileNotFoundError: - pass + assert hass.states.get('a.Demo_Mode') is not None - def test_if_demo_state_shows_by_default(self): - """Test if demo state shows if we give no configuration.""" - setup_component(self.hass, demo.DOMAIN, {demo.DOMAIN: {}}) - self.assertIsNotNone(self.hass.states.get('a.Demo_Mode')) +@asyncio.coroutine +def test_hiding_demo_state(hass, minimize_demo_platforms): + """Test if you can hide the demo card.""" + yield from async_setup_component(hass, demo.DOMAIN, { + demo.DOMAIN: {'hide_demo_state': 1}}) - def test_hiding_demo_state(self): - """Test if you can hide the demo card.""" - setup_component(self.hass, demo.DOMAIN, { - demo.DOMAIN: {'hide_demo_state': 1}}) + assert hass.states.get('a.Demo_Mode') is None - self.assertIsNone(self.hass.states.get('a.Demo_Mode')) - def test_all_entities_can_be_loaded_over_json(self): - """Test if you can hide the demo card.""" - setup_component(self.hass, demo.DOMAIN, { - demo.DOMAIN: {'hide_demo_state': 1}}) +@asyncio.coroutine +def test_all_entities_can_be_loaded_over_json(hass): + """Test if you can hide the demo card.""" + yield from async_setup_component(hass, demo.DOMAIN, { + demo.DOMAIN: {'hide_demo_state': 1}}) - try: - json.dumps(self.hass.states.all(), cls=JSONEncoder) - except Exception: - self.fail('Unable to convert all demo entities to JSON. ' - 'Wrong data in state machine!') + try: + json.dumps(hass.states.async_all(), cls=JSONEncoder) + except Exception: + pytest.fail('Unable to convert all demo entities to JSON. ' + 'Wrong data in state machine!') diff --git a/tests/components/test_intent_script.py b/tests/components/test_intent_script.py new file mode 100644 index 0000000000000..2c7a03e645aef --- /dev/null +++ b/tests/components/test_intent_script.py @@ -0,0 +1,45 @@ +"""Test intent_script component.""" +import asyncio + +from homeassistant.bootstrap import async_setup_component +from homeassistant.helpers import intent + +from tests.common import async_mock_service + + +@asyncio.coroutine +def test_intent_script(hass): + """Test intent scripts work.""" + calls = async_mock_service(hass, 'test', 'service') + + yield from async_setup_component(hass, 'intent_script', { + 'intent_script': { + 'HelloWorld': { + 'action': { + 'service': 'test.service', + 'data_template': { + 'hello': '{{ name }}' + } + }, + 'card': { + 'title': 'Hello {{ name }}', + 'content': 'Content for {{ name }}', + }, + 'speech': { + 'text': 'Good morning {{ name }}' + } + } + } + }) + + response = yield from intent.async_handle( + hass, 'test', 'HelloWorld', {'name': {'value': 'Paulus'}} + ) + + assert len(calls) == 1 + assert calls[0].data['hello'] == 'Paulus' + + assert response.speech['plain']['speech'] == 'Good morning Paulus' + + assert response.card['simple']['title'] == 'Hello Paulus' + assert response.card['simple']['content'] == 'Content for Paulus' diff --git a/tests/components/test_shopping_list.py b/tests/components/test_shopping_list.py new file mode 100644 index 0000000000000..867e695e2d578 --- /dev/null +++ b/tests/components/test_shopping_list.py @@ -0,0 +1,61 @@ +"""Test shopping list component.""" +import asyncio + +from homeassistant.bootstrap import async_setup_component +from homeassistant.helpers import intent + + +@asyncio.coroutine +def test_add_item(hass): + """Test adding an item intent.""" + yield from async_setup_component(hass, 'shopping_list', {}) + + response = yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + + assert response.speech['plain']['speech'] == \ + "I've added beer to your shopping list" + + +@asyncio.coroutine +def test_recent_items_intent(hass): + """Test recent items.""" + yield from async_setup_component(hass, 'shopping_list', {}) + + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}} + ) + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'soda'}} + ) + + response = yield from intent.async_handle( + hass, 'test', 'HassShoppingListLastItems' + ) + + assert response.speech['plain']['speech'] == \ + "These are the top 5 items in your shopping list: soda, wine, beer" + + +@asyncio.coroutine +def test_api(hass, test_client): + """Test the API.""" + yield from async_setup_component(hass, 'shopping_list', {}) + + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}} + ) + + client = yield from test_client(hass.http.app) + resp = yield from client.get('/api/shopping_list') + + assert resp.status == 200 + data = yield from resp.json() + assert data == ['beer', 'wine'] diff --git a/tests/components/test_snips.py b/tests/components/test_snips.py index 5687723e17aee..5e49bbd03827c 100644 --- a/tests/components/test_snips.py +++ b/tests/components/test_snips.py @@ -2,7 +2,7 @@ import asyncio from homeassistant.bootstrap import async_setup_component -from tests.common import async_fire_mqtt_message, async_mock_service +from tests.common import async_fire_mqtt_message, async_mock_intent EXAMPLE_MSG = """ { @@ -16,7 +16,7 @@ "slotName": "light_color", "value": { "kind": "Custom", - "value": "blue" + "value": "green" } } ] @@ -27,27 +27,19 @@ @asyncio.coroutine def test_snips_call_action(hass, mqtt_mock): """Test calling action via Snips.""" - calls = async_mock_service(hass, 'test', 'service') - result = yield from async_setup_component(hass, "snips", { - "snips": { - "intents": { - "Lights": { - "action": { - "service": "test.service", - "data_template": { - "color": "{{ light_color }}" - } - } - } - } - } + "snips": {}, }) assert result + intents = async_mock_intent(hass, 'Lights') + async_fire_mqtt_message(hass, 'hermes/nlu/intentParsed', EXAMPLE_MSG) yield from hass.async_block_till_done() - assert len(calls) == 1 - call = calls[0] - assert call.data.get('color') == 'blue' + assert len(intents) == 1 + intent = intents[0] + assert intent.platform == 'snips' + assert intent.intent_type == 'Lights' + assert intent.slots == {'light_color': {'value': 'green'}} + assert intent.text_input == 'turn the lights green' From 8e8ec7a7c354f85bb51a006ba0b131b20632b674 Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Sat, 22 Jul 2017 09:21:38 -0400 Subject: [PATCH 065/118] Remove code in wink.py overwriting hass.data configurator (#8595) --- homeassistant/components/wink.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 58a6f51b67b95..1783d4bd79af5 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -103,7 +103,7 @@ def _read_config_file(file_path): def _request_app_setup(hass, config): """Assist user with configuring the Wink dev application.""" - hass.data['configurator'] = True + hass.data[DOMAIN]['configurator'] = True configurator = get_component('configurator') # pylint: disable=unused-argument @@ -151,7 +151,7 @@ def wink_configuration_callback(callback_data): def _request_oauth_completion(hass, config): """Request user complete Wink OAuth2 flow.""" - hass.data['configurator'] = True + hass.data[DOMAIN]['configurator'] = True configurator = get_component('configurator') if DOMAIN in hass.data[DOMAIN]['configuring']: configurator.notify_errors( From b4f392b181fd5f87ea1ac0f1c7029cce9e90f33c Mon Sep 17 00:00:00 2001 From: Teemu R Date: Sat, 22 Jul 2017 19:36:14 +0200 Subject: [PATCH 066/118] bump python-mirobo version for more robust protocol handling, make the platform to update on startup (#8602) --- homeassistant/components/switch/xiaomi_vacuum.py | 8 ++++---- requirements_all.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/switch/xiaomi_vacuum.py b/homeassistant/components/switch/xiaomi_vacuum.py index 20906dd8df19f..393cabb72b9ca 100644 --- a/homeassistant/components/switch/xiaomi_vacuum.py +++ b/homeassistant/components/switch/xiaomi_vacuum.py @@ -22,7 +22,7 @@ vol.Optional(CONF_NAME): cv.string, }) -REQUIREMENTS = ['python-mirobo==0.1.1'] +REQUIREMENTS = ['python-mirobo==0.1.2'] # pylint: disable=unused-argument @@ -32,7 +32,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) - add_devices_callback([MiroboSwitch(name, host, token)]) + add_devices_callback([MiroboSwitch(name, host, token)], True) class MiroboSwitch(SwitchDevice): @@ -107,7 +107,7 @@ def turn_off(self, **kwargs): def update(self): """Fetch state from the device.""" - from mirobo import VacuumException + from mirobo import DeviceException try: state = self.vacuum.status() _LOGGER.debug("got state from the vacuum: %s", state) @@ -120,5 +120,5 @@ def update(self): self._state = state.state_code self._is_on = state.is_on - except VacuumException as ex: + except DeviceException as ex: _LOGGER.error("Got exception while fetching the state: %s", ex) diff --git a/requirements_all.txt b/requirements_all.txt index 6bfc3a70ee63f..8e5d3d52fa3ea 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -718,7 +718,7 @@ python-juicenet==0.0.5 # python-lirc==1.2.3 # homeassistant.components.switch.xiaomi_vacuum -python-mirobo==0.1.1 +python-mirobo==0.1.2 # homeassistant.components.media_player.mpd python-mpd2==0.5.5 From 1807b45222fd82ba4b78fa8e700b7bee8e974c3b Mon Sep 17 00:00:00 2001 From: Sean Gollschewsky Date: Sat, 22 Jul 2017 18:50:31 +0100 Subject: [PATCH 067/118] Binary sensor ping fixed for hassio (#8573) * Add support for multiple ping utilities. * Added support for differing flavours of ping included with different distributions (specifically alpine linux for hassio's homeassistant). * Updated as per comments in PR --- homeassistant/components/binary_sensor/ping.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/binary_sensor/ping.py b/homeassistant/components/binary_sensor/ping.py index cb5bc4333a21c..1919c7ab64d6b 100644 --- a/homeassistant/components/binary_sensor/ping.py +++ b/homeassistant/components/binary_sensor/ping.py @@ -35,6 +35,9 @@ PING_MATCHER = re.compile( r'(?P\d+.\d+)\/(?P\d+.\d+)\/(?P\d+.\d+)\/(?P\d+.\d+)') +PING_MATCHER_BUSYBOX = re.compile( + r'(?P\d+.\d+)\/(?P\d+.\d+)\/(?P\d+.\d+)') + WIN32_PING_MATCHER = re.compile( r'(?P\d+)ms.+(?P\d+)ms.+(?P\d+)ms') @@ -126,7 +129,14 @@ def ping(self): 'avg': rtt_avg, 'max': rtt_max, 'mdev': ''} - + if 'max/' not in str(out): + match = PING_MATCHER_BUSYBOX.search(str(out).split('\n')[-1]) + rtt_min, rtt_avg, rtt_max = match.groups() + return { + 'min': rtt_min, + 'avg': rtt_avg, + 'max': rtt_max, + 'mdev': ''} match = PING_MATCHER.search(str(out).split('\n')[-1]) rtt_min, rtt_avg, rtt_max, rtt_mdev = match.groups() return { From 2f08a91fdd7b6dae9976cb46741466bd4216e018 Mon Sep 17 00:00:00 2001 From: Open Home Automation Date: Sat, 22 Jul 2017 20:00:13 +0200 Subject: [PATCH 068/118] Simplified percent conversion, better logging (#8568) * Simplified percent conversion, better logging * Unnecessary pass statement (unnecessary-pass) --- homeassistant/components/sensor/knx.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/sensor/knx.py b/homeassistant/components/sensor/knx.py index d4752666821ba..80a88ca925aa5 100644 --- a/homeassistant/components/sensor/knx.py +++ b/homeassistant/components/sensor/knx.py @@ -160,8 +160,12 @@ def convert_float(raw_value): Defined in KNX 3.7.2 - 3.10 """ from knxip.conversion import knx2_to_float + from knxip.core import KNXException - return knx2_to_float(raw_value) + try: + return knx2_to_float(raw_value) + except KNXException as exception: + _LOGGER.error("Can't convert %s to float (%s)", raw_value, exception) def convert_percent(raw_value): @@ -170,14 +174,11 @@ def convert_percent(raw_value): 1byte percentage scaled KNX Telegram. Defined in KNX 3.7.2 - 3.10. """ - summed_value = 0 + value = 0 try: - # convert raw value in bytes - for val in raw_value: - summed_value *= 256 - summed_value += val - except TypeError: + value = raw_value[0] + except (IndexError, ValueError): # pknx returns a non-iterable type for unsuccessful reads - pass + _LOGGER.error("Can't convert %s to percent value", raw_value) - return round(summed_value * 100 / 255) + return round(value * 100 / 255) From 9043895407c3d4876f96764ef316bd55f17997ea Mon Sep 17 00:00:00 2001 From: Thomas Klingbeil Date: Sat, 22 Jul 2017 20:34:58 +0200 Subject: [PATCH 069/118] make attributes in the fritzdect module easier to process (#8436) * make attributes in the fritzdect module easier to process * remove spaces in attribute names * move units to separate attributes * make attributes in the fritzdect module easier to process * remove spaces in attribute names * move units to separate attributes * Use new python formating syntax and attribute constant * Shorten too long line * Fix indent --- homeassistant/components/switch/fritzdect.py | 34 ++++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/switch/fritzdect.py b/homeassistant/components/switch/fritzdect.py index fc185c9f6a320..5893b3419d547 100644 --- a/homeassistant/components/switch/fritzdect.py +++ b/homeassistant/components/switch/fritzdect.py @@ -12,7 +12,7 @@ from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, CONF_USERNAME) import homeassistant.helpers.config_validation as cv -from homeassistant.const import TEMP_CELSIUS, STATE_UNKNOWN +from homeassistant.const import TEMP_CELSIUS, ATTR_TEMPERATURE, STATE_UNKNOWN REQUIREMENTS = ['fritzhome==1.0.2'] @@ -21,13 +21,15 @@ # Standard Fritz Box IP DEFAULT_HOST = 'fritz.box' -ATTR_CURRENT_CONSUMPTION = 'Current Consumption' -ATTR_CURRENT_CONSUMPTION_UNIT = 'W' +ATTR_CURRENT_CONSUMPTION = 'current_consumption' +ATTR_CURRENT_CONSUMPTION_UNIT = 'current_consumption_unit' +ATTR_CURRENT_CONSUMPTION_UNIT_VALUE = 'W' -ATTR_TOTAL_CONSUMPTION = 'Total Consumption' -ATTR_TOTAL_CONSUMPTION_UNIT = 'kWh' +ATTR_TOTAL_CONSUMPTION = 'total_consumption' +ATTR_TOTAL_CONSUMPTION_UNIT = 'total_consumption_unit' +ATTR_TOTAL_CONSUMPTION_UNIT_VALUE = 'kWh' -ATTR_TEMPERATURE = 'Temperature' +ATTR_TEMPERATURE_UNIT = 'temperature_unit' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, @@ -86,17 +88,21 @@ def device_state_attributes(self): if self.data.has_powermeter and \ self.data.current_consumption != STATE_UNKNOWN and \ self.data.total_consumption != STATE_UNKNOWN: - attrs[ATTR_CURRENT_CONSUMPTION] = "%.1f %s" % \ - (self.data.current_consumption, ATTR_CURRENT_CONSUMPTION_UNIT) - attrs[ATTR_TOTAL_CONSUMPTION] = "%.3f %s" % \ - (self.data.total_consumption, ATTR_TOTAL_CONSUMPTION_UNIT) + attrs[ATTR_CURRENT_CONSUMPTION] = "{:.1f}".format( + self.data.current_consumption) + attrs[ATTR_CURRENT_CONSUMPTION_UNIT] = "{}".format( + ATTR_CURRENT_CONSUMPTION_UNIT_VALUE) + attrs[ATTR_TOTAL_CONSUMPTION] = "{:.3f}".format( + self.data.total_consumption) + attrs[ATTR_TOTAL_CONSUMPTION_UNIT] = "{}".format( + ATTR_TOTAL_CONSUMPTION_UNIT_VALUE) if self.data.has_temperature and \ self.data.temperature != STATE_UNKNOWN: - attrs[ATTR_TEMPERATURE] = "%.1f %s" % \ - (self.units.temperature(self.data.temperature, TEMP_CELSIUS), - self.units.temperature_unit) - + attrs[ATTR_TEMPERATURE] = "{}".format( + self.units.temperature(self.data.temperature, TEMP_CELSIUS)) + attrs[ATTR_TEMPERATURE_UNIT] = "{}".format( + self.units.temperature_unit) return attrs @property From dac9716cf4d2e92415948664d05204591eafb43d Mon Sep 17 00:00:00 2001 From: Chia-liang Kao Date: Sun, 23 Jul 2017 03:22:49 -0500 Subject: [PATCH 070/118] Fix STATION_SCHEMA validation on longitude (#8610) --- homeassistant/components/sensor/citybikes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/citybikes.py b/homeassistant/components/sensor/citybikes.py index 4cb532d26eb15..32b82b156315c 100644 --- a/homeassistant/components/sensor/citybikes.py +++ b/homeassistant/components/sensor/citybikes.py @@ -84,7 +84,7 @@ vol.Required(ATTR_FREE_BIKES): cv.positive_int, vol.Required(ATTR_EMPTY_SLOTS): vol.Any(cv.positive_int, None), vol.Required(ATTR_LATITUDE): cv.latitude, - vol.Required(ATTR_LONGITUDE): cv.latitude, + vol.Required(ATTR_LONGITUDE): cv.longitude, vol.Required(ATTR_ID): cv.string, vol.Required(ATTR_NAME): cv.string, vol.Required(ATTR_TIMESTAMP): cv.string, From c6bf529d38d639337d5b9f8995f4aa6acddc826a Mon Sep 17 00:00:00 2001 From: Koen Ekelschot Date: Sun, 23 Jul 2017 15:59:27 +0200 Subject: [PATCH 071/118] Allow set_cover_position in scenes (#8613) --- homeassistant/helpers/state.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/homeassistant/helpers/state.py b/homeassistant/helpers/state.py index 19113f243d20b..93953fcd69ed6 100644 --- a/homeassistant/helpers/state.py +++ b/homeassistant/helpers/state.py @@ -24,17 +24,19 @@ from homeassistant.components.climate.ecobee import ( ATTR_FAN_MIN_ON_TIME, SERVICE_SET_FAN_MIN_ON_TIME, ATTR_RESUME_ALL, SERVICE_RESUME_PROGRAM) +from homeassistant.components.cover import ( + ATTR_POSITION) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_OPTION, ATTR_TEMPERATURE, SERVICE_ALARM_ARM_AWAY, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_DISARM, SERVICE_ALARM_TRIGGER, SERVICE_LOCK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_SEEK, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_UNLOCK, SERVICE_VOLUME_MUTE, SERVICE_VOLUME_SET, SERVICE_OPEN_COVER, - SERVICE_CLOSE_COVER, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, - STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, STATE_CLOSED, STATE_HOME, - STATE_LOCKED, STATE_NOT_HOME, STATE_OFF, STATE_ON, STATE_OPEN, - STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_UNLOCKED, - SERVICE_SELECT_OPTION) + SERVICE_CLOSE_COVER, SERVICE_SET_COVER_POSITION, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED, + STATE_CLOSED, STATE_HOME, STATE_LOCKED, STATE_NOT_HOME, STATE_OFF, + STATE_ON, STATE_OPEN, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, + STATE_UNLOCKED, SERVICE_SELECT_OPTION) from homeassistant.core import State from homeassistant.util.async import run_coroutine_threadsafe @@ -63,7 +65,8 @@ SERVICE_SET_AUX_HEAT: [ATTR_AUX_HEAT], SERVICE_SELECT_SOURCE: [ATTR_INPUT_SOURCE], SERVICE_SEND_IR_CODE: [ATTR_IR_CODE], - SERVICE_SELECT_OPTION: [ATTR_OPTION] + SERVICE_SELECT_OPTION: [ATTR_OPTION], + SERVICE_SET_COVER_POSITION: [ATTR_POSITION] } # Update this dict when new services are added to HA. From 77d8e393a1e4da040fe53c8b79cada5f0cde7365 Mon Sep 17 00:00:00 2001 From: cribbstechnologies Date: Sun, 23 Jul 2017 14:19:58 -0400 Subject: [PATCH 072/118] better but still not great (#8618) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 66c9cedea7448..40a393517da95 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -Home Assistant |Build Status| |Coverage Status| |Join the chat at https://gitter.im/home-assistant/home-assistant| |Join the dev chat at https://gitter.im/home-assistant/home-assistant/devs| +Home Assistant |Build Status| |Coverage Status| | Join the chat `at discord `_ | Join the dev chat `at discord `_ | ============================================================================================================================================================================================== Home Assistant is a home automation platform running on Python 3. It is able to track and control all devices at home and offer a platform for automating control. From cc2de5e1dceb345e0286084309f1a7b79edc86ea Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 23 Jul 2017 20:20:23 +0200 Subject: [PATCH 073/118] Upgrade youtube_dl to 2017.7.23 (#8617) --- homeassistant/components/media_extractor.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_extractor.py b/homeassistant/components/media_extractor.py index 559af46e9f681..cb00c8fe035e2 100644 --- a/homeassistant/components/media_extractor.py +++ b/homeassistant/components/media_extractor.py @@ -15,7 +15,7 @@ from homeassistant.config import load_yaml_config_file from homeassistant.helpers import config_validation as cv -REQUIREMENTS = ['youtube_dl==2017.7.9'] +REQUIREMENTS = ['youtube_dl==2017.7.23'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 8e5d3d52fa3ea..97066df38da11 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -971,7 +971,7 @@ yeelight==0.3.0 yeelightsunflower==0.0.8 # homeassistant.components.media_extractor -youtube_dl==2017.7.9 +youtube_dl==2017.7.23 # homeassistant.components.light.zengge zengge==0.2 From 486bcc4cae604a8d4ad6d499ff22d3e6ef9c4d50 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 23 Jul 2017 20:20:38 +0200 Subject: [PATCH 074/118] Upgrade mypy to 0.520 (#8616) --- requirements_test.txt | 2 +- requirements_test_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements_test.txt b/requirements_test.txt index 95f9bfef32942..cc54c21c18b7b 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -3,7 +3,7 @@ # new version flake8==3.3 pylint==1.6.5 -mypy==0.511 +mypy==0.520 pydocstyle==1.1.1 coveralls>=1.1 pytest>=2.9.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 491f5574b3221..9d2842c7bbb7b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -4,7 +4,7 @@ # new version flake8==3.3 pylint==1.6.5 -mypy==0.511 +mypy==0.520 pydocstyle==1.1.1 coveralls>=1.1 pytest>=2.9.2 From 5d810dae86aa98c527e82cab1fb10a607dcb7851 Mon Sep 17 00:00:00 2001 From: Phil Hawthorne Date: Mon, 24 Jul 2017 06:42:41 +1000 Subject: [PATCH 075/118] REST binary sensor value_template optional (#8596) According to the documentation, the `value_template` for the REST binary_sensor is not required. However, if you don't provide this when setting up a binary sensor, the component fails. Looks like a variable was not being set, which I've now included. This should make the REST binary sensor act the same way as the REST sensor now. --- homeassistant/components/binary_sensor/rest.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/binary_sensor/rest.py b/homeassistant/components/binary_sensor/rest.py index abdbc8251c7bc..6d1745700bd1f 100644 --- a/homeassistant/components/binary_sensor/rest.py +++ b/homeassistant/components/binary_sensor/rest.py @@ -107,6 +107,8 @@ def is_on(self): if self.rest.data is None: return False + response = self.rest.data + if self._value_template is not None: response = self._value_template.\ async_render_with_possible_json_value(self.rest.data, False) From 3fec2955a5ee4f4ab9e1354fb94071a639fc9ac1 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Mon, 24 Jul 2017 02:46:23 -0400 Subject: [PATCH 076/118] Bumped Amcrest version (#8624) --- homeassistant/components/amcrest.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/amcrest.py b/homeassistant/components/amcrest.py index 9760ee5d60773..157b9574a0647 100644 --- a/homeassistant/components/amcrest.py +++ b/homeassistant/components/amcrest.py @@ -17,7 +17,7 @@ from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['amcrest==1.2.0'] +REQUIREMENTS = ['amcrest==1.2.1'] DEPENDENCIES = ['ffmpeg'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 97066df38da11..10036a0361570 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -61,7 +61,7 @@ aiopvapi==1.4 alarmdecoder==0.12.3 # homeassistant.components.amcrest -amcrest==1.2.0 +amcrest==1.2.1 # homeassistant.components.media_player.anthemav anthemav==1.1.8 From 1831a7da68d7fc6902a88d31ab320a729624bb9e Mon Sep 17 00:00:00 2001 From: Daniel Schaal Date: Mon, 24 Jul 2017 08:47:38 +0200 Subject: [PATCH 077/118] Check if /dev/input/by-id exists (#8601) --- homeassistant/components/keyboard_remote.py | 25 ++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/keyboard_remote.py b/homeassistant/components/keyboard_remote.py index 88d406ace0b16..5a81f6d2a9e3c 100644 --- a/homeassistant/components/keyboard_remote.py +++ b/homeassistant/components/keyboard_remote.py @@ -94,20 +94,25 @@ def __init__(self, hass, config): if self.dev is not None: _LOGGER.debug("Keyboard connected, %s", self.device_id) else: - id_folder = '/dev/input/by-id/' - device_names = [InputDevice(file_name).name - for file_name in list_devices()] _LOGGER.debug( 'Keyboard not connected, %s.\n\ - Check /dev/input/event* permissions.\ - Possible device names are:\n %s.\n \ - Possible device descriptors are %s:\n %s', - self.device_id, - device_names, - id_folder, - os.listdir(id_folder) + Check /dev/input/event* permissions.', + self.device_id ) + id_folder = '/dev/input/by-id/' + + if os.path.isdir(id_folder): + device_names = [InputDevice(file_name).name + for file_name in list_devices()] + _LOGGER.debug( + 'Possible device names are:\n %s.\n \ + Possible device descriptors are %s:\n %s', + device_names, + id_folder, + os.listdir(id_folder) + ) + threading.Thread.__init__(self) self.stopped = threading.Event() self.hass = hass From 4b449f5f93aa41f7be1d7d23f2223587bb16551f Mon Sep 17 00:00:00 2001 From: Phil Cole Date: Mon, 24 Jul 2017 08:48:20 +0200 Subject: [PATCH 078/118] Tado Fix #8606 (#8621) Handle case where 'mode' and 'fanSpeed' are missing JSON. Based on changes in commit https://github.com/wmalgadey/tado_component/commit/adfb608f86b8bf4c1c43e71b4067cbfe1de9ba85 --- homeassistant/components/climate/tado.py | 41 ++++++++++++++---------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/climate/tado.py b/homeassistant/components/climate/tado.py index 8a2e6621af3bc..459cbec04974c 100644 --- a/homeassistant/components/climate/tado.py +++ b/homeassistant/components/climate/tado.py @@ -273,31 +273,38 @@ def update(self): else: self._device_is_active = True - if self._device_is_active: - overlay = False - overlay_data = None - termination = self._current_operation - cooling = False - fan_speed = CONST_MODE_OFF + overlay = False + overlay_data = None + termination = self._current_operation + cooling = False + fan_speed = CONST_MODE_OFF + + if 'overlay' in data: + overlay_data = data['overlay'] + overlay = overlay_data is not None + + if overlay: + termination = overlay_data['termination']['type'] - if 'overlay' in data: - overlay_data = data['overlay'] - overlay = overlay_data is not None + if 'setting' in overlay_data: + setting_data = overlay_data['setting'] + setting = setting is not None - if overlay: - termination = overlay_data['termination']['type'] + if setting: + if 'mode' in setting_data: + cooling = setting_data['mode'] == 'COOL' - if 'setting' in overlay_data: - cooling = overlay_data['setting']['mode'] == 'COOL' - fan_speed = overlay_data['setting']['fanSpeed'] + if 'fanSpeed' in setting_data: + fan_speed = setting_data['fanSpeed'] + if self._device_is_active: # If you set mode manualy to off, there will be an overlay # and a termination, but we want to see the mode "OFF" - self._overlay_mode = termination self._current_operation = termination - self._cooling = cooling - self._current_fan = fan_speed + + self._cooling = cooling + self._current_fan = fan_speed def _control_heating(self): """Send new target temperature to mytado.""" From f0293eeac22c2fa8cf29a1741ff7c1f420ce8a6b Mon Sep 17 00:00:00 2001 From: Russell Cloran Date: Sun, 23 Jul 2017 23:49:03 -0700 Subject: [PATCH 079/118] prometheus: Fix zwave battery level (#8615) --- homeassistant/components/prometheus.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/prometheus.py b/homeassistant/components/prometheus.py index 18a3a932d36ab..f244bcdd74010 100644 --- a/homeassistant/components/prometheus.py +++ b/homeassistant/components/prometheus.py @@ -216,6 +216,9 @@ def _handle_switch(self, state): value = state_helper.state_as_number(state) metric.labels(**self._labels(state)).set(value) + def _handle_zwave(self, state): + self._battery(state) + class PrometheusView(HomeAssistantView): """Handle Prometheus requests.""" From b0b6026c68787e9b0a25bd4a177f6c3994e51064 Mon Sep 17 00:00:00 2001 From: Anton Lundin Date: Mon, 24 Jul 2017 08:51:07 +0200 Subject: [PATCH 080/118] ubus: Make multiple instances work again (#8571) Back in "ubus: Refresh session on Access denied (#8111)" I added the decorator _refresh_on_acccess_denied. Somehow that stopped multiple ubus trackers from working in parallel, and only the one first init'ed worked. Changing the order of the decorators fixes the issue but, I'm sorry to say I can't figure out why. There's some magic somewhere which I'm missing. Signed-off-by: Anton Lundin --- homeassistant/components/device_tracker/ubus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/device_tracker/ubus.py b/homeassistant/components/device_tracker/ubus.py index e3cef60c376d6..8d4cd1dcd739c 100644 --- a/homeassistant/components/device_tracker/ubus.py +++ b/homeassistant/components/device_tracker/ubus.py @@ -115,8 +115,8 @@ def get_device_name(self, device): return self.mac2name.get(device.upper(), None) - @Throttle(MIN_TIME_BETWEEN_SCANS) @_refresh_on_acccess_denied + @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the Luci router is up to date. From f3d9086ff4d2972a8839365db830841ff2e0e881 Mon Sep 17 00:00:00 2001 From: Jeff Wilson Date: Mon, 24 Jul 2017 02:53:03 -0400 Subject: [PATCH 081/118] Properly slugify switch.flux update service name (#8545) --- homeassistant/components/switch/flux.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/switch/flux.py b/homeassistant/components/switch/flux.py index dea4285e3a90d..5613bcbb19e19 100644 --- a/homeassistant/components/switch/flux.py +++ b/homeassistant/components/switch/flux.py @@ -15,6 +15,7 @@ from homeassistant.const import CONF_NAME, CONF_PLATFORM from homeassistant.helpers.event import track_time_change from homeassistant.helpers.sun import get_astral_event_date +from homeassistant.util import slugify from homeassistant.util.color import ( color_temperature_to_rgb, color_RGB_to_xy, color_temperature_kelvin_to_mired) @@ -111,7 +112,8 @@ def update(call=None): """Update lights.""" flux.flux_update() - hass.services.register(DOMAIN, name + '_update', update) + service_name = slugify("{} {}".format(name, 'update')) + hass.services.register(DOMAIN, service_name, update) class FluxSwitch(SwitchDevice): From a2abb4ae0a694389494792527e79e7b4c949d452 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 24 Jul 2017 00:11:58 -0700 Subject: [PATCH 082/118] Update frontend --- homeassistant/components/frontend/version.py | 6 +++--- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 138190 -> 138831 bytes .../www_static/home-assistant-polymer | 2 +- .../www_static/panels/ha-panel-config.html | 2 +- .../www_static/panels/ha-panel-config.html.gz | Bin 15074 -> 15057 bytes .../www_static/panels/ha-panel-hassio.html | 2 +- .../www_static/panels/ha-panel-hassio.html.gz | Bin 409 -> 378 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2485 -> 2487 bytes 10 files changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 6ab94fe5a789a..ddfd8a3305124 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -3,17 +3,17 @@ FINGERPRINTS = { "compatibility.js": "8e4c44b5f4288cc48ec1ba94a9bec812", "core.js": "d4a7cb8c80c62b536764e0e81385f6aa", - "frontend.html": "7bd9aa75b2602768e66cf7e20845d7c4", + "frontend.html": "d0142106cf282596062e5b2060128f81", "mdi.html": "e91f61a039ed0a9936e7ee5360da3870", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-automation.html": "72a5c1856cece8d9246328e84185ab0b", - "panels/ha-panel-config.html": "c0e043028cfa75d6d4dc5e0de0bb6dc1", + "panels/ha-panel-config.html": "5e2df66aa534c4dadd08c60c361f5d45", "panels/ha-panel-dev-event.html": "4886c821235492b1b92739b580d21c61", "panels/ha-panel-dev-info.html": "24e888ec7a8acd0c395b34396e9001bc", "panels/ha-panel-dev-service.html": "ac2c50e486927dc4443e93d79f08c06e", "panels/ha-panel-dev-state.html": "8f1a27c04db6329d31cfcc7d0d6a0869", "panels/ha-panel-dev-template.html": "82cd543177c417e5c6612e07df851e6b", - "panels/ha-panel-hassio.html": "96d563215cf7bf7b0eeaf8625bafa4ef", + "panels/ha-panel-hassio.html": "262d31efd9add719e0325da5cf79a096", "panels/ha-panel-history.html": "35177e2046c9a4191c8f51f8160255ce", "panels/ha-panel-iframe.html": "238189f21e670b6dcfac937e5ebd7d3b", "panels/ha-panel-kiosk.html": "2ac2df41bd447600692a0054892fc094", diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 3205a1d7d4f40..ad1e407587e7e 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -2,4 +2,4 @@ this._useContent&&u.Logical.saveChildNodes(this)},_setupRoot:function(){this._useContent&&(this._createLocalRoot(),this.dataHost||l(u.Logical.getChildNodes(this)))},_createLocalRoot:function(){this.shadyRoot=this.root,this.shadyRoot._distributionClean=!1,this.shadyRoot._hasDistributed=!1,this.shadyRoot._isShadyRoot=!0,this.shadyRoot._dirtyRoots=[];var e=this.shadyRoot._insertionPoints=!this._notes||this._notes._hasContent?this.shadyRoot.querySelectorAll("content"):[];u.Logical.saveChildNodes(this.shadyRoot);for(var t,o=0;o0?~setTimeout(e,t):(this._twiddle.textContent=this._twiddleContent++,this._callbacks.push(e),this._currVal++)},cancel:function(e){if(e<0)clearTimeout(~e);else{var t=e-this._lastVal;if(t>=0){if(!this._callbacks[t])throw"invalid async handle: "+e;this._callbacks[t]=null}}},_atEndOfMicrotask:function(){for(var e=this._callbacks.length,t=0;t \ No newline at end of file +return performance.now()};else var t=function(){return Date.now()};var e=function(t,e,i){this.target=t,this.currentTime=e,this.timelineTime=i,this.type="cancel",this.bubbles=!1,this.cancelable=!1,this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},i=window.Element.prototype.animate;window.Element.prototype.animate=function(n,r){var o=i.call(this,n,r);o._cancelHandlers=[],o.oncancel=null;var a=o.cancel;o.cancel=function(){a.call(this);var i=new e(this,null,t()),n=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){n.forEach(function(t){t.call(i.target,i)})},0)};var s=o.addEventListener;o.addEventListener=function(t,e){"function"==typeof e&&"cancel"==t?this._cancelHandlers.push(e):s.call(this,t,e)};var u=o.removeEventListener;return o.removeEventListener=function(t,e){if("cancel"==t){var i=this._cancelHandlers.indexOf(e);i>=0&&this._cancelHandlers.splice(i,1)}else u.call(this,t,e)},o}}}(),function(t){var e=document.documentElement,i=null,n=!1;try{var r=getComputedStyle(e).getPropertyValue("opacity"),o="0"==r?"1":"0";i=e.animate({opacity:[o,o]},{duration:1}),i.currentTime=0,n=getComputedStyle(e).getPropertyValue("opacity")==o}catch(t){}finally{i&&i.cancel()}if(!n){var a=window.Element.prototype.animate;window.Element.prototype.animate=function(e,i){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&e[Symbol.iterator]&&(e=Array.from(e)),Array.isArray(e)||null===e||(e=t.convertToArrayForm(e)),a.call(this,e,i)}}}(c),function(t,e,i){function n(t){var i=e.timeline;i.currentTime=t,i._discardAnimations(),0==i._animations.length?o=!1:requestAnimationFrame(n)}var r=window.requestAnimationFrame;window.requestAnimationFrame=function(t){return r(function(i){e.timeline._updateAnimationsPromises(),t(i),e.timeline._updateAnimationsPromises()})},e.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},e.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){e.animationsWithPromises=e.animationsWithPromises.filter(function(t){return t._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(t){return"finished"!=t.playState&&"idle"!=t.playState})},_play:function(t){var i=new e.Animation(t,this);return this._animations.push(i),e.restartWebAnimationsNextTick(),i._updatePromises(),i._animation.play(),i._updatePromises(),i},play:function(t){return t&&t.remove(),this._play(t)}};var o=!1;e.restartWebAnimationsNextTick=function(){o||(o=!0,requestAnimationFrame(n))};var a=new e.AnimationTimeline;e.timeline=a;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return a}})}catch(t){}try{window.document.timeline=a}catch(t){}}(0,e),function(t,e,i){e.animationsWithPromises=[],e.Animation=function(e,i){if(this.id="",e&&e._id&&(this.id=e._id),this.effect=e,e&&(e._animation=this),!i)throw new Error("Animation with null timeline is not supported");this._timeline=i,this._sequenceNumber=t.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},e.Animation.prototype={_updatePromises:function(){var t=this._oldPlayState,e=this.playState;return this._readyPromise&&e!==t&&("idle"==e?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==t?this._resolveReadyPromise():"pending"==e&&(this._readyPromise=void 0)),this._finishedPromise&&e!==t&&("idle"==e?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==e?this._resolveFinishedPromise():"finished"==t&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var t,i,n,r,o=!!this._animation;o&&(t=this.playbackRate,i=this._paused,n=this.startTime,r=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=e.newUnderlyingAnimationForKeyframeEffect(this.effect),e.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=e.newUnderlyingAnimationForGroup(this.effect),e.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&e.bindAnimationForCustomEffect(this),o&&(1!=t&&(this.playbackRate=t),null!==n?this.startTime=n:null!==r?this.currentTime=r:null!==this._holdTime&&(this.currentTime=this._holdTime),i&&this.pause()),this._updatePromises()},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var t=this.effect._timing.delay;this._childAnimations.forEach(function(i){this._arrangeChildren(i,t),this.effect instanceof window.SequenceEffect&&(t+=e.groupChildDuration(i.effect))}.bind(this))}},_setExternalAnimation:function(t){if(this.effect&&this._isGroup)for(var e=0;e \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index baceb29a98504762bb696a9090a16641c8b8df42..055f78334dc5f54ff652fc6261ecc9fc4edd133a 100644 GIT binary patch delta 27533 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 delta 26886 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index c7be840a9d73b..0c428134dfb63 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit c7be840a9d73b6a32a0d74b1a5c0fb4475018d75 +Subproject commit 0c428134dfb6374b4a120cb729396242b4c2f2d7 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html index e54ba31fb3e47..9ba6338ce0039 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html @@ -1 +1 @@ -

\ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html.gz index a0745b91349ec77b3bb8846abb57ad2bba6a624f..2364c355d66f65be42c949cf3d6fdbd309d9f248 100644 GIT binary patch delta 13870 zcmV+}HqpuAbchWhzQq$gUw>$AnzozZXq{rjqr6t&AOpyvn`O%in z*{|6T+b`LA03bk8@}qOkkxC^6>*1T;Pmy$%0sWH;0pou*a*vLP6`}nM^$TTq+>8G4 zF)(nE#J#2PFM$GCCQhrmKpLNlbP4=h%tP?NDT@)70iuE8?H52BPavcb00;s6MYP={ zwCNocd0FN#j0po9zcCv|Ce350;{+=CkiCU(N)$zr7b4v!Q;-eI(ClL7`*Q7hIZH(+v z0`k*R6d-E{?uh}udl6^nVhnZQz$~qRhiPz^AsQ+-JRv&$UPz9ca|3uSx(O6z){2NyMcRx z{c(R#0cU@ZWj$b8fT@|wcaMP~1%QkPXR~aCMLqwnx=70Kq!1wDuf+JE7)8j|_0(^{ zej7qw2-u@2vI;|4j}lO1t*`U<39RjJd91v(EkCdlp)qTHBaMU#g87O9O8H6>7`hM> z&<6Ab@mv6LW!>L~#wrlf8WPs4***#c=#_uqVGY`9H>ghyS|$n2<`trv71Un0*MkB%lAwaCHOn__n`jVaHlso zIF`Iwf|y}U%$y=oODSf2E95PSQ&%8@%D)4()k)gZQ~1MVtubv;?ELAol?GSL=hcq) zT*Aq@I8K*Nqm6jla77Upr(@|G}gqGq#uG4ryv?-Q85O ztf;|uEV7LZqMAiRbKx>8M&^)MJ31+-qGgl~P1+97x~y6W_1p?f=#O%}v`W;8bt&e2 ztvvxRnP@(VDJ-HE5|w12aI?HuP_h)1^%OAX33o&lNi8(|#6Z6mX;|n_oKAn-8>QFhcn#(5NZVDH6PMabIce6ABfudQ;h&o1-?%(g|dNjgq+g+j^B=Igsih!Hu9j&|SXW=r${K)gj9+!5otiD*d~fO$J-j8waQd4eJ~66aIIo zs(lVQkEmKAS3W0^iYtE-G?BaI9{YEVB6_}SxZYMr(Ps}U`mCeq_YW)jeMiwB9#-^+ zj-t;WR`hx8xk7&mxjiD6IRu1dJ)2C=${M9~`k#_g`dA2rTq&rfKvrEQtqjkRvCLws z@pE4lkcI+f^QX>2n*h`CuS$faqbA$*4m0i8HgrN7PM&&JIkkVk=NE<}Gp26M_R*0> zpgcSDFETiM%Rj4~J;w57IeR4LZii1`S@TSr_Hqz?4|No2$IHG^s_lKyefkjp%>FV0 z*dw7CPJ&pjhplB^q&Q2EWyc2>@fenhWn?I@20$lL%k3gZdJH`(KVM2zo?W%?F3>Gd zHmxe54LyPOX4lu}yE)Tb<<|tjt}+py%Z0pmml#ptZ`g4y6u+ z$flvvFr6{Nb{_8MzhH+@k4RU-S^U!~yls?H4BXyp76CT5A$h8Xg|2xcr0#!yo0Jt8;-DFNmGnHs_ik_h)c~HKf=mTuGsK3FIYQTCpPXdQIKX7E<__cOt zOv%U1&aS@xZ#F|4{kD9fc2AJT{D{{2!+P!pWppR0B`Dd$idLzj&<~4LGXoPAL-qhe zXNB0M2b|@ZNG)Vd1b$dufI(sjh??ZBK%jrKPyPVQbMv z%UM#O<_GQ5+=A`IZMxE5z~r|X*7S9kLBis)hy+T?v*cX0ygVw8hsl|@R`_a1W5{Y} zag-bnmB`qs!m)uHw7Yu*2vq`v5($>N|JwMR{6`HQg1p?@y` z7uP_(i0_|GZx&&aRYl%eML9b~0({f;R8#yzzb2TyUju5wgUFf2nMh4qdgxn{>4qca zJKqE%|C1eZ6J{}R;I;1Mn!X>A8kK+Vbaucq3t~lQV-~8?ehtmtR{O@bkTyBSJ*gHx zYxR&hOsmu^~C%UCCl1JC;=uxil4MNLx#v;Zt~$QrMWG_pLZQYPRI(h2fpZW=q#0?vdpSM(2MhEwL{p zhdN+fs!yiMt??{H;41cY*j#bk4G(Z$|h^X?3^S3N_u-kf5faoS9onS;%O}; zTEhlvB8n4o4>GsX^o8=7gHx>*1PA0+bKb>Sd@d%?!+;c^wjC4Lp4jBn0eR-Y;1mv5 zJS)f~a7Iw(R5-CyCAgC|5vU5I0uVa?63%4?GTAu<9mP?EUMFelRKQA-A0kSYfv2z{6L{?2IXN7R8i@0*2A<%a8tt%mgCM9mPlF(qMJcxtp z0vEDE{4q<=lmjUM%veFm(D?<#0VZi!m`AgWzF`qeU>?qj0$0%Xd{jVACa$5UMc7tL z%>6T$Wop}qbuMDI>hUjH^lXHIJcTC3szt6crEw-<)hD=Wo{Z#(a*sK?kVe*iM?H_O zAAP0MR=rkC@EU)?$k-JuPdc3>=4Z?+|1@&YP?@mwT}@LBxP-8m8sJYOj+LK#2xFin zL>*A(itc*gOlqyZtL6~ulSQ8LlGB(%ygT-P{@4F@&We1}$i0WzVX-PQp1(^vQWjEh zPnZNWgR%SQX_2rxeV>0>vf91~>ZR~L5V>kE+Z#1j zgC!t~z>pcW0g`A7<~qs7pwnR^eyx%;Ov+v5JC#!>38ZX7&u?S0KN+JTUI48*RiBJf z3I)IJ7GCCB9>2Q#BaB`*lCUFnz_L9Ak@P@uWM;#w_i~ze?#B-Yhi)L(@J+I^XysR{ zM$>y%`FDSbMax#;CDOVetyZr76rdKeLg()!ExHJH%^f6GD=OZeD;M{fi_nKjbt~EY zt6XCB#A}?N3de#b>NFW$cG!)zwd=P$E#y7ISV;4@(^p%b|MerFRncPu`zV(cME@#k3rtR49I_au*A$9+6YJKNgp~EgdH>XUgH`K zFUYAd71?=pVd&ntt8|**NDEQdpr``bivb9T=I%~??-8>s7G1`QjM@YfNlZw#tEwq% zrbHPI;JSJQ+t$9S1FB#*=3Nbfq+JXH))L%S6ZCJZo4OoV$Vd;gxD;U*`L%H_z(W)V zl01L6joduW^-%Qh^Vc-!Wdr&9+)-WVoZ&|LnltEm543*_{0D4GHA!D$fvE^54b4GG zwpC_juQbt`0Zay6Zvcf&6v-q^al2fJ%T;~LAX8>o8D9zJ*Us(t)dPF*@}GN;*j=dZWD;NRz1=(9TVa2Ucj-fq(|zo3_6=-cJ2cJT!W@!r{J*P>4<7&P-KeA z4vNe%L6ylWC}m(*G3ES-DEJJ;hWce;FeYLb7BNmxi*whS&PQ>Gol!DFZn z`dCch*ORAR9HT3eGp|nyB(MK+JJo-|!(cT!>hH+xK%aJBMH}4am#FVctymm&WFJe8 zJ4wa?9v?Y_;oi^2;>PP@s2UguP8R;Kw*?=Pk(%`mGIbcr&QZP8fX`G%-FEddw6&fe z(3R>`AI}{#q(?yduROSX!bxjOEsmn;_BgYJh<|VNej3 zm*VynumRKnnG|;Co`5+CAAc9OZovDgnDhz1Fl`aQuV1I|Y3-oN){SPR81KWn7LHO- znms=dU~hnimxfT)X%6e&9-e=j2<4I9*WxS&yNOO5=Gkk|7XN(2=b~~>lJe8x+xkdm zQKdN7rNje>T^YZ7fR+OBpC68sg8d9coa~e~ag3WM#tBjSUfe*<10&@lP?hAf@{t{) zdi^1l)>RBzq&%ups1MclcAZw)cX0*lX$iokCjxgib+C|wJme7DIHG?XxxNe_W@7%8 zR2P3YkpOC#QY*MPI%;OBoZuebKVE8PvkHcXi1OueYfDaknWfBaTL%NEr#;$Nq-{kq z*zdjBg+8Sj+#i~|l39*>lEcxgDDz?<&m7%*E~|&WxX}zL8u!{1a}b4jil~(v(D4}m zUQ9`Lc@H)P5jedqz$kyul?;dx{5vqwvGIfc;u|Wp+t|o;jD!$Gs|nVXjr*fL4ppf0)oD4!cD~abzdxb5U6sgg zUDgrd^L9@_niRHl#l)St_+$VUr^APxa#wsyuS1Q)suZPT=^@6gV5;-nW`u}rl-u@ zfsJ($o~3zSc;9~qN?G-nXKRu8%d_?MYGZ?)h_inw?lDp=rFZA9)WqF^y!Hlt36H!W zgAvNGn8#U5ROoS6UbfEqe^=ie&=wd}0c}h5Bv7#R3?-$W;>%7{-|Kd7H@<5Qc9@_m z=bps0bh<&QH+gX&oo3xG?|6c~dgWMKJumf?l<+7TI{`anj&$$uO{Uc?Q?&AQ4_C14 zgz|q0K_2Gl$e}xw&b+k>uLeU0s&T?tiEr1h-GQp9_MJ>7LK|$@EEq-XfnAd~XSG^o z`B#(mbqoODo{RAEvmqMwi$?mEzc9JrK=-d=1X+E^+tVbPj>NIrLZI_HZC)P9jSuvW zoX}<L-YrJb(12h^&{J)znT2k@HdIClY-98sgn9l9!~KGZ)J zXCPtM*ZFT4PsTg^iJLzzsATkG?5?Q-EE(6=`LepTDB^@r+~B1?<&OO`LZ7Gfs2+dd zr9UtWFl}Kvw=Eh~x>M=x5h)I`d@K%ui1~aAcNX+-zq-Iv7YhBr`JW>FpUz|ki^ZvM zemQ*iR_Z_j#i?dF9^$yelUXe2C_u?bP!@6OnqY^KV^}wXUc#&7LQ*1PJBT|8vMHneicAr+dfs5b0WDE@u zs5|s=gLov~z~G{RfzW62yV*LG?rMk+*{dAXRHMuxENd{vV2<`{sIxPme{ct@b%3`t zFNRR1M@x~DWKQOp$Pv#6D27V} z%`v$zh$HLCB-FfRr!2H^5zK$?Cw3iSl8@4>Qy0!#Jn9n6F4vi8YA<2jkXGa0^5ukUxy)em2`1wk}Xb8Y~1HA(h zp6@&Hu7d;LAGCn3p#y(p1)#OmZK1goWULkWcUhFp=U;~7oNOEr1rbpWJx9*D_s~4t zw4Ki<)CWqzsTS8432t*m31IOT#tox&Rf%zb0$r@94*Eg`LJQ;_F)(YZi|4dq9^ynj zBuA7esH@C`5U2d!*%|0Zk&D+X;N_U@O(~7DP_3`<)&|-^dMkf#WAGq7_?rP6*RXtr z!)ox->R9}zz9hmozK^mU7wQHsV65&jPH&NxLaL>n3oDK+fO2{Re%JS|{t{R}5tbk* zd1w@iykx_Jx)1<4u8Cq%lb$NlrC!W;OW-Y&(2Rsy#0xmGf?|O$;h6jPpNY6$U$=g? z?AM(vS`C0R*!6#b6XcN*N`&FYFatBm4>To!bdZ52Jj6IwCz;P-7P`uv361uH1ahNn z!)skml;I_}XvmtqFtTTc>APjssn#%4JCA&j3=VqPM7`wlY`!& zWJWMTKa#tV)hhvLE5A9VQ>YQroKYe6UfK8fO&=v0bIkVkgUq<(M#oIQ#z zxLd|S3Ip#4qq=WqQuNhJ@m8IAh9+BOB~5vOVm*J87bnTH6gn0pQMQa^Et4@U0#ZNs zz&Ne)=|-Y1K;C|iE#}m`p@It4t%1BFSX6I~C8PB*>2X$GC>DVGO^0 zU@3J^Iw&uOus^9s0F)75F>S^QxIk~xhwJPk`_yiM>ySl`vg1g=Kbi%r8sTdr^zDBi zJO6-REHv?=Y9MRy@AdV6;|(!8^smlFZbT4V`OM!n;@jq=>RgcAB!k7&^^G~i^XE>* z^JT|F?R8pTPo!>~K&PPQSKID-kz_+0W{$MTRe-DC9z?RK=_n^(G^5Sy@b^+49TlY$ zOO$k|6n-g$unH5`Uk8W5Zg3Fn1vh`e``|Ko6?_gp1iu9@gLlEl;8U<4ybaz2zXrcY zU||0eZT_d+*gOyZ6>XwGn$temoPEHX!9OESg9~a9Q1%)Ft+DfvonR*YA!E0KFVP>m zZNbm*gPigE@Z%rw61?P4G87I5q^`pYW1M@a4;#HVGD$?r)5)3}O` zK(C>Hiz+(xOfy|7P#LQD?2>hA6KkriG4qm~!|5^WhgQ^g8$))e#T}GL-hc3gM zY<5Ea;!?uWulZbMaxFTSfBL5|I+xN&x{NN(wP$gO4&dk#G|0=PibQ`Ad0>dUU$ z^It?`zsE^*!!@S_u>|AuRlPG44zIiB1VA^R$Dkks)@g6XFf)bVym!Va^e6BT)+ZAG zfRew5S2xfxV0yvVEqulJB~py(1&s8WFjNr`NF0n(5f}T&Q&({cAkzf!qT8E3Bj_}p zX>YQnQM?m>cYz+DsMvog=&Qr0@mYzW&n)>z#8s6)On|CCcK(n%#U6AOfwhK^an9X!VChkamB9KAd^Ezuns!cl~zKT)l1-T61P6N69tE{0o zD#C_)5x5ByO{jl~%qH?pQBb)0g!LI@l9$fsuq;EhFeyO{Rq_)wF}!y7Q=V7s7^yCx zz_Tf#xK zK<6x)DLpm77hiH%Mw?Oh(3A@pW!`|sb{I8Rt(w>R3*Wc)%(}@K79l&rp>MGQ^%E*k z(ZNs#MJ&4bh;d*-q9sYu!L7`JyIg0uCX69#zA#E7!cr9Yu z9oj|MYAAz>rGQi?`!?>ycR!eH{z^bhRzr*0a}gOmLHBdjB3+V*nn4^+AxNTJ6h>>%E#iPHXHAX}k(sqpmdy!@YmK`y#_3@JM2}Z@_>E1%_vMAUg*2K^+~f z;rZ%)tu*~a7l;Amh)gdKKe%vc-m_!KV5QqzU%$3alF5Z)h%!=y^?oY*S1D0%l?L=s zRVdGB(~`qGaVRcjzes6G3o!QwjvYF?kPF0wg22>{R)e@VbFyv`G}n8)fnrF1L%Yxi}K2F zrVF2KFm#2p|AYM*IeKBdJH@kaT0C15CmFm73Q*nl(t%j`L$=F6U6r;OI^PW2Y}jrP zhtPmZioA|aXe(X=D156OucjJ`F4uq7ZZIsubt)Sn0p6A?_0Sz*Xru!{s;u(6zExiv zd3b~7k@nZBoX?PR3wmsg&ef+Jz8`z;MvSq0fxA)C-@Z@JL#SgAjcng#$EjpeYA6^E zc;Kq?YN`xgfl;h;J{vioeg8#bGnX;1fSqN;3LSO+nWAs~;8(oM(zE3fxr0N7b!U@VlV$?=@0_D%xGXC1bSk z*>|#yy{faVn9tt;Ae+szf7yDgwp@SAP3h+N%jN9s?AIwb8L0YHo7B=+!+${GMT_tt zdW~#!U~K@=Zhn`J?*?|5f$Gi@QcXH+#T^)~BWA!@hd9`Q;s|j0YH}bf?^?@xnM$u3&6#}&g=J|hg-*#hh zMq^bDp7*g*+SmvM1u4A5m{GhGgzHaKMAQ1Z{xl5ujC!9a!Z-(|LK$jLOPmJ$#%>+# zV%@*RRxZ0?N7{ihwpXrMG?w-#UOUC|Ke&oM!8p%?33B2oKw!|!PzMIAMN!g_s1)Ve zio{$Shjv^RwY>R`1^Q7!_3D2SAfnaa91QNU_MAZK)y^sCx@EMsryk}2Mui^Vmr?qV zd2R*jM6FqO4pS~cZ_7-3vKkq6 zw^rG`G&bBlBXsvJUsU$x%?LotJ}Zk8iZ&{h=R|ntG$jwCJ$B|C%;$eMJB`_W9bl?I zIBkkg=&_-^Rbm9407;+?NkwcvuaiI}0gzotqQ2mEtglbK5q1<^OtIF1Vtw600U*1O zWTAkb8MXGT(R+kQbIk{;E8{3%)>jMciYwqAjQP9(OJfAXSOhsRe1cV*4L2{ULH|KPv2kQ9&7iqOP7`h?}0XBcVzq8{1ty(>RjFr(b@bncoliK zI~WBo^+=}Q-#i)U#LwIWfAh7!9X<~}14i_m*?aTBJCH}@d}ZPGF;W$w9`sgI0l$Xt zqL0wDw>$Zgeg25XZ0-Gg{%U>w{a_W?e15$=H{a=K12kdqcKai9%mi5PUG$lmWbKkF zyyPK$(_~vP0*8OZ&ToKS7N?i*R-nf;q?py1v5B1{3_v?c3L)5u0SD(@cJKcL$<}y8Ssl%_U z^a=>eGfbM9RJ`(O>-18lm92(tU~iS0`la8!jrt%D>AhO+lIZHVscObvcAvK{=rV5* z*{>KE-JyR0CSe_?Pf-GG?GIFhT|>;+zogSn8-IHs3=h}WrNKhNfR$ED_nXftI@?5g zung$|h)i|yRI8KX4yWb}b%*Pv_8HnwmWXRv{@1H5wc0AfGtK693b%g8`xsqmBaQb6 z{q3j^jTn1$;Nmc#pkpo-d^AzYFk~}J6+tDxvy6Y8;Sa1`EuiQIYFWC9 z`*(k%7zUfB`&DMs6h;J8Sti6T86mEm6%UM?C zbg!e?Ybr_&on%MHO4PyfpbUUU(6oA2RtZBDIbB5*IgKhpY}iT4tU{r|2RrN+Y2&ay z-~(#TIkic@0Lw?M+D|)jYy_ibSB-3$*R_8wiB<`}ahB9(O@2JgK>4wza7}i?=Xt8* zsPGq3V05z!0+HEl3L{KJ-${)bijX( zreA#TsigS+Q%UjDPbI}&r;_6CQ%S^Ib?}Q~1nKq(|G;oV-lEEjmyqNh>7G9Z9nBUm za{tOW_pIX(al<^XXp?;;yu6MNY9EK%@-6*F9hk+#jnuz*5ko_zvyR|u(cIxx=UqFw z`_?*hbaDGP&_|R`GK%O8IVRYcpdN={VSOKGHNq2o=wc^StqWYic$~~My3Ra$lZSme+>J; zJ}d5h*Jl%dFCTQb0>`iRRI%S1&#B5g!?#~-)?cfyJg^SsTK6BAq*-?q@M+kNI|PjJ zl^tUpnOzu{{1T4(j$e}SofixAjY0@jm$~O%V56LZH0q;+x*gA%5;J*qoxbi$jn2= zE3v6_$2B^mXpK)EKJL6@MxIBmF)*-kS2Q0=zJFjD(74B1pJDFkQL{repuvds;pO{T zQNx<$t>exQz+u80ce&Q^6dzAQC{+*hF^!PEa3s#g#*Lnz&ldYUP15sm9G%xf%(O^=W zvlM1iTj0}6c>PM%alb~r5h>L_ouF_Jv4vHo)@@EXD`R&W~@x5 zBHIO>!+d0Kl~I0_8@-i9d`cDCtw}l_u5Jw|SBhG4h%l+2NRNI%zt}C;4Oc!C#D2}FJli78)(D6jFz%Qm{eRAe>-w!)kgnAJ+sZaW*v zp#wPmEM{KCzQljK%2}iCe$mIsSUj@m%e!qutE6$W1C=*su&Fb)<;gMxY{`1kPNg0& z^vK8KsfVSZRz4n;zUqppGIY%+kX6xpXo$#CJ|B;Xi%XhJsr&?@cr7qcwH4Z@Vl^;X z6&R}SlTjlMImV6E@(F{iS877oQlX!~$r=TtY^%|a$7z4yV5F92{djy_oKac2_Ty2R z06jS}FPQH}j|I z4c+a(Fc2*A<8>{x6g~3Hw;)6PTpLKo?h;#8iBR1V{fGwwNpJEO9q-54)yr4pd;bNK z4KZf|e?YT#F;M{lm6OOaCjnKn@G>v~0WFguG#ddWlRY#Uf6sa4O!A_}4AT>#oDuxx zsk-CrlGD(^;itMMaTcG;nz>vk$$!y&9M_@eIH5oAFG@tIZT!p~tmtk&i_L{~>Mg%m z&o3@FtKcMiBpxj;JIDV%!O3I1^r79(*L&p)sN;bvztrmQVFkXHtGn&Db0z9K9e~gh z^bdWb_5sh!e_}*-OOQDp{`KkN-311tH`>rum$eBa1+Q;Q1z|`91|T1{yb`8Edel)) zOIq?epTr3kSYKbW+JRSgEquPIxLFnxUy;0fq_jW`r%7x-UZ@fuX~TlmDvecoQji|@ zLtlYVSFH!}eA9 zK>P&;oU@E-$igIpziCQt$Iy8>9)r|$-u>h7(BVyIkgbj~kz)MH$Wn0*{|O>6c7A#N zZojv?f48e;-U`jJoFzQ1W+ipRead$I#5oqE7d;IW^b~vyV5Q8}b`if~-h2pN1|8Xo zvKjzg)nQVl!c!=r4%z1to|(&lKd1>Zi3=P9h3XnoUG0*u10x_B@D3KU zeNeCuG0b!9Zol1o`RTp$?!%|YJX>!(Q@zj3f3lR+mBhRxf)y$I?+*@NzJ2@jm+6hq zKYhj1GVCdf9;lRc_bdzdf#pIykwjq4Ek|3S`+3jM=d>)PYD%~HQnPvx+@K<=hV@;a z_!dNDEkr(DjGMeD^-UQY8+g~aD}{r4f&8dEN{)|tRl-YQ*81}13*~=~%iC<^Sr0%F ze~&yD-}_bw!HVb!vtZOpF^~kUOwV`+UWtr*S7EvS8L^Y4GLc&C7qam|*3K(s-ca6Y zA#Y!&yUz8+z;yOZQn951NX3hCr?)i_+vU#IpucD|!VnSNVbw&|xQ5cjNtO*d%?){T zcR$!_-s)Y|w|d)jG#OP#WtT?B=-c2oe@`~~?s!>cxuVLlt4feI52{gCU=GI`U5@8w zd37RF>G7DTw6IHA*4d|xvewwk>1~TvlZz#QDemr>-nPBgnBSWqfU+;wV5M$Kiqwp6 z@&AK1cL)_IH&@BX-sAbwqe{MRm*IhKSUSLRn%_9;B#ZW}?bGJ$c&YDm?}lh`e=yLe zq08vCLL$GTj7qeR&Sok+_n?#lrbDY z9m{zVTJ4D{dDr21K8M9zG8lyi6?e@dZjuF}DC zpANkWNUkU_=gtM1ZOTYYs_ND`FX#_Dj342E`tRy;;!*qm$K_;8tUuH9ztARfQql^6oZBL@i;yvmno(E!n_Fq3P$9w?)KaGoJ6@acQw{vAg z1j?Hp$1P$X7vh}Gp1CHdElwS}=}m)FFsY$Jl4Ph=)LYirnJAz5e+y++2}(Tyk*^7U z;7gZUWErJdBgCoGtI$Nk+IYIp3i5*~)y1Ms@! zrgZKStZL`IoiW0VizlPS(hu+af8OQkYE7RGuBx2%o~4&U?@R0H724!~g&Q delta 13887 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 N{|CI;ShL^I0007S4 \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-hassio.html.gz index 03b8a09f320d02b2f305c7298c4a974c64d689d7..6a1c2905cf0087ed1d383c04a1cd8ff53c21f228 100644 GIT binary patch literal 378 zcmV-=0fqh_iwFP!0000217%XdYTPgo{S`&0U9i{W7L3=>(uTc+1k(1hEM;QNA_Ylf zq;VGG_}?qpO}5aJX5PFR-WyG$+1a+y2&!!yGKfw?h{${S^T&O8C)=i4i!Y?cwo&9t zM{2MrjM_^LWe*;0sUb!~iOuMG3yf_Od9>IbwNVQFX;LPp!dQFqcw<~ofx+|KR4cDp zCzKA17dhU`<1xRdlN268pi4&9C}UC6rF7_r4Cmw_#kmk@V9ekWBqUq74o}%tV|DeD z1b4yo+&+;V9fr+hV*Q`Nq7T$#V1u!qGFCsnykf`2Dy;rWWD$JvA?OoW#C(t~fkIVJ zJofm>cmq3NeRDg{1u#RW6XQJijt%+EcDfj^=(0O}d4B%=?fb9ych)BE)9f`yHPw0!)p9<60L~?vHbnve055p9ga7~l literal 409 zcmV;K0cQRmiwFP!0000217%XdZrd;n{S{TG1h8Z5HW-e94O@}Rumat734(yN7)XO8 zdJ^5tNd51V?4~KOlc-1X@jXh7W@p<*BdE4<$RIimAtG<(&mZ^YN7**jl6)dHwv8fJ zI#Pp0VboS?D0}c|OARp^O4W?6x4_sokw=T|UK^#*A1=zolo)GI9`B6nDKL1Rnrf+Q z7KYM+@gm1tx!>pWaFD`72z1WK5@jrEI+qUpkl}p!mg1ZUG%#jx4ib_r+{n}Irm?#D zNrJmzdTt-cjt;}>Vq*QD!J-e;V_<`^zGSTa{`4C=E*4?+XCjN>i>shFU=~wfc> zY{;+Hm$UJT&YRt*$H(KBufJYiSev+6USOAIuVe+id7WO(Ze`&IYm0XzV3X;Uya!`Z z2_})12-YZesc&OQ%#Gp{$cZ?l6+N3sVI$YmdYabhm6zo<)$)(3`QQBm?Ez(aegXgh Dn#jvt diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index 62d99bab65cf5..a73aff72274db 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","0db8ddbf9b3ec817eebadc6866a9499d"],["/frontend/panels/dev-event-4886c821235492b1b92739b580d21c61.html","0f16df49a7d965ddc1fd55f7bd3ffd3f"],["/frontend/panels/dev-info-24e888ec7a8acd0c395b34396e9001bc.html","7bb116813e8dbab7bcfabdf4de3ec83f"],["/frontend/panels/dev-service-ac2c50e486927dc4443e93d79f08c06e.html","1daf8c159d2fab036f7094b0e737f1a0"],["/frontend/panels/dev-state-8f1a27c04db6329d31cfcc7d0d6a0869.html","002ea95ab67f5c06f9112008a81e571b"],["/frontend/panels/dev-template-82cd543177c417e5c6612e07df851e6b.html","81c4dbc540739dcf49c351cf565db71b"],["/frontend/panels/map-b4923812c695dd8a69ad3da380ffe7b4.html","e88c1c3fc6d3dd0db561ce0a1f5beaf5"],["/static/compatibility-8e4c44b5f4288cc48ec1ba94a9bec812.js","4704a985ad259e324c3d8a0a40f6d937"],["/static/core-d4a7cb8c80c62b536764e0e81385f6aa.js","37e34ec6aa0fa155c7d50e2883be1ead"],["/static/frontend-7bd9aa75b2602768e66cf7e20845d7c4.html","054d60e22570068f7b2f43cb893d40f7"],["/static/mdi-e91f61a039ed0a9936e7ee5360da3870.html","5e587bc82719b740a4f0798722a83aee"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","32b5a9b7ada86304bec6b43d3f2194f0"]],cacheName="sw-precache-v3--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(e){return e.redirected?("body"in e?Promise.resolve(e.body):e.blob()).then(function(t){return new Response(t,{headers:e.headers,status:e.status,statusText:e.statusText})}):Promise.resolve(e)},createCacheKey=function(e,t,n,a){var c=new URL(e);return a&&c.pathname.match(a)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,t){var n=new URL(e);return n.search=n.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),n.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],a=new URL(t,self.location),c=createCacheKey(a,hashParamName,n,!1);return[a.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(n){if(!t.has(n)){var a=new Request(n,{credentials:"same-origin"});return fetch(a).then(function(t){if(!t.ok)throw new Error("Request for "+n+" returned a response with status "+t.status);return cleanResponse(t).then(function(t){return e.put(n,t)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(n){return Promise.all(n.map(function(n){if(!t.has(n.url))return e.delete(n)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,n=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(n);t||(n=addDirectoryIndex(n,"index.html"),t=urlsToCacheKeys.has(n));!t&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(n=new URL("/",self.location).toString(),t=urlsToCacheKeys.has(n)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url)&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var n,a;for(n=0;nm_T72Kc5`O=dUUX}8_oWb&ANNWB>l zxRjVsq)I||T*v>t2c#rRmgH=wA8bM(aqq>s=RN>y)zPTaZ7H=iDOR=AWmAtj(l3h_ zLe5FOYpc#C=dLBaYU>espXs)<9Z%1xwl@p*K3It5@fWMMx_9nRFRkfj^oBHM@Y&Xu zy3u7(N@0HdbWOE>A*w1D^0Q5@cJ7L@rB|zNzMZ`j{klu-4FgvRE%0ksj%VgvEoP7B zG3DypC0)|Jdt{0C=|=CEcA&erNKr+au;0xJmrbYBm-#1>dO&Y@<#-j z8lG55-L%^UXJ>oj+=8^6+t!6xmKVKwx87VYs^~(lZLr+C1?hRCF0EHD-@LWlISEB= zcWKc5`!KfetQSqKf#vuuHfvp4V!5o=8@>3{HMQmbu!4}b{7*l3Y5ho|rFLYU>wCw| z8+Cj6k2f!W^9*z98LSwbb}ib`vL$Jl0}Vwvn|}CUU0ANA{8-2^N`jQdJ|({5Ohy5v z%J(UYm~UOV_^@buv(&{>)KqmBimu0Gd_E4-G?uB){U8c6Kj(SoCqb4+DN{a|G4D}; z9#-&J6=5b4mBo=#k{2q9iX>M-QQ+^ip0X~Qu^&>JrX&-Q3aOY3vM3M2Ad4wujOTKr zCdqToIr_^-RUYC-_Li#dd6s9qDqGT9`0cC+ovVx_O#kA4H zl_*llqfGfw!GgF*SQh4tk{~I#U{7e$Len_KM}8t%sPZ`QGZk=INSP?6V!@z%3mo%F zWRb|@q=;ZZk#X)bmWq^9l<@qt9!-m7)vNNQio$>=i41u{k&I*R6H8Q)Mx5e&qblVR z*2pMiaG{d$mJA}86~SToNmWQI;~c&ZQtrz*gKtw2XF>%^fK)|6Ngi%Az=@K}ppY?M zW2<=-b4g6_BFae=(V)QqRLTq4ES4DLWmW3iaY`Yakw-=7Lx>DP2A+#76j=_>a^L&Z zK|z=>%%qV}ew0z*hcbXUOoXh6RTdA zMrj-|PDz5?LXiC}VXtYnszke%Ccw@l%T$!-;3Lms1UE+Y5eyOuxWcf*9QlfKo%l}MnK%(f`!GABPr zh=EUg5S0rtqYjm(RUa3CMtnrv-%|TApRKJC0iuR0E_oV6DhLpvA@V!R0!HAG*p+re zxrw}{MtbkYh&^-;WxWmqL4%Ho zS9s0D{S_78)aTouYeiqC4^50I{HFSesj0K?UjKrEI2rmH)IXGS;UUS)Ye@Gx zlv=XK+&Me5AEwWz+Hr-an>T$;wViucRwU}z)B&W9rbm0K7Je`$k$P@hrY>70rk}rR zn?>1~*IiRx6FLs_&bh?1YI56o+=S`9CTye9*6!V=eLz7PMy~PS%1jJ{_3yXzMQ`WK z57X*h9@t@a)e@>j-(CKbZuc;Bg0NT+h#+pu1DinXxr~e4-7ES>8UZ$6?pI~w|?-P+b52y8M_y0x5@AHY3lF{cQWQTQ400;4{a-MJ+u}J`w^PnwWwCqndGqtpy;CjZUzh{ zf_gXy0AJI;SH}0ky#r_p`z=M)U0NM1ALDc}D{Je1%hcg)Qy;N&kl%cE^t^3u`W*FB z+crRLtzlF&=5Qj;tZ@DtN(LIsx z;msol+8qzT(cR~A`5rzT=xY|ZCkSAUtJfgbJ_81BZjQz$T{8JUm~!GwFOKp>HVw*xD@;Uv5U5wU$Tm)Z|& zu!X1k0cWD8kG(Juf1*)}#Ppy`0ACQ?7!2LA}X~D0cq*Cp2VxJMUYP zZSFHC_x_%XChmCpGKvmgWa3lwqCc3FixV5$Y{flN*srp~v>yg2m z9(42x>ATJvnN&Jha5?(!<@ft|Ba^JJbhgty^G{QMx$5ReGQ?!KAAQR&M~WYa_%~P_00VN ziE@q24MM-Uv5sAP_8psBPe2s}9h->1Y}&|)I6rql>KfgMKsRFaAsd+NP&9JYnI^y9 z5We>MIop|F#l{R1YVUj1&bG)seq-yWv+TYzfZo0{o^%7g?!AEO{$HI5DIjAO001ff B*n$Ij@LDp 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 From 654ad41464917892ec5bdefee989d71f319fcd60 Mon Sep 17 00:00:00 2001 From: matt2005 Date: Mon, 24 Jul 2017 14:22:12 +0100 Subject: [PATCH 083/118] added onvif camera fix for non-virtual env installations (#8592) * added fix for non-virtual env installations * fixed new line at end of file * moved import os to top of file --- homeassistant/components/camera/onvif.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/camera/onvif.py b/homeassistant/components/camera/onvif.py index f1c94f79c0b2d..711eb75a7445e 100644 --- a/homeassistant/components/camera/onvif.py +++ b/homeassistant/components/camera/onvif.py @@ -6,6 +6,7 @@ """ import asyncio import logging +import os import voluptuous as vol @@ -54,6 +55,7 @@ class ONVIFCamera(Camera): def __init__(self, hass, config): """Initialize a ONVIF camera.""" from onvif import ONVIFService + import onvif super().__init__() self._name = config.get(CONF_NAME) @@ -63,7 +65,7 @@ def __init__(self, hass, config): config.get(CONF_HOST), config.get(CONF_PORT)), config.get(CONF_USERNAME), config.get(CONF_PASSWORD), - '{}/deps/onvif/wsdl/media.wsdl'.format(hass.config.config_dir) + '{}/wsdl/media.wsdl'.format(os.path.dirname(onvif.__file__)) ) self._input = media.GetStreamUri().Uri _LOGGER.debug("ONVIF Camera Using the following URL for %s: %s", From f86bd155801a704c9bb6a7080b603a762ce526d6 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jul 2017 16:45:02 +0200 Subject: [PATCH 084/118] Cleanup old device_tracker stuff (#8627) * Cleanup old device_tracker stuff * Fix lint --- .../components/device_tracker/actiontec.py | 26 +- .../components/device_tracker/aruba.py | 19 +- .../components/device_tracker/asuswrt.py | 33 +- .../device_tracker/bt_home_hub_5.py | 38 +- .../components/device_tracker/cisco_ios.py | 5 - .../components/device_tracker/ddwrt.py | 104 +++--- .../components/device_tracker/fritz.py | 5 - .../components/device_tracker/linksys_ap.py | 30 +- .../device_tracker/linksys_smart.py | 84 ++--- .../components/device_tracker/luci.py | 80 ++-- .../components/device_tracker/mikrotik.py | 98 +++-- .../components/device_tracker/netgear.py | 19 +- .../components/device_tracker/nmap_tracker.py | 6 +- .../components/device_tracker/sky_hub.py | 38 +- .../components/device_tracker/snmp.py | 20 +- .../components/device_tracker/swisscom.py | 26 +- .../components/device_tracker/thomson.py | 30 +- .../components/device_tracker/tomato.py | 85 ++--- .../components/device_tracker/tplink.py | 344 +++++++++--------- .../components/device_tracker/ubus.py | 86 ++--- .../components/device_tracker/volvooncall.py | 3 +- .../components/device_tracker/xiaomi.py | 46 +-- 22 files changed, 512 insertions(+), 713 deletions(-) diff --git a/homeassistant/components/device_tracker/actiontec.py b/homeassistant/components/device_tracker/actiontec.py index 882df57538523..64e1a60ad0867 100644 --- a/homeassistant/components/device_tracker/actiontec.py +++ b/homeassistant/components/device_tracker/actiontec.py @@ -7,9 +7,7 @@ import logging import re import telnetlib -import threading from collections import namedtuple -from datetime import timedelta import voluptuous as vol import homeassistant.helpers.config_validation as cv @@ -17,9 +15,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) _LOGGER = logging.getLogger(__name__) @@ -54,7 +49,6 @@ def __init__(self, config): self.host = config[CONF_HOST] self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] - self.lock = threading.Lock() self.last_results = [] data = self.get_actiontec_data() self.success_init = data is not None @@ -74,7 +68,6 @@ def get_device_name(self, device): return client.ip return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the router is up to date. @@ -84,16 +77,15 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - now = dt_util.now() - actiontec_data = self.get_actiontec_data() - if not actiontec_data: - return False - self.last_results = [Device(data['mac'], name, now) - for name, data in actiontec_data.items() - if data['timevalid'] > -60] - _LOGGER.info("Scan successful") - return True + now = dt_util.now() + actiontec_data = self.get_actiontec_data() + if not actiontec_data: + return False + self.last_results = [Device(data['mac'], name, now) + for name, data in actiontec_data.items() + if data['timevalid'] > -60] + _LOGGER.info("Scan successful") + return True def get_actiontec_data(self): """Retrieve data from Actiontec MI424WR and return parsed result.""" diff --git a/homeassistant/components/device_tracker/aruba.py b/homeassistant/components/device_tracker/aruba.py index bfb1588b323cc..cef5eabd90158 100644 --- a/homeassistant/components/device_tracker/aruba.py +++ b/homeassistant/components/device_tracker/aruba.py @@ -6,8 +6,6 @@ """ import logging import re -import threading -from datetime import timedelta import voluptuous as vol @@ -15,14 +13,11 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) REQUIREMENTS = ['pexpect==4.0.1'] -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - _DEVICES_REGEX = re.compile( r'(?P([^\s]+))\s+' + r'(?P([0-9]{1,3}[\.]){3}[0-9]{1,3})\s+' + @@ -52,8 +47,6 @@ def __init__(self, config): self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] - self.lock = threading.Lock() - self.last_results = {} # Test the router is accessible. @@ -74,7 +67,6 @@ def get_device_name(self, device): return client['name'] return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the Aruba Access Point is up to date. @@ -83,13 +75,12 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - data = self.get_aruba_data() - if not data: - return False + data = self.get_aruba_data() + if not data: + return False - self.last_results = data.values() - return True + self.last_results = data.values() + return True def get_aruba_data(self): """Retrieve data from Aruba Access Point and return parsed result.""" diff --git a/homeassistant/components/device_tracker/asuswrt.py b/homeassistant/components/device_tracker/asuswrt.py index b28d16cc4a181..9b214441ac965 100644 --- a/homeassistant/components/device_tracker/asuswrt.py +++ b/homeassistant/components/device_tracker/asuswrt.py @@ -8,9 +8,7 @@ import re import socket import telnetlib -import threading from collections import namedtuple -from datetime import timedelta import voluptuous as vol @@ -18,7 +16,6 @@ DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_PORT) -from homeassistant.util import Throttle import homeassistant.helpers.config_validation as cv REQUIREMENTS = ['pexpect==4.0.1'] @@ -32,8 +29,6 @@ DEFAULT_SSH_PORT = 22 -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - SECRET_GROUP = 'Password or SSH Key' PLATFORM_SCHEMA = vol.All( @@ -123,8 +118,6 @@ def __init__(self, config): self.password, self.mode == "ap") - self.lock = threading.Lock() - self.last_results = {} # Test the router is accessible. @@ -145,7 +138,6 @@ def get_device_name(self, device): return client['host'] return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the ASUSWRT router is up to date. @@ -154,19 +146,18 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - _LOGGER.info('Checking Devices') - data = self.get_asuswrt_data() - if not data: - return False - - active_clients = [client for client in data.values() if - client['status'] == 'REACHABLE' or - client['status'] == 'DELAY' or - client['status'] == 'STALE' or - client['status'] == 'IN_ASSOCLIST'] - self.last_results = active_clients - return True + _LOGGER.info('Checking Devices') + data = self.get_asuswrt_data() + if not data: + return False + + active_clients = [client for client in data.values() if + client['status'] == 'REACHABLE' or + client['status'] == 'DELAY' or + client['status'] == 'STALE' or + client['status'] == 'IN_ASSOCLIST'] + self.last_results = active_clients + return True def get_asuswrt_data(self): """Retrieve data from ASUSWRT and return parsed result.""" diff --git a/homeassistant/components/device_tracker/bt_home_hub_5.py b/homeassistant/components/device_tracker/bt_home_hub_5.py index 5c1a14b446b0f..a3b5bcac77c82 100644 --- a/homeassistant/components/device_tracker/bt_home_hub_5.py +++ b/homeassistant/components/device_tracker/bt_home_hub_5.py @@ -6,8 +6,6 @@ """ import logging import re -import threading -from datetime import timedelta import xml.etree.ElementTree as ET import json from urllib.parse import unquote @@ -19,13 +17,10 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST -from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) _MAC_REGEX = re.compile(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})') -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string }) @@ -46,11 +41,7 @@ def __init__(self, config): """Initialise the scanner.""" _LOGGER.info("Initialising BT Home Hub 5") self.host = config.get(CONF_HOST, '192.168.1.254') - - self.lock = threading.Lock() - self.last_results = {} - self.url = 'http://{}/nonAuth/home_status.xml'.format(self.host) # Test the router is accessible @@ -65,17 +56,15 @@ def scan_devices(self): def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" - with self.lock: - # If not initialised and not already scanned and not found. - if device not in self.last_results: - self._update_info() + # If not initialised and not already scanned and not found. + if device not in self.last_results: + self._update_info() - if not self.last_results: - return None + if not self.last_results: + return None - return self.last_results.get(device) + return self.last_results.get(device) - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the BT Home Hub 5 is up to date. @@ -84,18 +73,17 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - _LOGGER.info("Scanning") + _LOGGER.info("Scanning") - data = _get_homehub_data(self.url) + data = _get_homehub_data(self.url) - if not data: - _LOGGER.warning("Error scanning devices") - return False + if not data: + _LOGGER.warning("Error scanning devices") + return False - self.last_results = data + self.last_results = data - return True + return True def _get_homehub_data(url): diff --git a/homeassistant/components/device_tracker/cisco_ios.py b/homeassistant/components/device_tracker/cisco_ios.py index 99ed06de486bb..0978ba99593e6 100644 --- a/homeassistant/components/device_tracker/cisco_ios.py +++ b/homeassistant/components/device_tracker/cisco_ios.py @@ -5,7 +5,6 @@ https://home-assistant.io/components/device_tracker.cisco_ios/ """ import logging -from datetime import timedelta import voluptuous as vol @@ -14,9 +13,6 @@ DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, \ CONF_PORT -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) _LOGGER = logging.getLogger(__name__) @@ -65,7 +61,6 @@ def scan_devices(self): return self.last_results - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """ Ensure the information from the Cisco router is up to date. diff --git a/homeassistant/components/device_tracker/ddwrt.py b/homeassistant/components/device_tracker/ddwrt.py index 4f1efcdb27ccc..3d36a1b428c02 100644 --- a/homeassistant/components/device_tracker/ddwrt.py +++ b/homeassistant/components/device_tracker/ddwrt.py @@ -6,8 +6,6 @@ """ import logging import re -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -16,9 +14,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) _LOGGER = logging.getLogger(__name__) @@ -50,8 +45,6 @@ def __init__(self, config): self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] - self.lock = threading.Lock() - self.last_results = {} self.mac2name = {} @@ -69,68 +62,65 @@ def scan_devices(self): def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" - with self.lock: - # If not initialised and not already scanned and not found. - if device not in self.mac2name: - url = 'http://{}/Status_Lan.live.asp'.format(self.host) - data = self.get_ddwrt_data(url) - - if not data: - return None - - dhcp_leases = data.get('dhcp_leases', None) - - if not dhcp_leases: - return None - - # Remove leading and trailing quotes and spaces - cleaned_str = dhcp_leases.replace( - "\"", "").replace("\'", "").replace(" ", "") - elements = cleaned_str.split(',') - num_clients = int(len(elements) / 5) - self.mac2name = {} - for idx in range(0, num_clients): - # The data is a single array - # every 5 elements represents one host, the MAC - # is the third element and the name is the first. - mac_index = (idx * 5) + 2 - if mac_index < len(elements): - mac = elements[mac_index] - self.mac2name[mac] = elements[idx * 5] - - return self.mac2name.get(device) - - @Throttle(MIN_TIME_BETWEEN_SCANS) + # If not initialised and not already scanned and not found. + if device not in self.mac2name: + url = 'http://{}/Status_Lan.live.asp'.format(self.host) + data = self.get_ddwrt_data(url) + + if not data: + return None + + dhcp_leases = data.get('dhcp_leases', None) + + if not dhcp_leases: + return None + + # Remove leading and trailing quotes and spaces + cleaned_str = dhcp_leases.replace( + "\"", "").replace("\'", "").replace(" ", "") + elements = cleaned_str.split(',') + num_clients = int(len(elements) / 5) + self.mac2name = {} + for idx in range(0, num_clients): + # The data is a single array + # every 5 elements represents one host, the MAC + # is the third element and the name is the first. + mac_index = (idx * 5) + 2 + if mac_index < len(elements): + mac = elements[mac_index] + self.mac2name[mac] = elements[idx * 5] + + return self.mac2name.get(device) + def _update_info(self): """Ensure the information from the DD-WRT router is up to date. Return boolean if scanning successful. """ - with self.lock: - _LOGGER.info("Checking ARP") + _LOGGER.info("Checking ARP") - url = 'http://{}/Status_Wireless.live.asp'.format(self.host) - data = self.get_ddwrt_data(url) + url = 'http://{}/Status_Wireless.live.asp'.format(self.host) + data = self.get_ddwrt_data(url) - if not data: - return False + if not data: + return False - self.last_results = [] + self.last_results = [] - active_clients = data.get('active_wireless', None) - if not active_clients: - return False + active_clients = data.get('active_wireless', None) + if not active_clients: + return False - # The DD-WRT UI uses its own data format and then - # regex's out values so this is done here too - # Remove leading and trailing single quotes. - clean_str = active_clients.strip().strip("'") - elements = clean_str.split("','") + # The DD-WRT UI uses its own data format and then + # regex's out values so this is done here too + # Remove leading and trailing single quotes. + clean_str = active_clients.strip().strip("'") + elements = clean_str.split("','") - self.last_results.extend(item for item in elements - if _MAC_REGEX.match(item)) + self.last_results.extend(item for item in elements + if _MAC_REGEX.match(item)) - return True + return True def get_ddwrt_data(self, url): """Retrieve data from DD-WRT and return parsed result.""" diff --git a/homeassistant/components/device_tracker/fritz.py b/homeassistant/components/device_tracker/fritz.py index 25de0a35c8228..5210329179ff0 100644 --- a/homeassistant/components/device_tracker/fritz.py +++ b/homeassistant/components/device_tracker/fritz.py @@ -5,7 +5,6 @@ https://home-assistant.io/components/device_tracker.fritz/ """ import logging -from datetime import timedelta import voluptuous as vol @@ -13,12 +12,9 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle REQUIREMENTS = ['fritzconnection==0.6.3'] -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - _LOGGER = logging.getLogger(__name__) CONF_DEFAULT_IP = '169.254.1.1' # This IP is valid for all FRITZ!Box routers. @@ -88,7 +84,6 @@ def get_device_name(self, mac): return None return ret - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Retrieve latest information from the FRITZ!Box.""" if not self.success_init: diff --git a/homeassistant/components/device_tracker/linksys_ap.py b/homeassistant/components/device_tracker/linksys_ap.py index 01f97eb6e425e..196235f32f4f6 100644 --- a/homeassistant/components/device_tracker/linksys_ap.py +++ b/homeassistant/components/device_tracker/linksys_ap.py @@ -6,8 +6,6 @@ """ import base64 import logging -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -16,9 +14,7 @@ from homeassistant.components.device_tracker import DOMAIN, PLATFORM_SCHEMA from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_VERIFY_SSL) -from homeassistant.util import Throttle -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) INTERFACES = 2 DEFAULT_TIMEOUT = 10 @@ -51,8 +47,6 @@ def __init__(self, config): self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] self.verify_ssl = config[CONF_VERIFY_SSL] - - self.lock = threading.Lock() self.last_results = [] # Check if the access point is accessible @@ -76,24 +70,22 @@ def get_device_name(self, mac): """ return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Check for connected devices.""" from bs4 import BeautifulSoup as BS - with self.lock: - _LOGGER.info("Checking Linksys AP") - - self.last_results = [] - for interface in range(INTERFACES): - request = self._make_request(interface) - self.last_results.extend( - [x.find_all('td')[1].text - for x in BS(request.content, "html.parser") - .find_all(class_='section-row')] - ) + _LOGGER.info("Checking Linksys AP") - return True + self.last_results = [] + for interface in range(INTERFACES): + request = self._make_request(interface) + self.last_results.extend( + [x.find_all('td')[1].text + for x in BS(request.content, "html.parser") + .find_all(class_='section-row')] + ) + + return True def _make_request(self, unit=0): # No, the '&&' is not a typo - this is expected by the web interface. diff --git a/homeassistant/components/device_tracker/linksys_smart.py b/homeassistant/components/device_tracker/linksys_smart.py index e71502ba5eeeb..4bcbb600b8bdb 100644 --- a/homeassistant/components/device_tracker/linksys_smart.py +++ b/homeassistant/components/device_tracker/linksys_smart.py @@ -1,7 +1,5 @@ """Support for Linksys Smart Wifi routers.""" import logging -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -10,9 +8,7 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST -from homeassistant.util import Throttle -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) DEFAULT_TIMEOUT = 10 _LOGGER = logging.getLogger(__name__) @@ -36,8 +32,6 @@ class LinksysSmartWifiDeviceScanner(DeviceScanner): def __init__(self, config): """Initialize the scanner.""" self.host = config[CONF_HOST] - - self.lock = threading.Lock() self.last_results = {} # Check if the access point is accessible @@ -55,48 +49,46 @@ def get_device_name(self, mac): """Return the name (if known) of the device.""" return self.last_results.get(mac) - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Check for connected devices.""" - with self.lock: - _LOGGER.info("Checking Linksys Smart Wifi") - - self.last_results = {} - response = self._make_request() - if response.status_code != 200: - _LOGGER.error( - "Got HTTP status code %d when getting device list", - response.status_code) - return False - try: - data = response.json() - result = data["responses"][0] - devices = result["output"]["devices"] - for device in devices: - macs = device["knownMACAddresses"] - if not macs: - _LOGGER.warning( - "Skipping device without known MAC address") - continue - mac = macs[-1] - connections = device["connections"] - if not connections: - _LOGGER.debug("Device %s is not connected", mac) - continue - - name = None - for prop in device["properties"]: - if prop["name"] == "userDeviceName": - name = prop["value"] - if not name: - name = device.get("friendlyName", device["deviceID"]) - - _LOGGER.debug("Device %s is connected", mac) - self.last_results[mac] = name - except (KeyError, IndexError): - _LOGGER.exception("Router returned unexpected response") - return False - return True + _LOGGER.info("Checking Linksys Smart Wifi") + + self.last_results = {} + response = self._make_request() + if response.status_code != 200: + _LOGGER.error( + "Got HTTP status code %d when getting device list", + response.status_code) + return False + try: + data = response.json() + result = data["responses"][0] + devices = result["output"]["devices"] + for device in devices: + macs = device["knownMACAddresses"] + if not macs: + _LOGGER.warning( + "Skipping device without known MAC address") + continue + mac = macs[-1] + connections = device["connections"] + if not connections: + _LOGGER.debug("Device %s is not connected", mac) + continue + + name = None + for prop in device["properties"]: + if prop["name"] == "userDeviceName": + name = prop["value"] + if not name: + name = device.get("friendlyName", device["deviceID"]) + + _LOGGER.debug("Device %s is connected", mac) + self.last_results[mac] = name + except (KeyError, IndexError): + _LOGGER.exception("Router returned unexpected response") + return False + return True def _make_request(self): # Weirdly enough, this doesn't seem to require authentication diff --git a/homeassistant/components/device_tracker/luci.py b/homeassistant/components/device_tracker/luci.py index 24af81b281e76..a4b826a009f90 100644 --- a/homeassistant/components/device_tracker/luci.py +++ b/homeassistant/components/device_tracker/luci.py @@ -7,8 +7,6 @@ import json import logging import re -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -18,9 +16,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) _LOGGER = logging.getLogger(__name__) @@ -55,12 +50,8 @@ def __init__(self, config): self.parse_api_pattern = re.compile(r"(?P\w*) = (?P.*);") - self.lock = threading.Lock() - self.last_results = {} - self.refresh_token() - self.mac2name = None self.success_init = self.token is not None @@ -75,24 +66,22 @@ def scan_devices(self): def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" - with self.lock: - if self.mac2name is None: - url = 'http://{}/cgi-bin/luci/rpc/uci'.format(self.host) - result = _req_json_rpc(url, 'get_all', 'dhcp', - params={'auth': self.token}) - if result: - hosts = [x for x in result.values() - if x['.type'] == 'host' and - 'mac' in x and 'name' in x] - mac2name_list = [ - (x['mac'].upper(), x['name']) for x in hosts] - self.mac2name = dict(mac2name_list) - else: - # Error, handled in the _req_json_rpc - return - return self.mac2name.get(device.upper(), None) - - @Throttle(MIN_TIME_BETWEEN_SCANS) + if self.mac2name is None: + url = 'http://{}/cgi-bin/luci/rpc/uci'.format(self.host) + result = _req_json_rpc(url, 'get_all', 'dhcp', + params={'auth': self.token}) + if result: + hosts = [x for x in result.values() + if x['.type'] == 'host' and + 'mac' in x and 'name' in x] + mac2name_list = [ + (x['mac'].upper(), x['name']) for x in hosts] + self.mac2name = dict(mac2name_list) + else: + # Error, handled in the _req_json_rpc + return + return self.mac2name.get(device.upper(), None) + def _update_info(self): """Ensure the information from the Luci router is up to date. @@ -101,30 +90,29 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - _LOGGER.info("Checking ARP") + _LOGGER.info("Checking ARP") - url = 'http://{}/cgi-bin/luci/rpc/sys'.format(self.host) + url = 'http://{}/cgi-bin/luci/rpc/sys'.format(self.host) - try: - result = _req_json_rpc(url, 'net.arptable', - params={'auth': self.token}) - except InvalidLuciTokenError: - _LOGGER.info("Refreshing token") - self.refresh_token() - return False + try: + result = _req_json_rpc(url, 'net.arptable', + params={'auth': self.token}) + except InvalidLuciTokenError: + _LOGGER.info("Refreshing token") + self.refresh_token() + return False - if result: - self.last_results = [] - for device_entry in result: - # Check if the Flags for each device contain - # NUD_REACHABLE and if so, add it to last_results - if int(device_entry['Flags'], 16) & 0x2: - self.last_results.append(device_entry['HW address']) + if result: + self.last_results = [] + for device_entry in result: + # Check if the Flags for each device contain + # NUD_REACHABLE and if so, add it to last_results + if int(device_entry['Flags'], 16) & 0x2: + self.last_results.append(device_entry['HW address']) - return True + return True - return False + return False def _req_json_rpc(url, method, *args, **kwargs): diff --git a/homeassistant/components/device_tracker/mikrotik.py b/homeassistant/components/device_tracker/mikrotik.py index fc1918f08cc02..4e43b6ac10ddc 100644 --- a/homeassistant/components/device_tracker/mikrotik.py +++ b/homeassistant/components/device_tracker/mikrotik.py @@ -5,25 +5,17 @@ https://home-assistant.io/components/device_tracker.mikrotik/ """ import logging -import threading -from datetime import timedelta import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) -from homeassistant.const import (CONF_HOST, - CONF_PASSWORD, - CONF_USERNAME, - CONF_PORT) -from homeassistant.util import Throttle +from homeassistant.const import ( + CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_PORT) REQUIREMENTS = ['librouteros==1.0.2'] -# Return cached results if last scan was less then this time ago. -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - MTK_DEFAULT_API_PORT = '8728' _LOGGER = logging.getLogger(__name__) @@ -54,12 +46,9 @@ def __init__(self, config): self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] - self.lock = threading.Lock() - self.connected = False self.success_init = False self.client = None - self.wireless_exist = None self.success_init = self.connect_to_device() @@ -118,51 +107,48 @@ def scan_devices(self): def get_device_name(self, mac): """Return the name of the given device or None if we don't know.""" - with self.lock: - return self.last_results.get(mac) + return self.last_results.get(mac) - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Retrieve latest information from the Mikrotik box.""" - with self.lock: - if self.wireless_exist: - devices_tracker = 'wireless' - else: - devices_tracker = 'ip' - - _LOGGER.info( - "Loading %s devices from Mikrotik (%s) ...", - devices_tracker, - self.host + if self.wireless_exist: + devices_tracker = 'wireless' + else: + devices_tracker = 'ip' + + _LOGGER.info( + "Loading %s devices from Mikrotik (%s) ...", + devices_tracker, + self.host + ) + + device_names = self.client(cmd='/ip/dhcp-server/lease/getall') + if self.wireless_exist: + devices = self.client( + cmd='/interface/wireless/registration-table/getall' ) + else: + devices = device_names - device_names = self.client(cmd='/ip/dhcp-server/lease/getall') - if self.wireless_exist: - devices = self.client( - cmd='/interface/wireless/registration-table/getall' - ) - else: - devices = device_names - - if device_names is None and devices is None: - return False - - mac_names = {device.get('mac-address'): device.get('host-name') - for device in device_names - if device.get('mac-address')} - - if self.wireless_exist: - self.last_results = { - device.get('mac-address'): - mac_names.get(device.get('mac-address')) - for device in devices - } - else: - self.last_results = { - device.get('mac-address'): - mac_names.get(device.get('mac-address')) - for device in device_names - if device.get('active-address') - } - - return True + if device_names is None and devices is None: + return False + + mac_names = {device.get('mac-address'): device.get('host-name') + for device in device_names + if device.get('mac-address')} + + if self.wireless_exist: + self.last_results = { + device.get('mac-address'): + mac_names.get(device.get('mac-address')) + for device in devices + } + else: + self.last_results = { + device.get('mac-address'): + mac_names.get(device.get('mac-address')) + for device in device_names + if device.get('active-address') + } + + return True diff --git a/homeassistant/components/device_tracker/netgear.py b/homeassistant/components/device_tracker/netgear.py index b3ec442198ebf..d2b8bc274ca3a 100644 --- a/homeassistant/components/device_tracker/netgear.py +++ b/homeassistant/components/device_tracker/netgear.py @@ -5,8 +5,6 @@ https://home-assistant.io/components/device_tracker.netgear/ """ import logging -import threading -from datetime import timedelta import voluptuous as vol @@ -15,14 +13,11 @@ DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import ( CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_PORT) -from homeassistant.util import Throttle REQUIREMENTS = ['pynetgear==0.3.3'] _LOGGER = logging.getLogger(__name__) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - DEFAULT_HOST = 'routerlogin.net' DEFAULT_USER = 'admin' DEFAULT_PORT = 5000 @@ -56,8 +51,6 @@ def __init__(self, host, username, password, port): import pynetgear self.last_results = [] - self.lock = threading.Lock() - self._api = pynetgear.Netgear(password, host, username, port) _LOGGER.info("Logging in") @@ -85,7 +78,6 @@ def get_device_name(self, mac): except StopIteration: return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Retrieve latest information from the Netgear router. @@ -94,12 +86,11 @@ def _update_info(self): if not self.success_init: return - with self.lock: - _LOGGER.info("Scanning") + _LOGGER.info("Scanning") - results = self._api.get_attached_devices() + results = self._api.get_attached_devices() - if results is None: - _LOGGER.warning("Error scanning devices") + if results is None: + _LOGGER.warning("Error scanning devices") - self.last_results = results or [] + self.last_results = results or [] diff --git a/homeassistant/components/device_tracker/nmap_tracker.py b/homeassistant/components/device_tracker/nmap_tracker.py index 8a845adf0b804..e9d70142ad11e 100644 --- a/homeassistant/components/device_tracker/nmap_tracker.py +++ b/homeassistant/components/device_tracker/nmap_tracker.py @@ -4,11 +4,11 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/device_tracker.nmap_tracker/ """ +from datetime import timedelta import logging import re import subprocess from collections import namedtuple -from datetime import timedelta import voluptuous as vol @@ -17,7 +17,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOSTS -from homeassistant.util import Throttle REQUIREMENTS = ['python-nmap==0.6.1'] @@ -29,8 +28,6 @@ CONF_OPTIONS = 'scan_options' DEFAULT_OPTIONS = '-F --host-timeout 5s' -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOSTS): cv.ensure_list, @@ -97,7 +94,6 @@ def get_device_name(self, mac): return filter_named[0] return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Scan the network for devices. diff --git a/homeassistant/components/device_tracker/sky_hub.py b/homeassistant/components/device_tracker/sky_hub.py index ef58c50991cb7..c48c9bd029b94 100644 --- a/homeassistant/components/device_tracker/sky_hub.py +++ b/homeassistant/components/device_tracker/sky_hub.py @@ -6,8 +6,6 @@ """ import logging import re -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -16,13 +14,10 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST -from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) _MAC_REGEX = re.compile(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})') -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string }) @@ -43,11 +38,7 @@ def __init__(self, config): """Initialise the scanner.""" _LOGGER.info("Initialising Sky Hub") self.host = config.get(CONF_HOST, '192.168.1.254') - - self.lock = threading.Lock() - self.last_results = {} - self.url = 'http://{}/'.format(self.host) # Test the router is accessible @@ -62,17 +53,15 @@ def scan_devices(self): def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" - with self.lock: - # If not initialised and not already scanned and not found. - if device not in self.last_results: - self._update_info() + # If not initialised and not already scanned and not found. + if device not in self.last_results: + self._update_info() - if not self.last_results: - return None + if not self.last_results: + return None - return self.last_results.get(device) + return self.last_results.get(device) - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the Sky Hub is up to date. @@ -81,18 +70,17 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - _LOGGER.info("Scanning") + _LOGGER.info("Scanning") - data = _get_skyhub_data(self.url) + data = _get_skyhub_data(self.url) - if not data: - _LOGGER.warning('Error scanning devices') - return False + if not data: + _LOGGER.warning('Error scanning devices') + return False - self.last_results = data + self.last_results = data - return True + return True def _get_skyhub_data(url): diff --git a/homeassistant/components/device_tracker/snmp.py b/homeassistant/components/device_tracker/snmp.py index a3be40036cb1d..46b1686b21dbf 100644 --- a/homeassistant/components/device_tracker/snmp.py +++ b/homeassistant/components/device_tracker/snmp.py @@ -6,8 +6,6 @@ """ import binascii import logging -import threading -from datetime import timedelta import voluptuous as vol @@ -15,7 +13,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST -from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) @@ -28,8 +25,6 @@ DEFAULT_COMMUNITY = 'public' -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_COMMUNITY, default=DEFAULT_COMMUNITY): cv.string, @@ -68,9 +63,6 @@ def __init__(self, config): privProtocol=cfg.usmAesCfb128Protocol ) self.baseoid = cmdgen.MibVariable(config[CONF_BASEOID]) - - self.lock = threading.Lock() - self.last_results = [] # Test the router is accessible @@ -90,7 +82,6 @@ def get_device_name(self, device): # We have no names return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the device is up to date. @@ -99,13 +90,12 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - data = self.get_snmp_data() - if not data: - return False + data = self.get_snmp_data() + if not data: + return False - self.last_results = data - return True + self.last_results = data + return True def get_snmp_data(self): """Fetch MAC addresses from access point via SNMP.""" diff --git a/homeassistant/components/device_tracker/swisscom.py b/homeassistant/components/device_tracker/swisscom.py index d2a5a57e4910d..e64d30942ca92 100644 --- a/homeassistant/components/device_tracker/swisscom.py +++ b/homeassistant/components/device_tracker/swisscom.py @@ -5,8 +5,6 @@ https://home-assistant.io/components/device_tracker.swisscom/ """ import logging -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -15,9 +13,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) _LOGGER = logging.getLogger(__name__) @@ -41,9 +36,6 @@ class SwisscomDeviceScanner(DeviceScanner): def __init__(self, config): """Initialize the scanner.""" self.host = config[CONF_HOST] - - self.lock = threading.Lock() - self.last_results = {} # Test the router is accessible. @@ -64,7 +56,6 @@ def get_device_name(self, device): return client['host'] return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the Swisscom router is up to date. @@ -73,16 +64,15 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - _LOGGER.info("Loading data from Swisscom Internet Box") - data = self.get_swisscom_data() - if not data: - return False + _LOGGER.info("Loading data from Swisscom Internet Box") + data = self.get_swisscom_data() + if not data: + return False - active_clients = [client for client in data.values() if - client['status']] - self.last_results = active_clients - return True + active_clients = [client for client in data.values() if + client['status']] + self.last_results = active_clients + return True def get_swisscom_data(self): """Retrieve data from Swisscom and return parsed result.""" diff --git a/homeassistant/components/device_tracker/thomson.py b/homeassistant/components/device_tracker/thomson.py index 6efe8d59bebdc..3fa161e467dec 100644 --- a/homeassistant/components/device_tracker/thomson.py +++ b/homeassistant/components/device_tracker/thomson.py @@ -7,8 +7,6 @@ import logging import re import telnetlib -import threading -from datetime import timedelta import voluptuous as vol @@ -16,9 +14,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) _LOGGER = logging.getLogger(__name__) @@ -54,9 +49,6 @@ def __init__(self, config): self.host = config[CONF_HOST] self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] - - self.lock = threading.Lock() - self.last_results = {} # Test the router is accessible. @@ -77,7 +69,6 @@ def get_device_name(self, device): return client['host'] return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the THOMSON router is up to date. @@ -86,17 +77,16 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - _LOGGER.info("Checking ARP") - data = self.get_thomson_data() - if not data: - return False - - # Flag C stands for CONNECTED - active_clients = [client for client in data.values() if - client['status'].find('C') != -1] - self.last_results = active_clients - return True + _LOGGER.info("Checking ARP") + data = self.get_thomson_data() + if not data: + return False + + # Flag C stands for CONNECTED + active_clients = [client for client in data.values() if + client['status'].find('C') != -1] + self.last_results = active_clients + return True def get_thomson_data(self): """Retrieve data from THOMSON and return parsed result.""" diff --git a/homeassistant/components/device_tracker/tomato.py b/homeassistant/components/device_tracker/tomato.py index 0b330c933d8d8..57e83eaeb94a9 100644 --- a/homeassistant/components/device_tracker/tomato.py +++ b/homeassistant/components/device_tracker/tomato.py @@ -7,8 +7,6 @@ import json import logging import re -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -17,9 +15,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) CONF_HTTP_ID = 'http_id' @@ -54,8 +49,6 @@ def __init__(self, config): self.parse_api_pattern = re.compile(r"(?P\w*) = (?P.*);") self.logger = logging.getLogger("{}.{}".format(__name__, "Tomato")) - self.lock = threading.Lock() - self.last_results = {"wldev": [], "dhcpd_lease": []} self.success_init = self._update_tomato_info() @@ -76,50 +69,48 @@ def get_device_name(self, device): return filter_named[0] - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_tomato_info(self): """Ensure the information from the Tomato router is up to date. Return boolean if scanning successful. """ - with self.lock: - self.logger.info("Scanning") - - try: - response = requests.Session().send(self.req, timeout=3) - # Calling and parsing the Tomato api here. We only need the - # wldev and dhcpd_lease values. - if response.status_code == 200: - - for param, value in \ - self.parse_api_pattern.findall(response.text): - - if param == 'wldev' or param == 'dhcpd_lease': - self.last_results[param] = \ - json.loads(value.replace("'", '"')) - return True - - elif response.status_code == 401: - # Authentication error - self.logger.exception(( - "Failed to authenticate, " - "please check your username and password")) - return False - - except requests.exceptions.ConnectionError: - # We get this if we could not connect to the router or - # an invalid http_id was supplied. - self.logger.exception("Failed to connect to the router or " - "invalid http_id supplied") + self.logger.info("Scanning") + + try: + response = requests.Session().send(self.req, timeout=3) + # Calling and parsing the Tomato api here. We only need the + # wldev and dhcpd_lease values. + if response.status_code == 200: + + for param, value in \ + self.parse_api_pattern.findall(response.text): + + if param == 'wldev' or param == 'dhcpd_lease': + self.last_results[param] = \ + json.loads(value.replace("'", '"')) + return True + + elif response.status_code == 401: + # Authentication error + self.logger.exception(( + "Failed to authenticate, " + "please check your username and password")) return False - except requests.exceptions.Timeout: - # We get this if we could not connect to the router or - # an invalid http_id was supplied. - self.logger.exception("Connection to the router timed out") - return False - - except ValueError: - # If JSON decoder could not parse the response. - self.logger.exception("Failed to parse response from router") - return False + except requests.exceptions.ConnectionError: + # We get this if we could not connect to the router or + # an invalid http_id was supplied. + self.logger.exception("Failed to connect to the router or " + "invalid http_id supplied") + return False + + except requests.exceptions.Timeout: + # We get this if we could not connect to the router or + # an invalid http_id was supplied. + self.logger.exception("Connection to the router timed out") + return False + + except ValueError: + # If JSON decoder could not parse the response. + self.logger.exception("Failed to parse response from router") + return False diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index ccf0c2d01afb3..a52de48d061cf 100755 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -8,8 +8,7 @@ import hashlib import logging import re -import threading -from datetime import timedelta, datetime +from datetime import datetime import requests import voluptuous as vol @@ -18,9 +17,6 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle - -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) _LOGGER = logging.getLogger(__name__) @@ -59,7 +55,6 @@ def __init__(self, config): self.password = password self.last_results = {} - self.lock = threading.Lock() self.success_init = self._update_info() def scan_devices(self): @@ -72,28 +67,26 @@ def get_device_name(self, device): """Get firmware doesn't save the name of the wireless device.""" return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the TP-Link router is up to date. Return boolean if scanning successful. """ - with self.lock: - _LOGGER.info("Loading wireless clients...") + _LOGGER.info("Loading wireless clients...") - url = 'http://{}/userRpm/WlanStationRpm.htm'.format(self.host) - referer = 'http://{}'.format(self.host) - page = requests.get( - url, auth=(self.username, self.password), - headers={'referer': referer}, timeout=4) + url = 'http://{}/userRpm/WlanStationRpm.htm'.format(self.host) + referer = 'http://{}'.format(self.host) + page = requests.get( + url, auth=(self.username, self.password), + headers={'referer': referer}, timeout=4) - result = self.parse_macs.findall(page.text) + result = self.parse_macs.findall(page.text) - if result: - self.last_results = [mac.replace("-", ":") for mac in result] - return True + if result: + self.last_results = [mac.replace("-", ":") for mac in result] + return True - return False + return False class Tplink2DeviceScanner(TplinkDeviceScanner): @@ -109,47 +102,45 @@ def get_device_name(self, device): """Get firmware doesn't save the name of the wireless device.""" return self.last_results.get(device) - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the TP-Link router is up to date. Return boolean if scanning successful. """ - with self.lock: - _LOGGER.info("Loading wireless clients...") + _LOGGER.info("Loading wireless clients...") - url = 'http://{}/data/map_access_wireless_client_grid.json' \ - .format(self.host) - referer = 'http://{}'.format(self.host) + url = 'http://{}/data/map_access_wireless_client_grid.json' \ + .format(self.host) + referer = 'http://{}'.format(self.host) - # Router uses Authorization cookie instead of header - # Let's create the cookie - username_password = '{}:{}'.format(self.username, self.password) - b64_encoded_username_password = base64.b64encode( - username_password.encode('ascii') - ).decode('ascii') - cookie = 'Authorization=Basic {}' \ - .format(b64_encoded_username_password) + # Router uses Authorization cookie instead of header + # Let's create the cookie + username_password = '{}:{}'.format(self.username, self.password) + b64_encoded_username_password = base64.b64encode( + username_password.encode('ascii') + ).decode('ascii') + cookie = 'Authorization=Basic {}' \ + .format(b64_encoded_username_password) - response = requests.post( - url, headers={'referer': referer, 'cookie': cookie}, - timeout=4) + response = requests.post( + url, headers={'referer': referer, 'cookie': cookie}, + timeout=4) - try: - result = response.json().get('data') - except ValueError: - _LOGGER.error("Router didn't respond with JSON. " - "Check if credentials are correct.") - return False + try: + result = response.json().get('data') + except ValueError: + _LOGGER.error("Router didn't respond with JSON. " + "Check if credentials are correct.") + return False - if result: - self.last_results = { - device['mac_addr'].replace('-', ':'): device['name'] - for device in result - } - return True + if result: + self.last_results = { + device['mac_addr'].replace('-', ':'): device['name'] + for device in result + } + return True - return False + return False class Tplink3DeviceScanner(TplinkDeviceScanner): @@ -202,70 +193,67 @@ def _get_auth_tokens(self): response.text) return False - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the TP-Link router is up to date. Return boolean if scanning successful. """ - with self.lock: - if (self.stok == '') or (self.sysauth == ''): - self._get_auth_tokens() - - _LOGGER.info("Loading wireless clients...") - - url = ('http://{}/cgi-bin/luci/;stok={}/admin/wireless?' - 'form=statistics').format(self.host, self.stok) - referer = 'http://{}/webpages/index.html'.format(self.host) - - response = requests.post(url, - params={'operation': 'load'}, - headers={'referer': referer}, - cookies={'sysauth': self.sysauth}, - timeout=5) - - try: - json_response = response.json() - - if json_response.get('success'): - result = response.json().get('data') - else: - if json_response.get('errorcode') == 'timeout': - _LOGGER.info("Token timed out. Relogging on next scan") - self.stok = '' - self.sysauth = '' - return False - _LOGGER.error( - "An unknown error happened while fetching data") + if (self.stok == '') or (self.sysauth == ''): + self._get_auth_tokens() + + _LOGGER.info("Loading wireless clients...") + + url = ('http://{}/cgi-bin/luci/;stok={}/admin/wireless?' + 'form=statistics').format(self.host, self.stok) + referer = 'http://{}/webpages/index.html'.format(self.host) + + response = requests.post(url, + params={'operation': 'load'}, + headers={'referer': referer}, + cookies={'sysauth': self.sysauth}, + timeout=5) + + try: + json_response = response.json() + + if json_response.get('success'): + result = response.json().get('data') + else: + if json_response.get('errorcode') == 'timeout': + _LOGGER.info("Token timed out. Relogging on next scan") + self.stok = '' + self.sysauth = '' return False - except ValueError: - _LOGGER.error("Router didn't respond with JSON. " - "Check if credentials are correct") + _LOGGER.error( + "An unknown error happened while fetching data") return False + except ValueError: + _LOGGER.error("Router didn't respond with JSON. " + "Check if credentials are correct") + return False - if result: - self.last_results = { - device['mac'].replace('-', ':'): device['mac'] - for device in result - } - return True + if result: + self.last_results = { + device['mac'].replace('-', ':'): device['mac'] + for device in result + } + return True - return False + return False def _log_out(self): - with self.lock: - _LOGGER.info("Logging out of router admin interface...") + _LOGGER.info("Logging out of router admin interface...") - url = ('http://{}/cgi-bin/luci/;stok={}/admin/system?' - 'form=logout').format(self.host, self.stok) - referer = 'http://{}/webpages/index.html'.format(self.host) + url = ('http://{}/cgi-bin/luci/;stok={}/admin/system?' + 'form=logout').format(self.host, self.stok) + referer = 'http://{}/webpages/index.html'.format(self.host) - requests.post(url, - params={'operation': 'write'}, - headers={'referer': referer}, - cookies={'sysauth': self.sysauth}) - self.stok = '' - self.sysauth = '' + requests.post(url, + params={'operation': 'write'}, + headers={'referer': referer}, + cookies={'sysauth': self.sysauth}) + self.stok = '' + self.sysauth = '' class Tplink4DeviceScanner(TplinkDeviceScanner): @@ -318,38 +306,36 @@ def _get_auth_tokens(self): _LOGGER.error("Couldn't fetch auth tokens") return False - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the TP-Link router is up to date. Return boolean if scanning successful. """ - with self.lock: - if (self.credentials == '') or (self.token == ''): - self._get_auth_tokens() + if (self.credentials == '') or (self.token == ''): + self._get_auth_tokens() - _LOGGER.info("Loading wireless clients...") + _LOGGER.info("Loading wireless clients...") - mac_results = [] + mac_results = [] - # Check both the 2.4GHz and 5GHz client list URLs - for clients_url in ('WlanStationRpm.htm', 'WlanStationRpm_5g.htm'): - url = 'http://{}/{}/userRpm/{}' \ - .format(self.host, self.token, clients_url) - referer = 'http://{}'.format(self.host) - cookie = 'Authorization=Basic {}'.format(self.credentials) + # Check both the 2.4GHz and 5GHz client list URLs + for clients_url in ('WlanStationRpm.htm', 'WlanStationRpm_5g.htm'): + url = 'http://{}/{}/userRpm/{}' \ + .format(self.host, self.token, clients_url) + referer = 'http://{}'.format(self.host) + cookie = 'Authorization=Basic {}'.format(self.credentials) - page = requests.get(url, headers={ - 'cookie': cookie, - 'referer': referer - }) - mac_results.extend(self.parse_macs.findall(page.text)) + page = requests.get(url, headers={ + 'cookie': cookie, + 'referer': referer + }) + mac_results.extend(self.parse_macs.findall(page.text)) - if not mac_results: - return False + if not mac_results: + return False - self.last_results = [mac.replace("-", ":") for mac in mac_results] - return True + self.last_results = [mac.replace("-", ":") for mac in mac_results] + return True class Tplink5DeviceScanner(TplinkDeviceScanner): @@ -365,69 +351,67 @@ def get_device_name(self, device): """Get firmware doesn't save the name of the wireless device.""" return None - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the TP-Link AP is up to date. Return boolean if scanning successful. """ - with self.lock: - _LOGGER.info("Loading wireless clients...") - - base_url = 'http://{}'.format(self.host) - - header = { - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12;" - " rv:53.0) Gecko/20100101 Firefox/53.0", - "Accept": "application/json, text/javascript, */*; q=0.01", - "Accept-Language": "Accept-Language: en-US,en;q=0.5", - "Accept-Encoding": "gzip, deflate", - "Content-Type": "application/x-www-form-urlencoded; " - "charset=UTF-8", - "X-Requested-With": "XMLHttpRequest", - "Referer": "http://" + self.host + "/", - "Connection": "keep-alive", - "Pragma": "no-cache", - "Cache-Control": "no-cache" - } - - password_md5 = hashlib.md5( - self.password.encode('utf')).hexdigest().upper() - - # create a session to handle cookie easier - session = requests.session() - session.get(base_url, headers=header) - - login_data = {"username": self.username, "password": password_md5} - session.post(base_url, login_data, headers=header) - - # a timestamp is required to be sent as get parameter - timestamp = int(datetime.now().timestamp() * 1e3) - - client_list_url = '{}/data/monitor.client.client.json'.format( - base_url) - - get_params = { - 'operation': 'load', - '_': timestamp - } - - response = session.get(client_list_url, - headers=header, - params=get_params) - session.close() - try: - list_of_devices = response.json() - except ValueError: - _LOGGER.error("AP didn't respond with JSON. " - "Check if credentials are correct.") - return False + _LOGGER.info("Loading wireless clients...") + + base_url = 'http://{}'.format(self.host) + + header = { + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12;" + " rv:53.0) Gecko/20100101 Firefox/53.0", + "Accept": "application/json, text/javascript, */*; q=0.01", + "Accept-Language": "Accept-Language: en-US,en;q=0.5", + "Accept-Encoding": "gzip, deflate", + "Content-Type": "application/x-www-form-urlencoded; " + "charset=UTF-8", + "X-Requested-With": "XMLHttpRequest", + "Referer": "http://" + self.host + "/", + "Connection": "keep-alive", + "Pragma": "no-cache", + "Cache-Control": "no-cache" + } + + password_md5 = hashlib.md5( + self.password.encode('utf')).hexdigest().upper() + + # create a session to handle cookie easier + session = requests.session() + session.get(base_url, headers=header) + + login_data = {"username": self.username, "password": password_md5} + session.post(base_url, login_data, headers=header) + + # a timestamp is required to be sent as get parameter + timestamp = int(datetime.now().timestamp() * 1e3) + + client_list_url = '{}/data/monitor.client.client.json'.format( + base_url) + + get_params = { + 'operation': 'load', + '_': timestamp + } + + response = session.get(client_list_url, + headers=header, + params=get_params) + session.close() + try: + list_of_devices = response.json() + except ValueError: + _LOGGER.error("AP didn't respond with JSON. " + "Check if credentials are correct.") + return False - if list_of_devices: - self.last_results = { - device['MAC'].replace('-', ':'): device['DeviceName'] - for device in list_of_devices['data'] - } - return True + if list_of_devices: + self.last_results = { + device['MAC'].replace('-', ':'): device['DeviceName'] + for device in list_of_devices['data'] + } + return True - return False + return False diff --git a/homeassistant/components/device_tracker/ubus.py b/homeassistant/components/device_tracker/ubus.py index 8d4cd1dcd739c..64b9a633cbd94 100644 --- a/homeassistant/components/device_tracker/ubus.py +++ b/homeassistant/components/device_tracker/ubus.py @@ -7,8 +7,6 @@ import json import logging import re -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -17,12 +15,8 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle from homeassistant.exceptions import HomeAssistantError -# Return cached results if last scan was less then this time ago. -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - _LOGGER = logging.getLogger(__name__) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -70,7 +64,6 @@ def __init__(self, config): self.password = config[CONF_PASSWORD] self.parse_api_pattern = re.compile(r"(?P\w*) = (?P.*);") - self.lock = threading.Lock() self.last_results = {} self.url = 'http://{}/ubus'.format(host) @@ -89,34 +82,32 @@ def scan_devices(self): @_refresh_on_acccess_denied def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" - with self.lock: - if self.leasefile is None: - result = _req_json_rpc( - self.url, self.session_id, 'call', 'uci', 'get', - config="dhcp", type="dnsmasq") - if result: - values = result["values"].values() - self.leasefile = next(iter(values))["leasefile"] - else: - return - - if self.mac2name is None: - result = _req_json_rpc( - self.url, self.session_id, 'call', 'file', 'read', - path=self.leasefile) - if result: - self.mac2name = dict() - for line in result["data"].splitlines(): - hosts = line.split(" ") - self.mac2name[hosts[1].upper()] = hosts[3] - else: - # Error, handled in the _req_json_rpc - return - - return self.mac2name.get(device.upper(), None) + if self.leasefile is None: + result = _req_json_rpc( + self.url, self.session_id, 'call', 'uci', 'get', + config="dhcp", type="dnsmasq") + if result: + values = result["values"].values() + self.leasefile = next(iter(values))["leasefile"] + else: + return + + if self.mac2name is None: + result = _req_json_rpc( + self.url, self.session_id, 'call', 'file', 'read', + path=self.leasefile) + if result: + self.mac2name = dict() + for line in result["data"].splitlines(): + hosts = line.split(" ") + self.mac2name[hosts[1].upper()] = hosts[3] + else: + # Error, handled in the _req_json_rpc + return + + return self.mac2name.get(device.upper(), None) @_refresh_on_acccess_denied - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the Luci router is up to date. @@ -125,25 +116,24 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - _LOGGER.info("Checking ARP") + _LOGGER.info("Checking ARP") - if not self.hostapd: - hostapd = _req_json_rpc( - self.url, self.session_id, 'list', 'hostapd.*', '') - self.hostapd.extend(hostapd.keys()) + if not self.hostapd: + hostapd = _req_json_rpc( + self.url, self.session_id, 'list', 'hostapd.*', '') + self.hostapd.extend(hostapd.keys()) - self.last_results = [] - results = 0 - for hostapd in self.hostapd: - result = _req_json_rpc( - self.url, self.session_id, 'call', hostapd, 'get_clients') + self.last_results = [] + results = 0 + for hostapd in self.hostapd: + result = _req_json_rpc( + self.url, self.session_id, 'call', hostapd, 'get_clients') - if result: - results = results + 1 - self.last_results.extend(result['clients'].keys()) + if result: + results = results + 1 + self.last_results.extend(result['clients'].keys()) - return bool(results) + return bool(results) def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params): diff --git a/homeassistant/components/device_tracker/volvooncall.py b/homeassistant/components/device_tracker/volvooncall.py index 9bd5727510ad3..4312c5dd54a19 100644 --- a/homeassistant/components/device_tracker/volvooncall.py +++ b/homeassistant/components/device_tracker/volvooncall.py @@ -9,8 +9,7 @@ from homeassistant.util import slugify from homeassistant.helpers.dispatcher import ( dispatcher_connect, dispatcher_send) -from homeassistant.components.volvooncall import ( - DATA_KEY, SIGNAL_VEHICLE_SEEN) +from homeassistant.components.volvooncall import DATA_KEY, SIGNAL_VEHICLE_SEEN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/device_tracker/xiaomi.py b/homeassistant/components/device_tracker/xiaomi.py index a7b0a1ad3267f..8b8db3da2d8b8 100644 --- a/homeassistant/components/device_tracker/xiaomi.py +++ b/homeassistant/components/device_tracker/xiaomi.py @@ -5,8 +5,6 @@ https://home-assistant.io/components/device_tracker.xiaomi/ """ import logging -import threading -from datetime import timedelta import requests import voluptuous as vol @@ -15,12 +13,9 @@ from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME -from homeassistant.util import Throttle _LOGGER = logging.getLogger(__name__) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_USERNAME, default='admin'): cv.string, @@ -47,8 +42,6 @@ def __init__(self, config): self.username = config[CONF_USERNAME] self.password = config[CONF_PASSWORD] - self.lock = threading.Lock() - self.last_results = {} self.token = _get_token(self.host, self.username, self.password) @@ -62,21 +55,19 @@ def scan_devices(self): def get_device_name(self, device): """Return the name of the given device or None if we don't know.""" - with self.lock: - if self.mac2name is None: - result = self._retrieve_list_with_retry() - if result: - hosts = [x for x in result - if 'mac' in x and 'name' in x] - mac2name_list = [ - (x['mac'].upper(), x['name']) for x in hosts] - self.mac2name = dict(mac2name_list) - else: - # Error, handled in the _retrieve_list_with_retry - return - return self.mac2name.get(device.upper(), None) - - @Throttle(MIN_TIME_BETWEEN_SCANS) + if self.mac2name is None: + result = self._retrieve_list_with_retry() + if result: + hosts = [x for x in result + if 'mac' in x and 'name' in x] + mac2name_list = [ + (x['mac'].upper(), x['name']) for x in hosts] + self.mac2name = dict(mac2name_list) + else: + # Error, handled in the _retrieve_list_with_retry + return + return self.mac2name.get(device.upper(), None) + def _update_info(self): """Ensure the informations from the router are up to date. @@ -85,12 +76,11 @@ def _update_info(self): if not self.success_init: return False - with self.lock: - result = self._retrieve_list_with_retry() - if result: - self._store_result(result) - return True - return False + result = self._retrieve_list_with_retry() + if result: + self._store_result(result) + return True + return False def _retrieve_list_with_retry(self): """Retrieve the device list with a retry if token is invalid. From 1d3113761698af2abd38c773ed079eccf60a9736 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 24 Jul 2017 07:47:57 -0700 Subject: [PATCH 085/118] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 40a393517da95..62a0d0a80039f 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -Home Assistant |Build Status| |Coverage Status| | Join the chat `at discord `_ | Join the dev chat `at discord `_ | +Home Assistant |Build Status| |Coverage Status| | `Join Chat `_ ============================================================================================================================================================================================== Home Assistant is a home automation platform running on Python 3. It is able to track and control all devices at home and offer a platform for automating control. From 9d9ca64f2604548b98337c39529e2c703f43c560 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 24 Jul 2017 07:53:14 -0700 Subject: [PATCH 086/118] Update README.rst --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 62a0d0a80039f..039e8a922af82 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -Home Assistant |Build Status| |Coverage Status| | `Join Chat `_ -============================================================================================================================================================================================== +Home Assistant |Build Status| |Coverage Status| |Chat Status| +============================================================= Home Assistant is a home automation platform running on Python 3. It is able to track and control all devices at home and offer a platform for automating control. @@ -31,6 +31,8 @@ of a component, check the `Home Assistant help section Date: Tue, 25 Jul 2017 01:59:10 +1000 Subject: [PATCH 087/118] Add support for using credstash as a secret store (#8494) --- homeassistant/scripts/credstash.py | 71 ++++++++++++++++++++++++++++++ homeassistant/util/yaml.py | 14 ++++++ pylintrc | 2 + requirements_all.txt | 6 +++ tests/util/test_yaml.py | 11 +++++ 5 files changed, 104 insertions(+) create mode 100644 homeassistant/scripts/credstash.py diff --git a/homeassistant/scripts/credstash.py b/homeassistant/scripts/credstash.py new file mode 100644 index 0000000000000..9ba945626e2e1 --- /dev/null +++ b/homeassistant/scripts/credstash.py @@ -0,0 +1,71 @@ +"""Script to get, put and delete secrets stored in credstash.""" +import argparse +import getpass + +from homeassistant.util.yaml import _SECRET_NAMESPACE + +REQUIREMENTS = ['credstash==1.13.2', 'botocore==1.4.93'] + + +def run(args): + """Handle credstash script.""" + parser = argparse.ArgumentParser( + description=("Modify Home-Assistant secrets in credstash." + "Use the secrets in configuration files with: " + "!secret ")) + parser.add_argument( + '--script', choices=['credstash']) + parser.add_argument( + 'action', choices=['get', 'put', 'del', 'list'], + help="Get, put or delete a secret, or list all available secrets") + parser.add_argument( + 'name', help="Name of the secret", nargs='?', default=None) + parser.add_argument( + 'value', help="The value to save when putting a secret", + nargs='?', default=None) + + import credstash + import botocore + + args = parser.parse_args(args) + table = _SECRET_NAMESPACE + + try: + credstash.listSecrets(table=table) + except botocore.errorfactory.ClientError: + credstash.createDdbTable(table=table) + + if args.action == 'list': + secrets = [i['name'] for i in credstash.listSecrets(table=table)] + deduped_secrets = sorted(set(secrets)) + + print('Saved secrets:') + for secret in deduped_secrets: + print(secret) + return 0 + + if args.name is None: + parser.print_help() + return 1 + + if args.action == 'put': + if args.value: + the_secret = args.value + else: + the_secret = getpass.getpass('Please enter the secret for {}: ' + .format(args.name)) + current_version = credstash.getHighestVersion(args.name, table=table) + credstash.putSecret(args.name, + the_secret, + version=int(current_version) + 1, + table=table) + print('Secret {} put successfully'.format(args.name)) + elif args.action == 'get': + the_secret = credstash.getSecret(args.name, table=table) + if the_secret is None: + print('Secret {} not found'.format(args.name)) + else: + print('Secret {}={}'.format(args.name, the_secret)) + elif args.action == 'del': + credstash.deleteSecrets(args.name, table=table) + print('Deleted secret {}'.format(args.name)) diff --git a/homeassistant/util/yaml.py b/homeassistant/util/yaml.py index 7827f484fdf2d..fb682ac6f197d 100644 --- a/homeassistant/util/yaml.py +++ b/homeassistant/util/yaml.py @@ -12,6 +12,11 @@ except ImportError: keyring = None +try: + import credstash +except ImportError: + credstash = None + from homeassistant.exceptions import HomeAssistantError _LOGGER = logging.getLogger(__name__) @@ -257,6 +262,15 @@ def _secret_yaml(loader: SafeLineLoader, _LOGGER.debug("Secret %s retrieved from keyring", node.value) return pwd + if credstash: + try: + pwd = credstash.getSecret(node.value, table=_SECRET_NAMESPACE) + if pwd: + _LOGGER.debug("Secret %s retrieved from credstash", node.value) + return pwd + except credstash.ItemNotFound: + pass + _LOGGER.error("Secret %s not defined", node.value) raise HomeAssistantError(node.value) diff --git a/pylintrc b/pylintrc index e94cbffe9f936..1ed8d2af3363e 100644 --- a/pylintrc +++ b/pylintrc @@ -14,6 +14,8 @@ reports=no # too-few-* - same as too-many-* # abstract-method - with intro of async there are always methods missing +generated-members=botocore.errorfactory + disable= abstract-class-little-used, abstract-class-not-used, diff --git a/requirements_all.txt b/requirements_all.txt index 10036a0361570..aa99cd0370183 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -115,6 +115,9 @@ blockchain==1.3.3 # homeassistant.components.tts.amazon_polly boto3==1.4.3 +# homeassistant.scripts.credstash +botocore==1.4.93 + # homeassistant.components.sensor.broadlink # homeassistant.components.switch.broadlink broadlink==0.5 @@ -136,6 +139,9 @@ colorlog>2.1,<3 # homeassistant.components.binary_sensor.concord232 concord232==0.14 +# homeassistant.scripts.credstash +credstash==1.13.2 + # homeassistant.components.sensor.crimereports crimereports==1.0.0 diff --git a/tests/util/test_yaml.py b/tests/util/test_yaml.py index 0ccb6f5d6d08d..c2eda2401f50f 100644 --- a/tests/util/test_yaml.py +++ b/tests/util/test_yaml.py @@ -2,6 +2,7 @@ import io import os import unittest +import logging from unittest.mock import patch from homeassistant.exceptions import HomeAssistantError @@ -372,6 +373,16 @@ def test_secrets_keyring(self): _yaml = load_yaml(self._yaml_path, yaml_str) self.assertEqual({'http': {'api_password': 'yeah'}}, _yaml) + @patch.object(yaml, 'credstash') + def test_secrets_credstash(self, mock_credstash): + """Test credstash fallback & get_password.""" + mock_credstash.getSecret.return_value = 'yeah' + yaml_str = 'http:\n api_password: !secret http_pw_credstash' + _yaml = load_yaml(self._yaml_path, yaml_str) + log = logging.getLogger() + log.error(_yaml['http']) + self.assertEqual({'api_password': 'yeah'}, _yaml['http']) + def test_secrets_logger_removed(self): """Ensure logger: debug was removed.""" with self.assertRaises(yaml.HomeAssistantError): From ecc1429453fa7727e749ecceee069253f154aea6 Mon Sep 17 00:00:00 2001 From: Corey Pauley Date: Mon, 24 Jul 2017 11:00:01 -0500 Subject: [PATCH 088/118] Added support for default value when environment variable is missing (#8484) * Added support for a default value when an environment variable is missing * Shouldn't have used docstring --- homeassistant/util/yaml.py | 9 +++++++-- tests/util/test_yaml.py | 7 +++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/homeassistant/util/yaml.py b/homeassistant/util/yaml.py index fb682ac6f197d..4129a67bf5777 100644 --- a/homeassistant/util/yaml.py +++ b/homeassistant/util/yaml.py @@ -205,8 +205,13 @@ def _construct_seq(loader: SafeLineLoader, node: yaml.nodes.Node): def _env_var_yaml(loader: SafeLineLoader, node: yaml.nodes.Node): """Load environment variables and embed it into the configuration YAML.""" - if node.value in os.environ: - return os.environ[node.value] + args = node.value.split() + + # Check for a default value + if len(args) > 1: + return os.getenv(args[0], ' '.join(args[1:])) + elif args[0] in os.environ: + return os.environ[args[0]] else: _LOGGER.error("Environment variable %s not defined.", node.value) raise HomeAssistantError(node.value) diff --git a/tests/util/test_yaml.py b/tests/util/test_yaml.py index c2eda2401f50f..a15efb7a77eae 100644 --- a/tests/util/test_yaml.py +++ b/tests/util/test_yaml.py @@ -60,6 +60,13 @@ def test_enviroment_variable(self): assert doc['password'] == "secret_password" del os.environ["PASSWORD"] + def test_environment_variable_default(self): + """Test config file with default value for environment variable.""" + conf = "password: !env_var PASSWORD secret_password" + with io.StringIO(conf) as file: + doc = yaml.yaml.safe_load(file) + assert doc['password'] == "secret_password" + def test_invalid_enviroment_variable(self): """Test config file with no enviroment variable sat.""" conf = "password: !env_var PASSWORD" From cc03f7ee6a566e72972c823c86f6318179dcfbb1 Mon Sep 17 00:00:00 2001 From: Colin O'Dell Date: Mon, 24 Jul 2017 12:06:38 -0400 Subject: [PATCH 089/118] Manual alarm with MQTT control (#8257) * Manual alarm with MQTT control * Duplicate manual control panel code instead of extending it * Duplicate manual alarm test as well; modify for manual_mqtt * Add MQTT-specific tests for manual_mqtt alarm --- .coveragerc | 1 + .../alarm_control_panel/manual_mqtt.py | 235 ++++++++ .../alarm_control_panel/test_manual_mqtt.py | 559 ++++++++++++++++++ 3 files changed, 795 insertions(+) create mode 100644 homeassistant/components/alarm_control_panel/manual_mqtt.py create mode 100644 tests/components/alarm_control_panel/test_manual_mqtt.py diff --git a/.coveragerc b/.coveragerc index 3ec0b119cb8e9..dc2f39b997781 100644 --- a/.coveragerc +++ b/.coveragerc @@ -211,6 +211,7 @@ omit = homeassistant/components/alarm_control_panel/alarmdotcom.py homeassistant/components/alarm_control_panel/concord232.py + homeassistant/components/alarm_control_panel/manual_mqtt.py homeassistant/components/alarm_control_panel/nx584.py homeassistant/components/alarm_control_panel/simplisafe.py homeassistant/components/alarm_control_panel/totalconnect.py diff --git a/homeassistant/components/alarm_control_panel/manual_mqtt.py b/homeassistant/components/alarm_control_panel/manual_mqtt.py new file mode 100644 index 0000000000000..b554a667b2a0c --- /dev/null +++ b/homeassistant/components/alarm_control_panel/manual_mqtt.py @@ -0,0 +1,235 @@ +""" +Support for manual alarms controllable via MQTT. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/alarm_control_panel.manual_mqtt/ +""" +import asyncio +import datetime +import logging + +import voluptuous as vol + +import homeassistant.components.alarm_control_panel as alarm +import homeassistant.util.dt as dt_util +from homeassistant.const import ( + STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, CONF_PLATFORM, + CONF_NAME, CONF_CODE, CONF_PENDING_TIME, CONF_TRIGGER_TIME, + CONF_DISARM_AFTER_TRIGGER) +import homeassistant.components.mqtt as mqtt + +from homeassistant.helpers.event import async_track_state_change +from homeassistant.core import callback + +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.event import track_point_in_time + +CONF_PAYLOAD_DISARM = 'payload_disarm' +CONF_PAYLOAD_ARM_HOME = 'payload_arm_home' +CONF_PAYLOAD_ARM_AWAY = 'payload_arm_away' + +DEFAULT_ALARM_NAME = 'HA Alarm' +DEFAULT_PENDING_TIME = 60 +DEFAULT_TRIGGER_TIME = 120 +DEFAULT_DISARM_AFTER_TRIGGER = False +DEFAULT_ARM_AWAY = 'ARM_AWAY' +DEFAULT_ARM_HOME = 'ARM_HOME' +DEFAULT_DISARM = 'DISARM' + +DEPENDENCIES = ['mqtt'] + +PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ + vol.Required(CONF_PLATFORM): 'manual_mqtt', + vol.Optional(CONF_NAME, default=DEFAULT_ALARM_NAME): cv.string, + vol.Optional(CONF_CODE): cv.string, + vol.Optional(CONF_PENDING_TIME, default=DEFAULT_PENDING_TIME): + vol.All(vol.Coerce(int), vol.Range(min=0)), + vol.Optional(CONF_TRIGGER_TIME, default=DEFAULT_TRIGGER_TIME): + vol.All(vol.Coerce(int), vol.Range(min=1)), + vol.Optional(CONF_DISARM_AFTER_TRIGGER, + default=DEFAULT_DISARM_AFTER_TRIGGER): cv.boolean, + vol.Required(mqtt.CONF_COMMAND_TOPIC): mqtt.valid_publish_topic, + vol.Required(mqtt.CONF_STATE_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_PAYLOAD_ARM_AWAY, default=DEFAULT_ARM_AWAY): cv.string, + vol.Optional(CONF_PAYLOAD_ARM_HOME, default=DEFAULT_ARM_HOME): cv.string, + vol.Optional(CONF_PAYLOAD_DISARM, default=DEFAULT_DISARM): cv.string, +}) + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the manual MQTT alarm platform.""" + add_devices([ManualMQTTAlarm( + hass, + config[CONF_NAME], + config.get(CONF_CODE), + config.get(CONF_PENDING_TIME, DEFAULT_PENDING_TIME), + config.get(CONF_TRIGGER_TIME, DEFAULT_TRIGGER_TIME), + config.get(CONF_DISARM_AFTER_TRIGGER, DEFAULT_DISARM_AFTER_TRIGGER), + config.get(mqtt.CONF_STATE_TOPIC), + config.get(mqtt.CONF_COMMAND_TOPIC), + config.get(mqtt.CONF_QOS), + config.get(CONF_PAYLOAD_DISARM), + config.get(CONF_PAYLOAD_ARM_HOME), + config.get(CONF_PAYLOAD_ARM_AWAY))]) + + +class ManualMQTTAlarm(alarm.AlarmControlPanel): + """ + Representation of an alarm status. + + When armed, will be pending for 'pending_time', after that armed. + When triggered, will be pending for 'trigger_time'. After that will be + triggered for 'trigger_time', after that we return to the previous state + or disarm if `disarm_after_trigger` is true. + """ + + def __init__(self, hass, name, code, pending_time, + trigger_time, disarm_after_trigger, + state_topic, command_topic, qos, + payload_disarm, payload_arm_home, payload_arm_away): + """Init the manual MQTT alarm panel.""" + self._state = STATE_ALARM_DISARMED + self._hass = hass + self._name = name + self._code = str(code) if code else None + self._pending_time = datetime.timedelta(seconds=pending_time) + self._trigger_time = datetime.timedelta(seconds=trigger_time) + self._disarm_after_trigger = disarm_after_trigger + self._pre_trigger_state = self._state + self._state_ts = None + + self._state_topic = state_topic + self._command_topic = command_topic + self._qos = qos + self._payload_disarm = payload_disarm + self._payload_arm_home = payload_arm_home + self._payload_arm_away = payload_arm_away + + @property + def should_poll(self): + """Return the polling state.""" + return False + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def state(self): + """Return the state of the device.""" + if self._state in (STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_AWAY) and \ + self._pending_time and self._state_ts + self._pending_time > \ + dt_util.utcnow(): + return STATE_ALARM_PENDING + + if self._state == STATE_ALARM_TRIGGERED and self._trigger_time: + if self._state_ts + self._pending_time > dt_util.utcnow(): + return STATE_ALARM_PENDING + elif (self._state_ts + self._pending_time + + self._trigger_time) < dt_util.utcnow(): + if self._disarm_after_trigger: + return STATE_ALARM_DISARMED + return self._pre_trigger_state + + 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._state_ts = dt_util.utcnow() + self.schedule_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._state_ts = dt_util.utcnow() + self.schedule_update_ha_state() + + if self._pending_time: + track_point_in_time( + self._hass, self.async_update_ha_state, + self._state_ts + self._pending_time) + + 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._state_ts = dt_util.utcnow() + self.schedule_update_ha_state() + + if self._pending_time: + track_point_in_time( + self._hass, self.async_update_ha_state, + self._state_ts + self._pending_time) + + def alarm_trigger(self, code=None): + """Send alarm trigger command. No code needed.""" + self._pre_trigger_state = self._state + self._state = STATE_ALARM_TRIGGERED + self._state_ts = dt_util.utcnow() + self.schedule_update_ha_state() + + if self._trigger_time: + track_point_in_time( + self._hass, self.async_update_ha_state, + self._state_ts + self._pending_time) + + track_point_in_time( + self._hass, self.async_update_ha_state, + self._state_ts + self._pending_time + self._trigger_time) + + def _validate_code(self, code, state): + """Validate given code.""" + check = self._code is None or code == self._code + if not check: + _LOGGER.warning("Invalid code given for %s", state) + return check + + def async_added_to_hass(self): + """Subscribe mqtt events. + + This method must be run in the event loop and returns a coroutine. + """ + async_track_state_change( + self.hass, self.entity_id, self._async_state_changed_listener + ) + + @callback + def message_received(topic, payload, qos): + """Run when new MQTT message has been received.""" + if payload == self._payload_disarm: + self.async_alarm_disarm(self._code) + elif payload == self._payload_arm_home: + self.async_alarm_arm_home(self._code) + elif payload == self._payload_arm_away: + self.async_alarm_arm_away(self._code) + else: + _LOGGER.warning("Received unexpected payload: %s", payload) + return + + return mqtt.async_subscribe( + self.hass, self._command_topic, message_received, self._qos) + + @asyncio.coroutine + def _async_state_changed_listener(self, entity_id, old_state, new_state): + """Publish state change to MQTT.""" + mqtt.async_publish(self.hass, self._state_topic, new_state.state, + self._qos, True) diff --git a/tests/components/alarm_control_panel/test_manual_mqtt.py b/tests/components/alarm_control_panel/test_manual_mqtt.py new file mode 100644 index 0000000000000..c4dcd57ca39ad --- /dev/null +++ b/tests/components/alarm_control_panel/test_manual_mqtt.py @@ -0,0 +1,559 @@ +"""The tests for the manual_mqtt Alarm Control Panel component.""" +from datetime import timedelta +import unittest +from unittest.mock import patch + +from homeassistant.setup import setup_component +from homeassistant.const import ( + STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, + STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED) +from homeassistant.components import alarm_control_panel +import homeassistant.util.dt as dt_util + +from tests.common import ( + fire_time_changed, get_test_home_assistant, + mock_mqtt_component, fire_mqtt_message, assert_setup_component) + +CODE = 'HELLO_CODE' + + +class TestAlarmControlPanelManualMqtt(unittest.TestCase): + """Test the manual_mqtt alarm module.""" + + def setUp(self): # pylint: disable=invalid-name + """Setup things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.mock_publish = mock_mqtt_component(self.hass) + + def tearDown(self): # pylint: disable=invalid-name + """Stop down everything that was started.""" + self.hass.stop() + + def test_fail_setup_without_state_topic(self): + """Test for failing with no state topic.""" + with assert_setup_component(0) as config: + assert setup_component(self.hass, alarm_control_panel.DOMAIN, { + alarm_control_panel.DOMAIN: { + 'platform': 'mqtt_alarm', + 'command_topic': 'alarm/command' + } + }) + assert not config[alarm_control_panel.DOMAIN] + + def test_fail_setup_without_command_topic(self): + """Test failing with no command topic.""" + with assert_setup_component(0): + assert setup_component(self.hass, alarm_control_panel.DOMAIN, { + alarm_control_panel.DOMAIN: { + 'platform': 'mqtt_alarm', + 'state_topic': 'alarm/state' + } + }) + + def test_arm_home_no_pending(self): + """Test arm home method.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'code': CODE, + 'pending_time': 0, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_HOME, + self.hass.states.get(entity_id).state) + + def test_arm_home_with_pending(self): + """Test arm home method.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'code': CODE, + 'pending_time': 1, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE, entity_id) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_HOME, + self.hass.states.get(entity_id).state) + + def test_arm_home_with_invalid_code(self): + """Attempt to arm home without a valid code.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'code': CODE, + 'pending_time': 1, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_home(self.hass, CODE + '2') + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_arm_away_no_pending(self): + """Test arm home method.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'code': CODE, + 'pending_time': 0, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE, entity_id) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_AWAY, + self.hass.states.get(entity_id).state) + + def test_arm_away_with_pending(self): + """Test arm home method.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'code': CODE, + 'pending_time': 1, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_AWAY, + self.hass.states.get(entity_id).state) + + def test_arm_away_with_invalid_code(self): + """Attempt to arm away without a valid code.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'code': CODE, + 'pending_time': 1, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_arm_away(self.hass, CODE + '2') + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_trigger_no_pending(self): + """Test triggering when no pending submitted method.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'trigger_time': 1, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=60) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + def test_trigger_with_pending(self): + """Test arm home method.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'pending_time': 2, + 'trigger_time': 3, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=2) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=5) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_trigger_with_disarm_after_trigger(self): + """Test disarm after trigger.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'trigger_time': 5, + 'pending_time': 0, + 'disarm_after_trigger': True, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass, entity_id=entity_id) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=5) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_disarm_while_pending_trigger(self): + """Test disarming while pending state.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'trigger_time': 5, + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_disarm(self.hass, entity_id=entity_id) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=5) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_disarm_during_trigger_with_invalid_code(self): + """Test disarming while code is invalid.""" + self.assertTrue(setup_component( + self.hass, alarm_control_panel.DOMAIN, + {'alarm_control_panel': { + 'platform': 'manual_mqtt', + 'name': 'test', + 'pending_time': 5, + 'code': CODE + '2', + 'disarm_after_trigger': False, + 'command_topic': 'alarm/command', + 'state_topic': 'alarm/state', + }})) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_disarm(self.hass, entity_id=entity_id) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + future = dt_util.utcnow() + timedelta(seconds=5) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_TRIGGERED, + self.hass.states.get(entity_id).state) + + def test_arm_home_via_command_topic(self): + """Test arming home via command topic.""" + assert setup_component(self.hass, alarm_control_panel.DOMAIN, { + alarm_control_panel.DOMAIN: { + 'platform': 'manual_mqtt', + 'name': 'test', + 'pending_time': 1, + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + 'payload_arm_home': 'ARM_HOME', + } + }) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + # Fire the arm command via MQTT; ensure state changes to pending + fire_mqtt_message(self.hass, 'alarm/command', 'ARM_HOME') + self.hass.block_till_done() + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + # Fast-forward a little bit + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_HOME, + self.hass.states.get(entity_id).state) + + def test_arm_away_via_command_topic(self): + """Test arming away via command topic.""" + assert setup_component(self.hass, alarm_control_panel.DOMAIN, { + alarm_control_panel.DOMAIN: { + 'platform': 'manual_mqtt', + 'name': 'test', + 'pending_time': 1, + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + 'payload_arm_away': 'ARM_AWAY', + } + }) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + # Fire the arm command via MQTT; ensure state changes to pending + fire_mqtt_message(self.hass, 'alarm/command', 'ARM_AWAY') + self.hass.block_till_done() + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + # Fast-forward a little bit + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_ARMED_AWAY, + self.hass.states.get(entity_id).state) + + def test_disarm_pending_via_command_topic(self): + """Test disarming pending alarm via command topic.""" + assert setup_component(self.hass, alarm_control_panel.DOMAIN, { + alarm_control_panel.DOMAIN: { + 'platform': 'manual_mqtt', + 'name': 'test', + 'pending_time': 1, + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + 'payload_disarm': 'DISARM', + } + }) + + entity_id = 'alarm_control_panel.test' + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + alarm_control_panel.alarm_trigger(self.hass) + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_PENDING, + self.hass.states.get(entity_id).state) + + # Now that we're pending, receive a command to disarm + fire_mqtt_message(self.hass, 'alarm/command', 'DISARM') + self.hass.block_till_done() + + self.assertEqual(STATE_ALARM_DISARMED, + self.hass.states.get(entity_id).state) + + def test_state_changes_are_published_to_mqtt(self): + """Test publishing of MQTT messages when state changes.""" + assert setup_component(self.hass, alarm_control_panel.DOMAIN, { + alarm_control_panel.DOMAIN: { + 'platform': 'manual_mqtt', + 'name': 'test', + 'pending_time': 1, + 'trigger_time': 1, + 'state_topic': 'alarm/state', + 'command_topic': 'alarm/command', + } + }) + + # Component should send disarmed alarm state on startup + self.hass.block_till_done() + self.assertEqual(('alarm/state', STATE_ALARM_DISARMED, 0, True), + self.mock_publish.mock_calls[-2][1]) + + # Arm in home mode + alarm_control_panel.alarm_arm_home(self.hass) + self.hass.block_till_done() + self.assertEqual(('alarm/state', STATE_ALARM_PENDING, 0, True), + self.mock_publish.mock_calls[-2][1]) + # Fast-forward a little bit + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + self.assertEqual(('alarm/state', STATE_ALARM_ARMED_HOME, 0, True), + self.mock_publish.mock_calls[-2][1]) + + # Arm in away mode + alarm_control_panel.alarm_arm_away(self.hass) + self.hass.block_till_done() + self.assertEqual(('alarm/state', STATE_ALARM_PENDING, 0, True), + self.mock_publish.mock_calls[-2][1]) + # Fast-forward a little bit + future = dt_util.utcnow() + timedelta(seconds=1) + with patch(('homeassistant.components.alarm_control_panel.manual_mqtt.' + 'dt_util.utcnow'), return_value=future): + fire_time_changed(self.hass, future) + self.hass.block_till_done() + self.assertEqual(('alarm/state', STATE_ALARM_ARMED_AWAY, 0, True), + self.mock_publish.mock_calls[-2][1]) + + # Disarm + alarm_control_panel.alarm_disarm(self.hass) + self.hass.block_till_done() + self.assertEqual(('alarm/state', STATE_ALARM_DISARMED, 0, True), + self.mock_publish.mock_calls[-2][1]) From 3b7f16f189e632b574f91c41f81543941119c992 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Tue, 25 Jul 2017 00:05:47 -0400 Subject: [PATCH 090/118] Catch and log Lyft API errors (#8635) --- homeassistant/components/sensor/lyft.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/sensor/lyft.py b/homeassistant/components/sensor/lyft.py index c16fae9f5d5ef..11ca07f7fb88b 100644 --- a/homeassistant/components/sensor/lyft.py +++ b/homeassistant/components/sensor/lyft.py @@ -45,20 +45,27 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Lyft sensor.""" from lyft_rides.auth import ClientCredentialGrant + from lyft_rides.errors import APIError auth_flow = ClientCredentialGrant(client_id=config.get(CONF_CLIENT_ID), client_secret=config.get( CONF_CLIENT_SECRET), scopes="public", is_sandbox_mode=False) - session = auth_flow.get_session() + try: + session = auth_flow.get_session() + + timeandpriceest = LyftEstimate( + session, config[CONF_START_LATITUDE], config[CONF_START_LONGITUDE], + config.get(CONF_END_LATITUDE), config.get(CONF_END_LONGITUDE)) + timeandpriceest.fetch_data() + except APIError as exc: + _LOGGER.error("Error setting up Lyft platform: %s", exc) + return False wanted_product_ids = config.get(CONF_PRODUCT_IDS) dev = [] - timeandpriceest = LyftEstimate( - session, config[CONF_START_LATITUDE], config[CONF_START_LONGITUDE], - config.get(CONF_END_LATITUDE), config.get(CONF_END_LONGITUDE)) for product_id, product in timeandpriceest.products.items(): if (wanted_product_ids is not None) and \ (product_id not in wanted_product_ids): @@ -188,14 +195,18 @@ def __init__(self, session, start_latitude, start_longitude, self.end_latitude = end_latitude self.end_longitude = end_longitude self.products = None - self.__real_update() @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """Get the latest product info and estimates from the Lyft API.""" - self.__real_update() + from lyft_rides.errors import APIError + try: + self.fetch_data() + except APIError as exc: + _LOGGER.error("Error fetching Lyft data: %s", exc) - def __real_update(self): + def fetch_data(self): + """Get the latest product info and estimates from the Lyft API.""" from lyft_rides.client import LyftRidesClient client = LyftRidesClient(self._session) From ad7370e1c25ed4aa9e69ea1a425731c16d9504af Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 25 Jul 2017 00:29:05 -0700 Subject: [PATCH 091/118] Update frontend --- homeassistant/components/frontend/version.py | 20 +++++++++--------- .../frontend/www_static/frontend.html | 8 +++---- .../frontend/www_static/frontend.html.gz | Bin 138831 -> 139371 bytes .../www_static/home-assistant-polymer | 2 +- .../panels/ha-panel-automation.html | 2 +- .../panels/ha-panel-automation.html.gz | Bin 28564 -> 28583 bytes .../www_static/panels/ha-panel-config.html | 2 +- .../www_static/panels/ha-panel-config.html.gz | Bin 15057 -> 15061 bytes .../www_static/panels/ha-panel-dev-event.html | 2 +- .../panels/ha-panel-dev-event.html.gz | Bin 2743 -> 2730 bytes .../panels/ha-panel-dev-service.html | 2 +- .../panels/ha-panel-dev-service.html.gz | Bin 23776 -> 23797 bytes .../www_static/panels/ha-panel-dev-state.html | 2 +- .../panels/ha-panel-dev-state.html.gz | Bin 2956 -> 2943 bytes .../panels/ha-panel-dev-template.html | 2 +- .../panels/ha-panel-dev-template.html.gz | Bin 11433 -> 11445 bytes .../www_static/panels/ha-panel-map.html | 2 +- .../www_static/panels/ha-panel-map.html.gz | Bin 44197 -> 44202 bytes .../panels/ha-panel-shopping-list.html | 2 +- .../panels/ha-panel-shopping-list.html.gz | Bin 5303 -> 5308 bytes .../www_static/panels/ha-panel-zwave.html | 2 +- .../www_static/panels/ha-panel-zwave.html.gz | Bin 10543 -> 10548 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2487 -> 2490 bytes .../www_static/webcomponents-lite.min.js.gz | Bin 12360 -> 12334 bytes 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index ddfd8a3305124..a0958f65d95bf 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -3,22 +3,22 @@ FINGERPRINTS = { "compatibility.js": "8e4c44b5f4288cc48ec1ba94a9bec812", "core.js": "d4a7cb8c80c62b536764e0e81385f6aa", - "frontend.html": "d0142106cf282596062e5b2060128f81", + "frontend.html": "c44e49b9a0d9b9e4a626b7af34ca97d0", "mdi.html": "e91f61a039ed0a9936e7ee5360da3870", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", - "panels/ha-panel-automation.html": "72a5c1856cece8d9246328e84185ab0b", - "panels/ha-panel-config.html": "5e2df66aa534c4dadd08c60c361f5d45", - "panels/ha-panel-dev-event.html": "4886c821235492b1b92739b580d21c61", + "panels/ha-panel-automation.html": "1982116c49ad26ee8d89295edc797084", + "panels/ha-panel-config.html": "fafeac72f83dd6cc42218f8978f6a7af", + "panels/ha-panel-dev-event.html": "77784d5f0c73fcc3b29b6cc050bdf324", "panels/ha-panel-dev-info.html": "24e888ec7a8acd0c395b34396e9001bc", - "panels/ha-panel-dev-service.html": "ac2c50e486927dc4443e93d79f08c06e", - "panels/ha-panel-dev-state.html": "8f1a27c04db6329d31cfcc7d0d6a0869", - "panels/ha-panel-dev-template.html": "82cd543177c417e5c6612e07df851e6b", + "panels/ha-panel-dev-service.html": "86a42a17f4894478b6b77bc636beafd0", + "panels/ha-panel-dev-state.html": "31ef6ffe3347cdda5bb0cbbc54b62cde", + "panels/ha-panel-dev-template.html": "d1d76e20fe9622cddee33e67318abde8", "panels/ha-panel-hassio.html": "262d31efd9add719e0325da5cf79a096", "panels/ha-panel-history.html": "35177e2046c9a4191c8f51f8160255ce", "panels/ha-panel-iframe.html": "238189f21e670b6dcfac937e5ebd7d3b", "panels/ha-panel-kiosk.html": "2ac2df41bd447600692a0054892fc094", "panels/ha-panel-logbook.html": "7c45bd41c146ec38b9938b8a5188bb0d", - "panels/ha-panel-map.html": "b4923812c695dd8a69ad3da380ffe7b4", - "panels/ha-panel-shopping-list.html": "75602d06b41702c8093bd91c10374101", - "panels/ha-panel-zwave.html": "8c8e7844d33163f560e1f691550a8369" + "panels/ha-panel-map.html": "50501cd53eb4304e9e46eb719aa894b7", + "panels/ha-panel-shopping-list.html": "c04af28c6475b90cbf2cf63ba1b841d0", + "panels/ha-panel-zwave.html": "422f95f820f8b6b231265351ffcf4dd1" } diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index ad1e407587e7e..ca86fd55d2248 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -1,5 +1,5 @@ - \ No newline at end of file +;if(t)for(var n in e){var r=t[n];if(r)for(var s,i=0,o=r.length;i1){for(var a=0;a+~])"},resolveCss:Polymer.ResolveUrl.resolveCss,parser:Polymer.CssParse,ruleTypes:Polymer.CssParse.types}}(),Polymer.StyleTransformer=function(){var e=Polymer.StyleUtil,t=Polymer.Settings,n={dom:function(e,t,n,r){this._transformDom(e,t||"",n,r)},_transformDom:function(e,t,n,r){e.setAttribute&&this.element(e,t,n,r);for(var s=Polymer.dom(e).childNodes,i=0;i *"),r&&r(e)}}for(var u,f=0,p=i.length;f *"),e=e.replace(P,l+" $1"),e=e.replace(o,function(e,i,o){if(r)o=o.replace(_," ");else{var l=a._transformCompoundSelector(o,i,t,n);r=r||l.stop,s=s||l.hostContext,i=l.combinator,o=l.value}return i+o}),s&&(e=e.replace(f,function(e,t,r,s){return t+r+" "+n+s+i+" "+t+n+r+s})),e},_transformCompoundSelector:function(e,t,n,r){var s=e.search(_),i=!1;e.indexOf(u)>=0?i=!0:e.indexOf(l)>=0?e=this._transformHostSelector(e,r):0!==s&&(e=n?this._transformSimpleSelector(e,n):e),e.indexOf(p)>=0&&(t="");var o;return s>=0&&(e=e.replace(_," "),o=!0),{value:e,combinator:t,stop:o,hostContext:i}},_transformSimpleSelector:function(e,t){var n=e.split(v);return n[0]+=t,n.join(v)},_transformHostSelector:function(e,t){var n=e.match(h),r=n&&n[2].trim()||"";if(r){if(r[0].match(a))return e.replace(h,function(e,n,r){return t+r});return r.split(a)[0]===t?r:S}return e.replace(l,t)},documentRule:function(e){e.selector=e.parsedSelector,this.normalizeRootSelector(e),t.useNativeShadow||this._transformRule(e,this._transformDocumentSelector)},normalizeRootSelector:function(e){e.selector=e.selector.replace(c,"html");var t=e.selector.split(i);t=t.filter(function(e){return!e.match(C)}),e.selector=t.join(i)},_transformDocumentSelector:function(e){return e.match(_)?this._transformComplexSelector(e,s):this._transformSimpleSelector(e.trim(),s)},_slottedToContent:function(e){return e.replace(E,p+"> $1")},SCOPE_NAME:"style-scope"},r=n.SCOPE_NAME,s=":not(["+r+"]):not(."+r+")",i=",",o=/(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=\[])+)/g,a=/[[.:#*]/,l=":host",c=":root",h=/(:host)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/,u=":host-context",f=/(.*)(?::host-context)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))(.*)/,p="::content",_=/::content|::shadow|\/deep\//,d=".",m="["+r+"~=",y="]",v=":",g="class",P=new RegExp("^("+p+")"),S="should_not_match",E=/(?:::slotted)(?:\(((?:\([^)(]*\)|[^)(]*)+?)\))/g,C=/:host(?:\s*>\s*\*)?/;return n}(),Polymer.StyleExtends=function(){var e=Polymer.StyleUtil;return{hasExtends:function(e){return Boolean(e.match(this.rx.EXTEND))},transform:function(t){var n=e.rulesForStyle(t),r=this;return e.forEachRule(n,function(e){if(r._mapRuleOntoParent(e),e.parent)for(var t;t=r.rx.EXTEND.exec(e.cssText);){var n=t[1],s=r._findExtendor(n,e);s&&r._extendRule(e,s)}e.cssText=e.cssText.replace(r.rx.EXTEND,"")}),e.toCssText(n,function(e){e.selector.match(r.rx.STRIP)&&(e.cssText="")},!0)},_mapRuleOntoParent:function(e){if(e.parent){for(var t,n=e.parent.map||(e.parent.map={}),r=e.selector.split(","),s=0;s1&&(t=i[0].trim(),r=n(t,i.slice(1).join(":")),a[t]=r));return a}function s(e){var t=m.__currentElementProto,n=t&&t.is;for(var r in e.dependants)r!==n&&(e.dependants[r].__applyShimInvalid=!0)}function i(n,i,o,a){if(o&&c.processVariableAndFallback(o,function(e,n){n&&t(n)&&(a="@apply "+n+";")}),!a)return n;var h=l(a),u=n.slice(0,n.indexOf("--")),f=r(h),p=f,d=t(i),m=d&&d.properties;m?(p=Object.create(m),p=Polymer.Base.mixin(p,f)):e(i,p);var y,v,g=[],P=!1;for(y in p)v=f[y],void 0===v&&(v="initial"),!m||y in m||(P=!0),g.push(i+_+y+": "+v);return P&&s(d),d&&(d.properties=p),o&&(u=n+";"+u),u+g.join("; ")+";"}function o(e,t,n){return"var("+t+",var("+n+"))"}function a(n,r){n=n.replace(f,"");var s=[],i=t(n);if(i||(e(n,{}),i=t(n)),i){var o=m.__currentElementProto;o&&(i.dependants[o.is]=o);var a,l,c;for(a in i.properties)c=r&&r[a],l=[a,": var(",n,_,a],c&&l.push(",",c),l.push(")"),s.push(l.join(""))}return s.join("; ")}function l(e){for(var t;t=h.exec(e);){var n=t[0],s=t[1],i=t.index,o=i+n.indexOf("@apply"),l=i+n.length,c=e.slice(0,o),u=e.slice(l),f=r(c),p=a(s,f);e=[c,p,u].join(""),h.lastIndex=i+p.length}return e}var c=Polymer.StyleUtil,h=c.rx.MIXIN_MATCH,u=c.rx.VAR_ASSIGN,f=/;\s*/m,p=/^\s*(initial)|(inherit)\s*$/,_="_-_",d={},m={_measureElement:null,_map:d,_separator:_,transform:function(e,t){this.__currentElementProto=t,c.forRulesInStyles(e,this._boundFindDefinitions),c.forRulesInStyles(e,this._boundFindApplications),t&&(t.__applyShimInvalid=!1),this.__currentElementProto=null},_findDefinitions:function(e){var t=e.parsedCssText;t=t.replace(/var\(\s*(--[^,]*),\s*(--[^)]*)\)/g,o),t=t.replace(u,i),e.cssText=t,":root"===e.selector&&(e.selector=":host > *")},_findApplications:function(e){e.cssText=l(e.cssText)},transformRule:function(e){this._findDefinitions(e),this._findApplications(e)},_getInitialValueForProperty:function(e){return this._measureElement||(this._measureElement=document.createElement("meta"),this._measureElement.style.all="initial",document.head.appendChild(this._measureElement)),window.getComputedStyle(this._measureElement).getPropertyValue(e)}};return m._boundTransformRule=m.transformRule.bind(m),m._boundFindDefinitions=m._findDefinitions.bind(m),m._boundFindApplications=m._findApplications.bind(m),m}(),function(){var e=Polymer.Base._prepElement,t=Polymer.Settings.useNativeShadow,n=Polymer.StyleUtil,r=Polymer.StyleTransformer,s=Polymer.StyleExtends,i=Polymer.ApplyShim,o=Polymer.Settings;Polymer.Base._addFeature({_prepElement:function(t){this._encapsulateStyle&&"shady"!==this.__cssBuild&&r.element(t,this.is,this._scopeCssViaAttr),e.call(this,t)},_prepStyles:function(){void 0===this._encapsulateStyle&&(this._encapsulateStyle=!t),t||(this._scopeStyle=n.applyStylePlaceHolder(this.is)),this.__cssBuild=n.cssBuildTypeForModule(this.is)},_prepShimStyles:function(){if(this._template){var e=n.isTargetedBuild(this.__cssBuild);if(o.useNativeCSSProperties&&"shadow"===this.__cssBuild&&e)return void(o.preserveStyleIncludes&&n.styleIncludesToTemplate(this._template));this._styles=this._styles||this._collectStyles(),o.useNativeCSSProperties&&!this.__cssBuild&&i.transform(this._styles,this);var s=o.useNativeCSSProperties&&e?this._styles.length&&this._styles[0].textContent.trim():r.elementStyles(this);this._prepStyleProperties(),!this._needsStyleProperties()&&s&&n.applyCss(s,this.is,t?this._template.content:null,this._scopeStyle)}else this._styles=[]},_collectStyles:function(){var e=[],t="",r=this.styleModules;if(r)for(var i,o=0,a=r.length;o=0)e=this.valueForProperties(e,t);else{var r=this,s=function(e,n,s,i){var o=r.valueForProperty(t[n],t);return o&&"initial"!==o?"apply-shim-inherit"===o&&(o="inherit"):o=r.valueForProperty(t[s]||s,t)||s,e+(o||"")+i};e=n.processVariableAndFallback(e,s)}return e&&e.trim()||""},valueForProperties:function(e,t){for(var n,r,s=e.split(";"),i=0;i\s*\*/,_checkRoot:function(e,t){return Boolean(t.match(this._rootSelector))||"html"===e&&t.indexOf("html")>-1},whenHostOrRootRule:function(e,t,n,s){if(t.propertyInfo||self.decorateRule(t),t.propertyInfo.properties){var o=e.is?r._calcHostScope(e.is,e.extends):"html",a=t.parsedSelector,l=this._checkRoot(o,a),c=!l&&0===a.indexOf(":host");if("shady"===(e.__cssBuild||n.__cssBuild)&&(l=a===o+" > *."+o||a.indexOf("html")>-1,c=!l&&0===a.indexOf(o)),l||c){var h=o;c&&(i.useNativeShadow&&!t.transformedSelector&&(t.transformedSelector=r._transformRuleCss(t,r._transformComplexSelector,e.is,o)),h=t.transformedSelector||t.parsedSelector),l&&"html"===o&&(h=t.transformedSelector||t.parsedSelector),s({selector:h,isHost:c,isRoot:l})}}},hostAndRootPropertiesForScope:function(e){var r={},s={},i=this;return n.forActiveRulesInStyles(e._styles,function(n,o){i.whenHostOrRootRule(e,n,o,function(o){var a=e._element||e;t.call(a,o.selector)&&(o.isHost?i.collectProperties(n,r):i.collectProperties(n,s))})}),{rootProps:s,hostProps:r}},transformStyles:function(e,t,n){var s=this,o=r._calcHostScope(e.is,e.extends),a=e.extends?"\\"+o.slice(0,-1)+"\\]":o,l=new RegExp(this.rx.HOST_PREFIX+a+this.rx.HOST_SUFFIX),c=this._elementKeyframeTransforms(e,n);return r.elementStyles(e,function(r){s.applyProperties(r,t),i.useNativeShadow||Polymer.StyleUtil.isKeyframesSelector(r)||!r.cssText||(s.applyKeyframeTransforms(r,c),s._scopeSelector(r,l,o,e._scopeCssViaAttr,n))})},_elementKeyframeTransforms:function(e,t){var n=e._styles._keyframes,r={};if(!i.useNativeShadow&&n)for(var s=0,o=n[s];s-1&&(o.textContent=a),n.applyStyle(o,null,e._scopeStyle)):a&&(o=n.applyCss(a,r,null,e._scopeStyle)),o&&(o._useCount=o._useCount||0,e._customStyle!=o&&o._useCount++,e._customStyle=o),o},mixinCustomStyle:function(e,t){var n;for(var r in t)((n=t[r])||0===n)&&(e[r]=n)},updateNativeStyleProperties:function(e,t){var n=e.__customStyleProperties;if(n)for(var r=0;rthis.MAX&&s.shift()},retrieve:function(e,t,n){var r=this.cache[e];if(r)for(var s,i=r.length-1;i>=0;i--)if(s=r[i],n===s.styles&&this._objectsEqual(t,s.keyValues))return s},clear:function(){this.cache={}},_objectsEqual:function(e,t){var n,r;for(var s in e)if(n=e[s],r=t[s],!("object"==typeof n&&n?this._objectsStrictlyEqual(n,r):n===r))return!1;return!Array.isArray(e)||e.length===t.length},_objectsStrictlyEqual:function(e,t){return this._objectsEqual(e,t)&&this._objectsEqual(t,e)}}}(),Polymer.StyleDefaults=function(){var e=Polymer.StyleProperties,t=Polymer.StyleCache,n=Polymer.Settings.useNativeCSSProperties;return{_styles:[],_properties:null,customStyle:{},_styleCache:new t,_element:Polymer.DomApi.wrap(document.documentElement),addStyle:function(e){this._styles.push(e),this._properties=null},get _styleProperties(){return this._properties||(e.decorateStyles(this._styles,this),this._styles._scopeStyleProperties=null,this._properties=e.hostAndRootPropertiesForScope(this).rootProps,e.mixinCustomStyle(this._properties,this.customStyle),e.reify(this._properties)),this._properties},hasStyleProperties:function(){return Boolean(this._properties)},_needsStyleProperties:function(){},_computeStyleProperties:function(){return this._styleProperties},updateStyles:function(t){this._properties=null,t&&Polymer.Base.mixin(this.customStyle,t),this._styleCache.clear() +;for(var r,s=0;s0&&l.push(t);return[{removed:a,added:l}]}},Polymer.Collection.get=function(e){return Polymer._collections.get(e)||new Polymer.Collection(e)},Polymer.Collection.applySplices=function(e,t){var n=Polymer._collections.get(e);return n?n._applySplices(t):null},Polymer({is:"dom-repeat",extends:"template",_template:null,properties:{items:{type:Array},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},sort:{type:Function,observer:"_sortChanged"},filter:{type:Function,observer:"_filterChanged"},observe:{type:String,observer:"_observeChanged"},delay:Number,renderedItemCount:{type:Number,notify:!Polymer.Settings.suppressTemplateNotifications,readOnly:!0},initialCount:{type:Number,observer:"_initializeChunking"},targetFramerate:{type:Number,value:20},notifyDomChange:{type:Boolean},_targetFrameTime:{type:Number,computed:"_computeFrameTime(targetFramerate)"}},behaviors:[Polymer.Templatizer],observers:["_itemsChanged(items.*)"],created:function(){this._instances=[],this._pool=[],this._limit=1/0;var e=this;this._boundRenderChunk=function(){e._renderChunk()}},detached:function(){this.__isDetached=!0;for(var e=0;e=0;t--){var n=this._instances[t];n.isPlaceholder&&t=this._limit&&(n=this._downgradeInstance(t,n.__key__)),e[n.__key__]=t,n.isPlaceholder||n.__setProperty(this.indexAs,t,!0)}this._pool.length=0,this._setRenderedItemCount(this._instances.length),Polymer.Settings.suppressTemplateNotifications&&!this.notifyDomChange||this.fire("dom-change"),this._tryRenderChunk()},_applyFullRefresh:function(){var e,t=this.collection;if(this._sortFn)e=t?t.getKeys():[];else{e=[];var n=this.items;if(n)for(var r=0;r=r;a--)this._detachAndRemoveInstance(a)},_numericSort:function(e,t){return e-t},_applySplicesUserSort:function(e){for(var t,n,r=this.collection,s={},i=0;i=0;i--){var c=a[i];void 0!==c&&this._detachAndRemoveInstance(c)}var h=this;if(l.length){this._filterFn&&(l=l.filter(function(e){return h._filterFn(r.getItem(e))})),l.sort(function(e,t){return h._sortFn(r.getItem(e),r.getItem(t))});var u=0;for(i=0;i>1,a=this._instances[o].__key__,l=this._sortFn(n.getItem(a),r);if(l<0)e=o+1;else{if(!(l>0)){i=o;break}s=o-1}}return i<0&&(i=s+1),this._insertPlaceholder(i,t),i},_applySplicesArrayOrder:function(e){for(var t,n=0;n=0?(e=this.as+"."+e.substring(n+1),i._notifyPath(e,t,!0)):i.__setProperty(this.as,t,!0))}},itemForElement:function(e){var t=this.modelForElement(e);return t&&t[this.as]},keyForElement:function(e){var t=this.modelForElement(e);return t&&t.__key__},indexForElement:function(e){var t=this.modelForElement(e);return t&&t[this.indexAs]}}),Polymer({is:"array-selector",_template:null,properties:{items:{type:Array,observer:"clearSelection"},multi:{type:Boolean,value:!1,observer:"clearSelection"},selected:{type:Object,notify:!0},selectedItem:{type:Object,notify:!0},toggle:{type:Boolean,value:!1}},clearSelection:function(){if(Array.isArray(this.selected))for(var e=0;e \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index 055f78334dc5f54ff652fc6261ecc9fc4edd133a..a55204f203c36e36624813e501c97257c6755fd0 100644 GIT binary patch delta 134602 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

)E7R9=tpew*&oF)4w!~Rc$IP0J8uYZL_IXZ=~ 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

  • fcn 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�&%3&3wnjn65% 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 0c428134dfb63..19b903dfb7c94 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 0c428134dfb6374b4a120cb729396242b4c2f2d7 +Subproject commit 19b903dfb7c940bfafdecc5407526647d0aed2f2 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-automation.html b/homeassistant/components/frontend/www_static/panels/ha-panel-automation.html index 4da09363373b3..376d9b8a3786e 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-automation.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-automation.html @@ -1 +1 @@ -

    \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-automation.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-automation.html.gz index 7d3cf0d815209a9b2ba44eb7514f268b69e3c4d1..051b7e0552a7065c41904a7bcd46576a865a0247 100644 GIT binary patch delta 26465 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 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html index 9ba6338ce0039..104b090ed61e8 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-config.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-config.html.gz index 2364c355d66f65be42c949cf3d6fdbd309d9f248..8e8ba12d1b4532597551ce2009b91bf186ce2a58 100644 GIT binary patch delta 13954 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

    ^aNzrc7SJ_xfUE$tmbxu8 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 delta 13950 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 YjRh3%yF^~BCh7M71)sv1&U?@R02z}}zW@LL diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html index 6f501f7db2603..236e0fb286a0b 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html @@ -1 +1 @@ -

    \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-event.html.gz index 1a8faa4f3e695ff5a79e906e02423c17a7070022..2f78956badfd8a3fe5ac4488af922636ad13de64 100644 GIT binary patch delta 2390 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 V70~{cJ*3~h{{xklh^zu1008lgwmSd- diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html index ed1ff9fe85dd2..aeab2aaf465e2 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-service.html.gz index c76c9bc6de1a339afa24abd6beaa2b5f3af5bb4c..c479a26990fa287447a8722b88b4831855debd10 100644 GIT binary patch delta 23142 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 R{p{j@0rFIlJJNgs0RX{Xh4BCY delta 23118 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≪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 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html index 6f03db94edf10..75d9dfa9d6e8d 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-state.html.gz index 742f5eef9eef0b78a23e827bec24a7235641a3a5..e28e4ae8f301e798d009882fbd31708b939cd57a 100644 GIT binary patch delta 2657 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 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html index bb27f9a2d7d5f..c1be19536395a 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-dev-template.html.gz index 9c3063c0d6c27794f6ee9a0f5f60e4524a3f7b9b..d5877c44dc039c5abd0d54a552cf7154ad8ac25b 100644 GIT binary patch delta 10855 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.options.maxZoom?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,z(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},invalidateSize:function(t){if(!this._loaded)return this;t=i({animate:!1,pan:!0},!0===t?{animate:!0}:t);var n=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var o=this.getSize(),s=n.divideBy(2).round(),r=o.divideBy(2).round(),a=s.subtract(r);return a.x||a.y?(t.animate&&t.pan?this.panBy(a):(t.pan&&this._rawPanBy(a),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(e(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:n,newSize:o})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){if(t=this._locateOptions=i({timeout:1e4,watch:!1},t),!("geolocation"in navigator))return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var n=e(this._handleGeolocationResponse,this),o=e(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(n,o,t):navigator.geolocation.getCurrentPosition(n,o,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var i=t.code,e=t.message||(1===i?"permission denied":2===i?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:i,message:"Geolocation error: "+e+"."})},_handleGeolocationResponse:function(t){var i=t.coords.latitude,e=t.coords.longitude,n=new M(i,e),o=n.toBounds(t.coords.accuracy),s=this._locateOptions;if(s.setView){var r=this.getBoundsZoom(o);this.setView(n,s.maxZoom?Math.min(r,s.maxZoom):r)}var a={latlng:n,bounds:o,timestamp:t.timestamp};for(var h in t.coords)"number"==typeof t.coords[h]&&(a[h]=t.coords[h]);this.fire("locationfound",a)},addHandler:function(t,i){if(!i)return this;var e=this[t]=new i(this);return this._handlers.push(e),this.options[t]&&e.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}ut(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this._loaded&&this.fire("unload");var t;for(t in this._layers)this._layers[t].remove();for(t in this._panes)ut(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,i){var e="leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),n=ht("div",e,i||this._mapPane);return t&&(this._panes[t]=n),n},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new T(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,i,e){t=z(t),e=w(e||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),a=t.getSouthEast(),h=this.getSize().subtract(e),u=b(this.project(a,n),this.project(r,n)).getSize(),l=Ki?this.options.zoomSnap:1,c=h.x/u.x,_=h.y/u.y,d=i?Math.max(c,_):Math.min(c,_);return n=this.getScaleZoom(d,n),l&&(n=Math.round(n/(l/100))*(l/100),n=i?Math.ceil(n/l)*l:Math.floor(n/l)*l),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new x(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,i){var e=this._getTopLeftPoint(t,i);return new P(e,e.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,i){var e=this.options.crs;return i=void 0===i?this._zoom:i,e.scale(t)/e.scale(i)},getScaleZoom:function(t,i){var e=this.options.crs;i=void 0===i?this._zoom:i;var n=e.zoom(t*e.scale(i));return isNaN(n)?1/0:n},project:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.latLngToPoint(C(t),i)},unproject:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.pointToLatLng(w(t),i)},layerPointToLatLng:function(t){var i=w(t).add(this.getPixelOrigin());return this.unproject(i)},latLngToLayerPoint:function(t){return this.project(C(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(C(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(z(t))},distance:function(t,i){return this.options.crs.distance(C(t),C(i))},containerPointToLayerPoint:function(t){return w(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return w(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var i=this.containerPointToLayerPoint(w(t));return this.layerPointToLatLng(i)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(C(t)))},mouseEventToContainerPoint:function(t){return tt(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var i=this._container=rt(t);if(!i)throw new Error("Map container not found.");if(i._leaflet_id)throw new Error("Map container is already initialized.");V(i,"scroll",this._onScroll,this),this._containerId=n(i)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&Ki,pt(t,"leaflet-container"+(te?" leaflet-touch":"")+(ne?" leaflet-retina":"")+(Bi?" leaflet-oldie":"")+(Wi?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var i=at(t,"position");"absolute"!==i&&"relative"!==i&&"fixed"!==i&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Lt(this._mapPane,new x(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(pt(t.markerPane,"leaflet-zoom-hide"),pt(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,i){Lt(this._mapPane,new x(0,0));var e=!this._loaded;this._loaded=!0,i=this._limitZoom(i),this.fire("viewprereset");var n=this._zoom!==i;this._moveStart(n)._move(t,i)._moveEnd(n),this.fire("viewreset"),e&&this.fire("load")},_moveStart:function(t){return t&&this.fire("zoomstart"),this.fire("movestart")},_move:function(t,i,e){void 0===i&&(i=this._zoom);var n=this._zoom!==i;return this._zoom=i,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(n||e&&e.pinch)&&this.fire("zoom",e),this.fire("move",e)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return g(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Lt(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={},this._targets[n(this._container)]=this;var i=t?G:V;i(this._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress",this._handleDOMEvent,this),this.options.trackResize&&i(window,"resize",this._onResize,this),Ki&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){g(this._resizeRequest),this._resizeRequest=f(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,o=[],s="mouseout"===i||"mouseover"===i,r=t.target||t.srcElement,a=!1;r;){if((e=this._targets[n(r)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){a=!0;break}if(e&&e.listens(i,!0)){if(s&&!ot(r,t))break;if(o.push(e),s)break}if(r===this._container)break;r=r.parentNode}return o.length||a||s||!ot(r,t)||(o=[this]),o},_handleDOMEvent:function(t){if(this._loaded&&!nt(t)){var i=t.type;"mousedown"!==i&&"keypress"!==i||zt(t.target||t.srcElement),this._fireDOMEvent(t,i)}},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,n){if("click"===t.type){var o=i({},t);o.type="preclick",this._fireDOMEvent(o,o.type,n)}if(!t._stopped&&(n=(n||[]).concat(this._findEventTargets(t,e)),n.length)){var s=n[0];"contextmenu"===e&&s.listens(e,!0)&&$(t);var r={originalEvent:t};if("keypress"!==t.type){var a=s.options&&"icon"in s.options;r.containerPoint=a?this.latLngToContainerPoint(s.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=a?s.getLatLng():this.layerPointToLatLng(r.layerPoint)}for(var h=0;h0?Math.round(t-i)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(i))},_limitZoom:function(t){var i=this.getMinZoom(),e=this.getMaxZoom(),n=Ki?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(i,Math.min(e,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){mt(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,i){var e=this._getCenterOffset(t)._floor();return!(!0!==(i&&i.animate)&&!this.getSize().contains(e)||(this.panBy(e,i),0))},_createAnimProxy:function(){var t=this._proxy=ht("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(t){var i=Pe,e=this._proxy.style[i];wt(this._proxy,this.project(t.center,t.zoom),this.getZoomScale(t.zoom,1)),e===this._proxy.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",function(){var t=this.getCenter(),i=this.getZoom();wt(this._proxy,this.project(t,i),this.getZoomScale(i,1))},this),this._on("unload",this._destroyAnimProxy,this)},_destroyAnimProxy:function(){ut(this._proxy),delete this._proxy},_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,i,e){if(this._animatingZoom)return!0;if(e=e||{},!this._zoomAnimated||!1===e.animate||this._nothingToAnimate()||Math.abs(i-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o)||(f(function(){this._moveStart(!0)._animateZoom(t,i,!0)},this),0))},_animateZoom:function(t,i,n,o){n&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,pt(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:o}),setTimeout(e(this._onZoomTransitionEnd,this),250)},_onZoomTransitionEnd:function(){this._animatingZoom&&(mt(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),f(function(){this._moveEnd(!0)},this))}}),ke=v.extend({options:{position:"topright"},initialize:function(t){l(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return pt(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this},remove:function(){return this._map?(ut(this._container),this.onRemove&&this.onRemove(this._map),this._map=null,this):this},_refocusOnMap:function(t){this._map&&t&&t.screenX>0&&t.screenY>0&&this._map.getContainer().focus()}}),Be=function(t){return new ke(t)};Se.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){function t(t,o){var s=e+t+" "+e+o;i[t+o]=ht("div",s,n)}var i=this._controlCorners={},e="leaflet-",n=this._controlContainer=ht("div",e+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){for(var t in this._controlCorners)ut(this._controlCorners[t]);ut(this._controlContainer),delete this._controlCorners,delete this._controlContainer}});var Ie=ke.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,i,e,n){return e1,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=i&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var i=this._getLayer(n(t.target)),e=i.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;e&&this._map.fire(e,i)},_createRadioElement:function(t,i){var e='",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),o=this._map.hasLayer(t.layer);t.overlay?(i=document.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=o):i=this._createRadioElement("leaflet-base-layers",o),this._layerControlInputs.push(i),i.layerId=n(t.layer),V(i,"click",this._onInputClick,this);var s=document.createElement("span");s.innerHTML=" "+t.name;var r=document.createElement("div");return e.appendChild(r),r.appendChild(i),r.appendChild(s),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e,n=this._layerControlInputs,o=[],s=[];this._handlingClick=!0;for(var r=n.length-1;r>=0;r--)t=n[r],i=this._getLayer(t.layerId).layer,e=this._map.hasLayer(i),t.checked&&!e?o.push(i):!t.checked&&e&&s.push(i);for(r=0;r=0;o--)t=e[o],i=this._getLayer(t.layerId).layer,t.disabled=void 0!==i.options.minZoom&&ni.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),Ae=function(t,i,e){return new Ie(t,i,e)},Oe=ke.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=ht("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=ht("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),J(s),V(s,"click",Q),V(s,"click",o,this),V(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";mt(this._zoomInButton,i),mt(this._zoomOutButton,i),(this._disabled||t._zoom===t.getMinZoom())&&pt(this._zoomOutButton,i),(this._disabled||t._zoom===t.getMaxZoom())&&pt(this._zoomInButton,i)}});Se.mergeOptions({zoomControl:!0}),Se.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new Oe,this.addControl(this.zoomControl))});var Re=function(t){return new Oe(t)},De=ke.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=ht("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=ht("div",i,e)),t.imperial&&(this._iScale=ht("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;o>5280?(i=o/5280,e=this._getRoundNum(i),this._updateScale(this._iScale,e+" mi",e/i)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,i,e){t.style.width=Math.round(this.options.maxWidth*e)+"px",t.innerHTML=i},_getRoundNum:function(t){var i=Math.pow(10,(Math.floor(t)+"").length-1),e=t/i;return e=e>=10?10:e>=5?5:e>=3?3:e>=2?2:1,i*e}}),Ne=function(t){return new De(t)},je=ke.extend({options:{position:"bottomright",prefix:'
    Leaflet'},initialize:function(t){l(this,t),this._attributions={}},onAdd:function(t){t.attributionControl=this,this._container=ht("div","leaflet-control-attribution"),J(this._container);for(var i in t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Se.mergeOptions({attributionControl:!0}),Se.addInitHook(function(){this.options.attributionControl&&(new je).addTo(this)});var We=function(t){return new je(t)};ke.Layers=Ie,ke.Zoom=Oe,ke.Scale=De,ke.Attribution=je,Be.layers=Ae,Be.zoom=Re,Be.scale=Ne,Be.attribution=We;var He,Fe=v.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled?this:(this._enabled=!0,this.addHooks(),this)},disable:function(){return this._enabled?(this._enabled=!1,this.removeHooks(),this):this},enabled:function(){return!!this._enabled}}),Ue={Events:xi},Ve=!1,Ge=te?"touchstart mousedown":"mousedown",qe={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},Ke={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},Ye=wi.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){l(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(V(this._dragStartTarget,Ge,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(L.Draggable._dragging===this&&this.finishDrag(),G(this._dragStartTarget,Ge,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!dt(this._element,"leaflet-zoom-anim")&&!(Ve||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||(Ve=this,this._preventOutline&&zt(this._element),bt(),zi(),this._moving)))){this.fire("down");var i=t.touches?t.touches[0]:t;this._startPoint=new x(i.clientX,i.clientY),V(document,Ke[t.type],this._onMove,this),V(document,qe[t.type],this._onUp,this)}},_onMove:function(t){if(!t._simulated&&this._enabled){if(t.touches&&t.touches.length>1)return void(this._moved=!0);var i=t.touches&&1===t.touches.length?t.touches[0]:t,e=new x(i.clientX,i.clientY),n=e.subtract(this._startPoint);(n.x||n.y)&&(Math.abs(n.x)+Math.abs(n.y)1e-7;h++)i=s*Math.sin(a),i=Math.pow((1-i)/(1+i),s/2),u=Math.PI/2-2*Math.atan(r*i)-a,a+=u;return new M(a*e,t.x*e/n)}},tn=(Object.freeze||Object)({LonLat:$e,Mercator:Qe,SphericalMercator:bi}),en=i({},Pi,{code:"EPSG:3395",projection:Qe,transformation:function(){var t=.5/(Math.PI*Qe.R);return E(t,.5,-t,.5)}()}),nn=i({},Pi,{code:"EPSG:4326",projection:$e,transformation:E(1/180,1,-1/180,.5)}),on=i({},Li,{projection:$e,transformation:E(1,0,-1,0),scale:function(t){return Math.pow(2,t)},zoom:function(t){return Math.log(t)/Math.LN2},distance:function(t,i){var e=i.lng-t.lng,n=i.lat-t.lat;return Math.sqrt(e*e+n*n)},infinite:!0});Li.Earth=Pi,Li.EPSG3395=en,Li.EPSG3857=Zi,Li.EPSG900913=Ei,Li.EPSG4326=nn,Li.Simple=on;var sn=wi.extend({options:{pane:"overlayPane",attribution:null,bubblingMouseEvents:!0},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[n(t)]=this,this}, removeInteractiveTarget:function(t){return delete this._map._targets[n(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var i=t.target;if(i.hasLayer(this)){if(this._map=i,this._zoomAnimated=i._zoomAnimated,this.getEvents){var e=this.getEvents();i.on(e,this),this.once("remove",function(){i.off(e,this)},this)}this.onAdd(i),this.getAttribution&&i.attributionControl&&i.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),i.fire("layeradd",{layer:this})}}});Se.include({addLayer:function(t){var i=n(t);return this._layers[i]?this:(this._layers[i]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this)},removeLayer:function(t){var i=n(t);return this._layers[i]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[i],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null,this):this},hasLayer:function(t){return!!t&&n(t)in this._layers},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},_addLayers:function(t){t=t?pi(t)?t:[t]:[];for(var i=0,e=t.length;ithis._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()i)return r=(n-i)/e,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,i){return i=i||this._defaultShape(),t=C(t),i.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new T,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return jt(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var i=[],e=jt(t),n=0,o=t.length;n=2&&i[0]instanceof M&&i[0].equals(i[e-1])&&i.pop(),i},_setLatLngs:function(t){gn.prototype._setLatLngs.call(this,t),jt(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return jt(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,i=this.options.weight,e=new x(i,i);if(t=new P(t.min.subtract(e),t.max.add(e)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t)){if(this.options.noClip)return void(this._parts=this._rings);for(var n,o=0,s=this._rings.length;ot.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||gn.prototype._containsPoint.call(this,t,!0)}}),yn=hn.extend({initialize:function(t,i){l(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=pi(t)?t:t.features;if(o){for(i=0,e=o.length;io?(i.height=o+"px",pt(t,s)):mt(t,s),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),e=this._getAnchor();Lt(this._container,i.add(e))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,i=parseInt(at(this._container,"marginBottom"),10)||0,e=this._container.offsetHeight+i,n=this._containerWidth,o=new x(this._containerLeft,-e-this._containerBottom);o._add(Pt(this._container));var s=t.layerPointToContainerPoint(o),r=w(this.options.autoPanPadding),a=w(this.options.autoPanPaddingTopLeft||r),h=w(this.options.autoPanPaddingBottomRight||r),u=t.getSize(),l=0,c=0;s.x+n+h.x>u.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c])}},_onCloseButtonClick:function(t){this._close(),Q(t)},_getAnchor:function(){return w(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}}),Mn=function(t,i){return new zn(t,i)};Se.mergeOptions({closePopupOnClick:!0}),Se.include({openPopup:function(t,i,e){return t instanceof zn||(t=new zn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),sn.include({bindPopup:function(t,i){return t instanceof zn?(l(t,i),this._popup=t,t._source=this):(this._popup&&!i||(this._popup=new zn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){if(t instanceof sn||(i=t,t=this),t instanceof hn)for(var e in this._layers){t=this._layers[e];break}return i||(i=t.getCenter?t.getCenter():t.getLatLng()),this._popup&&this._map&&(this._popup._source=t,this._popup.update(),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;if(this._popup&&this._map)return Q(t),i instanceof pn?void this.openPopup(t.layer||t.target,t.latlng):void(this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var Cn=Tn.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Tn.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Tn.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Tn.prototype.getEvents.call(this);return te&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=ht("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i=this._map,e=this._container,n=i.latLngToContainerPoint(i.getCenter()),o=i.layerPointToContainerPoint(t),s=this.options.direction,r=e.offsetWidth,a=e.offsetHeight,h=w(this.options.offset),u=this._getAnchor();"top"===s?t=t.add(w(-r/2+h.x,-a+h.y+u.y,!0)):"bottom"===s?t=t.subtract(w(r/2-h.x,-h.y,!0)):"center"===s?t=t.subtract(w(r/2+h.x,a/2-u.y+h.y,!0)):"right"===s||"auto"===s&&o.xthis.options.maxZoom||en&&this._retainParent(o,s,r,n))},_retainChildren:function(t,i,e,n){for(var o=2*t;o<2*t+2;o++)for(var s=2*i;s<2*i+2;s++){var r=new x(o,s);r.z=e+1;var a=this._tileCoordsToKey(r),h=this._tiles[a];h&&h.active?h.retain=!0:(h&&h.loaded&&(h.retain=!0),e+1this.options.maxZoom||void 0!==this.options.minZoom&&o1)return void this._setView(t,e);for(var c=o.min.y;c<=o.max.y;c++)for(var _=o.min.x;_<=o.max.x;_++){var d=new x(_,c);d.z=this._tileZoom,this._isValidTile(d)&&(this._tiles[this._tileCoordsToKey(d)]||r.push(d))}if(r.sort(function(t,i){return t.distanceTo(s)-i.distanceTo(s)}),0!==r.length){this._loading||(this._loading=!0,this.fire("loading"));var p=document.createDocumentFragment();for(_=0;_e.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return z(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToBounds:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e),s=i.unproject(n,t.z),r=i.unproject(o,t.z),a=new T(s,r);return this.options.noWrap||i.wrapLatLngBounds(a),a},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new x(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ut(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){pt(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=r,t.onmousemove=r,Bi&&this.options.opacity<1&&vt(t,this.options.opacity),Oi&&!Ri&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var n=this._getTilePos(t),o=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),e(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&f(e(this._tileReady,this,t,null,s)),Lt(s,n),this._tiles[o]={el:s,coords:t,current:!0},i.appendChild(s),this.fire("tileloadstart",{tile:s,coords:t})},_tileReady:function(t,i,n){if(this._map){i&&this.fire("tileerror",{error:i,tile:n,coords:t});var o=this._tileCoordsToKey(t);(n=this._tiles[o])&&(n.loaded=+new Date,this._map._fadeAnimated?(vt(n.el,0),g(this._fadeFrame),this._fadeFrame=f(this._updateOpacity,this)):(n.active=!0,this._pruneTiles()),i||(pt(n.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:n.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),Bi||!this._map._fadeAnimated?f(this._pruneTiles,this):setTimeout(e(this._pruneTiles,this),250)))}},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new x(this._wrapX?s(t.x,this._wrapX):t.x,this._wrapY?s(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new P(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}}),kn=Sn.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,i=l(this,i),i.detectRetina&&ne&&i.maxZoom>0&&(i.tileSize=Math.floor(i.tileSize/2),i.zoomReverse?(i.zoomOffset--,i.minZoom++):(i.zoomOffset++,i.maxZoom--),i.minZoom=Math.max(0,i.minZoom)),"string"==typeof i.subdomains&&(i.subdomains=i.subdomains.split("")),Oi||this.on("tileunload",this._onTileRemove)},setUrl:function(t,i){return this._url=t,i||this.redraw(),this},createTile:function(t,i){var n=document.createElement("img");return V(n,"load",e(this._tileOnLoad,this,i,n)),V(n,"error",e(this._tileOnError,this,i,n)),this.options.crossOrigin&&(n.crossOrigin=""),n.alt="",n.setAttribute("role","presentation"),n.src=this.getTileUrl(t),n},getTileUrl:function(t){var e={r:ne?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var n=this._globalTileRange.max.y-t.y;this.options.tms&&(e.y=n),e["-y"]=n}return _(this._url,i(e,this.options))},_tileOnLoad:function(t,i){Bi?setTimeout(e(t,this,null,i),0):t(null,i)},_tileOnError:function(t,i,e){var n=this.options.errorTileUrl;n&&i.src!==n&&(i.src=n),t(e,i)},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,i=this.options.maxZoom,e=this.options.zoomReverse,n=this.options.zoomOffset;return e&&(t=i-t),t+n},_getSubdomain:function(t){var i=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[i]},_abortLoading:function(){var t,i;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&(i=this._tiles[t].el,i.onload=r,i.onerror=r,i.complete||(i.src=mi,ut(i)))}}),Bn=kn.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var n=i({},this.defaultWmsParams);for(var o in e)o in this.options||(n[o]=e[o]);e=l(this,e),n.width=n.height=e.tileSize*(e.detectRetina&&ne?2:1),this.wmsParams=n},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var i=this._wmsVersion>=1.3?"crs":"srs";this.wmsParams[i]=this._crs.code,kn.prototype.onAdd.call(this,t)},getTileUrl:function(t){var i=this._tileCoordsToBounds(t),e=this._crs.project(i.getNorthWest()),n=this._crs.project(i.getSouthEast()),o=(this._wmsVersion>=1.3&&this._crs===nn?[n.y,e.x,e.y,n.x]:[e.x,n.y,n.x,e.y]).join(","),s=kn.prototype.getTileUrl.call(this,t);return s+c(this.wmsParams,s,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+o},setParams:function(t,e){return i(this.wmsParams,t),e||this.redraw(),this}});kn.WMS=Bn,si.wms=ri;var In=sn.extend({options:{padding:.1},initialize:function(t){l(this,t),n(this),this._layers=this._layers||{}},onAdd:function(){this._container||(this._initContainer(),this._zoomAnimated&&pt(this._container,"leaflet-zoom-animated")),this.getPane().appendChild(this._container),this._update(),this.on("update",this._updatePaths,this)},onRemove:function(){this.off("update",this._updatePaths,this),this._destroyContainer()},getEvents:function(){var t={viewreset:this._reset,zoom:this._onZoom,moveend:this._update,zoomend:this._onZoomEnd};return this._zoomAnimated&&(t.zoomanim=this._onAnimZoom),t},_onAnimZoom:function(t){this._updateTransform(t.center,t.zoom)},_onZoom:function(){this._updateTransform(this._map.getCenter(),this._map.getZoom())},_updateTransform:function(t,i){var e=this._map.getZoomScale(i,this._zoom),n=Pt(this._container),o=this._map.getSize().multiplyBy(.5+this.options.padding),s=this._map.project(this._center,i),r=this._map.project(t,i),a=r.subtract(s),h=o.multiplyBy(-e).add(n).add(o).subtract(a);Ki?wt(this._container,h,e):Lt(this._container,h)},_reset:function(){this._update(),this._updateTransform(this._center,this._zoom);for(var t in this._layers)this._layers[t]._reset()},_onZoomEnd:function(){for(var t in this._layers)this._layers[t]._project()},_updatePaths:function(){for(var t in this._layers)this._layers[t]._update()},_update:function(){var t=this.options.padding,i=this._map.getSize(),e=this._map.containerPointToLayerPoint(i.multiplyBy(-t)).round();this._bounds=new P(e,e.add(i.multiplyBy(1+2*t)).round()),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}}),An=In.extend({getEvents:function(){var t=In.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){In.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=document.createElement("canvas");V(t,"mousemove",o(this._onMouseMove,32,this),this),V(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this),V(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_destroyContainer:function(){delete this._ctx,ut(this._container),G(this._container),delete this._container},_updatePaths:function(){if(!this._postponeUpdatePaths){var t;this._redrawBounds=null;for(var i in this._layers)t=this._layers[i],t._update();this._redraw()}},_update:function(){if(!this._map._animatingZoom||!this._bounds){this._drawnLayers={},In.prototype._update.call(this);var t=this._bounds,i=this._container,e=t.getSize(),n=ne?2:1;Lt(i,t.min),i.width=n*e.x,i.height=n*e.y,i.style.width=e.x+"px",i.style.height=e.y+"px",ne&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_reset:function(){In.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t),this._layers[n(t)]=t;var i=t._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=i),this._drawLast=i,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var i=t._order,e=i.next,n=i.prev;e?e.prev=n:this._drawLast=n,n?n.next=e:this._drawFirst=e,delete t._order,delete this._layers[L.stamp(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if(t.options.dashArray){var i,e=t.options.dashArray.split(","),n=[];for(i=0;i')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),Rn={_initContainer:function(){this._container=ht("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(In.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=On("shape");pt(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=On("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[n(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ut(i),t.removeInteractiveTarget(i),delete this._layers[n(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i||(i=t._stroke=On("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=pi(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e||(e=t._fill=On("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){ct(t._container)},_bringToBack:function(t){_t(t._container)}},Dn=re?On:S,Nn=In.extend({getEvents:function(){var t=In.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=Dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=Dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ut(this._container),G(this._container),delete this._container,delete this._rootGroup},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){In.prototype._update.call(this);var t=this._bounds,i=t.getSize(),e=this._container;this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),Lt(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update")}},_initPath:function(t){var i=t._path=Dn("path");t.options.className&&pt(i,t.options.className),t.options.interactive&&pt(i,"leaflet-interactive"),this._updateStyle(t),this._layers[n(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ut(t._path),t.removeInteractiveTarget(t._path),delete this._layers[n(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,k(t._parts,i))},_updateCircle:function(t){var i=t._point,e=t._radius,n=t._radiusY||e,o="a"+e+","+n+" 0 1,0 ",s=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+o+2*e+",0 "+o+2*-e+",0 ";this._setPath(t,s)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){ct(t._path)},_bringToBack:function(t){_t(t._path)}});re&&Nn.include(Rn),Se.include({getRenderer:function(t){var i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return i||(i=this._renderer=this.options.preferCanvas&&ai()||hi()),this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=Nn&&hi({pane:t})||An&&ai({pane:t}),this._paneRenderers[t]=i),i}});var jn=vn.extend({initialize:function(t,i){vn.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return t=z(t),[t.getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Nn.create=Dn,Nn.pointsToPath=k,yn.geometryToLayer=Kt,yn.coordsToLatLng=Yt,yn.coordsToLatLngs=Xt,yn.latLngToCoords=Jt,yn.latLngsToCoords=$t,yn.getFeature=Qt,yn.asFeature=ti,Se.mergeOptions({boxZoom:!0});var Wn=Fe.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){V(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){G(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ut(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){return!(!t.shiftKey||1!==t.which&&1!==t.button)&&(this._clearDeferredResetState(),this._resetState(),zi(),bt(),this._startPoint=this._map.mouseEventToContainerPoint(t),void V(document,{contextmenu:Q,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this))},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=ht("div","leaflet-zoom-box",this._container),pt(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new P(this._point,this._startPoint),e=i.getSize();Lt(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ut(this._box),mt(this._container,"leaflet-crosshair")),Mi(),Tt(),G(document,{contextmenu:Q,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(e(this._resetState,this),0);var i=new T(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Se.addInitHook("addHandler","boxZoom",Wn),Se.mergeOptions({doubleClickZoom:!0});var Hn=Fe.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Se.addInitHook("addHandler","doubleClickZoom",Hn),Se.mergeOptions({dragging:!0,inertia:!Ri,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var Fn=Fe.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new Ye(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}pt(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){mt(this._map._container,"leaflet-grab"),mt(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t=this._map;if(t._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var i=z(this._map.options.maxBounds);this._offsetLimit=b(this._map.latLngToContainerPoint(i.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(i.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(i),i-this._times[0]>50&&(this._positions.shift(),this._times.shift())}this._map.fire("move",t).fire("drag",t)},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),i=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=i.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,i){return t-(t-i)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),i=this._offsetLimit;t.xi.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){ -var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)0?s:-s))-i;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(i+r):t.setZoomAround(this._lastMousePos,i+r))}});Se.addInitHook("addHandler","scrollWheelZoom",Vn),Se.mergeOptions({tap:!0,tapTolerance:15});var Gn=Fe.extend({addHooks:function(){V(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){G(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if($(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new x(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&pt(n,"leaflet-active"),this._holdTimeout=setTimeout(e(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),V(document,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),G(document,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],e=i.target;e&&e.tagName&&"a"===e.tagName.toLowerCase()&&mt(e,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var i=t.touches[0];this._newPos=new x(i.clientX,i.clientY),this._simulateEvent("mousemove",i)},_simulateEvent:function(t,i){var e=document.createEvent("MouseEvents");e._simulated=!0,i.target._simulatedClick=!0,e.initMouseEvent(t,!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),i.target.dispatchEvent(e)}});te&&!Qi&&Se.addInitHook("addHandler","tap",Gn),Se.mergeOptions({touchZoom:te&&!Ri,bounceAtZoomLimits:!0});var qn=Fe.extend({addHooks:function(){pt(this._map._container,"leaflet-touch-zoom"),V(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){mt(this._map._container,"leaflet-touch-zoom"),G(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(e.add(n)._divideBy(2))),this._startDist=e.distanceTo(n),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),V(document,"touchmove",this._onTouchMove,this),V(document,"touchend",this._onTouchEnd,this),$(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var i=this._map,n=i.mouseEventToContainerPoint(t.touches[0]),o=i.mouseEventToContainerPoint(t.touches[1]),s=n.distanceTo(o)/this._startDist;if(this._zoom=i.getScaleZoom(s,this._startZoom),!i.options.bounceAtZoomLimits&&(this._zoomi.getMaxZoom()&&s>1)&&(this._zoom=i._limitZoom(this._zoom)),"center"===i.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=n._add(o)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=i.unproject(i.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(i._moveStart(!0),this._moved=!0),g(this._animRequest);var a=e(i._move,i,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=f(a,this,!0),$(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,g(this._animRequest),G(document,"touchmove",this._onTouchMove),G(document,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}});Se.addInitHook("addHandler","touchZoom",qn),Se.BoxZoom=Wn,Se.DoubleClickZoom=Hn,Se.Drag=Fn,Se.Keyboard=Un,Se.ScrollWheelZoom=Vn,Se.Tap=Gn,Se.TouchZoom=qn;var Kn=window.L;window.L=t,t.version="1.1.0",t.noConflict=li,t.Control=ke,t.control=Be,t.Browser=ae,t.Evented=wi,t.Mixin=Ue,t.Util=yi,t.Class=v,t.Handler=Fe,t.extend=i,t.bind=e,t.stamp=n,t.setOptions=l,t.DomEvent=Le,t.DomUtil=Ze,t.PosAnimation=Ee,t.Draggable=Ye,t.LineUtil=Xe,t.PolyUtil=Je,t.Point=x,t.point=w,t.Bounds=P,t.bounds=b,t.Transformation=Z,t.transformation=E,t.Projection=tn,t.LatLng=M,t.latLng=C,t.LatLngBounds=T,t.latLngBounds=z,t.CRS=Li,t.GeoJSON=yn,t.geoJSON=ii,t.geoJson=wn,t.Layer=sn,t.LayerGroup=rn,t.layerGroup=an,t.FeatureGroup=hn,t.featureGroup=un,t.ImageOverlay=Ln,t.imageOverlay=Pn,t.VideoOverlay=bn,t.videoOverlay=ei,t.DivOverlay=Tn,t.Popup=zn,t.popup=Mn,t.Tooltip=Cn,t.tooltip=Zn,t.Icon=ln,t.icon=Ht,t.DivIcon=En,t.divIcon=ni,t.Marker=dn,t.marker=Ft,t.TileLayer=kn,t.tileLayer=si,t.GridLayer=Sn,t.gridLayer=oi,t.SVG=Nn,t.svg=hi,t.Renderer=In,t.Canvas=An,t.canvas=ai,t.Path=pn,t.CircleMarker=mn,t.circleMarker=Ut,t.Circle=fn,t.circle=Vt,t.Polyline=gn,t.polyline=Gt,t.Polygon=vn,t.polygon=qt,t.Rectangle=jn,t.rectangle=ui,t.Map=Se,t.map=Ct}) \ No newline at end of file +var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)0?s:-s))-i;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(i+r):t.setZoomAround(this._lastMousePos,i+r))}});Se.addInitHook("addHandler","scrollWheelZoom",Vn),Se.mergeOptions({tap:!0,tapTolerance:15});var Gn=Fe.extend({addHooks:function(){V(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){G(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if($(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new x(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&pt(n,"leaflet-active"),this._holdTimeout=setTimeout(e(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),V(document,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),G(document,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],e=i.target;e&&e.tagName&&"a"===e.tagName.toLowerCase()&&mt(e,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var i=t.touches[0];this._newPos=new x(i.clientX,i.clientY),this._simulateEvent("mousemove",i)},_simulateEvent:function(t,i){var e=document.createEvent("MouseEvents");e._simulated=!0,i.target._simulatedClick=!0,e.initMouseEvent(t,!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),i.target.dispatchEvent(e)}});te&&!Qi&&Se.addInitHook("addHandler","tap",Gn),Se.mergeOptions({touchZoom:te&&!Ri,bounceAtZoomLimits:!0});var qn=Fe.extend({addHooks:function(){pt(this._map._container,"leaflet-touch-zoom"),V(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){mt(this._map._container,"leaflet-touch-zoom"),G(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(e.add(n)._divideBy(2))),this._startDist=e.distanceTo(n),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),V(document,"touchmove",this._onTouchMove,this),V(document,"touchend",this._onTouchEnd,this),$(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var i=this._map,n=i.mouseEventToContainerPoint(t.touches[0]),o=i.mouseEventToContainerPoint(t.touches[1]),s=n.distanceTo(o)/this._startDist;if(this._zoom=i.getScaleZoom(s,this._startZoom),!i.options.bounceAtZoomLimits&&(this._zoomi.getMaxZoom()&&s>1)&&(this._zoom=i._limitZoom(this._zoom)),"center"===i.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=n._add(o)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=i.unproject(i.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(i._moveStart(!0),this._moved=!0),g(this._animRequest);var a=e(i._move,i,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=f(a,this,!0),$(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,g(this._animRequest),G(document,"touchmove",this._onTouchMove),G(document,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}});Se.addInitHook("addHandler","touchZoom",qn),Se.BoxZoom=Wn,Se.DoubleClickZoom=Hn,Se.Drag=Fn,Se.Keyboard=Un,Se.ScrollWheelZoom=Vn,Se.Tap=Gn,Se.TouchZoom=qn;var Kn=window.L;window.L=t,t.version="1.1.0",t.noConflict=li,t.Control=ke,t.control=Be,t.Browser=ae,t.Evented=wi,t.Mixin=Ue,t.Util=yi,t.Class=v,t.Handler=Fe,t.extend=i,t.bind=e,t.stamp=n,t.setOptions=l,t.DomEvent=Le,t.DomUtil=Ze,t.PosAnimation=Ee,t.Draggable=Ye,t.LineUtil=Xe,t.PolyUtil=Je,t.Point=x,t.point=w,t.Bounds=P,t.bounds=b,t.Transformation=Z,t.transformation=E,t.Projection=tn,t.LatLng=M,t.latLng=C,t.LatLngBounds=T,t.latLngBounds=z,t.CRS=Li,t.GeoJSON=yn,t.geoJSON=ii,t.geoJson=wn,t.Layer=sn,t.LayerGroup=rn,t.layerGroup=an,t.FeatureGroup=hn,t.featureGroup=un,t.ImageOverlay=Ln,t.imageOverlay=Pn,t.VideoOverlay=bn,t.videoOverlay=ei,t.DivOverlay=Tn,t.Popup=zn,t.popup=Mn,t.Tooltip=Cn,t.tooltip=Zn,t.Icon=ln,t.icon=Ht,t.DivIcon=En,t.divIcon=ni,t.Marker=dn,t.marker=Ft,t.TileLayer=kn,t.tileLayer=si,t.GridLayer=Sn,t.gridLayer=oi,t.SVG=Nn,t.svg=hi,t.Renderer=In,t.Canvas=An,t.canvas=ai,t.Path=pn,t.CircleMarker=mn,t.circleMarker=Ut,t.Circle=fn,t.circle=Vt,t.Polyline=gn,t.polyline=Gt,t.Polygon=vn,t.polygon=qt,t.Rectangle=jn,t.rectangle=ui,t.Map=Se,t.map=Ct}) \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-map.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-map.html.gz index ac93508be615c5d062f3bfa51d06e61d0114c23d..7f5a96d3c93b0a2722969ced358fd1fe9dd3163e 100644 GIT binary patch delta 2044 zcmV8EYOpxT#fS^O1hN ztma|x^-imaov(xFYY!qCZaj2SeQDj%9u#Ym;{H)G0@1||tYI4&G-}2d?rr9(-iTH` zK#H5BYh)91Y~&WNX(i|b7n`Nuh)dL}p%Zm2J`Rec3IeN{x7h-2e^#pznPfB(6lK4n zWPv^PxiAio)Ik!YDe&A>2m`rR>Zc6V{g;8oCc~40{Qa+rfnzK-3@kBGV+Vj4yu^knY{e2X69Rr{dw94dIQ+8K8s0g_TIz3_wqUk zrpp>w$v!0nJ>fV?e@F==$kCYKiQ@41FCmM$y+lfVn$G*_JU=VOz^ArZ{fW(gLro;h zhdpGY1vkDo*v~E|sNEqNVj@{G;+#$51uNyWESf&<*YSwHPsq77C|YZd)VJ ztT8fd!i}|9A-yED7Pz4KDXhXNGG4rxNI@VQWq+IO)Y>NANbrS2#e>0teLSFkzyKmR&(&LUtj3(q| zBu%?h6;vCyj@0t*i>8L-y6sqfG7a8=H4+tjnM=o8y- z{Ft`gJbRO3>dehW`dW9uk4DBdRW3X?qyeo~Z}v9A`p!j4?^CzpmCEh;R=!&447`rn zq=Cr^~8_i$S1JT?YMh$xJx` zOq<9w96Tl%7*RU4jN3`QRh_F+E$kZmu2WIVzBZ&giJmoscul@{SgR@t!a%u1k%K|G z^TY$L6R6z+87AJXW?Apcqap*^qtKHOqc;LJCX-2{bqDIjvHdxw(38cZCjnWL?V~aQ z_>&-{7#HQN-5@VXSDPZ&ZPr;&8)Z;W8dI`I#*xOMf{V+r%M7mc9RmQPXVEmVyJU}wBB7TXq-TV zKY5HQ(pj+-w`Z?NtE#+0y1{@b2C5^S^!2W_7e&^?8;x z1GcS}^8;cl>%(Bl%@N+BG`%%q9`P}l*63``al@)yji74**+2XQVt61uuN>}=2K&SP zxIY+ve-w`%D8J_~wO^CEsZS7VF8jK=x*EVT7Ijkru*jK{8LBXU27)7pcBAj^C^8fJ zEfkvF=DrDKm}}|sF|BWkspUm;kQbNeAra01yFiPDLO2dQgbN(~t%SlMW^@;GM$5nM zWT-4R0U9shSV_-ZhT|T&uIT+xt)%Hd4M&RZV@~rk_^Zm$*Gb+0B8oe*%i@gkVQdf4 zhAXj}Ha(?;&fst**ZJa0qrWUMB#e|1`$9@K1EA%?!9Lkuneblc9WOT`PtY)o$dm1= z96D~#aeR1evpQ-wC!$ti+R~;2QRRZuRzQu0F zWo+nlU`$E6H^+s-BY7l3B)h$`uaoYpE&;!j9jsj|?tuT38)vxp-FMGN{*7af!`eP~ a6tKXsS;D9-2z*%GC;u0{mT+MyU;+SO%kl#N delta 2043 zcmV4o56&5GJap1>X7{!ucn(8Ug{VH+7VYDNw2#pP<*h*mv7ikqZs zWD|32c~CFrvio2B1~`_ihR6Ll@#`HFf90;`#~*#a(6s}Y%Ge>4#kWxt|ifhhG6 zFwTioHxg7Ru-8-wW42c6r;N(|mx0C543M9Z-Xj44Au2l@9#L%R5coZk90@Dw&!1HS zx$Xh}Y$w>=4R%yAvWC$PYLncVZ2PX}+gm*RdD;ik0ywWeOGIo=-ovT)@;V8o%Nn@G zJ|zS_;Uh{21SH7Oe{SH3V&?cSA$GaFM526}&im;+KP$$-lD4_}iOp(5O{BnwJ>-}L zEFi~Zf18}s+9uxQQxy6U-=#;|ZNv!vL4Z*)L|y(&*Wn-(qZvb<;fJIm|||IImAo zPv4)jZ2mNAL$O9LtjWy7{(Hxdx;SuHyl;=(o4snzP zmFRqm1BC+IR$_ggqN0gP#!l_8CoEKT66?z|or3aQfBQ>&YS-z~xsFF-CPZT-IJ;97 zR2#RBfb#B(riSCX?O$alAM>Watg%Ff@&J*GcIiHB2Qr+$z}}`gjSVAD%5jqZZFbnmM7CvZsiw?vTD+z z@l1Kp)&!HGpc?`QY?HpAK_;;LGOzQKe2xNb7bnn0U`G7bC?;y&web-z{!pHyA>#tb z=?j6PlO>@z9zO~?CH9RH^qgqte`|Naxjnv5RH2c#5W>qlSrtx`d!Zmx16b=uvUhM* z&Tre)v$5zC+eQ4Cw%t5?lVa-3%|-fJcfjvM#x+$gJU65PtyXXLHp2SOMM_Umx8gy{ z?fF(dQ0WZ3j@f#6*aigL!)Y_dTsAn9?x8O?q_2;0CKwn|`mc=JNxfB_t5PlO8vCwOQOmwIr00m9HG_CfzIRxw zDha|sc|Vi;q8R}wlNF;k0=65IPNQ`Pn#8gFIi@I+%A+R%FO%}4GB8kza1-bAnUu={ zwMXQbu`ClKiwLjoB^#rWtlc0lNmrX9*KO8WPa9=WPa0FQ^Tm@?q(1@Ala!<*0c(@E zq%Q{)Mny}zXlRq}q)RDjmws_$I21>Hwynv#uJzkRIwO@a1S_(-y+`~LlXa69s80b+lV_-N z0yNZ<+^8CA7NPZdc}0aV89!dZZ`KsHYqR$AMT&sV8?@>Tp1evIQgPVoSK6?$M(ReY z#nRygxe*vVX9);hhCdsTE2#Ika5$d6qQ;HlvpF17a)d!(hpy5#FLSy)|MU@iCaz=vU71 zxT?I0pcetzKl}t@cp#mu9PW<>`@{XXKNx<06ptP#7w0dv3zNU8PY_lv`?|Wi8o)9Z zbyESb$ZwM#sxW`Xd?Vj=qwnr02ot&}6q?=Uz6oVSYw6uFt#68{GW;Xs`t0;e*%$mRgQQBoDeTA_fvLKM**Q>-TjqJcdAZ%UWcaL1kd>!nxO6>$+ zE29?pd=iX{xYQU=_?!uE&zp<+xQek19=`G6-otqB;ZZzQ_PjtTMsdagy$pQ@~VJ5>VkD89vR#${~ibYS>Mx;Mv#!XtSkq9MDzvRjk$t1bbmlOn8L0-k@9fvgi2 Zo4~MH!T>D@d|2Hl{};u{_#6~q0ssf5^u7Q9 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html index 99d4b1db86e35..20d85cfdee988 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz index f80112f596de006935b9393f102991d2ac6264aa..6c71d75c39096ba7237d6622b4046bb8c125c169 100644 GIT binary patch delta 5091 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 CjRUR# diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html b/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html index f4142c54f2364..884618cd34cd1 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html @@ -1 +1 @@ -

    \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-zwave.html.gz index 271ecd66614574e05e16afc3d92badd497f1a482..9c93970e3362608d6013993438de8f079b7cd37f 100644 GIT binary patch delta 8566 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ƠGf}%FtCCZJL6O2ghxpjM!y_vU}H<$($a* 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 delta 8561 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 rej3RqIOVqOL|Q>euQ8 zhy}_IP1)M$+%~A!O*KOAE8euWFYbY{uP3MwqyiNvch8lR8TG|eIzD_^8c3Bh=n^F#MMklG=#atQ1UGB#c4f7rRs4QVU}emQpi9^U$8vpEMj?rx$g&DY}BNj2SJhr z3^U1rr(7r?Ln4U`MaI-=H7zz*g}`x^Komldswm5&D9w1nQxcP~gd-^FZ!~2I8KhJm zL6FCppGHDr5GN_wl%*W}Cp2l$IA#H=L@8t}N`;gVbM6by2^F4%Bx|FGWm1Hx3RD)P zeiYMo6{&zE5GkfCd16Nzm#fmKl7UPU3<>o-2}!m@(u!nikP$eTZB&JM%DBupV`&

    ;Pd7zR2e3qm1AMsSQVkx^tJxq_z=;h_99 z&(e_4W`NiU-dIgWx09ykwXP>`yPxsTbtyfqm9de9xe!E-C`pKp0l`cG90Gt0xSz1^ ziTb6OFZ3WQB{y=4o*?Xe7cu1%m=wk=48tIdz9;Kfl*M{E2vbPW9#L@69z{rrD@%xs zlx0%lHp%{;u(vp0m(UE-Krof&xukFe6$g1j`6GydXXK-Z1!7lPVG6@U!Ic?|gFO63 zf8MH^cTCT7pYe4 zgxZ6sSi&4zsx*!Kyd-GgGsXQ4HlO)?um%`KO&|jiWGtpo&LD|GG9_m|5|3b4+BI?$ zd38nUy&Y5RQRh%pLl{tmP{5@iAxkLG$$be$yksg2a^jYCdFggV<~La4%xbU4o2oOu zV&k!OZnsz}ufcgi6{;&?&ktt2R@7AKEz5C>c||cwt0NTQ}1`72PNrP?<8H2Hn4 zm!Bt>E=c)Ts`#cp-@K|Mew#fsF{bdF>IXAZXFt6Cg$m-d?`x?3Q8@>XlFXta>0V2v z7VUB1oSoSZ)8{koxZvsfT~||W=iU`1LiH9~0;$E>(VnUyKNyoxKDRAXm#u=PpTBA9 zWzm|~ZCzd=bsXlMb3wml&28s#6Q=i?u#HMvySJP6feJ-Ga*hAiW}+Vq&+qY@-p-i^ z)9PIu*kN|nAXSU5yZk5K>|yAFTlF}KLmWrd*_n7iacLZ6SI*s?ExeZ66R|j-ZHLdT zGt0R494k>v{P6bGiw)Umv**^#I`#$}#}#`nDB3rq@Z*B$SrT(lKJs~?Y}4K0(91c! zsn7iBJ{h#LHGI1DU0W~lSRV|--ny2`H7(ZaRYy>{$Iw5;F&c`cfCwMpZv1(;mgd z0@_7~K_B{`cVgdi>4ed~uQ$|cJ2ZYJZTmgxfdK|OJu?QnKtI8yTRnKr?Gi^>_uVn^ zW42FVyV|#jIQ%Twp#Q1bG2RuI_l`5|t#Y zlyAU6{X zCW1ORdjQ|!zt_h1;NB8wlJ;9b*@y3mVJpPI}OX2?=o#d~?y#Of)a&|9s|ZgfZF zd-CRy1MQ9n$kFZBV)c=H*wfc6a8D4x99OT1So;jKur3hvRT>|lif|~|?x9qs51US=Ybl$frYS89}2m4#0T6K1I zP>$?R*6+6c{F&W%Rd=u|?o6&K?}mfs=j*!piVgKucT1=WWn`HXK1H$f=RZ+Hwzu=H zCE4aab8_F$e!JQ1qk8@ zc;kbPE+PHUS|gK6dkZc`KfL~NA8*Pe!aW)A;z)*=_V+{NJ}P9x%~NY) z%-u~4M|$8zef`_cHJ44*y3nQRC=Ovhyld<3$}D0#7FQ^(;Y!Wiq7Aoh=Eq#6J=~r- zPX+ewjTPCRN5u=Z?fyoZ47VFkD z`PGK-mDkPL&XiVc%rK$$u~Y4Ai`?TkwthOx?mL6f+jqv3ZlJF_FHm*=FV(`KJ!2LC E02H;~YybcN literal 2487 zcmV;o2}t%IiwFP!000021EpANbKAHT{VNKm>m_T72Kc5`O=dUUX}8_oWb&ANNWB>l zxRjVsq)I||T*v>t2c#rRmgH=wA8bM(aqq>s=RN>y)zPTaZ7H=iDOR=AWmAtj(l3h_ zLe5FOYpc#C=dLBaYU>espXs)<9Z%1xwl@p*K3It5@fWMMx_9nRFRkfj^oBHM@Y&Xu zy3u7(N@0HdbWOE>A*w1D^0Q5@cJ7L@rB|zNzMZ`j{klu-4FgvRE%0ksj%VgvEoP7B zG3DypC0)|Jdt{0C=|=CEcA&erNKr+au;0xJmrbYBm-#1>dO&Y@<#-j z8lG55-L%^UXJ>oj+=8^6+t!6xmKVKwx87VYs^~(lZLr+C1?hRCF0EHD-@LWlISEB= zcWKc5`!KfetQSqKf#vuuHfvp4V!5o=8@>3{HMQmbu!4}b{7*l3Y5ho|rFLYU>wCw| z8+Cj6k2f!W^9*z98LSwbb}ib`vL$Jl0}Vwvn|}CUU0ANA{8-2^N`jQdJ|({5Ohy5v z%J(UYm~UOV_^@buv(&{>)KqmBimu0Gd_E4-G?uB){U8c6Kj(SoCqb4+DN{a|G4D}; z9#-&J6=5b4mBo=#k{2q9iX>M-QQ+^ip0X~Qu^&>JrX&-Q3aOY3vM3M2Ad4wujOTKr zCdqToIr_^-RUYC-_Li#dd6s9qDqGT9`0cC+ovVx_O#kA4H zl_*llqfGfw!GgF*SQh4tk{~I#U{7e$Len_KM}8t%sPZ`QGZk=INSP?6V!@z%3mo%F zWRb|@q=;ZZk#X)bmWq^9l<@qt9!-m7)vNNQio$>=i41u{k&I*R6H8Q)Mx5e&qblVR z*2pMiaG{d$mJA}86~SToNmWQI;~c&ZQtrz*gKtw2XF>%^fK)|6Ngi%Az=@K}ppY?M zW2<=-b4g6_BFae=(V)QqRLTq4ES4DLWmW3iaY`Yakw-=7Lx>DP2A+#76j=_>a^L&Z zK|z=>%%qV}ew0z*hcbXUOoXh6RTdA zMrj-|PDz5?LXiC}VXtYnszke%Ccw@l%T$!-;3Lms1UE+Y5eyOuxWcf*9QlfKo%l}MnK%(f`!GABPr zh=EUg5S0rtqYjm(RUa3CMtnrv-%|TApRKJC0iuR0E_oV6DhLpvA@V!R0!HAG*p+re zxrw}{MtbkYh&^-;WxWmqL4%Ho zS9s0D{S_78)aTouYeiqC4^50I{HFSesj0K?UjKrEI2rmH)IXGS;UUS)Ye@Gx zlv=XK+&Me5AEwWz+Hr-an>T$;wViucRwU}z)B&W9rbm0K7Je`$k$P@hrY>70rk}rR zn?>1~*IiRx6FLs_&bh?1YI56o+=S`9CTye9*6!V=eLz7PMy~PS%1jJ{_3yXzMQ`WK z57X*h9@t@a)e@>j-(CKbZuc;Bg0NT+h#+pu1DinXxr~e4-7ES>8UZ$6?pI~w|?-P+b52y8M_y0x5@AHY3lF{cQWQTQ400;4{a-MJ+u}J`w^PnwWwCqndGqtpy;CjZUzh{ zf_gXy0AJI;SH}0ky#r_p`z=M)U0NM1ALDc}D{Je1%hcg)Qy;N&kl%cE^t^3u`W*FB z+crRLtzlF&=5Qj;tZ@DtN(LIsx z;msol+8qzT(cR~A`5rzT=xY|ZCkSAUtJfgbJ_81BZjQz$T{8JUm~!GwFOKp>HVw*xD@;Uv5U5wU$Tm)Z|& zu!X1k0cWD8kG(Juf1*)}#Ppy`0ACQ?7!2LA}X~D0cq*Cp2VxJMUYP zZSFHC_x_%XChmCpGKvmgWa3lwqCc3FixV5$Y{flN*srp~v>yg2m z9(42x>ATJvnN&Jha5?(!<@ft|Ba^JJbhgty^G{QMx$5ReGQ?!KAAQR&M~WYa_%~P_00VN ziE@q24MM-Uv5sAP_8psBPe2s}9h->1Y}&|)I6rql>KfgMKsRFaAsd+NP&9JYnI^y9 z5We>MIop|F#l{R1YVUj1&bG)seq-yWv+TYzfZo0{o^%7g?!AEO{$HI5DIjAO001ff B*n Date: Tue, 25 Jul 2017 00:42:59 -0700 Subject: [PATCH 092/118] Tweak conversation/intent/shopping list (#8636) --- homeassistant/components/conversation.py | 8 +++++++- homeassistant/components/shopping_list.py | 13 +++++++++---- homeassistant/helpers/intent.py | 2 +- tests/components/test_shopping_list.py | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/conversation.py b/homeassistant/components/conversation.py index b682b318c7b90..303e83e7e0ef4 100644 --- a/homeassistant/components/conversation.py +++ b/homeassistant/components/conversation.py @@ -151,7 +151,7 @@ def _process(hass, text): if not entity_ids: _LOGGER.error( "Could not find entity id %s from text %s", name, text) - return + return None if command == 'on': yield from hass.services.async_call( @@ -169,6 +169,8 @@ def _process(hass, text): _LOGGER.error('Got unsupported command %s from text %s', command, text) + return None + class ConversationProcessView(http.HomeAssistantView): """View to retrieve shopping list content.""" @@ -194,4 +196,8 @@ def post(self, request): intent_result = yield from _process(hass, text) + if intent_result is None: + intent_result = intent.IntentResponse() + intent_result.async_set_speech("Sorry, I didn't understand that") + return self.json(intent_result) diff --git a/homeassistant/components/shopping_list.py b/homeassistant/components/shopping_list.py index 7247579fa39b4..ac59c15572a30 100644 --- a/homeassistant/components/shopping_list.py +++ b/homeassistant/components/shopping_list.py @@ -70,11 +70,16 @@ class ListTopItemsIntent(intent.IntentHandler): @asyncio.coroutine def async_handle(self, intent_obj): """Handle the intent.""" + items = intent_obj.hass.data[DOMAIN][-5:] response = intent_obj.create_response() - response.async_set_speech( - "These are the top 5 items in your shopping list: {}".format( - ', '.join(reversed(intent_obj.hass.data[DOMAIN][-5:])))) - intent_obj.hass.bus.async_fire(EVENT) + + if len(items) == 0: + response.async_set_speech( + "There are no items on your shopping list") + else: + response.async_set_speech( + "These are the top {} items on your shopping list: {}".format( + min(len(items), 5), ', '.join(reversed(items)))) return response diff --git a/homeassistant/helpers/intent.py b/homeassistant/helpers/intent.py index 459d89a83ce23..8843bf53df99f 100644 --- a/homeassistant/helpers/intent.py +++ b/homeassistant/helpers/intent.py @@ -134,7 +134,7 @@ def create_response(self): class IntentResponse: """Response to an intent.""" - def __init__(self, intent): + def __init__(self, intent=None): """Initialize an IntentResponse.""" self.intent = intent self.speech = {} diff --git a/tests/components/test_shopping_list.py b/tests/components/test_shopping_list.py index 867e695e2d578..c25ce593c5419 100644 --- a/tests/components/test_shopping_list.py +++ b/tests/components/test_shopping_list.py @@ -38,7 +38,7 @@ def test_recent_items_intent(hass): ) assert response.speech['plain']['speech'] == \ - "These are the top 5 items in your shopping list: soda, wine, beer" + "These are the top 3 items on your shopping list: soda, wine, beer" @asyncio.coroutine From cd2703e1216dc93363153fba4971861b618a5196 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 25 Jul 2017 23:35:05 -0700 Subject: [PATCH 093/118] Update dependencies cast + discovery (#8646) --- homeassistant/components/discovery.py | 2 +- homeassistant/components/media_player/cast.py | 2 +- requirements_all.txt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 3dfe4b9731cb9..af4604cb7d7e7 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -21,7 +21,7 @@ from homeassistant.helpers.discovery import async_load_platform, async_discover import homeassistant.util.dt as dt_util -REQUIREMENTS = ['netdisco==1.0.1'] +REQUIREMENTS = ['netdisco==1.1.0'] DOMAIN = 'discovery' diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 51acf68d819e2..c416157169ead 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -20,7 +20,7 @@ import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['pychromecast==0.8.1'] +REQUIREMENTS = ['pychromecast==0.8.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index aa99cd0370183..ce220e17399d0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -410,7 +410,7 @@ myusps==1.1.2 nad_receiver==0.0.6 # homeassistant.components.discovery -netdisco==1.0.1 +netdisco==1.1.0 # homeassistant.components.sensor.neurio_energy neurio==0.3.1 @@ -541,7 +541,7 @@ pybbox==0.0.5-alpha # pybluez==0.22 # homeassistant.components.media_player.cast -pychromecast==0.8.1 +pychromecast==0.8.2 # homeassistant.components.media_player.cmus pycmus==0.1.0 From e83816c05523412b3f4efdc941d90288441b571a Mon Sep 17 00:00:00 2001 From: Sean Gollschewsky Date: Wed, 26 Jul 2017 08:04:40 +0100 Subject: [PATCH 094/118] Add component Light TPLink (#8643) * Add new component for TPLink light bulbs. * Update with result of gen_requirements_all. * Add new component light.tplink. --- .coveragerc | 1 + homeassistant/components/light/tplink.py | 116 +++++++++++++++++++++++ requirements_all.txt | 1 + 3 files changed, 118 insertions(+) create mode 100644 homeassistant/components/light/tplink.py diff --git a/.coveragerc b/.coveragerc index dc2f39b997781..c9bd40dfc6581 100644 --- a/.coveragerc +++ b/.coveragerc @@ -306,6 +306,7 @@ omit = homeassistant/components/light/piglow.py homeassistant/components/light/sensehat.py homeassistant/components/light/tikteck.py + homeassistant/components/light/tplink.py homeassistant/components/light/tradfri.py homeassistant/components/light/x10.py homeassistant/components/light/yeelight.py diff --git a/homeassistant/components/light/tplink.py b/homeassistant/components/light/tplink.py new file mode 100644 index 0000000000000..333661870d14d --- /dev/null +++ b/homeassistant/components/light/tplink.py @@ -0,0 +1,116 @@ +""" +Support for TPLink lights. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/light.tplink/ +""" +import logging +from homeassistant.const import (CONF_HOST, CONF_NAME) +from homeassistant.components.light import ( + Light, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_KELVIN, + SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP) +from homeassistant.util.color import \ + color_temperature_mired_to_kelvin as mired_to_kelvin +from homeassistant.util.color import \ + color_temperature_kelvin_to_mired as kelvin_to_mired + +REQUIREMENTS = ['pyHS100==0.2.4.2'] + +_LOGGER = logging.getLogger(__name__) + +SUPPORT_TPLINK = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Initialise pyLB100 SmartBulb.""" + from pyHS100 import SmartBulb + host = config.get(CONF_HOST) + name = config.get(CONF_NAME) + add_devices([TPLinkSmartBulb(SmartBulb(host), name)], True) + + +def brightness_to_percentage(byt): + """Convert brightness from absolute 0..255 to percentage.""" + return (byt*100.0)/255.0 + + +def brightness_from_percentage(percent): + """Convert percentage to absolute value 0..255.""" + return (percent*255.0)/100.0 + + +class TPLinkSmartBulb(Light): + """Representation of a TPLink Smart Bulb.""" + + def __init__(self, smartbulb, name): + """Initialize the bulb.""" + self.smartbulb = smartbulb + + # Use the name set on the device if not set + if name is None: + self._name = self.smartbulb.alias + else: + self._name = name + + self._state = None + _LOGGER.debug("Setting up TP-Link Smart Bulb") + + @property + def name(self): + """Return the name of the Smart Bulb, if any.""" + return self._name + + def turn_on(self, **kwargs): + """Turn the light on.""" + if ATTR_COLOR_TEMP in kwargs: + self.smartbulb.color_temp = \ + mired_to_kelvin(kwargs[ATTR_COLOR_TEMP]) + if ATTR_KELVIN in kwargs: + self.smartbulb.color_temp = kwargs[ATTR_KELVIN] + if ATTR_BRIGHTNESS in kwargs: + brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness or 255) + self.smartbulb.brightness = brightness_to_percentage(brightness) + + self.smartbulb.state = self.smartbulb.BULB_STATE_ON + + def turn_off(self): + """Turn the light off.""" + self.smartbulb.state = self.smartbulb.BULB_STATE_OFF + + @property + def color_temp(self): + """Return the color temperature of this light in mireds for HA.""" + if self.smartbulb.is_color: + if (self.smartbulb.color_temp is not None and + self.smartbulb.color_temp != 0): + return kelvin_to_mired(self.smartbulb.color_temp) + else: + return None + else: + return None + + @property + def brightness(self): + """Return the brightness of this light between 0..255.""" + return brightness_from_percentage(self.smartbulb.brightness) + + @property + def is_on(self): + """True if device is on.""" + return self.smartbulb.state == \ + self.smartbulb.BULB_STATE_ON + + def update(self): + """Update the TP-Link Bulb's state.""" + from pyHS100 import SmartPlugException + try: + self._state = self.smartbulb.state == \ + self.smartbulb.BULB_STATE_ON + + except (SmartPlugException, OSError) as ex: + _LOGGER.warning('Could not read state for %s: %s', self.name, ex) + + @property + def supported_features(self): + """Flag supported features.""" + return SUPPORT_TPLINK diff --git a/requirements_all.txt b/requirements_all.txt index ce220e17399d0..d8c3bfa8abeeb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -509,6 +509,7 @@ py-cpuinfo==3.3.0 # homeassistant.components.hdmi_cec pyCEC==0.4.13 +# homeassistant.components.light.tplink # homeassistant.components.switch.tplink pyHS100==0.2.4.2 From 7c120748ce9605d0fb3d8cad0ea40032e116c205 Mon Sep 17 00:00:00 2001 From: Marcelo Moreira de Mello Date: Wed, 26 Jul 2017 05:05:48 -0400 Subject: [PATCH 095/118] Fixes Fitbit sensor to report battery level with the expected device (#8647) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/sensor/fitbit.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/fitbit.py b/homeassistant/components/sensor/fitbit.py index 0c10d2159eac3..c0256e3a88b86 100644 --- a/homeassistant/components/sensor/fitbit.py +++ b/homeassistant/components/sensor/fitbit.py @@ -433,9 +433,8 @@ def device_state_attributes(self): def update(self): """Get the latest data from the Fitbit API and update the states.""" - if self.resource_type == 'devices/battery': - response = self.client.get_devices() - self._state = response[0].get('battery') + if self.resource_type == 'devices/battery' and self.extra: + self._state = self.extra.get('battery') else: container = self.resource_type.replace("/", "-") response = self.client.time_series(self.resource_type, period='7d') From 81a27e726ce9df9d2eb0c88441db6c8a31161d93 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Wed, 26 Jul 2017 12:33:00 +0200 Subject: [PATCH 096/118] Upgrade aiolifx (#8648) This release includes a fix for multizone lights with zone counts that are not a multiple of eight. --- homeassistant/components/light/lifx.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/lifx.py b/homeassistant/components/light/lifx.py index a6c5f8558755e..908a9d24e0450 100644 --- a/homeassistant/components/light/lifx.py +++ b/homeassistant/components/light/lifx.py @@ -33,7 +33,7 @@ _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['aiolifx==0.5.2', 'aiolifx_effects==0.1.1'] +REQUIREMENTS = ['aiolifx==0.5.4', 'aiolifx_effects==0.1.1'] UDP_BROADCAST_PORT = 56700 diff --git a/requirements_all.txt b/requirements_all.txt index d8c3bfa8abeeb..9820d0888cdad 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -49,7 +49,7 @@ aiodns==1.1.1 aiohttp_cors==0.5.3 # homeassistant.components.light.lifx -aiolifx==0.5.2 +aiolifx==0.5.4 # homeassistant.components.light.lifx aiolifx_effects==0.1.1 From fff269e790b1e741e43a360ec6502d166b6b73b2 Mon Sep 17 00:00:00 2001 From: Thomas Delaet Date: Wed, 26 Jul 2017 14:03:29 +0200 Subject: [PATCH 097/118] Velbus (#8076) * add Velbus changes * update library version * fix python-velbus version * bug fix and update python-velbus * change config handling * update velbus components/platforms * add support for Velbus switches * fix bugs * typo * add velbus fan * update velbus library * bug fix in logic of fan handling of speed settings * add Velbus changes change config handling update velbus components/platforms add support for Velbus switches add velbus fan * remove duplicate entry * fix documentation links * fix linting error * regen requirements_all.txt * add support for Velbus cover * bugfix in cover component * bugfix in cover component * remove unused imports * Travis fixes * fix style * fix style * Update velbus.py * Update velbus.py * Update velbus.py * Update requirements_all.txt * Update velbus.py * Update velbus.py * Update velbus.py * Update velbus.py * fix style * Update velbus.py * Update velbus.py * Update velbus.py * Update velbus.py * Update velbus.py * Update velbus.py --- .coveragerc | 3 + .../components/binary_sensor/velbus.py | 96 +++++++++ homeassistant/components/cover/velbus.py | 160 +++++++++++++++ homeassistant/components/fan/velbus.py | 187 ++++++++++++++++++ homeassistant/components/light/velbus.py | 104 ++++++++++ homeassistant/components/switch/velbus.py | 111 +++++++++++ homeassistant/components/velbus.py | 43 ++++ requirements_all.txt | 3 + 8 files changed, 707 insertions(+) create mode 100644 homeassistant/components/binary_sensor/velbus.py create mode 100644 homeassistant/components/cover/velbus.py create mode 100644 homeassistant/components/fan/velbus.py create mode 100644 homeassistant/components/light/velbus.py create mode 100644 homeassistant/components/switch/velbus.py create mode 100644 homeassistant/components/velbus.py diff --git a/.coveragerc b/.coveragerc index c9bd40dfc6581..c4051af513677 100644 --- a/.coveragerc +++ b/.coveragerc @@ -172,6 +172,9 @@ omit = homeassistant/components/twilio.py homeassistant/components/notify/twilio_sms.py homeassistant/components/notify/twilio_call.py + + homeassistant/components/velbus.py + homeassistant/components/*/velbus.py homeassistant/components/velux.py homeassistant/components/*/velux.py diff --git a/homeassistant/components/binary_sensor/velbus.py b/homeassistant/components/binary_sensor/velbus.py new file mode 100644 index 0000000000000..214edcf946385 --- /dev/null +++ b/homeassistant/components/binary_sensor/velbus.py @@ -0,0 +1,96 @@ +""" +Support for Velbus Binary Sensors. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.velbus/ +""" +import asyncio +import logging + + +import voluptuous as vol + +from homeassistant.const import CONF_NAME, CONF_DEVICES +from homeassistant.components.binary_sensor import BinarySensorDevice +from homeassistant.components.binary_sensor import PLATFORM_SCHEMA +from homeassistant.components.velbus import DOMAIN +import homeassistant.helpers.config_validation as cv + + +DEPENDENCIES = ['velbus'] + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_DEVICES): vol.All(cv.ensure_list, [ + { + vol.Required('module'): cv.positive_int, + vol.Required('channel'): cv.positive_int, + vol.Required(CONF_NAME): cv.string, + vol.Optional('is_pushbutton'): cv.boolean + } + ]) +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up Velbus binary sensors.""" + velbus = hass.data[DOMAIN] + + add_devices(VelbusBinarySensor(sensor, velbus) + for sensor in config[CONF_DEVICES]) + + +class VelbusBinarySensor(BinarySensorDevice): + """Representation of a Velbus Binary Sensor.""" + + def __init__(self, binary_sensor, velbus): + """Initialize a Velbus light.""" + self._velbus = velbus + self._name = binary_sensor[CONF_NAME] + self._module = binary_sensor['module'] + self._channel = binary_sensor['channel'] + self._is_pushbutton = 'is_pushbutton' in binary_sensor \ + and binary_sensor['is_pushbutton'] + self._state = False + + @asyncio.coroutine + def async_added_to_hass(self): + """Add listener for Velbus messages on bus.""" + yield from self.hass.async_add_job( + self._velbus.subscribe, self._on_message) + + def _on_message(self, message): + import velbus + if isinstance(message, velbus.PushButtonStatusMessage): + if message.address == self._module and \ + self._channel in message.get_channels(): + if self._is_pushbutton: + if self._channel in message.closed: + self._toggle() + else: + pass + else: + self._toggle() + + def _toggle(self): + if self._state is True: + self._state = False + else: + self._state = True + self.schedule_update_ha_state() + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def name(self): + """Return the display name of this sensor.""" + return self._name + + @property + def is_on(self): + """Return true if the sensor is on.""" + return self._state diff --git a/homeassistant/components/cover/velbus.py b/homeassistant/components/cover/velbus.py new file mode 100644 index 0000000000000..ab5d6e8ef7947 --- /dev/null +++ b/homeassistant/components/cover/velbus.py @@ -0,0 +1,160 @@ +""" +Support for Velbus covers. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/cover.velbus/ +""" +import logging +import asyncio +import time + +import voluptuous as vol + +from homeassistant.components.cover import ( + CoverDevice, PLATFORM_SCHEMA, SUPPORT_OPEN, SUPPORT_CLOSE, + SUPPORT_STOP) +from homeassistant.components.velbus import DOMAIN +from homeassistant.const import (CONF_COVERS, CONF_NAME) +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +COVER_SCHEMA = vol.Schema({ + vol.Required('module'): cv.positive_int, + vol.Required('open_channel'): cv.positive_int, + vol.Required('close_channel'): cv.positive_int, + vol.Required(CONF_NAME): cv.string +}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_COVERS): vol.Schema({cv.slug: COVER_SCHEMA}), +}) + +DEPENDENCIES = ['velbus'] + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up cover controlled by Velbus.""" + devices = config.get(CONF_COVERS, {}) + covers = [] + + velbus = hass.data[DOMAIN] + for device_name, device_config in devices.items(): + covers.append( + VelbusCover( + velbus, + device_config.get(CONF_NAME, device_name), + device_config.get('module'), + device_config.get('open_channel'), + device_config.get('close_channel') + ) + ) + + if not covers: + _LOGGER.error("No covers added") + return False + + add_devices(covers) + + +class VelbusCover(CoverDevice): + """Representation a Velbus cover.""" + + def __init__(self, velbus, name, module, open_channel, close_channel): + """Initialize the cover.""" + self._velbus = velbus + self._name = name + self._close_channel_state = None + self._open_channel_state = None + self._module = module + self._open_channel = open_channel + self._close_channel = close_channel + + @asyncio.coroutine + def async_added_to_hass(self): + """Add listener for Velbus messages on bus.""" + def _init_velbus(): + """Initialize Velbus on startup.""" + self._velbus.subscribe(self._on_message) + self.get_status() + + yield from self.hass.async_add_job(_init_velbus) + + def _on_message(self, message): + import velbus + if isinstance(message, velbus.RelayStatusMessage): + if message.address == self._module: + if message.channel == self._close_channel: + self._close_channel_state = message.is_on() + self.schedule_update_ha_state() + if message.channel == self._open_channel: + self._open_channel_state = message.is_on() + self.schedule_update_ha_state() + + @property + def supported_features(self): + """Flag supported features.""" + return SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_STOP + + @property + def should_poll(self): + """Disable polling.""" + return False + + @property + def name(self): + """Return the name of the cover.""" + return self._name + + @property + def is_closed(self): + """Return if the cover is closed.""" + return self._close_channel_state + + @property + def current_cover_position(self): + """Return current position of cover. + + None is unknown. + """ + return None + + def _relay_off(self, channel): + import velbus + message = velbus.SwitchRelayOffMessage() + message.set_defaults(self._module) + message.relay_channels = [channel] + self._velbus.send(message) + + def _relay_on(self, channel): + import velbus + message = velbus.SwitchRelayOnMessage() + message.set_defaults(self._module) + message.relay_channels = [channel] + self._velbus.send(message) + + def open_cover(self, **kwargs): + """Open the cover.""" + self._relay_off(self._close_channel) + time.sleep(0.3) + self._relay_on(self._open_channel) + + def close_cover(self, **kwargs): + """Close the cover.""" + self._relay_off(self._open_channel) + time.sleep(0.3) + self._relay_on(self._close_channel) + + def stop_cover(self, **kwargs): + """Stop the cover.""" + self._relay_off(self._open_channel) + time.sleep(0.3) + self._relay_off(self._close_channel) + + def get_status(self): + """Retrieve current status.""" + import velbus + message = velbus.ModuleStatusRequestMessage() + message.set_defaults(self._module) + message.channels = [self._open_channel, self._close_channel] + self._velbus.send(message) diff --git a/homeassistant/components/fan/velbus.py b/homeassistant/components/fan/velbus.py new file mode 100644 index 0000000000000..c0d125aa5ab6b --- /dev/null +++ b/homeassistant/components/fan/velbus.py @@ -0,0 +1,187 @@ +""" +Support for Velbus platform. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/fan.velbus/ +""" +import asyncio +import logging +import voluptuous as vol + +from homeassistant.components.fan import ( + SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH, FanEntity, SUPPORT_SET_SPEED, + PLATFORM_SCHEMA) +from homeassistant.components.velbus import DOMAIN +from homeassistant.const import CONF_NAME, CONF_DEVICES, STATE_OFF +import homeassistant.helpers.config_validation as cv + +DEPENDENCIES = ['velbus'] + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_DEVICES): vol.All(cv.ensure_list, [ + { + vol.Required('module'): cv.positive_int, + vol.Required('channel_low'): cv.positive_int, + vol.Required('channel_medium'): cv.positive_int, + vol.Required('channel_high'): cv.positive_int, + vol.Required(CONF_NAME): cv.string, + } + ]) +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up Fans.""" + velbus = hass.data[DOMAIN] + add_devices(VelbusFan(fan, velbus) for fan in config[CONF_DEVICES]) + + +class VelbusFan(FanEntity): + """Representation of a Velbus Fan.""" + + def __init__(self, fan, velbus): + """Initialize a Velbus light.""" + self._velbus = velbus + self._name = fan[CONF_NAME] + self._module = fan['module'] + self._channel_low = fan['channel_low'] + self._channel_medium = fan['channel_medium'] + self._channel_high = fan['channel_high'] + self._channels = [self._channel_low, self._channel_medium, + self._channel_high] + self._channels_state = [False, False, False] + self._speed = STATE_OFF + + @asyncio.coroutine + def async_added_to_hass(self): + """Add listener for Velbus messages on bus.""" + def _init_velbus(): + """Initialize Velbus on startup.""" + self._velbus.subscribe(self._on_message) + self.get_status() + + yield from self.hass.async_add_job(_init_velbus) + + def _on_message(self, message): + import velbus + if isinstance(message, velbus.RelayStatusMessage) and \ + message.address == self._module and \ + message.channel in self._channels: + if message.channel == self._channel_low: + self._channels_state[0] = message.is_on() + elif message.channel == self._channel_medium: + self._channels_state[1] = message.is_on() + elif message.channel == self._channel_high: + self._channels_state[2] = message.is_on() + self._calculate_speed() + self.schedule_update_ha_state() + + def _calculate_speed(self): + if self._is_off(): + self._speed = STATE_OFF + elif self._is_low(): + self._speed = SPEED_LOW + elif self._is_medium(): + self._speed = SPEED_MEDIUM + elif self._is_high(): + self._speed = SPEED_HIGH + + def _is_off(self): + return self._channels_state[0] is False and \ + self._channels_state[1] is False and \ + self._channels_state[2] is False + + def _is_low(self): + return self._channels_state[0] is True and \ + self._channels_state[1] is False and \ + self._channels_state[2] is False + + def _is_medium(self): + return self._channels_state[0] is True and \ + self._channels_state[1] is True and \ + self._channels_state[2] is False + + def _is_high(self): + return self._channels_state[0] is True and \ + self._channels_state[1] is False and \ + self._channels_state[2] is True + + @property + def name(self): + """Return the display name of this light.""" + return self._name + + @property + def should_poll(self): + """Disable polling.""" + return False + + @property + def speed(self): + """Return the current speed.""" + return self._speed + + @property + def speed_list(self): + """Get the list of available speeds.""" + return [STATE_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] + + def turn_on(self, speed, **kwargs): + """Turn on the entity.""" + if speed is None: + speed = SPEED_MEDIUM + self.set_speed(speed) + + def turn_off(self): + """Turn off the entity.""" + self.set_speed(STATE_OFF) + + def set_speed(self, speed): + """Set the speed of the fan.""" + channels_off = [] + channels_on = [] + if speed == STATE_OFF: + channels_off = self._channels + elif speed == SPEED_LOW: + channels_off = [self._channel_medium, self._channel_high] + channels_on = [self._channel_low] + elif speed == SPEED_MEDIUM: + channels_off = [self._channel_high] + channels_on = [self._channel_low, self._channel_medium] + elif speed == SPEED_HIGH: + channels_off = [self._channel_medium] + channels_on = [self._channel_low, self._channel_high] + for channel in channels_off: + self._relay_off(channel) + for channel in channels_on: + self._relay_on(channel) + self.schedule_update_ha_state() + + def _relay_on(self, channel): + import velbus + message = velbus.SwitchRelayOnMessage() + message.set_defaults(self._module) + message.relay_channels = [channel] + self._velbus.send(message) + + def _relay_off(self, channel): + import velbus + message = velbus.SwitchRelayOffMessage() + message.set_defaults(self._module) + message.relay_channels = [channel] + self._velbus.send(message) + + def get_status(self): + """Retrieve current status.""" + import velbus + message = velbus.ModuleStatusRequestMessage() + message.set_defaults(self._module) + message.channels = self._channels + self._velbus.send(message) + + @property + def supported_features(self): + """Flag supported features.""" + return SUPPORT_SET_SPEED diff --git a/homeassistant/components/light/velbus.py b/homeassistant/components/light/velbus.py new file mode 100644 index 0000000000000..8a02b36b75faa --- /dev/null +++ b/homeassistant/components/light/velbus.py @@ -0,0 +1,104 @@ +""" +Support for Velbus lights. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/light.velbus/ +""" +import asyncio +import logging + +import voluptuous as vol + +from homeassistant.const import CONF_NAME, CONF_DEVICES +from homeassistant.components.light import Light, PLATFORM_SCHEMA +from homeassistant.components.velbus import DOMAIN +import homeassistant.helpers.config_validation as cv + +DEPENDENCIES = ['velbus'] + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_DEVICES): vol.All(cv.ensure_list, [ + { + vol.Required('module'): cv.positive_int, + vol.Required('channel'): cv.positive_int, + vol.Required(CONF_NAME): cv.string + } + ]) +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up Lights.""" + velbus = hass.data[DOMAIN] + add_devices(VelbusLight(light, velbus) for light in config[CONF_DEVICES]) + + +class VelbusLight(Light): + """Representation of a Velbus Light.""" + + def __init__(self, light, velbus): + """Initialize a Velbus light.""" + self._velbus = velbus + self._name = light[CONF_NAME] + self._module = light['module'] + self._channel = light['channel'] + self._state = False + + @asyncio.coroutine + def async_added_to_hass(self): + """Add listener for Velbus messages on bus.""" + def _init_velbus(): + """Initialize Velbus on startup.""" + self._velbus.subscribe(self._on_message) + self.get_status() + + yield from self.hass.async_add_job(_init_velbus) + + def _on_message(self, message): + import velbus + if isinstance(message, velbus.RelayStatusMessage) and \ + message.address == self._module and \ + message.channel == self._channel: + self._state = message.is_on() + self.schedule_update_ha_state() + + @property + def name(self): + """Return the display name of this light.""" + return self._name + + @property + def should_poll(self): + """Disable polling.""" + return False + + @property + def is_on(self): + """Return true if the light is on.""" + return self._state + + def turn_on(self, **kwargs): + """Instruct the light to turn on.""" + import velbus + message = velbus.SwitchRelayOnMessage() + message.set_defaults(self._module) + message.relay_channels = [self._channel] + self._velbus.send(message) + + def turn_off(self, **kwargs): + """Instruct the light to turn off.""" + import velbus + message = velbus.SwitchRelayOffMessage() + message.set_defaults(self._module) + message.relay_channels = [self._channel] + self._velbus.send(message) + + def get_status(self): + """Retrieve current status.""" + import velbus + message = velbus.ModuleStatusRequestMessage() + message.set_defaults(self._module) + message.channels = [self._channel] + self._velbus.send(message) diff --git a/homeassistant/components/switch/velbus.py b/homeassistant/components/switch/velbus.py new file mode 100644 index 0000000000000..15090091a5248 --- /dev/null +++ b/homeassistant/components/switch/velbus.py @@ -0,0 +1,111 @@ +""" +Support for Velbus switches. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.velbus/ +""" + +import asyncio +import logging + +import voluptuous as vol + +from homeassistant.const import CONF_NAME, CONF_DEVICES +from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA +from homeassistant.components.velbus import DOMAIN +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +SWITCH_SCHEMA = { + vol.Required('module'): cv.positive_int, + vol.Required('channel'): cv.positive_int, + vol.Required(CONF_NAME): cv.string +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_DEVICES): + vol.All(cv.ensure_list, [SWITCH_SCHEMA]) +}) + +DEPENDENCIES = ['velbus'] + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the Switch.""" + velbus = hass.data[DOMAIN] + devices = [] + + for switch in config[CONF_DEVICES]: + devices.append(VelbusSwitch(switch, velbus)) + add_devices(devices) + return True + + +class VelbusSwitch(SwitchDevice): + """Representation of a switch.""" + + def __init__(self, switch, velbus): + """Initialize a Velbus switch.""" + self._velbus = velbus + self._name = switch[CONF_NAME] + self._module = switch['module'] + self._channel = switch['channel'] + self._state = False + + @asyncio.coroutine + def async_added_to_hass(self): + """Add listener for Velbus messages on bus.""" + def _init_velbus(): + """Initialize Velbus on startup.""" + self._velbus.subscribe(self._on_message) + self.get_status() + + yield from self.hass.async_add_job(_init_velbus) + + def _on_message(self, message): + import velbus + if isinstance(message, velbus.RelayStatusMessage) and \ + message.address == self._module and \ + message.channel == self._channel: + self._state = message.is_on() + self.schedule_update_ha_state() + + @property + def name(self): + """Return the display name of this switch.""" + return self._name + + @property + def should_poll(self): + """Disable polling.""" + return False + + @property + def is_on(self): + """Return true if the switch is on.""" + return self._state + + def turn_on(self, **kwargs): + """Instruct the switch to turn on.""" + import velbus + message = velbus.SwitchRelayOnMessage() + message.set_defaults(self._module) + message.relay_channels = [self._channel] + self._velbus.send(message) + + def turn_off(self, **kwargs): + """Instruct the switch to turn off.""" + import velbus + message = velbus.SwitchRelayOffMessage() + message.set_defaults(self._module) + message.relay_channels = [self._channel] + self._velbus.send(message) + + def get_status(self): + """Retrieve current status.""" + import velbus + message = velbus.ModuleStatusRequestMessage() + message.set_defaults(self._module) + message.channels = [self._channel] + self._velbus.send(message) diff --git a/homeassistant/components/velbus.py b/homeassistant/components/velbus.py new file mode 100644 index 0000000000000..ff2db955d31aa --- /dev/null +++ b/homeassistant/components/velbus.py @@ -0,0 +1,43 @@ +""" +Support for Velbus platform. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/velbus/ +""" +import logging +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.const import EVENT_HOMEASSISTANT_STOP, CONF_PORT + +REQUIREMENTS = ['python-velbus==2.0.11'] + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = 'velbus' + + +VELBUS_MESSAGE = 'velbus.message' + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_PORT): cv.string, + }) +}, extra=vol.ALLOW_EXTRA) + + +def setup(hass, config): + """Set up the Velbus platform.""" + import velbus + port = config[DOMAIN].get(CONF_PORT) + connection = velbus.VelbusUSBConnection(port) + controller = velbus.Controller(connection) + hass.data[DOMAIN] = controller + + def stop_velbus(event): + """Disconnect from serial port.""" + _LOGGER.debug("Shutting down ") + connection.stop() + + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_velbus) + return True diff --git a/requirements_all.txt b/requirements_all.txt index 9820d0888cdad..aad16af8592bf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -761,6 +761,9 @@ python-telegram-bot==6.1.0 # homeassistant.components.sensor.twitch python-twitch==1.3.0 +# homeassistant.components.velbus +python-velbus==2.0.11 + # homeassistant.components.media_player.vlc python-vlc==1.1.2 From abcfcdd8872dfe36c3a96afafdb4ba7f6abeb47d Mon Sep 17 00:00:00 2001 From: Boyi C Date: Wed, 26 Jul 2017 22:46:21 +0800 Subject: [PATCH 098/118] Yahoo Weather update, supports forecast for more days (#8626) * work on weather panel * update yahooweather with more forecast details * Update yweather to allow user input forecast date * fix for houndci * fix long line * fix1 * Revert "work on weather panel" This reverts commit 28b4972233de42617fb05df574de22743604edfd. revert unintentional submodule change * fix2 fix typo, add try catch to another int() * fix pylint * fix3 * fix4 * Update yweather.py * Update yweather.py * Remove global data construct * Yahoo API support only 5 days forecast * remove forecast * fix lint * fix lint p2 * Update yweather.py --- homeassistant/components/weather/yweather.py | 64 +++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/homeassistant/components/weather/yweather.py b/homeassistant/components/weather/yweather.py index 0e216273d65a2..687d919ed95ca 100644 --- a/homeassistant/components/weather/yweather.py +++ b/homeassistant/components/weather/yweather.py @@ -11,17 +11,21 @@ import homeassistant.helpers.config_validation as cv from homeassistant.components.weather import ( - WeatherEntity, PLATFORM_SCHEMA, ATTR_FORECAST_TEMP) + WeatherEntity, PLATFORM_SCHEMA, + ATTR_FORECAST_TEMP, ATTR_FORECAST_TIME) from homeassistant.const import (TEMP_CELSIUS, CONF_NAME, STATE_UNKNOWN) REQUIREMENTS = ["yahooweather==0.8"] _LOGGER = logging.getLogger(__name__) +DATA_CONDITION = 'yahoo_condition' + ATTR_FORECAST_CONDITION = 'condition' ATTRIBUTION = "Weather details provided by Yahoo! Inc." -CONF_FORECAST = 'forecast' +ATTR_FORECAST_TEMP_LOW = 'templow' + CONF_WOEID = 'woeid' DEFAULT_NAME = 'Yweather' @@ -33,23 +37,22 @@ 'fog': [19, 20, 21, 22, 23], 'hail': [17, 18, 35], 'lightning': [37], - 'lightning-rainy': [38, 39], + 'lightning-rainy': [38, 39, 47], 'partlycloudy': [44], 'pouring': [40, 45], 'rainy': [9, 11, 12], 'snowy': [8, 13, 14, 15, 16, 41, 42, 43], - 'snowy-rainy': [5, 6, 7, 10, 46, 47], - 'sunny': [32], + 'snowy-rainy': [5, 6, 7, 10, 46], + 'sunny': [32, 33, 34], 'windy': [24], 'windy-variant': [], 'exceptional': [0, 1, 2, 3, 4, 25, 36], } + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_WOEID, default=None): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_FORECAST, default=0): - vol.All(vol.Coerce(int), vol.Range(min=0, max=5)), }) @@ -59,7 +62,6 @@ def setup_platform(hass, config, add_devices, discovery_info=None): unit = hass.config.units.temperature_unit woeid = config.get(CONF_WOEID) - forecast = config.get(CONF_FORECAST) name = config.get(CONF_NAME) yunit = UNIT_C if unit == TEMP_CELSIUS else UNIT_F @@ -77,22 +79,23 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.critical("Can't retrieve weather data from Yahoo!") return False - if forecast >= len(yahoo_api.yahoo.Forecast): - _LOGGER.error("Yahoo! only support %d days forecast", - len(yahoo_api.yahoo.Forecast)) - return False + # create condition helper + if DATA_CONDITION not in hass.data: + hass.data[DATA_CONDITION] = [str(x) for x in range(0, 50)] + for cond, condlst in CONDITION_CLASSES.items(): + for condi in condlst: + hass.data[DATA_CONDITION][condi] = cond - add_devices([YahooWeatherWeather(yahoo_api, name, forecast)], True) + add_devices([YahooWeatherWeather(yahoo_api, name)], True) class YahooWeatherWeather(WeatherEntity): """Representation of Yahoo! weather data.""" - def __init__(self, weather_data, name, forecast): + def __init__(self, weather_data, name): """Initialize the sensor.""" self._name = name self._data = weather_data - self._forecast = forecast @property def name(self): @@ -103,9 +106,9 @@ def name(self): def condition(self): """Return the current condition.""" try: - return [k for k, v in CONDITION_CLASSES.items() if - int(self._data.yahoo.Now['code']) in v][0] - except IndexError: + return self.hass.data[DATA_CONDITION][int( + self._data.yahoo.Now['code'])] + except (ValueError, IndexError): return STATE_UNKNOWN @property @@ -138,6 +141,11 @@ def wind_speed(self): """Return the wind speed.""" return self._data.yahoo.Wind['speed'] + @property + def wind_bearing(self): + """Return the wind direction.""" + return self._data.yahoo.Wind['direction'] + @property def attribution(self): """Return the attribution.""" @@ -147,19 +155,17 @@ def attribution(self): def forecast(self): """Return the forecast array.""" try: - forecast_condition = \ - [k for k, v in CONDITION_CLASSES.items() if - int(self._data.yahoo.Forecast[self._forecast]['code']) - in v][0] - except IndexError: + return [ + { + ATTR_FORECAST_TIME: v['date'], + ATTR_FORECAST_TEMP:int(v['high']), + ATTR_FORECAST_TEMP_LOW: int(v['low']), + ATTR_FORECAST_CONDITION: + self.hass.data[DATA_CONDITION][int(v['code'])] + } for v in self._data.yahoo.Forecast] + except (ValueError, IndexError): return STATE_UNKNOWN - return [{ - ATTR_FORECAST_CONDITION: forecast_condition, - ATTR_FORECAST_TEMP: - self._data.yahoo.Forecast[self._forecast]['high'], - }] - def update(self): """Get the latest data from Yahoo! and updates the states.""" self._data.update() From 438edc5ca115a3a02bbc3887bdaafaf8ab24eb8e Mon Sep 17 00:00:00 2001 From: Greg Laabs Date: Wed, 26 Jul 2017 08:22:01 -0700 Subject: [PATCH 099/118] History performance improvements for single-entity requests (#8632) * Bugfix: remove superfluous domain filter This filter is already applied later in the function by the `filters` object, where it is conditionally applied when appropriate. This fixes the problem where we get a domain filter even when searching for a single entity_id, which needlessly harms the query's performance. * Performance: build different query when only getting single entity When querying the history of a single entity, we can use an entirely different method for the "synthetic zero data point" by simply sorting by date and doing a LIMIT 1. This performs thousands of times better than the multi-entity query when the current recorder_run has been going for a while. * Add entity_id filter to single-entity request The entity_id filter was handled inside the `filters.apply` logic which is used in most cases, BUT didn't work when no `filters` was passed in to the method. Now it'll work even if no `filters` object is passed in. * Fix linting errors in history.py * Undo removal of domain filter Putting back the domain filter that was removed in 76a6371705dcd57483e55dcc03435ae867c184d2 - there are use-cases where get_states is called without a filter object, so we need the domain filter to work in those cases as well. * Fix truncated comment --- homeassistant/components/history.py | 47 +++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/history.py b/homeassistant/components/history.py index 9800a15c16b32..893ff23df3547 100644 --- a/homeassistant/components/history.py +++ b/homeassistant/components/history.py @@ -119,19 +119,42 @@ def get_states(hass, utc_point_in_time, entity_ids=None, run=None, from sqlalchemy import and_, func with session_scope(hass=hass) as session: - most_recent_state_ids = session.query( - func.max(States.state_id).label('max_state_id') - ).filter( - (States.created >= run.start) & - (States.created < utc_point_in_time) & - (~States.domain.in_(IGNORE_DOMAINS))) + if entity_ids and len(entity_ids) == 1: + # Use an entirely different (and extremely fast) query if we only + # have a single entity id + most_recent_state_ids = session.query( + States.state_id.label('max_state_id') + ).filter( + (States.created < utc_point_in_time) & + (States.entity_id.in_(entity_ids)) + ).order_by( + States.created.desc()) + + if filters: + most_recent_state_ids = filters.apply(most_recent_state_ids, + entity_ids) + + most_recent_state_ids = most_recent_state_ids.limit(1) - if filters: - most_recent_state_ids = filters.apply(most_recent_state_ids, - entity_ids) - - most_recent_state_ids = most_recent_state_ids.group_by( - States.entity_id).subquery() + else: + # We have more than one entity to look at (most commonly we want + # all entities,) so we need to do a search on all states since the + # last recorder run started. + most_recent_state_ids = session.query( + func.max(States.state_id).label('max_state_id') + ).filter( + (States.created >= run.start) & + (States.created < utc_point_in_time) & + (~States.domain.in_(IGNORE_DOMAINS))) + + if filters: + most_recent_state_ids = filters.apply(most_recent_state_ids, + entity_ids) + + most_recent_state_ids = most_recent_state_ids.group_by( + States.entity_id) + + most_recent_state_ids = most_recent_state_ids.subquery() query = session.query(States).join(most_recent_state_ids, and_( States.state_id == most_recent_state_ids.c.max_state_id)) From 3318f02664fb46b3ce7de758984414d1256dd94b Mon Sep 17 00:00:00 2001 From: Jeff Wilson Date: Wed, 26 Jul 2017 11:22:31 -0400 Subject: [PATCH 100/118] Add transition support to light.zha (#8548) * Add transition support to light.zha * Address hound formatting * Address hound comments Look, nobody is perfect... alright? * Update zha.py --- homeassistant/components/light/zha.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/light/zha.py b/homeassistant/components/light/zha.py index 619723d316889..2a3ce18d74ef4 100644 --- a/homeassistant/components/light/zha.py +++ b/homeassistant/components/light/zha.py @@ -9,11 +9,14 @@ from homeassistant.components import light, zha from homeassistant.util.color import color_RGB_to_xy +from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['zha'] +DEFAULT_DURATION = 0.5 + @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): @@ -48,6 +51,7 @@ def __init__(self, **kwargs): import bellows.zigbee.zcl.clusters as zcl_clusters if zcl_clusters.general.LevelControl.cluster_id in self._in_clusters: self._supported_features |= light.SUPPORT_BRIGHTNESS + self._supported_features |= light.SUPPORT_TRANSITION self._brightness = 0 if zcl_clusters.lighting.Color.cluster_id in self._in_clusters: # Not sure all color lights necessarily support this directly @@ -62,14 +66,15 @@ def __init__(self, **kwargs): @property def is_on(self) -> bool: """Return true if entity is on.""" - if self._state == 'unknown': + if self._state == STATE_UNKNOWN: return False return bool(self._state) @asyncio.coroutine def async_turn_on(self, **kwargs): """Turn the entity on.""" - duration = 5 # tenths of s + duration = kwargs.get(light.ATTR_TRANSITION, DEFAULT_DURATION) + duration = duration * 10 # tenths of s if light.ATTR_COLOR_TEMP in kwargs: temperature = kwargs[light.ATTR_COLOR_TEMP] yield from self._endpoint.light_color.move_to_color_temp( @@ -91,7 +96,8 @@ def async_turn_on(self, **kwargs): ) if self._brightness is not None: - brightness = kwargs.get('brightness', self._brightness or 255) + brightness = kwargs.get( + light.ATTR_BRIGHTNESS, self._brightness or 255) self._brightness = brightness # Move to level with on/off: yield from self._endpoint.level.move_to_level_with_on_off( From 3b4ea864a10c6923bec25e643d6d27ba022a7832 Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 26 Jul 2017 20:49:52 +0100 Subject: [PATCH 101/118] Add uk_transport component. (#8600) --- .../components/sensor/uk_transport.py | 275 ++++++++++ tests/components/sensor/test_uk_transport.py | 93 ++++ tests/fixtures/uk_transport_bus.json | 110 ++++ tests/fixtures/uk_transport_train.json | 511 ++++++++++++++++++ 4 files changed, 989 insertions(+) create mode 100644 homeassistant/components/sensor/uk_transport.py create mode 100644 tests/components/sensor/test_uk_transport.py create mode 100644 tests/fixtures/uk_transport_bus.json create mode 100644 tests/fixtures/uk_transport_train.json diff --git a/homeassistant/components/sensor/uk_transport.py b/homeassistant/components/sensor/uk_transport.py new file mode 100644 index 0000000000000..b9ce98ec25743 --- /dev/null +++ b/homeassistant/components/sensor/uk_transport.py @@ -0,0 +1,275 @@ +"""Support for UK public transport data provided by transportapi.com. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.uk_transport/ +""" +import logging +import re +from datetime import datetime, timedelta +import requests +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger(__name__) + +ATTR_ATCOCODE = 'atcocode' +ATTR_LOCALITY = 'locality' +ATTR_STOP_NAME = 'stop_name' +ATTR_REQUEST_TIME = 'request_time' +ATTR_NEXT_BUSES = 'next_buses' +ATTR_STATION_CODE = 'station_code' +ATTR_CALLING_AT = 'calling_at' +ATTR_NEXT_TRAINS = 'next_trains' + +CONF_API_APP_KEY = 'app_key' +CONF_API_APP_ID = 'app_id' +CONF_QUERIES = 'queries' +CONF_MODE = 'mode' +CONF_ORIGIN = 'origin' +CONF_DESTINATION = 'destination' + +_QUERY_SCHEME = vol.Schema({ + vol.Required(CONF_MODE): + vol.All(cv.ensure_list, [vol.In(list(['bus', 'train']))]), + vol.Required(CONF_ORIGIN): cv.string, + vol.Required(CONF_DESTINATION): cv.string, +}) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_API_APP_ID): cv.string, + vol.Required(CONF_API_APP_KEY): cv.string, + vol.Required(CONF_QUERIES): [_QUERY_SCHEME], +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Get the uk_transport sensor.""" + sensors = [] + number_sensors = len(config.get(CONF_QUERIES)) + interval = timedelta(seconds=87*number_sensors) + + for query in config.get(CONF_QUERIES): + if 'bus' in query.get(CONF_MODE): + stop_atcocode = query.get(CONF_ORIGIN) + bus_direction = query.get(CONF_DESTINATION) + sensors.append( + UkTransportLiveBusTimeSensor( + config.get(CONF_API_APP_ID), + config.get(CONF_API_APP_KEY), + stop_atcocode, + bus_direction, + interval)) + + elif 'train' in query.get(CONF_MODE): + station_code = query.get(CONF_ORIGIN) + calling_at = query.get(CONF_DESTINATION) + sensors.append( + UkTransportLiveTrainTimeSensor( + config.get(CONF_API_APP_ID), + config.get(CONF_API_APP_KEY), + station_code, + calling_at, + interval)) + + add_devices(sensors, True) + + +class UkTransportSensor(Entity): + """ + Sensor that reads the UK transport web API. + + transportapi.com provides comprehensive transport data for UK train, tube + and bus travel across the UK via simple JSON API. Subclasses of this + base class can be used to access specific types of information. + """ + + TRANSPORT_API_URL_BASE = "https://transportapi.com/v3/uk/" + ICON = 'mdi:train' + + def __init__(self, name, api_app_id, api_app_key, url): + """Initialize the sensor.""" + self._data = {} + self._api_app_id = api_app_id + self._api_app_key = api_app_key + self._url = self.TRANSPORT_API_URL_BASE + url + self._name = name + self._state = None + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + @property + def unit_of_measurement(self): + """Return the unit this state is expressed in.""" + return "min" + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return self.ICON + + def _do_api_request(self, params): + """Perform an API request.""" + request_params = dict({ + 'app_id': self._api_app_id, + 'app_key': self._api_app_key, + }, **params) + + response = requests.get(self._url, params=request_params) + if response.status_code != 200: + _LOGGER.warning('Invalid response from API') + elif 'error' in response.json(): + if 'exceeded' in response.json()['error']: + self._state = 'Useage limites exceeded' + if 'invalid' in response.json()['error']: + self._state = 'Credentials invalid' + else: + self._data = response.json() + + +class UkTransportLiveBusTimeSensor(UkTransportSensor): + """Live bus time sensor from UK transportapi.com.""" + + ICON = 'mdi:bus' + + def __init__(self, api_app_id, api_app_key, + stop_atcocode, bus_direction, interval): + """Construct a live bus time sensor.""" + self._stop_atcocode = stop_atcocode + self._bus_direction = bus_direction + self._next_buses = [] + self._destination_re = re.compile( + '{}'.format(bus_direction), re.IGNORECASE + ) + + sensor_name = 'Next bus to {}'.format(bus_direction) + stop_url = 'bus/stop/{}/live.json'.format(stop_atcocode) + + UkTransportSensor.__init__( + self, sensor_name, api_app_id, api_app_key, stop_url + ) + self.update = Throttle(interval)(self._update) + + def _update(self): + """Get the latest live departure data for the specified stop.""" + params = {'group': 'route', 'nextbuses': 'no'} + + self._do_api_request(params) + + if self._data != {}: + self._next_buses = [] + + for (route, departures) in self._data['departures'].items(): + for departure in departures: + if self._destination_re.search(departure['direction']): + self._next_buses.append({ + 'route': route, + 'direction': departure['direction'], + 'scheduled': departure['aimed_departure_time'], + 'estimated': departure['best_departure_estimate'] + }) + + self._state = min(map( + _delta_mins, [bus['scheduled'] for bus in self._next_buses] + )) + + @property + def device_state_attributes(self): + """Return other details about the sensor state.""" + attrs = {} + if self._data is not None: + for key in [ + ATTR_ATCOCODE, ATTR_LOCALITY, ATTR_STOP_NAME, + ATTR_REQUEST_TIME + ]: + attrs[key] = self._data.get(key) + attrs[ATTR_NEXT_BUSES] = self._next_buses + return attrs + + +class UkTransportLiveTrainTimeSensor(UkTransportSensor): + """Live train time sensor from UK transportapi.com.""" + + ICON = 'mdi:train' + + def __init__(self, api_app_id, api_app_key, + station_code, calling_at, interval): + """Construct a live bus time sensor.""" + self._station_code = station_code + self._calling_at = calling_at + self._next_trains = [] + + sensor_name = 'Next train to {}'.format(calling_at) + query_url = 'train/station/{}/live.json'.format(station_code) + + UkTransportSensor.__init__( + self, sensor_name, api_app_id, api_app_key, query_url + ) + self.update = Throttle(interval)(self._update) + + def _update(self): + """Get the latest live departure data for the specified stop.""" + params = {'darwin': 'false', + 'calling_at': self._calling_at, + 'train_status': 'passenger'} + + self._do_api_request(params) + self._next_trains = [] + + if self._data != {}: + if self._data['departures']['all'] == []: + self._state = 'No departures' + else: + for departure in self._data['departures']['all']: + self._next_trains.append({ + 'origin_name': departure['origin_name'], + 'destination_name': departure['destination_name'], + 'status': departure['status'], + 'scheduled': departure['aimed_departure_time'], + 'estimated': departure['expected_departure_time'], + 'platform': departure['platform'], + 'operator_name': departure['operator_name'] + }) + + self._state = min(map( + _delta_mins, + [train['scheduled'] for train in self._next_trains] + )) + + @property + def device_state_attributes(self): + """Return other details about the sensor state.""" + attrs = {} + if self._data is not None: + attrs[ATTR_STATION_CODE] = self._station_code + attrs[ATTR_CALLING_AT] = self._calling_at + if self._next_trains: + attrs[ATTR_NEXT_TRAINS] = self._next_trains + return attrs + + +def _delta_mins(hhmm_time_str): + """Calculate time delta in minutes to a time in hh:mm format.""" + now = datetime.now() + hhmm_time = datetime.strptime(hhmm_time_str, '%H:%M') + + hhmm_datetime = datetime( + now.year, now.month, now.day, + hour=hhmm_time.hour, minute=hhmm_time.minute + ) + if hhmm_datetime < now: + hhmm_datetime += timedelta(days=1) + + delta_mins = (hhmm_datetime - now).seconds // 60 + return delta_mins diff --git a/tests/components/sensor/test_uk_transport.py b/tests/components/sensor/test_uk_transport.py new file mode 100644 index 0000000000000..b051d8e1a1b37 --- /dev/null +++ b/tests/components/sensor/test_uk_transport.py @@ -0,0 +1,93 @@ +"""The tests for the uk_transport platform.""" +import re + +import requests_mock +import unittest + +from homeassistant.components.sensor.uk_transport import ( + UkTransportSensor, + ATTR_ATCOCODE, ATTR_LOCALITY, ATTR_STOP_NAME, ATTR_NEXT_BUSES, + ATTR_STATION_CODE, ATTR_CALLING_AT, ATTR_NEXT_TRAINS, + CONF_API_APP_KEY, CONF_API_APP_ID) +from homeassistant.setup import setup_component +from tests.common import load_fixture, get_test_home_assistant + +BUS_ATCOCODE = '340000368SHE' +BUS_DIRECTION = 'Wantage' +TRAIN_STATION_CODE = 'WIM' +TRAIN_DESTINATION_NAME = 'WAT' + +VALID_CONFIG = { + 'platform': 'uk_transport', + CONF_API_APP_ID: 'foo', + CONF_API_APP_KEY: 'ebcd1234', + 'queries': [{ + 'mode': 'bus', + 'origin': BUS_ATCOCODE, + 'destination': BUS_DIRECTION}, + { + 'mode': 'train', + 'origin': TRAIN_STATION_CODE, + 'destination': TRAIN_DESTINATION_NAME}] + } + + +class TestUkTransportSensor(unittest.TestCase): + """Test the uk_transport platform.""" + + def setUp(self): + """Initialize values for this testcase class.""" + self.hass = get_test_home_assistant() + self.config = VALID_CONFIG + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + + @requests_mock.Mocker() + def test_bus(self, mock_req): + """Test for operational uk_transport sensor with proper attributes.""" + with requests_mock.Mocker() as mock_req: + uri = re.compile(UkTransportSensor.TRANSPORT_API_URL_BASE + '*') + mock_req.get(uri, text=load_fixture('uk_transport_bus.json')) + self.assertTrue( + setup_component(self.hass, 'sensor', {'sensor': self.config})) + + bus_state = self.hass.states.get('sensor.next_bus_to_wantage') + + assert type(bus_state.state) == str + assert bus_state.name == 'Next bus to {}'.format(BUS_DIRECTION) + assert bus_state.attributes.get(ATTR_ATCOCODE) == BUS_ATCOCODE + assert bus_state.attributes.get(ATTR_LOCALITY) == 'Harwell Campus' + assert bus_state.attributes.get(ATTR_STOP_NAME) == 'Bus Station' + assert len(bus_state.attributes.get(ATTR_NEXT_BUSES)) == 2 + + direction_re = re.compile(BUS_DIRECTION) + for bus in bus_state.attributes.get(ATTR_NEXT_BUSES): + print(bus['direction'], direction_re.match(bus['direction'])) + assert direction_re.search(bus['direction']) is not None + + @requests_mock.Mocker() + def test_train(self, mock_req): + """Test for operational uk_transport sensor with proper attributes.""" + with requests_mock.Mocker() as mock_req: + uri = re.compile(UkTransportSensor.TRANSPORT_API_URL_BASE + '*') + mock_req.get(uri, text=load_fixture('uk_transport_train.json')) + self.assertTrue( + setup_component(self.hass, 'sensor', {'sensor': self.config})) + + train_state = self.hass.states.get('sensor.next_train_to_WAT') + + assert type(train_state.state) == str + assert train_state.name == 'Next train to {}'.format( + TRAIN_DESTINATION_NAME) + assert train_state.attributes.get( + ATTR_STATION_CODE) == TRAIN_STATION_CODE + assert train_state.attributes.get( + ATTR_CALLING_AT) == TRAIN_DESTINATION_NAME + assert len(train_state.attributes.get(ATTR_NEXT_TRAINS)) == 25 + + assert train_state.attributes.get( + ATTR_NEXT_TRAINS)[0]['destination_name'] == 'London Waterloo' + assert train_state.attributes.get( + ATTR_NEXT_TRAINS)[0]['estimated'] == '06:13' diff --git a/tests/fixtures/uk_transport_bus.json b/tests/fixtures/uk_transport_bus.json new file mode 100644 index 0000000000000..5e1e27a4ba314 --- /dev/null +++ b/tests/fixtures/uk_transport_bus.json @@ -0,0 +1,110 @@ +{ + "atcocode": "340000368SHE", + "bearing": "", + "departures": { + "32A": [{ + "aimed_departure_time": "10:18", + "best_departure_estimate": "10:18", + "date": "2017-05-09", + "dir": "outbound", + "direction": "Market Place (Wantage)", + "expected_departure_date": null, + "expected_departure_time": null, + "id": "https://transportapi.com/v3/uk/bus/route/THTR/32A/outbound/340000368SHE/2017-05-09/10:18/timetable.json?app_id=e99&app_key=058", + "line": "32A", + "line_name": "32A", + "mode": "bus", + "operator": "THTR", + "operator_name": "Thames Travel", + "source": "Traveline timetable (not a nextbuses live region)" + }, + { + "aimed_departure_time": "11:00", + "best_departure_estimate": "11:00", + "date": "2017-05-09", + "dir": "outbound", + "direction": "Stratton Way (Abingdon Town Centre)", + "expected_departure_date": null, + "expected_departure_time": null, + "id": "https://transportapi.com/v3/uk/bus/route/THTR/32A/outbound/340000368SHE/2017-05-09/11:00/timetable.json?app_id=e99&app_key=058", + "line": "32A", + "line_name": "32A", + "mode": "bus", + "operator": "THTR", + "operator_name": "Thames Travel", + "source": "Traveline timetable (not a nextbuses live region)" + }, + { + "aimed_departure_time": "11:18", + "best_departure_estimate": "11:18", + "date": "2017-05-09", + "dir": "outbound", + "direction": "Market Place (Wantage)", + "expected_departure_date": null, + "expected_departure_time": null, + "id": "https://transportapi.com/v3/uk/bus/route/THTR/32A/outbound/340000368SHE/2017-05-09/11:18/timetable.json?app_id=e99&app_key=058", + "line": "32A", + "line_name": "32A", + "mode": "bus", + "operator": "THTR", + "operator_name": "Thames Travel", + "source": "Traveline timetable (not a nextbuses live region)" + } + ], + "X32": [{ + "aimed_departure_time": "10:09", + "best_departure_estimate": "10:09", + "date": "2017-05-09", + "dir": "inbound", + "direction": "Parkway Station (Didcot)", + "expected_departure_date": null, + "expected_departure_time": null, + "id": "https://transportapi.com/v3/uk/bus/route/THTR/X32/inbound/340000368SHE/2017-05-09/10:09/timetable.json?app_id=e99&app_key=058", + "line": "X32", + "line_name": "X32", + "mode": "bus", + "operator": "THTR", + "operator_name": "Thames Travel", + "source": "Traveline timetable (not a nextbuses live region)" + }, + { + "aimed_departure_time": "10:30", + "best_departure_estimate": "10:30", + "date": "2017-05-09", + "dir": "inbound", + "direction": "Parks Road (Oxford City Centre)", + "expected_departure_date": null, + "expected_departure_time": null, + "id": "https://transportapi.com/v3/uk/bus/route/THTR/X32/inbound/340000368SHE/2017-05-09/10:30/timetable.json?app_id=e99&app_key=058", + "line": "X32", + "line_name": "X32", + "mode": "bus", + "operator": "THTR", + "operator_name": "Thames Travel", + "source": "Traveline timetable (not a nextbuses live region)" + }, + { + "aimed_departure_time": "10:39", + "best_departure_estimate": "10:39", + "date": "2017-05-09", + "dir": "inbound", + "direction": "Parkway Station (Didcot)", + "expected_departure_date": null, + "expected_departure_time": null, + "id": "https://transportapi.com/v3/uk/bus/route/THTR/X32/inbound/340000368SHE/2017-05-09/10:39/timetable.json?app_id=e99&app_key=058", + "line": "X32", + "line_name": "X32", + "mode": "bus", + "operator": "THTR", + "operator_name": "Thames Travel", + "source": "Traveline timetable (not a nextbuses live region)" + } + ] + }, + "indicator": "in", + "locality": "Harwell Campus", + "name": "Bus Station (in)", + "request_time": "2017-05-09T10:03:41+01:00", + "smscode": "oxfajwgp", + "stop_name": "Bus Station" +} diff --git a/tests/fixtures/uk_transport_train.json b/tests/fixtures/uk_transport_train.json new file mode 100644 index 0000000000000..b06e8db6ca70d --- /dev/null +++ b/tests/fixtures/uk_transport_train.json @@ -0,0 +1,511 @@ +{ + "date": "2017-07-10", + "time_of_day": "06:10", + "request_time": "2017-07-10T06:10:05+01:00", + "station_name": "Wimbledon", + "station_code": "WIM", + "departures": { + "all": [ + { + "mode": "train", + "service": "24671405", + "train_uid": "W36814", + "platform": "8", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:13", + "aimed_arrival_time": null, + "aimed_pass_time": null, + "origin_name": "Wimbledon", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "STARTS HERE", + "expected_arrival_time": null, + "expected_departure_time": "06:13", + "best_arrival_estimate_mins": null, + "best_departure_estimate_mins": 2 + }, + { + "mode": "train", + "service": "24673205", + "train_uid": "W36613", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:14", + "aimed_arrival_time": "06:13", + "aimed_pass_time": null, + "origin_name": "Hampton Court", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "EARLY", + "expected_arrival_time": "06:13", + "expected_departure_time": "06:14", + "best_arrival_estimate_mins": 2, + "best_departure_estimate_mins": 3 + }, + { + "mode": "train", + "service": "24673505", + "train_uid": "W36012", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:20", + "aimed_arrival_time": "06:20", + "aimed_pass_time": null, + "origin_name": "Guildford", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:20", + "expected_departure_time": "06:20", + "best_arrival_estimate_mins": 9, + "best_departure_estimate_mins": 9 + }, + { + "mode": "train", + "service": "24673305", + "train_uid": "W34087", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:23", + "aimed_arrival_time": "06:23", + "aimed_pass_time": null, + "origin_name": "Dorking", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "XX", + "status": "ON TIME", + "expected_arrival_time": "06:23", + "expected_departure_time": "06:23", + "best_arrival_estimate_mins": 12, + "best_departure_estimate_mins": 12 + }, + { + "mode": "train", + "service": "24671505", + "train_uid": "W37471", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:32", + "aimed_arrival_time": "06:31", + "aimed_pass_time": null, + "origin_name": "London Waterloo", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:31", + "expected_departure_time": "06:32", + "best_arrival_estimate_mins": 20, + "best_departure_estimate_mins": 21 + }, + { + "mode": "train", + "service": "24673605", + "train_uid": "W35790", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:35", + "aimed_arrival_time": "06:35", + "aimed_pass_time": null, + "origin_name": "Woking", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:35", + "expected_departure_time": "06:35", + "best_arrival_estimate_mins": 24, + "best_departure_estimate_mins": 24 + }, + { + "mode": "train", + "service": "24673705", + "train_uid": "W35665", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:38", + "aimed_arrival_time": "06:38", + "aimed_pass_time": null, + "origin_name": "Epsom", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:38", + "expected_departure_time": "06:38", + "best_arrival_estimate_mins": 27, + "best_departure_estimate_mins": 27 + }, + { + "mode": "train", + "service": "24671405", + "train_uid": "W36816", + "platform": "8", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:43", + "aimed_arrival_time": "06:43", + "aimed_pass_time": null, + "origin_name": "London Waterloo", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:43", + "expected_departure_time": "06:43", + "best_arrival_estimate_mins": 32, + "best_departure_estimate_mins": 32 + }, + { + "mode": "train", + "service": "24673205", + "train_uid": "W36618", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:44", + "aimed_arrival_time": "06:43", + "aimed_pass_time": null, + "origin_name": "Hampton Court", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:43", + "expected_departure_time": "06:44", + "best_arrival_estimate_mins": 32, + "best_departure_estimate_mins": 33 + }, + { + "mode": "train", + "service": "24673105", + "train_uid": "W36429", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:47", + "aimed_arrival_time": "06:46", + "aimed_pass_time": null, + "origin_name": "Shepperton", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:46", + "expected_departure_time": "06:47", + "best_arrival_estimate_mins": 35, + "best_departure_estimate_mins": 36 + }, + { + "mode": "train", + "service": "24629204", + "train_uid": "W36916", + "platform": "6", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:47", + "aimed_arrival_time": "06:47", + "aimed_pass_time": null, + "origin_name": "Basingstoke", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "LATE", + "expected_arrival_time": "06:48", + "expected_departure_time": "06:48", + "best_arrival_estimate_mins": 37, + "best_departure_estimate_mins": 37 + }, + { + "mode": "train", + "service": "24673505", + "train_uid": "W36016", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:50", + "aimed_arrival_time": "06:49", + "aimed_pass_time": null, + "origin_name": "Guildford", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:49", + "expected_departure_time": "06:50", + "best_arrival_estimate_mins": 38, + "best_departure_estimate_mins": 39 + }, + { + "mode": "train", + "service": "24673705", + "train_uid": "W35489", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:53", + "aimed_arrival_time": "06:52", + "aimed_pass_time": null, + "origin_name": "Guildford", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "EARLY", + "expected_arrival_time": "06:52", + "expected_departure_time": "06:53", + "best_arrival_estimate_mins": 41, + "best_departure_estimate_mins": 42 + }, + { + "mode": "train", + "service": "24673405", + "train_uid": "W37107", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "06:58", + "aimed_arrival_time": "06:57", + "aimed_pass_time": null, + "origin_name": "Chessington South", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "06:57", + "expected_departure_time": "06:58", + "best_arrival_estimate_mins": 46, + "best_departure_estimate_mins": 47 + }, + { + "mode": "train", + "service": "24671505", + "train_uid": "W37473", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:02", + "aimed_arrival_time": "07:01", + "aimed_pass_time": null, + "origin_name": "London Waterloo", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "EARLY", + "expected_arrival_time": "07:01", + "expected_departure_time": "07:02", + "best_arrival_estimate_mins": 50, + "best_departure_estimate_mins": 51 + }, + { + "mode": "train", + "service": "24673605", + "train_uid": "W35795", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:05", + "aimed_arrival_time": "07:04", + "aimed_pass_time": null, + "origin_name": "Woking", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:04", + "expected_departure_time": "07:05", + "best_arrival_estimate_mins": 53, + "best_departure_estimate_mins": 54 + }, + { + "mode": "train", + "service": "24673305", + "train_uid": "W34090", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:08", + "aimed_arrival_time": "07:07", + "aimed_pass_time": null, + "origin_name": "Dorking", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "XX", + "status": "ON TIME", + "expected_arrival_time": "07:07", + "expected_departure_time": "07:08", + "best_arrival_estimate_mins": 56, + "best_departure_estimate_mins": 57 + }, + { + "mode": "train", + "service": "24673205", + "train_uid": "W36623", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:13", + "aimed_arrival_time": "07:12", + "aimed_pass_time": null, + "origin_name": "Hampton Court", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:12", + "expected_departure_time": "07:13", + "best_arrival_estimate_mins": 61, + "best_departure_estimate_mins": 62 + }, + { + "mode": "train", + "service": "24671405", + "train_uid": "W36819", + "platform": "8", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:13", + "aimed_arrival_time": "07:13", + "aimed_pass_time": null, + "origin_name": "London Waterloo", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:13", + "expected_departure_time": "07:13", + "best_arrival_estimate_mins": 62, + "best_departure_estimate_mins": 62 + }, + { + "mode": "train", + "service": "24673105", + "train_uid": "W36434", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:16", + "aimed_arrival_time": "07:15", + "aimed_pass_time": null, + "origin_name": "Shepperton", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:15", + "expected_departure_time": "07:16", + "best_arrival_estimate_mins": 64, + "best_departure_estimate_mins": 65 + }, + { + "mode": "train", + "service": "24673505", + "train_uid": "W36019", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:19", + "aimed_arrival_time": "07:18", + "aimed_pass_time": null, + "origin_name": "Guildford", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:18", + "expected_departure_time": "07:19", + "best_arrival_estimate_mins": 67, + "best_departure_estimate_mins": 68 + }, + { + "mode": "train", + "service": "24673705", + "train_uid": "W35494", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:22", + "aimed_arrival_time": "07:21", + "aimed_pass_time": null, + "origin_name": "Guildford", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:21", + "expected_departure_time": "07:22", + "best_arrival_estimate_mins": 70, + "best_departure_estimate_mins": 71 + }, + { + "mode": "train", + "service": "24673205", + "train_uid": "W36810", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:25", + "aimed_arrival_time": "07:24", + "aimed_pass_time": null, + "origin_name": "Esher", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:24", + "expected_departure_time": "07:25", + "best_arrival_estimate_mins": 73, + "best_departure_estimate_mins": 74 + }, + { + "mode": "train", + "service": "24673405", + "train_uid": "W37112", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:28", + "aimed_arrival_time": "07:27", + "aimed_pass_time": null, + "origin_name": "Chessington South", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:27", + "expected_departure_time": "07:28", + "best_arrival_estimate_mins": 76, + "best_departure_estimate_mins": 77 + }, + { + "mode": "train", + "service": "24671505", + "train_uid": "W37476", + "platform": "5", + "operator": "SW", + "operator_name": "South West Trains", + "aimed_departure_time": "07:32", + "aimed_arrival_time": "07:31", + "aimed_pass_time": null, + "origin_name": "London Waterloo", + "source": "Network Rail", + "destination_name": "London Waterloo", + "category": "OO", + "status": "ON TIME", + "expected_arrival_time": "07:31", + "expected_departure_time": "07:32", + "best_arrival_estimate_mins": 80, + "best_departure_estimate_mins": 81 + } + ] + } +} From f5eeb252a74a4ae563cac2deedf93d82b73ebfa7 Mon Sep 17 00:00:00 2001 From: kfcook <809694+kfcook@users.noreply.github.com> Date: Thu, 27 Jul 2017 02:14:12 -0400 Subject: [PATCH 102/118] Added support for SerenaHoneycombShades to Lutron Caseta (#8662) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- homeassistant/components/cover/lutron_caseta.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/cover/lutron_caseta.py b/homeassistant/components/cover/lutron_caseta.py index 2c411c61ba48e..6857aaebf9bc9 100644 --- a/homeassistant/components/cover/lutron_caseta.py +++ b/homeassistant/components/cover/lutron_caseta.py @@ -23,7 +23,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Lutron Caseta Serena shades as a cover device.""" devs = [] bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] - cover_devices = bridge.get_devices_by_types(["SerenaRollerShade"]) + cover_devices = bridge.get_devices_by_types(["SerenaRollerShade", + "SerenaHoneycombShade"]) for cover_device in cover_devices: dev = LutronCasetaCover(cover_device, bridge) devs.append(dev) From 9d5c61b2f07574637b430b222dbb587aa783649c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=ADlio=20Costa?= Date: Thu, 27 Jul 2017 07:24:15 +0100 Subject: [PATCH 103/118] MQTT Switch: add availability_topic for online/offline status (#8593) * mqtt switch: add availability_topic for online/offline status * fix method doc strings * MQTT Switch: add test --- homeassistant/components/mqtt/__init__.py | 1 + homeassistant/components/switch/mqtt.py | 38 ++++++++++++++++--- tests/components/switch/test_mqtt.py | 45 ++++++++++++++++++++++- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 3c75648892b4a..929ae0fc45575 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -58,6 +58,7 @@ CONF_STATE_TOPIC = 'state_topic' CONF_COMMAND_TOPIC = 'command_topic' +CONF_AVAILABILITY_TOPIC = 'availability_topic' CONF_QOS = 'qos' CONF_RETAIN = 'retain' diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index e9c282e4c45fc..1169e5a3d5d6d 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -11,7 +11,8 @@ from homeassistant.core import callback from homeassistant.components.mqtt import ( - CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_QOS, CONF_RETAIN) + CONF_STATE_TOPIC, CONF_COMMAND_TOPIC, CONF_AVAILABILITY_TOPIC, CONF_QOS, + CONF_RETAIN) from homeassistant.components.switch import SwitchDevice from homeassistant.const import ( CONF_NAME, CONF_OPTIMISTIC, CONF_VALUE_TEMPLATE, CONF_PAYLOAD_OFF, @@ -50,6 +51,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): config.get(CONF_NAME), config.get(CONF_STATE_TOPIC), config.get(CONF_COMMAND_TOPIC), + config.get(CONF_AVAILABILITY_TOPIC), config.get(CONF_QOS), config.get(CONF_RETAIN), config.get(CONF_PAYLOAD_ON), @@ -62,13 +64,16 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): class MqttSwitch(SwitchDevice): """Representation of a switch that can be toggled using MQTT.""" - def __init__(self, name, state_topic, command_topic, qos, retain, - payload_on, payload_off, optimistic, value_template): + def __init__(self, name, state_topic, command_topic, availability_topic, + qos, retain, payload_on, payload_off, optimistic, + value_template): """Initialize the MQTT switch.""" self._state = False self._name = name self._state_topic = state_topic self._command_topic = command_topic + self._availability_topic = availability_topic + self._available = True if availability_topic is None else False self._qos = qos self._retain = retain self._payload_on = payload_on @@ -83,8 +88,8 @@ def async_added_to_hass(self): This method is a coroutine. """ @callback - def message_received(topic, payload, qos): - """Handle new MQTT messages.""" + def state_message_received(topic, payload, qos): + """Handle new MQTT state messages.""" if self._template is not None: payload = self._template.async_render_with_possible_json_value( payload) @@ -95,12 +100,28 @@ def message_received(topic, payload, qos): self.hass.async_add_job(self.async_update_ha_state()) + @callback + def availability_message_received(topic, payload, qos): + """Handle new MQTT availability messages.""" + if payload == self._payload_on: + self._available = True + elif payload == self._payload_off: + self._available = False + + self.hass.async_add_job(self.async_update_ha_state()) + if self._state_topic is None: # Force into optimistic mode. self._optimistic = True else: yield from mqtt.async_subscribe( - self.hass, self._state_topic, message_received, self._qos) + self.hass, self._state_topic, state_message_received, + self._qos) + + if self._availability_topic is not None: + yield from mqtt.async_subscribe( + self.hass, self._availability_topic, + availability_message_received, self._qos) @property def should_poll(self): @@ -112,6 +133,11 @@ def name(self): """Return the name of the switch.""" return self._name + @property + def available(self) -> bool: + """Return if switch is available.""" + return self._available + @property def is_on(self): """Return true if device is on.""" diff --git a/tests/components/switch/test_mqtt.py b/tests/components/switch/test_mqtt.py index 8215eae26cc5e..133978a7bd86f 100644 --- a/tests/components/switch/test_mqtt.py +++ b/tests/components/switch/test_mqtt.py @@ -2,7 +2,8 @@ import unittest from homeassistant.setup import setup_component -from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE +from homeassistant.const import STATE_ON, STATE_OFF, STATE_UNAVAILABLE,\ + ATTR_ASSUMED_STATE import homeassistant.components.switch as switch from tests.common import ( mock_mqtt_component, fire_mqtt_message, get_test_home_assistant) @@ -110,3 +111,45 @@ def test_controlling_state_via_topic_and_json_message(self): state = self.hass.states.get('switch.test') self.assertEqual(STATE_OFF, state.state) + + def test_controlling_availability(self): + """Test the controlling state via topic.""" + assert setup_component(self.hass, switch.DOMAIN, { + switch.DOMAIN: { + 'platform': 'mqtt', + 'name': 'test', + 'state_topic': 'state-topic', + 'command_topic': 'command-topic', + 'availability_topic': 'availability_topic', + 'payload_on': 1, + 'payload_off': 0 + } + }) + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability_topic', '1') + self.hass.block_till_done() + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_OFF, state.state) + self.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) + + fire_mqtt_message(self.hass, 'availability_topic', '0') + self.hass.block_till_done() + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'state-topic', '1') + self.hass.block_till_done() + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_UNAVAILABLE, state.state) + + fire_mqtt_message(self.hass, 'availability_topic', '1') + self.hass.block_till_done() + + state = self.hass.states.get('switch.test') + self.assertEqual(STATE_ON, state.state) From 1e8c00ac021afa28488b33c0b9b4ef25cd818e61 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Wed, 26 Jul 2017 23:58:34 -0700 Subject: [PATCH 104/118] Adding support for mapping keys to value in statsd (#8665) * Adding ability to map specific states to values * Adding test for mapping --- homeassistant/components/statsd.py | 8 +++++++- tests/components/test_statsd.py | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/statsd.py b/homeassistant/components/statsd.py index 452faf8933bc3..3613f53c098de 100644 --- a/homeassistant/components/statsd.py +++ b/homeassistant/components/statsd.py @@ -19,6 +19,7 @@ CONF_ATTR = 'log_attributes' CONF_RATE = 'rate' +CONF_VALUE_MAP = 'value_mapping' DEFAULT_HOST = 'localhost' DEFAULT_PORT = 8125 @@ -34,6 +35,7 @@ vol.Optional(CONF_PREFIX, default=DEFAULT_PREFIX): cv.string, vol.Optional(CONF_RATE, default=DEFAULT_RATE): vol.All(vol.Coerce(int), vol.Range(min=1)), + vol.Optional(CONF_VALUE_MAP, default=None): dict, }), }, extra=vol.ALLOW_EXTRA) @@ -47,6 +49,7 @@ def setup(hass, config): port = conf.get(CONF_PORT) sample_rate = conf.get(CONF_RATE) prefix = conf.get(CONF_PREFIX) + value_mapping = conf.get(CONF_VALUE_MAP) show_attribute_flag = conf.get(CONF_ATTR) statsd_client = statsd.StatsClient(host=host, port=port, prefix=prefix) @@ -59,7 +62,10 @@ def statsd_event_listener(event): return try: - _state = state_helper.state_as_number(state) + if value_mapping and state.state in value_mapping: + _state = float(value_mapping[state.state]) + else: + _state = state_helper.state_as_number(state) except ValueError: # Set the state to none and continue for any numeric attributes. _state = None diff --git a/tests/components/test_statsd.py b/tests/components/test_statsd.py index eb8933b77bee0..5fd907fe0b10a 100644 --- a/tests/components/test_statsd.py +++ b/tests/components/test_statsd.py @@ -86,6 +86,7 @@ def test_event_listener_defaults(self, mock_client): config = { 'statsd': { 'host': 'host', + 'value_mapping': {'custom': 3} } } @@ -98,6 +99,7 @@ def test_event_listener_defaults(self, mock_client): valid = {'1': 1, '1.0': 1.0, + 'custom': 3, STATE_ON: 1, STATE_OFF: 0} for in_, out in valid.items(): From b59c29943b82bd1e791e44cb9eac27dc3f07fcef Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 27 Jul 2017 17:22:40 +0200 Subject: [PATCH 105/118] Upgrade fuzzywuzzy to 0.15.1 (#8671) --- homeassistant/components/conversation.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/conversation.py b/homeassistant/components/conversation.py index 303e83e7e0ef4..62611b82496fa 100644 --- a/homeassistant/components/conversation.py +++ b/homeassistant/components/conversation.py @@ -19,7 +19,7 @@ from homeassistant.components import http -REQUIREMENTS = ['fuzzywuzzy==0.15.0'] +REQUIREMENTS = ['fuzzywuzzy==0.15.1'] DEPENDENCIES = ['http'] ATTR_TEXT = 'text' diff --git a/requirements_all.txt b/requirements_all.txt index aad16af8592bf..60947488fba4b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -235,7 +235,7 @@ fritzhome==1.0.2 fsapi==0.0.7 # homeassistant.components.conversation -fuzzywuzzy==0.15.0 +fuzzywuzzy==0.15.1 # homeassistant.components.tts.google gTTS-token==1.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9d2842c7bbb7b..8c40e75c2885a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -43,7 +43,7 @@ dsmr_parser==0.8 evohomeclient==0.2.5 # homeassistant.components.conversation -fuzzywuzzy==0.15.0 +fuzzywuzzy==0.15.1 # homeassistant.components.tts.google gTTS-token==1.1.1 From 4fcaea23a840de26a6e573a00ccd494fd205f54e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 27 Jul 2017 17:23:07 +0200 Subject: [PATCH 106/118] Upgrade libnacl to 1.5.2 (#8670) --- homeassistant/components/device_tracker/owntracks.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/owntracks.py b/homeassistant/components/device_tracker/owntracks.py index ab4ba315c0245..b23008336ac06 100644 --- a/homeassistant/components/device_tracker/owntracks.py +++ b/homeassistant/components/device_tracker/owntracks.py @@ -21,7 +21,7 @@ from homeassistant.components.device_tracker import PLATFORM_SCHEMA DEPENDENCIES = ['mqtt'] -REQUIREMENTS = ['libnacl==1.5.1'] +REQUIREMENTS = ['libnacl==1.5.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 60947488fba4b..741ed38f47e25 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -353,7 +353,7 @@ keyring>=9.3,<10.0 knxip==0.5 # homeassistant.components.device_tracker.owntracks -libnacl==1.5.1 +libnacl==1.5.2 # homeassistant.components.dyson libpurecoollink==0.2.0 From 74581b57f8d04c958b3ba7a26919d7cfa90c242f Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 27 Jul 2017 17:23:51 +0200 Subject: [PATCH 107/118] Upgrade sqlalchemy to 1.1.12 (#8669) --- homeassistant/components/recorder/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 63dbf9fc1b17e..77a049376e552 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -33,7 +33,7 @@ from .const import DATA_INSTANCE from .util import session_scope -REQUIREMENTS = ['sqlalchemy==1.1.11'] +REQUIREMENTS = ['sqlalchemy==1.1.12'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 741ed38f47e25..a7c8ebb0f2891 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -881,7 +881,7 @@ speedtest-cli==1.0.6 # homeassistant.components.recorder # homeassistant.scripts.db_migrator -sqlalchemy==1.1.11 +sqlalchemy==1.1.12 # homeassistant.components.statsd statsd==3.2.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8c40e75c2885a..01f948120311d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -130,7 +130,7 @@ somecomfort==0.4.1 # homeassistant.components.recorder # homeassistant.scripts.db_migrator -sqlalchemy==1.1.11 +sqlalchemy==1.1.12 # homeassistant.components.statsd statsd==3.2.1 From 9e6817b6d05d656edca85ae14794787de3b11a25 Mon Sep 17 00:00:00 2001 From: Daniel Perna Date: Thu, 27 Jul 2017 17:45:59 +0200 Subject: [PATCH 108/118] Upgrade pyhomematic to 0.1.30 (#8673) --- homeassistant/components/homematic.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/homematic.py b/homeassistant/components/homematic.py index a8fc645ee4cce..f9583d9be7ae0 100644 --- a/homeassistant/components/homematic.py +++ b/homeassistant/components/homematic.py @@ -21,7 +21,7 @@ from homeassistant.helpers.event import track_time_interval from homeassistant.config import load_yaml_config_file -REQUIREMENTS = ['pyhomematic==0.1.29'] +REQUIREMENTS = ['pyhomematic==0.1.30'] DOMAIN = 'homematic' diff --git a/requirements_all.txt b/requirements_all.txt index a7c8ebb0f2891..b6ee7eb5d06b4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -590,7 +590,7 @@ pyharmony==1.0.16 pyhik==0.1.3 # homeassistant.components.homematic -pyhomematic==0.1.29 +pyhomematic==0.1.30 # homeassistant.components.sensor.hydroquebec pyhydroquebec==1.2.0 From 51108b8fe9e0718d868a464f4abd0a6c6418ce65 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 27 Jul 2017 21:23:22 +0200 Subject: [PATCH 109/118] Hass.io: logo support / timeout handling (#8668) * Disable auth on logo / no timeout for addons update/install * fix tests --- homeassistant/components/hassio.py | 35 +++++++++++++++++++++++++----- tests/components/test_hassio.py | 22 +++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/hassio.py b/homeassistant/components/hassio.py index 4ce60fed014dd..1ba599c72b42a 100644 --- a/homeassistant/components/hassio.py +++ b/homeassistant/components/hassio.py @@ -25,8 +25,15 @@ DOMAIN = 'hassio' DEPENDENCIES = ['http'] -TIMEOUT = 10 -NO_TIMEOUT = set(['homeassistant/update', 'host/update', 'supervisor/update']) +NO_TIMEOUT = { + re.compile(r'^homeassistant/update$'), re.compile(r'^host/update$'), + re.compile(r'^supervisor/update$'), re.compile(r'^addons/[^/]*/update$'), + re.compile(r'^addons/[^/]*/install$') +} + +NO_AUTH = { + re.compile(r'^panel$'), re.compile(r'^addons/[^/]*/logo$') +} @asyncio.coroutine @@ -71,7 +78,7 @@ def is_connected(self): This method is a coroutine. """ try: - with async_timeout.timeout(TIMEOUT, loop=self.loop): + with async_timeout.timeout(10, loop=self.loop): request = yield from self.websession.get( "http://{}{}".format(self._ip, "/supervisor/ping") ) @@ -97,12 +104,12 @@ def command_proxy(self, path, request): This method is a coroutine. """ - read_timeout = 0 if path in NO_TIMEOUT else 300 + read_timeout = _get_timeout(path) try: data = None headers = None - with async_timeout.timeout(TIMEOUT, loop=self.loop): + with async_timeout.timeout(10, loop=self.loop): data = yield from request.read() if data: headers = {CONTENT_TYPE: request.content_type} @@ -140,7 +147,7 @@ def __init__(self, hassio): @asyncio.coroutine def _handle(self, request, path): """Route data to hassio.""" - if path != 'panel' and not request[KEY_AUTHENTICATED]: + if _need_auth(path) and not request[KEY_AUTHENTICATED]: return web.Response(status=401) client = yield from self.hassio.command_proxy(path, request) @@ -173,3 +180,19 @@ def _create_response_log(client, data): status=client.status, content_type=CONTENT_TYPE_TEXT_PLAIN, ) + + +def _get_timeout(path): + """Return timeout for a url path.""" + for re_path in NO_TIMEOUT: + if re_path.match(path): + return 0 + return 300 + + +def _need_auth(path): + """Return if a path need a auth.""" + for re_path in NO_AUTH: + if re_path.match(path): + return False + return True diff --git a/tests/components/test_hassio.py b/tests/components/test_hassio.py index eb0754fdc0abf..ccb568914955f 100644 --- a/tests/components/test_hassio.py +++ b/tests/components/test_hassio.py @@ -106,6 +106,28 @@ def test_forward_request_no_auth_for_panel(hassio_client): assert mresp.mock_calls[0][1] == (response, 'data') +@asyncio.coroutine +def test_forward_request_no_auth_for_logo(hassio_client): + """Test no auth needed for .""" + response = MagicMock() + response.read.return_value = mock_coro('data') + + with patch('homeassistant.components.hassio.HassIO.command_proxy', + Mock(return_value=mock_coro(response))), \ + patch('homeassistant.components.hassio._create_response') as mresp: + mresp.return_value = 'response' + resp = yield from hassio_client.get('/api/hassio/addons/bl_b392/logo') + + # Check we got right response + assert resp.status == 200 + body = yield from resp.text() + assert body == 'response' + + # Check we forwarded command + assert len(mresp.mock_calls) == 1 + assert mresp.mock_calls[0][1] == (response, 'data') + + @asyncio.coroutine def test_forward_log_request(hassio_client): """Test fetching normal log path.""" From 0ab0e35d5985103a1056af45110461d96556eb4f Mon Sep 17 00:00:00 2001 From: Brian Gehrich Date: Thu, 27 Jul 2017 16:33:17 -0400 Subject: [PATCH 110/118] Updated pysnmp to 4.3.9 (#8675) --- homeassistant/components/device_tracker/snmp.py | 2 +- homeassistant/components/sensor/snmp.py | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/device_tracker/snmp.py b/homeassistant/components/device_tracker/snmp.py index 46b1686b21dbf..3efae2b9ce2e5 100644 --- a/homeassistant/components/device_tracker/snmp.py +++ b/homeassistant/components/device_tracker/snmp.py @@ -16,7 +16,7 @@ _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['pysnmp==4.3.8'] +REQUIREMENTS = ['pysnmp==4.3.9'] CONF_COMMUNITY = 'community' CONF_AUTHKEY = 'authkey' diff --git a/homeassistant/components/sensor/snmp.py b/homeassistant/components/sensor/snmp.py index 75a6f68a0a227..361ce55142678 100644 --- a/homeassistant/components/sensor/snmp.py +++ b/homeassistant/components/sensor/snmp.py @@ -15,7 +15,7 @@ from homeassistant.const import ( CONF_HOST, CONF_NAME, CONF_PORT, CONF_UNIT_OF_MEASUREMENT) -REQUIREMENTS = ['pysnmp==4.3.8'] +REQUIREMENTS = ['pysnmp==4.3.9'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index b6ee7eb5d06b4..5bce15dbfd29b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -684,7 +684,7 @@ pysma==0.1.3 # homeassistant.components.device_tracker.snmp # homeassistant.components.sensor.snmp -pysnmp==4.3.8 +pysnmp==4.3.9 # homeassistant.components.sensor.thinkingcleaner # homeassistant.components.switch.thinkingcleaner From e8ce41874c8b637f666ab8809ff40be75c48221e Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 27 Jul 2017 15:57:30 -0700 Subject: [PATCH 111/118] Fix COMMAND_CLASS_BARRIER_OPERATOR for dev branch of OpenZwave (#8574) * Update zwave.py to work with updated OpenZwave library Update zwave.py to work with updated OpenZwave library * Update zwave.py * Update zwave.py * Update to fix garage door openers Update to fix garage door support for latest version of openzwavelib * Update to cover.zwave list of states Update to cover.zwave to provide list of states based on dev version of openzwave lib * Some values not saved * Formatting fix * Formatting fix * Variable typo * Formatting fix * Formatting * Variable Update Variable Update and properties added * Formatting fixes * Formatting Fix * Update test case for door states * Formatting / Testing process fix * Formatting * Formatting / Test Fixes * Variable rename * Added members to CoverDevice * Removed un-needed else * Formatting * Formatting * Variable name changes and const updates * Changed variable names to cover_state * Added constains into const.py * Updated to change the main state on the cover device * Fixes * Formatting fixes * Formatting/Variables * Formatting * Variable fixes * Import update * Formatting / Variables * Update test for new states * Revert state changes * Test fix * Variable Fix * Formatting * Variable typo * Missing constant * Variable fix * Requested changes * Added is_opening * Added is_closing * Updated test based on changes * Formatting * Changed cover_state back to _state * Formatting and variable fixes * Test fixes * Formatting and variable touchup * Formatting * Optimizations * Add new cover features to demo * Add tests for demo cover closing/opening * Remove unused STATE_STOPPED * Add tests for new zwave cover values --- homeassistant/components/cover/__init__.py | 17 +++++++++- homeassistant/components/cover/demo.py | 38 ++++++++++++++++------ homeassistant/components/cover/zwave.py | 18 ++++++++-- homeassistant/const.py | 2 ++ tests/components/cover/test_demo.py | 8 +++++ tests/components/cover/test_zwave.py | 27 +++++++++++---- 6 files changed, 90 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index df096c9ba8087..23c0be1a43e1b 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -23,7 +23,7 @@ SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, SERVICE_SET_COVER_POSITION, SERVICE_STOP_COVER, SERVICE_OPEN_COVER_TILT, SERVICE_CLOSE_COVER_TILT, SERVICE_STOP_COVER_TILT, SERVICE_SET_COVER_TILT_POSITION, STATE_OPEN, - STATE_CLOSED, STATE_UNKNOWN, ATTR_ENTITY_ID) + STATE_CLOSED, STATE_UNKNOWN, STATE_OPENING, STATE_CLOSING, ATTR_ENTITY_ID) _LOGGER = logging.getLogger(__name__) @@ -225,6 +225,11 @@ def current_cover_tilt_position(self): @property def state(self): """Return the state of the cover.""" + if self.is_opening: + return STATE_OPENING + if self.is_closing: + return STATE_CLOSING + closed = self.is_closed if closed is None: @@ -262,6 +267,16 @@ def supported_features(self): return supported_features + @property + def is_opening(self): + """Return if the cover is opening or not.""" + pass + + @property + def is_closing(self): + """Return if the cover is closing or not.""" + pass + @property def is_closed(self): """Return if the cover is closed or not.""" diff --git a/homeassistant/components/cover/demo.py b/homeassistant/components/cover/demo.py index ed0606597467a..827b50c8af9d1 100644 --- a/homeassistant/components/cover/demo.py +++ b/homeassistant/components/cover/demo.py @@ -35,10 +35,12 @@ def __init__(self, hass, name, position=None, tilt_position=None, self._set_position = None self._set_tilt_position = None self._tilt_position = tilt_position - self._closing = True - self._closing_tilt = True + self._requested_closing = True + self._requested_closing_tilt = True self._unsub_listener_cover = None self._unsub_listener_cover_tilt = None + self._is_opening = False + self._is_closing = False if position is None: self._closed = True else: @@ -69,6 +71,16 @@ def is_closed(self): """Return if the cover is closed.""" return self._closed + @property + def is_closing(self): + """Return if the cover is closing.""" + return self._is_closing + + @property + def is_opening(self): + """Return if the cover is opening.""" + return self._is_opening + @property def device_class(self): """Return the class of this device, from component DEVICE_CLASSES.""" @@ -90,8 +102,10 @@ def close_cover(self, **kwargs): self.schedule_update_ha_state() return + self._is_closing = True self._listen_cover() - self._closing = True + self._requested_closing = True + self.schedule_update_ha_state() def close_cover_tilt(self, **kwargs): """Close the cover tilt.""" @@ -99,7 +113,7 @@ def close_cover_tilt(self, **kwargs): return self._listen_cover_tilt() - self._closing_tilt = True + self._requested_closing_tilt = True def open_cover(self, **kwargs): """Open the cover.""" @@ -110,8 +124,10 @@ def open_cover(self, **kwargs): self.schedule_update_ha_state() return + self._is_opening = True self._listen_cover() - self._closing = False + self._requested_closing = False + self.schedule_update_ha_state() def open_cover_tilt(self, **kwargs): """Open the cover tilt.""" @@ -119,7 +135,7 @@ def open_cover_tilt(self, **kwargs): return self._listen_cover_tilt() - self._closing_tilt = False + self._requested_closing_tilt = False def set_cover_position(self, position, **kwargs): """Move the cover to a specific position.""" @@ -128,7 +144,7 @@ def set_cover_position(self, position, **kwargs): return self._listen_cover() - self._closing = position < self._position + self._requested_closing = position < self._position def set_cover_tilt_position(self, tilt_position, **kwargs): """Move the cover til to a specific position.""" @@ -137,10 +153,12 @@ def set_cover_tilt_position(self, tilt_position, **kwargs): return self._listen_cover_tilt() - self._closing_tilt = tilt_position < self._tilt_position + self._requested_closing_tilt = tilt_position < self._tilt_position def stop_cover(self, **kwargs): """Stop the cover.""" + self._is_closing = False + self._is_opening = False if self._position is None: return if self._unsub_listener_cover is not None: @@ -166,7 +184,7 @@ def _listen_cover(self): def _time_changed_cover(self, now): """Track time changes.""" - if self._closing: + if self._requested_closing: self._position -= 10 else: self._position += 10 @@ -186,7 +204,7 @@ def _listen_cover_tilt(self): def _time_changed_cover_tilt(self, now): """Track time changes.""" - if self._closing_tilt: + if self._requested_closing_tilt: self._tilt_position -= 10 else: self._tilt_position += 10 diff --git a/homeassistant/components/cover/zwave.py b/homeassistant/components/cover/zwave.py index 6ec70d9a85a9d..b8daab8150320 100644 --- a/homeassistant/components/cover/zwave.py +++ b/homeassistant/components/cover/zwave.py @@ -110,24 +110,36 @@ class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice): def __init__(self, values): """Initialize the zwave garage door.""" ZWaveDeviceEntity.__init__(self, values, DOMAIN) + self._state = None self.update_properties() def update_properties(self): """Handle data changes for node values.""" self._state = self.values.primary.data + _LOGGER.debug("self._state=%s", self._state) + + @property + def is_opening(self): + """Return true if cover is in an opening state.""" + return self._state == "Opening" + + @property + def is_closing(self): + """Return true if cover is in an closing state.""" + return self._state == "Closing" @property def is_closed(self): """Return the current position of Zwave garage door.""" - return not self._state + return self._state == "Closed" def close_cover(self): """Close the garage door.""" - self.values.primary.data = False + self.values.primary.data = "Closed" def open_cover(self): """Open the garage door.""" - self.values.primary.data = True + self.values.primary.data = "Opened" @property def device_class(self): diff --git a/homeassistant/const.py b/homeassistant/const.py index b4b2aac52e300..ca8075b10abf3 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -188,7 +188,9 @@ STATE_NOT_HOME = 'not_home' STATE_UNKNOWN = 'unknown' STATE_OPEN = 'open' +STATE_OPENING = 'opening' STATE_CLOSED = 'closed' +STATE_CLOSING = 'closing' STATE_PLAYING = 'playing' STATE_PAUSED = 'paused' STATE_IDLE = 'idle' diff --git a/tests/components/cover/test_demo.py b/tests/components/cover/test_demo.py index 83907de7708bf..9d26a6a4f4a35 100644 --- a/tests/components/cover/test_demo.py +++ b/tests/components/cover/test_demo.py @@ -38,29 +38,37 @@ def test_supported_features(self): def test_close_cover(self): """Test closing the cover.""" state = self.hass.states.get(ENTITY_COVER) + self.assertEqual(state.state, 'open') self.assertEqual(70, state.attributes.get('current_position')) cover.close_cover(self.hass, ENTITY_COVER) self.hass.block_till_done() + state = self.hass.states.get(ENTITY_COVER) + self.assertEqual(state.state, 'closing') for _ in range(7): future = dt_util.utcnow() + timedelta(seconds=1) fire_time_changed(self.hass, future) self.hass.block_till_done() state = self.hass.states.get(ENTITY_COVER) + self.assertEqual(state.state, 'closed') self.assertEqual(0, state.attributes.get('current_position')) def test_open_cover(self): """Test opening the cover.""" state = self.hass.states.get(ENTITY_COVER) + self.assertEqual(state.state, 'open') self.assertEqual(70, state.attributes.get('current_position')) cover.open_cover(self.hass, ENTITY_COVER) self.hass.block_till_done() + state = self.hass.states.get(ENTITY_COVER) + self.assertEqual(state.state, 'opening') for _ in range(7): future = dt_util.utcnow() + timedelta(seconds=1) fire_time_changed(self.hass, future) self.hass.block_till_done() state = self.hass.states.get(ENTITY_COVER) + self.assertEqual(state.state, 'open') self.assertEqual(100, state.attributes.get('current_position')) def test_set_cover_position(self): diff --git a/tests/components/cover/test_zwave.py b/tests/components/cover/test_zwave.py index e1ee6075cead7..fe9abe7172c68 100644 --- a/tests/components/cover/test_zwave.py +++ b/tests/components/cover/test_zwave.py @@ -161,31 +161,46 @@ def test_roller_reverse_open_close(hass, mock_openzwave): def test_garage_value_changed(hass, mock_openzwave): """Test position changed.""" node = MockNode() - value = MockValue(data=False, node=node, + value = MockValue(data="Closed", node=node, command_class=const.COMMAND_CLASS_BARRIER_OPERATOR) values = MockEntityValues(primary=value, node=node) device = zwave.get_device(hass=hass, node=node, values=values, node_config={}) assert device.is_closed + assert not device.is_opening + assert not device.is_closing - value.data = True + value.data = "Opening" value_changed(value) + assert not device.is_closed + assert device.is_opening + assert not device.is_closing + value.data = "Opened" + value_changed(value) + assert not device.is_closed + assert not device.is_opening + assert not device.is_closing + + value.data = "Closing" + value_changed(value) assert not device.is_closed + assert not device.is_opening + assert device.is_closing def test_garage_commands(hass, mock_openzwave): """Test position changed.""" node = MockNode() - value = MockValue(data=False, node=node, + value = MockValue(data="Closed", node=node, command_class=const.COMMAND_CLASS_BARRIER_OPERATOR) values = MockEntityValues(primary=value, node=node) device = zwave.get_device(hass=hass, node=node, values=values, node_config={}) - assert value.data is False + assert value.data == "Closed" device.open_cover() - assert value.data is True + assert value.data == "Opened" device.close_cover() - assert value.data is False + assert value.data == "Closed" From 0c97fe7eac0e5145fa7e9d3ac723ddb19433b2c8 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 28 Jul 2017 02:38:06 -0700 Subject: [PATCH 112/118] Version bump to 0.50 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index ca8075b10abf3..751aa31608438 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 50 -PATCH_VERSION = '0.dev0' +PATCH_VERSION = '0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 4, 2) From 828c469ef7acc9e0c45d181cd07431c82b060aa4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 28 Jul 2017 20:53:15 -0700 Subject: [PATCH 113/118] Fix Lint --- homeassistant/components/device_tracker/ubus.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/device_tracker/ubus.py b/homeassistant/components/device_tracker/ubus.py index cac4b7769e3dc..9ccc61dffc91f 100644 --- a/homeassistant/components/device_tracker/ubus.py +++ b/homeassistant/components/device_tracker/ubus.py @@ -80,7 +80,7 @@ def scan_devices(self): return self.last_results @_refresh_on_acccess_denied - def get_device_name(self, device): + def get_device_name(self, mac): """Return the name of the given device or None if we don't know.""" if self.leasefile is None: result = _req_json_rpc( @@ -105,10 +105,9 @@ def get_device_name(self, device): # Error, handled in the _req_json_rpc return - return self.mac2name.get(device.upper(), None) + return self.mac2name.get(mac.upper(), None) @_refresh_on_acccess_denied - @Throttle(MIN_TIME_BETWEEN_SCANS) def _update_info(self): """Ensure the information from the Luci router is up to date. From 56f4486e0b86b6278f8853ed8741fab35bd77db0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 29 Jul 2017 10:45:14 -0700 Subject: [PATCH 114/118] Update frontend --- homeassistant/components/frontend/version.py | 4 +- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 139371 -> 139470 bytes .../www_static/home-assistant-polymer | 2 +- .../panels/ha-panel-shopping-list.html | 108 +++++++++++++++++- .../panels/ha-panel-shopping-list.html.gz | Bin 5308 -> 6144 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2490 -> 2491 bytes 8 files changed, 112 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index a0958f65d95bf..985177e95f33e 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -3,7 +3,7 @@ FINGERPRINTS = { "compatibility.js": "8e4c44b5f4288cc48ec1ba94a9bec812", "core.js": "d4a7cb8c80c62b536764e0e81385f6aa", - "frontend.html": "c44e49b9a0d9b9e4a626b7af34ca97d0", + "frontend.html": "c544d43b2305b922e230c7c4e74d7613", "mdi.html": "e91f61a039ed0a9936e7ee5360da3870", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-automation.html": "1982116c49ad26ee8d89295edc797084", @@ -19,6 +19,6 @@ "panels/ha-panel-kiosk.html": "2ac2df41bd447600692a0054892fc094", "panels/ha-panel-logbook.html": "7c45bd41c146ec38b9938b8a5188bb0d", "panels/ha-panel-map.html": "50501cd53eb4304e9e46eb719aa894b7", - "panels/ha-panel-shopping-list.html": "c04af28c6475b90cbf2cf63ba1b841d0", + "panels/ha-panel-shopping-list.html": "0a6020ff6aec96a1e6220e00ea5b15f8", "panels/ha-panel-zwave.html": "422f95f820f8b6b231265351ffcf4dd1" } diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index ca86fd55d2248..23c00301cf3e3 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -2,4 +2,4 @@ this._useContent&&u.Logical.saveChildNodes(this)},_setupRoot:function(){this._useContent&&(this._createLocalRoot(),this.dataHost||l(u.Logical.getChildNodes(this)))},_createLocalRoot:function(){this.shadyRoot=this.root,this.shadyRoot._distributionClean=!1,this.shadyRoot._hasDistributed=!1,this.shadyRoot._isShadyRoot=!0,this.shadyRoot._dirtyRoots=[];var e=this.shadyRoot._insertionPoints=!this._notes||this._notes._hasContent?this.shadyRoot.querySelectorAll("content"):[];u.Logical.saveChildNodes(this.shadyRoot);for(var t,o=0;o0?~setTimeout(e,t):(this._twiddle.textContent=this._twiddleContent++,this._callbacks.push(e),this._currVal++)},cancel:function(e){if(e<0)clearTimeout(~e);else{var t=e-this._lastVal;if(t>=0){if(!this._callbacks[t])throw"invalid async handle: "+e;this._callbacks[t]=null}}},_atEndOfMicrotask:function(){for(var e=this._callbacks.length,t=0;t \ No newline at end of file +;return"matrix("+o(i[0])+" "+o(i[1])+" "+o(i[4])+" "+o(i[5])+" "+o(i[12])+" "+o(i[13])+")"}}(n),function(t,e){function i(t,e){e.concat([t]).forEach(function(e){e in document.documentElement.style&&(n[t]=e),r[e]=t})}var n={},r={};i("transform",["webkitTransform","msTransform"]),i("transformOrigin",["webkitTransformOrigin"]),i("perspective",["webkitPerspective"]),i("perspectiveOrigin",["webkitPerspectiveOrigin"]),t.propertyName=function(t){return n[t]||t},t.unprefixedPropertyName=function(t){return r[t]||t}}(n)}(),function(){if(void 0===document.createElement("div").animate([]).oncancel){var t;if(window.performance&&performance.now)var t=function(){return performance.now()};else var t=function(){return Date.now()};var e=function(t,e,i){this.target=t,this.currentTime=e,this.timelineTime=i,this.type="cancel",this.bubbles=!1,this.cancelable=!1,this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},i=window.Element.prototype.animate;window.Element.prototype.animate=function(n,r){var o=i.call(this,n,r);o._cancelHandlers=[],o.oncancel=null;var a=o.cancel;o.cancel=function(){a.call(this);var i=new e(this,null,t()),n=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){n.forEach(function(t){t.call(i.target,i)})},0)};var s=o.addEventListener;o.addEventListener=function(t,e){"function"==typeof e&&"cancel"==t?this._cancelHandlers.push(e):s.call(this,t,e)};var u=o.removeEventListener;return o.removeEventListener=function(t,e){if("cancel"==t){var i=this._cancelHandlers.indexOf(e);i>=0&&this._cancelHandlers.splice(i,1)}else u.call(this,t,e)},o}}}(),function(t){var e=document.documentElement,i=null,n=!1;try{var r=getComputedStyle(e).getPropertyValue("opacity"),o="0"==r?"1":"0";i=e.animate({opacity:[o,o]},{duration:1}),i.currentTime=0,n=getComputedStyle(e).getPropertyValue("opacity")==o}catch(t){}finally{i&&i.cancel()}if(!n){var a=window.Element.prototype.animate;window.Element.prototype.animate=function(e,i){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&e[Symbol.iterator]&&(e=Array.from(e)),Array.isArray(e)||null===e||(e=t.convertToArrayForm(e)),a.call(this,e,i)}}}(i),function(t,e,i){function n(t){var i=e.timeline;i.currentTime=t,i._discardAnimations(),0==i._animations.length?o=!1:requestAnimationFrame(n)}var r=window.requestAnimationFrame;window.requestAnimationFrame=function(t){return r(function(i){e.timeline._updateAnimationsPromises(),t(i),e.timeline._updateAnimationsPromises()})},e.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},e.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){e.animationsWithPromises=e.animationsWithPromises.filter(function(t){return t._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(t){return"finished"!=t.playState&&"idle"!=t.playState})},_play:function(t){var i=new e.Animation(t,this);return this._animations.push(i),e.restartWebAnimationsNextTick(),i._updatePromises(),i._animation.play(),i._updatePromises(),i},play:function(t){return t&&t.remove(),this._play(t)}};var o=!1;e.restartWebAnimationsNextTick=function(){o||(o=!0,requestAnimationFrame(n))};var a=new e.AnimationTimeline;e.timeline=a;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return a}})}catch(t){}try{window.document.timeline=a}catch(t){}}(0,r),function(t,e,i){e.animationsWithPromises=[],e.Animation=function(e,i){if(this.id="",e&&e._id&&(this.id=e._id),this.effect=e,e&&(e._animation=this),!i)throw new Error("Animation with null timeline is not supported");this._timeline=i,this._sequenceNumber=t.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},e.Animation.prototype={_updatePromises:function(){var t=this._oldPlayState,e=this.playState;return this._readyPromise&&e!==t&&("idle"==e?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==t?this._resolveReadyPromise():"pending"==e&&(this._readyPromise=void 0)),this._finishedPromise&&e!==t&&("idle"==e?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==e?this._resolveFinishedPromise():"finished"==t&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var t,i,n,r,o=!!this._animation;o&&(t=this.playbackRate,i=this._paused,n=this.startTime,r=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=e.newUnderlyingAnimationForKeyframeEffect(this.effect),e.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=e.newUnderlyingAnimationForGroup(this.effect),e.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&e.bindAnimationForCustomEffect(this),o&&(1!=t&&(this.playbackRate=t),null!==n?this.startTime=n:null!==r?this.currentTime=r:null!==this._holdTime&&(this.currentTime=this._holdTime),i&&this.pause()),this._updatePromises()},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var t=this.effect._timing.delay;this._childAnimations.forEach(function(i){this._arrangeChildren(i,t),this.effect instanceof window.SequenceEffect&&(t+=e.groupChildDuration(i.effect))}.bind(this))}},_setExternalAnimation:function(t){if(this.effect&&this._isGroup)for(var e=0;e \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index a55204f203c36e36624813e501c97257c6755fd0..ad2cc4fb8cf0038f3583228f4f1371e0b31af173 100644 GIT binary patch delta 83077 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 QgpX0Z4h0{m=KEf3sr|eede(>Z#D8 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

    \ No newline at end of file + \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz index 6c71d75c39096ba7237d6622b4046bb8c125c169..76577a763119ab74f445f4ec39294e974c418994 100644 GIT binary patch literal 6144 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 Ot^WnUqSg?9O8@|0oJ1)A diff --git a/homeassistant/components/frontend/www_static/service_worker.js b/homeassistant/components/frontend/www_static/service_worker.js index bb8dcaf473563..05af75abb2394 100644 --- a/homeassistant/components/frontend/www_static/service_worker.js +++ b/homeassistant/components/frontend/www_static/service_worker.js @@ -1 +1 @@ -"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}function notificationEventCallback(e,t){firePushCallback({action:t.action,data:t.notification.data,tag:t.notification.tag,type:e},t.notification.data.jwt)}function firePushCallback(e,t){delete e.data.jwt,0===Object.keys(e.data).length&&e.data.constructor===Object&&delete e.data,fetch("/api/notify.html5/callback",{method:"POST",headers:new Headers({"Content-Type":"application/json",Authorization:"Bearer "+t}),body:JSON.stringify(e)})}var precacheConfig=[["/","e8a916ce10360ad5d87ca48fc5444525"],["/frontend/panels/dev-event-77784d5f0c73fcc3b29b6cc050bdf324.html","eebf53a12ae770fea7c5429de2db810c"],["/frontend/panels/dev-info-24e888ec7a8acd0c395b34396e9001bc.html","7bb116813e8dbab7bcfabdf4de3ec83f"],["/frontend/panels/dev-service-86a42a17f4894478b6b77bc636beafd0.html","86888ff94a1958074cde156739687ba0"],["/frontend/panels/dev-state-31ef6ffe3347cdda5bb0cbbc54b62cde.html","38dc27f1f817045900f396a61c7e736f"],["/frontend/panels/dev-template-d1d76e20fe9622cddee33e67318abde8.html","2973bd8b33775239a4a05d6d569dd331"],["/frontend/panels/map-50501cd53eb4304e9e46eb719aa894b7.html","410d870df0226d08078d8dc45d02a8ef"],["/static/compatibility-8e4c44b5f4288cc48ec1ba94a9bec812.js","4704a985ad259e324c3d8a0a40f6d937"],["/static/core-d4a7cb8c80c62b536764e0e81385f6aa.js","37e34ec6aa0fa155c7d50e2883be1ead"],["/static/frontend-c44e49b9a0d9b9e4a626b7af34ca97d0.html","de85e6c361344f98a02beed34046df6b"],["/static/mdi-e91f61a039ed0a9936e7ee5360da3870.html","5e587bc82719b740a4f0798722a83aee"],["static/fonts/roboto/Roboto-Bold.ttf","d329cc8b34667f114a95422aaad1b063"],["static/fonts/roboto/Roboto-Light.ttf","7b5fb88f12bec8143f00e21bc3222124"],["static/fonts/roboto/Roboto-Medium.ttf","fe13e4170719c2fc586501e777bde143"],["static/fonts/roboto/Roboto-Regular.ttf","ac3f799d5bbaf5196fab15ab8de8431c"],["static/icons/favicon-192x192.png","419903b8422586a7e28021bbe9011175"],["static/icons/favicon.ico","04235bda7843ec2fceb1cbe2bc696cf4"],["static/images/card_media_player_bg.png","a34281d1c1835d338a642e90930e61aa"],["static/webcomponents-lite.min.js","32b5a9b7ada86304bec6b43d3f2194f0"]],cacheName="sw-precache-v3--"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var a=new URL(e);return"/"===a.pathname.slice(-1)&&(a.pathname+=t),a.toString()},cleanResponse=function(e){return e.redirected?("body"in e?Promise.resolve(e.body):e.blob()).then(function(t){return new Response(t,{headers:e.headers,status:e.status,statusText:e.statusText})}):Promise.resolve(e)},createCacheKey=function(e,t,a,n){var c=new URL(e);return n&&c.pathname.match(n)||(c.search+=(c.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(a)),c.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var a=new URL(t).pathname;return e.some(function(e){return a.match(e)})},stripIgnoredUrlParameters=function(e,t){var a=new URL(e);return a.search=a.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),a.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],a=e[1],n=new URL(t,self.location),c=createCacheKey(n,hashParamName,a,!1);return[n.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(a){if(!t.has(a)){var n=new Request(a,{credentials:"same-origin"});return fetch(n).then(function(t){if(!t.ok)throw new Error("Request for "+a+" returned a response with status "+t.status);return cleanResponse(t).then(function(t){return e.put(a,t)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(a){return Promise.all(a.map(function(a){if(!t.has(a.url))return e.delete(a)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,a=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);t=urlsToCacheKeys.has(a);t||(a=addDirectoryIndex(a,"index.html"),t=urlsToCacheKeys.has(a));!t&&"navigate"===e.request.mode&&isPathWhitelisted(["^((?!(static|api|local|service_worker.js|manifest.json)).)*$"],e.request.url)&&(a=new URL("/",self.location).toString(),t=urlsToCacheKeys.has(a)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(a)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}),self.addEventListener("push",function(e){var t;e.data&&(t=e.data.json(),e.waitUntil(self.registration.showNotification(t.title,t).then(function(e){firePushCallback({type:"received",tag:t.tag,data:t.data},t.data.jwt)})))}),self.addEventListener("notificationclick",function(e){var t;notificationEventCallback("clicked",e),e.notification.close(),e.notification.data&&e.notification.data.url&&(t=e.notification.data.url)&&e.waitUntil(clients.matchAll({type:"window"}).then(function(e){var a,n;for(a=0;aa zLID{PNn|K8rcSGAvAHS)jysPH5tSsOhplOjx2pt2zKqnNg< zNChN;NHJx}6FbtlT$M(Z3}l*MNT}yYNU|l8RwPq{jKINcqbkf(#%0DCOVc=HIYi*c zGLdnTOUYPpTot92aZLUWgp3*Ti1`ub7$wNlAO|26dAiXMe+9nGQeP@R3=`=SY?-9} zMX~fl$Z*(<0jLlYQ7>0C;6+*Jn{kGbh$0@VD9kb;A|gY;f#Aj}$ZnPDE7XnaF&Rggjbj02y#UVc!$=OEF*QK~_p`j9D0lK^T2c)~_gw^>PrV zkfJ@J;GjK

    DE`1_UI36ekf2#ICf$6o!d{D>E1edH9X~yj3;tn4af8;~7Cj20=<( z@o9&g@>LK7X?#+SNB?NOAB8OD5-7V;=AvyO4+O`MGEtrgwFgnLggLfUX&U)?NzlM& ziu)UEKJ)ot4KRwDKn5bnD9tlQG>bwqC1*Yok6>5YHF6Vqbw%m3sRRiH2TwuhmSreX$UsP6usr50VtInO?+09L)TEpTL6QXwGs%Ic zTqqzzB8dz|#?)ywEjCw$z;Tv96he@yD9fWL&3M975|glmBPi)_G-U}Hq*NY3kjI&y zMnYl`Cn?#Kr5yYxG=FK(IA#H=L@8t}N`;gVbM6by2^F4%Bx|FGWm1Hx3RD)PeiYMo z6{&zE5GkfCd16Nzm#fmKl7UPU3<>o-2}!m@(u!nikP$eTZB&JM%DBupV`&z4g`PB$+JP|eQAvX!U*y# z1{uaV68{8~8Tb(SDv>!$A1P=EoQSB%Gm-fs33<$tG>OnhqEHsA1fZA8Qe+VddiE6r zaV%09`$(2Bj!ppu@1EQZLSr%*qnzj9OZtxyBq6a06pIAp=>wO@2QemsB>{^fm6O3C zN0cn`qeQBN?@3?EVvKp9k^p>`qx2!qS%N7d8ShJA1n@?1lavE0NtLmYg}D$!jwnfp zjsd|;0UQE=47i`L?}_@Qm@o7oD1k06POgnEDXaSjJ_x9SCqwiIS5lo z(H>E7&>lrdi7S%_1SEgtqlg7!S6X2T!$iTA8H|HG{6>G?s+xC9&vT#gj36R|ASJH& zv_nq$DhPr!J}Jkef3)6@LKbrglwB!v(YBBWf@4UTC{KjigQ!@-99yb1jr_bMXy7x& z{S7vs`FyYj7)4DW0}*5_rcllxi9#|ZXFd{-U{~5Taua!VMd`Du1PKKQ)xx1YV-^4a DGqNuE From f0e5f688650f5b2414ca5b868a3be82b209446d3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 29 Jul 2017 08:48:09 -0700 Subject: [PATCH 115/118] Shopping List: edit name / complete status (#8666) * Shopping List: edit name / complete status * Change ID to be UUID based --- homeassistant/components/shopping_list.py | 72 ++++++++++++++++-- tests/components/test_shopping_list.py | 90 ++++++++++++++++++++++- 2 files changed, 154 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/shopping_list.py b/homeassistant/components/shopping_list.py index ac59c15572a30..9922960da3ff8 100644 --- a/homeassistant/components/shopping_list.py +++ b/homeassistant/components/shopping_list.py @@ -1,9 +1,11 @@ """Component to manage a shoppling list.""" import asyncio import logging +import uuid import voluptuous as vol +from homeassistant.const import HTTP_NOT_FOUND, HTTP_BAD_REQUEST from homeassistant.core import callback from homeassistant.components import http from homeassistant.helpers import intent @@ -17,15 +19,20 @@ EVENT = 'shopping_list_updated' INTENT_ADD_ITEM = 'HassShoppingListAddItem' INTENT_LAST_ITEMS = 'HassShoppingListLastItems' +ITEM_UPDATE_SCHEMA = vol.Schema({ + 'complete': bool, + 'name': str, +}) @asyncio.coroutine def async_setup(hass, config): """Initialize the shopping list.""" - hass.data[DOMAIN] = [] + hass.data[DOMAIN] = ShoppingData([]) intent.async_register(hass, AddItemIntent()) intent.async_register(hass, ListTopItemsIntent()) hass.http.register_view(ShoppingListView) + hass.http.register_view(UpdateShoppingListItemView) hass.components.conversation.async_register(INTENT_ADD_ITEM, [ 'Add {item} to my shopping list', ]) @@ -37,6 +44,37 @@ def async_setup(hass, config): return True +class ShoppingData: + """Class to hold shopping list data.""" + + def __init__(self, items): + """Initialize the shopping list.""" + self.items = items + + def add(self, name): + """Add a shopping list item.""" + self.items.append({ + 'name': name, + 'id': uuid.uuid4().hex, + 'complete': False + }) + + def update(self, item_id, info): + """Update a shopping list item.""" + item = next((itm for itm in self.items if itm['id'] == item_id), None) + + if item is None: + raise KeyError + + info = ITEM_UPDATE_SCHEMA(info) + item.update(info) + return item + + def clear_completed(self): + """Clear completed items.""" + self.items = [itm for itm in self.items if not itm['complete']] + + class AddItemIntent(intent.IntentHandler): """Handle AddItem intents.""" @@ -50,7 +88,7 @@ def async_handle(self, intent_obj): """Handle the intent.""" slots = self.async_validate_slots(intent_obj.slots) item = slots['item']['value'] - intent_obj.hass.data[DOMAIN].append(item) + intent_obj.hass.data[DOMAIN].add(item) response = intent_obj.create_response() response.async_set_speech( @@ -70,16 +108,17 @@ class ListTopItemsIntent(intent.IntentHandler): @asyncio.coroutine def async_handle(self, intent_obj): """Handle the intent.""" - items = intent_obj.hass.data[DOMAIN][-5:] + items = intent_obj.hass.data[DOMAIN].items[-5:] response = intent_obj.create_response() - if len(items) == 0: + if not items: response.async_set_speech( "There are no items on your shopping list") else: response.async_set_speech( "These are the top {} items on your shopping list: {}".format( - min(len(items), 5), ', '.join(reversed(items)))) + min(len(items), 5), + ', '.join(itm['name'] for itm in reversed(items)))) return response @@ -92,4 +131,25 @@ class ShoppingListView(http.HomeAssistantView): @callback def get(self, request): """Retrieve if API is running.""" - return self.json(request.app['hass'].data[DOMAIN]) + return self.json(request.app['hass'].data[DOMAIN].items) + + +class UpdateShoppingListItemView(http.HomeAssistantView): + """View to retrieve shopping list content.""" + + url = '/api/shopping_list/{item_id}' + name = "api:shopping_list:id" + + @callback + def post(self, request, item_id): + """Retrieve if API is running.""" + data = yield from request.json() + + try: + item = request.app['hass'].data[DOMAIN].update(item_id, data) + request.app['hass'].bus.async_fire(EVENT) + return self.json(item) + except KeyError: + return self.json_message('Item not found', HTTP_NOT_FOUND) + except vol.Invalid: + return self.json_message('Item not found', HTTP_BAD_REQUEST) diff --git a/tests/components/test_shopping_list.py b/tests/components/test_shopping_list.py index c25ce593c5419..e4a99ad39d4fa 100644 --- a/tests/components/test_shopping_list.py +++ b/tests/components/test_shopping_list.py @@ -42,7 +42,7 @@ def test_recent_items_intent(hass): @asyncio.coroutine -def test_api(hass, test_client): +def test_api_get_all(hass, test_client): """Test the API.""" yield from async_setup_component(hass, 'shopping_list', {}) @@ -58,4 +58,90 @@ def test_api(hass, test_client): assert resp.status == 200 data = yield from resp.json() - assert data == ['beer', 'wine'] + assert len(data) == 2 + assert data[0]['name'] == 'beer' + assert not data[0]['complete'] + assert data[1]['name'] == 'wine' + assert not data[1]['complete'] + + +@asyncio.coroutine +def test_api_update(hass, test_client): + """Test the API.""" + yield from async_setup_component(hass, 'shopping_list', {}) + + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}} + ) + + beer_id = hass.data['shopping_list'].items[0]['id'] + wine_id = hass.data['shopping_list'].items[1]['id'] + + client = yield from test_client(hass.http.app) + resp = yield from client.post( + '/api/shopping_list/{}'.format(beer_id), json={ + 'name': 'soda' + }) + + assert resp.status == 200 + data = yield from resp.json() + assert data == { + 'id': beer_id, + 'name': 'soda', + 'complete': False + } + + resp = yield from client.post( + '/api/shopping_list/{}'.format(wine_id), json={ + 'complete': True + }) + + assert resp.status == 200 + data = yield from resp.json() + assert data == { + 'id': wine_id, + 'name': 'wine', + 'complete': True + } + + beer, wine = hass.data['shopping_list'].items + assert beer == { + 'id': beer_id, + 'name': 'soda', + 'complete': False + } + assert wine == { + 'id': wine_id, + 'name': 'wine', + 'complete': True + } + + +@asyncio.coroutine +def test_api_update_fails(hass, test_client): + """Test the API.""" + yield from async_setup_component(hass, 'shopping_list', {}) + + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + + client = yield from test_client(hass.http.app) + resp = yield from client.post( + '/api/shopping_list/non_existing', json={ + 'name': 'soda' + }) + + assert resp.status == 404 + + beer_id = hass.data['shopping_list'].items[0]['id'] + client = yield from test_client(hass.http.app) + resp = yield from client.post( + '/api/shopping_list/{}'.format(beer_id), json={ + 'name': 123, + }) + + assert resp.status == 400 From c376bc2e451734d03f559a5743a9020c105992be Mon Sep 17 00:00:00 2001 From: William Scanlon Date: Fri, 28 Jul 2017 12:02:16 -0400 Subject: [PATCH 116/118] Support for Wink local control (#8607) * Support for Wink local control --- homeassistant/components/wink.py | 38 ++++++++++++++++++++++---------- requirements_all.txt | 2 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 1783d4bd79af5..e6d60aa55687d 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -25,7 +25,7 @@ from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['python-wink==1.3.1', 'pubnubsub-handler==1.0.2'] +REQUIREMENTS = ['python-wink==1.4.2', 'pubnubsub-handler==1.0.2'] _LOGGER = logging.getLogger(__name__) @@ -36,10 +36,10 @@ CONF_CLIENT_ID = 'client_id' CONF_CLIENT_SECRET = 'client_secret' CONF_USER_AGENT = 'user_agent' -CONF_OATH = 'oath' +CONF_OAUTH = 'oauth' +CONF_LOCAL_CONTROL = 'local_control' CONF_APPSPOT = 'appspot' -CONF_DEFINED_BOTH_MSG = 'Remove access token to use oath2.' -CONF_MISSING_OATH_MSG = 'Missing oath2 credentials.' +CONF_MISSING_OAUTH_MSG = 'Missing oauth2 credentials.' CONF_TOKEN_URL = "https://winkbearertoken.appspot.com/token" ATTR_ACCESS_TOKEN = 'access_token' @@ -64,15 +64,14 @@ CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Inclusive(CONF_EMAIL, CONF_APPSPOT, - msg=CONF_MISSING_OATH_MSG): cv.string, + msg=CONF_MISSING_OAUTH_MSG): cv.string, vol.Inclusive(CONF_PASSWORD, CONF_APPSPOT, - msg=CONF_MISSING_OATH_MSG): cv.string, - vol.Inclusive(CONF_CLIENT_ID, CONF_OATH, - msg=CONF_MISSING_OATH_MSG): cv.string, - vol.Inclusive(CONF_CLIENT_SECRET, CONF_OATH, - msg=CONF_MISSING_OATH_MSG): cv.string, - vol.Exclusive(CONF_EMAIL, CONF_OATH, - msg=CONF_DEFINED_BOTH_MSG): cv.string, + msg=CONF_MISSING_OAUTH_MSG): cv.string, + vol.Inclusive(CONF_CLIENT_ID, CONF_OAUTH, + msg=CONF_MISSING_OAUTH_MSG): cv.string, + vol.Inclusive(CONF_CLIENT_SECRET, CONF_OAUTH, + msg=CONF_MISSING_OAUTH_MSG): cv.string, + vol.Optional(CONF_LOCAL_CONTROL, default=False): cv.boolean }) }, extra=vol.ALLOW_EXTRA) @@ -206,8 +205,11 @@ def _get_wink_token_from_web(): client_secret = config[DOMAIN].get(ATTR_CLIENT_SECRET) email = config[DOMAIN].get(CONF_EMAIL) password = config[DOMAIN].get(CONF_PASSWORD) + local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL) if None not in [client_id, client_secret]: _LOGGER.info("Using legacy oauth authentication") + if not local_control: + pywink.disable_local_control() hass.data[DOMAIN]["oauth"]["client_id"] = client_id hass.data[DOMAIN]["oauth"]["client_secret"] = client_secret hass.data[DOMAIN]["oauth"]["email"] = email @@ -216,11 +218,14 @@ def _get_wink_token_from_web(): client_id, client_secret) elif None not in [email, password]: _LOGGER.info("Using web form authentication") + pywink.disable_local_control() hass.data[DOMAIN]["oauth"]["email"] = email hass.data[DOMAIN]["oauth"]["password"] = password _get_wink_token_from_web() else: _LOGGER.info("Using new oauth authentication") + if not local_control: + pywink.disable_local_control() config_path = hass.config.path(WINK_CONFIG_FILE) if os.path.isfile(config_path): config_file = _read_config_file(config_path) @@ -304,6 +309,15 @@ def stop_subscription(event): hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription) + def save_credentials(event): + """Save currently set oauth credentials.""" + if hass.data[DOMAIN]["oauth"].get("email") is None: + config_path = hass.config.path(WINK_CONFIG_FILE) + _config = pywink.get_current_oauth_credentials() + _write_config_file(config_path, _config) + + hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials) + def force_update(call): """Force all devices to poll the Wink API.""" _LOGGER.info("Refreshing Wink states from API") diff --git a/requirements_all.txt b/requirements_all.txt index 5bce15dbfd29b..84e3618d2a03f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -768,7 +768,7 @@ python-velbus==2.0.11 python-vlc==1.1.2 # homeassistant.components.wink -python-wink==1.3.1 +python-wink==1.4.2 # homeassistant.components.zwave python_openzwave==0.4.0.31 From 12dec93565a1bea09876d6cb9a429be7968f3599 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 29 Jul 2017 12:18:50 -0700 Subject: [PATCH 117/118] Update frontend --- homeassistant/components/frontend/version.py | 4 ++-- .../frontend/www_static/frontend.html | 2 +- .../frontend/www_static/frontend.html.gz | Bin 139470 -> 139501 bytes .../www_static/home-assistant-polymer | 2 +- .../panels/ha-panel-shopping-list.html | 10 +++++++--- .../panels/ha-panel-shopping-list.html.gz | Bin 6144 -> 15408 bytes .../frontend/www_static/service_worker.js | 2 +- .../frontend/www_static/service_worker.js.gz | Bin 2491 -> 2492 bytes 8 files changed, 12 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/frontend/version.py b/homeassistant/components/frontend/version.py index 985177e95f33e..469452f7e4974 100644 --- a/homeassistant/components/frontend/version.py +++ b/homeassistant/components/frontend/version.py @@ -3,7 +3,7 @@ FINGERPRINTS = { "compatibility.js": "8e4c44b5f4288cc48ec1ba94a9bec812", "core.js": "d4a7cb8c80c62b536764e0e81385f6aa", - "frontend.html": "c544d43b2305b922e230c7c4e74d7613", + "frontend.html": "7d599996578579600f1000d6d25e649d", "mdi.html": "e91f61a039ed0a9936e7ee5360da3870", "micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a", "panels/ha-panel-automation.html": "1982116c49ad26ee8d89295edc797084", @@ -19,6 +19,6 @@ "panels/ha-panel-kiosk.html": "2ac2df41bd447600692a0054892fc094", "panels/ha-panel-logbook.html": "7c45bd41c146ec38b9938b8a5188bb0d", "panels/ha-panel-map.html": "50501cd53eb4304e9e46eb719aa894b7", - "panels/ha-panel-shopping-list.html": "0a6020ff6aec96a1e6220e00ea5b15f8", + "panels/ha-panel-shopping-list.html": "1d7126efc9ff9a102df7465d803a11d1", "panels/ha-panel-zwave.html": "422f95f820f8b6b231265351ffcf4dd1" } diff --git a/homeassistant/components/frontend/www_static/frontend.html b/homeassistant/components/frontend/www_static/frontend.html index 23c00301cf3e3..7dd7b17c987c4 100644 --- a/homeassistant/components/frontend/www_static/frontend.html +++ b/homeassistant/components/frontend/www_static/frontend.html @@ -2,4 +2,4 @@ this._useContent&&u.Logical.saveChildNodes(this)},_setupRoot:function(){this._useContent&&(this._createLocalRoot(),this.dataHost||l(u.Logical.getChildNodes(this)))},_createLocalRoot:function(){this.shadyRoot=this.root,this.shadyRoot._distributionClean=!1,this.shadyRoot._hasDistributed=!1,this.shadyRoot._isShadyRoot=!0,this.shadyRoot._dirtyRoots=[];var e=this.shadyRoot._insertionPoints=!this._notes||this._notes._hasContent?this.shadyRoot.querySelectorAll("content"):[];u.Logical.saveChildNodes(this.shadyRoot);for(var t,o=0;o0?~setTimeout(e,t):(this._twiddle.textContent=this._twiddleContent++,this._callbacks.push(e),this._currVal++)},cancel:function(e){if(e<0)clearTimeout(~e);else{var t=e-this._lastVal;if(t>=0){if(!this._callbacks[t])throw"invalid async handle: "+e;this._callbacks[t]=null}}},_atEndOfMicrotask:function(){for(var e=this._callbacks.length,t=0;t \ No newline at end of file +;return"matrix("+o(i[0])+" "+o(i[1])+" "+o(i[4])+" "+o(i[5])+" "+o(i[12])+" "+o(i[13])+")"}}(n),function(t,e){function i(t,e){e.concat([t]).forEach(function(e){e in document.documentElement.style&&(n[t]=e),r[e]=t})}var n={},r={};i("transform",["webkitTransform","msTransform"]),i("transformOrigin",["webkitTransformOrigin"]),i("perspective",["webkitPerspective"]),i("perspectiveOrigin",["webkitPerspectiveOrigin"]),t.propertyName=function(t){return n[t]||t},t.unprefixedPropertyName=function(t){return r[t]||t}}(n)}(),function(){if(void 0===document.createElement("div").animate([]).oncancel){var t;if(window.performance&&performance.now)var t=function(){return performance.now()};else var t=function(){return Date.now()};var e=function(t,e,i){this.target=t,this.currentTime=e,this.timelineTime=i,this.type="cancel",this.bubbles=!1,this.cancelable=!1,this.currentTarget=t,this.defaultPrevented=!1,this.eventPhase=Event.AT_TARGET,this.timeStamp=Date.now()},i=window.Element.prototype.animate;window.Element.prototype.animate=function(n,r){var o=i.call(this,n,r);o._cancelHandlers=[],o.oncancel=null;var a=o.cancel;o.cancel=function(){a.call(this);var i=new e(this,null,t()),n=this._cancelHandlers.concat(this.oncancel?[this.oncancel]:[]);setTimeout(function(){n.forEach(function(t){t.call(i.target,i)})},0)};var s=o.addEventListener;o.addEventListener=function(t,e){"function"==typeof e&&"cancel"==t?this._cancelHandlers.push(e):s.call(this,t,e)};var u=o.removeEventListener;return o.removeEventListener=function(t,e){if("cancel"==t){var i=this._cancelHandlers.indexOf(e);i>=0&&this._cancelHandlers.splice(i,1)}else u.call(this,t,e)},o}}}(),function(t){var e=document.documentElement,i=null,n=!1;try{var r=getComputedStyle(e).getPropertyValue("opacity"),o="0"==r?"1":"0";i=e.animate({opacity:[o,o]},{duration:1}),i.currentTime=0,n=getComputedStyle(e).getPropertyValue("opacity")==o}catch(t){}finally{i&&i.cancel()}if(!n){var a=window.Element.prototype.animate;window.Element.prototype.animate=function(e,i){return window.Symbol&&Symbol.iterator&&Array.prototype.from&&e[Symbol.iterator]&&(e=Array.from(e)),Array.isArray(e)||null===e||(e=t.convertToArrayForm(e)),a.call(this,e,i)}}}(i),function(t,e,i){function n(t){var i=e.timeline;i.currentTime=t,i._discardAnimations(),0==i._animations.length?o=!1:requestAnimationFrame(n)}var r=window.requestAnimationFrame;window.requestAnimationFrame=function(t){return r(function(i){e.timeline._updateAnimationsPromises(),t(i),e.timeline._updateAnimationsPromises()})},e.AnimationTimeline=function(){this._animations=[],this.currentTime=void 0},e.AnimationTimeline.prototype={getAnimations:function(){return this._discardAnimations(),this._animations.slice()},_updateAnimationsPromises:function(){e.animationsWithPromises=e.animationsWithPromises.filter(function(t){return t._updatePromises()})},_discardAnimations:function(){this._updateAnimationsPromises(),this._animations=this._animations.filter(function(t){return"finished"!=t.playState&&"idle"!=t.playState})},_play:function(t){var i=new e.Animation(t,this);return this._animations.push(i),e.restartWebAnimationsNextTick(),i._updatePromises(),i._animation.play(),i._updatePromises(),i},play:function(t){return t&&t.remove(),this._play(t)}};var o=!1;e.restartWebAnimationsNextTick=function(){o||(o=!0,requestAnimationFrame(n))};var a=new e.AnimationTimeline;e.timeline=a;try{Object.defineProperty(window.document,"timeline",{configurable:!0,get:function(){return a}})}catch(t){}try{window.document.timeline=a}catch(t){}}(0,r),function(t,e,i){e.animationsWithPromises=[],e.Animation=function(e,i){if(this.id="",e&&e._id&&(this.id=e._id),this.effect=e,e&&(e._animation=this),!i)throw new Error("Animation with null timeline is not supported");this._timeline=i,this._sequenceNumber=t.sequenceNumber++,this._holdTime=0,this._paused=!1,this._isGroup=!1,this._animation=null,this._childAnimations=[],this._callback=null,this._oldPlayState="idle",this._rebuildUnderlyingAnimation(),this._animation.cancel(),this._updatePromises()},e.Animation.prototype={_updatePromises:function(){var t=this._oldPlayState,e=this.playState;return this._readyPromise&&e!==t&&("idle"==e?(this._rejectReadyPromise(),this._readyPromise=void 0):"pending"==t?this._resolveReadyPromise():"pending"==e&&(this._readyPromise=void 0)),this._finishedPromise&&e!==t&&("idle"==e?(this._rejectFinishedPromise(),this._finishedPromise=void 0):"finished"==e?this._resolveFinishedPromise():"finished"==t&&(this._finishedPromise=void 0)),this._oldPlayState=this.playState,this._readyPromise||this._finishedPromise},_rebuildUnderlyingAnimation:function(){this._updatePromises();var t,i,n,r,o=!!this._animation;o&&(t=this.playbackRate,i=this._paused,n=this.startTime,r=this.currentTime,this._animation.cancel(),this._animation._wrapper=null,this._animation=null),(!this.effect||this.effect instanceof window.KeyframeEffect)&&(this._animation=e.newUnderlyingAnimationForKeyframeEffect(this.effect),e.bindAnimationForKeyframeEffect(this)),(this.effect instanceof window.SequenceEffect||this.effect instanceof window.GroupEffect)&&(this._animation=e.newUnderlyingAnimationForGroup(this.effect),e.bindAnimationForGroup(this)),this.effect&&this.effect._onsample&&e.bindAnimationForCustomEffect(this),o&&(1!=t&&(this.playbackRate=t),null!==n?this.startTime=n:null!==r?this.currentTime=r:null!==this._holdTime&&(this.currentTime=this._holdTime),i&&this.pause()),this._updatePromises()},_updateChildren:function(){if(this.effect&&"idle"!=this.playState){var t=this.effect._timing.delay;this._childAnimations.forEach(function(i){this._arrangeChildren(i,t),this.effect instanceof window.SequenceEffect&&(t+=e.groupChildDuration(i.effect))}.bind(this))}},_setExternalAnimation:function(t){if(this.effect&&this._isGroup)for(var e=0;e \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/frontend.html.gz b/homeassistant/components/frontend/www_static/frontend.html.gz index ad2cc4fb8cf0038f3583228f4f1371e0b31af173..d41c459ae9b59c2f9233602083606c4a653c80d6 100644 GIT binary patch delta 27986 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

    @lk)6`u`Uq_30 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 diff --git a/homeassistant/components/frontend/www_static/home-assistant-polymer b/homeassistant/components/frontend/www_static/home-assistant-polymer index 23f0744fe272b..7f6aeaf2a2e8a 160000 --- a/homeassistant/components/frontend/www_static/home-assistant-polymer +++ b/homeassistant/components/frontend/www_static/home-assistant-polymer @@ -1 +1 @@ -Subproject commit 23f0744fe272b6d306dde9592d872c34d53fa6b7 +Subproject commit 7f6aeaf2a2e8a91f59030300fbf47f0b8e3952f1 diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html index ea6e121dcf698..0eb37f1a00d6f 100644 --- a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html +++ b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html @@ -1,4 +1,4 @@ -

    \ No newline at end of file diff --git a/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz b/homeassistant/components/frontend/www_static/panels/ha-panel-shopping-list.html.gz index 76577a763119ab74f445f4ec39294e974c418994..687f39056836d14629c45edd06169259406744f6 100644 GIT binary patch literal 15408 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 a-db5{VlL>5>-r{p^}hifAaDR^=KuhUXDcB9 literal 6144 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 G761SN73}%| literal 2491 zcmV;s2}JfEiwFP!000021EpAPbKAHP{woTn=Ob&1A_=}))nx9{Oq=%ZlF7^DL+Z;c zfQ7__B2^Ny3RqIOVqOL|Q>euQ8 zhy}_IP1)M$+%~A!O*KOAE8euWbrmMTZa^DN9&#xRhW zXTrL4=|k0YX35D4DlFTH#H%qHpO4ct%_12qU!+V4!FZVSLI-j>24GD0vq6Pv|KsRgc36vn)fALIy(mg5@!15z7ysPH5tSsOhplOjx2pt2zK zqnNgv7=2IHuPBT4auBAFqCKMEpgoFEi8xD$ zjFe?k;x@_tp0Kw#UzgAf(m*hk=DDPB1QiE)LirAf9O>`~`XR6`h0giyexAR$XA(8+xXMZ9Dx407U@b$RJ_MdmkH;>>EV$D67% zzGCCCb#Av|o9YKMQ)fTC{e=qRwC`)E{!uvxkCM!yBI#aB zr55dR;GCV=57Xx}?YQ9S`dwF3ZRg$SfWI*KJ*1A$1()opV9IWzB8paTBKZny`&ZTf4WL_JImTKXQ%#)@Gs~4A1ZJo8Hcu z2h-|Z9N1xY)gV=iuDkpv-t1xMf?M@CibEVn)!CVNKyhgtWLM7Joh`hU+7q!jpKXWF ztuxEG_8cowOZ@Qm)r$?;XtU?m%sTc49LE)VE-2bJr10Z{=vfkTP(Jc`p={IL;n2%D zy{XUq={^~>vo(CW^<7&p@mL=W!``}<$~7(4>QzTjxyR5y#y*nPBQo0z2L1((*HY7` zZ9>X9-Lwzi%q-KntD+>$$3D~^^=Zw`5k@_uY>X{+^`HDpr|bVu>iSX_)kal6Cet3p z!~)tyhe03upLb&4a_NN8zOOgbYCAN3C2jjX>45H zU6gjWgVv**RoUC*cltDSc!oO}^P4Co_4ZFq12-PE7EAjPn%)(ZYiv#O*aHx{C?Gcz z3?_m)IC}u!;=k9%_u$?VXp;6@K-pecEm=OM)5W}~totof`?F1T#LixR{ngQnroQfS z)XS!+3AI7PNY&;FBLI^!|53_66{<{5f_d`fwdNAGfrd_DNz$5bqZ_ z>Qu^ybf6cYN7vAf@Y|~Eokm4FB8IoLG0*C$Dmn{}H?|+@cM)Zsx~ar9Ir9 zIZp-l?u{EI1aqBrxYg4)f>yW27=mWwd-r#utSPx4O!ufAnKbSh;5_=yF{^fR?vTDZ z=Ke&9a=_-ALchMYj$M0p9h+NCi7FIy{uKVQX(Oj_e(n&dE9ypox)Gy~vVqACsut_k zH2Kwr@Riri+0K+!Y|JpB_OVm#Y>V9EH@1E{%kDda(A#&$lWw4|J1 Date: Sat, 29 Jul 2017 12:22:38 -0700 Subject: [PATCH 118/118] Persist shopping list + clear completed (#8697) --- homeassistant/components/shopping_list.py | 71 +++++++++++++++++++---- tests/components/test_shopping_list.py | 53 ++++++++++++++++- 2 files changed, 111 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/shopping_list.py b/homeassistant/components/shopping_list.py index 9922960da3ff8..ad9fae67bc64d 100644 --- a/homeassistant/components/shopping_list.py +++ b/homeassistant/components/shopping_list.py @@ -1,6 +1,8 @@ """Component to manage a shoppling list.""" import asyncio +import json import logging +import os import uuid import voluptuous as vol @@ -23,43 +25,55 @@ 'complete': bool, 'name': str, }) +PERSISTENCE = '.shopping_list.json' @asyncio.coroutine def async_setup(hass, config): """Initialize the shopping list.""" - hass.data[DOMAIN] = ShoppingData([]) + data = hass.data[DOMAIN] = ShoppingData(hass) + yield from data.async_load() + intent.async_register(hass, AddItemIntent()) intent.async_register(hass, ListTopItemsIntent()) + hass.http.register_view(ShoppingListView) hass.http.register_view(UpdateShoppingListItemView) + hass.http.register_view(ClearCompletedItemsView) + hass.components.conversation.async_register(INTENT_ADD_ITEM, [ 'Add {item} to my shopping list', ]) hass.components.conversation.async_register(INTENT_LAST_ITEMS, [ 'What is on my shopping list' ]) + hass.components.frontend.register_built_in_panel( 'shopping-list', 'Shopping List', 'mdi:cart') + return True class ShoppingData: """Class to hold shopping list data.""" - def __init__(self, items): + def __init__(self, hass): """Initialize the shopping list.""" - self.items = items + self.hass = hass + self.items = [] - def add(self, name): + @callback + def async_add(self, name): """Add a shopping list item.""" self.items.append({ 'name': name, 'id': uuid.uuid4().hex, 'complete': False }) + self.hass.async_add_job(self.save) - def update(self, item_id, info): + @callback + def async_update(self, item_id, info): """Update a shopping list item.""" item = next((itm for itm in self.items if itm['id'] == item_id), None) @@ -68,11 +82,33 @@ def update(self, item_id, info): info = ITEM_UPDATE_SCHEMA(info) item.update(info) + self.hass.async_add_job(self.save) return item - def clear_completed(self): + @callback + def async_clear_completed(self): """Clear completed items.""" self.items = [itm for itm in self.items if not itm['complete']] + self.hass.async_add_job(self.save) + + @asyncio.coroutine + def async_load(self): + """Load items.""" + def load(): + """Load the items synchronously.""" + path = self.hass.config.path(PERSISTENCE) + if not os.path.isfile(path): + return [] + with open(path) as file: + return json.loads(file.read()) + + items = yield from self.hass.async_add_job(load) + self.items = items + + def save(self): + """Save the items.""" + with open(self.hass.config.path(PERSISTENCE), 'wt') as file: + file.write(json.dumps(self.items, sort_keys=True, indent=4)) class AddItemIntent(intent.IntentHandler): @@ -88,7 +124,7 @@ def async_handle(self, intent_obj): """Handle the intent.""" slots = self.async_validate_slots(intent_obj.slots) item = slots['item']['value'] - intent_obj.hass.data[DOMAIN].add(item) + intent_obj.hass.data[DOMAIN].async_add(item) response = intent_obj.create_response() response.async_set_speech( @@ -137,8 +173,8 @@ def get(self, request): class UpdateShoppingListItemView(http.HomeAssistantView): """View to retrieve shopping list content.""" - url = '/api/shopping_list/{item_id}' - name = "api:shopping_list:id" + url = '/api/shopping_list/item/{item_id}' + name = "api:shopping_list:item:id" @callback def post(self, request, item_id): @@ -146,10 +182,25 @@ def post(self, request, item_id): data = yield from request.json() try: - item = request.app['hass'].data[DOMAIN].update(item_id, data) + item = request.app['hass'].data[DOMAIN].async_update(item_id, data) request.app['hass'].bus.async_fire(EVENT) return self.json(item) except KeyError: return self.json_message('Item not found', HTTP_NOT_FOUND) except vol.Invalid: return self.json_message('Item not found', HTTP_BAD_REQUEST) + + +class ClearCompletedItemsView(http.HomeAssistantView): + """View to retrieve shopping list content.""" + + url = '/api/shopping_list/clear_completed' + name = "api:shopping_list:clear_completed" + + @callback + def post(self, request): + """Retrieve if API is running.""" + hass = request.app['hass'] + hass.data[DOMAIN].async_clear_completed() + hass.bus.async_fire(EVENT) + return self.json_message('Cleared completed items.') diff --git a/tests/components/test_shopping_list.py b/tests/components/test_shopping_list.py index e4a99ad39d4fa..449eab6501656 100644 --- a/tests/components/test_shopping_list.py +++ b/tests/components/test_shopping_list.py @@ -1,10 +1,20 @@ """Test shopping list component.""" import asyncio +from unittest.mock import patch + +import pytest from homeassistant.bootstrap import async_setup_component from homeassistant.helpers import intent +@pytest.fixture(autouse=True) +def mock_shopping_list_save(): + """Stub out the persistence.""" + with patch('homeassistant.components.shopping_list.ShoppingData.save'): + yield + + @asyncio.coroutine def test_add_item(hass): """Test adding an item intent.""" @@ -82,7 +92,7 @@ def test_api_update(hass, test_client): client = yield from test_client(hass.http.app) resp = yield from client.post( - '/api/shopping_list/{}'.format(beer_id), json={ + '/api/shopping_list/item/{}'.format(beer_id), json={ 'name': 'soda' }) @@ -95,7 +105,7 @@ def test_api_update(hass, test_client): } resp = yield from client.post( - '/api/shopping_list/{}'.format(wine_id), json={ + '/api/shopping_list/item/{}'.format(wine_id), json={ 'complete': True }) @@ -140,8 +150,45 @@ def test_api_update_fails(hass, test_client): beer_id = hass.data['shopping_list'].items[0]['id'] client = yield from test_client(hass.http.app) resp = yield from client.post( - '/api/shopping_list/{}'.format(beer_id), json={ + '/api/shopping_list/item/{}'.format(beer_id), json={ 'name': 123, }) assert resp.status == 400 + + +@asyncio.coroutine +def test_api_clear_completed(hass, test_client): + """Test the API.""" + yield from async_setup_component(hass, 'shopping_list', {}) + + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'beer'}} + ) + yield from intent.async_handle( + hass, 'test', 'HassShoppingListAddItem', {'item': {'value': 'wine'}} + ) + + beer_id = hass.data['shopping_list'].items[0]['id'] + wine_id = hass.data['shopping_list'].items[1]['id'] + + client = yield from test_client(hass.http.app) + + # Mark beer as completed + resp = yield from client.post( + '/api/shopping_list/item/{}'.format(beer_id), json={ + 'complete': True + }) + assert resp.status == 200 + + resp = yield from client.post('/api/shopping_list/clear_completed') + assert resp.status == 200 + + items = hass.data['shopping_list'].items + assert len(items) == 1 + + assert items[0] == { + 'id': wine_id, + 'name': 'wine', + 'complete': False + }
  • 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