From 1205eaaa22bece41c9055d7533c7c28f2907c183 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 11 Aug 2018 08:59:46 +0200 Subject: [PATCH 001/159] Version bump to 0.77.0dev0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 1b9dc8986a5..7d99b952ce6 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 = 76 +MINOR_VERSION = 77 PATCH_VERSION = '0.dev0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) From d3fed52254053a24e901cde8528c0e407d429311 Mon Sep 17 00:00:00 2001 From: Thom Troy Date: Sun, 12 Aug 2018 16:48:15 +0100 Subject: [PATCH 002/159] Eph ember support operation modes (#15820) * add operation mode support for climate.EphEmber * fix linting errors from py3.5 * remove STATE_ALL_DAY and cleanup some code based on review * use explicit None return with get * fix none return --- homeassistant/components/climate/ephember.py | 64 ++++++++++++++++++-- requirements_all.txt | 2 +- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/climate/ephember.py b/homeassistant/components/climate/ephember.py index 419237b4645..f8fb3d3d522 100644 --- a/homeassistant/components/climate/ephember.py +++ b/homeassistant/components/climate/ephember.py @@ -9,24 +9,35 @@ from datetime import timedelta import voluptuous as vol from homeassistant.components.climate import ( - ClimateDevice, PLATFORM_SCHEMA, STATE_HEAT, STATE_IDLE, SUPPORT_AUX_HEAT, + ClimateDevice, PLATFORM_SCHEMA, STATE_HEAT, STATE_OFF, + STATE_AUTO, SUPPORT_AUX_HEAT, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE) from homeassistant.const import ( TEMP_CELSIUS, CONF_USERNAME, CONF_PASSWORD, ATTR_TEMPERATURE) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['pyephember==0.1.1'] +REQUIREMENTS = ['pyephember==0.2.0'] _LOGGER = logging.getLogger(__name__) # Return cached results if last scan was less then this time ago SCAN_INTERVAL = timedelta(seconds=120) +OPERATION_LIST = [STATE_AUTO, STATE_HEAT, STATE_OFF] + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string }) +EPH_TO_HA_STATE = { + 'AUTO': STATE_AUTO, + 'ON': STATE_HEAT, + 'OFF': STATE_OFF +} + +HA_STATE_TO_EPH = {value: key for key, value in EPH_TO_HA_STATE.items()} + def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the ephember thermostat.""" @@ -61,9 +72,11 @@ class EphEmberThermostat(ClimateDevice): def supported_features(self): """Return the list of supported features.""" if self._hot_water: - return SUPPORT_AUX_HEAT + return SUPPORT_AUX_HEAT | SUPPORT_OPERATION_MODE - return SUPPORT_TARGET_TEMPERATURE | SUPPORT_AUX_HEAT + return (SUPPORT_TARGET_TEMPERATURE | + SUPPORT_AUX_HEAT | + SUPPORT_OPERATION_MODE) @property def name(self): @@ -93,12 +106,40 @@ class EphEmberThermostat(ClimateDevice): return 1 + @property + def device_state_attributes(self): + """Show Device Attributes.""" + attributes = { + 'currently_active': self._zone['isCurrentlyActive'] + } + return attributes + @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" + mode = self._ember.get_zone_mode(self._zone_name) + return self.map_mode_eph_hass(mode) + + @property + def operation_list(self): + """Return the supported operations.""" + return OPERATION_LIST + + def set_operation_mode(self, operation_mode): + """Set the operation mode.""" + mode = self.map_mode_hass_eph(operation_mode) + if mode is not None: + self._ember.set_mode_by_name(self._zone_name, mode) + else: + _LOGGER.error("Invalid operation mode provided %s", operation_mode) + + @property + def is_on(self): + """Return current state.""" if self._zone['isCurrentlyActive']: - return STATE_HEAT - return STATE_IDLE + return True + + return None @property def is_aux_heat_on(self): @@ -152,3 +193,14 @@ class EphEmberThermostat(ClimateDevice): def update(self): """Get the latest data.""" self._zone = self._ember.get_zone(self._zone_name) + + @staticmethod + def map_mode_hass_eph(operation_mode): + """Map from home assistant mode to eph mode.""" + from pyephember.pyephember import ZoneMode + return getattr(ZoneMode, HA_STATE_TO_EPH.get(operation_mode), None) + + @staticmethod + def map_mode_eph_hass(operation_mode): + """Map from eph mode to home assistant mode.""" + return EPH_TO_HA_STATE.get(operation_mode.name, STATE_AUTO) diff --git a/requirements_all.txt b/requirements_all.txt index 7f4521e3522..47fe286f093 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -835,7 +835,7 @@ pyemby==1.5 pyenvisalink==2.3 # homeassistant.components.climate.ephember -pyephember==0.1.1 +pyephember==0.2.0 # homeassistant.components.sensor.fido pyfido==2.1.1 From e8218c4b292adf9451418af339ba2983d736c453 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sun, 12 Aug 2018 20:22:54 +0200 Subject: [PATCH 003/159] Upgrade pymysensors to 0.17.0 (#15942) --- homeassistant/components/mysensors/__init__.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/mysensors/__init__.py b/homeassistant/components/mysensors/__init__.py index 980efcf5805..e498539f2f9 100644 --- a/homeassistant/components/mysensors/__init__.py +++ b/homeassistant/components/mysensors/__init__.py @@ -22,7 +22,7 @@ from .const import ( from .device import get_mysensors_devices from .gateway import get_mysensors_gateway, setup_gateways, finish_setup -REQUIREMENTS = ['pymysensors==0.16.0'] +REQUIREMENTS = ['pymysensors==0.17.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 47fe286f093..79da92c24e8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -953,7 +953,7 @@ pymusiccast==0.1.6 pymyq==0.0.11 # homeassistant.components.mysensors -pymysensors==0.16.0 +pymysensors==0.17.0 # homeassistant.components.lock.nello pynello==1.5.1 From b7486e5605388ee5b2e63150c79626b713b357cb Mon Sep 17 00:00:00 2001 From: Lev Aronsky Date: Sun, 12 Aug 2018 23:28:47 +0300 Subject: [PATCH 004/159] Fixed race condition in Generic Thermostat (#15784) * Fixed race condition in Generic Thermostat * Added a comment to clarify the meaning of the `time` argument. --- .../components/climate/generic_thermostat.py | 140 ++++++++---------- 1 file changed, 58 insertions(+), 82 deletions(-) diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 3f1d9a208ac..307c96bce32 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -123,6 +123,7 @@ class GenericThermostat(ClimateDevice): self._enabled = True self._active = False self._cur_temp = None + self._temp_lock = asyncio.Lock() self._min_temp = min_temp self._max_temp = max_temp self._target_temp = target_temp @@ -140,7 +141,7 @@ class GenericThermostat(ClimateDevice): if self._keep_alive: async_track_time_interval( - hass, self._async_keep_alive, self._keep_alive) + hass, self._async_control_heating, self._keep_alive) sensor_state = hass.states.get(sensor_entity_id) if sensor_state and sensor_state.state != STATE_UNKNOWN: @@ -234,31 +235,30 @@ class GenericThermostat(ClimateDevice): if operation_mode == STATE_HEAT: self._current_operation = STATE_HEAT self._enabled = True - self._async_control_heating() + await self._async_control_heating() elif operation_mode == STATE_COOL: self._current_operation = STATE_COOL self._enabled = True - self._async_control_heating() + await self._async_control_heating() elif operation_mode == STATE_OFF: self._current_operation = STATE_OFF self._enabled = False if self._is_device_active: - self._heater_turn_off() + await self._async_heater_turn_off() else: _LOGGER.error("Unrecognized operation mode: %s", operation_mode) return # Ensure we update the current operation after changing the mode self.schedule_update_ha_state() - @asyncio.coroutine - def async_set_temperature(self, **kwargs): + async def async_set_temperature(self, **kwargs): """Set new target temperature.""" temperature = kwargs.get(ATTR_TEMPERATURE) if temperature is None: return self._target_temp = temperature - self._async_control_heating() - yield from self.async_update_ha_state() + await self._async_control_heating() + await self.async_update_ha_state() @property def min_temp(self): @@ -278,15 +278,14 @@ class GenericThermostat(ClimateDevice): # Get default temp from super class return super().max_temp - @asyncio.coroutine - def _async_sensor_changed(self, entity_id, old_state, new_state): + async def _async_sensor_changed(self, entity_id, old_state, new_state): """Handle temperature changes.""" if new_state is None: return self._async_update_temp(new_state) - self._async_control_heating() - yield from self.async_update_ha_state() + await self._async_control_heating() + await self.async_update_ha_state() @callback def _async_switch_changed(self, entity_id, old_state, new_state): @@ -295,14 +294,6 @@ class GenericThermostat(ClimateDevice): return self.async_schedule_update_ha_state() - @callback - def _async_keep_alive(self, time): - """Call at constant intervals for keep-alive purposes.""" - if self._is_device_active: - self._heater_turn_on() - else: - self._heater_turn_off() - @callback def _async_update_temp(self, state): """Update thermostat with latest state from sensor.""" @@ -314,62 +305,51 @@ class GenericThermostat(ClimateDevice): except ValueError as ex: _LOGGER.error("Unable to update from sensor: %s", ex) - @callback - def _async_control_heating(self): + async def _async_control_heating(self, time=None): """Check if we need to turn heating on or off.""" - if not self._active and None not in (self._cur_temp, - self._target_temp): - self._active = True - _LOGGER.info("Obtained current and target temperature. " - "Generic thermostat active. %s, %s", - self._cur_temp, self._target_temp) + async with self._temp_lock: + if not self._active and None not in (self._cur_temp, + self._target_temp): + self._active = True + _LOGGER.info("Obtained current and target temperature. " + "Generic thermostat active. %s, %s", + self._cur_temp, self._target_temp) - if not self._active: - return - - if not self._enabled: - return - - if self.min_cycle_duration: - if self._is_device_active: - current_state = STATE_ON - else: - current_state = STATE_OFF - long_enough = condition.state( - self.hass, self.heater_entity_id, current_state, - self.min_cycle_duration) - if not long_enough: + if not self._active or not self._enabled: return - if self.ac_mode: - is_cooling = self._is_device_active - if is_cooling: - too_cold = self._target_temp - self._cur_temp >= \ - self._cold_tolerance - if too_cold: - _LOGGER.info("Turning off AC %s", self.heater_entity_id) - self._heater_turn_off() - else: - too_hot = self._cur_temp - self._target_temp >= \ - self._hot_tolerance - if too_hot: - _LOGGER.info("Turning on AC %s", self.heater_entity_id) - self._heater_turn_on() - else: - is_heating = self._is_device_active - if is_heating: - too_hot = self._cur_temp - self._target_temp >= \ - self._hot_tolerance - if too_hot: + if self.min_cycle_duration: + if self._is_device_active: + current_state = STATE_ON + else: + current_state = STATE_OFF + long_enough = condition.state( + self.hass, self.heater_entity_id, current_state, + self.min_cycle_duration) + if not long_enough: + return + + too_cold = \ + self._target_temp - self._cur_temp >= self._cold_tolerance + too_hot = \ + self._cur_temp - self._target_temp >= self._hot_tolerance + if self._is_device_active: + if (self.ac_mode and too_cold) or \ + (not self.ac_mode and too_hot): _LOGGER.info("Turning off heater %s", self.heater_entity_id) - self._heater_turn_off() + await self._async_heater_turn_off() + elif time is not None: + # The time argument is passed only in keep-alive case + await self._async_heater_turn_on() else: - too_cold = self._target_temp - self._cur_temp >= \ - self._cold_tolerance - if too_cold: + if (self.ac_mode and too_hot) or \ + (not self.ac_mode and too_cold): _LOGGER.info("Turning on heater %s", self.heater_entity_id) - self._heater_turn_on() + await self._async_heater_turn_on() + elif time is not None: + # The time argument is passed only in keep-alive case + await self._async_heater_turn_off() @property def _is_device_active(self): @@ -381,36 +361,32 @@ class GenericThermostat(ClimateDevice): """Return the list of supported features.""" return self._support_flags - @callback - def _heater_turn_on(self): + async def _async_heater_turn_on(self): """Turn heater toggleable device on.""" data = {ATTR_ENTITY_ID: self.heater_entity_id} - self.hass.async_add_job( - self.hass.services.async_call(HA_DOMAIN, SERVICE_TURN_ON, data)) + await self.hass.services.async_call(HA_DOMAIN, SERVICE_TURN_ON, data) - @callback - def _heater_turn_off(self): + async def _async_heater_turn_off(self): """Turn heater toggleable device off.""" data = {ATTR_ENTITY_ID: self.heater_entity_id} - self.hass.async_add_job( - self.hass.services.async_call(HA_DOMAIN, SERVICE_TURN_OFF, data)) + await self.hass.services.async_call(HA_DOMAIN, SERVICE_TURN_OFF, data) @property def is_away_mode_on(self): """Return true if away mode is on.""" return self._is_away - def turn_away_mode_on(self): + async def async_turn_away_mode_on(self): """Turn away mode on by setting it on away hold indefinitely.""" self._is_away = True self._saved_target_temp = self._target_temp self._target_temp = self._away_temp - self._async_control_heating() - self.schedule_update_ha_state() + await self._async_control_heating() + await self.async_update_ha_state() - def turn_away_mode_off(self): + async def async_turn_away_mode_off(self): """Turn away off.""" self._is_away = False self._target_temp = self._saved_target_temp - self._async_control_heating() - self.schedule_update_ha_state() + await self._async_control_heating() + await self.async_update_ha_state() From 31fbfed0a6e1c8fbae0cd3b0ec60aefd59461bb5 Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Mon, 13 Aug 2018 08:17:15 +0200 Subject: [PATCH 005/159] Fix magic cube support of the Aqara LAN Protocol V2 (#15940) --- homeassistant/components/binary_sensor/xiaomi_aqara.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/homeassistant/components/binary_sensor/xiaomi_aqara.py b/homeassistant/components/binary_sensor/xiaomi_aqara.py index 2a9746b4a01..f53d07f2995 100644 --- a/homeassistant/components/binary_sensor/xiaomi_aqara.py +++ b/homeassistant/components/binary_sensor/xiaomi_aqara.py @@ -378,6 +378,13 @@ class XiaomiCube(XiaomiBinarySensor): }) self._last_action = data['status'] + if 'cube_status' in data: + self._hass.bus.fire('cube_action', { + 'entity_id': self.entity_id, + 'action_type': data['cube_status'] + }) + self._last_action = data['cube_status'] + if 'rotate' in data: self._hass.bus.fire('cube_action', { 'entity_id': self.entity_id, From 272be7cdaed912d7eb71bd1770a8b29a95727e44 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 13 Aug 2018 00:26:20 -0700 Subject: [PATCH 006/159] Remove remote.API from core.Config (#15951) * Use core.ApiConfig replace remote.API in core.Config * Move ApiConfig to http --- homeassistant/components/http/__init__.py | 28 ++++++++++++-- homeassistant/core.py | 4 +- tests/components/http/test_init.py | 45 +++++++++++++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index 9f1b5995839..c1d80667983 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -8,6 +8,7 @@ from ipaddress import ip_network import logging import os import ssl +from typing import Optional from aiohttp import web from aiohttp.web_exceptions import HTTPMovedPermanently @@ -16,7 +17,6 @@ import voluptuous as vol from homeassistant.const import ( EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, SERVER_PORT) import homeassistant.helpers.config_validation as cv -import homeassistant.remote as rem import homeassistant.util as hass_util from homeassistant.util.logging import HideSensitiveDataFilter from homeassistant.util import ssl as ssl_util @@ -82,6 +82,28 @@ CONFIG_SCHEMA = vol.Schema({ }, extra=vol.ALLOW_EXTRA) +class ApiConfig: + """Configuration settings for API server.""" + + def __init__(self, host: str, port: Optional[int] = SERVER_PORT, + use_ssl: bool = False, + api_password: Optional[str] = None) -> None: + """Initialize a new API config object.""" + self.host = host + self.port = port + self.api_password = api_password + + if host.startswith(("http://", "https://")): + self.base_url = host + elif use_ssl: + self.base_url = "https://{}".format(host) + else: + self.base_url = "http://{}".format(host) + + if port is not None: + self.base_url += ':{}'.format(port) + + async def async_setup(hass, config): """Set up the HTTP API and debug interface.""" conf = config.get(DOMAIN) @@ -146,8 +168,8 @@ async def async_setup(hass, config): host = hass_util.get_local_ip() port = server_port - hass.config.api = rem.API(host, api_password, port, - ssl_certificate is not None) + hass.config.api = ApiConfig(host, port, ssl_certificate is not None, + api_password) return True diff --git a/homeassistant/core.py b/homeassistant/core.py index cc027c6f5d0..2b7a2479471 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -1145,8 +1145,8 @@ class Config: # List of loaded components self.components = set() # type: set - # Remote.API object pointing at local API - self.api = None + # API (HTTP) server configuration + self.api = None # type: Optional[Any] # Directory that holds the configuration self.config_dir = None # type: Optional[str] diff --git a/tests/components/http/test_init.py b/tests/components/http/test_init.py index 2ffaf17bebc..c52f60a5f1b 100644 --- a/tests/components/http/test_init.py +++ b/tests/components/http/test_init.py @@ -1,5 +1,6 @@ """The tests for the Home Assistant HTTP component.""" import logging +import unittest from homeassistant.setup import async_setup_component @@ -33,6 +34,50 @@ async def test_registering_view_while_running(hass, aiohttp_client, hass.http.register_view(TestView) +class TestApiConfig(unittest.TestCase): + """Test API configuration methods.""" + + def test_api_base_url_with_domain(hass): + """Test setting API URL with domain.""" + api_config = http.ApiConfig('example.com') + assert api_config.base_url == 'http://example.com:8123' + + def test_api_base_url_with_ip(hass): + """Test setting API URL with IP.""" + api_config = http.ApiConfig('1.1.1.1') + assert api_config.base_url == 'http://1.1.1.1:8123' + + def test_api_base_url_with_ip_and_port(hass): + """Test setting API URL with IP and port.""" + api_config = http.ApiConfig('1.1.1.1', 8124) + assert api_config.base_url == 'http://1.1.1.1:8124' + + def test_api_base_url_with_protocol(hass): + """Test setting API URL with protocol.""" + api_config = http.ApiConfig('https://example.com') + assert api_config.base_url == 'https://example.com:8123' + + def test_api_base_url_with_protocol_and_port(hass): + """Test setting API URL with protocol and port.""" + api_config = http.ApiConfig('https://example.com', 433) + assert api_config.base_url == 'https://example.com:433' + + def test_api_base_url_with_ssl_enable(hass): + """Test setting API URL with use_ssl enabled.""" + api_config = http.ApiConfig('example.com', use_ssl=True) + assert api_config.base_url == 'https://example.com:8123' + + def test_api_base_url_with_ssl_enable_and_port(hass): + """Test setting API URL with use_ssl enabled and port.""" + api_config = http.ApiConfig('1.1.1.1', use_ssl=True, port=8888) + assert api_config.base_url == 'https://1.1.1.1:8888' + + def test_api_base_url_with_protocol_and_ssl_enable(hass): + """Test setting API URL with specific protocol and use_ssl enabled.""" + api_config = http.ApiConfig('http://example.com', use_ssl=True) + assert api_config.base_url == 'http://example.com:8123' + + async def test_api_base_url_with_domain(hass): """Test setting API URL.""" result = await async_setup_component(hass, 'http', { From 23427098039a44d11c45e082c17f52e37594db33 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 13 Aug 2018 10:52:47 +0200 Subject: [PATCH 007/159] Upgrade beautifulsoup4 to 4.6.3 (#15946) --- homeassistant/components/device_tracker/linksys_ap.py | 2 +- homeassistant/components/sensor/geizhals.py | 9 +++++---- homeassistant/components/sensor/scrape.py | 4 ++-- homeassistant/components/sensor/sytadin.py | 2 +- requirements_all.txt | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/device_tracker/linksys_ap.py b/homeassistant/components/device_tracker/linksys_ap.py index a2a371163fd..5fa33583567 100644 --- a/homeassistant/components/device_tracker/linksys_ap.py +++ b/homeassistant/components/device_tracker/linksys_ap.py @@ -19,7 +19,7 @@ from homeassistant.const import ( INTERFACES = 2 DEFAULT_TIMEOUT = 10 -REQUIREMENTS = ['beautifulsoup4==4.6.1'] +REQUIREMENTS = ['beautifulsoup4==4.6.3'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/geizhals.py b/homeassistant/components/sensor/geizhals.py index 06062b26b00..0458c2022af 100644 --- a/homeassistant/components/sensor/geizhals.py +++ b/homeassistant/components/sensor/geizhals.py @@ -15,14 +15,16 @@ from homeassistant.util import Throttle from homeassistant.helpers.entity import Entity from homeassistant.const import (CONF_DOMAIN, CONF_NAME) -REQUIREMENTS = ['beautifulsoup4==4.6.1'] +REQUIREMENTS = ['beautifulsoup4==4.6.3'] + _LOGGER = logging.getLogger(__name__) -CONF_PRODUCT_ID = 'product_id' CONF_DESCRIPTION = 'description' +CONF_PRODUCT_ID = 'product_id' CONF_REGEX = 'regex' ICON = 'mdi:coin' + MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=120) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @@ -54,8 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class Geizwatch(Entity): """Implementation of Geizwatch.""" - def __init__(self, name, description, product_id, domain, - regex): + def __init__(self, name, description, product_id, domain, regex): """Initialize the sensor.""" self._name = name self.description = description diff --git a/homeassistant/components/sensor/scrape.py b/homeassistant/components/sensor/scrape.py index e7aace8ec6d..0b57528c519 100644 --- a/homeassistant/components/sensor/scrape.py +++ b/homeassistant/components/sensor/scrape.py @@ -19,12 +19,12 @@ from homeassistant.const import ( from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['beautifulsoup4==4.6.1'] +REQUIREMENTS = ['beautifulsoup4==4.6.3'] _LOGGER = logging.getLogger(__name__) -CONF_SELECT = 'select' CONF_ATTR = 'attribute' +CONF_SELECT = 'select' DEFAULT_NAME = 'Web scrape' DEFAULT_VERIFY_SSL = True diff --git a/homeassistant/components/sensor/sytadin.py b/homeassistant/components/sensor/sytadin.py index ff8e7d7ddfe..4aeb0cca32f 100644 --- a/homeassistant/components/sensor/sytadin.py +++ b/homeassistant/components/sensor/sytadin.py @@ -18,7 +18,7 @@ from homeassistant.const import ( from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle -REQUIREMENTS = ['beautifulsoup4==4.6.1'] +REQUIREMENTS = ['beautifulsoup4==4.6.3'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 79da92c24e8..7bef70ed377 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -163,7 +163,7 @@ batinfo==0.4.2 # homeassistant.components.sensor.geizhals # homeassistant.components.sensor.scrape # homeassistant.components.sensor.sytadin -beautifulsoup4==4.6.1 +beautifulsoup4==4.6.3 # homeassistant.components.zha bellows==0.6.0 From 6aee535d7c0b4b0490dc7537fe60d1a79edff997 Mon Sep 17 00:00:00 2001 From: "Hovo (Luke)" Date: Mon, 13 Aug 2018 19:23:27 +1000 Subject: [PATCH 008/159] Allow wait template to run the remainder of the script (#15836) * Adding new feature to allow a wait template to run the remainer of the script on timeout * Styling changes * Fixing file permissions, adding test for new code * changed variable name, refactored script to pass information into async_set_timeout * Changing the default behaviour to continue to run the script after timeout --- homeassistant/helpers/config_validation.py | 1 + homeassistant/helpers/script.py | 20 ++++-- tests/helpers/test_script.py | 82 +++++++++++++++++++++- 3 files changed, 94 insertions(+), 9 deletions(-) diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 056d45ad656..26de41387f5 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -613,6 +613,7 @@ _SCRIPT_WAIT_TEMPLATE_SCHEMA = vol.Schema({ vol.Optional(CONF_ALIAS): string, vol.Required("wait_template"): template, vol.Optional(CONF_TIMEOUT): vol.All(time_period, positive_timedelta), + vol.Optional("continue_on_timeout"): boolean, }) SCRIPT_SCHEMA = vol.All( diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index a139be4b260..acaeb545815 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -30,6 +30,7 @@ CONF_EVENT_DATA = 'event_data' CONF_EVENT_DATA_TEMPLATE = 'event_data_template' CONF_DELAY = 'delay' CONF_WAIT_TEMPLATE = 'wait_template' +CONF_CONTINUE = 'continue_on_timeout' def call_from_config(hass: HomeAssistant, config: ConfigType, @@ -143,7 +144,8 @@ class Script(): self.hass.async_add_job(self._change_listener) if CONF_TIMEOUT in action: - self._async_set_timeout(action, variables) + self._async_set_timeout( + action, variables, action.get(CONF_CONTINUE, True)) return @@ -214,17 +216,23 @@ class Script(): self._log("Test condition {}: {}".format(self.last_action, check)) return check - def _async_set_timeout(self, action, variables): - """Schedule a timeout to abort script.""" + def _async_set_timeout(self, action, variables, continue_on_timeout=True): + """Schedule a timeout to abort or continue script.""" timeout = action[CONF_TIMEOUT] unsub = None @callback def async_script_timeout(now): - """Call after timeout is retrieve stop script.""" + """Call after timeout is retrieve.""" self._async_listener.remove(unsub) - self._log("Timeout reached, abort script.") - self.async_stop() + + # Check if we want to continue to execute + # the script after the timeout + if continue_on_timeout: + self.hass.async_add_job(self.async_run(variables)) + else: + self._log("Timeout reached, abort script.") + self.async_stop() unsub = async_track_point_in_utc_time( self.hass, async_script_timeout, diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index 4297ca26e7d..7e60cc796cc 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -375,8 +375,84 @@ class TestScriptHelper(unittest.TestCase): assert script_obj.can_cancel assert len(events) == 2 - def test_wait_template_timeout(self): - """Test the wait template.""" + def test_wait_template_timeout_halt(self): + """Test the wait template, halt on timeout.""" + event = 'test_event' + events = [] + + @callback + def record_event(event): + """Add recorded event to set.""" + events.append(event) + + self.hass.bus.listen(event, record_event) + + self.hass.states.set('switch.test', 'on') + + script_obj = script.Script(self.hass, cv.SCRIPT_SCHEMA([ + {'event': event}, + { + 'wait_template': "{{states.switch.test.state == 'off'}}", + 'continue_on_timeout': False, + 'timeout': 5 + }, + {'event': event}])) + + script_obj.run() + self.hass.block_till_done() + + assert script_obj.is_running + assert script_obj.can_cancel + assert script_obj.last_action == event + assert len(events) == 1 + + future = dt_util.utcnow() + timedelta(seconds=5) + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + assert not script_obj.is_running + assert len(events) == 1 + + def test_wait_template_timeout_continue(self): + """Test the wait template with continuing the script.""" + event = 'test_event' + events = [] + + @callback + def record_event(event): + """Add recorded event to set.""" + events.append(event) + + self.hass.bus.listen(event, record_event) + + self.hass.states.set('switch.test', 'on') + + script_obj = script.Script(self.hass, cv.SCRIPT_SCHEMA([ + {'event': event}, + { + 'wait_template': "{{states.switch.test.state == 'off'}}", + 'timeout': 5, + 'continue_on_timeout': True + }, + {'event': event}])) + + script_obj.run() + self.hass.block_till_done() + + assert script_obj.is_running + assert script_obj.can_cancel + assert script_obj.last_action == event + assert len(events) == 1 + + future = dt_util.utcnow() + timedelta(seconds=5) + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + assert not script_obj.is_running + assert len(events) == 2 + + def test_wait_template_timeout_default(self): + """Test the wait template with default contiune.""" event = 'test_event' events = [] @@ -410,7 +486,7 @@ class TestScriptHelper(unittest.TestCase): self.hass.block_till_done() assert not script_obj.is_running - assert len(events) == 1 + assert len(events) == 2 def test_wait_template_variables(self): """Test the wait template with variables.""" From 45f12dd3c79a4657dfa1b8f908ec40653be32d9d Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 13 Aug 2018 02:26:06 -0700 Subject: [PATCH 009/159] MQTT embedded broker has to set its own password. (#15929) --- homeassistant/components/mqtt/__init__.py | 16 +++++- homeassistant/components/mqtt/server.py | 26 ++++----- tests/components/mqtt/test_server.py | 65 +++++++++++++++++++---- 3 files changed, 82 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 3928eb945aa..70d4d7aa5d7 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -32,7 +32,8 @@ from homeassistant.util.async_ import ( from homeassistant.const import ( EVENT_HOMEASSISTANT_STOP, CONF_VALUE_TEMPLATE, CONF_USERNAME, CONF_PASSWORD, CONF_PORT, CONF_PROTOCOL, CONF_PAYLOAD) -from homeassistant.components.mqtt.server import HBMQTT_CONFIG_SCHEMA + +from .server import HBMQTT_CONFIG_SCHEMA REQUIREMENTS = ['paho-mqtt==1.3.1'] @@ -306,7 +307,8 @@ async def _async_setup_server(hass: HomeAssistantType, return None success, broker_config = \ - await server.async_start(hass, conf.get(CONF_EMBEDDED)) + await server.async_start( + hass, conf.get(CONF_PASSWORD), conf.get(CONF_EMBEDDED)) if not success: return None @@ -349,6 +351,16 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: if CONF_EMBEDDED not in conf and CONF_BROKER in conf: broker_config = None else: + if (conf.get(CONF_PASSWORD) is None and + config.get('http') is not None and + config['http'].get('api_password') is not None): + _LOGGER.error("Starting from 0.77, embedded MQTT broker doesn't" + " use api_password as default password any more." + " Please set password configuration. See https://" + "home-assistant.io/docs/mqtt/broker#embedded-broker" + " for details") + return False + broker_config = await _async_setup_server(hass, config) if CONF_BROKER in conf: diff --git a/homeassistant/components/mqtt/server.py b/homeassistant/components/mqtt/server.py index 8a012928792..5fc365342ae 100644 --- a/homeassistant/components/mqtt/server.py +++ b/homeassistant/components/mqtt/server.py @@ -27,27 +27,29 @@ HBMQTT_CONFIG_SCHEMA = vol.Any(None, vol.Schema({ }) }, extra=vol.ALLOW_EXTRA)) +_LOGGER = logging.getLogger(__name__) + @asyncio.coroutine -def async_start(hass, server_config): +def async_start(hass, password, server_config): """Initialize MQTT Server. This method is a coroutine. """ from hbmqtt.broker import Broker, BrokerException + passwd = tempfile.NamedTemporaryFile() try: - passwd = tempfile.NamedTemporaryFile() - if server_config is None: - server_config, client_config = generate_config(hass, passwd) + server_config, client_config = generate_config( + hass, passwd, password) else: client_config = None broker = Broker(server_config, hass.loop) yield from broker.start() except BrokerException: - logging.getLogger(__name__).exception("Error initializing MQTT server") + _LOGGER.exception("Error initializing MQTT server") return False, None finally: passwd.close() @@ -63,9 +65,10 @@ def async_start(hass, server_config): return True, client_config -def generate_config(hass, passwd): +def generate_config(hass, passwd, password): """Generate a configuration based on current Home Assistant instance.""" - from homeassistant.components.mqtt import PROTOCOL_311 + from . import PROTOCOL_311 + config = { 'listeners': { 'default': { @@ -79,29 +82,26 @@ def generate_config(hass, passwd): }, }, 'auth': { - 'allow-anonymous': hass.config.api.api_password is None + 'allow-anonymous': password is None }, 'plugins': ['auth_anonymous'], } - if hass.config.api.api_password: + if password: username = 'homeassistant' - password = hass.config.api.api_password # Encrypt with what hbmqtt uses to verify from passlib.apps import custom_app_context passwd.write( 'homeassistant:{}\n'.format( - custom_app_context.encrypt( - hass.config.api.api_password)).encode('utf-8')) + custom_app_context.encrypt(password)).encode('utf-8')) passwd.flush() config['auth']['password-file'] = passwd.name config['plugins'].append('auth_file') else: username = None - password = None client_config = ('localhost', 1883, username, password, None, PROTOCOL_311) diff --git a/tests/components/mqtt/test_server.py b/tests/components/mqtt/test_server.py index 1c37c9049f3..d5d54f457d6 100644 --- a/tests/components/mqtt/test_server.py +++ b/tests/components/mqtt/test_server.py @@ -4,6 +4,7 @@ import sys import pytest +from homeassistant.const import CONF_PASSWORD from homeassistant.setup import setup_component import homeassistant.components.mqtt as mqtt @@ -19,9 +20,6 @@ class TestMQTT: def setup_method(self, method): """Setup things to be run when tests are started.""" self.hass = get_test_home_assistant() - setup_component(self.hass, 'http', { - 'api_password': 'super_secret' - }) def teardown_method(self, method): """Stop everything that was started.""" @@ -32,14 +30,36 @@ class TestMQTT: @patch('hbmqtt.broker.Broker', Mock(return_value=MagicMock())) @patch('hbmqtt.broker.Broker.start', Mock(return_value=mock_coro())) @patch('homeassistant.components.mqtt.MQTT') - def test_creating_config_with_http_pass(self, mock_mqtt): - """Test if the MQTT server gets started and subscribe/publish msg.""" + def test_creating_config_with_http_pass_only(self, mock_mqtt): + """Test if the MQTT server failed starts. + + Since 0.77, MQTT server has to setup its own password. + If user has api_password but don't have mqtt.password, MQTT component + will fail to start + """ mock_mqtt().async_connect.return_value = mock_coro(True) self.hass.bus.listen_once = MagicMock() - password = 'super_secret' + assert not setup_component(self.hass, mqtt.DOMAIN, { + 'http': {'api_password': 'http_secret'} + }) - self.hass.config.api = MagicMock(api_password=password) - assert setup_component(self.hass, mqtt.DOMAIN, {}) + @patch('passlib.apps.custom_app_context', Mock(return_value='')) + @patch('tempfile.NamedTemporaryFile', Mock(return_value=MagicMock())) + @patch('hbmqtt.broker.Broker', Mock(return_value=MagicMock())) + @patch('hbmqtt.broker.Broker.start', Mock(return_value=mock_coro())) + @patch('homeassistant.components.mqtt.MQTT') + def test_creating_config_with_pass_and_no_http_pass(self, mock_mqtt): + """Test if the MQTT server gets started with password. + + Since 0.77, MQTT server has to setup its own password. + """ + mock_mqtt().async_connect.return_value = mock_coro(True) + self.hass.bus.listen_once = MagicMock() + password = 'mqtt_secret' + + assert setup_component(self.hass, mqtt.DOMAIN, { + mqtt.DOMAIN: {CONF_PASSWORD: password}, + }) assert mock_mqtt.called from pprint import pprint pprint(mock_mqtt.mock_calls) @@ -51,8 +71,33 @@ class TestMQTT: @patch('hbmqtt.broker.Broker', Mock(return_value=MagicMock())) @patch('hbmqtt.broker.Broker.start', Mock(return_value=mock_coro())) @patch('homeassistant.components.mqtt.MQTT') - def test_creating_config_with_http_no_pass(self, mock_mqtt): - """Test if the MQTT server gets started and subscribe/publish msg.""" + def test_creating_config_with_pass_and_http_pass(self, mock_mqtt): + """Test if the MQTT server gets started with password. + + Since 0.77, MQTT server has to setup its own password. + """ + mock_mqtt().async_connect.return_value = mock_coro(True) + self.hass.bus.listen_once = MagicMock() + password = 'mqtt_secret' + + self.hass.config.api = MagicMock(api_password='api_password') + assert setup_component(self.hass, mqtt.DOMAIN, { + 'http': {'api_password': 'http_secret'}, + mqtt.DOMAIN: {CONF_PASSWORD: password}, + }) + assert mock_mqtt.called + from pprint import pprint + pprint(mock_mqtt.mock_calls) + assert mock_mqtt.mock_calls[1][1][5] == 'homeassistant' + assert mock_mqtt.mock_calls[1][1][6] == password + + @patch('passlib.apps.custom_app_context', Mock(return_value='')) + @patch('tempfile.NamedTemporaryFile', Mock(return_value=MagicMock())) + @patch('hbmqtt.broker.Broker', Mock(return_value=MagicMock())) + @patch('hbmqtt.broker.Broker.start', Mock(return_value=mock_coro())) + @patch('homeassistant.components.mqtt.MQTT') + def test_creating_config_without_pass(self, mock_mqtt): + """Test if the MQTT server gets started without password.""" mock_mqtt().async_connect.return_value = mock_coro(True) self.hass.bus.listen_once = MagicMock() From 50daef9a52f323a15d92b97b16b661dee794728c Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 13 Aug 2018 02:27:18 -0700 Subject: [PATCH 010/159] Add context to login flow (#15914) * Add context to login flow * source -> context * Fix unit test * Update comment --- homeassistant/auth/__init__.py | 4 ++-- homeassistant/auth/providers/__init__.py | 2 +- homeassistant/auth/providers/homeassistant.py | 2 +- .../auth/providers/insecure_example.py | 2 +- .../auth/providers/legacy_api_password.py | 2 +- homeassistant/components/auth/login_flow.py | 3 +-- .../components/config/config_entries.py | 2 +- homeassistant/config_entries.py | 17 +++++------------ homeassistant/data_entry_flow.py | 8 ++++---- tests/components/cast/test_init.py | 5 +++-- tests/components/config/test_config_entries.py | 4 +--- tests/components/sonos/test_init.py | 5 +++-- tests/helpers/test_config_entry_flow.py | 3 ++- tests/test_config_entries.py | 9 ++++++--- tests/test_data_entry_flow.py | 6 ++++-- 15 files changed, 36 insertions(+), 38 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 8eaa9cdbb97..9695e77f6f1 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -215,9 +215,9 @@ class AuthManager: """Create a login flow.""" auth_provider = self._providers[handler] - return await auth_provider.async_credential_flow() + return await auth_provider.async_credential_flow(context) - async def _async_finish_login_flow(self, result): + async def _async_finish_login_flow(self, context, result): """Result of a credential login flow.""" if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: return None diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index 68cc1c7edd2..ac5b6107b8a 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -123,7 +123,7 @@ class AuthProvider: # Implement by extending class - async def async_credential_flow(self): + async def async_credential_flow(self, context): """Return the data flow for logging in with auth provider.""" raise NotImplementedError diff --git a/homeassistant/auth/providers/homeassistant.py b/homeassistant/auth/providers/homeassistant.py index e9693b09634..5a2355264ab 100644 --- a/homeassistant/auth/providers/homeassistant.py +++ b/homeassistant/auth/providers/homeassistant.py @@ -158,7 +158,7 @@ class HassAuthProvider(AuthProvider): self.data = Data(self.hass) await self.data.async_load() - async def async_credential_flow(self): + async def async_credential_flow(self, context): """Return a flow to login.""" return LoginFlow(self) diff --git a/homeassistant/auth/providers/insecure_example.py b/homeassistant/auth/providers/insecure_example.py index c86c8eb71f1..96f824140ed 100644 --- a/homeassistant/auth/providers/insecure_example.py +++ b/homeassistant/auth/providers/insecure_example.py @@ -31,7 +31,7 @@ class InvalidAuthError(HomeAssistantError): class ExampleAuthProvider(AuthProvider): """Example auth provider based on hardcoded usernames and passwords.""" - async def async_credential_flow(self): + async def async_credential_flow(self, context): """Return a flow to login.""" return LoginFlow(self) diff --git a/homeassistant/auth/providers/legacy_api_password.py b/homeassistant/auth/providers/legacy_api_password.py index 1f92fb60f13..f2f467e07ec 100644 --- a/homeassistant/auth/providers/legacy_api_password.py +++ b/homeassistant/auth/providers/legacy_api_password.py @@ -36,7 +36,7 @@ class LegacyApiPasswordAuthProvider(AuthProvider): DEFAULT_TITLE = 'Legacy API Password' - async def async_credential_flow(self): + async def async_credential_flow(self, context): """Return a flow to login.""" return LoginFlow(self) diff --git a/homeassistant/components/auth/login_flow.py b/homeassistant/components/auth/login_flow.py index 8b983b6d19f..7b80e52a8d7 100644 --- a/homeassistant/components/auth/login_flow.py +++ b/homeassistant/components/auth/login_flow.py @@ -54,7 +54,6 @@ have type "create_entry" and "result" key will contain an authorization code. "flow_id": "8f7e42faab604bcab7ac43c44ca34d58", "handler": ["insecure_example", null], "result": "411ee2f916e648d691e937ae9344681e", - "source": "user", "title": "Example", "type": "create_entry", "version": 1 @@ -152,7 +151,7 @@ class LoginFlowIndexView(HomeAssistantView): handler = data['handler'] try: - result = await self._flow_mgr.async_init(handler) + result = await self._flow_mgr.async_init(handler, context={}) except data_entry_flow.UnknownHandler: return self.json_message('Invalid handler specified', 404) except data_entry_flow.UnknownStep: diff --git a/homeassistant/components/config/config_entries.py b/homeassistant/components/config/config_entries.py index 57fdbd31d20..04d2c713cdc 100644 --- a/homeassistant/components/config/config_entries.py +++ b/homeassistant/components/config/config_entries.py @@ -96,7 +96,7 @@ class ConfigManagerFlowIndexView(FlowManagerIndexView): return self.json([ flw for flw in hass.config_entries.flow.async_progress() - if flw['source'] != config_entries.SOURCE_USER]) + if flw['context']['source'] != config_entries.SOURCE_USER]) class ConfigManagerFlowResourceView(FlowManagerResourceView): diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 51114a2a416..b2e8389e449 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -372,10 +372,10 @@ class ConfigEntries: return await entry.async_unload( self.hass, component=getattr(self.hass.components, component)) - async def _async_finish_flow(self, result): + async def _async_finish_flow(self, context, result): """Finish a config flow and add an entry.""" # If no discovery config entries in progress, remove notification. - if not any(ent['source'] in DISCOVERY_SOURCES for ent + if not any(ent['context']['source'] in DISCOVERY_SOURCES for ent in self.hass.config_entries.flow.async_progress()): self.hass.components.persistent_notification.async_dismiss( DISCOVERY_NOTIFICATION_ID) @@ -383,15 +383,12 @@ class ConfigEntries: if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: return None - source = result['source'] - if source is None: - source = SOURCE_USER entry = ConfigEntry( version=result['version'], domain=result['handler'], title=result['title'], data=result['data'], - source=source, + source=context['source'], ) self._entries.append(entry) await self._async_schedule_save() @@ -406,7 +403,7 @@ class ConfigEntries: self.hass, entry.domain, self._hass_config) # Return Entry if they not from a discovery request - if result['source'] not in DISCOVERY_SOURCES: + if context['source'] not in DISCOVERY_SOURCES: return entry return entry @@ -422,10 +419,7 @@ class ConfigEntries: if handler is None: raise data_entry_flow.UnknownHandler - if context is not None: - source = context.get('source', SOURCE_USER) - else: - source = SOURCE_USER + source = context['source'] # Make sure requirements and dependencies of component are resolved await async_process_deps_reqs( @@ -442,7 +436,6 @@ class ConfigEntries: ) flow = handler() - flow.source = source flow.init_step = source return flow diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index 7609ffa615a..f820911e396 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -46,7 +46,7 @@ class FlowManager: return [{ 'flow_id': flow.flow_id, 'handler': flow.handler, - 'source': flow.source, + 'context': flow.context, } for flow in self._progress.values()] async def async_init(self, handler: Hashable, *, context: Dict = None, @@ -57,6 +57,7 @@ class FlowManager: flow.hass = self.hass flow.handler = handler flow.flow_id = uuid.uuid4().hex + flow.context = context self._progress[flow.flow_id] = flow return await self._async_handle_step(flow, flow.init_step, data) @@ -108,7 +109,7 @@ class FlowManager: self._progress.pop(flow.flow_id) # We pass a copy of the result because we're mutating our version - entry = await self._async_finish_flow(dict(result)) + entry = await self._async_finish_flow(flow.context, dict(result)) if result['type'] == RESULT_TYPE_CREATE_ENTRY: result['result'] = entry @@ -122,8 +123,8 @@ class FlowHandler: flow_id = None hass = None handler = None - source = None cur_step = None + context = None # Set by _async_create_flow callback init_step = 'init' @@ -156,7 +157,6 @@ class FlowHandler: 'handler': self.handler, 'title': title, 'data': data, - 'source': self.source, } @callback diff --git a/tests/components/cast/test_init.py b/tests/components/cast/test_init.py index 3ed9ea7b88e..1ffbd375b75 100644 --- a/tests/components/cast/test_init.py +++ b/tests/components/cast/test_init.py @@ -1,7 +1,7 @@ """Tests for the Cast config flow.""" from unittest.mock import patch -from homeassistant import data_entry_flow +from homeassistant import config_entries, data_entry_flow from homeassistant.setup import async_setup_component from homeassistant.components import cast @@ -15,7 +15,8 @@ async def test_creating_entry_sets_up_media_player(hass): MockDependency('pychromecast', 'discovery'), \ patch('pychromecast.discovery.discover_chromecasts', return_value=True): - result = await hass.config_entries.flow.async_init(cast.DOMAIN) + result = await hass.config_entries.flow.async_init( + cast.DOMAIN, context={'source': config_entries.SOURCE_USER}) assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY await hass.async_block_till_done() diff --git a/tests/components/config/test_config_entries.py b/tests/components/config/test_config_entries.py index f85d7df1a86..ba053050f99 100644 --- a/tests/components/config/test_config_entries.py +++ b/tests/components/config/test_config_entries.py @@ -202,7 +202,6 @@ def test_create_account(hass, client): 'handler': 'test', 'title': 'Test Entry', 'type': 'create_entry', - 'source': 'user', 'version': 1, } @@ -264,7 +263,6 @@ def test_two_step_flow(hass, client): 'type': 'create_entry', 'title': 'user-title', 'version': 1, - 'source': 'user', } @@ -295,7 +293,7 @@ def test_get_progress_index(hass, client): { 'flow_id': form['flow_id'], 'handler': 'test', - 'source': 'hassio' + 'context': {'source': 'hassio'} } ] diff --git a/tests/components/sonos/test_init.py b/tests/components/sonos/test_init.py index 9fe22fc7e79..ab4eed31fee 100644 --- a/tests/components/sonos/test_init.py +++ b/tests/components/sonos/test_init.py @@ -1,7 +1,7 @@ """Tests for the Sonos config flow.""" from unittest.mock import patch -from homeassistant import data_entry_flow +from homeassistant import config_entries, data_entry_flow from homeassistant.setup import async_setup_component from homeassistant.components import sonos @@ -13,7 +13,8 @@ async def test_creating_entry_sets_up_media_player(hass): with patch('homeassistant.components.media_player.sonos.async_setup_entry', return_value=mock_coro(True)) as mock_setup, \ patch('soco.discover', return_value=True): - result = await hass.config_entries.flow.async_init(sonos.DOMAIN) + result = await hass.config_entries.flow.async_init( + sonos.DOMAIN, context={'source': config_entries.SOURCE_USER}) assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY await hass.async_block_till_done() diff --git a/tests/helpers/test_config_entry_flow.py b/tests/helpers/test_config_entry_flow.py index 46c58320d50..9eede7dff9b 100644 --- a/tests/helpers/test_config_entry_flow.py +++ b/tests/helpers/test_config_entry_flow.py @@ -109,7 +109,8 @@ async def test_user_init_trumps_discovery(hass, flow_conf): assert result['type'] == data_entry_flow.RESULT_TYPE_FORM # User starts flow - result = await hass.config_entries.flow.async_init('test', data={}) + result = await hass.config_entries.flow.async_init( + 'test', context={'source': config_entries.SOURCE_USER}, data={}) assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY # Discovery flow has been aborted diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index 8ac4c642b0a..1f6fd8756e6 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -116,7 +116,8 @@ def test_add_entry_calls_setup_entry(hass, manager): }) with patch.dict(config_entries.HANDLERS, {'comp': TestFlow, 'beer': 5}): - yield from manager.flow.async_init('comp') + yield from manager.flow.async_init( + 'comp', context={'source': config_entries.SOURCE_USER}) yield from hass.async_block_till_done() assert len(mock_setup_entry.mock_calls) == 1 @@ -171,7 +172,8 @@ async def test_saving_and_loading(hass): ) with patch.dict(config_entries.HANDLERS, {'test': TestFlow}): - await hass.config_entries.flow.async_init('test') + await hass.config_entries.flow.async_init( + 'test', context={'source': config_entries.SOURCE_USER}) class Test2Flow(data_entry_flow.FlowHandler): VERSION = 3 @@ -187,7 +189,8 @@ async def test_saving_and_loading(hass): with patch('homeassistant.config_entries.HANDLERS.get', return_value=Test2Flow): - await hass.config_entries.flow.async_init('test') + await hass.config_entries.flow.async_init( + 'test', context={'source': config_entries.SOURCE_USER}) # To trigger the call_later async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=1)) diff --git a/tests/test_data_entry_flow.py b/tests/test_data_entry_flow.py index dc10f3d8d1a..c5d5bbb50bf 100644 --- a/tests/test_data_entry_flow.py +++ b/tests/test_data_entry_flow.py @@ -25,8 +25,10 @@ def manager(): if context is not None else 'user_input' return flow - async def async_add_entry(result): + async def async_add_entry(context, result): if (result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY): + result['source'] = context.get('source') \ + if context is not None else 'user' entries.append(result) manager = data_entry_flow.FlowManager( @@ -168,7 +170,7 @@ async def test_create_saves_data(manager): assert entry['handler'] == 'test' assert entry['title'] == 'Test Title' assert entry['data'] == 'Test Data' - assert entry['source'] == 'user_input' + assert entry['source'] == 'user' async def test_discovery_init_flow(manager): From da8f93dca2189df9e2b2c324e60d8359da2752f3 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 13 Aug 2018 03:40:06 -0700 Subject: [PATCH 011/159] Add trusted networks auth provider (#15812) * Add context to login flow * Add trusted networks auth provider * source -> context --- .../auth/providers/trusted_networks.py | 125 ++++++++++++++++++ homeassistant/components/auth/login_flow.py | 11 +- homeassistant/components/http/__init__.py | 1 + homeassistant/components/websocket_api.py | 5 +- .../providers/test_legacy_api_password.py | 11 +- tests/auth/providers/test_trusted_networks.py | 106 +++++++++++++++ 6 files changed, 247 insertions(+), 12 deletions(-) create mode 100644 homeassistant/auth/providers/trusted_networks.py create mode 100644 tests/auth/providers/test_trusted_networks.py diff --git a/homeassistant/auth/providers/trusted_networks.py b/homeassistant/auth/providers/trusted_networks.py new file mode 100644 index 00000000000..7a4b0126505 --- /dev/null +++ b/homeassistant/auth/providers/trusted_networks.py @@ -0,0 +1,125 @@ +"""Trusted Networks auth provider. + +It shows list of users if access from trusted network. +Abort login flow if not access from trusted network. +""" +import voluptuous as vol + +from homeassistant import data_entry_flow +from homeassistant.core import callback +from homeassistant.exceptions import HomeAssistantError +from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS + +CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend({ +}, extra=vol.PREVENT_EXTRA) + + +class InvalidAuthError(HomeAssistantError): + """Raised when try to access from untrusted networks.""" + + +class InvalidUserError(HomeAssistantError): + """Raised when try to login as invalid user.""" + + +@AUTH_PROVIDERS.register('trusted_networks') +class TrustedNetworksAuthProvider(AuthProvider): + """Trusted Networks auth provider. + + Allow passwordless access from trusted network. + """ + + DEFAULT_TITLE = 'Trusted Networks' + + async def async_credential_flow(self, context): + """Return a flow to login.""" + users = await self.store.async_get_users() + available_users = {user.id: user.name + for user in users + if not user.system_generated and user.is_active} + + return LoginFlow(self, context.get('ip_address'), available_users) + + async def async_get_or_create_credentials(self, flow_result): + """Get credentials based on the flow result.""" + user_id = flow_result['user'] + + users = await self.store.async_get_users() + for user in users: + if (not user.system_generated and + user.is_active and + user.id == user_id): + for credential in await self.async_credentials(): + if credential.data['user_id'] == user_id: + return credential + cred = self.async_create_credentials({'user_id': user_id}) + await self.store.async_link_user(user, cred) + return cred + + # We only allow login as exist user + raise InvalidUserError + + async def async_user_meta_for_credentials(self, credentials): + """Return extra user metadata for credentials. + + Trusted network auth provider should never create new user. + """ + raise NotImplementedError + + @callback + def async_validate_access(self, ip_address): + """Make sure the access from trusted networks. + + Raise InvalidAuthError if not. + Raise InvalidAuthError if trusted_networks is not config + """ + if (not hasattr(self.hass, 'http') or + not self.hass.http or not self.hass.http.trusted_networks): + raise InvalidAuthError('trusted_networks is not configured') + + if not any(ip_address in trusted_network for trusted_network + in self.hass.http.trusted_networks): + raise InvalidAuthError('Not in trusted_networks') + + +class LoginFlow(data_entry_flow.FlowHandler): + """Handler for the login flow.""" + + def __init__(self, auth_provider, ip_address, available_users): + """Initialize the login flow.""" + self._auth_provider = auth_provider + self._available_users = available_users + self._ip_address = ip_address + + async def async_step_init(self, user_input=None): + """Handle the step of the form.""" + errors = {} + try: + self._auth_provider.async_validate_access(self._ip_address) + + except InvalidAuthError: + errors['base'] = 'invalid_auth' + return self.async_show_form( + step_id='init', + data_schema=None, + errors=errors, + ) + + if user_input is not None: + user_id = user_input['user'] + if user_id not in self._available_users: + errors['base'] = 'invalid_auth' + + if not errors: + return self.async_create_entry( + title=self._auth_provider.name, + data=user_input + ) + + schema = {'user': vol.In(self._available_users)} + + return self.async_show_form( + step_id='init', + data_schema=vol.Schema(schema), + errors=errors, + ) diff --git a/homeassistant/components/auth/login_flow.py b/homeassistant/components/auth/login_flow.py index 7b80e52a8d7..e1d21bbb632 100644 --- a/homeassistant/components/auth/login_flow.py +++ b/homeassistant/components/auth/login_flow.py @@ -63,6 +63,7 @@ import aiohttp.web import voluptuous as vol from homeassistant import data_entry_flow +from homeassistant.components.http import KEY_REAL_IP from homeassistant.components.http.ban import process_wrong_login, \ log_invalid_auth from homeassistant.components.http.data_validator import RequestDataValidator @@ -151,7 +152,8 @@ class LoginFlowIndexView(HomeAssistantView): handler = data['handler'] try: - result = await self._flow_mgr.async_init(handler, context={}) + result = await self._flow_mgr.async_init( + handler, context={'ip_address': request[KEY_REAL_IP]}) except data_entry_flow.UnknownHandler: return self.json_message('Invalid handler specified', 404) except data_entry_flow.UnknownStep: @@ -188,6 +190,13 @@ class LoginFlowResourceView(HomeAssistantView): return self.json_message('Invalid client id', 400) try: + # do not allow change ip during login flow + for flow in self._flow_mgr.async_progress(): + if (flow['flow_id'] == flow_id and + flow['context']['ip_address'] != + request.get(KEY_REAL_IP)): + return self.json_message('IP address changed', 400) + result = await self._flow_mgr.async_configure(flow_id, data) except data_entry_flow.UnknownFlow: return self.json_message('Invalid flow specified', 404) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index c1d80667983..2fbfa099209 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -220,6 +220,7 @@ class HomeAssistantHTTP: self.ssl_key = ssl_key self.server_host = server_host self.server_port = server_port + self.trusted_networks = trusted_networks self.is_ban_enabled = is_ban_enabled self._handler = None self.server = None diff --git a/homeassistant/components/websocket_api.py b/homeassistant/components/websocket_api.py index d9c92fa357f..2a1e808188a 100644 --- a/homeassistant/components/websocket_api.py +++ b/homeassistant/components/websocket_api.py @@ -344,7 +344,10 @@ class ActiveConnection: if request[KEY_AUTHENTICATED]: authenticated = True - else: + # always request auth when auth is active + # even request passed pre-authentication (trusted networks) + # or when using legacy api_password + if self.hass.auth.active or not authenticated: self.debug("Request auth") await self.wsock.send_json(auth_required_message()) msg = await wsock.receive_json() diff --git a/tests/auth/providers/test_legacy_api_password.py b/tests/auth/providers/test_legacy_api_password.py index 71642bd7a32..0c129088c8b 100644 --- a/tests/auth/providers/test_legacy_api_password.py +++ b/tests/auth/providers/test_legacy_api_password.py @@ -63,18 +63,9 @@ async def test_verify_not_load(hass, provider): async def test_verify_login(hass, provider): - """Test we raise if http module not load.""" + """Test login using legacy api password auth provider.""" hass.http = Mock(api_password='test-password') provider.async_validate_login('test-password') hass.http = Mock(api_password='test-password') with pytest.raises(legacy_api_password.InvalidAuthError): provider.async_validate_login('invalid-password') - - -async def test_utf_8_username_password(provider): - """Test that we create a new credential.""" - credentials = await provider.async_get_or_create_credentials({ - 'username': '🎉', - 'password': '😎', - }) - assert credentials.is_new is True diff --git a/tests/auth/providers/test_trusted_networks.py b/tests/auth/providers/test_trusted_networks.py new file mode 100644 index 00000000000..ca8b5bd90a2 --- /dev/null +++ b/tests/auth/providers/test_trusted_networks.py @@ -0,0 +1,106 @@ +"""Test the Trusted Networks auth provider.""" +from unittest.mock import Mock + +import pytest +import voluptuous as vol + +from homeassistant import auth +from homeassistant.auth import auth_store +from homeassistant.auth.providers import trusted_networks as tn_auth + + +@pytest.fixture +def store(hass): + """Mock store.""" + return auth_store.AuthStore(hass) + + +@pytest.fixture +def provider(hass, store): + """Mock provider.""" + return tn_auth.TrustedNetworksAuthProvider(hass, store, { + 'type': 'trusted_networks' + }) + + +@pytest.fixture +def manager(hass, store, provider): + """Mock manager.""" + return auth.AuthManager(hass, store, { + (provider.type, provider.id): provider + }) + + +async def test_trusted_networks_credentials(manager, provider): + """Test trusted_networks credentials related functions.""" + owner = await manager.async_create_user("test-owner") + tn_owner_cred = await provider.async_get_or_create_credentials({ + 'user': owner.id + }) + assert tn_owner_cred.is_new is False + assert any(cred.id == tn_owner_cred.id for cred in owner.credentials) + + user = await manager.async_create_user("test-user") + tn_user_cred = await provider.async_get_or_create_credentials({ + 'user': user.id + }) + assert tn_user_cred.id != tn_owner_cred.id + assert tn_user_cred.is_new is False + assert any(cred.id == tn_user_cred.id for cred in user.credentials) + + with pytest.raises(tn_auth.InvalidUserError): + await provider.async_get_or_create_credentials({ + 'user': 'invalid-user' + }) + + +async def test_validate_access(provider): + """Test validate access from trusted networks.""" + with pytest.raises(tn_auth.InvalidAuthError): + provider.async_validate_access('192.168.0.1') + + provider.hass.http = Mock(trusted_networks=['192.168.0.1']) + provider.async_validate_access('192.168.0.1') + + with pytest.raises(tn_auth.InvalidAuthError): + provider.async_validate_access('127.0.0.1') + + +async def test_login_flow(manager, provider): + """Test login flow.""" + owner = await manager.async_create_user("test-owner") + user = await manager.async_create_user("test-user") + + # trusted network didn't loaded + flow = await provider.async_credential_flow({'ip_address': '127.0.0.1'}) + step = await flow.async_step_init() + assert step['step_id'] == 'init' + assert step['errors']['base'] == 'invalid_auth' + + provider.hass.http = Mock(trusted_networks=['192.168.0.1']) + + # not from trusted network + flow = await provider.async_credential_flow({'ip_address': '127.0.0.1'}) + step = await flow.async_step_init() + assert step['step_id'] == 'init' + assert step['errors']['base'] == 'invalid_auth' + + # from trusted network, list users + flow = await provider.async_credential_flow({'ip_address': '192.168.0.1'}) + step = await flow.async_step_init() + assert step['step_id'] == 'init' + + schema = step['data_schema'] + assert schema({'user': owner.id}) + with pytest.raises(vol.Invalid): + assert schema({'user': 'invalid-user'}) + + # login with invalid user + step = await flow.async_step_init({'user': 'invalid-user'}) + assert step['step_id'] == 'init' + assert step['errors']['base'] == 'invalid_auth' + + # login with valid user + step = await flow.async_step_init({'user': user.id}) + assert step['type'] == 'create_entry' + assert step['data']['user'] == user.id From c998a55fe70956593d2406633dfb3ca152a8899b Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 13 Aug 2018 10:08:45 -0700 Subject: [PATCH 012/159] Bump python-lakeside dependency This should fix https://github.com/home-assistant/home-assistant/issues/15374 --- homeassistant/components/eufy.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/eufy.py b/homeassistant/components/eufy.py index 69d4905228a..31a4dddd424 100644 --- a/homeassistant/components/eufy.py +++ b/homeassistant/components/eufy.py @@ -15,7 +15,7 @@ from homeassistant.helpers import discovery import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['lakeside==0.7'] +REQUIREMENTS = ['lakeside==0.10'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 7bef70ed377..3f6dcd937f2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -498,7 +498,7 @@ kiwiki-client==0.1.1 konnected==0.1.2 # homeassistant.components.eufy -lakeside==0.7 +lakeside==0.10 # homeassistant.components.device_tracker.owntracks # homeassistant.components.device_tracker.owntracks_http From 39647a15ae0d7d79f4fb467c6e46018957c405bb Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Mon, 13 Aug 2018 15:18:25 -0400 Subject: [PATCH 013/159] Add monitored conditions for Unifi device_tracker (#15888) * Add support for monitored_conditions for attributes * Update unifi tests * Add list of available attrs --- .../components/device_tracker/unifi.py | 35 ++++++++++-- tests/components/device_tracker/test_unifi.py | 56 +++++++++++++++---- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/device_tracker/unifi.py b/homeassistant/components/device_tracker/unifi.py index b7efe65dd01..627d2092a11 100644 --- a/homeassistant/components/device_tracker/unifi.py +++ b/homeassistant/components/device_tracker/unifi.py @@ -12,7 +12,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.components.device_tracker import ( DOMAIN, PLATFORM_SCHEMA, DeviceScanner) from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD -from homeassistant.const import CONF_VERIFY_SSL +from homeassistant.const import CONF_VERIFY_SSL, CONF_MONITORED_CONDITIONS import homeassistant.util.dt as dt_util REQUIREMENTS = ['pyunifi==2.13'] @@ -31,6 +31,18 @@ DEFAULT_DETECTION_TIME = timedelta(seconds=300) NOTIFICATION_ID = 'unifi_notification' NOTIFICATION_TITLE = 'Unifi Device Tracker Setup' +AVAILABLE_ATTRS = [ + '_id', '_is_guest_by_uap', '_last_seen_by_uap', '_uptime_by_uap', + 'ap_mac', 'assoc_time', 'authorized', 'bssid', 'bytes-r', 'ccq', + 'channel', 'essid', 'first_seen', 'hostname', 'idletime', 'ip', + 'is_11r', 'is_guest', 'is_wired', 'last_seen', 'latest_assoc_time', + 'mac', 'name', 'noise', 'noted', 'oui', 'powersave_enabled', + 'qos_policy_applied', 'radio', 'radio_proto', 'rssi', 'rx_bytes', + 'rx_bytes-r', 'rx_packets', 'rx_rate', 'signal', 'site_id', + 'tx_bytes', 'tx_bytes-r', 'tx_packets', 'tx_power', 'tx_rate', + 'uptime', 'user_id', 'usergroup_id', 'vlan' +] + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, vol.Optional(CONF_SITE_ID, default='default'): cv.string, @@ -41,6 +53,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ cv.boolean, cv.isfile), vol.Optional(CONF_DETECTION_TIME, default=DEFAULT_DETECTION_TIME): vol.All( cv.time_period, cv.positive_timedelta), + vol.Optional(CONF_MONITORED_CONDITIONS): + vol.All(cv.ensure_list, [vol.In(AVAILABLE_ATTRS)]), vol.Optional(CONF_SSID_FILTER): vol.All(cv.ensure_list, [cv.string]) }) @@ -56,6 +70,7 @@ def get_scanner(hass, config): port = config[DOMAIN].get(CONF_PORT) verify_ssl = config[DOMAIN].get(CONF_VERIFY_SSL) detection_time = config[DOMAIN].get(CONF_DETECTION_TIME) + monitored_conditions = config[DOMAIN].get(CONF_MONITORED_CONDITIONS) ssid_filter = config[DOMAIN].get(CONF_SSID_FILTER) try: @@ -72,18 +87,20 @@ def get_scanner(hass, config): notification_id=NOTIFICATION_ID) return False - return UnifiScanner(ctrl, detection_time, ssid_filter) + return UnifiScanner(ctrl, detection_time, ssid_filter, + monitored_conditions) class UnifiScanner(DeviceScanner): """Provide device_tracker support from Unifi WAP client data.""" def __init__(self, controller, detection_time: timedelta, - ssid_filter) -> None: + ssid_filter, monitored_conditions) -> None: """Initialize the scanner.""" self._detection_time = detection_time self._controller = controller self._ssid_filter = ssid_filter + self._monitored_conditions = monitored_conditions self._update() def _update(self): @@ -125,6 +142,14 @@ class UnifiScanner(DeviceScanner): def get_extra_attributes(self, device): """Return the extra attributes of the device.""" + if not self._monitored_conditions: + return {} + client = self._clients.get(device, {}) - _LOGGER.debug("Device mac %s attributes %s", device, client) - return client + attributes = {} + for variable in self._monitored_conditions: + if variable in client: + attributes[variable] = client[variable] + + _LOGGER.debug("Device mac %s attributes %s", device, attributes) + return attributes diff --git a/tests/components/device_tracker/test_unifi.py b/tests/components/device_tracker/test_unifi.py index ccc58d728ed..33adff9adf8 100644 --- a/tests/components/device_tracker/test_unifi.py +++ b/tests/components/device_tracker/test_unifi.py @@ -10,7 +10,8 @@ import voluptuous as vol from homeassistant.components.device_tracker import DOMAIN, unifi as unifi from homeassistant.const import (CONF_HOST, CONF_USERNAME, CONF_PASSWORD, - CONF_PLATFORM, CONF_VERIFY_SSL) + CONF_PLATFORM, CONF_VERIFY_SSL, + CONF_MONITORED_CONDITIONS) DEFAULT_DETECTION_TIME = timedelta(seconds=300) @@ -54,7 +55,7 @@ def test_config_valid_verify_ssl(hass, mock_scanner, mock_ctrl): assert mock_scanner.call_count == 1 assert mock_scanner.call_args == mock.call(mock_ctrl.return_value, DEFAULT_DETECTION_TIME, - None) + None, None) def test_config_minimal(hass, mock_scanner, mock_ctrl): @@ -76,7 +77,7 @@ def test_config_minimal(hass, mock_scanner, mock_ctrl): assert mock_scanner.call_count == 1 assert mock_scanner.call_args == mock.call(mock_ctrl.return_value, DEFAULT_DETECTION_TIME, - None) + None, None) def test_config_full(hass, mock_scanner, mock_ctrl): @@ -88,6 +89,7 @@ def test_config_full(hass, mock_scanner, mock_ctrl): CONF_PASSWORD: 'password', CONF_HOST: 'myhost', CONF_VERIFY_SSL: False, + CONF_MONITORED_CONDITIONS: ['essid', 'signal'], 'port': 123, 'site_id': 'abcdef01', 'detection_time': 300, @@ -101,9 +103,11 @@ def test_config_full(hass, mock_scanner, mock_ctrl): version='v4', site_id='abcdef01', ssl_verify=False) assert mock_scanner.call_count == 1 - assert mock_scanner.call_args == mock.call(mock_ctrl.return_value, - DEFAULT_DETECTION_TIME, - None) + assert mock_scanner.call_args == mock.call( + mock_ctrl.return_value, + DEFAULT_DETECTION_TIME, + None, + config[DOMAIN][CONF_MONITORED_CONDITIONS]) def test_config_error(): @@ -157,7 +161,7 @@ def test_scanner_update(): 'last_seen': dt_util.as_timestamp(dt_util.utcnow())}, ] ctrl.get_clients.return_value = fake_clients - unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None) + unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None, None) assert ctrl.get_clients.call_count == 1 assert ctrl.get_clients.call_args == mock.call() @@ -167,7 +171,7 @@ def test_scanner_update_error(): ctrl = mock.MagicMock() ctrl.get_clients.side_effect = APIError( '/', 500, 'foo', {}, None) - unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None) + unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None, None) def test_scan_devices(): @@ -180,7 +184,7 @@ def test_scan_devices(): 'last_seen': dt_util.as_timestamp(dt_util.utcnow())}, ] ctrl.get_clients.return_value = fake_clients - scanner = unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None) + scanner = unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None, None) assert set(scanner.scan_devices()) == set(['123', '234']) @@ -200,7 +204,8 @@ def test_scan_devices_filtered(): ssid_filter = ['foonet', 'barnet'] ctrl.get_clients.return_value = fake_clients - scanner = unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, ssid_filter) + scanner = unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, ssid_filter, + None) assert set(scanner.scan_devices()) == set(['123', '234', '890']) @@ -221,8 +226,37 @@ def test_get_device_name(): 'last_seen': '1504786810'}, ] ctrl.get_clients.return_value = fake_clients - scanner = unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None) + scanner = unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None, None) assert scanner.get_device_name('123') == 'foobar' assert scanner.get_device_name('234') == 'Nice Name' assert scanner.get_device_name('456') is None assert scanner.get_device_name('unknown') is None + + +def test_monitored_conditions(): + """Test the filtering of attributes.""" + ctrl = mock.MagicMock() + fake_clients = [ + {'mac': '123', + 'hostname': 'foobar', + 'essid': 'barnet', + 'signal': -60, + 'last_seen': dt_util.as_timestamp(dt_util.utcnow())}, + {'mac': '234', + 'name': 'Nice Name', + 'essid': 'barnet', + 'signal': -42, + 'last_seen': dt_util.as_timestamp(dt_util.utcnow())}, + {'mac': '456', + 'hostname': 'wired', + 'essid': 'barnet', + 'last_seen': dt_util.as_timestamp(dt_util.utcnow())}, + ] + ctrl.get_clients.return_value = fake_clients + scanner = unifi.UnifiScanner(ctrl, DEFAULT_DETECTION_TIME, None, + ['essid', 'signal']) + assert scanner.get_extra_attributes('123') == {'essid': 'barnet', + 'signal': -60} + assert scanner.get_extra_attributes('234') == {'essid': 'barnet', + 'signal': -42} + assert scanner.get_extra_attributes('456') == {'essid': 'barnet'} From 1b5cfa7331b39e014be0ae7fc758a2d426486fd1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 Aug 2018 22:39:13 +0200 Subject: [PATCH 014/159] Deprecate remote.api (#15955) --- homeassistant/remote.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/remote.py b/homeassistant/remote.py index 313f98a890c..c254dd500f7 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -48,6 +48,7 @@ class API: port: Optional[int] = SERVER_PORT, use_ssl: bool = False) -> None: """Init the API.""" + _LOGGER.warning('This class is deprecated and will be removed in 0.77') self.host = host self.port = port self.api_password = api_password From f411fb89e67e220da76f004119aa764798b0eabb Mon Sep 17 00:00:00 2001 From: Colin Frei Date: Mon, 13 Aug 2018 22:44:20 +0200 Subject: [PATCH 015/159] Netatmo public (#15684) * Add a sensor for netatmo public data * A bit of cleanup before submitting pull request * Add netatmo_public file to .coveragerc, as per pull request template instructions * Fixes for tox complaining * make calculations simpler, based on review feedback * explicitly pass required_data parameter to netatmo API * remove unnecessary spaces * remove debug code * code style fix --- .coveragerc | 1 + .../components/sensor/netatmo_public.py | 142 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 homeassistant/components/sensor/netatmo_public.py diff --git a/.coveragerc b/.coveragerc index f06e9356d21..de1d8463477 100644 --- a/.coveragerc +++ b/.coveragerc @@ -683,6 +683,7 @@ omit = homeassistant/components/sensor/mvglive.py homeassistant/components/sensor/nederlandse_spoorwegen.py homeassistant/components/sensor/netdata.py + homeassistant/components/sensor/netdata_public.py homeassistant/components/sensor/neurio_energy.py homeassistant/components/sensor/nsw_fuel_station.py homeassistant/components/sensor/nut.py diff --git a/homeassistant/components/sensor/netatmo_public.py b/homeassistant/components/sensor/netatmo_public.py new file mode 100644 index 00000000000..9a1485c36cf --- /dev/null +++ b/homeassistant/components/sensor/netatmo_public.py @@ -0,0 +1,142 @@ +""" +Support for Sensors using public Netatmo data. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.netatmo_public/. +""" +from datetime import timedelta +import logging + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import (CONF_NAME, CONF_TYPE) +from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['netatmo'] + +CONF_AREAS = 'areas' +CONF_LAT_NE = 'lat_ne' +CONF_LON_NE = 'lon_ne' +CONF_LAT_SW = 'lat_sw' +CONF_LON_SW = 'lon_sw' + +DEFAULT_NAME = 'Netatmo Public Data' +DEFAULT_TYPE = 'max' +SENSOR_TYPES = {'max', 'avg'} + +# NetAtmo Data is uploaded to server every 10 minutes +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=600) + + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_AREAS): vol.All(cv.ensure_list, [ + { + vol.Required(CONF_LAT_NE): cv.latitude, + vol.Required(CONF_LAT_SW): cv.latitude, + vol.Required(CONF_LON_NE): cv.longitude, + vol.Required(CONF_LON_SW): cv.longitude, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_TYPE, default=DEFAULT_TYPE): + vol.In(SENSOR_TYPES) + } + ]), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the access to Netatmo binary sensor.""" + netatmo = hass.components.netatmo + + sensors = [] + areas = config.get(CONF_AREAS) + for area_conf in areas: + data = NetatmoPublicData(netatmo.NETATMO_AUTH, + lat_ne=area_conf.get(CONF_LAT_NE), + lon_ne=area_conf.get(CONF_LON_NE), + lat_sw=area_conf.get(CONF_LAT_SW), + lon_sw=area_conf.get(CONF_LON_SW), + calculation=area_conf.get(CONF_TYPE)) + sensors.append(NetatmoPublicSensor(area_conf.get(CONF_NAME), data)) + add_devices(sensors) + + +class NetatmoPublicSensor(Entity): + """Represent a single sensor in a Netatmo.""" + + def __init__(self, name, data): + """Initialize the sensor.""" + self.netatmo_data = data + self._name = name + self._state = None + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def icon(self): + """Icon to use in the frontend.""" + return 'mdi:weather-rainy' + + @property + def device_class(self): + """Return the device class of the sensor.""" + return None + + @property + def state(self): + """Return true if binary sensor is on.""" + return self._state + + @property + def unit_of_measurement(self): + """Return the unit of measurement of this entity.""" + return 'mm' + + def update(self): + """Get the latest data from NetAtmo API and updates the states.""" + self.netatmo_data.update() + self._state = self.netatmo_data.data + + +class NetatmoPublicData: + """Get the latest data from NetAtmo.""" + + def __init__(self, auth, lat_ne, lon_ne, lat_sw, lon_sw, calculation): + """Initialize the data object.""" + self.auth = auth + self.data = None + self.lat_ne = lat_ne + self.lon_ne = lon_ne + self.lat_sw = lat_sw + self.lon_sw = lon_sw + self.calculation = calculation + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """Request an update from the Netatmo API.""" + import pyatmo + _LOGGER.error('Updating Netatmo data.') + raindata = pyatmo.PublicData(self.auth, + LAT_NE=self.lat_ne, + LON_NE=self.lon_ne, + LAT_SW=self.lat_sw, + LON_SW=self.lon_sw, + required_data_type="rain") + + if raindata.CountStationInArea() == 0: + _LOGGER.warning('No Rain Station available in this area.') + return + + raindata_live = raindata.getLive() + + if self.calculation == 'avg': + self.data = sum(raindata_live.values()) / len(raindata_live) + else: + self.data = max(raindata_live.values()) From 3a60c8bbed58eb49d0ff7a4b8b822ba4e2c7bbb9 Mon Sep 17 00:00:00 2001 From: Conrad Juhl Andersen Date: Mon, 13 Aug 2018 22:50:23 +0200 Subject: [PATCH 016/159] Update Xiaomi Vacuum to new StateVacuumDevice (#15643) * Add support for states * Woof? * Fixed some errors * VacuumDevice -> StateVacuumDevice * VacuumDevice -> StateVacuumDevice * Added split of start and pause --- .../components/vacuum/xiaomi_miio.py | 79 ++++++++++--------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/homeassistant/components/vacuum/xiaomi_miio.py b/homeassistant/components/vacuum/xiaomi_miio.py index f6789d78b9a..2c6057e1cf6 100644 --- a/homeassistant/components/vacuum/xiaomi_miio.py +++ b/homeassistant/components/vacuum/xiaomi_miio.py @@ -13,8 +13,10 @@ import voluptuous as vol from homeassistant.components.vacuum import ( ATTR_CLEANED_AREA, DOMAIN, PLATFORM_SCHEMA, SUPPORT_BATTERY, SUPPORT_CLEAN_SPOT, SUPPORT_FAN_SPEED, SUPPORT_LOCATE, SUPPORT_PAUSE, - SUPPORT_RETURN_HOME, SUPPORT_SEND_COMMAND, SUPPORT_STATUS, SUPPORT_STOP, - SUPPORT_TURN_OFF, SUPPORT_TURN_ON, VACUUM_SERVICE_SCHEMA, VacuumDevice) + SUPPORT_RETURN_HOME, SUPPORT_SEND_COMMAND, SUPPORT_STOP, + SUPPORT_STATE, SUPPORT_START, VACUUM_SERVICE_SCHEMA, StateVacuumDevice, + STATE_CLEANING, STATE_DOCKED, STATE_PAUSED, STATE_IDLE, STATE_RETURNING, + STATE_ERROR) from homeassistant.const import ( ATTR_ENTITY_ID, CONF_HOST, CONF_NAME, CONF_TOKEN, STATE_OFF, STATE_ON) import homeassistant.helpers.config_validation as cv @@ -77,10 +79,25 @@ SERVICE_TO_METHOD = { 'schema': SERVICE_SCHEMA_REMOTE_CONTROL}, } -SUPPORT_XIAOMI = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PAUSE | \ +SUPPORT_XIAOMI = SUPPORT_STATE | SUPPORT_PAUSE | \ SUPPORT_STOP | SUPPORT_RETURN_HOME | SUPPORT_FAN_SPEED | \ SUPPORT_SEND_COMMAND | SUPPORT_LOCATE | \ - SUPPORT_STATUS | SUPPORT_BATTERY | SUPPORT_CLEAN_SPOT + SUPPORT_BATTERY | SUPPORT_CLEAN_SPOT | SUPPORT_START + + +STATE_CODE_TO_STATE = { + 3: STATE_IDLE, + 5: STATE_CLEANING, + 6: STATE_RETURNING, + 8: STATE_DOCKED, + 9: STATE_ERROR, + 10: STATE_PAUSED, + 11: STATE_CLEANING, + 12: STATE_ERROR, + 15: STATE_RETURNING, + 16: STATE_CLEANING, + 17: STATE_CLEANING, +} @asyncio.coroutine @@ -135,7 +152,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): schema=schema) -class MiroboVacuum(VacuumDevice): +class MiroboVacuum(StateVacuumDevice): """Representation of a Xiaomi Vacuum cleaner robot.""" def __init__(self, name, vacuum): @@ -144,7 +161,6 @@ class MiroboVacuum(VacuumDevice): self._vacuum = vacuum self.vacuum_state = None - self._is_on = False self._available = False self.consumable_state = None @@ -157,10 +173,16 @@ class MiroboVacuum(VacuumDevice): return self._name @property - def status(self): + def state(self): """Return the status of the vacuum cleaner.""" if self.vacuum_state is not None: - return self.vacuum_state.state + try: + return STATE_CODE_TO_STATE[int(self.vacuum_state.state_code)] + except KeyError: + _LOGGER.error("STATE not supported: %s, state_code: %s", + self.vacuum_state.state, + self.vacuum_state.state_code) + return None @property def battery_level(self): @@ -217,11 +239,6 @@ class MiroboVacuum(VacuumDevice): attrs[ATTR_ERROR] = self.vacuum_state.error return attrs - @property - def is_on(self) -> bool: - """Return True if entity is on.""" - return self._is_on - @property def available(self) -> bool: """Return True if entity is available.""" @@ -243,26 +260,22 @@ class MiroboVacuum(VacuumDevice): _LOGGER.error(mask_error, exc) return False - @asyncio.coroutine - def async_turn_on(self, **kwargs): - """Turn the vacuum on.""" - is_on = yield from self._try_command( + async def async_start(self): + """Start or resume the cleaning task.""" + await self._try_command( "Unable to start the vacuum: %s", self._vacuum.start) - self._is_on = is_on - @asyncio.coroutine - def async_turn_off(self, **kwargs): - """Turn the vacuum off and return to home.""" - yield from self.async_stop() - yield from self.async_return_to_base() + async def async_pause(self): + """Pause the cleaning task.""" + if self.state == STATE_CLEANING: + await self._try_command( + "Unable to set start/pause: %s", self._vacuum.pause) @asyncio.coroutine def async_stop(self, **kwargs): """Stop the vacuum cleaner.""" - stopped = yield from self._try_command( + yield from self._try_command( "Unable to stop: %s", self._vacuum.stop) - if stopped: - self._is_on = False @asyncio.coroutine def async_set_fan_speed(self, fan_speed, **kwargs): @@ -281,22 +294,11 @@ class MiroboVacuum(VacuumDevice): "Unable to set fan speed: %s", self._vacuum.set_fan_speed, fan_speed) - @asyncio.coroutine - def async_start_pause(self, **kwargs): - """Start, pause or resume the cleaning task.""" - if self.vacuum_state and self.is_on: - yield from self._try_command( - "Unable to set start/pause: %s", self._vacuum.pause) - else: - yield from self.async_turn_on() - @asyncio.coroutine def async_return_to_base(self, **kwargs): """Set the vacuum cleaner to return to the dock.""" - return_home = yield from self._try_command( + yield from self._try_command( "Unable to return home: %s", self._vacuum.home) - if return_home: - self._is_on = False @asyncio.coroutine def async_clean_spot(self, **kwargs): @@ -365,7 +367,6 @@ class MiroboVacuum(VacuumDevice): self.clean_history = self._vacuum.clean_history() self.dnd_state = self._vacuum.dnd_status() - self._is_on = state.is_on self._available = True except OSError as exc: _LOGGER.error("Got OSError while fetching the state: %s", exc) From 3fbb56d5fb20390acf4bf079a21c7d7046aaa211 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 Aug 2018 21:27:34 +0200 Subject: [PATCH 017/159] Update frontend to 20180813.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index e248bc20ccd..41cfdd3edd8 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180811.0'] +REQUIREMENTS = ['home-assistant-frontend==20180813.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 3f6dcd937f2..c667848e940 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -433,7 +433,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180811.0 +home-assistant-frontend==20180813.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index cfe98bd7d4e..ffc55c23210 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -84,7 +84,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180811.0 +home-assistant-frontend==20180813.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 69b694ff2619797a8ff249aa2044aa083e3a905b Mon Sep 17 00:00:00 2001 From: Daniel Perna Date: Tue, 14 Aug 2018 07:43:16 +0200 Subject: [PATCH 018/159] HomeMatic: Enable entity registry (#15950) * Set unique ID * Excluding setups that resolve names * Added support for resolvenames again --- .../components/homematic/__init__.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/homematic/__init__.py b/homeassistant/components/homematic/__init__.py index f737e2ad7d2..76c97793da0 100644 --- a/homeassistant/components/homematic/__init__.py +++ b/homeassistant/components/homematic/__init__.py @@ -47,6 +47,7 @@ ATTR_ERRORCODE = 'error' ATTR_MESSAGE = 'message' ATTR_MODE = 'mode' ATTR_TIME = 'time' +ATTR_UNIQUE_ID = 'unique_id' EVENT_KEYPRESS = 'homematic.keypress' EVENT_IMPULSE = 'homematic.impulse' @@ -173,6 +174,7 @@ DEVICE_SCHEMA = vol.Schema({ vol.Required(ATTR_INTERFACE): cv.string, vol.Optional(ATTR_CHANNEL, default=1): vol.Coerce(int), vol.Optional(ATTR_PARAM): cv.string, + vol.Optional(ATTR_UNIQUE_ID): cv.string, }) CONFIG_SCHEMA = vol.Schema({ @@ -530,16 +532,21 @@ def _get_devices(hass, discovery_type, keys, interface): _LOGGER.debug("%s: Handling %s: %s: %s", discovery_type, key, param, channels) for channel in channels: - name = _create_ha_name( + name = _create_ha_id( name=device.NAME, channel=channel, param=param, count=len(channels) ) + unique_id = _create_ha_id( + name=key, channel=channel, param=param, + count=len(channels) + ) device_dict = { CONF_PLATFORM: "homematic", ATTR_ADDRESS: key, ATTR_INTERFACE: interface, ATTR_NAME: name, - ATTR_CHANNEL: channel + ATTR_CHANNEL: channel, + ATTR_UNIQUE_ID: unique_id } if param is not None: device_dict[ATTR_PARAM] = param @@ -554,7 +561,7 @@ def _get_devices(hass, discovery_type, keys, interface): return device_arr -def _create_ha_name(name, channel, param, count): +def _create_ha_id(name, channel, param, count): """Generate a unique entity id.""" # HMDevice is a simple device if count == 1 and param is None: @@ -725,6 +732,7 @@ class HMDevice(Entity): self._interface = config.get(ATTR_INTERFACE) self._channel = config.get(ATTR_CHANNEL) self._state = config.get(ATTR_PARAM) + self._unique_id = config.get(ATTR_UNIQUE_ID) self._data = {} self._homematic = None self._hmdevice = None @@ -740,6 +748,11 @@ class HMDevice(Entity): """Load data init callbacks.""" yield from self.hass.async_add_job(self.link_homematic) + @property + def unique_id(self): + """Return unique ID. HomeMatic entity IDs are unique by default.""" + return self._unique_id.replace(" ", "_") + @property def should_poll(self): """Return false. HomeMatic states are pushed by the XML-RPC Server.""" From 6540d2e0735b3c8575730376b4e0b1a862a63850 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 08:20:17 +0200 Subject: [PATCH 019/159] Switch to intermediate Mozilla cert profile (#15957) * Allow choosing intermediate SSL profile * Fix tests --- homeassistant/components/http/__init__.py | 20 ++++++-- homeassistant/util/ssl.py | 56 ++++++++++++++++++++++- tests/components/http/test_init.py | 56 +++++++++++++++++++++++ tests/scripts/test_check_config.py | 4 +- 4 files changed, 130 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index 2fbfa099209..9ded94fa6fd 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -49,6 +49,10 @@ CONF_TRUSTED_PROXIES = 'trusted_proxies' CONF_TRUSTED_NETWORKS = 'trusted_networks' CONF_LOGIN_ATTEMPTS_THRESHOLD = 'login_attempts_threshold' CONF_IP_BAN_ENABLED = 'ip_ban_enabled' +CONF_SSL_PROFILE = 'ssl_profile' + +SSL_MODERN = 'modern' +SSL_INTERMEDIATE = 'intermediate' _LOGGER = logging.getLogger(__name__) @@ -74,7 +78,9 @@ HTTP_SCHEMA = vol.Schema({ vol.Optional(CONF_LOGIN_ATTEMPTS_THRESHOLD, default=NO_LOGIN_ATTEMPT_THRESHOLD): vol.Any(cv.positive_int, NO_LOGIN_ATTEMPT_THRESHOLD), - vol.Optional(CONF_IP_BAN_ENABLED, default=True): cv.boolean + vol.Optional(CONF_IP_BAN_ENABLED, default=True): cv.boolean, + vol.Optional(CONF_SSL_PROFILE, default=SSL_MODERN): + vol.In([SSL_INTERMEDIATE, SSL_MODERN]), }) CONFIG_SCHEMA = vol.Schema({ @@ -123,6 +129,7 @@ async def async_setup(hass, config): trusted_networks = conf[CONF_TRUSTED_NETWORKS] is_ban_enabled = conf[CONF_IP_BAN_ENABLED] login_threshold = conf[CONF_LOGIN_ATTEMPTS_THRESHOLD] + ssl_profile = conf[CONF_SSL_PROFILE] if api_password is not None: logging.getLogger('aiohttp.access').addFilter( @@ -141,7 +148,8 @@ async def async_setup(hass, config): trusted_proxies=trusted_proxies, trusted_networks=trusted_networks, login_threshold=login_threshold, - is_ban_enabled=is_ban_enabled + is_ban_enabled=is_ban_enabled, + ssl_profile=ssl_profile, ) async def stop_server(event): @@ -181,7 +189,7 @@ class HomeAssistantHTTP: ssl_certificate, ssl_peer_certificate, ssl_key, server_host, server_port, cors_origins, use_x_forwarded_for, trusted_proxies, trusted_networks, - login_threshold, is_ban_enabled): + login_threshold, is_ban_enabled, ssl_profile): """Initialize the HTTP Home Assistant server.""" app = self.app = web.Application( middlewares=[staticresource_middleware]) @@ -222,6 +230,7 @@ class HomeAssistantHTTP: self.server_port = server_port self.trusted_networks = trusted_networks self.is_ban_enabled = is_ban_enabled + self.ssl_profile = ssl_profile self._handler = None self.server = None @@ -308,7 +317,10 @@ class HomeAssistantHTTP: if self.ssl_certificate: try: - context = ssl_util.server_context() + if self.ssl_profile == SSL_INTERMEDIATE: + context = ssl_util.server_context_intermediate() + else: + context = ssl_util.server_context_modern() context.load_cert_chain(self.ssl_certificate, self.ssl_key) except OSError as error: _LOGGER.error("Could not read SSL certificate from %s: %s", diff --git a/homeassistant/util/ssl.py b/homeassistant/util/ssl.py index 392c5986c89..b78395cdb0d 100644 --- a/homeassistant/util/ssl.py +++ b/homeassistant/util/ssl.py @@ -13,7 +13,7 @@ def client_context() -> ssl.SSLContext: return context -def server_context() -> ssl.SSLContext: +def server_context_modern() -> ssl.SSLContext: """Return an SSL context following the Mozilla recommendations. TLS configuration follows the best-practice guidelines specified here: @@ -37,4 +37,58 @@ def server_context() -> ssl.SSLContext: "ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:" "ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256" ) + + return context + + +def server_context_intermediate() -> ssl.SSLContext: + """Return an SSL context following the Mozilla recommendations. + + TLS configuration follows the best-practice guidelines specified here: + https://wiki.mozilla.org/Security/Server_Side_TLS + Intermediate guidelines are followed. + """ + context = ssl.SSLContext(ssl.PROTOCOL_TLS) # pylint: disable=no-member + + context.options |= ( + ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | + ssl.OP_CIPHER_SERVER_PREFERENCE + ) + if hasattr(ssl, 'OP_NO_COMPRESSION'): + context.options |= ssl.OP_NO_COMPRESSION + + context.set_ciphers( + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "ECDHE-ECDSA-AES256-GCM-SHA384:" + "ECDHE-RSA-AES256-GCM-SHA384:" + "DHE-RSA-AES128-GCM-SHA256:" + "DHE-RSA-AES256-GCM-SHA384:" + "ECDHE-ECDSA-AES128-SHA256:" + "ECDHE-RSA-AES128-SHA256:" + "ECDHE-ECDSA-AES128-SHA:" + "ECDHE-RSA-AES256-SHA384:" + "ECDHE-RSA-AES128-SHA:" + "ECDHE-ECDSA-AES256-SHA384:" + "ECDHE-ECDSA-AES256-SHA:" + "ECDHE-RSA-AES256-SHA:" + "DHE-RSA-AES128-SHA256:" + "DHE-RSA-AES128-SHA:" + "DHE-RSA-AES256-SHA256:" + "DHE-RSA-AES256-SHA:" + "ECDHE-ECDSA-DES-CBC3-SHA:" + "ECDHE-RSA-DES-CBC3-SHA:" + "EDH-RSA-DES-CBC3-SHA:" + "AES128-GCM-SHA256:" + "AES256-GCM-SHA384:" + "AES128-SHA256:" + "AES256-SHA256:" + "AES128-SHA:" + "AES256-SHA:" + "DES-CBC3-SHA:" + "!DSS" + ) + return context diff --git a/tests/components/http/test_init.py b/tests/components/http/test_init.py index c52f60a5f1b..9f6441c5238 100644 --- a/tests/components/http/test_init.py +++ b/tests/components/http/test_init.py @@ -1,10 +1,13 @@ """The tests for the Home Assistant HTTP component.""" import logging import unittest +from unittest.mock import patch from homeassistant.setup import async_setup_component import homeassistant.components.http as http +from homeassistant.util.ssl import ( + server_context_modern, server_context_intermediate) class TestView(http.HomeAssistantView): @@ -169,3 +172,56 @@ async def test_proxy_config_only_trust_proxies(hass): http.CONF_TRUSTED_PROXIES: ['127.0.0.1'] } }) is not True + + +async def test_ssl_profile_defaults_modern(hass): + """Test default ssl profile.""" + assert await async_setup_component(hass, 'http', {}) is True + + hass.http.ssl_certificate = 'bla' + + with patch('ssl.SSLContext.load_cert_chain'), \ + patch('homeassistant.util.ssl.server_context_modern', + side_effect=server_context_modern) as mock_context: + await hass.async_start() + await hass.async_block_till_done() + + assert len(mock_context.mock_calls) == 1 + + +async def test_ssl_profile_change_intermediate(hass): + """Test setting ssl profile to intermediate.""" + assert await async_setup_component(hass, 'http', { + 'http': { + 'ssl_profile': 'intermediate' + } + }) is True + + hass.http.ssl_certificate = 'bla' + + with patch('ssl.SSLContext.load_cert_chain'), \ + patch('homeassistant.util.ssl.server_context_intermediate', + side_effect=server_context_intermediate) as mock_context: + await hass.async_start() + await hass.async_block_till_done() + + assert len(mock_context.mock_calls) == 1 + + +async def test_ssl_profile_change_modern(hass): + """Test setting ssl profile to modern.""" + assert await async_setup_component(hass, 'http', { + 'http': { + 'ssl_profile': 'modern' + } + }) is True + + hass.http.ssl_certificate = 'bla' + + with patch('ssl.SSLContext.load_cert_chain'), \ + patch('homeassistant.util.ssl.server_context_modern', + side_effect=server_context_modern) as mock_context: + await hass.async_start() + await hass.async_block_till_done() + + assert len(mock_context.mock_calls) == 1 diff --git a/tests/scripts/test_check_config.py b/tests/scripts/test_check_config.py index 59d8e27a672..532197b4072 100644 --- a/tests/scripts/test_check_config.py +++ b/tests/scripts/test_check_config.py @@ -159,7 +159,9 @@ class TestCheckConfig(unittest.TestCase): 'login_attempts_threshold': -1, 'server_host': '0.0.0.0', 'server_port': 8123, - 'trusted_networks': []} + 'trusted_networks': [], + 'ssl_profile': 'modern', + } assert res['secret_cache'] == {secrets_path: {'http_pw': 'abc123'}} assert res['secrets'] == {'http_pw': 'abc123'} assert normalize_yaml_files(res) == [ From 619d01150f9c131041c6b64a6bb255e5dd28a68d Mon Sep 17 00:00:00 2001 From: cgtobi Date: Tue, 14 Aug 2018 11:44:27 +0200 Subject: [PATCH 020/159] Fix google calendar documentation link. (#15968) --- homeassistant/components/calendar/google.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/calendar/google.py b/homeassistant/components/calendar/google.py index 925bbcacddf..9b14f773c22 100644 --- a/homeassistant/components/calendar/google.py +++ b/homeassistant/components/calendar/google.py @@ -2,7 +2,7 @@ Support for Google Calendar Search binary sensors. For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.google_calendar/ +https://home-assistant.io/components/calendar.google/ """ import logging from datetime import timedelta From ea073b5e8741d8a4273a8193448cc21629c2a696 Mon Sep 17 00:00:00 2001 From: Colin Frei Date: Tue, 14 Aug 2018 11:46:41 +0200 Subject: [PATCH 021/159] Remove unnecessary log (#15966) --- homeassistant/components/sensor/netatmo_public.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/sensor/netatmo_public.py b/homeassistant/components/sensor/netatmo_public.py index 9a1485c36cf..4d2364ffb7c 100644 --- a/homeassistant/components/sensor/netatmo_public.py +++ b/homeassistant/components/sensor/netatmo_public.py @@ -122,7 +122,6 @@ class NetatmoPublicData: def update(self): """Request an update from the Netatmo API.""" import pyatmo - _LOGGER.error('Updating Netatmo data.') raindata = pyatmo.PublicData(self.auth, LAT_NE=self.lat_ne, LON_NE=self.lon_ne, From e3a2e586237deaa2cf57cbcaf0e5d9edbee82dbb Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Tue, 14 Aug 2018 10:53:08 +0100 Subject: [PATCH 022/159] remove-phantomjs-from-docker (#15936) --- Dockerfile | 1 - virtualization/Docker/Dockerfile.dev | 1 - virtualization/Docker/scripts/phantomjs | 15 --------------- virtualization/Docker/setup_docker_prereqs | 5 ----- 4 files changed, 22 deletions(-) delete mode 100755 virtualization/Docker/scripts/phantomjs diff --git a/Dockerfile b/Dockerfile index 75d9e9eb716..c84e6162d04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,6 @@ LABEL maintainer="Paulus Schoutsen " #ENV INSTALL_OPENALPR no #ENV INSTALL_FFMPEG no #ENV INSTALL_LIBCEC no -#ENV INSTALL_PHANTOMJS no #ENV INSTALL_SSOCR no #ENV INSTALL_IPERF3 no diff --git a/virtualization/Docker/Dockerfile.dev b/virtualization/Docker/Dockerfile.dev index d0599c2e74c..79072703031 100644 --- a/virtualization/Docker/Dockerfile.dev +++ b/virtualization/Docker/Dockerfile.dev @@ -10,7 +10,6 @@ LABEL maintainer="Paulus Schoutsen " #ENV INSTALL_OPENALPR no #ENV INSTALL_FFMPEG no #ENV INSTALL_LIBCEC no -#ENV INSTALL_PHANTOMJS no #ENV INSTALL_COAP no #ENV INSTALL_SSOCR no #ENV INSTALL_IPERF3 no diff --git a/virtualization/Docker/scripts/phantomjs b/virtualization/Docker/scripts/phantomjs deleted file mode 100755 index 7700b08f293..00000000000 --- a/virtualization/Docker/scripts/phantomjs +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# Sets up phantomjs. - -# Stop on errors -set -e - -PHANTOMJS_VERSION="2.1.1" - -cd /usr/src/app/ -mkdir -p build && cd build - -curl -LSO https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -tar -xjf phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -mv phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin/phantomjs /usr/bin/phantomjs -/usr/bin/phantomjs -v \ No newline at end of file diff --git a/virtualization/Docker/setup_docker_prereqs b/virtualization/Docker/setup_docker_prereqs index 15504ea57af..65acf92b855 100755 --- a/virtualization/Docker/setup_docker_prereqs +++ b/virtualization/Docker/setup_docker_prereqs @@ -7,7 +7,6 @@ set -e INSTALL_TELLSTICK="${INSTALL_TELLSTICK:-yes}" INSTALL_OPENALPR="${INSTALL_OPENALPR:-yes}" INSTALL_LIBCEC="${INSTALL_LIBCEC:-yes}" -INSTALL_PHANTOMJS="${INSTALL_PHANTOMJS:-yes}" INSTALL_SSOCR="${INSTALL_SSOCR:-yes}" # Required debian packages for running hass or components @@ -59,10 +58,6 @@ if [ "$INSTALL_LIBCEC" == "yes" ]; then virtualization/Docker/scripts/libcec fi -if [ "$INSTALL_PHANTOMJS" == "yes" ]; then - virtualization/Docker/scripts/phantomjs -fi - if [ "$INSTALL_SSOCR" == "yes" ]; then virtualization/Docker/scripts/ssocr fi From 800eb4d86a42849d0d519f536ba6eed7f5ed78be Mon Sep 17 00:00:00 2001 From: Khalid Date: Tue, 14 Aug 2018 12:55:40 +0300 Subject: [PATCH 023/159] Fix issue when reading worxlandroid pin code (#15930) Fixes #14050 --- homeassistant/components/sensor/worxlandroid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/worxlandroid.py b/homeassistant/components/sensor/worxlandroid.py index c49ce36bd49..8963bb135e0 100644 --- a/homeassistant/components/sensor/worxlandroid.py +++ b/homeassistant/components/sensor/worxlandroid.py @@ -28,7 +28,7 @@ DEFAULT_TIMEOUT = 5 PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_HOST): cv.string, vol.Required(CONF_PIN): - vol.All(vol.Coerce(int), vol.Range(min=1000, max=9999)), + vol.All(vol.Coerce(str), vol.Match(r'\d{4}')), vol.Optional(CONF_ALLOW_UNREACHABLE, default=True): cv.boolean, vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int, }) From 10a2ecd1d61ae3d2355301096ba096dcf3e065ab Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 14 Aug 2018 12:29:31 +0200 Subject: [PATCH 024/159] Make setup fail if location is not available (#15967) * Make setup fail if location is not available * Lint --- .../components/sensor/worldtidesinfo.py | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/sensor/worldtidesinfo.py b/homeassistant/components/sensor/worldtidesinfo.py index 597a971e208..adaa327d39a 100644 --- a/homeassistant/components/sensor/worldtidesinfo.py +++ b/homeassistant/components/sensor/worldtidesinfo.py @@ -1,24 +1,26 @@ """ -This component provides HA sensor support for the worldtides.info API. +Support for the worldtides.info API. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.worldtidesinfo/ """ +from datetime import timedelta import logging import time -from datetime import timedelta import requests import voluptuous as vol -import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import (CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, - CONF_NAME, STATE_UNKNOWN) +from homeassistant.const import ( + ATTR_ATTRIBUTION, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME) +import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) +CONF_ATTRIBUTION = "Data provided by WorldTides" + DEFAULT_NAME = 'WorldTidesInfo' SCAN_INTERVAL = timedelta(seconds=3600) @@ -42,7 +44,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if None in (lat, lon): _LOGGER.error("Latitude or longitude not set in Home Assistant config") - add_devices([WorldTidesInfoSensor(name, lat, lon, key)], True) + tides = WorldTidesInfoSensor(name, lat, lon, key) + tides.update() + if tides.data.get('error') == 'No location found': + _LOGGER.error("Location not available") + return + + add_devices([tides]) class WorldTidesInfoSensor(Entity): @@ -64,13 +72,14 @@ class WorldTidesInfoSensor(Entity): @property def device_state_attributes(self): """Return the state attributes of this device.""" - attr = {} - if "High" in str(self.data['extremes'][0]['type']): + attr = {ATTR_ATTRIBUTION: CONF_ATTRIBUTION} + + if 'High' in str(self.data['extremes'][0]['type']): attr['high_tide_time_utc'] = self.data['extremes'][0]['date'] attr['high_tide_height'] = self.data['extremes'][0]['height'] attr['low_tide_time_utc'] = self.data['extremes'][1]['date'] attr['low_tide_height'] = self.data['extremes'][1]['height'] - elif "Low" in str(self.data['extremes'][0]['type']): + elif 'Low' in str(self.data['extremes'][0]['type']): attr['high_tide_time_utc'] = self.data['extremes'][1]['date'] attr['high_tide_height'] = self.data['extremes'][1]['height'] attr['low_tide_time_utc'] = self.data['extremes'][0]['date'] @@ -81,30 +90,30 @@ class WorldTidesInfoSensor(Entity): def state(self): """Return the state of the device.""" if self.data: - if "High" in str(self.data['extremes'][0]['type']): + if 'High' in str(self.data['extremes'][0]['type']): tidetime = time.strftime('%I:%M %p', time.localtime( self.data['extremes'][0]['dt'])) - return "High tide at %s" % (tidetime) - if "Low" in str(self.data['extremes'][0]['type']): + return "High tide at {}".format(tidetime) + if 'Low' in str(self.data['extremes'][0]['type']): tidetime = time.strftime('%I:%M %p', time.localtime( self.data['extremes'][0]['dt'])) - return "Low tide at %s" % (tidetime) - return STATE_UNKNOWN - return STATE_UNKNOWN + return "Low tide at {}".format(tidetime) + return None + return None def update(self): """Get the latest data from WorldTidesInfo API.""" start = int(time.time()) - resource = 'https://www.worldtides.info/api?extremes&length=86400' \ - '&key=%s&lat=%s&lon=%s&start=%s' % (self._key, self._lat, - self._lon, start) + resource = ('https://www.worldtides.info/api?extremes&length=86400' + '&key={}&lat={}&lon={}&start={}').format( + self._key, self._lat, self._lon, start) try: self.data = requests.get(resource, timeout=10).json() - _LOGGER.debug("Data = %s", self.data) - _LOGGER.info("Tide data queried with start time set to: %s", - (start)) + _LOGGER.debug("Data: %s", self.data) + _LOGGER.debug( + "Tide data queried with start time set to: %s", start) except ValueError as err: - _LOGGER.error("Check WorldTidesInfo %s", err.args) + _LOGGER.error( + "Error retrieving data from WorldTidesInfo: %s", err.args) self.data = None - raise From 91e1ae035e06399dc5d176c965f70227bb917643 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 12:29:55 +0200 Subject: [PATCH 025/159] Remove warning (#15969) --- homeassistant/components/services.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index 6b8bded59b8..62da489aab4 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -506,9 +506,9 @@ homeassistant: reload_core_config: description: Reload the core configuration. restart: - description: Restart the Home Assistant service. It is normal to get a "Failed to call service homeassistant/restart" message. + description: Restart the Home Assistant service. stop: - description: Stop the Home Assistant service. It is normal to get a "Failed to call service homeassistant/stop" message. + description: Stop the Home Assistant service. toggle: description: Generic service to toggle devices on/off under any domain. Same usage as the light.turn_on, switch.turn_on, etc. services. fields: From 051903d30cbf70d171a8f0f8f9581962422b86c4 Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Tue, 14 Aug 2018 07:49:04 -0400 Subject: [PATCH 026/159] Update waterfurnace library to 0.7, add reconnect logic (#15657) One of the features of the waterfurnace 0.7 is timingout out stuck connections on the websocket (which tends to happen after 48 - 96 hours of operation). This requires the homeassistant component to catch and reconnect under these circumstances. This has turned out to be pretty robust in preventing stuck sockets over the last month. --- homeassistant/components/waterfurnace.py | 53 +++++++++++++++++------- requirements_all.txt | 2 +- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/waterfurnace.py b/homeassistant/components/waterfurnace.py index a587285e0ba..de49b5cd437 100644 --- a/homeassistant/components/waterfurnace.py +++ b/homeassistant/components/waterfurnace.py @@ -18,7 +18,8 @@ from homeassistant.core import callback from homeassistant.helpers import config_validation as cv from homeassistant.helpers import discovery -REQUIREMENTS = ["waterfurnace==0.4.0"] + +REQUIREMENTS = ["waterfurnace==0.7.0"] _LOGGER = logging.getLogger(__name__) @@ -26,6 +27,11 @@ DOMAIN = "waterfurnace" UPDATE_TOPIC = DOMAIN + "_update" CONF_UNIT = "unit" SCAN_INTERVAL = timedelta(seconds=10) +ERROR_INTERVAL = timedelta(seconds=300) +MAX_FAILS = 10 +NOTIFICATION_ID = 'waterfurnace_website_notification' +NOTIFICATION_TITLE = 'WaterFurnace website status' + CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -80,6 +86,36 @@ class WaterFurnaceData(threading.Thread): self.unit = client.unit self.data = None self._shutdown = False + self._fails = 0 + + def _reconnect(self): + """Reconnect on a failure.""" + import waterfurnace.waterfurnace as wf + self._fails += 1 + if self._fails > MAX_FAILS: + _LOGGER.error( + "Failed to refresh login credentials. Thread stopped.") + self.hass.components.persistent_notification.create( + "Error:
Connection to waterfurnace website failed " + "the maximum number of times. Thread has stopped.", + title=NOTIFICATION_TITLE, + notification_id=NOTIFICATION_ID) + + self._shutdown = True + return + + # sleep first before the reconnect attempt + _LOGGER.debug("Sleeping for fail # %s", self._fails) + time.sleep(self._fails * ERROR_INTERVAL.seconds) + + try: + self.client.login() + self.data = self.client.read() + except wf.WFException: + _LOGGER.exception("Failed to reconnect attempt %s", self._fails) + else: + _LOGGER.debug("Reconnected to furnace") + self._fails = 0 def run(self): """Thread run loop.""" @@ -117,20 +153,7 @@ class WaterFurnaceData(threading.Thread): # that pretty much can all be solved by logging in and # back out again. _LOGGER.exception("Failed to read data, attempting to recover") - try: - self.client.login() - except Exception: # pylint: disable=broad-except - # nested exception handling, something really bad - # happened during the login, which means we're not - # in a recoverable state. Stop the thread so we - # don't do just keep poking at the service. - _LOGGER.error( - "Failed to refresh login credentials. Thread stopped.") - return - else: - _LOGGER.error( - "Lost our connection to websocket, trying again") - time.sleep(SCAN_INTERVAL.seconds) + self._reconnect() else: self.hass.helpers.dispatcher.dispatcher_send(UPDATE_TOPIC) diff --git a/requirements_all.txt b/requirements_all.txt index c667848e940..e97d03a7c1f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1444,7 +1444,7 @@ warrant==0.6.1 watchdog==0.8.3 # homeassistant.components.waterfurnace -waterfurnace==0.4.0 +waterfurnace==0.7.0 # homeassistant.components.media_player.gpmdp websocket-client==0.37.0 From ee5d49a033e5b95801863f31b2e68f54c9358b2b Mon Sep 17 00:00:00 2001 From: kbickar Date: Tue, 14 Aug 2018 09:50:44 -0400 Subject: [PATCH 027/159] Added error handling for sense API timeouts (#15789) * Added error handling for sense API timeouts * Moved imports in function * Moved imports to more appropriate function * Change exception to custom package version --- homeassistant/components/sensor/sense.py | 9 +++++++-- requirements_all.txt | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sensor/sense.py b/homeassistant/components/sensor/sense.py index 16f4ccb9b6c..89e0d15bf48 100644 --- a/homeassistant/components/sensor/sense.py +++ b/homeassistant/components/sensor/sense.py @@ -16,7 +16,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['sense_energy==0.3.1'] +REQUIREMENTS = ['sense_energy==0.4.1'] _LOGGER = logging.getLogger(__name__) @@ -139,7 +139,12 @@ class Sense(Entity): def update(self): """Get the latest data, update state.""" - self.update_sensor() + from sense_energy import SenseAPITimeoutException + try: + self.update_sensor() + except SenseAPITimeoutException: + _LOGGER.error("Timeout retrieving data") + return if self._sensor_type == ACTIVE_TYPE: if self._is_production: diff --git a/requirements_all.txt b/requirements_all.txt index e97d03a7c1f..52c3168991d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1265,7 +1265,7 @@ sendgrid==5.4.1 sense-hat==2.2.0 # homeassistant.components.sensor.sense -sense_energy==0.3.1 +sense_energy==0.4.1 # homeassistant.components.media_player.aquostv sharp_aquos_rc==0.3.2 From e776f88eecc6cd543a7749cc9b0a38660eb33e77 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 21:14:12 +0200 Subject: [PATCH 028/159] Use JWT for access tokens (#15972) * Use JWT for access tokens * Update requirements * Improvements --- homeassistant/auth/__init__.py | 64 +++++++++++++------ homeassistant/auth/auth_store.py | 56 ++++++++-------- homeassistant/auth/models.py | 22 +------ homeassistant/components/auth/__init__.py | 6 +- homeassistant/components/http/auth.py | 6 +- homeassistant/components/websocket_api.py | 9 +-- homeassistant/package_constraints.txt | 1 + requirements_all.txt | 1 + setup.py | 1 + tests/auth/test_init.py | 45 ++++--------- tests/common.py | 14 ++-- tests/components/auth/test_init.py | 24 +++++-- tests/components/auth/test_init_link_user.py | 2 +- tests/components/config/test_auth.py | 16 +++-- .../test_auth_provider_homeassistant.py | 38 ++++++++--- tests/components/conftest.py | 2 +- tests/components/hassio/test_init.py | 6 +- tests/components/http/test_auth.py | 8 ++- tests/components/test_api.py | 22 +++++-- tests/components/test_websocket_api.py | 15 +++-- 20 files changed, 203 insertions(+), 155 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 9695e77f6f1..148f97702e3 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -4,10 +4,12 @@ import logging from collections import OrderedDict from typing import List, Awaitable +import jwt + from homeassistant import data_entry_flow from homeassistant.core import callback, HomeAssistant +from homeassistant.util import dt as dt_util -from . import models from . import auth_store from .providers import auth_provider_from_config @@ -54,7 +56,6 @@ class AuthManager: self.login_flow = data_entry_flow.FlowManager( hass, self._async_create_login_flow, self._async_finish_login_flow) - self._access_tokens = OrderedDict() @property def active(self): @@ -181,35 +182,56 @@ class AuthManager: return await self._store.async_create_refresh_token(user, client_id) - async def async_get_refresh_token(self, token): + async def async_get_refresh_token(self, token_id): + """Get refresh token by id.""" + return await self._store.async_get_refresh_token(token_id) + + async def async_get_refresh_token_by_token(self, token): """Get refresh token by token.""" - return await self._store.async_get_refresh_token(token) + return await self._store.async_get_refresh_token_by_token(token) @callback def async_create_access_token(self, refresh_token): """Create a new access token.""" - access_token = models.AccessToken(refresh_token=refresh_token) - self._access_tokens[access_token.token] = access_token - return access_token + # pylint: disable=no-self-use + return jwt.encode({ + 'iss': refresh_token.id, + 'iat': dt_util.utcnow(), + 'exp': dt_util.utcnow() + refresh_token.access_token_expiration, + }, refresh_token.jwt_key, algorithm='HS256').decode() - @callback - def async_get_access_token(self, token): - """Get an access token.""" - tkn = self._access_tokens.get(token) - - if tkn is None: - _LOGGER.debug('Attempt to get non-existing access token') + async def async_validate_access_token(self, token): + """Return if an access token is valid.""" + try: + unverif_claims = jwt.decode(token, verify=False) + except jwt.InvalidTokenError: return None - if tkn.expired or not tkn.refresh_token.user.is_active: - if tkn.expired: - _LOGGER.debug('Attempt to get expired access token') - else: - _LOGGER.debug('Attempt to get access token for inactive user') - self._access_tokens.pop(token) + refresh_token = await self.async_get_refresh_token( + unverif_claims.get('iss')) + + if refresh_token is None: + jwt_key = '' + issuer = '' + else: + jwt_key = refresh_token.jwt_key + issuer = refresh_token.id + + try: + jwt.decode( + token, + jwt_key, + leeway=10, + issuer=issuer, + algorithms=['HS256'] + ) + except jwt.InvalidTokenError: return None - return tkn + if not refresh_token.user.is_active: + return None + + return refresh_token async def _async_create_login_flow(self, handler, *, context, data): """Create a login flow.""" diff --git a/homeassistant/auth/auth_store.py b/homeassistant/auth/auth_store.py index 8fd66d4bbb7..806cd109d78 100644 --- a/homeassistant/auth/auth_store.py +++ b/homeassistant/auth/auth_store.py @@ -1,6 +1,7 @@ """Storage for auth models.""" from collections import OrderedDict from datetime import timedelta +import hmac from homeassistant.util import dt as dt_util @@ -110,22 +111,36 @@ class AuthStore: async def async_create_refresh_token(self, user, client_id=None): """Create a new token for a user.""" refresh_token = models.RefreshToken(user=user, client_id=client_id) - user.refresh_tokens[refresh_token.token] = refresh_token + user.refresh_tokens[refresh_token.id] = refresh_token await self.async_save() return refresh_token - async def async_get_refresh_token(self, token): - """Get refresh token by token.""" + async def async_get_refresh_token(self, token_id): + """Get refresh token by id.""" if self._users is None: await self.async_load() for user in self._users.values(): - refresh_token = user.refresh_tokens.get(token) + refresh_token = user.refresh_tokens.get(token_id) if refresh_token is not None: return refresh_token return None + async def async_get_refresh_token_by_token(self, token): + """Get refresh token by token.""" + if self._users is None: + await self.async_load() + + found = None + + for user in self._users.values(): + for refresh_token in user.refresh_tokens.values(): + if hmac.compare_digest(refresh_token.token, token): + found = refresh_token + + return found + async def async_load(self): """Load the users.""" data = await self._store.async_load() @@ -153,9 +168,11 @@ class AuthStore: data=cred_dict['data'], )) - refresh_tokens = OrderedDict() - for rt_dict in data['refresh_tokens']: + # Filter out the old keys that don't have jwt_key (pre-0.76) + if 'jwt_key' not in rt_dict: + continue + token = models.RefreshToken( id=rt_dict['id'], user=users[rt_dict['user_id']], @@ -164,18 +181,9 @@ class AuthStore: access_token_expiration=timedelta( seconds=rt_dict['access_token_expiration']), token=rt_dict['token'], + jwt_key=rt_dict['jwt_key'] ) - refresh_tokens[token.id] = token - users[rt_dict['user_id']].refresh_tokens[token.token] = token - - for ac_dict in data['access_tokens']: - refresh_token = refresh_tokens[ac_dict['refresh_token_id']] - token = models.AccessToken( - refresh_token=refresh_token, - created_at=dt_util.parse_datetime(ac_dict['created_at']), - token=ac_dict['token'], - ) - refresh_token.access_tokens.append(token) + users[rt_dict['user_id']].refresh_tokens[token.id] = token self._users = users @@ -213,27 +221,15 @@ class AuthStore: 'access_token_expiration': refresh_token.access_token_expiration.total_seconds(), 'token': refresh_token.token, + 'jwt_key': refresh_token.jwt_key, } for user in self._users.values() for refresh_token in user.refresh_tokens.values() ] - access_tokens = [ - { - 'id': user.id, - 'refresh_token_id': refresh_token.id, - 'created_at': access_token.created_at.isoformat(), - 'token': access_token.token, - } - for user in self._users.values() - for refresh_token in user.refresh_tokens.values() - for access_token in refresh_token.access_tokens - ] - data = { 'users': users, 'credentials': credentials, - 'access_tokens': access_tokens, 'refresh_tokens': refresh_tokens, } diff --git a/homeassistant/auth/models.py b/homeassistant/auth/models.py index 38e054dc7cf..3f49c56bce6 100644 --- a/homeassistant/auth/models.py +++ b/homeassistant/auth/models.py @@ -39,26 +39,8 @@ class RefreshToken: default=ACCESS_TOKEN_EXPIRATION) token = attr.ib(type=str, default=attr.Factory(lambda: generate_secret(64))) - access_tokens = attr.ib(type=list, default=attr.Factory(list), cmp=False) - - -@attr.s(slots=True) -class AccessToken: - """Access token to access the API. - - These will only ever be stored in memory and not be persisted. - """ - - refresh_token = attr.ib(type=RefreshToken) - created_at = attr.ib(type=datetime, default=attr.Factory(dt_util.utcnow)) - token = attr.ib(type=str, - default=attr.Factory(generate_secret)) - - @property - def expired(self): - """Return if this token has expired.""" - expires = self.created_at + self.refresh_token.access_token_expiration - return dt_util.utcnow() > expires + jwt_key = attr.ib(type=str, + default=attr.Factory(lambda: generate_secret(64))) @attr.s(slots=True) diff --git a/homeassistant/components/auth/__init__.py b/homeassistant/components/auth/__init__.py index 0b2b4fb1a2e..102bfe58b55 100644 --- a/homeassistant/components/auth/__init__.py +++ b/homeassistant/components/auth/__init__.py @@ -155,7 +155,7 @@ class GrantTokenView(HomeAssistantView): access_token = hass.auth.async_create_access_token(refresh_token) return self.json({ - 'access_token': access_token.token, + 'access_token': access_token, 'token_type': 'Bearer', 'refresh_token': refresh_token.token, 'expires_in': @@ -178,7 +178,7 @@ class GrantTokenView(HomeAssistantView): 'error': 'invalid_request', }, status_code=400) - refresh_token = await hass.auth.async_get_refresh_token(token) + refresh_token = await hass.auth.async_get_refresh_token_by_token(token) if refresh_token is None: return self.json({ @@ -193,7 +193,7 @@ class GrantTokenView(HomeAssistantView): access_token = hass.auth.async_create_access_token(refresh_token) return self.json({ - 'access_token': access_token.token, + 'access_token': access_token, 'token_type': 'Bearer', 'expires_in': int(refresh_token.access_token_expiration.total_seconds()), diff --git a/homeassistant/components/http/auth.py b/homeassistant/components/http/auth.py index 77621e3bc7c..d01d1b50c5a 100644 --- a/homeassistant/components/http/auth.py +++ b/homeassistant/components/http/auth.py @@ -106,11 +106,11 @@ async def async_validate_auth_header(request, api_password=None): if auth_type == 'Bearer': hass = request.app['hass'] - access_token = hass.auth.async_get_access_token(auth_val) - if access_token is None: + refresh_token = await hass.auth.async_validate_access_token(auth_val) + if refresh_token is None: return False - request['hass_user'] = access_token.refresh_token.user + request['hass_user'] = refresh_token.user return True if auth_type == 'Basic' and api_password is not None: diff --git a/homeassistant/components/websocket_api.py b/homeassistant/components/websocket_api.py index 2a1e808188a..36811337ec1 100644 --- a/homeassistant/components/websocket_api.py +++ b/homeassistant/components/websocket_api.py @@ -355,11 +355,12 @@ class ActiveConnection: if self.hass.auth.active and 'access_token' in msg: self.debug("Received access_token") - token = self.hass.auth.async_get_access_token( - msg['access_token']) - authenticated = token is not None + refresh_token = \ + await self.hass.auth.async_validate_access_token( + msg['access_token']) + authenticated = refresh_token is not None if authenticated: - request['hass_user'] = token.refresh_token.user + request['hass_user'] = refresh_token.user elif ((not self.hass.auth.active or self.hass.auth.support_legacy) and diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 29e10838f21..3aa1e3643c6 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -4,6 +4,7 @@ async_timeout==3.0.0 attrs==18.1.0 certifi>=2018.04.16 jinja2>=2.10 +PyJWT==1.6.4 pip>=8.0.3 pytz>=2018.04 pyyaml>=3.13,<4 diff --git a/requirements_all.txt b/requirements_all.txt index 52c3168991d..cf64fde7c64 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -5,6 +5,7 @@ async_timeout==3.0.0 attrs==18.1.0 certifi>=2018.04.16 jinja2>=2.10 +PyJWT==1.6.4 pip>=8.0.3 pytz>=2018.04 pyyaml>=3.13,<4 diff --git a/setup.py b/setup.py index b319df9067d..bd1e70aa8ae 100755 --- a/setup.py +++ b/setup.py @@ -38,6 +38,7 @@ REQUIRES = [ 'attrs==18.1.0', 'certifi>=2018.04.16', 'jinja2>=2.10', + 'PyJWT==1.6.4', 'pip>=8.0.3', 'pytz>=2018.04', 'pyyaml>=3.13,<4', diff --git a/tests/auth/test_init.py b/tests/auth/test_init.py index cad4bbdbd71..da5daca7cf6 100644 --- a/tests/auth/test_init.py +++ b/tests/auth/test_init.py @@ -199,9 +199,7 @@ async def test_saving_loading(hass, hass_storage): }) user = await manager.async_get_or_create_user(step['result']) await manager.async_activate_user(user) - refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID) - - manager.async_create_access_token(refresh_token) + await manager.async_create_refresh_token(user, CLIENT_ID) await flush_store(manager._store._store) @@ -211,30 +209,6 @@ async def test_saving_loading(hass, hass_storage): assert users[0] == user -def test_access_token_expired(): - """Test that the expired property on access tokens work.""" - refresh_token = auth_models.RefreshToken( - user=None, - client_id='bla' - ) - - access_token = auth_models.AccessToken( - refresh_token=refresh_token - ) - - assert access_token.expired is False - - with patch('homeassistant.util.dt.utcnow', - return_value=dt_util.utcnow() + - auth_const.ACCESS_TOKEN_EXPIRATION): - assert access_token.expired is True - - almost_exp = \ - dt_util.utcnow() + auth_const.ACCESS_TOKEN_EXPIRATION - timedelta(1) - with patch('homeassistant.util.dt.utcnow', return_value=almost_exp): - assert access_token.expired is False - - async def test_cannot_retrieve_expired_access_token(hass): """Test that we cannot retrieve expired access tokens.""" manager = await auth.auth_manager_from_config(hass, []) @@ -244,15 +218,20 @@ async def test_cannot_retrieve_expired_access_token(hass): assert refresh_token.client_id == CLIENT_ID access_token = manager.async_create_access_token(refresh_token) - assert manager.async_get_access_token(access_token.token) is access_token + assert ( + await manager.async_validate_access_token(access_token) + is refresh_token + ) with patch('homeassistant.util.dt.utcnow', - return_value=dt_util.utcnow() + - auth_const.ACCESS_TOKEN_EXPIRATION): - assert manager.async_get_access_token(access_token.token) is None + return_value=dt_util.utcnow() - + auth_const.ACCESS_TOKEN_EXPIRATION - timedelta(seconds=11)): + access_token = manager.async_create_access_token(refresh_token) - # Even with unpatched time, it should have been removed from manager - assert manager.async_get_access_token(access_token.token) is None + assert ( + await manager.async_validate_access_token(access_token) + is None + ) async def test_generating_system_user(hass): diff --git a/tests/common.py b/tests/common.py index df333cca735..81e4774ccd4 100644 --- a/tests/common.py +++ b/tests/common.py @@ -314,12 +314,18 @@ def mock_registry(hass, mock_entries=None): class MockUser(auth_models.User): """Mock a user in Home Assistant.""" - def __init__(self, id='mock-id', is_owner=False, is_active=True, + def __init__(self, id=None, is_owner=False, is_active=True, name='Mock User', system_generated=False): """Initialize mock user.""" - super().__init__( - id=id, is_owner=is_owner, is_active=is_active, name=name, - system_generated=system_generated) + kwargs = { + 'is_owner': is_owner, + 'is_active': is_active, + 'name': name, + 'system_generated': system_generated + } + if id is not None: + kwargs['id'] = id + super().__init__(**kwargs) def add_to_hass(self, hass): """Test helper to add entry to hass.""" diff --git a/tests/components/auth/test_init.py b/tests/components/auth/test_init.py index eea768c96a0..f1a1bb5bd3c 100644 --- a/tests/components/auth/test_init.py +++ b/tests/components/auth/test_init.py @@ -44,7 +44,10 @@ async def test_login_new_user_and_trying_refresh_token(hass, aiohttp_client): assert resp.status == 200 tokens = await resp.json() - assert hass.auth.async_get_access_token(tokens['access_token']) is not None + assert ( + await hass.auth.async_validate_access_token(tokens['access_token']) + is not None + ) # Use refresh token to get more tokens. resp = await client.post('/auth/token', data={ @@ -56,7 +59,10 @@ async def test_login_new_user_and_trying_refresh_token(hass, aiohttp_client): assert resp.status == 200 tokens = await resp.json() assert 'refresh_token' not in tokens - assert hass.auth.async_get_access_token(tokens['access_token']) is not None + assert ( + await hass.auth.async_validate_access_token(tokens['access_token']) + is not None + ) # Test using access token to hit API. resp = await client.get('/api/') @@ -98,7 +104,9 @@ async def test_ws_current_user(hass, hass_ws_client, hass_access_token): } }) - user = hass_access_token.refresh_token.user + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + user = refresh_token.user credential = Credentials(auth_provider_type='homeassistant', auth_provider_id=None, data={}, id='test-id') @@ -169,7 +177,10 @@ async def test_refresh_token_system_generated(hass, aiohttp_client): assert resp.status == 200 tokens = await resp.json() - assert hass.auth.async_get_access_token(tokens['access_token']) is not None + assert ( + await hass.auth.async_validate_access_token(tokens['access_token']) + is not None + ) async def test_refresh_token_different_client_id(hass, aiohttp_client): @@ -208,4 +219,7 @@ async def test_refresh_token_different_client_id(hass, aiohttp_client): assert resp.status == 200 tokens = await resp.json() - assert hass.auth.async_get_access_token(tokens['access_token']) is not None + assert ( + await hass.auth.async_validate_access_token(tokens['access_token']) + is not None + ) diff --git a/tests/components/auth/test_init_link_user.py b/tests/components/auth/test_init_link_user.py index 13515db87fa..e209e0ee856 100644 --- a/tests/components/auth/test_init_link_user.py +++ b/tests/components/auth/test_init_link_user.py @@ -52,7 +52,7 @@ async def async_get_code(hass, aiohttp_client): 'user': user, 'code': step['result'], 'client': client, - 'access_token': access_token.token, + 'access_token': access_token, } diff --git a/tests/components/config/test_auth.py b/tests/components/config/test_auth.py index fe8f351955f..cd04eedf08e 100644 --- a/tests/components/config/test_auth.py +++ b/tests/components/config/test_auth.py @@ -122,11 +122,13 @@ async def test_delete_unable_self_account(hass, hass_ws_client, hass_access_token): """Test we cannot delete our own account.""" client = await hass_ws_client(hass, hass_access_token) + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) await client.send_json({ 'id': 5, 'type': auth_config.WS_TYPE_DELETE, - 'user_id': hass_access_token.refresh_token.user.id, + 'user_id': refresh_token.user.id, }) result = await client.receive_json() @@ -137,7 +139,9 @@ async def test_delete_unable_self_account(hass, hass_ws_client, async def test_delete_unknown_user(hass, hass_ws_client, hass_access_token): """Test we cannot delete an unknown user.""" client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True await client.send_json({ 'id': 5, @@ -153,7 +157,9 @@ async def test_delete_unknown_user(hass, hass_ws_client, hass_access_token): async def test_delete(hass, hass_ws_client, hass_access_token): """Test delete command works.""" client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True test_user = MockUser( id='efg', ).add_to_hass(hass) @@ -174,7 +180,9 @@ async def test_delete(hass, hass_ws_client, hass_access_token): async def test_create(hass, hass_ws_client, hass_access_token): """Test create command works.""" client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True assert len(await hass.auth.async_get_users()) == 1 diff --git a/tests/components/config/test_auth_provider_homeassistant.py b/tests/components/config/test_auth_provider_homeassistant.py index cd2cbc44539..a374083c2ab 100644 --- a/tests/components/config/test_auth_provider_homeassistant.py +++ b/tests/components/config/test_auth_provider_homeassistant.py @@ -9,7 +9,7 @@ from tests.common import MockUser, register_auth_provider @pytest.fixture(autouse=True) -def setup_config(hass, aiohttp_client): +def setup_config(hass): """Fixture that sets up the auth provider homeassistant module.""" hass.loop.run_until_complete(register_auth_provider(hass, { 'type': 'homeassistant' @@ -22,7 +22,9 @@ async def test_create_auth_system_generated_user(hass, hass_access_token, """Test we can't add auth to system generated users.""" system_user = MockUser(system_generated=True).add_to_hass(hass) client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True await client.send_json({ 'id': 5, @@ -47,7 +49,9 @@ async def test_create_auth_unknown_user(hass_ws_client, hass, hass_access_token): """Test create pointing at unknown user.""" client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True await client.send_json({ 'id': 5, @@ -86,7 +90,9 @@ async def test_create_auth(hass, hass_ws_client, hass_access_token, """Test create auth command works.""" client = await hass_ws_client(hass, hass_access_token) user = MockUser().add_to_hass(hass) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True assert len(user.credentials) == 0 @@ -117,7 +123,9 @@ async def test_create_auth_duplicate_username(hass, hass_ws_client, """Test we can't create auth with a duplicate username.""" client = await hass_ws_client(hass, hass_access_token) user = MockUser().add_to_hass(hass) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True hass_storage[prov_ha.STORAGE_KEY] = { 'version': 1, @@ -145,7 +153,9 @@ async def test_delete_removes_just_auth(hass_ws_client, hass, hass_storage, hass_access_token): """Test deleting an auth without being connected to a user.""" client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True hass_storage[prov_ha.STORAGE_KEY] = { 'version': 1, @@ -171,7 +181,9 @@ async def test_delete_removes_credential(hass, hass_ws_client, hass_access_token, hass_storage): """Test deleting auth that is connected to a user.""" client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True user = MockUser().add_to_hass(hass) user.credentials.append( @@ -216,7 +228,9 @@ async def test_delete_requires_owner(hass, hass_ws_client, hass_access_token): async def test_delete_unknown_auth(hass, hass_ws_client, hass_access_token): """Test trying to delete an unknown auth username.""" client = await hass_ws_client(hass, hass_access_token) - hass_access_token.refresh_token.user.is_owner = True + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_owner = True await client.send_json({ 'id': 5, @@ -240,7 +254,9 @@ async def test_change_password(hass, hass_ws_client, hass_access_token): 'username': 'test-user' }) - user = hass_access_token.refresh_token.user + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + user = refresh_token.user await hass.auth.async_link_user(user, credentials) client = await hass_ws_client(hass, hass_access_token) @@ -268,7 +284,9 @@ async def test_change_password_wrong_pw(hass, hass_ws_client, 'username': 'test-user' }) - user = hass_access_token.refresh_token.user + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + user = refresh_token.user await hass.auth.async_link_user(user, credentials) client = await hass_ws_client(hass, hass_access_token) diff --git a/tests/components/conftest.py b/tests/components/conftest.py index 5f6a17a4101..bb9b643296e 100644 --- a/tests/components/conftest.py +++ b/tests/components/conftest.py @@ -28,7 +28,7 @@ def hass_ws_client(aiohttp_client): await websocket.send_json({ 'type': websocket_api.TYPE_AUTH, - 'access_token': access_token.token + 'access_token': access_token }) auth_ok = await websocket.receive_json() diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index b1975669731..4fd59dd3f7a 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -106,7 +106,11 @@ async def test_setup_api_push_api_data_default(hass, aioclient_mock, ) assert hassio_user is not None assert hassio_user.system_generated - assert refresh_token in hassio_user.refresh_tokens + for token in hassio_user.refresh_tokens.values(): + if token.token == refresh_token: + break + else: + assert False, 'refresh token not found' async def test_setup_api_push_api_data_no_auth(hass, aioclient_mock, diff --git a/tests/components/http/test_auth.py b/tests/components/http/test_auth.py index 31cba79a6c8..8e7a62e2e9f 100644 --- a/tests/components/http/test_auth.py +++ b/tests/components/http/test_auth.py @@ -156,9 +156,9 @@ async def test_access_with_trusted_ip(app2, aiohttp_client): async def test_auth_active_access_with_access_token_in_header( - app, aiohttp_client, hass_access_token): + hass, app, aiohttp_client, hass_access_token): """Test access with access token in header.""" - token = hass_access_token.token + token = hass_access_token setup_auth(app, [], True, api_password=None) client = await aiohttp_client(app) @@ -182,7 +182,9 @@ async def test_auth_active_access_with_access_token_in_header( '/', headers={'Authorization': 'BEARER {}'.format(token)}) assert req.status == 401 - hass_access_token.refresh_token.user.is_active = False + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_active = False req = await client.get( '/', headers={'Authorization': 'Bearer {}'.format(token)}) assert req.status == 401 diff --git a/tests/components/test_api.py b/tests/components/test_api.py index 09dc27e97c1..2be1168b86a 100644 --- a/tests/components/test_api.py +++ b/tests/components/test_api.py @@ -448,13 +448,15 @@ async def test_api_fire_event_context(hass, mock_api_client, await mock_api_client.post( const.URL_API_EVENTS_EVENT.format("test.event"), headers={ - 'authorization': 'Bearer {}'.format(hass_access_token.token) + 'authorization': 'Bearer {}'.format(hass_access_token) }) await hass.async_block_till_done() + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + assert len(test_value) == 1 - assert test_value[0].context.user_id == \ - hass_access_token.refresh_token.user.id + assert test_value[0].context.user_id == refresh_token.user.id async def test_api_call_service_context(hass, mock_api_client, @@ -465,12 +467,15 @@ async def test_api_call_service_context(hass, mock_api_client, await mock_api_client.post( '/api/services/test_domain/test_service', headers={ - 'authorization': 'Bearer {}'.format(hass_access_token.token) + 'authorization': 'Bearer {}'.format(hass_access_token) }) await hass.async_block_till_done() + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + assert len(calls) == 1 - assert calls[0].context.user_id == hass_access_token.refresh_token.user.id + assert calls[0].context.user_id == refresh_token.user.id async def test_api_set_state_context(hass, mock_api_client, hass_access_token): @@ -481,8 +486,11 @@ async def test_api_set_state_context(hass, mock_api_client, hass_access_token): 'state': 'on' }, headers={ - 'authorization': 'Bearer {}'.format(hass_access_token.token) + 'authorization': 'Bearer {}'.format(hass_access_token) }) + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + state = hass.states.get('light.kitchen') - assert state.context.user_id == hass_access_token.refresh_token.user.id + assert state.context.user_id == refresh_token.user.id diff --git a/tests/components/test_websocket_api.py b/tests/components/test_websocket_api.py index 1fac1af9f64..199a9d804f8 100644 --- a/tests/components/test_websocket_api.py +++ b/tests/components/test_websocket_api.py @@ -334,7 +334,7 @@ async def test_auth_active_with_token(hass, aiohttp_client, hass_access_token): await ws.send_json({ 'type': wapi.TYPE_AUTH, - 'access_token': hass_access_token.token + 'access_token': hass_access_token }) auth_msg = await ws.receive_json() @@ -344,7 +344,9 @@ async def test_auth_active_with_token(hass, aiohttp_client, hass_access_token): async def test_auth_active_user_inactive(hass, aiohttp_client, hass_access_token): """Test authenticating with a token.""" - hass_access_token.refresh_token.user.is_active = False + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + refresh_token.user.is_active = False assert await async_setup_component(hass, 'websocket_api', { 'http': { 'api_password': API_PASSWORD @@ -361,7 +363,7 @@ async def test_auth_active_user_inactive(hass, aiohttp_client, await ws.send_json({ 'type': wapi.TYPE_AUTH, - 'access_token': hass_access_token.token + 'access_token': hass_access_token }) auth_msg = await ws.receive_json() @@ -465,7 +467,7 @@ async def test_call_service_context_with_user(hass, aiohttp_client, await ws.send_json({ 'type': wapi.TYPE_AUTH, - 'access_token': hass_access_token.token + 'access_token': hass_access_token }) auth_msg = await ws.receive_json() @@ -484,12 +486,15 @@ async def test_call_service_context_with_user(hass, aiohttp_client, msg = await ws.receive_json() assert msg['success'] + refresh_token = await hass.auth.async_validate_access_token( + hass_access_token) + assert len(calls) == 1 call = calls[0] assert call.domain == 'domain_test' assert call.service == 'test_service' assert call.data == {'hello': 'world'} - assert call.context.user_id == hass_access_token.refresh_token.user.id + assert call.context.user_id == refresh_token.user.id async def test_call_service_context_no_user(hass, aiohttp_client): From c7f7912bca7ef83ff7fdd2299f9e03acf5a8bacd Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Tue, 14 Aug 2018 15:15:33 -0400 Subject: [PATCH 029/159] adds support for momentary and beep/blink switches (#15973) --- homeassistant/components/konnected.py | 34 +++++++++++++------- homeassistant/components/switch/konnected.py | 29 ++++++++++++----- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/konnected.py b/homeassistant/components/konnected.py index a3e9ff86ed0..9e85e85818d 100644 --- a/homeassistant/components/konnected.py +++ b/homeassistant/components/konnected.py @@ -32,6 +32,10 @@ DOMAIN = 'konnected' CONF_ACTIVATION = 'activation' CONF_API_HOST = 'api_host' +CONF_MOMENTARY = 'momentary' +CONF_PAUSE = 'pause' +CONF_REPEAT = 'repeat' + STATE_LOW = 'low' STATE_HIGH = 'high' @@ -53,7 +57,13 @@ _SWITCH_SCHEMA = vol.All( vol.Exclusive(CONF_ZONE, 'a_pin'): vol.Any(*ZONE_TO_PIN), vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_ACTIVATION, default=STATE_HIGH): - vol.All(vol.Lower, vol.Any(STATE_HIGH, STATE_LOW)) + vol.All(vol.Lower, vol.Any(STATE_HIGH, STATE_LOW)), + vol.Optional(CONF_MOMENTARY): + vol.All(vol.Coerce(int), vol.Range(min=10)), + vol.Optional(CONF_PAUSE): + vol.All(vol.Coerce(int), vol.Range(min=10)), + vol.Optional(CONF_REPEAT): + vol.All(vol.Coerce(int), vol.Range(min=-1)), }), cv.has_at_least_one_key(CONF_PIN, CONF_ZONE) ) @@ -185,7 +195,7 @@ class KonnectedDevice: sensors[pin].get('name'), sensors[pin].get(ATTR_STATE)) - actuators = {} + actuators = [] for entity in self.config().get(CONF_SWITCHES) or []: if 'zone' in entity: pin = ZONE_TO_PIN[entity['zone']] @@ -200,16 +210,18 @@ class KonnectedDevice: else: initial_state = None - actuators[pin] = { + act = { + CONF_PIN: pin, CONF_NAME: entity.get( CONF_NAME, 'Konnected {} Actuator {}'.format( self.device_id[6:], PIN_TO_ZONE[pin])), ATTR_STATE: initial_state, CONF_ACTIVATION: entity[CONF_ACTIVATION], - } - _LOGGER.debug('Set up actuator %s (initial state: %s)', - actuators[pin].get(CONF_NAME), - actuators[pin].get(ATTR_STATE)) + CONF_MOMENTARY: entity.get(CONF_MOMENTARY), + CONF_PAUSE: entity.get(CONF_PAUSE), + CONF_REPEAT: entity.get(CONF_REPEAT)} + actuators.append(act) + _LOGGER.debug('Set up actuator %s', act) device_data = { 'client': self.client, @@ -237,11 +249,10 @@ class KonnectedDevice: def actuator_configuration(self): """Return the configuration map for syncing actuators.""" - return [{'pin': p, + return [{'pin': data.get(CONF_PIN), 'trigger': (0 if data.get(CONF_ACTIVATION) in [0, STATE_LOW] else 1)} - for p, data in - self.stored_configuration[CONF_SWITCHES].items()] + for data in self.stored_configuration[CONF_SWITCHES]] def sync_device_config(self): """Sync the new pin configuration to the Konnected device.""" @@ -320,8 +331,7 @@ class KonnectedView(HomeAssistantView): if device is None: return self.json_message('unregistered device', status_code=HTTP_BAD_REQUEST) - pin_data = device[CONF_BINARY_SENSORS].get(pin_num) or \ - device[CONF_SWITCHES].get(pin_num) + pin_data = device[CONF_BINARY_SENSORS].get(pin_num) if pin_data is None: return self.json_message('unregistered sensor/actuator', diff --git a/homeassistant/components/switch/konnected.py b/homeassistant/components/switch/konnected.py index 53c6406b28a..06d3385f567 100644 --- a/homeassistant/components/switch/konnected.py +++ b/homeassistant/components/switch/konnected.py @@ -8,10 +8,11 @@ https://home-assistant.io/components/switch.konnected/ import logging from homeassistant.components.konnected import ( - DOMAIN as KONNECTED_DOMAIN, PIN_TO_ZONE, CONF_ACTIVATION, - STATE_LOW, STATE_HIGH) + DOMAIN as KONNECTED_DOMAIN, PIN_TO_ZONE, CONF_ACTIVATION, CONF_MOMENTARY, + CONF_PAUSE, CONF_REPEAT, STATE_LOW, STATE_HIGH) from homeassistant.helpers.entity import ToggleEntity -from homeassistant.const import (CONF_DEVICES, CONF_SWITCHES, ATTR_STATE) +from homeassistant.const import ( + CONF_DEVICES, CONF_SWITCHES, CONF_PIN, ATTR_STATE) _LOGGER = logging.getLogger(__name__) @@ -27,9 +28,9 @@ async def async_setup_platform(hass, config, async_add_devices, data = hass.data[KONNECTED_DOMAIN] device_id = discovery_info['device_id'] client = data[CONF_DEVICES][device_id]['client'] - switches = [KonnectedSwitch(device_id, pin_num, pin_data, client) - for pin_num, pin_data in - data[CONF_DEVICES][device_id][CONF_SWITCHES].items()] + switches = [ + KonnectedSwitch(device_id, pin_data.get(CONF_PIN), pin_data, client) + for pin_data in data[CONF_DEVICES][device_id][CONF_SWITCHES]] async_add_devices(switches) @@ -42,6 +43,9 @@ class KonnectedSwitch(ToggleEntity): self._device_id = device_id self._pin_num = pin_num self._activation = self._data.get(CONF_ACTIVATION, STATE_HIGH) + self._momentary = self._data.get(CONF_MOMENTARY) + self._pause = self._data.get(CONF_PAUSE) + self._repeat = self._data.get(CONF_REPEAT) self._state = self._boolean_state(self._data.get(ATTR_STATE)) self._name = self._data.get( 'name', 'Konnected {} Actuator {}'.format( @@ -62,10 +66,19 @@ class KonnectedSwitch(ToggleEntity): def turn_on(self, **kwargs): """Send a command to turn on the switch.""" resp = self._client.put_device( - self._pin_num, int(self._activation == STATE_HIGH)) + self._pin_num, + int(self._activation == STATE_HIGH), + self._momentary, + self._repeat, + self._pause + ) if resp.get(ATTR_STATE) is not None: - self._set_state(self._boolean_state(resp.get(ATTR_STATE))) + self._set_state(True) + + if self._momentary and resp.get(ATTR_STATE) != -1: + # Immediately set the state back off for momentary switches + self._set_state(self._boolean_state(False)) def turn_off(self, **kwargs): """Send a command to turn off the switch.""" From 0ad9fcd8a0b541117335e0ed2906e8f5b52ca796 Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Tue, 14 Aug 2018 20:28:29 +0100 Subject: [PATCH 030/159] Add -j$(nproc) make option to speed up build time (#15928) Adding `-j$(nproc)` reduces build time on the external dependencies by approximately 25%. --- virtualization/Docker/scripts/libcec | 4 ++-- virtualization/Docker/scripts/openalpr | 4 ++-- virtualization/Docker/scripts/ssocr | 4 ++-- virtualization/Docker/scripts/tellstick | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/virtualization/Docker/scripts/libcec b/virtualization/Docker/scripts/libcec index 56cbaeb16d7..481b3e700ac 100755 --- a/virtualization/Docker/scripts/libcec +++ b/virtualization/Docker/scripts/libcec @@ -41,7 +41,7 @@ git submodule update --init src/platform -DPYTHON_LIBRARY="${PYTHON_LIBRARY}" \ -DPYTHON_INCLUDE_DIR="${PYTHON_INCLUDE_DIR}" \ .. - make + make -j$(nproc) make install ldconfig -) \ No newline at end of file +) diff --git a/virtualization/Docker/scripts/openalpr b/virtualization/Docker/scripts/openalpr index 5ee36ecd4ed..b9e403710f1 100755 --- a/virtualization/Docker/scripts/openalpr +++ b/virtualization/Docker/scripts/openalpr @@ -26,7 +26,7 @@ cd build cmake -DWITH_TEST=FALSE -DWITH_BINDING_JAVA=FALSE --DWITH_BINDING_PYTHON=FALSE --DWITH_BINDING_GO=FALSE -DWITH_DAEMON=FALSE -DCMAKE_INSTALL_PREFIX:PATH=/usr/local .. # compile the library -make +make -j$(nproc) # Install the binaries/libraries to your local system (prefix is /usr/local) -make install \ No newline at end of file +make install diff --git a/virtualization/Docker/scripts/ssocr b/virtualization/Docker/scripts/ssocr index 7054951407a..6778bcab90d 100755 --- a/virtualization/Docker/scripts/ssocr +++ b/virtualization/Docker/scripts/ssocr @@ -18,7 +18,7 @@ git clone --depth 1 https://github.com/auerswal/ssocr.git ssocr cd ssocr/ # Compile the library -make +make -j$(nproc) # Install the binaries/libraries to your local system (prefix is /usr/local) -make install \ No newline at end of file +make install diff --git a/virtualization/Docker/scripts/tellstick b/virtualization/Docker/scripts/tellstick index d4bf8b331f3..c9658d14029 100755 --- a/virtualization/Docker/scripts/tellstick +++ b/virtualization/Docker/scripts/tellstick @@ -14,4 +14,4 @@ echo "deb http://download.telldus.com/debian/ stable main" >> /etc/apt/sources.l wget -qO - http://download.telldus.com/debian/telldus-public.key | apt-key add - apt-get update -apt-get install -y --no-install-recommends ${PACKAGES[@]} \ No newline at end of file +apt-get install -y --no-install-recommends ${PACKAGES[@]} From 486efa9aba1e07c1fcc495f39fa135ad674fefd5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 22:02:01 +0200 Subject: [PATCH 031/159] Pin crypto (#15978) * Pin crypto * Fix PyJWT import once --- homeassistant/components/notify/html5.py | 2 +- homeassistant/package_constraints.txt | 1 + requirements_all.txt | 4 +--- requirements_test_all.txt | 3 --- setup.py | 2 ++ 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/notify/html5.py b/homeassistant/components/notify/html5.py index e280aa67e40..1ed50472004 100644 --- a/homeassistant/components/notify/html5.py +++ b/homeassistant/components/notify/html5.py @@ -26,7 +26,7 @@ from homeassistant.const import ( from homeassistant.helpers import config_validation as cv from homeassistant.util import ensure_unique_string -REQUIREMENTS = ['pywebpush==1.6.0', 'PyJWT==1.6.0'] +REQUIREMENTS = ['pywebpush==1.6.0'] DEPENDENCIES = ['frontend'] diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 3aa1e3643c6..26628d7fe62 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -5,6 +5,7 @@ attrs==18.1.0 certifi>=2018.04.16 jinja2>=2.10 PyJWT==1.6.4 +cryptography==2.3.1 pip>=8.0.3 pytz>=2018.04 pyyaml>=3.13,<4 diff --git a/requirements_all.txt b/requirements_all.txt index cf64fde7c64..4736e4e4c6d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -6,6 +6,7 @@ attrs==18.1.0 certifi>=2018.04.16 jinja2>=2.10 PyJWT==1.6.4 +cryptography==2.3.1 pip>=8.0.3 pytz>=2018.04 pyyaml>=3.13,<4 @@ -39,9 +40,6 @@ Mastodon.py==1.3.1 # homeassistant.components.isy994 PyISY==1.1.0 -# homeassistant.components.notify.html5 -PyJWT==1.6.0 - # homeassistant.components.sensor.mvglive PyMVGLive==1.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ffc55c23210..4115fcfcb3f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -21,9 +21,6 @@ requests_mock==1.5.2 # homeassistant.components.homekit HAP-python==2.2.2 -# homeassistant.components.notify.html5 -PyJWT==1.6.0 - # homeassistant.components.sensor.rmvtransport PyRMVtransport==0.0.7 diff --git a/setup.py b/setup.py index bd1e70aa8ae..7484dc286e6 100755 --- a/setup.py +++ b/setup.py @@ -39,6 +39,8 @@ REQUIRES = [ 'certifi>=2018.04.16', 'jinja2>=2.10', 'PyJWT==1.6.4', + # PyJWT has loose dependency. We want the latest one. + 'cryptography==2.3.1', 'pip>=8.0.3', 'pytz>=2018.04', 'pyyaml>=3.13,<4', From 555184a4b729852584d72273790e06eb131f8c76 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 15 Aug 2018 07:49:34 +0200 Subject: [PATCH 032/159] Update Glances sensor (#15981) * Refactor Glances sensor * Add glances_api to requirements_all.txt * Add support for version as configuration option --- homeassistant/components/sensor/glances.py | 71 ++++++++++++++-------- requirements_all.txt | 3 + 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/homeassistant/components/sensor/glances.py b/homeassistant/components/sensor/glances.py index a6dfd89e45a..c2a6607334d 100644 --- a/homeassistant/components/sensor/glances.py +++ b/homeassistant/components/sensor/glances.py @@ -4,25 +4,30 @@ Support gathering system information of hosts which are running glances. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.glances/ """ -import logging from datetime import timedelta +import logging -import requests import voluptuous as vol -import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( - CONF_HOST, CONF_PORT, CONF_NAME, CONF_RESOURCES, TEMP_CELSIUS) + CONF_HOST, CONF_NAME, CONF_PORT, CONF_RESOURCES, TEMP_CELSIUS) +from homeassistant.exceptions import PlatformNotReady +from homeassistant.helpers.aiohttp_client import async_get_clientsession +import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle +REQUIREMENTS = ['glances_api==0.1.0'] + _LOGGER = logging.getLogger(__name__) -_RESOURCE = 'api/2/all' + +CONF_VERSION = 'version' DEFAULT_HOST = 'localhost' DEFAULT_NAME = 'Glances' DEFAULT_PORT = '61208' +DEFAULT_VERSION = 2 MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1) @@ -53,33 +58,43 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, vol.Optional(CONF_RESOURCES, default=['disk_use']): vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), + vol.Optional(CONF_VERSION, default=DEFAULT_VERSION): vol.In([2, 3]), }) -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Glances sensor.""" +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Set up the Glances sensors.""" + from glances_api import Glances + name = config.get(CONF_NAME) host = config.get(CONF_HOST) port = config.get(CONF_PORT) - url = 'http://{}:{}/{}'.format(host, port, _RESOURCE) + version = config.get(CONF_VERSION) var_conf = config.get(CONF_RESOURCES) - rest = GlancesData(url) - rest.update() + session = async_get_clientsession(hass) + glances = GlancesData( + Glances(hass.loop, session, host=host, port=port, version=version)) + + await glances.async_update() + + if glances.api.data is None: + raise PlatformNotReady dev = [] for resource in var_conf: - dev.append(GlancesSensor(rest, name, resource)) + dev.append(GlancesSensor(glances, name, resource)) - add_devices(dev, True) + async_add_devices(dev, True) class GlancesSensor(Entity): """Implementation of a Glances sensor.""" - def __init__(self, rest, name, sensor_type): + def __init__(self, glances, name, sensor_type): """Initialize the sensor.""" - self.rest = rest + self.glances = glances self._name = name self.type = sensor_type self._state = None @@ -103,17 +118,17 @@ class GlancesSensor(Entity): @property def available(self): """Could the device be accessed during the last update call.""" - return self.rest.data is not None + return self.glances.available @property def state(self): """Return the state of the resources.""" return self._state - def update(self): + async def async_update(self): """Get the latest data from REST API.""" - self.rest.update() - value = self.rest.data + await self.glances.async_update() + value = self.glances.api.data if value is not None: if self.type == 'disk_use_percent': @@ -179,17 +194,19 @@ class GlancesSensor(Entity): class GlancesData: """The class for handling the data retrieval.""" - def __init__(self, resource): + def __init__(self, api): """Initialize the data object.""" - self._resource = resource - self.data = {} + self.api = api + self.available = True @Throttle(MIN_TIME_BETWEEN_UPDATES) - def update(self): + async def async_update(self): """Get the latest data from the Glances REST API.""" + from glances_api.exceptions import GlancesApiError + try: - response = requests.get(self._resource, timeout=10) - self.data = response.json() - except requests.exceptions.ConnectionError: - _LOGGER.error("Connection error: %s", self._resource) - self.data = None + await self.api.get_data() + self.available = True + except GlancesApiError: + _LOGGER.error("Unable to fetch data from Glances") + self.available = False diff --git a/requirements_all.txt b/requirements_all.txt index 4736e4e4c6d..e9de6c91a72 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -386,6 +386,9 @@ gearbest_parser==1.0.7 # homeassistant.components.sensor.gitter gitterpy==0.1.7 +# homeassistant.components.sensor.glances +glances_api==0.1.0 + # homeassistant.components.notify.gntp gntp==1.0.3 From c31035d34898fd822229ba94e12ceea6e5dad2c1 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 14 Aug 2018 23:09:19 -0700 Subject: [PATCH 033/159] Teak mqtt error message for 0.76 release (#15983) --- homeassistant/components/mqtt/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 70d4d7aa5d7..19bacbc8d4c 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -354,11 +354,11 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool: if (conf.get(CONF_PASSWORD) is None and config.get('http') is not None and config['http'].get('api_password') is not None): - _LOGGER.error("Starting from 0.77, embedded MQTT broker doesn't" - " use api_password as default password any more." - " Please set password configuration. See https://" - "home-assistant.io/docs/mqtt/broker#embedded-broker" - " for details") + _LOGGER.error( + "Starting from release 0.76, the embedded MQTT broker does not" + " use api_password as default password anymore. Please set" + " password configuration. See https://home-assistant.io/docs/" + "mqtt/broker#embedded-broker for details") return False broker_config = await _async_setup_server(hass, config) From dc460f4d6a3faa246114d14a1f4c8a099e44710c Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 15 Aug 2018 00:56:05 -0700 Subject: [PATCH 034/159] Fix 0.76 beta2 hassio token issue (#15987) --- homeassistant/components/hassio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/hassio/__init__.py b/homeassistant/components/hassio/__init__.py index 13c486533d9..e0356017e3e 100644 --- a/homeassistant/components/hassio/__init__.py +++ b/homeassistant/components/hassio/__init__.py @@ -178,7 +178,7 @@ def async_setup(hass, config): refresh_token = None if 'hassio_user' in data: user = yield from hass.auth.async_get_user(data['hassio_user']) - if user: + if user and user.refresh_tokens: refresh_token = list(user.refresh_tokens.values())[0] if refresh_token is None: From 39fd70231f6baae9d53d37e9510343975eaf2114 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 15 Aug 2018 10:47:58 +0200 Subject: [PATCH 035/159] Upgrade psutil to 5.4.7 (#15982) --- homeassistant/components/sensor/systemmonitor.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 1883ee89d4e..b9a04e546d3 100644 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -15,7 +15,7 @@ from homeassistant.helpers.entity import Entity import homeassistant.helpers.config_validation as cv import homeassistant.util.dt as dt_util -REQUIREMENTS = ['psutil==5.4.6'] +REQUIREMENTS = ['psutil==5.4.7'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index e9de6c91a72..f51b801d5c1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -695,7 +695,7 @@ proliphix==0.4.1 prometheus_client==0.2.0 # homeassistant.components.sensor.systemmonitor -psutil==5.4.6 +psutil==5.4.7 # homeassistant.components.wink pubnubsub-handler==1.0.2 From 9cfbd067d3fd9287a13fedbf3f77f24d8ac92d4b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 15 Aug 2018 10:50:11 +0200 Subject: [PATCH 036/159] Update translations --- .../components/deconz/.translations/de.json | 3 ++- .../homematicip_cloud/.translations/de.json | 4 +++- .../homematicip_cloud/.translations/no.json | 2 +- .../homematicip_cloud/.translations/pt.json | 2 +- homeassistant/components/hue/.translations/de.json | 2 +- homeassistant/components/hue/.translations/ro.json | 4 ++++ homeassistant/components/nest/.translations/de.json | 2 ++ .../components/sensor/.translations/moon.ar.json | 6 ++++++ .../components/sensor/.translations/moon.ca.json | 12 ++++++++++++ .../components/sensor/.translations/moon.de.json | 12 ++++++++++++ .../components/sensor/.translations/moon.en.json | 12 ++++++++++++ .../components/sensor/.translations/moon.es-419.json | 12 ++++++++++++ .../components/sensor/.translations/moon.fr.json | 12 ++++++++++++ .../components/sensor/.translations/moon.ko.json | 12 ++++++++++++ .../components/sensor/.translations/moon.nl.json | 12 ++++++++++++ .../components/sensor/.translations/moon.no.json | 12 ++++++++++++ .../components/sensor/.translations/moon.ru.json | 12 ++++++++++++ .../components/sensor/.translations/moon.sl.json | 12 ++++++++++++ .../sensor/.translations/moon.zh-Hans.json | 12 ++++++++++++ .../sensor/.translations/moon.zh-Hant.json | 12 ++++++++++++ 20 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 homeassistant/components/sensor/.translations/moon.ar.json create mode 100644 homeassistant/components/sensor/.translations/moon.ca.json create mode 100644 homeassistant/components/sensor/.translations/moon.de.json create mode 100644 homeassistant/components/sensor/.translations/moon.en.json create mode 100644 homeassistant/components/sensor/.translations/moon.es-419.json create mode 100644 homeassistant/components/sensor/.translations/moon.fr.json create mode 100644 homeassistant/components/sensor/.translations/moon.ko.json create mode 100644 homeassistant/components/sensor/.translations/moon.nl.json create mode 100644 homeassistant/components/sensor/.translations/moon.no.json create mode 100644 homeassistant/components/sensor/.translations/moon.ru.json create mode 100644 homeassistant/components/sensor/.translations/moon.sl.json create mode 100644 homeassistant/components/sensor/.translations/moon.zh-Hans.json create mode 100644 homeassistant/components/sensor/.translations/moon.zh-Hant.json diff --git a/homeassistant/components/deconz/.translations/de.json b/homeassistant/components/deconz/.translations/de.json index b09b7e15b31..51b496906a2 100644 --- a/homeassistant/components/deconz/.translations/de.json +++ b/homeassistant/components/deconz/.translations/de.json @@ -24,7 +24,8 @@ "data": { "allow_clip_sensor": "Import virtueller Sensoren zulassen", "allow_deconz_groups": "Import von deCONZ-Gruppen zulassen" - } + }, + "title": "Weitere Konfigurationsoptionen f\u00fcr deCONZ" } }, "title": "deCONZ Zigbee Gateway" diff --git a/homeassistant/components/homematicip_cloud/.translations/de.json b/homeassistant/components/homematicip_cloud/.translations/de.json index 8e4130a3251..61a9bd6eb40 100644 --- a/homeassistant/components/homematicip_cloud/.translations/de.json +++ b/homeassistant/components/homematicip_cloud/.translations/de.json @@ -17,9 +17,11 @@ "hapid": "Accesspoint ID (SGTIN)", "name": "Name (optional, wird als Pr\u00e4fix f\u00fcr alle Ger\u00e4te verwendet)", "pin": "PIN Code (optional)" - } + }, + "title": "HometicIP Accesspoint ausw\u00e4hlen" }, "link": { + "description": "Dr\u00fccken Sie den blauen Taster auf dem Accesspoint, sowie den Senden Button um HomematicIP mit Home Assistant zu verbinden.\n\n![Position des Tasters auf dem AP](/static/images/config_flows/config_homematicip_cloud.png)", "title": "Verkn\u00fcpfe den Accesspoint" } }, diff --git a/homeassistant/components/homematicip_cloud/.translations/no.json b/homeassistant/components/homematicip_cloud/.translations/no.json index 7e164abd3bb..650c921af31 100644 --- a/homeassistant/components/homematicip_cloud/.translations/no.json +++ b/homeassistant/components/homematicip_cloud/.translations/no.json @@ -22,7 +22,7 @@ }, "link": { "description": "Trykk p\u00e5 den bl\u00e5 knappen p\u00e5 tilgangspunktet og send knappen for \u00e5 registrere HomematicIP med Home Assistant. \n\n![Plassering av knapp p\u00e5 bridge](/static/images/config_flows/config_homematicip_cloud.png)", - "title": "Link Tilgangspunkt" + "title": "Link tilgangspunkt" } }, "title": "HomematicIP Sky" diff --git a/homeassistant/components/homematicip_cloud/.translations/pt.json b/homeassistant/components/homematicip_cloud/.translations/pt.json index ef742e2ce5e..2266e83ac44 100644 --- a/homeassistant/components/homematicip_cloud/.translations/pt.json +++ b/homeassistant/components/homematicip_cloud/.translations/pt.json @@ -21,7 +21,7 @@ "title": "Escolher ponto de acesso HomematicIP" }, "link": { - "description": "Pressione o bot\u00e3o azul no accesspoint e o bot\u00e3o enviar para registrar HomematicIP com Home Assistant.\n\n! [Localiza\u00e7\u00e3o do bot\u00e3o na ponte] (/ static/images/config_flows/config_homematicip_cloud.png)", + "description": "Pressione o bot\u00e3o azul no ponto de acesso e o bot\u00e3o enviar para registrar HomematicIP com o Home Assistant.\n\n![Localiza\u00e7\u00e3o do bot\u00e3o na ponte](/ static/images/config_flows/config_homematicip_cloud.png)", "title": "Associar ponto de acesso" } }, diff --git a/homeassistant/components/hue/.translations/de.json b/homeassistant/components/hue/.translations/de.json index dc0968dc88a..a0bd50d8514 100644 --- a/homeassistant/components/hue/.translations/de.json +++ b/homeassistant/components/hue/.translations/de.json @@ -24,6 +24,6 @@ "title": "Hub verbinden" } }, - "title": "" + "title": "Philips Hue" } } \ No newline at end of file diff --git a/homeassistant/components/hue/.translations/ro.json b/homeassistant/components/hue/.translations/ro.json index 91541edcc7d..69cee1198d3 100644 --- a/homeassistant/components/hue/.translations/ro.json +++ b/homeassistant/components/hue/.translations/ro.json @@ -1,5 +1,9 @@ { "config": { + "abort": { + "all_configured": "Toate pun\u021bile Philips Hue sunt deja configurate", + "discover_timeout": "Imposibil de descoperit podurile Hue" + }, "error": { "linking": "A ap\u0103rut o eroare de leg\u0103tur\u0103 necunoscut\u0103.", "register_failed": "Nu a reu\u0219it \u00eenregistrarea, \u00eencerca\u021bi din nou" diff --git a/homeassistant/components/nest/.translations/de.json b/homeassistant/components/nest/.translations/de.json index 32c72ef7d96..86b50ab3c10 100644 --- a/homeassistant/components/nest/.translations/de.json +++ b/homeassistant/components/nest/.translations/de.json @@ -2,6 +2,8 @@ "config": { "abort": { "already_setup": "Sie k\u00f6nnen nur ein einziges Nest-Konto konfigurieren.", + "authorize_url_fail": "Unbekannter Fehler beim Erstellen der Authorisierungs-URL", + "authorize_url_timeout": "Zeit\u00fcberschreitung beim Erstellen der Authorisierungs-URL", "no_flows": "Sie m\u00fcssen Nest konfigurieren, bevor Sie sich authentifizieren k\u00f6nnen. [Bitte lesen Sie die Anweisungen] (https://www.home-assistant.io/components/nest/)." }, "error": { diff --git a/homeassistant/components/sensor/.translations/moon.ar.json b/homeassistant/components/sensor/.translations/moon.ar.json new file mode 100644 index 00000000000..94af741f5f4 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.ar.json @@ -0,0 +1,6 @@ +{ + "state": { + "first_quarter": "\u0627\u0644\u0631\u0628\u0639 \u0627\u0644\u0623\u0648\u0644", + "full_moon": "\u0627\u0644\u0642\u0645\u0631 \u0627\u0644\u0643\u0627\u0645\u0644" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.ca.json b/homeassistant/components/sensor/.translations/moon.ca.json new file mode 100644 index 00000000000..56eaf8d3b4c --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.ca.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Quart creixent", + "full_moon": "Lluna plena", + "last_quarter": "Quart minvant", + "new_moon": "Lluna nova", + "waning_crescent": "Lluna vella minvant", + "waning_gibbous": "Gibosa minvant", + "waxing_crescent": "Lluna nova visible", + "waxing_gibbous": "Gibosa creixent" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.de.json b/homeassistant/components/sensor/.translations/moon.de.json new file mode 100644 index 00000000000..aebca53ec4d --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.de.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Erstes Viertel", + "full_moon": "Vollmond", + "last_quarter": "Letztes Viertel", + "new_moon": "Neumond", + "waning_crescent": "Abnehmende Sichel", + "waning_gibbous": "Drittes Viertel", + "waxing_crescent": " Zunehmende Sichel", + "waxing_gibbous": "Zweites Viertel" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.en.json b/homeassistant/components/sensor/.translations/moon.en.json new file mode 100644 index 00000000000..587b9496114 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.en.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "First quarter", + "full_moon": "Full moon", + "last_quarter": "Last quarter", + "new_moon": "New moon", + "waning_crescent": "Waning crescent", + "waning_gibbous": "Waning gibbous", + "waxing_crescent": "Waxing crescent", + "waxing_gibbous": "Waxing gibbous" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.es-419.json b/homeassistant/components/sensor/.translations/moon.es-419.json new file mode 100644 index 00000000000..71cfab736cb --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.es-419.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Cuarto creciente", + "full_moon": "Luna llena", + "last_quarter": "Cuarto menguante", + "new_moon": "Luna nueva", + "waning_crescent": "Luna menguante", + "waning_gibbous": "Luna menguante gibosa", + "waxing_crescent": "Luna creciente", + "waxing_gibbous": "Luna creciente gibosa" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.fr.json b/homeassistant/components/sensor/.translations/moon.fr.json new file mode 100644 index 00000000000..fac2b654a46 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.fr.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Premier quartier", + "full_moon": "Pleine lune", + "last_quarter": "Dernier quartier", + "new_moon": "Nouvelle lune", + "waning_crescent": "Dernier croissant", + "waning_gibbous": "Gibbeuse d\u00e9croissante", + "waxing_crescent": "Premier croissant", + "waxing_gibbous": "Gibbeuse croissante" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.ko.json b/homeassistant/components/sensor/.translations/moon.ko.json new file mode 100644 index 00000000000..7e62250b892 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.ko.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "\ubc18\ub2ec(\ucc28\uc624\ub974\ub294)", + "full_moon": "\ubcf4\ub984\ub2ec", + "last_quarter": "\ubc18\ub2ec(\uc904\uc5b4\ub4dc\ub294)", + "new_moon": "\uc0ad\uc6d4", + "waning_crescent": "\uadf8\ubbd0\ub2ec", + "waning_gibbous": "\ud558\ud604\ub2ec", + "waxing_crescent": "\ucd08\uc2b9\ub2ec", + "waxing_gibbous": "\uc0c1\ud604\ub2ec" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.nl.json b/homeassistant/components/sensor/.translations/moon.nl.json new file mode 100644 index 00000000000..5e78d429b9f --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.nl.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Eerste kwartier", + "full_moon": "Volle maan", + "last_quarter": "Laatste kwartier", + "new_moon": "Nieuwe maan", + "waning_crescent": "Krimpende, sikkelvormige maan", + "waning_gibbous": "Krimpende, vooruitspringende maan", + "waxing_crescent": "Wassende, sikkelvormige maan", + "waxing_gibbous": "Wassende, vooruitspringende maan" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.no.json b/homeassistant/components/sensor/.translations/moon.no.json new file mode 100644 index 00000000000..104412c90ba --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.no.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "F\u00f8rste kvartdel", + "full_moon": "Fullm\u00e5ne", + "last_quarter": "Siste kvartdel", + "new_moon": "Nym\u00e5ne", + "waning_crescent": "Minkende halvm\u00e5ne", + "waning_gibbous": "Minkende trekvartm\u00e5ne", + "waxing_crescent": "Voksende halvm\u00e5ne", + "waxing_gibbous": "Voksende trekvartm\u00e5ne" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.ru.json b/homeassistant/components/sensor/.translations/moon.ru.json new file mode 100644 index 00000000000..6db932a1aed --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.ru.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "\u041f\u0435\u0440\u0432\u0430\u044f \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044c", + "full_moon": "\u041f\u043e\u043b\u043d\u043e\u043b\u0443\u043d\u0438\u0435", + "last_quarter": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044c", + "new_moon": "\u041d\u043e\u0432\u043e\u043b\u0443\u043d\u0438\u0435", + "waning_crescent": "\u0421\u0442\u0430\u0440\u0430\u044f \u043b\u0443\u043d\u0430", + "waning_gibbous": "\u0423\u0431\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u043b\u0443\u043d\u0430", + "waxing_crescent": "\u041c\u043e\u043b\u043e\u0434\u0430\u044f \u043b\u0443\u043d\u0430", + "waxing_gibbous": "\u041f\u0440\u0438\u0431\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u043b\u0443\u043d\u0430" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.sl.json b/homeassistant/components/sensor/.translations/moon.sl.json new file mode 100644 index 00000000000..41e873e4def --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.sl.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Prvi krajec", + "full_moon": "Polna luna", + "last_quarter": "Zadnji krajec", + "new_moon": "Mlaj", + "waning_crescent": "Zadnji izbo\u010dec", + "waning_gibbous": "Zadnji srpec", + "waxing_crescent": " Prvi izbo\u010dec", + "waxing_gibbous": "Prvi srpec" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.zh-Hans.json b/homeassistant/components/sensor/.translations/moon.zh-Hans.json new file mode 100644 index 00000000000..22ab0d49f62 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.zh-Hans.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "\u4e0a\u5f26\u6708", + "full_moon": "\u6ee1\u6708", + "last_quarter": "\u4e0b\u5f26\u6708", + "new_moon": "\u65b0\u6708", + "waning_crescent": "\u6b8b\u6708", + "waning_gibbous": "\u4e8f\u51f8\u6708", + "waxing_crescent": "\u5ce8\u7709\u6708", + "waxing_gibbous": "\u76c8\u51f8\u6708" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.zh-Hant.json b/homeassistant/components/sensor/.translations/moon.zh-Hant.json new file mode 100644 index 00000000000..9cf4aad011e --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.zh-Hant.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "\u4e0a\u5f26\u6708", + "full_moon": "\u6eff\u6708", + "last_quarter": "\u4e0b\u5f26\u6708", + "new_moon": "\u65b0\u6708", + "waning_crescent": "\u6b98\u6708", + "waning_gibbous": "\u8667\u51f8\u6708", + "waxing_crescent": "\u86fe\u7709\u6708", + "waxing_gibbous": "\u76c8\u51f8\u6708" + } +} \ No newline at end of file From e52ba87af15a2fcbe732d68bfee243996d3e2071 Mon Sep 17 00:00:00 2001 From: Josh Shoemaker Date: Thu, 16 Aug 2018 01:18:29 -0400 Subject: [PATCH 037/159] Upgrade aladdin_connect to 0.3 and provide Unique ID (#15986) * Upgrade aladdin_connect to 0.2 and set unique_id * update code to be Python 3.5 compatible --- homeassistant/components/cover/aladdin_connect.py | 7 ++++++- requirements_all.txt | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/cover/aladdin_connect.py b/homeassistant/components/cover/aladdin_connect.py index efaea39bb86..ef1f94d1bcd 100644 --- a/homeassistant/components/cover/aladdin_connect.py +++ b/homeassistant/components/cover/aladdin_connect.py @@ -14,7 +14,7 @@ from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, STATE_CLOSED, STATE_OPENING, STATE_CLOSING, STATE_OPEN) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['aladdin_connect==0.1'] +REQUIREMENTS = ['aladdin_connect==0.3'] _LOGGER = logging.getLogger(__name__) @@ -79,6 +79,11 @@ class AladdinDevice(CoverDevice): """Flag supported features.""" return SUPPORTED_FEATURES + @property + def unique_id(self): + """Return a unique ID.""" + return '{}-{}'.format(self._device_id, self._number) + @property def name(self): """Return the name of the garage door.""" diff --git a/requirements_all.txt b/requirements_all.txt index f51b801d5c1..f0579eb0ba5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -111,7 +111,7 @@ aiolifx_effects==0.1.2 aiopvapi==1.5.4 # homeassistant.components.cover.aladdin_connect -aladdin_connect==0.1 +aladdin_connect==0.3 # homeassistant.components.alarmdecoder alarmdecoder==1.13.2 From b682e48e12686eec8776ab5eb527c1e36a5826e3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 09:50:11 +0200 Subject: [PATCH 038/159] Entity service (#15991) * Add entity service helper * Use entity service helper * Context --- .../alarm_control_panel/__init__.py | 62 +++++-------- homeassistant/components/counter/__init__.py | 31 ++----- homeassistant/components/cover/__init__.py | 74 +++++++-------- homeassistant/components/input_boolean.py | 35 +++----- homeassistant/components/input_number.py | 45 +++------- homeassistant/components/input_select.py | 68 ++++---------- homeassistant/components/input_text.py | 17 +--- homeassistant/components/lock/__init__.py | 44 +++------ homeassistant/components/remote/__init__.py | 49 ++++------ homeassistant/components/switch/__init__.py | 41 +++------ homeassistant/components/timer/__init__.py | 46 +++------- homeassistant/components/vacuum/__init__.py | 89 ++++++++++--------- homeassistant/helpers/entity_component.py | 12 +++ homeassistant/helpers/service.py | 50 +++++++++++ 14 files changed, 276 insertions(+), 387 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index 0a4dd6bde78..f9f2a4e03be 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -26,20 +26,6 @@ ATTR_CHANGED_BY = 'changed_by' ENTITY_ID_FORMAT = DOMAIN + '.{}' -SERVICE_TO_METHOD = { - SERVICE_ALARM_DISARM: 'alarm_disarm', - SERVICE_ALARM_ARM_HOME: 'alarm_arm_home', - SERVICE_ALARM_ARM_AWAY: 'alarm_arm_away', - SERVICE_ALARM_ARM_NIGHT: 'alarm_arm_night', - SERVICE_ALARM_ARM_CUSTOM_BYPASS: 'alarm_arm_custom_bypass', - SERVICE_ALARM_TRIGGER: 'alarm_trigger' -} - -ATTR_TO_PROPERTY = [ - ATTR_CODE, - ATTR_CODE_FORMAT -] - ALARM_SERVICE_SCHEMA = vol.Schema({ vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, vol.Optional(ATTR_CODE): cv.string, @@ -126,30 +112,30 @@ def async_setup(hass, config): yield from component.async_setup(config) - @asyncio.coroutine - def async_alarm_service_handler(service): - """Map services to methods on Alarm.""" - target_alarms = component.async_extract_from_service(service) - - code = service.data.get(ATTR_CODE) - - method = "async_{}".format(SERVICE_TO_METHOD[service.service]) - - update_tasks = [] - for alarm in target_alarms: - yield from getattr(alarm, method)(code) - - if not alarm.should_poll: - continue - update_tasks.append(alarm.async_update_ha_state(True)) - - if update_tasks: - yield from asyncio.wait(update_tasks, loop=hass.loop) - - for service in SERVICE_TO_METHOD: - hass.services.async_register( - DOMAIN, service, async_alarm_service_handler, - schema=ALARM_SERVICE_SCHEMA) + component.async_register_entity_service( + SERVICE_ALARM_DISARM, ALARM_SERVICE_SCHEMA, + 'async_alarm_disarm' + ) + component.async_register_entity_service( + SERVICE_ALARM_ARM_HOME, ALARM_SERVICE_SCHEMA, + 'async_alarm_arm_home' + ) + component.async_register_entity_service( + SERVICE_ALARM_ARM_AWAY, ALARM_SERVICE_SCHEMA, + 'async_alarm_arm_away' + ) + component.async_register_entity_service( + SERVICE_ALARM_ARM_NIGHT, ALARM_SERVICE_SCHEMA, + 'async_alarm_arm_night' + ) + component.async_register_entity_service( + SERVICE_ALARM_ARM_CUSTOM_BYPASS, ALARM_SERVICE_SCHEMA, + 'async_alarm_arm_custom_bypass' + ) + component.async_register_entity_service( + SERVICE_ALARM_TRIGGER, ALARM_SERVICE_SCHEMA, + 'async_alarm_trigger' + ) return True diff --git a/homeassistant/components/counter/__init__.py b/homeassistant/components/counter/__init__.py index 03e5b273468..d720819a0ab 100644 --- a/homeassistant/components/counter/__init__.py +++ b/homeassistant/components/counter/__init__.py @@ -4,7 +4,6 @@ Component to count within automations. For more details about this component, please refer to the documentation at https://home-assistant.io/components/counter/ """ -import asyncio import logging import voluptuous as vol @@ -114,27 +113,15 @@ async def async_setup(hass, config): if not entities: return False - async def async_handler_service(service): - """Handle a call to the counter services.""" - target_counters = component.async_extract_from_service(service) - - if service.service == SERVICE_INCREMENT: - attr = 'async_increment' - elif service.service == SERVICE_DECREMENT: - attr = 'async_decrement' - elif service.service == SERVICE_RESET: - attr = 'async_reset' - - tasks = [getattr(counter, attr)() for counter in target_counters] - if tasks: - await asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_INCREMENT, async_handler_service) - hass.services.async_register( - DOMAIN, SERVICE_DECREMENT, async_handler_service) - hass.services.async_register( - DOMAIN, SERVICE_RESET, async_handler_service) + component.async_register_entity_service( + SERVICE_INCREMENT, SERVICE_SCHEMA, + 'async_increment') + component.async_register_entity_service( + SERVICE_DECREMENT, SERVICE_SCHEMA, + 'async_decrement') + component.async_register_entity_service( + SERVICE_RESET, SERVICE_SCHEMA, + 'async_reset') await component.async_add_entities(entities) return True diff --git a/homeassistant/components/cover/__init__.py b/homeassistant/components/cover/__init__.py index f5d3d798e2e..05c5e46e44e 100644 --- a/homeassistant/components/cover/__init__.py +++ b/homeassistant/components/cover/__init__.py @@ -4,7 +4,6 @@ Support for Cover devices. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/cover/ """ -import asyncio from datetime import timedelta import functools as ft import logging @@ -73,21 +72,6 @@ COVER_SET_COVER_TILT_POSITION_SCHEMA = COVER_SERVICE_SCHEMA.extend({ vol.All(vol.Coerce(int), vol.Range(min=0, max=100)), }) -SERVICE_TO_METHOD = { - SERVICE_OPEN_COVER: {'method': 'async_open_cover'}, - SERVICE_CLOSE_COVER: {'method': 'async_close_cover'}, - SERVICE_SET_COVER_POSITION: { - 'method': 'async_set_cover_position', - 'schema': COVER_SET_COVER_POSITION_SCHEMA}, - SERVICE_STOP_COVER: {'method': 'async_stop_cover'}, - SERVICE_OPEN_COVER_TILT: {'method': 'async_open_cover_tilt'}, - SERVICE_CLOSE_COVER_TILT: {'method': 'async_close_cover_tilt'}, - SERVICE_STOP_COVER_TILT: {'method': 'async_stop_cover_tilt'}, - SERVICE_SET_COVER_TILT_POSITION: { - 'method': 'async_set_cover_tilt_position', - 'schema': COVER_SET_COVER_TILT_POSITION_SCHEMA}, -} - @bind_hass def is_closed(hass, entity_id=None): @@ -161,30 +145,46 @@ async def async_setup(hass, config): await component.async_setup(config) - async def async_handle_cover_service(service): - """Handle calls to the cover services.""" - covers = component.async_extract_from_service(service) - method = SERVICE_TO_METHOD.get(service.service) - params = service.data.copy() - params.pop(ATTR_ENTITY_ID, None) + component.async_register_entity_service( + SERVICE_OPEN_COVER, COVER_SERVICE_SCHEMA, + 'async_open_cover' + ) - # call method - update_tasks = [] - for cover in covers: - await getattr(cover, method['method'])(**params) - if not cover.should_poll: - continue - update_tasks.append(cover.async_update_ha_state(True)) + component.async_register_entity_service( + SERVICE_CLOSE_COVER, COVER_SERVICE_SCHEMA, + 'async_close_cover' + ) - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) + component.async_register_entity_service( + SERVICE_SET_COVER_POSITION, COVER_SET_COVER_POSITION_SCHEMA, + 'async_set_cover_position' + ) + + component.async_register_entity_service( + SERVICE_STOP_COVER, COVER_SERVICE_SCHEMA, + 'async_stop_cover' + ) + + component.async_register_entity_service( + SERVICE_OPEN_COVER_TILT, COVER_SERVICE_SCHEMA, + 'async_open_cover_tilt' + ) + + component.async_register_entity_service( + SERVICE_CLOSE_COVER_TILT, COVER_SERVICE_SCHEMA, + 'async_close_cover_tilt' + ) + + component.async_register_entity_service( + SERVICE_STOP_COVER_TILT, COVER_SERVICE_SCHEMA, + 'async_stop_cover_tilt' + ) + + component.async_register_entity_service( + SERVICE_SET_COVER_TILT_POSITION, COVER_SET_COVER_TILT_POSITION_SCHEMA, + 'async_set_cover_tilt_position' + ) - for service_name in SERVICE_TO_METHOD: - schema = SERVICE_TO_METHOD[service_name].get( - 'schema', COVER_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, service_name, async_handle_cover_service, - schema=schema) hass.helpers.intent.async_register(intent.ServiceIntentHandler( INTENT_OPEN_COVER, DOMAIN, SERVICE_OPEN_COVER, "Opened {}")) diff --git a/homeassistant/components/input_boolean.py b/homeassistant/components/input_boolean.py index 9c8435614a2..b9c4dcc685e 100644 --- a/homeassistant/components/input_boolean.py +++ b/homeassistant/components/input_boolean.py @@ -4,7 +4,6 @@ Component to keep track of user controlled booleans for within automation. For more details about this component, please refer to the documentation at https://home-assistant.io/components/input_boolean/ """ -import asyncio import logging import voluptuous as vol @@ -84,30 +83,20 @@ async def async_setup(hass, config): if not entities: return False - async def async_handler_service(service): - """Handle a calls to the input boolean services.""" - target_inputs = component.async_extract_from_service(service) + component.async_register_entity_service( + SERVICE_TURN_ON, SERVICE_SCHEMA, + 'async_turn_on' + ) - if service.service == SERVICE_TURN_ON: - attr = 'async_turn_on' - elif service.service == SERVICE_TURN_OFF: - attr = 'async_turn_off' - else: - attr = 'async_toggle' + component.async_register_entity_service( + SERVICE_TURN_OFF, SERVICE_SCHEMA, + 'async_turn_off' + ) - tasks = [getattr(input_b, attr)() for input_b in target_inputs] - if tasks: - await asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_TURN_OFF, async_handler_service, - schema=SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TURN_ON, async_handler_service, - schema=SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TOGGLE, async_handler_service, - schema=SERVICE_SCHEMA) + component.async_register_entity_service( + SERVICE_TOGGLE, SERVICE_SCHEMA, + 'async_toggle' + ) await component.async_add_entities(entities) return True diff --git a/homeassistant/components/input_number.py b/homeassistant/components/input_number.py index e18169fca73..2f25ca143b8 100644 --- a/homeassistant/components/input_number.py +++ b/homeassistant/components/input_number.py @@ -82,19 +82,6 @@ CONFIG_SCHEMA = vol.Schema({ }, required=True, extra=vol.ALLOW_EXTRA) -SERVICE_TO_METHOD = { - SERVICE_SET_VALUE: { - 'method': 'async_set_value', - 'schema': SERVICE_SET_VALUE_SCHEMA}, - SERVICE_INCREMENT: { - 'method': 'async_increment', - 'schema': SERVICE_DEFAULT_SCHEMA}, - SERVICE_DECREMENT: { - 'method': 'async_decrement', - 'schema': SERVICE_DEFAULT_SCHEMA}, -} - - @bind_hass def set_value(hass, entity_id, value): """Set input_number to value.""" @@ -144,28 +131,20 @@ def async_setup(hass, config): if not entities: return False - @asyncio.coroutine - def async_handle_service(service): - """Handle calls to input_number services.""" - target_inputs = component.async_extract_from_service(service) - method = SERVICE_TO_METHOD.get(service.service) - params = service.data.copy() - params.pop(ATTR_ENTITY_ID, None) + component.async_register_entity_service( + SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA, + 'async_set_value' + ) - # call method - update_tasks = [] - for target_input in target_inputs: - yield from getattr(target_input, method['method'])(**params) - if not target_input.should_poll: - continue - update_tasks.append(target_input.async_update_ha_state(True)) + component.async_register_entity_service( + SERVICE_INCREMENT, SERVICE_DEFAULT_SCHEMA, + 'async_increment' + ) - if update_tasks: - yield from asyncio.wait(update_tasks, loop=hass.loop) - - for service, data in SERVICE_TO_METHOD.items(): - hass.services.async_register( - DOMAIN, service, async_handle_service, schema=data['schema']) + component.async_register_entity_service( + SERVICE_DECREMENT, SERVICE_DEFAULT_SCHEMA, + 'async_decrement' + ) yield from component.async_add_entities(entities) return True diff --git a/homeassistant/components/input_select.py b/homeassistant/components/input_select.py index f16b029c1d7..04e9b04787c 100644 --- a/homeassistant/components/input_select.py +++ b/homeassistant/components/input_select.py @@ -129,61 +129,25 @@ def async_setup(hass, config): if not entities: return False - @asyncio.coroutine - def async_select_option_service(call): - """Handle a calls to the input select option service.""" - target_inputs = component.async_extract_from_service(call) + component.async_register_entity_service( + SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION_SCHEMA, + 'async_select_option' + ) - tasks = [input_select.async_select_option(call.data[ATTR_OPTION]) - for input_select in target_inputs] - if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) + component.async_register_entity_service( + SERVICE_SELECT_NEXT, SERVICE_SELECT_NEXT_SCHEMA, + lambda entity, call: entity.async_offset_index(1) + ) - hass.services.async_register( - DOMAIN, SERVICE_SELECT_OPTION, async_select_option_service, - schema=SERVICE_SELECT_OPTION_SCHEMA) + component.async_register_entity_service( + SERVICE_SELECT_PREVIOUS, SERVICE_SELECT_PREVIOUS_SCHEMA, + lambda entity, call: entity.async_offset_index(-1) + ) - @asyncio.coroutine - def async_select_next_service(call): - """Handle a calls to the input select next service.""" - target_inputs = component.async_extract_from_service(call) - - tasks = [input_select.async_offset_index(1) - for input_select in target_inputs] - if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SELECT_NEXT, async_select_next_service, - schema=SERVICE_SELECT_NEXT_SCHEMA) - - @asyncio.coroutine - def async_select_previous_service(call): - """Handle a calls to the input select previous service.""" - target_inputs = component.async_extract_from_service(call) - - tasks = [input_select.async_offset_index(-1) - for input_select in target_inputs] - if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SELECT_PREVIOUS, async_select_previous_service, - schema=SERVICE_SELECT_PREVIOUS_SCHEMA) - - @asyncio.coroutine - def async_set_options_service(call): - """Handle a calls to the set options service.""" - target_inputs = component.async_extract_from_service(call) - - tasks = [input_select.async_set_options(call.data[ATTR_OPTIONS]) - for input_select in target_inputs] - if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_OPTIONS, async_set_options_service, - schema=SERVICE_SET_OPTIONS_SCHEMA) + component.async_register_entity_service( + SERVICE_SET_OPTIONS, SERVICE_SET_OPTIONS_SCHEMA, + 'async_set_options' + ) yield from component.async_add_entities(entities) return True diff --git a/homeassistant/components/input_text.py b/homeassistant/components/input_text.py index 6433a01fb6d..2cb4f58a130 100644 --- a/homeassistant/components/input_text.py +++ b/homeassistant/components/input_text.py @@ -107,19 +107,10 @@ def async_setup(hass, config): if not entities: return False - @asyncio.coroutine - def async_set_value_service(call): - """Handle a calls to the input box services.""" - target_inputs = component.async_extract_from_service(call) - - tasks = [input_text.async_set_value(call.data[ATTR_VALUE]) - for input_text in target_inputs] - if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_VALUE, async_set_value_service, - schema=SERVICE_SET_VALUE_SCHEMA) + component.async_register_entity_service( + SERVICE_SET_VALUE, SERVICE_SET_VALUE_SCHEMA, + 'async_set_value' + ) yield from component.async_add_entities(entities) return True diff --git a/homeassistant/components/lock/__init__.py b/homeassistant/components/lock/__init__.py index f03d028a38f..3c4ff7cdedd 100644 --- a/homeassistant/components/lock/__init__.py +++ b/homeassistant/components/lock/__init__.py @@ -101,38 +101,18 @@ def async_setup(hass, config): yield from component.async_setup(config) - @asyncio.coroutine - def async_handle_lock_service(service): - """Handle calls to the lock services.""" - target_locks = component.async_extract_from_service(service) - - code = service.data.get(ATTR_CODE) - - update_tasks = [] - for entity in target_locks: - if service.service == SERVICE_LOCK: - yield from entity.async_lock(code=code) - elif service.service == SERVICE_OPEN: - yield from entity.async_open(code=code) - else: - yield from entity.async_unlock(code=code) - - if not entity.should_poll: - continue - update_tasks.append(entity.async_update_ha_state(True)) - - if update_tasks: - yield from asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_UNLOCK, async_handle_lock_service, - schema=LOCK_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_LOCK, async_handle_lock_service, - schema=LOCK_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_OPEN, async_handle_lock_service, - schema=LOCK_SERVICE_SCHEMA) + component.async_register_entity_service( + SERVICE_UNLOCK, LOCK_SERVICE_SCHEMA, + 'async_unlock' + ) + component.async_register_entity_service( + SERVICE_LOCK, LOCK_SERVICE_SCHEMA, + 'async_lock' + ) + component.async_register_entity_service( + SERVICE_OPEN, LOCK_SERVICE_SCHEMA, + 'async_open' + ) return True diff --git a/homeassistant/components/remote/__init__.py b/homeassistant/components/remote/__init__.py index ddae36b92a7..11ecb20f7aa 100644 --- a/homeassistant/components/remote/__init__.py +++ b/homeassistant/components/remote/__init__.py @@ -134,42 +134,25 @@ def async_setup(hass, config): _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_REMOTES) yield from component.async_setup(config) - @asyncio.coroutine - def async_handle_remote_service(service): - """Handle calls to the remote services.""" - target_remotes = component.async_extract_from_service(service) - kwargs = service.data.copy() + component.async_register_entity_service( + SERVICE_TURN_OFF, REMOTE_SERVICE_ACTIVITY_SCHEMA, + 'async_turn_off' + ) - update_tasks = [] - for remote in target_remotes: - if service.service == SERVICE_TURN_ON: - yield from remote.async_turn_on(**kwargs) - elif service.service == SERVICE_TOGGLE: - yield from remote.async_toggle(**kwargs) - elif service.service == SERVICE_SEND_COMMAND: - yield from remote.async_send_command(**kwargs) - else: - yield from remote.async_turn_off(**kwargs) + component.async_register_entity_service( + SERVICE_TURN_ON, REMOTE_SERVICE_ACTIVITY_SCHEMA, + 'async_turn_on' + ) - if not remote.should_poll: - continue - update_tasks.append(remote.async_update_ha_state(True)) + component.async_register_entity_service( + SERVICE_TOGGLE, REMOTE_SERVICE_ACTIVITY_SCHEMA, + 'async_toggle' + ) - if update_tasks: - yield from asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_TURN_OFF, async_handle_remote_service, - schema=REMOTE_SERVICE_ACTIVITY_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TURN_ON, async_handle_remote_service, - schema=REMOTE_SERVICE_ACTIVITY_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TOGGLE, async_handle_remote_service, - schema=REMOTE_SERVICE_ACTIVITY_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_SEND_COMMAND, async_handle_remote_service, - schema=REMOTE_SERVICE_SEND_COMMAND_SCHEMA) + component.async_register_entity_service( + SERVICE_SEND_COMMAND, REMOTE_SERVICE_SEND_COMMAND_SCHEMA, + 'async_send_command' + ) return True diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index cb69240ee73..3ca52a91758 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -4,7 +4,6 @@ Component to interface with various switches that can be controlled remotely. For more details about this component, please refer to the documentation at https://home-assistant.io/components/switch/ """ -import asyncio from datetime import timedelta import logging @@ -99,36 +98,20 @@ async def async_setup(hass, config): _LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_SWITCHES) await component.async_setup(config) - async def async_handle_switch_service(service): - """Handle calls to the switch services.""" - target_switches = component.async_extract_from_service(service) + component.async_register_entity_service( + SERVICE_TURN_OFF, SWITCH_SERVICE_SCHEMA, + 'async_turn_off' + ) - update_tasks = [] - for switch in target_switches: - if service.service == SERVICE_TURN_ON: - await switch.async_turn_on() - elif service.service == SERVICE_TOGGLE: - await switch.async_toggle() - else: - await switch.async_turn_off() + component.async_register_entity_service( + SERVICE_TURN_ON, SWITCH_SERVICE_SCHEMA, + 'async_turn_on' + ) - if not switch.should_poll: - continue - update_tasks.append( - switch.async_update_ha_state(True, service.context)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_TURN_OFF, async_handle_switch_service, - schema=SWITCH_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TURN_ON, async_handle_switch_service, - schema=SWITCH_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TOGGLE, async_handle_switch_service, - schema=SWITCH_SERVICE_SCHEMA) + component.async_register_entity_service( + SERVICE_TOGGLE, SWITCH_SERVICE_SCHEMA, + 'async_toggle' + ) return True diff --git a/homeassistant/components/timer/__init__.py b/homeassistant/components/timer/__init__.py index 5a363e84d7b..8406b3ff5ec 100644 --- a/homeassistant/components/timer/__init__.py +++ b/homeassistant/components/timer/__init__.py @@ -4,7 +4,6 @@ Timer component. For more details about this component, please refer to the documentation at https://home-assistant.io/components/timer/ """ -import asyncio import logging from datetime import timedelta @@ -141,39 +140,18 @@ async def async_setup(hass, config): if not entities: return False - async def async_handler_service(service): - """Handle a call to the timer services.""" - target_timers = component.async_extract_from_service(service) - - attr = None - if service.service == SERVICE_PAUSE: - attr = 'async_pause' - elif service.service == SERVICE_CANCEL: - attr = 'async_cancel' - elif service.service == SERVICE_FINISH: - attr = 'async_finish' - - tasks = [getattr(timer, attr)() for timer in target_timers if attr] - if service.service == SERVICE_START: - for timer in target_timers: - tasks.append( - timer.async_start(service.data.get(ATTR_DURATION)) - ) - if tasks: - await asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_START, async_handler_service, - schema=SERVICE_SCHEMA_DURATION) - hass.services.async_register( - DOMAIN, SERVICE_PAUSE, async_handler_service, - schema=SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_CANCEL, async_handler_service, - schema=SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_FINISH, async_handler_service, - schema=SERVICE_SCHEMA) + component.async_register_entity_service( + SERVICE_START, SERVICE_SCHEMA_DURATION, + 'async_start') + component.async_register_entity_service( + SERVICE_PAUSE, SERVICE_SCHEMA, + 'async_pause') + component.async_register_entity_service( + SERVICE_CANCEL, SERVICE_SCHEMA, + 'async_cancel') + component.async_register_entity_service( + SERVICE_FINISH, SERVICE_SCHEMA, + 'async_finish') await component.async_add_entities(entities) return True diff --git a/homeassistant/components/vacuum/__init__.py b/homeassistant/components/vacuum/__init__.py index 97d009626b8..1808737d281 100644 --- a/homeassistant/components/vacuum/__init__.py +++ b/homeassistant/components/vacuum/__init__.py @@ -62,23 +62,6 @@ VACUUM_SEND_COMMAND_SERVICE_SCHEMA = VACUUM_SERVICE_SCHEMA.extend({ vol.Optional(ATTR_PARAMS): vol.Any(dict, cv.ensure_list), }) -SERVICE_TO_METHOD = { - SERVICE_TURN_ON: {'method': 'async_turn_on'}, - SERVICE_TURN_OFF: {'method': 'async_turn_off'}, - SERVICE_TOGGLE: {'method': 'async_toggle'}, - SERVICE_START_PAUSE: {'method': 'async_start_pause'}, - SERVICE_START: {'method': 'async_start'}, - SERVICE_PAUSE: {'method': 'async_pause'}, - SERVICE_RETURN_TO_BASE: {'method': 'async_return_to_base'}, - SERVICE_CLEAN_SPOT: {'method': 'async_clean_spot'}, - SERVICE_LOCATE: {'method': 'async_locate'}, - SERVICE_STOP: {'method': 'async_stop'}, - SERVICE_SET_FAN_SPEED: {'method': 'async_set_fan_speed', - 'schema': VACUUM_SET_FAN_SPEED_SERVICE_SCHEMA}, - SERVICE_SEND_COMMAND: {'method': 'async_send_command', - 'schema': VACUUM_SEND_COMMAND_SERVICE_SCHEMA}, -} - STATE_CLEANING = 'cleaning' STATE_DOCKED = 'docked' STATE_IDLE = STATE_IDLE @@ -207,30 +190,54 @@ def async_setup(hass, config): yield from component.async_setup(config) - @asyncio.coroutine - def async_handle_vacuum_service(service): - """Map services to methods on VacuumDevice.""" - method = SERVICE_TO_METHOD.get(service.service) - target_vacuums = component.async_extract_from_service(service) - params = service.data.copy() - params.pop(ATTR_ENTITY_ID, None) - - update_tasks = [] - for vacuum in target_vacuums: - yield from getattr(vacuum, method['method'])(**params) - if not vacuum.should_poll: - continue - update_tasks.append(vacuum.async_update_ha_state(True)) - - if update_tasks: - yield from asyncio.wait(update_tasks, loop=hass.loop) - - for service in SERVICE_TO_METHOD: - schema = SERVICE_TO_METHOD[service].get( - 'schema', VACUUM_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, service, async_handle_vacuum_service, - schema=schema) + component.async_register_entity_service( + SERVICE_TURN_ON, VACUUM_SERVICE_SCHEMA, + 'async_turn_on' + ) + component.async_register_entity_service( + SERVICE_TURN_OFF, VACUUM_SERVICE_SCHEMA, + 'async_turn_off' + ) + component.async_register_entity_service( + SERVICE_TOGGLE, VACUUM_SERVICE_SCHEMA, + 'async_toggle' + ) + component.async_register_entity_service( + SERVICE_START_PAUSE, VACUUM_SERVICE_SCHEMA, + 'async_start_pause' + ) + component.async_register_entity_service( + SERVICE_START, VACUUM_SERVICE_SCHEMA, + 'async_start' + ) + component.async_register_entity_service( + SERVICE_PAUSE, VACUUM_SERVICE_SCHEMA, + 'async_pause' + ) + component.async_register_entity_service( + SERVICE_RETURN_TO_BASE, VACUUM_SERVICE_SCHEMA, + 'async_return_to_base' + ) + component.async_register_entity_service( + SERVICE_CLEAN_SPOT, VACUUM_SERVICE_SCHEMA, + 'async_clean_spot' + ) + component.async_register_entity_service( + SERVICE_LOCATE, VACUUM_SERVICE_SCHEMA, + 'async_locate' + ) + component.async_register_entity_service( + SERVICE_STOP, VACUUM_SERVICE_SCHEMA, + 'async_stop' + ) + component.async_register_entity_service( + SERVICE_SET_FAN_SPEED, VACUUM_SET_FAN_SPEED_SERVICE_SCHEMA, + 'async_set_fan_speed' + ) + component.async_register_entity_service( + SERVICE_SEND_COMMAND, VACUUM_SEND_COMMAND_SERVICE_SCHEMA, + 'async_send_command' + ) return True diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 72b6ceecbfd..cf035095a84 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -142,6 +142,18 @@ class EntityComponent: return [entity for entity in self.entities if entity.available and entity.entity_id in entity_ids] + @callback + def async_register_entity_service(self, name, schema, func): + """Register an entity service.""" + async def handle_service(call): + """Handle the service.""" + await self.hass.helpers.service.entity_service_call( + self._platforms.values(), func, call + ) + + self.hass.services.async_register( + self.domain, name, handle_service, schema) + async def _async_setup_platform(self, platform_type, platform_config, discovery_info=None): """Set up a platform for this component.""" diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 8aa3b553f3a..acad72a860a 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -1,4 +1,5 @@ """Service calling related helpers.""" +import asyncio import logging from os import path @@ -178,3 +179,52 @@ async def async_get_all_descriptions(hass): descriptions[domain][service] = description return descriptions + + +@bind_hass +async def entity_service_call(hass, platforms, func, call): + """Handle an entity service call. + + Calls all platforms simultaneously. + """ + tasks = [] + all_entities = ATTR_ENTITY_ID not in call.data + if not all_entities: + entity_ids = set( + extract_entity_ids(hass, call, True)) + + if isinstance(func, str): + data = {key: val for key, val in call.data.items() + if key != ATTR_ENTITY_ID} + else: + data = call + + tasks = [ + _handle_service_platform_call(func, data, [ + entity for entity in platform.entities.values() + if all_entities or entity.entity_id in entity_ids + ], call.context) for platform in platforms + ] + + if tasks: + await asyncio.wait(tasks) + + +async def _handle_service_platform_call(func, data, entities, context): + """Handle a function call.""" + tasks = [] + + for entity in entities: + if not entity.available: + continue + + if isinstance(func, str): + await getattr(entity, func)(**data) + else: + await func(entity, data) + + if entity.should_poll: + tasks.append(entity.async_update_ha_state(True, context)) + + if tasks: + await asyncio.wait(tasks) From 83b0ef4e267772bc8d36b3e1f46165153150fb31 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 13:46:43 +0200 Subject: [PATCH 039/159] Fix Nest async from sync (#15997) --- homeassistant/components/nest/__init__.py | 43 +++++++++++++---------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/homeassistant/components/nest/__init__.py b/homeassistant/components/nest/__init__.py index de9783ba931..d25b94bbc17 100644 --- a/homeassistant/components/nest/__init__.py +++ b/homeassistant/components/nest/__init__.py @@ -4,10 +4,10 @@ Support for Nest devices. For more details about this component, please refer to the documentation at https://home-assistant.io/components/nest/ """ -from concurrent.futures import ThreadPoolExecutor import logging import socket from datetime import datetime, timedelta +import threading import voluptuous as vol @@ -16,8 +16,9 @@ from homeassistant.const import ( CONF_STRUCTURE, CONF_FILENAME, CONF_BINARY_SENSORS, CONF_SENSORS, CONF_MONITORED_CONDITIONS, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP) +from homeassistant.core import callback from homeassistant.helpers import config_validation as cv -from homeassistant.helpers.dispatcher import async_dispatcher_send, \ +from homeassistant.helpers.dispatcher import dispatcher_send, \ async_dispatcher_connect from homeassistant.helpers.entity import Entity @@ -71,24 +72,25 @@ CONFIG_SCHEMA = vol.Schema({ }, extra=vol.ALLOW_EXTRA) -async def async_nest_update_event_broker(hass, nest): +def nest_update_event_broker(hass, nest): """ Dispatch SIGNAL_NEST_UPDATE to devices when nest stream API received data. - nest.update_event.wait will block the thread in most of time, - so specific an executor to save default thread pool. + Runs in its own thread. """ _LOGGER.debug("listening nest.update_event") - with ThreadPoolExecutor(max_workers=1) as executor: - while True: - await hass.loop.run_in_executor(executor, nest.update_event.wait) - if hass.is_running: - nest.update_event.clear() - _LOGGER.debug("dispatching nest data update") - async_dispatcher_send(hass, SIGNAL_NEST_UPDATE) - else: - _LOGGER.debug("stop listening nest.update_event") - return + + while hass.is_running: + nest.update_event.wait() + + if not hass.is_running: + break + + nest.update_event.clear() + _LOGGER.debug("dispatching nest data update") + dispatcher_send(hass, SIGNAL_NEST_UPDATE) + + _LOGGER.debug("stop listening nest.update_event") async def async_setup(hass, config): @@ -167,16 +169,21 @@ async def async_setup_entry(hass, entry): hass.services.async_register( DOMAIN, 'set_mode', set_mode, schema=AWAY_SCHEMA) + @callback def start_up(event): """Start Nest update event listener.""" - hass.async_add_job(async_nest_update_event_broker, hass, nest) + threading.Thread( + name='Nest update listener', + target=nest_update_event_broker, + args=(hass, nest) + ).start() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, start_up) + @callback def shut_down(event): """Stop Nest update event listener.""" - if nest: - nest.update_event.set() + nest.update_event.set() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, shut_down) From b5e7414be2eb6eea903248c5267447b20b9fcbca Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Thu, 16 Aug 2018 14:19:42 +0200 Subject: [PATCH 040/159] Fix mysensors connection task blocking setup (#15938) * Fix mysensors connection task blocking setup * Schedule the connection task without having the core track the task to avoid blocking setup. * Cancel the connection task, if not cancelled already, when home assistant stops. * Use done instead of cancelled --- homeassistant/components/mysensors/gateway.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/mysensors/gateway.py b/homeassistant/components/mysensors/gateway.py index 8c80604d188..88725e67940 100644 --- a/homeassistant/components/mysensors/gateway.py +++ b/homeassistant/components/mysensors/gateway.py @@ -186,12 +186,16 @@ def _discover_mysensors_platform(hass, platform, new_devices): async def _gw_start(hass, gateway): """Start the gateway.""" + # Don't use hass.async_create_task to avoid holding up setup indefinitely. + connect_task = hass.loop.create_task(gateway.start()) + @callback def gw_stop(event): """Trigger to stop the gateway.""" hass.async_add_job(gateway.stop()) + if not connect_task.done(): + connect_task.cancel() - await gateway.start() hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gw_stop) if gateway.device == 'mqtt': # Gatways connected via mqtt doesn't send gateway ready message. From e4d41fe313a124e8a8cd2fc9174acd1214abb210 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 14:21:43 +0200 Subject: [PATCH 041/159] Bump frontend to 20180816.0 --- homeassistant/components/frontend/__init__.py | 2 +- homeassistant/components/map.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 41cfdd3edd8..c3c742f43b1 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180813.0'] +REQUIREMENTS = ['home-assistant-frontend==20180816.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/homeassistant/components/map.py b/homeassistant/components/map.py index 30cb00af69e..c0184239a1a 100644 --- a/homeassistant/components/map.py +++ b/homeassistant/components/map.py @@ -10,5 +10,5 @@ DOMAIN = 'map' async def async_setup(hass, config): """Register the built-in map panel.""" await hass.components.frontend.async_register_built_in_panel( - 'map', 'map', 'mdi:account-location') + 'map', 'map', 'hass:account-location') return True diff --git a/requirements_all.txt b/requirements_all.txt index f0579eb0ba5..894e9ef1706 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -435,7 +435,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180813.0 +home-assistant-frontend==20180816.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4115fcfcb3f..0958b6d7280 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180813.0 +home-assistant-frontend==20180816.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 1ff1639cefb1c1a14e64287fccc1dbe0e2f8e52d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 14:28:59 +0200 Subject: [PATCH 042/159] More entity service (#15998) * Camera use entity service * Convert climate services * Convert light * Convert media player * Migrate fan --- homeassistant/components/camera/__init__.py | 117 +++----- homeassistant/components/climate/__init__.py | 278 +++++------------- homeassistant/components/fan/__init__.py | 75 ++--- homeassistant/components/light/__init__.py | 37 ++- .../components/media_player/__init__.py | 163 +++++----- tests/components/camera/test_demo.py | 15 +- tests/components/light/test_rflink.py | 9 +- 7 files changed, 252 insertions(+), 442 deletions(-) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 736bcec1e9c..6a15510cf54 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -189,74 +189,26 @@ async def async_setup(hass, config): hass.helpers.event.async_track_time_interval( update_tokens, TOKEN_CHANGE_INTERVAL) - async def async_handle_camera_service(service): - """Handle calls to the camera services.""" - target_cameras = component.async_extract_from_service(service) - - update_tasks = [] - for camera in target_cameras: - if service.service == SERVICE_ENABLE_MOTION: - await camera.async_enable_motion_detection() - elif service.service == SERVICE_DISABLE_MOTION: - await camera.async_disable_motion_detection() - elif service.service == SERVICE_TURN_OFF and \ - camera.supported_features & SUPPORT_ON_OFF: - await camera.async_turn_off() - elif service.service == SERVICE_TURN_ON and \ - camera.supported_features & SUPPORT_ON_OFF: - await camera.async_turn_on() - - if not camera.should_poll: - continue - update_tasks.append(camera.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - async def async_handle_snapshot_service(service): - """Handle snapshot services calls.""" - target_cameras = component.async_extract_from_service(service) - filename = service.data[ATTR_FILENAME] - filename.hass = hass - - for camera in target_cameras: - snapshot_file = filename.async_render( - variables={ATTR_ENTITY_ID: camera}) - - # check if we allow to access to that file - if not hass.config.is_allowed_path(snapshot_file): - _LOGGER.error( - "Can't write %s, no access to path!", snapshot_file) - continue - - image = await camera.async_camera_image() - - def _write_image(to_file, image_data): - """Executor helper to write image.""" - with open(to_file, 'wb') as img_file: - img_file.write(image_data) - - try: - await hass.async_add_job( - _write_image, snapshot_file, image) - except OSError as err: - _LOGGER.error("Can't write image to file: %s", err) - - hass.services.async_register( - DOMAIN, SERVICE_TURN_OFF, async_handle_camera_service, - schema=CAMERA_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TURN_ON, async_handle_camera_service, - schema=CAMERA_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_ENABLE_MOTION, async_handle_camera_service, - schema=CAMERA_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_DISABLE_MOTION, async_handle_camera_service, - schema=CAMERA_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_SNAPSHOT, async_handle_snapshot_service, - schema=CAMERA_SERVICE_SNAPSHOT) + component.async_register_entity_service( + SERVICE_ENABLE_MOTION, CAMERA_SERVICE_SCHEMA, + 'async_enable_motion_detection' + ) + component.async_register_entity_service( + SERVICE_DISABLE_MOTION, CAMERA_SERVICE_SCHEMA, + 'async_disable_motion_detection' + ) + component.async_register_entity_service( + SERVICE_TURN_OFF, CAMERA_SERVICE_SCHEMA, + 'async_turn_off' + ) + component.async_register_entity_service( + SERVICE_TURN_ON, CAMERA_SERVICE_SCHEMA, + 'async_turn_on' + ) + component.async_register_entity_service( + SERVICE_SNAPSHOT, CAMERA_SERVICE_SNAPSHOT, + async_handle_snapshot_service + ) return True @@ -553,3 +505,32 @@ def websocket_camera_thumbnail(hass, connection, msg): msg['id'], 'image_fetch_failed', 'Unable to fetch image')) hass.async_add_job(send_camera_still()) + + +async def async_handle_snapshot_service(camera, service): + """Handle snapshot services calls.""" + hass = camera.hass + filename = service.data[ATTR_FILENAME] + filename.hass = hass + + snapshot_file = filename.async_render( + variables={ATTR_ENTITY_ID: camera}) + + # check if we allow to access to that file + if not hass.config.is_allowed_path(snapshot_file): + _LOGGER.error( + "Can't write %s, no access to path!", snapshot_file) + return + + image = await camera.async_camera_image() + + def _write_image(to_file, image_data): + """Executor helper to write image.""" + with open(to_file, 'wb') as img_file: + img_file.write(image_data) + + try: + await hass.async_add_executor_job( + _write_image, snapshot_file, image) + except OSError as err: + _LOGGER.error("Can't write image to file: %s", err) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 9584422e2b4..90abe2343d2 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -4,7 +4,6 @@ Provides functionality to interact with climate devices. For more details about this component, please refer to the documentation at https://home-assistant.io/components/climate/ """ -import asyncio from datetime import timedelta import logging import functools as ft @@ -250,209 +249,46 @@ async def async_setup(hass, config): EntityComponent(_LOGGER, DOMAIN, hass, SCAN_INTERVAL) await component.async_setup(config) - async def async_away_mode_set_service(service): - """Set away mode on target climate devices.""" - target_climate = component.async_extract_from_service(service) - - away_mode = service.data.get(ATTR_AWAY_MODE) - - update_tasks = [] - for climate in target_climate: - if away_mode: - await climate.async_turn_away_mode_on() - else: - await climate.async_turn_away_mode_off() - - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_AWAY_MODE, async_away_mode_set_service, - schema=SET_AWAY_MODE_SCHEMA) - - async def async_hold_mode_set_service(service): - """Set hold mode on target climate devices.""" - target_climate = component.async_extract_from_service(service) - - hold_mode = service.data.get(ATTR_HOLD_MODE) - - update_tasks = [] - for climate in target_climate: - await climate.async_set_hold_mode(hold_mode) - - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_HOLD_MODE, async_hold_mode_set_service, - schema=SET_HOLD_MODE_SCHEMA) - - async def async_aux_heat_set_service(service): - """Set auxiliary heater on target climate devices.""" - target_climate = component.async_extract_from_service(service) - - aux_heat = service.data.get(ATTR_AUX_HEAT) - - update_tasks = [] - for climate in target_climate: - if aux_heat: - await climate.async_turn_aux_heat_on() - else: - await climate.async_turn_aux_heat_off() - - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_AUX_HEAT, async_aux_heat_set_service, - schema=SET_AUX_HEAT_SCHEMA) - - async def async_temperature_set_service(service): - """Set temperature on the target climate devices.""" - target_climate = component.async_extract_from_service(service) - - update_tasks = [] - for climate in target_climate: - kwargs = {} - for value, temp in service.data.items(): - if value in CONVERTIBLE_ATTRIBUTE: - kwargs[value] = convert_temperature( - temp, - hass.config.units.temperature_unit, - climate.temperature_unit - ) - else: - kwargs[value] = temp - - await climate.async_set_temperature(**kwargs) - - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_TEMPERATURE, async_temperature_set_service, - schema=SET_TEMPERATURE_SCHEMA) - - async def async_humidity_set_service(service): - """Set humidity on the target climate devices.""" - target_climate = component.async_extract_from_service(service) - - humidity = service.data.get(ATTR_HUMIDITY) - - update_tasks = [] - for climate in target_climate: - await climate.async_set_humidity(humidity) - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_HUMIDITY, async_humidity_set_service, - schema=SET_HUMIDITY_SCHEMA) - - async def async_fan_mode_set_service(service): - """Set fan mode on target climate devices.""" - target_climate = component.async_extract_from_service(service) - - fan = service.data.get(ATTR_FAN_MODE) - - update_tasks = [] - for climate in target_climate: - await climate.async_set_fan_mode(fan) - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_FAN_MODE, async_fan_mode_set_service, - schema=SET_FAN_MODE_SCHEMA) - - async def async_operation_set_service(service): - """Set operating mode on the target climate devices.""" - target_climate = component.async_extract_from_service(service) - - operation_mode = service.data.get(ATTR_OPERATION_MODE) - - update_tasks = [] - for climate in target_climate: - await climate.async_set_operation_mode(operation_mode) - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_OPERATION_MODE, async_operation_set_service, - schema=SET_OPERATION_MODE_SCHEMA) - - async def async_swing_set_service(service): - """Set swing mode on the target climate devices.""" - target_climate = component.async_extract_from_service(service) - - swing_mode = service.data.get(ATTR_SWING_MODE) - - update_tasks = [] - for climate in target_climate: - await climate.async_set_swing_mode(swing_mode) - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_SWING_MODE, async_swing_set_service, - schema=SET_SWING_MODE_SCHEMA) - - async def async_on_off_service(service): - """Handle on/off calls.""" - target_climate = component.async_extract_from_service(service) - - update_tasks = [] - for climate in target_climate: - if service.service == SERVICE_TURN_ON: - await climate.async_turn_on() - elif service.service == SERVICE_TURN_OFF: - await climate.async_turn_off() - - if not climate.should_poll: - continue - update_tasks.append(climate.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_TURN_OFF, async_on_off_service, - schema=ON_OFF_SERVICE_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TURN_ON, async_on_off_service, - schema=ON_OFF_SERVICE_SCHEMA) + component.async_register_entity_service( + SERVICE_SET_AWAY_MODE, SET_AWAY_MODE_SCHEMA, + async_service_away_mode + ) + component.async_register_entity_service( + SERVICE_SET_HOLD_MODE, SET_HOLD_MODE_SCHEMA, + 'async_set_hold_mode' + ) + component.async_register_entity_service( + SERVICE_SET_AUX_HEAT, SET_AUX_HEAT_SCHEMA, + async_service_aux_heat + ) + component.async_register_entity_service( + SERVICE_SET_TEMPERATURE, SET_TEMPERATURE_SCHEMA, + async_service_temperature_set + ) + component.async_register_entity_service( + SERVICE_SET_HUMIDITY, SET_HUMIDITY_SCHEMA, + 'async_set_humidity' + ) + component.async_register_entity_service( + SERVICE_SET_FAN_MODE, SET_FAN_MODE_SCHEMA, + 'async_set_fan_mode' + ) + component.async_register_entity_service( + SERVICE_SET_OPERATION_MODE, SET_OPERATION_MODE_SCHEMA, + 'async_set_operation_mode' + ) + component.async_register_entity_service( + SERVICE_SET_SWING_MODE, SET_SWING_MODE_SCHEMA, + 'async_set_swing_mode' + ) + component.async_register_entity_service( + SERVICE_TURN_OFF, ON_OFF_SERVICE_SCHEMA, + 'async_turn_off' + ) + component.async_register_entity_service( + SERVICE_TURN_ON, ON_OFF_SERVICE_SCHEMA, + 'async_turn_on' + ) return True @@ -812,3 +648,37 @@ class ClimateDevice(Entity): def max_humidity(self): """Return the maximum humidity.""" return DEFAULT_MAX_HUMIDITY + + +async def async_service_away_mode(entity, service): + """Handle away mode service.""" + if service.data[ATTR_AWAY_MODE]: + await entity.async_turn_away_mode_on() + else: + await entity.async_turn_away_mode_off() + + +async def async_service_aux_heat(entity, service): + """Handle aux heat service.""" + if service.data[ATTR_AUX_HEAT]: + await entity.async_turn_aux_heat_on() + else: + await entity.async_turn_aux_heat_off() + + +async def async_service_temperature_set(entity, service): + """Handle set temperature service.""" + hass = entity.hass + kwargs = {} + + for value, temp in service.data.items(): + if value in CONVERTIBLE_ATTRIBUTE: + kwargs[value] = convert_temperature( + temp, + hass.config.units.temperature_unit, + entity.temperature_unit + ) + else: + kwargs[value] = temp + + await entity.async_set_temperature(**kwargs) diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index db0e8c590fd..f2704e84bc5 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -89,33 +89,6 @@ FAN_SET_DIRECTION_SCHEMA = vol.Schema({ vol.Optional(ATTR_DIRECTION): cv.string }) # type: dict -SERVICE_TO_METHOD = { - SERVICE_TURN_ON: { - 'method': 'async_turn_on', - 'schema': FAN_TURN_ON_SCHEMA, - }, - SERVICE_TURN_OFF: { - 'method': 'async_turn_off', - 'schema': FAN_TURN_OFF_SCHEMA, - }, - SERVICE_TOGGLE: { - 'method': 'async_toggle', - 'schema': FAN_TOGGLE_SCHEMA, - }, - SERVICE_SET_SPEED: { - 'method': 'async_set_speed', - 'schema': FAN_SET_SPEED_SCHEMA, - }, - SERVICE_OSCILLATE: { - 'method': 'async_oscillate', - 'schema': FAN_OSCILLATE_SCHEMA, - }, - SERVICE_SET_DIRECTION: { - 'method': 'async_set_direction', - 'schema': FAN_SET_DIRECTION_SCHEMA, - }, -} - @bind_hass def is_on(hass, entity_id: str = None) -> bool: @@ -204,30 +177,30 @@ def async_setup(hass, config: dict): yield from component.async_setup(config) - @asyncio.coroutine - def async_handle_fan_service(service): - """Handle service call for fans.""" - method = SERVICE_TO_METHOD.get(service.service) - params = service.data.copy() - - # Convert the entity ids to valid fan ids - target_fans = component.async_extract_from_service(service) - params.pop(ATTR_ENTITY_ID, None) - - update_tasks = [] - for fan in target_fans: - yield from getattr(fan, method['method'])(**params) - if not fan.should_poll: - continue - update_tasks.append(fan.async_update_ha_state(True)) - - if update_tasks: - yield from asyncio.wait(update_tasks, loop=hass.loop) - - for service_name in SERVICE_TO_METHOD: - schema = SERVICE_TO_METHOD[service_name].get('schema') - hass.services.async_register( - DOMAIN, service_name, async_handle_fan_service, schema=schema) + component.async_register_entity_service( + SERVICE_TURN_ON, FAN_TURN_ON_SCHEMA, + 'async_turn_on' + ) + component.async_register_entity_service( + SERVICE_TURN_OFF, FAN_TURN_OFF_SCHEMA, + 'async_turn_off' + ) + component.async_register_entity_service( + SERVICE_TOGGLE, FAN_TOGGLE_SCHEMA, + 'async_toggle' + ) + component.async_register_entity_service( + SERVICE_SET_SPEED, FAN_SET_SPEED_SCHEMA, + 'async_set_speed' + ) + component.async_register_entity_service( + SERVICE_OSCILLATE, FAN_OSCILLATE_SCHEMA, + 'async_oscillate' + ) + component.async_register_entity_service( + SERVICE_SET_DIRECTION, FAN_SET_DIRECTION_SCHEMA, + 'async_set_direction' + ) return True diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 8b4b2137711..456ad6d69be 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -332,8 +332,8 @@ async def async_setup(hass, config): if not profiles_valid: return False - async def async_handle_light_service(service): - """Handle a turn light on or off service call.""" + async def async_handle_light_on_service(service): + """Handle a turn light on service call.""" # Get the validated data params = service.data.copy() @@ -345,17 +345,12 @@ async def async_setup(hass, config): update_tasks = [] for light in target_lights: - if service.service == SERVICE_TURN_ON: - pars = params - if not pars: - pars = params.copy() - pars[ATTR_PROFILE] = Profiles.get_default(light.entity_id) - preprocess_turn_on_alternatives(pars) - await light.async_turn_on(**pars) - elif service.service == SERVICE_TURN_OFF: - await light.async_turn_off(**params) - else: - await light.async_toggle(**params) + pars = params + if not pars: + pars = params.copy() + pars[ATTR_PROFILE] = Profiles.get_default(light.entity_id) + preprocess_turn_on_alternatives(pars) + await light.async_turn_on(**pars) if not light.should_poll: continue @@ -368,16 +363,18 @@ async def async_setup(hass, config): # Listen for light on and light off service calls. hass.services.async_register( - DOMAIN, SERVICE_TURN_ON, async_handle_light_service, + DOMAIN, SERVICE_TURN_ON, async_handle_light_on_service, schema=LIGHT_TURN_ON_SCHEMA) - hass.services.async_register( - DOMAIN, SERVICE_TURN_OFF, async_handle_light_service, - schema=LIGHT_TURN_OFF_SCHEMA) + component.async_register_entity_service( + SERVICE_TURN_OFF, LIGHT_TURN_OFF_SCHEMA, + 'async_turn_off' + ) - hass.services.async_register( - DOMAIN, SERVICE_TOGGLE, async_handle_light_service, - schema=LIGHT_TOGGLE_SCHEMA) + component.async_register_entity_service( + SERVICE_TOGGLE, LIGHT_TOGGLE_SCHEMA, + 'async_toggle' + ) hass.helpers.intent.async_register(SetIntentHandler()) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index c475291227a..31c254c0a39 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -151,42 +151,6 @@ MEDIA_PLAYER_SET_SHUFFLE_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({ vol.Required(ATTR_MEDIA_SHUFFLE): cv.boolean, }) -SERVICE_TO_METHOD = { - SERVICE_TURN_ON: {'method': 'async_turn_on'}, - SERVICE_TURN_OFF: {'method': 'async_turn_off'}, - SERVICE_TOGGLE: {'method': 'async_toggle'}, - SERVICE_VOLUME_UP: {'method': 'async_volume_up'}, - SERVICE_VOLUME_DOWN: {'method': 'async_volume_down'}, - SERVICE_MEDIA_PLAY_PAUSE: {'method': 'async_media_play_pause'}, - SERVICE_MEDIA_PLAY: {'method': 'async_media_play'}, - SERVICE_MEDIA_PAUSE: {'method': 'async_media_pause'}, - SERVICE_MEDIA_STOP: {'method': 'async_media_stop'}, - SERVICE_MEDIA_NEXT_TRACK: {'method': 'async_media_next_track'}, - SERVICE_MEDIA_PREVIOUS_TRACK: {'method': 'async_media_previous_track'}, - SERVICE_CLEAR_PLAYLIST: {'method': 'async_clear_playlist'}, - SERVICE_VOLUME_SET: { - 'method': 'async_set_volume_level', - 'schema': MEDIA_PLAYER_SET_VOLUME_SCHEMA}, - SERVICE_VOLUME_MUTE: { - 'method': 'async_mute_volume', - 'schema': MEDIA_PLAYER_MUTE_VOLUME_SCHEMA}, - SERVICE_MEDIA_SEEK: { - 'method': 'async_media_seek', - 'schema': MEDIA_PLAYER_MEDIA_SEEK_SCHEMA}, - SERVICE_SELECT_SOURCE: { - 'method': 'async_select_source', - 'schema': MEDIA_PLAYER_SELECT_SOURCE_SCHEMA}, - SERVICE_SELECT_SOUND_MODE: { - 'method': 'async_select_sound_mode', - 'schema': MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA}, - SERVICE_PLAY_MEDIA: { - 'method': 'async_play_media', - 'schema': MEDIA_PLAYER_PLAY_MEDIA_SCHEMA}, - SERVICE_SHUFFLE_SET: { - 'method': 'async_set_shuffle', - 'schema': MEDIA_PLAYER_SET_SHUFFLE_SCHEMA}, -} - ATTR_TO_PROPERTY = [ ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_MUTED, @@ -409,50 +373,89 @@ async def async_setup(hass, config): await component.async_setup(config) - async def async_service_handler(service): - """Map services to methods on MediaPlayerDevice.""" - method = SERVICE_TO_METHOD.get(service.service) - if not method: - return - - params = {} - if service.service == SERVICE_VOLUME_SET: - params['volume'] = service.data.get(ATTR_MEDIA_VOLUME_LEVEL) - elif service.service == SERVICE_VOLUME_MUTE: - params['mute'] = service.data.get(ATTR_MEDIA_VOLUME_MUTED) - elif service.service == SERVICE_MEDIA_SEEK: - params['position'] = service.data.get(ATTR_MEDIA_SEEK_POSITION) - elif service.service == SERVICE_SELECT_SOURCE: - params['source'] = service.data.get(ATTR_INPUT_SOURCE) - elif service.service == SERVICE_SELECT_SOUND_MODE: - params['sound_mode'] = service.data.get(ATTR_SOUND_MODE) - elif service.service == SERVICE_PLAY_MEDIA: - params['media_type'] = \ - service.data.get(ATTR_MEDIA_CONTENT_TYPE) - params['media_id'] = service.data.get(ATTR_MEDIA_CONTENT_ID) - params[ATTR_MEDIA_ENQUEUE] = \ - service.data.get(ATTR_MEDIA_ENQUEUE) - elif service.service == SERVICE_SHUFFLE_SET: - params[ATTR_MEDIA_SHUFFLE] = \ - service.data.get(ATTR_MEDIA_SHUFFLE) - target_players = component.async_extract_from_service(service) - - update_tasks = [] - for player in target_players: - await getattr(player, method['method'])(**params) - if not player.should_poll: - continue - update_tasks.append(player.async_update_ha_state(True)) - - if update_tasks: - await asyncio.wait(update_tasks, loop=hass.loop) - - for service in SERVICE_TO_METHOD: - schema = SERVICE_TO_METHOD[service].get( - 'schema', MEDIA_PLAYER_SCHEMA) - hass.services.async_register( - DOMAIN, service, async_service_handler, - schema=schema) + component.async_register_entity_service( + SERVICE_TURN_ON, MEDIA_PLAYER_SCHEMA, + 'async_turn_on' + ) + component.async_register_entity_service( + SERVICE_TURN_OFF, MEDIA_PLAYER_SCHEMA, + 'async_turn_off' + ) + component.async_register_entity_service( + SERVICE_TOGGLE, MEDIA_PLAYER_SCHEMA, + 'async_toggle' + ) + component.async_register_entity_service( + SERVICE_VOLUME_UP, MEDIA_PLAYER_SCHEMA, + 'async_volume_up' + ) + component.async_register_entity_service( + SERVICE_VOLUME_DOWN, MEDIA_PLAYER_SCHEMA, + 'async_volume_down' + ) + component.async_register_entity_service( + SERVICE_MEDIA_PLAY_PAUSE, MEDIA_PLAYER_SCHEMA, + 'async_media_play_pause' + ) + component.async_register_entity_service( + SERVICE_MEDIA_PLAY, MEDIA_PLAYER_SCHEMA, + 'async_media_play' + ) + component.async_register_entity_service( + SERVICE_MEDIA_PAUSE, MEDIA_PLAYER_SCHEMA, + 'async_media_pause' + ) + component.async_register_entity_service( + SERVICE_MEDIA_STOP, MEDIA_PLAYER_SCHEMA, + 'async_media_stop' + ) + component.async_register_entity_service( + SERVICE_MEDIA_NEXT_TRACK, MEDIA_PLAYER_SCHEMA, + 'async_media_next_track' + ) + component.async_register_entity_service( + SERVICE_MEDIA_PREVIOUS_TRACK, MEDIA_PLAYER_SCHEMA, + 'async_media_previous_track' + ) + component.async_register_entity_service( + SERVICE_CLEAR_PLAYLIST, MEDIA_PLAYER_SCHEMA, + 'async_clear_playlist' + ) + component.async_register_entity_service( + SERVICE_VOLUME_SET, MEDIA_PLAYER_SET_VOLUME_SCHEMA, + lambda entity, call: entity.async_set_volume_level( + volume=call.data[ATTR_MEDIA_VOLUME_LEVEL]) + ) + component.async_register_entity_service( + SERVICE_VOLUME_MUTE, MEDIA_PLAYER_MUTE_VOLUME_SCHEMA, + lambda entity, call: entity.async_mute_volume( + mute=call.data[ATTR_MEDIA_VOLUME_MUTED]) + ) + component.async_register_entity_service( + SERVICE_MEDIA_SEEK, MEDIA_PLAYER_MEDIA_SEEK_SCHEMA, + lambda entity, call: entity.async_media_seek( + position=call.data[ATTR_MEDIA_SEEK_POSITION]) + ) + component.async_register_entity_service( + SERVICE_SELECT_SOURCE, MEDIA_PLAYER_SELECT_SOURCE_SCHEMA, + 'async_select_source' + ) + component.async_register_entity_service( + SERVICE_SELECT_SOUND_MODE, MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA, + 'async_select_sound_mode' + ) + component.async_register_entity_service( + SERVICE_PLAY_MEDIA, MEDIA_PLAYER_PLAY_MEDIA_SCHEMA, + lambda entity, call: entity.async_play_media( + media_type=call.data[ATTR_MEDIA_CONTENT_TYPE], + media_id=call.data[ATTR_MEDIA_CONTENT_ID], + enqueue=call.data.get(ATTR_MEDIA_ENQUEUE) + ) + ) + component.async_register_entity_service( + SERVICE_SHUFFLE_SET, MEDIA_PLAYER_SET_SHUFFLE_SCHEMA, + 'async_set_shuffle' + ) return True diff --git a/tests/components/camera/test_demo.py b/tests/components/camera/test_demo.py index b901b723c0b..63c70ddc6ca 100644 --- a/tests/components/camera/test_demo.py +++ b/tests/components/camera/test_demo.py @@ -1,5 +1,5 @@ """The tests for local file camera component.""" -from unittest.mock import mock_open, patch, PropertyMock +from unittest.mock import mock_open, patch import pytest @@ -67,19 +67,6 @@ async def test_turn_off_invalid_camera(hass, demo_camera): assert demo_camera.state == STATE_STREAMING -async def test_turn_off_unsupport_camera(hass, demo_camera): - """Turn off unsupported camera should quietly fail.""" - assert demo_camera.state == STATE_STREAMING - with patch('homeassistant.components.camera.demo.DemoCamera' - '.supported_features', new_callable=PropertyMock) as m: - m.return_value = 0 - - await camera.async_turn_off(hass, demo_camera.entity_id) - await hass.async_block_till_done() - - assert demo_camera.state == STATE_STREAMING - - async def test_motion_detection(hass): """Test motion detection services.""" # Setup platform diff --git a/tests/components/light/test_rflink.py b/tests/components/light/test_rflink.py index a6e6d3c1a85..c55c16077e0 100644 --- a/tests/components/light/test_rflink.py +++ b/tests/components/light/test_rflink.py @@ -356,11 +356,10 @@ def test_signal_repetitions_cancelling(hass, monkeypatch): yield from hass.async_block_till_done() - print(protocol.send_command_ack.call_args_list) - assert protocol.send_command_ack.call_args_list[0][0][1] == 'off' - assert protocol.send_command_ack.call_args_list[1][0][1] == 'on' - assert protocol.send_command_ack.call_args_list[2][0][1] == 'on' - assert protocol.send_command_ack.call_args_list[3][0][1] == 'on' + assert protocol.send_command_ack.call_args_list[0][0][1] == 'on' + assert protocol.send_command_ack.call_args_list[1][0][1] == 'off' + assert protocol.send_command_ack.call_args_list[2][0][1] == 'off' + assert protocol.send_command_ack.call_args_list[3][0][1] == 'off' @asyncio.coroutine From 2a210607d392cac85bb82dd576877ddb192c85c5 Mon Sep 17 00:00:00 2001 From: Max Prokhorov Date: Thu, 16 Aug 2018 17:14:54 +0300 Subject: [PATCH 043/159] Wemo custom ports and network errors handling (#14516) * Update wemo component * Support custom ports in static addresses * Handle device_from_description exceptions * Process static addresses before doing discovery * Fail on inaccessable static address * str.format instead of old formatting * Validate static host[:port] earlier * Fix comment formatting * slice looks ambiguous in the log, keep voluptuous exception path intact --- .../components/binary_sensor/wemo.py | 10 ++- homeassistant/components/light/wemo.py | 10 ++- homeassistant/components/switch/wemo.py | 10 ++- homeassistant/components/wemo.py | 74 +++++++++++++++---- 4 files changed, 87 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/binary_sensor/wemo.py b/homeassistant/components/binary_sensor/wemo.py index a589ab4e8c8..bde6accf421 100644 --- a/homeassistant/components/binary_sensor/wemo.py +++ b/homeassistant/components/binary_sensor/wemo.py @@ -5,8 +5,10 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/binary_sensor.wemo/ """ import logging +import requests from homeassistant.components.binary_sensor import BinarySensorDevice +from homeassistant.exceptions import PlatformNotReady DEPENDENCIES = ['wemo'] @@ -20,7 +22,13 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): if discovery_info is not None: location = discovery_info['ssdp_description'] mac = discovery_info['mac_address'] - device = discovery.device_from_description(location, mac) + + try: + device = discovery.device_from_description(location, mac) + except (requests.exceptions.ConnectionError, + requests.exceptions.Timeout) as err: + _LOGGER.error('Unable to access %s (%s)', location, err) + raise PlatformNotReady if device: add_devices_callback([WemoBinarySensor(hass, device)]) diff --git a/homeassistant/components/light/wemo.py b/homeassistant/components/light/wemo.py index 4c912d60fb7..78dedb12718 100644 --- a/homeassistant/components/light/wemo.py +++ b/homeassistant/components/light/wemo.py @@ -7,11 +7,13 @@ https://home-assistant.io/components/light.wemo/ import asyncio import logging from datetime import timedelta +import requests from homeassistant import util from homeassistant.components.light import ( Light, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_TRANSITION, SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_COLOR, SUPPORT_TRANSITION) +from homeassistant.exceptions import PlatformNotReady import homeassistant.util.color as color_util DEPENDENCIES = ['wemo'] @@ -32,7 +34,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if discovery_info is not None: location = discovery_info['ssdp_description'] mac = discovery_info['mac_address'] - device = discovery.device_from_description(location, mac) + + try: + device = discovery.device_from_description(location, mac) + except (requests.exceptions.ConnectionError, + requests.exceptions.Timeout) as err: + _LOGGER.error('Unable to access %s (%s)', location, err) + raise PlatformNotReady if device.model_name == 'Dimmer': add_devices([WemoDimmer(device)]) diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index 35ea435bf48..594f290273e 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -7,10 +7,12 @@ https://home-assistant.io/components/switch.wemo/ import asyncio import logging from datetime import datetime, timedelta +import requests import async_timeout from homeassistant.components.switch import SwitchDevice +from homeassistant.exceptions import PlatformNotReady from homeassistant.util import convert from homeassistant.const import ( STATE_OFF, STATE_ON, STATE_STANDBY, STATE_UNKNOWN) @@ -40,7 +42,13 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): if discovery_info is not None: location = discovery_info['ssdp_description'] mac = discovery_info['mac_address'] - device = discovery.device_from_description(location, mac) + + try: + device = discovery.device_from_description(location, mac) + except (requests.exceptions.ConnectionError, + requests.exceptions.Timeout) as err: + _LOGGER.error('Unable to access %s (%s)', location, err) + raise PlatformNotReady if device: add_devices_callback([WemoSwitch(device)]) diff --git a/homeassistant/components/wemo.py b/homeassistant/components/wemo.py index 27027cc9eb4..2ce2ff475a2 100644 --- a/homeassistant/components/wemo.py +++ b/homeassistant/components/wemo.py @@ -6,6 +6,7 @@ https://home-assistant.io/components/wemo/ """ import logging +import requests import voluptuous as vol from homeassistant.components.discovery import SERVICE_WEMO @@ -36,11 +37,32 @@ KNOWN_DEVICES = [] _LOGGER = logging.getLogger(__name__) + +def coerce_host_port(value): + """Validate that provided value is either just host or host:port. + + Returns (host, None) or (host, port) respectively. + """ + host, _, port = value.partition(':') + + if not host: + raise vol.Invalid('host cannot be empty') + + if port: + port = cv.port(port) + else: + port = None + + return host, port + + CONF_STATIC = 'static' CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ - vol.Optional(CONF_STATIC, default=[]): vol.Schema([cv.string]) + vol.Optional(CONF_STATIC, default=[]): vol.Schema([ + vol.All(cv.string, coerce_host_port) + ]) }), }, extra=vol.ALLOW_EXTRA) @@ -79,23 +101,47 @@ def setup(hass, config): discovery.listen(hass, SERVICE_WEMO, discovery_dispatch) - _LOGGER.info("Scanning for WeMo devices.") - devices = [(device.host, device) for device in pywemo.discover_devices()] + def setup_url_for_device(device): + """Determine setup.xml url for given device.""" + return 'http://{}:{}/setup.xml'.format(device.host, device.port) - # Add static devices from the config file. - devices.extend((address, None) - for address in config.get(DOMAIN, {}).get(CONF_STATIC, [])) - - for address, device in devices: - port = pywemo.ouimeaux_device.probe_wemo(address) + def setup_url_for_address(host, port): + """Determine setup.xml url for given host and port pair.""" if not port: - _LOGGER.warning('Unable to probe wemo at %s', address) - continue - _LOGGER.info('Adding wemo at %s:%i', address, port) + port = pywemo.ouimeaux_device.probe_wemo(host) - url = 'http://%s:%i/setup.xml' % (address, port) - if device is None: + if not port: + return None + + return 'http://{}:{}/setup.xml'.format(host, port) + + devices = [] + + for host, port in config.get(DOMAIN, {}).get(CONF_STATIC, []): + url = setup_url_for_address(host, port) + + if not url: + _LOGGER.error( + 'Unable to get description url for %s', + '{}:{}'.format(host, port) if port else host) + return False + + try: device = pywemo.discovery.device_from_description(url, None) + except (requests.exceptions.ConnectionError, + requests.exceptions.Timeout) as err: + _LOGGER.error('Unable to access %s (%s)', url, err) + return False + + devices.append((url, device)) + + _LOGGER.info("Scanning for WeMo devices.") + devices.extend( + (setup_url_for_device(device), device) + for device in pywemo.discover_devices()) + + for url, device in devices: + _LOGGER.info('Adding wemo at %s:%i', device.host, device.port) discovery_info = { 'model_name': device.model_name, From 834077190f8027bec65885f4397bfb350b6b2e71 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 22:17:14 +0200 Subject: [PATCH 044/159] Clean up input-datetime (#16000) --- homeassistant/components/input_datetime.py | 128 ++++++++------------- homeassistant/helpers/config_validation.py | 15 --- tests/components/test_input_datetime.py | 14 ++- tests/helpers/test_config_validation.py | 15 --- 4 files changed, 60 insertions(+), 112 deletions(-) diff --git a/homeassistant/components/input_datetime.py b/homeassistant/components/input_datetime.py index a77b67792f5..df35ae53ba9 100644 --- a/homeassistant/components/input_datetime.py +++ b/homeassistant/components/input_datetime.py @@ -4,14 +4,12 @@ Component to offer a way to select a date and / or a time. For more details about this component, please refer to the documentation at https://home-assistant.io/components/input_datetime/ """ -import asyncio import logging import datetime import voluptuous as vol -from homeassistant.const import ( - ATTR_ENTITY_ID, CONF_ICON, CONF_NAME, STATE_UNKNOWN) +from homeassistant.const import ATTR_ENTITY_ID, CONF_ICON, CONF_NAME import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent @@ -39,6 +37,15 @@ SERVICE_SET_DATETIME_SCHEMA = vol.Schema({ vol.Optional(ATTR_TIME): cv.time, }) + +def has_date_or_time(conf): + """Check at least date or time is true.""" + if conf[CONF_HAS_DATE] or conf[CONF_HAS_TIME]: + return conf + + raise vol.Invalid('Entity needs at least a date or a time') + + CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ cv.slug: vol.All({ @@ -47,23 +54,11 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_HAS_TIME, default=False): cv.boolean, vol.Optional(CONF_ICON): cv.icon, vol.Optional(CONF_INITIAL): cv.string, - }, cv.has_at_least_one_key_value((CONF_HAS_DATE, True), - (CONF_HAS_TIME, True)))}) + }, has_date_or_time)}) }, extra=vol.ALLOW_EXTRA) -@asyncio.coroutine -def async_set_datetime(hass, entity_id, dt_value): - """Set date and / or time of input_datetime.""" - yield from hass.services.async_call(DOMAIN, SERVICE_SET_DATETIME, { - ATTR_ENTITY_ID: entity_id, - ATTR_DATE: dt_value.date(), - ATTR_TIME: dt_value.time() - }) - - -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up an input datetime.""" component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -81,32 +76,24 @@ def async_setup(hass, config): if not entities: return False - @asyncio.coroutine - def async_set_datetime_service(call): + async def async_set_datetime_service(entity, call): """Handle a call to the input datetime 'set datetime' service.""" - target_inputs = component.async_extract_from_service(call) + time = call.data.get(ATTR_TIME) + date = call.data.get(ATTR_DATE) + if (entity.has_date and not date) or (entity.has_time and not time): + _LOGGER.error("Invalid service data for %s " + "input_datetime.set_datetime: %s", + entity.entity_id, str(call.data)) + return - tasks = [] - for input_datetime in target_inputs: - time = call.data.get(ATTR_TIME) - date = call.data.get(ATTR_DATE) - if (input_datetime.has_date() and not date) or \ - (input_datetime.has_time() and not time): - _LOGGER.error("Invalid service data for " - "input_datetime.set_datetime: %s", - str(call.data)) - continue + entity.async_set_datetime(date, time) - tasks.append(input_datetime.async_set_datetime(date, time)) + component.async_register_entity_service( + SERVICE_SET_DATETIME, SERVICE_SET_DATETIME_SCHEMA, + async_set_datetime_service + ) - if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) - - hass.services.async_register( - DOMAIN, SERVICE_SET_DATETIME, async_set_datetime_service, - schema=SERVICE_SET_DATETIME_SCHEMA) - - yield from component.async_add_entities(entities) + await component.async_add_entities(entities) return True @@ -117,14 +104,13 @@ class InputDatetime(Entity): """Initialize a select input.""" self.entity_id = ENTITY_ID_FORMAT.format(object_id) self._name = name - self._has_date = has_date - self._has_time = has_time + self.has_date = has_date + self.has_time = has_time self._icon = icon self._initial = initial self._current_datetime = None - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Run when entity about to be added.""" restore_val = None @@ -134,27 +120,18 @@ class InputDatetime(Entity): # Priority 2: Old state if restore_val is None: - old_state = yield from async_get_last_state(self.hass, - self.entity_id) + old_state = await async_get_last_state(self.hass, self.entity_id) if old_state is not None: restore_val = old_state.state if restore_val is not None: - if not self._has_date: + if not self.has_date: self._current_datetime = dt_util.parse_time(restore_val) - elif not self._has_time: + elif not self.has_time: self._current_datetime = dt_util.parse_date(restore_val) else: self._current_datetime = dt_util.parse_datetime(restore_val) - def has_date(self): - """Return whether the input datetime carries a date.""" - return self._has_date - - def has_time(self): - """Return whether the input datetime carries a time.""" - return self._has_time - @property def should_poll(self): """If entity should be polled.""" @@ -173,55 +150,50 @@ class InputDatetime(Entity): @property def state(self): """Return the state of the component.""" - if self._current_datetime is None: - return STATE_UNKNOWN - return self._current_datetime @property def state_attributes(self): """Return the state attributes.""" attrs = { - 'has_date': self._has_date, - 'has_time': self._has_time, + 'has_date': self.has_date, + 'has_time': self.has_time, } if self._current_datetime is None: return attrs - if self._has_date and self._current_datetime is not None: + if self.has_date and self._current_datetime is not None: attrs['year'] = self._current_datetime.year attrs['month'] = self._current_datetime.month attrs['day'] = self._current_datetime.day - if self._has_time and self._current_datetime is not None: + if self.has_time and self._current_datetime is not None: attrs['hour'] = self._current_datetime.hour attrs['minute'] = self._current_datetime.minute attrs['second'] = self._current_datetime.second - if self._current_datetime is not None: - if not self._has_date: - attrs['timestamp'] = self._current_datetime.hour * 3600 + \ - self._current_datetime.minute * 60 + \ - self._current_datetime.second - elif not self._has_time: - extended = datetime.datetime.combine(self._current_datetime, - datetime.time(0, 0)) - attrs['timestamp'] = extended.timestamp() - else: - attrs['timestamp'] = self._current_datetime.timestamp() + if not self.has_date: + attrs['timestamp'] = self._current_datetime.hour * 3600 + \ + self._current_datetime.minute * 60 + \ + self._current_datetime.second + elif not self.has_time: + extended = datetime.datetime.combine(self._current_datetime, + datetime.time(0, 0)) + attrs['timestamp'] = extended.timestamp() + else: + attrs['timestamp'] = self._current_datetime.timestamp() return attrs - @asyncio.coroutine def async_set_datetime(self, date_val, time_val): """Set a new date / time.""" - if self._has_date and self._has_time and date_val and time_val: + if self.has_date and self.has_time and date_val and time_val: self._current_datetime = datetime.datetime.combine(date_val, time_val) - elif self._has_date and not self._has_time and date_val: + elif self.has_date and not self.has_time and date_val: self._current_datetime = date_val - if self._has_time and not self._has_date and time_val: + if self.has_time and not self.has_date and time_val: self._current_datetime = time_val - yield from self.async_update_ha_state() + self.async_schedule_update_ha_state() diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 26de41387f5..bbd863b5693 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -60,21 +60,6 @@ def has_at_least_one_key(*keys: str) -> Callable: return validate -def has_at_least_one_key_value(*items: list) -> Callable: - """Validate that at least one (key, value) pair exists.""" - def validate(obj: Dict) -> Dict: - """Test (key,value) exist in dict.""" - if not isinstance(obj, dict): - raise vol.Invalid('expected dictionary') - - for item in obj.items(): - if item in items: - return obj - raise vol.Invalid('must contain one of {}.'.format(str(items))) - - return validate - - def boolean(value: Any) -> bool: """Validate and coerce a boolean value.""" if isinstance(value, str): diff --git a/tests/components/test_input_datetime.py b/tests/components/test_input_datetime.py index 5d3f1782831..7277a8d7d3a 100644 --- a/tests/components/test_input_datetime.py +++ b/tests/components/test_input_datetime.py @@ -7,11 +7,20 @@ import datetime from homeassistant.core import CoreState, State from homeassistant.setup import setup_component, async_setup_component from homeassistant.components.input_datetime import ( - DOMAIN, async_set_datetime) + DOMAIN, ATTR_ENTITY_ID, ATTR_DATE, ATTR_TIME, SERVICE_SET_DATETIME) from tests.common import get_test_home_assistant, mock_restore_cache +async def async_set_datetime(hass, entity_id, dt_value): + """Set date and / or time of input_datetime.""" + await hass.services.async_call(DOMAIN, SERVICE_SET_DATETIME, { + ATTR_ENTITY_ID: entity_id, + ATTR_DATE: dt_value.date(), + ATTR_TIME: dt_value.time() + }, blocking=True) + + class TestInputDatetime(unittest.TestCase): """Test the input datetime component.""" @@ -57,7 +66,6 @@ def test_set_datetime(hass): dt_obj = datetime.datetime(2017, 9, 7, 19, 46) yield from async_set_datetime(hass, entity_id, dt_obj) - yield from hass.async_block_till_done() state = hass.states.get(entity_id) assert state.state == str(dt_obj) @@ -89,7 +97,6 @@ def test_set_datetime_time(hass): time_portion = dt_obj.time() yield from async_set_datetime(hass, entity_id, dt_obj) - yield from hass.async_block_till_done() state = hass.states.get(entity_id) assert state.state == str(time_portion) @@ -144,7 +151,6 @@ def test_set_datetime_date(hass): date_portion = dt_obj.date() yield from async_set_datetime(hass, entity_id, dt_obj) - yield from hass.async_block_till_done() state = hass.states.get(entity_id) assert state.state == str(date_portion) diff --git a/tests/helpers/test_config_validation.py b/tests/helpers/test_config_validation.py index 28efcb3e868..ab575c61789 100644 --- a/tests/helpers/test_config_validation.py +++ b/tests/helpers/test_config_validation.py @@ -523,21 +523,6 @@ def test_has_at_least_one_key(): schema(value) -def test_has_at_least_one_key_value(): - """Test has_at_least_one_key_value validator.""" - schema = vol.Schema(cv.has_at_least_one_key_value(('drink', 'beer'), - ('drink', 'soda'), - ('food', 'maultaschen'))) - - for value in (None, [], {}, {'wine': None}, {'drink': 'water'}): - with pytest.raises(vol.MultipleInvalid): - schema(value) - - for value in ({'drink': 'beer'}, {'food': 'maultaschen'}, - {'drink': 'soda', 'food': 'maultaschen'}): - schema(value) - - def test_enum(): """Test enum validator.""" class TestEnum(enum.Enum): From bc21a1b944791cdf47fde15fe47ce4f1ac7e99c1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 22:15:39 +0200 Subject: [PATCH 045/159] Bump frontend to 20180816.1 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index c3c742f43b1..40fb6056684 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180816.0'] +REQUIREMENTS = ['home-assistant-frontend==20180816.1'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 894e9ef1706..4754851b8e7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -435,7 +435,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180816.0 +home-assistant-frontend==20180816.1 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 0958b6d7280..8b153494025 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180816.0 +home-assistant-frontend==20180816.1 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From e9e5bce10c725b779a930e918bd5c68c03793328 Mon Sep 17 00:00:00 2001 From: Alexxander0 Date: Thu, 16 Aug 2018 22:19:29 +0200 Subject: [PATCH 046/159] BMW Connected drive: option to disable the services (#15993) * Update __init__.py * Update bmw_connected_drive.py * Update __init__.py * Update bmw_connected_drive.py * Update __init__.py * Update __init__.py * Update __init__.py * Update __init__.py * Update __init__.py * Update __init__.py * Update __init__.py * Update bmw_connected_drive.py --- .../bmw_connected_drive/__init__.py | 23 +++++++++++-------- .../components/lock/bmw_connected_drive.py | 7 +++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/bmw_connected_drive/__init__.py b/homeassistant/components/bmw_connected_drive/__init__.py index 061b09c1b3b..b0ad1a867a8 100644 --- a/homeassistant/components/bmw_connected_drive/__init__.py +++ b/homeassistant/components/bmw_connected_drive/__init__.py @@ -20,6 +20,7 @@ _LOGGER = logging.getLogger(__name__) DOMAIN = 'bmw_connected_drive' CONF_REGION = 'region' +CONF_READ_ONLY = 'read_only' ATTR_VIN = 'vin' ACCOUNT_SCHEMA = vol.Schema({ @@ -27,6 +28,7 @@ ACCOUNT_SCHEMA = vol.Schema({ vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_REGION): vol.Any('north_america', 'china', 'rest_of_world'), + vol.Optional(CONF_READ_ONLY, default=False): cv.boolean, }) CONFIG_SCHEMA = vol.Schema({ @@ -82,8 +84,10 @@ def setup_account(account_config: dict, hass, name: str) \ username = account_config[CONF_USERNAME] password = account_config[CONF_PASSWORD] region = account_config[CONF_REGION] + read_only = account_config[CONF_READ_ONLY] _LOGGER.debug('Adding new account %s', name) - cd_account = BMWConnectedDriveAccount(username, password, region, name) + cd_account = BMWConnectedDriveAccount(username, password, region, name, + read_only) def execute_service(call): """Execute a service for a vehicle. @@ -99,13 +103,13 @@ def setup_account(account_config: dict, hass, name: str) \ function_name = _SERVICE_MAP[call.service] function_call = getattr(vehicle.remote_services, function_name) function_call() - - # register the remote services - for service in _SERVICE_MAP: - hass.services.register( - DOMAIN, service, - execute_service, - schema=SERVICE_SCHEMA) + if not read_only: + # register the remote services + for service in _SERVICE_MAP: + hass.services.register( + DOMAIN, service, + execute_service, + schema=SERVICE_SCHEMA) # update every UPDATE_INTERVAL minutes, starting now # this should even out the load on the servers @@ -122,13 +126,14 @@ class BMWConnectedDriveAccount: """Representation of a BMW vehicle.""" def __init__(self, username: str, password: str, region_str: str, - name: str) -> None: + name: str, read_only) -> None: """Constructor.""" from bimmer_connected.account import ConnectedDriveAccount from bimmer_connected.country_selector import get_region_from_name region = get_region_from_name(region_str) + self.read_only = read_only self.account = ConnectedDriveAccount(username, password, region) self.name = name self._update_listeners = [] diff --git a/homeassistant/components/lock/bmw_connected_drive.py b/homeassistant/components/lock/bmw_connected_drive.py index 52734b1259c..f4fb6d1fbf0 100644 --- a/homeassistant/components/lock/bmw_connected_drive.py +++ b/homeassistant/components/lock/bmw_connected_drive.py @@ -23,9 +23,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ', '.join([a.name for a in accounts])) devices = [] for account in accounts: - for vehicle in account.account.vehicles: - device = BMWLock(account, vehicle, 'lock', 'BMW lock') - devices.append(device) + if not account.read_only: + for vehicle in account.account.vehicles: + device = BMWLock(account, vehicle, 'lock', 'BMW lock') + devices.append(device) add_devices(devices, True) From 649f17fe475ef2a377cea81487741ae02fd96d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Thu, 16 Aug 2018 23:25:41 +0300 Subject: [PATCH 047/159] Add type hints to homeassistant.auth (#15853) * Always load users in auth store before use * Use namedtuple instead of dict for user meta * Ignore auth store tokens with invalid created_at * Add type hints to homeassistant.auth --- homeassistant/auth/__init__.py | 89 ++++++---- homeassistant/auth/auth_store.py | 73 ++++++-- homeassistant/auth/models.py | 19 +- homeassistant/auth/providers/__init__.py | 166 +++++++++--------- homeassistant/auth/providers/homeassistant.py | 53 +++--- .../auth/providers/insecure_example.py | 28 +-- .../auth/providers/legacy_api_password.py | 34 ++-- .../auth/providers/trusted_networks.py | 36 ++-- tox.ini | 2 +- 9 files changed, 300 insertions(+), 200 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 148f97702e3..b710ca9999e 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -2,7 +2,7 @@ import asyncio import logging from collections import OrderedDict -from typing import List, Awaitable +from typing import Any, Dict, List, Optional, Tuple, cast import jwt @@ -10,15 +10,17 @@ from homeassistant import data_entry_flow from homeassistant.core import callback, HomeAssistant from homeassistant.util import dt as dt_util -from . import auth_store -from .providers import auth_provider_from_config +from . import auth_store, models +from .providers import auth_provider_from_config, AuthProvider _LOGGER = logging.getLogger(__name__) +_ProviderKey = Tuple[str, Optional[str]] +_ProviderDict = Dict[_ProviderKey, AuthProvider] async def auth_manager_from_config( hass: HomeAssistant, - provider_configs: List[dict]) -> Awaitable['AuthManager']: + provider_configs: List[Dict[str, Any]]) -> 'AuthManager': """Initialize an auth manager from config.""" store = auth_store.AuthStore(hass) if provider_configs: @@ -26,9 +28,9 @@ async def auth_manager_from_config( *[auth_provider_from_config(hass, store, config) for config in provider_configs]) else: - providers = [] + providers = () # So returned auth providers are in same order as config - provider_hash = OrderedDict() + provider_hash = OrderedDict() # type: _ProviderDict for provider in providers: if provider is None: continue @@ -49,7 +51,8 @@ async def auth_manager_from_config( class AuthManager: """Manage the authentication for Home Assistant.""" - def __init__(self, hass, store, providers): + def __init__(self, hass: HomeAssistant, store: auth_store.AuthStore, + providers: _ProviderDict) -> None: """Initialize the auth manager.""" self._store = store self._providers = providers @@ -58,12 +61,12 @@ class AuthManager: self._async_finish_login_flow) @property - def active(self): + def active(self) -> bool: """Return if any auth providers are registered.""" return bool(self._providers) @property - def support_legacy(self): + def support_legacy(self) -> bool: """ Return if legacy_api_password auth providers are registered. @@ -75,19 +78,19 @@ class AuthManager: return False @property - def auth_providers(self): + def auth_providers(self) -> List[AuthProvider]: """Return a list of available auth providers.""" return list(self._providers.values()) - async def async_get_users(self): + async def async_get_users(self) -> List[models.User]: """Retrieve all users.""" return await self._store.async_get_users() - async def async_get_user(self, user_id): + async def async_get_user(self, user_id: str) -> Optional[models.User]: """Retrieve a user.""" return await self._store.async_get_user(user_id) - async def async_create_system_user(self, name): + async def async_create_system_user(self, name: str) -> models.User: """Create a system user.""" return await self._store.async_create_user( name=name, @@ -95,19 +98,20 @@ class AuthManager: is_active=True, ) - async def async_create_user(self, name): + async def async_create_user(self, name: str) -> models.User: """Create a user.""" kwargs = { 'name': name, 'is_active': True, - } + } # type: Dict[str, Any] if await self._user_should_be_owner(): kwargs['is_owner'] = True return await self._store.async_create_user(**kwargs) - async def async_get_or_create_user(self, credentials): + async def async_get_or_create_user(self, credentials: models.Credentials) \ + -> models.User: """Get or create a user.""" if not credentials.is_new: for user in await self._store.async_get_users(): @@ -127,15 +131,16 @@ class AuthManager: return await self._store.async_create_user( credentials=credentials, - name=info.get('name'), - is_active=info.get('is_active', False) + name=info.name, + is_active=info.is_active, ) - async def async_link_user(self, user, credentials): + async def async_link_user(self, user: models.User, + credentials: models.Credentials) -> None: """Link credentials to an existing user.""" await self._store.async_link_user(user, credentials) - async def async_remove_user(self, user): + async def async_remove_user(self, user: models.User) -> None: """Remove a user.""" tasks = [ self.async_remove_credentials(credentials) @@ -147,27 +152,32 @@ class AuthManager: await self._store.async_remove_user(user) - async def async_activate_user(self, user): + async def async_activate_user(self, user: models.User) -> None: """Activate a user.""" await self._store.async_activate_user(user) - async def async_deactivate_user(self, user): + async def async_deactivate_user(self, user: models.User) -> None: """Deactivate a user.""" if user.is_owner: raise ValueError('Unable to deactive the owner') await self._store.async_deactivate_user(user) - async def async_remove_credentials(self, credentials): + async def async_remove_credentials( + self, credentials: models.Credentials) -> None: """Remove credentials.""" provider = self._async_get_auth_provider(credentials) if (provider is not None and hasattr(provider, 'async_will_remove_credentials')): - await provider.async_will_remove_credentials(credentials) + # https://github.com/python/mypy/issues/1424 + await provider.async_will_remove_credentials( # type: ignore + credentials) await self._store.async_remove_credentials(credentials) - async def async_create_refresh_token(self, user, client_id=None): + async def async_create_refresh_token(self, user: models.User, + client_id: Optional[str] = None) \ + -> models.RefreshToken: """Create a new refresh token for a user.""" if not user.is_active: raise ValueError('User is not active') @@ -182,16 +192,19 @@ class AuthManager: return await self._store.async_create_refresh_token(user, client_id) - async def async_get_refresh_token(self, token_id): + async def async_get_refresh_token( + self, token_id: str) -> Optional[models.RefreshToken]: """Get refresh token by id.""" return await self._store.async_get_refresh_token(token_id) - async def async_get_refresh_token_by_token(self, token): + async def async_get_refresh_token_by_token( + self, token: str) -> Optional[models.RefreshToken]: """Get refresh token by token.""" return await self._store.async_get_refresh_token_by_token(token) @callback - def async_create_access_token(self, refresh_token): + def async_create_access_token(self, + refresh_token: models.RefreshToken) -> str: """Create a new access token.""" # pylint: disable=no-self-use return jwt.encode({ @@ -200,7 +213,8 @@ class AuthManager: 'exp': dt_util.utcnow() + refresh_token.access_token_expiration, }, refresh_token.jwt_key, algorithm='HS256').decode() - async def async_validate_access_token(self, token): + async def async_validate_access_token( + self, token: str) -> Optional[models.RefreshToken]: """Return if an access token is valid.""" try: unverif_claims = jwt.decode(token, verify=False) @@ -208,7 +222,7 @@ class AuthManager: return None refresh_token = await self.async_get_refresh_token( - unverif_claims.get('iss')) + cast(str, unverif_claims.get('iss'))) if refresh_token is None: jwt_key = '' @@ -228,18 +242,22 @@ class AuthManager: except jwt.InvalidTokenError: return None - if not refresh_token.user.is_active: + if refresh_token is None or not refresh_token.user.is_active: return None return refresh_token - async def _async_create_login_flow(self, handler, *, context, data): + async def _async_create_login_flow( + self, handler: _ProviderKey, *, context: Optional[Dict], + data: Optional[Any]) -> data_entry_flow.FlowHandler: """Create a login flow.""" auth_provider = self._providers[handler] return await auth_provider.async_credential_flow(context) - async def _async_finish_login_flow(self, context, result): + async def _async_finish_login_flow( + self, context: Optional[Dict], result: Dict[str, Any]) \ + -> Optional[models.Credentials]: """Result of a credential login flow.""" if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: return None @@ -249,13 +267,14 @@ class AuthManager: result['data']) @callback - def _async_get_auth_provider(self, credentials): + def _async_get_auth_provider( + self, credentials: models.Credentials) -> Optional[AuthProvider]: """Helper to get auth provider from a set of credentials.""" auth_provider_key = (credentials.auth_provider_type, credentials.auth_provider_id) return self._providers.get(auth_provider_key) - async def _user_should_be_owner(self): + async def _user_should_be_owner(self) -> bool: """Determine if user should be owner. A user should be an owner if it is the first non-system user that is diff --git a/homeassistant/auth/auth_store.py b/homeassistant/auth/auth_store.py index 806cd109d78..07ab40ceaea 100644 --- a/homeassistant/auth/auth_store.py +++ b/homeassistant/auth/auth_store.py @@ -1,8 +1,11 @@ """Storage for auth models.""" from collections import OrderedDict from datetime import timedelta +from logging import getLogger +from typing import Any, Dict, List, Optional # noqa: F401 import hmac +from homeassistant.core import HomeAssistant from homeassistant.util import dt as dt_util from . import models @@ -20,35 +23,41 @@ class AuthStore: called that needs it. """ - def __init__(self, hass): + def __init__(self, hass: HomeAssistant) -> None: """Initialize the auth store.""" self.hass = hass - self._users = None + self._users = None # type: Optional[Dict[str, models.User]] self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) - async def async_get_users(self): + async def async_get_users(self) -> List[models.User]: """Retrieve all users.""" if self._users is None: await self.async_load() + assert self._users is not None return list(self._users.values()) - async def async_get_user(self, user_id): + async def async_get_user(self, user_id: str) -> Optional[models.User]: """Retrieve a user by id.""" if self._users is None: await self.async_load() + assert self._users is not None return self._users.get(user_id) - async def async_create_user(self, name, is_owner=None, is_active=None, - system_generated=None, credentials=None): + async def async_create_user( + self, name: Optional[str], is_owner: Optional[bool] = None, + is_active: Optional[bool] = None, + system_generated: Optional[bool] = None, + credentials: Optional[models.Credentials] = None) -> models.User: """Create a new user.""" if self._users is None: await self.async_load() + assert self._users is not None kwargs = { 'name': name - } + } # type: Dict[str, Any] if is_owner is not None: kwargs['is_owner'] = is_owner @@ -71,29 +80,39 @@ class AuthStore: await self.async_link_user(new_user, credentials) return new_user - async def async_link_user(self, user, credentials): + async def async_link_user(self, user: models.User, + credentials: models.Credentials) -> None: """Add credentials to an existing user.""" user.credentials.append(credentials) await self.async_save() credentials.is_new = False - async def async_remove_user(self, user): + async def async_remove_user(self, user: models.User) -> None: """Remove a user.""" + if self._users is None: + await self.async_load() + assert self._users is not None + self._users.pop(user.id) await self.async_save() - async def async_activate_user(self, user): + async def async_activate_user(self, user: models.User) -> None: """Activate a user.""" user.is_active = True await self.async_save() - async def async_deactivate_user(self, user): + async def async_deactivate_user(self, user: models.User) -> None: """Activate a user.""" user.is_active = False await self.async_save() - async def async_remove_credentials(self, credentials): + async def async_remove_credentials( + self, credentials: models.Credentials) -> None: """Remove credentials.""" + if self._users is None: + await self.async_load() + assert self._users is not None + for user in self._users.values(): found = None @@ -108,17 +127,21 @@ class AuthStore: await self.async_save() - async def async_create_refresh_token(self, user, client_id=None): + async def async_create_refresh_token( + self, user: models.User, client_id: Optional[str] = None) \ + -> models.RefreshToken: """Create a new token for a user.""" refresh_token = models.RefreshToken(user=user, client_id=client_id) user.refresh_tokens[refresh_token.id] = refresh_token await self.async_save() return refresh_token - async def async_get_refresh_token(self, token_id): + async def async_get_refresh_token( + self, token_id: str) -> Optional[models.RefreshToken]: """Get refresh token by id.""" if self._users is None: await self.async_load() + assert self._users is not None for user in self._users.values(): refresh_token = user.refresh_tokens.get(token_id) @@ -127,10 +150,12 @@ class AuthStore: return None - async def async_get_refresh_token_by_token(self, token): + async def async_get_refresh_token_by_token( + self, token: str) -> Optional[models.RefreshToken]: """Get refresh token by token.""" if self._users is None: await self.async_load() + assert self._users is not None found = None @@ -141,7 +166,7 @@ class AuthStore: return found - async def async_load(self): + async def async_load(self) -> None: """Load the users.""" data = await self._store.async_load() @@ -150,7 +175,7 @@ class AuthStore: if self._users is not None: return - users = OrderedDict() + users = OrderedDict() # type: Dict[str, models.User] if data is None: self._users = users @@ -173,11 +198,17 @@ class AuthStore: if 'jwt_key' not in rt_dict: continue + created_at = dt_util.parse_datetime(rt_dict['created_at']) + if created_at is None: + getLogger(__name__).error( + 'Ignoring refresh token %(id)s with invalid created_at ' + '%(created_at)s for user_id %(user_id)s', rt_dict) + continue token = models.RefreshToken( id=rt_dict['id'], user=users[rt_dict['user_id']], client_id=rt_dict['client_id'], - created_at=dt_util.parse_datetime(rt_dict['created_at']), + created_at=created_at, access_token_expiration=timedelta( seconds=rt_dict['access_token_expiration']), token=rt_dict['token'], @@ -187,8 +218,12 @@ class AuthStore: self._users = users - async def async_save(self): + async def async_save(self) -> None: """Save users.""" + if self._users is None: + await self.async_load() + assert self._users is not None + users = [ { 'id': user.id, diff --git a/homeassistant/auth/models.py b/homeassistant/auth/models.py index 3f49c56bce6..a6500510e0d 100644 --- a/homeassistant/auth/models.py +++ b/homeassistant/auth/models.py @@ -1,5 +1,6 @@ """Auth models.""" from datetime import datetime, timedelta +from typing import Dict, List, NamedTuple, Optional # noqa: F401 import uuid import attr @@ -14,17 +15,21 @@ from .util import generate_secret class User: """A user.""" - name = attr.ib(type=str) + name = attr.ib(type=str) # type: Optional[str] id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex)) is_owner = attr.ib(type=bool, default=False) is_active = attr.ib(type=bool, default=False) system_generated = attr.ib(type=bool, default=False) # List of credentials of a user. - credentials = attr.ib(type=list, default=attr.Factory(list), cmp=False) + credentials = attr.ib( + type=list, default=attr.Factory(list), cmp=False + ) # type: List[Credentials] # Tokens associated with a user. - refresh_tokens = attr.ib(type=dict, default=attr.Factory(dict), cmp=False) + refresh_tokens = attr.ib( + type=dict, default=attr.Factory(dict), cmp=False + ) # type: Dict[str, RefreshToken] @attr.s(slots=True) @@ -32,7 +37,7 @@ class RefreshToken: """RefreshToken for a user to grant new access tokens.""" user = attr.ib(type=User) - client_id = attr.ib(type=str) + client_id = attr.ib(type=str) # type: Optional[str] id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex)) created_at = attr.ib(type=datetime, default=attr.Factory(dt_util.utcnow)) access_token_expiration = attr.ib(type=timedelta, @@ -48,10 +53,14 @@ class Credentials: """Credentials for a user on an auth provider.""" auth_provider_type = attr.ib(type=str) - auth_provider_id = attr.ib(type=str) + auth_provider_id = attr.ib(type=str) # type: Optional[str] # Allow the auth provider to store data to represent their auth. data = attr.ib(type=dict) id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex)) is_new = attr.ib(type=bool, default=True) + + +UserMeta = NamedTuple("UserMeta", + [('name', Optional[str]), ('is_active', bool)]) diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index ac5b6107b8a..328d83343d7 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -1,16 +1,19 @@ """Auth providers for Home Assistant.""" import importlib import logging +import types +from typing import Any, Dict, List, Optional import voluptuous as vol from voluptuous.humanize import humanize_error -from homeassistant import requirements -from homeassistant.core import callback +from homeassistant import data_entry_flow, requirements +from homeassistant.core import callback, HomeAssistant from homeassistant.const import CONF_TYPE, CONF_NAME, CONF_ID from homeassistant.util.decorator import Registry -from homeassistant.auth.models import Credentials +from homeassistant.auth.auth_store import AuthStore +from homeassistant.auth.models import Credentials, UserMeta _LOGGER = logging.getLogger(__name__) DATA_REQS = 'auth_prov_reqs_processed' @@ -25,7 +28,80 @@ AUTH_PROVIDER_SCHEMA = vol.Schema({ }, extra=vol.ALLOW_EXTRA) -async def auth_provider_from_config(hass, store, config): +class AuthProvider: + """Provider of user authentication.""" + + DEFAULT_TITLE = 'Unnamed auth provider' + + def __init__(self, hass: HomeAssistant, store: AuthStore, + config: Dict[str, Any]) -> None: + """Initialize an auth provider.""" + self.hass = hass + self.store = store + self.config = config + + @property + def id(self) -> Optional[str]: # pylint: disable=invalid-name + """Return id of the auth provider. + + Optional, can be None. + """ + return self.config.get(CONF_ID) + + @property + def type(self) -> str: + """Return type of the provider.""" + return self.config[CONF_TYPE] # type: ignore + + @property + def name(self) -> str: + """Return the name of the auth provider.""" + return self.config.get(CONF_NAME, self.DEFAULT_TITLE) + + async def async_credentials(self) -> List[Credentials]: + """Return all credentials of this provider.""" + users = await self.store.async_get_users() + return [ + credentials + for user in users + for credentials in user.credentials + if (credentials.auth_provider_type == self.type and + credentials.auth_provider_id == self.id) + ] + + @callback + def async_create_credentials(self, data: Dict[str, str]) -> Credentials: + """Create credentials.""" + return Credentials( + auth_provider_type=self.type, + auth_provider_id=self.id, + data=data, + ) + + # Implement by extending class + + async def async_credential_flow( + self, context: Optional[Dict]) -> data_entry_flow.FlowHandler: + """Return the data flow for logging in with auth provider.""" + raise NotImplementedError + + async def async_get_or_create_credentials( + self, flow_result: Dict[str, str]) -> Credentials: + """Get credentials based on the flow result.""" + raise NotImplementedError + + async def async_user_meta_for_credentials( + self, credentials: Credentials) -> UserMeta: + """Return extra user metadata for credentials. + + Will be used to populate info when creating a new user. + """ + raise NotImplementedError + + +async def auth_provider_from_config( + hass: HomeAssistant, store: AuthStore, + config: Dict[str, Any]) -> Optional[AuthProvider]: """Initialize an auth provider from a config.""" provider_name = config[CONF_TYPE] module = await load_auth_provider_module(hass, provider_name) @@ -34,16 +110,17 @@ async def auth_provider_from_config(hass, store, config): return None try: - config = module.CONFIG_SCHEMA(config) + config = module.CONFIG_SCHEMA(config) # type: ignore except vol.Invalid as err: _LOGGER.error('Invalid configuration for auth provider %s: %s', provider_name, humanize_error(config, err)) return None - return AUTH_PROVIDERS[provider_name](hass, store, config) + return AUTH_PROVIDERS[provider_name](hass, store, config) # type: ignore -async def load_auth_provider_module(hass, provider): +async def load_auth_provider_module( + hass: HomeAssistant, provider: str) -> Optional[types.ModuleType]: """Load an auth provider.""" try: module = importlib.import_module( @@ -62,82 +139,13 @@ async def load_auth_provider_module(hass, provider): elif provider in processed: return module + # https://github.com/python/mypy/issues/1424 + reqs = module.REQUIREMENTS # type: ignore req_success = await requirements.async_process_requirements( - hass, 'auth provider {}'.format(provider), module.REQUIREMENTS) + hass, 'auth provider {}'.format(provider), reqs) if not req_success: return None processed.add(provider) return module - - -class AuthProvider: - """Provider of user authentication.""" - - DEFAULT_TITLE = 'Unnamed auth provider' - - def __init__(self, hass, store, config): - """Initialize an auth provider.""" - self.hass = hass - self.store = store - self.config = config - - @property - def id(self): # pylint: disable=invalid-name - """Return id of the auth provider. - - Optional, can be None. - """ - return self.config.get(CONF_ID) - - @property - def type(self): - """Return type of the provider.""" - return self.config[CONF_TYPE] - - @property - def name(self): - """Return the name of the auth provider.""" - return self.config.get(CONF_NAME, self.DEFAULT_TITLE) - - async def async_credentials(self): - """Return all credentials of this provider.""" - users = await self.store.async_get_users() - return [ - credentials - for user in users - for credentials in user.credentials - if (credentials.auth_provider_type == self.type and - credentials.auth_provider_id == self.id) - ] - - @callback - def async_create_credentials(self, data): - """Create credentials.""" - return Credentials( - auth_provider_type=self.type, - auth_provider_id=self.id, - data=data, - ) - - # Implement by extending class - - async def async_credential_flow(self, context): - """Return the data flow for logging in with auth provider.""" - raise NotImplementedError - - async def async_get_or_create_credentials(self, flow_result): - """Get credentials based on the flow result.""" - raise NotImplementedError - - async def async_user_meta_for_credentials(self, credentials): - """Return extra user metadata for credentials. - - Will be used to populate info when creating a new user. - - Values to populate: - - name: string - - is_active: boolean - """ - return {} diff --git a/homeassistant/auth/providers/homeassistant.py b/homeassistant/auth/providers/homeassistant.py index 5a2355264ab..7dbdf97b083 100644 --- a/homeassistant/auth/providers/homeassistant.py +++ b/homeassistant/auth/providers/homeassistant.py @@ -3,24 +3,25 @@ import base64 from collections import OrderedDict import hashlib import hmac -from typing import Dict # noqa: F401 pylint: disable=unused-import +from typing import Any, Dict, List, Optional # noqa: F401,E501 pylint: disable=unused-import import voluptuous as vol from homeassistant import data_entry_flow from homeassistant.const import CONF_ID -from homeassistant.core import callback +from homeassistant.core import callback, HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.auth.util import generate_secret from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS +from ..models import Credentials, UserMeta STORAGE_VERSION = 1 STORAGE_KEY = 'auth_provider.homeassistant' -def _disallow_id(conf): +def _disallow_id(conf: Dict[str, Any]) -> Dict[str, Any]: """Disallow ID in config.""" if CONF_ID in conf: raise vol.Invalid( @@ -46,13 +47,13 @@ class InvalidUser(HomeAssistantError): class Data: """Hold the user data.""" - def __init__(self, hass): + def __init__(self, hass: HomeAssistant) -> None: """Initialize the user data store.""" self.hass = hass self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) - self._data = None + self._data = None # type: Optional[Dict[str, Any]] - async def async_load(self): + async def async_load(self) -> None: """Load stored data.""" data = await self._store.async_load() @@ -65,9 +66,9 @@ class Data: self._data = data @property - def users(self): + def users(self) -> List[Dict[str, str]]: """Return users.""" - return self._data['users'] + return self._data['users'] # type: ignore def validate_login(self, username: str, password: str) -> None: """Validate a username and password. @@ -79,7 +80,7 @@ class Data: found = None # Compare all users to avoid timing attacks. - for user in self._data['users']: + for user in self.users: if username == user['username']: found = user @@ -94,8 +95,8 @@ class Data: def hash_password(self, password: str, for_storage: bool = False) -> bytes: """Encode a password.""" - hashed = hashlib.pbkdf2_hmac( - 'sha512', password.encode(), self._data['salt'].encode(), 100000) + salt = self._data['salt'].encode() # type: ignore + hashed = hashlib.pbkdf2_hmac('sha512', password.encode(), salt, 100000) if for_storage: hashed = base64.b64encode(hashed) return hashed @@ -137,7 +138,7 @@ class Data: else: raise InvalidUser - async def async_save(self): + async def async_save(self) -> None: """Save data.""" await self._store.async_save(self._data) @@ -150,7 +151,7 @@ class HassAuthProvider(AuthProvider): data = None - async def async_initialize(self): + async def async_initialize(self) -> None: """Initialize the auth provider.""" if self.data is not None: return @@ -158,19 +159,22 @@ class HassAuthProvider(AuthProvider): self.data = Data(self.hass) await self.data.async_load() - async def async_credential_flow(self, context): + async def async_credential_flow( + self, context: Optional[Dict]) -> 'LoginFlow': """Return a flow to login.""" return LoginFlow(self) - async def async_validate_login(self, username: str, password: str): + async def async_validate_login(self, username: str, password: str) -> None: """Helper to validate a username and password.""" if self.data is None: await self.async_initialize() + assert self.data is not None await self.hass.async_add_executor_job( self.data.validate_login, username, password) - async def async_get_or_create_credentials(self, flow_result): + async def async_get_or_create_credentials( + self, flow_result: Dict[str, str]) -> Credentials: """Get credentials based on the flow result.""" username = flow_result['username'] @@ -183,17 +187,17 @@ class HassAuthProvider(AuthProvider): 'username': username }) - async def async_user_meta_for_credentials(self, credentials): + async def async_user_meta_for_credentials( + self, credentials: Credentials) -> UserMeta: """Get extra info for this credential.""" - return { - 'name': credentials.data['username'], - 'is_active': True, - } + return UserMeta(name=credentials.data['username'], is_active=True) - async def async_will_remove_credentials(self, credentials): + async def async_will_remove_credentials( + self, credentials: Credentials) -> None: """When credentials get removed, also remove the auth.""" if self.data is None: await self.async_initialize() + assert self.data is not None try: self.data.async_remove_auth(credentials.data['username']) @@ -206,11 +210,12 @@ class HassAuthProvider(AuthProvider): class LoginFlow(data_entry_flow.FlowHandler): """Handler for the login flow.""" - def __init__(self, auth_provider): + def __init__(self, auth_provider: HassAuthProvider) -> None: """Initialize the login flow.""" self._auth_provider = auth_provider - async def async_step_init(self, user_input=None): + async def async_step_init( + self, user_input: Dict[str, str] = None) -> Dict[str, Any]: """Handle the step of the form.""" errors = {} diff --git a/homeassistant/auth/providers/insecure_example.py b/homeassistant/auth/providers/insecure_example.py index 96f824140ed..144ca967302 100644 --- a/homeassistant/auth/providers/insecure_example.py +++ b/homeassistant/auth/providers/insecure_example.py @@ -1,6 +1,7 @@ """Example auth provider.""" from collections import OrderedDict import hmac +from typing import Any, Dict, Optional import voluptuous as vol @@ -9,6 +10,7 @@ from homeassistant import data_entry_flow from homeassistant.core import callback from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS +from ..models import Credentials, UserMeta USER_SCHEMA = vol.Schema({ @@ -31,12 +33,13 @@ class InvalidAuthError(HomeAssistantError): class ExampleAuthProvider(AuthProvider): """Example auth provider based on hardcoded usernames and passwords.""" - async def async_credential_flow(self, context): + async def async_credential_flow( + self, context: Optional[Dict]) -> 'LoginFlow': """Return a flow to login.""" return LoginFlow(self) @callback - def async_validate_login(self, username, password): + def async_validate_login(self, username: str, password: str) -> None: """Helper to validate a username and password.""" user = None @@ -56,7 +59,8 @@ class ExampleAuthProvider(AuthProvider): password.encode('utf-8')): raise InvalidAuthError - async def async_get_or_create_credentials(self, flow_result): + async def async_get_or_create_credentials( + self, flow_result: Dict[str, str]) -> Credentials: """Get credentials based on the flow result.""" username = flow_result['username'] @@ -69,32 +73,32 @@ class ExampleAuthProvider(AuthProvider): 'username': username }) - async def async_user_meta_for_credentials(self, credentials): + async def async_user_meta_for_credentials( + self, credentials: Credentials) -> UserMeta: """Return extra user metadata for credentials. Will be used to populate info when creating a new user. """ username = credentials.data['username'] - info = { - 'is_active': True, - } + name = None for user in self.config['users']: if user['username'] == username: - info['name'] = user.get('name') + name = user.get('name') break - return info + return UserMeta(name=name, is_active=True) class LoginFlow(data_entry_flow.FlowHandler): """Handler for the login flow.""" - def __init__(self, auth_provider): + def __init__(self, auth_provider: ExampleAuthProvider) -> None: """Initialize the login flow.""" self._auth_provider = auth_provider - async def async_step_init(self, user_input=None): + async def async_step_init( + self, user_input: Dict[str, str] = None) -> Dict[str, Any]: """Handle the step of the form.""" errors = {} @@ -111,7 +115,7 @@ class LoginFlow(data_entry_flow.FlowHandler): data=user_input ) - schema = OrderedDict() + schema = OrderedDict() # type: Dict[str, type] schema['username'] = str schema['password'] = str diff --git a/homeassistant/auth/providers/legacy_api_password.py b/homeassistant/auth/providers/legacy_api_password.py index f2f467e07ec..f276997bf06 100644 --- a/homeassistant/auth/providers/legacy_api_password.py +++ b/homeassistant/auth/providers/legacy_api_password.py @@ -5,14 +5,17 @@ It will be removed when auth system production ready """ from collections import OrderedDict import hmac +from typing import Any, Dict, Optional import voluptuous as vol +from homeassistant.components.http import HomeAssistantHTTP # noqa: F401 from homeassistant.exceptions import HomeAssistantError from homeassistant import data_entry_flow from homeassistant.core import callback from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS +from ..models import Credentials, UserMeta USER_SCHEMA = vol.Schema({ @@ -36,25 +39,29 @@ class LegacyApiPasswordAuthProvider(AuthProvider): DEFAULT_TITLE = 'Legacy API Password' - async def async_credential_flow(self, context): + async def async_credential_flow( + self, context: Optional[Dict]) -> 'LoginFlow': """Return a flow to login.""" return LoginFlow(self) @callback - def async_validate_login(self, password): + def async_validate_login(self, password: str) -> None: """Helper to validate a username and password.""" - if not hasattr(self.hass, 'http'): + hass_http = getattr(self.hass, 'http', None) # type: HomeAssistantHTTP + + if not hass_http: raise ValueError('http component is not loaded') - if self.hass.http.api_password is None: + if hass_http.api_password is None: raise ValueError('http component is not configured using' ' api_password') - if not hmac.compare_digest(self.hass.http.api_password.encode('utf-8'), + if not hmac.compare_digest(hass_http.api_password.encode('utf-8'), password.encode('utf-8')): raise InvalidAuthError - async def async_get_or_create_credentials(self, flow_result): + async def async_get_or_create_credentials( + self, flow_result: Dict[str, str]) -> Credentials: """Return LEGACY_USER always.""" for credential in await self.async_credentials(): if credential.data['username'] == LEGACY_USER: @@ -64,26 +71,25 @@ class LegacyApiPasswordAuthProvider(AuthProvider): 'username': LEGACY_USER }) - async def async_user_meta_for_credentials(self, credentials): + async def async_user_meta_for_credentials( + self, credentials: Credentials) -> UserMeta: """ Set name as LEGACY_USER always. Will be used to populate info when creating a new user. """ - return { - 'name': LEGACY_USER, - 'is_active': True, - } + return UserMeta(name=LEGACY_USER, is_active=True) class LoginFlow(data_entry_flow.FlowHandler): """Handler for the login flow.""" - def __init__(self, auth_provider): + def __init__(self, auth_provider: LegacyApiPasswordAuthProvider) -> None: """Initialize the login flow.""" self._auth_provider = auth_provider - async def async_step_init(self, user_input=None): + async def async_step_init( + self, user_input: Dict[str, str] = None) -> Dict[str, Any]: """Handle the step of the form.""" errors = {} @@ -100,7 +106,7 @@ class LoginFlow(data_entry_flow.FlowHandler): data={} ) - schema = OrderedDict() + schema = OrderedDict() # type: Dict[str, type] schema['password'] = str return self.async_show_form( diff --git a/homeassistant/auth/providers/trusted_networks.py b/homeassistant/auth/providers/trusted_networks.py index 7a4b0126505..3233fa5537f 100644 --- a/homeassistant/auth/providers/trusted_networks.py +++ b/homeassistant/auth/providers/trusted_networks.py @@ -3,12 +3,16 @@ It shows list of users if access from trusted network. Abort login flow if not access from trusted network. """ +from typing import Any, Dict, Optional, cast + import voluptuous as vol from homeassistant import data_entry_flow +from homeassistant.components.http import HomeAssistantHTTP # noqa: F401 from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS +from ..models import Credentials, UserMeta CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend({ }, extra=vol.PREVENT_EXTRA) @@ -31,16 +35,20 @@ class TrustedNetworksAuthProvider(AuthProvider): DEFAULT_TITLE = 'Trusted Networks' - async def async_credential_flow(self, context): + async def async_credential_flow( + self, context: Optional[Dict]) -> 'LoginFlow': """Return a flow to login.""" + assert context is not None users = await self.store.async_get_users() available_users = {user.id: user.name for user in users if not user.system_generated and user.is_active} - return LoginFlow(self, context.get('ip_address'), available_users) + return LoginFlow(self, cast(str, context.get('ip_address')), + available_users) - async def async_get_or_create_credentials(self, flow_result): + async def async_get_or_create_credentials( + self, flow_result: Dict[str, str]) -> Credentials: """Get credentials based on the flow result.""" user_id = flow_result['user'] @@ -59,7 +67,8 @@ class TrustedNetworksAuthProvider(AuthProvider): # We only allow login as exist user raise InvalidUserError - async def async_user_meta_for_credentials(self, credentials): + async def async_user_meta_for_credentials( + self, credentials: Credentials) -> UserMeta: """Return extra user metadata for credentials. Trusted network auth provider should never create new user. @@ -67,31 +76,36 @@ class TrustedNetworksAuthProvider(AuthProvider): raise NotImplementedError @callback - def async_validate_access(self, ip_address): + def async_validate_access(self, ip_address: str) -> None: """Make sure the access from trusted networks. Raise InvalidAuthError if not. - Raise InvalidAuthError if trusted_networks is not config + Raise InvalidAuthError if trusted_networks is not configured. """ - if (not hasattr(self.hass, 'http') or - not self.hass.http or not self.hass.http.trusted_networks): + hass_http = getattr(self.hass, 'http', None) # type: HomeAssistantHTTP + + if not hass_http or not hass_http.trusted_networks: raise InvalidAuthError('trusted_networks is not configured') if not any(ip_address in trusted_network for trusted_network - in self.hass.http.trusted_networks): + in hass_http.trusted_networks): raise InvalidAuthError('Not in trusted_networks') class LoginFlow(data_entry_flow.FlowHandler): """Handler for the login flow.""" - def __init__(self, auth_provider, ip_address, available_users): + def __init__(self, auth_provider: TrustedNetworksAuthProvider, + ip_address: str, available_users: Dict[str, Optional[str]]) \ + -> None: """Initialize the login flow.""" self._auth_provider = auth_provider self._available_users = available_users self._ip_address = ip_address - async def async_step_init(self, user_input=None): + async def async_step_init( + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: """Handle the step of the form.""" errors = {} try: diff --git a/tox.ini b/tox.ini index d6ef1981bef..e1261457c47 100644 --- a/tox.ini +++ b/tox.ini @@ -58,4 +58,4 @@ whitelist_externals=/bin/bash deps = -r{toxinidir}/requirements_test.txt commands = - /bin/bash -c 'mypy homeassistant/*.py homeassistant/util/' + /bin/bash -c 'mypy homeassistant/*.py homeassistant/auth/ homeassistant/util/' From 279ead20857af76974982e57996f17b71c46a4e0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 22:41:44 +0200 Subject: [PATCH 048/159] Disable the DLNA component discovery (#16006) --- homeassistant/components/discovery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index b400d1d8885..41cf3791256 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -85,11 +85,11 @@ SERVICE_HANDLERS = { 'volumio': ('media_player', 'volumio'), 'nanoleaf_aurora': ('light', 'nanoleaf_aurora'), 'freebox': ('device_tracker', 'freebox'), - 'dlna_dmr': ('media_player', 'dlna_dmr'), } OPTIONAL_SERVICE_HANDLERS = { SERVICE_HOMEKIT: ('homekit_controller', None), + 'dlna_dmr': ('media_player', 'dlna_dmr'), } CONF_IGNORE = 'ignore' From 45452e510c5f675f999291b7a100da4e42b8e8b7 Mon Sep 17 00:00:00 2001 From: Steven Looman Date: Thu, 16 Aug 2018 22:42:11 +0200 Subject: [PATCH 049/159] Fix message "Updating dlna_dmr media_player took longer than ..." (#16005) --- homeassistant/components/media_player/dlna_dmr.py | 4 ++-- requirements_all.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/media_player/dlna_dmr.py b/homeassistant/components/media_player/dlna_dmr.py index 9b6beb83341..c40e3ed0ca9 100644 --- a/homeassistant/components/media_player/dlna_dmr.py +++ b/homeassistant/components/media_player/dlna_dmr.py @@ -35,7 +35,7 @@ from homeassistant.util import get_local_ip DLNA_DMR_DATA = 'dlna_dmr' REQUIREMENTS = [ - 'async-upnp-client==0.12.2', + 'async-upnp-client==0.12.3', ] DEFAULT_NAME = 'DLNA Digital Media Renderer' @@ -126,7 +126,7 @@ async def async_setup_platform(hass: HomeAssistant, name = config.get(CONF_NAME) elif discovery_info is not None: url = discovery_info['ssdp_description'] - name = discovery_info['name'] + name = discovery_info.get('name') if DLNA_DMR_DATA not in hass.data: hass.data[DLNA_DMR_DATA] = {} diff --git a/requirements_all.txt b/requirements_all.txt index 4754851b8e7..652a546641f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -138,7 +138,7 @@ apns2==0.3.0 asterisk_mbox==0.4.0 # homeassistant.components.media_player.dlna_dmr -async-upnp-client==0.12.2 +async-upnp-client==0.12.3 # homeassistant.components.light.avion # avion==0.7 From 07840f539793ed975c428f202e3104f50ac138cc Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Fri, 17 Aug 2018 05:28:00 +0200 Subject: [PATCH 050/159] Fix check config packages key error (#15840) * Fix packages deletion in check_config script * The config key for packages is not present if core config validation failed. We need to do a safe dict deletion using dict.pop. * Add check_config test for bad core config --- homeassistant/scripts/check_config.py | 2 +- tests/scripts/test_check_config.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index d7be5b1a91c..e0c933df5bb 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -325,7 +325,7 @@ def check_ha_config_file(hass): # Merge packages merge_packages_config( hass, config, core_config.get(CONF_PACKAGES, {}), _pack_error) - del core_config[CONF_PACKAGES] + core_config.pop(CONF_PACKAGES, None) # Ensure we have no None values after merge for key, value in config.items(): diff --git a/tests/scripts/test_check_config.py b/tests/scripts/test_check_config.py index 532197b4072..28438a5e4b3 100644 --- a/tests/scripts/test_check_config.py +++ b/tests/scripts/test_check_config.py @@ -22,6 +22,12 @@ BASE_CONFIG = ( '\n\n' ) +BAD_CORE_CONFIG = ( + 'homeassistant:\n' + ' unit_system: bad\n' + '\n\n' +) + def normalize_yaml_files(check_dict): """Remove configuration path from ['yaml_files'].""" @@ -47,6 +53,17 @@ class TestCheckConfig(unittest.TestCase): self.maxDiff = None # pylint: disable=invalid-name # pylint: disable=no-self-use,invalid-name + @patch('os.path.isfile', return_value=True) + def test_bad_core_config(self, isfile_patch): + """Test a bad core config setup.""" + files = { + YAML_CONFIG_FILE: BAD_CORE_CONFIG, + } + with patch_yaml_files(files): + res = check_config.check(get_test_config_dir()) + assert res['except'].keys() == {'homeassistant'} + assert res['except']['homeassistant'][1] == {'unit_system': 'bad'} + @patch('os.path.isfile', return_value=True) def test_config_platform_valid(self, isfile_patch): """Test a valid platform setup.""" From f2e399ccf3b790df3c9cc57fb430cfbd3981780b Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Fri, 17 Aug 2018 07:41:56 +0200 Subject: [PATCH 051/159] Update SoCo to 0.16 (#16007) --- .../components/media_player/sonos.py | 28 ++++++------------- homeassistant/components/sonos/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 5375001f75c..96038e7bb2b 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -33,6 +33,7 @@ _LOGGER = logging.getLogger(__name__) # Quiet down soco logging to just actual problems. logging.getLogger('soco').setLevel(logging.WARNING) +logging.getLogger('soco.events').setLevel(logging.ERROR) logging.getLogger('soco.data_structures_entry').setLevel(logging.ERROR) _SOCO_SERVICES_LOGGER = logging.getLogger('soco.services') @@ -55,6 +56,7 @@ DATA_SONOS = 'sonos_devices' SOURCE_LINEIN = 'Line-in' SOURCE_TV = 'TV' +CONF_ADVERTISE_ADDR = 'advertise_addr' CONF_INTERFACE_ADDR = 'interface_addr' # Service call validation schemas @@ -73,6 +75,7 @@ ATTR_SONOS_GROUP = 'sonos_group' UPNP_ERRORS_TO_IGNORE = ['701', '711'] PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_ADVERTISE_ADDR): cv.string, vol.Optional(CONF_INTERFACE_ADDR): cv.string, vol.Optional(CONF_HOSTS): vol.All(cv.ensure_list, [cv.string]), }) @@ -141,25 +144,14 @@ async def async_setup_entry(hass, config_entry, async_add_devices): def _setup_platform(hass, config, add_devices, discovery_info): """Set up the Sonos platform.""" import soco - import soco.events - import soco.exceptions - - orig_parse_event_xml = soco.events.parse_event_xml - - def safe_parse_event_xml(xml): - """Avoid SoCo 0.14 event thread dying from invalid xml.""" - try: - return orig_parse_event_xml(xml) - # pylint: disable=broad-except - except Exception as ex: - _LOGGER.debug("Dodged exception: %s %s", type(ex), str(ex)) - return {} - - soco.events.parse_event_xml = safe_parse_event_xml if DATA_SONOS not in hass.data: hass.data[DATA_SONOS] = SonosData() + advertise_addr = config.get(CONF_ADVERTISE_ADDR) + if advertise_addr: + soco.config.EVENT_ADVERTISE_IP = advertise_addr + players = [] if discovery_info: player = soco.SoCo(discovery_info.get('host')) @@ -451,7 +443,7 @@ class SonosDevice(MediaPlayerDevice): def _set_favorites(self): """Set available favorites.""" - # SoCo 0.14 raises a generic Exception on invalid xml in favorites. + # SoCo 0.16 raises a generic Exception on invalid xml in favorites. # Filter those out now so our list is safe to use. # pylint: disable=broad-except try: @@ -863,9 +855,7 @@ class SonosDevice(MediaPlayerDevice): src = fav.pop() uri = src.reference.get_uri() if _is_radio_uri(uri): - # SoCo 0.14 fails to XML escape the title parameter - from xml.sax.saxutils import escape - self.soco.play_uri(uri, title=escape(source)) + self.soco.play_uri(uri, title=source) else: self.soco.clear_queue() self.soco.add_to_queue(src.reference) diff --git a/homeassistant/components/sonos/__init__.py b/homeassistant/components/sonos/__init__.py index bbc05a3aa61..6c9280195cc 100644 --- a/homeassistant/components/sonos/__init__.py +++ b/homeassistant/components/sonos/__init__.py @@ -4,7 +4,7 @@ from homeassistant.helpers import config_entry_flow DOMAIN = 'sonos' -REQUIREMENTS = ['SoCo==0.14'] +REQUIREMENTS = ['SoCo==0.16'] async def async_setup(hass, config): diff --git a/requirements_all.txt b/requirements_all.txt index 652a546641f..38b1d071c5c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -59,7 +59,7 @@ PyXiaomiGateway==0.9.5 RtmAPI==0.7.0 # homeassistant.components.sonos -SoCo==0.14 +SoCo==0.16 # homeassistant.components.sensor.travisci TravisPy==0.3.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8b153494025..3d0274e859b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -25,7 +25,7 @@ HAP-python==2.2.2 PyRMVtransport==0.0.7 # homeassistant.components.sonos -SoCo==0.14 +SoCo==0.16 # homeassistant.components.device_tracker.automatic aioautomatic==0.6.5 From fdbab3e20c2bf90660ae6da327337cbf040a59e5 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Fri, 17 Aug 2018 16:39:41 +0200 Subject: [PATCH 052/159] Upgrade sendgrid to 5.5.0 (#16021) --- homeassistant/components/notify/sendgrid.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/sendgrid.py b/homeassistant/components/notify/sendgrid.py index 92b709af8ad..5fd085f3d26 100644 --- a/homeassistant/components/notify/sendgrid.py +++ b/homeassistant/components/notify/sendgrid.py @@ -14,7 +14,7 @@ from homeassistant.const import ( CONF_API_KEY, CONF_SENDER, CONF_RECIPIENT, CONTENT_TYPE_TEXT_PLAIN) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['sendgrid==5.4.1'] +REQUIREMENTS = ['sendgrid==5.5.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 38b1d071c5c..72bd1d03c2e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1260,7 +1260,7 @@ schiene==0.22 scsgate==0.1.0 # homeassistant.components.notify.sendgrid -sendgrid==5.4.1 +sendgrid==5.5.0 # homeassistant.components.light.sensehat # homeassistant.components.sensor.sensehat From 2ad0bd40362841646e097885098f0864c91220b4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 17 Aug 2018 20:18:21 +0200 Subject: [PATCH 053/159] Split out storage delay save (#16017) * Split out storage delayed write * Update code using delayed save * Fix tests * Fix typing test * Add callback decorator --- homeassistant/auth/auth_store.py | 49 ++++++++++++++++++-------------- homeassistant/config_entries.py | 14 +++++---- homeassistant/helpers/storage.py | 32 ++++++++++++++++----- tests/helpers/test_storage.py | 8 +++--- 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/homeassistant/auth/auth_store.py b/homeassistant/auth/auth_store.py index 07ab40ceaea..5b26cf2f5f8 100644 --- a/homeassistant/auth/auth_store.py +++ b/homeassistant/auth/auth_store.py @@ -5,7 +5,7 @@ from logging import getLogger from typing import Any, Dict, List, Optional # noqa: F401 import hmac -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, callback from homeassistant.util import dt as dt_util from . import models @@ -32,7 +32,7 @@ class AuthStore: async def async_get_users(self) -> List[models.User]: """Retrieve all users.""" if self._users is None: - await self.async_load() + await self._async_load() assert self._users is not None return list(self._users.values()) @@ -40,7 +40,7 @@ class AuthStore: async def async_get_user(self, user_id: str) -> Optional[models.User]: """Retrieve a user by id.""" if self._users is None: - await self.async_load() + await self._async_load() assert self._users is not None return self._users.get(user_id) @@ -52,7 +52,7 @@ class AuthStore: credentials: Optional[models.Credentials] = None) -> models.User: """Create a new user.""" if self._users is None: - await self.async_load() + await self._async_load() assert self._users is not None kwargs = { @@ -73,7 +73,7 @@ class AuthStore: self._users[new_user.id] = new_user if credentials is None: - await self.async_save() + self._async_schedule_save() return new_user # Saving is done inside the link. @@ -84,33 +84,33 @@ class AuthStore: credentials: models.Credentials) -> None: """Add credentials to an existing user.""" user.credentials.append(credentials) - await self.async_save() + self._async_schedule_save() credentials.is_new = False async def async_remove_user(self, user: models.User) -> None: """Remove a user.""" if self._users is None: - await self.async_load() + await self._async_load() assert self._users is not None self._users.pop(user.id) - await self.async_save() + self._async_schedule_save() async def async_activate_user(self, user: models.User) -> None: """Activate a user.""" user.is_active = True - await self.async_save() + self._async_schedule_save() async def async_deactivate_user(self, user: models.User) -> None: """Activate a user.""" user.is_active = False - await self.async_save() + self._async_schedule_save() async def async_remove_credentials( self, credentials: models.Credentials) -> None: """Remove credentials.""" if self._users is None: - await self.async_load() + await self._async_load() assert self._users is not None for user in self._users.values(): @@ -125,7 +125,7 @@ class AuthStore: user.credentials.pop(found) break - await self.async_save() + self._async_schedule_save() async def async_create_refresh_token( self, user: models.User, client_id: Optional[str] = None) \ @@ -133,14 +133,14 @@ class AuthStore: """Create a new token for a user.""" refresh_token = models.RefreshToken(user=user, client_id=client_id) user.refresh_tokens[refresh_token.id] = refresh_token - await self.async_save() + self._async_schedule_save() return refresh_token async def async_get_refresh_token( self, token_id: str) -> Optional[models.RefreshToken]: """Get refresh token by id.""" if self._users is None: - await self.async_load() + await self._async_load() assert self._users is not None for user in self._users.values(): @@ -154,7 +154,7 @@ class AuthStore: self, token: str) -> Optional[models.RefreshToken]: """Get refresh token by token.""" if self._users is None: - await self.async_load() + await self._async_load() assert self._users is not None found = None @@ -166,7 +166,7 @@ class AuthStore: return found - async def async_load(self) -> None: + async def _async_load(self) -> None: """Load the users.""" data = await self._store.async_load() @@ -218,11 +218,18 @@ class AuthStore: self._users = users - async def async_save(self) -> None: + @callback + def _async_schedule_save(self) -> None: """Save users.""" if self._users is None: - await self.async_load() - assert self._users is not None + return + + self._store.async_delay_save(self._data_to_save, 1) + + @callback + def _data_to_save(self) -> Dict: + """Return the data to store.""" + assert self._users is not None users = [ { @@ -262,10 +269,8 @@ class AuthStore: for refresh_token in user.refresh_tokens.values() ] - data = { + return { 'users': users, 'credentials': credentials, 'refresh_tokens': refresh_tokens, } - - await self._store.async_save(data, delay=1) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index b2e8389e449..e9c5bc07e57 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -320,7 +320,7 @@ class ConfigEntries: raise UnknownEntry entry = self._entries.pop(found) - await self._async_schedule_save() + self._async_schedule_save() unloaded = await entry.async_unload(self.hass) @@ -391,7 +391,7 @@ class ConfigEntries: source=context['source'], ) self._entries.append(entry) - await self._async_schedule_save() + self._async_schedule_save() # Setup entry if entry.domain in self.hass.config.components: @@ -439,12 +439,16 @@ class ConfigEntries: flow.init_step = source return flow - async def _async_schedule_save(self): + def _async_schedule_save(self): """Save the entity registry to a file.""" - data = { + self._store.async_delay_save(self._data_to_save, SAVE_DELAY) + + @callback + def _data_to_save(self): + """Return data to save.""" + return { 'entries': [entry.as_dict() for entry in self._entries] } - await self._store.async_save(data, delay=SAVE_DELAY) async def _old_conf_migrator(old_config): diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index a68b489868d..47d182d9a7c 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -2,7 +2,7 @@ import asyncio import logging import os -from typing import Dict, Optional +from typing import Dict, Optional, Callable from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.core import callback @@ -76,8 +76,13 @@ class Store: async def _async_load(self): """Helper to load the data.""" + # Check if we have a pending write if self._data is not None: data = self._data + + # If we didn't generate data yet, do it now. + if 'data_func' in data: + data['data'] = data.pop('data_func')() else: data = await self.hass.async_add_executor_job( json.load_json, self.path) @@ -95,8 +100,8 @@ class Store: self._load_task = None return stored - async def async_save(self, data: Dict, *, delay: Optional[int] = None): - """Save data with an optional delay.""" + async def async_save(self, data): + """Save data.""" self._data = { 'version': self.version, 'key': self.key, @@ -104,11 +109,20 @@ class Store: } self._async_cleanup_delay_listener() + self._async_cleanup_stop_listener() + await self._async_handle_write_data() - if delay is None: - self._async_cleanup_stop_listener() - await self._async_handle_write_data() - return + @callback + def async_delay_save(self, data_func: Callable[[], Dict], + delay: Optional[int] = None): + """Save data with an optional delay.""" + self._data = { + 'version': self.version, + 'key': self.key, + 'data_func': data_func, + } + + self._async_cleanup_delay_listener() self._unsub_delay_listener = async_call_later( self.hass, delay, self._async_callback_delayed_write) @@ -151,6 +165,10 @@ class Store: async def _async_handle_write_data(self, *_args): """Handler to handle writing the config.""" data = self._data + + if 'data_func' in data: + data['data'] = data.pop('data_func')() + self._data = None async with self._write_lock: diff --git a/tests/helpers/test_storage.py b/tests/helpers/test_storage.py index f414eaec97c..b35b2596802 100644 --- a/tests/helpers/test_storage.py +++ b/tests/helpers/test_storage.py @@ -56,7 +56,7 @@ async def test_loading_parallel(hass, store, hass_storage, caplog): async def test_saving_with_delay(hass, store, hass_storage): """Test saving data after a delay.""" - await store.async_save(MOCK_DATA, delay=1) + store.async_delay_save(lambda: MOCK_DATA, 1) assert store.key not in hass_storage async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=1)) @@ -71,7 +71,7 @@ async def test_saving_with_delay(hass, store, hass_storage): async def test_saving_on_stop(hass, hass_storage): """Test delayed saves trigger when we quit Home Assistant.""" store = storage.Store(hass, MOCK_VERSION, MOCK_KEY) - await store.async_save(MOCK_DATA, delay=1) + store.async_delay_save(lambda: MOCK_DATA, 1) assert store.key not in hass_storage hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) @@ -92,7 +92,7 @@ async def test_loading_while_delay(hass, store, hass_storage): 'data': {'delay': 'no'}, } - await store.async_save({'delay': 'yes'}, delay=1) + store.async_delay_save(lambda: {'delay': 'yes'}, 1) assert hass_storage[store.key] == { 'version': MOCK_VERSION, 'key': MOCK_KEY, @@ -105,7 +105,7 @@ async def test_loading_while_delay(hass, store, hass_storage): async def test_writing_while_writing_delay(hass, store, hass_storage): """Test a write while a write with delay is active.""" - await store.async_save({'delay': 'yes'}, delay=1) + store.async_delay_save(lambda: {'delay': 'yes'}, 1) assert store.key not in hass_storage await store.async_save({'delay': 'no'}) assert hass_storage[store.key] == { From 3800f00564acbb85656d8bb1a08726deff1ff74e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Fri, 17 Aug 2018 21:22:49 +0300 Subject: [PATCH 054/159] Disable assuming Optional type for values with None default (#16029) https://www.python.org/dev/peps/pep-0484/#union-types "Type checkers should move towards requiring the optional type to be made explicit." --- homeassistant/auth/providers/homeassistant.py | 3 ++- homeassistant/auth/providers/insecure_example.py | 3 ++- homeassistant/auth/providers/legacy_api_password.py | 3 ++- homeassistant/config_entries.py | 2 +- homeassistant/data_entry_flow.py | 10 ++++++---- homeassistant/remote.py | 9 +++++---- homeassistant/util/__init__.py | 4 ++-- homeassistant/util/dt.py | 6 +++--- mypy.ini | 1 + 9 files changed, 24 insertions(+), 17 deletions(-) diff --git a/homeassistant/auth/providers/homeassistant.py b/homeassistant/auth/providers/homeassistant.py index 7dbdf97b083..a2d91767b95 100644 --- a/homeassistant/auth/providers/homeassistant.py +++ b/homeassistant/auth/providers/homeassistant.py @@ -215,7 +215,8 @@ class LoginFlow(data_entry_flow.FlowHandler): self._auth_provider = auth_provider async def async_step_init( - self, user_input: Dict[str, str] = None) -> Dict[str, Any]: + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: """Handle the step of the form.""" errors = {} diff --git a/homeassistant/auth/providers/insecure_example.py b/homeassistant/auth/providers/insecure_example.py index 144ca967302..a4f411e69e0 100644 --- a/homeassistant/auth/providers/insecure_example.py +++ b/homeassistant/auth/providers/insecure_example.py @@ -98,7 +98,8 @@ class LoginFlow(data_entry_flow.FlowHandler): self._auth_provider = auth_provider async def async_step_init( - self, user_input: Dict[str, str] = None) -> Dict[str, Any]: + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: """Handle the step of the form.""" errors = {} diff --git a/homeassistant/auth/providers/legacy_api_password.py b/homeassistant/auth/providers/legacy_api_password.py index f276997bf06..064cfc046bd 100644 --- a/homeassistant/auth/providers/legacy_api_password.py +++ b/homeassistant/auth/providers/legacy_api_password.py @@ -89,7 +89,8 @@ class LoginFlow(data_entry_flow.FlowHandler): self._auth_provider = auth_provider async def async_step_init( - self, user_input: Dict[str, str] = None) -> Dict[str, Any]: + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: """Handle the step of the form.""" errors = {} diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index e9c5bc07e57..be665d6b9e6 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -302,7 +302,7 @@ class ConfigEntries: return result @callback - def async_entries(self, domain: str = None) -> List[ConfigEntry]: + def async_entries(self, domain: Optional[str] = None) -> List[ConfigEntry]: """Return all entries or entries for a specific domain.""" if domain is None: return list(self._entries) diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index f820911e396..d99d70ce2ec 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -49,7 +49,8 @@ class FlowManager: 'context': flow.context, } for flow in self._progress.values()] - async def async_init(self, handler: Hashable, *, context: Dict = None, + async def async_init(self, handler: Hashable, *, + context: Optional[Dict] = None, data: Any = None) -> Any: """Start a configuration flow.""" flow = await self._async_create_flow( @@ -63,7 +64,7 @@ class FlowManager: return await self._async_handle_step(flow, flow.init_step, data) async def async_configure( - self, flow_id: str, user_input: str = None) -> Any: + self, flow_id: str, user_input: Optional[str] = None) -> Any: """Continue a configuration flow.""" flow = self._progress.get(flow_id) @@ -134,8 +135,9 @@ class FlowHandler: @callback def async_show_form(self, *, step_id: str, data_schema: vol.Schema = None, - errors: Dict = None, - description_placeholders: Dict = None) -> Dict: + errors: Optional[Dict] = None, + description_placeholders: Optional[Dict] = None) \ + -> Dict: """Return the definition of a form to gather user input.""" return { 'type': RESULT_TYPE_FORM, diff --git a/homeassistant/remote.py b/homeassistant/remote.py index c254dd500f7..16c37f210e7 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -76,7 +76,7 @@ class API: return self.status == APIStatus.OK - def __call__(self, method: str, path: str, data: Dict = None, + def __call__(self, method: str, path: str, data: Optional[Dict] = None, timeout: int = 5) -> requests.Response: """Make a call to the Home Assistant API.""" if data is None: @@ -161,7 +161,7 @@ def get_event_listeners(api: API) -> Dict: return {} -def fire_event(api: API, event_type: str, data: Dict = None) -> None: +def fire_event(api: API, event_type: str, data: Optional[Dict] = None) -> None: """Fire an event at remote API.""" try: req = api(METH_POST, URL_API_EVENTS_EVENT.format(event_type), data) @@ -228,7 +228,8 @@ def remove_state(api: API, entity_id: str) -> bool: def set_state(api: API, entity_id: str, new_state: str, - attributes: Dict = None, force_update: bool = False) -> bool: + attributes: Optional[Dict] = None, force_update: bool = False) \ + -> bool: """Tell API to update state for entity_id. Return True if success. @@ -280,7 +281,7 @@ def get_services(api: API) -> Dict: def call_service(api: API, domain: str, service: str, - service_data: Dict = None, + service_data: Optional[Dict] = None, timeout: int = 5) -> None: """Call a service at the remote API.""" try: diff --git a/homeassistant/util/__init__.py b/homeassistant/util/__init__.py index 64c9f4f02c9..1e74c500fc1 100644 --- a/homeassistant/util/__init__.py +++ b/homeassistant/util/__init__.py @@ -154,7 +154,7 @@ class OrderedEnum(enum.Enum): class OrderedSet(MutableSet[T]): """Ordered set taken from http://code.activestate.com/recipes/576694/.""" - def __init__(self, iterable: Iterable[T] = None) -> None: + def __init__(self, iterable: Optional[Iterable[T]] = None) -> None: """Initialize the set.""" self.end = end = [] # type: List[Any] end += [None, end, end] # sentinel node for doubly linked list @@ -260,7 +260,7 @@ class Throttle: """ def __init__(self, min_time: timedelta, - limit_no_throttle: timedelta = None) -> None: + limit_no_throttle: Optional[timedelta] = None) -> None: """Initialize the throttle.""" self.min_time = min_time self.limit_no_throttle = limit_no_throttle diff --git a/homeassistant/util/dt.py b/homeassistant/util/dt.py index ce6775b9ea7..729195fb3fd 100644 --- a/homeassistant/util/dt.py +++ b/homeassistant/util/dt.py @@ -53,7 +53,7 @@ def utcnow() -> dt.datetime: return dt.datetime.now(UTC) -def now(time_zone: dt.tzinfo = None) -> dt.datetime: +def now(time_zone: Optional[dt.tzinfo] = None) -> dt.datetime: """Get now in specified time zone.""" return dt.datetime.now(time_zone or DEFAULT_TIME_ZONE) @@ -97,8 +97,8 @@ def utc_from_timestamp(timestamp: float) -> dt.datetime: return UTC.localize(dt.datetime.utcfromtimestamp(timestamp)) -def start_of_local_day(dt_or_d: - Union[dt.date, dt.datetime] = None) -> dt.datetime: +def start_of_local_day( + dt_or_d: Union[dt.date, dt.datetime, None] = None) -> dt.datetime: """Return local datetime object of start of day from date or datetime.""" if dt_or_d is None: date = now().date() # type: dt.date diff --git a/mypy.ini b/mypy.ini index 875aec5eda7..1ffdaa0e509 100644 --- a/mypy.ini +++ b/mypy.ini @@ -3,6 +3,7 @@ check_untyped_defs = true disallow_untyped_calls = true follow_imports = silent ignore_missing_imports = true +no_implicit_optional = true warn_incomplete_stub = true warn_redundant_casts = true warn_return_any = true From fa88d918b1ed3421511c97946002c6ee20e58f86 Mon Sep 17 00:00:00 2001 From: Steven Looman Date: Fri, 17 Aug 2018 21:29:31 +0200 Subject: [PATCH 055/159] Upgrade to async_upnp_client==0.12.4 --- homeassistant/components/media_player/dlna_dmr.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/dlna_dmr.py b/homeassistant/components/media_player/dlna_dmr.py index c40e3ed0ca9..ebb1ab8d383 100644 --- a/homeassistant/components/media_player/dlna_dmr.py +++ b/homeassistant/components/media_player/dlna_dmr.py @@ -35,7 +35,7 @@ from homeassistant.util import get_local_ip DLNA_DMR_DATA = 'dlna_dmr' REQUIREMENTS = [ - 'async-upnp-client==0.12.3', + 'async-upnp-client==0.12.4', ] DEFAULT_NAME = 'DLNA Digital Media Renderer' diff --git a/requirements_all.txt b/requirements_all.txt index 72bd1d03c2e..8e201620664 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -138,7 +138,7 @@ apns2==0.3.0 asterisk_mbox==0.4.0 # homeassistant.components.media_player.dlna_dmr -async-upnp-client==0.12.3 +async-upnp-client==0.12.4 # homeassistant.components.light.avion # avion==0.7 From ec2e94425eda418163c7f33e4791ca1c6e027e4b Mon Sep 17 00:00:00 2001 From: Wim Haanstra Date: Sat, 18 Aug 2018 09:40:29 +0200 Subject: [PATCH 056/159] Update RitAssist to support maximum speed and current address (#16037) Update RitAssist dependency to 0.9.2 so we support fetching the current maximum speed and address for a device. --- homeassistant/components/device_tracker/ritassist.py | 6 +++++- requirements_all.txt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/ritassist.py b/homeassistant/components/device_tracker/ritassist.py index 9fc50de5062..f0973de39bd 100644 --- a/homeassistant/components/device_tracker/ritassist.py +++ b/homeassistant/components/device_tracker/ritassist.py @@ -14,7 +14,7 @@ from homeassistant.components.device_tracker import PLATFORM_SCHEMA from homeassistant.const import CONF_USERNAME, CONF_PASSWORD from homeassistant.helpers.event import track_utc_time_change -REQUIREMENTS = ['ritassist==0.5'] +REQUIREMENTS = ['ritassist==0.9.2'] _LOGGER = logging.getLogger(__name__) @@ -78,6 +78,10 @@ class RitAssistDeviceScanner: for device in devices: if (not self._include or device.license_plate in self._include): + + if device.active or device.current_address is None: + device.get_map_details() + self._see(dev_id=device.plate_as_id, gps=(device.latitude, device.longitude), attributes=device.state_attributes, diff --git a/requirements_all.txt b/requirements_all.txt index 8e201620664..b3b8a7a5449 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1227,7 +1227,7 @@ rflink==0.0.37 ring_doorbell==0.2.1 # homeassistant.components.device_tracker.ritassist -ritassist==0.5 +ritassist==0.9.2 # homeassistant.components.notify.rocketchat rocketchat-API==0.6.1 From e782e2c0f38426f9135dd0384f47dc86881f31fb Mon Sep 17 00:00:00 2001 From: Ed Marshall Date: Sat, 18 Aug 2018 00:54:23 -0700 Subject: [PATCH 057/159] Handle missing mpd capabilities (#15945) * Handle missing mpd capabilities It is possible to configure mpd without volume or playlist support. Gracefully degrade when either of these features appears to be missing. Resolves: #14459, #15927 * Use longer name for exception * Only return support flags post-connection * Small consistency fixes to mpd.py for review. --- homeassistant/components/media_player/mpd.py | 65 +++++++++++++------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/media_player/mpd.py b/homeassistant/components/media_player/mpd.py index 4b3dfc2ccbb..be9dfa77377 100644 --- a/homeassistant/components/media_player/mpd.py +++ b/homeassistant/components/media_player/mpd.py @@ -32,9 +32,8 @@ DEFAULT_PORT = 6600 PLAYLIST_UPDATE_INTERVAL = timedelta(seconds=120) -SUPPORT_MPD = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_STEP | \ - SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | SUPPORT_VOLUME_MUTE | \ - SUPPORT_PLAY_MEDIA | SUPPORT_PLAY | SUPPORT_SELECT_SOURCE | \ +SUPPORT_MPD = SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | \ + SUPPORT_NEXT_TRACK | SUPPORT_PLAY_MEDIA | SUPPORT_PLAY | \ SUPPORT_CLEAR_PLAYLIST | SUPPORT_SHUFFLE_SET | SUPPORT_SEEK | \ SUPPORT_STOP | SUPPORT_TURN_OFF | SUPPORT_TURN_ON @@ -72,7 +71,7 @@ class MpdDevice(MediaPlayerDevice): self._status = None self._currentsong = None - self._playlists = [] + self._playlists = None self._currentplaylist = None self._is_connected = False self._muted = False @@ -202,12 +201,24 @@ class MpdDevice(MediaPlayerDevice): @property def volume_level(self): """Return the volume level.""" - return int(self._status['volume'])/100 + if 'volume' in self._status: + return int(self._status['volume'])/100 + return None @property def supported_features(self): """Flag media player features that are supported.""" - return SUPPORT_MPD + if self._status is None: + return None + + supported = SUPPORT_MPD + if 'volume' in self._status: + supported |= \ + SUPPORT_VOLUME_SET | SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE + if self._playlists is not None: + supported |= SUPPORT_SELECT_SOURCE + + return supported @property def source(self): @@ -226,27 +237,36 @@ class MpdDevice(MediaPlayerDevice): @Throttle(PLAYLIST_UPDATE_INTERVAL) def _update_playlists(self, **kwargs): """Update available MPD playlists.""" - self._playlists = [] - for playlist_data in self._client.listplaylists(): - self._playlists.append(playlist_data['playlist']) + import mpd + + try: + self._playlists = [] + for playlist_data in self._client.listplaylists(): + self._playlists.append(playlist_data['playlist']) + except mpd.CommandError as error: + self._playlists = None + _LOGGER.warning("Playlists could not be updated: %s:", error) def set_volume_level(self, volume): """Set volume of media player.""" - self._client.setvol(int(volume * 100)) + if 'volume' in self._status: + self._client.setvol(int(volume * 100)) def volume_up(self): """Service to send the MPD the command for volume up.""" - current_volume = int(self._status['volume']) + if 'volume' in self._status: + current_volume = int(self._status['volume']) - if current_volume <= 100: - self._client.setvol(current_volume + 5) + if current_volume <= 100: + self._client.setvol(current_volume + 5) def volume_down(self): """Service to send the MPD the command for volume down.""" - current_volume = int(self._status['volume']) + if 'volume' in self._status: + current_volume = int(self._status['volume']) - if current_volume >= 0: - self._client.setvol(current_volume - 5) + if current_volume >= 0: + self._client.setvol(current_volume - 5) def media_play(self): """Service to send the MPD the command for play/pause.""" @@ -270,12 +290,13 @@ class MpdDevice(MediaPlayerDevice): def mute_volume(self, mute): """Mute. Emulated with set_volume_level.""" - if mute is True: - self._muted_volume = self.volume_level - self.set_volume_level(0) - elif mute is False: - self.set_volume_level(self._muted_volume) - self._muted = mute + if 'volume' in self._status: + if mute: + self._muted_volume = self.volume_level + self.set_volume_level(0) + else: + self.set_volume_level(self._muted_volume) + self._muted = mute def play_media(self, media_type, media_id, **kwargs): """Send the media player the command for playing a playlist.""" From ef193b0f64cdd89b2855030e638763f970eb8e5b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 18 Aug 2018 11:15:33 +0200 Subject: [PATCH 058/159] Bump frontend to 20180818.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 40fb6056684..e17bbad78d1 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180816.1'] +REQUIREMENTS = ['home-assistant-frontend==20180818.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index b3b8a7a5449..bcc521c1fdc 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -435,7 +435,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180816.1 +home-assistant-frontend==20180818.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3d0274e859b..6f4dece3a75 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180816.1 +home-assistant-frontend==20180818.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 8ec550d6e069517453f014f40570ecc6a12a38de Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 18 Aug 2018 13:34:33 +0200 Subject: [PATCH 059/159] Storage entity registry (#16018) * Split out storage delayed write * Update code using delayed save * Fix tests * Fix typing test * Add callback decorator * Migrate entity registry to storage helper * Make double loading protection easier * Lint * Fix tests * Ordered Dict --- homeassistant/helpers/entity_registry.py | 102 ++++++++++---------- homeassistant/helpers/storage.py | 8 +- tests/common.py | 7 +- tests/components/light/test_init.py | 20 ++-- tests/components/sensor/test_mqtt.py | 49 +++++----- tests/helpers/test_entity_registry.py | 116 ++++++++++++----------- tests/helpers/test_storage.py | 14 ++- 7 files changed, 167 insertions(+), 149 deletions(-) diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 2fa64ff8680..285d4cbd23a 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -6,15 +6,10 @@ identified by their domain, platform and a unique id provided by that platform. The Entity Registry will persist itself 10 seconds after a new entity is registered. Registering a new entity while a timer is in progress resets the timer. - -After initializing, call EntityRegistry.async_ensure_loaded to load the data -from disk. """ - from collections import OrderedDict from itertools import chain import logging -import os import weakref import attr @@ -22,7 +17,7 @@ import attr from homeassistant.core import callback, split_entity_id, valid_entity_id from homeassistant.loader import bind_hass from homeassistant.util import ensure_unique_string, slugify -from homeassistant.util.yaml import load_yaml, save_yaml +from homeassistant.util.yaml import load_yaml PATH_REGISTRY = 'entity_registry.yaml' DATA_REGISTRY = 'entity_registry' @@ -32,6 +27,9 @@ _UNDEF = object() DISABLED_HASS = 'hass' DISABLED_USER = 'user' +STORAGE_VERSION = 1 +STORAGE_KEY = 'core.entity_registry' + @attr.s(slots=True, frozen=True) class RegistryEntry: @@ -79,8 +77,7 @@ class EntityRegistry: """Initialize the registry.""" self.hass = hass self.entities = None - self._load_task = None - self._sched_save = None + self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) @callback def async_is_registered(self, entity_id): @@ -199,71 +196,72 @@ class EntityRegistry: return new - async def async_ensure_loaded(self): - """Load the registry from disk.""" - if self.entities is not None: - return - - if self._load_task is None: - self._load_task = self.hass.async_add_job(self._async_load) - - await self._load_task - - async def _async_load(self): + async def async_load(self): """Load the entity registry.""" - path = self.hass.config.path(PATH_REGISTRY) + data = await self.hass.helpers.storage.async_migrator( + self.hass.config.path(PATH_REGISTRY), self._store, + old_conf_load_func=load_yaml, + old_conf_migrate_func=_async_migrate + ) entities = OrderedDict() - if os.path.isfile(path): - data = await self.hass.async_add_job(load_yaml, path) - - for entity_id, info in data.items(): - entities[entity_id] = RegistryEntry( - entity_id=entity_id, - config_entry_id=info.get('config_entry_id'), - unique_id=info['unique_id'], - platform=info['platform'], - name=info.get('name'), - disabled_by=info.get('disabled_by') + if data is not None: + for entity in data['entities']: + entities[entity['entity_id']] = RegistryEntry( + entity_id=entity['entity_id'], + config_entry_id=entity.get('config_entry_id'), + unique_id=entity['unique_id'], + platform=entity['platform'], + name=entity.get('name'), + disabled_by=entity.get('disabled_by') ) self.entities = entities - self._load_task = None @callback def async_schedule_save(self): """Schedule saving the entity registry.""" - if self._sched_save is not None: - self._sched_save.cancel() + self._store.async_delay_save(self._data_to_save, SAVE_DELAY) - self._sched_save = self.hass.loop.call_later( - SAVE_DELAY, self.hass.async_add_job, self._async_save - ) + @callback + def _data_to_save(self): + """Data of entity registry to store in a file.""" + data = {} - async def _async_save(self): - """Save the entity registry to a file.""" - self._sched_save = None - data = OrderedDict() - - for entry in self.entities.values(): - data[entry.entity_id] = { + data['entities'] = [ + { + 'entity_id': entry.entity_id, 'config_entry_id': entry.config_entry_id, 'unique_id': entry.unique_id, 'platform': entry.platform, 'name': entry.name, - } + } for entry in self.entities.values() + ] - await self.hass.async_add_job( - save_yaml, self.hass.config.path(PATH_REGISTRY), data) + return data @bind_hass async def async_get_registry(hass) -> EntityRegistry: """Return entity registry instance.""" - registry = hass.data.get(DATA_REGISTRY) + task = hass.data.get(DATA_REGISTRY) - if registry is None: - registry = hass.data[DATA_REGISTRY] = EntityRegistry(hass) + if task is None: + async def _load_reg(): + registry = EntityRegistry(hass) + await registry.async_load() + return registry - await registry.async_ensure_loaded() - return registry + task = hass.data[DATA_REGISTRY] = hass.async_create_task(_load_reg()) + + return await task + + +async def _async_migrate(entities): + """Migrate the YAML config file to storage helper format.""" + return { + 'entities': [ + {'entity_id': entity_id, **info} + for entity_id, info in entities.items() + ] + } diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index 47d182d9a7c..8931341f1a2 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -15,7 +15,9 @@ _LOGGER = logging.getLogger(__name__) @bind_hass -async def async_migrator(hass, old_path, store, *, old_conf_migrate_func=None): +async def async_migrator(hass, old_path, store, *, + old_conf_load_func=json.load_json, + old_conf_migrate_func=None): """Helper function to migrate old data to a store and then load data. async def old_conf_migrate_func(old_data) @@ -25,7 +27,7 @@ async def async_migrator(hass, old_path, store, *, old_conf_migrate_func=None): if not os.path.isfile(old_path): return None - return json.load_json(old_path) + return old_conf_load_func(old_path) config = await hass.async_add_executor_job(load_old_config) @@ -52,7 +54,7 @@ class Store: self._data = None self._unsub_delay_listener = None self._unsub_stop_listener = None - self._write_lock = asyncio.Lock() + self._write_lock = asyncio.Lock(loop=hass.loop) self._load_task = None @property diff --git a/tests/common.py b/tests/common.py index 81e4774ccd4..e7445751783 100644 --- a/tests/common.py +++ b/tests/common.py @@ -307,7 +307,12 @@ def mock_registry(hass, mock_entries=None): """Mock the Entity Registry.""" registry = entity_registry.EntityRegistry(hass) registry.entities = mock_entries or {} - hass.data[entity_registry.DATA_REGISTRY] = registry + + async def _get_reg(): + return registry + + hass.data[entity_registry.DATA_REGISTRY] = \ + hass.loop.create_task(_get_reg()) return registry diff --git a/tests/components/light/test_init.py b/tests/components/light/test_init.py index 4d779eef461..0f73c5a38c6 100644 --- a/tests/components/light/test_init.py +++ b/tests/components/light/test_init.py @@ -14,7 +14,7 @@ from homeassistant.components import light from homeassistant.helpers.intent import IntentHandleError from tests.common import ( - async_mock_service, mock_service, get_test_home_assistant) + async_mock_service, mock_service, get_test_home_assistant, mock_storage) class TestLight(unittest.TestCase): @@ -333,10 +333,11 @@ class TestLight(unittest.TestCase): "group.all_lights.default,.4,.6,99\n" with mock.patch('os.path.isfile', side_effect=_mock_isfile): with mock.patch('builtins.open', side_effect=_mock_open): - self.assertTrue(setup_component( - self.hass, light.DOMAIN, - {light.DOMAIN: {CONF_PLATFORM: 'test'}} - )) + with mock_storage(): + self.assertTrue(setup_component( + self.hass, light.DOMAIN, + {light.DOMAIN: {CONF_PLATFORM: 'test'}} + )) dev, _, _ = platform.DEVICES light.turn_on(self.hass, dev.entity_id) @@ -371,10 +372,11 @@ class TestLight(unittest.TestCase): "light.ceiling_2.default,.6,.6,100\n" with mock.patch('os.path.isfile', side_effect=_mock_isfile): with mock.patch('builtins.open', side_effect=_mock_open): - self.assertTrue(setup_component( - self.hass, light.DOMAIN, - {light.DOMAIN: {CONF_PLATFORM: 'test'}} - )) + with mock_storage(): + self.assertTrue(setup_component( + self.hass, light.DOMAIN, + {light.DOMAIN: {CONF_PLATFORM: 'test'}} + )) dev = next(filter(lambda x: x.entity_id == 'light.ceiling_2', platform.DEVICES)) diff --git a/tests/components/sensor/test_mqtt.py b/tests/components/sensor/test_mqtt.py index 2583f52b3d2..234afff3418 100644 --- a/tests/components/sensor/test_mqtt.py +++ b/tests/components/sensor/test_mqtt.py @@ -5,13 +5,14 @@ from datetime import timedelta, datetime from unittest.mock import patch import homeassistant.core as ha -from homeassistant.setup import setup_component +from homeassistant.setup import setup_component, async_setup_component import homeassistant.components.sensor as sensor from homeassistant.const import EVENT_STATE_CHANGED, STATE_UNAVAILABLE import homeassistant.util.dt as dt_util from tests.common import mock_mqtt_component, fire_mqtt_message, \ - assert_setup_component + assert_setup_component, async_fire_mqtt_message, \ + async_mock_mqtt_component from tests.common import get_test_home_assistant, mock_component @@ -331,27 +332,6 @@ class TestSensorMQTT(unittest.TestCase): state.attributes.get('val')) self.assertEqual('100', state.state) - def test_unique_id(self): - """Test unique id option only creates one sensor per unique_id.""" - assert setup_component(self.hass, sensor.DOMAIN, { - sensor.DOMAIN: [{ - 'platform': 'mqtt', - 'name': 'Test 1', - 'state_topic': 'test-topic', - 'unique_id': 'TOTALLY_UNIQUE' - }, { - 'platform': 'mqtt', - 'name': 'Test 2', - 'state_topic': 'test-topic', - 'unique_id': 'TOTALLY_UNIQUE' - }] - }) - - fire_mqtt_message(self.hass, 'test-topic', 'payload') - self.hass.block_till_done() - - assert len(self.hass.states.all()) == 1 - def test_invalid_device_class(self): """Test device_class option with invalid value.""" with assert_setup_component(0): @@ -384,3 +364,26 @@ class TestSensorMQTT(unittest.TestCase): assert state.attributes['device_class'] == 'temperature' state = self.hass.states.get('sensor.test_2') assert 'device_class' not in state.attributes + + +async def test_unique_id(hass): + """Test unique id option only creates one sensor per unique_id.""" + await async_mock_mqtt_component(hass) + assert await async_setup_component(hass, sensor.DOMAIN, { + sensor.DOMAIN: [{ + 'platform': 'mqtt', + 'name': 'Test 1', + 'state_topic': 'test-topic', + 'unique_id': 'TOTALLY_UNIQUE' + }, { + 'platform': 'mqtt', + 'name': 'Test 2', + 'state_topic': 'test-topic', + 'unique_id': 'TOTALLY_UNIQUE' + }] + }) + + async_fire_mqtt_message(hass, 'test-topic', 'payload') + await hass.async_block_till_done() + + assert len(hass.states.async_all()) == 1 diff --git a/tests/helpers/test_entity_registry.py b/tests/helpers/test_entity_registry.py index 5a9efd5c041..d0c088a6f69 100644 --- a/tests/helpers/test_entity_registry.py +++ b/tests/helpers/test_entity_registry.py @@ -1,6 +1,6 @@ """Tests for the Entity Registry.""" import asyncio -from unittest.mock import patch, mock_open +from unittest.mock import patch import pytest @@ -61,29 +61,13 @@ def test_get_or_create_suggested_object_id_conflict_existing(hass, registry): @asyncio.coroutine def test_create_triggers_save(hass, registry): """Test that registering entry triggers a save.""" - with patch.object(hass.loop, 'call_later') as mock_call_later: + with patch.object(registry, 'async_schedule_save') as mock_schedule_save: registry.async_get_or_create('light', 'hue', '1234') - assert len(mock_call_later.mock_calls) == 1 + assert len(mock_schedule_save.mock_calls) == 1 -@asyncio.coroutine -def test_save_timer_reset_on_subsequent_save(hass, registry): - """Test we reset the save timer on a new create.""" - with patch.object(hass.loop, 'call_later') as mock_call_later: - registry.async_get_or_create('light', 'hue', '1234') - - assert len(mock_call_later.mock_calls) == 1 - - with patch.object(hass.loop, 'call_later') as mock_call_later_2: - registry.async_get_or_create('light', 'hue', '5678') - - assert len(mock_call_later().cancel.mock_calls) == 1 - assert len(mock_call_later_2.mock_calls) == 1 - - -@asyncio.coroutine -def test_loading_saving_data(hass, registry): +async def test_loading_saving_data(hass, registry): """Test that we load/save data correctly.""" orig_entry1 = registry.async_get_or_create('light', 'hue', '1234') orig_entry2 = registry.async_get_or_create( @@ -91,18 +75,11 @@ def test_loading_saving_data(hass, registry): assert len(registry.entities) == 2 - with patch(YAML__OPEN_PATH, mock_open(), create=True) as mock_write: - yield from registry._async_save() - - # Mock open calls are: open file, context enter, write, context leave - written = mock_write.mock_calls[2][1][0] - # Now load written data in new registry registry2 = entity_registry.EntityRegistry(hass) + registry2._store = registry._store - with patch('os.path.isfile', return_value=True), \ - patch(YAML__OPEN_PATH, mock_open(read_data=written), create=True): - yield from registry2._async_load() + await registry2.async_load() # Ensure same order assert list(registry.entities) == list(registry2.entities) @@ -139,32 +116,37 @@ def test_is_registered(registry): assert not registry.async_is_registered('light.non_existing') -@asyncio.coroutine -def test_loading_extra_values(hass): +async def test_loading_extra_values(hass, hass_storage): """Test we load extra data from the registry.""" - written = """ -test.named: - platform: super_platform - unique_id: with-name - name: registry override -test.no_name: - platform: super_platform - unique_id: without-name -test.disabled_user: - platform: super_platform - unique_id: disabled-user - disabled_by: user -test.disabled_hass: - platform: super_platform - unique_id: disabled-hass - disabled_by: hass -""" + hass_storage[entity_registry.STORAGE_KEY] = { + 'version': entity_registry.STORAGE_VERSION, + 'data': { + 'entities': [ + { + 'entity_id': 'test.named', + 'platform': 'super_platform', + 'unique_id': 'with-name', + 'name': 'registry override', + }, { + 'entity_id': 'test.no_name', + 'platform': 'super_platform', + 'unique_id': 'without-name', + }, { + 'entity_id': 'test.disabled_user', + 'platform': 'super_platform', + 'unique_id': 'disabled-user', + 'disabled_by': 'user', + }, { + 'entity_id': 'test.disabled_hass', + 'platform': 'super_platform', + 'unique_id': 'disabled-hass', + 'disabled_by': 'hass', + } + ] + } + } - registry = entity_registry.EntityRegistry(hass) - - with patch('os.path.isfile', return_value=True), \ - patch(YAML__OPEN_PATH, mock_open(read_data=written), create=True): - yield from registry._async_load() + registry = await entity_registry.async_get_registry(hass) entry_with_name = registry.async_get_or_create( 'test', 'super_platform', 'with-name') @@ -202,3 +184,31 @@ async def test_updating_config_entry_id(registry): 'light', 'hue', '5678', config_entry_id='mock-id-2') assert entry.entity_id == entry2.entity_id assert entry2.config_entry_id == 'mock-id-2' + + +async def test_migration(hass): + """Test migration from old data to new.""" + old_conf = { + 'light.kitchen': { + 'config_entry_id': 'test-config-id', + 'unique_id': 'test-unique', + 'platform': 'test-platform', + 'name': 'Test Name', + 'disabled_by': 'hass', + } + } + with patch('os.path.isfile', return_value=True), patch('os.remove'), \ + patch('homeassistant.helpers.entity_registry.load_yaml', + return_value=old_conf): + registry = await entity_registry.async_get_registry(hass) + + assert registry.async_is_registered('light.kitchen') + entry = registry.async_get_or_create( + domain='light', + platform='test-platform', + unique_id='test-unique', + config_entry_id='test-config-id', + ) + assert entry.name == 'Test Name' + assert entry.disabled_by == 'hass' + assert entry.config_entry_id == 'test-config-id' diff --git a/tests/helpers/test_storage.py b/tests/helpers/test_storage.py index b35b2596802..6cb75899d35 100644 --- a/tests/helpers/test_storage.py +++ b/tests/helpers/test_storage.py @@ -141,11 +141,10 @@ async def test_migrator_no_existing_config(hass, store, hass_storage): async def test_migrator_existing_config(hass, store, hass_storage): """Test migrating existing config.""" with patch('os.path.isfile', return_value=True), \ - patch('os.remove') as mock_remove, \ - patch('homeassistant.util.json.load_json', - return_value={'old': 'config'}): + patch('os.remove') as mock_remove: data = await storage.async_migrator( - hass, 'old-path', store) + hass, 'old-path', store, + old_conf_load_func=lambda _: {'old': 'config'}) assert len(mock_remove.mock_calls) == 1 assert data == {'old': 'config'} @@ -163,12 +162,11 @@ async def test_migrator_transforming_config(hass, store, hass_storage): return {'new': old_config['old']} with patch('os.path.isfile', return_value=True), \ - patch('os.remove') as mock_remove, \ - patch('homeassistant.util.json.load_json', - return_value={'old': 'config'}): + patch('os.remove') as mock_remove: data = await storage.async_migrator( hass, 'old-path', store, - old_conf_migrate_func=old_conf_migrate_func) + old_conf_migrate_func=old_conf_migrate_func, + old_conf_load_func=lambda _: {'old': 'config'}) assert len(mock_remove.mock_calls) == 1 assert data == {'new': 'config'} From b901a26c47151e56978bd16aec94252e3f21a804 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 18 Aug 2018 13:35:51 +0200 Subject: [PATCH 060/159] Attempt to fix flaky TTS test (#16025) --- tests/components/tts/test_init.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py index e8746ee762f..0970f0d7490 100644 --- a/tests/components/tts/test_init.py +++ b/tests/components/tts/test_init.py @@ -44,11 +44,11 @@ class TestTTS: def teardown_method(self): """Stop everything that was started.""" + self.hass.stop() + if os.path.isdir(self.default_tts_cache): shutil.rmtree(self.default_tts_cache) - self.hass.stop() - def test_setup_component_demo(self): """Setup the demo platform with defaults.""" config = { From c105045dab8698cb183556665441fca7613a49ed Mon Sep 17 00:00:00 2001 From: Daniel Shokouhi Date: Sat, 18 Aug 2018 11:20:32 -0700 Subject: [PATCH 061/159] Update neato to support new StateVacuumDevice (#16035) * Update neato to support new vacuum states * Remove changes submitted in error * Lint * Review comments and fix resume cleaning * Lint --- homeassistant/components/vacuum/neato.py | 70 +++++++++--------------- 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/homeassistant/components/vacuum/neato.py b/homeassistant/components/vacuum/neato.py index 224e763a097..82c5187f7b0 100644 --- a/homeassistant/components/vacuum/neato.py +++ b/homeassistant/components/vacuum/neato.py @@ -8,10 +8,10 @@ import logging from datetime import timedelta import requests -from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.components.vacuum import ( - VacuumDevice, SUPPORT_BATTERY, SUPPORT_PAUSE, SUPPORT_RETURN_HOME, - SUPPORT_STATUS, SUPPORT_STOP, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, + StateVacuumDevice, SUPPORT_BATTERY, SUPPORT_PAUSE, SUPPORT_RETURN_HOME, + SUPPORT_STATE, SUPPORT_STOP, SUPPORT_START, STATE_IDLE, + STATE_PAUSED, STATE_CLEANING, STATE_DOCKED, STATE_RETURNING, STATE_ERROR, SUPPORT_MAP, ATTR_STATUS, ATTR_BATTERY_LEVEL, ATTR_BATTERY_ICON, SUPPORT_LOCATE) from homeassistant.components.neato import ( @@ -24,8 +24,8 @@ DEPENDENCIES = ['neato'] SCAN_INTERVAL = timedelta(minutes=5) SUPPORT_NEATO = SUPPORT_BATTERY | SUPPORT_PAUSE | SUPPORT_RETURN_HOME | \ - SUPPORT_STOP | SUPPORT_TURN_OFF | SUPPORT_TURN_ON | \ - SUPPORT_STATUS | SUPPORT_MAP | SUPPORT_LOCATE + SUPPORT_STOP | SUPPORT_START | \ + SUPPORT_STATE | SUPPORT_MAP | SUPPORT_LOCATE ATTR_CLEAN_START = 'clean_start' ATTR_CLEAN_STOP = 'clean_stop' @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): add_devices(dev, True) -class NeatoConnectedVacuum(VacuumDevice): +class NeatoConnectedVacuum(StateVacuumDevice): """Representation of a Neato Connected Vacuum.""" def __init__(self, hass, robot): @@ -79,36 +79,30 @@ class NeatoConnectedVacuum(VacuumDevice): _LOGGER.debug('self._state=%s', self._state) if self._state['state'] == 1: if self._state['details']['isCharging']: + self._clean_state = STATE_DOCKED self._status_state = 'Charging' elif (self._state['details']['isDocked'] and not self._state['details']['isCharging']): + self._clean_state = STATE_DOCKED self._status_state = 'Docked' else: + self._clean_state = STATE_IDLE self._status_state = 'Stopped' elif self._state['state'] == 2: if ALERTS.get(self._state['error']) is None: + self._clean_state = STATE_CLEANING self._status_state = ( MODE.get(self._state['cleaning']['mode']) + ' ' + ACTION.get(self._state['action'])) else: self._status_state = ALERTS.get(self._state['error']) elif self._state['state'] == 3: + self._clean_state = STATE_PAUSED self._status_state = 'Paused' elif self._state['state'] == 4: + self._clean_state = STATE_ERROR self._status_state = ERRORS.get(self._state['error']) - if (self._state['action'] == 1 or - self._state['action'] == 2 or - self._state['action'] == 3 and - self._state['state'] == 2): - self._clean_state = STATE_ON - elif (self._state['action'] == 11 or - self._state['action'] == 12 and - self._state['state'] == 2): - self._clean_state = STATE_ON - else: - self._clean_state = STATE_OFF - if not self._mapdata.get(self.robot.serial, {}).get('maps', []): return self.clean_time_start = ( @@ -147,17 +141,17 @@ class NeatoConnectedVacuum(VacuumDevice): return self._state['details']['charge'] @property - def status(self): + def state(self): """Return the status of the vacuum cleaner.""" - return self._status_state + return self._clean_state @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes of the vacuum cleaner.""" data = {} - if self.status is not None: - data[ATTR_STATUS] = self.status + if self._status_state is not None: + data[ATTR_STATUS] = self._status_state if self.battery_level is not None: data[ATTR_BATTERY_LEVEL] = self.battery_level @@ -181,38 +175,26 @@ class NeatoConnectedVacuum(VacuumDevice): return data - def turn_on(self, **kwargs): - """Turn the vacuum on and start cleaning.""" - self.robot.start_cleaning() + def start(self): + """Start cleaning or resume cleaning.""" + if self._state['state'] == 1: + self.robot.start_cleaning() + elif self._state['state'] == 3: + self.robot.resume_cleaning() - @property - def is_on(self): - """Return true if switch is on.""" - return self._clean_state == STATE_ON - - def turn_off(self, **kwargs): - """Turn the switch off.""" + def pause(self): + """Pause the vacuum.""" self.robot.pause_cleaning() - self.robot.send_to_base() def return_to_base(self, **kwargs): """Set the vacuum cleaner to return to the dock.""" + self._clean_state = STATE_RETURNING self.robot.send_to_base() def stop(self, **kwargs): """Stop the vacuum cleaner.""" self.robot.stop_cleaning() - def start_pause(self, **kwargs): - """Start, pause or resume the cleaning task.""" - if self._state['state'] == 1: - self.robot.start_cleaning() - elif self._state['state'] == 2 and\ - ALERTS.get(self._state['error']) is None: - self.robot.pause_cleaning() - if self._state['state'] == 3: - self.robot.resume_cleaning() - def locate(self, **kwargs): """Locate the robot by making it emit a sound.""" self.robot.locate() From 8beb349e883591532f2fd3604ee95d394a6cb0d6 Mon Sep 17 00:00:00 2001 From: Dan Klaffenbach Date: Sun, 19 Aug 2018 13:57:28 +0200 Subject: [PATCH 062/159] vacuum/xiaomi_miio: Expose "sensor_dirty_left" attribute (#16003) --- homeassistant/components/vacuum/xiaomi_miio.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/vacuum/xiaomi_miio.py b/homeassistant/components/vacuum/xiaomi_miio.py index 2c6057e1cf6..367c8c03d0e 100644 --- a/homeassistant/components/vacuum/xiaomi_miio.py +++ b/homeassistant/components/vacuum/xiaomi_miio.py @@ -52,6 +52,7 @@ ATTR_DO_NOT_DISTURB_END = 'do_not_disturb_end' ATTR_MAIN_BRUSH_LEFT = 'main_brush_left' ATTR_SIDE_BRUSH_LEFT = 'side_brush_left' ATTR_FILTER_LEFT = 'filter_left' +ATTR_SENSOR_DIRTY_LEFT = 'sensor_dirty_left' ATTR_CLEANING_COUNT = 'cleaning_count' ATTR_CLEANED_TOTAL_AREA = 'total_cleaned_area' ATTR_CLEANING_TOTAL_TIME = 'total_cleaning_time' @@ -234,7 +235,12 @@ class MiroboVacuum(StateVacuumDevice): / 3600), ATTR_FILTER_LEFT: int( self.consumable_state.filter_left.total_seconds() - / 3600)}) + / 3600), + ATTR_SENSOR_DIRTY_LEFT: int( + self.consumable_state.sensor_dirty_left.total_seconds() + / 3600) + }) + if self.vacuum_state.got_error: attrs[ATTR_ERROR] = self.vacuum_state.error return attrs From 81d3161a5e2ced733e4b3febc6baf58f9936f41c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Aug 2018 17:22:09 +0200 Subject: [PATCH 063/159] Add forgiving add column (#16057) * Add forgiving add column * Lint --- .../components/recorder/migration.py | 27 ++++++++++++++----- tests/components/recorder/test_migrate.py | 25 +++++++++++++---- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/recorder/migration.py b/homeassistant/components/recorder/migration.py index 939985ebfb1..5633830dc51 100644 --- a/homeassistant/components/recorder/migration.py +++ b/homeassistant/components/recorder/migration.py @@ -117,7 +117,13 @@ def _drop_index(engine, table_name, index_name): def _add_columns(engine, table_name, columns_def): """Add columns to a table.""" from sqlalchemy import text - from sqlalchemy.exc import SQLAlchemyError + from sqlalchemy.exc import OperationalError + + _LOGGER.info("Adding columns %s to table %s. Note: this can take several " + "minutes on large databases and slow computers. Please " + "be patient!", + ', '.join(column.split(' ')[0] for column in columns_def), + table_name) columns_def = ['ADD COLUMN {}'.format(col_def) for col_def in columns_def] @@ -126,13 +132,22 @@ def _add_columns(engine, table_name, columns_def): table=table_name, columns_def=', '.join(columns_def)))) return - except SQLAlchemyError: - pass + except OperationalError: + # Some engines support adding all columns at once, + # this error is when they dont' + _LOGGER.info('Unable to use quick column add. Adding 1 by 1.') for column_def in columns_def: - engine.execute(text("ALTER TABLE {table} {column_def}".format( - table=table_name, - column_def=column_def))) + try: + engine.execute(text("ALTER TABLE {table} {column_def}".format( + table=table_name, + column_def=column_def))) + except OperationalError as err: + if 'duplicate' not in str(err).lower(): + raise + + _LOGGER.warning('Column %s already exists on %s, continueing', + column_def.split(' ')[0], table_name) def _apply_update(engine, new_version, old_version): diff --git a/tests/components/recorder/test_migrate.py b/tests/components/recorder/test_migrate.py index 5ac9b3adb81..1c48c261372 100644 --- a/tests/components/recorder/test_migrate.py +++ b/tests/components/recorder/test_migrate.py @@ -5,11 +5,11 @@ from unittest.mock import patch, call import pytest from sqlalchemy import create_engine +from sqlalchemy.pool import StaticPool from homeassistant.bootstrap import async_setup_component -from homeassistant.components.recorder import wait_connection_ready, migration -from homeassistant.components.recorder.models import SCHEMA_VERSION -from homeassistant.components.recorder.const import DATA_INSTANCE +from homeassistant.components.recorder import ( + wait_connection_ready, migration, const, models) from tests.components.recorder import models_original @@ -37,8 +37,8 @@ def test_schema_update_calls(hass): yield from wait_connection_ready(hass) update.assert_has_calls([ - call(hass.data[DATA_INSTANCE].engine, version+1, 0) for version - in range(0, SCHEMA_VERSION)]) + call(hass.data[const.DATA_INSTANCE].engine, version+1, 0) for version + in range(0, models.SCHEMA_VERSION)]) @asyncio.coroutine @@ -65,3 +65,18 @@ def test_invalid_update(): """Test that an invalid new version raises an exception.""" with pytest.raises(ValueError): migration._apply_update(None, -1, 0) + + +def test_forgiving_add_column(): + """Test that add column will continue if column exists.""" + engine = create_engine( + 'sqlite://', + poolclass=StaticPool + ) + engine.execute('CREATE TABLE hello (id int)') + migration._add_columns(engine, 'hello', [ + 'context_id CHARACTER(36)', + ]) + migration._add_columns(engine, 'hello', [ + 'context_id CHARACTER(36)', + ]) From 21b88f2fe89a714308e163a871bb4423a68bc88e Mon Sep 17 00:00:00 2001 From: huangyupeng Date: Mon, 20 Aug 2018 00:55:10 +0800 Subject: [PATCH 064/159] Tuya fix login problem and add login platform param (#16058) * add a platform param to distinguish different app's account. * fix requirements --- homeassistant/components/tuya.py | 10 ++++++---- requirements_all.txt | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/tuya.py b/homeassistant/components/tuya.py index 490c11baad7..33f34164b02 100644 --- a/homeassistant/components/tuya.py +++ b/homeassistant/components/tuya.py @@ -10,14 +10,14 @@ import voluptuous as vol from homeassistant.core import callback import homeassistant.helpers.config_validation as cv -from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD) +from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM) from homeassistant.helpers import discovery from homeassistant.helpers.dispatcher import ( dispatcher_send, async_dispatcher_connect) from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import track_time_interval -REQUIREMENTS = ['tuyapy==0.1.2'] +REQUIREMENTS = ['tuyapy==0.1.3'] _LOGGER = logging.getLogger(__name__) @@ -45,7 +45,8 @@ CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_COUNTRYCODE): cv.string + vol.Required(CONF_COUNTRYCODE): cv.string, + vol.Optional(CONF_PLATFORM, default='tuya'): cv.string, }) }, extra=vol.ALLOW_EXTRA) @@ -58,9 +59,10 @@ def setup(hass, config): username = config[DOMAIN][CONF_USERNAME] password = config[DOMAIN][CONF_PASSWORD] country_code = config[DOMAIN][CONF_COUNTRYCODE] + platform = config[DOMAIN][CONF_PLATFORM] hass.data[DATA_TUYA] = tuya - tuya.init(username, password, country_code) + tuya.init(username, password, country_code, platform) hass.data[DOMAIN] = { 'entities': {} } diff --git a/requirements_all.txt b/requirements_all.txt index bcc521c1fdc..132696dcb10 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1392,7 +1392,7 @@ tplink==0.2.1 transmissionrpc==0.11 # homeassistant.components.tuya -tuyapy==0.1.2 +tuyapy==0.1.3 # homeassistant.components.twilio twilio==5.7.0 From 7c95e96ce8fc12a114d8663b60c77a6f7aa6d0e3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Aug 2018 18:56:31 +0200 Subject: [PATCH 065/159] Add notify platforms to loaded components (#16063) --- homeassistant/components/notify/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/notify/__init__.py b/homeassistant/components/notify/__init__.py index 13cd6203ed4..4de35d3f850 100644 --- a/homeassistant/components/notify/__init__.py +++ b/homeassistant/components/notify/__init__.py @@ -156,6 +156,8 @@ def async_setup(hass, config): DOMAIN, platform_name_slug, async_notify_message, schema=NOTIFY_SERVICE_SCHEMA) + hass.config.components.add('{}.{}'.format(DOMAIN, p_type)) + return True setup_tasks = [async_setup_platform(p_type, p_config) for p_type, p_config From 9e1fa7ef42cbad0f2fe36e51651a6f1d00d31dec Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Aug 2018 18:57:06 +0200 Subject: [PATCH 066/159] Column syntax fix + Add a file if migration in progress (#16061) * Add a file if migration in progress * Warning * Convert message for migration to warning --- .../components/recorder/migration.py | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/recorder/migration.py b/homeassistant/components/recorder/migration.py index 5633830dc51..0dff21a5986 100644 --- a/homeassistant/components/recorder/migration.py +++ b/homeassistant/components/recorder/migration.py @@ -1,39 +1,53 @@ """Schema migration helpers.""" import logging +import os from .util import session_scope _LOGGER = logging.getLogger(__name__) +PROGRESS_FILE = '.migration_progress' def migrate_schema(instance): """Check if the schema needs to be upgraded.""" from .models import SchemaChanges, SCHEMA_VERSION + progress_path = instance.hass.config.path(PROGRESS_FILE) + with session_scope(session=instance.get_session()) as session: res = session.query(SchemaChanges).order_by( SchemaChanges.change_id.desc()).first() current_version = getattr(res, 'schema_version', None) if current_version == SCHEMA_VERSION: + # Clean up if old migration left file + if os.path.isfile(progress_path): + _LOGGER.warning("Found existing migration file, cleaning up") + os.remove(instance.hass.config.path(PROGRESS_FILE)) return - _LOGGER.debug("Database requires upgrade. Schema version: %s", - current_version) + with open(progress_path, 'w'): + pass + + _LOGGER.warning("Database requires upgrade. Schema version: %s", + current_version) if current_version is None: current_version = _inspect_schema_version(instance.engine, session) _LOGGER.debug("No schema version found. Inspected version: %s", current_version) - for version in range(current_version, SCHEMA_VERSION): - new_version = version + 1 - _LOGGER.info("Upgrading recorder db schema to version %s", - new_version) - _apply_update(instance.engine, new_version, current_version) - session.add(SchemaChanges(schema_version=new_version)) + try: + for version in range(current_version, SCHEMA_VERSION): + new_version = version + 1 + _LOGGER.info("Upgrading recorder db schema to version %s", + new_version) + _apply_update(instance.engine, new_version, current_version) + session.add(SchemaChanges(schema_version=new_version)) - _LOGGER.info("Upgrade to version %s done", new_version) + _LOGGER.info("Upgrade to version %s done", new_version) + finally: + os.remove(instance.hass.config.path(PROGRESS_FILE)) def _create_index(engine, table_name, index_name): @@ -125,7 +139,7 @@ def _add_columns(engine, table_name, columns_def): ', '.join(column.split(' ')[0] for column in columns_def), table_name) - columns_def = ['ADD COLUMN {}'.format(col_def) for col_def in columns_def] + columns_def = ['ADD {}'.format(col_def) for col_def in columns_def] try: engine.execute(text("ALTER TABLE {table} {columns_def}".format( @@ -147,7 +161,7 @@ def _add_columns(engine, table_name, columns_def): raise _LOGGER.warning('Column %s already exists on %s, continueing', - column_def.split(' ')[0], table_name) + column_def.split(' ')[1], table_name) def _apply_update(engine, new_version, old_version): From dbd0763f83d0857fceb00e2c973a4ec91663ddcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Sun, 19 Aug 2018 22:29:08 +0200 Subject: [PATCH 067/159] Grammar and spelling fixes (#16065) --- homeassistant/bootstrap.py | 2 +- .../alarm_control_panel/__init__.py | 2 +- .../alarm_control_panel/simplisafe.py | 2 +- .../components/automation/__init__.py | 2 +- .../components/binary_sensor/__init__.py | 2 +- .../components/binary_sensor/hikvision.py | 2 +- homeassistant/components/camera/__init__.py | 4 +- .../components/cast/.translations/en.json | 4 +- homeassistant/components/cast/strings.json | 2 +- homeassistant/components/climate/__init__.py | 2 +- homeassistant/components/deconz/__init__.py | 2 +- .../components/device_tracker/ritassist.py | 2 +- homeassistant/components/homekit/__init__.py | 4 +- homeassistant/components/homekit/util.py | 2 +- homeassistant/components/http/cors.py | 8 ++-- homeassistant/components/ihc/__init__.py | 4 +- homeassistant/components/ihc/services.yaml | 14 +++--- homeassistant/components/light/__init__.py | 2 +- homeassistant/components/light/ihc.py | 4 +- homeassistant/components/light/lw12wifi.py | 2 +- .../components/lock/bmw_connected_drive.py | 2 +- .../components/media_player/__init__.py | 2 +- .../components/media_player/channels.py | 2 +- .../components/media_player/vizio.py | 2 +- .../components/mysensors/__init__.py | 2 +- homeassistant/components/nest/__init__.py | 2 +- homeassistant/components/sabnzbd.py | 4 +- homeassistant/components/scene/__init__.py | 2 +- homeassistant/components/sensor/__init__.py | 2 +- .../components/sensor/cert_expiry.py | 2 +- .../components/sensor/duke_energy.py | 4 +- homeassistant/components/sensor/fints.py | 2 +- homeassistant/components/sensor/ihc.py | 4 +- homeassistant/components/sensor/melissa.py | 2 +- homeassistant/components/sensor/nut.py | 2 +- homeassistant/components/sensor/sht31.py | 2 +- homeassistant/components/sensor/sigfox.py | 2 +- homeassistant/components/sensor/uscis.py | 2 +- .../components/sensor/wirelesstag.py | 4 +- .../components/sonos/.translations/en.json | 4 +- homeassistant/components/sonos/strings.json | 2 +- homeassistant/components/switch/__init__.py | 2 +- homeassistant/components/switch/ihc.py | 4 +- homeassistant/components/waterfurnace.py | 2 +- homeassistant/components/wirelesstag.py | 2 +- homeassistant/components/zone/__init__.py | 2 +- homeassistant/config_entries.py | 2 +- homeassistant/helpers/discovery.py | 2 +- homeassistant/helpers/entity_component.py | 2 +- homeassistant/helpers/entity_platform.py | 10 ++-- homeassistant/setup.py | 6 +-- .../alarm_control_panel/test_manual.py | 2 +- .../alarm_control_panel/test_manual_mqtt.py | 2 +- .../alarm_control_panel/test_mqtt.py | 2 +- tests/components/auth/__init__.py | 2 +- tests/components/automation/test_event.py | 2 +- tests/components/automation/test_init.py | 2 +- tests/components/automation/test_litejet.py | 2 +- tests/components/automation/test_mqtt.py | 2 +- .../automation/test_numeric_state.py | 2 +- tests/components/automation/test_state.py | 2 +- tests/components/automation/test_sun.py | 2 +- tests/components/automation/test_template.py | 2 +- tests/components/automation/test_time.py | 2 +- tests/components/automation/test_zone.py | 2 +- .../binary_sensor/test_command_line.py | 2 +- tests/components/binary_sensor/test_ffmpeg.py | 16 +++---- tests/components/binary_sensor/test_mqtt.py | 2 +- tests/components/binary_sensor/test_nx584.py | 2 +- tests/components/binary_sensor/test_rest.py | 4 +- tests/components/binary_sensor/test_tcp.py | 2 +- .../components/binary_sensor/test_template.py | 2 +- .../components/binary_sensor/test_workday.py | 8 ++-- tests/components/calendar/test_google.py | 2 +- tests/components/camera/test_init.py | 6 +-- tests/components/camera/test_uvc.py | 8 ++-- tests/components/climate/test_demo.py | 2 +- .../climate/test_generic_thermostat.py | 48 +++++++++---------- tests/components/climate/test_mqtt.py | 2 +- tests/components/cover/test_command_line.py | 2 +- tests/components/cover/test_demo.py | 2 +- tests/components/cover/test_group.py | 2 +- tests/components/cover/test_mqtt.py | 2 +- tests/components/cover/test_rfxtrx.py | 2 +- .../components/device_tracker/test_asuswrt.py | 8 ++-- tests/components/device_tracker/test_ddwrt.py | 4 +- .../device_tracker/test_geofency.py | 2 +- tests/components/device_tracker/test_init.py | 2 +- tests/components/device_tracker/test_mqtt.py | 2 +- .../device_tracker/test_mqtt_json.py | 2 +- .../device_tracker/test_owntracks.py | 4 +- .../components/device_tracker/test_tplink.py | 2 +- .../device_tracker/test_unifi_direct.py | 2 +- .../device_tracker/test_upc_connect.py | 16 +++---- tests/components/emulated_hue/test_hue_api.py | 2 +- tests/components/emulated_hue/test_upnp.py | 2 +- tests/components/fan/test_dyson.py | 2 +- tests/components/fan/test_mqtt.py | 2 +- tests/components/fan/test_template.py | 2 +- tests/components/group/test_init.py | 8 ++-- tests/components/http/test_auth.py | 4 +- tests/components/http/test_cors.py | 2 +- tests/components/hue/test_init.py | 2 +- .../image_processing/test_facebox.py | 6 +-- .../components/image_processing/test_init.py | 22 ++++----- .../test_microsoft_face_detect.py | 10 ++-- .../test_microsoft_face_identify.py | 10 ++-- .../image_processing/test_openalpr_cloud.py | 18 +++---- .../image_processing/test_openalpr_local.py | 12 ++--- tests/components/light/test_demo.py | 2 +- tests/components/light/test_init.py | 2 +- tests/components/light/test_litejet.py | 2 +- tests/components/light/test_mochad.py | 8 ++-- tests/components/light/test_mqtt.py | 2 +- tests/components/light/test_mqtt_json.py | 2 +- tests/components/light/test_mqtt_template.py | 2 +- tests/components/light/test_rfxtrx.py | 2 +- tests/components/light/test_template.py | 2 +- tests/components/lock/test_demo.py | 2 +- tests/components/lock/test_mqtt.py | 2 +- .../media_player/test_async_helpers.py | 4 +- tests/components/media_player/test_cast.py | 6 +-- tests/components/media_player/test_demo.py | 4 +- tests/components/media_player/test_sonos.py | 2 +- .../media_player/test_soundtouch.py | 2 +- .../components/media_player/test_universal.py | 2 +- tests/components/media_player/test_yamaha.py | 2 +- tests/components/mqtt/test_init.py | 4 +- tests/components/mqtt/test_server.py | 8 ++-- tests/components/notify/test_apns.py | 2 +- tests/components/notify/test_command_line.py | 2 +- tests/components/notify/test_demo.py | 2 +- tests/components/notify/test_file.py | 2 +- tests/components/notify/test_group.py | 2 +- tests/components/notify/test_smtp.py | 2 +- .../persistent_notification/test_init.py | 2 +- tests/components/recorder/test_init.py | 4 +- tests/components/recorder/test_purge.py | 2 +- tests/components/recorder/test_util.py | 2 +- tests/components/remote/test_demo.py | 2 +- tests/components/remote/test_init.py | 2 +- tests/components/scene/test_init.py | 2 +- tests/components/scene/test_litejet.py | 2 +- tests/components/sensor/test_command_line.py | 2 +- tests/components/sensor/test_dyson.py | 2 +- tests/components/sensor/test_filter.py | 2 +- tests/components/sensor/test_google_wifi.py | 6 +-- .../sensor/test_imap_email_content.py | 4 +- tests/components/sensor/test_mfi.py | 4 +- tests/components/sensor/test_mhz19.py | 2 +- tests/components/sensor/test_moldindicator.py | 2 +- tests/components/sensor/test_mqtt.py | 2 +- tests/components/sensor/test_mqtt_room.py | 2 +- tests/components/sensor/test_rest.py | 6 +-- tests/components/sensor/test_rfxtrx.py | 2 +- tests/components/sensor/test_season.py | 2 +- tests/components/sensor/test_statistics.py | 2 +- tests/components/sensor/test_tcp.py | 2 +- tests/components/sensor/test_template.py | 2 +- tests/components/sensor/test_yweather.py | 2 +- tests/components/switch/test_command_line.py | 2 +- tests/components/switch/test_flux.py | 2 +- tests/components/switch/test_init.py | 2 +- tests/components/switch/test_litejet.py | 2 +- tests/components/switch/test_mfi.py | 2 +- tests/components/switch/test_mochad.py | 4 +- tests/components/switch/test_mqtt.py | 2 +- tests/components/switch/test_rest.py | 4 +- tests/components/switch/test_rfxtrx.py | 2 +- tests/components/switch/test_template.py | 2 +- tests/components/switch/test_wake_on_lan.py | 2 +- tests/components/test_alert.py | 2 +- tests/components/test_configurator.py | 2 +- tests/components/test_datadog.py | 2 +- .../test_device_sun_light_trigger.py | 2 +- tests/components/test_dyson.py | 2 +- tests/components/test_ffmpeg.py | 24 +++++----- tests/components/test_folder_watcher.py | 2 +- tests/components/test_google.py | 2 +- tests/components/test_graphite.py | 2 +- tests/components/test_history.py | 2 +- tests/components/test_history_graph.py | 2 +- tests/components/test_influxdb.py | 4 +- tests/components/test_init.py | 2 +- tests/components/test_input_boolean.py | 2 +- tests/components/test_input_datetime.py | 2 +- tests/components/test_input_number.py | 2 +- tests/components/test_input_select.py | 2 +- tests/components/test_input_text.py | 2 +- tests/components/test_introduction.py | 2 +- tests/components/test_kira.py | 2 +- tests/components/test_litejet.py | 2 +- tests/components/test_logbook.py | 2 +- tests/components/test_logentries.py | 2 +- tests/components/test_logger.py | 4 +- tests/components/test_microsoft_face.py | 22 ++++----- tests/components/test_mqtt_eventstream.py | 2 +- tests/components/test_mqtt_statestream.py | 2 +- tests/components/test_panel_iframe.py | 2 +- tests/components/test_pilight.py | 4 +- tests/components/test_proximity.py | 2 +- tests/components/test_rest_command.py | 6 +-- tests/components/test_rfxtrx.py | 2 +- tests/components/test_rss_feed_template.py | 2 +- tests/components/test_script.py | 2 +- tests/components/test_shell_command.py | 2 +- tests/components/test_splunk.py | 2 +- tests/components/test_statsd.py | 2 +- tests/components/test_sun.py | 2 +- tests/components/test_updater.py | 8 ++-- tests/components/test_weblink.py | 2 +- tests/components/tts/test_google.py | 2 +- tests/components/tts/test_init.py | 46 +++++++++--------- tests/components/tts/test_marytts.py | 2 +- tests/components/tts/test_voicerss.py | 2 +- tests/components/tts/test_yandextts.py | 2 +- tests/components/vacuum/test_demo.py | 2 +- tests/components/vacuum/test_dyson.py | 2 +- tests/components/weather/test_darksky.py | 2 +- tests/components/weather/test_ipma.py | 2 +- tests/components/weather/test_weather.py | 2 +- tests/components/weather/test_yweather.py | 2 +- tests/components/zone/test_init.py | 2 +- tests/conftest.py | 2 +- tests/helpers/test_aiohttp_client.py | 2 +- tests/helpers/test_condition.py | 2 +- tests/helpers/test_config_entry_flow.py | 4 +- tests/helpers/test_discovery.py | 18 +++---- tests/helpers/test_dispatcher.py | 2 +- tests/helpers/test_entity.py | 2 +- tests/helpers/test_entity_component.py | 2 +- tests/helpers/test_event.py | 2 +- tests/helpers/test_location.py | 10 ++-- tests/helpers/test_script.py | 2 +- tests/helpers/test_service.py | 2 +- tests/helpers/test_sun.py | 2 +- tests/helpers/test_temperature.py | 4 +- tests/helpers/test_template.py | 2 +- tests/test_config_entries.py | 2 +- tests/test_core.py | 10 ++-- tests/test_loader.py | 2 +- tests/test_requirements.py | 2 +- tests/test_setup.py | 14 +++--- tests/util/test_dt.py | 2 +- 244 files changed, 453 insertions(+), 453 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 43c7168dd2e..5c85267ca44 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -307,7 +307,7 @@ def async_enable_logging(hass: core.HomeAssistant, hass.data[DATA_LOGGING] = err_log_path else: _LOGGER.error( - "Unable to setup error log %s (access denied)", err_log_path) + "Unable to set up error log %s (access denied)", err_log_path) async def async_mount_local_lib_path(config_dir: str) -> str: diff --git a/homeassistant/components/alarm_control_panel/__init__.py b/homeassistant/components/alarm_control_panel/__init__.py index f9f2a4e03be..63977ed88c7 100644 --- a/homeassistant/components/alarm_control_panel/__init__.py +++ b/homeassistant/components/alarm_control_panel/__init__.py @@ -141,7 +141,7 @@ def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/alarm_control_panel/simplisafe.py b/homeassistant/components/alarm_control_panel/simplisafe.py index b400a927b5e..47b274875fc 100644 --- a/homeassistant/components/alarm_control_panel/simplisafe.py +++ b/homeassistant/components/alarm_control_panel/simplisafe.py @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): try: simplisafe = SimpliSafeApiInterface(username, password) except SimpliSafeAPIException: - _LOGGER.error("Failed to setup SimpliSafe") + _LOGGER.error("Failed to set up SimpliSafe") return systems = [] diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index 8b1cd3cad84..c6c0af90d15 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -1,5 +1,5 @@ """ -Allow to setup simple automation rules via the config file. +Allow to set up simple automation rules via the config file. For more details about this component, please refer to the documentation at https://home-assistant.io/components/automation/ diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py index 26878044fe2..7b2da21ff6a 100644 --- a/homeassistant/components/binary_sensor/__init__.py +++ b/homeassistant/components/binary_sensor/__init__.py @@ -58,7 +58,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/binary_sensor/hikvision.py b/homeassistant/components/binary_sensor/hikvision.py index de6ad8223d7..78e8f9a973e 100644 --- a/homeassistant/components/binary_sensor/hikvision.py +++ b/homeassistant/components/binary_sensor/hikvision.py @@ -90,7 +90,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): data = HikvisionData(hass, url, port, name, username, password) if data.sensors is None: - _LOGGER.error("Hikvision event stream has no data, unable to setup") + _LOGGER.error("Hikvision event stream has no data, unable to set up") return False entities = [] diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index 6a15510cf54..76860702165 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -145,7 +145,7 @@ async def async_get_image(hass, entity_id, timeout=10): component = hass.data.get(DOMAIN) if component is None: - raise HomeAssistantError('Camera component not setup') + raise HomeAssistantError('Camera component not set up') camera = component.get_entity(entity_id) @@ -214,7 +214,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/cast/.translations/en.json b/homeassistant/components/cast/.translations/en.json index 55d79a7d560..5222e4da3a1 100644 --- a/homeassistant/components/cast/.translations/en.json +++ b/homeassistant/components/cast/.translations/en.json @@ -6,10 +6,10 @@ }, "step": { "confirm": { - "description": "Do you want to setup Google Cast?", + "description": "Do you want to set up Google Cast?", "title": "Google Cast" } }, "title": "Google Cast" } -} \ No newline at end of file +} diff --git a/homeassistant/components/cast/strings.json b/homeassistant/components/cast/strings.json index 7f480de0e8b..eecdecbfdf9 100644 --- a/homeassistant/components/cast/strings.json +++ b/homeassistant/components/cast/strings.json @@ -4,7 +4,7 @@ "step": { "confirm": { "title": "Google Cast", - "description": "Do you want to setup Google Cast?" + "description": "Do you want to set up Google Cast?" } }, "abort": { diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index 90abe2343d2..f33f68b9423 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -294,7 +294,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index eacfe22e818..a0b2b5a23cb 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -105,7 +105,7 @@ async def async_setup_entry(hass, config_entry): @callback def async_add_remote(sensors): - """Setup remote from deCONZ.""" + """Set up remote from deCONZ.""" from pydeconz.sensor import SWITCH as DECONZ_REMOTE allow_clip_sensor = config_entry.data.get(CONF_ALLOW_CLIP_SENSOR, True) for sensor in sensors: diff --git a/homeassistant/components/device_tracker/ritassist.py b/homeassistant/components/device_tracker/ritassist.py index f0973de39bd..c41ae9f2ec2 100644 --- a/homeassistant/components/device_tracker/ritassist.py +++ b/homeassistant/components/device_tracker/ritassist.py @@ -57,7 +57,7 @@ class RitAssistDeviceScanner: config.get(CONF_PASSWORD)) def setup(self, hass): - """Setup a timer and start gathering devices.""" + """Set up a timer and start gathering devices.""" self._refresh() track_utc_time_change(hass, lambda now: self._refresh(), diff --git a/homeassistant/components/homekit/__init__.py b/homeassistant/components/homekit/__init__.py index ad2f8b4ac6d..eac02855b0b 100644 --- a/homeassistant/components/homekit/__init__.py +++ b/homeassistant/components/homekit/__init__.py @@ -57,7 +57,7 @@ CONFIG_SCHEMA = vol.Schema({ async def async_setup(hass, config): - """Setup the HomeKit component.""" + """Set up the HomeKit component.""" _LOGGER.debug('Begin setup HomeKit') conf = config[DOMAIN] @@ -196,7 +196,7 @@ class HomeKit(): self.driver = None def setup(self): - """Setup bridge and accessory driver.""" + """Set up bridge and accessory driver.""" from .accessories import HomeBridge, HomeDriver self.hass.bus.async_listen_once( diff --git a/homeassistant/components/homekit/util.py b/homeassistant/components/homekit/util.py index 23a907d43f7..9d60530edd7 100644 --- a/homeassistant/components/homekit/util.py +++ b/homeassistant/components/homekit/util.py @@ -109,7 +109,7 @@ def show_setup_message(hass, pincode): """Display persistent notification with setup information.""" pin = pincode.decode() _LOGGER.info('Pincode: %s', pin) - message = 'To setup Home Assistant in the Home App, enter the ' \ + message = 'To set up Home Assistant in the Home App, enter the ' \ 'following code:\n### {}'.format(pin) hass.components.persistent_notification.create( message, 'HomeKit Setup', HOMEKIT_NOTIFY_ID) diff --git a/homeassistant/components/http/cors.py b/homeassistant/components/http/cors.py index 555f302f8e1..5698c6048e3 100644 --- a/homeassistant/components/http/cors.py +++ b/homeassistant/components/http/cors.py @@ -1,4 +1,4 @@ -"""Provide cors support for the HTTP component.""" +"""Provide CORS support for the HTTP component.""" from aiohttp.hdrs import ACCEPT, ORIGIN, CONTENT_TYPE @@ -17,7 +17,7 @@ ALLOWED_CORS_HEADERS = [ @callback def setup_cors(app, origins): - """Setup cors.""" + """Set up CORS.""" import aiohttp_cors cors = aiohttp_cors.setup(app, defaults={ @@ -30,7 +30,7 @@ def setup_cors(app, origins): cors_added = set() def _allow_cors(route, config=None): - """Allow cors on a route.""" + """Allow CORS on a route.""" if hasattr(route, 'resource'): path = route.resource else: @@ -55,7 +55,7 @@ def setup_cors(app, origins): return async def cors_startup(app): - """Initialize cors when app starts up.""" + """Initialize CORS when app starts up.""" for route in list(app.router.routes()): _allow_cors(route) diff --git a/homeassistant/components/ihc/__init__.py b/homeassistant/components/ihc/__init__.py index 672964f765e..9b00f3bd789 100644 --- a/homeassistant/components/ihc/__init__.py +++ b/homeassistant/components/ihc/__init__.py @@ -123,7 +123,7 @@ def setup(hass, config): def autosetup_ihc_products(hass: HomeAssistantType, config, ihc_controller): - """Auto setup of IHC products from the ihc project file.""" + """Auto setup of IHC products from the IHC project file.""" project_xml = ihc_controller.get_project() if not project_xml: _LOGGER.error("Unable to read project from ICH controller") @@ -177,7 +177,7 @@ def get_discovery_info(component_setup, groups): def setup_service_functions(hass: HomeAssistantType, ihc_controller): - """Setup the IHC service functions.""" + """Set up the IHC service functions.""" def set_runtime_value_bool(call): """Set a IHC runtime bool value service function.""" ihc_id = call.data[ATTR_IHC_ID] diff --git a/homeassistant/components/ihc/services.yaml b/homeassistant/components/ihc/services.yaml index 7b6053eff89..a0cc6774fdf 100644 --- a/homeassistant/components/ihc/services.yaml +++ b/homeassistant/components/ihc/services.yaml @@ -1,26 +1,26 @@ -# Describes the format for available ihc services +# Describes the format for available IHC services set_runtime_value_bool: - description: Set a boolean runtime value on the ihc controller + description: Set a boolean runtime value on the IHC controller fields: ihc_id: - description: The integer ihc resource id + description: The integer IHC resource id value: description: The boolean value to set set_runtime_value_int: - description: Set an integer runtime value on the ihc controller + description: Set an integer runtime value on the IHC controller fields: ihc_id: - description: The integer ihc resource id + description: The integer IHC resource id value: description: The integer value to set set_runtime_value_float: - description: Set a float runtime value on the ihc controller + description: Set a float runtime value on the IHC controller fields: ihc_id: - description: The integer ihc resource id + description: The integer IHC resource id value: description: The float value to set diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index 456ad6d69be..ddee4108e31 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -382,7 +382,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/light/ihc.py b/homeassistant/components/light/ihc.py index 5a7e85d50dc..aef50b12ad7 100644 --- a/homeassistant/components/light/ihc.py +++ b/homeassistant/components/light/ihc.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the ihc lights platform.""" + """Set up the IHC lights platform.""" ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] info = hass.data[IHC_DATA][IHC_INFO] devices = [] @@ -109,7 +109,7 @@ class IhcLight(IHCDevice, Light): self.ihc_controller.set_runtime_value_bool(self.ihc_id, False) def on_ihc_change(self, ihc_id, value): - """Callback from Ihc notifications.""" + """Callback from IHC notifications.""" if isinstance(value, bool): self._dimmable = False self._state = value != 0 diff --git a/homeassistant/components/light/lw12wifi.py b/homeassistant/components/light/lw12wifi.py index f81d8368f98..5b5a3b6f5c9 100644 --- a/homeassistant/components/light/lw12wifi.py +++ b/homeassistant/components/light/lw12wifi.py @@ -37,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup LW-12 WiFi LED Controller platform.""" + """Set up LW-12 WiFi LED Controller platform.""" import lw12 # Assign configuration variables. diff --git a/homeassistant/components/lock/bmw_connected_drive.py b/homeassistant/components/lock/bmw_connected_drive.py index f4fb6d1fbf0..e48fd1af3c3 100644 --- a/homeassistant/components/lock/bmw_connected_drive.py +++ b/homeassistant/components/lock/bmw_connected_drive.py @@ -17,7 +17,7 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the BMW Connected Drive lock.""" + """Set up the BMW Connected Drive lock.""" accounts = hass.data[BMW_DOMAIN] _LOGGER.debug('Found BMW accounts: %s', ', '.join([a.name for a in accounts])) diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 31c254c0a39..7c49b095c66 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -461,7 +461,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/media_player/channels.py b/homeassistant/components/media_player/channels.py index 6ccc6061703..16c768796c5 100644 --- a/homeassistant/components/media_player/channels.py +++ b/homeassistant/components/media_player/channels.py @@ -56,7 +56,7 @@ REQUIREMENTS = ['pychannels==1.0.0'] def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the Channels platform.""" + """Set up the Channels platform.""" device = ChannelsPlayer( config.get('name'), config.get(CONF_HOST), diff --git a/homeassistant/components/media_player/vizio.py b/homeassistant/components/media_player/vizio.py index 046aecbb92e..40ad0ef209c 100644 --- a/homeassistant/components/media_player/vizio.py +++ b/homeassistant/components/media_player/vizio.py @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device = VizioDevice(host, token, name, volume_step) if device.validate_setup() is False: - _LOGGER.error("Failed to setup Vizio TV platform, " + _LOGGER.error("Failed to set up Vizio TV platform, " "please check if host and API key are correct") return diff --git a/homeassistant/components/mysensors/__init__.py b/homeassistant/components/mysensors/__init__.py index e498539f2f9..7ca9ea9f9ea 100644 --- a/homeassistant/components/mysensors/__init__.py +++ b/homeassistant/components/mysensors/__init__.py @@ -133,7 +133,7 @@ def setup_mysensors_platform( async_add_devices=None): """Set up a MySensors platform.""" # Only act if called via MySensors by discovery event. - # Otherwise gateway is not setup. + # Otherwise gateway is not set up. if not discovery_info: return if device_args is None: diff --git a/homeassistant/components/nest/__init__.py b/homeassistant/components/nest/__init__.py index d25b94bbc17..57111350396 100644 --- a/homeassistant/components/nest/__init__.py +++ b/homeassistant/components/nest/__init__.py @@ -119,7 +119,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup Nest from a config entry.""" + """Set up Nest from a config entry.""" from nest import Nest nest = Nest(access_token=entry.data['tokens']['access_token']) diff --git a/homeassistant/components/sabnzbd.py b/homeassistant/components/sabnzbd.py index b9c75c87c1d..f23831259a5 100644 --- a/homeassistant/components/sabnzbd.py +++ b/homeassistant/components/sabnzbd.py @@ -110,7 +110,7 @@ async def async_configure_sabnzbd(hass, config, use_ssl, name=DEFAULT_NAME, async def async_setup(hass, config): - """Setup the SABnzbd component.""" + """Set up the SABnzbd component.""" async def sabnzbd_discovered(service, info): """Handle service discovery.""" ssl = info.get('properties', {}).get('https', '0') == '1' @@ -129,7 +129,7 @@ async def async_setup(hass, config): @callback def async_setup_sabnzbd(hass, sab_api, config, name): - """Setup SABnzbd sensors and services.""" + """Set up SABnzbd sensors and services.""" sab_api_data = SabnzbdApiData(sab_api, name, config.get(CONF_SENSORS, {})) if config.get(CONF_SENSORS): diff --git a/homeassistant/components/scene/__init__.py b/homeassistant/components/scene/__init__.py index 7b76836555c..8771a84c1d6 100644 --- a/homeassistant/components/scene/__init__.py +++ b/homeassistant/components/scene/__init__.py @@ -95,7 +95,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/sensor/__init__.py b/homeassistant/components/sensor/__init__.py index 8550d175b63..948f844cfd4 100644 --- a/homeassistant/components/sensor/__init__.py +++ b/homeassistant/components/sensor/__init__.py @@ -43,7 +43,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/sensor/cert_expiry.py b/homeassistant/components/sensor/cert_expiry.py index 1ccaf2f6925..00139a30620 100644 --- a/homeassistant/components/sensor/cert_expiry.py +++ b/homeassistant/components/sensor/cert_expiry.py @@ -1,5 +1,5 @@ """ -Counter for the days till a HTTPS (TLS) certificate will expire. +Counter for the days until an HTTPS (TLS) certificate will expire. For more details about this sensor please refer to the documentation at https://home-assistant.io/components/sensor.cert_expiry/ diff --git a/homeassistant/components/sensor/duke_energy.py b/homeassistant/components/sensor/duke_energy.py index 458a2929d0b..17f118e3cb4 100644 --- a/homeassistant/components/sensor/duke_energy.py +++ b/homeassistant/components/sensor/duke_energy.py @@ -28,7 +28,7 @@ LAST_BILL_DAYS_BILLED = "last_bills_days_billed" def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup all Duke Energy meters.""" + """Set up all Duke Energy meters.""" from pydukeenergy.api import DukeEnergy, DukeEnergyException try: @@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): config[CONF_PASSWORD], update_interval=120) except DukeEnergyException: - _LOGGER.error("Failed to setup Duke Energy") + _LOGGER.error("Failed to set up Duke Energy") return add_devices([DukeEnergyMeter(meter) for meter in duke.get_meters()]) diff --git a/homeassistant/components/sensor/fints.py b/homeassistant/components/sensor/fints.py index ef064e84228..b30bdd4a30c 100644 --- a/homeassistant/components/sensor/fints.py +++ b/homeassistant/components/sensor/fints.py @@ -151,7 +151,7 @@ class FinTsClient: class FinTsAccount(Entity): - """Sensor for a FinTS balanc account. + """Sensor for a FinTS balance account. A balance account contains an amount of money (=balance). The amount may also be negative. diff --git a/homeassistant/components/sensor/ihc.py b/homeassistant/components/sensor/ihc.py index 2dcf2c3f7be..7af034c4b93 100644 --- a/homeassistant/components/sensor/ihc.py +++ b/homeassistant/components/sensor/ihc.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the ihc sensor platform.""" + """Set up the IHC sensor platform.""" ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] info = hass.data[IHC_DATA][IHC_INFO] devices = [] @@ -77,6 +77,6 @@ class IHCSensor(IHCDevice, Entity): return self._unit_of_measurement def on_ihc_change(self, ihc_id, value): - """Callback when ihc resource changes.""" + """Callback when IHC resource changes.""" self._state = value self.schedule_update_ha_state() diff --git a/homeassistant/components/sensor/melissa.py b/homeassistant/components/sensor/melissa.py index f67722b0198..634ef4ad810 100644 --- a/homeassistant/components/sensor/melissa.py +++ b/homeassistant/components/sensor/melissa.py @@ -16,7 +16,7 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the melissa sensor platform.""" + """Set up the melissa sensor platform.""" sensors = [] api = hass.data[DATA_MELISSA] devices = api.fetch_devices().values() diff --git a/homeassistant/components/sensor/nut.py b/homeassistant/components/sensor/nut.py index 7126bd89ef9..79ad176e42e 100644 --- a/homeassistant/components/sensor/nut.py +++ b/homeassistant/components/sensor/nut.py @@ -164,7 +164,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): data = PyNUTData(host, port, alias, username, password) if data.status is None: - _LOGGER.error("NUT Sensor has no data, unable to setup") + _LOGGER.error("NUT Sensor has no data, unable to set up") raise PlatformNotReady _LOGGER.debug('NUT Sensors Available: %s', data.status) diff --git a/homeassistant/components/sensor/sht31.py b/homeassistant/components/sensor/sht31.py index 2aeff8e73d8..04b78c283c7 100644 --- a/homeassistant/components/sensor/sht31.py +++ b/homeassistant/components/sensor/sht31.py @@ -47,7 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the sensor platform.""" + """Set up the sensor platform.""" from Adafruit_SHT31 import SHT31 i2c_address = config.get(CONF_I2C_ADDRESS) diff --git a/homeassistant/components/sensor/sigfox.py b/homeassistant/components/sensor/sigfox.py index 408435a9667..191b3f54f35 100644 --- a/homeassistant/components/sensor/sigfox.py +++ b/homeassistant/components/sensor/sigfox.py @@ -77,7 +77,7 @@ class SigfoxAPI: _LOGGER.error( "Unable to login to Sigfox API, error code %s", str( response.status_code)) - raise ValueError('Sigfox component not setup') + raise ValueError('Sigfox component not set up') return True def get_device_types(self): diff --git a/homeassistant/components/sensor/uscis.py b/homeassistant/components/sensor/uscis.py index ed3c9ca8587..167f12f66c0 100644 --- a/homeassistant/components/sensor/uscis.py +++ b/homeassistant/components/sensor/uscis.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setting the platform in HASS and Case Information.""" + """Set up the platform in HASS and Case Information.""" uscis = UscisSensor(config['case_id'], config[CONF_FRIENDLY_NAME]) uscis.update() if uscis.valid_case_id: diff --git a/homeassistant/components/sensor/wirelesstag.py b/homeassistant/components/sensor/wirelesstag.py index ad2115e9bd3..8c3fae6e990 100644 --- a/homeassistant/components/sensor/wirelesstag.py +++ b/homeassistant/components/sensor/wirelesstag.py @@ -1,5 +1,5 @@ """ -Sensor support for Wirelss Sensor Tags platform. +Sensor support for Wireless Sensor Tags platform. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.wirelesstag/ @@ -58,7 +58,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the sensor platform.""" + """Set up the sensor platform.""" platform = hass.data.get(WIRELESSTAG_DOMAIN) sensors = [] tags = platform.tags diff --git a/homeassistant/components/sonos/.translations/en.json b/homeassistant/components/sonos/.translations/en.json index c7aae4302f6..05c9d2fa780 100644 --- a/homeassistant/components/sonos/.translations/en.json +++ b/homeassistant/components/sonos/.translations/en.json @@ -6,10 +6,10 @@ }, "step": { "confirm": { - "description": "Do you want to setup Sonos?", + "description": "Do you want to set up Sonos?", "title": "Sonos" } }, "title": "Sonos" } -} \ No newline at end of file +} diff --git a/homeassistant/components/sonos/strings.json b/homeassistant/components/sonos/strings.json index 4aa68712d59..0422919c1aa 100644 --- a/homeassistant/components/sonos/strings.json +++ b/homeassistant/components/sonos/strings.json @@ -4,7 +4,7 @@ "step": { "confirm": { "title": "Sonos", - "description": "Do you want to setup Sonos?" + "description": "Do you want to set up Sonos?" } }, "abort": { diff --git a/homeassistant/components/switch/__init__.py b/homeassistant/components/switch/__init__.py index 3ca52a91758..c95c752435a 100644 --- a/homeassistant/components/switch/__init__.py +++ b/homeassistant/components/switch/__init__.py @@ -117,7 +117,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Setup a config entry.""" + """Set up a config entry.""" return await hass.data[DOMAIN].async_setup_entry(entry) diff --git a/homeassistant/components/switch/ihc.py b/homeassistant/components/switch/ihc.py index 3f461784693..c2fbeacef59 100644 --- a/homeassistant/components/switch/ihc.py +++ b/homeassistant/components/switch/ihc.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): - """Setup the ihc switch platform.""" + """Set up the IHC switch platform.""" ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] info = hass.data[IHC_DATA][IHC_INFO] devices = [] @@ -70,6 +70,6 @@ class IHCSwitch(IHCDevice, SwitchDevice): self.ihc_controller.set_runtime_value_bool(self.ihc_id, False) def on_ihc_change(self, ihc_id, value): - """Callback when the ihc resource changes.""" + """Callback when the IHC resource changes.""" self._state = value self.schedule_update_ha_state() diff --git a/homeassistant/components/waterfurnace.py b/homeassistant/components/waterfurnace.py index de49b5cd437..e9024131af8 100644 --- a/homeassistant/components/waterfurnace.py +++ b/homeassistant/components/waterfurnace.py @@ -43,7 +43,7 @@ CONFIG_SCHEMA = vol.Schema({ def setup(hass, base_config): - """Setup waterfurnace platform.""" + """Set up waterfurnace platform.""" import waterfurnace.waterfurnace as wf config = base_config.get(DOMAIN) diff --git a/homeassistant/components/wirelesstag.py b/homeassistant/components/wirelesstag.py index 0f8f47f5100..0afd976c9e3 100644 --- a/homeassistant/components/wirelesstag.py +++ b/homeassistant/components/wirelesstag.py @@ -87,7 +87,7 @@ class WirelessTagPlatform: 'content': content, 'disabled': False, 'nat': True}) def install_push_notifications(self, binary_sensors): - """Setup local push notification from tag manager.""" + """Set up local push notification from tag manager.""" _LOGGER.info("Registering local push notifications.") configs = [] diff --git a/homeassistant/components/zone/__init__.py b/homeassistant/components/zone/__init__.py index ee19e00266c..3754bf5edbc 100644 --- a/homeassistant/components/zone/__init__.py +++ b/homeassistant/components/zone/__init__.py @@ -44,7 +44,7 @@ PLATFORM_SCHEMA = vol.Schema({ async def async_setup(hass, config): - """Setup configured zones as well as home assistant zone if necessary.""" + """Set up configured zones as well as home assistant zone if necessary.""" hass.data[DOMAIN] = {} entities = set() zone_entries = configured_zones(hass) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index be665d6b9e6..ad3ed896dd4 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -411,7 +411,7 @@ class ConfigEntries: async def _async_create_flow(self, handler_key, *, context, data): """Create a flow for specified handler. - Handler key is the domain of the component that we want to setup. + Handler key is the domain of the component that we want to set up. """ component = getattr(self.hass.components, handler_key) handler = HANDLERS.get(handler_key) diff --git a/homeassistant/helpers/discovery.py b/homeassistant/helpers/discovery.py index 7d0730a969c..698cee0fcc2 100644 --- a/homeassistant/helpers/discovery.py +++ b/homeassistant/helpers/discovery.py @@ -159,7 +159,7 @@ async def async_load_platform(hass, component, platform, discovered=None, setup_success = await setup.async_setup_component( hass, component, hass_config) - # No need to fire event if we could not setup component + # No need to fire event if we could not set up component if not setup_success: return diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index cf035095a84..1f99c90eb00 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -94,7 +94,7 @@ class EntityComponent: self.hass, self.domain, component_platform_discovered) async def async_setup_entry(self, config_entry): - """Setup a config entry.""" + """Set up a config entry.""" platform_type = config_entry.domain platform = await async_prepare_setup_platform( self.hass, self.config, self.domain, platform_type) diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index dc1e376f471..bda3db7ebd9 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -71,13 +71,13 @@ class EntityPlatform: self.parallel_updates = None async def async_setup(self, platform_config, discovery_info=None): - """Setup the platform from a config file.""" + """Set up the platform from a config file.""" platform = self.platform hass = self.hass @callback def async_create_setup_task(): - """Get task to setup platform.""" + """Get task to set up platform.""" if getattr(platform, 'async_setup_platform', None): return platform.async_setup_platform( hass, platform_config, @@ -93,21 +93,21 @@ class EntityPlatform: await self._async_setup_platform(async_create_setup_task) async def async_setup_entry(self, config_entry): - """Setup the platform from a config entry.""" + """Set up the platform from a config entry.""" # Store it so that we can save config entry ID in entity registry self.config_entry = config_entry platform = self.platform @callback def async_create_setup_task(): - """Get task to setup platform.""" + """Get task to set up platform.""" return platform.async_setup_entry( self.hass, config_entry, self._async_schedule_add_entities) return await self._async_setup_platform(async_create_setup_task) async def _async_setup_platform(self, async_create_setup_task, tries=0): - """Helper to setup a platform via config file or config entry. + """Helper to set up a platform via config file or config entry. async_create_setup_task creates a coroutine that sets up platform. """ diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 31404b978eb..41201264da2 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -64,7 +64,7 @@ async def _async_process_dependencies( if dep in loader.DEPENDENCY_BLACKLIST] if blacklisted: - _LOGGER.error("Unable to setup dependencies of %s: " + _LOGGER.error("Unable to set up dependencies of %s: " "found blacklisted dependencies: %s", name, ', '.join(blacklisted)) return False @@ -81,7 +81,7 @@ async def _async_process_dependencies( in enumerate(results) if not res] if failed: - _LOGGER.error("Unable to setup dependencies of %s. " + _LOGGER.error("Unable to set up dependencies of %s. " "Setup failed for dependencies: %s", name, ', '.join(failed)) @@ -238,7 +238,7 @@ async def async_process_deps_reqs( hass, config, name, module.DEPENDENCIES) # type: ignore if not dep_success: - raise HomeAssistantError("Could not setup all dependencies.") + raise HomeAssistantError("Could not set up all dependencies.") if not hass.config.skip_pip and hasattr(module, 'REQUIREMENTS'): req_success = await requirements.async_process_requirements( diff --git a/tests/components/alarm_control_panel/test_manual.py b/tests/components/alarm_control_panel/test_manual.py index e4b29d43e48..02e528db914 100644 --- a/tests/components/alarm_control_panel/test_manual.py +++ b/tests/components/alarm_control_panel/test_manual.py @@ -22,7 +22,7 @@ class TestAlarmControlPanelManual(unittest.TestCase): """Test the manual alarm module.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/alarm_control_panel/test_manual_mqtt.py b/tests/components/alarm_control_panel/test_manual_mqtt.py index 719352c5419..5b601f089dd 100644 --- a/tests/components/alarm_control_panel/test_manual_mqtt.py +++ b/tests/components/alarm_control_panel/test_manual_mqtt.py @@ -21,7 +21,7 @@ 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.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/alarm_control_panel/test_mqtt.py b/tests/components/alarm_control_panel/test_mqtt.py index dee9b3959ca..ce152a3d7c9 100644 --- a/tests/components/alarm_control_panel/test_mqtt.py +++ b/tests/components/alarm_control_panel/test_mqtt.py @@ -21,7 +21,7 @@ class TestAlarmControlPanelMQTT(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/auth/__init__.py b/tests/components/auth/__init__.py index ce94d1ecbfa..e5eed4fca24 100644 --- a/tests/components/auth/__init__.py +++ b/tests/components/auth/__init__.py @@ -18,7 +18,7 @@ BASE_CONFIG = [{ async def async_setup_auth(hass, aiohttp_client, provider_configs=BASE_CONFIG, setup_api=False): - """Helper to setup authentication and create a HTTP client.""" + """Helper to set up authentication and create an HTTP client.""" hass.auth = await auth.auth_manager_from_config(hass, provider_configs) ensure_auth_manager_loaded(hass.auth) await async_setup_component(hass, 'auth', { diff --git a/tests/components/automation/test_event.py b/tests/components/automation/test_event.py index aea6e517e38..1b1ab440f5d 100644 --- a/tests/components/automation/test_event.py +++ b/tests/components/automation/test_event.py @@ -13,7 +13,7 @@ class TestAutomationEvent(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') self.calls = [] diff --git a/tests/components/automation/test_init.py b/tests/components/automation/test_init.py index b1990fb80aa..c3bd6c224af 100644 --- a/tests/components/automation/test_init.py +++ b/tests/components/automation/test_init.py @@ -22,7 +22,7 @@ class TestAutomation(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.calls = mock_service(self.hass, 'test', 'automation') diff --git a/tests/components/automation/test_litejet.py b/tests/components/automation/test_litejet.py index e6445415490..ca6f7796cfc 100644 --- a/tests/components/automation/test_litejet.py +++ b/tests/components/automation/test_litejet.py @@ -23,7 +23,7 @@ class TestLiteJetTrigger(unittest.TestCase): @mock.patch('pylitejet.LiteJet') def setup_method(self, method, mock_pylitejet): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.start() diff --git a/tests/components/automation/test_mqtt.py b/tests/components/automation/test_mqtt.py index d1eb0d63ee8..f4669e803b6 100644 --- a/tests/components/automation/test_mqtt.py +++ b/tests/components/automation/test_mqtt.py @@ -14,7 +14,7 @@ class TestAutomationMQTT(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') mock_mqtt_component(self.hass) diff --git a/tests/components/automation/test_numeric_state.py b/tests/components/automation/test_numeric_state.py index de453675a57..0d73514f306 100644 --- a/tests/components/automation/test_numeric_state.py +++ b/tests/components/automation/test_numeric_state.py @@ -18,7 +18,7 @@ class TestAutomationNumericState(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') self.calls = [] diff --git a/tests/components/automation/test_state.py b/tests/components/automation/test_state.py index 22c84b88935..6b1a8914aad 100644 --- a/tests/components/automation/test_state.py +++ b/tests/components/automation/test_state.py @@ -19,7 +19,7 @@ class TestAutomationState(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') self.hass.states.set('test.entity', 'hello') diff --git a/tests/components/automation/test_sun.py b/tests/components/automation/test_sun.py index 355d088719f..4556b7cbe45 100644 --- a/tests/components/automation/test_sun.py +++ b/tests/components/automation/test_sun.py @@ -19,7 +19,7 @@ class TestAutomationSun(unittest.TestCase): """Test the sun automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') setup_component(self.hass, sun.DOMAIN, { diff --git a/tests/components/automation/test_template.py b/tests/components/automation/test_template.py index 937fa16988a..5d75a273aea 100644 --- a/tests/components/automation/test_template.py +++ b/tests/components/automation/test_template.py @@ -14,7 +14,7 @@ class TestAutomationTemplate(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') self.hass.states.set('test.entity', 'hello') diff --git a/tests/components/automation/test_time.py b/tests/components/automation/test_time.py index 5d5d5ea29ec..251acfa3431 100644 --- a/tests/components/automation/test_time.py +++ b/tests/components/automation/test_time.py @@ -18,7 +18,7 @@ class TestAutomationTime(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') self.calls = [] diff --git a/tests/components/automation/test_zone.py b/tests/components/automation/test_zone.py index 3dc4b75b8ae..cca1c63e8c1 100644 --- a/tests/components/automation/test_zone.py +++ b/tests/components/automation/test_zone.py @@ -13,7 +13,7 @@ class TestAutomationZone(unittest.TestCase): """Test the event automation.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'group') assert setup_component(self.hass, zone.DOMAIN, { diff --git a/tests/components/binary_sensor/test_command_line.py b/tests/components/binary_sensor/test_command_line.py index 07389c7c8a9..d469fc65e8e 100644 --- a/tests/components/binary_sensor/test_command_line.py +++ b/tests/components/binary_sensor/test_command_line.py @@ -12,7 +12,7 @@ class TestCommandSensorBinarySensor(unittest.TestCase): """Test the Command line Binary sensor.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/binary_sensor/test_ffmpeg.py b/tests/components/binary_sensor/test_ffmpeg.py index da9350008d8..4e6629c0afd 100644 --- a/tests/components/binary_sensor/test_ffmpeg.py +++ b/tests/components/binary_sensor/test_ffmpeg.py @@ -11,7 +11,7 @@ class TestFFmpegNoiseSetup: """Test class for ffmpeg.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.config = { @@ -29,7 +29,7 @@ class TestFFmpegNoiseSetup: self.hass.stop() def test_setup_component(self): - """Setup ffmpeg component.""" + """Set up ffmpeg component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config) @@ -38,7 +38,7 @@ class TestFFmpegNoiseSetup: @patch('haffmpeg.SensorNoise.open_sensor', return_value=mock_coro()) def test_setup_component_start(self, mock_start): - """Setup ffmpeg component.""" + """Set up ffmpeg component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config) @@ -53,7 +53,7 @@ class TestFFmpegNoiseSetup: @patch('haffmpeg.SensorNoise') def test_setup_component_start_callback(self, mock_ffmpeg): - """Setup ffmpeg component.""" + """Set up ffmpeg component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config) @@ -76,7 +76,7 @@ class TestFFmpegMotionSetup: """Test class for ffmpeg.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.config = { @@ -94,7 +94,7 @@ class TestFFmpegMotionSetup: self.hass.stop() def test_setup_component(self): - """Setup ffmpeg component.""" + """Set up ffmpeg component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config) @@ -103,7 +103,7 @@ class TestFFmpegMotionSetup: @patch('haffmpeg.SensorMotion.open_sensor', return_value=mock_coro()) def test_setup_component_start(self, mock_start): - """Setup ffmpeg component.""" + """Set up ffmpeg component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config) @@ -118,7 +118,7 @@ class TestFFmpegMotionSetup: @patch('haffmpeg.SensorMotion') def test_setup_component_start_callback(self, mock_ffmpeg): - """Setup ffmpeg component.""" + """Set up ffmpeg component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config) diff --git a/tests/components/binary_sensor/test_mqtt.py b/tests/components/binary_sensor/test_mqtt.py index 71eba2df950..57050c2cbf5 100644 --- a/tests/components/binary_sensor/test_mqtt.py +++ b/tests/components/binary_sensor/test_mqtt.py @@ -16,7 +16,7 @@ class TestSensorMQTT(unittest.TestCase): """Test the MQTT sensor.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) diff --git a/tests/components/binary_sensor/test_nx584.py b/tests/components/binary_sensor/test_nx584.py index 4d1d85d30fb..117c32203eb 100644 --- a/tests/components/binary_sensor/test_nx584.py +++ b/tests/components/binary_sensor/test_nx584.py @@ -21,7 +21,7 @@ class TestNX584SensorSetup(unittest.TestCase): """Test the NX584 sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self._mock_client = mock.patch.object(nx584_client, 'Client') self._mock_client.start() diff --git a/tests/components/binary_sensor/test_rest.py b/tests/components/binary_sensor/test_rest.py index d0670bf5154..d1c26624452 100644 --- a/tests/components/binary_sensor/test_rest.py +++ b/tests/components/binary_sensor/test_rest.py @@ -19,7 +19,7 @@ class TestRestBinarySensorSetup(unittest.TestCase): """Tests for setting up the REST binary sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): @@ -121,7 +121,7 @@ class TestRestBinarySensor(unittest.TestCase): """Tests for REST binary sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.rest = Mock('RestData') self.rest.update = Mock('RestData.update', diff --git a/tests/components/binary_sensor/test_tcp.py b/tests/components/binary_sensor/test_tcp.py index 8602de84d25..69673f09a46 100644 --- a/tests/components/binary_sensor/test_tcp.py +++ b/tests/components/binary_sensor/test_tcp.py @@ -13,7 +13,7 @@ class TestTCPBinarySensor(unittest.TestCase): """Test the TCP Binary Sensor.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/components/binary_sensor/test_template.py b/tests/components/binary_sensor/test_template.py index 62623a04f3c..eba3a368f56 100644 --- a/tests/components/binary_sensor/test_template.py +++ b/tests/components/binary_sensor/test_template.py @@ -23,7 +23,7 @@ class TestBinarySensorTemplate(unittest.TestCase): # pylint: disable=invalid-name def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/components/binary_sensor/test_workday.py b/tests/components/binary_sensor/test_workday.py index 893745ce3de..5aa5a5dad5c 100644 --- a/tests/components/binary_sensor/test_workday.py +++ b/tests/components/binary_sensor/test_workday.py @@ -16,7 +16,7 @@ class TestWorkdaySetup: """Test class for workday sensor.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # Set valid default config for test @@ -97,7 +97,7 @@ class TestWorkdaySetup: self.hass.stop() def test_setup_component_province(self): - """Setup workday component.""" + """Set up workday component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config_province) @@ -145,7 +145,7 @@ class TestWorkdaySetup: assert entity.state == 'off' def test_setup_component_noprovince(self): - """Setup workday component.""" + """Set up workday component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config_noprovince) @@ -191,7 +191,7 @@ class TestWorkdaySetup: assert entity.state == 'on' def test_setup_component_invalidprovince(self): - """Setup workday component.""" + """Set up workday component.""" with assert_setup_component(1, 'binary_sensor'): setup_component(self.hass, 'binary_sensor', self.config_invalidprovince) diff --git a/tests/components/calendar/test_google.py b/tests/components/calendar/test_google.py index d176cd758b4..e07f7a6306a 100644 --- a/tests/components/calendar/test_google.py +++ b/tests/components/calendar/test_google.py @@ -25,7 +25,7 @@ class TestComponentsGoogleCalendar(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.http = Mock() diff --git a/tests/components/camera/test_init.py b/tests/components/camera/test_init.py index cf902ca1779..053fa6d29dc 100644 --- a/tests/components/camera/test_init.py +++ b/tests/components/camera/test_init.py @@ -34,7 +34,7 @@ class TestSetupCamera: """Test class for setup camera.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -42,7 +42,7 @@ class TestSetupCamera: self.hass.stop() def test_setup_component(self): - """Setup demo platform on camera component.""" + """Set up demo platform on camera component.""" config = { camera.DOMAIN: { 'platform': 'demo' @@ -57,7 +57,7 @@ class TestGetImage: """Test class for camera.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() setup_component( diff --git a/tests/components/camera/test_uvc.py b/tests/components/camera/test_uvc.py index 18292d32a02..328ba5096ea 100644 --- a/tests/components/camera/test_uvc.py +++ b/tests/components/camera/test_uvc.py @@ -17,7 +17,7 @@ class TestUVCSetup(unittest.TestCase): """Test the UVC camera platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): @@ -134,7 +134,7 @@ class TestUVCSetup(unittest.TestCase): @mock.patch.object(uvc, 'UnifiVideoCamera') @mock.patch('uvcclient.nvr.UVCRemote') def setup_nvr_errors_during_indexing(self, error, mock_remote, mock_uvc): - """Setup test for NVR errors during indexing.""" + """Set up test for NVR errors during indexing.""" config = { 'platform': 'uvc', 'nvr': 'foo', @@ -163,7 +163,7 @@ class TestUVCSetup(unittest.TestCase): @mock.patch('uvcclient.nvr.UVCRemote.__init__') def setup_nvr_errors_during_initialization(self, error, mock_remote, mock_uvc): - """Setup test for NVR errors during initialization.""" + """Set up test for NVR errors during initialization.""" config = { 'platform': 'uvc', 'nvr': 'foo', @@ -195,7 +195,7 @@ class TestUVC(unittest.TestCase): """Test class for UVC.""" def setup_method(self, method): - """Setup the mock camera.""" + """Set up the mock camera.""" self.nvr = mock.MagicMock() self.uuid = 'uuid' self.name = 'name' diff --git a/tests/components/climate/test_demo.py b/tests/components/climate/test_demo.py index b2633a75583..0cd6d288536 100644 --- a/tests/components/climate/test_demo.py +++ b/tests/components/climate/test_demo.py @@ -19,7 +19,7 @@ class TestDemoClimate(unittest.TestCase): """Test the demo climate hvac.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.units = METRIC_SYSTEM self.assertTrue(setup_component(self.hass, climate.DOMAIN, { diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 7bc0b0a18e7..59ddb004bec 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -42,7 +42,7 @@ class TestSetupClimateGenericThermostat(unittest.TestCase): """Test the Generic thermostat with custom config.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name @@ -79,7 +79,7 @@ class TestGenericThermostatHeaterSwitching(unittest.TestCase): """ def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.units = METRIC_SYSTEM self.assertTrue(run_coroutine_threadsafe( @@ -142,7 +142,7 @@ class TestGenericThermostatHeaterSwitching(unittest.TestCase): self.hass.states.get(heater_switch).state) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) @@ -152,7 +152,7 @@ class TestClimateGenericThermostat(unittest.TestCase): """Test the Generic thermostat.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.units = METRIC_SYSTEM assert setup_component(self.hass, climate.DOMAIN, {'climate': { @@ -368,13 +368,13 @@ class TestClimateGenericThermostat(unittest.TestCase): self.assertEqual(ENT_SWITCH, call.data['entity_id']) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) def _setup_switch(self, is_on): - """Setup the test switch.""" + """Set up the test switch.""" self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) self.calls = [] @@ -391,7 +391,7 @@ class TestClimateGenericThermostatACMode(unittest.TestCase): """Test the Generic thermostat.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.temperature_unit = TEMP_CELSIUS assert setup_component(self.hass, climate.DOMAIN, {'climate': { @@ -533,13 +533,13 @@ class TestClimateGenericThermostatACMode(unittest.TestCase): self.assertEqual(0, len(self.calls)) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) def _setup_switch(self, is_on): - """Setup the test switch.""" + """Set up the test switch.""" self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) self.calls = [] @@ -556,7 +556,7 @@ class TestClimateGenericThermostatACModeMinCycle(unittest.TestCase): """Test the Generic Thermostat.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.temperature_unit = TEMP_CELSIUS assert setup_component(self.hass, climate.DOMAIN, {'climate': { @@ -627,13 +627,13 @@ class TestClimateGenericThermostatACModeMinCycle(unittest.TestCase): self.assertEqual(ENT_SWITCH, call.data['entity_id']) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) def _setup_switch(self, is_on): - """Setup the test switch.""" + """Set up the test switch.""" self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) self.calls = [] @@ -650,7 +650,7 @@ class TestClimateGenericThermostatMinCycle(unittest.TestCase): """Test the Generic thermostat.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.temperature_unit = TEMP_CELSIUS assert setup_component(self.hass, climate.DOMAIN, {'climate': { @@ -720,13 +720,13 @@ class TestClimateGenericThermostatMinCycle(unittest.TestCase): self.assertEqual(ENT_SWITCH, call.data['entity_id']) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) def _setup_switch(self, is_on): - """Setup the test switch.""" + """Set up the test switch.""" self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) self.calls = [] @@ -743,7 +743,7 @@ class TestClimateGenericThermostatACKeepAlive(unittest.TestCase): """Test the Generic Thermostat.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.temperature_unit = TEMP_CELSIUS assert setup_component(self.hass, climate.DOMAIN, {'climate': { @@ -813,13 +813,13 @@ class TestClimateGenericThermostatACKeepAlive(unittest.TestCase): self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now}) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) def _setup_switch(self, is_on): - """Setup the test switch.""" + """Set up the test switch.""" self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) self.calls = [] @@ -836,7 +836,7 @@ class TestClimateGenericThermostatKeepAlive(unittest.TestCase): """Test the Generic Thermostat.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.temperature_unit = TEMP_CELSIUS assert setup_component(self.hass, climate.DOMAIN, {'climate': { @@ -905,13 +905,13 @@ class TestClimateGenericThermostatKeepAlive(unittest.TestCase): self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now}) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) def _setup_switch(self, is_on): - """Setup the test switch.""" + """Set up the test switch.""" self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) self.calls = [] @@ -999,7 +999,7 @@ class TestClimateGenericThermostatRestoreState(unittest.TestCase): """Test generic thermostat when restore state from HA startup.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.temperature_unit = TEMP_CELSIUS @@ -1048,13 +1048,13 @@ class TestClimateGenericThermostatRestoreState(unittest.TestCase): }}) def _setup_sensor(self, temp, unit=TEMP_CELSIUS): - """Setup the test sensor.""" + """Set up the test sensor.""" self.hass.states.set(ENT_SENSOR, temp, { ATTR_UNIT_OF_MEASUREMENT: unit }) def _setup_switch(self, is_on): - """Setup the test switch.""" + """Set up the test switch.""" self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF) self.calls = [] diff --git a/tests/components/climate/test_mqtt.py b/tests/components/climate/test_mqtt.py index 5db77331cd4..f46a23e4f97 100644 --- a/tests/components/climate/test_mqtt.py +++ b/tests/components/climate/test_mqtt.py @@ -35,7 +35,7 @@ class TestMQTTClimate(unittest.TestCase): """Test the mqtt climate hvac.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) self.hass.config.units = METRIC_SYSTEM diff --git a/tests/components/cover/test_command_line.py b/tests/components/cover/test_command_line.py index b7049d35021..346c3f94683 100644 --- a/tests/components/cover/test_command_line.py +++ b/tests/components/cover/test_command_line.py @@ -17,7 +17,7 @@ class TestCommandCover(unittest.TestCase): """Test the cover command line platform.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.rs = cmd_rs.CommandCover(self.hass, 'foo', 'command_open', 'command_close', diff --git a/tests/components/cover/test_demo.py b/tests/components/cover/test_demo.py index 9d26a6a4f4a..65aa9a9b9ef 100644 --- a/tests/components/cover/test_demo.py +++ b/tests/components/cover/test_demo.py @@ -14,7 +14,7 @@ class TestCoverDemo(unittest.TestCase): """Test the Demo cover.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.assertTrue(setup_component(self.hass, cover.DOMAIN, {'cover': { 'platform': 'demo', diff --git a/tests/components/cover/test_group.py b/tests/components/cover/test_group.py index 288e1c5e047..028845983a0 100644 --- a/tests/components/cover/test_group.py +++ b/tests/components/cover/test_group.py @@ -35,7 +35,7 @@ class TestMultiCover(unittest.TestCase): """Test the group cover platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/cover/test_mqtt.py b/tests/components/cover/test_mqtt.py index aea6398e3ae..ad68c2416ca 100644 --- a/tests/components/cover/test_mqtt.py +++ b/tests/components/cover/test_mqtt.py @@ -15,7 +15,7 @@ class TestCoverMQTT(unittest.TestCase): """Test the MQTT cover.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/cover/test_rfxtrx.py b/tests/components/cover/test_rfxtrx.py index be2c456296b..ab8b8f9a93c 100644 --- a/tests/components/cover/test_rfxtrx.py +++ b/tests/components/cover/test_rfxtrx.py @@ -14,7 +14,7 @@ class TestCoverRfxtrx(unittest.TestCase): """Test the Rfxtrx cover platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component('rfxtrx') diff --git a/tests/components/device_tracker/test_asuswrt.py b/tests/components/device_tracker/test_asuswrt.py index 956b407eeaa..8c5af618288 100644 --- a/tests/components/device_tracker/test_asuswrt.py +++ b/tests/components/device_tracker/test_asuswrt.py @@ -116,7 +116,7 @@ WAKE_DEVICES_NO_IP = { def setup_module(): - """Setup the test module.""" + """Set up the test module.""" global FAKEFILE FAKEFILE = get_test_config_dir('fake_file') with open(FAKEFILE, 'w') as out: @@ -138,7 +138,7 @@ class TestComponentsDeviceTrackerASUSWRT(unittest.TestCase): hass = None def setup_method(self, _): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'zone') @@ -500,7 +500,7 @@ class TestSshConnection(unittest.TestCase): """Testing SshConnection.""" def setUp(self): - """Setup test env.""" + """Set up test env.""" self.connection = SshConnection( 'fake', 'fake', 'fake', 'fake', 'fake') self.connection._connected = True @@ -544,7 +544,7 @@ class TestTelnetConnection(unittest.TestCase): """Testing TelnetConnection.""" def setUp(self): - """Setup test env.""" + """Set up test env.""" self.connection = TelnetConnection( 'fake', 'fake', 'fake', 'fake') self.connection._connected = True diff --git a/tests/components/device_tracker/test_ddwrt.py b/tests/components/device_tracker/test_ddwrt.py index 416b7be4a8a..3e60e1bae46 100644 --- a/tests/components/device_tracker/test_ddwrt.py +++ b/tests/components/device_tracker/test_ddwrt.py @@ -41,7 +41,7 @@ class TestDdwrt(unittest.TestCase): super().run(result) def setup_method(self, _): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'zone') @@ -220,7 +220,7 @@ class TestDdwrt(unittest.TestCase): with requests_mock.Mocker() as mock_request: mock_request.register_uri( 'GET', r'http://%s/Status_Wireless.live.asp' % TEST_HOST, - # First request has to work to setup connection + # First request has to work to set up connection [{'text': load_fixture('Ddwrt_Status_Wireless.txt')}, # Second request to get active devices fails {'text': None}]) diff --git a/tests/components/device_tracker/test_geofency.py b/tests/components/device_tracker/test_geofency.py index a955dd0cc11..d84940d9fbf 100644 --- a/tests/components/device_tracker/test_geofency.py +++ b/tests/components/device_tracker/test_geofency.py @@ -122,7 +122,7 @@ def geofency_client(loop, hass, aiohttp_client): @pytest.fixture(autouse=True) def setup_zones(loop, hass): - """Setup Zone config in HA.""" + """Set up Zone config in HA.""" assert loop.run_until_complete(async_setup_component( hass, zone.DOMAIN, { 'zone': { diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index 0b17b4e0ac8..e9e4650e41a 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -39,7 +39,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.yaml_devices = self.hass.config.path(device_tracker.YAML_DEVICES) diff --git a/tests/components/device_tracker/test_mqtt.py b/tests/components/device_tracker/test_mqtt.py index de7865517a8..8e4d0dc2769 100644 --- a/tests/components/device_tracker/test_mqtt.py +++ b/tests/components/device_tracker/test_mqtt.py @@ -19,7 +19,7 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase): """Test MQTT device tracker platform.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) diff --git a/tests/components/device_tracker/test_mqtt_json.py b/tests/components/device_tracker/test_mqtt_json.py index 8ab6346f19b..41c1d9c0885 100644 --- a/tests/components/device_tracker/test_mqtt_json.py +++ b/tests/components/device_tracker/test_mqtt_json.py @@ -29,7 +29,7 @@ class TestComponentsDeviceTrackerJSONMQTT(unittest.TestCase): """Test JSON MQTT device tracker platform.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) diff --git a/tests/components/device_tracker/test_owntracks.py b/tests/components/device_tracker/test_owntracks.py index 37a3e570b53..8883ea22600 100644 --- a/tests/components/device_tracker/test_owntracks.py +++ b/tests/components/device_tracker/test_owntracks.py @@ -327,7 +327,7 @@ class TestDeviceTrackerOwnTracks(BaseMQTT): # pylint: disable=invalid-name def setup_method(self, _): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) mock_component(self.hass, 'group') @@ -1316,7 +1316,7 @@ class TestDeviceTrackerOwnTrackConfigs(BaseMQTT): # pylint: disable=invalid-name def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) mock_component(self.hass, 'group') diff --git a/tests/components/device_tracker/test_tplink.py b/tests/components/device_tracker/test_tplink.py index 88e38108133..b9f1f5f5e5a 100644 --- a/tests/components/device_tracker/test_tplink.py +++ b/tests/components/device_tracker/test_tplink.py @@ -16,7 +16,7 @@ class TestTplink4DeviceScanner(unittest.TestCase): """Tests for the Tplink4DeviceScanner class.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/device_tracker/test_unifi_direct.py b/tests/components/device_tracker/test_unifi_direct.py index d1ede721142..1f9cbd24f12 100644 --- a/tests/components/device_tracker/test_unifi_direct.py +++ b/tests/components/device_tracker/test_unifi_direct.py @@ -31,7 +31,7 @@ class TestComponentsDeviceTrackerUnifiDirect(unittest.TestCase): 'unifi_direct.UnifiDeviceScanner' def setup_method(self, _): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'zone') diff --git a/tests/components/device_tracker/test_upc_connect.py b/tests/components/device_tracker/test_upc_connect.py index 6294ba3467a..6b38edc3ce9 100644 --- a/tests/components/device_tracker/test_upc_connect.py +++ b/tests/components/device_tracker/test_upc_connect.py @@ -37,7 +37,7 @@ class TestUPCConnect: """Tests for the Ddwrt device tracker platform.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'zone') mock_component(self.hass, 'group') @@ -52,7 +52,7 @@ class TestUPCConnect: 'UPCDeviceScanner.async_scan_devices', return_value=async_scan_devices_mock) def test_setup_platform(self, scan_mock, aioclient_mock): - """Setup a platform.""" + """Set up a platform.""" aioclient_mock.get( "http://{}/common_page/login.html".format(self.host), cookies={'sessionToken': '654321'} @@ -74,7 +74,7 @@ class TestUPCConnect: @patch('homeassistant.components.device_tracker._LOGGER.error') def test_setup_platform_timeout_webservice(self, mock_error, aioclient_mock): - """Setup a platform with api timeout.""" + """Set up a platform with api timeout.""" aioclient_mock.get( "http://{}/common_page/login.html".format(self.host), cookies={'sessionToken': '654321'}, @@ -97,7 +97,7 @@ class TestUPCConnect: @patch('homeassistant.components.device_tracker._LOGGER.error') def test_setup_platform_timeout_loginpage(self, mock_error, aioclient_mock): - """Setup a platform with timeout on loginpage.""" + """Set up a platform with timeout on loginpage.""" aioclient_mock.get( "http://{}/common_page/login.html".format(self.host), exc=asyncio.TimeoutError() @@ -120,7 +120,7 @@ class TestUPCConnect: str(mock_error.call_args_list[-1]) def test_scan_devices(self, aioclient_mock): - """Setup a upc platform and scan device.""" + """Set up a upc platform and scan device.""" aioclient_mock.get( "http://{}/common_page/login.html".format(self.host), cookies={'sessionToken': '654321'} @@ -156,7 +156,7 @@ class TestUPCConnect: '70:EE:50:27:A1:38'] def test_scan_devices_without_session(self, aioclient_mock): - """Setup a upc platform and scan device with no token.""" + """Set up a upc platform and scan device with no token.""" aioclient_mock.get( "http://{}/common_page/login.html".format(self.host), cookies={'sessionToken': '654321'} @@ -197,7 +197,7 @@ class TestUPCConnect: '70:EE:50:27:A1:38'] def test_scan_devices_without_session_wrong_re(self, aioclient_mock): - """Setup a upc platform and scan device with no token and wrong.""" + """Set up a upc platform and scan device with no token and wrong.""" aioclient_mock.get( "http://{}/common_page/login.html".format(self.host), cookies={'sessionToken': '654321'} @@ -237,7 +237,7 @@ class TestUPCConnect: assert mac_list == [] def test_scan_devices_parse_error(self, aioclient_mock): - """Setup a upc platform and scan device with parse error.""" + """Set up a upc platform and scan device with parse error.""" aioclient_mock.get( "http://{}/common_page/login.html".format(self.host), cookies={'sessionToken': '654321'} diff --git a/tests/components/emulated_hue/test_hue_api.py b/tests/components/emulated_hue/test_hue_api.py index c99d273a458..3920a45ddf6 100644 --- a/tests/components/emulated_hue/test_hue_api.py +++ b/tests/components/emulated_hue/test_hue_api.py @@ -26,7 +26,7 @@ JSON_HEADERS = {CONTENT_TYPE: const.CONTENT_TYPE_JSON} @pytest.fixture def hass_hue(loop, hass): - """Setup a Home Assistant instance for these tests.""" + """Set up a Home Assistant instance for these tests.""" # We need to do this to get access to homeassistant/turn_(on,off) loop.run_until_complete( core_components.async_setup(hass, {core.DOMAIN: {}})) diff --git a/tests/components/emulated_hue/test_upnp.py b/tests/components/emulated_hue/test_upnp.py index 8315de34e06..f5377b1812c 100644 --- a/tests/components/emulated_hue/test_upnp.py +++ b/tests/components/emulated_hue/test_upnp.py @@ -50,7 +50,7 @@ class TestEmulatedHue(unittest.TestCase): @classmethod def setUpClass(cls): - """Setup the class.""" + """Set up the class.""" cls.hass = hass = get_test_home_assistant() # We need to do this to get access to homeassistant/turn_(on,off) diff --git a/tests/components/fan/test_dyson.py b/tests/components/fan/test_dyson.py index 2953ea2754b..a935210784b 100644 --- a/tests/components/fan/test_dyson.py +++ b/tests/components/fan/test_dyson.py @@ -68,7 +68,7 @@ class DysonTest(unittest.TestCase): """Dyson Sensor component test class.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/fan/test_mqtt.py b/tests/components/fan/test_mqtt.py index 9060d7b9986..7f69e56218b 100644 --- a/tests/components/fan/test_mqtt.py +++ b/tests/components/fan/test_mqtt.py @@ -13,7 +13,7 @@ class TestMqttFan(unittest.TestCase): """Test the MQTT fan platform.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/fan/test_template.py b/tests/components/fan/test_template.py index 53eb9e8e2d4..e229083069d 100644 --- a/tests/components/fan/test_template.py +++ b/tests/components/fan/test_template.py @@ -33,7 +33,7 @@ class TestTemplateFan: # pylint: disable=invalid-name def setup_method(self, method): - """Setup.""" + """Set up.""" self.hass = get_test_home_assistant() self.calls = [] diff --git a/tests/components/group/test_init.py b/tests/components/group/test_init.py index a5e9bbc0b82..47101dd415a 100644 --- a/tests/components/group/test_init.py +++ b/tests/components/group/test_init.py @@ -19,7 +19,7 @@ class TestComponentsGroup(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name @@ -28,7 +28,7 @@ class TestComponentsGroup(unittest.TestCase): self.hass.stop() def test_setup_group_with_mixed_groupable_states(self): - """Try to setup a group with mixed groupable states.""" + """Try to set up a group with mixed groupable states.""" self.hass.states.set('light.Bowl', STATE_ON) self.hass.states.set('device_tracker.Paulus', STATE_HOME) group.Group.create_group( @@ -41,7 +41,7 @@ class TestComponentsGroup(unittest.TestCase): group.ENTITY_ID_FORMAT.format('person_and_light')).state) def test_setup_group_with_a_non_existing_state(self): - """Try to setup a group with a non existing state.""" + """Try to set up a group with a non existing state.""" self.hass.states.set('light.Bowl', STATE_ON) grp = group.Group.create_group( @@ -62,7 +62,7 @@ class TestComponentsGroup(unittest.TestCase): self.assertEqual(STATE_UNKNOWN, grp.state) def test_setup_empty_group(self): - """Try to setup an empty group.""" + """Try to set up an empty group.""" grp = group.Group.create_group(self.hass, 'nothing', []) self.assertEqual(STATE_UNKNOWN, grp.state) diff --git a/tests/components/http/test_auth.py b/tests/components/http/test_auth.py index 8e7a62e2e9f..e96531c0961 100644 --- a/tests/components/http/test_auth.py +++ b/tests/components/http/test_auth.py @@ -38,7 +38,7 @@ async def mock_handler(request): @pytest.fixture def app(hass): - """Fixture to setup a web.Application.""" + """Fixture to set up a web.Application.""" app = web.Application() app['hass'] = hass app.router.add_get('/', mock_handler) @@ -48,7 +48,7 @@ def app(hass): @pytest.fixture def app2(hass): - """Fixture to setup a web.Application without real_ip middleware.""" + """Fixture to set up a web.Application without real_ip middleware.""" app = web.Application() app['hass'] = hass app.router.add_get('/', mock_handler) diff --git a/tests/components/http/test_cors.py b/tests/components/http/test_cors.py index a510d2b3829..c95146d5cca 100644 --- a/tests/components/http/test_cors.py +++ b/tests/components/http/test_cors.py @@ -49,7 +49,7 @@ async def mock_handler(request): @pytest.fixture def client(loop, aiohttp_client): - """Fixture to setup a web.Application.""" + """Fixture to set up a web.Application.""" app = web.Application() app.router.add_get('/', mock_handler) setup_cors(app, [TRUSTED_ORIGIN]) diff --git a/tests/components/hue/test_init.py b/tests/components/hue/test_init.py index ea656ba8fc6..d12270cd908 100644 --- a/tests/components/hue/test_init.py +++ b/tests/components/hue/test_init.py @@ -8,7 +8,7 @@ from tests.common import mock_coro, MockConfigEntry async def test_setup_with_no_config(hass): - """Test that we do not discover anything or try to setup a bridge.""" + """Test that we do not discover anything or try to set up a bridge.""" with patch.object(hass, 'config_entries') as mock_config_entries, \ patch.object(hue, 'configured_hosts', return_value=[]): assert await async_setup_component(hass, hue.DOMAIN, {}) is True diff --git a/tests/components/image_processing/test_facebox.py b/tests/components/image_processing/test_facebox.py index b1d9fb8bf79..62e47a07c08 100644 --- a/tests/components/image_processing/test_facebox.py +++ b/tests/components/image_processing/test_facebox.py @@ -141,13 +141,13 @@ def test_valid_file_path(): async def test_setup_platform(hass, mock_healthybox): - """Setup platform with one entity.""" + """Set up platform with one entity.""" await async_setup_component(hass, ip.DOMAIN, VALID_CONFIG) assert hass.states.get(VALID_ENTITY_ID) async def test_setup_platform_with_auth(hass, mock_healthybox): - """Setup platform with one entity and auth.""" + """Set up platform with one entity and auth.""" valid_config_auth = VALID_CONFIG.copy() valid_config_auth[ip.DOMAIN][CONF_USERNAME] = MOCK_USERNAME valid_config_auth[ip.DOMAIN][CONF_PASSWORD] = MOCK_PASSWORD @@ -297,7 +297,7 @@ async def test_teach_service( async def test_setup_platform_with_name(hass, mock_healthybox): - """Setup platform with one entity and a name.""" + """Set up platform with one entity and a name.""" named_entity_id = 'image_processing.{}'.format(MOCK_NAME) valid_config_named = VALID_CONFIG.copy() diff --git a/tests/components/image_processing/test_init.py b/tests/components/image_processing/test_init.py index ab2e3be11d6..4240e173b26 100644 --- a/tests/components/image_processing/test_init.py +++ b/tests/components/image_processing/test_init.py @@ -16,7 +16,7 @@ class TestSetupImageProcessing: """Test class for setup image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -24,7 +24,7 @@ class TestSetupImageProcessing: self.hass.stop() def test_setup_component(self): - """Setup demo platform on image_process component.""" + """Set up demo platform on image_process component.""" config = { ip.DOMAIN: { 'platform': 'demo' @@ -35,7 +35,7 @@ class TestSetupImageProcessing: setup_component(self.hass, ip.DOMAIN, config) def test_setup_component_with_service(self): - """Setup demo platform on image_process component test service.""" + """Set up demo platform on image_process component test service.""" config = { ip.DOMAIN: { 'platform': 'demo' @@ -52,7 +52,7 @@ class TestImageProcessing: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() setup_component( @@ -113,7 +113,7 @@ class TestImageProcessingAlpr: """Test class for alpr image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() config = { @@ -149,7 +149,7 @@ class TestImageProcessingAlpr: self.hass.stop() def test_alpr_event_single_call(self, aioclient_mock): - """Setup and scan a picture and test plates from event.""" + """Set up and scan a picture and test plates from event.""" aioclient_mock.get(self.url, content=b'image') ip.scan(self.hass, entity_id='image_processing.demo_alpr') @@ -168,7 +168,7 @@ class TestImageProcessingAlpr: assert event_data[0]['entity_id'] == 'image_processing.demo_alpr' def test_alpr_event_double_call(self, aioclient_mock): - """Setup and scan a picture and test plates from event.""" + """Set up and scan a picture and test plates from event.""" aioclient_mock.get(self.url, content=b'image') ip.scan(self.hass, entity_id='image_processing.demo_alpr') @@ -192,7 +192,7 @@ class TestImageProcessingAlpr: new_callable=PropertyMock(return_value=95)) def test_alpr_event_single_call_confidence(self, confidence_mock, aioclient_mock): - """Setup and scan a picture and test plates from event.""" + """Set up and scan a picture and test plates from event.""" aioclient_mock.get(self.url, content=b'image') ip.scan(self.hass, entity_id='image_processing.demo_alpr') @@ -215,7 +215,7 @@ class TestImageProcessingFace: """Test class for face image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() config = { @@ -251,7 +251,7 @@ class TestImageProcessingFace: self.hass.stop() def test_face_event_call(self, aioclient_mock): - """Setup and scan a picture and test faces from event.""" + """Set up and scan a picture and test faces from event.""" aioclient_mock.get(self.url, content=b'image') ip.scan(self.hass, entity_id='image_processing.demo_face') @@ -276,7 +276,7 @@ class TestImageProcessingFace: 'DemoImageProcessingFace.confidence', new_callable=PropertyMock(return_value=None)) def test_face_event_call_no_confidence(self, mock_config, aioclient_mock): - """Setup and scan a picture and test faces from event.""" + """Set up and scan a picture and test faces from event.""" aioclient_mock.get(self.url, content=b'image') ip.scan(self.hass, entity_id='image_processing.demo_face') diff --git a/tests/components/image_processing/test_microsoft_face_detect.py b/tests/components/image_processing/test_microsoft_face_detect.py index acc2519c9b7..9047c5b8475 100644 --- a/tests/components/image_processing/test_microsoft_face_detect.py +++ b/tests/components/image_processing/test_microsoft_face_detect.py @@ -15,7 +15,7 @@ class TestMicrosoftFaceDetectSetup: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -25,7 +25,7 @@ class TestMicrosoftFaceDetectSetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_setup_platform(self, store_mock): - """Setup platform with one entity.""" + """Set up platform with one entity.""" config = { ip.DOMAIN: { 'platform': 'microsoft_face_detect', @@ -51,7 +51,7 @@ class TestMicrosoftFaceDetectSetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_setup_platform_name(self, store_mock): - """Setup platform with one entity and set name.""" + """Set up platform with one entity and set name.""" config = { ip.DOMAIN: { 'platform': 'microsoft_face_detect', @@ -78,7 +78,7 @@ class TestMicrosoftFaceDetect: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.config = { @@ -108,7 +108,7 @@ class TestMicrosoftFaceDetect: 'MicrosoftFaceDetectEntity.should_poll', new_callable=PropertyMock(return_value=False)) def test_ms_detect_process_image(self, poll_mock, aioclient_mock): - """Setup and scan a picture and test plates from event.""" + """Set up and scan a picture and test plates from event.""" aioclient_mock.get( self.endpoint_url.format("persongroups"), text=load_fixture('microsoft_face_persongroups.json') diff --git a/tests/components/image_processing/test_microsoft_face_identify.py b/tests/components/image_processing/test_microsoft_face_identify.py index 8797f661767..6d3eae38728 100644 --- a/tests/components/image_processing/test_microsoft_face_identify.py +++ b/tests/components/image_processing/test_microsoft_face_identify.py @@ -15,7 +15,7 @@ class TestMicrosoftFaceIdentifySetup: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -25,7 +25,7 @@ class TestMicrosoftFaceIdentifySetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_setup_platform(self, store_mock): - """Setup platform with one entity.""" + """Set up platform with one entity.""" config = { ip.DOMAIN: { 'platform': 'microsoft_face_identify', @@ -51,7 +51,7 @@ class TestMicrosoftFaceIdentifySetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_setup_platform_name(self, store_mock): - """Setup platform with one entity and set name.""" + """Set up platform with one entity and set name.""" config = { ip.DOMAIN: { 'platform': 'microsoft_face_identify', @@ -79,7 +79,7 @@ class TestMicrosoftFaceIdentify: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.config = { @@ -109,7 +109,7 @@ class TestMicrosoftFaceIdentify: 'MicrosoftFaceIdentifyEntity.should_poll', new_callable=PropertyMock(return_value=False)) def test_ms_identify_process_image(self, poll_mock, aioclient_mock): - """Setup and scan a picture and test plates from event.""" + """Set up and scan a picture and test plates from event.""" aioclient_mock.get( self.endpoint_url.format("persongroups"), text=load_fixture('microsoft_face_persongroups.json') diff --git a/tests/components/image_processing/test_openalpr_cloud.py b/tests/components/image_processing/test_openalpr_cloud.py index 65e735a6f7e..2d6015e3fe7 100644 --- a/tests/components/image_processing/test_openalpr_cloud.py +++ b/tests/components/image_processing/test_openalpr_cloud.py @@ -16,7 +16,7 @@ class TestOpenAlprCloudSetup: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -24,7 +24,7 @@ class TestOpenAlprCloudSetup: self.hass.stop() def test_setup_platform(self): - """Setup platform with one entity.""" + """Set up platform with one entity.""" config = { ip.DOMAIN: { 'platform': 'openalpr_cloud', @@ -45,7 +45,7 @@ class TestOpenAlprCloudSetup: assert self.hass.states.get('image_processing.openalpr_demo_camera') def test_setup_platform_name(self): - """Setup platform with one entity and set name.""" + """Set up platform with one entity and set name.""" config = { ip.DOMAIN: { 'platform': 'openalpr_cloud', @@ -67,7 +67,7 @@ class TestOpenAlprCloudSetup: assert self.hass.states.get('image_processing.test_local') def test_setup_platform_without_api_key(self): - """Setup platform with one entity without api_key.""" + """Set up platform with one entity without api_key.""" config = { ip.DOMAIN: { 'platform': 'openalpr_cloud', @@ -85,7 +85,7 @@ class TestOpenAlprCloudSetup: setup_component(self.hass, ip.DOMAIN, config) def test_setup_platform_without_region(self): - """Setup platform with one entity without region.""" + """Set up platform with one entity without region.""" config = { ip.DOMAIN: { 'platform': 'openalpr_cloud', @@ -107,7 +107,7 @@ class TestOpenAlprCloud: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() config = { @@ -151,7 +151,7 @@ class TestOpenAlprCloud: self.hass.stop() def test_openalpr_process_image(self, aioclient_mock): - """Setup and scan a picture and test plates from event.""" + """Set up and scan a picture and test plates from event.""" aioclient_mock.post( OPENALPR_API_URL, params=self.params, text=load_fixture('alpr_cloud.json'), status=200 @@ -179,7 +179,7 @@ class TestOpenAlprCloud: 'image_processing.test_local' def test_openalpr_process_image_api_error(self, aioclient_mock): - """Setup and scan a picture and test api error.""" + """Set up and scan a picture and test api error.""" aioclient_mock.post( OPENALPR_API_URL, params=self.params, text="{'error': 'error message'}", status=400 @@ -195,7 +195,7 @@ class TestOpenAlprCloud: assert len(self.alpr_events) == 0 def test_openalpr_process_image_api_timeout(self, aioclient_mock): - """Setup and scan a picture and test api error.""" + """Set up and scan a picture and test api error.""" aioclient_mock.post( OPENALPR_API_URL, params=self.params, exc=asyncio.TimeoutError() diff --git a/tests/components/image_processing/test_openalpr_local.py b/tests/components/image_processing/test_openalpr_local.py index 38e94166c5a..772d66670a0 100644 --- a/tests/components/image_processing/test_openalpr_local.py +++ b/tests/components/image_processing/test_openalpr_local.py @@ -30,7 +30,7 @@ class TestOpenAlprLocalSetup: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -38,7 +38,7 @@ class TestOpenAlprLocalSetup: self.hass.stop() def test_setup_platform(self): - """Setup platform with one entity.""" + """Set up platform with one entity.""" config = { ip.DOMAIN: { 'platform': 'openalpr_local', @@ -58,7 +58,7 @@ class TestOpenAlprLocalSetup: assert self.hass.states.get('image_processing.openalpr_demo_camera') def test_setup_platform_name(self): - """Setup platform with one entity and set name.""" + """Set up platform with one entity and set name.""" config = { ip.DOMAIN: { 'platform': 'openalpr_local', @@ -79,7 +79,7 @@ class TestOpenAlprLocalSetup: assert self.hass.states.get('image_processing.test_local') def test_setup_platform_without_region(self): - """Setup platform with one entity without region.""" + """Set up platform with one entity without region.""" config = { ip.DOMAIN: { 'platform': 'openalpr_local', @@ -100,7 +100,7 @@ class TestOpenAlprLocal: """Test class for image processing.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() config = { @@ -143,7 +143,7 @@ class TestOpenAlprLocal: @patch('asyncio.create_subprocess_exec', return_value=mock_async_subprocess()) def test_openalpr_process_image(self, popen_mock, aioclient_mock): - """Setup and scan a picture and test plates from event.""" + """Set up and scan a picture and test plates from event.""" aioclient_mock.get(self.url, content=b'image') ip.scan(self.hass, entity_id='image_processing.test_local') diff --git a/tests/components/light/test_demo.py b/tests/components/light/test_demo.py index 8ba6385166b..db575bba5ba 100644 --- a/tests/components/light/test_demo.py +++ b/tests/components/light/test_demo.py @@ -15,7 +15,7 @@ class TestDemoLight(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.assertTrue(setup_component(self.hass, light.DOMAIN, {'light': { 'platform': 'demo', diff --git a/tests/components/light/test_init.py b/tests/components/light/test_init.py index 0f73c5a38c6..66dbadb5c38 100644 --- a/tests/components/light/test_init.py +++ b/tests/components/light/test_init.py @@ -22,7 +22,7 @@ class TestLight(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/light/test_litejet.py b/tests/components/light/test_litejet.py index dd4b4b4a56e..3040c95e0ac 100644 --- a/tests/components/light/test_litejet.py +++ b/tests/components/light/test_litejet.py @@ -21,7 +21,7 @@ class TestLiteJetLight(unittest.TestCase): @mock.patch('pylitejet.LiteJet') def setup_method(self, method, mock_pylitejet): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.start() diff --git a/tests/components/light/test_mochad.py b/tests/components/light/test_mochad.py index 5c82ab06085..68cdffcd999 100644 --- a/tests/components/light/test_mochad.py +++ b/tests/components/light/test_mochad.py @@ -28,7 +28,7 @@ class TestMochadSwitchSetup(unittest.TestCase): THING = 'light' def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): @@ -57,7 +57,7 @@ class TestMochadLight(unittest.TestCase): """Test for mochad light platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() controller_mock = mock.MagicMock() dev_dict = {'address': 'a1', 'name': 'fake_light', @@ -94,7 +94,7 @@ class TestMochadLight256Levels(unittest.TestCase): """Test for mochad light platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() controller_mock = mock.MagicMock() dev_dict = {'address': 'a1', 'name': 'fake_light', @@ -126,7 +126,7 @@ class TestMochadLight64Levels(unittest.TestCase): """Test for mochad light platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() controller_mock = mock.MagicMock() dev_dict = {'address': 'a1', 'name': 'fake_light', diff --git a/tests/components/light/test_mqtt.py b/tests/components/light/test_mqtt.py index 404d60c0a2e..1245411dcc4 100644 --- a/tests/components/light/test_mqtt.py +++ b/tests/components/light/test_mqtt.py @@ -158,7 +158,7 @@ class TestLightMQTT(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/light/test_mqtt_json.py b/tests/components/light/test_mqtt_json.py index f16685b3575..90875285f17 100644 --- a/tests/components/light/test_mqtt_json.py +++ b/tests/components/light/test_mqtt_json.py @@ -107,7 +107,7 @@ class TestLightMQTTJSON(unittest.TestCase): """Test the MQTT JSON light.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/light/test_mqtt_template.py b/tests/components/light/test_mqtt_template.py index 1cf09f2ccb5..8f92d659b9b 100644 --- a/tests/components/light/test_mqtt_template.py +++ b/tests/components/light/test_mqtt_template.py @@ -43,7 +43,7 @@ class TestLightMQTTTemplate(unittest.TestCase): """Test the MQTT Template light.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/light/test_rfxtrx.py b/tests/components/light/test_rfxtrx.py index a1f63e45748..8a8e94ec179 100644 --- a/tests/components/light/test_rfxtrx.py +++ b/tests/components/light/test_rfxtrx.py @@ -14,7 +14,7 @@ class TestLightRfxtrx(unittest.TestCase): """Test the Rfxtrx light platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'rfxtrx') diff --git a/tests/components/light/test_template.py b/tests/components/light/test_template.py index 962760672f1..cc481fabb5c 100644 --- a/tests/components/light/test_template.py +++ b/tests/components/light/test_template.py @@ -20,7 +20,7 @@ class TestTemplateLight: # pylint: disable=invalid-name def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.calls = [] diff --git a/tests/components/lock/test_demo.py b/tests/components/lock/test_demo.py index 1d774248f35..500cc7f9a6a 100644 --- a/tests/components/lock/test_demo.py +++ b/tests/components/lock/test_demo.py @@ -14,7 +14,7 @@ class TestLockDemo(unittest.TestCase): """Test the demo lock.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.assertTrue(setup_component(self.hass, lock.DOMAIN, { 'lock': { diff --git a/tests/components/lock/test_mqtt.py b/tests/components/lock/test_mqtt.py index f87b8f8b74b..4ef8532f39e 100644 --- a/tests/components/lock/test_mqtt.py +++ b/tests/components/lock/test_mqtt.py @@ -13,7 +13,7 @@ class TestLockMQTT(unittest.TestCase): """Test the MQTT lock.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/media_player/test_async_helpers.py b/tests/components/media_player/test_async_helpers.py index 11e324e9132..5908ea02a37 100644 --- a/tests/components/media_player/test_async_helpers.py +++ b/tests/components/media_player/test_async_helpers.py @@ -123,7 +123,7 @@ class TestAsyncMediaPlayer(unittest.TestCase): """Test the media_player module.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.player = AsyncMediaPlayer(self.hass) @@ -176,7 +176,7 @@ class TestSyncMediaPlayer(unittest.TestCase): """Test the media_player module.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.player = SyncMediaPlayer(self.hass) diff --git a/tests/components/media_player/test_cast.py b/tests/components/media_player/test_cast.py index 47be39c68e5..8364d8c96ef 100644 --- a/tests/components/media_player/test_cast.py +++ b/tests/components/media_player/test_cast.py @@ -48,7 +48,7 @@ def get_fake_chromecast_info(host='192.168.178.42', port=8009, async def async_setup_cast(hass, config=None, discovery_info=None): - """Helper to setup the cast platform.""" + """Helper to set up the cast platform.""" if config is None: config = {} add_devices = Mock() @@ -62,7 +62,7 @@ async def async_setup_cast(hass, config=None, discovery_info=None): async def async_setup_cast_internal_discovery(hass, config=None, discovery_info=None): - """Setup the cast platform and the discovery.""" + """Set up the cast platform and the discovery.""" listener = MagicMock(services={}) with patch('pychromecast.start_discovery', @@ -85,7 +85,7 @@ async def async_setup_cast_internal_discovery(hass, config=None, async def async_setup_media_player_cast(hass: HomeAssistantType, info: ChromecastInfo): - """Setup the cast platform with async_setup_component.""" + """Set up the cast platform with async_setup_component.""" chromecast = get_fake_chromecast(info) cast.CastStatusListener = MagicMock() diff --git a/tests/components/media_player/test_demo.py b/tests/components/media_player/test_demo.py index 65ca2eb6a01..121018e7541 100644 --- a/tests/components/media_player/test_demo.py +++ b/tests/components/media_player/test_demo.py @@ -25,7 +25,7 @@ class TestDemoMediaPlayer(unittest.TestCase): """Test the media_player module.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): @@ -227,7 +227,7 @@ class TestMediaPlayerWeb(unittest.TestCase): """Test the media player web views sensor.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() assert setup_component(self.hass, http.DOMAIN, { diff --git a/tests/components/media_player/test_sonos.py b/tests/components/media_player/test_sonos.py index 7d0d675f66f..cd2ce2b9707 100644 --- a/tests/components/media_player/test_sonos.py +++ b/tests/components/media_player/test_sonos.py @@ -135,7 +135,7 @@ class TestSonosMediaPlayer(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def monkey_available(self): diff --git a/tests/components/media_player/test_soundtouch.py b/tests/components/media_player/test_soundtouch.py index 2da2622e08a..62356e6afca 100644 --- a/tests/components/media_player/test_soundtouch.py +++ b/tests/components/media_player/test_soundtouch.py @@ -148,7 +148,7 @@ class TestSoundtouchMediaPlayer(unittest.TestCase): """Bose Soundtouch test class.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() logging.disable(logging.CRITICAL) diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index c9a1cdc79d8..ab8e316422a 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -158,7 +158,7 @@ class TestMediaPlayer(unittest.TestCase): """Test the media_player module.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_mp_1 = MockMediaPlayer(self.hass, 'mock1') diff --git a/tests/components/media_player/test_yamaha.py b/tests/components/media_player/test_yamaha.py index 980284737a2..a55429c0c7b 100644 --- a/tests/components/media_player/test_yamaha.py +++ b/tests/components/media_player/test_yamaha.py @@ -33,7 +33,7 @@ class TestYamahaMediaPlayer(unittest.TestCase): """Test the Yamaha media player.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.main_zone = _create_zone_mock('Main zone', 'http://main') self.device = FakeYamahaDevice( diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 05c5de71b8c..89836c34f22 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -45,7 +45,7 @@ class TestMQTTComponent(unittest.TestCase): """Test the MQTT component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) self.calls = [] @@ -188,7 +188,7 @@ class TestMQTTCallbacks(unittest.TestCase): """Test the MQTT callbacks.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_client(self.hass) self.calls = [] diff --git a/tests/components/mqtt/test_server.py b/tests/components/mqtt/test_server.py index d5d54f457d6..c761c47542f 100644 --- a/tests/components/mqtt/test_server.py +++ b/tests/components/mqtt/test_server.py @@ -18,7 +18,7 @@ class TestMQTT: """Test the MQTT component.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): @@ -33,7 +33,7 @@ class TestMQTT: def test_creating_config_with_http_pass_only(self, mock_mqtt): """Test if the MQTT server failed starts. - Since 0.77, MQTT server has to setup its own password. + Since 0.77, MQTT server has to set up its own password. If user has api_password but don't have mqtt.password, MQTT component will fail to start """ @@ -51,7 +51,7 @@ class TestMQTT: def test_creating_config_with_pass_and_no_http_pass(self, mock_mqtt): """Test if the MQTT server gets started with password. - Since 0.77, MQTT server has to setup its own password. + Since 0.77, MQTT server has to set up its own password. """ mock_mqtt().async_connect.return_value = mock_coro(True) self.hass.bus.listen_once = MagicMock() @@ -74,7 +74,7 @@ class TestMQTT: def test_creating_config_with_pass_and_http_pass(self, mock_mqtt): """Test if the MQTT server gets started with password. - Since 0.77, MQTT server has to setup its own password. + Since 0.77, MQTT server has to set up its own password. """ mock_mqtt().async_connect.return_value = mock_coro(True) self.hass.bus.listen_once = MagicMock() diff --git a/tests/components/notify/test_apns.py b/tests/components/notify/test_apns.py index 0bd0333a6fb..dc120dc4ff6 100644 --- a/tests/components/notify/test_apns.py +++ b/tests/components/notify/test_apns.py @@ -28,7 +28,7 @@ class TestApns(unittest.TestCase): """Test the APNS component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/notify/test_command_line.py b/tests/components/notify/test_command_line.py index 2575e1418f4..57933063ba1 100644 --- a/tests/components/notify/test_command_line.py +++ b/tests/components/notify/test_command_line.py @@ -13,7 +13,7 @@ class TestCommandLine(unittest.TestCase): """Test the command line notifications.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/notify/test_demo.py b/tests/components/notify/test_demo.py index 71b472afe74..f98fa258186 100644 --- a/tests/components/notify/test_demo.py +++ b/tests/components/notify/test_demo.py @@ -20,7 +20,7 @@ class TestNotifyDemo(unittest.TestCase): """Test the demo notify.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.events = [] self.calls = [] diff --git a/tests/components/notify/test_file.py b/tests/components/notify/test_file.py index d59bbe4d720..fb4ab42e97b 100644 --- a/tests/components/notify/test_file.py +++ b/tests/components/notify/test_file.py @@ -16,7 +16,7 @@ class TestNotifyFile(unittest.TestCase): """Test the file notify.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/notify/test_group.py b/tests/components/notify/test_group.py index 8e7ef4348f7..bbd7c11ffeb 100644 --- a/tests/components/notify/test_group.py +++ b/tests/components/notify/test_group.py @@ -14,7 +14,7 @@ class TestNotifyGroup(unittest.TestCase): """Test the notify.group platform.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.events = [] self.service1 = demo.DemoNotificationService(self.hass) diff --git a/tests/components/notify/test_smtp.py b/tests/components/notify/test_smtp.py index 29e34974c6c..fca0e3c79e3 100644 --- a/tests/components/notify/test_smtp.py +++ b/tests/components/notify/test_smtp.py @@ -19,7 +19,7 @@ class TestNotifySmtp(unittest.TestCase): """Test the smtp notify.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mailer = MockSMTP('localhost', 25, 5, 'test@test.com', 1, 'testuser', 'testpass', diff --git a/tests/components/persistent_notification/test_init.py b/tests/components/persistent_notification/test_init.py index df780675a18..a609247b839 100644 --- a/tests/components/persistent_notification/test_init.py +++ b/tests/components/persistent_notification/test_init.py @@ -9,7 +9,7 @@ class TestPersistentNotification: """Test persistent notification component.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() setup_component(self.hass, pn.DOMAIN, {}) diff --git a/tests/components/recorder/test_init.py b/tests/components/recorder/test_init.py index 191c0d6e733..7460a65b0ce 100644 --- a/tests/components/recorder/test_init.py +++ b/tests/components/recorder/test_init.py @@ -19,7 +19,7 @@ class TestRecorder(unittest.TestCase): """Test the recorder module.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() init_recorder_component(self.hass) self.hass.start() @@ -92,7 +92,7 @@ def hass_recorder(): hass = get_test_home_assistant() def setup_recorder(config=None): - """Setup with params.""" + """Set up with params.""" init_recorder_component(hass, config) hass.start() hass.block_till_done() diff --git a/tests/components/recorder/test_purge.py b/tests/components/recorder/test_purge.py index 91aa69b4484..f33236f0ceb 100644 --- a/tests/components/recorder/test_purge.py +++ b/tests/components/recorder/test_purge.py @@ -16,7 +16,7 @@ class TestRecorderPurge(unittest.TestCase): """Base class for common recorder tests.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() init_recorder_component(self.hass) self.hass.start() diff --git a/tests/components/recorder/test_util.py b/tests/components/recorder/test_util.py index ad130b1ca91..83d109fcfc5 100644 --- a/tests/components/recorder/test_util.py +++ b/tests/components/recorder/test_util.py @@ -14,7 +14,7 @@ def hass_recorder(): hass = get_test_home_assistant() def setup_recorder(config=None): - """Setup with params.""" + """Set up with params.""" init_recorder_component(hass, config) hass.start() hass.block_till_done() diff --git a/tests/components/remote/test_demo.py b/tests/components/remote/test_demo.py index ed9968c2d10..a0290987ff2 100644 --- a/tests/components/remote/test_demo.py +++ b/tests/components/remote/test_demo.py @@ -15,7 +15,7 @@ class TestDemoRemote(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.assertTrue(setup_component(self.hass, remote.DOMAIN, {'remote': { 'platform': 'demo', diff --git a/tests/components/remote/test_init.py b/tests/components/remote/test_init.py index b4d2ff98688..d98ec941f8b 100644 --- a/tests/components/remote/test_init.py +++ b/tests/components/remote/test_init.py @@ -19,7 +19,7 @@ class TestRemote(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/scene/test_init.py b/tests/components/scene/test_init.py index a832e249832..3298d7648d9 100644 --- a/tests/components/scene/test_init.py +++ b/tests/components/scene/test_init.py @@ -14,7 +14,7 @@ class TestScene(unittest.TestCase): """Test the scene component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() test_light = loader.get_component(self.hass, 'light.test') test_light.init() diff --git a/tests/components/scene/test_litejet.py b/tests/components/scene/test_litejet.py index 37a9aa5b2b5..864ffc41735 100644 --- a/tests/components/scene/test_litejet.py +++ b/tests/components/scene/test_litejet.py @@ -21,7 +21,7 @@ class TestLiteJetScene(unittest.TestCase): @mock.patch('pylitejet.LiteJet') def setup_method(self, method, mock_pylitejet): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.start() diff --git a/tests/components/sensor/test_command_line.py b/tests/components/sensor/test_command_line.py index 808f8cff6a1..82cdef014b9 100644 --- a/tests/components/sensor/test_command_line.py +++ b/tests/components/sensor/test_command_line.py @@ -11,7 +11,7 @@ class TestCommandSensorSensor(unittest.TestCase): """Test the Command line sensor.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/sensor/test_dyson.py b/tests/components/sensor/test_dyson.py index dcbafcae6e3..cc32872e6f0 100644 --- a/tests/components/sensor/test_dyson.py +++ b/tests/components/sensor/test_dyson.py @@ -52,7 +52,7 @@ class DysonTest(unittest.TestCase): """Dyson Sensor component test class.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/sensor/test_filter.py b/tests/components/sensor/test_filter.py index cf2cc9c4205..b0683b04aa0 100644 --- a/tests/components/sensor/test_filter.py +++ b/tests/components/sensor/test_filter.py @@ -17,7 +17,7 @@ class TestFilterSensor(unittest.TestCase): """Test the Data Filter sensor.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() raw_values = [20, 19, 18, 21, 22, 0] self.values = [] diff --git a/tests/components/sensor/test_google_wifi.py b/tests/components/sensor/test_google_wifi.py index 1004c20b314..55afedab536 100644 --- a/tests/components/sensor/test_google_wifi.py +++ b/tests/components/sensor/test_google_wifi.py @@ -36,7 +36,7 @@ class TestGoogleWifiSetup(unittest.TestCase): """Tests for setting up the Google Wifi sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): @@ -83,7 +83,7 @@ class TestGoogleWifiSensor(unittest.TestCase): """Tests for Google Wifi sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up 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) @@ -93,7 +93,7 @@ class TestGoogleWifiSensor(unittest.TestCase): self.hass.stop() def setup_api(self, data, mock_req): - """Setup API with fake data.""" + """Set up API with fake data.""" resource = '{}{}{}'.format( 'http://', 'localhost', google_wifi.ENDPOINT) now = datetime(1970, month=1, day=1) diff --git a/tests/components/sensor/test_imap_email_content.py b/tests/components/sensor/test_imap_email_content.py index cd5c079a431..a07d94e3dcd 100644 --- a/tests/components/sensor/test_imap_email_content.py +++ b/tests/components/sensor/test_imap_email_content.py @@ -17,7 +17,7 @@ class FakeEMailReader: """A test class for sending test emails.""" def __init__(self, messages): - """Setup the fake email reader.""" + """Set up the fake email reader.""" self._messages = messages def connect(self): @@ -35,7 +35,7 @@ class EmailContentSensor(unittest.TestCase): """Test the IMAP email content sensor.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/sensor/test_mfi.py b/tests/components/sensor/test_mfi.py index ae967449ef2..a10246ad777 100644 --- a/tests/components/sensor/test_mfi.py +++ b/tests/components/sensor/test_mfi.py @@ -31,7 +31,7 @@ class TestMfiSensorSetup(unittest.TestCase): } def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): @@ -131,7 +131,7 @@ class TestMfiSensor(unittest.TestCase): """Test for mFi sensor platform.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.port = mock.MagicMock() self.sensor = mfi.MfiSensor(self.port, self.hass) diff --git a/tests/components/sensor/test_mhz19.py b/tests/components/sensor/test_mhz19.py index 6d071489691..421035995dc 100644 --- a/tests/components/sensor/test_mhz19.py +++ b/tests/components/sensor/test_mhz19.py @@ -15,7 +15,7 @@ class TestMHZ19Sensor(unittest.TestCase): hass = None def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/components/sensor/test_moldindicator.py b/tests/components/sensor/test_moldindicator.py index 32cd0206dec..4f1b40bf9ef 100644 --- a/tests/components/sensor/test_moldindicator.py +++ b/tests/components/sensor/test_moldindicator.py @@ -15,7 +15,7 @@ class TestSensorMoldIndicator(unittest.TestCase): """Test the MoldIndicator sensor.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.states.set('test.indoortemp', '20', {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) diff --git a/tests/components/sensor/test_mqtt.py b/tests/components/sensor/test_mqtt.py index 234afff3418..feef647b7b7 100644 --- a/tests/components/sensor/test_mqtt.py +++ b/tests/components/sensor/test_mqtt.py @@ -20,7 +20,7 @@ class TestSensorMQTT(unittest.TestCase): """Test the MQTT sensor.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) diff --git a/tests/components/sensor/test_mqtt_room.py b/tests/components/sensor/test_mqtt_room.py index c79017338e1..88fa611b2a6 100644 --- a/tests/components/sensor/test_mqtt_room.py +++ b/tests/components/sensor/test_mqtt_room.py @@ -50,7 +50,7 @@ class TestMQTTRoomSensor(unittest.TestCase): """Test the room presence sensor.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_mqtt_component(self.hass) self.assertTrue(setup_component(self.hass, sensor.DOMAIN, { diff --git a/tests/components/sensor/test_rest.py b/tests/components/sensor/test_rest.py index f2362867979..4d40ad394cd 100644 --- a/tests/components/sensor/test_rest.py +++ b/tests/components/sensor/test_rest.py @@ -19,7 +19,7 @@ class TestRestSensorSetup(unittest.TestCase): """Tests for setting up the REST sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): @@ -121,7 +121,7 @@ class TestRestSensor(unittest.TestCase): """Tests for REST sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.initial_state = 'initial_state' self.rest = Mock('rest.RestData') @@ -267,7 +267,7 @@ class TestRestData(unittest.TestCase): """Tests for RestData.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.method = "GET" self.resource = "http://localhost" self.verify_ssl = True diff --git a/tests/components/sensor/test_rfxtrx.py b/tests/components/sensor/test_rfxtrx.py index e049eabbe56..3f577127a11 100644 --- a/tests/components/sensor/test_rfxtrx.py +++ b/tests/components/sensor/test_rfxtrx.py @@ -15,7 +15,7 @@ class TestSensorRfxtrx(unittest.TestCase): """Test the Rfxtrx sensor platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'rfxtrx') diff --git a/tests/components/sensor/test_season.py b/tests/components/sensor/test_season.py index 5c071982f7f..4c82399648e 100644 --- a/tests/components/sensor/test_season.py +++ b/tests/components/sensor/test_season.py @@ -66,7 +66,7 @@ class TestSeason(unittest.TestCase): self.DEVICE = device def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/sensor/test_statistics.py b/tests/components/sensor/test_statistics.py index 48ebf720633..466b89cc0d1 100644 --- a/tests/components/sensor/test_statistics.py +++ b/tests/components/sensor/test_statistics.py @@ -17,7 +17,7 @@ class TestStatisticsSensor(unittest.TestCase): """Test the Statistics sensor.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.values = [17, 20, 15.2, 5, 3.8, 9.2, 6.7, 14, 6] self.count = len(self.values) diff --git a/tests/components/sensor/test_tcp.py b/tests/components/sensor/test_tcp.py index 4c1e976ea51..cbc097955c8 100644 --- a/tests/components/sensor/test_tcp.py +++ b/tests/components/sensor/test_tcp.py @@ -39,7 +39,7 @@ class TestTCPSensor(unittest.TestCase): """Test the TCP Sensor.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/components/sensor/test_template.py b/tests/components/sensor/test_template.py index 6861d3a5070..2211f092d7b 100644 --- a/tests/components/sensor/test_template.py +++ b/tests/components/sensor/test_template.py @@ -11,7 +11,7 @@ class TestTemplateSensor: # pylint: disable=invalid-name def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/components/sensor/test_yweather.py b/tests/components/sensor/test_yweather.py index aeee47bfa80..8b3361a4360 100644 --- a/tests/components/sensor/test_yweather.py +++ b/tests/components/sensor/test_yweather.py @@ -129,7 +129,7 @@ class TestWeather(unittest.TestCase): """Test the Yahoo weather component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/switch/test_command_line.py b/tests/components/switch/test_command_line.py index 40f999fa43b..9ec0507627d 100644 --- a/tests/components/switch/test_command_line.py +++ b/tests/components/switch/test_command_line.py @@ -17,7 +17,7 @@ class TestCommandSwitch(unittest.TestCase): """Test the command switch.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/switch/test_flux.py b/tests/components/switch/test_flux.py index 155ed85dac2..f9ea88c5254 100644 --- a/tests/components/switch/test_flux.py +++ b/tests/components/switch/test_flux.py @@ -17,7 +17,7 @@ class TestSwitchFlux(unittest.TestCase): """Test the Flux switch platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/switch/test_init.py b/tests/components/switch/test_init.py index 55e44299294..579898437ca 100644 --- a/tests/components/switch/test_init.py +++ b/tests/components/switch/test_init.py @@ -15,7 +15,7 @@ class TestSwitch(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() platform = loader.get_component(self.hass, 'switch.test') platform.init() diff --git a/tests/components/switch/test_litejet.py b/tests/components/switch/test_litejet.py index e0d6e290def..45e5509c169 100644 --- a/tests/components/switch/test_litejet.py +++ b/tests/components/switch/test_litejet.py @@ -21,7 +21,7 @@ class TestLiteJetSwitch(unittest.TestCase): @mock.patch('pylitejet.LiteJet') def setup_method(self, method, mock_pylitejet): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.start() diff --git a/tests/components/switch/test_mfi.py b/tests/components/switch/test_mfi.py index ae3edec2102..d2bf3c57ab6 100644 --- a/tests/components/switch/test_mfi.py +++ b/tests/components/switch/test_mfi.py @@ -49,7 +49,7 @@ class TestMfiSwitch(unittest.TestCase): """Test for mFi switch platform.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.port = mock.MagicMock() self.switch = mfi.MfiSwitch(self.port) diff --git a/tests/components/switch/test_mochad.py b/tests/components/switch/test_mochad.py index a5e6e2c9ae6..f241a4b9f61 100644 --- a/tests/components/switch/test_mochad.py +++ b/tests/components/switch/test_mochad.py @@ -29,7 +29,7 @@ class TestMochadSwitchSetup(unittest.TestCase): THING = 'switch' def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): @@ -58,7 +58,7 @@ class TestMochadSwitch(unittest.TestCase): """Test for mochad switch platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() controller_mock = mock.MagicMock() dev_dict = {'address': 'a1', 'name': 'fake_switch'} diff --git a/tests/components/switch/test_mqtt.py b/tests/components/switch/test_mqtt.py index 7cd5a42b4a3..c9bfd02156f 100644 --- a/tests/components/switch/test_mqtt.py +++ b/tests/components/switch/test_mqtt.py @@ -15,7 +15,7 @@ class TestSwitchMQTT(unittest.TestCase): """Test the MQTT switch.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_publish = mock_mqtt_component(self.hass) diff --git a/tests/components/switch/test_rest.py b/tests/components/switch/test_rest.py index e3f11ec19a0..cb27ab40855 100644 --- a/tests/components/switch/test_rest.py +++ b/tests/components/switch/test_rest.py @@ -14,7 +14,7 @@ class TestRestSwitchSetup: """Tests for setting up the REST switch platform.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -95,7 +95,7 @@ class TestRestSwitch: """Tests for REST switch platform.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.name = 'foo' self.method = 'post' diff --git a/tests/components/switch/test_rfxtrx.py b/tests/components/switch/test_rfxtrx.py index 938093aa95b..ae242a1dafb 100644 --- a/tests/components/switch/test_rfxtrx.py +++ b/tests/components/switch/test_rfxtrx.py @@ -14,7 +14,7 @@ class TestSwitchRfxtrx(unittest.TestCase): """Test the Rfxtrx switch platform.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() mock_component(self.hass, 'rfxtrx') diff --git a/tests/components/switch/test_template.py b/tests/components/switch/test_template.py index 8f7bbda8e98..47766e31f4d 100644 --- a/tests/components/switch/test_template.py +++ b/tests/components/switch/test_template.py @@ -16,7 +16,7 @@ class TestTemplateSwitch: # pylint: disable=invalid-name def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.calls = [] diff --git a/tests/components/switch/test_wake_on_lan.py b/tests/components/switch/test_wake_on_lan.py index 167c3bb35ac..abe1532cec7 100644 --- a/tests/components/switch/test_wake_on_lan.py +++ b/tests/components/switch/test_wake_on_lan.py @@ -33,7 +33,7 @@ class TestWOLSwitch(unittest.TestCase): """Test the wol switch.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/test_alert.py b/tests/components/test_alert.py index d9eb33be37d..90d732ac38e 100644 --- a/tests/components/test_alert.py +++ b/tests/components/test_alert.py @@ -36,7 +36,7 @@ class TestAlert(unittest.TestCase): """Test the alert module.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/test_configurator.py b/tests/components/test_configurator.py index 809c02548dc..22f0d6646aa 100644 --- a/tests/components/test_configurator.py +++ b/tests/components/test_configurator.py @@ -13,7 +13,7 @@ class TestConfigurator(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/test_datadog.py b/tests/components/test_datadog.py index f1820c4d250..f9724989f97 100644 --- a/tests/components/test_datadog.py +++ b/tests/components/test_datadog.py @@ -20,7 +20,7 @@ class TestDatadog(unittest.TestCase): """Test the Datadog component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_device_sun_light_trigger.py b/tests/components/test_device_sun_light_trigger.py index 774185c51c1..35d53f9a5c8 100644 --- a/tests/components/test_device_sun_light_trigger.py +++ b/tests/components/test_device_sun_light_trigger.py @@ -18,7 +18,7 @@ class TestDeviceSunLightTrigger(unittest.TestCase): """Test the device sun light trigger module.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.scanner = loader.get_component( diff --git a/tests/components/test_dyson.py b/tests/components/test_dyson.py index 38f3e60dcf4..19c39754eb2 100644 --- a/tests/components/test_dyson.py +++ b/tests/components/test_dyson.py @@ -36,7 +36,7 @@ class DysonTest(unittest.TestCase): """Dyson parent component test class.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_ffmpeg.py b/tests/components/test_ffmpeg.py index 44c3a1dd695..76b1300774b 100644 --- a/tests/components/test_ffmpeg.py +++ b/tests/components/test_ffmpeg.py @@ -42,7 +42,7 @@ class TestFFmpegSetup: """Test class for ffmpeg.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self): @@ -50,14 +50,14 @@ class TestFFmpegSetup: self.hass.stop() def test_setup_component(self): - """Setup ffmpeg component.""" + """Set up ffmpeg component.""" with assert_setup_component(2): setup_component(self.hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) assert self.hass.data[ffmpeg.DATA_FFMPEG].binary == 'ffmpeg' def test_setup_component_test_service(self): - """Setup ffmpeg component test services.""" + """Set up ffmpeg component test services.""" with assert_setup_component(2): setup_component(self.hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -68,7 +68,7 @@ class TestFFmpegSetup: @asyncio.coroutine def test_setup_component_test_register(hass): - """Setup ffmpeg component test register.""" + """Set up ffmpeg component test register.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -83,7 +83,7 @@ def test_setup_component_test_register(hass): @asyncio.coroutine def test_setup_component_test_register_no_startup(hass): - """Setup ffmpeg component test register without startup.""" + """Set up ffmpeg component test register without startup.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -98,7 +98,7 @@ def test_setup_component_test_register_no_startup(hass): @asyncio.coroutine def test_setup_component_test_service_start(hass): - """Setup ffmpeg component test service start.""" + """Set up ffmpeg component test service start.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -114,7 +114,7 @@ def test_setup_component_test_service_start(hass): @asyncio.coroutine def test_setup_component_test_service_stop(hass): - """Setup ffmpeg component test service stop.""" + """Set up ffmpeg component test service stop.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -130,7 +130,7 @@ def test_setup_component_test_service_stop(hass): @asyncio.coroutine def test_setup_component_test_service_restart(hass): - """Setup ffmpeg component test service restart.""" + """Set up ffmpeg component test service restart.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -147,7 +147,7 @@ def test_setup_component_test_service_restart(hass): @asyncio.coroutine def test_setup_component_test_service_start_with_entity(hass): - """Setup ffmpeg component test service start.""" + """Set up ffmpeg component test service start.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -164,7 +164,7 @@ def test_setup_component_test_service_start_with_entity(hass): @asyncio.coroutine def test_setup_component_test_run_test_false(hass): - """Setup ffmpeg component test run_test false.""" + """Set up ffmpeg component test run_test false.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: { @@ -180,7 +180,7 @@ def test_setup_component_test_run_test_false(hass): @asyncio.coroutine def test_setup_component_test_run_test(hass): - """Setup ffmpeg component test run_test.""" + """Set up ffmpeg component test run_test.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) @@ -206,7 +206,7 @@ def test_setup_component_test_run_test(hass): @asyncio.coroutine def test_setup_component_test_run_test_test_fail(hass): - """Setup ffmpeg component test run_test.""" + """Set up ffmpeg component test run_test.""" with assert_setup_component(2): yield from async_setup_component( hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) diff --git a/tests/components/test_folder_watcher.py b/tests/components/test_folder_watcher.py index b5ac9cca9d9..451d9ae3e0e 100644 --- a/tests/components/test_folder_watcher.py +++ b/tests/components/test_folder_watcher.py @@ -8,7 +8,7 @@ from tests.common import MockDependency async def test_invalid_path_setup(hass): - """Test that an invalid path is not setup.""" + """Test that an invalid path is not set up.""" assert not await async_setup_component( hass, folder_watcher.DOMAIN, { folder_watcher.DOMAIN: { diff --git a/tests/components/test_google.py b/tests/components/test_google.py index 0ee066fcfee..b8dc29b5dea 100644 --- a/tests/components/test_google.py +++ b/tests/components/test_google.py @@ -14,7 +14,7 @@ class TestGoogle(unittest.TestCase): """Test the Google component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_graphite.py b/tests/components/test_graphite.py index 892fe5b5f4d..7ceda9e191e 100644 --- a/tests/components/test_graphite.py +++ b/tests/components/test_graphite.py @@ -17,7 +17,7 @@ class TestGraphite(unittest.TestCase): """Test the Graphite component.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.gf = graphite.GraphiteFeeder(self.hass, 'foo', 123, 'ha') diff --git a/tests/components/test_history.py b/tests/components/test_history.py index b348498b07e..ef2f7a17a19 100644 --- a/tests/components/test_history.py +++ b/tests/components/test_history.py @@ -17,7 +17,7 @@ class TestComponentHistory(unittest.TestCase): """Test History component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_history_graph.py b/tests/components/test_history_graph.py index 554f7f29dd7..9b7733a7ec2 100644 --- a/tests/components/test_history_graph.py +++ b/tests/components/test_history_graph.py @@ -10,7 +10,7 @@ class TestGraph(unittest.TestCase): """Test the Google component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_influxdb.py b/tests/components/test_influxdb.py index e2323aca855..7d1b7527612 100644 --- a/tests/components/test_influxdb.py +++ b/tests/components/test_influxdb.py @@ -21,7 +21,7 @@ class TestInfluxDB(unittest.TestCase): """Test the InfluxDB component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.handler_method = None self.hass.bus.listen = mock.Mock() @@ -96,7 +96,7 @@ class TestInfluxDB(unittest.TestCase): assert not setup_component(self.hass, influxdb.DOMAIN, config) def _setup(self, **kwargs): - """Setup the client.""" + """Set up the client.""" config = { 'influxdb': { 'host': 'host', diff --git a/tests/components/test_init.py b/tests/components/test_init.py index 1e565054637..355f3dc0e96 100644 --- a/tests/components/test_init.py +++ b/tests/components/test_init.py @@ -25,7 +25,7 @@ class TestComponentsCore(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.assertTrue(run_coroutine_threadsafe( comps.async_setup(self.hass, {}), self.hass.loop diff --git a/tests/components/test_input_boolean.py b/tests/components/test_input_boolean.py index e39b12481bc..964d1763e4e 100644 --- a/tests/components/test_input_boolean.py +++ b/tests/components/test_input_boolean.py @@ -22,7 +22,7 @@ class TestInputBoolean(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/test_input_datetime.py b/tests/components/test_input_datetime.py index 7277a8d7d3a..0d21061e022 100644 --- a/tests/components/test_input_datetime.py +++ b/tests/components/test_input_datetime.py @@ -26,7 +26,7 @@ class TestInputDatetime(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/test_input_number.py b/tests/components/test_input_number.py index fde940efa1a..d416dcae154 100644 --- a/tests/components/test_input_number.py +++ b/tests/components/test_input_number.py @@ -16,7 +16,7 @@ class TestInputNumber(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/test_input_select.py b/tests/components/test_input_select.py index 20d9656d8b0..82da80253c5 100644 --- a/tests/components/test_input_select.py +++ b/tests/components/test_input_select.py @@ -19,7 +19,7 @@ class TestInputSelect(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/test_input_text.py b/tests/components/test_input_text.py index c288375ec8f..405f7de8272 100644 --- a/tests/components/test_input_text.py +++ b/tests/components/test_input_text.py @@ -15,7 +15,7 @@ class TestInputText(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/test_introduction.py b/tests/components/test_introduction.py index 99b373961cc..b7099d04878 100644 --- a/tests/components/test_introduction.py +++ b/tests/components/test_introduction.py @@ -11,7 +11,7 @@ class TestIntroduction(unittest.TestCase): """Test Introduction.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/test_kira.py b/tests/components/test_kira.py index a80d766c3fd..67ab679800f 100644 --- a/tests/components/test_kira.py +++ b/tests/components/test_kira.py @@ -36,7 +36,7 @@ class TestKiraSetup(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() _base_mock = MagicMock() pykira = _base_mock.pykira diff --git a/tests/components/test_litejet.py b/tests/components/test_litejet.py index dfbcb9d99d8..3b46e9d274c 100644 --- a/tests/components/test_litejet.py +++ b/tests/components/test_litejet.py @@ -12,7 +12,7 @@ class TestLiteJet(unittest.TestCase): """Test the litejet component.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.start() self.hass.block_till_done() diff --git a/tests/components/test_logbook.py b/tests/components/test_logbook.py index a3a5273ed4e..cf78fbec352 100644 --- a/tests/components/test_logbook.py +++ b/tests/components/test_logbook.py @@ -26,7 +26,7 @@ class TestComponentLogbook(unittest.TestCase): EMPTY_CONFIG = logbook.CONFIG_SCHEMA({logbook.DOMAIN: {}}) def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() init_recorder_component(self.hass) # Force an in memory DB assert setup_component(self.hass, logbook.DOMAIN, self.EMPTY_CONFIG) diff --git a/tests/components/test_logentries.py b/tests/components/test_logentries.py index bff80c958f3..843a043cee6 100644 --- a/tests/components/test_logentries.py +++ b/tests/components/test_logentries.py @@ -14,7 +14,7 @@ class TestLogentries(unittest.TestCase): """Test the Logentries component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_logger.py b/tests/components/test_logger.py index a55a66c6505..f774af2169c 100644 --- a/tests/components/test_logger.py +++ b/tests/components/test_logger.py @@ -24,7 +24,7 @@ class TestUpdater(unittest.TestCase): """Test logger component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.log_filter = None @@ -34,7 +34,7 @@ class TestUpdater(unittest.TestCase): self.hass.stop() def setup_logger(self, config): - """Setup logger and save log filter.""" + """Set up logger and save log filter.""" setup_component(self.hass, logger.DOMAIN, config) self.log_filter = logging.root.handlers[-1].filters[0] diff --git a/tests/components/test_microsoft_face.py b/tests/components/test_microsoft_face.py index 92f840b8033..601d5e7ebcc 100644 --- a/tests/components/test_microsoft_face.py +++ b/tests/components/test_microsoft_face.py @@ -13,7 +13,7 @@ class TestMicrosoftFaceSetup: """Test the microsoft face component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.config = { @@ -31,21 +31,21 @@ class TestMicrosoftFaceSetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_setup_component(self, mock_update): - """Setup component.""" + """Set up component.""" with assert_setup_component(3, mf.DOMAIN): setup_component(self.hass, mf.DOMAIN, self.config) @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_setup_component_wrong_api_key(self, mock_update): - """Setup component without api key.""" + """Set up component without api key.""" with assert_setup_component(0, mf.DOMAIN): setup_component(self.hass, mf.DOMAIN, {mf.DOMAIN: {}}) @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_setup_component_test_service(self, mock_update): - """Setup component.""" + """Set up component.""" with assert_setup_component(3, mf.DOMAIN): setup_component(self.hass, mf.DOMAIN, self.config) @@ -57,7 +57,7 @@ class TestMicrosoftFaceSetup: assert self.hass.services.has_service(mf.DOMAIN, 'face_person') def test_setup_component_test_entities(self, aioclient_mock): - """Setup component.""" + """Set up component.""" aioclient_mock.get( self.endpoint_url.format("persongroups"), text=load_fixture('microsoft_face_persongroups.json') @@ -95,7 +95,7 @@ class TestMicrosoftFaceSetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_service_groups(self, mock_update, aioclient_mock): - """Setup component, test groups services.""" + """Set up component, test groups services.""" aioclient_mock.put( self.endpoint_url.format("persongroups/service_group"), status=200, text="{}" @@ -123,7 +123,7 @@ class TestMicrosoftFaceSetup: assert len(aioclient_mock.mock_calls) == 2 def test_service_person(self, aioclient_mock): - """Setup component, test person services.""" + """Set up component, test person services.""" aioclient_mock.get( self.endpoint_url.format("persongroups"), text=load_fixture('microsoft_face_persongroups.json') @@ -175,7 +175,7 @@ class TestMicrosoftFaceSetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_service_train(self, mock_update, aioclient_mock): - """Setup component, test train groups services.""" + """Set up component, test train groups services.""" with assert_setup_component(3, mf.DOMAIN): setup_component(self.hass, mf.DOMAIN, self.config) @@ -192,7 +192,7 @@ class TestMicrosoftFaceSetup: @patch('homeassistant.components.camera.async_get_image', return_value=mock_coro(camera.Image('image/jpeg', b'Test'))) def test_service_face(self, camera_mock, aioclient_mock): - """Setup component, test person face services.""" + """Set up component, test person face services.""" aioclient_mock.get( self.endpoint_url.format("persongroups"), text=load_fixture('microsoft_face_persongroups.json') @@ -229,7 +229,7 @@ class TestMicrosoftFaceSetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_service_status_400(self, mock_update, aioclient_mock): - """Setup component, test groups services with error.""" + """Set up component, test groups services with error.""" aioclient_mock.put( self.endpoint_url.format("persongroups/service_group"), status=400, text="{'error': {'message': 'Error'}}" @@ -248,7 +248,7 @@ class TestMicrosoftFaceSetup: @patch('homeassistant.components.microsoft_face.' 'MicrosoftFace.update_store', return_value=mock_coro()) def test_service_status_timeout(self, mock_update, aioclient_mock): - """Setup component, test groups services with timeout.""" + """Set up component, test groups services with timeout.""" aioclient_mock.put( self.endpoint_url.format("persongroups/service_group"), status=400, exc=asyncio.TimeoutError() diff --git a/tests/components/test_mqtt_eventstream.py b/tests/components/test_mqtt_eventstream.py index 8da1311c87d..a6881672339 100644 --- a/tests/components/test_mqtt_eventstream.py +++ b/tests/components/test_mqtt_eventstream.py @@ -22,7 +22,7 @@ class TestMqttEventStream: """Test the MQTT eventstream module.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_mqtt = mock_mqtt_component(self.hass) diff --git a/tests/components/test_mqtt_statestream.py b/tests/components/test_mqtt_statestream.py index 4cf79e679cd..97c4c0647e8 100644 --- a/tests/components/test_mqtt_statestream.py +++ b/tests/components/test_mqtt_statestream.py @@ -16,7 +16,7 @@ class TestMqttStateStream: """Test the MQTT statestream module.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.mock_mqtt = mock_mqtt_component(self.hass) diff --git a/tests/components/test_panel_iframe.py b/tests/components/test_panel_iframe.py index 214eda04ad8..3ac06c09a26 100644 --- a/tests/components/test_panel_iframe.py +++ b/tests/components/test_panel_iframe.py @@ -11,7 +11,7 @@ class TestPanelIframe(unittest.TestCase): """Test the panel_iframe component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/test_pilight.py b/tests/components/test_pilight.py index 24052a56839..9304463b6fd 100644 --- a/tests/components/test_pilight.py +++ b/tests/components/test_pilight.py @@ -70,7 +70,7 @@ class TestPilight(unittest.TestCase): """Test the Pilight component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.skip_teardown_stop = False @@ -351,7 +351,7 @@ class TestPilightCallrateThrottler(unittest.TestCase): """Test the Throttler used to throttle calls to send_code.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/test_proximity.py b/tests/components/test_proximity.py index 42f1cbf4b43..f69ace46014 100644 --- a/tests/components/test_proximity.py +++ b/tests/components/test_proximity.py @@ -12,7 +12,7 @@ class TestProximity(unittest.TestCase): """Test the Proximity component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.states.set( 'zone.home', 'zoning', diff --git a/tests/components/test_rest_command.py b/tests/components/test_rest_command.py index 097fb799d40..b66628a3562 100644 --- a/tests/components/test_rest_command.py +++ b/tests/components/test_rest_command.py @@ -14,7 +14,7 @@ class TestRestCommandSetup: """Test the rest command component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.config = { @@ -51,7 +51,7 @@ class TestRestCommandComponent: """Test the rest command component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.url = "https://example.com/" self.config = { rc.DOMAIN: { @@ -81,7 +81,7 @@ class TestRestCommandComponent: self.hass.stop() def test_setup_tests(self): - """Setup test config and test it.""" + """Set up test config and test it.""" with assert_setup_component(4): setup_component(self.hass, rc.DOMAIN, self.config) diff --git a/tests/components/test_rfxtrx.py b/tests/components/test_rfxtrx.py index 1730d3a5371..93bf0b16dc5 100644 --- a/tests/components/test_rfxtrx.py +++ b/tests/components/test_rfxtrx.py @@ -15,7 +15,7 @@ class TestRFXTRX(unittest.TestCase): """Test the Rfxtrx component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/test_rss_feed_template.py b/tests/components/test_rss_feed_template.py index 36f68e57c9f..64876dbea44 100644 --- a/tests/components/test_rss_feed_template.py +++ b/tests/components/test_rss_feed_template.py @@ -9,7 +9,7 @@ from homeassistant.setup import async_setup_component @pytest.fixture def mock_http_client(loop, hass, aiohttp_client): - """Setup test fixture.""" + """Set up test fixture.""" config = { 'rss_feed_template': { 'testfeed': { diff --git a/tests/components/test_script.py b/tests/components/test_script.py index c4282cdfbaf..8ad782cf697 100644 --- a/tests/components/test_script.py +++ b/tests/components/test_script.py @@ -18,7 +18,7 @@ class TestScriptComponent(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/components/test_shell_command.py b/tests/components/test_shell_command.py index a1acffd62e5..e945befbb84 100644 --- a/tests/components/test_shell_command.py +++ b/tests/components/test_shell_command.py @@ -33,7 +33,7 @@ class TestShellCommand(unittest.TestCase): """Test the shell_command component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started. + """Set up things to be run when tests are started. Also seems to require a child watcher attached to the loop when run from pytest. diff --git a/tests/components/test_splunk.py b/tests/components/test_splunk.py index 38143119112..173c822ddb6 100644 --- a/tests/components/test_splunk.py +++ b/tests/components/test_splunk.py @@ -16,7 +16,7 @@ class TestSplunk(unittest.TestCase): """Test the Splunk component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_statsd.py b/tests/components/test_statsd.py index 5fd907fe0b1..6bd00e50646 100644 --- a/tests/components/test_statsd.py +++ b/tests/components/test_statsd.py @@ -16,7 +16,7 @@ class TestStatsd(unittest.TestCase): """Test the StatsD component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/test_sun.py b/tests/components/test_sun.py index d5a4ecfcb81..aa94bf2bdd3 100644 --- a/tests/components/test_sun.py +++ b/tests/components/test_sun.py @@ -17,7 +17,7 @@ class TestSun(unittest.TestCase): """Test the sun module.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/test_updater.py b/tests/components/test_updater.py index 28ffcac2b13..23b669928f4 100644 --- a/tests/components/test_updater.py +++ b/tests/components/test_updater.py @@ -46,7 +46,7 @@ def test_new_version_shows_entity_after_hour( res = yield from async_setup_component( hass, updater.DOMAIN, {updater.DOMAIN: {}}) - assert res, 'Updater failed to setup' + assert res, 'Updater failed to set up' with patch('homeassistant.components.updater.current_version', MOCK_VERSION): @@ -65,7 +65,7 @@ def test_same_version_not_show_entity( res = yield from async_setup_component( hass, updater.DOMAIN, {updater.DOMAIN: {}}) - assert res, 'Updater failed to setup' + assert res, 'Updater failed to set up' with patch('homeassistant.components.updater.current_version', MOCK_VERSION): @@ -85,7 +85,7 @@ def test_disable_reporting(hass, mock_get_uuid, mock_get_newest_version): hass, updater.DOMAIN, {updater.DOMAIN: { 'reporting': False }}) - assert res, 'Updater failed to setup' + assert res, 'Updater failed to set up' with patch('homeassistant.components.updater.current_version', MOCK_VERSION): @@ -187,7 +187,7 @@ def test_new_version_shows_entity_after_hour_hassio( res = yield from async_setup_component( hass, updater.DOMAIN, {updater.DOMAIN: {}}) - assert res, 'Updater failed to setup' + assert res, 'Updater failed to set up' with patch('homeassistant.components.updater.current_version', MOCK_VERSION): diff --git a/tests/components/test_weblink.py b/tests/components/test_weblink.py index f35398e034c..8e71c89cdd6 100644 --- a/tests/components/test_weblink.py +++ b/tests/components/test_weblink.py @@ -11,7 +11,7 @@ class TestComponentWeblink(unittest.TestCase): """Test the Weblink component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/components/tts/test_google.py b/tests/components/tts/test_google.py index cf9a7b2db29..f328e3e9f16 100644 --- a/tests/components/tts/test_google.py +++ b/tests/components/tts/test_google.py @@ -19,7 +19,7 @@ class TestTTSGooglePlatform: """Test the Google speech component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.url = "https://translate.google.com/translate_tts" diff --git a/tests/components/tts/test_init.py b/tests/components/tts/test_init.py index 0970f0d7490..719fe2716e7 100644 --- a/tests/components/tts/test_init.py +++ b/tests/components/tts/test_init.py @@ -33,7 +33,7 @@ class TestTTS: """Test the Google speech component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.demo_provider = DemoProvider('en') self.default_tts_cache = self.hass.config.path(tts.DEFAULT_CACHE_DIR) @@ -50,7 +50,7 @@ class TestTTS: shutil.rmtree(self.default_tts_cache) def test_setup_component_demo(self): - """Setup the demo platform with defaults.""" + """Set up the demo platform with defaults.""" config = { tts.DOMAIN: { 'platform': 'demo', @@ -65,7 +65,7 @@ class TestTTS: @patch('os.mkdir', side_effect=OSError(2, "No access")) def test_setup_component_demo_no_access_cache_folder(self, mock_mkdir): - """Setup the demo platform with defaults.""" + """Set up the demo platform with defaults.""" config = { tts.DOMAIN: { 'platform': 'demo', @@ -78,7 +78,7 @@ class TestTTS: assert not self.hass.services.has_service(tts.DOMAIN, 'clear_cache') def test_setup_component_and_test_service(self): - """Setup the demo platform and call service.""" + """Set up the demo platform and call service.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -106,7 +106,7 @@ class TestTTS: "265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3")) def test_setup_component_and_test_service_with_config_language(self): - """Setup the demo platform and call service.""" + """Set up the demo platform and call service.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -135,7 +135,7 @@ class TestTTS: "265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3")) def test_setup_component_and_test_service_with_wrong_conf_language(self): - """Setup the demo platform and call service with wrong config.""" + """Set up the demo platform and call service with wrong config.""" config = { tts.DOMAIN: { 'platform': 'demo', @@ -147,7 +147,7 @@ class TestTTS: setup_component(self.hass, tts.DOMAIN, config) def test_setup_component_and_test_service_with_service_language(self): - """Setup the demo platform and call service.""" + """Set up the demo platform and call service.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -176,7 +176,7 @@ class TestTTS: "265944c108cbb00b2a621be5930513e03a0bb2cd_de_-_demo.mp3")) def test_setup_component_test_service_with_wrong_service_language(self): - """Setup the demo platform and call service.""" + """Set up the demo platform and call service.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -200,7 +200,7 @@ class TestTTS: "265944c108cbb00b2a621be5930513e03a0bb2cd_lang_-_demo.mp3")) def test_setup_component_and_test_service_with_service_options(self): - """Setup the demo platform and call service with options.""" + """Set up the demo platform and call service with options.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -237,7 +237,7 @@ class TestTTS: @patch('homeassistant.components.tts.demo.DemoProvider.default_options', new_callable=PropertyMock(return_value={'voice': 'alex'})) def test_setup_component_and_test_with_service_options_def(self, def_mock): - """Setup the demo platform and call service with default options.""" + """Set up the demo platform and call service with default options.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -269,7 +269,7 @@ class TestTTS: opt_hash))) def test_setup_component_and_test_service_with_service_options_wrong(self): - """Setup the demo platform and call service with wrong options.""" + """Set up the demo platform and call service with wrong options.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -299,7 +299,7 @@ class TestTTS: opt_hash))) def test_setup_component_and_test_service_clear_cache(self): - """Setup the demo platform and call service clear cache.""" + """Set up the demo platform and call service clear cache.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -329,7 +329,7 @@ class TestTTS: "265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3")) def test_setup_component_and_test_service_with_receive_voice(self): - """Setup the demo platform and call service and receive voice.""" + """Set up the demo platform and call service and receive voice.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -359,7 +359,7 @@ class TestTTS: assert req.content == demo_data def test_setup_component_and_test_service_with_receive_voice_german(self): - """Setup the demo platform and call service and receive voice.""" + """Set up the demo platform and call service and receive voice.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -390,7 +390,7 @@ class TestTTS: assert req.content == demo_data def test_setup_component_and_web_view_wrong_file(self): - """Setup the demo platform and receive wrong file from web.""" + """Set up the demo platform and receive wrong file from web.""" config = { tts.DOMAIN: { 'platform': 'demo', @@ -409,7 +409,7 @@ class TestTTS: assert req.status_code == 404 def test_setup_component_and_web_view_wrong_filename(self): - """Setup the demo platform and receive wrong filename from web.""" + """Set up the demo platform and receive wrong filename from web.""" config = { tts.DOMAIN: { 'platform': 'demo', @@ -428,7 +428,7 @@ class TestTTS: assert req.status_code == 404 def test_setup_component_test_without_cache(self): - """Setup demo platform without cache.""" + """Set up demo platform without cache.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -452,7 +452,7 @@ class TestTTS: "265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3")) def test_setup_component_test_with_cache_call_service_without_cache(self): - """Setup demo platform with cache and call service without cache.""" + """Set up demo platform with cache and call service without cache.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -477,7 +477,7 @@ class TestTTS: "265944c108cbb00b2a621be5930513e03a0bb2cd_en_-_demo.mp3")) def test_setup_component_test_with_cache_dir(self): - """Setup demo platform with cache and call service without cache.""" + """Set up demo platform with cache and call service without cache.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) _, demo_data = self.demo_provider.get_tts_audio("bla", 'en') @@ -515,7 +515,7 @@ class TestTTS: @patch('homeassistant.components.tts.demo.DemoProvider.get_tts_audio', return_value=(None, None)) def test_setup_component_test_with_error_on_get_tts(self, tts_mock): - """Setup demo platform with wrong get_tts_audio.""" + """Set up demo platform with wrong get_tts_audio.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) config = { @@ -535,7 +535,7 @@ class TestTTS: assert len(calls) == 0 def test_setup_component_load_cache_retrieve_without_mem_cache(self): - """Setup component and load cache and get without mem cache.""" + """Set up component and load cache and get without mem cache.""" _, demo_data = self.demo_provider.get_tts_audio("bla", 'en') cache_file = os.path.join( self.default_tts_cache, @@ -565,7 +565,7 @@ class TestTTS: assert req.content == demo_data def test_setup_component_and_web_get_url(self): - """Setup the demo platform and receive wrong file from web.""" + """Set up the demo platform and receive wrong file from web.""" config = { tts.DOMAIN: { 'platform': 'demo', @@ -589,7 +589,7 @@ class TestTTS: .format(self.hass.config.api.base_url)) def test_setup_component_and_web_get_url_bad_config(self): - """Setup the demo platform and receive wrong file from web.""" + """Set up the demo platform and receive wrong file from web.""" config = { tts.DOMAIN: { 'platform': 'demo', diff --git a/tests/components/tts/test_marytts.py b/tests/components/tts/test_marytts.py index 7ec2ae39cd6..110473d75a8 100644 --- a/tests/components/tts/test_marytts.py +++ b/tests/components/tts/test_marytts.py @@ -18,7 +18,7 @@ class TestTTSMaryTTSPlatform: """Test the speech component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.url = "http://localhost:59125/process?" diff --git a/tests/components/tts/test_voicerss.py b/tests/components/tts/test_voicerss.py index 365cf1ff73b..334e35a9386 100644 --- a/tests/components/tts/test_voicerss.py +++ b/tests/components/tts/test_voicerss.py @@ -18,7 +18,7 @@ class TestTTSVoiceRSSPlatform: """Test the voicerss speech component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.url = "https://api.voicerss.org/" diff --git a/tests/components/tts/test_yandextts.py b/tests/components/tts/test_yandextts.py index 82d20318928..2675e322507 100644 --- a/tests/components/tts/test_yandextts.py +++ b/tests/components/tts/test_yandextts.py @@ -17,7 +17,7 @@ class TestTTSYandexPlatform: """Test the speech component.""" def setup_method(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self._base_url = "https://tts.voicetech.yandex.net/generate?" diff --git a/tests/components/vacuum/test_demo.py b/tests/components/vacuum/test_demo.py index bd6f2ae543c..1fc8f8cd5c1 100644 --- a/tests/components/vacuum/test_demo.py +++ b/tests/components/vacuum/test_demo.py @@ -30,7 +30,7 @@ class TestVacuumDemo(unittest.TestCase): """Test the Demo vacuum.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.assertTrue(setup_component( self.hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: 'demo'}})) diff --git a/tests/components/vacuum/test_dyson.py b/tests/components/vacuum/test_dyson.py index 8a4e6d57b91..5e32fc9daef 100644 --- a/tests/components/vacuum/test_dyson.py +++ b/tests/components/vacuum/test_dyson.py @@ -67,7 +67,7 @@ class DysonTest(unittest.TestCase): """Dyson 360 eye robot vacuum component test class.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/components/weather/test_darksky.py b/tests/components/weather/test_darksky.py index 41687451cd6..5423943e6fd 100644 --- a/tests/components/weather/test_darksky.py +++ b/tests/components/weather/test_darksky.py @@ -17,7 +17,7 @@ class TestDarkSky(unittest.TestCase): """Test the Dark Sky weather component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.units = METRIC_SYSTEM self.lat = self.hass.config.latitude = 37.8267 diff --git a/tests/components/weather/test_ipma.py b/tests/components/weather/test_ipma.py index 7df6166a2b6..d438e118573 100644 --- a/tests/components/weather/test_ipma.py +++ b/tests/components/weather/test_ipma.py @@ -52,7 +52,7 @@ class TestIPMA(unittest.TestCase): """Test the IPMA weather component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.units = METRIC_SYSTEM self.lat = self.hass.config.latitude = 40.00 diff --git a/tests/components/weather/test_weather.py b/tests/components/weather/test_weather.py index a88e9979551..42b1dacc5f8 100644 --- a/tests/components/weather/test_weather.py +++ b/tests/components/weather/test_weather.py @@ -17,7 +17,7 @@ class TestWeather(unittest.TestCase): """Test the Weather component.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.units = METRIC_SYSTEM self.assertTrue(setup_component(self.hass, weather.DOMAIN, { diff --git a/tests/components/weather/test_yweather.py b/tests/components/weather/test_yweather.py index 3e5eff9dae7..8ecaa67535e 100644 --- a/tests/components/weather/test_yweather.py +++ b/tests/components/weather/test_yweather.py @@ -83,7 +83,7 @@ class TestWeather(unittest.TestCase): self.DEVICES.append(device) def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.hass.config.units = METRIC_SYSTEM diff --git a/tests/components/zone/test_init.py b/tests/components/zone/test_init.py index 92dee05818d..ba98915e777 100644 --- a/tests/components/zone/test_init.py +++ b/tests/components/zone/test_init.py @@ -42,7 +42,7 @@ class TestComponentZone(unittest.TestCase): """Test the zone component.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/conftest.py b/tests/conftest.py index 28c47948666..61c5c1c7dd5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,4 @@ -"""Setup some common test helper things.""" +"""Set up some common test helper things.""" import asyncio import functools import logging diff --git a/tests/helpers/test_aiohttp_client.py b/tests/helpers/test_aiohttp_client.py index ccfe1b1aff9..699342381f9 100644 --- a/tests/helpers/test_aiohttp_client.py +++ b/tests/helpers/test_aiohttp_client.py @@ -30,7 +30,7 @@ class TestHelpersAiohttpClient(unittest.TestCase): """Test homeassistant.helpers.aiohttp_client module.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index aa7b5170648..69fab77715c 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -11,7 +11,7 @@ class TestConditionHelper: """Test condition helpers.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/helpers/test_config_entry_flow.py b/tests/helpers/test_config_entry_flow.py index 9eede7dff9b..a9b4dc158e0 100644 --- a/tests/helpers/test_config_entry_flow.py +++ b/tests/helpers/test_config_entry_flow.py @@ -49,7 +49,7 @@ async def test_user_no_devices_found(hass, flow_conf): async def test_user_no_confirmation(hass, flow_conf): - """Test user requires no confirmation to setup.""" + """Test user requires no confirmation to set up.""" flow = config_entries.HANDLERS['test']() flow.hass = hass flow_conf['discovered'] = True @@ -118,7 +118,7 @@ async def test_user_init_trumps_discovery(hass, flow_conf): async def test_import_no_confirmation(hass, flow_conf): - """Test import requires no confirmation to setup.""" + """Test import requires no confirmation to set up.""" flow = config_entries.HANDLERS['test']() flow.hass = hass flow_conf['discovered'] = True diff --git a/tests/helpers/test_discovery.py b/tests/helpers/test_discovery.py index c7b39954d85..8ee8d4596fe 100644 --- a/tests/helpers/test_discovery.py +++ b/tests/helpers/test_discovery.py @@ -16,7 +16,7 @@ class TestHelpersDiscovery: """Tests for discovery helper methods.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): @@ -117,7 +117,7 @@ class TestHelpersDiscovery: platform_calls = [] def component_setup(hass, config): - """Setup mock component.""" + """Set up mock component.""" discovery.load_platform(hass, 'switch', 'test_circular', 'disc', config) component_calls.append(1) @@ -125,7 +125,7 @@ class TestHelpersDiscovery: def setup_platform(hass, config, add_devices_callback, discovery_info=None): - """Setup mock platform.""" + """Set up mock platform.""" platform_calls.append('disc' if discovery_info else 'component') loader.set_component( @@ -158,21 +158,21 @@ class TestHelpersDiscovery: def test_1st_discovers_2nd_component(self, mock_signal): """Test that we don't break if one component discovers the other. - If the first component fires a discovery event to setup the - second component while the second component is about to be setup, - it should not setup the second component twice. + If the first component fires a discovery event to set up the + second component while the second component is about to be set up, + it should not set up the second component twice. """ component_calls = [] def component1_setup(hass, config): - """Setup mock component.""" + """Set up mock component.""" print('component1 setup') discovery.discover(hass, 'test_component2', component='test_component2') return True def component2_setup(hass, config): - """Setup mock component.""" + """Set up mock component.""" component_calls.append(1) return True @@ -186,7 +186,7 @@ class TestHelpersDiscovery: @callback def do_setup(): - """Setup 2 components.""" + """Set up 2 components.""" self.hass.async_add_job(setup.async_setup_component( self.hass, 'test_component1', {})) self.hass.async_add_job(setup.async_setup_component( diff --git a/tests/helpers/test_dispatcher.py b/tests/helpers/test_dispatcher.py index 55e67def2bc..ef1ad2336eb 100644 --- a/tests/helpers/test_dispatcher.py +++ b/tests/helpers/test_dispatcher.py @@ -12,7 +12,7 @@ class TestHelpersDispatcher: """Tests for discovery helper methods.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/helpers/test_entity.py b/tests/helpers/test_entity.py index e24bec489f4..f9355f97ba3 100644 --- a/tests/helpers/test_entity.py +++ b/tests/helpers/test_entity.py @@ -75,7 +75,7 @@ class TestHelpersEntity: """Test homeassistant.helpers.entity module.""" def setup_method(self, method): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.entity = entity.Entity() self.entity.entity_id = 'test.overwrite_hidden_true' self.hass = self.entity.hass = get_test_home_assistant() diff --git a/tests/helpers/test_entity_component.py b/tests/helpers/test_entity_component.py index b4910723c8d..1ce12e0b9ad 100644 --- a/tests/helpers/test_entity_component.py +++ b/tests/helpers/test_entity_component.py @@ -39,7 +39,7 @@ class TestHelpersEntityComponent(unittest.TestCase): self.hass.stop() def test_setting_up_group(self): - """Setup the setting of a group.""" + """Set up the setting of a group.""" setup_component(self.hass, 'group', {'group': {}}) component = EntityComponent(_LOGGER, DOMAIN, self.hass, group_name='everyone') diff --git a/tests/helpers/test_event.py b/tests/helpers/test_event.py index 73f2b9ff5a4..deefcec773a 100644 --- a/tests/helpers/test_event.py +++ b/tests/helpers/test_event.py @@ -37,7 +37,7 @@ class TestEventHelpers(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/helpers/test_location.py b/tests/helpers/test_location.py index 068e1a58ac2..22f69c18326 100644 --- a/tests/helpers/test_location.py +++ b/tests/helpers/test_location.py @@ -7,15 +7,15 @@ from homeassistant.helpers import location class TestHelpersLocation(unittest.TestCase): - """Setup the tests.""" + """Set up the tests.""" def test_has_location_with_invalid_states(self): - """Setup the tests.""" + """Set up the tests.""" for state in (None, 1, "hello", object): self.assertFalse(location.has_location(state)) def test_has_location_with_states_with_invalid_locations(self): - """Setup the tests.""" + """Set up the tests.""" state = State('hello.world', 'invalid', { ATTR_LATITUDE: 'no number', ATTR_LONGITUDE: 123.12 @@ -23,7 +23,7 @@ class TestHelpersLocation(unittest.TestCase): self.assertFalse(location.has_location(state)) def test_has_location_with_states_with_valid_location(self): - """Setup the tests.""" + """Set up the tests.""" state = State('hello.world', 'invalid', { ATTR_LATITUDE: 123.12, ATTR_LONGITUDE: 123.12 @@ -31,7 +31,7 @@ class TestHelpersLocation(unittest.TestCase): self.assertTrue(location.has_location(state)) def test_closest_with_no_states_with_location(self): - """Setup the tests.""" + """Set up the tests.""" state = State('light.test', 'on') state2 = State('light.test', 'on', { ATTR_LATITUDE: 'invalid', diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index 7e60cc796cc..ba5bdbcdc6e 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -21,7 +21,7 @@ class TestScriptHelper(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py index 79054726c03..529804bd307 100644 --- a/tests/helpers/test_service.py +++ b/tests/helpers/test_service.py @@ -19,7 +19,7 @@ class TestServiceHelpers(unittest.TestCase): """Test the Home Assistant service helpers.""" def setUp(self): # pylint: disable=invalid-name - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.calls = mock_service(self.hass, 'test_domain', 'test_service') diff --git a/tests/helpers/test_sun.py b/tests/helpers/test_sun.py index 2cfe28e5178..b1c7f62e776 100644 --- a/tests/helpers/test_sun.py +++ b/tests/helpers/test_sun.py @@ -15,7 +15,7 @@ class TestSun(unittest.TestCase): """Test the sun helpers.""" def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() def tearDown(self): diff --git a/tests/helpers/test_temperature.py b/tests/helpers/test_temperature.py index 96e7bd6c74f..e2366d8866a 100644 --- a/tests/helpers/test_temperature.py +++ b/tests/helpers/test_temperature.py @@ -13,10 +13,10 @@ TEMP = 24.636626 class TestHelpersTemperature(unittest.TestCase): - """Setup the temperature tests.""" + """Set up the temperature tests.""" def setUp(self): - """Setup the tests.""" + """Set up the tests.""" self.hass = get_test_home_assistant() self.hass.config.unit_system = METRIC_SYSTEM diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 2dfcb2a58e5..37614f9ee45 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -27,7 +27,7 @@ class TestHelpersTemplate(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup the tests.""" + """Set up the tests.""" self.hass = get_test_home_assistant() self.hass.config.units = UnitSystem('custom', TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS, diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index 1f6fd8756e6..d8756d87a19 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -231,7 +231,7 @@ async def test_forward_entry_sets_up_component(hass): async def test_forward_entry_does_not_setup_entry_if_setup_fails(hass): - """Test we do not setup entry if component setup fails.""" + """Test we do not set up entry if component setup fails.""" entry = MockConfigEntry(domain='original') mock_setup = MagicMock(return_value=mock_coro(False)) diff --git a/tests/test_core.py b/tests/test_core.py index f23bed6bc8a..ce066135709 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -130,7 +130,7 @@ class TestHomeAssistant(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name @@ -291,7 +291,7 @@ class TestEventBus(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.bus = self.hass.bus @@ -495,7 +495,7 @@ class TestStateMachine(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.states = self.hass.states self.states.set("light.Bowl", "on") @@ -620,7 +620,7 @@ class TestServiceRegistry(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() self.services = self.hass.services @@ -775,7 +775,7 @@ class TestConfig(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup things to be run when tests are started.""" + """Set up things to be run when tests are started.""" self.config = ha.Config() self.assertIsNone(self.config.config_dir) diff --git a/tests/test_loader.py b/tests/test_loader.py index d87201fb61b..4beb7db570e 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -17,7 +17,7 @@ class TestLoader(unittest.TestCase): # pylint: disable=invalid-name def setUp(self): - """Setup tests.""" + """Set up tests.""" self.hass = get_test_home_assistant() # pylint: disable=invalid-name diff --git a/tests/test_requirements.py b/tests/test_requirements.py index 8ae0f6c11de..e3ef797df4d 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -16,7 +16,7 @@ class TestRequirements: # pylint: disable=invalid-name, no-self-use def setup_method(self, method): - """Setup the test.""" + """Set up the test.""" self.hass = get_test_home_assistant() def teardown_method(self, method): diff --git a/tests/test_setup.py b/tests/test_setup.py index 6f0c282e016..1ced1206f65 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -34,7 +34,7 @@ class TestSetup: # pylint: disable=invalid-name, no-self-use def setup_method(self, method): - """Setup the test.""" + """Set up the test.""" self.hass = get_test_home_assistant() def teardown_method(self, method): @@ -179,7 +179,7 @@ class TestSetup: assert not setup.setup_component(self.hass, 'non_existing') def test_component_not_double_initialized(self): - """Test we do not setup a component twice.""" + """Test we do not set up a component twice.""" mock_setup = mock.MagicMock(return_value=True) loader.set_component( @@ -206,7 +206,7 @@ class TestSetup: assert 'comp' not in self.hass.config.components def test_component_not_setup_twice_if_loaded_during_other_setup(self): - """Test component setup while waiting for lock is not setup twice.""" + """Test component setup while waiting for lock is not set up twice.""" result = [] @asyncio.coroutine @@ -219,7 +219,7 @@ class TestSetup: 'comp', MockModule('comp', async_setup=async_setup)) def setup_component(): - """Setup the component.""" + """Set up the component.""" setup.setup_component(self.hass, 'comp') thread = threading.Thread(target=setup_component) @@ -231,7 +231,7 @@ class TestSetup: assert len(result) == 1 def test_component_not_setup_missing_dependencies(self): - """Test we do not setup a component if not all dependencies loaded.""" + """Test we do not set up a component if not all dependencies loaded.""" deps = ['non_existing'] loader.set_component( self.hass, 'comp', MockModule('comp', dependencies=deps)) @@ -377,7 +377,7 @@ class TestSetup: call_order = [] def component1_setup(hass, config): - """Setup mock component.""" + """Set up mock component.""" discovery.discover(hass, 'test_component2', component='test_component2') discovery.discover(hass, 'test_component3', @@ -385,7 +385,7 @@ class TestSetup: return True def component_track_setup(hass, config): - """Setup mock component.""" + """Set up mock component.""" call_order.append(1) return True diff --git a/tests/util/test_dt.py b/tests/util/test_dt.py index feee69ad3c8..d670917c055 100644 --- a/tests/util/test_dt.py +++ b/tests/util/test_dt.py @@ -11,7 +11,7 @@ class TestDateUtil(unittest.TestCase): """Test util date methods.""" def setUp(self): - """Setup the tests.""" + """Set up the tests.""" self.orig_default_time_zone = dt_util.DEFAULT_TIME_ZONE def tearDown(self): From 994e2b66243eeab09446dc4ddad46d1ec05585a4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 20 Aug 2018 11:52:23 +0200 Subject: [PATCH 068/159] Update frontend to 20180820.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index e17bbad78d1..a436cc483ae 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180818.0'] +REQUIREMENTS = ['home-assistant-frontend==20180820.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 132696dcb10..2c0bb46a73f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -435,7 +435,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180818.0 +home-assistant-frontend==20180820.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 6f4dece3a75..f158327feca 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180818.0 +home-assistant-frontend==20180820.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 121abb450a730ac7c5cb65a4703f3e8d91343638 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 20 Aug 2018 14:03:35 +0200 Subject: [PATCH 069/159] Use aiohttp web.AppRunner (#16020) * Use aiohttp web.AppRunner * Stop site --- homeassistant/components/http/__init__.py | 33 ++++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index 9ded94fa6fd..ac08c26229c 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -232,7 +232,8 @@ class HomeAssistantHTTP: self.is_ban_enabled = is_ban_enabled self.ssl_profile = ssl_profile self._handler = None - self.server = None + self.runner = None + self.site = None def register_view(self, view): """Register a view with the WSGI server. @@ -308,7 +309,7 @@ class HomeAssistantHTTP: self.app.router.add_route('GET', url_pattern, serve_file) async def start(self): - """Start the WSGI server.""" + """Start the aiohttp server.""" # We misunderstood the startup signal. You're not allowed to change # anything during startup. Temp workaround. # pylint: disable=protected-access @@ -321,7 +322,9 @@ class HomeAssistantHTTP: context = ssl_util.server_context_intermediate() else: context = ssl_util.server_context_modern() - context.load_cert_chain(self.ssl_certificate, self.ssl_key) + await self.hass.async_add_executor_job( + context.load_cert_chain, self.ssl_certificate, + self.ssl_key) except OSError as error: _LOGGER.error("Could not read SSL certificate from %s: %s", self.ssl_certificate, error) @@ -329,7 +332,9 @@ class HomeAssistantHTTP: if self.ssl_peer_certificate: context.verify_mode = ssl.CERT_REQUIRED - context.load_verify_locations(cafile=self.ssl_peer_certificate) + await self.hass.async_add_executor_job( + context.load_verify_locations, + self.ssl_peer_certificate) else: context = None @@ -340,21 +345,17 @@ class HomeAssistantHTTP: # To work around this we now prevent the router from getting frozen self.app._router.freeze = lambda: None - self._handler = self.app.make_handler(loop=self.hass.loop) - + self.runner = web.AppRunner(self.app) + await self.runner.setup() + self.site = web.TCPSite(self.runner, self.server_host, + self.server_port, ssl_context=context) try: - self.server = await self.hass.loop.create_server( - self._handler, self.server_host, self.server_port, ssl=context) + await self.site.start() except OSError as error: _LOGGER.error("Failed to create HTTP server at port %d: %s", self.server_port, error) async def stop(self): - """Stop the WSGI server.""" - if self.server: - self.server.close() - await self.server.wait_closed() - await self.app.shutdown() - if self._handler: - await self._handler.shutdown(10) - await self.app.cleanup() + """Stop the aiohttp server.""" + await self.site.stop() + await self.runner.cleanup() From 1f0d1136880b415143237a65bf0788b74bb2e795 Mon Sep 17 00:00:00 2001 From: Kevin Siml Date: Mon, 20 Aug 2018 14:11:52 +0200 Subject: [PATCH 070/159] Update pushsafer.py (#16060) --- homeassistant/components/notify/pushsafer.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/homeassistant/components/notify/pushsafer.py b/homeassistant/components/notify/pushsafer.py index 30068854f2e..443d56521c1 100644 --- a/homeassistant/components/notify/pushsafer.py +++ b/homeassistant/components/notify/pushsafer.py @@ -32,6 +32,10 @@ ATTR_ICONCOLOR = 'iconcolor' ATTR_URL = 'url' ATTR_URLTITLE = 'urltitle' ATTR_TIME2LIVE = 'time2live' +ATTR_PRIORITY = 'priority' +ATTR_RETRY = 'retry' +ATTR_EXPIRE = 'expire' +ATTR_ANSWER = 'answer' ATTR_PICTURE1 = 'picture1' # Attributes contained in picture1 @@ -106,6 +110,10 @@ class PushsaferNotificationService(BaseNotificationService): 'u': data.get(ATTR_URL, ""), 'ut': data.get(ATTR_URLTITLE, ""), 'l': data.get(ATTR_TIME2LIVE, ""), + 'pr': data.get(ATTR_PRIORITY, ""), + 're': data.get(ATTR_RETRY, ""), + 'ex': data.get(ATTR_EXPIRE, ""), + 'a': data.get(ATTR_ANSWER, ""), 'p': picture1_encoded } From 18d19fde0be7fe569b08a2ddbb67d01fb9b76bd6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 20 Aug 2018 14:18:07 +0200 Subject: [PATCH 071/159] Alexa: context + log events (#16023) --- homeassistant/components/alexa/smart_home.py | 243 ++++++++++--------- tests/components/alexa/test_smart_home.py | 77 +++++- 2 files changed, 194 insertions(+), 126 deletions(-) diff --git a/homeassistant/components/alexa/smart_home.py b/homeassistant/components/alexa/smart_home.py index 042d878fceb..9fbcecfa577 100644 --- a/homeassistant/components/alexa/smart_home.py +++ b/homeassistant/components/alexa/smart_home.py @@ -53,6 +53,7 @@ CONF_DISPLAY_CATEGORIES = 'display_categories' HANDLERS = Registry() ENTITY_ADAPTERS = Registry() +EVENT_ALEXA_SMART_HOME = 'alexa_smart_home' class _DisplayCategory: @@ -703,24 +704,47 @@ class SmartHomeView(http.HomeAssistantView): return b'' if response is None else self.json(response) -@asyncio.coroutine -def async_handle_message(hass, config, message): +async def async_handle_message(hass, config, request, context=None): """Handle incoming API messages.""" - assert message[API_DIRECTIVE][API_HEADER]['payloadVersion'] == '3' + assert request[API_DIRECTIVE][API_HEADER]['payloadVersion'] == '3' + + if context is None: + context = ha.Context() # Read head data - message = message[API_DIRECTIVE] - namespace = message[API_HEADER]['namespace'] - name = message[API_HEADER]['name'] + request = request[API_DIRECTIVE] + namespace = request[API_HEADER]['namespace'] + name = request[API_HEADER]['name'] # Do we support this API request? funct_ref = HANDLERS.get((namespace, name)) - if not funct_ref: + if funct_ref: + response = await funct_ref(hass, config, request, context) + else: _LOGGER.warning( "Unsupported API request %s/%s", namespace, name) - return api_error(message) + response = api_error(request) - return (yield from funct_ref(hass, config, message)) + request_info = { + 'namespace': namespace, + 'name': name, + } + + if API_ENDPOINT in request and 'endpointId' in request[API_ENDPOINT]: + request_info['entity_id'] = \ + request[API_ENDPOINT]['endpointId'].replace('#', '.') + + response_header = response[API_EVENT][API_HEADER] + + hass.bus.async_fire(EVENT_ALEXA_SMART_HOME, { + 'request': request_info, + 'response': { + 'namespace': response_header['namespace'], + 'name': response_header['name'], + } + }, context=context) + + return response def api_message(request, @@ -784,8 +808,7 @@ def api_error(request, @HANDLERS.register(('Alexa.Discovery', 'Discover')) -@asyncio.coroutine -def async_api_discovery(hass, config, request): +async def async_api_discovery(hass, config, request, context): """Create a API formatted discovery response. Async friendly. @@ -827,8 +850,7 @@ def async_api_discovery(hass, config, request): def extract_entity(funct): """Decorate for extract entity object from request.""" - @asyncio.coroutine - def async_api_entity_wrapper(hass, config, request): + async def async_api_entity_wrapper(hass, config, request, context): """Process a turn on request.""" entity_id = request[API_ENDPOINT]['endpointId'].replace('#', '.') @@ -839,15 +861,14 @@ def extract_entity(funct): request[API_HEADER]['name'], entity_id) return api_error(request, error_type='NO_SUCH_ENDPOINT') - return (yield from funct(hass, config, request, entity)) + return await funct(hass, config, request, context, entity) return async_api_entity_wrapper @HANDLERS.register(('Alexa.PowerController', 'TurnOn')) @extract_entity -@asyncio.coroutine -def async_api_turn_on(hass, config, request, entity): +async def async_api_turn_on(hass, config, request, context, entity): """Process a turn on request.""" domain = entity.domain if entity.domain == group.DOMAIN: @@ -857,17 +878,16 @@ def async_api_turn_on(hass, config, request, entity): if entity.domain == cover.DOMAIN: service = cover.SERVICE_OPEN_COVER - yield from hass.services.async_call(domain, service, { + await hass.services.async_call(domain, service, { ATTR_ENTITY_ID: entity.entity_id - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.PowerController', 'TurnOff')) @extract_entity -@asyncio.coroutine -def async_api_turn_off(hass, config, request, entity): +async def async_api_turn_off(hass, config, request, context, entity): """Process a turn off request.""" domain = entity.domain if entity.domain == group.DOMAIN: @@ -877,32 +897,30 @@ def async_api_turn_off(hass, config, request, entity): if entity.domain == cover.DOMAIN: service = cover.SERVICE_CLOSE_COVER - yield from hass.services.async_call(domain, service, { + await hass.services.async_call(domain, service, { ATTR_ENTITY_ID: entity.entity_id - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.BrightnessController', 'SetBrightness')) @extract_entity -@asyncio.coroutine -def async_api_set_brightness(hass, config, request, entity): +async def async_api_set_brightness(hass, config, request, context, entity): """Process a set brightness request.""" brightness = int(request[API_PAYLOAD]['brightness']) - yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, { + await hass.services.async_call(entity.domain, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity.entity_id, light.ATTR_BRIGHTNESS_PCT: brightness, - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.BrightnessController', 'AdjustBrightness')) @extract_entity -@asyncio.coroutine -def async_api_adjust_brightness(hass, config, request, entity): +async def async_api_adjust_brightness(hass, config, request, context, entity): """Process an adjust brightness request.""" brightness_delta = int(request[API_PAYLOAD]['brightnessDelta']) @@ -915,18 +933,17 @@ def async_api_adjust_brightness(hass, config, request, entity): # set brightness brightness = max(0, brightness_delta + current) - yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, { + await hass.services.async_call(entity.domain, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity.entity_id, light.ATTR_BRIGHTNESS_PCT: brightness, - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.ColorController', 'SetColor')) @extract_entity -@asyncio.coroutine -def async_api_set_color(hass, config, request, entity): +async def async_api_set_color(hass, config, request, context, entity): """Process a set color request.""" rgb = color_util.color_hsb_to_RGB( float(request[API_PAYLOAD]['color']['hue']), @@ -934,25 +951,25 @@ def async_api_set_color(hass, config, request, entity): float(request[API_PAYLOAD]['color']['brightness']) ) - yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, { + await hass.services.async_call(entity.domain, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity.entity_id, light.ATTR_RGB_COLOR: rgb, - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.ColorTemperatureController', 'SetColorTemperature')) @extract_entity -@asyncio.coroutine -def async_api_set_color_temperature(hass, config, request, entity): +async def async_api_set_color_temperature(hass, config, request, context, + entity): """Process a set color temperature request.""" kelvin = int(request[API_PAYLOAD]['colorTemperatureInKelvin']) - yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, { + await hass.services.async_call(entity.domain, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity.entity_id, light.ATTR_KELVIN: kelvin, - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @@ -960,17 +977,17 @@ def async_api_set_color_temperature(hass, config, request, entity): @HANDLERS.register( ('Alexa.ColorTemperatureController', 'DecreaseColorTemperature')) @extract_entity -@asyncio.coroutine -def async_api_decrease_color_temp(hass, config, request, entity): +async def async_api_decrease_color_temp(hass, config, request, context, + entity): """Process a decrease color temperature request.""" current = int(entity.attributes.get(light.ATTR_COLOR_TEMP)) max_mireds = int(entity.attributes.get(light.ATTR_MAX_MIREDS)) value = min(max_mireds, current + 50) - yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, { + await hass.services.async_call(entity.domain, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity.entity_id, light.ATTR_COLOR_TEMP: value, - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @@ -978,31 +995,30 @@ def async_api_decrease_color_temp(hass, config, request, entity): @HANDLERS.register( ('Alexa.ColorTemperatureController', 'IncreaseColorTemperature')) @extract_entity -@asyncio.coroutine -def async_api_increase_color_temp(hass, config, request, entity): +async def async_api_increase_color_temp(hass, config, request, context, + entity): """Process an increase color temperature request.""" current = int(entity.attributes.get(light.ATTR_COLOR_TEMP)) min_mireds = int(entity.attributes.get(light.ATTR_MIN_MIREDS)) value = max(min_mireds, current - 50) - yield from hass.services.async_call(entity.domain, SERVICE_TURN_ON, { + await hass.services.async_call(entity.domain, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity.entity_id, light.ATTR_COLOR_TEMP: value, - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.SceneController', 'Activate')) @extract_entity -@asyncio.coroutine -def async_api_activate(hass, config, request, entity): +async def async_api_activate(hass, config, request, context, entity): """Process an activate request.""" domain = entity.domain - yield from hass.services.async_call(domain, SERVICE_TURN_ON, { + await hass.services.async_call(domain, SERVICE_TURN_ON, { ATTR_ENTITY_ID: entity.entity_id - }, blocking=False) + }, blocking=False, context=context) payload = { 'cause': {'type': _Cause.VOICE_INTERACTION}, @@ -1019,14 +1035,13 @@ def async_api_activate(hass, config, request, entity): @HANDLERS.register(('Alexa.SceneController', 'Deactivate')) @extract_entity -@asyncio.coroutine -def async_api_deactivate(hass, config, request, entity): +async def async_api_deactivate(hass, config, request, context, entity): """Process a deactivate request.""" domain = entity.domain - yield from hass.services.async_call(domain, SERVICE_TURN_OFF, { + await hass.services.async_call(domain, SERVICE_TURN_OFF, { ATTR_ENTITY_ID: entity.entity_id - }, blocking=False) + }, blocking=False, context=context) payload = { 'cause': {'type': _Cause.VOICE_INTERACTION}, @@ -1043,8 +1058,7 @@ def async_api_deactivate(hass, config, request, entity): @HANDLERS.register(('Alexa.PercentageController', 'SetPercentage')) @extract_entity -@asyncio.coroutine -def async_api_set_percentage(hass, config, request, entity): +async def async_api_set_percentage(hass, config, request, context, entity): """Process a set percentage request.""" percentage = int(request[API_PAYLOAD]['percentage']) service = None @@ -1066,16 +1080,15 @@ def async_api_set_percentage(hass, config, request, entity): service = SERVICE_SET_COVER_POSITION data[cover.ATTR_POSITION] = percentage - yield from hass.services.async_call( - entity.domain, service, data, blocking=False) + await hass.services.async_call( + entity.domain, service, data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.PercentageController', 'AdjustPercentage')) @extract_entity -@asyncio.coroutine -def async_api_adjust_percentage(hass, config, request, entity): +async def async_api_adjust_percentage(hass, config, request, context, entity): """Process an adjust percentage request.""" percentage_delta = int(request[API_PAYLOAD]['percentageDelta']) service = None @@ -1114,20 +1127,19 @@ def async_api_adjust_percentage(hass, config, request, entity): data[cover.ATTR_POSITION] = max(0, percentage_delta + current) - yield from hass.services.async_call( - entity.domain, service, data, blocking=False) + await hass.services.async_call( + entity.domain, service, data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.LockController', 'Lock')) @extract_entity -@asyncio.coroutine -def async_api_lock(hass, config, request, entity): +async def async_api_lock(hass, config, request, context, entity): """Process a lock request.""" - yield from hass.services.async_call(entity.domain, SERVICE_LOCK, { + await hass.services.async_call(entity.domain, SERVICE_LOCK, { ATTR_ENTITY_ID: entity.entity_id - }, blocking=False) + }, blocking=False, context=context) # Alexa expects a lockState in the response, we don't know the actual # lockState at this point but assume it is locked. It is reported @@ -1144,20 +1156,18 @@ def async_api_lock(hass, config, request, entity): # Not supported by Alexa yet @HANDLERS.register(('Alexa.LockController', 'Unlock')) @extract_entity -@asyncio.coroutine -def async_api_unlock(hass, config, request, entity): +async def async_api_unlock(hass, config, request, context, entity): """Process an unlock request.""" - yield from hass.services.async_call(entity.domain, SERVICE_UNLOCK, { + await hass.services.async_call(entity.domain, SERVICE_UNLOCK, { ATTR_ENTITY_ID: entity.entity_id - }, blocking=False) + }, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.Speaker', 'SetVolume')) @extract_entity -@asyncio.coroutine -def async_api_set_volume(hass, config, request, entity): +async def async_api_set_volume(hass, config, request, context, entity): """Process a set volume request.""" volume = round(float(request[API_PAYLOAD]['volume'] / 100), 2) @@ -1166,17 +1176,16 @@ def async_api_set_volume(hass, config, request, entity): media_player.ATTR_MEDIA_VOLUME_LEVEL: volume, } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, SERVICE_VOLUME_SET, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.InputController', 'SelectInput')) @extract_entity -@asyncio.coroutine -def async_api_select_input(hass, config, request, entity): +async def async_api_select_input(hass, config, request, context, entity): """Process a set input request.""" media_input = request[API_PAYLOAD]['input'] @@ -1200,17 +1209,16 @@ def async_api_select_input(hass, config, request, entity): media_player.ATTR_INPUT_SOURCE: media_input, } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, media_player.SERVICE_SELECT_SOURCE, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.Speaker', 'AdjustVolume')) @extract_entity -@asyncio.coroutine -def async_api_adjust_volume(hass, config, request, entity): +async def async_api_adjust_volume(hass, config, request, context, entity): """Process an adjust volume request.""" volume_delta = int(request[API_PAYLOAD]['volume']) @@ -1229,17 +1237,16 @@ def async_api_adjust_volume(hass, config, request, entity): media_player.ATTR_MEDIA_VOLUME_LEVEL: volume, } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, media_player.SERVICE_VOLUME_SET, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.StepSpeaker', 'AdjustVolume')) @extract_entity -@asyncio.coroutine -def async_api_adjust_volume_step(hass, config, request, entity): +async def async_api_adjust_volume_step(hass, config, request, context, entity): """Process an adjust volume step request.""" # media_player volume up/down service does not support specifying steps # each component handles it differently e.g. via config. @@ -1252,13 +1259,13 @@ def async_api_adjust_volume_step(hass, config, request, entity): } if volume_step > 0: - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, media_player.SERVICE_VOLUME_UP, - data, blocking=False) + data, blocking=False, context=context) elif volume_step < 0: - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, media_player.SERVICE_VOLUME_DOWN, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @@ -1266,8 +1273,7 @@ def async_api_adjust_volume_step(hass, config, request, entity): @HANDLERS.register(('Alexa.StepSpeaker', 'SetMute')) @HANDLERS.register(('Alexa.Speaker', 'SetMute')) @extract_entity -@asyncio.coroutine -def async_api_set_mute(hass, config, request, entity): +async def async_api_set_mute(hass, config, request, context, entity): """Process a set mute request.""" mute = bool(request[API_PAYLOAD]['mute']) @@ -1276,89 +1282,84 @@ def async_api_set_mute(hass, config, request, entity): media_player.ATTR_MEDIA_VOLUME_MUTED: mute, } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, media_player.SERVICE_VOLUME_MUTE, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.PlaybackController', 'Play')) @extract_entity -@asyncio.coroutine -def async_api_play(hass, config, request, entity): +async def async_api_play(hass, config, request, context, entity): """Process a play request.""" data = { ATTR_ENTITY_ID: entity.entity_id } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, SERVICE_MEDIA_PLAY, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.PlaybackController', 'Pause')) @extract_entity -@asyncio.coroutine -def async_api_pause(hass, config, request, entity): +async def async_api_pause(hass, config, request, context, entity): """Process a pause request.""" data = { ATTR_ENTITY_ID: entity.entity_id } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, SERVICE_MEDIA_PAUSE, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.PlaybackController', 'Stop')) @extract_entity -@asyncio.coroutine -def async_api_stop(hass, config, request, entity): +async def async_api_stop(hass, config, request, context, entity): """Process a stop request.""" data = { ATTR_ENTITY_ID: entity.entity_id } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, SERVICE_MEDIA_STOP, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.PlaybackController', 'Next')) @extract_entity -@asyncio.coroutine -def async_api_next(hass, config, request, entity): +async def async_api_next(hass, config, request, context, entity): """Process a next request.""" data = { ATTR_ENTITY_ID: entity.entity_id } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, SERVICE_MEDIA_NEXT_TRACK, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa.PlaybackController', 'Previous')) @extract_entity -@asyncio.coroutine -def async_api_previous(hass, config, request, entity): +async def async_api_previous(hass, config, request, context, entity): """Process a previous request.""" data = { ATTR_ENTITY_ID: entity.entity_id } - yield from hass.services.async_call( + await hass.services.async_call( entity.domain, SERVICE_MEDIA_PREVIOUS_TRACK, - data, blocking=False) + data, blocking=False, context=context) return api_message(request) @@ -1405,7 +1406,7 @@ def temperature_from_object(temp_obj, to_unit, interval=False): @HANDLERS.register(('Alexa.ThermostatController', 'SetTargetTemperature')) @extract_entity -async def async_api_set_target_temp(hass, config, request, entity): +async def async_api_set_target_temp(hass, config, request, context, entity): """Process a set target temperature request.""" unit = entity.attributes[CONF_UNIT_OF_MEASUREMENT] min_temp = entity.attributes.get(climate.ATTR_MIN_TEMP) @@ -1439,14 +1440,15 @@ async def async_api_set_target_temp(hass, config, request, entity): data[climate.ATTR_TARGET_TEMP_HIGH] = temp_high await hass.services.async_call( - entity.domain, climate.SERVICE_SET_TEMPERATURE, data, blocking=False) + entity.domain, climate.SERVICE_SET_TEMPERATURE, data, blocking=False, + context=context) return api_message(request) @HANDLERS.register(('Alexa.ThermostatController', 'AdjustTargetTemperature')) @extract_entity -async def async_api_adjust_target_temp(hass, config, request, entity): +async def async_api_adjust_target_temp(hass, config, request, context, entity): """Process an adjust target temperature request.""" unit = entity.attributes[CONF_UNIT_OF_MEASUREMENT] min_temp = entity.attributes.get(climate.ATTR_MIN_TEMP) @@ -1466,14 +1468,16 @@ async def async_api_adjust_target_temp(hass, config, request, entity): } await hass.services.async_call( - entity.domain, climate.SERVICE_SET_TEMPERATURE, data, blocking=False) + entity.domain, climate.SERVICE_SET_TEMPERATURE, data, blocking=False, + context=context) return api_message(request) @HANDLERS.register(('Alexa.ThermostatController', 'SetThermostatMode')) @extract_entity -async def async_api_set_thermostat_mode(hass, config, request, entity): +async def async_api_set_thermostat_mode(hass, config, request, context, + entity): """Process a set thermostat mode request.""" mode = request[API_PAYLOAD]['thermostatMode'] mode = mode if isinstance(mode, str) else mode['value'] @@ -1499,15 +1503,14 @@ async def async_api_set_thermostat_mode(hass, config, request, entity): await hass.services.async_call( entity.domain, climate.SERVICE_SET_OPERATION_MODE, data, - blocking=False) + blocking=False, context=context) return api_message(request) @HANDLERS.register(('Alexa', 'ReportState')) @extract_entity -@asyncio.coroutine -def async_api_reportstate(hass, config, request, entity): +async def async_api_reportstate(hass, config, request, context, entity): """Process a ReportState request.""" alexa_entity = ENTITY_ADAPTERS[entity.domain](config, entity) properties = [] diff --git a/tests/components/alexa/test_smart_home.py b/tests/components/alexa/test_smart_home.py index cf8535653a9..1fc38b71c52 100644 --- a/tests/components/alexa/test_smart_home.py +++ b/tests/components/alexa/test_smart_home.py @@ -5,6 +5,7 @@ from uuid import uuid4 import pytest +from homeassistant.core import Context, callback from homeassistant.const import ( TEMP_FAHRENHEIT, STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN) @@ -18,6 +19,17 @@ from tests.common import async_mock_service DEFAULT_CONFIG = smart_home.Config(should_expose=lambda entity_id: True) +@pytest.fixture +def events(hass): + """Fixture that catches alexa events.""" + events = [] + hass.bus.async_listen( + smart_home.EVENT_ALEXA_SMART_HOME, + callback(lambda e: events.append(e)) + ) + yield events + + def get_new_request(namespace, name, endpoint=None): """Generate a new API message.""" raw_msg = { @@ -145,7 +157,7 @@ def assert_endpoint_capabilities(endpoint, *interfaces): @asyncio.coroutine -def test_switch(hass): +def test_switch(hass, events): """Test switch discovery.""" device = ('switch.test', 'on', {'friendly_name': "Test switch"}) appliance = yield from discovery_test(device, hass) @@ -963,23 +975,26 @@ def assert_request_calls_service( response_type='Response', payload=None): """Assert an API request calls a hass service.""" + context = Context() request = get_new_request(namespace, name, endpoint) if payload: request['directive']['payload'] = payload domain, service_name = service.split('.') - call = async_mock_service(hass, domain, service_name) + calls = async_mock_service(hass, domain, service_name) msg = yield from smart_home.async_handle_message( - hass, DEFAULT_CONFIG, request) + hass, DEFAULT_CONFIG, request, context) yield from hass.async_block_till_done() - assert len(call) == 1 + assert len(calls) == 1 + call = calls[0] assert 'event' in msg - assert call[0].data['entity_id'] == endpoint.replace('#', '.') + assert call.data['entity_id'] == endpoint.replace('#', '.') assert msg['event']['header']['name'] == response_type + assert call.context == context - return call[0], msg + return call, msg @asyncio.coroutine @@ -1372,3 +1387,53 @@ def test_api_select_input(hass, domain, payload, source_list, idx): hass, payload={'input': payload}) assert call.data['source'] == source_list[idx] + + +async def test_logging_request(hass, events): + """Test that we log requests.""" + context = Context() + request = get_new_request('Alexa.Discovery', 'Discover') + await smart_home.async_handle_message( + hass, DEFAULT_CONFIG, request, context) + + # To trigger event listener + await hass.async_block_till_done() + + assert len(events) == 1 + event = events[0] + + assert event.data['request'] == { + 'namespace': 'Alexa.Discovery', + 'name': 'Discover', + } + assert event.data['response'] == { + 'namespace': 'Alexa.Discovery', + 'name': 'Discover.Response' + } + assert event.context == context + + +async def test_logging_request_with_entity(hass, events): + """Test that we log requests.""" + context = Context() + request = get_new_request('Alexa.PowerController', 'TurnOn', 'switch#xy') + await smart_home.async_handle_message( + hass, DEFAULT_CONFIG, request, context) + + # To trigger event listener + await hass.async_block_till_done() + + assert len(events) == 1 + event = events[0] + + assert event.data['request'] == { + 'namespace': 'Alexa.PowerController', + 'name': 'TurnOn', + 'entity_id': 'switch.xy' + } + # Entity doesn't exist + assert event.data['response'] == { + 'namespace': 'Alexa', + 'name': 'ErrorResponse' + } + assert event.context == context From a708a81fa8c606deb28aba8e806145e70400ffb0 Mon Sep 17 00:00:00 2001 From: Oleksii Serdiuk Date: Mon, 20 Aug 2018 14:22:41 +0200 Subject: [PATCH 072/159] openuv: Add Current UV Level to list of conditions (#16042) Calculated from UV index, based on table from https://www.openuv.io/kb/uv-index-levels-colors --- homeassistant/components/openuv.py | 2 ++ homeassistant/components/sensor/openuv.py | 25 +++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/openuv.py b/homeassistant/components/openuv.py index dd038611ae9..d696f0e5100 100644 --- a/homeassistant/components/openuv.py +++ b/homeassistant/components/openuv.py @@ -37,6 +37,7 @@ TOPIC_UPDATE = '{0}_data_update'.format(DOMAIN) TYPE_CURRENT_OZONE_LEVEL = 'current_ozone_level' TYPE_CURRENT_UV_INDEX = 'current_uv_index' +TYPE_CURRENT_UV_LEVEL = 'current_uv_level' TYPE_MAX_UV_INDEX = 'max_uv_index' TYPE_PROTECTION_WINDOW = 'uv_protection_window' TYPE_SAFE_EXPOSURE_TIME_1 = 'safe_exposure_time_type_1' @@ -59,6 +60,7 @@ SENSORS = { TYPE_CURRENT_OZONE_LEVEL: ( 'Current Ozone Level', 'mdi:vector-triangle', 'du'), TYPE_CURRENT_UV_INDEX: ('Current UV Index', 'mdi:weather-sunny', 'index'), + TYPE_CURRENT_UV_LEVEL: ('Current UV Level', 'mdi:weather-sunny', None), TYPE_MAX_UV_INDEX: ('Max UV Index', 'mdi:weather-sunny', 'index'), TYPE_SAFE_EXPOSURE_TIME_1: ( 'Skin Type 1 Safe Exposure Time', 'mdi:timer', 'minutes'), diff --git a/homeassistant/components/sensor/openuv.py b/homeassistant/components/sensor/openuv.py index b30c2908c40..42ff999bdd5 100644 --- a/homeassistant/components/sensor/openuv.py +++ b/homeassistant/components/sensor/openuv.py @@ -11,10 +11,10 @@ from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.components.openuv import ( DATA_UV, DOMAIN, SENSORS, TOPIC_UPDATE, TYPE_CURRENT_OZONE_LEVEL, - TYPE_CURRENT_UV_INDEX, TYPE_MAX_UV_INDEX, TYPE_SAFE_EXPOSURE_TIME_1, - TYPE_SAFE_EXPOSURE_TIME_2, TYPE_SAFE_EXPOSURE_TIME_3, - TYPE_SAFE_EXPOSURE_TIME_4, TYPE_SAFE_EXPOSURE_TIME_5, - TYPE_SAFE_EXPOSURE_TIME_6, OpenUvEntity) + TYPE_CURRENT_UV_INDEX, TYPE_CURRENT_UV_LEVEL, TYPE_MAX_UV_INDEX, + TYPE_SAFE_EXPOSURE_TIME_1, TYPE_SAFE_EXPOSURE_TIME_2, + TYPE_SAFE_EXPOSURE_TIME_3, TYPE_SAFE_EXPOSURE_TIME_4, + TYPE_SAFE_EXPOSURE_TIME_5, TYPE_SAFE_EXPOSURE_TIME_6, OpenUvEntity) from homeassistant.util.dt import as_local, parse_datetime DEPENDENCIES = ['openuv'] @@ -31,6 +31,12 @@ EXPOSURE_TYPE_MAP = { TYPE_SAFE_EXPOSURE_TIME_6: 'st6' } +UV_LEVEL_EXTREME = "Extreme" +UV_LEVEL_VHIGH = "Very High" +UV_LEVEL_HIGH = "High" +UV_LEVEL_MODERATE = "Moderate" +UV_LEVEL_LOW = "Low" + async def async_setup_platform( hass, config, async_add_devices, discovery_info=None): @@ -105,6 +111,17 @@ class OpenUvSensor(OpenUvEntity): self._state = data['ozone'] elif self._sensor_type == TYPE_CURRENT_UV_INDEX: self._state = data['uv'] + elif self._sensor_type == TYPE_CURRENT_UV_LEVEL: + if data['uv'] >= 11: + self._state = UV_LEVEL_EXTREME + elif data['uv'] >= 8: + self._state = UV_LEVEL_VHIGH + elif data['uv'] >= 6: + self._state = UV_LEVEL_HIGH + elif data['uv'] >= 3: + self._state = UV_LEVEL_MODERATE + else: + self._state = UV_LEVEL_LOW elif self._sensor_type == TYPE_MAX_UV_INDEX: self._state = data['uv_max'] self._attrs.update({ From 975befd136fb0d4b3c6b785733f90ce587bda29a Mon Sep 17 00:00:00 2001 From: Tim Bailey Date: Mon, 20 Aug 2018 22:34:52 +1000 Subject: [PATCH 073/159] TpLink Device Tracker Error (#15918) * Fix 'Error setting up platform tplink' error when a scanner fails even if another scanner would succeed * Try to fix tox errors * Adjust code based on PR comments --- .../components/device_tracker/tplink.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/device_tracker/tplink.py b/homeassistant/components/device_tracker/tplink.py index 346f381db34..9bf85e39faf 100644 --- a/homeassistant/components/device_tracker/tplink.py +++ b/homeassistant/components/device_tracker/tplink.py @@ -69,11 +69,16 @@ class TplinkDeviceScanner(DeviceScanner): password = config[CONF_PASSWORD] username = config[CONF_USERNAME] - self.tplink_client = TpLinkClient( - password, host=host, username=username) + self.success_init = False + try: + self.tplink_client = TpLinkClient( + password, host=host, username=username) - self.last_results = {} - self.success_init = self._update_info() + self.last_results = {} + + self.success_init = self._update_info() + except requests.exceptions.ConnectionError: + _LOGGER.debug("ConnectionError in TplinkDeviceScanner") def scan_devices(self): """Scan for new devices and return a list with found device IDs.""" @@ -115,7 +120,11 @@ class Tplink1DeviceScanner(DeviceScanner): self.password = password self.last_results = {} - self.success_init = self._update_info() + self.success_init = False + try: + self.success_init = self._update_info() + except requests.exceptions.ConnectionError: + _LOGGER.debug("ConnectionError in Tplink1DeviceScanner") def scan_devices(self): """Scan for new devices and return a list with found device IDs.""" From d1e1b9b38a06b82f6b609e68cbb99c15b934ffb3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 20 Aug 2018 16:34:18 +0200 Subject: [PATCH 074/159] Deprecated stuff (#16019) * Use async with for locks * Fix regex in template test * Close session correctly * Use correct current_task method * push camera cleanup * Lint * Revert current_task * Update websocket_api.py * Mock executor_job betteR * Fix async_create_task mock --- homeassistant/components/camera/push.py | 2 ++ .../components/device_tracker/__init__.py | 20 +++++++++---------- homeassistant/components/websocket_api.py | 1 - tests/common.py | 18 ++++++++++++++++- tests/components/camera/test_push.py | 4 ++-- tests/helpers/test_template.py | 12 +++++------ tests/test_util/aiohttp.py | 15 +++++++++++++- 7 files changed, 50 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/camera/push.py b/homeassistant/components/camera/push.py index def5c53dd3f..f5ea336d576 100644 --- a/homeassistant/components/camera/push.py +++ b/homeassistant/components/camera/push.py @@ -21,6 +21,8 @@ import homeassistant.util.dt as dt_util _LOGGER = logging.getLogger(__name__) +DEPENDENCIES = ['http'] + CONF_BUFFER_SIZE = 'buffer' CONF_IMAGE_FIELD = 'field' diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 74cb0a77fef..408672a974f 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -330,19 +330,18 @@ class DeviceTracker: }) # update known_devices.yaml - self.hass.async_add_job( + self.hass.async_create_task( self.async_update_config( self.hass.config.path(YAML_DEVICES), dev_id, device) ) - @asyncio.coroutine - def async_update_config(self, path, dev_id, device): + async def async_update_config(self, path, dev_id, device): """Add device to YAML configuration file. This method is a coroutine. """ - with (yield from self._is_updating): - yield from self.hass.async_add_job( + async with self._is_updating: + await self.hass.async_add_executor_job( update_config, self.hass.config.path(YAML_DEVICES), dev_id, device) @@ -681,8 +680,7 @@ def async_setup_scanner_platform(hass: HomeAssistantType, config: ConfigType, # Initial scan of each mac we also tell about host name for config seen = set() # type: Any - @asyncio.coroutine - def async_device_tracker_scan(now: dt_util.dt.datetime): + async def async_device_tracker_scan(now: dt_util.dt.datetime): """Handle interval matches.""" if update_lock.locked(): _LOGGER.warning( @@ -690,18 +688,18 @@ def async_setup_scanner_platform(hass: HomeAssistantType, config: ConfigType, "scan interval %s", platform, interval) return - with (yield from update_lock): - found_devices = yield from scanner.async_scan_devices() + async with update_lock: + found_devices = await scanner.async_scan_devices() for mac in found_devices: if mac in seen: host_name = None else: - host_name = yield from scanner.async_get_device_name(mac) + host_name = await scanner.async_get_device_name(mac) seen.add(mac) try: - extra_attributes = (yield from + extra_attributes = (await scanner.async_get_extra_attributes(mac)) except NotImplementedError: extra_attributes = dict() diff --git a/homeassistant/components/websocket_api.py b/homeassistant/components/websocket_api.py index 36811337ec1..c25f4418263 100644 --- a/homeassistant/components/websocket_api.py +++ b/homeassistant/components/websocket_api.py @@ -325,7 +325,6 @@ class ActiveConnection: await wsock.prepare(request) self.debug("Connected") - # Get a reference to current task so we can cancel our connection self._handle_task = asyncio.Task.current_task(loop=self.hass.loop) @callback diff --git a/tests/common.py b/tests/common.py index e7445751783..c56cadc16f9 100644 --- a/tests/common.py +++ b/tests/common.py @@ -123,14 +123,30 @@ def async_test_home_assistant(loop): INSTANCES.append(hass) orig_async_add_job = hass.async_add_job + orig_async_add_executor_job = hass.async_add_executor_job + orig_async_create_task = hass.async_create_task def async_add_job(target, *args): - """Add a magic mock.""" + """Add job.""" if isinstance(target, Mock): return mock_coro(target(*args)) return orig_async_add_job(target, *args) + def async_add_executor_job(target, *args): + """Add executor job.""" + if isinstance(target, Mock): + return mock_coro(target(*args)) + return orig_async_add_executor_job(target, *args) + + def async_create_task(coroutine): + """Create task.""" + if isinstance(coroutine, Mock): + return mock_coro() + return orig_async_create_task(coroutine) + hass.async_add_job = async_add_job + hass.async_add_executor_job = async_add_executor_job + hass.async_create_task = async_create_task hass.config.location_name = 'test home' hass.config.config_dir = get_test_config_dir() diff --git a/tests/components/camera/test_push.py b/tests/components/camera/test_push.py index 78053e540f5..f9a3c62aa4a 100644 --- a/tests/components/camera/test_push.py +++ b/tests/components/camera/test_push.py @@ -30,7 +30,7 @@ async def test_bad_posting(aioclient_mock, hass, aiohttp_client): assert resp.status == 400 -async def test_posting_url(aioclient_mock, hass, aiohttp_client): +async def test_posting_url(hass, aiohttp_client): """Test that posting to api endpoint works.""" await async_setup_component(hass, 'camera', { 'camera': { @@ -38,7 +38,7 @@ async def test_posting_url(aioclient_mock, hass, aiohttp_client): 'name': 'config_test', }}) - client = await async_setup_auth(hass, aiohttp_client) + client = await aiohttp_client(hass.http.app) files = {'image': io.BytesIO(b'fake')} # initial state diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 37614f9ee45..6f426c290c5 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -511,8 +511,8 @@ class TestHelpersTemplate(unittest.TestCase): def test_regex_match(self): """Test regex_match method.""" - tpl = template.Template(""" -{{ '123-456-7890' | regex_match('(\d{3})-(\d{3})-(\d{4})') }} + tpl = template.Template(r""" +{{ '123-456-7890' | regex_match('(\\d{3})-(\\d{3})-(\\d{4})') }} """, self.hass) self.assertEqual('True', tpl.render()) @@ -528,8 +528,8 @@ class TestHelpersTemplate(unittest.TestCase): def test_regex_search(self): """Test regex_search method.""" - tpl = template.Template(""" -{{ '123-456-7890' | regex_search('(\d{3})-(\d{3})-(\d{4})') }} + tpl = template.Template(r""" +{{ '123-456-7890' | regex_search('(\\d{3})-(\\d{3})-(\\d{4})') }} """, self.hass) self.assertEqual('True', tpl.render()) @@ -545,8 +545,8 @@ class TestHelpersTemplate(unittest.TestCase): def test_regex_replace(self): """Test regex_replace method.""" - tpl = template.Template(""" -{{ 'Hello World' | regex_replace('(Hello\s)',) }} + tpl = template.Template(r""" +{{ 'Hello World' | regex_replace('(Hello\\s)',) }} """, self.hass) self.assertEqual('World', tpl.render()) diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index 813eb84707c..d662f3b1955 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -12,6 +12,8 @@ from yarl import URL from aiohttp.client_exceptions import ClientResponseError +from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE + retype = type(re.compile('')) @@ -216,7 +218,18 @@ def mock_aiohttp_client(): """Context manager to mock aiohttp client.""" mocker = AiohttpClientMocker() + def create_session(hass, *args): + session = mocker.create_session(hass.loop) + + async def close_session(event): + """Close session.""" + await session.close() + + hass.bus.async_listen_once(EVENT_HOMEASSISTANT_CLOSE, close_session) + + return session + with mock.patch( 'homeassistant.helpers.aiohttp_client.async_create_clientsession', - side_effect=lambda hass, *args: mocker.create_session(hass.loop)): + side_effect=create_session): yield mocker From 1be61df9c0596be0fbdce9bd0b15a6bfe56199e8 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 20 Aug 2018 17:39:53 +0200 Subject: [PATCH 075/159] Add recent context (#15989) * Add recent context * Add async_set_context to components not using new services --- homeassistant/components/alert.py | 1 + homeassistant/components/light/__init__.py | 4 ++- homeassistant/helpers/entity.py | 27 ++++++++++++++++-- homeassistant/helpers/service.py | 4 ++- tests/components/counter/test_init.py | 23 ++++++++++++++- tests/components/test_input_boolean.py | 23 ++++++++++++++- tests/components/test_input_datetime.py | 26 ++++++++++++++++- tests/components/test_input_number.py | 26 ++++++++++++++++- tests/components/test_input_select.py | 29 ++++++++++++++++++- tests/components/test_input_text.py | 26 ++++++++++++++++- tests/helpers/test_entity.py | 33 +++++++++++++++++++++- 11 files changed, 211 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/alert.py b/homeassistant/components/alert.py index 80a02b3275d..3ec01fc6ab8 100644 --- a/homeassistant/components/alert.py +++ b/homeassistant/components/alert.py @@ -111,6 +111,7 @@ def async_setup(hass, config): for alert_id in alert_ids: alert = all_alerts[alert_id] + alert.async_set_context(service_call.context) if service_call.service == SERVICE_TURN_ON: yield from alert.async_turn_on() elif service_call.service == SERVICE_TOGGLE: diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index ddee4108e31..bc7f136322b 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -345,6 +345,8 @@ async def async_setup(hass, config): update_tasks = [] for light in target_lights: + light.async_set_context(service.context) + pars = params if not pars: pars = params.copy() @@ -356,7 +358,7 @@ async def async_setup(hass, config): continue update_tasks.append( - light.async_update_ha_state(True, service.context)) + light.async_update_ha_state(True)) if update_tasks: await asyncio.wait(update_tasks, loop=hass.loop) diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index c356c266db6..f27a387b9ee 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -1,5 +1,6 @@ """An abstract class for entities.""" import asyncio +from datetime import timedelta import logging import functools as ft from timeit import default_timer as timer @@ -16,6 +17,7 @@ from homeassistant.config import DATA_CUSTOMIZE from homeassistant.exceptions import NoEntitySpecifiedError from homeassistant.util import ensure_unique_string, slugify from homeassistant.util.async_ import run_callback_threadsafe +from homeassistant.util import dt as dt_util _LOGGER = logging.getLogger(__name__) SLOW_UPDATE_WARNING = 10 @@ -85,6 +87,10 @@ class Entity: # Hold list for functions to call on remove. _on_remove = None + # Context + _context = None + _context_set = None + @property def should_poll(self) -> bool: """Return True if entity has to be polled for state. @@ -173,13 +179,24 @@ class Entity: """Flag supported features.""" return None + @property + def context_recent_time(self): + """Time that a context is considered recent.""" + return timedelta(seconds=5) + # DO NOT OVERWRITE # These properties and methods are either managed by Home Assistant or they # are used to perform a very specific function. Overwriting these may # produce undesirable effects in the entity's operation. + @callback + def async_set_context(self, context): + """Set the context the entity currently operates under.""" + self._context = context + self._context_set = dt_util.utcnow() + @asyncio.coroutine - def async_update_ha_state(self, force_refresh=False, context=None): + def async_update_ha_state(self, force_refresh=False): """Update Home Assistant with current state of entity. If force_refresh == True will update entity before setting state. @@ -278,8 +295,14 @@ class Entity: # Could not convert state to float pass + if (self._context is not None and + dt_util.utcnow() - self._context_set > + self.context_recent_time): + self._context = None + self._context_set = None + self.hass.states.async_set( - self.entity_id, state, attr, self.force_update, context) + self.entity_id, state, attr, self.force_update, self._context) def schedule_update_ha_state(self, force_refresh=False): """Schedule an update ha state change task. diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index acad72a860a..fcdc3cfe856 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -218,13 +218,15 @@ async def _handle_service_platform_call(func, data, entities, context): if not entity.available: continue + entity.async_set_context(context) + if isinstance(func, str): await getattr(entity, func)(**data) else: await func(entity, data) if entity.should_poll: - tasks.append(entity.async_update_ha_state(True, context)) + tasks.append(entity.async_update_ha_state(True)) if tasks: await asyncio.wait(tasks) diff --git a/tests/components/counter/test_init.py b/tests/components/counter/test_init.py index f4c6ee9c7da..af36c1c8f95 100644 --- a/tests/components/counter/test_init.py +++ b/tests/components/counter/test_init.py @@ -4,7 +4,7 @@ import asyncio import unittest import logging -from homeassistant.core import CoreState, State +from homeassistant.core import CoreState, State, Context from homeassistant.setup import setup_component, async_setup_component from homeassistant.components.counter import ( DOMAIN, decrement, increment, reset, CONF_INITIAL, CONF_STEP, CONF_NAME, @@ -202,3 +202,24 @@ def test_no_initial_state_and_no_restore_state(hass): state = hass.states.get('counter.test1') assert state assert int(state.state) == 0 + + +async def test_counter_context(hass): + """Test that counter context works.""" + assert await async_setup_component(hass, 'counter', { + 'counter': { + 'test': {} + } + }) + + state = hass.states.get('counter.test') + assert state is not None + + await hass.services.async_call('counter', 'increment', { + 'entity_id': state.entity_id, + }, True, Context(user_id='abcd')) + + state2 = hass.states.get('counter.test') + assert state2 is not None + assert state.state != state2.state + assert state2.context.user_id == 'abcd' diff --git a/tests/components/test_input_boolean.py b/tests/components/test_input_boolean.py index 964d1763e4e..999e7ac100f 100644 --- a/tests/components/test_input_boolean.py +++ b/tests/components/test_input_boolean.py @@ -4,7 +4,7 @@ import asyncio import unittest import logging -from homeassistant.core import CoreState, State +from homeassistant.core import CoreState, State, Context from homeassistant.setup import setup_component, async_setup_component from homeassistant.components.input_boolean import ( DOMAIN, is_on, toggle, turn_off, turn_on, CONF_INITIAL) @@ -158,3 +158,24 @@ def test_initial_state_overrules_restore_state(hass): state = hass.states.get('input_boolean.b2') assert state assert state.state == 'on' + + +async def test_input_boolean_context(hass): + """Test that input_boolean context works.""" + assert await async_setup_component(hass, 'input_boolean', { + 'input_boolean': { + 'ac': {CONF_INITIAL: True}, + } + }) + + state = hass.states.get('input_boolean.ac') + assert state is not None + + await hass.services.async_call('input_boolean', 'turn_off', { + 'entity_id': state.entity_id, + }, True, Context(user_id='abcd')) + + state2 = hass.states.get('input_boolean.ac') + assert state2 is not None + assert state.state != state2.state + assert state2.context.user_id == 'abcd' diff --git a/tests/components/test_input_datetime.py b/tests/components/test_input_datetime.py index 0d21061e022..9ced2aaa072 100644 --- a/tests/components/test_input_datetime.py +++ b/tests/components/test_input_datetime.py @@ -4,7 +4,7 @@ import asyncio import unittest import datetime -from homeassistant.core import CoreState, State +from homeassistant.core import CoreState, State, Context from homeassistant.setup import setup_component, async_setup_component from homeassistant.components.input_datetime import ( DOMAIN, ATTR_ENTITY_ID, ATTR_DATE, ATTR_TIME, SERVICE_SET_DATETIME) @@ -208,3 +208,27 @@ def test_restore_state(hass): state_bogus = hass.states.get('input_datetime.test_bogus_data') assert state_bogus.state == str(initial) + + +async def test_input_datetime_context(hass): + """Test that input_datetime context works.""" + assert await async_setup_component(hass, 'input_datetime', { + 'input_datetime': { + 'only_date': { + 'has_date': True, + } + } + }) + + state = hass.states.get('input_datetime.only_date') + assert state is not None + + await hass.services.async_call('input_datetime', 'set_datetime', { + 'entity_id': state.entity_id, + 'date': '2018-01-02' + }, True, Context(user_id='abcd')) + + state2 = hass.states.get('input_datetime.only_date') + assert state2 is not None + assert state.state != state2.state + assert state2.context.user_id == 'abcd' diff --git a/tests/components/test_input_number.py b/tests/components/test_input_number.py index d416dcae154..659aaa524d9 100644 --- a/tests/components/test_input_number.py +++ b/tests/components/test_input_number.py @@ -3,7 +3,7 @@ import asyncio import unittest -from homeassistant.core import CoreState, State +from homeassistant.core import CoreState, State, Context from homeassistant.setup import setup_component, async_setup_component from homeassistant.components.input_number import ( DOMAIN, set_value, increment, decrement) @@ -236,3 +236,27 @@ def test_no_initial_state_and_no_restore_state(hass): state = hass.states.get('input_number.b1') assert state assert float(state.state) == 0 + + +async def test_input_number_context(hass): + """Test that input_number context works.""" + assert await async_setup_component(hass, 'input_number', { + 'input_number': { + 'b1': { + 'min': 0, + 'max': 100, + }, + } + }) + + state = hass.states.get('input_number.b1') + assert state is not None + + await hass.services.async_call('input_number', 'increment', { + 'entity_id': state.entity_id, + }, True, Context(user_id='abcd')) + + state2 = hass.states.get('input_number.b1') + assert state2 is not None + assert state.state != state2.state + assert state2.context.user_id == 'abcd' diff --git a/tests/components/test_input_select.py b/tests/components/test_input_select.py index 82da80253c5..1c73abfbb94 100644 --- a/tests/components/test_input_select.py +++ b/tests/components/test_input_select.py @@ -5,7 +5,7 @@ import unittest from tests.common import get_test_home_assistant, mock_restore_cache -from homeassistant.core import State +from homeassistant.core import State, Context from homeassistant.setup import setup_component, async_setup_component from homeassistant.components.input_select import ( ATTR_OPTIONS, DOMAIN, SERVICE_SET_OPTIONS, @@ -276,3 +276,30 @@ def test_initial_state_overrules_restore_state(hass): state = hass.states.get('input_select.s2') assert state assert state.state == 'middle option' + + +async def test_input_select_context(hass): + """Test that input_select context works.""" + assert await async_setup_component(hass, 'input_select', { + 'input_select': { + 's1': { + 'options': [ + 'first option', + 'middle option', + 'last option', + ], + } + } + }) + + state = hass.states.get('input_select.s1') + assert state is not None + + await hass.services.async_call('input_select', 'select_next', { + 'entity_id': state.entity_id, + }, True, Context(user_id='abcd')) + + state2 = hass.states.get('input_select.s1') + assert state2 is not None + assert state.state != state2.state + assert state2.context.user_id == 'abcd' diff --git a/tests/components/test_input_text.py b/tests/components/test_input_text.py index 405f7de8272..7c8a0e65023 100644 --- a/tests/components/test_input_text.py +++ b/tests/components/test_input_text.py @@ -3,7 +3,7 @@ import asyncio import unittest -from homeassistant.core import CoreState, State +from homeassistant.core import CoreState, State, Context from homeassistant.setup import setup_component, async_setup_component from homeassistant.components.input_text import (DOMAIN, set_value) @@ -180,3 +180,27 @@ def test_no_initial_state_and_no_restore_state(hass): state = hass.states.get('input_text.b1') assert state assert str(state.state) == 'unknown' + + +async def test_input_text_context(hass): + """Test that input_text context works.""" + assert await async_setup_component(hass, 'input_text', { + 'input_text': { + 't1': { + 'initial': 'bla', + } + } + }) + + state = hass.states.get('input_text.t1') + assert state is not None + + await hass.services.async_call('input_text', 'set_value', { + 'entity_id': state.entity_id, + 'value': 'new_value', + }, True, Context(user_id='abcd')) + + state2 = hass.states.get('input_text.t1') + assert state2 is not None + assert state.state != state2.state + assert state2.context.user_id == 'abcd' diff --git a/tests/helpers/test_entity.py b/tests/helpers/test_entity.py index f9355f97ba3..a51787225ca 100644 --- a/tests/helpers/test_entity.py +++ b/tests/helpers/test_entity.py @@ -1,11 +1,13 @@ """Test the entity helper.""" # pylint: disable=protected-access import asyncio -from unittest.mock import MagicMock, patch +from datetime import timedelta +from unittest.mock import MagicMock, patch, PropertyMock import pytest import homeassistant.helpers.entity as entity +from homeassistant.core import Context from homeassistant.const import ATTR_HIDDEN, ATTR_DEVICE_CLASS from homeassistant.config import DATA_CUSTOMIZE from homeassistant.helpers.entity_values import EntityValues @@ -412,3 +414,32 @@ async def test_async_remove_runs_callbacks(hass): ent.async_on_remove(lambda: result.append(1)) await ent.async_remove() assert len(result) == 1 + + +async def test_set_context(hass): + """Test setting context.""" + context = Context() + ent = entity.Entity() + ent.hass = hass + ent.entity_id = 'hello.world' + ent.async_set_context(context) + await ent.async_update_ha_state() + assert hass.states.get('hello.world').context == context + + +async def test_set_context_expired(hass): + """Test setting context.""" + context = Context() + + with patch.object(entity.Entity, 'context_recent_time', + new_callable=PropertyMock) as recent: + recent.return_value = timedelta(seconds=-5) + ent = entity.Entity() + ent.hass = hass + ent.entity_id = 'hello.world' + ent.async_set_context(context) + await ent.async_update_ha_state() + + assert hass.states.get('hello.world').context != context + assert ent._context is None + assert ent._context_set is None From df6239e0fc3d36a56f1892482835ab2c2d2299f2 Mon Sep 17 00:00:00 2001 From: Greg Laabs Date: Mon, 20 Aug 2018 08:42:53 -0700 Subject: [PATCH 076/159] Add ecovacs component (#15520) * Ecovacs Deebot vacuums * All core features implemented Getting fan speed and locating the vac are still unsupported until sucks adds support * Move init queries to the added_to_hass method * Adding support for subscribing to events from the sucks library This support does not exist in sucks yet; this commit serves as a sort of TDD approach of what such support COULD look like. * Add OverloadUT as ecovacs code owner * Full support for Ecovacs vacuums (Deebot) * Add requirements * Linting fixes * Make API Device ID random on each boot * Fix unique ID Never worked before, as it should have been looking for a key, not an attribute * Fix random string generation to work in Python 3.5 (thanks, Travis!) * Add new files to .coveragerc * Code review changes (Will require a sucks version bump in a coming commit; waiting for it to release) * Bump sucks to 0.9.1 now that it has released * Update requirements_all.txt as well * Bump sucks version to fix lifespan value errors * Revert to sucks 0.9.1 and include a fix for a bug in that release Sucks is being slow to release currently, so doing this so we can get a version out the door. * Switch state_attributes to device_state_attributes --- .coveragerc | 3 + CODEOWNERS | 2 + homeassistant/components/ecovacs.py | 87 +++++++++ homeassistant/components/vacuum/ecovacs.py | 198 +++++++++++++++++++++ requirements_all.txt | 3 + 5 files changed, 293 insertions(+) create mode 100644 homeassistant/components/ecovacs.py create mode 100644 homeassistant/components/vacuum/ecovacs.py diff --git a/.coveragerc b/.coveragerc index de1d8463477..989830e5c9d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -104,6 +104,9 @@ omit = homeassistant/components/fritzbox.py homeassistant/components/switch/fritzbox.py + homeassistant/components/ecovacs.py + homeassistant/components/*/ecovacs.py + homeassistant/components/eufy.py homeassistant/components/*/eufy.py diff --git a/CODEOWNERS b/CODEOWNERS index 53f577d02eb..c756cb383d4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -87,6 +87,8 @@ homeassistant/components/*/axis.py @kane610 homeassistant/components/*/bmw_connected_drive.py @ChristianKuehnel homeassistant/components/*/broadlink.py @danielhiversen homeassistant/components/*/deconz.py @kane610 +homeassistant/components/ecovacs.py @OverloadUT +homeassistant/components/*/ecovacs.py @OverloadUT homeassistant/components/eight_sleep.py @mezz64 homeassistant/components/*/eight_sleep.py @mezz64 homeassistant/components/hive.py @Rendili @KJonline diff --git a/homeassistant/components/ecovacs.py b/homeassistant/components/ecovacs.py new file mode 100644 index 00000000000..2e51b048d15 --- /dev/null +++ b/homeassistant/components/ecovacs.py @@ -0,0 +1,87 @@ +"""Parent component for Ecovacs Deebot vacuums. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/ecovacs/ +""" + +import logging +import random +import string + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers import discovery +from homeassistant.const import CONF_USERNAME, CONF_PASSWORD, \ + EVENT_HOMEASSISTANT_STOP + +REQUIREMENTS = ['sucks==0.9.1'] + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = "ecovacs" + +CONF_COUNTRY = "country" +CONF_CONTINENT = "continent" + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + vol.Required(CONF_COUNTRY): vol.All(vol.Lower, cv.string), + vol.Required(CONF_CONTINENT): vol.All(vol.Lower, cv.string), + }) +}, extra=vol.ALLOW_EXTRA) + +ECOVACS_DEVICES = "ecovacs_devices" + +# Generate a random device ID on each bootup +ECOVACS_API_DEVICEID = ''.join( + random.choice(string.ascii_uppercase + string.digits) for _ in range(8) +) + + +def setup(hass, config): + """Set up the Ecovacs component.""" + _LOGGER.debug("Creating new Ecovacs component") + + hass.data[ECOVACS_DEVICES] = [] + + from sucks import EcoVacsAPI, VacBot + + ecovacs_api = EcoVacsAPI(ECOVACS_API_DEVICEID, + config[DOMAIN].get(CONF_USERNAME), + EcoVacsAPI.md5(config[DOMAIN].get(CONF_PASSWORD)), + config[DOMAIN].get(CONF_COUNTRY), + config[DOMAIN].get(CONF_CONTINENT)) + + devices = ecovacs_api.devices() + _LOGGER.debug("Ecobot devices: %s", devices) + + for device in devices: + _LOGGER.info("Discovered Ecovacs device on account: %s", + device['nick']) + vacbot = VacBot(ecovacs_api.uid, + ecovacs_api.REALM, + ecovacs_api.resource, + ecovacs_api.user_access_token, + device, + config[DOMAIN].get(CONF_CONTINENT).lower(), + monitor=True) + hass.data[ECOVACS_DEVICES].append(vacbot) + + def stop(event: object) -> None: + """Shut down open connections to Ecovacs XMPP server.""" + for device in hass.data[ECOVACS_DEVICES]: + _LOGGER.info("Shutting down connection to Ecovacs device %s", + device.vacuum['nick']) + device.disconnect() + + # Listen for HA stop to disconnect. + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop) + + if hass.data[ECOVACS_DEVICES]: + _LOGGER.debug("Starting vacuum components") + discovery.load_platform(hass, "vacuum", DOMAIN, {}, config) + + return True diff --git a/homeassistant/components/vacuum/ecovacs.py b/homeassistant/components/vacuum/ecovacs.py new file mode 100644 index 00000000000..e0870a48861 --- /dev/null +++ b/homeassistant/components/vacuum/ecovacs.py @@ -0,0 +1,198 @@ +""" +Support for Ecovacs Ecovacs Vaccums. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/vacuum.neato/ +""" +import logging + +from homeassistant.components.vacuum import ( + VacuumDevice, SUPPORT_BATTERY, SUPPORT_RETURN_HOME, SUPPORT_CLEAN_SPOT, + SUPPORT_STATUS, SUPPORT_STOP, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, + SUPPORT_LOCATE, SUPPORT_FAN_SPEED, SUPPORT_SEND_COMMAND, ) +from homeassistant.components.ecovacs import ( + ECOVACS_DEVICES) +from homeassistant.helpers.icon import icon_for_battery_level + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['ecovacs'] + +SUPPORT_ECOVACS = ( + SUPPORT_BATTERY | SUPPORT_RETURN_HOME | SUPPORT_CLEAN_SPOT | + SUPPORT_STOP | SUPPORT_TURN_OFF | SUPPORT_TURN_ON | SUPPORT_LOCATE | + SUPPORT_STATUS | SUPPORT_SEND_COMMAND | SUPPORT_FAN_SPEED) + +ATTR_ERROR = 'error' +ATTR_COMPONENT_PREFIX = 'component_' + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the Ecovacs vacuums.""" + vacuums = [] + for device in hass.data[ECOVACS_DEVICES]: + vacuums.append(EcovacsVacuum(device)) + _LOGGER.debug("Adding Ecovacs Vacuums to Hass: %s", vacuums) + add_devices(vacuums, True) + + +class EcovacsVacuum(VacuumDevice): + """Ecovacs Vacuums such as Deebot.""" + + def __init__(self, device): + """Initialize the Ecovacs Vacuum.""" + self.device = device + self.device.connect_and_wait_until_ready() + try: + self._name = '{}'.format(self.device.vacuum['nick']) + except KeyError: + # In case there is no nickname defined, use the device id + self._name = '{}'.format(self.device.vacuum['did']) + + self._fan_speed = None + self._error = None + _LOGGER.debug("Vacuum initialized: %s", self.name) + + async def async_added_to_hass(self) -> None: + """Set up the event listeners now that hass is ready.""" + self.device.statusEvents.subscribe(lambda _: + self.schedule_update_ha_state()) + self.device.batteryEvents.subscribe(lambda _: + self.schedule_update_ha_state()) + self.device.lifespanEvents.subscribe(lambda _: + self.schedule_update_ha_state()) + self.device.errorEvents.subscribe(self.on_error) + + def on_error(self, error): + """Handle an error event from the robot. + + This will not change the entity's state. If the error caused the state + to change, that will come through as a separate on_status event + """ + if error == 'no_error': + self._error = None + else: + self._error = error + + self.hass.bus.fire('ecovacs_error', { + 'entity_id': self.entity_id, + 'error': error + }) + self.schedule_update_ha_state() + + @property + def should_poll(self) -> bool: + """Return True if entity has to be polled for state.""" + return False + + @property + def unique_id(self) -> str: + """Return an unique ID.""" + return self.device.vacuum.get('did', None) + + @property + def is_on(self): + """Return true if vacuum is currently cleaning.""" + return self.device.is_cleaning + + @property + def is_charging(self): + """Return true if vacuum is currently charging.""" + return self.device.is_charging + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def supported_features(self): + """Flag vacuum cleaner robot features that are supported.""" + return SUPPORT_ECOVACS + + @property + def status(self): + """Return the status of the vacuum cleaner.""" + return self.device.vacuum_status + + def return_to_base(self, **kwargs): + """Set the vacuum cleaner to return to the dock.""" + from sucks import Charge + self.device.run(Charge()) + + @property + def battery_icon(self): + """Return the battery icon for the vacuum cleaner.""" + return icon_for_battery_level( + battery_level=self.battery_level, charging=self.is_charging) + + @property + def battery_level(self): + """Return the battery level of the vacuum cleaner.""" + if self.device.battery_status is not None: + return self.device.battery_status * 100 + + return super().battery_level + + @property + def fan_speed(self): + """Return the fan speed of the vacuum cleaner.""" + return self.device.fan_speed + + @property + def fan_speed_list(self): + """Get the list of available fan speed steps of the vacuum cleaner.""" + from sucks import FAN_SPEED_NORMAL, FAN_SPEED_HIGH + return [FAN_SPEED_NORMAL, FAN_SPEED_HIGH] + + def turn_on(self, **kwargs): + """Turn the vacuum on and start cleaning.""" + from sucks import Clean + self.device.run(Clean()) + + def turn_off(self, **kwargs): + """Turn the vacuum off stopping the cleaning and returning home.""" + self.return_to_base() + + def stop(self, **kwargs): + """Stop the vacuum cleaner.""" + from sucks import Stop + self.device.run(Stop()) + + def clean_spot(self, **kwargs): + """Perform a spot clean-up.""" + from sucks import Spot + self.device.run(Spot()) + + def locate(self, **kwargs): + """Locate the vacuum cleaner.""" + from sucks import PlaySound + self.device.run(PlaySound()) + + def set_fan_speed(self, fan_speed, **kwargs): + """Set fan speed.""" + if self.is_on: + from sucks import Clean + self.device.run(Clean( + mode=self.device.clean_status, speed=fan_speed)) + + def send_command(self, command, params=None, **kwargs): + """Send a command to a vacuum cleaner.""" + from sucks import VacBotCommand + self.device.run(VacBotCommand(command, params)) + + @property + def device_state_attributes(self): + """Return the device-specific state attributes of this vacuum.""" + data = {} + data[ATTR_ERROR] = self._error + + for key, val in self.device.components.items(): + attr_name = ATTR_COMPONENT_PREFIX + key + data[attr_name] = int(val * 100 / 0.2777778) + # The above calculation includes a fix for a bug in sucks 0.9.1 + # When sucks 0.9.2+ is released, it should be changed to the + # following: + # data[attr_name] = int(val * 100) + + return data diff --git a/requirements_all.txt b/requirements_all.txt index 2c0bb46a73f..468076fc4e8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1339,6 +1339,9 @@ statsd==3.2.1 # homeassistant.components.sensor.steam_online steamodd==4.21 +# homeassistant.components.ecovacs +sucks==0.9.1 + # homeassistant.components.camera.onvif suds-passworddigest-homeassistant==0.1.2a0.dev0 From 85a724e2898f4a02d5e9fe4410daff77b82e6e94 Mon Sep 17 00:00:00 2001 From: Andrey Kupreychik Date: Mon, 20 Aug 2018 23:51:25 +0700 Subject: [PATCH 077/159] Bumped NDMS2 client library to 0.0.4 to get compatible with python 3.5 (#16077) --- homeassistant/components/device_tracker/keenetic_ndms2.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/device_tracker/keenetic_ndms2.py b/homeassistant/components/device_tracker/keenetic_ndms2.py index 4b5e3d6333d..4be6d96eb5a 100644 --- a/homeassistant/components/device_tracker/keenetic_ndms2.py +++ b/homeassistant/components/device_tracker/keenetic_ndms2.py @@ -15,7 +15,7 @@ from homeassistant.const import ( CONF_HOST, CONF_PORT, CONF_PASSWORD, CONF_USERNAME ) -REQUIREMENTS = ['ndms2_client==0.0.3'] +REQUIREMENTS = ['ndms2_client==0.0.4'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 468076fc4e8..1b2e4d7a220 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -594,7 +594,7 @@ nad_receiver==0.0.9 nanoleaf==0.4.1 # homeassistant.components.device_tracker.keenetic_ndms2 -ndms2_client==0.0.3 +ndms2_client==0.0.4 # homeassistant.components.sensor.netdata netdata==0.1.2 From 439f7978c3d2db189915b66c9f8ebd97bd2f799c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Mon, 20 Aug 2018 22:42:48 +0200 Subject: [PATCH 078/159] fritzdect change to current_power_w (#16079) --- homeassistant/components/switch/fritzdect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/switch/fritzdect.py b/homeassistant/components/switch/fritzdect.py index 9c0f852846a..36a53edefc9 100644 --- a/homeassistant/components/switch/fritzdect.py +++ b/homeassistant/components/switch/fritzdect.py @@ -105,7 +105,7 @@ class FritzDectSwitch(SwitchDevice): return attrs @property - def current_power_watt(self): + def current_power_w(self): """Return the current power usage in Watt.""" try: return float(self.data.current_consumption) From b1ba11510b9fd840cf3b2a672f033ecafa4dd11f Mon Sep 17 00:00:00 2001 From: Daniel Perna Date: Mon, 20 Aug 2018 23:43:04 +0200 Subject: [PATCH 079/159] Update pyhomematic to 0.1.47 (#16083) --- homeassistant/components/homematic/__init__.py | 6 +++--- requirements_all.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/homematic/__init__.py b/homeassistant/components/homematic/__init__.py index 76c97793da0..7b50d1f1cda 100644 --- a/homeassistant/components/homematic/__init__.py +++ b/homeassistant/components/homematic/__init__.py @@ -20,7 +20,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.loader import bind_hass -REQUIREMENTS = ['pyhomematic==0.1.46'] +REQUIREMENTS = ['pyhomematic==0.1.47'] _LOGGER = logging.getLogger(__name__) @@ -78,7 +78,7 @@ HM_DEVICE_TYPES = { DISCOVER_CLIMATE: [ 'Thermostat', 'ThermostatWall', 'MAXThermostat', 'ThermostatWall2', 'MAXWallThermostat', 'IPThermostat', 'IPThermostatWall', - 'ThermostatGroup'], + 'ThermostatGroup', 'IPThermostatWall230V'], DISCOVER_BINARY_SENSORS: [ 'ShutterContact', 'Smoke', 'SmokeV2', 'Motion', 'MotionV2', 'MotionIP', 'RemoteMotion', 'WeatherSensor', 'TiltSensor', @@ -103,7 +103,7 @@ HM_ATTRIBUTE_SUPPORT = { 'LOW_BAT': ['battery', {0: 'High', 1: 'Low'}], 'ERROR': ['sabotage', {0: 'No', 1: 'Yes'}], 'SABOTAGE': ['sabotage', {0: 'No', 1: 'Yes'}], - 'RSSI_DEVICE': ['rssi', {}], + 'RSSI_PEER': ['rssi', {}], 'VALVE_STATE': ['valve', {}], 'BATTERY_STATE': ['battery', {}], 'CONTROL_MODE': ['mode', { diff --git a/requirements_all.txt b/requirements_all.txt index 1b2e4d7a220..5041b4d4bfd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -876,7 +876,7 @@ pyhik==0.1.8 pyhiveapi==0.2.14 # homeassistant.components.homematic -pyhomematic==0.1.46 +pyhomematic==0.1.47 # homeassistant.components.sensor.hydroquebec pyhydroquebec==2.2.2 From f84a31871e80fb69490670ae176fb7dd0d1672a6 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 21 Aug 2018 01:18:04 -0700 Subject: [PATCH 080/159] Get user after login flow finished (#16047) * Get user after login flow finished * Add optional parameter 'type' to /auth/login_flow * Update __init__.py --- homeassistant/auth/__init__.py | 13 +++-- homeassistant/components/auth/__init__.py | 59 ++++++++++++-------- homeassistant/components/auth/login_flow.py | 25 ++++++--- tests/auth/test_init.py | 18 +++--- tests/components/auth/test_init.py | 19 ++++--- tests/components/auth/test_init_link_user.py | 1 + 6 files changed, 83 insertions(+), 52 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index b710ca9999e..52240ab78c6 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -2,7 +2,7 @@ import asyncio import logging from collections import OrderedDict -from typing import Any, Dict, List, Optional, Tuple, cast +from typing import Any, Dict, List, Optional, Tuple, cast, Union import jwt @@ -257,15 +257,20 @@ class AuthManager: async def _async_finish_login_flow( self, context: Optional[Dict], result: Dict[str, Any]) \ - -> Optional[models.Credentials]: - """Result of a credential login flow.""" + -> Optional[Union[models.User, models.Credentials]]: + """Return a user as result of login flow.""" if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: return None auth_provider = self._providers[result['handler']] - return await auth_provider.async_get_or_create_credentials( + cred = await auth_provider.async_get_or_create_credentials( result['data']) + if context is not None and context.get('credential_only'): + return cred + + return await self.async_get_or_create_user(cred) + @callback def _async_get_auth_provider( self, credentials: models.Credentials) -> Optional[AuthProvider]: diff --git a/homeassistant/components/auth/__init__.py b/homeassistant/components/auth/__init__.py index 102bfe58b55..08bb3e679b8 100644 --- a/homeassistant/components/auth/__init__.py +++ b/homeassistant/components/auth/__init__.py @@ -51,6 +51,7 @@ from datetime import timedelta import voluptuous as vol +from homeassistant.auth.models import User, Credentials from homeassistant.components import websocket_api from homeassistant.components.http.ban import log_invalid_auth from homeassistant.components.http.data_validator import RequestDataValidator @@ -68,22 +69,25 @@ SCHEMA_WS_CURRENT_USER = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ vol.Required('type'): WS_TYPE_CURRENT_USER, }) +RESULT_TYPE_CREDENTIALS = 'credentials' +RESULT_TYPE_USER = 'user' + _LOGGER = logging.getLogger(__name__) async def async_setup(hass, config): """Component to allow users to login.""" - store_credentials, retrieve_credentials = _create_cred_store() + store_result, retrieve_result = _create_auth_code_store() - hass.http.register_view(GrantTokenView(retrieve_credentials)) - hass.http.register_view(LinkUserView(retrieve_credentials)) + hass.http.register_view(GrantTokenView(retrieve_result)) + hass.http.register_view(LinkUserView(retrieve_result)) hass.components.websocket_api.async_register_command( WS_TYPE_CURRENT_USER, websocket_current_user, SCHEMA_WS_CURRENT_USER ) - await login_flow.async_setup(hass, store_credentials) + await login_flow.async_setup(hass, store_result) return True @@ -96,9 +100,9 @@ class GrantTokenView(HomeAssistantView): requires_auth = False cors_allowed = True - def __init__(self, retrieve_credentials): + def __init__(self, retrieve_user): """Initialize the grant token view.""" - self._retrieve_credentials = retrieve_credentials + self._retrieve_user = retrieve_user @log_invalid_auth async def post(self, request): @@ -134,15 +138,16 @@ class GrantTokenView(HomeAssistantView): 'error': 'invalid_request', }, status_code=400) - credentials = self._retrieve_credentials(client_id, code) + user = self._retrieve_user(client_id, RESULT_TYPE_USER, code) - if credentials is None: + if user is None or not isinstance(user, User): return self.json({ 'error': 'invalid_request', 'error_description': 'Invalid code', }, status_code=400) - user = await hass.auth.async_get_or_create_user(credentials) + # refresh user + user = await hass.auth.async_get_user(user.id) if not user.is_active: return self.json({ @@ -220,7 +225,7 @@ class LinkUserView(HomeAssistantView): user = request['hass_user'] credentials = self._retrieve_credentials( - data['client_id'], data['code']) + data['client_id'], RESULT_TYPE_CREDENTIALS, data['code']) if credentials is None: return self.json_message('Invalid code', status_code=400) @@ -230,37 +235,45 @@ class LinkUserView(HomeAssistantView): @callback -def _create_cred_store(): - """Create a credential store.""" - temp_credentials = {} +def _create_auth_code_store(): + """Create an in memory store.""" + temp_results = {} @callback - def store_credentials(client_id, credentials): - """Store credentials and return a code to retrieve it.""" + def store_result(client_id, result): + """Store flow result and return a code to retrieve it.""" + if isinstance(result, User): + result_type = RESULT_TYPE_USER + elif isinstance(result, Credentials): + result_type = RESULT_TYPE_CREDENTIALS + else: + raise ValueError('result has to be either User or Credentials') + code = uuid.uuid4().hex - temp_credentials[(client_id, code)] = (dt_util.utcnow(), credentials) + temp_results[(client_id, result_type, code)] = \ + (dt_util.utcnow(), result_type, result) return code @callback - def retrieve_credentials(client_id, code): - """Retrieve credentials.""" - key = (client_id, code) + def retrieve_result(client_id, result_type, code): + """Retrieve flow result.""" + key = (client_id, result_type, code) - if key not in temp_credentials: + if key not in temp_results: return None - created, credentials = temp_credentials.pop(key) + created, _, result = temp_results.pop(key) # OAuth 4.2.1 # The authorization code MUST expire shortly after it is issued to # mitigate the risk of leaks. A maximum authorization code lifetime of # 10 minutes is RECOMMENDED. if dt_util.utcnow() - created < timedelta(minutes=10): - return credentials + return result return None - return store_credentials, retrieve_credentials + return store_result, retrieve_result @callback diff --git a/homeassistant/components/auth/login_flow.py b/homeassistant/components/auth/login_flow.py index e1d21bbb632..a518bdde415 100644 --- a/homeassistant/components/auth/login_flow.py +++ b/homeassistant/components/auth/login_flow.py @@ -22,10 +22,14 @@ Pass in parameter 'client_id' and 'redirect_url' validate by indieauth. Pass in parameter 'handler' to specify the auth provider to use. Auth providers are identified by type and id. +And optional parameter 'type' has to set as 'link_user' if login flow used for +link credential to exist user. Default 'type' is 'authorize'. + { "client_id": "https://hassbian.local:8123/", "handler": ["local_provider", null], - "redirect_url": "https://hassbian.local:8123/" + "redirect_url": "https://hassbian.local:8123/", + "type': "authorize" } Return value will be a step in a data entry flow. See the docs for data entry @@ -49,6 +53,9 @@ flow for details. Progress the flow. Most flows will be 1 page, but could optionally add extra login challenges, like TFA. Once the flow has finished, the returned step will have type "create_entry" and "result" key will contain an authorization code. +The authorization code associated with an authorized user by default, it will +associate with an credential if "type" set to "link_user" in +"/auth/login_flow" { "flow_id": "8f7e42faab604bcab7ac43c44ca34d58", @@ -71,12 +78,12 @@ from homeassistant.components.http.view import HomeAssistantView from . import indieauth -async def async_setup(hass, store_credentials): +async def async_setup(hass, store_result): """Component to allow users to login.""" hass.http.register_view(AuthProvidersView) hass.http.register_view(LoginFlowIndexView(hass.auth.login_flow)) hass.http.register_view( - LoginFlowResourceView(hass.auth.login_flow, store_credentials)) + LoginFlowResourceView(hass.auth.login_flow, store_result)) class AuthProvidersView(HomeAssistantView): @@ -138,6 +145,7 @@ class LoginFlowIndexView(HomeAssistantView): vol.Required('client_id'): str, vol.Required('handler'): vol.Any(str, list), vol.Required('redirect_uri'): str, + vol.Optional('type', default='authorize'): str, })) @log_invalid_auth async def post(self, request, data): @@ -153,7 +161,10 @@ class LoginFlowIndexView(HomeAssistantView): try: result = await self._flow_mgr.async_init( - handler, context={'ip_address': request[KEY_REAL_IP]}) + handler, context={ + 'ip_address': request[KEY_REAL_IP], + 'credential_only': data.get('type') == 'link_user', + }) except data_entry_flow.UnknownHandler: return self.json_message('Invalid handler specified', 404) except data_entry_flow.UnknownStep: @@ -169,10 +180,10 @@ class LoginFlowResourceView(HomeAssistantView): name = 'api:auth:login_flow:resource' requires_auth = False - def __init__(self, flow_mgr, store_credentials): + def __init__(self, flow_mgr, store_result): """Initialize the login flow resource view.""" self._flow_mgr = flow_mgr - self._store_credentials = store_credentials + self._store_result = store_result async def get(self, request): """Do not allow getting status of a flow in progress.""" @@ -212,7 +223,7 @@ class LoginFlowResourceView(HomeAssistantView): return self.json(_prepare_result_json(result)) result.pop('data') - result['result'] = self._store_credentials(client_id, result['result']) + result['result'] = self._store_result(client_id, result['result']) return self.json(result) diff --git a/tests/auth/test_init.py b/tests/auth/test_init.py index da5daca7cf6..5ea3b528b4e 100644 --- a/tests/auth/test_init.py +++ b/tests/auth/test_init.py @@ -77,8 +77,7 @@ async def test_create_new_user(hass, hass_storage): 'password': 'test-pass', }) assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - credentials = step['result'] - user = await manager.async_get_or_create_user(credentials) + user = step['result'] assert user is not None assert user.is_owner is False assert user.name == 'Test Name' @@ -134,9 +133,8 @@ async def test_login_as_existing_user(mock_hass): 'password': 'test-pass', }) assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - credentials = step['result'] - user = await manager.async_get_or_create_user(credentials) + user = step['result'] assert user is not None assert user.id == 'mock-user' assert user.is_owner is False @@ -166,16 +164,18 @@ async def test_linking_user_to_two_auth_providers(hass, hass_storage): 'username': 'test-user', 'password': 'test-pass', }) - user = await manager.async_get_or_create_user(step['result']) + user = step['result'] assert user is not None - step = await manager.login_flow.async_init(('insecure_example', - 'another-provider')) + step = await manager.login_flow.async_init( + ('insecure_example', 'another-provider'), + context={'credential_only': True}) step = await manager.login_flow.async_configure(step['flow_id'], { 'username': 'another-user', 'password': 'another-password', }) - await manager.async_link_user(user, step['result']) + new_credential = step['result'] + await manager.async_link_user(user, new_credential) assert len(user.credentials) == 2 @@ -197,7 +197,7 @@ async def test_saving_loading(hass, hass_storage): 'username': 'test-user', 'password': 'test-pass', }) - user = await manager.async_get_or_create_user(step['result']) + user = step['result'] await manager.async_activate_user(user) await manager.async_create_refresh_token(user, CLIENT_ID) diff --git a/tests/components/auth/test_init.py b/tests/components/auth/test_init.py index f1a1bb5bd3c..79749da1461 100644 --- a/tests/components/auth/test_init.py +++ b/tests/components/auth/test_init.py @@ -3,13 +3,14 @@ from datetime import timedelta from unittest.mock import patch from homeassistant.auth.models import Credentials +from homeassistant.components.auth import RESULT_TYPE_USER from homeassistant.setup import async_setup_component from homeassistant.util.dt import utcnow from homeassistant.components import auth from . import async_setup_auth -from tests.common import CLIENT_ID, CLIENT_REDIRECT_URI +from tests.common import CLIENT_ID, CLIENT_REDIRECT_URI, MockUser async def test_login_new_user_and_trying_refresh_token(hass, aiohttp_client): @@ -74,26 +75,26 @@ async def test_login_new_user_and_trying_refresh_token(hass, aiohttp_client): assert resp.status == 200 -def test_credential_store_expiration(): - """Test that the credential store will not return expired tokens.""" - store, retrieve = auth._create_cred_store() +def test_auth_code_store_expiration(): + """Test that the auth code store will not return expired tokens.""" + store, retrieve = auth._create_auth_code_store() client_id = 'bla' - credentials = 'creds' + user = MockUser(id='mock_user') now = utcnow() with patch('homeassistant.util.dt.utcnow', return_value=now): - code = store(client_id, credentials) + code = store(client_id, user) with patch('homeassistant.util.dt.utcnow', return_value=now + timedelta(minutes=10)): - assert retrieve(client_id, code) is None + assert retrieve(client_id, RESULT_TYPE_USER, code) is None with patch('homeassistant.util.dt.utcnow', return_value=now): - code = store(client_id, credentials) + code = store(client_id, user) with patch('homeassistant.util.dt.utcnow', return_value=now + timedelta(minutes=9, seconds=59)): - assert retrieve(client_id, code) == credentials + assert retrieve(client_id, RESULT_TYPE_USER, code) == user async def test_ws_current_user(hass, hass_ws_client, hass_access_token): diff --git a/tests/components/auth/test_init_link_user.py b/tests/components/auth/test_init_link_user.py index e209e0ee856..5166f661491 100644 --- a/tests/components/auth/test_init_link_user.py +++ b/tests/components/auth/test_init_link_user.py @@ -34,6 +34,7 @@ async def async_get_code(hass, aiohttp_client): 'client_id': CLIENT_ID, 'handler': ['insecure_example', '2nd auth'], 'redirect_uri': CLIENT_REDIRECT_URI, + 'type': 'link_user', }) assert resp.status == 200 step = await resp.json() From ef07460792dc674b91143b79fa39b8684d71fe21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Tue, 21 Aug 2018 10:56:28 +0200 Subject: [PATCH 081/159] Upgrade pytest to 3.7.2 (#16091) --- 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 5c2bd3404ed..542c378c89f 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -13,5 +13,5 @@ pytest-aiohttp==0.3.0 pytest-cov==2.5.1 pytest-sugar==0.9.1 pytest-timeout==1.3.1 -pytest==3.7.1 +pytest==3.7.2 requests_mock==1.5.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f158327feca..73e5aa88e04 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -14,7 +14,7 @@ pytest-aiohttp==0.3.0 pytest-cov==2.5.1 pytest-sugar==0.9.1 pytest-timeout==1.3.1 -pytest==3.7.1 +pytest==3.7.2 requests_mock==1.5.2 From 68cd65567d5cf6333129f62f610c5df63b53cf12 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 21 Aug 2018 11:41:52 +0200 Subject: [PATCH 082/159] Forgiving add index in migration (#16092) --- homeassistant/components/recorder/migration.py | 11 ++++++++++- tests/components/recorder/test_migrate.py | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/recorder/migration.py b/homeassistant/components/recorder/migration.py index 0dff21a5986..207f2f53a7f 100644 --- a/homeassistant/components/recorder/migration.py +++ b/homeassistant/components/recorder/migration.py @@ -57,6 +57,7 @@ def _create_index(engine, table_name, index_name): within the table definition described in the models """ from sqlalchemy import Table + from sqlalchemy.exc import OperationalError from . import models table = Table(table_name, models.Base.metadata) @@ -67,7 +68,15 @@ def _create_index(engine, table_name, index_name): _LOGGER.info("Adding index `%s` to database. Note: this can take several " "minutes on large databases and slow computers. Please " "be patient!", index_name) - index.create(engine) + try: + index.create(engine) + except OperationalError as err: + if 'already exists' not in str(err).lower(): + raise + + _LOGGER.warning('Index %s already exists on %s, continueing', + index_name, table_name) + _LOGGER.debug("Finished creating %s", index_name) diff --git a/tests/components/recorder/test_migrate.py b/tests/components/recorder/test_migrate.py index 1c48c261372..93da4ec109b 100644 --- a/tests/components/recorder/test_migrate.py +++ b/tests/components/recorder/test_migrate.py @@ -80,3 +80,13 @@ def test_forgiving_add_column(): migration._add_columns(engine, 'hello', [ 'context_id CHARACTER(36)', ]) + + +def test_forgiving_add_index(): + """Test that add index will continue if index exists.""" + engine = create_engine( + 'sqlite://', + poolclass=StaticPool + ) + models.Base.metadata.create_all(engine) + migration._create_index(engine, "states", "ix_states_context_id") From 507e8f8f1210a2c2ca21a870ac9ad9a1581e0b52 Mon Sep 17 00:00:00 2001 From: Flip Hess Date: Tue, 21 Aug 2018 15:29:11 +0200 Subject: [PATCH 083/159] Add verify ssl to generic camera (#15949) * Add verify_ssl option to generic camera * Remove flake8 errors * Add test for ssl verification on and off * Fix lint errors --- homeassistant/components/camera/generic.py | 10 +++-- tests/components/camera/test_generic.py | 45 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/camera/generic.py b/homeassistant/components/camera/generic.py index 911c14e7232..d1b5c7214fc 100644 --- a/homeassistant/components/camera/generic.py +++ b/homeassistant/components/camera/generic.py @@ -15,7 +15,7 @@ import voluptuous as vol from homeassistant.const import ( CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_AUTHENTICATION, - HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION) + HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION, CONF_VERIFY_SSL) from homeassistant.exceptions import TemplateError from homeassistant.components.camera import ( PLATFORM_SCHEMA, DEFAULT_CONTENT_TYPE, Camera) @@ -42,6 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_USERNAME): cv.string, vol.Optional(CONF_CONTENT_TYPE, default=DEFAULT_CONTENT_TYPE): cv.string, vol.Optional(CONF_FRAMERATE, default=2): cv.positive_int, + vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean, }) @@ -65,6 +66,7 @@ class GenericCamera(Camera): self._limit_refetch = device_info[CONF_LIMIT_REFETCH_TO_URL_CHANGE] self._frame_interval = 1 / device_info[CONF_FRAMERATE] self.content_type = device_info[CONF_CONTENT_TYPE] + self.verify_ssl = device_info[CONF_VERIFY_SSL] username = device_info.get(CONF_USERNAME) password = device_info.get(CONF_PASSWORD) @@ -108,7 +110,8 @@ class GenericCamera(Camera): def fetch(): """Read image from a URL.""" try: - response = requests.get(url, timeout=10, auth=self._auth) + response = requests.get(url, timeout=10, auth=self._auth, + verify=self.verify_ssl) return response.content except requests.exceptions.RequestException as error: _LOGGER.error("Error getting camera image: %s", error) @@ -119,7 +122,8 @@ class GenericCamera(Camera): # async else: try: - websession = async_get_clientsession(self.hass) + websession = async_get_clientsession( + self.hass, verify_ssl=self.verify_ssl) with async_timeout.timeout(10, loop=self.hass.loop): response = yield from websession.get( url, auth=self._auth) diff --git a/tests/components/camera/test_generic.py b/tests/components/camera/test_generic.py index 01edca1e996..b981fced320 100644 --- a/tests/components/camera/test_generic.py +++ b/tests/components/camera/test_generic.py @@ -1,5 +1,6 @@ """The tests for generic camera component.""" import asyncio + from unittest import mock from homeassistant.setup import async_setup_component @@ -32,6 +33,50 @@ def test_fetching_url(aioclient_mock, hass, aiohttp_client): assert aioclient_mock.call_count == 2 +@asyncio.coroutine +def test_fetching_without_verify_ssl(aioclient_mock, hass, aiohttp_client): + """Test that it fetches the given url when ssl verify is off.""" + aioclient_mock.get('https://example.com', text='hello world') + + yield from async_setup_component(hass, 'camera', { + 'camera': { + 'name': 'config_test', + 'platform': 'generic', + 'still_image_url': 'https://example.com', + 'username': 'user', + 'password': 'pass', + 'verify_ssl': 'false', + }}) + + client = yield from aiohttp_client(hass.http.app) + + resp = yield from client.get('/api/camera_proxy/camera.config_test') + + assert resp.status == 200 + + +@asyncio.coroutine +def test_fetching_url_with_verify_ssl(aioclient_mock, hass, aiohttp_client): + """Test that it fetches the given url when ssl verify is explicitly on.""" + aioclient_mock.get('https://example.com', text='hello world') + + yield from async_setup_component(hass, 'camera', { + 'camera': { + 'name': 'config_test', + 'platform': 'generic', + 'still_image_url': 'https://example.com', + 'username': 'user', + 'password': 'pass', + 'verify_ssl': 'true', + }}) + + client = yield from aiohttp_client(hass.http.app) + + resp = yield from client.get('/api/camera_proxy/camera.config_test') + + assert resp.status == 200 + + @asyncio.coroutine def test_limit_refetch(aioclient_mock, hass, aiohttp_client): """Test that it fetches the given url.""" From ae5c4c7e1360dce0e1ab87613849b20578752a97 Mon Sep 17 00:00:00 2001 From: Krasimir Zhelev Date: Tue, 21 Aug 2018 15:30:40 +0200 Subject: [PATCH 084/159] Upgrade afsapi to 0.0.4, prevents aiohttp session close message, Fixes #13099 (#16098) --- homeassistant/components/media_player/frontier_silicon.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/media_player/frontier_silicon.py b/homeassistant/components/media_player/frontier_silicon.py index ab594f47e14..b59c9a199b8 100644 --- a/homeassistant/components/media_player/frontier_silicon.py +++ b/homeassistant/components/media_player/frontier_silicon.py @@ -20,7 +20,7 @@ from homeassistant.const import ( CONF_HOST, CONF_PORT, CONF_PASSWORD) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['afsapi==0.0.3'] +REQUIREMENTS = ['afsapi==0.0.4'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 5041b4d4bfd..1b87a3dbeff 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -77,7 +77,7 @@ YesssSMS==0.1.1b3 abodepy==0.13.1 # homeassistant.components.media_player.frontier_silicon -afsapi==0.0.3 +afsapi==0.0.4 # homeassistant.components.device_tracker.automatic aioautomatic==0.6.5 From 7bb53449428b0787cca1d0c986c93a458401e6fb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 21 Aug 2018 15:49:58 +0200 Subject: [PATCH 085/159] Remove homeassistant.remote (#16099) * Remove homeassistant.remote * Use direct import for API * Fix docstring --- docs/source/api/homeassistant.rst | 8 - homeassistant/components/api.py | 4 +- homeassistant/components/http/view.py | 4 +- homeassistant/components/mqtt_eventstream.py | 2 +- homeassistant/components/mqtt_statestream.py | 2 +- homeassistant/components/notify/aws_lambda.py | 2 +- homeassistant/components/notify/html5.py | 11 - homeassistant/components/recorder/models.py | 2 +- homeassistant/components/splunk.py | 2 +- homeassistant/components/websocket_api.py | 2 +- homeassistant/helpers/json.py | 27 ++ homeassistant/remote.py | 317 ------------------ tests/components/device_tracker/test_init.py | 2 +- tests/components/recorder/models_original.py | 2 +- tests/components/test_demo.py | 2 +- tests/components/test_mqtt_eventstream.py | 2 +- tests/helpers/test_json.py | 21 ++ tests/test_remote.py | 205 ----------- 18 files changed, 62 insertions(+), 555 deletions(-) create mode 100644 homeassistant/helpers/json.py delete mode 100644 homeassistant/remote.py create mode 100644 tests/helpers/test_json.py delete mode 100644 tests/test_remote.py diff --git a/docs/source/api/homeassistant.rst b/docs/source/api/homeassistant.rst index f5ff069451d..599f5fb8019 100644 --- a/docs/source/api/homeassistant.rst +++ b/docs/source/api/homeassistant.rst @@ -60,14 +60,6 @@ loader module :undoc-members: :show-inheritance: -remote module ---------------------------- - -.. automodule:: homeassistant.remote - :members: - :undoc-members: - :show-inheritance: - Module contents --------------- diff --git a/homeassistant/components/api.py b/homeassistant/components/api.py index de28eeff5ca..0fbb4de39f1 100644 --- a/homeassistant/components/api.py +++ b/homeassistant/components/api.py @@ -24,7 +24,7 @@ from homeassistant.exceptions import TemplateError from homeassistant.helpers import template from homeassistant.helpers.service import async_get_all_descriptions from homeassistant.helpers.state import AsyncTrackStates -import homeassistant.remote as rem +from homeassistant.helpers.json import JSONEncoder _LOGGER = logging.getLogger(__name__) @@ -102,7 +102,7 @@ class APIEventStream(HomeAssistantView): if event.event_type == EVENT_HOMEASSISTANT_STOP: data = stop_obj else: - data = json.dumps(event, cls=rem.JSONEncoder) + data = json.dumps(event, cls=JSONEncoder) await to_write.put(data) diff --git a/homeassistant/components/http/view.py b/homeassistant/components/http/view.py index 22ef34de54a..b3b2587fc45 100644 --- a/homeassistant/components/http/view.py +++ b/homeassistant/components/http/view.py @@ -11,10 +11,10 @@ import logging from aiohttp import web from aiohttp.web_exceptions import HTTPUnauthorized, HTTPInternalServerError -import homeassistant.remote as rem from homeassistant.components.http.ban import process_success_login from homeassistant.core import Context, is_callback from homeassistant.const import CONTENT_TYPE_JSON +from homeassistant.helpers.json import JSONEncoder from .const import KEY_AUTHENTICATED, KEY_REAL_IP @@ -44,7 +44,7 @@ class HomeAssistantView: """Return a JSON response.""" try: msg = json.dumps( - result, sort_keys=True, cls=rem.JSONEncoder).encode('UTF-8') + result, sort_keys=True, cls=JSONEncoder).encode('UTF-8') except TypeError as err: _LOGGER.error('Unable to serialize to JSON: %s\n%s', err, result) raise HTTPInternalServerError diff --git a/homeassistant/components/mqtt_eventstream.py b/homeassistant/components/mqtt_eventstream.py index ea4463f5c23..0e01310115f 100644 --- a/homeassistant/components/mqtt_eventstream.py +++ b/homeassistant/components/mqtt_eventstream.py @@ -17,7 +17,7 @@ from homeassistant.const import ( EVENT_STATE_CHANGED, EVENT_TIME_CHANGED, MATCH_ALL) from homeassistant.core import EventOrigin, State import homeassistant.helpers.config_validation as cv -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder DOMAIN = 'mqtt_eventstream' DEPENDENCIES = ['mqtt'] diff --git a/homeassistant/components/mqtt_statestream.py b/homeassistant/components/mqtt_statestream.py index 205a638c574..592e31cbff1 100644 --- a/homeassistant/components/mqtt_statestream.py +++ b/homeassistant/components/mqtt_statestream.py @@ -15,7 +15,7 @@ from homeassistant.core import callback from homeassistant.components.mqtt import valid_publish_topic from homeassistant.helpers.entityfilter import generate_filter from homeassistant.helpers.event import async_track_state_change -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder import homeassistant.helpers.config_validation as cv CONF_BASE_TOPIC = 'base_topic' diff --git a/homeassistant/components/notify/aws_lambda.py b/homeassistant/components/notify/aws_lambda.py index 46ac2f89d33..8a3cb900f4b 100644 --- a/homeassistant/components/notify/aws_lambda.py +++ b/homeassistant/components/notify/aws_lambda.py @@ -15,7 +15,7 @@ from homeassistant.const import ( from homeassistant.components.notify import ( ATTR_TARGET, PLATFORM_SCHEMA, BaseNotificationService) import homeassistant.helpers.config_validation as cv -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder REQUIREMENTS = ['boto3==1.4.7'] diff --git a/homeassistant/components/notify/html5.py b/homeassistant/components/notify/html5.py index 1ed50472004..fa93cc4ba4d 100644 --- a/homeassistant/components/notify/html5.py +++ b/homeassistant/components/notify/html5.py @@ -132,17 +132,6 @@ def _load_config(filename): return {} -class JSONBytesDecoder(json.JSONEncoder): - """JSONEncoder to decode bytes objects to unicode.""" - - # pylint: disable=method-hidden, arguments-differ - def default(self, obj): - """Decode object if it's a bytes object, else defer to base class.""" - if isinstance(obj, bytes): - return obj.decode() - return json.JSONEncoder.default(self, obj) - - class HTML5PushRegistrationView(HomeAssistantView): """Accepts push registrations from a browser.""" diff --git a/homeassistant/components/recorder/models.py b/homeassistant/components/recorder/models.py index b8b777990f7..700dd57eacf 100644 --- a/homeassistant/components/recorder/models.py +++ b/homeassistant/components/recorder/models.py @@ -11,7 +11,7 @@ from sqlalchemy.ext.declarative import declarative_base import homeassistant.util.dt as dt_util from homeassistant.core import ( Context, Event, EventOrigin, State, split_entity_id) -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder # SQLAlchemy Schema # pylint: disable=invalid-name diff --git a/homeassistant/components/splunk.py b/homeassistant/components/splunk.py index a5b42eb9b5a..28863f6a436 100644 --- a/homeassistant/components/splunk.py +++ b/homeassistant/components/splunk.py @@ -15,7 +15,7 @@ from homeassistant.const import ( CONF_SSL, CONF_HOST, CONF_NAME, CONF_PORT, CONF_TOKEN, EVENT_STATE_CHANGED) from homeassistant.helpers import state as state_helper import homeassistant.helpers.config_validation as cv -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/websocket_api.py b/homeassistant/components/websocket_api.py index c25f4418263..1ba0e20d553 100644 --- a/homeassistant/components/websocket_api.py +++ b/homeassistant/components/websocket_api.py @@ -20,7 +20,7 @@ from homeassistant.const import ( __version__) from homeassistant.core import Context, callback from homeassistant.loader import bind_hass -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder from homeassistant.helpers import config_validation as cv from homeassistant.helpers.service import async_get_all_descriptions from homeassistant.components.http import HomeAssistantView diff --git a/homeassistant/helpers/json.py b/homeassistant/helpers/json.py new file mode 100644 index 00000000000..c28ee8c5c2c --- /dev/null +++ b/homeassistant/helpers/json.py @@ -0,0 +1,27 @@ +"""Helpers to help with encoding Home Assistant objects in JSON.""" +from datetime import datetime +import json +import logging + +from typing import Any + +_LOGGER = logging.getLogger(__name__) + + +class JSONEncoder(json.JSONEncoder): + """JSONEncoder that supports Home Assistant objects.""" + + # pylint: disable=method-hidden + def default(self, o: Any) -> Any: + """Convert Home Assistant objects. + + Hand other objects to the original method. + """ + if isinstance(o, datetime): + return o.isoformat() + if isinstance(o, set): + return list(o) + if hasattr(o, 'as_dict'): + return o.as_dict() + + return json.JSONEncoder.default(self, o) diff --git a/homeassistant/remote.py b/homeassistant/remote.py deleted file mode 100644 index 16c37f210e7..00000000000 --- a/homeassistant/remote.py +++ /dev/null @@ -1,317 +0,0 @@ -""" -Support for an interface to work with a remote instance of Home Assistant. - -If a connection error occurs while communicating with the API a -HomeAssistantError will be raised. - -For more details about the Python API, please refer to the documentation at -https://home-assistant.io/developers/python_api/ -""" -from datetime import datetime -import enum -import json -import logging -import urllib.parse - -from typing import Optional, Dict, Any, List - -from aiohttp.hdrs import METH_GET, METH_POST, METH_DELETE, CONTENT_TYPE -import requests - -from homeassistant import core as ha -from homeassistant.const import ( - URL_API, SERVER_PORT, URL_API_CONFIG, URL_API_EVENTS, URL_API_STATES, - URL_API_SERVICES, CONTENT_TYPE_JSON, HTTP_HEADER_HA_AUTH, - URL_API_EVENTS_EVENT, URL_API_STATES_ENTITY, URL_API_SERVICES_SERVICE) -from homeassistant.exceptions import HomeAssistantError - -_LOGGER = logging.getLogger(__name__) - - -class APIStatus(enum.Enum): - """Representation of an API status.""" - - OK = "ok" - INVALID_PASSWORD = "invalid_password" - CANNOT_CONNECT = "cannot_connect" - UNKNOWN = "unknown" - - def __str__(self) -> str: - """Return the state.""" - return self.value # type: ignore - - -class API: - """Object to pass around Home Assistant API location and credentials.""" - - def __init__(self, host: str, api_password: Optional[str] = None, - port: Optional[int] = SERVER_PORT, - use_ssl: bool = False) -> None: - """Init the API.""" - _LOGGER.warning('This class is deprecated and will be removed in 0.77') - self.host = host - self.port = port - self.api_password = api_password - - if host.startswith(("http://", "https://")): - self.base_url = host - elif use_ssl: - self.base_url = "https://{}".format(host) - else: - self.base_url = "http://{}".format(host) - - if port is not None: - self.base_url += ':{}'.format(port) - - self.status = None # type: Optional[APIStatus] - self._headers = {CONTENT_TYPE: CONTENT_TYPE_JSON} - - if api_password is not None: - self._headers[HTTP_HEADER_HA_AUTH] = api_password - - def validate_api(self, force_validate: bool = False) -> bool: - """Test if we can communicate with the API.""" - if self.status is None or force_validate: - self.status = validate_api(self) - - return self.status == APIStatus.OK - - def __call__(self, method: str, path: str, data: Optional[Dict] = None, - timeout: int = 5) -> requests.Response: - """Make a call to the Home Assistant API.""" - if data is None: - data_str = None - else: - data_str = json.dumps(data, cls=JSONEncoder) - - url = urllib.parse.urljoin(self.base_url, path) - - try: - if method == METH_GET: - return requests.get( - url, params=data_str, timeout=timeout, - headers=self._headers) - - return requests.request( - method, url, data=data_str, timeout=timeout, - headers=self._headers) - - except requests.exceptions.ConnectionError: - _LOGGER.exception("Error connecting to server") - raise HomeAssistantError("Error connecting to server") - - except requests.exceptions.Timeout: - error = "Timeout when talking to {}".format(self.host) - _LOGGER.exception(error) - raise HomeAssistantError(error) - - def __repr__(self) -> str: - """Return the representation of the API.""" - return "".format( - self.base_url, 'yes' if self.api_password is not None else 'no') - - -class JSONEncoder(json.JSONEncoder): - """JSONEncoder that supports Home Assistant objects.""" - - # pylint: disable=method-hidden - def default(self, o: Any) -> Any: - """Convert Home Assistant objects. - - Hand other objects to the original method. - """ - if isinstance(o, datetime): - return o.isoformat() - if isinstance(o, set): - return list(o) - if hasattr(o, 'as_dict'): - return o.as_dict() - - return json.JSONEncoder.default(self, o) - - -def validate_api(api: API) -> APIStatus: - """Make a call to validate API.""" - try: - req = api(METH_GET, URL_API) - - if req.status_code == 200: - return APIStatus.OK - - if req.status_code == 401: - return APIStatus.INVALID_PASSWORD - - return APIStatus.UNKNOWN - - except HomeAssistantError: - return APIStatus.CANNOT_CONNECT - - -def get_event_listeners(api: API) -> Dict: - """List of events that is being listened for.""" - try: - req = api(METH_GET, URL_API_EVENTS) - - return req.json() if req.status_code == 200 else {} # type: ignore - - except (HomeAssistantError, ValueError): - # ValueError if req.json() can't parse the json - _LOGGER.exception("Unexpected result retrieving event listeners") - - return {} - - -def fire_event(api: API, event_type: str, data: Optional[Dict] = None) -> None: - """Fire an event at remote API.""" - try: - req = api(METH_POST, URL_API_EVENTS_EVENT.format(event_type), data) - - if req.status_code != 200: - _LOGGER.error("Error firing event: %d - %s", - req.status_code, req.text) - - except HomeAssistantError: - _LOGGER.exception("Error firing event") - - -def get_state(api: API, entity_id: str) -> Optional[ha.State]: - """Query given API for state of entity_id.""" - try: - req = api(METH_GET, URL_API_STATES_ENTITY.format(entity_id)) - - # req.status_code == 422 if entity does not exist - - return ha.State.from_dict(req.json()) \ - if req.status_code == 200 else None - - except (HomeAssistantError, ValueError): - # ValueError if req.json() can't parse the json - _LOGGER.exception("Error fetching state") - - return None - - -def get_states(api: API) -> List[ha.State]: - """Query given API for all states.""" - try: - req = api(METH_GET, - URL_API_STATES) - - return [ha.State.from_dict(item) for - item in req.json()] - - except (HomeAssistantError, ValueError, AttributeError): - # ValueError if req.json() can't parse the json - _LOGGER.exception("Error fetching states") - - return [] - - -def remove_state(api: API, entity_id: str) -> bool: - """Call API to remove state for entity_id. - - Return True if entity is gone (removed/never existed). - """ - try: - req = api(METH_DELETE, URL_API_STATES_ENTITY.format(entity_id)) - - if req.status_code in (200, 404): - return True - - _LOGGER.error("Error removing state: %d - %s", - req.status_code, req.text) - return False - except HomeAssistantError: - _LOGGER.exception("Error removing state") - - return False - - -def set_state(api: API, entity_id: str, new_state: str, - attributes: Optional[Dict] = None, force_update: bool = False) \ - -> bool: - """Tell API to update state for entity_id. - - Return True if success. - """ - attributes = attributes or {} - - data = {'state': new_state, - 'attributes': attributes, - 'force_update': force_update} - - try: - req = api(METH_POST, URL_API_STATES_ENTITY.format(entity_id), data) - - if req.status_code not in (200, 201): - _LOGGER.error("Error changing state: %d - %s", - req.status_code, req.text) - return False - - return True - - except HomeAssistantError: - _LOGGER.exception("Error setting state") - - return False - - -def is_state(api: API, entity_id: str, state: str) -> bool: - """Query API to see if entity_id is specified state.""" - cur_state = get_state(api, entity_id) - - return bool(cur_state and cur_state.state == state) - - -def get_services(api: API) -> Dict: - """Return a list of dicts. - - Each dict has a string "domain" and a list of strings "services". - """ - try: - req = api(METH_GET, URL_API_SERVICES) - - return req.json() if req.status_code == 200 else {} # type: ignore - - except (HomeAssistantError, ValueError): - # ValueError if req.json() can't parse the json - _LOGGER.exception("Got unexpected services result") - - return {} - - -def call_service(api: API, domain: str, service: str, - service_data: Optional[Dict] = None, - timeout: int = 5) -> None: - """Call a service at the remote API.""" - try: - req = api(METH_POST, - URL_API_SERVICES_SERVICE.format(domain, service), - service_data, timeout=timeout) - - if req.status_code != 200: - _LOGGER.error("Error calling service: %d - %s", - req.status_code, req.text) - - except HomeAssistantError: - _LOGGER.exception("Error calling service") - - -def get_config(api: API) -> Dict: - """Return configuration.""" - try: - req = api(METH_GET, URL_API_CONFIG) - - if req.status_code != 200: - return {} - - result = req.json() - if 'components' in result: - result['components'] = set(result['components']) - return result # type: ignore - - except (HomeAssistantError, ValueError): - # ValueError if req.json() can't parse the JSON - _LOGGER.exception("Got unexpected configuration results") - - return {} diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index e9e4650e41a..97a4ea7c067 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -20,7 +20,7 @@ from homeassistant.const import ( STATE_HOME, STATE_NOT_HOME, CONF_PLATFORM, ATTR_ICON) import homeassistant.components.device_tracker as device_tracker from homeassistant.exceptions import HomeAssistantError -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder from tests.common import ( get_test_home_assistant, fire_time_changed, diff --git a/tests/components/recorder/models_original.py b/tests/components/recorder/models_original.py index 990414d7713..7096e84c82b 100644 --- a/tests/components/recorder/models_original.py +++ b/tests/components/recorder/models_original.py @@ -14,7 +14,7 @@ from sqlalchemy.ext.declarative import declarative_base import homeassistant.util.dt as dt_util from homeassistant.core import Event, EventOrigin, State, split_entity_id -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder # SQLAlchemy Schema # pylint: disable=invalid-name diff --git a/tests/components/test_demo.py b/tests/components/test_demo.py index 258e3d96297..b0b2524180f 100644 --- a/tests/components/test_demo.py +++ b/tests/components/test_demo.py @@ -7,7 +7,7 @@ import pytest from homeassistant.setup import async_setup_component from homeassistant.components import demo, device_tracker -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder @pytest.fixture(autouse=True) diff --git a/tests/components/test_mqtt_eventstream.py b/tests/components/test_mqtt_eventstream.py index a6881672339..1613198e4ce 100644 --- a/tests/components/test_mqtt_eventstream.py +++ b/tests/components/test_mqtt_eventstream.py @@ -6,7 +6,7 @@ from homeassistant.setup import setup_component import homeassistant.components.mqtt_eventstream as eventstream from homeassistant.const import EVENT_STATE_CHANGED from homeassistant.core import State, callback -from homeassistant.remote import JSONEncoder +from homeassistant.helpers.json import JSONEncoder import homeassistant.util.dt as dt_util from tests.common import ( diff --git a/tests/helpers/test_json.py b/tests/helpers/test_json.py new file mode 100644 index 00000000000..1d6e7eb6ede --- /dev/null +++ b/tests/helpers/test_json.py @@ -0,0 +1,21 @@ +"""Test Home Assistant remote methods and classes.""" +import pytest + +from homeassistant import core +from homeassistant.helpers.json import JSONEncoder +from homeassistant.util import dt as dt_util + + +def test_json_encoder(hass): + """Test the JSON Encoder.""" + ha_json_enc = JSONEncoder() + state = core.State('test.test', 'hello') + + assert ha_json_enc.default(state) == state.as_dict() + + # Default method raises TypeError if non HA object + with pytest.raises(TypeError): + ha_json_enc.default(1) + + now = dt_util.utcnow() + assert ha_json_enc.default(now) == now.isoformat() diff --git a/tests/test_remote.py b/tests/test_remote.py deleted file mode 100644 index 9aa730d6eb6..00000000000 --- a/tests/test_remote.py +++ /dev/null @@ -1,205 +0,0 @@ -"""Test Home Assistant remote methods and classes.""" -# pylint: disable=protected-access -import unittest - -from homeassistant import remote, setup, core as ha -import homeassistant.components.http as http -from homeassistant.const import HTTP_HEADER_HA_AUTH, EVENT_STATE_CHANGED -import homeassistant.util.dt as dt_util - -from tests.common import ( - get_test_instance_port, get_test_home_assistant) - -API_PASSWORD = 'test1234' -MASTER_PORT = get_test_instance_port() -BROKEN_PORT = get_test_instance_port() -HTTP_BASE_URL = 'http://127.0.0.1:{}'.format(MASTER_PORT) - -HA_HEADERS = {HTTP_HEADER_HA_AUTH: API_PASSWORD} - -broken_api = remote.API('127.0.0.1', "bladybla", port=get_test_instance_port()) -hass, master_api = None, None - - -def _url(path=''): - """Helper method to generate URLs.""" - return HTTP_BASE_URL + path - - -# pylint: disable=invalid-name -def setUpModule(): - """Initialization of a Home Assistant server instance.""" - global hass, master_api - - hass = get_test_home_assistant() - - hass.bus.listen('test_event', lambda _: _) - hass.states.set('test.test', 'a_state') - - setup.setup_component( - hass, http.DOMAIN, - {http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD, - http.CONF_SERVER_PORT: MASTER_PORT}}) - - setup.setup_component(hass, 'api') - - hass.start() - - master_api = remote.API('127.0.0.1', API_PASSWORD, MASTER_PORT) - - -# pylint: disable=invalid-name -def tearDownModule(): - """Stop the Home Assistant server.""" - hass.stop() - - -class TestRemoteMethods(unittest.TestCase): - """Test the homeassistant.remote module.""" - - def tearDown(self): - """Stop everything that was started.""" - hass.block_till_done() - - def test_validate_api(self): - """Test Python API validate_api.""" - self.assertEqual(remote.APIStatus.OK, remote.validate_api(master_api)) - - self.assertEqual( - remote.APIStatus.INVALID_PASSWORD, - remote.validate_api( - remote.API('127.0.0.1', API_PASSWORD + 'A', MASTER_PORT))) - - self.assertEqual( - remote.APIStatus.CANNOT_CONNECT, remote.validate_api(broken_api)) - - def test_get_event_listeners(self): - """Test Python API get_event_listeners.""" - local_data = hass.bus.listeners - remote_data = remote.get_event_listeners(master_api) - - for event in remote_data: - self.assertEqual(local_data.pop(event["event"]), - event["listener_count"]) - - self.assertEqual(len(local_data), 0) - - self.assertEqual({}, remote.get_event_listeners(broken_api)) - - def test_fire_event(self): - """Test Python API fire_event.""" - test_value = [] - - @ha.callback - def listener(event): - """Helper method that will verify our event got called.""" - test_value.append(1) - - hass.bus.listen("test.event_no_data", listener) - remote.fire_event(master_api, "test.event_no_data") - hass.block_till_done() - self.assertEqual(1, len(test_value)) - - # Should not trigger any exception - remote.fire_event(broken_api, "test.event_no_data") - - def test_get_state(self): - """Test Python API get_state.""" - self.assertEqual( - hass.states.get('test.test'), - remote.get_state(master_api, 'test.test')) - - self.assertEqual(None, remote.get_state(broken_api, 'test.test')) - - def test_get_states(self): - """Test Python API get_state_entity_ids.""" - self.assertEqual(hass.states.all(), remote.get_states(master_api)) - self.assertEqual([], remote.get_states(broken_api)) - - def test_remove_state(self): - """Test Python API set_state.""" - hass.states.set('test.remove_state', 'set_test') - - self.assertIn('test.remove_state', hass.states.entity_ids()) - remote.remove_state(master_api, 'test.remove_state') - self.assertNotIn('test.remove_state', hass.states.entity_ids()) - - def test_set_state(self): - """Test Python API set_state.""" - remote.set_state(master_api, 'test.test', 'set_test') - - state = hass.states.get('test.test') - - self.assertIsNotNone(state) - self.assertEqual('set_test', state.state) - - self.assertFalse(remote.set_state(broken_api, 'test.test', 'set_test')) - - def test_set_state_with_push(self): - """Test Python API set_state with push option.""" - events = [] - hass.bus.listen(EVENT_STATE_CHANGED, lambda ev: events.append(ev)) - - remote.set_state(master_api, 'test.test', 'set_test_2') - remote.set_state(master_api, 'test.test', 'set_test_2') - hass.block_till_done() - self.assertEqual(1, len(events)) - - remote.set_state( - master_api, 'test.test', 'set_test_2', force_update=True) - hass.block_till_done() - self.assertEqual(2, len(events)) - - def test_is_state(self): - """Test Python API is_state.""" - self.assertTrue( - remote.is_state(master_api, 'test.test', - hass.states.get('test.test').state)) - - self.assertFalse( - remote.is_state(broken_api, 'test.test', - hass.states.get('test.test').state)) - - def test_get_services(self): - """Test Python API get_services.""" - local_services = hass.services.services - - for serv_domain in remote.get_services(master_api): - local = local_services.pop(serv_domain["domain"]) - - self.assertEqual(local, serv_domain["services"]) - - self.assertEqual({}, remote.get_services(broken_api)) - - def test_call_service(self): - """Test Python API services.call.""" - test_value = [] - - @ha.callback - def listener(service_call): - """Helper method that will verify that our service got called.""" - test_value.append(1) - - hass.services.register("test_domain", "test_service", listener) - - remote.call_service(master_api, "test_domain", "test_service") - - hass.block_till_done() - - self.assertEqual(1, len(test_value)) - - # Should not raise an exception - remote.call_service(broken_api, "test_domain", "test_service") - - def test_json_encoder(self): - """Test the JSON Encoder.""" - ha_json_enc = remote.JSONEncoder() - state = hass.states.get('test.test') - - self.assertEqual(state.as_dict(), ha_json_enc.default(state)) - - # Default method raises TypeError if non HA object - self.assertRaises(TypeError, ha_json_enc.default, 1) - - now = dt_util.utcnow() - self.assertEqual(now.isoformat(), ha_json_enc.default(now)) From b26506ad4a7de4951d11078d4097ce541fd5be6b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 21 Aug 2018 19:03:46 +0200 Subject: [PATCH 086/159] Use new session when fetching remote urls (#16093) --- homeassistant/components/auth/indieauth.py | 16 ++++++------ tests/components/auth/test_indieauth.py | 29 +++++++++++++++++----- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/auth/indieauth.py b/homeassistant/components/auth/indieauth.py index 48f7ab06ab4..bcf73258ffa 100644 --- a/homeassistant/components/auth/indieauth.py +++ b/homeassistant/components/auth/indieauth.py @@ -4,6 +4,7 @@ from html.parser import HTMLParser from ipaddress import ip_address, ip_network from urllib.parse import urlparse, urljoin +import aiohttp from aiohttp.client_exceptions import ClientError # IP addresses of loopback interfaces @@ -76,18 +77,17 @@ async def fetch_redirect_uris(hass, url): We do not implement extracting redirect uris from headers. """ - session = hass.helpers.aiohttp_client.async_get_clientsession() parser = LinkTagParser('redirect_uri') chunks = 0 try: - resp = await session.get(url, timeout=5) + async with aiohttp.ClientSession() as session: + async with session.get(url, timeout=5) as resp: + async for data in resp.content.iter_chunked(1024): + parser.feed(data.decode()) + chunks += 1 - async for data in resp.content.iter_chunked(1024): - parser.feed(data.decode()) - chunks += 1 - - if chunks == 10: - break + if chunks == 10: + break except (asyncio.TimeoutError, ClientError): pass diff --git a/tests/components/auth/test_indieauth.py b/tests/components/auth/test_indieauth.py index 75e61af2e71..d30ead10cb2 100644 --- a/tests/components/auth/test_indieauth.py +++ b/tests/components/auth/test_indieauth.py @@ -1,4 +1,5 @@ """Tests for the client validator.""" +import asyncio from unittest.mock import patch import pytest @@ -6,6 +7,18 @@ import pytest from homeassistant.components.auth import indieauth from tests.common import mock_coro +from tests.test_util.aiohttp import AiohttpClientMocker + + +@pytest.fixture +def mock_session(): + """Mock aiohttp.ClientSession.""" + mocker = AiohttpClientMocker() + + with patch('aiohttp.ClientSession', + side_effect=lambda *args, **kwargs: + mocker.create_session(asyncio.get_event_loop())): + yield mocker def test_client_id_scheme(): @@ -120,9 +133,9 @@ async def test_verify_redirect_uri(): ) -async def test_find_link_tag(hass, aioclient_mock): +async def test_find_link_tag(hass, mock_session): """Test finding link tag.""" - aioclient_mock.get("http://127.0.0.1:8000", text=""" + mock_session.get("http://127.0.0.1:8000", text=""" @@ -142,11 +155,15 @@ async def test_find_link_tag(hass, aioclient_mock): ] -async def test_find_link_tag_max_size(hass, aioclient_mock): +async def test_find_link_tag_max_size(hass, mock_session): """Test finding link tag.""" - text = ("0" * 1024 * 10) + '' - aioclient_mock.get("http://127.0.0.1:8000", text=text) + text = ''.join([ + '', + ("0" * 1024 * 10), + '', + ]) + mock_session.get("http://127.0.0.1:8000", text=text) redirect_uris = await indieauth.fetch_redirect_uris( hass, "http://127.0.0.1:8000") - assert redirect_uris == [] + assert redirect_uris == ["http://127.0.0.1:8000/wine"] From 00c6f56cc8a10b371107e9ba1cb44df45b017ff5 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 21 Aug 2018 10:48:24 -0700 Subject: [PATCH 087/159] Allow finish_flow callback to change data entry result type (#16100) * Allow finish_flow callback to change data entry result type * Add unit test --- homeassistant/auth/__init__.py | 19 ++++++----- homeassistant/config_entries.py | 18 +++++------ homeassistant/data_entry_flow.py | 17 ++++++---- tests/test_data_entry_flow.py | 55 +++++++++++++++++++++++++++++--- 4 files changed, 80 insertions(+), 29 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 52240ab78c6..9f5252be67d 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -2,7 +2,7 @@ import asyncio import logging from collections import OrderedDict -from typing import Any, Dict, List, Optional, Tuple, cast, Union +from typing import Any, Dict, List, Optional, Tuple, cast import jwt @@ -256,20 +256,23 @@ class AuthManager: return await auth_provider.async_credential_flow(context) async def _async_finish_login_flow( - self, context: Optional[Dict], result: Dict[str, Any]) \ - -> Optional[Union[models.User, models.Credentials]]: + self, flow: data_entry_flow.FlowHandler, result: Dict[str, Any]) \ + -> Dict[str, Any]: """Return a user as result of login flow.""" if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: - return None + return result auth_provider = self._providers[result['handler']] - cred = await auth_provider.async_get_or_create_credentials( + credentials = await auth_provider.async_get_or_create_credentials( result['data']) - if context is not None and context.get('credential_only'): - return cred + if flow.context is not None and flow.context.get('credential_only'): + result['result'] = credentials + return result - return await self.async_get_or_create_user(cred) + user = await self.async_get_or_create_user(credentials) + result['result'] = user + return result @callback def _async_get_auth_provider( diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index ad3ed896dd4..1858937ec82 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -372,23 +372,24 @@ class ConfigEntries: return await entry.async_unload( self.hass, component=getattr(self.hass.components, component)) - async def _async_finish_flow(self, context, result): + async def _async_finish_flow(self, flow, result): """Finish a config flow and add an entry.""" - # If no discovery config entries in progress, remove notification. + # Remove notification if no other discovery config entries in progress if not any(ent['context']['source'] in DISCOVERY_SOURCES for ent - in self.hass.config_entries.flow.async_progress()): + in self.hass.config_entries.flow.async_progress() + if ent['flow_id'] != flow.flow_id): self.hass.components.persistent_notification.async_dismiss( DISCOVERY_NOTIFICATION_ID) if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: - return None + return result entry = ConfigEntry( version=result['version'], domain=result['handler'], title=result['title'], data=result['data'], - source=context['source'], + source=flow.context['source'], ) self._entries.append(entry) self._async_schedule_save() @@ -402,11 +403,8 @@ class ConfigEntries: await async_setup_component( self.hass, entry.domain, self._hass_config) - # Return Entry if they not from a discovery request - if context['source'] not in DISCOVERY_SOURCES: - return entry - - return entry + result['result'] = entry + return result async def _async_create_flow(self, handler_key, *, context, data): """Create a flow for specified handler. diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index d99d70ce2ec..a54c07fc1b8 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -64,7 +64,7 @@ class FlowManager: return await self._async_handle_step(flow, flow.init_step, data) async def async_configure( - self, flow_id: str, user_input: Optional[str] = None) -> Any: + self, flow_id: str, user_input: Optional[Dict] = None) -> Any: """Continue a configuration flow.""" flow = self._progress.get(flow_id) @@ -86,7 +86,7 @@ class FlowManager: raise UnknownFlow async def _async_handle_step(self, flow: Any, step_id: str, - user_input: Optional[str]) -> Dict: + user_input: Optional[Dict]) -> Dict: """Handle a step of a flow.""" method = "async_step_{}".format(step_id) @@ -106,14 +106,17 @@ class FlowManager: flow.cur_step = (result['step_id'], result['data_schema']) return result + # We pass a copy of the result because we're mutating our version + result = await self._async_finish_flow(flow, dict(result)) + + # _async_finish_flow may change result type, check it again + if result['type'] == RESULT_TYPE_FORM: + flow.cur_step = (result['step_id'], result['data_schema']) + return result + # Abort and Success results both finish the flow self._progress.pop(flow.flow_id) - # We pass a copy of the result because we're mutating our version - entry = await self._async_finish_flow(flow.context, dict(result)) - - if result['type'] == RESULT_TYPE_CREATE_ENTRY: - result['result'] = entry return result diff --git a/tests/test_data_entry_flow.py b/tests/test_data_entry_flow.py index c5d5bbb50bf..aa8240ff567 100644 --- a/tests/test_data_entry_flow.py +++ b/tests/test_data_entry_flow.py @@ -25,11 +25,12 @@ def manager(): if context is not None else 'user_input' return flow - async def async_add_entry(context, result): - if (result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY): - result['source'] = context.get('source') \ - if context is not None else 'user' + async def async_add_entry(flow, result): + if result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY: + result['source'] = flow.context.get('source') \ + if flow.context is not None else 'user' entries.append(result) + return result manager = data_entry_flow.FlowManager( None, async_create_flow, async_add_entry) @@ -198,3 +199,49 @@ async def test_discovery_init_flow(manager): assert entry['title'] == 'hello' assert entry['data'] == data assert entry['source'] == 'discovery' + + +async def test_finish_callback_change_result_type(hass): + """Test finish callback can change result type.""" + class TestFlow(data_entry_flow.FlowHandler): + VERSION = 1 + + async def async_step_init(self, input): + """Return init form with one input field 'count'.""" + if input is not None: + return self.async_create_entry(title='init', data=input) + return self.async_show_form( + step_id='init', + data_schema=vol.Schema({'count': int})) + + async def async_create_flow(handler_name, *, context, data): + """Create a test flow.""" + return TestFlow() + + async def async_finish_flow(flow, result): + """Redirect to init form if count <= 1.""" + if result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY: + if (result['data'] is None or + result['data'].get('count', 0) <= 1): + return flow.async_show_form( + step_id='init', + data_schema=vol.Schema({'count': int})) + else: + result['result'] = result['data']['count'] + return result + + manager = data_entry_flow.FlowManager( + hass, async_create_flow, async_finish_flow) + + result = await manager.async_init('test') + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['step_id'] == 'init' + + result = await manager.async_configure(result['flow_id'], {'count': 0}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['step_id'] == 'init' + assert 'result' not in result + + result = await manager.async_configure(result['flow_id'], {'count': 2}) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['result'] == 2 From cdb8361050135ff19d8448876e9c32ffc2c02b74 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 21 Aug 2018 20:02:55 +0200 Subject: [PATCH 088/159] Add support for revoking refresh tokens (#16095) * Add support for revoking refresh tokens * Lint * Split revoke logic in own method * Simplify * Update docs --- homeassistant/auth/__init__.py | 8 +++- homeassistant/auth/auth_store.py | 12 ++++++ homeassistant/components/auth/__init__.py | 47 +++++++++++++++++++++-- tests/auth/test_init.py | 17 ++++++++ tests/components/auth/test_init.py | 43 +++++++++++++++++++++ 5 files changed, 122 insertions(+), 5 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 9f5252be67d..51c9c25b474 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -202,6 +202,12 @@ class AuthManager: """Get refresh token by token.""" return await self._store.async_get_refresh_token_by_token(token) + async def async_remove_refresh_token(self, + refresh_token: models.RefreshToken) \ + -> None: + """Delete a refresh token.""" + await self._store.async_remove_refresh_token(refresh_token) + @callback def async_create_access_token(self, refresh_token: models.RefreshToken) -> str: @@ -215,7 +221,7 @@ class AuthManager: async def async_validate_access_token( self, token: str) -> Optional[models.RefreshToken]: - """Return if an access token is valid.""" + """Return refresh token if an access token is valid.""" try: unverif_claims = jwt.decode(token, verify=False) except jwt.InvalidTokenError: diff --git a/homeassistant/auth/auth_store.py b/homeassistant/auth/auth_store.py index 5b26cf2f5f8..0f12d69211c 100644 --- a/homeassistant/auth/auth_store.py +++ b/homeassistant/auth/auth_store.py @@ -136,6 +136,18 @@ class AuthStore: self._async_schedule_save() return refresh_token + async def async_remove_refresh_token( + self, refresh_token: models.RefreshToken) -> None: + """Remove a refresh token.""" + if self._users is None: + await self._async_load() + assert self._users is not None + + for user in self._users.values(): + if user.refresh_tokens.pop(refresh_token.id, None): + self._async_schedule_save() + break + async def async_get_refresh_token( self, token_id: str) -> Optional[models.RefreshToken]: """Get refresh token by id.""" diff --git a/homeassistant/components/auth/__init__.py b/homeassistant/components/auth/__init__.py index 08bb3e679b8..4251b23e514 100644 --- a/homeassistant/components/auth/__init__.py +++ b/homeassistant/components/auth/__init__.py @@ -44,11 +44,23 @@ a limited expiration. "expires_in": 1800, "token_type": "Bearer" } + +## Revoking a refresh token + +It is also possible to revoke a refresh token and all access tokens that have +ever been granted by that refresh token. Response code will ALWAYS be 200. + +{ + "token": "IJKLMNOPQRST", + "action": "revoke" +} + """ import logging import uuid from datetime import timedelta +from aiohttp import web import voluptuous as vol from homeassistant.auth.models import User, Credentials @@ -79,7 +91,7 @@ async def async_setup(hass, config): """Component to allow users to login.""" store_result, retrieve_result = _create_auth_code_store() - hass.http.register_view(GrantTokenView(retrieve_result)) + hass.http.register_view(TokenView(retrieve_result)) hass.http.register_view(LinkUserView(retrieve_result)) hass.components.websocket_api.async_register_command( @@ -92,8 +104,8 @@ async def async_setup(hass, config): return True -class GrantTokenView(HomeAssistantView): - """View to grant tokens.""" +class TokenView(HomeAssistantView): + """View to issue or revoke tokens.""" url = '/auth/token' name = 'api:auth:token' @@ -101,7 +113,7 @@ class GrantTokenView(HomeAssistantView): cors_allowed = True def __init__(self, retrieve_user): - """Initialize the grant token view.""" + """Initialize the token view.""" self._retrieve_user = retrieve_user @log_invalid_auth @@ -112,6 +124,13 @@ class GrantTokenView(HomeAssistantView): grant_type = data.get('grant_type') + # IndieAuth 6.3.5 + # The revocation endpoint is the same as the token endpoint. + # The revocation request includes an additional parameter, + # action=revoke. + if data.get('action') == 'revoke': + return await self._async_handle_revoke_token(hass, data) + if grant_type == 'authorization_code': return await self._async_handle_auth_code(hass, data) @@ -122,6 +141,25 @@ class GrantTokenView(HomeAssistantView): 'error': 'unsupported_grant_type', }, status_code=400) + async def _async_handle_revoke_token(self, hass, data): + """Handle revoke token request.""" + # OAuth 2.0 Token Revocation [RFC7009] + # 2.2 The authorization server responds with HTTP status code 200 + # if the token has been revoked successfully or if the client + # submitted an invalid token. + token = data.get('token') + + if token is None: + return web.Response(status=200) + + refresh_token = await hass.auth.async_get_refresh_token_by_token(token) + + if refresh_token is None: + return web.Response(status=200) + + await hass.auth.async_remove_refresh_token(refresh_token) + return web.Response(status=200) + async def _async_handle_auth_code(self, hass, data): """Handle authorization code request.""" client_id = data.get('client_id') @@ -136,6 +174,7 @@ class GrantTokenView(HomeAssistantView): if code is None: return self.json({ 'error': 'invalid_request', + 'error_description': 'Invalid code', }, status_code=400) user = self._retrieve_user(client_id, RESULT_TYPE_USER, code) diff --git a/tests/auth/test_init.py b/tests/auth/test_init.py index 5ea3b528b4e..5dc6ebf135d 100644 --- a/tests/auth/test_init.py +++ b/tests/auth/test_init.py @@ -281,3 +281,20 @@ async def test_cannot_deactive_owner(mock_hass): with pytest.raises(ValueError): await manager.async_deactivate_user(owner) + + +async def test_remove_refresh_token(mock_hass): + """Test that we can remove a refresh token.""" + manager = await auth.auth_manager_from_config(mock_hass, []) + user = MockUser().add_to_auth_manager(manager) + refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID) + access_token = manager.async_create_access_token(refresh_token) + + await manager.async_remove_refresh_token(refresh_token) + + assert ( + await manager.async_get_refresh_token(refresh_token.id) is None + ) + assert ( + await manager.async_validate_access_token(access_token) is None + ) diff --git a/tests/components/auth/test_init.py b/tests/components/auth/test_init.py index 79749da1461..7b9dda6acb3 100644 --- a/tests/components/auth/test_init.py +++ b/tests/components/auth/test_init.py @@ -224,3 +224,46 @@ async def test_refresh_token_different_client_id(hass, aiohttp_client): await hass.auth.async_validate_access_token(tokens['access_token']) is not None ) + + +async def test_revoking_refresh_token(hass, aiohttp_client): + """Test that we can revoke refresh tokens.""" + client = await async_setup_auth(hass, aiohttp_client) + user = await hass.auth.async_create_user('Test User') + refresh_token = await hass.auth.async_create_refresh_token(user, CLIENT_ID) + + # Test that we can create an access token + resp = await client.post('/auth/token', data={ + 'client_id': CLIENT_ID, + 'grant_type': 'refresh_token', + 'refresh_token': refresh_token.token, + }) + + assert resp.status == 200 + tokens = await resp.json() + assert ( + await hass.auth.async_validate_access_token(tokens['access_token']) + is not None + ) + + # Revoke refresh token + resp = await client.post('/auth/token', data={ + 'token': refresh_token.token, + 'action': 'revoke', + }) + assert resp.status == 200 + + # Old access token should be no longer valid + assert ( + await hass.auth.async_validate_access_token(tokens['access_token']) + is None + ) + + # Test that we no longer can create an access token + resp = await client.post('/auth/token', data={ + 'client_id': CLIENT_ID, + 'grant_type': 'refresh_token', + 'refresh_token': refresh_token.token, + }) + + assert resp.status == 400 From 1ce51bfbd69110cb09562104799168533e73399f Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 21 Aug 2018 11:03:38 -0700 Subject: [PATCH 089/159] Refactoring login flow (#16104) * Abstract LoginFlow * Lint and typings --- homeassistant/auth/__init__.py | 2 +- homeassistant/auth/providers/__init__.py | 40 ++++++++++++++++--- homeassistant/auth/providers/homeassistant.py | 32 ++++++--------- .../auth/providers/insecure_example.py | 27 +++++-------- .../auth/providers/legacy_api_password.py | 33 +++++---------- .../auth/providers/trusted_networks.py | 23 +++++------ tests/auth/providers/test_homeassistant.py | 12 +++--- tests/auth/providers/test_trusted_networks.py | 6 +-- 8 files changed, 89 insertions(+), 86 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 51c9c25b474..3b61229d59a 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -259,7 +259,7 @@ class AuthManager: """Create a login flow.""" auth_provider = self._providers[handler] - return await auth_provider.async_credential_flow(context) + return await auth_provider.async_login_flow(context) async def _async_finish_login_flow( self, flow: data_entry_flow.FlowHandler, result: Dict[str, Any]) \ diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index 328d83343d7..b2338a8d6ea 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -10,10 +10,11 @@ from voluptuous.humanize import humanize_error from homeassistant import data_entry_flow, requirements from homeassistant.core import callback, HomeAssistant from homeassistant.const import CONF_TYPE, CONF_NAME, CONF_ID +from homeassistant.util import dt as dt_util from homeassistant.util.decorator import Registry -from homeassistant.auth.auth_store import AuthStore -from homeassistant.auth.models import Credentials, UserMeta +from ..auth_store import AuthStore +from ..models import Credentials, UserMeta _LOGGER = logging.getLogger(__name__) DATA_REQS = 'auth_prov_reqs_processed' @@ -80,9 +81,11 @@ class AuthProvider: # Implement by extending class - async def async_credential_flow( - self, context: Optional[Dict]) -> data_entry_flow.FlowHandler: - """Return the data flow for logging in with auth provider.""" + async def async_login_flow(self, context: Optional[Dict]) -> 'LoginFlow': + """Return the data flow for logging in with auth provider. + + Auth provider should extend LoginFlow and return an instance. + """ raise NotImplementedError async def async_get_or_create_credentials( @@ -149,3 +152,30 @@ async def load_auth_provider_module( processed.add(provider) return module + + +class LoginFlow(data_entry_flow.FlowHandler): + """Handler for the login flow.""" + + def __init__(self, auth_provider: AuthProvider) -> None: + """Initialize the login flow.""" + self._auth_provider = auth_provider + self.created_at = dt_util.utcnow() + self.user = None + + async def async_step_init( + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: + """Handle the first step of login flow. + + Return self.async_show_form(step_id='init') if user_input == None. + Return await self.async_finish(flow_result) if login init step pass. + """ + raise NotImplementedError + + async def async_finish(self, flow_result: Any) -> Dict: + """Handle the pass of login flow.""" + return self.async_create_entry( + title=self._auth_provider.name, + data=flow_result + ) diff --git a/homeassistant/auth/providers/homeassistant.py b/homeassistant/auth/providers/homeassistant.py index a2d91767b95..29be774cf8a 100644 --- a/homeassistant/auth/providers/homeassistant.py +++ b/homeassistant/auth/providers/homeassistant.py @@ -3,19 +3,18 @@ import base64 from collections import OrderedDict import hashlib import hmac -from typing import Any, Dict, List, Optional # noqa: F401,E501 pylint: disable=unused-import +from typing import Any, Dict, List, Optional, cast import voluptuous as vol -from homeassistant import data_entry_flow from homeassistant.const import CONF_ID from homeassistant.core import callback, HomeAssistant from homeassistant.exceptions import HomeAssistantError -from homeassistant.auth.util import generate_secret - -from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS +from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, LoginFlow from ..models import Credentials, UserMeta +from ..util import generate_secret + STORAGE_VERSION = 1 STORAGE_KEY = 'auth_provider.homeassistant' @@ -159,10 +158,10 @@ class HassAuthProvider(AuthProvider): self.data = Data(self.hass) await self.data.async_load() - async def async_credential_flow( - self, context: Optional[Dict]) -> 'LoginFlow': + async def async_login_flow( + self, context: Optional[Dict]) -> LoginFlow: """Return a flow to login.""" - return LoginFlow(self) + return HassLoginFlow(self) async def async_validate_login(self, username: str, password: str) -> None: """Helper to validate a username and password.""" @@ -207,13 +206,9 @@ class HassAuthProvider(AuthProvider): pass -class LoginFlow(data_entry_flow.FlowHandler): +class HassLoginFlow(LoginFlow): """Handler for the login flow.""" - def __init__(self, auth_provider: HassAuthProvider) -> None: - """Initialize the login flow.""" - self._auth_provider = auth_provider - async def async_step_init( self, user_input: Optional[Dict[str, str]] = None) \ -> Dict[str, Any]: @@ -222,16 +217,15 @@ class LoginFlow(data_entry_flow.FlowHandler): if user_input is not None: try: - await self._auth_provider.async_validate_login( - user_input['username'], user_input['password']) + await cast(HassAuthProvider, self._auth_provider)\ + .async_validate_login(user_input['username'], + user_input['password']) except InvalidAuth: errors['base'] = 'invalid_auth' if not errors: - return self.async_create_entry( - title=self._auth_provider.name, - data=user_input - ) + user_input.pop('password') + return await self.async_finish(user_input) schema = OrderedDict() # type: Dict[str, type] schema['username'] = str diff --git a/homeassistant/auth/providers/insecure_example.py b/homeassistant/auth/providers/insecure_example.py index a4f411e69e0..d267ccb7a1c 100644 --- a/homeassistant/auth/providers/insecure_example.py +++ b/homeassistant/auth/providers/insecure_example.py @@ -1,15 +1,14 @@ """Example auth provider.""" from collections import OrderedDict import hmac -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, cast import voluptuous as vol from homeassistant.exceptions import HomeAssistantError -from homeassistant import data_entry_flow from homeassistant.core import callback -from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS +from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, LoginFlow from ..models import Credentials, UserMeta @@ -33,10 +32,9 @@ class InvalidAuthError(HomeAssistantError): class ExampleAuthProvider(AuthProvider): """Example auth provider based on hardcoded usernames and passwords.""" - async def async_credential_flow( - self, context: Optional[Dict]) -> 'LoginFlow': + async def async_login_flow(self, context: Optional[Dict]) -> LoginFlow: """Return a flow to login.""" - return LoginFlow(self) + return ExampleLoginFlow(self) @callback def async_validate_login(self, username: str, password: str) -> None: @@ -90,13 +88,9 @@ class ExampleAuthProvider(AuthProvider): return UserMeta(name=name, is_active=True) -class LoginFlow(data_entry_flow.FlowHandler): +class ExampleLoginFlow(LoginFlow): """Handler for the login flow.""" - def __init__(self, auth_provider: ExampleAuthProvider) -> None: - """Initialize the login flow.""" - self._auth_provider = auth_provider - async def async_step_init( self, user_input: Optional[Dict[str, str]] = None) \ -> Dict[str, Any]: @@ -105,16 +99,15 @@ class LoginFlow(data_entry_flow.FlowHandler): if user_input is not None: try: - self._auth_provider.async_validate_login( - user_input['username'], user_input['password']) + cast(ExampleAuthProvider, self._auth_provider)\ + .async_validate_login(user_input['username'], + user_input['password']) except InvalidAuthError: errors['base'] = 'invalid_auth' if not errors: - return self.async_create_entry( - title=self._auth_provider.name, - data=user_input - ) + user_input.pop('password') + return await self.async_finish(user_input) schema = OrderedDict() # type: Dict[str, type] schema['username'] = str diff --git a/homeassistant/auth/providers/legacy_api_password.py b/homeassistant/auth/providers/legacy_api_password.py index 064cfc046bd..dffe458976c 100644 --- a/homeassistant/auth/providers/legacy_api_password.py +++ b/homeassistant/auth/providers/legacy_api_password.py @@ -3,18 +3,16 @@ Support Legacy API password auth provider. It will be removed when auth system production ready """ -from collections import OrderedDict import hmac -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, cast import voluptuous as vol from homeassistant.components.http import HomeAssistantHTTP # noqa: F401 -from homeassistant.exceptions import HomeAssistantError -from homeassistant import data_entry_flow from homeassistant.core import callback +from homeassistant.exceptions import HomeAssistantError -from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS +from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, LoginFlow from ..models import Credentials, UserMeta @@ -39,10 +37,9 @@ class LegacyApiPasswordAuthProvider(AuthProvider): DEFAULT_TITLE = 'Legacy API Password' - async def async_credential_flow( - self, context: Optional[Dict]) -> 'LoginFlow': + async def async_login_flow(self, context: Optional[Dict]) -> LoginFlow: """Return a flow to login.""" - return LoginFlow(self) + return LegacyLoginFlow(self) @callback def async_validate_login(self, password: str) -> None: @@ -81,13 +78,9 @@ class LegacyApiPasswordAuthProvider(AuthProvider): return UserMeta(name=LEGACY_USER, is_active=True) -class LoginFlow(data_entry_flow.FlowHandler): +class LegacyLoginFlow(LoginFlow): """Handler for the login flow.""" - def __init__(self, auth_provider: LegacyApiPasswordAuthProvider) -> None: - """Initialize the login flow.""" - self._auth_provider = auth_provider - async def async_step_init( self, user_input: Optional[Dict[str, str]] = None) \ -> Dict[str, Any]: @@ -96,22 +89,16 @@ class LoginFlow(data_entry_flow.FlowHandler): if user_input is not None: try: - self._auth_provider.async_validate_login( - user_input['password']) + cast(LegacyApiPasswordAuthProvider, self._auth_provider)\ + .async_validate_login(user_input['password']) except InvalidAuthError: errors['base'] = 'invalid_auth' if not errors: - return self.async_create_entry( - title=self._auth_provider.name, - data={} - ) - - schema = OrderedDict() # type: Dict[str, type] - schema['password'] = str + return await self.async_finish({}) return self.async_show_form( step_id='init', - data_schema=vol.Schema(schema), + data_schema=vol.Schema({'password': str}), errors=errors, ) diff --git a/homeassistant/auth/providers/trusted_networks.py b/homeassistant/auth/providers/trusted_networks.py index 3233fa5537f..0bc37946e0b 100644 --- a/homeassistant/auth/providers/trusted_networks.py +++ b/homeassistant/auth/providers/trusted_networks.py @@ -7,11 +7,11 @@ from typing import Any, Dict, Optional, cast import voluptuous as vol -from homeassistant import data_entry_flow from homeassistant.components.http import HomeAssistantHTTP # noqa: F401 from homeassistant.core import callback from homeassistant.exceptions import HomeAssistantError -from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS + +from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, LoginFlow from ..models import Credentials, UserMeta CONFIG_SCHEMA = AUTH_PROVIDER_SCHEMA.extend({ @@ -35,8 +35,7 @@ class TrustedNetworksAuthProvider(AuthProvider): DEFAULT_TITLE = 'Trusted Networks' - async def async_credential_flow( - self, context: Optional[Dict]) -> 'LoginFlow': + async def async_login_flow(self, context: Optional[Dict]) -> LoginFlow: """Return a flow to login.""" assert context is not None users = await self.store.async_get_users() @@ -44,8 +43,8 @@ class TrustedNetworksAuthProvider(AuthProvider): for user in users if not user.system_generated and user.is_active} - return LoginFlow(self, cast(str, context.get('ip_address')), - available_users) + return TrustedNetworksLoginFlow( + self, cast(str, context.get('ip_address')), available_users) async def async_get_or_create_credentials( self, flow_result: Dict[str, str]) -> Credentials: @@ -92,14 +91,14 @@ class TrustedNetworksAuthProvider(AuthProvider): raise InvalidAuthError('Not in trusted_networks') -class LoginFlow(data_entry_flow.FlowHandler): +class TrustedNetworksLoginFlow(LoginFlow): """Handler for the login flow.""" def __init__(self, auth_provider: TrustedNetworksAuthProvider, ip_address: str, available_users: Dict[str, Optional[str]]) \ -> None: """Initialize the login flow.""" - self._auth_provider = auth_provider + super().__init__(auth_provider) self._available_users = available_users self._ip_address = ip_address @@ -109,7 +108,8 @@ class LoginFlow(data_entry_flow.FlowHandler): """Handle the step of the form.""" errors = {} try: - self._auth_provider.async_validate_access(self._ip_address) + cast(TrustedNetworksAuthProvider, self._auth_provider)\ + .async_validate_access(self._ip_address) except InvalidAuthError: errors['base'] = 'invalid_auth' @@ -125,10 +125,7 @@ class LoginFlow(data_entry_flow.FlowHandler): errors['base'] = 'invalid_auth' if not errors: - return self.async_create_entry( - title=self._auth_provider.name, - data=user_input - ) + return await self.async_finish(user_input) schema = {'user': vol.In(self._available_users)} diff --git a/tests/auth/providers/test_homeassistant.py b/tests/auth/providers/test_homeassistant.py index 9db6293d98a..b87f981570e 100644 --- a/tests/auth/providers/test_homeassistant.py +++ b/tests/auth/providers/test_homeassistant.py @@ -4,7 +4,7 @@ from unittest.mock import Mock import pytest from homeassistant import data_entry_flow -from homeassistant.auth import auth_manager_from_config +from homeassistant.auth import auth_manager_from_config, auth_store from homeassistant.auth.providers import ( auth_provider_from_config, homeassistant as hass_auth) @@ -24,7 +24,7 @@ async def test_adding_user(data, hass): async def test_adding_user_duplicate_username(data, hass): - """Test adding a user.""" + """Test adding a user with duplicate username.""" data.add_auth('test-user', 'test-pass') with pytest.raises(hass_auth.InvalidUser): data.add_auth('test-user', 'other-pass') @@ -37,7 +37,7 @@ async def test_validating_password_invalid_user(data, hass): async def test_validating_password_invalid_password(data, hass): - """Test validating an invalid user.""" + """Test validating an invalid password.""" data.add_auth('test-user', 'test-pass') with pytest.raises(hass_auth.InvalidAuth): @@ -67,8 +67,9 @@ async def test_login_flow_validates(data, hass): data.add_auth('test-user', 'test-pass') await data.async_save() - provider = hass_auth.HassAuthProvider(hass, None, {}) - flow = hass_auth.LoginFlow(provider) + provider = hass_auth.HassAuthProvider(hass, auth_store.AuthStore(hass), + {'type': 'homeassistant'}) + flow = await provider.async_login_flow({}) result = await flow.async_step_init() assert result['type'] == data_entry_flow.RESULT_TYPE_FORM @@ -91,6 +92,7 @@ async def test_login_flow_validates(data, hass): 'password': 'test-pass', }) assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['data']['username'] == 'test-user' async def test_saving_loading(data, hass): diff --git a/tests/auth/providers/test_trusted_networks.py b/tests/auth/providers/test_trusted_networks.py index ca8b5bd90a2..5a7021a647a 100644 --- a/tests/auth/providers/test_trusted_networks.py +++ b/tests/auth/providers/test_trusted_networks.py @@ -72,7 +72,7 @@ async def test_login_flow(manager, provider): user = await manager.async_create_user("test-user") # trusted network didn't loaded - flow = await provider.async_credential_flow({'ip_address': '127.0.0.1'}) + flow = await provider.async_login_flow({'ip_address': '127.0.0.1'}) step = await flow.async_step_init() assert step['step_id'] == 'init' assert step['errors']['base'] == 'invalid_auth' @@ -80,13 +80,13 @@ async def test_login_flow(manager, provider): provider.hass.http = Mock(trusted_networks=['192.168.0.1']) # not from trusted network - flow = await provider.async_credential_flow({'ip_address': '127.0.0.1'}) + flow = await provider.async_login_flow({'ip_address': '127.0.0.1'}) step = await flow.async_step_init() assert step['step_id'] == 'init' assert step['errors']['base'] == 'invalid_auth' # from trusted network, list users - flow = await provider.async_credential_flow({'ip_address': '192.168.0.1'}) + flow = await provider.async_login_flow({'ip_address': '192.168.0.1'}) step = await flow.async_step_init() assert step['step_id'] == 'init' From 0e1fb74e1bd362952a5181d9995de43508d636f4 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 21 Aug 2018 21:25:16 +0200 Subject: [PATCH 090/159] Minor updates (#16106) --- .../alarm_control_panel/homematicip_cloud.py | 25 ++++++------- .../components/binary_sensor/homematic.py | 21 ++++++----- .../binary_sensor/homematicip_cloud.py | 23 ++++++------ homeassistant/components/climate/homematic.py | 9 +++-- .../components/climate/homematicip_cloud.py | 23 ++++++------ homeassistant/components/cover/homematic.py | 6 +-- .../components/homematicip_cloud/__init__.py | 19 +++++----- .../homematicip_cloud/config_flow.py | 30 +++++++-------- .../components/homematicip_cloud/const.py | 1 - .../components/homematicip_cloud/device.py | 31 ++++++++-------- .../components/homematicip_cloud/errors.py | 10 ++--- .../components/homematicip_cloud/hap.py | 29 +++++++-------- .../components/homematicip_cloud/strings.json | 12 +++--- homeassistant/components/light/homematic.py | 3 +- .../components/light/homematicip_cloud.py | 37 +++++++++---------- homeassistant/components/lock/homematic.py | 6 +-- homeassistant/components/sensor/homematic.py | 9 +++-- .../components/sensor/homematicip_cloud.py | 31 ++++++++-------- homeassistant/components/switch/homematic.py | 3 +- .../components/switch/homematicip_cloud.py | 24 ++++++------ 20 files changed, 172 insertions(+), 180 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/homematicip_cloud.py b/homeassistant/components/alarm_control_panel/homematicip_cloud.py index 79f872951db..9f5b52a31f4 100644 --- a/homeassistant/components/alarm_control_panel/homematicip_cloud.py +++ b/homeassistant/components/alarm_control_panel/homematicip_cloud.py @@ -1,32 +1,31 @@ """ -Support for HomematicIP alarm control panel. +Support for HomematicIP Cloud alarm control panel. -For more details about this component, please refer to the documentation at +For more details about this platform, please refer to the documentation at https://home-assistant.io/components/alarm_control_panel.homematicip_cloud/ """ import logging +from homeassistant.components.alarm_control_panel import AlarmControlPanel +from homeassistant.components.homematicip_cloud import ( + HMIPC_HAPID, HomematicipGenericDevice) +from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN from homeassistant.const import ( STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED) -from homeassistant.components.alarm_control_panel import AlarmControlPanel -from homeassistant.components.homematicip_cloud import ( - HomematicipGenericDevice, DOMAIN as HMIPC_DOMAIN, - HMIPC_HAPID) - - -DEPENDENCIES = ['homematicip_cloud'] _LOGGER = logging.getLogger(__name__) +DEPENDENCIES = ['homematicip_cloud'] + HMIP_ZONE_AWAY = 'EXTERNAL' HMIP_ZONE_HOME = 'INTERNAL' -async def async_setup_platform(hass, config, async_add_devices, - discovery_info=None): - """Set up the HomematicIP alarm control devices.""" +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Set up the HomematicIP Cloud alarm control devices.""" pass @@ -45,7 +44,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): class HomematicipSecurityZone(HomematicipGenericDevice, AlarmControlPanel): - """Representation of an HomematicIP security zone group.""" + """Representation of an HomematicIP Cloud security zone group.""" def __init__(self, home, device): """Initialize the security zone group.""" diff --git a/homeassistant/components/binary_sensor/homematic.py b/homeassistant/components/binary_sensor/homematic.py index d85c10f9a34..a0ec359e048 100644 --- a/homeassistant/components/binary_sensor/homematic.py +++ b/homeassistant/components/binary_sensor/homematic.py @@ -5,27 +5,28 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/binary_sensor.homematic/ """ import logging -from homeassistant.const import STATE_UNKNOWN + from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.components.homematic import HMDevice, ATTR_DISCOVER_DEVICES +from homeassistant.components.homematic import ATTR_DISCOVER_DEVICES, HMDevice +from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['homematic'] SENSOR_TYPES_CLASS = { - 'Remote': None, - 'ShutterContact': 'opening', - 'MaxShutterContact': 'opening', 'IPShutterContact': 'opening', - 'Smoke': 'smoke', - 'SmokeV2': 'smoke', + 'MaxShutterContact': 'opening', 'Motion': 'motion', 'MotionV2': 'motion', - 'RemoteMotion': None, - 'WeatherSensor': None, - 'TiltSensor': None, 'PresenceIP': 'motion', + 'Remote': None, + 'RemoteMotion': None, + 'ShutterContact': 'opening', + 'Smoke': 'smoke', + 'SmokeV2': 'smoke', + 'TiltSensor': None, + 'WeatherSensor': None, } diff --git a/homeassistant/components/binary_sensor/homematicip_cloud.py b/homeassistant/components/binary_sensor/homematicip_cloud.py index 962817827f0..72dc2c8b462 100644 --- a/homeassistant/components/binary_sensor/homematicip_cloud.py +++ b/homeassistant/components/binary_sensor/homematicip_cloud.py @@ -1,16 +1,15 @@ """ -Support for HomematicIP binary sensor. +Support for HomematicIP Cloud binary sensor. -For more details about this component, please refer to the documentation at +For more details about this platform, please refer to the documentation at https://home-assistant.io/components/binary_sensor.homematicip_cloud/ """ - import logging from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.homematicip_cloud import ( - HomematicipGenericDevice, DOMAIN as HMIPC_DOMAIN, - HMIPC_HAPID) + HMIPC_HAPID, HomematicipGenericDevice) +from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN DEPENDENCIES = ['homematicip_cloud'] @@ -19,14 +18,14 @@ _LOGGER = logging.getLogger(__name__) STATE_SMOKE_OFF = 'IDLE_OFF' -async def async_setup_platform(hass, config, async_add_devices, - discovery_info=None): - """Set up the binary sensor devices.""" +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Set up the HomematicIP Cloud binary sensor devices.""" pass async def async_setup_entry(hass, config_entry, async_add_devices): - """Set up the HomematicIP binary sensor from a config entry.""" + """Set up the HomematicIP Cloud binary sensor from a config entry.""" from homematicip.aio.device import ( AsyncShutterContact, AsyncMotionDetectorIndoor, AsyncSmokeDetector) @@ -45,7 +44,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): class HomematicipShutterContact(HomematicipGenericDevice, BinarySensorDevice): - """HomematicIP shutter contact.""" + """Representation of a HomematicIP Cloud shutter contact.""" @property def device_class(self): @@ -65,7 +64,7 @@ class HomematicipShutterContact(HomematicipGenericDevice, BinarySensorDevice): class HomematicipMotionDetector(HomematicipGenericDevice, BinarySensorDevice): - """HomematicIP motion detector.""" + """Representation of a HomematicIP Cloud motion detector.""" @property def device_class(self): @@ -81,7 +80,7 @@ class HomematicipMotionDetector(HomematicipGenericDevice, BinarySensorDevice): class HomematicipSmokeDetector(HomematicipGenericDevice, BinarySensorDevice): - """HomematicIP smoke detector.""" + """Representation of a HomematicIP Cloud smoke detector.""" @property def device_class(self): diff --git a/homeassistant/components/climate/homematic.py b/homeassistant/components/climate/homematic.py index a2725f6f3aa..dd773bcd993 100644 --- a/homeassistant/components/climate/homematic.py +++ b/homeassistant/components/climate/homematic.py @@ -5,12 +5,13 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/climate.homematic/ """ import logging + from homeassistant.components.climate import ( - ClimateDevice, STATE_AUTO, SUPPORT_TARGET_TEMPERATURE, - SUPPORT_OPERATION_MODE) + STATE_AUTO, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE, + ClimateDevice) from homeassistant.components.homematic import ( - HMDevice, ATTR_DISCOVER_DEVICES, HM_ATTRIBUTE_SUPPORT) -from homeassistant.const import TEMP_CELSIUS, STATE_UNKNOWN, ATTR_TEMPERATURE + ATTR_DISCOVER_DEVICES, HM_ATTRIBUTE_SUPPORT, HMDevice) +from homeassistant.const import ATTR_TEMPERATURE, STATE_UNKNOWN, TEMP_CELSIUS DEPENDENCIES = ['homematic'] diff --git a/homeassistant/components/climate/homematicip_cloud.py b/homeassistant/components/climate/homematicip_cloud.py index 8cf47159c10..6b47096df1b 100644 --- a/homeassistant/components/climate/homematicip_cloud.py +++ b/homeassistant/components/climate/homematicip_cloud.py @@ -1,19 +1,18 @@ """ -Support for HomematicIP climate. +Support for HomematicIP Cloud climate devices. -For more details about this component, please refer to the documentation at +For more details about this platform, please refer to the documentation at https://home-assistant.io/components/climate.homematicip_cloud/ """ - import logging from homeassistant.components.climate import ( - ClimateDevice, SUPPORT_TARGET_TEMPERATURE, ATTR_TEMPERATURE, - STATE_AUTO, STATE_MANUAL) -from homeassistant.const import TEMP_CELSIUS + ATTR_TEMPERATURE, STATE_AUTO, STATE_MANUAL, SUPPORT_TARGET_TEMPERATURE, + ClimateDevice) from homeassistant.components.homematicip_cloud import ( - HomematicipGenericDevice, DOMAIN as HMIPC_DOMAIN, - HMIPC_HAPID) + HMIPC_HAPID, HomematicipGenericDevice) +from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN +from homeassistant.const import TEMP_CELSIUS _LOGGER = logging.getLogger(__name__) @@ -27,9 +26,9 @@ HA_STATE_TO_HMIP = { HMIP_STATE_TO_HA = {value: key for key, value in HA_STATE_TO_HMIP.items()} -async def async_setup_platform(hass, config, async_add_devices, - discovery_info=None): - """Set up the HomematicIP climate devices.""" +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Set up the HomematicIP Cloud climate devices.""" pass @@ -48,7 +47,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): class HomematicipHeatingGroup(HomematicipGenericDevice, ClimateDevice): - """Representation of a MomematicIP heating group.""" + """Representation of a HomematicIP heating group.""" def __init__(self, home, device): """Initialize heating group.""" diff --git a/homeassistant/components/cover/homematic.py b/homeassistant/components/cover/homematic.py index 2736b656a15..9975b426558 100644 --- a/homeassistant/components/cover/homematic.py +++ b/homeassistant/components/cover/homematic.py @@ -6,9 +6,9 @@ https://home-assistant.io/components/cover.homematic/ """ import logging -from homeassistant.components.cover import CoverDevice, ATTR_POSITION,\ - ATTR_TILT_POSITION -from homeassistant.components.homematic import HMDevice, ATTR_DISCOVER_DEVICES +from homeassistant.components.cover import ( + ATTR_POSITION, ATTR_TILT_POSITION, CoverDevice) +from homeassistant.components.homematic import ATTR_DISCOVER_DEVICES, HMDevice from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/homematicip_cloud/__init__.py b/homeassistant/components/homematicip_cloud/__init__.py index f2cc8f443ac..05c5c970d2e 100644 --- a/homeassistant/components/homematicip_cloud/__init__.py +++ b/homeassistant/components/homematicip_cloud/__init__.py @@ -1,24 +1,23 @@ """ -Support for HomematicIP components. +Support for HomematicIP Cloud components. For more details about this component, please refer to the documentation at https://home-assistant.io/components/homematicip_cloud/ """ - import logging import voluptuous as vol -import homeassistant.helpers.config_validation as cv from homeassistant import config_entries +from homeassistant.const import CONF_NAME +import homeassistant.helpers.config_validation as cv -from .const import ( - DOMAIN, HMIPC_HAPID, HMIPC_AUTHTOKEN, HMIPC_NAME, - CONF_ACCESSPOINT, CONF_AUTHTOKEN, CONF_NAME) -# Loading the config flow file will register the flow from .config_flow import configured_haps -from .hap import HomematicipHAP, HomematicipAuth # noqa: F401 +from .const import ( + CONF_ACCESSPOINT, CONF_AUTHTOKEN, DOMAIN, HMIPC_AUTHTOKEN, HMIPC_HAPID, + HMIPC_NAME) from .device import HomematicipGenericDevice # noqa: F401 +from .hap import HomematicipAuth, HomematicipHAP # noqa: F401 REQUIREMENTS = ['homematicip==0.9.8'] @@ -34,7 +33,7 @@ CONFIG_SCHEMA = vol.Schema({ async def async_setup(hass, config): - """Set up the HomematicIP component.""" + """Set up the HomematicIP Cloud component.""" hass.data[DOMAIN] = {} accesspoints = config.get(DOMAIN, []) @@ -54,7 +53,7 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): - """Set up an accsspoint from a config entry.""" + """Set up an access point from a config entry.""" hap = HomematicipHAP(hass, entry) hapid = entry.data[HMIPC_HAPID].replace('-', '').upper() hass.data[DOMAIN][hapid] = hap diff --git a/homeassistant/components/homematicip_cloud/config_flow.py b/homeassistant/components/homematicip_cloud/config_flow.py index 78970031d11..d5045cf151b 100644 --- a/homeassistant/components/homematicip_cloud/config_flow.py +++ b/homeassistant/components/homematicip_cloud/config_flow.py @@ -1,25 +1,25 @@ -"""Config flow to configure HomematicIP Cloud.""" +"""Config flow to configure the HomematicIP Cloud component.""" import voluptuous as vol from homeassistant import config_entries, data_entry_flow from homeassistant.core import callback -from .const import ( - DOMAIN as HMIPC_DOMAIN, _LOGGER, - HMIPC_HAPID, HMIPC_AUTHTOKEN, HMIPC_PIN, HMIPC_NAME) +from .const import DOMAIN as HMIPC_DOMAIN +from .const import HMIPC_AUTHTOKEN, HMIPC_HAPID, HMIPC_NAME, HMIPC_PIN +from .const import _LOGGER from .hap import HomematicipAuth @callback def configured_haps(hass): - """Return a set of the configured accesspoints.""" + """Return a set of the configured access points.""" return set(entry.data[HMIPC_HAPID] for entry in hass.config_entries.async_entries(HMIPC_DOMAIN)) @config_entries.HANDLERS.register(HMIPC_DOMAIN) class HomematicipCloudFlowHandler(data_entry_flow.FlowHandler): - """Config flow HomematicIP Cloud.""" + """Config flow for the HomematicIP Cloud component.""" VERSION = 1 @@ -44,28 +44,28 @@ class HomematicipCloudFlowHandler(data_entry_flow.FlowHandler): self.auth = HomematicipAuth(self.hass, user_input) connected = await self.auth.async_setup() if connected: - _LOGGER.info("Connection established") + _LOGGER.info("Connection to HomematicIP Cloud established") return await self.async_step_link() return self.async_show_form( step_id='init', data_schema=vol.Schema({ vol.Required(HMIPC_HAPID): str, - vol.Optional(HMIPC_PIN): str, vol.Optional(HMIPC_NAME): str, + vol.Optional(HMIPC_PIN): str, }), errors=errors ) async def async_step_link(self, user_input=None): - """Attempt to link with the HomematicIP Cloud accesspoint.""" + """Attempt to link with the HomematicIP Cloud access point.""" errors = {} pressed = await self.auth.async_checkbutton() if pressed: authtoken = await self.auth.async_register() if authtoken: - _LOGGER.info("Write config entry") + _LOGGER.info("Write config entry for HomematicIP Cloud") return self.async_create_entry( title=self.auth.config.get(HMIPC_HAPID), data={ @@ -73,13 +73,13 @@ class HomematicipCloudFlowHandler(data_entry_flow.FlowHandler): HMIPC_AUTHTOKEN: authtoken, HMIPC_NAME: self.auth.config.get(HMIPC_NAME) }) - return self.async_abort(reason='conection_aborted') + return self.async_abort(reason='connection_aborted') errors['base'] = 'press_the_button' return self.async_show_form(step_id='link', errors=errors) async def async_step_import(self, import_info): - """Import a new bridge as a config entry.""" + """Import a new access point as a config entry.""" hapid = import_info[HMIPC_HAPID] authtoken = import_info[HMIPC_AUTHTOKEN] name = import_info[HMIPC_NAME] @@ -88,13 +88,13 @@ class HomematicipCloudFlowHandler(data_entry_flow.FlowHandler): if hapid in configured_haps(self.hass): return self.async_abort(reason='already_configured') - _LOGGER.info('Imported authentication for %s', hapid) + _LOGGER.info("Imported authentication for %s", hapid) return self.async_create_entry( title=hapid, data={ - HMIPC_HAPID: hapid, HMIPC_AUTHTOKEN: authtoken, - HMIPC_NAME: name + HMIPC_HAPID: hapid, + HMIPC_NAME: name, } ) diff --git a/homeassistant/components/homematicip_cloud/const.py b/homeassistant/components/homematicip_cloud/const.py index 54b05c464b5..ba9c37b83d7 100644 --- a/homeassistant/components/homematicip_cloud/const.py +++ b/homeassistant/components/homematicip_cloud/const.py @@ -14,7 +14,6 @@ COMPONENTS = [ 'switch', ] -CONF_NAME = 'name' CONF_ACCESSPOINT = 'accesspoint' CONF_AUTHTOKEN = 'authtoken' diff --git a/homeassistant/components/homematicip_cloud/device.py b/homeassistant/components/homematicip_cloud/device.py index bb21e1df3d5..9c335befda4 100644 --- a/homeassistant/components/homematicip_cloud/device.py +++ b/homeassistant/components/homematicip_cloud/device.py @@ -1,25 +1,25 @@ -"""GenericDevice for the HomematicIP Cloud component.""" +"""Generic device for the HomematicIP Cloud component.""" import logging from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) -ATTR_HOME_ID = 'home_id' -ATTR_HOME_NAME = 'home_name' +ATTR_CONNECTED = 'connected' ATTR_DEVICE_ID = 'device_id' ATTR_DEVICE_LABEL = 'device_label' -ATTR_STATUS_UPDATE = 'status_update' -ATTR_FIRMWARE_STATE = 'firmware_state' -ATTR_UNREACHABLE = 'unreachable' -ATTR_LOW_BATTERY = 'low_battery' -ATTR_MODEL_TYPE = 'model_type' -ATTR_GROUP_TYPE = 'group_type' ATTR_DEVICE_RSSI = 'device_rssi' ATTR_DUTY_CYCLE = 'duty_cycle' -ATTR_CONNECTED = 'connected' -ATTR_SABOTAGE = 'sabotage' +ATTR_FIRMWARE_STATE = 'firmware_state' +ATTR_GROUP_TYPE = 'group_type' +ATTR_HOME_ID = 'home_id' +ATTR_HOME_NAME = 'home_name' +ATTR_LOW_BATTERY = 'low_battery' +ATTR_MODEL_TYPE = 'model_type' ATTR_OPERATION_LOCK = 'operation_lock' +ATTR_SABOTAGE = 'sabotage' +ATTR_STATUS_UPDATE = 'status_update' +ATTR_UNREACHABLE = 'unreachable' class HomematicipGenericDevice(Entity): @@ -30,8 +30,7 @@ class HomematicipGenericDevice(Entity): self._home = home self._device = device self.post = post - _LOGGER.info('Setting up %s (%s)', self.name, - self._device.modelType) + _LOGGER.info("Setting up %s (%s)", self.name, self._device.modelType) async def async_added_to_hass(self): """Register callbacks.""" @@ -39,16 +38,16 @@ class HomematicipGenericDevice(Entity): def _device_changed(self, json, **kwargs): """Handle device state changes.""" - _LOGGER.debug('Event %s (%s)', self.name, self._device.modelType) + _LOGGER.debug("Event %s (%s)", self.name, self._device.modelType) self.async_schedule_update_ha_state() @property def name(self): """Return the name of the generic device.""" name = self._device.label - if (self._home.name is not None and self._home.name != ''): + if self._home.name is not None and self._home.name != '': name = "{} {}".format(self._home.name, name) - if (self.post is not None and self.post != ''): + if self.post is not None and self.post != '': name = "{} {}".format(name, self.post) return name diff --git a/homeassistant/components/homematicip_cloud/errors.py b/homeassistant/components/homematicip_cloud/errors.py index cb2925d1a70..1102cde6fbe 100644 --- a/homeassistant/components/homematicip_cloud/errors.py +++ b/homeassistant/components/homematicip_cloud/errors.py @@ -1,21 +1,21 @@ -"""Errors for the HomematicIP component.""" +"""Errors for the HomematicIP Cloud component.""" from homeassistant.exceptions import HomeAssistantError class HmipcException(HomeAssistantError): - """Base class for HomematicIP exceptions.""" + """Base class for HomematicIP Cloud exceptions.""" class HmipcConnectionError(HmipcException): - """Unable to connect to the HomematicIP cloud server.""" + """Unable to connect to the HomematicIP Cloud server.""" class HmipcConnectionWait(HmipcException): - """Wait for registration to the HomematicIP cloud server.""" + """Wait for registration to the HomematicIP Cloud server.""" class HmipcRegistrationFailed(HmipcException): - """Registration on HomematicIP cloud failed.""" + """Registration on HomematicIP Cloud failed.""" class HmipcPressButton(HmipcException): diff --git a/homeassistant/components/homematicip_cloud/hap.py b/homeassistant/components/homematicip_cloud/hap.py index 9715a5fc024..6fddc7c001e 100644 --- a/homeassistant/components/homematicip_cloud/hap.py +++ b/homeassistant/components/homematicip_cloud/hap.py @@ -1,14 +1,13 @@ -"""Accesspoint for the HomematicIP Cloud component.""" +"""Access point for the HomematicIP Cloud component.""" import asyncio import logging from homeassistant import config_entries -from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.core import callback +from homeassistant.helpers.aiohttp_client import async_get_clientsession from .const import ( - HMIPC_HAPID, HMIPC_AUTHTOKEN, HMIPC_PIN, HMIPC_NAME, - COMPONENTS) + COMPONENTS, HMIPC_AUTHTOKEN, HMIPC_HAPID, HMIPC_NAME, HMIPC_PIN) from .errors import HmipcConnectionError _LOGGER = logging.getLogger(__name__) @@ -74,10 +73,10 @@ class HomematicipAuth: class HomematicipHAP: - """Manages HomematicIP http and websocket connection.""" + """Manages HomematicIP HTTP and WebSocket connection.""" def __init__(self, hass, config_entry): - """Initialize HomematicIP cloud connection.""" + """Initialize HomematicIP Cloud connection.""" self.hass = hass self.config_entry = config_entry self.home = None @@ -100,7 +99,7 @@ class HomematicipHAP: except HmipcConnectionError: retry_delay = 2 ** min(tries + 1, 6) _LOGGER.error("Error connecting to HomematicIP with HAP %s. " - "Retrying in %d seconds.", + "Retrying in %d seconds", self.config_entry.data.get(HMIPC_HAPID), retry_delay) async def retry_setup(_now): @@ -113,7 +112,7 @@ class HomematicipHAP: return False - _LOGGER.info('Connected to HomematicIP with HAP %s.', + _LOGGER.info("Connected to HomematicIP with HAP %s", self.config_entry.data.get(HMIPC_HAPID)) for component in COMPONENTS: @@ -127,7 +126,7 @@ class HomematicipHAP: def async_update(self, *args, **kwargs): """Async update the home device. - Triggered when the hmip HOME_CHANGED event has fired. + Triggered when the HMIP HOME_CHANGED event has fired. There are several occasions for this event to happen. We are only interested to check whether the access point is still connected. If not, device state changes cannot @@ -147,7 +146,7 @@ class HomematicipHAP: job.add_done_callback(self.get_state_finished) async def get_state(self): - """Update hmip state and tell hass.""" + """Update HMIP state and tell Home Assistant.""" await self.home.get_current_state() self.update_all() @@ -161,11 +160,11 @@ class HomematicipHAP: # Somehow connection could not recover. Will disconnect and # so reconnect loop is taking over. _LOGGER.error( - "updating state after himp access point reconnect failed.") + "Updating state after HMIP access point reconnect failed") self.hass.async_add_job(self.home.disable_events()) def set_all_to_unavailable(self): - """Set all devices to unavailable and tell Hass.""" + """Set all devices to unavailable and tell Home Assistant.""" for device in self.home.devices: device.unreach = True self.update_all() @@ -190,7 +189,7 @@ class HomematicipHAP: return async def async_connect(self): - """Start websocket connection.""" + """Start WebSocket connection.""" from homematicip.base.base_connection import HmipConnectionError tries = 0 @@ -210,7 +209,7 @@ class HomematicipHAP: tries += 1 retry_delay = 2 ** min(tries + 1, 6) _LOGGER.error("Error connecting to HomematicIP with HAP %s. " - "Retrying in %d seconds.", + "Retrying in %d seconds", self.config_entry.data.get(HMIPC_HAPID), retry_delay) try: self._retry_task = self.hass.async_add_job(asyncio.sleep( @@ -227,7 +226,7 @@ class HomematicipHAP: if self._retry_task is not None: self._retry_task.cancel() self.home.disable_events() - _LOGGER.info("Closed connection to HomematicIP cloud server.") + _LOGGER.info("Closed connection to HomematicIP cloud server") for component in COMPONENTS: await self.hass.config_entries.async_forward_entry_unload( self.config_entry, component) diff --git a/homeassistant/components/homematicip_cloud/strings.json b/homeassistant/components/homematicip_cloud/strings.json index 887a3a5780b..f2d38a1dc7b 100644 --- a/homeassistant/components/homematicip_cloud/strings.json +++ b/homeassistant/components/homematicip_cloud/strings.json @@ -3,16 +3,16 @@ "title": "HomematicIP Cloud", "step": { "init": { - "title": "Pick HomematicIP Accesspoint", + "title": "Pick HomematicIP Access point", "data": { - "hapid": "Accesspoint ID (SGTIN)", + "hapid": "Access point ID (SGTIN)", "pin": "Pin Code (optional)", "name": "Name (optional, used as name prefix for all devices)" } }, "link": { - "title": "Link Accesspoint", - "description": "Press the blue button on the accesspoint and the submit button to register HomematicIP with Home Assistant.\n\n![Location of button on bridge](/static/images/config_flows/config_homematicip_cloud.png)" + "title": "Link Access point", + "description": "Press the blue button on the access point and the submit button to register HomematicIP with Home Assistant.\n\n![Location of button on bridge](/static/images/config_flows/config_homematicip_cloud.png)" } }, "error": { @@ -23,8 +23,8 @@ }, "abort": { "unknown": "Unknown error occurred.", - "conection_aborted": "Could not connect to HMIP server", - "already_configured": "Accesspoint is already configured" + "connection_aborted": "Could not connect to HMIP server", + "already_configured": "Access point is already configured" } } } diff --git a/homeassistant/components/light/homematic.py b/homeassistant/components/light/homematic.py index a3db1ff30ff..2d7c855c538 100644 --- a/homeassistant/components/light/homematic.py +++ b/homeassistant/components/light/homematic.py @@ -5,9 +5,10 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.homematic/ """ import logging + +from homeassistant.components.homematic import ATTR_DISCOVER_DEVICES, HMDevice from homeassistant.components.light import ( ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) -from homeassistant.components.homematic import HMDevice, ATTR_DISCOVER_DEVICES from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/light/homematicip_cloud.py b/homeassistant/components/light/homematicip_cloud.py index 617a7209a86..f958879386d 100644 --- a/homeassistant/components/light/homematicip_cloud.py +++ b/homeassistant/components/light/homematicip_cloud.py @@ -1,37 +1,35 @@ """ -Support for HomematicIP light. +Support for HomematicIP Cloud lights. -For more details about this component, please refer to the documentation at +For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.homematicip_cloud/ """ - import logging -from homeassistant.components.light import ( - Light, ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS) from homeassistant.components.homematicip_cloud import ( - HomematicipGenericDevice, DOMAIN as HMIPC_DOMAIN, - HMIPC_HAPID) + HMIPC_HAPID, HomematicipGenericDevice) +from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) DEPENDENCIES = ['homematicip_cloud'] _LOGGER = logging.getLogger(__name__) +ATTR_ENERGY_COUNTER = 'energy_counter_kwh' ATTR_POWER_CONSUMPTION = 'power_consumption' -ATTR_ENERGIE_COUNTER = 'energie_counter_kwh' ATTR_PROFILE_MODE = 'profile_mode' -async def async_setup_platform(hass, config, async_add_devices, - discovery_info=None): - """Old way of setting up HomematicIP lights.""" +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Old way of setting up HomematicIP Cloud lights.""" pass async def async_setup_entry(hass, config_entry, async_add_devices): - """Set up the HomematicIP lights from a config entry.""" - from homematicip.aio.device import ( - AsyncBrandSwitchMeasuring, AsyncDimmer) + """Set up the HomematicIP Cloud lights from a config entry.""" + from homematicip.aio.device import AsyncBrandSwitchMeasuring, AsyncDimmer home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home devices = [] @@ -46,7 +44,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): class HomematicipLight(HomematicipGenericDevice, Light): - """MomematicIP light device.""" + """Representation of a HomematicIP Cloud light device.""" def __init__(self, home, device): """Initialize the light device.""" @@ -67,7 +65,7 @@ class HomematicipLight(HomematicipGenericDevice, Light): class HomematicipLightMeasuring(HomematicipLight): - """MomematicIP measuring light device.""" + """Representation of a HomematicIP Cloud measuring light device.""" @property def device_state_attributes(self): @@ -79,13 +77,13 @@ class HomematicipLightMeasuring(HomematicipLight): round(self._device.currentPowerConsumption, 2) }) attr.update({ - ATTR_ENERGIE_COUNTER: round(self._device.energyCounter, 2) + ATTR_ENERGY_COUNTER: round(self._device.energyCounter, 2) }) return attr class HomematicipDimmer(HomematicipGenericDevice, Light): - """MomematicIP dimmer light device.""" + """Representation of HomematicIP Cloud dimmer light device.""" def __init__(self, home, device): """Initialize the dimmer light device.""" @@ -109,8 +107,7 @@ class HomematicipDimmer(HomematicipGenericDevice, Light): async def async_turn_on(self, **kwargs): """Turn the light on.""" if ATTR_BRIGHTNESS in kwargs: - await self._device.set_dim_level( - kwargs[ATTR_BRIGHTNESS]/255.0) + await self._device.set_dim_level(kwargs[ATTR_BRIGHTNESS]/255.0) else: await self._device.set_dim_level(1) diff --git a/homeassistant/components/lock/homematic.py b/homeassistant/components/lock/homematic.py index 0d70849e37e..7c4195d7c8b 100644 --- a/homeassistant/components/lock/homematic.py +++ b/homeassistant/components/lock/homematic.py @@ -5,10 +5,10 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/lock.homematic/ """ import logging -from homeassistant.components.lock import LockDevice, SUPPORT_OPEN -from homeassistant.components.homematic import HMDevice, ATTR_DISCOVER_DEVICES -from homeassistant.const import STATE_UNKNOWN +from homeassistant.components.homematic import ATTR_DISCOVER_DEVICES, HMDevice +from homeassistant.components.lock import SUPPORT_OPEN, LockDevice +from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/homematic.py b/homeassistant/components/sensor/homematic.py index 60741a9f3c8..0303525abcf 100644 --- a/homeassistant/components/sensor/homematic.py +++ b/homeassistant/components/sensor/homematic.py @@ -5,8 +5,9 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.homematic/ """ import logging + +from homeassistant.components.homematic import ATTR_DISCOVER_DEVICES, HMDevice from homeassistant.const import STATE_UNKNOWN -from homeassistant.components.homematic import HMDevice, ATTR_DISCOVER_DEVICES _LOGGER = logging.getLogger(__name__) @@ -70,7 +71,7 @@ HM_ICON_HA_CAST = { def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the HomeMatic platform.""" + """Set up the HomeMatic sensor platform.""" if discovery_info is None: return @@ -83,7 +84,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class HMSensor(HMDevice): - """Represents various HomeMatic sensors in Home Assistant.""" + """Representation of a HomeMatic sensor.""" @property def state(self): @@ -111,4 +112,4 @@ class HMSensor(HMDevice): if self._state: self._data.update({self._state: STATE_UNKNOWN}) else: - _LOGGER.critical("Can't initialize sensor %s", self._name) + _LOGGER.critical("Unable to initialize sensor: %s", self._name) diff --git a/homeassistant/components/sensor/homematicip_cloud.py b/homeassistant/components/sensor/homematicip_cloud.py index 7292e3b2f40..7d4944f5f5f 100644 --- a/homeassistant/components/sensor/homematicip_cloud.py +++ b/homeassistant/components/sensor/homematicip_cloud.py @@ -1,18 +1,17 @@ """ -Support for HomematicIP sensors. +Support for HomematicIP Cloud sensors. -For more details about this component, please refer to the documentation at +For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.homematicip_cloud/ """ - import logging from homeassistant.components.homematicip_cloud import ( - HomematicipGenericDevice, DOMAIN as HMIPC_DOMAIN, - HMIPC_HAPID) + HMIPC_HAPID, HomematicipGenericDevice) +from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN from homeassistant.const import ( - TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY, - DEVICE_CLASS_ILLUMINANCE) + DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE, + TEMP_CELSIUS) _LOGGER = logging.getLogger(__name__) @@ -25,14 +24,14 @@ ATTR_TEMPERATURE_OFFSET = 'temperature_offset' ATTR_HUMIDITY = 'humidity' -async def async_setup_platform(hass, config, async_add_devices, - discovery_info=None): - """Set up the HomematicIP sensors devices.""" +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Set up the HomematicIP Cloud sensors devices.""" pass async def async_setup_entry(hass, config_entry, async_add_devices): - """Set up the HomematicIP sensors from a config entry.""" + """Set up the HomematicIP Cloud sensors from a config entry.""" from homematicip.device import ( HeatingThermostat, TemperatureHumiditySensorWithoutDisplay, TemperatureHumiditySensorDisplay, MotionDetectorIndoor) @@ -54,7 +53,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): class HomematicipAccesspointStatus(HomematicipGenericDevice): - """Representation of an HomeMaticIP access point.""" + """Representation of an HomeMaticIP Cloud access point.""" def __init__(self, home): """Initialize access point device.""" @@ -82,7 +81,7 @@ class HomematicipAccesspointStatus(HomematicipGenericDevice): class HomematicipHeatingThermostat(HomematicipGenericDevice): - """MomematicIP heating thermostat representation.""" + """Represenation of a HomematicIP heating thermostat device.""" def __init__(self, home, device): """Initialize heating thermostat device.""" @@ -115,7 +114,7 @@ class HomematicipHeatingThermostat(HomematicipGenericDevice): class HomematicipHumiditySensor(HomematicipGenericDevice): - """MomematicIP humidity device.""" + """Represenation of a HomematicIP Cloud humidity device.""" def __init__(self, home, device): """Initialize the thermometer device.""" @@ -138,7 +137,7 @@ class HomematicipHumiditySensor(HomematicipGenericDevice): class HomematicipTemperatureSensor(HomematicipGenericDevice): - """MomematicIP the thermometer device.""" + """Representation of a HomematicIP Cloud thermometer device.""" def __init__(self, home, device): """Initialize the thermometer device.""" @@ -161,7 +160,7 @@ class HomematicipTemperatureSensor(HomematicipGenericDevice): class HomematicipIlluminanceSensor(HomematicipGenericDevice): - """MomematicIP the thermometer device.""" + """Represenation of a HomematicIP Illuminance device.""" def __init__(self, home, device): """Initialize the device.""" diff --git a/homeassistant/components/switch/homematic.py b/homeassistant/components/switch/homematic.py index 487947598bb..2cd4145e87a 100644 --- a/homeassistant/components/switch/homematic.py +++ b/homeassistant/components/switch/homematic.py @@ -5,8 +5,9 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.homematic/ """ import logging + +from homeassistant.components.homematic import ATTR_DISCOVER_DEVICES, HMDevice from homeassistant.components.switch import SwitchDevice -from homeassistant.components.homematic import HMDevice, ATTR_DISCOVER_DEVICES from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/switch/homematicip_cloud.py b/homeassistant/components/switch/homematicip_cloud.py index 68884aaaa02..3211cecabfc 100644 --- a/homeassistant/components/switch/homematicip_cloud.py +++ b/homeassistant/components/switch/homematicip_cloud.py @@ -1,16 +1,15 @@ """ -Support for HomematicIP switch. +Support for HomematicIP Cloud switch. -For more details about this component, please refer to the documentation at +For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.homematicip_cloud/ """ - import logging -from homeassistant.components.switch import SwitchDevice from homeassistant.components.homematicip_cloud import ( - HomematicipGenericDevice, DOMAIN as HMIPC_DOMAIN, - HMIPC_HAPID) + HMIPC_HAPID, HomematicipGenericDevice) +from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN +from homeassistant.components.switch import SwitchDevice DEPENDENCIES = ['homematicip_cloud'] @@ -21,17 +20,16 @@ ATTR_ENERGIE_COUNTER = 'energie_counter' ATTR_PROFILE_MODE = 'profile_mode' -async def async_setup_platform(hass, config, async_add_devices, - discovery_info=None): - """Set up the HomematicIP switch devices.""" +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Set up the HomematicIP Cloud switch devices.""" pass async def async_setup_entry(hass, config_entry, async_add_devices): """Set up the HomematicIP switch from a config entry.""" from homematicip.device import ( - PlugableSwitch, PlugableSwitchMeasuring, - BrandSwitchMeasuring) + PlugableSwitch, PlugableSwitchMeasuring, BrandSwitchMeasuring) home = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]].home devices = [] @@ -51,7 +49,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): class HomematicipSwitch(HomematicipGenericDevice, SwitchDevice): - """MomematicIP switch device.""" + """representation of a HomematicIP Cloud switch device.""" def __init__(self, home, device): """Initialize the switch device.""" @@ -72,7 +70,7 @@ class HomematicipSwitch(HomematicipGenericDevice, SwitchDevice): class HomematicipSwitchMeasuring(HomematicipSwitch): - """MomematicIP measuring switch device.""" + """Representation of a HomematicIP measuring switch device.""" @property def current_power_w(self): From 7ed8ed83e393cf9a74d65559577aafe4d213cc6f Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Tue, 21 Aug 2018 21:25:48 +0200 Subject: [PATCH 091/159] Bump python-miio version (#16110) --- homeassistant/components/device_tracker/xiaomi_miio.py | 2 +- homeassistant/components/fan/xiaomi_miio.py | 2 +- homeassistant/components/light/xiaomi_miio.py | 2 +- homeassistant/components/remote/xiaomi_miio.py | 2 +- homeassistant/components/sensor/xiaomi_miio.py | 2 +- homeassistant/components/switch/xiaomi_miio.py | 2 +- homeassistant/components/vacuum/xiaomi_miio.py | 2 +- requirements_all.txt | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/device_tracker/xiaomi_miio.py b/homeassistant/components/device_tracker/xiaomi_miio.py index 074d6a1054e..f811631766e 100644 --- a/homeassistant/components/device_tracker/xiaomi_miio.py +++ b/homeassistant/components/device_tracker/xiaomi_miio.py @@ -20,7 +20,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_TOKEN): vol.All(cv.string, vol.Length(min=32, max=32)), }) -REQUIREMENTS = ['python-miio==0.4.0', 'construct==2.9.41'] +REQUIREMENTS = ['python-miio==0.4.1', 'construct==2.9.41'] def get_scanner(hass, config): diff --git a/homeassistant/components/fan/xiaomi_miio.py b/homeassistant/components/fan/xiaomi_miio.py index 1616d388816..ee8f49f897a 100644 --- a/homeassistant/components/fan/xiaomi_miio.py +++ b/homeassistant/components/fan/xiaomi_miio.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 'zhimi.humidifier.ca1']), }) -REQUIREMENTS = ['python-miio==0.4.0', 'construct==2.9.41'] +REQUIREMENTS = ['python-miio==0.4.1', 'construct==2.9.41'] ATTR_MODEL = 'model' diff --git a/homeassistant/components/light/xiaomi_miio.py b/homeassistant/components/light/xiaomi_miio.py index fbb8dd66f01..2171d084bf0 100644 --- a/homeassistant/components/light/xiaomi_miio.py +++ b/homeassistant/components/light/xiaomi_miio.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 'philips.light.candle2']), }) -REQUIREMENTS = ['python-miio==0.4.0', 'construct==2.9.41'] +REQUIREMENTS = ['python-miio==0.4.1', 'construct==2.9.41'] # The light does not accept cct values < 1 CCT_MIN = 1 diff --git a/homeassistant/components/remote/xiaomi_miio.py b/homeassistant/components/remote/xiaomi_miio.py index eda09e3af64..0375226adec 100644 --- a/homeassistant/components/remote/xiaomi_miio.py +++ b/homeassistant/components/remote/xiaomi_miio.py @@ -22,7 +22,7 @@ from homeassistant.exceptions import PlatformNotReady import homeassistant.helpers.config_validation as cv from homeassistant.util.dt import utcnow -REQUIREMENTS = ['python-miio==0.4.0', 'construct==2.9.41'] +REQUIREMENTS = ['python-miio==0.4.1', 'construct==2.9.41'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/xiaomi_miio.py b/homeassistant/components/sensor/xiaomi_miio.py index 63d93d31cf3..6fb89c5109e 100644 --- a/homeassistant/components/sensor/xiaomi_miio.py +++ b/homeassistant/components/sensor/xiaomi_miio.py @@ -25,7 +25,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }) -REQUIREMENTS = ['python-miio==0.4.0', 'construct==2.9.41'] +REQUIREMENTS = ['python-miio==0.4.1', 'construct==2.9.41'] ATTR_POWER = 'power' ATTR_CHARGING = 'charging' diff --git a/homeassistant/components/switch/xiaomi_miio.py b/homeassistant/components/switch/xiaomi_miio.py index 37b16f44ea8..56203c0552a 100644 --- a/homeassistant/components/switch/xiaomi_miio.py +++ b/homeassistant/components/switch/xiaomi_miio.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 'chuangmi.plug.v3']), }) -REQUIREMENTS = ['python-miio==0.4.0', 'construct==2.9.41'] +REQUIREMENTS = ['python-miio==0.4.1', 'construct==2.9.41'] ATTR_POWER = 'power' ATTR_TEMPERATURE = 'temperature' diff --git a/homeassistant/components/vacuum/xiaomi_miio.py b/homeassistant/components/vacuum/xiaomi_miio.py index 367c8c03d0e..5be594e55a2 100644 --- a/homeassistant/components/vacuum/xiaomi_miio.py +++ b/homeassistant/components/vacuum/xiaomi_miio.py @@ -21,7 +21,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, CONF_HOST, CONF_NAME, CONF_TOKEN, STATE_OFF, STATE_ON) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['python-miio==0.4.0', 'construct==2.9.41'] +REQUIREMENTS = ['python-miio==0.4.1', 'construct==2.9.41'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 1b87a3dbeff..b0c420a59a7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1088,7 +1088,7 @@ python-juicenet==0.0.5 # homeassistant.components.sensor.xiaomi_miio # homeassistant.components.switch.xiaomi_miio # homeassistant.components.vacuum.xiaomi_miio -python-miio==0.4.0 +python-miio==0.4.1 # homeassistant.components.media_player.mpd python-mpd2==1.0.0 From b9733d0d9999b1012e87b82e7a507f65abc6cc4a Mon Sep 17 00:00:00 2001 From: Dan Klaffenbach Date: Wed, 22 Aug 2018 00:20:26 +0200 Subject: [PATCH 092/159] homematic: Add homematic.put_paramset service (#16024) Service to call putParamset method of XML-RPC API --- .../components/homematic/__init__.py | 43 +++++++++++++++++++ .../components/homematic/services.yaml | 17 ++++++++ 2 files changed, 60 insertions(+) diff --git a/homeassistant/components/homematic/__init__.py b/homeassistant/components/homematic/__init__.py index 7b50d1f1cda..527b8c8f018 100644 --- a/homeassistant/components/homematic/__init__.py +++ b/homeassistant/components/homematic/__init__.py @@ -48,6 +48,8 @@ ATTR_MESSAGE = 'message' ATTR_MODE = 'mode' ATTR_TIME = 'time' ATTR_UNIQUE_ID = 'unique_id' +ATTR_PARAMSET_KEY = 'paramset_key' +ATTR_PARAMSET = 'paramset' EVENT_KEYPRESS = 'homematic.keypress' EVENT_IMPULSE = 'homematic.impulse' @@ -58,6 +60,7 @@ SERVICE_RECONNECT = 'reconnect' SERVICE_SET_VARIABLE_VALUE = 'set_variable_value' SERVICE_SET_DEVICE_VALUE = 'set_device_value' SERVICE_SET_INSTALL_MODE = 'set_install_mode' +SERVICE_PUT_PARAMSET = 'put_paramset' HM_DEVICE_TYPES = { DISCOVER_SWITCHES: [ @@ -232,6 +235,13 @@ SCHEMA_SERVICE_SET_INSTALL_MODE = vol.Schema({ vol.Optional(ATTR_ADDRESS): vol.All(cv.string, vol.Upper), }) +SCHEMA_SERVICE_PUT_PARAMSET = vol.Schema({ + vol.Required(ATTR_INTERFACE): cv.string, + vol.Required(ATTR_ADDRESS): vol.All(cv.string, vol.Upper), + vol.Required(ATTR_PARAMSET_KEY): vol.All(cv.string, vol.Upper), + vol.Required(ATTR_PARAMSET): dict, +}) + @bind_hass def virtualkey(hass, address, channel, param, interface=None): @@ -271,6 +281,19 @@ def set_device_value(hass, address, channel, param, value, interface=None): hass.services.call(DOMAIN, SERVICE_SET_DEVICE_VALUE, data) +@bind_hass +def put_paramset(hass, interface, address, paramset_key, paramset): + """Call putParamset XML-RPC method of supplied interface.""" + data = { + ATTR_INTERFACE: interface, + ATTR_ADDRESS: address, + ATTR_PARAMSET_KEY: paramset_key, + ATTR_PARAMSET: paramset, + } + + hass.services.call(DOMAIN, SERVICE_PUT_PARAMSET, data) + + @bind_hass def set_install_mode(hass, interface, mode=None, time=None, address=None): """Call setInstallMode XML-RPC method of supplied interface.""" @@ -439,6 +462,26 @@ def setup(hass, config): DOMAIN, SERVICE_SET_INSTALL_MODE, _service_handle_install_mode, schema=SCHEMA_SERVICE_SET_INSTALL_MODE) + def _service_put_paramset(service): + """Service to call the putParamset method on a HomeMatic connection.""" + interface = service.data.get(ATTR_INTERFACE) + address = service.data.get(ATTR_ADDRESS) + paramset_key = service.data.get(ATTR_PARAMSET_KEY) + # When passing in the paramset from a YAML file we get an OrderedDict + # here instead of a dict, so add this explicit cast. + # The service schema makes sure that this cast works. + paramset = dict(service.data.get(ATTR_PARAMSET)) + + _LOGGER.debug( + "Calling putParamset: %s, %s, %s, %s", + interface, address, paramset_key, paramset + ) + homematic.putParamset(interface, address, paramset_key, paramset) + + hass.services.register( + DOMAIN, SERVICE_PUT_PARAMSET, _service_put_paramset, + schema=SCHEMA_SERVICE_PUT_PARAMSET) + return True diff --git a/homeassistant/components/homematic/services.yaml b/homeassistant/components/homematic/services.yaml index c2946b51842..044bcfa46ad 100644 --- a/homeassistant/components/homematic/services.yaml +++ b/homeassistant/components/homematic/services.yaml @@ -66,3 +66,20 @@ set_install_mode: address: description: (Optional) Address of homematic device or BidCoS-RF to learn example: LEQ3948571 + +put_paramset: + description: Call to putParamset in the RPC XML interface + fields: + interface: + description: The interfaces name from the config + example: wireless + address: + description: Address of Homematic device + example: LEQ3948571 + paramset_key: + description: The paramset_key argument to putParamset + example: MASTER + paramset: + description: A paramset dictionary + example: '{"WEEK_PROGRAM_POINTER": 1}' + From 523af4fbcac61e581feb045a9bb1455da6e3b519 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 22 Aug 2018 07:15:56 +0200 Subject: [PATCH 093/159] Upgrade shodan to 1.9.1 (#16113) --- homeassistant/components/sensor/shodan.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/shodan.py b/homeassistant/components/sensor/shodan.py index dfc49ce6639..b94d0cc011c 100644 --- a/homeassistant/components/sensor/shodan.py +++ b/homeassistant/components/sensor/shodan.py @@ -14,7 +14,7 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['shodan==1.9.0'] +REQUIREMENTS = ['shodan==1.9.1'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index b0c420a59a7..8185f6aa2d1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1273,7 +1273,7 @@ sense_energy==0.4.1 sharp_aquos_rc==0.3.2 # homeassistant.components.sensor.shodan -shodan==1.9.0 +shodan==1.9.1 # homeassistant.components.notify.simplepush simplepush==1.1.4 From 6864a44b5ad3485cb55064431cf20ec860ce1a6b Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 22 Aug 2018 07:16:21 +0200 Subject: [PATCH 094/159] Upgrade sendgrid to 5.6.0 (#16111) --- homeassistant/components/notify/sendgrid.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/notify/sendgrid.py b/homeassistant/components/notify/sendgrid.py index 5fd085f3d26..231a17455d1 100644 --- a/homeassistant/components/notify/sendgrid.py +++ b/homeassistant/components/notify/sendgrid.py @@ -14,7 +14,7 @@ from homeassistant.const import ( CONF_API_KEY, CONF_SENDER, CONF_RECIPIENT, CONTENT_TYPE_TEXT_PLAIN) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['sendgrid==5.5.0'] +REQUIREMENTS = ['sendgrid==5.6.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 8185f6aa2d1..ada216de5d8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1260,7 +1260,7 @@ schiene==0.22 scsgate==0.1.0 # homeassistant.components.notify.sendgrid -sendgrid==5.5.0 +sendgrid==5.6.0 # homeassistant.components.light.sensehat # homeassistant.components.sensor.sensehat From a31501d99eb90430a6de9ea366fbea59fc944dad Mon Sep 17 00:00:00 2001 From: Tom Harris Date: Wed, 22 Aug 2018 03:09:04 -0400 Subject: [PATCH 095/159] Merge insteon_plm and insteon_local to insteon component (#16102) * Implement X10 * Add X10 after add_device_callback * Ref device by id not hex and add x10OnOffSwitch name * X10 services and add sensor device * Correctly reference X10_HOUSECODE_SCHEMA * Log adding of X10 devices * Add X10 All Units Off, All Lights On and All Lights Off devices * Correct ref to X10 states vs devices * Add X10 All Units Off, All Lights On and All Lights Off devices * Correct X10 config * Debug x10 device additions * Config x10 from bool to housecode char * Pass PLM to X10 device create * Remove PLM to call to add_x10_device * Unconfuse x10 config and method names * Correct spelling of x10_all_lights_off_housecode * Bump insteonplm to 0.10.0 to support X10 * Add host to config options * Add username and password to config for hub connectivity * Add username and password to config for hub * Convert port to int if host is defined * Add KeypadLinc * Update config schema to require either port or host * Solidify Hub and PLM configuration to ensure proper settings * Update hub schema * Bump insteonplm version * Fix pylint and flake issues * Bump insteonplm to 0.12.1 * Merge insteon_plm and insteon_local to insteon * Rename insteon_plm to insteon * Bump insteonplm to 0.12.2 * Flake8 cleanup * Update .coveragerc for insteon_plm, insteon_local and insteon changes * Add persistent notification * Fix reference to insteon_plm * Fix indentation * Shorten message and fix grammer * Add comment to remove in release 0.90 * Hound fix --- .coveragerc | 9 +- .../{insteon_plm.py => insteon.py} | 18 +- .../fan/{insteon_plm.py => insteon.py} | 16 +- homeassistant/components/fan/insteon_local.py | 107 ----------- .../{insteon_plm => insteon}/__init__.py | 169 +++++++++++------- .../{insteon_plm => insteon}/services.yaml | 0 homeassistant/components/insteon_local.py | 84 ++------- homeassistant/components/insteon_plm.py | 30 ++++ .../light/{insteon_plm.py => insteon.py} | 16 +- .../components/light/insteon_local.py | 98 ---------- .../sensor/{insteon_plm.py => insteon.py} | 16 +- .../switch/{insteon_plm.py => insteon.py} | 25 ++- .../components/switch/insteon_local.py | 83 --------- requirements_all.txt | 7 +- 14 files changed, 204 insertions(+), 474 deletions(-) rename homeassistant/components/binary_sensor/{insteon_plm.py => insteon.py} (76%) rename homeassistant/components/fan/{insteon_plm.py => insteon.py} (86%) delete mode 100644 homeassistant/components/fan/insteon_local.py rename homeassistant/components/{insteon_plm => insteon}/__init__.py (73%) rename homeassistant/components/{insteon_plm => insteon}/services.yaml (100%) create mode 100644 homeassistant/components/insteon_plm.py rename homeassistant/components/light/{insteon_plm.py => insteon.py} (80%) delete mode 100644 homeassistant/components/light/insteon_local.py rename homeassistant/components/sensor/{insteon_plm.py => insteon.py} (61%) rename homeassistant/components/switch/{insteon_plm.py => insteon.py} (69%) delete mode 100644 homeassistant/components/switch/insteon_local.py diff --git a/.coveragerc b/.coveragerc index 989830e5c9d..62f710f3680 100644 --- a/.coveragerc +++ b/.coveragerc @@ -136,12 +136,13 @@ omit = homeassistant/components/ihc/* homeassistant/components/*/ihc.py + + homeassistant/components/insteon/* + homeassistant/components/*/insteon.py homeassistant/components/insteon_local.py - homeassistant/components/*/insteon_local.py - - homeassistant/components/insteon_plm/* - homeassistant/components/*/insteon_plm.py + + homeassistant/components/insteon_plm.py homeassistant/components/ios.py homeassistant/components/*/ios.py diff --git a/homeassistant/components/binary_sensor/insteon_plm.py b/homeassistant/components/binary_sensor/insteon.py similarity index 76% rename from homeassistant/components/binary_sensor/insteon_plm.py rename to homeassistant/components/binary_sensor/insteon.py index 25fc3fb5d73..789ad894a41 100644 --- a/homeassistant/components/binary_sensor/insteon_plm.py +++ b/homeassistant/components/binary_sensor/insteon.py @@ -2,15 +2,15 @@ Support for INSTEON dimmers via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/binary_sensor.insteon_plm/ +https://home-assistant.io/components/binary_sensor.insteon/ """ import asyncio import logging from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] _LOGGER = logging.getLogger(__name__) @@ -24,27 +24,27 @@ SENSOR_TYPES = {'openClosedSensor': 'opening', @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] name = device.states[state_key].name if name != 'dryLeakSensor': _LOGGER.debug('Adding device %s entity %s to Binary Sensor platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMBinarySensor(device, state_key) + new_entity = InsteonBinarySensor(device, state_key) async_add_devices([new_entity]) -class InsteonPLMBinarySensor(InsteonPLMEntity, BinarySensorDevice): +class InsteonBinarySensor(InsteonEntity, BinarySensorDevice): """A Class for an Insteon device entity.""" def __init__(self, device, state_key): - """Initialize the INSTEON PLM binary sensor.""" + """Initialize the INSTEON binary sensor.""" super().__init__(device, state_key) self._sensor_type = SENSOR_TYPES.get(self._insteon_device_state.name) diff --git a/homeassistant/components/fan/insteon_plm.py b/homeassistant/components/fan/insteon.py similarity index 86% rename from homeassistant/components/fan/insteon_plm.py rename to homeassistant/components/fan/insteon.py index 0911295d090..62fa48935ec 100644 --- a/homeassistant/components/fan/insteon_plm.py +++ b/homeassistant/components/fan/insteon.py @@ -2,7 +2,7 @@ Support for INSTEON fans via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/fan.insteon_plm/ +https://home-assistant.io/components/fan.insteon/ """ import asyncio import logging @@ -14,9 +14,9 @@ from homeassistant.components.fan import (SPEED_OFF, FanEntity, SUPPORT_SET_SPEED) from homeassistant.const import STATE_OFF -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] SPEED_TO_HEX = {SPEED_OFF: 0x00, SPEED_LOW: 0x3f, @@ -30,22 +30,22 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] _LOGGER.debug('Adding device %s entity %s to Fan platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMFan(device, state_key) + new_entity = InsteonFan(device, state_key) async_add_devices([new_entity]) -class InsteonPLMFan(InsteonPLMEntity, FanEntity): +class InsteonFan(InsteonEntity, FanEntity): """An INSTEON fan component.""" @property diff --git a/homeassistant/components/fan/insteon_local.py b/homeassistant/components/fan/insteon_local.py deleted file mode 100644 index 28b93c86ed7..00000000000 --- a/homeassistant/components/fan/insteon_local.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -Support for Insteon fans via local hub control. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/fan.insteon_local/ -""" -import logging -from datetime import timedelta - -from homeassistant import util -from homeassistant.components.fan import ( - ATTR_SPEED, SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH, - SUPPORT_SET_SPEED, FanEntity) - -_CONFIGURING = {} -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['insteon_local'] -DOMAIN = 'fan' - -MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - -SUPPORT_INSTEON_LOCAL = SUPPORT_SET_SPEED - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Insteon local fan platform.""" - insteonhub = hass.data['insteon_local'] - if discovery_info is None: - return - - linked = discovery_info['linked'] - device_list = [] - for device_id in linked: - if (linked[device_id]['cat_type'] == 'dimmer' and - linked[device_id]['sku'] == '2475F'): - device = insteonhub.fan(device_id) - device_list.append( - InsteonLocalFanDevice(device) - ) - - add_devices(device_list) - - -class InsteonLocalFanDevice(FanEntity): - """An abstract Class for an Insteon node.""" - - def __init__(self, node): - """Initialize the device.""" - self.node = node - self._speed = SPEED_OFF - - @property - def name(self): - """Return the name of the node.""" - return self.node.device_id - - @property - def unique_id(self): - """Return the ID of this Insteon node.""" - return self.node.device_id - - @property - def speed(self) -> str: - """Return the current speed.""" - return self._speed - - @property - def speed_list(self) -> list: - """Get the list of available speeds.""" - return [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH] - - @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) - def update(self): - """Update state of the fan.""" - resp = self.node.status() - if 'cmd2' in resp: - if resp['cmd2'] == '00': - self._speed = SPEED_OFF - elif resp['cmd2'] == '55': - self._speed = SPEED_LOW - elif resp['cmd2'] == 'AA': - self._speed = SPEED_MEDIUM - elif resp['cmd2'] == 'FF': - self._speed = SPEED_HIGH - - @property - def supported_features(self): - """Flag supported features.""" - return SUPPORT_INSTEON_LOCAL - - def turn_on(self, speed: str = None, **kwargs) -> None: - """Turn device on.""" - if speed is None: - speed = kwargs.get(ATTR_SPEED, SPEED_MEDIUM) - - self.set_speed(speed) - - def turn_off(self, **kwargs) -> None: - """Turn device off.""" - self.node.off() - - def set_speed(self, speed: str) -> None: - """Set the speed of the fan.""" - if self.node.on(speed): - self._speed = speed diff --git a/homeassistant/components/insteon_plm/__init__.py b/homeassistant/components/insteon/__init__.py similarity index 73% rename from homeassistant/components/insteon_plm/__init__.py rename to homeassistant/components/insteon/__init__.py index 055015b74f5..212cdbac3b8 100644 --- a/homeassistant/components/insteon_plm/__init__.py +++ b/homeassistant/components/insteon/__init__.py @@ -1,8 +1,8 @@ """ -Support for INSTEON PowerLinc Modem. +Support for INSTEON Modems (PLM and Hub). For more details about this component, please refer to the documentation at -https://home-assistant.io/components/insteon_plm/ +https://home-assistant.io/components/insteon/ """ import asyncio import collections @@ -12,18 +12,24 @@ import voluptuous as vol from homeassistant.core import callback from homeassistant.const import (CONF_PORT, EVENT_HOMEASSISTANT_STOP, CONF_PLATFORM, - CONF_ENTITY_ID) + CONF_ENTITY_ID, + CONF_HOST) import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['insteonplm==0.11.7'] +REQUIREMENTS = ['insteonplm==0.12.3'] _LOGGER = logging.getLogger(__name__) -DOMAIN = 'insteon_plm' +DOMAIN = 'insteon' +CONF_IP_PORT = 'ip_port' +CONF_HUB_USERNAME = 'username' +CONF_HUB_PASSWORD = 'password' CONF_OVERRIDE = 'device_override' +CONF_PLM_HUB_MSG = ('Must configure either a PLM port or a Hub host, username ' + 'and password') CONF_ADDRESS = 'address' CONF_CAT = 'cat' CONF_SUBCAT = 'subcat' @@ -56,8 +62,8 @@ HOUSECODES = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'] BUTTON_PRESSED_STATE_NAME = 'onLevelButton' -EVENT_BUTTON_ON = 'insteon_plm.button_on' -EVENT_BUTTON_OFF = 'insteon_plm.button_off' +EVENT_BUTTON_ON = 'insteon.button_on' +EVENT_BUTTON_OFF = 'insteon.button_off' EVENT_CONF_BUTTON = 'button' CONF_DEVICE_OVERRIDE_SCHEMA = vol.All( @@ -79,17 +85,34 @@ CONF_X10_SCHEMA = vol.All( })) CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_PORT): cv.string, - vol.Optional(CONF_OVERRIDE): vol.All( - cv.ensure_list_csv, [CONF_DEVICE_OVERRIDE_SCHEMA]), - vol.Optional(CONF_X10_ALL_UNITS_OFF): vol.In(HOUSECODES), - vol.Optional(CONF_X10_ALL_LIGHTS_ON): vol.In(HOUSECODES), - vol.Optional(CONF_X10_ALL_LIGHTS_OFF): vol.In(HOUSECODES), - vol.Optional(CONF_X10): vol.All( - cv.ensure_list_csv, [CONF_X10_SCHEMA]) - }) -}, extra=vol.ALLOW_EXTRA) + DOMAIN: vol.All( + vol.Schema( + {vol.Exclusive(CONF_PORT, 'plm_or_hub', + msg=CONF_PLM_HUB_MSG): cv.isdevice, + vol.Exclusive(CONF_HOST, 'plm_or_hub', + msg=CONF_PLM_HUB_MSG): cv.string, + vol.Optional(CONF_IP_PORT, default=25105): int, + vol.Optional(CONF_HUB_USERNAME): cv.string, + vol.Optional(CONF_HUB_PASSWORD): cv.string, + vol.Optional(CONF_OVERRIDE): vol.All( + cv.ensure_list_csv, [CONF_DEVICE_OVERRIDE_SCHEMA]), + vol.Optional(CONF_X10_ALL_UNITS_OFF): vol.In(HOUSECODES), + vol.Optional(CONF_X10_ALL_LIGHTS_ON): vol.In(HOUSECODES), + vol.Optional(CONF_X10_ALL_LIGHTS_OFF): vol.In(HOUSECODES), + vol.Optional(CONF_X10): vol.All(cv.ensure_list_csv, + [CONF_X10_SCHEMA]) + }, extra=vol.ALLOW_EXTRA, required=True), + cv.has_at_least_one_key(CONF_PORT, CONF_HOST), + vol.Schema( + {vol.Inclusive(CONF_HOST, 'hub', + msg=CONF_PLM_HUB_MSG): cv.string, + vol.Inclusive(CONF_HUB_USERNAME, 'hub', + msg=CONF_PLM_HUB_MSG): cv.string, + vol.Inclusive(CONF_HUB_PASSWORD, 'hub', + msg=CONF_PLM_HUB_MSG): cv.string, + }, extra=vol.ALLOW_EXTRA, required=True)) + }, extra=vol.ALLOW_EXTRA) + ADD_ALL_LINK_SCHEMA = vol.Schema({ vol.Required(SRV_ALL_LINK_GROUP): vol.Range(min=0, max=255), @@ -116,14 +139,18 @@ X10_HOUSECODE_SCHEMA = vol.Schema({ @asyncio.coroutine def async_setup(hass, config): - """Set up the connection to the PLM.""" + """Set up the connection to the modem.""" import insteonplm ipdb = IPDB() - plm = None + insteon_modem = None conf = config[DOMAIN] port = conf.get(CONF_PORT) + host = conf.get(CONF_HOST) + ip_port = conf.get(CONF_IP_PORT) + username = conf.get(CONF_HUB_USERNAME) + password = conf.get(CONF_HUB_PASSWORD) overrides = conf.get(CONF_OVERRIDE, []) x10_devices = conf.get(CONF_X10, []) x10_all_units_off_housecode = conf.get(CONF_X10_ALL_UNITS_OFF) @@ -131,7 +158,7 @@ def async_setup(hass, config): x10_all_lights_off_housecode = conf.get(CONF_X10_ALL_LIGHTS_OFF) @callback - def async_plm_new_device(device): + def async_new_insteon_device(device): """Detect device from transport to be delegated to platform.""" for state_key in device.states: platform_info = ipdb[device.states[state_key]] @@ -143,7 +170,7 @@ def async_setup(hass, config): _fire_button_on_off_event) else: - _LOGGER.info("New INSTEON PLM device: %s (%s) %s", + _LOGGER.info("New INSTEON device: %s (%s) %s", device.address, device.states[state_key].name, platform) @@ -160,12 +187,12 @@ def async_setup(hass, config): group = service.data.get(SRV_ALL_LINK_GROUP) mode = service.data.get(SRV_ALL_LINK_MODE) link_mode = 1 if mode.lower() == SRV_CONTROLLER else 0 - plm.start_all_linking(link_mode, group) + insteon_modem.start_all_linking(link_mode, group) def del_all_link(service): """Delete an INSTEON All-Link between two devices.""" group = service.data.get(SRV_ALL_LINK_GROUP) - plm.start_all_linking(255, group) + insteon_modem.start_all_linking(255, group) def load_aldb(service): """Load the device All-Link database.""" @@ -194,22 +221,22 @@ def async_setup(hass, config): """Print the All-Link Database for a device.""" # For now this sends logs to the log file. # Furture direction is to create an INSTEON control panel. - print_aldb_to_log(plm.aldb) + print_aldb_to_log(insteon_modem.aldb) def x10_all_units_off(service): """Send the X10 All Units Off command.""" housecode = service.data.get(SRV_HOUSECODE) - plm.x10_all_units_off(housecode) + insteon_modem.x10_all_units_off(housecode) def x10_all_lights_off(service): """Send the X10 All Lights Off command.""" housecode = service.data.get(SRV_HOUSECODE) - plm.x10_all_lights_off(housecode) + insteon_modem.x10_all_lights_off(housecode) def x10_all_lights_on(service): """Send the X10 All Lights On command.""" housecode = service.data.get(SRV_HOUSECODE) - plm.x10_all_lights_on(housecode) + insteon_modem.x10_all_lights_on(housecode) def _register_services(): hass.services.register(DOMAIN, SRV_ADD_ALL_LINK, add_all_link, @@ -231,11 +258,11 @@ def async_setup(hass, config): hass.services.register(DOMAIN, SRV_X10_ALL_LIGHTS_ON, x10_all_lights_on, schema=X10_HOUSECODE_SCHEMA) - _LOGGER.debug("Insteon_plm Services registered") + _LOGGER.debug("Insteon Services registered") def _fire_button_on_off_event(address, group, val): # Firing an event when a button is pressed. - device = plm.devices[address.hex] + device = insteon_modem.devices[address.hex] state_name = device.states[group].name button = ("" if state_name == BUTTON_PRESSED_STATE_NAME else state_name[-1].lower()) @@ -250,13 +277,23 @@ def async_setup(hass, config): event, address.hex, button) hass.bus.fire(event, schema) - _LOGGER.info("Looking for PLM on %s", port) - conn = yield from insteonplm.Connection.create( - device=port, - loop=hass.loop, - workdir=hass.config.config_dir) + if host: + _LOGGER.info('Connecting to Insteon Hub on %s', host) + conn = yield from insteonplm.Connection.create( + host=host, + port=ip_port, + username=username, + password=password, + loop=hass.loop, + workdir=hass.config.config_dir) + else: + _LOGGER.info("Looking for Insteon PLM on %s", port) + conn = yield from insteonplm.Connection.create( + device=port, + loop=hass.loop, + workdir=hass.config.config_dir) - plm = conn.protocol + insteon_modem = conn.protocol for device_override in overrides: # @@ -265,32 +302,32 @@ def async_setup(hass, config): address = device_override.get('address') for prop in device_override: if prop in [CONF_CAT, CONF_SUBCAT]: - plm.devices.add_override(address, prop, - device_override[prop]) + insteon_modem.devices.add_override(address, prop, + device_override[prop]) elif prop in [CONF_FIRMWARE, CONF_PRODUCT_KEY]: - plm.devices.add_override(address, CONF_PRODUCT_KEY, - device_override[prop]) + insteon_modem.devices.add_override(address, CONF_PRODUCT_KEY, + device_override[prop]) hass.data[DOMAIN] = {} - hass.data[DOMAIN]['plm'] = plm + hass.data[DOMAIN]['modem'] = insteon_modem hass.data[DOMAIN]['entities'] = {} hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, conn.close) - plm.devices.add_device_callback(async_plm_new_device) + insteon_modem.devices.add_device_callback(async_new_insteon_device) if x10_all_units_off_housecode: - device = plm.add_x10_device(x10_all_units_off_housecode, - 20, - 'allunitsoff') + device = insteon_modem.add_x10_device(x10_all_units_off_housecode, + 20, + 'allunitsoff') if x10_all_lights_on_housecode: - device = plm.add_x10_device(x10_all_lights_on_housecode, - 21, - 'alllightson') + device = insteon_modem.add_x10_device(x10_all_lights_on_housecode, + 21, + 'alllightson') if x10_all_lights_off_housecode: - device = plm.add_x10_device(x10_all_lights_off_housecode, - 22, - 'alllightsoff') + device = insteon_modem.add_x10_device(x10_all_lights_off_housecode, + 22, + 'alllightsoff') for device in x10_devices: housecode = device.get(CONF_HOUSECODE) unitcode = device.get(CONF_UNITCODE) @@ -300,11 +337,11 @@ def async_setup(hass, config): x10_type = 'dimmable' elif device.get(CONF_PLATFORM) == 'binary_sensor': x10_type = 'sensor' - _LOGGER.debug("Adding X10 device to insteonplm: %s %d %s", + _LOGGER.debug("Adding X10 device to Insteon: %s %d %s", housecode, unitcode, x10_type) - device = plm.add_x10_device(housecode, - unitcode, - x10_type) + device = insteon_modem.add_x10_device(housecode, + unitcode, + x10_type) if device and hasattr(device.states[0x01], 'steps'): device.states[0x01].steps = steps @@ -324,11 +361,14 @@ class IPDB: from insteonplm.states.onOff import (OnOffSwitch, OnOffSwitch_OutletTop, OnOffSwitch_OutletBottom, - OpenClosedRelay) + OpenClosedRelay, + OnOffKeypadA, + OnOffKeypad) from insteonplm.states.dimmable import (DimmableSwitch, DimmableSwitch_Fan, - DimmableRemote) + DimmableRemote, + DimmableKeypadA) from insteonplm.states.sensor import (VariableSensor, OnOffSensor, @@ -347,6 +387,8 @@ class IPDB: State(OnOffSwitch_OutletBottom, 'switch'), State(OpenClosedRelay, 'switch'), State(OnOffSwitch, 'switch'), + State(OnOffKeypadA, 'switch'), + State(OnOffKeypad, 'switch'), State(LeakSensorDryWet, 'binary_sensor'), State(IoLincSensor, 'binary_sensor'), @@ -357,6 +399,7 @@ class IPDB: State(DimmableSwitch_Fan, 'fan'), State(DimmableSwitch, 'light'), State(DimmableRemote, 'on_off_events'), + State(DimmableKeypadA, 'light'), State(X10DimmableSwitch, 'light'), State(X10OnOffSwitch, 'switch'), @@ -382,11 +425,11 @@ class IPDB: return None -class InsteonPLMEntity(Entity): +class InsteonEntity(Entity): """INSTEON abstract base entity.""" def __init__(self, device, state_key): - """Initialize the INSTEON PLM binary sensor.""" + """Initialize the INSTEON binary sensor.""" self._insteon_device_state = device.states[state_key] self._insteon_device = device self._insteon_device.aldb.add_loaded_callback(self._aldb_loaded) @@ -429,11 +472,17 @@ class InsteonPLMEntity(Entity): @callback def async_entity_update(self, deviceid, statename, val): """Receive notification from transport that new data exists.""" + _LOGGER.debug('Received update for device %s group %d statename %s', + self.address, self.group, + self._insteon_device_state.name) self.async_schedule_update_ha_state() @asyncio.coroutine def async_added_to_hass(self): """Register INSTEON update events.""" + _LOGGER.debug('Tracking updates for device %s group %d statename %s', + self.address, self.group, + self._insteon_device_state.name) self._insteon_device_state.register_updates( self.async_entity_update) self.hass.data[DOMAIN]['entities'][self.entity_id] = self @@ -460,7 +509,7 @@ def print_aldb_to_log(aldb): _LOGGER.info('ALDB load status is %s', aldb.status.name) if aldb.status not in [ALDBStatus.LOADED, ALDBStatus.PARTIAL]: _LOGGER.warning('Device All-Link database not loaded') - _LOGGER.warning('Use service insteon_plm.load_aldb first') + _LOGGER.warning('Use service insteon.load_aldb first') return _LOGGER.info('RecID In Use Mode HWM Group Address Data 1 Data 2 Data 3') diff --git a/homeassistant/components/insteon_plm/services.yaml b/homeassistant/components/insteon/services.yaml similarity index 100% rename from homeassistant/components/insteon_plm/services.yaml rename to homeassistant/components/insteon/services.yaml diff --git a/homeassistant/components/insteon_local.py b/homeassistant/components/insteon_local.py index a18d4e0aa14..1dfb0c6e4cb 100644 --- a/homeassistant/components/insteon_local.py +++ b/homeassistant/components/insteon_local.py @@ -5,82 +5,24 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/insteon_local/ """ import logging -import os - -import requests -import voluptuous as vol - -from homeassistant.const import ( - CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_TIMEOUT, CONF_USERNAME) -import homeassistant.helpers.config_validation as cv -from homeassistant.helpers.discovery import load_platform - -REQUIREMENTS = ['insteonlocal==0.53'] _LOGGER = logging.getLogger(__name__) -DEFAULT_PORT = 25105 -DEFAULT_TIMEOUT = 10 -DOMAIN = 'insteon_local' - -INSTEON_CACHE = '.insteon_local_cache' - -INSTEON_PLATFORMS = [ - 'light', - 'switch', - 'fan', -] - -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_HOST): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - vol.Required(CONF_USERNAME): cv.string, - vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, - vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int, - }) -}, extra=vol.ALLOW_EXTRA) - def setup(hass, config): - """Set up the local Insteon hub.""" - from insteonlocal.Hub import Hub + """Setup the insteon_local component. - conf = config[DOMAIN] - username = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) - host = conf.get(CONF_HOST) - port = conf.get(CONF_PORT) - timeout = conf.get(CONF_TIMEOUT) + This component is depreciated as of release 0.77 and should be removed in + release 0.90. + """ + _LOGGER.warning('The insteon_local comonent has been replaced by ' + 'the insteon component') + _LOGGER.warning('Please see https://home-assistant.io/components/insteon') - try: - if not os.path.exists(hass.config.path(INSTEON_CACHE)): - os.makedirs(hass.config.path(INSTEON_CACHE)) + hass.components.persistent_notification.create( + 'insteon_local has been replaced by the insteon component.
' + 'Please see https://home-assistant.io/components/insteon', + title='insteon_local Component Deactivated', + notification_id='insteon_local') - insteonhub = Hub(host, username, password, port, timeout, _LOGGER, - hass.config.path(INSTEON_CACHE)) - - # Check for successful connection - insteonhub.get_buffer_status() - except requests.exceptions.ConnectTimeout: - _LOGGER.error("Could not connect", exc_info=True) - return False - except requests.exceptions.ConnectionError: - _LOGGER.error("Could not connect", exc_info=True) - return False - except requests.exceptions.RequestException: - if insteonhub.http_code == 401: - _LOGGER.error("Bad username or password for Insteon_local hub") - else: - _LOGGER.error("Error on Insteon_local hub check", exc_info=True) - return False - - linked = insteonhub.get_linked() - - hass.data['insteon_local'] = insteonhub - - for insteon_platform in INSTEON_PLATFORMS: - load_platform(hass, insteon_platform, DOMAIN, {'linked': linked}, - config) - - return True + return False diff --git a/homeassistant/components/insteon_plm.py b/homeassistant/components/insteon_plm.py new file mode 100644 index 00000000000..bd41819a0fa --- /dev/null +++ b/homeassistant/components/insteon_plm.py @@ -0,0 +1,30 @@ +""" +Support for INSTEON PowerLinc Modem. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/insteon_plm/ +""" +import asyncio +import logging + +_LOGGER = logging.getLogger(__name__) + + +@asyncio.coroutine +def async_setup(hass, config): + """Setup the insteon_plm component. + + This component is depreciated as of release 0.77 and should be removed in + release 0.90. + """ + _LOGGER.warning('The insteon_plm comonent has been replaced by ' + 'the insteon component') + _LOGGER.warning('Please see https://home-assistant.io/components/insteon') + + hass.components.persistent_notification.create( + 'insteon_plm has been replaced by the insteon component.
' + 'Please see https://home-assistant.io/components/insteon', + title='insteon_plm Component Deactivated', + notification_id='insteon_plm') + + return False diff --git a/homeassistant/components/light/insteon_plm.py b/homeassistant/components/light/insteon.py similarity index 80% rename from homeassistant/components/light/insteon_plm.py rename to homeassistant/components/light/insteon.py index 8a3b463c2bd..88a9ab01de5 100644 --- a/homeassistant/components/light/insteon_plm.py +++ b/homeassistant/components/light/insteon.py @@ -2,40 +2,40 @@ Support for Insteon lights via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/light.insteon_plm/ +https://home-assistant.io/components/light.insteon/ """ import asyncio import logging -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity from homeassistant.components.light import ( ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) _LOGGER = logging.getLogger(__name__) -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] MAX_BRIGHTNESS = 255 @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the Insteon PLM device.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the Insteon component.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] _LOGGER.debug('Adding device %s entity %s to Light platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMDimmerDevice(device, state_key) + new_entity = InsteonDimmerDevice(device, state_key) async_add_devices([new_entity]) -class InsteonPLMDimmerDevice(InsteonPLMEntity, Light): +class InsteonDimmerDevice(InsteonEntity, Light): """A Class for an Insteon device.""" @property diff --git a/homeassistant/components/light/insteon_local.py b/homeassistant/components/light/insteon_local.py deleted file mode 100644 index e2bc54de517..00000000000 --- a/homeassistant/components/light/insteon_local.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -Support for Insteon dimmers via local hub control. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/light.insteon_local/ -""" -import logging -from datetime import timedelta - -from homeassistant.components.light import ( - ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS, Light) -from homeassistant import util - -_CONFIGURING = {} -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['insteon_local'] -DOMAIN = 'light' - -MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5) - -SUPPORT_INSTEON_LOCAL = SUPPORT_BRIGHTNESS - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Insteon local light platform.""" - insteonhub = hass.data['insteon_local'] - if discovery_info is None: - return - - linked = discovery_info['linked'] - device_list = [] - for device_id in linked: - if linked[device_id]['cat_type'] == 'dimmer': - device = insteonhub.dimmer(device_id) - device_list.append( - InsteonLocalDimmerDevice(device) - ) - - add_devices(device_list) - - -class InsteonLocalDimmerDevice(Light): - """An abstract Class for an Insteon node.""" - - def __init__(self, node): - """Initialize the device.""" - self.node = node - self._value = 0 - - @property - def name(self): - """Return the name of the node.""" - return self.node.device_id - - @property - def unique_id(self): - """Return the ID of this Insteon node.""" - return self.node.device_id - - @property - def brightness(self): - """Return the brightness of this light between 0..255.""" - return self._value - - @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) - def update(self): - """Update state of the light.""" - resp = self.node.status(0) - - while 'error' in resp and resp['error'] is True: - resp = self.node.status(0) - - if 'cmd2' in resp: - self._value = int(resp['cmd2'], 16) - - @property - def is_on(self): - """Return the boolean response if the node is on.""" - return self._value != 0 - - @property - def supported_features(self): - """Flag supported features.""" - return SUPPORT_INSTEON_LOCAL - - def turn_on(self, **kwargs): - """Turn device on.""" - brightness = 100 - if ATTR_BRIGHTNESS in kwargs: - brightness = int(kwargs[ATTR_BRIGHTNESS]) / 255 * 100 - - self.node.change_level(brightness) - - def turn_off(self, **kwargs): - """Turn device off.""" - self.node.off() diff --git a/homeassistant/components/sensor/insteon_plm.py b/homeassistant/components/sensor/insteon.py similarity index 61% rename from homeassistant/components/sensor/insteon_plm.py rename to homeassistant/components/sensor/insteon.py index 61f5877ed78..59c0fee7617 100644 --- a/homeassistant/components/sensor/insteon_plm.py +++ b/homeassistant/components/sensor/insteon.py @@ -2,35 +2,35 @@ Support for INSTEON dimmers via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/sensor.insteon_plm/ +https://home-assistant.io/components/sensor.insteon/ """ import asyncio import logging -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity from homeassistant.helpers.entity import Entity -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] _LOGGER = logging.getLogger(__name__) @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] _LOGGER.debug('Adding device %s entity %s to Sensor platform', device.address.hex, device.states[state_key].name) - new_entity = InsteonPLMSensorDevice(device, state_key) + new_entity = InsteonSensorDevice(device, state_key) async_add_devices([new_entity]) -class InsteonPLMSensorDevice(InsteonPLMEntity, Entity): +class InsteonSensorDevice(InsteonEntity, Entity): """A Class for an Insteon device.""" diff --git a/homeassistant/components/switch/insteon_plm.py b/homeassistant/components/switch/insteon.py similarity index 69% rename from homeassistant/components/switch/insteon_plm.py rename to homeassistant/components/switch/insteon.py index c357d1ccc04..8575b16c69b 100644 --- a/homeassistant/components/switch/insteon_plm.py +++ b/homeassistant/components/switch/insteon.py @@ -2,26 +2,26 @@ Support for INSTEON dimmers via PowerLinc Modem. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/switch.insteon_plm/ +https://home-assistant.io/components/switch.insteon/ """ import asyncio import logging -from homeassistant.components.insteon_plm import InsteonPLMEntity +from homeassistant.components.insteon import InsteonEntity from homeassistant.components.switch import SwitchDevice -DEPENDENCIES = ['insteon_plm'] +DEPENDENCIES = ['insteon'] _LOGGER = logging.getLogger(__name__) @asyncio.coroutine def async_setup_platform(hass, config, async_add_devices, discovery_info=None): - """Set up the INSTEON PLM device class for the hass platform.""" - plm = hass.data['insteon_plm'].get('plm') + """Set up the INSTEON device class for the hass platform.""" + insteon_modem = hass.data['insteon'].get('modem') address = discovery_info['address'] - device = plm.devices[address] + device = insteon_modem.devices[address] state_key = discovery_info['state_key'] state_name = device.states[state_key].name @@ -30,17 +30,16 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): device.address.hex, device.states[state_key].name) new_entity = None - if state_name in ['lightOnOff', 'outletTopOnOff', 'outletBottomOnOff', - 'x10OnOffSwitch']: - new_entity = InsteonPLMSwitchDevice(device, state_key) - elif state_name == 'openClosedRelay': - new_entity = InsteonPLMOpenClosedDevice(device, state_key) + if state_name == 'openClosedRelay': + new_entity = InsteonOpenClosedDevice(device, state_key) + else: + new_entity = InsteonSwitchDevice(device, state_key) if new_entity is not None: async_add_devices([new_entity]) -class InsteonPLMSwitchDevice(InsteonPLMEntity, SwitchDevice): +class InsteonSwitchDevice(InsteonEntity, SwitchDevice): """A Class for an Insteon device.""" @property @@ -59,7 +58,7 @@ class InsteonPLMSwitchDevice(InsteonPLMEntity, SwitchDevice): self._insteon_device_state.off() -class InsteonPLMOpenClosedDevice(InsteonPLMEntity, SwitchDevice): +class InsteonOpenClosedDevice(InsteonEntity, SwitchDevice): """A Class for an Insteon device.""" @property diff --git a/homeassistant/components/switch/insteon_local.py b/homeassistant/components/switch/insteon_local.py deleted file mode 100644 index c4c8a854670..00000000000 --- a/homeassistant/components/switch/insteon_local.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -Support for Insteon switch devices via local hub support. - -For more details about this component, please refer to the documentation at -https://home-assistant.io/components/switch.insteon_local/ -""" -import logging -from datetime import timedelta - -from homeassistant.components.switch import SwitchDevice -from homeassistant import util - -_CONFIGURING = {} -_LOGGER = logging.getLogger(__name__) - -DEPENDENCIES = ['insteon_local'] -DOMAIN = 'switch' - -MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100) -MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10) - - -def setup_platform(hass, config, add_devices, discovery_info=None): - """Set up the Insteon local switch platform.""" - insteonhub = hass.data['insteon_local'] - if discovery_info is None: - return - - linked = discovery_info['linked'] - device_list = [] - for device_id in linked: - if linked[device_id]['cat_type'] == 'switch': - device = insteonhub.switch(device_id) - device_list.append( - InsteonLocalSwitchDevice(device) - ) - - add_devices(device_list) - - -class InsteonLocalSwitchDevice(SwitchDevice): - """An abstract Class for an Insteon node.""" - - def __init__(self, node): - """Initialize the device.""" - self.node = node - self._state = False - - @property - def name(self): - """Return the name of the node.""" - return self.node.device_id - - @property - def unique_id(self): - """Return the ID of this Insteon node.""" - return self.node.device_id - - @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) - def update(self): - """Get the updated status of the switch.""" - resp = self.node.status(0) - - while 'error' in resp and resp['error'] is True: - resp = self.node.status(0) - - if 'cmd2' in resp: - self._state = int(resp['cmd2'], 16) > 0 - - @property - def is_on(self): - """Return the boolean response if the node is on.""" - return self._state - - def turn_on(self, **kwargs): - """Turn device on.""" - self.node.on() - self._state = True - - def turn_off(self, **kwargs): - """Turn device off.""" - self.node.off() - self._state = False diff --git a/requirements_all.txt b/requirements_all.txt index ada216de5d8..8bd39162d98 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -468,11 +468,8 @@ ihcsdk==2.2.0 # homeassistant.components.sensor.influxdb influxdb==5.0.0 -# homeassistant.components.insteon_local -insteonlocal==0.53 - -# homeassistant.components.insteon_plm -insteonplm==0.11.7 +# homeassistant.components.insteon +insteonplm==0.12.3 # homeassistant.components.sensor.iperf3 iperf3==0.1.10 From ae6398015242ba0739cc17742899f825cf3f623b Mon Sep 17 00:00:00 2001 From: Jerad Meisner Date: Wed, 22 Aug 2018 00:17:29 -0700 Subject: [PATCH 096/159] Remove unit_of_measurement from climate entities (#16012) * Remove unit_of_measurement from climate base class. * Updated google_assistant component and tests to use core temp units. * Fixes * Convert Alexa component to use core temp units for climate entities. * Fix tests. * Converted prometheus component. * Remove unit_of_measurement from homekit thermostat tests. * Small fix. --- homeassistant/components/alexa/smart_home.py | 65 ++++----- homeassistant/components/climate/__init__.py | 7 +- .../components/climate/generic_thermostat.py | 10 +- homeassistant/components/climate/knx.py | 4 +- homeassistant/components/climate/maxcube.py | 3 +- homeassistant/components/climate/sensibo.py | 10 +- .../components/google_assistant/smart_home.py | 4 +- .../components/google_assistant/trait.py | 55 ++++---- homeassistant/components/prometheus.py | 13 +- tests/components/alexa/test_smart_home.py | 7 +- .../climate/test_generic_thermostat.py | 64 +++------ .../google_assistant/test_google_assistant.py | 3 +- .../components/google_assistant/test_trait.py | 123 +++++++++--------- .../homekit/test_type_thermostats.py | 40 ++---- 14 files changed, 184 insertions(+), 224 deletions(-) diff --git a/homeassistant/components/alexa/smart_home.py b/homeassistant/components/alexa/smart_home.py index 9fbcecfa577..eab725c4653 100644 --- a/homeassistant/components/alexa/smart_home.py +++ b/homeassistant/components/alexa/smart_home.py @@ -13,12 +13,13 @@ import homeassistant.util.color as color_util from homeassistant.util.temperature import convert as convert_temperature from homeassistant.util.decorator import Registry from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, CONF_NAME, - SERVICE_LOCK, SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PAUSE, - SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_STOP, + ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_TEMPERATURE, + ATTR_UNIT_OF_MEASUREMENT, CONF_NAME, SERVICE_LOCK, + SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, + SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_STOP, SERVICE_SET_COVER_POSITION, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_UNLOCK, SERVICE_VOLUME_SET, TEMP_FAHRENHEIT, TEMP_CELSIUS, - CONF_UNIT_OF_MEASUREMENT, STATE_LOCKED, STATE_UNLOCKED, STATE_ON) + STATE_LOCKED, STATE_UNLOCKED, STATE_ON) from .const import CONF_FILTER, CONF_ENTITY_CONFIG @@ -160,7 +161,8 @@ class _AlexaEntity: The API handlers should manipulate entities only through this interface. """ - def __init__(self, config, entity): + def __init__(self, hass, config, entity): + self.hass = hass self.config = config self.entity = entity self.entity_conf = config.entity_config.get(entity.entity_id, {}) @@ -384,6 +386,10 @@ class _AlexaInputController(_AlexaInterface): class _AlexaTemperatureSensor(_AlexaInterface): + def __init__(self, hass, entity): + _AlexaInterface.__init__(self, entity) + self.hass = hass + def name(self): return 'Alexa.TemperatureSensor' @@ -397,9 +403,10 @@ class _AlexaTemperatureSensor(_AlexaInterface): if name != 'temperature': raise _UnsupportedProperty(name) - unit = self.entity.attributes[CONF_UNIT_OF_MEASUREMENT] + unit = self.entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT) temp = self.entity.state if self.entity.domain == climate.DOMAIN: + unit = self.hass.config.units.temperature_unit temp = self.entity.attributes.get( climate.ATTR_CURRENT_TEMPERATURE) return { @@ -409,6 +416,10 @@ class _AlexaTemperatureSensor(_AlexaInterface): class _AlexaThermostatController(_AlexaInterface): + def __init__(self, hass, entity): + _AlexaInterface.__init__(self, entity) + self.hass = hass + def name(self): return 'Alexa.ThermostatController' @@ -439,8 +450,7 @@ class _AlexaThermostatController(_AlexaInterface): raise _UnsupportedProperty(name) return mode - unit = self.entity.attributes[CONF_UNIT_OF_MEASUREMENT] - temp = None + unit = self.hass.config.units.temperature_unit if name == 'targetSetpoint': temp = self.entity.attributes.get(climate.ATTR_TEMPERATURE) elif name == 'lowerSetpoint': @@ -491,8 +501,8 @@ class _ClimateCapabilities(_AlexaEntity): return [_DisplayCategory.THERMOSTAT] def interfaces(self): - yield _AlexaThermostatController(self.entity) - yield _AlexaTemperatureSensor(self.entity) + yield _AlexaThermostatController(self.hass, self.entity) + yield _AlexaTemperatureSensor(self.hass, self.entity) @ENTITY_ADAPTERS.register(cover.DOMAIN) @@ -609,11 +619,11 @@ class _SensorCapabilities(_AlexaEntity): def interfaces(self): attrs = self.entity.attributes - if attrs.get(CONF_UNIT_OF_MEASUREMENT) in ( + if attrs.get(ATTR_UNIT_OF_MEASUREMENT) in ( TEMP_FAHRENHEIT, TEMP_CELSIUS, ): - yield _AlexaTemperatureSensor(self.entity) + yield _AlexaTemperatureSensor(self.hass, self.entity) class _Cause: @@ -823,7 +833,7 @@ async def async_api_discovery(hass, config, request, context): if entity.domain not in ENTITY_ADAPTERS: continue - alexa_entity = ENTITY_ADAPTERS[entity.domain](config, entity) + alexa_entity = ENTITY_ADAPTERS[entity.domain](hass, config, entity) endpoint = { 'displayCategories': alexa_entity.display_categories(), @@ -1364,11 +1374,12 @@ async def async_api_previous(hass, config, request, context, entity): return api_message(request) -def api_error_temp_range(request, temp, min_temp, max_temp, unit): +def api_error_temp_range(hass, request, temp, min_temp, max_temp): """Create temperature value out of range API error response. Async friendly. """ + unit = hass.config.units.temperature_unit temp_range = { 'minimumValue': { 'value': min_temp, @@ -1389,8 +1400,9 @@ def api_error_temp_range(request, temp, min_temp, max_temp, unit): ) -def temperature_from_object(temp_obj, to_unit, interval=False): +def temperature_from_object(hass, temp_obj, interval=False): """Get temperature from Temperature object in requested unit.""" + to_unit = hass.config.units.temperature_unit from_unit = TEMP_CELSIUS temp = float(temp_obj['value']) @@ -1408,7 +1420,6 @@ def temperature_from_object(temp_obj, to_unit, interval=False): @extract_entity async def async_api_set_target_temp(hass, config, request, context, entity): """Process a set target temperature request.""" - unit = entity.attributes[CONF_UNIT_OF_MEASUREMENT] min_temp = entity.attributes.get(climate.ATTR_MIN_TEMP) max_temp = entity.attributes.get(climate.ATTR_MAX_TEMP) @@ -1418,25 +1429,22 @@ async def async_api_set_target_temp(hass, config, request, context, entity): payload = request[API_PAYLOAD] if 'targetSetpoint' in payload: - temp = temperature_from_object( - payload['targetSetpoint'], unit) + temp = temperature_from_object(hass, payload['targetSetpoint']) if temp < min_temp or temp > max_temp: return api_error_temp_range( - request, temp, min_temp, max_temp, unit) + hass, request, temp, min_temp, max_temp) data[ATTR_TEMPERATURE] = temp if 'lowerSetpoint' in payload: - temp_low = temperature_from_object( - payload['lowerSetpoint'], unit) + temp_low = temperature_from_object(hass, payload['lowerSetpoint']) if temp_low < min_temp or temp_low > max_temp: return api_error_temp_range( - request, temp_low, min_temp, max_temp, unit) + hass, request, temp_low, min_temp, max_temp) data[climate.ATTR_TARGET_TEMP_LOW] = temp_low if 'upperSetpoint' in payload: - temp_high = temperature_from_object( - payload['upperSetpoint'], unit) + temp_high = temperature_from_object(hass, payload['upperSetpoint']) if temp_high < min_temp or temp_high > max_temp: return api_error_temp_range( - request, temp_high, min_temp, max_temp, unit) + hass, request, temp_high, min_temp, max_temp) data[climate.ATTR_TARGET_TEMP_HIGH] = temp_high await hass.services.async_call( @@ -1450,17 +1458,16 @@ async def async_api_set_target_temp(hass, config, request, context, entity): @extract_entity async def async_api_adjust_target_temp(hass, config, request, context, entity): """Process an adjust target temperature request.""" - unit = entity.attributes[CONF_UNIT_OF_MEASUREMENT] min_temp = entity.attributes.get(climate.ATTR_MIN_TEMP) max_temp = entity.attributes.get(climate.ATTR_MAX_TEMP) temp_delta = temperature_from_object( - request[API_PAYLOAD]['targetSetpointDelta'], unit, interval=True) + hass, request[API_PAYLOAD]['targetSetpointDelta'], interval=True) target_temp = float(entity.attributes.get(ATTR_TEMPERATURE)) + temp_delta if target_temp < min_temp or target_temp > max_temp: return api_error_temp_range( - request, target_temp, min_temp, max_temp, unit) + hass, request, target_temp, min_temp, max_temp) data = { ATTR_ENTITY_ID: entity.entity_id, @@ -1512,7 +1519,7 @@ async def async_api_set_thermostat_mode(hass, config, request, context, @extract_entity async def async_api_reportstate(hass, config, request, context, entity): """Process a ReportState request.""" - alexa_entity = ENTITY_ADAPTERS[entity.domain](config, entity) + alexa_entity = ENTITY_ADAPTERS[entity.domain](hass, config, entity) properties = [] for interface in alexa_entity.interfaces(): properties.extend(interface.serialize_properties()) diff --git a/homeassistant/components/climate/__init__.py b/homeassistant/components/climate/__init__.py index f33f68b9423..a3273f67cc2 100644 --- a/homeassistant/components/climate/__init__.py +++ b/homeassistant/components/climate/__init__.py @@ -320,7 +320,7 @@ class ClimateDevice(Entity): @property def precision(self): """Return the precision of the system.""" - if self.unit_of_measurement == TEMP_CELSIUS: + if self.hass.config.units.temperature_unit == TEMP_CELSIUS: return PRECISION_TENTHS return PRECISION_WHOLE @@ -394,11 +394,6 @@ class ClimateDevice(Entity): return data - @property - def unit_of_measurement(self): - """Return the unit of measurement to display.""" - return self.hass.config.units.temperature_unit - @property def temperature_unit(self): """Return the unit of measurement used by the platform.""" diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 307c96bce32..9e5ff3bbf20 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -16,9 +16,8 @@ from homeassistant.components.climate import ( ATTR_OPERATION_MODE, ATTR_AWAY_MODE, SUPPORT_OPERATION_MODE, SUPPORT_AWAY_MODE, SUPPORT_TARGET_TEMPERATURE, PLATFORM_SCHEMA) from homeassistant.const import ( - ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF, ATTR_TEMPERATURE, - CONF_NAME, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, - STATE_UNKNOWN) + STATE_ON, STATE_OFF, ATTR_TEMPERATURE, CONF_NAME, ATTR_ENTITY_ID, + SERVICE_TURN_ON, SERVICE_TURN_OFF, STATE_UNKNOWN) from homeassistant.helpers import condition from homeassistant.helpers.event import ( async_track_state_change, async_track_time_interval) @@ -297,11 +296,8 @@ class GenericThermostat(ClimateDevice): @callback def _async_update_temp(self, state): """Update thermostat with latest state from sensor.""" - unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) - try: - self._cur_temp = self.hass.config.units.temperature( - float(state.state), unit) + self._cur_temp = float(state.state) except ValueError as ex: _LOGGER.error("Unable to update from sensor: %s", ex) diff --git a/homeassistant/components/climate/knx.py b/homeassistant/components/climate/knx.py index f53cf2491dc..1f95a8cb43d 100644 --- a/homeassistant/components/climate/knx.py +++ b/homeassistant/components/climate/knx.py @@ -122,8 +122,6 @@ class KNXClimate(ClimateDevice): self.hass = hass self.async_register_callbacks() - self._unit_of_measurement = TEMP_CELSIUS - @property def supported_features(self): """Return the list of supported features.""" @@ -157,7 +155,7 @@ class KNXClimate(ClimateDevice): @property def temperature_unit(self): """Return the unit of measurement.""" - return self._unit_of_measurement + return TEMP_CELSIUS @property def current_temperature(self): diff --git a/homeassistant/components/climate/maxcube.py b/homeassistant/components/climate/maxcube.py index 712ebb4f4ce..204d5a3649c 100644 --- a/homeassistant/components/climate/maxcube.py +++ b/homeassistant/components/climate/maxcube.py @@ -45,7 +45,6 @@ class MaxCubeClimate(ClimateDevice): def __init__(self, handler, name, rf_address): """Initialize MAX! Cube ClimateDevice.""" self._name = name - self._unit_of_measurement = TEMP_CELSIUS self._operation_list = [STATE_AUTO, STATE_MANUAL, STATE_BOOST, STATE_VACATION] self._rf_address = rf_address @@ -81,7 +80,7 @@ class MaxCubeClimate(ClimateDevice): @property def temperature_unit(self): """Return the unit of measurement.""" - return self._unit_of_measurement + return TEMP_CELSIUS @property def current_temperature(self): diff --git a/homeassistant/components/climate/sensibo.py b/homeassistant/components/climate/sensibo.py index 363653608e8..a2c4ea0ba99 100644 --- a/homeassistant/components/climate/sensibo.py +++ b/homeassistant/components/climate/sensibo.py @@ -71,7 +71,8 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for dev in ( yield from client.async_get_devices(_INITIAL_FETCH_FIELDS)): if config[CONF_ID] == ALL or dev['id'] in config[CONF_ID]: - devices.append(SensiboClimate(client, dev)) + devices.append(SensiboClimate( + client, dev, hass.config.units.temperature_unit)) except (aiohttp.client_exceptions.ClientConnectorError, asyncio.TimeoutError): _LOGGER.exception('Failed to connect to Sensibo servers.') @@ -106,7 +107,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): class SensiboClimate(ClimateDevice): """Representation of a Sensibo device.""" - def __init__(self, client, data): + def __init__(self, client, data, units): """Build SensiboClimate. client: aiohttp session. @@ -115,6 +116,7 @@ class SensiboClimate(ClimateDevice): self._client = client self._id = data['id'] self._external_state = None + self._units = units self._do_update(data) @property @@ -139,7 +141,7 @@ class SensiboClimate(ClimateDevice): self._temperatures_list = self._current_capabilities[ 'temperatures'].get(temperature_unit_key, {}).get('values', []) else: - self._temperature_unit = self.unit_of_measurement + self._temperature_unit = self._units self._temperatures_list = [] self._supported_features = 0 for key in self._ac_states: @@ -175,7 +177,7 @@ class SensiboClimate(ClimateDevice): @property def target_temperature_step(self): """Return the supported step of target temperature.""" - if self.temperature_unit == self.unit_of_measurement: + if self.temperature_unit == self.hass.config.units.temperature_unit: # We are working in same units as the a/c unit. Use whole degrees # like the API supports. return 1 diff --git a/homeassistant/components/google_assistant/smart_home.py b/homeassistant/components/google_assistant/smart_home.py index 63a3e641170..675e86f9d39 100644 --- a/homeassistant/components/google_assistant/smart_home.py +++ b/homeassistant/components/google_assistant/smart_home.py @@ -77,7 +77,7 @@ class _GoogleEntity: domain = state.domain features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0) - return [Trait(state) for Trait in trait.TRAITS + return [Trait(self.hass, state) for Trait in trait.TRAITS if Trait.supported(domain, features)] @callback @@ -159,7 +159,7 @@ class _GoogleEntity: executed = False for trt in self.traits(): if trt.can_execute(command, params): - await trt.execute(self.hass, command, params) + await trt.execute(command, params) executed = True break diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index 1d369eb87da..d45a84caaa3 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -14,7 +14,6 @@ from homeassistant.components import ( ) from homeassistant.const import ( ATTR_ENTITY_ID, - ATTR_UNIT_OF_MEASUREMENT, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF, @@ -55,10 +54,9 @@ def register_trait(trait): return trait -def _google_temp_unit(state): +def _google_temp_unit(units): """Return Google temperature unit.""" - if (state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == - TEMP_FAHRENHEIT): + if units == TEMP_FAHRENHEIT: return 'F' return 'C' @@ -68,8 +66,9 @@ class _Trait: commands = [] - def __init__(self, state): + def __init__(self, hass, state): """Initialize a trait for a state.""" + self.hass = hass self.state = state def sync_attributes(self): @@ -84,7 +83,7 @@ class _Trait: """Test if command can be executed.""" return command in self.commands - async def execute(self, hass, command, params): + async def execute(self, command, params): """Execute a trait command.""" raise NotImplementedError @@ -141,24 +140,24 @@ class BrightnessTrait(_Trait): return response - async def execute(self, hass, command, params): + async def execute(self, command, params): """Execute a brightness command.""" domain = self.state.domain if domain == light.DOMAIN: - await hass.services.async_call( + await self.hass.services.async_call( light.DOMAIN, light.SERVICE_TURN_ON, { ATTR_ENTITY_ID: self.state.entity_id, light.ATTR_BRIGHTNESS_PCT: params['brightness'] }, blocking=True) elif domain == cover.DOMAIN: - await hass.services.async_call( + await self.hass.services.async_call( cover.DOMAIN, cover.SERVICE_SET_COVER_POSITION, { ATTR_ENTITY_ID: self.state.entity_id, cover.ATTR_POSITION: params['brightness'] }, blocking=True) elif domain == media_player.DOMAIN: - await hass.services.async_call( + await self.hass.services.async_call( media_player.DOMAIN, media_player.SERVICE_VOLUME_SET, { ATTR_ENTITY_ID: self.state.entity_id, media_player.ATTR_MEDIA_VOLUME_LEVEL: @@ -201,7 +200,7 @@ class OnOffTrait(_Trait): return {'on': self.state.state != cover.STATE_CLOSED} return {'on': self.state.state != STATE_OFF} - async def execute(self, hass, command, params): + async def execute(self, command, params): """Execute an OnOff command.""" domain = self.state.domain @@ -220,7 +219,7 @@ class OnOffTrait(_Trait): service_domain = domain service = SERVICE_TURN_ON if params['on'] else SERVICE_TURN_OFF - await hass.services.async_call(service_domain, service, { + await self.hass.services.async_call(service_domain, service, { ATTR_ENTITY_ID: self.state.entity_id }, blocking=True) @@ -268,14 +267,14 @@ class ColorSpectrumTrait(_Trait): return (command in self.commands and 'spectrumRGB' in params.get('color', {})) - async def execute(self, hass, command, params): + async def execute(self, command, params): """Execute a color spectrum command.""" # Convert integer to hex format and left pad with 0's till length 6 hex_value = "{0:06x}".format(params['color']['spectrumRGB']) color = color_util.color_RGB_to_hs( *color_util.rgb_hex_to_rgb_list(hex_value)) - await hass.services.async_call(light.DOMAIN, SERVICE_TURN_ON, { + await self.hass.services.async_call(light.DOMAIN, SERVICE_TURN_ON, { ATTR_ENTITY_ID: self.state.entity_id, light.ATTR_HS_COLOR: color }, blocking=True) @@ -331,7 +330,7 @@ class ColorTemperatureTrait(_Trait): return (command in self.commands and 'temperature' in params.get('color', {})) - async def execute(self, hass, command, params): + async def execute(self, command, params): """Execute a color temperature command.""" temp = color_util.color_temperature_kelvin_to_mired( params['color']['temperature']) @@ -344,7 +343,7 @@ class ColorTemperatureTrait(_Trait): "Temperature should be between {} and {}".format(min_temp, max_temp)) - await hass.services.async_call(light.DOMAIN, SERVICE_TURN_ON, { + await self.hass.services.async_call(light.DOMAIN, SERVICE_TURN_ON, { ATTR_ENTITY_ID: self.state.entity_id, light.ATTR_COLOR_TEMP: temp, }, blocking=True) @@ -376,12 +375,13 @@ class SceneTrait(_Trait): """Return scene query attributes.""" return {} - async def execute(self, hass, command, params): + async def execute(self, command, params): """Execute a scene command.""" # Don't block for scripts as they can be slow. - await hass.services.async_call(self.state.domain, SERVICE_TURN_ON, { - ATTR_ENTITY_ID: self.state.entity_id - }, blocking=self.state.domain != script.DOMAIN) + await self.hass.services.async_call( + self.state.domain, SERVICE_TURN_ON, { + ATTR_ENTITY_ID: self.state.entity_id + }, blocking=self.state.domain != script.DOMAIN) @register_trait @@ -425,7 +425,8 @@ class TemperatureSettingTrait(_Trait): return { 'availableThermostatModes': ','.join(modes), - 'thermostatTemperatureUnit': _google_temp_unit(self.state), + 'thermostatTemperatureUnit': _google_temp_unit( + self.hass.config.units.temperature_unit) } def query_attributes(self): @@ -437,7 +438,7 @@ class TemperatureSettingTrait(_Trait): if operation is not None and operation in self.hass_to_google: response['thermostatMode'] = self.hass_to_google[operation] - unit = self.state.attributes[ATTR_UNIT_OF_MEASUREMENT] + unit = self.hass.config.units.temperature_unit current_temp = attrs.get(climate.ATTR_CURRENT_TEMPERATURE) if current_temp is not None: @@ -465,10 +466,10 @@ class TemperatureSettingTrait(_Trait): return response - async def execute(self, hass, command, params): + async def execute(self, command, params): """Execute a temperature point or mode command.""" # All sent in temperatures are always in Celsius - unit = self.state.attributes[ATTR_UNIT_OF_MEASUREMENT] + unit = self.hass.config.units.temperature_unit min_temp = self.state.attributes[climate.ATTR_MIN_TEMP] max_temp = self.state.attributes[climate.ATTR_MAX_TEMP] @@ -482,7 +483,7 @@ class TemperatureSettingTrait(_Trait): "Temperature should be between {} and {}".format(min_temp, max_temp)) - await hass.services.async_call( + await self.hass.services.async_call( climate.DOMAIN, climate.SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: self.state.entity_id, climate.ATTR_TEMPERATURE: temp @@ -508,7 +509,7 @@ class TemperatureSettingTrait(_Trait): "Lower bound for temperature range should be between " "{} and {}".format(min_temp, max_temp)) - await hass.services.async_call( + await self.hass.services.async_call( climate.DOMAIN, climate.SERVICE_SET_TEMPERATURE, { ATTR_ENTITY_ID: self.state.entity_id, climate.ATTR_TARGET_TEMP_HIGH: temp_high, @@ -516,7 +517,7 @@ class TemperatureSettingTrait(_Trait): }, blocking=True) elif command == COMMAND_THERMOSTAT_SET_MODE: - await hass.services.async_call( + await self.hass.services.async_call( climate.DOMAIN, climate.SERVICE_SET_OPERATION_MODE, { ATTR_ENTITY_ID: self.state.entity_id, climate.ATTR_OPERATION_MODE: diff --git a/homeassistant/components/prometheus.py b/homeassistant/components/prometheus.py index da986f024a4..5fa768b6983 100644 --- a/homeassistant/components/prometheus.py +++ b/homeassistant/components/prometheus.py @@ -49,7 +49,9 @@ def setup(hass, config): conf = config[DOMAIN] entity_filter = conf[CONF_FILTER] namespace = conf.get(CONF_PROM_NAMESPACE) - metrics = PrometheusMetrics(prometheus_client, entity_filter, namespace) + climate_units = hass.config.units.temperature_unit + metrics = PrometheusMetrics(prometheus_client, entity_filter, namespace, + climate_units) hass.bus.listen(EVENT_STATE_CHANGED, metrics.handle_event) return True @@ -58,7 +60,8 @@ def setup(hass, config): class PrometheusMetrics: """Model all of the metrics which should be exposed to Prometheus.""" - def __init__(self, prometheus_client, entity_filter, namespace): + def __init__(self, prometheus_client, entity_filter, namespace, + climate_units): """Initialize Prometheus Metrics.""" self.prometheus_client = prometheus_client self._filter = entity_filter @@ -67,6 +70,7 @@ class PrometheusMetrics: else: self.metrics_prefix = "" self._metrics = {} + self._climate_units = climate_units def handle_event(self, event): """Listen for new messages on the bus, and add them to Prometheus.""" @@ -173,8 +177,7 @@ class PrometheusMetrics: def _handle_climate(self, state): temp = state.attributes.get(ATTR_TEMPERATURE) if temp: - unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) - if unit == TEMP_FAHRENHEIT: + if self._climate_units == TEMP_FAHRENHEIT: temp = fahrenheit_to_celsius(temp) metric = self._metric( 'temperature_c', self.prometheus_client.Gauge, @@ -183,7 +186,7 @@ class PrometheusMetrics: current_temp = state.attributes.get(ATTR_CURRENT_TEMPERATURE) if current_temp: - if unit == TEMP_FAHRENHEIT: + if self._climate_units == TEMP_FAHRENHEIT: current_temp = fahrenheit_to_celsius(current_temp) metric = self._metric( 'current_temperature_c', self.prometheus_client.Gauge, diff --git a/tests/components/alexa/test_smart_home.py b/tests/components/alexa/test_smart_home.py index 1fc38b71c52..88c69194407 100644 --- a/tests/components/alexa/test_smart_home.py +++ b/tests/components/alexa/test_smart_home.py @@ -7,8 +7,8 @@ import pytest from homeassistant.core import Context, callback from homeassistant.const import ( - TEMP_FAHRENHEIT, STATE_LOCKED, STATE_UNLOCKED, - STATE_UNKNOWN) + TEMP_CELSIUS, TEMP_FAHRENHEIT, STATE_LOCKED, + STATE_UNLOCKED, STATE_UNKNOWN) from homeassistant.setup import async_setup_component from homeassistant.components import alexa from homeassistant.components.alexa import smart_home @@ -707,6 +707,7 @@ def test_unknown_sensor(hass): async def test_thermostat(hass): """Test thermostat discovery.""" + hass.config.units.temperature_unit = TEMP_FAHRENHEIT device = ( 'climate.test_thermostat', 'cool', @@ -721,7 +722,6 @@ async def test_thermostat(hass): 'operation_list': ['heat', 'cool', 'auto', 'off'], 'min_temp': 50, 'max_temp': 90, - 'unit_of_measurement': TEMP_FAHRENHEIT, } ) appliance = await discovery_test(device, hass) @@ -838,6 +838,7 @@ async def test_thermostat(hass): payload={'thermostatMode': {'value': 'INVALID'}} ) assert msg['event']['payload']['type'] == 'UNSUPPORTED_THERMOSTAT_MODE' + hass.config.units.temperature_unit = TEMP_CELSIUS @asyncio.coroutine diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index 59ddb004bec..ac587db13fa 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -9,7 +9,6 @@ import homeassistant.core as ha from homeassistant.core import callback, CoreState, State from homeassistant.setup import setup_component, async_setup_component from homeassistant.const import ( - ATTR_UNIT_OF_MEASUREMENT, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON, @@ -141,11 +140,9 @@ class TestGenericThermostatHeaterSwitching(unittest.TestCase): self.assertEqual(STATE_ON, self.hass.states.get(heater_switch).state) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) class TestClimateGenericThermostat(unittest.TestCase): @@ -222,30 +219,15 @@ class TestClimateGenericThermostat(unittest.TestCase): state = self.hass.states.get(ENTITY) self.assertEqual(23, state.attributes.get('temperature')) - def test_sensor_bad_unit(self): - """Test sensor that have bad unit.""" - state = self.hass.states.get(ENTITY) - temp = state.attributes.get('current_temperature') - unit = state.attributes.get('unit_of_measurement') - - self._setup_sensor(22.0, unit='bad_unit') - self.hass.block_till_done() - - state = self.hass.states.get(ENTITY) - self.assertEqual(unit, state.attributes.get('unit_of_measurement')) - self.assertEqual(temp, state.attributes.get('current_temperature')) - def test_sensor_bad_value(self): """Test sensor that have None as state.""" state = self.hass.states.get(ENTITY) temp = state.attributes.get('current_temperature') - unit = state.attributes.get('unit_of_measurement') self._setup_sensor(None) self.hass.block_till_done() state = self.hass.states.get(ENTITY) - self.assertEqual(unit, state.attributes.get('unit_of_measurement')) self.assertEqual(temp, state.attributes.get('current_temperature')) def test_set_target_temp_heater_on(self): @@ -367,11 +349,9 @@ class TestClimateGenericThermostat(unittest.TestCase): self.assertEqual(SERVICE_TURN_ON, call.service) self.assertEqual(ENT_SWITCH, call.data['entity_id']) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) def _setup_switch(self, is_on): """Set up the test switch.""" @@ -532,11 +512,9 @@ class TestClimateGenericThermostatACMode(unittest.TestCase): self.hass.block_till_done() self.assertEqual(0, len(self.calls)) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) def _setup_switch(self, is_on): """Set up the test switch.""" @@ -626,11 +604,9 @@ class TestClimateGenericThermostatACModeMinCycle(unittest.TestCase): self.assertEqual(SERVICE_TURN_OFF, call.service) self.assertEqual(ENT_SWITCH, call.data['entity_id']) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) def _setup_switch(self, is_on): """Set up the test switch.""" @@ -719,11 +695,9 @@ class TestClimateGenericThermostatMinCycle(unittest.TestCase): self.assertEqual(SERVICE_TURN_OFF, call.service) self.assertEqual(ENT_SWITCH, call.data['entity_id']) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) def _setup_switch(self, is_on): """Set up the test switch.""" @@ -812,11 +786,9 @@ class TestClimateGenericThermostatACKeepAlive(unittest.TestCase): """Send a time changed event.""" self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now}) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) def _setup_switch(self, is_on): """Set up the test switch.""" @@ -904,11 +876,9 @@ class TestClimateGenericThermostatKeepAlive(unittest.TestCase): """Send a time changed event.""" self.hass.bus.fire(ha.EVENT_TIME_CHANGED, {ha.ATTR_NOW: now}) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) def _setup_switch(self, is_on): """Set up the test switch.""" @@ -1047,11 +1017,9 @@ class TestClimateGenericThermostatRestoreState(unittest.TestCase): 'ac_mode': True }}) - def _setup_sensor(self, temp, unit=TEMP_CELSIUS): + def _setup_sensor(self, temp): """Set up the test sensor.""" - self.hass.states.set(ENT_SENSOR, temp, { - ATTR_UNIT_OF_MEASUREMENT: unit - }) + self.hass.states.set(ENT_SENSOR, temp) def _setup_switch(self, is_on): """Set up the test switch.""" diff --git a/tests/components/google_assistant/test_google_assistant.py b/tests/components/google_assistant/test_google_assistant.py index d45680d132e..d9682940bdc 100644 --- a/tests/components/google_assistant/test_google_assistant.py +++ b/tests/components/google_assistant/test_google_assistant.py @@ -232,10 +232,10 @@ def test_query_climate_request(hass_fixture, assistant_client): def test_query_climate_request_f(hass_fixture, assistant_client): """Test a query request.""" # Mock demo devices as fahrenheit to see if we convert to celsius + hass_fixture.config.units.temperature_unit = const.TEMP_FAHRENHEIT for entity_id in ('climate.hvac', 'climate.heatpump', 'climate.ecobee'): state = hass_fixture.states.get(entity_id) attr = dict(state.attributes) - attr[const.ATTR_UNIT_OF_MEASUREMENT] = const.TEMP_FAHRENHEIT hass_fixture.states.async_set(entity_id, state.state, attr) reqid = '5711642932632160984' @@ -282,6 +282,7 @@ def test_query_climate_request_f(hass_fixture, assistant_client): 'thermostatMode': 'cool', 'thermostatHumidityAmbient': 54, } + hass_fixture.config.units.temperature_unit = const.TEMP_CELSIUS @asyncio.coroutine diff --git a/tests/components/google_assistant/test_trait.py b/tests/components/google_assistant/test_trait.py index 1f7ee011e61..c18ed4b7bf3 100644 --- a/tests/components/google_assistant/test_trait.py +++ b/tests/components/google_assistant/test_trait.py @@ -3,7 +3,7 @@ import pytest from homeassistant.const import ( STATE_ON, STATE_OFF, ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, - ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS, TEMP_FAHRENHEIT) + TEMP_CELSIUS, TEMP_FAHRENHEIT) from homeassistant.core import State, DOMAIN as HA_DOMAIN from homeassistant.components import ( climate, @@ -27,7 +27,7 @@ async def test_brightness_light(hass): assert trait.BrightnessTrait.supported(light.DOMAIN, light.SUPPORT_BRIGHTNESS) - trt = trait.BrightnessTrait(State('light.bla', light.STATE_ON, { + trt = trait.BrightnessTrait(hass, State('light.bla', light.STATE_ON, { light.ATTR_BRIGHTNESS: 243 })) @@ -38,7 +38,7 @@ async def test_brightness_light(hass): } calls = async_mock_service(hass, light.DOMAIN, light.SERVICE_TURN_ON) - await trt.execute(hass, trait.COMMAND_BRIGHTNESS_ABSOLUTE, { + await trt.execute(trait.COMMAND_BRIGHTNESS_ABSOLUTE, { 'brightness': 50 }) assert len(calls) == 1 @@ -53,7 +53,7 @@ async def test_brightness_cover(hass): assert trait.BrightnessTrait.supported(cover.DOMAIN, cover.SUPPORT_SET_POSITION) - trt = trait.BrightnessTrait(State('cover.bla', cover.STATE_OPEN, { + trt = trait.BrightnessTrait(hass, State('cover.bla', cover.STATE_OPEN, { cover.ATTR_CURRENT_POSITION: 75 })) @@ -65,7 +65,7 @@ async def test_brightness_cover(hass): calls = async_mock_service( hass, cover.DOMAIN, cover.SERVICE_SET_COVER_POSITION) - await trt.execute(hass, trait.COMMAND_BRIGHTNESS_ABSOLUTE, { + await trt.execute(trait.COMMAND_BRIGHTNESS_ABSOLUTE, { 'brightness': 50 }) assert len(calls) == 1 @@ -80,7 +80,7 @@ async def test_brightness_media_player(hass): assert trait.BrightnessTrait.supported(media_player.DOMAIN, media_player.SUPPORT_VOLUME_SET) - trt = trait.BrightnessTrait(State( + trt = trait.BrightnessTrait(hass, State( 'media_player.bla', media_player.STATE_PLAYING, { media_player.ATTR_MEDIA_VOLUME_LEVEL: .3 })) @@ -93,7 +93,7 @@ async def test_brightness_media_player(hass): calls = async_mock_service( hass, media_player.DOMAIN, media_player.SERVICE_VOLUME_SET) - await trt.execute(hass, trait.COMMAND_BRIGHTNESS_ABSOLUTE, { + await trt.execute(trait.COMMAND_BRIGHTNESS_ABSOLUTE, { 'brightness': 60 }) assert len(calls) == 1 @@ -107,7 +107,7 @@ async def test_onoff_group(hass): """Test OnOff trait support for group domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) - trt_on = trait.OnOffTrait(State('group.bla', STATE_ON)) + trt_on = trait.OnOffTrait(hass, State('group.bla', STATE_ON)) assert trt_on.sync_attributes() == {} @@ -115,13 +115,13 @@ async def test_onoff_group(hass): 'on': True } - trt_off = trait.OnOffTrait(State('group.bla', STATE_OFF)) + trt_off = trait.OnOffTrait(hass, State('group.bla', STATE_OFF)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, HA_DOMAIN, SERVICE_TURN_ON) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 @@ -130,7 +130,7 @@ async def test_onoff_group(hass): } off_calls = async_mock_service(hass, HA_DOMAIN, SERVICE_TURN_OFF) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 @@ -143,7 +143,7 @@ async def test_onoff_input_boolean(hass): """Test OnOff trait support for input_boolean domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) - trt_on = trait.OnOffTrait(State('input_boolean.bla', STATE_ON)) + trt_on = trait.OnOffTrait(hass, State('input_boolean.bla', STATE_ON)) assert trt_on.sync_attributes() == {} @@ -151,13 +151,13 @@ async def test_onoff_input_boolean(hass): 'on': True } - trt_off = trait.OnOffTrait(State('input_boolean.bla', STATE_OFF)) + trt_off = trait.OnOffTrait(hass, State('input_boolean.bla', STATE_OFF)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, input_boolean.DOMAIN, SERVICE_TURN_ON) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 @@ -167,7 +167,7 @@ async def test_onoff_input_boolean(hass): off_calls = async_mock_service(hass, input_boolean.DOMAIN, SERVICE_TURN_OFF) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 @@ -180,7 +180,7 @@ async def test_onoff_switch(hass): """Test OnOff trait support for switch domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) - trt_on = trait.OnOffTrait(State('switch.bla', STATE_ON)) + trt_on = trait.OnOffTrait(hass, State('switch.bla', STATE_ON)) assert trt_on.sync_attributes() == {} @@ -188,13 +188,13 @@ async def test_onoff_switch(hass): 'on': True } - trt_off = trait.OnOffTrait(State('switch.bla', STATE_OFF)) + trt_off = trait.OnOffTrait(hass, State('switch.bla', STATE_OFF)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, switch.DOMAIN, SERVICE_TURN_ON) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 @@ -203,7 +203,7 @@ async def test_onoff_switch(hass): } off_calls = async_mock_service(hass, switch.DOMAIN, SERVICE_TURN_OFF) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 @@ -216,7 +216,7 @@ async def test_onoff_fan(hass): """Test OnOff trait support for fan domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) - trt_on = trait.OnOffTrait(State('fan.bla', STATE_ON)) + trt_on = trait.OnOffTrait(hass, State('fan.bla', STATE_ON)) assert trt_on.sync_attributes() == {} @@ -224,13 +224,13 @@ async def test_onoff_fan(hass): 'on': True } - trt_off = trait.OnOffTrait(State('fan.bla', STATE_OFF)) + trt_off = trait.OnOffTrait(hass, State('fan.bla', STATE_OFF)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, fan.DOMAIN, SERVICE_TURN_ON) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 @@ -239,7 +239,7 @@ async def test_onoff_fan(hass): } off_calls = async_mock_service(hass, fan.DOMAIN, SERVICE_TURN_OFF) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 @@ -252,7 +252,7 @@ async def test_onoff_light(hass): """Test OnOff trait support for light domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) - trt_on = trait.OnOffTrait(State('light.bla', STATE_ON)) + trt_on = trait.OnOffTrait(hass, State('light.bla', STATE_ON)) assert trt_on.sync_attributes() == {} @@ -260,13 +260,13 @@ async def test_onoff_light(hass): 'on': True } - trt_off = trait.OnOffTrait(State('light.bla', STATE_OFF)) + trt_off = trait.OnOffTrait(hass, State('light.bla', STATE_OFF)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, light.DOMAIN, SERVICE_TURN_ON) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 @@ -275,7 +275,7 @@ async def test_onoff_light(hass): } off_calls = async_mock_service(hass, light.DOMAIN, SERVICE_TURN_OFF) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 @@ -288,7 +288,7 @@ async def test_onoff_cover(hass): """Test OnOff trait support for cover domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) - trt_on = trait.OnOffTrait(State('cover.bla', cover.STATE_OPEN)) + trt_on = trait.OnOffTrait(hass, State('cover.bla', cover.STATE_OPEN)) assert trt_on.sync_attributes() == {} @@ -296,13 +296,13 @@ async def test_onoff_cover(hass): 'on': True } - trt_off = trait.OnOffTrait(State('cover.bla', cover.STATE_CLOSED)) + trt_off = trait.OnOffTrait(hass, State('cover.bla', cover.STATE_CLOSED)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, cover.DOMAIN, cover.SERVICE_OPEN_COVER) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 @@ -312,7 +312,7 @@ async def test_onoff_cover(hass): off_calls = async_mock_service(hass, cover.DOMAIN, cover.SERVICE_CLOSE_COVER) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 @@ -325,7 +325,7 @@ async def test_onoff_media_player(hass): """Test OnOff trait support for media_player domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) - trt_on = trait.OnOffTrait(State('media_player.bla', STATE_ON)) + trt_on = trait.OnOffTrait(hass, State('media_player.bla', STATE_ON)) assert trt_on.sync_attributes() == {} @@ -333,13 +333,13 @@ async def test_onoff_media_player(hass): 'on': True } - trt_off = trait.OnOffTrait(State('media_player.bla', STATE_OFF)) + trt_off = trait.OnOffTrait(hass, State('media_player.bla', STATE_OFF)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, media_player.DOMAIN, SERVICE_TURN_ON) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 @@ -348,7 +348,7 @@ async def test_onoff_media_player(hass): } off_calls = async_mock_service(hass, media_player.DOMAIN, SERVICE_TURN_OFF) - await trt_on.execute(hass, trait.COMMAND_ONOFF, { + await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 @@ -363,7 +363,7 @@ async def test_color_spectrum_light(hass): assert trait.ColorSpectrumTrait.supported(light.DOMAIN, light.SUPPORT_COLOR) - trt = trait.ColorSpectrumTrait(State('light.bla', STATE_ON, { + trt = trait.ColorSpectrumTrait(hass, State('light.bla', STATE_ON, { light.ATTR_HS_COLOR: (0, 94), })) @@ -389,7 +389,7 @@ async def test_color_spectrum_light(hass): }) calls = async_mock_service(hass, light.DOMAIN, SERVICE_TURN_ON) - await trt.execute(hass, trait.COMMAND_COLOR_ABSOLUTE, { + await trt.execute(trait.COMMAND_COLOR_ABSOLUTE, { 'color': { 'spectrumRGB': 1052927 } @@ -407,7 +407,7 @@ async def test_color_temperature_light(hass): assert trait.ColorTemperatureTrait.supported(light.DOMAIN, light.SUPPORT_COLOR_TEMP) - trt = trait.ColorTemperatureTrait(State('light.bla', STATE_ON, { + trt = trait.ColorTemperatureTrait(hass, State('light.bla', STATE_ON, { light.ATTR_MIN_MIREDS: 200, light.ATTR_COLOR_TEMP: 300, light.ATTR_MAX_MIREDS: 500, @@ -438,14 +438,14 @@ async def test_color_temperature_light(hass): calls = async_mock_service(hass, light.DOMAIN, SERVICE_TURN_ON) with pytest.raises(helpers.SmartHomeError) as err: - await trt.execute(hass, trait.COMMAND_COLOR_ABSOLUTE, { + await trt.execute(trait.COMMAND_COLOR_ABSOLUTE, { 'color': { 'temperature': 5555 } }) assert err.value.code == const.ERR_VALUE_OUT_OF_RANGE - await trt.execute(hass, trait.COMMAND_COLOR_ABSOLUTE, { + await trt.execute(trait.COMMAND_COLOR_ABSOLUTE, { 'color': { 'temperature': 2857 } @@ -461,13 +461,13 @@ async def test_scene_scene(hass): """Test Scene trait support for scene domain.""" assert trait.SceneTrait.supported(scene.DOMAIN, 0) - trt = trait.SceneTrait(State('scene.bla', scene.STATE)) + trt = trait.SceneTrait(hass, State('scene.bla', scene.STATE)) assert trt.sync_attributes() == {} assert trt.query_attributes() == {} assert trt.can_execute(trait.COMMAND_ACTIVATE_SCENE, {}) calls = async_mock_service(hass, scene.DOMAIN, SERVICE_TURN_ON) - await trt.execute(hass, trait.COMMAND_ACTIVATE_SCENE, {}) + await trt.execute(trait.COMMAND_ACTIVATE_SCENE, {}) assert len(calls) == 1 assert calls[0].data == { ATTR_ENTITY_ID: 'scene.bla', @@ -478,13 +478,13 @@ async def test_scene_script(hass): """Test Scene trait support for script domain.""" assert trait.SceneTrait.supported(script.DOMAIN, 0) - trt = trait.SceneTrait(State('script.bla', STATE_OFF)) + trt = trait.SceneTrait(hass, State('script.bla', STATE_OFF)) assert trt.sync_attributes() == {} assert trt.query_attributes() == {} assert trt.can_execute(trait.COMMAND_ACTIVATE_SCENE, {}) calls = async_mock_service(hass, script.DOMAIN, SERVICE_TURN_ON) - await trt.execute(hass, trait.COMMAND_ACTIVATE_SCENE, {}) + await trt.execute(trait.COMMAND_ACTIVATE_SCENE, {}) # We don't wait till script execution is done. await hass.async_block_till_done() @@ -501,7 +501,9 @@ async def test_temperature_setting_climate_range(hass): assert trait.TemperatureSettingTrait.supported( climate.DOMAIN, climate.SUPPORT_OPERATION_MODE) - trt = trait.TemperatureSettingTrait(State( + hass.config.units.temperature_unit = TEMP_FAHRENHEIT + + trt = trait.TemperatureSettingTrait(hass, State( 'climate.bla', climate.STATE_AUTO, { climate.ATTR_CURRENT_TEMPERATURE: 70, climate.ATTR_CURRENT_HUMIDITY: 25, @@ -515,8 +517,7 @@ async def test_temperature_setting_climate_range(hass): climate.ATTR_TARGET_TEMP_HIGH: 75, climate.ATTR_TARGET_TEMP_LOW: 65, climate.ATTR_MIN_TEMP: 50, - climate.ATTR_MAX_TEMP: 80, - ATTR_UNIT_OF_MEASUREMENT: TEMP_FAHRENHEIT, + climate.ATTR_MAX_TEMP: 80 })) assert trt.sync_attributes() == { 'availableThermostatModes': 'off,cool,heat,heatcool', @@ -535,7 +536,7 @@ async def test_temperature_setting_climate_range(hass): calls = async_mock_service( hass, climate.DOMAIN, climate.SERVICE_SET_TEMPERATURE) - await trt.execute(hass, trait.COMMAND_THERMOSTAT_TEMPERATURE_SET_RANGE, { + await trt.execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SET_RANGE, { 'thermostatTemperatureSetpointHigh': 25, 'thermostatTemperatureSetpointLow': 20, }) @@ -548,7 +549,7 @@ async def test_temperature_setting_climate_range(hass): calls = async_mock_service( hass, climate.DOMAIN, climate.SERVICE_SET_OPERATION_MODE) - await trt.execute(hass, trait.COMMAND_THERMOSTAT_SET_MODE, { + await trt.execute(trait.COMMAND_THERMOSTAT_SET_MODE, { 'thermostatMode': 'heatcool', }) assert len(calls) == 1 @@ -558,11 +559,11 @@ async def test_temperature_setting_climate_range(hass): } with pytest.raises(helpers.SmartHomeError) as err: - await trt.execute( - hass, trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, { - 'thermostatTemperatureSetpoint': -100, - }) + await trt.execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, { + 'thermostatTemperatureSetpoint': -100, + }) assert err.value.code == const.ERR_VALUE_OUT_OF_RANGE + hass.config.units.temperature_unit = TEMP_CELSIUS async def test_temperature_setting_climate_setpoint(hass): @@ -571,7 +572,9 @@ async def test_temperature_setting_climate_setpoint(hass): assert trait.TemperatureSettingTrait.supported( climate.DOMAIN, climate.SUPPORT_OPERATION_MODE) - trt = trait.TemperatureSettingTrait(State( + hass.config.units.temperature_unit = TEMP_CELSIUS + + trt = trait.TemperatureSettingTrait(hass, State( 'climate.bla', climate.STATE_AUTO, { climate.ATTR_OPERATION_MODE: climate.STATE_COOL, climate.ATTR_OPERATION_LIST: [ @@ -581,8 +584,7 @@ async def test_temperature_setting_climate_setpoint(hass): climate.ATTR_MIN_TEMP: 10, climate.ATTR_MAX_TEMP: 30, climate.ATTR_TEMPERATURE: 18, - climate.ATTR_CURRENT_TEMPERATURE: 20, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, + climate.ATTR_CURRENT_TEMPERATURE: 20 })) assert trt.sync_attributes() == { 'availableThermostatModes': 'off,cool', @@ -601,12 +603,11 @@ async def test_temperature_setting_climate_setpoint(hass): hass, climate.DOMAIN, climate.SERVICE_SET_TEMPERATURE) with pytest.raises(helpers.SmartHomeError): - await trt.execute( - hass, trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, { - 'thermostatTemperatureSetpoint': -100, - }) + await trt.execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, { + 'thermostatTemperatureSetpoint': -100, + }) - await trt.execute(hass, trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, { + await trt.execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, { 'thermostatTemperatureSetpoint': 19, }) assert len(calls) == 1 diff --git a/tests/components/homekit/test_type_thermostats.py b/tests/components/homekit/test_type_thermostats.py index 45c340e58c4..687a9e9513c 100644 --- a/tests/components/homekit/test_type_thermostats.py +++ b/tests/components/homekit/test_type_thermostats.py @@ -12,8 +12,8 @@ from homeassistant.components.climate import ( from homeassistant.components.homekit.const import ( PROP_MAX_VALUE, PROP_MIN_VALUE) from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT, - CONF_TEMPERATURE_UNIT, STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT) + ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, CONF_TEMPERATURE_UNIT, STATE_OFF, + TEMP_FAHRENHEIT) from tests.common import async_mock_service from tests.components.homekit.common import patch_debounce @@ -58,8 +58,7 @@ async def test_default_thermostat(hass, hk_driver, cls): hass.states.async_set(entity_id, STATE_HEAT, {ATTR_OPERATION_MODE: STATE_HEAT, ATTR_TEMPERATURE: 22.0, - ATTR_CURRENT_TEMPERATURE: 18.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 18.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 22.0 assert acc.char_current_heat_cool.value == 1 @@ -70,8 +69,7 @@ async def test_default_thermostat(hass, hk_driver, cls): hass.states.async_set(entity_id, STATE_HEAT, {ATTR_OPERATION_MODE: STATE_HEAT, ATTR_TEMPERATURE: 22.0, - ATTR_CURRENT_TEMPERATURE: 23.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 23.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 22.0 assert acc.char_current_heat_cool.value == 0 @@ -82,8 +80,7 @@ async def test_default_thermostat(hass, hk_driver, cls): hass.states.async_set(entity_id, STATE_COOL, {ATTR_OPERATION_MODE: STATE_COOL, ATTR_TEMPERATURE: 20.0, - ATTR_CURRENT_TEMPERATURE: 25.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 25.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 20.0 assert acc.char_current_heat_cool.value == 2 @@ -94,8 +91,7 @@ async def test_default_thermostat(hass, hk_driver, cls): hass.states.async_set(entity_id, STATE_COOL, {ATTR_OPERATION_MODE: STATE_COOL, ATTR_TEMPERATURE: 20.0, - ATTR_CURRENT_TEMPERATURE: 19.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 19.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 20.0 assert acc.char_current_heat_cool.value == 0 @@ -106,8 +102,7 @@ async def test_default_thermostat(hass, hk_driver, cls): hass.states.async_set(entity_id, STATE_OFF, {ATTR_OPERATION_MODE: STATE_OFF, ATTR_TEMPERATURE: 22.0, - ATTR_CURRENT_TEMPERATURE: 18.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 18.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 22.0 assert acc.char_current_heat_cool.value == 0 @@ -119,8 +114,7 @@ async def test_default_thermostat(hass, hk_driver, cls): {ATTR_OPERATION_MODE: STATE_AUTO, ATTR_OPERATION_LIST: [STATE_HEAT, STATE_COOL], ATTR_TEMPERATURE: 22.0, - ATTR_CURRENT_TEMPERATURE: 18.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 18.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 22.0 assert acc.char_current_heat_cool.value == 1 @@ -132,8 +126,7 @@ async def test_default_thermostat(hass, hk_driver, cls): {ATTR_OPERATION_MODE: STATE_AUTO, ATTR_OPERATION_LIST: [STATE_HEAT, STATE_COOL], ATTR_TEMPERATURE: 22.0, - ATTR_CURRENT_TEMPERATURE: 25.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 25.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 22.0 assert acc.char_current_heat_cool.value == 2 @@ -145,8 +138,7 @@ async def test_default_thermostat(hass, hk_driver, cls): {ATTR_OPERATION_MODE: STATE_AUTO, ATTR_OPERATION_LIST: [STATE_HEAT, STATE_COOL], ATTR_TEMPERATURE: 22.0, - ATTR_CURRENT_TEMPERATURE: 22.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 22.0}) await hass.async_block_till_done() assert acc.char_target_temp.value == 22.0 assert acc.char_current_heat_cool.value == 0 @@ -201,8 +193,7 @@ async def test_auto_thermostat(hass, hk_driver, cls): {ATTR_OPERATION_MODE: STATE_AUTO, ATTR_TARGET_TEMP_HIGH: 22.0, ATTR_TARGET_TEMP_LOW: 20.0, - ATTR_CURRENT_TEMPERATURE: 18.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 18.0}) await hass.async_block_till_done() assert acc.char_heating_thresh_temp.value == 20.0 assert acc.char_cooling_thresh_temp.value == 22.0 @@ -215,8 +206,7 @@ async def test_auto_thermostat(hass, hk_driver, cls): {ATTR_OPERATION_MODE: STATE_AUTO, ATTR_TARGET_TEMP_HIGH: 23.0, ATTR_TARGET_TEMP_LOW: 19.0, - ATTR_CURRENT_TEMPERATURE: 24.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 24.0}) await hass.async_block_till_done() assert acc.char_heating_thresh_temp.value == 19.0 assert acc.char_cooling_thresh_temp.value == 23.0 @@ -229,8 +219,7 @@ async def test_auto_thermostat(hass, hk_driver, cls): {ATTR_OPERATION_MODE: STATE_AUTO, ATTR_TARGET_TEMP_HIGH: 23.0, ATTR_TARGET_TEMP_LOW: 19.0, - ATTR_CURRENT_TEMPERATURE: 21.0, - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + ATTR_CURRENT_TEMPERATURE: 21.0}) await hass.async_block_till_done() assert acc.char_heating_thresh_temp.value == 19.0 assert acc.char_cooling_thresh_temp.value == 23.0 @@ -334,8 +323,7 @@ async def test_thermostat_fahrenheit(hass, hk_driver, cls): ATTR_TARGET_TEMP_HIGH: 75.2, ATTR_TARGET_TEMP_LOW: 68, ATTR_TEMPERATURE: 71.6, - ATTR_CURRENT_TEMPERATURE: 73.4, - ATTR_UNIT_OF_MEASUREMENT: TEMP_FAHRENHEIT}) + ATTR_CURRENT_TEMPERATURE: 73.4}) await hass.async_block_till_done() assert acc.char_heating_thresh_temp.value == 20.0 assert acc.char_cooling_thresh_temp.value == 24.0 From 7e7f9bc6ac9683de8dc06396c7b5ddf9505ac129 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 22 Aug 2018 00:52:34 -0700 Subject: [PATCH 097/159] Add multi-factor authentication modules (#15489) * Get user after login flow finished * Add multi factor authentication support * Typings --- homeassistant/auth/__init__.py | 133 ++++++- homeassistant/auth/mfa_modules/__init__.py | 141 +++++++ .../auth/mfa_modules/insecure_example.py | 82 ++++ homeassistant/auth/providers/__init__.py | 72 +++- .../auth/providers/trusted_networks.py | 5 + homeassistant/config.py | 15 +- homeassistant/const.py | 1 + homeassistant/scripts/auth.py | 6 +- script/gen_requirements_all.py | 6 +- tests/auth/mfa_modules/__init__.py | 1 + .../auth/mfa_modules/test_insecure_example.py | 127 ++++++ tests/auth/providers/test_homeassistant.py | 2 +- tests/auth/providers/test_insecure_example.py | 2 +- .../providers/test_legacy_api_password.py | 2 +- tests/auth/providers/test_trusted_networks.py | 2 +- tests/auth/test_init.py | 361 +++++++++++++++++- tests/common.py | 4 +- tests/components/auth/__init__.py | 9 +- 18 files changed, 925 insertions(+), 46 deletions(-) create mode 100644 homeassistant/auth/mfa_modules/__init__.py create mode 100644 homeassistant/auth/mfa_modules/insecure_example.py create mode 100644 tests/auth/mfa_modules/__init__.py create mode 100644 tests/auth/mfa_modules/test_insecure_example.py diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 3b61229d59a..c0beba1a227 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -6,21 +6,26 @@ from typing import Any, Dict, List, Optional, Tuple, cast import jwt +import voluptuous as vol + from homeassistant import data_entry_flow from homeassistant.core import callback, HomeAssistant from homeassistant.util import dt as dt_util from . import auth_store, models -from .providers import auth_provider_from_config, AuthProvider +from .mfa_modules import auth_mfa_module_from_config, MultiFactorAuthModule +from .providers import auth_provider_from_config, AuthProvider, LoginFlow _LOGGER = logging.getLogger(__name__) +_MfaModuleDict = Dict[str, MultiFactorAuthModule] _ProviderKey = Tuple[str, Optional[str]] _ProviderDict = Dict[_ProviderKey, AuthProvider] async def auth_manager_from_config( hass: HomeAssistant, - provider_configs: List[Dict[str, Any]]) -> 'AuthManager': + provider_configs: List[Dict[str, Any]], + module_configs: List[Dict[str, Any]]) -> 'AuthManager': """Initialize an auth manager from config.""" store = auth_store.AuthStore(hass) if provider_configs: @@ -44,7 +49,28 @@ async def auth_manager_from_config( continue provider_hash[key] = provider - manager = AuthManager(hass, store, provider_hash) + + if module_configs: + modules = await asyncio.gather( + *[auth_mfa_module_from_config(hass, config) + for config in module_configs]) + else: + modules = () + # So returned auth modules are in same order as config + module_hash = OrderedDict() # type: _MfaModuleDict + for module in modules: + if module is None: + continue + + if module.id in module_hash: + _LOGGER.error( + 'Found duplicate multi-factor module: %s. Please add unique ' + 'IDs if you want to have the same module twice.', module.id) + continue + + module_hash[module.id] = module + + manager = AuthManager(hass, store, provider_hash, module_hash) return manager @@ -52,10 +78,13 @@ class AuthManager: """Manage the authentication for Home Assistant.""" def __init__(self, hass: HomeAssistant, store: auth_store.AuthStore, - providers: _ProviderDict) -> None: + providers: _ProviderDict, mfa_modules: _MfaModuleDict) \ + -> None: """Initialize the auth manager.""" + self.hass = hass self._store = store self._providers = providers + self._mfa_modules = mfa_modules self.login_flow = data_entry_flow.FlowManager( hass, self._async_create_login_flow, self._async_finish_login_flow) @@ -82,6 +111,16 @@ class AuthManager: """Return a list of available auth providers.""" return list(self._providers.values()) + @property + def auth_mfa_modules(self) -> List[MultiFactorAuthModule]: + """Return a list of available auth modules.""" + return list(self._mfa_modules.values()) + + def get_auth_mfa_module(self, module_id: str) \ + -> Optional[MultiFactorAuthModule]: + """Return an multi-factor auth module, None if not found.""" + return self._mfa_modules.get(module_id) + async def async_get_users(self) -> List[models.User]: """Retrieve all users.""" return await self._store.async_get_users() @@ -90,6 +129,16 @@ class AuthManager: """Retrieve a user.""" return await self._store.async_get_user(user_id) + async def async_get_user_by_credentials( + self, credentials: models.Credentials) -> Optional[models.User]: + """Get a user by credential, return None if not found.""" + for user in await self.async_get_users(): + for creds in user.credentials: + if creds.id == credentials.id: + return user + + return None + async def async_create_system_user(self, name: str) -> models.User: """Create a system user.""" return await self._store.async_create_user( @@ -114,12 +163,11 @@ class AuthManager: -> models.User: """Get or create a user.""" if not credentials.is_new: - for user in await self._store.async_get_users(): - for creds in user.credentials: - if creds.id == credentials.id: - return user - - raise ValueError('Unable to find the user.') + user = await self.async_get_user_by_credentials(credentials) + if user is None: + raise ValueError('Unable to find the user.') + else: + return user auth_provider = self._async_get_auth_provider(credentials) @@ -175,6 +223,49 @@ class AuthManager: await self._store.async_remove_credentials(credentials) + async def async_enable_user_mfa(self, user: models.User, + mfa_module_id: str, data: Any) -> None: + """Enable a multi-factor auth module for user.""" + if user.system_generated: + raise ValueError('System generated users cannot enable ' + 'multi-factor auth module.') + + module = self.get_auth_mfa_module(mfa_module_id) + if module is None: + raise ValueError('Unable find multi-factor auth module: {}' + .format(mfa_module_id)) + + if module.setup_schema is not None: + try: + # pylint: disable=not-callable + data = module.setup_schema(data) + except vol.Invalid as err: + raise ValueError('Data does not match schema: {}'.format(err)) + + await module.async_setup_user(user.id, data) + + async def async_disable_user_mfa(self, user: models.User, + mfa_module_id: str) -> None: + """Disable a multi-factor auth module for user.""" + if user.system_generated: + raise ValueError('System generated users cannot disable ' + 'multi-factor auth module.') + + module = self.get_auth_mfa_module(mfa_module_id) + if module is None: + raise ValueError('Unable find multi-factor auth module: {}' + .format(mfa_module_id)) + + await module.async_depose_user(user.id) + + async def async_get_enabled_mfa(self, user: models.User) -> List[str]: + """List enabled mfa modules for user.""" + module_ids = [] + for module_id, module in self._mfa_modules.items(): + if await module.async_is_user_setup(user.id): + module_ids.append(module_id) + return module_ids + async def async_create_refresh_token(self, user: models.User, client_id: Optional[str] = None) \ -> models.RefreshToken: @@ -262,12 +353,17 @@ class AuthManager: return await auth_provider.async_login_flow(context) async def _async_finish_login_flow( - self, flow: data_entry_flow.FlowHandler, result: Dict[str, Any]) \ + self, flow: LoginFlow, result: Dict[str, Any]) \ -> Dict[str, Any]: """Return a user as result of login flow.""" if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY: return result + # we got final result + if isinstance(result['data'], models.User): + result['result'] = result['data'] + return result + auth_provider = self._providers[result['handler']] credentials = await auth_provider.async_get_or_create_credentials( result['data']) @@ -276,8 +372,19 @@ class AuthManager: result['result'] = credentials return result - user = await self.async_get_or_create_user(credentials) - result['result'] = user + # multi-factor module cannot enabled for new credential + # which has not linked to a user yet + if auth_provider.support_mfa and not credentials.is_new: + user = await self.async_get_user_by_credentials(credentials) + if user is not None: + modules = await self.async_get_enabled_mfa(user) + + if modules: + flow.user = user + flow.available_mfa_modules = modules + return await flow.async_step_select_mfa_module() + + result['result'] = await self.async_get_or_create_user(credentials) return result @callback diff --git a/homeassistant/auth/mfa_modules/__init__.py b/homeassistant/auth/mfa_modules/__init__.py new file mode 100644 index 00000000000..d0707c4a745 --- /dev/null +++ b/homeassistant/auth/mfa_modules/__init__.py @@ -0,0 +1,141 @@ +"""Plugable auth modules for Home Assistant.""" +from datetime import timedelta +import importlib +import logging +import types +from typing import Any, Dict, Optional + +import voluptuous as vol +from voluptuous.humanize import humanize_error + +from homeassistant import requirements +from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE +from homeassistant.core import HomeAssistant +from homeassistant.util.decorator import Registry + +MULTI_FACTOR_AUTH_MODULES = Registry() + +MULTI_FACTOR_AUTH_MODULE_SCHEMA = vol.Schema({ + vol.Required(CONF_TYPE): str, + vol.Optional(CONF_NAME): str, + # Specify ID if you have two mfa auth module for same type. + vol.Optional(CONF_ID): str, +}, extra=vol.ALLOW_EXTRA) + +SESSION_EXPIRATION = timedelta(minutes=5) + +DATA_REQS = 'mfa_auth_module_reqs_processed' + +_LOGGER = logging.getLogger(__name__) + + +class MultiFactorAuthModule: + """Multi-factor Auth Module of validation function.""" + + DEFAULT_TITLE = 'Unnamed auth module' + + def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None: + """Initialize an auth module.""" + self.hass = hass + self.config = config + + @property + def id(self) -> str: # pylint: disable=invalid-name + """Return id of the auth module. + + Default is same as type + """ + return self.config.get(CONF_ID, self.type) + + @property + def type(self) -> str: + """Return type of the module.""" + return self.config[CONF_TYPE] # type: ignore + + @property + def name(self) -> str: + """Return the name of the auth module.""" + return self.config.get(CONF_NAME, self.DEFAULT_TITLE) + + # Implement by extending class + + @property + def input_schema(self) -> vol.Schema: + """Return a voluptuous schema to define mfa auth module's input.""" + raise NotImplementedError + + @property + def setup_schema(self) -> Optional[vol.Schema]: + """Return a vol schema to validate mfa auth module's setup input. + + Optional + """ + return None + + async def async_setup_user(self, user_id: str, setup_data: Any) -> None: + """Set up user for mfa auth module.""" + raise NotImplementedError + + async def async_depose_user(self, user_id: str) -> None: + """Remove user from mfa module.""" + raise NotImplementedError + + async def async_is_user_setup(self, user_id: str) -> bool: + """Return whether user is setup.""" + raise NotImplementedError + + async def async_validation( + self, user_id: str, user_input: Dict[str, Any]) -> bool: + """Return True if validation passed.""" + raise NotImplementedError + + +async def auth_mfa_module_from_config( + hass: HomeAssistant, config: Dict[str, Any]) \ + -> Optional[MultiFactorAuthModule]: + """Initialize an auth module from a config.""" + module_name = config[CONF_TYPE] + module = await _load_mfa_module(hass, module_name) + + if module is None: + return None + + try: + config = module.CONFIG_SCHEMA(config) # type: ignore + except vol.Invalid as err: + _LOGGER.error('Invalid configuration for multi-factor module %s: %s', + module_name, humanize_error(config, err)) + return None + + return MULTI_FACTOR_AUTH_MODULES[module_name](hass, config) # type: ignore + + +async def _load_mfa_module(hass: HomeAssistant, module_name: str) \ + -> Optional[types.ModuleType]: + """Load an mfa auth module.""" + module_path = 'homeassistant.auth.mfa_modules.{}'.format(module_name) + + try: + module = importlib.import_module(module_path) + except ImportError: + _LOGGER.warning('Unable to find %s', module_path) + return None + + if hass.config.skip_pip or not hasattr(module, 'REQUIREMENTS'): + return module + + processed = hass.data.get(DATA_REQS) + if processed and module_name in processed: + return module + + processed = hass.data[DATA_REQS] = set() + + # https://github.com/python/mypy/issues/1424 + req_success = await requirements.async_process_requirements( + hass, module_path, module.REQUIREMENTS) # type: ignore + + if not req_success: + return None + + processed.add(module_name) + return module diff --git a/homeassistant/auth/mfa_modules/insecure_example.py b/homeassistant/auth/mfa_modules/insecure_example.py new file mode 100644 index 00000000000..59b3f64d2e0 --- /dev/null +++ b/homeassistant/auth/mfa_modules/insecure_example.py @@ -0,0 +1,82 @@ +"""Example auth module.""" +import logging +from typing import Any, Dict, Optional + +import voluptuous as vol + +from homeassistant.core import HomeAssistant + +from . import MultiFactorAuthModule, MULTI_FACTOR_AUTH_MODULES, \ + MULTI_FACTOR_AUTH_MODULE_SCHEMA + +CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({ + vol.Required('data'): [vol.Schema({ + vol.Required('user_id'): str, + vol.Required('pin'): str, + })] +}, extra=vol.PREVENT_EXTRA) + +_LOGGER = logging.getLogger(__name__) + + +@MULTI_FACTOR_AUTH_MODULES.register('insecure_example') +class InsecureExampleModule(MultiFactorAuthModule): + """Example auth module validate pin.""" + + DEFAULT_TITLE = 'Insecure Personal Identify Number' + + def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None: + """Initialize the user data store.""" + super().__init__(hass, config) + self._data = config['data'] + + @property + def input_schema(self) -> vol.Schema: + """Validate login flow input data.""" + return vol.Schema({'pin': str}) + + @property + def setup_schema(self) -> Optional[vol.Schema]: + """Validate async_setup_user input data.""" + return vol.Schema({'pin': str}) + + async def async_setup_user(self, user_id: str, setup_data: Any) -> None: + """Set up user to use mfa module.""" + # data shall has been validate in caller + pin = setup_data['pin'] + + for data in self._data: + if data['user_id'] == user_id: + # already setup, override + data['pin'] = pin + return + + self._data.append({'user_id': user_id, 'pin': pin}) + + async def async_depose_user(self, user_id: str) -> None: + """Remove user from mfa module.""" + found = None + for data in self._data: + if data['user_id'] == user_id: + found = data + break + if found: + self._data.remove(found) + + async def async_is_user_setup(self, user_id: str) -> bool: + """Return whether user is setup.""" + for data in self._data: + if data['user_id'] == user_id: + return True + return False + + async def async_validation( + self, user_id: str, user_input: Dict[str, Any]) -> bool: + """Return True if validation passed.""" + for data in self._data: + if data['user_id'] == user_id: + # user_input has been validate in caller + if data['pin'] == user_input['pin']: + return True + + return False diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index b2338a8d6ea..e8ef7cbf3d4 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -9,12 +9,13 @@ from voluptuous.humanize import humanize_error from homeassistant import data_entry_flow, requirements from homeassistant.core import callback, HomeAssistant -from homeassistant.const import CONF_TYPE, CONF_NAME, CONF_ID +from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE from homeassistant.util import dt as dt_util from homeassistant.util.decorator import Registry from ..auth_store import AuthStore -from ..models import Credentials, UserMeta +from ..models import Credentials, User, UserMeta # noqa: F401 +from ..mfa_modules import SESSION_EXPIRATION _LOGGER = logging.getLogger(__name__) DATA_REQS = 'auth_prov_reqs_processed' @@ -59,6 +60,11 @@ class AuthProvider: """Return the name of the auth provider.""" return self.config.get(CONF_NAME, self.DEFAULT_TITLE) + @property + def support_mfa(self) -> bool: + """Return whether multi-factor auth supported by the auth provider.""" + return True + async def async_credentials(self) -> List[Credentials]: """Return all credentials of this provider.""" users = await self.store.async_get_users() @@ -160,8 +166,11 @@ class LoginFlow(data_entry_flow.FlowHandler): def __init__(self, auth_provider: AuthProvider) -> None: """Initialize the login flow.""" self._auth_provider = auth_provider + self._auth_module_id = None # type: Optional[str] + self._auth_manager = auth_provider.hass.auth # type: ignore + self.available_mfa_modules = [] # type: List self.created_at = dt_util.utcnow() - self.user = None + self.user = None # type: Optional[User] async def async_step_init( self, user_input: Optional[Dict[str, str]] = None) \ @@ -173,6 +182,63 @@ class LoginFlow(data_entry_flow.FlowHandler): """ raise NotImplementedError + async def async_step_select_mfa_module( + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: + """Handle the step of select mfa module.""" + errors = {} + + if user_input is not None: + auth_module = user_input.get('multi_factor_auth_module') + if auth_module in self.available_mfa_modules: + self._auth_module_id = auth_module + return await self.async_step_mfa() + errors['base'] = 'invalid_auth_module' + + if len(self.available_mfa_modules) == 1: + self._auth_module_id = self.available_mfa_modules[0] + return await self.async_step_mfa() + + return self.async_show_form( + step_id='select_mfa_module', + data_schema=vol.Schema({ + 'multi_factor_auth_module': vol.In(self.available_mfa_modules) + }), + errors=errors, + ) + + async def async_step_mfa( + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: + """Handle the step of mfa validation.""" + errors = {} + + auth_module = self._auth_manager.get_auth_mfa_module( + self._auth_module_id) + if auth_module is None: + # Given an invalid input to async_step_select_mfa_module + # will show invalid_auth_module error + return await self.async_step_select_mfa_module(user_input={}) + + if user_input is not None: + expires = self.created_at + SESSION_EXPIRATION + if dt_util.utcnow() > expires: + errors['base'] = 'login_expired' + else: + result = await auth_module.async_validation( + self.user.id, user_input) # type: ignore + if not result: + errors['base'] = 'invalid_auth' + + if not errors: + return await self.async_finish(self.user) + + return self.async_show_form( + step_id='mfa', + data_schema=auth_module.input_schema, + errors=errors, + ) + async def async_finish(self, flow_result: Any) -> Dict: """Handle the pass of login flow.""" return self.async_create_entry( diff --git a/homeassistant/auth/providers/trusted_networks.py b/homeassistant/auth/providers/trusted_networks.py index 0bc37946e0b..37e032e58d7 100644 --- a/homeassistant/auth/providers/trusted_networks.py +++ b/homeassistant/auth/providers/trusted_networks.py @@ -35,6 +35,11 @@ class TrustedNetworksAuthProvider(AuthProvider): DEFAULT_TITLE = 'Trusted Networks' + @property + def support_mfa(self) -> bool: + """Trusted Networks auth provider does not support MFA.""" + return False + async def async_login_flow(self, context: Optional[Dict]) -> LoginFlow: """Return a flow to login.""" assert context is not None diff --git a/homeassistant/config.py b/homeassistant/config.py index 6120a20fd63..cc4eef3f97e 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -14,14 +14,16 @@ import voluptuous as vol from voluptuous.humanize import humanize_error from homeassistant import auth -from homeassistant.auth import providers as auth_providers +from homeassistant.auth import providers as auth_providers,\ + mfa_modules as auth_mfa_modules from homeassistant.const import ( ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_ASSUMED_STATE, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, CONF_PACKAGES, CONF_UNIT_SYSTEM, CONF_TIME_ZONE, CONF_ELEVATION, CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT, TEMP_CELSIUS, __version__, CONF_CUSTOMIZE, CONF_CUSTOMIZE_DOMAIN, CONF_CUSTOMIZE_GLOB, - CONF_WHITELIST_EXTERNAL_DIRS, CONF_AUTH_PROVIDERS, CONF_TYPE) + CONF_WHITELIST_EXTERNAL_DIRS, CONF_AUTH_PROVIDERS, CONF_AUTH_MFA_MODULES, + CONF_TYPE) from homeassistant.core import callback, DOMAIN as CONF_CORE, HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.loader import get_component, get_platform @@ -166,7 +168,10 @@ CORE_CONFIG_SCHEMA = CUSTOMIZE_CONFIG_SCHEMA.extend({ CONF_TYPE: vol.NotIn(['insecure_example'], 'The insecure_example auth provider' ' is for testing only.') - })]) + })]), + vol.Optional(CONF_AUTH_MFA_MODULES): + vol.All(cv.ensure_list, + [auth_mfa_modules.MULTI_FACTOR_AUTH_MODULE_SCHEMA]), }) @@ -412,7 +417,9 @@ async def async_process_ha_core_config( # Only load auth during startup. if not hasattr(hass, 'auth'): setattr(hass, 'auth', await auth.auth_manager_from_config( - hass, config.get(CONF_AUTH_PROVIDERS, []))) + hass, + config.get(CONF_AUTH_PROVIDERS, []), + config.get(CONF_AUTH_MFA_MODULES, []))) hac = hass.config diff --git a/homeassistant/const.py b/homeassistant/const.py index 7d99b952ce6..d72bde548d3 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -30,6 +30,7 @@ CONF_API_KEY = 'api_key' CONF_API_VERSION = 'api_version' CONF_AT = 'at' CONF_AUTHENTICATION = 'authentication' +CONF_AUTH_MFA_MODULES = 'auth_mfa_modules' CONF_AUTH_PROVIDERS = 'auth_providers' CONF_BASE = 'base' CONF_BEFORE = 'before' diff --git a/homeassistant/scripts/auth.py b/homeassistant/scripts/auth.py index d141faa4c27..be57957ef8c 100644 --- a/homeassistant/scripts/auth.py +++ b/homeassistant/scripts/auth.py @@ -5,15 +5,15 @@ import logging import os from homeassistant.auth import auth_manager_from_config +from homeassistant.auth.providers import homeassistant as hass_auth from homeassistant.core import HomeAssistant from homeassistant.config import get_default_config_dir -from homeassistant.auth.providers import homeassistant as hass_auth def run(args): """Handle Home Assistant auth provider script.""" parser = argparse.ArgumentParser( - description=("Manage Home Assistant users")) + description="Manage Home Assistant users") parser.add_argument( '--script', choices=['auth']) parser.add_argument( @@ -56,7 +56,7 @@ async def run_command(hass, args): hass.config.config_dir = os.path.join(os.getcwd(), args.config) hass.auth = await auth_manager_from_config(hass, [{ 'type': 'homeassistant', - }]) + }], []) provider = hass.auth.auth_providers[0] await provider.async_initialize() await args.func(hass, provider, args) diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 7652d29086b..61f39e3387f 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -165,8 +165,10 @@ def gather_modules(): errors = [] - for package in sorted(explore_module('homeassistant.components', True) + - explore_module('homeassistant.scripts', True)): + for package in sorted( + explore_module('homeassistant.components', True) + + explore_module('homeassistant.scripts', True) + + explore_module('homeassistant.auth', True)): try: module = importlib.import_module(package) except ImportError: diff --git a/tests/auth/mfa_modules/__init__.py b/tests/auth/mfa_modules/__init__.py new file mode 100644 index 00000000000..a49a158d1b0 --- /dev/null +++ b/tests/auth/mfa_modules/__init__.py @@ -0,0 +1 @@ +"""Tests for the multi-factor auth modules.""" diff --git a/tests/auth/mfa_modules/test_insecure_example.py b/tests/auth/mfa_modules/test_insecure_example.py new file mode 100644 index 00000000000..9d90532728a --- /dev/null +++ b/tests/auth/mfa_modules/test_insecure_example.py @@ -0,0 +1,127 @@ +"""Test the example module auth module.""" +from homeassistant import auth, data_entry_flow +from homeassistant.auth.mfa_modules import auth_mfa_module_from_config +from homeassistant.auth.models import Credentials +from tests.common import MockUser + + +async def test_validate(hass): + """Test validating pin.""" + auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'insecure_example', + 'data': [{'user_id': 'test-user', 'pin': '123456'}] + }) + + result = await auth_module.async_validation( + 'test-user', {'pin': '123456'}) + assert result is True + + result = await auth_module.async_validation( + 'test-user', {'pin': 'invalid'}) + assert result is False + + result = await auth_module.async_validation( + 'invalid-user', {'pin': '123456'}) + assert result is False + + +async def test_setup_user(hass): + """Test setup user.""" + auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'insecure_example', + 'data': [] + }) + + await auth_module.async_setup_user( + 'test-user', {'pin': '123456'}) + assert len(auth_module._data) == 1 + + result = await auth_module.async_validation( + 'test-user', {'pin': '123456'}) + assert result is True + + +async def test_depose_user(hass): + """Test despose user.""" + auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'insecure_example', + 'data': [{'user_id': 'test-user', 'pin': '123456'}] + }) + assert len(auth_module._data) == 1 + + await auth_module.async_depose_user('test-user') + assert len(auth_module._data) == 0 + + +async def test_is_user_setup(hass): + """Test is user setup.""" + auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'insecure_example', + 'data': [{'user_id': 'test-user', 'pin': '123456'}] + }) + assert await auth_module.async_is_user_setup('test-user') is True + assert await auth_module.async_is_user_setup('invalid-user') is False + + +async def test_login(hass): + """Test login flow with auth module.""" + hass.auth = await auth.auth_manager_from_config(hass, [{ + 'type': 'insecure_example', + 'users': [{'username': 'test-user', 'password': 'test-pass'}], + }], [{ + 'type': 'insecure_example', + 'data': [{'user_id': 'mock-user', 'pin': '123456'}] + }]) + user = MockUser( + id='mock-user', + is_owner=False, + is_active=False, + name='Paulus', + ).add_to_auth_manager(hass.auth) + await hass.auth.async_link_user(user, Credentials( + id='mock-id', + auth_provider_type='insecure_example', + auth_provider_id=None, + data={'username': 'test-user'}, + is_new=False, + )) + + provider = hass.auth.auth_providers[0] + result = await hass.auth.login_flow.async_init( + (provider.type, provider.id)) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + + result = await hass.auth.login_flow.async_configure( + result['flow_id'], { + 'username': 'incorrect-user', + 'password': 'test-pass', + }) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_auth' + + result = await hass.auth.login_flow.async_configure( + result['flow_id'], { + 'username': 'test-user', + 'password': 'incorrect-pass', + }) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_auth' + + result = await hass.auth.login_flow.async_configure( + result['flow_id'], { + 'username': 'test-user', + 'password': 'test-pass', + }) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['step_id'] == 'mfa' + assert result['data_schema'].schema.get('pin') == str + + result = await hass.auth.login_flow.async_configure( + result['flow_id'], {'pin': 'invalid-code'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_auth' + + result = await hass.auth.login_flow.async_configure( + result['flow_id'], {'pin': '123456'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['data'].id == 'mock-user' diff --git a/tests/auth/providers/test_homeassistant.py b/tests/auth/providers/test_homeassistant.py index b87f981570e..c92f8539b17 100644 --- a/tests/auth/providers/test_homeassistant.py +++ b/tests/auth/providers/test_homeassistant.py @@ -124,7 +124,7 @@ async def test_new_users_populate_values(hass, data): manager = await auth_manager_from_config(hass, [{ 'type': 'homeassistant' - }]) + }], []) provider = manager.auth_providers[0] credentials = await provider.async_get_or_create_credentials({ 'username': 'hello' diff --git a/tests/auth/providers/test_insecure_example.py b/tests/auth/providers/test_insecure_example.py index b472e4c95df..d50e8b0de96 100644 --- a/tests/auth/providers/test_insecure_example.py +++ b/tests/auth/providers/test_insecure_example.py @@ -40,7 +40,7 @@ def manager(hass, store, provider): """Mock manager.""" return AuthManager(hass, store, { (provider.type, provider.id): provider - }) + }, {}) async def test_create_new_credential(manager, provider): diff --git a/tests/auth/providers/test_legacy_api_password.py b/tests/auth/providers/test_legacy_api_password.py index 0c129088c8b..33178b06cb2 100644 --- a/tests/auth/providers/test_legacy_api_password.py +++ b/tests/auth/providers/test_legacy_api_password.py @@ -27,7 +27,7 @@ def manager(hass, store, provider): """Mock manager.""" return auth.AuthManager(hass, store, { (provider.type, provider.id): provider - }) + }, {}) async def test_create_new_credential(manager, provider): diff --git a/tests/auth/providers/test_trusted_networks.py b/tests/auth/providers/test_trusted_networks.py index 5a7021a647a..4839c72a86a 100644 --- a/tests/auth/providers/test_trusted_networks.py +++ b/tests/auth/providers/test_trusted_networks.py @@ -28,7 +28,7 @@ def manager(hass, store, provider): """Mock manager.""" return auth.AuthManager(hass, store, { (provider.type, provider.id): provider - }) + }, {}) async def test_trusted_networks_credentials(manager, provider): diff --git a/tests/auth/test_init.py b/tests/auth/test_init.py index 5dc6ebf135d..f724b40a71f 100644 --- a/tests/auth/test_init.py +++ b/tests/auth/test_init.py @@ -7,6 +7,7 @@ import pytest from homeassistant import auth, data_entry_flow from homeassistant.auth import ( models as auth_models, auth_store, const as auth_const) +from homeassistant.auth.mfa_modules import SESSION_EXPIRATION from homeassistant.util import dt as dt_util from tests.common import ( MockUser, ensure_auth_manager_loaded, flush_store, CLIENT_ID) @@ -40,7 +41,7 @@ async def test_auth_manager_from_config_validates_config_and_id(mock_hass): 'type': 'insecure_example', 'id': 'another', 'users': [], - }]) + }], []) providers = [{ 'name': provider.name, @@ -58,7 +59,65 @@ async def test_auth_manager_from_config_validates_config_and_id(mock_hass): }] -async def test_create_new_user(hass, hass_storage): +async def test_auth_manager_from_config_auth_modules(mock_hass): + """Test get auth modules.""" + manager = await auth.auth_manager_from_config(mock_hass, [{ + 'name': 'Test Name', + 'type': 'insecure_example', + 'users': [], + }, { + 'name': 'Test Name 2', + 'type': 'insecure_example', + 'id': 'another', + 'users': [], + }], [{ + 'name': 'Module 1', + 'type': 'insecure_example', + 'data': [], + }, { + 'name': 'Module 2', + 'type': 'insecure_example', + 'id': 'another', + 'data': [], + }, { + 'name': 'Duplicate ID', + 'type': 'insecure_example', + 'id': 'another', + 'data': [], + }]) + + providers = [{ + 'name': provider.name, + 'type': provider.type, + 'id': provider.id, + } for provider in manager.auth_providers] + assert providers == [{ + 'name': 'Test Name', + 'type': 'insecure_example', + 'id': None, + }, { + 'name': 'Test Name 2', + 'type': 'insecure_example', + 'id': 'another', + }] + + modules = [{ + 'name': module.name, + 'type': module.type, + 'id': module.id, + } for module in manager.auth_mfa_modules] + assert modules == [{ + 'name': 'Module 1', + 'type': 'insecure_example', + 'id': 'insecure_example', + }, { + 'name': 'Module 2', + 'type': 'insecure_example', + 'id': 'another', + }] + + +async def test_create_new_user(hass): """Test creating new user.""" manager = await auth.auth_manager_from_config(hass, [{ 'type': 'insecure_example', @@ -67,7 +126,7 @@ async def test_create_new_user(hass, hass_storage): 'password': 'test-pass', 'name': 'Test Name' }] - }]) + }], []) step = await manager.login_flow.async_init(('insecure_example', None)) assert step['type'] == data_entry_flow.RESULT_TYPE_FORM @@ -92,7 +151,8 @@ async def test_login_as_existing_user(mock_hass): 'password': 'test-pass', 'name': 'Test Name' }] - }]) + }], []) + mock_hass.auth = manager ensure_auth_manager_loaded(manager) # Add a fake user that we're not going to log in with @@ -157,7 +217,7 @@ async def test_linking_user_to_two_auth_providers(hass, hass_storage): 'username': 'another-user', 'password': 'another-password', }] - }]) + }], []) step = await manager.login_flow.async_init(('insecure_example', None)) step = await manager.login_flow.async_configure(step['flow_id'], { @@ -190,7 +250,7 @@ async def test_saving_loading(hass, hass_storage): 'username': 'test-user', 'password': 'test-pass', }] - }]) + }], []) step = await manager.login_flow.async_init(('insecure_example', None)) step = await manager.login_flow.async_configure(step['flow_id'], { @@ -211,7 +271,7 @@ async def test_saving_loading(hass, hass_storage): async def test_cannot_retrieve_expired_access_token(hass): """Test that we cannot retrieve expired access tokens.""" - manager = await auth.auth_manager_from_config(hass, []) + manager = await auth.auth_manager_from_config(hass, [], []) user = MockUser().add_to_auth_manager(manager) refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID) assert refresh_token.user.id is user.id @@ -236,7 +296,7 @@ async def test_cannot_retrieve_expired_access_token(hass): async def test_generating_system_user(hass): """Test that we can add a system user.""" - manager = await auth.auth_manager_from_config(hass, []) + manager = await auth.auth_manager_from_config(hass, [], []) user = await manager.async_create_system_user('Hass.io') token = await manager.async_create_refresh_token(user) assert user.system_generated @@ -246,7 +306,7 @@ async def test_generating_system_user(hass): async def test_refresh_token_requires_client_for_user(hass): """Test that we can add a system user.""" - manager = await auth.auth_manager_from_config(hass, []) + manager = await auth.auth_manager_from_config(hass, [], []) user = MockUser().add_to_auth_manager(manager) assert user.system_generated is False @@ -260,7 +320,7 @@ async def test_refresh_token_requires_client_for_user(hass): async def test_refresh_token_not_requires_client_for_system_user(hass): """Test that we can add a system user.""" - manager = await auth.auth_manager_from_config(hass, []) + manager = await auth.auth_manager_from_config(hass, [], []) user = await manager.async_create_system_user('Hass.io') assert user.system_generated is True @@ -274,7 +334,7 @@ async def test_refresh_token_not_requires_client_for_system_user(hass): async def test_cannot_deactive_owner(mock_hass): """Test that we cannot deactive the owner.""" - manager = await auth.auth_manager_from_config(mock_hass, []) + manager = await auth.auth_manager_from_config(mock_hass, [], []) owner = MockUser( is_owner=True, ).add_to_auth_manager(manager) @@ -285,7 +345,7 @@ async def test_cannot_deactive_owner(mock_hass): async def test_remove_refresh_token(mock_hass): """Test that we can remove a refresh token.""" - manager = await auth.auth_manager_from_config(mock_hass, []) + manager = await auth.auth_manager_from_config(mock_hass, [], []) user = MockUser().add_to_auth_manager(manager) refresh_token = await manager.async_create_refresh_token(user, CLIENT_ID) access_token = manager.async_create_access_token(refresh_token) @@ -298,3 +358,280 @@ async def test_remove_refresh_token(mock_hass): assert ( await manager.async_validate_access_token(access_token) is None ) + + +async def test_login_with_auth_module(mock_hass): + """Test login as existing user with auth module.""" + manager = await auth.auth_manager_from_config(mock_hass, [{ + 'type': 'insecure_example', + 'users': [{ + 'username': 'test-user', + 'password': 'test-pass', + 'name': 'Test Name' + }], + }], [{ + 'type': 'insecure_example', + 'data': [{ + 'user_id': 'mock-user', + 'pin': 'test-pin' + }] + }]) + mock_hass.auth = manager + ensure_auth_manager_loaded(manager) + + # Add fake user with credentials for example auth provider. + user = MockUser( + id='mock-user', + is_owner=False, + is_active=False, + name='Paulus', + ).add_to_auth_manager(manager) + user.credentials.append(auth_models.Credentials( + id='mock-id', + auth_provider_type='insecure_example', + auth_provider_id=None, + data={'username': 'test-user'}, + is_new=False, + )) + + step = await manager.login_flow.async_init(('insecure_example', None)) + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + + step = await manager.login_flow.async_configure(step['flow_id'], { + 'username': 'test-user', + 'password': 'test-pass', + }) + + # After auth_provider validated, request auth module input form + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + assert step['step_id'] == 'mfa' + + step = await manager.login_flow.async_configure(step['flow_id'], { + 'pin': 'invalid-pin', + }) + + # Invalid auth error + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + assert step['step_id'] == 'mfa' + assert step['errors'] == {'base': 'invalid_auth'} + + step = await manager.login_flow.async_configure(step['flow_id'], { + 'pin': 'test-pin', + }) + + # Finally passed, get user + assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + user = step['result'] + assert user is not None + assert user.id == 'mock-user' + assert user.is_owner is False + assert user.is_active is False + assert user.name == 'Paulus' + + +async def test_login_with_multi_auth_module(mock_hass): + """Test login as existing user with multiple auth modules.""" + manager = await auth.auth_manager_from_config(mock_hass, [{ + 'type': 'insecure_example', + 'users': [{ + 'username': 'test-user', + 'password': 'test-pass', + 'name': 'Test Name' + }], + }], [{ + 'type': 'insecure_example', + 'data': [{ + 'user_id': 'mock-user', + 'pin': 'test-pin' + }] + }, { + 'type': 'insecure_example', + 'id': 'module2', + 'data': [{ + 'user_id': 'mock-user', + 'pin': 'test-pin2' + }] + }]) + mock_hass.auth = manager + ensure_auth_manager_loaded(manager) + + # Add fake user with credentials for example auth provider. + user = MockUser( + id='mock-user', + is_owner=False, + is_active=False, + name='Paulus', + ).add_to_auth_manager(manager) + user.credentials.append(auth_models.Credentials( + id='mock-id', + auth_provider_type='insecure_example', + auth_provider_id=None, + data={'username': 'test-user'}, + is_new=False, + )) + + step = await manager.login_flow.async_init(('insecure_example', None)) + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + + step = await manager.login_flow.async_configure(step['flow_id'], { + 'username': 'test-user', + 'password': 'test-pass', + }) + + # After auth_provider validated, request select auth module + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + assert step['step_id'] == 'select_mfa_module' + + step = await manager.login_flow.async_configure(step['flow_id'], { + 'multi_factor_auth_module': 'module2', + }) + + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + assert step['step_id'] == 'mfa' + + step = await manager.login_flow.async_configure(step['flow_id'], { + 'pin': 'test-pin2', + }) + + # Finally passed, get user + assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + user = step['result'] + assert user is not None + assert user.id == 'mock-user' + assert user.is_owner is False + assert user.is_active is False + assert user.name == 'Paulus' + + +async def test_auth_module_expired_session(mock_hass): + """Test login as existing user.""" + manager = await auth.auth_manager_from_config(mock_hass, [{ + 'type': 'insecure_example', + 'users': [{ + 'username': 'test-user', + 'password': 'test-pass', + 'name': 'Test Name' + }], + }], [{ + 'type': 'insecure_example', + 'data': [{ + 'user_id': 'mock-user', + 'pin': 'test-pin' + }] + }]) + mock_hass.auth = manager + ensure_auth_manager_loaded(manager) + + # Add fake user with credentials for example auth provider. + user = MockUser( + id='mock-user', + is_owner=False, + is_active=False, + name='Paulus', + ).add_to_auth_manager(manager) + user.credentials.append(auth_models.Credentials( + id='mock-id', + auth_provider_type='insecure_example', + auth_provider_id=None, + data={'username': 'test-user'}, + is_new=False, + )) + + step = await manager.login_flow.async_init(('insecure_example', None)) + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + + step = await manager.login_flow.async_configure(step['flow_id'], { + 'username': 'test-user', + 'password': 'test-pass', + }) + + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + assert step['step_id'] == 'mfa' + + with patch('homeassistant.util.dt.utcnow', + return_value=dt_util.utcnow() + SESSION_EXPIRATION): + step = await manager.login_flow.async_configure(step['flow_id'], { + 'pin': 'test-pin', + }) + # Invalid auth due session timeout + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + assert step['step_id'] == 'mfa' + assert step['errors']['base'] == 'login_expired' + + # The second try will fail as well + step = await manager.login_flow.async_configure(step['flow_id'], { + 'pin': 'test-pin', + }) + assert step['type'] == data_entry_flow.RESULT_TYPE_FORM + assert step['step_id'] == 'mfa' + assert step['errors']['base'] == 'login_expired' + + +async def test_enable_mfa_for_user(hass, hass_storage): + """Test enable mfa module for user.""" + manager = await auth.auth_manager_from_config(hass, [{ + 'type': 'insecure_example', + 'users': [{ + 'username': 'test-user', + 'password': 'test-pass', + }] + }], [{ + 'type': 'insecure_example', + 'data': [], + }]) + + step = await manager.login_flow.async_init(('insecure_example', None)) + step = await manager.login_flow.async_configure(step['flow_id'], { + 'username': 'test-user', + 'password': 'test-pass', + }) + user = step['result'] + assert user is not None + + # new user don't have mfa enabled + modules = await manager.async_get_enabled_mfa(user) + assert len(modules) == 0 + + module = manager.get_auth_mfa_module('insecure_example') + # mfa module don't have data + assert bool(module._data) is False + + # test enable mfa for user + await manager.async_enable_user_mfa(user, 'insecure_example', + {'pin': 'test-pin'}) + assert len(module._data) == 1 + assert module._data[0] == {'user_id': user.id, 'pin': 'test-pin'} + + # test get enabled mfa + modules = await manager.async_get_enabled_mfa(user) + assert len(modules) == 1 + assert 'insecure_example' in modules + + # re-enable mfa for user will override + await manager.async_enable_user_mfa(user, 'insecure_example', + {'pin': 'test-pin-new'}) + assert len(module._data) == 1 + assert module._data[0] == {'user_id': user.id, 'pin': 'test-pin-new'} + modules = await manager.async_get_enabled_mfa(user) + assert len(modules) == 1 + assert 'insecure_example' in modules + + # system user cannot enable mfa + system_user = await manager.async_create_system_user('system-user') + with pytest.raises(ValueError): + await manager.async_enable_user_mfa(system_user, 'insecure_example', + {'pin': 'test-pin'}) + assert len(module._data) == 1 + modules = await manager.async_get_enabled_mfa(system_user) + assert len(modules) == 0 + + # disable mfa for user + await manager.async_disable_user_mfa(user, 'insecure_example') + assert bool(module._data) is False + + # test get enabled mfa + modules = await manager.async_get_enabled_mfa(user) + assert len(modules) == 0 + + # disable mfa for user don't enabled just silent fail + await manager.async_disable_user_mfa(user, 'insecure_example') diff --git a/tests/common.py b/tests/common.py index c56cadc16f9..f39f9ca0a18 100644 --- a/tests/common.py +++ b/tests/common.py @@ -118,7 +118,7 @@ def async_test_home_assistant(loop): hass = ha.HomeAssistant(loop) hass.config.async_load = Mock() store = auth_store.AuthStore(hass) - hass.auth = auth.AuthManager(hass, store, {}) + hass.auth = auth.AuthManager(hass, store, {}, {}) ensure_auth_manager_loaded(hass.auth) INSTANCES.append(hass) @@ -342,7 +342,7 @@ class MockUser(auth_models.User): 'is_owner': is_owner, 'is_active': is_active, 'name': name, - 'system_generated': system_generated + 'system_generated': system_generated, } if id is not None: kwargs['id'] = id diff --git a/tests/components/auth/__init__.py b/tests/components/auth/__init__.py index e5eed4fca24..224f9b16403 100644 --- a/tests/components/auth/__init__.py +++ b/tests/components/auth/__init__.py @@ -15,11 +15,14 @@ BASE_CONFIG = [{ }] }] +EMPTY_CONFIG = [] + async def async_setup_auth(hass, aiohttp_client, provider_configs=BASE_CONFIG, - setup_api=False): - """Helper to set up authentication and create an HTTP client.""" - hass.auth = await auth.auth_manager_from_config(hass, provider_configs) + module_configs=EMPTY_CONFIG, setup_api=False): + """Helper to set up authentication and create a HTTP client.""" + hass.auth = await auth.auth_manager_from_config( + hass, provider_configs, module_configs) ensure_auth_manager_loaded(hass.auth) await async_setup_component(hass, 'auth', { 'http': { From 0009be595c50a6a6ebd9cb45d62b45a27d0d57c3 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Wed, 22 Aug 2018 10:46:37 +0200 Subject: [PATCH 098/159] Device Registry (#15980) * First draft * Generate device id * No obscure registry * Dont store config_entry_id in device * Storage * Small mistake on rebase * Do storage more like entity registry * Improve device identification * Add tests * Remove deconz device support from PR * Fix hound comments, voff! * Fix comments and clean up * Fix proper indentation * Fix pydoc issues * Fix mochad component to not use self.device * Fix mochad light platform to not use self.device * Fix TankUtilitySensor to not use self.device * Fix Soundtouch to not use self.device * Fix Plex to not use self.device * Fix Emby to not use self.device * Fix Heatmiser to not use self.device * Fix Wemo lights to not use self.device * Fix Lifx to not use self.device * Fix Radiotherm to not use self.device * Fix Juicenet to not use self.device * Fix Qwikswitch to not use self.device * Fix Xiaomi miio to not use self.device * Fix Nest to not use self.device * Fix Tellduslive to not use self.device * Fix Knx to not use self.device * Clean up a small mistake in soundtouch * Fix comment from Ballob * Fix bad indentation * Fix indentatin * Lint * Remove unused variable * Lint --- homeassistant/components/binary_sensor/knx.py | 10 +- .../components/binary_sensor/nest.py | 5 +- .../components/binary_sensor/tellduslive.py | 2 +- homeassistant/components/camera/nest.py | 18 +-- homeassistant/components/climate/heatmiser.py | 1 - homeassistant/components/climate/knx.py | 30 ++--- homeassistant/components/climate/nest.py | 44 +++---- .../components/climate/radiotherm.py | 34 ++--- homeassistant/components/cover/knx.py | 34 ++--- homeassistant/components/cover/tellduslive.py | 8 +- homeassistant/components/juicenet.py | 12 +- homeassistant/components/light/knx.py | 32 ++--- homeassistant/components/light/lifx.py | 38 +++--- homeassistant/components/light/mochad.py | 16 +-- homeassistant/components/light/qwikswitch.py | 4 +- homeassistant/components/light/tellduslive.py | 8 +- homeassistant/components/light/wemo.py | 28 ++-- homeassistant/components/media_player/emby.py | 54 ++++---- homeassistant/components/media_player/plex.py | 63 +++++---- .../components/media_player/soundtouch.py | 17 +-- homeassistant/components/nest/__init__.py | 6 +- homeassistant/components/notify/knx.py | 8 +- homeassistant/components/qwikswitch.py | 6 +- .../components/remote/xiaomi_miio.py | 9 +- homeassistant/components/sensor/juicenet.py | 20 +-- homeassistant/components/sensor/knx.py | 10 +- homeassistant/components/sensor/nest.py | 10 +- .../components/sensor/tank_utility.py | 11 +- .../components/sensor/tellduslive.py | 2 +- homeassistant/components/switch/knx.py | 12 +- homeassistant/components/switch/mochad.py | 8 +- .../components/switch/tellduslive.py | 6 +- homeassistant/components/tellduslive.py | 26 ++-- homeassistant/helpers/device_registry.py | 121 ++++++++++++++++++ homeassistant/helpers/entity.py | 8 ++ homeassistant/helpers/entity_platform.py | 32 +++-- homeassistant/helpers/entity_registry.py | 16 ++- tests/components/light/test_mochad.py | 18 +-- tests/components/switch/test_mochad.py | 4 +- tests/helpers/test_device_registry.py | 78 +++++++++++ 40 files changed, 538 insertions(+), 331 deletions(-) create mode 100644 homeassistant/helpers/device_registry.py create mode 100644 tests/helpers/test_device_registry.py diff --git a/homeassistant/components/binary_sensor/knx.py b/homeassistant/components/binary_sensor/knx.py index e6b28047cb8..76142dc0af2 100644 --- a/homeassistant/components/binary_sensor/knx.py +++ b/homeassistant/components/binary_sensor/knx.py @@ -105,7 +105,7 @@ class KNXBinarySensor(BinarySensorDevice): def __init__(self, hass, device): """Initialize of KNX binary sensor.""" - self.device = device + self._device = device self.hass = hass self.async_register_callbacks() self.automations = [] @@ -116,12 +116,12 @@ class KNXBinarySensor(BinarySensorDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self.device.register_device_updated_cb(after_update_callback) + self._device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self.device.name + return self._device.name @property def available(self): @@ -136,9 +136,9 @@ class KNXBinarySensor(BinarySensorDevice): @property def device_class(self): """Return the class of this sensor.""" - return self.device.device_class + return self._device.device_class @property def is_on(self): """Return true if the binary sensor is on.""" - return self.device.is_on() + return self._device.is_on() diff --git a/homeassistant/components/binary_sensor/nest.py b/homeassistant/components/binary_sensor/nest.py index 31460c1eedc..03bc484983b 100644 --- a/homeassistant/components/binary_sensor/nest.py +++ b/homeassistant/components/binary_sensor/nest.py @@ -130,7 +130,7 @@ class NestBinarySensor(NestSensorDevice, BinarySensorDevice): def update(self): """Retrieve latest state.""" - value = getattr(self.device, self.variable) + value = getattr(self._device, self.variable) if self.variable in STRUCTURE_BINARY_TYPES: self._state = bool(STRUCTURE_BINARY_STATE_MAP [self.variable].get(value)) @@ -154,4 +154,5 @@ class NestActivityZoneSensor(NestBinarySensor): def update(self): """Retrieve latest state.""" - self._state = self.device.has_ongoing_motion_in_zone(self.zone.zone_id) + self._state = self._device.has_ongoing_motion_in_zone( + self.zone.zone_id) diff --git a/homeassistant/components/binary_sensor/tellduslive.py b/homeassistant/components/binary_sensor/tellduslive.py index e5d2d83fe47..6746d532780 100644 --- a/homeassistant/components/binary_sensor/tellduslive.py +++ b/homeassistant/components/binary_sensor/tellduslive.py @@ -31,4 +31,4 @@ class TelldusLiveSensor(TelldusLiveEntity, BinarySensorDevice): @property def is_on(self): """Return true if switch is on.""" - return self.device.is_on + return self._device.is_on diff --git a/homeassistant/components/camera/nest.py b/homeassistant/components/camera/nest.py index bf6700371fd..3f09bc9ee1c 100644 --- a/homeassistant/components/camera/nest.py +++ b/homeassistant/components/camera/nest.py @@ -46,7 +46,7 @@ class NestCamera(Camera): """Initialize a Nest Camera.""" super(NestCamera, self).__init__() self.structure = structure - self.device = device + self._device = device self._location = None self._name = None self._online = None @@ -93,7 +93,7 @@ class NestCamera(Camera): # Calling Nest API in is_streaming setter. # device.is_streaming would not immediately change until the process # finished in Nest Cam. - self.device.is_streaming = False + self._device.is_streaming = False def turn_on(self): """Turn on camera.""" @@ -105,15 +105,15 @@ class NestCamera(Camera): # Calling Nest API in is_streaming setter. # device.is_streaming would not immediately change until the process # finished in Nest Cam. - self.device.is_streaming = True + self._device.is_streaming = True def update(self): """Cache value from Python-nest.""" - self._location = self.device.where - self._name = self.device.name - self._online = self.device.online - self._is_streaming = self.device.is_streaming - self._is_video_history_enabled = self.device.is_video_history_enabled + self._location = self._device.where + self._name = self._device.name + self._online = self._device.online + self._is_streaming = self._device.is_streaming + self._is_video_history_enabled = self._device.is_video_history_enabled if self._is_video_history_enabled: # NestAware allowed 10/min @@ -130,7 +130,7 @@ class NestCamera(Camera): """Return a still image response from the camera.""" now = utcnow() if self._ready_for_snapshot(now): - url = self.device.snapshot_url + url = self._device.snapshot_url try: response = requests.get(url) diff --git a/homeassistant/components/climate/heatmiser.py b/homeassistant/components/climate/heatmiser.py index 12057e88647..116545afc15 100644 --- a/homeassistant/components/climate/heatmiser.py +++ b/homeassistant/components/climate/heatmiser.py @@ -58,7 +58,6 @@ class HeatmiserV3Thermostat(ClimateDevice): def __init__(self, heatmiser, device, name, serport): """Initialize the thermostat.""" self.heatmiser = heatmiser - self.device = device self.serport = serport self._current_temperature = None self._name = name diff --git a/homeassistant/components/climate/knx.py b/homeassistant/components/climate/knx.py index 1f95a8cb43d..a9d26288433 100644 --- a/homeassistant/components/climate/knx.py +++ b/homeassistant/components/climate/knx.py @@ -118,7 +118,7 @@ class KNXClimate(ClimateDevice): def __init__(self, hass, device): """Initialize of a KNX climate device.""" - self.device = device + self._device = device self.hass = hass self.async_register_callbacks() @@ -126,7 +126,7 @@ class KNXClimate(ClimateDevice): def supported_features(self): """Return the list of supported features.""" support = SUPPORT_TARGET_TEMPERATURE - if self.device.supports_operation_mode: + if self._device.supports_operation_mode: support |= SUPPORT_OPERATION_MODE return support @@ -135,12 +135,12 @@ class KNXClimate(ClimateDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self.device.register_device_updated_cb(after_update_callback) + self._device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self.device.name + return self._device.name @property def available(self): @@ -160,41 +160,41 @@ class KNXClimate(ClimateDevice): @property def current_temperature(self): """Return the current temperature.""" - return self.device.temperature.value + return self._device.temperature.value @property def target_temperature_step(self): """Return the supported step of target temperature.""" - return self.device.setpoint_shift_step + return self._device.setpoint_shift_step @property def target_temperature(self): """Return the temperature we try to reach.""" - return self.device.target_temperature.value + return self._device.target_temperature.value @property def min_temp(self): """Return the minimum temperature.""" - return self.device.target_temperature_min + return self._device.target_temperature_min @property def max_temp(self): """Return the maximum temperature.""" - return self.device.target_temperature_max + return self._device.target_temperature_max async def async_set_temperature(self, **kwargs): """Set new target temperature.""" temperature = kwargs.get(ATTR_TEMPERATURE) if temperature is None: return - await self.device.set_target_temperature(temperature) + await self._device.set_target_temperature(temperature) await self.async_update_ha_state() @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" - if self.device.supports_operation_mode: - return self.device.operation_mode.value + if self._device.supports_operation_mode: + return self._device.operation_mode.value return None @property @@ -202,11 +202,11 @@ class KNXClimate(ClimateDevice): """Return the list of available operation modes.""" return [operation_mode.value for operation_mode in - self.device.get_supported_operation_modes()] + self._device.get_supported_operation_modes()] async def async_set_operation_mode(self, operation_mode): """Set operation mode.""" - if self.device.supports_operation_mode: + if self._device.supports_operation_mode: from xknx.knx import HVACOperationMode knx_operation_mode = HVACOperationMode(operation_mode) - await self.device.set_operation_mode(knx_operation_mode) + await self._device.set_operation_mode(knx_operation_mode) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index fa3943c3e27..2fdb11866e0 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -57,7 +57,7 @@ class NestThermostat(ClimateDevice): """Initialize the thermostat.""" self._unit = temp_unit self.structure = structure - self.device = device + self._device = device self._fan_list = [STATE_ON, STATE_AUTO] # Set the default supported features @@ -68,13 +68,13 @@ class NestThermostat(ClimateDevice): self._operation_list = [STATE_OFF] # Add supported nest thermostat features - if self.device.can_heat: + if self._device.can_heat: self._operation_list.append(STATE_HEAT) - if self.device.can_cool: + if self._device.can_cool: self._operation_list.append(STATE_COOL) - if self.device.can_heat and self.device.can_cool: + if self._device.can_heat and self._device.can_cool: self._operation_list.append(STATE_AUTO) self._support_flags = (self._support_flags | SUPPORT_TARGET_TEMPERATURE_HIGH | @@ -83,7 +83,7 @@ class NestThermostat(ClimateDevice): self._operation_list.append(STATE_ECO) # feature of device - self._has_fan = self.device.has_fan + self._has_fan = self._device.has_fan if self._has_fan: self._support_flags = (self._support_flags | SUPPORT_FAN_MODE) @@ -125,7 +125,7 @@ class NestThermostat(ClimateDevice): @property def unique_id(self): """Unique ID for this device.""" - return self.device.serial + return self._device.serial @property def name(self): @@ -202,7 +202,7 @@ class NestThermostat(ClimateDevice): _LOGGER.debug("Nest set_temperature-output-value=%s", temp) try: if temp is not None: - self.device.target = temp + self._device.target = temp except nest.nest.APIError as api_error: _LOGGER.error("An error occurred while setting temperature: %s", api_error) @@ -220,7 +220,7 @@ class NestThermostat(ClimateDevice): _LOGGER.error( "An error occurred while setting device mode. " "Invalid operation mode: %s", operation_mode) - self.device.mode = device_mode + self._device.mode = device_mode @property def operation_list(self): @@ -254,7 +254,7 @@ class NestThermostat(ClimateDevice): def set_fan_mode(self, fan_mode): """Turn fan on/off.""" if self._has_fan: - self.device.fan = fan_mode.lower() + self._device.fan = fan_mode.lower() @property def min_temp(self): @@ -268,20 +268,20 @@ class NestThermostat(ClimateDevice): def update(self): """Cache value from Python-nest.""" - self._location = self.device.where - self._name = self.device.name - self._humidity = self.device.humidity - self._temperature = self.device.temperature - self._mode = self.device.mode - self._target_temperature = self.device.target - self._fan = self.device.fan + self._location = self._device.where + self._name = self._device.name + self._humidity = self._device.humidity + self._temperature = self._device.temperature + self._mode = self._device.mode + self._target_temperature = self._device.target + self._fan = self._device.fan self._away = self.structure.away == 'away' - self._eco_temperature = self.device.eco_temperature - self._locked_temperature = self.device.locked_temperature - self._min_temperature = self.device.min_temperature - self._max_temperature = self.device.max_temperature - self._is_locked = self.device.is_locked - if self.device.temperature_scale == 'C': + self._eco_temperature = self._device.eco_temperature + self._locked_temperature = self._device.locked_temperature + self._min_temperature = self._device.min_temperature + self._max_temperature = self._device.max_temperature + self._is_locked = self._device.is_locked + if self._device.temperature_scale == 'C': self._temperature_scale = TEMP_CELSIUS else: self._temperature_scale = TEMP_FAHRENHEIT diff --git a/homeassistant/components/climate/radiotherm.py b/homeassistant/components/climate/radiotherm.py index c8441a9f7af..d158eb52a9d 100644 --- a/homeassistant/components/climate/radiotherm.py +++ b/homeassistant/components/climate/radiotherm.py @@ -120,7 +120,7 @@ class RadioThermostat(ClimateDevice): def __init__(self, device, hold_temp, away_temps): """Initialize the thermostat.""" - self.device = device + self._device = device self._target_temperature = None self._current_temperature = None self._current_operation = STATE_IDLE @@ -137,8 +137,8 @@ class RadioThermostat(ClimateDevice): # Fan circulate mode is only supported by the CT80 models. import radiotherm - self._is_model_ct80 = isinstance(self.device, - radiotherm.thermostat.CT80) + self._is_model_ct80 = isinstance( + self._device, radiotherm.thermostat.CT80) @property def supported_features(self): @@ -194,7 +194,7 @@ class RadioThermostat(ClimateDevice): """Turn fan on/off.""" code = FAN_MODE_TO_CODE.get(fan_mode, None) if code is not None: - self.device.fmode = code + self._device.fmode = code @property def current_temperature(self): @@ -234,15 +234,15 @@ class RadioThermostat(ClimateDevice): # First time - get the name from the thermostat. This is # normally set in the radio thermostat web app. if self._name is None: - self._name = self.device.name['raw'] + self._name = self._device.name['raw'] # Request the current state from the thermostat. - data = self.device.tstat['raw'] + data = self._device.tstat['raw'] current_temp = data['temp'] if current_temp == -1: _LOGGER.error('%s (%s) was busy (temp == -1)', self._name, - self.device.host) + self._device.host) return # Map thermostat values into various STATE_ flags. @@ -277,30 +277,30 @@ class RadioThermostat(ClimateDevice): temperature = round_temp(temperature) if self._current_operation == STATE_COOL: - self.device.t_cool = temperature + self._device.t_cool = temperature elif self._current_operation == STATE_HEAT: - self.device.t_heat = temperature + self._device.t_heat = temperature elif self._current_operation == STATE_AUTO: if self._tstate == STATE_COOL: - self.device.t_cool = temperature + self._device.t_cool = temperature elif self._tstate == STATE_HEAT: - self.device.t_heat = temperature + self._device.t_heat = temperature # Only change the hold if requested or if hold mode was turned # on and we haven't set it yet. if kwargs.get('hold_changed', False) or not self._hold_set: if self._hold_temp or self._away: - self.device.hold = 1 + self._device.hold = 1 self._hold_set = True else: - self.device.hold = 0 + self._device.hold = 0 def set_time(self): """Set device time.""" # Calling this clears any local temperature override and # reverts to the scheduled temperature. now = datetime.datetime.now() - self.device.time = { + self._device.time = { 'day': now.weekday(), 'hour': now.hour, 'minute': now.minute @@ -309,13 +309,13 @@ class RadioThermostat(ClimateDevice): def set_operation_mode(self, operation_mode): """Set operation mode (auto, cool, heat, off).""" if operation_mode in (STATE_OFF, STATE_AUTO): - self.device.tmode = TEMP_MODE_TO_CODE[operation_mode] + self._device.tmode = TEMP_MODE_TO_CODE[operation_mode] # Setting t_cool or t_heat automatically changes tmode. elif operation_mode == STATE_COOL: - self.device.t_cool = self._target_temperature + self._device.t_cool = self._target_temperature elif operation_mode == STATE_HEAT: - self.device.t_heat = self._target_temperature + self._device.t_heat = self._target_temperature def turn_away_mode_on(self): """Turn away on. diff --git a/homeassistant/components/cover/knx.py b/homeassistant/components/cover/knx.py index 7bb20e4cf1f..59195d73a2f 100644 --- a/homeassistant/components/cover/knx.py +++ b/homeassistant/components/cover/knx.py @@ -96,7 +96,7 @@ class KNXCover(CoverDevice): def __init__(self, hass, device): """Initialize the cover.""" - self.device = device + self._device = device self.hass = hass self.async_register_callbacks() @@ -108,12 +108,12 @@ class KNXCover(CoverDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self.device.register_device_updated_cb(after_update_callback) + self._device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self.device.name + return self._device.name @property def available(self): @@ -130,56 +130,56 @@ class KNXCover(CoverDevice): """Flag supported features.""" supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | \ SUPPORT_SET_POSITION | SUPPORT_STOP - if self.device.supports_angle: + if self._device.supports_angle: supported_features |= SUPPORT_SET_TILT_POSITION return supported_features @property def current_cover_position(self): """Return the current position of the cover.""" - return self.device.current_position() + return self._device.current_position() @property def is_closed(self): """Return if the cover is closed.""" - return self.device.is_closed() + return self._device.is_closed() async def async_close_cover(self, **kwargs): """Close the cover.""" - if not self.device.is_closed(): - await self.device.set_down() + if not self._device.is_closed(): + await self._device.set_down() self.start_auto_updater() async def async_open_cover(self, **kwargs): """Open the cover.""" - if not self.device.is_open(): - await self.device.set_up() + if not self._device.is_open(): + await self._device.set_up() self.start_auto_updater() async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" if ATTR_POSITION in kwargs: position = kwargs[ATTR_POSITION] - await self.device.set_position(position) + await self._device.set_position(position) self.start_auto_updater() async def async_stop_cover(self, **kwargs): """Stop the cover.""" - await self.device.stop() + await self._device.stop() self.stop_auto_updater() @property def current_cover_tilt_position(self): """Return current tilt position of cover.""" - if not self.device.supports_angle: + if not self._device.supports_angle: return None - return self.device.current_angle() + return self._device.current_angle() async def async_set_cover_tilt_position(self, **kwargs): """Move the cover tilt to a specific position.""" if ATTR_TILT_POSITION in kwargs: tilt_position = kwargs[ATTR_TILT_POSITION] - await self.device.set_angle(tilt_position) + await self._device.set_angle(tilt_position) def start_auto_updater(self): """Start the autoupdater to update HASS while cover is moving.""" @@ -197,7 +197,7 @@ class KNXCover(CoverDevice): def auto_updater_hook(self, now): """Call for the autoupdater.""" self.async_schedule_update_ha_state() - if self.device.position_reached(): + if self._device.position_reached(): self.stop_auto_updater() - self.hass.add_job(self.device.auto_stop_if_necessary()) + self.hass.add_job(self._device.auto_stop_if_necessary()) diff --git a/homeassistant/components/cover/tellduslive.py b/homeassistant/components/cover/tellduslive.py index 4a78cb96d06..b4bde037a12 100644 --- a/homeassistant/components/cover/tellduslive.py +++ b/homeassistant/components/cover/tellduslive.py @@ -28,19 +28,19 @@ class TelldusLiveCover(TelldusLiveEntity, CoverDevice): @property def is_closed(self): """Return the current position of the cover.""" - return self.device.is_down + return self._device.is_down def close_cover(self, **kwargs): """Close the cover.""" - self.device.down() + self._device.down() self.changed() def open_cover(self, **kwargs): """Open the cover.""" - self.device.up() + self._device.up() self.changed() def stop_cover(self, **kwargs): """Stop the cover.""" - self.device.stop() + self._device.stop() self.changed() diff --git a/homeassistant/components/juicenet.py b/homeassistant/components/juicenet.py index 55567d45879..2ed32521f1d 100644 --- a/homeassistant/components/juicenet.py +++ b/homeassistant/components/juicenet.py @@ -46,29 +46,29 @@ class JuicenetDevice(Entity): def __init__(self, device, sensor_type, hass): """Initialise the sensor.""" self.hass = hass - self.device = device + self._device = device self.type = sensor_type @property def name(self): """Return the name of the device.""" - return self.device.name() + return self._device.name() def update(self): """Update state of the device.""" - self.device.update_state() + self._device.update_state() @property def _manufacturer_device_id(self): """Return the manufacturer device id.""" - return self.device.id() + return self._device.id() @property def _token(self): """Return the device API token.""" - return self.device.token() + return self._device.token() @property def unique_id(self): """Return a unique ID.""" - return "{}-{}".format(self.device.id(), self.type) + return "{}-{}".format(self._device.id(), self.type) diff --git a/homeassistant/components/light/knx.py b/homeassistant/components/light/knx.py index 8fa2b56d1d2..ee8389fbb71 100644 --- a/homeassistant/components/light/knx.py +++ b/homeassistant/components/light/knx.py @@ -79,7 +79,7 @@ class KNXLight(Light): def __init__(self, hass, device): """Initialize of KNX light.""" - self.device = device + self._device = device self.hass = hass self.async_register_callbacks() @@ -89,12 +89,12 @@ class KNXLight(Light): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self.device.register_device_updated_cb(after_update_callback) + self._device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self.device.name + return self._device.name @property def available(self): @@ -109,15 +109,15 @@ class KNXLight(Light): @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self.device.current_brightness \ - if self.device.supports_brightness else \ + return self._device.current_brightness \ + if self._device.supports_brightness else \ None @property def hs_color(self): """Return the HS color value.""" - if self.device.supports_color: - return color_util.color_RGB_to_hs(*self.device.current_color) + if self._device.supports_color: + return color_util.color_RGB_to_hs(*self._device.current_color) return None @property @@ -143,30 +143,30 @@ class KNXLight(Light): @property def is_on(self): """Return true if light is on.""" - return self.device.state + return self._device.state @property def supported_features(self): """Flag supported features.""" flags = 0 - if self.device.supports_brightness: + if self._device.supports_brightness: flags |= SUPPORT_BRIGHTNESS - if self.device.supports_color: + if self._device.supports_color: flags |= SUPPORT_COLOR return flags async def async_turn_on(self, **kwargs): """Turn the light on.""" if ATTR_BRIGHTNESS in kwargs: - if self.device.supports_brightness: - await self.device.set_brightness(int(kwargs[ATTR_BRIGHTNESS])) + if self._device.supports_brightness: + await self._device.set_brightness(int(kwargs[ATTR_BRIGHTNESS])) elif ATTR_HS_COLOR in kwargs: - if self.device.supports_color: - await self.device.set_color(color_util.color_hs_to_RGB( + if self._device.supports_color: + await self._device.set_color(color_util.color_hs_to_RGB( *kwargs[ATTR_HS_COLOR])) else: - await self.device.set_on() + await self._device.set_on() async def async_turn_off(self, **kwargs): """Turn the light off.""" - await self.device.set_off() + await self._device.set_off() diff --git a/homeassistant/components/light/lifx.py b/homeassistant/components/light/lifx.py index 3738fd8f004..8547d7a985d 100644 --- a/homeassistant/components/light/lifx.py +++ b/homeassistant/components/light/lifx.py @@ -389,7 +389,7 @@ class LIFXLight(Light): def __init__(self, device, effects_conductor): """Initialize the light.""" - self.device = device + self.light = device self.effects_conductor = effects_conductor self.registered = True self.postponed_update = None @@ -403,28 +403,28 @@ class LIFXLight(Light): @property def unique_id(self): """Return a unique ID.""" - return self.device.mac_addr + return self.light.mac_addr @property def name(self): """Return the name of the device.""" - return self.device.label + return self.light.label @property def who(self): """Return a string identifying the device.""" - return "%s (%s)" % (self.device.ip_addr, self.name) + return "%s (%s)" % (self.light.ip_addr, self.name) @property def min_mireds(self): """Return the coldest color_temp that this light supports.""" - kelvin = lifx_features(self.device)['max_kelvin'] + kelvin = lifx_features(self.light)['max_kelvin'] 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.""" - kelvin = lifx_features(self.device)['min_kelvin'] + kelvin = lifx_features(self.light)['min_kelvin'] return math.ceil(color_util.color_temperature_kelvin_to_mired(kelvin)) @property @@ -432,7 +432,7 @@ class LIFXLight(Light): """Flag supported features.""" support = SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION | SUPPORT_EFFECT - device_features = lifx_features(self.device) + device_features = lifx_features(self.light) if device_features['min_kelvin'] != device_features['max_kelvin']: support |= SUPPORT_COLOR_TEMP @@ -441,12 +441,12 @@ class LIFXLight(Light): @property def brightness(self): """Return the brightness of this light between 0..255.""" - return convert_16_to_8(self.device.color[2]) + return convert_16_to_8(self.light.color[2]) @property def color_temp(self): """Return the color temperature.""" - _, sat, _, kelvin = self.device.color + _, sat, _, kelvin = self.light.color if sat: return None return color_util.color_temperature_kelvin_to_mired(kelvin) @@ -454,12 +454,12 @@ class LIFXLight(Light): @property def is_on(self): """Return true if device is on.""" - return self.device.power_level != 0 + return self.light.power_level != 0 @property def effect(self): """Return the name of the currently running effect.""" - effect = self.effects_conductor.effect(self.device) + effect = self.effects_conductor.effect(self.light) if effect: return 'lifx_effect_' + effect.name return None @@ -497,7 +497,7 @@ class LIFXLight(Light): async def set_state(self, **kwargs): """Set a color on the light and turn it on/off.""" async with self.lock: - bulb = self.device + bulb = self.light await self.effects_conductor.stop([bulb]) @@ -545,12 +545,12 @@ class LIFXLight(Light): async def set_power(self, ack, pwr, duration=0): """Send a power change to the device.""" - await ack(partial(self.device.set_power, pwr, duration=duration)) + await ack(partial(self.light.set_power, pwr, duration=duration)) async def set_color(self, ack, hsbk, kwargs, duration=0): """Send a color change to the device.""" - hsbk = merge_hsbk(self.device.color, hsbk) - await ack(partial(self.device.set_color, hsbk, duration=duration)) + hsbk = merge_hsbk(self.light.color, hsbk) + await ack(partial(self.light.set_color, hsbk, duration=duration)) async def default_effect(self, **kwargs): """Start an effect with default parameters.""" @@ -563,7 +563,7 @@ class LIFXLight(Light): async def async_update(self): """Update bulb status.""" if self.available and not self.lock.locked(): - await AwaitAioLIFX().wait(self.device.get_color) + await AwaitAioLIFX().wait(self.light.get_color) class LIFXWhite(LIFXLight): @@ -600,7 +600,7 @@ class LIFXColor(LIFXLight): @property def hs_color(self): """Return the hs value.""" - hue, sat, _, _ = self.device.color + hue, sat, _, _ = self.light.color hue = hue / 65535 * 360 sat = sat / 65535 * 100 return (hue, sat) if sat else None @@ -611,7 +611,7 @@ class LIFXStrip(LIFXColor): async def set_color(self, ack, hsbk, kwargs, duration=0): """Send a color change to the device.""" - bulb = self.device + bulb = self.light num_zones = len(bulb.color_zones) zones = kwargs.get(ATTR_ZONES) @@ -659,7 +659,7 @@ class LIFXStrip(LIFXColor): while self.available and zone < top: # Each get_color_zones can update 8 zones at once resp = await AwaitAioLIFX().wait(partial( - self.device.get_color_zones, + self.light.get_color_zones, start_index=zone)) if resp: zone += 8 diff --git a/homeassistant/components/light/mochad.py b/homeassistant/components/light/mochad.py index 576e244103f..4aeb2c2c79b 100644 --- a/homeassistant/components/light/mochad.py +++ b/homeassistant/components/light/mochad.py @@ -54,8 +54,8 @@ class MochadLight(Light): self._name = dev.get(CONF_NAME, 'x10_light_dev_{}'.format(self._address)) self._comm_type = dev.get(mochad.CONF_COMM_TYPE, 'pl') - self.device = device.Device(ctrl, self._address, - comm_type=self._comm_type) + self.light = device.Device(ctrl, self._address, + comm_type=self._comm_type) self._brightness = 0 self._state = self._get_device_status() self._brightness_levels = dev.get(CONF_BRIGHTNESS_LEVELS) - 1 @@ -68,7 +68,7 @@ class MochadLight(Light): def _get_device_status(self): """Get the status of the light from mochad.""" with mochad.REQ_LOCK: - status = self.device.get_status().rstrip() + status = self.light.get_status().rstrip() return status == 'on' @property @@ -98,12 +98,12 @@ class MochadLight(Light): if self._brightness > brightness: bdelta = self._brightness - brightness mochad_brightness = self._calculate_brightness_value(bdelta) - self.device.send_cmd("dim {}".format(mochad_brightness)) + self.light.send_cmd("dim {}".format(mochad_brightness)) self._controller.read_data() elif self._brightness < brightness: bdelta = brightness - self._brightness mochad_brightness = self._calculate_brightness_value(bdelta) - self.device.send_cmd("bright {}".format(mochad_brightness)) + self.light.send_cmd("bright {}".format(mochad_brightness)) self._controller.read_data() def turn_on(self, **kwargs): @@ -112,10 +112,10 @@ class MochadLight(Light): with mochad.REQ_LOCK: if self._brightness_levels > 32: out_brightness = self._calculate_brightness_value(brightness) - self.device.send_cmd('xdim {}'.format(out_brightness)) + self.light.send_cmd('xdim {}'.format(out_brightness)) self._controller.read_data() else: - self.device.send_cmd("on") + self.light.send_cmd("on") self._controller.read_data() # There is no persistence for X10 modules so a fresh on command # will be full brightness @@ -128,7 +128,7 @@ class MochadLight(Light): def turn_off(self, **kwargs): """Send the command to turn the light on.""" with mochad.REQ_LOCK: - self.device.send_cmd('off') + self.light.send_cmd('off') self._controller.read_data() # There is no persistence for X10 modules so we need to prepare # to track a fresh on command will full brightness diff --git a/homeassistant/components/light/qwikswitch.py b/homeassistant/components/light/qwikswitch.py index 528f4f73c53..9d6e8f9169a 100644 --- a/homeassistant/components/light/qwikswitch.py +++ b/homeassistant/components/light/qwikswitch.py @@ -27,9 +27,9 @@ class QSLight(QSToggleEntity, Light): @property def brightness(self): """Return the brightness of this light (0-255).""" - return self.device.value if self.device.is_dimmer else None + return self._device.value if self._device.is_dimmer else None @property def supported_features(self): """Flag supported features.""" - return SUPPORT_BRIGHTNESS if self.device.is_dimmer else 0 + return SUPPORT_BRIGHTNESS if self._device.is_dimmer else 0 diff --git a/homeassistant/components/light/tellduslive.py b/homeassistant/components/light/tellduslive.py index 321cfd677b5..3908d43f62d 100644 --- a/homeassistant/components/light/tellduslive.py +++ b/homeassistant/components/light/tellduslive.py @@ -38,7 +38,7 @@ class TelldusLiveLight(TelldusLiveEntity, Light): @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self.device.dim_level + return self._device.dim_level @property def supported_features(self): @@ -48,15 +48,15 @@ class TelldusLiveLight(TelldusLiveEntity, Light): @property def is_on(self): """Return true if light is on.""" - return self.device.is_on + return self._device.is_on def turn_on(self, **kwargs): """Turn the light on.""" brightness = kwargs.get(ATTR_BRIGHTNESS, self._last_brightness) - self.device.dim(level=brightness) + self._device.dim(level=brightness) self.changed() def turn_off(self, **kwargs): """Turn the light off.""" - self.device.turn_off() + self._device.turn_off() self.changed() diff --git a/homeassistant/components/light/wemo.py b/homeassistant/components/light/wemo.py index 78dedb12718..f07865473d1 100644 --- a/homeassistant/components/light/wemo.py +++ b/homeassistant/components/light/wemo.py @@ -76,39 +76,39 @@ class WemoLight(Light): def __init__(self, device, update_lights): """Initialize the WeMo light.""" self.light_id = device.name - self.device = device + self.wemo = device self.update_lights = update_lights @property def unique_id(self): """Return the ID of this light.""" - return self.device.uniqueID + return self.wemo.uniqueID @property def name(self): """Return the name of the light.""" - return self.device.name + return self.wemo.name @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self.device.state.get('level', 255) + return self.wemo.state.get('level', 255) @property def hs_color(self): """Return the hs color values of this light.""" - xy_color = self.device.state.get('color_xy') + xy_color = self.wemo.state.get('color_xy') return color_util.color_xy_to_hs(*xy_color) if xy_color else None @property def color_temp(self): """Return the color temperature of this light in mireds.""" - return self.device.state.get('temperature_mireds') + return self.wemo.state.get('temperature_mireds') @property def is_on(self): """Return true if device is on.""" - return self.device.state['onoff'] != 0 + return self.wemo.state['onoff'] != 0 @property def supported_features(self): @@ -118,7 +118,7 @@ class WemoLight(Light): @property def available(self): """Return if light is available.""" - return self.device.state['available'] + return self.wemo.state['available'] def turn_on(self, **kwargs): """Turn the light on.""" @@ -128,23 +128,23 @@ class WemoLight(Light): if hs_color is not None: xy_color = color_util.color_hs_to_xy(*hs_color) - self.device.set_color(xy_color, transition=transitiontime) + self.wemo.set_color(xy_color, transition=transitiontime) if ATTR_COLOR_TEMP in kwargs: colortemp = kwargs[ATTR_COLOR_TEMP] - self.device.set_temperature(mireds=colortemp, - transition=transitiontime) + self.wemo.set_temperature(mireds=colortemp, + transition=transitiontime) if ATTR_BRIGHTNESS in kwargs: brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness or 255) - self.device.turn_on(level=brightness, transition=transitiontime) + self.wemo.turn_on(level=brightness, transition=transitiontime) else: - self.device.turn_on(transition=transitiontime) + self.wemo.turn_on(transition=transitiontime) def turn_off(self, **kwargs): """Turn the light off.""" transitiontime = int(kwargs.get(ATTR_TRANSITION, 0)) - self.device.turn_off(transition=transitiontime) + self.wemo.turn_off(transition=transitiontime) def update(self): """Synchronize state with bridge.""" diff --git a/homeassistant/components/media_player/emby.py b/homeassistant/components/media_player/emby.py index 1dfb19a33be..8dd4ebcb120 100644 --- a/homeassistant/components/media_player/emby.py +++ b/homeassistant/components/media_player/emby.py @@ -132,7 +132,7 @@ class EmbyDevice(MediaPlayerDevice): _LOGGER.debug("New Emby Device initialized with ID: %s", device_id) self.emby = emby self.device_id = device_id - self.device = self.emby.devices[self.device_id] + self._device = self.emby.devices[self.device_id] self._hidden = False self._available = True @@ -150,11 +150,11 @@ class EmbyDevice(MediaPlayerDevice): def async_update_callback(self, msg): """Handle device updates.""" # Check if we should update progress - if self.device.media_position: - if self.device.media_position != self.media_status_last_position: - self.media_status_last_position = self.device.media_position + if self._device.media_position: + if self._device.media_position != self.media_status_last_position: + self.media_status_last_position = self._device.media_position self.media_status_received = dt_util.utcnow() - elif not self.device.is_nowplaying: + elif not self._device.is_nowplaying: # No position, but we have an old value and are still playing self.media_status_last_position = None self.media_status_received = None @@ -187,13 +187,13 @@ class EmbyDevice(MediaPlayerDevice): @property def supports_remote_control(self): """Return control ability.""" - return self.device.supports_remote_control + return self._device.supports_remote_control @property def name(self): """Return the name of the device.""" - return 'Emby - {} - {}'.format(self.device.client, self.device.name) \ - or DEVICE_DEFAULT_NAME + return ('Emby - {} - {}'.format(self._device.client, self._device.name) + or DEVICE_DEFAULT_NAME) @property def should_poll(self): @@ -203,7 +203,7 @@ class EmbyDevice(MediaPlayerDevice): @property def state(self): """Return the state of the device.""" - state = self.device.state + state = self._device.state if state == 'Paused': return STATE_PAUSED if state == 'Playing': @@ -217,17 +217,17 @@ class EmbyDevice(MediaPlayerDevice): def app_name(self): """Return current user as app_name.""" # Ideally the media_player object would have a user property. - return self.device.username + return self._device.username @property def media_content_id(self): """Content ID of current playing media.""" - return self.device.media_id + return self._device.media_id @property def media_content_type(self): """Content type of current playing media.""" - media_type = self.device.media_type + media_type = self._device.media_type if media_type == 'Episode': return MEDIA_TYPE_TVSHOW if media_type == 'Movie': @@ -245,7 +245,7 @@ class EmbyDevice(MediaPlayerDevice): @property def media_duration(self): """Return the duration of current playing media in seconds.""" - return self.device.media_runtime + return self._device.media_runtime @property def media_position(self): @@ -264,42 +264,42 @@ class EmbyDevice(MediaPlayerDevice): @property def media_image_url(self): """Return the image URL of current playing media.""" - return self.device.media_image_url + return self._device.media_image_url @property def media_title(self): """Return the title of current playing media.""" - return self.device.media_title + return self._device.media_title @property def media_season(self): """Season of current playing media (TV Show only).""" - return self.device.media_season + return self._device.media_season @property def media_series_title(self): """Return the title of the series of current playing media (TV).""" - return self.device.media_series_title + return self._device.media_series_title @property def media_episode(self): """Return the episode of current playing media (TV only).""" - return self.device.media_episode + return self._device.media_episode @property def media_album_name(self): """Return the album name of current playing media (Music only).""" - return self.device.media_album_name + return self._device.media_album_name @property def media_artist(self): """Return the artist of current playing media (Music track only).""" - return self.device.media_artist + return self._device.media_artist @property def media_album_artist(self): """Return the album artist of current playing media (Music only).""" - return self.device.media_album_artist + return self._device.media_album_artist @property def supported_features(self): @@ -313,39 +313,39 @@ class EmbyDevice(MediaPlayerDevice): This method must be run in the event loop and returns a coroutine. """ - return self.device.media_play() + return self._device.media_play() def async_media_pause(self): """Pause the media player. This method must be run in the event loop and returns a coroutine. """ - return self.device.media_pause() + return self._device.media_pause() def async_media_stop(self): """Stop the media player. This method must be run in the event loop and returns a coroutine. """ - return self.device.media_stop() + return self._device.media_stop() def async_media_next_track(self): """Send next track command. This method must be run in the event loop and returns a coroutine. """ - return self.device.media_next() + return self._device.media_next() def async_media_previous_track(self): """Send next track command. This method must be run in the event loop and returns a coroutine. """ - return self.device.media_previous() + return self._device.media_previous() def async_media_seek(self, position): """Send seek command. This method must be run in the event loop and returns a coroutine. """ - return self.device.media_seek(position) + return self._device.media_seek(position) diff --git a/homeassistant/components/media_player/plex.py b/homeassistant/components/media_player/plex.py index e3c6f453c35..05947b3d67b 100644 --- a/homeassistant/components/media_player/plex.py +++ b/homeassistant/components/media_player/plex.py @@ -454,7 +454,7 @@ class PlexClient(MediaPlayerDevice): elif self._player_state == 'paused': self._is_player_active = True self._state = STATE_PAUSED - elif self.device: + elif self._device: self._is_player_active = False self._state = STATE_IDLE else: @@ -528,11 +528,6 @@ class PlexClient(MediaPlayerDevice): """Return the library name of playing media.""" return self._app_name - @property - def device(self): - """Return the device, if any.""" - return self._device - @property def marked_unavailable(self): """Return time device was marked unavailable.""" @@ -671,7 +666,7 @@ class PlexClient(MediaPlayerDevice): SUPPORT_TURN_OFF) # Not all devices support playback functionality # Playback includes volume, stop/play/pause, etc. - if self.device and 'playback' in self._device_protocol_capabilities: + if self._device and 'playback' in self._device_protocol_capabilities: return (SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | SUPPORT_STOP | SUPPORT_VOLUME_SET | SUPPORT_PLAY | @@ -681,22 +676,22 @@ class PlexClient(MediaPlayerDevice): def set_volume_level(self, volume): """Set volume level, range 0..1.""" - if self.device and 'playback' in self._device_protocol_capabilities: - self.device.setVolume( + if self._device and 'playback' in self._device_protocol_capabilities: + self._device.setVolume( int(volume * 100), self._active_media_plexapi_type) self._volume_level = volume # store since we can't retrieve @property def volume_level(self): """Return the volume level of the client (0..1).""" - if (self._is_player_active and self.device and + if (self._is_player_active and self._device and 'playback' in self._device_protocol_capabilities): return self._volume_level @property def is_volume_muted(self): """Return boolean if volume is currently muted.""" - if self._is_player_active and self.device: + if self._is_player_active and self._device: return self._volume_muted def mute_volume(self, mute): @@ -706,7 +701,7 @@ class PlexClient(MediaPlayerDevice): - On mute, store volume and set volume to 0 - On unmute, set volume to previously stored volume """ - if not (self.device and + if not (self._device and 'playback' in self._device_protocol_capabilities): return @@ -719,18 +714,18 @@ class PlexClient(MediaPlayerDevice): def media_play(self): """Send play command.""" - if self.device and 'playback' in self._device_protocol_capabilities: - self.device.play(self._active_media_plexapi_type) + if self._device and 'playback' in self._device_protocol_capabilities: + self._device.play(self._active_media_plexapi_type) def media_pause(self): """Send pause command.""" - if self.device and 'playback' in self._device_protocol_capabilities: - self.device.pause(self._active_media_plexapi_type) + if self._device and 'playback' in self._device_protocol_capabilities: + self._device.pause(self._active_media_plexapi_type) def media_stop(self): """Send stop command.""" - if self.device and 'playback' in self._device_protocol_capabilities: - self.device.stop(self._active_media_plexapi_type) + if self._device and 'playback' in self._device_protocol_capabilities: + self._device.stop(self._active_media_plexapi_type) def turn_off(self): """Turn the client off.""" @@ -739,17 +734,17 @@ class PlexClient(MediaPlayerDevice): def media_next_track(self): """Send next track command.""" - if self.device and 'playback' in self._device_protocol_capabilities: - self.device.skipNext(self._active_media_plexapi_type) + if self._device and 'playback' in self._device_protocol_capabilities: + self._device.skipNext(self._active_media_plexapi_type) def media_previous_track(self): """Send previous track command.""" - if self.device and 'playback' in self._device_protocol_capabilities: - self.device.skipPrevious(self._active_media_plexapi_type) + if self._device and 'playback' in self._device_protocol_capabilities: + self._device.skipPrevious(self._active_media_plexapi_type) def play_media(self, media_type, media_id, **kwargs): """Play a piece of media.""" - if not (self.device and + if not (self._device and 'playback' in self._device_protocol_capabilities): return @@ -757,7 +752,7 @@ class PlexClient(MediaPlayerDevice): media = None if media_type == 'MUSIC': - media = self.device.server.library.section( + media = self._device.server.library.section( src['library_name']).get(src['artist_name']).album( src['album_name']).get(src['track_name']) elif media_type == 'EPISODE': @@ -765,9 +760,9 @@ class PlexClient(MediaPlayerDevice): src['library_name'], src['show_name'], src['season_number'], src['episode_number']) elif media_type == 'PLAYLIST': - media = self.device.server.playlist(src['playlist_name']) + media = self._device.server.playlist(src['playlist_name']) elif media_type == 'VIDEO': - media = self.device.server.library.section( + media = self._device.server.library.section( src['library_name']).get(src['video_name']) import plexapi.playlist @@ -785,13 +780,13 @@ class PlexClient(MediaPlayerDevice): target_season = None target_episode = None - show = self.device.server.library.section(library_name).get( + show = self._device.server.library.section(library_name).get( show_name) if not season_number: playlist_name = "{} - {} Episodes".format( self.entity_id, show_name) - return self.device.server.createPlaylist( + return self._device.server.createPlaylist( playlist_name, show.episodes()) for season in show.seasons(): @@ -808,7 +803,7 @@ class PlexClient(MediaPlayerDevice): if not episode_number: playlist_name = "{} - {} Season {} Episodes".format( self.entity_id, show_name, str(season_number)) - return self.device.server.createPlaylist( + return self._device.server.createPlaylist( playlist_name, target_season.episodes()) for episode in target_season.episodes(): @@ -826,22 +821,22 @@ class PlexClient(MediaPlayerDevice): def _client_play_media(self, media, delete=False, **params): """Instruct Plex client to play a piece of media.""" - if not (self.device and + if not (self._device and 'playback' in self._device_protocol_capabilities): _LOGGER.error("Client cannot play media: %s", self.entity_id) return import plexapi.playqueue playqueue = plexapi.playqueue.PlayQueue.create( - self.device.server, media, **params) + self._device.server, media, **params) # Delete dynamic playlists used to build playqueue (ex. play tv season) if delete: media.delete() - server_url = self.device.server.baseurl.split(':') - self.device.sendCommand('playback/playMedia', **dict({ - 'machineIdentifier': self.device.server.machineIdentifier, + server_url = self._device.server.baseurl.split(':') + self._device.sendCommand('playback/playMedia', **dict({ + 'machineIdentifier': self._device.server.machineIdentifier, 'address': server_url[1].strip('/'), 'port': server_url[-1], 'key': media.key, diff --git a/homeassistant/components/media_player/soundtouch.py b/homeassistant/components/media_player/soundtouch.py index 8f14031481a..703c9a963ee 100644 --- a/homeassistant/components/media_player/soundtouch.py +++ b/homeassistant/components/media_player/soundtouch.py @@ -166,11 +166,6 @@ class SoundTouchDevice(MediaPlayerDevice): """Return specific soundtouch configuration.""" return self._config - @property - def device(self): - """Return Soundtouch device.""" - return self._device - def update(self): """Retrieve the latest data.""" self._status = self._device.status() @@ -323,8 +318,8 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to create zone without slaves") else: _LOGGER.info("Creating zone with master %s", - self.device.config.name) - self.device.create_zone([slave.device for slave in slaves]) + self._device.config.name) + self._device.create_zone([slave.device for slave in slaves]) def remove_zone_slave(self, slaves): """ @@ -341,8 +336,8 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to find slaves to remove") else: _LOGGER.info("Removing slaves from zone with master %s", - self.device.config.name) - self.device.remove_zone_slave([slave.device for slave in slaves]) + self._device.config.name) + self._device.remove_zone_slave([slave.device for slave in slaves]) def add_zone_slave(self, slaves): """ @@ -357,5 +352,5 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to find slaves to add") else: _LOGGER.info("Adding slaves to zone with master %s", - self.device.config.name) - self.device.add_zone_slave([slave.device for slave in slaves]) + self._device.config.name) + self._device.add_zone_slave([slave.device for slave in slaves]) diff --git a/homeassistant/components/nest/__init__.py b/homeassistant/components/nest/__init__.py index 57111350396..04163f1ca13 100644 --- a/homeassistant/components/nest/__init__.py +++ b/homeassistant/components/nest/__init__.py @@ -282,12 +282,12 @@ class NestSensorDevice(Entity): if device is not None: # device specific - self.device = device - self._name = "{} {}".format(self.device.name_long, + self._device = device + self._name = "{} {}".format(self._device.name_long, self.variable.replace('_', ' ')) else: # structure only - self.device = structure + self._device = structure self._name = "{} {}".format(self.structure.name, self.variable.replace('_', ' ')) diff --git a/homeassistant/components/notify/knx.py b/homeassistant/components/notify/knx.py index 750e3945569..f9a6a4b25f2 100644 --- a/homeassistant/components/notify/knx.py +++ b/homeassistant/components/notify/knx.py @@ -61,13 +61,13 @@ class KNXNotificationService(BaseNotificationService): def __init__(self, devices): """Initialize the service.""" - self.devices = devices + self._devices = devices @property def targets(self): """Return a dictionary of registered targets.""" ret = {} - for device in self.devices: + for device in self._devices: ret[device.name] = device.name return ret @@ -80,11 +80,11 @@ class KNXNotificationService(BaseNotificationService): async def _async_send_to_all_devices(self, message): """Send a notification to knx bus to all connected devices.""" - for device in self.devices: + for device in self._devices: await device.set(message) async def _async_send_to_device(self, message, names): """Send a notification to knx bus to device with given names.""" - for device in self.devices: + for device in self._devices: if device.name in names: await device.set(message) diff --git a/homeassistant/components/qwikswitch.py b/homeassistant/components/qwikswitch.py index 63e30a9491e..8af0e8db28d 100644 --- a/homeassistant/components/qwikswitch.py +++ b/homeassistant/components/qwikswitch.py @@ -98,13 +98,13 @@ class QSToggleEntity(QSEntity): def __init__(self, qsid, qsusb): """Initialize the ToggleEntity.""" - self.device = qsusb.devices[qsid] - super().__init__(qsid, self.device.name) + self._device = qsusb.devices[qsid] + super().__init__(qsid, self._device.name) @property def is_on(self): """Check if device is on (non-zero).""" - return self.device.value > 0 + return self._device.value > 0 async def async_turn_on(self, **kwargs): """Turn the device on.""" diff --git a/homeassistant/components/remote/xiaomi_miio.py b/homeassistant/components/remote/xiaomi_miio.py index 0375226adec..caab75bc841 100644 --- a/homeassistant/components/remote/xiaomi_miio.py +++ b/homeassistant/components/remote/xiaomi_miio.py @@ -187,11 +187,6 @@ class XiaomiMiioRemote(RemoteDevice): """Return the name of the remote.""" return self._name - @property - def device(self): - """Return the remote object.""" - return self._device - @property def hidden(self): """Return if we should hide entity.""" @@ -212,7 +207,7 @@ class XiaomiMiioRemote(RemoteDevice): """Return False if device is unreachable, else True.""" from miio import DeviceException try: - self.device.info() + self._device.info() return True except DeviceException: return False @@ -247,7 +242,7 @@ class XiaomiMiioRemote(RemoteDevice): _LOGGER.debug("Sending payload: '%s'", payload) try: - self.device.play(payload) + self._device.play(payload) except DeviceException as ex: _LOGGER.error( "Transmit of IR command failed, %s, exception: %s", diff --git a/homeassistant/components/sensor/juicenet.py b/homeassistant/components/sensor/juicenet.py index 0d305ca23c7..033e2d7acad 100644 --- a/homeassistant/components/sensor/juicenet.py +++ b/homeassistant/components/sensor/juicenet.py @@ -49,14 +49,14 @@ class JuicenetSensorDevice(JuicenetDevice, Entity): @property def name(self): """Return the name of the device.""" - return '{} {}'.format(self.device.name(), self._name) + return '{} {}'.format(self._device.name(), self._name) @property def icon(self): """Return the icon of the sensor.""" icon = None if self.type == 'status': - status = self.device.getStatus() + status = self._device.getStatus() if status == 'standby': icon = 'mdi:power-plug-off' elif status == 'plugged': @@ -87,19 +87,19 @@ class JuicenetSensorDevice(JuicenetDevice, Entity): """Return the state.""" state = None if self.type == 'status': - state = self.device.getStatus() + state = self._device.getStatus() elif self.type == 'temperature': - state = self.device.getTemperature() + state = self._device.getTemperature() elif self.type == 'voltage': - state = self.device.getVoltage() + state = self._device.getVoltage() elif self.type == 'amps': - state = self.device.getAmps() + state = self._device.getAmps() elif self.type == 'watts': - state = self.device.getWatts() + state = self._device.getWatts() elif self.type == 'charge_time': - state = self.device.getChargeTime() + state = self._device.getChargeTime() elif self.type == 'energy_added': - state = self.device.getEnergyAdded() + state = self._device.getEnergyAdded() else: state = 'Unknown' return state @@ -109,7 +109,7 @@ class JuicenetSensorDevice(JuicenetDevice, Entity): """Return the state attributes.""" attributes = {} if self.type == 'status': - man_dev_id = self.device.id() + man_dev_id = self._device.id() if man_dev_id: attributes["manufacturer_device_id"] = man_dev_id return attributes diff --git a/homeassistant/components/sensor/knx.py b/homeassistant/components/sensor/knx.py index 925b16cb4c7..b4d1f6653c0 100644 --- a/homeassistant/components/sensor/knx.py +++ b/homeassistant/components/sensor/knx.py @@ -64,7 +64,7 @@ class KNXSensor(Entity): def __init__(self, hass, device): """Initialize of a KNX sensor.""" - self.device = device + self._device = device self.hass = hass self.async_register_callbacks() @@ -74,12 +74,12 @@ class KNXSensor(Entity): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self.device.register_device_updated_cb(after_update_callback) + self._device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self.device.name + return self._device.name @property def available(self): @@ -94,12 +94,12 @@ class KNXSensor(Entity): @property def state(self): """Return the state of the sensor.""" - return self.device.resolve_state() + return self._device.resolve_state() @property def unit_of_measurement(self): """Return the unit this state is expressed in.""" - return self.device.unit_of_measurement() + return self._device.unit_of_measurement() @property def device_state_attributes(self): diff --git a/homeassistant/components/sensor/nest.py b/homeassistant/components/sensor/nest.py index d2e1501ad7e..bb1f3e67d4d 100644 --- a/homeassistant/components/sensor/nest.py +++ b/homeassistant/components/sensor/nest.py @@ -140,15 +140,15 @@ class NestBasicSensor(NestSensorDevice): self._unit = SENSOR_UNITS.get(self.variable) if self.variable in VARIABLE_NAME_MAPPING: - self._state = getattr(self.device, + self._state = getattr(self._device, VARIABLE_NAME_MAPPING[self.variable]) elif self.variable in PROTECT_SENSOR_TYPES \ and self.variable != 'color_status': # keep backward compatibility - state = getattr(self.device, self.variable) + state = getattr(self._device, self.variable) self._state = state.capitalize() if state is not None else None else: - self._state = getattr(self.device, self.variable) + self._state = getattr(self._device, self.variable) class NestTempSensor(NestSensorDevice): @@ -166,12 +166,12 @@ class NestTempSensor(NestSensorDevice): def update(self): """Retrieve latest state.""" - if self.device.temperature_scale == 'C': + if self._device.temperature_scale == 'C': self._unit = TEMP_CELSIUS else: self._unit = TEMP_FAHRENHEIT - temp = getattr(self.device, self.variable) + temp = getattr(self._device, self.variable) if temp is None: self._state = None diff --git a/homeassistant/components/sensor/tank_utility.py b/homeassistant/components/sensor/tank_utility.py index 01ace415159..1f565d44325 100644 --- a/homeassistant/components/sensor/tank_utility.py +++ b/homeassistant/components/sensor/tank_utility.py @@ -79,15 +79,10 @@ class TankUtilitySensor(Entity): self._token = token self._device = device self._state = STATE_UNKNOWN - self._name = "Tank Utility " + self.device + self._name = "Tank Utility " + self._device self._unit_of_measurement = SENSOR_UNIT_OF_MEASUREMENT self._attributes = {} - @property - def device(self): - """Return the device identifier.""" - return self._device - @property def state(self): """Return the state of the device.""" @@ -117,14 +112,14 @@ class TankUtilitySensor(Entity): from tank_utility import auth, device data = {} try: - data = device.get_device_data(self._token, self.device) + data = device.get_device_data(self._token, self._device) except requests.exceptions.HTTPError as http_error: if (http_error.response.status_code == requests.codes.unauthorized): # pylint: disable=no-member _LOGGER.info("Getting new token") self._token = auth.get_token(self._email, self._password, force=True) - data = device.get_device_data(self._token, self.device) + data = device.get_device_data(self._token, self._device) else: raise http_error data.update(data.pop("device", {})) diff --git a/homeassistant/components/sensor/tellduslive.py b/homeassistant/components/sensor/tellduslive.py index 123c11021b4..9d5a21b37c4 100644 --- a/homeassistant/components/sensor/tellduslive.py +++ b/homeassistant/components/sensor/tellduslive.py @@ -67,7 +67,7 @@ class TelldusLiveSensor(TelldusLiveEntity): @property def _value(self): """Return value of the sensor.""" - return self.device.value(*self._id[1:]) + return self._device.value(*self._id[1:]) @property def _value_as_temperature(self): diff --git a/homeassistant/components/switch/knx.py b/homeassistant/components/switch/knx.py index c13631ca5e6..4e0b29301fb 100644 --- a/homeassistant/components/switch/knx.py +++ b/homeassistant/components/switch/knx.py @@ -63,7 +63,7 @@ class KNXSwitch(SwitchDevice): def __init__(self, hass, device): """Initialize of KNX switch.""" - self.device = device + self._device = device self.hass = hass self.async_register_callbacks() @@ -73,12 +73,12 @@ class KNXSwitch(SwitchDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self.device.register_device_updated_cb(after_update_callback) + self._device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self.device.name + return self._device.name @property def available(self): @@ -93,12 +93,12 @@ class KNXSwitch(SwitchDevice): @property def is_on(self): """Return true if device is on.""" - return self.device.state + return self._device.state async def async_turn_on(self, **kwargs): """Turn the device on.""" - await self.device.set_on() + await self._device.set_on() async def async_turn_off(self, **kwargs): """Turn the device off.""" - await self.device.set_off() + await self._device.set_off() diff --git a/homeassistant/components/switch/mochad.py b/homeassistant/components/switch/mochad.py index f80784271c2..bb3b9c0ea65 100644 --- a/homeassistant/components/switch/mochad.py +++ b/homeassistant/components/switch/mochad.py @@ -48,7 +48,7 @@ class MochadSwitch(SwitchDevice): self._address = dev[CONF_ADDRESS] self._name = dev.get(CONF_NAME, 'x10_switch_dev_%s' % self._address) self._comm_type = dev.get(mochad.CONF_COMM_TYPE, 'pl') - self.device = device.Device(ctrl, self._address, + self.switch = device.Device(ctrl, self._address, comm_type=self._comm_type) # Init with false to avoid locking HA for long on CM19A (goes from rf # to pl via TM751, but not other way around) @@ -71,7 +71,7 @@ class MochadSwitch(SwitchDevice): try: # Recycle socket on new command to recover mochad connection self._controller.reconnect() - self.device.send_cmd('on') + self.switch.send_cmd('on') # No read data on CM19A which is rf only if self._comm_type == 'pl': self._controller.read_data() @@ -88,7 +88,7 @@ class MochadSwitch(SwitchDevice): try: # Recycle socket on new command to recover mochad connection self._controller.reconnect() - self.device.send_cmd('off') + self.switch.send_cmd('off') # No read data on CM19A which is rf only if self._comm_type == 'pl': self._controller.read_data() @@ -99,7 +99,7 @@ class MochadSwitch(SwitchDevice): def _get_device_status(self): """Get the status of the switch from mochad.""" with mochad.REQ_LOCK: - status = self.device.get_status().rstrip() + status = self.switch.get_status().rstrip() return status == 'on' @property diff --git a/homeassistant/components/switch/tellduslive.py b/homeassistant/components/switch/tellduslive.py index eec63ebaa5c..ac2b569f81c 100644 --- a/homeassistant/components/switch/tellduslive.py +++ b/homeassistant/components/switch/tellduslive.py @@ -28,14 +28,14 @@ class TelldusLiveSwitch(TelldusLiveEntity, ToggleEntity): @property def is_on(self): """Return true if switch is on.""" - return self.device.is_on + return self._device.is_on def turn_on(self, **kwargs): """Turn the switch on.""" - self.device.turn_on() + self._device.turn_on() self.changed() def turn_off(self, **kwargs): """Turn the switch off.""" - self.device.turn_off() + self._device.turn_off() self.changed() diff --git a/homeassistant/components/tellduslive.py b/homeassistant/components/tellduslive.py index c2b7ba9ba0f..58be267bbbc 100644 --- a/homeassistant/components/tellduslive.py +++ b/homeassistant/components/tellduslive.py @@ -287,13 +287,14 @@ class TelldusLiveEntity(Entity): self._id = device_id self._client = hass.data[DOMAIN] self._client.entities.append(self) - self._name = self.device.name + self._device = self._client.device(device_id) + self._name = self._device.name _LOGGER.debug('Created device %s', self) def changed(self): """Return the property of the device might have changed.""" - if self.device.name: - self._name = self.device.name + if self._device.name: + self._name = self._device.name self.schedule_update_ha_state() @property @@ -301,15 +302,10 @@ class TelldusLiveEntity(Entity): """Return the id of the device.""" return self._id - @property - def device(self): - """Return the representation of the device.""" - return self._client.device(self.device_id) - @property def _state(self): """Return the state of the device.""" - return self.device.state + return self._device.state @property def should_poll(self): @@ -347,16 +343,16 @@ class TelldusLiveEntity(Entity): from tellduslive import (BATTERY_LOW, BATTERY_UNKNOWN, BATTERY_OK) - if self.device.battery == BATTERY_LOW: + if self._device.battery == BATTERY_LOW: return 1 - if self.device.battery == BATTERY_UNKNOWN: + if self._device.battery == BATTERY_UNKNOWN: return None - if self.device.battery == BATTERY_OK: + if self._device.battery == BATTERY_OK: return 100 - return self.device.battery # Percentage + return self._device.battery # Percentage @property def _last_updated(self): """Return the last update of a device.""" - return str(datetime.fromtimestamp(self.device.lastUpdated)) \ - if self.device.lastUpdated else None + return str(datetime.fromtimestamp(self._device.lastUpdated)) \ + if self._device.lastUpdated else None diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py new file mode 100644 index 00000000000..78b38afa438 --- /dev/null +++ b/homeassistant/helpers/device_registry.py @@ -0,0 +1,121 @@ +"""Provide a way to connect entities belonging to one device.""" +import logging +import uuid + +import attr + +from homeassistant.core import callback +from homeassistant.loader import bind_hass + +_LOGGER = logging.getLogger(__name__) + +DATA_REGISTRY = 'device_registry' + +STORAGE_KEY = 'core.device_registry' +STORAGE_VERSION = 1 +SAVE_DELAY = 10 + + +@attr.s(slots=True, frozen=True) +class DeviceEntry: + """Device Registry Entry.""" + + identifiers = attr.ib(type=list) + manufacturer = attr.ib(type=str) + model = attr.ib(type=str) + connection = attr.ib(type=list) + name = attr.ib(type=str, default=None) + sw_version = attr.ib(type=str, default=None) + id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex)) + + +class DeviceRegistry: + """Class to hold a registry of devices.""" + + def __init__(self, hass): + """Initialize the device registry.""" + self.hass = hass + self.devices = None + self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) + + @callback + def async_get_device(self, identifiers: str, connections: tuple): + """Check if device is registered.""" + for device in self.devices: + if any(iden in device.identifiers for iden in identifiers) or \ + any(conn in device.connection for conn in connections): + return device + return None + + @callback + def async_get_or_create(self, identifiers, manufacturer, model, + connection, *, name=None, sw_version=None): + """Get device. Create if it doesn't exist.""" + device = self.async_get_device(identifiers, connection) + + if device is not None: + return device + + device = DeviceEntry( + identifiers=identifiers, + manufacturer=manufacturer, + model=model, + connection=connection, + name=name, + sw_version=sw_version + ) + + self.devices.append(device) + self.async_schedule_save() + + return device + + async def async_load(self): + """Load the device registry.""" + devices = await self._store.async_load() + + if devices is None: + self.devices = [] + return + + self.devices = [DeviceEntry(**device) for device in devices['devices']] + + @callback + def async_schedule_save(self): + """Schedule saving the device registry.""" + self._store.async_delay_save(self._data_to_save, SAVE_DELAY) + + @callback + def _data_to_save(self): + """Data of device registry to store in a file.""" + data = {} + + data['devices'] = [ + { + 'id': entry.id, + 'identifiers': entry.identifiers, + 'manufacturer': entry.manufacturer, + 'model': entry.model, + 'connection': entry.connection, + 'name': entry.name, + 'sw_version': entry.sw_version, + } for entry in self.devices + ] + + return data + + +@bind_hass +async def async_get_registry(hass) -> DeviceRegistry: + """Return device registry instance.""" + task = hass.data.get(DATA_REGISTRY) + + if task is None: + async def _load_reg(): + registry = DeviceRegistry(hass) + await registry.async_load() + return registry + + task = hass.data[DATA_REGISTRY] = hass.async_create_task(_load_reg()) + + return await task diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index f27a387b9ee..6d7392d00bf 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -130,6 +130,14 @@ class Entity: """ return None + @property + def device(self): + """Return device specific attributes. + + Implemented by platform classes. + """ + return None + @property def device_class(self) -> str: """Return the class of this device, from component DEVICE_CLASSES.""" diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index bda3db7ebd9..fa880b014ec 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -8,7 +8,6 @@ from homeassistant.util.async_ import ( run_callback_threadsafe, run_coroutine_threadsafe) from .event import async_track_time_interval, async_call_later -from .entity_registry import async_get_registry SLOW_SETUP_WARNING = 10 SLOW_SETUP_MAX_WAIT = 60 @@ -209,11 +208,14 @@ class EntityPlatform: hass = self.hass component_entities = set(hass.states.async_entity_ids(self.domain)) - registry = await async_get_registry(hass) - + device_registry = await \ + hass.helpers.device_registry.async_get_registry() + entity_registry = await \ + hass.helpers.entity_registry.async_get_registry() tasks = [ self._async_add_entity(entity, update_before_add, - component_entities, registry) + component_entities, entity_registry, + device_registry) for entity in new_entities] # No entities for processing @@ -233,7 +235,8 @@ class EntityPlatform: ) async def _async_add_entity(self, entity, update_before_add, - component_entities, registry): + component_entities, entity_registry, + device_registry): """Helper method to add an entity to the platform.""" if entity is None: raise ValueError('Entity cannot be None') @@ -269,10 +272,21 @@ class EntityPlatform: else: config_entry_id = None - entry = registry.async_get_or_create( + device = entity.device + if device is not None: + device = device_registry.async_get_or_create( + device['identifiers'], device['manufacturer'], + device['model'], device['connection'], + sw_version=device.get('sw_version')) + device_id = device.id + else: + device_id = None + + entry = entity_registry.async_get_or_create( self.domain, self.platform_name, entity.unique_id, suggested_object_id=suggested_object_id, - config_entry_id=config_entry_id) + config_entry_id=config_entry_id, + device_id=device_id) if entry.disabled: self.logger.info( @@ -288,7 +302,7 @@ class EntityPlatform: # We won't generate an entity ID if the platform has already set one # We will however make sure that platform cannot pick a registered ID elif (entity.entity_id is not None and - registry.async_is_registered(entity.entity_id)): + entity_registry.async_is_registered(entity.entity_id)): # If entity already registered, convert entity id to suggestion suggested_object_id = split_entity_id(entity.entity_id)[1] entity.entity_id = None @@ -302,7 +316,7 @@ class EntityPlatform: suggested_object_id = '{} {}'.format(self.entity_namespace, suggested_object_id) - entity.entity_id = registry.async_generate_entity_id( + entity.entity_id = entity_registry.async_generate_entity_id( self.domain, suggested_object_id) # Make sure it is valid in case an entity set the value themselves diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 285d4cbd23a..9c478b0b848 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -39,6 +39,7 @@ class RegistryEntry: unique_id = attr.ib(type=str) platform = attr.ib(type=str) name = attr.ib(type=str, default=None) + device_id = attr.ib(type=str, default=None) config_entry_id = attr.ib(type=str, default=None) disabled_by = attr.ib( type=str, default=None, @@ -107,7 +108,8 @@ class EntityRegistry: @callback def async_get_or_create(self, domain, platform, unique_id, *, - suggested_object_id=None, config_entry_id=None): + suggested_object_id=None, config_entry_id=None, + device_id=None): """Get entity. Create if it doesn't exist.""" entity_id = self.async_get_entity_id(domain, platform, unique_id) if entity_id: @@ -116,7 +118,8 @@ class EntityRegistry: return entry self._async_update_entity( - entity_id, config_entry_id=config_entry_id) + entity_id, config_entry_id=config_entry_id, + device_id=device_id) return self.entities[entity_id] entity_id = self.async_generate_entity_id( @@ -125,6 +128,7 @@ class EntityRegistry: entity = RegistryEntry( entity_id=entity_id, config_entry_id=config_entry_id, + device_id=device_id, unique_id=unique_id, platform=platform, ) @@ -146,7 +150,8 @@ class EntityRegistry: @callback def _async_update_entity(self, entity_id, *, name=_UNDEF, - config_entry_id=_UNDEF, new_entity_id=_UNDEF): + config_entry_id=_UNDEF, new_entity_id=_UNDEF, + device_id=_UNDEF): """Private facing update properties method.""" old = self.entities[entity_id] @@ -159,6 +164,9 @@ class EntityRegistry: config_entry_id != old.config_entry_id): changes['config_entry_id'] = config_entry_id + if (device_id is not _UNDEF and device_id != old.device_id): + changes['device_id'] = device_id + if new_entity_id is not _UNDEF and new_entity_id != old.entity_id: if self.async_is_registered(new_entity_id): raise ValueError('Entity is already registered') @@ -210,6 +218,7 @@ class EntityRegistry: entities[entity['entity_id']] = RegistryEntry( entity_id=entity['entity_id'], config_entry_id=entity.get('config_entry_id'), + device_id=entity.get('device_id'), unique_id=entity['unique_id'], platform=entity['platform'], name=entity.get('name'), @@ -232,6 +241,7 @@ class EntityRegistry: { 'entity_id': entry.entity_id, 'config_entry_id': entry.config_entry_id, + 'device_id': entry.device_id, 'unique_id': entry.unique_id, 'platform': entry.platform, 'name': entry.name, diff --git a/tests/components/light/test_mochad.py b/tests/components/light/test_mochad.py index 68cdffcd999..fa122777ca4 100644 --- a/tests/components/light/test_mochad.py +++ b/tests/components/light/test_mochad.py @@ -76,18 +76,18 @@ class TestMochadLight(unittest.TestCase): def test_turn_on_with_no_brightness(self): """Test turn_on.""" self.light.turn_on() - self.light.device.send_cmd.assert_called_once_with('on') + self.light.light.send_cmd.assert_called_once_with('on') def test_turn_on_with_brightness(self): """Test turn_on.""" self.light.turn_on(brightness=45) - self.light.device.send_cmd.assert_has_calls( + self.light.light.send_cmd.assert_has_calls( [mock.call('on'), mock.call('dim 25')]) def test_turn_off(self): """Test turn_off.""" self.light.turn_off() - self.light.device.send_cmd.assert_called_once_with('off') + self.light.light.send_cmd.assert_called_once_with('off') class TestMochadLight256Levels(unittest.TestCase): @@ -109,17 +109,17 @@ class TestMochadLight256Levels(unittest.TestCase): def test_turn_on_with_no_brightness(self): """Test turn_on.""" self.light.turn_on() - self.light.device.send_cmd.assert_called_once_with('xdim 255') + self.light.light.send_cmd.assert_called_once_with('xdim 255') def test_turn_on_with_brightness(self): """Test turn_on.""" self.light.turn_on(brightness=45) - self.light.device.send_cmd.assert_called_once_with('xdim 45') + self.light.light.send_cmd.assert_called_once_with('xdim 45') def test_turn_off(self): """Test turn_off.""" self.light.turn_off() - self.light.device.send_cmd.assert_called_once_with('off') + self.light.light.send_cmd.assert_called_once_with('off') class TestMochadLight64Levels(unittest.TestCase): @@ -141,14 +141,14 @@ class TestMochadLight64Levels(unittest.TestCase): def test_turn_on_with_no_brightness(self): """Test turn_on.""" self.light.turn_on() - self.light.device.send_cmd.assert_called_once_with('xdim 63') + self.light.light.send_cmd.assert_called_once_with('xdim 63') def test_turn_on_with_brightness(self): """Test turn_on.""" self.light.turn_on(brightness=45) - self.light.device.send_cmd.assert_called_once_with('xdim 11') + self.light.light.send_cmd.assert_called_once_with('xdim 11') def test_turn_off(self): """Test turn_off.""" self.light.turn_off() - self.light.device.send_cmd.assert_called_once_with('off') + self.light.light.send_cmd.assert_called_once_with('off') diff --git a/tests/components/switch/test_mochad.py b/tests/components/switch/test_mochad.py index f241a4b9f61..bfbd67e6b0c 100644 --- a/tests/components/switch/test_mochad.py +++ b/tests/components/switch/test_mochad.py @@ -76,9 +76,9 @@ class TestMochadSwitch(unittest.TestCase): def test_turn_on(self): """Test turn_on.""" self.switch.turn_on() - self.switch.device.send_cmd.assert_called_once_with('on') + self.switch.switch.send_cmd.assert_called_once_with('on') def test_turn_off(self): """Test turn_off.""" self.switch.turn_off() - self.switch.device.send_cmd.assert_called_once_with('off') + self.switch.switch.send_cmd.assert_called_once_with('off') diff --git a/tests/helpers/test_device_registry.py b/tests/helpers/test_device_registry.py new file mode 100644 index 00000000000..41e7d39e977 --- /dev/null +++ b/tests/helpers/test_device_registry.py @@ -0,0 +1,78 @@ +"""Tests for the Device Registry.""" +import pytest + +from homeassistant.helpers import device_registry + + +def mock_registry(hass, mock_entries=None): + """Mock the Device Registry.""" + registry = device_registry.DeviceRegistry(hass) + registry.devices = mock_entries or [] + + async def _get_reg(): + return registry + + hass.data[device_registry.DATA_REGISTRY] = \ + hass.loop.create_task(_get_reg()) + return registry + + +@pytest.fixture +def registry(hass): + """Return an empty, loaded, registry.""" + return mock_registry(hass) + + +async def test_get_or_create_returns_same_entry(registry): + """Make sure we do not duplicate entries.""" + entry = registry.async_get_or_create( + [['bridgeid', '0123']], 'manufacturer', 'model', + [['ethernet', '12:34:56:78:90:AB:CD:EF']]) + entry2 = registry.async_get_or_create( + [['bridgeid', '0123']], 'manufacturer', 'model', + [['ethernet', '11:22:33:44:55:66:77:88']]) + entry3 = registry.async_get_or_create( + [['bridgeid', '1234']], 'manufacturer', 'model', + [['ethernet', '12:34:56:78:90:AB:CD:EF']]) + + assert len(registry.devices) == 1 + assert entry is entry2 + assert entry is entry3 + assert entry.identifiers == [['bridgeid', '0123']] + + +async def test_loading_from_storage(hass, hass_storage): + """Test loading stored devices on start.""" + hass_storage[device_registry.STORAGE_KEY] = { + 'version': device_registry.STORAGE_VERSION, + 'data': { + 'devices': [ + { + 'connection': [ + [ + 'Zigbee', + '01.23.45.67.89' + ] + ], + 'id': 'abcdefghijklm', + 'identifiers': [ + [ + 'serial', + '12:34:56:78:90:AB:CD:EF' + ] + ], + 'manufacturer': 'manufacturer', + 'model': 'model', + 'name': 'name', + 'sw_version': 'version' + } + ] + } + } + + registry = await device_registry.async_get_registry(hass) + + entry = registry.async_get_or_create( + [['serial', '12:34:56:78:90:AB:CD:EF']], 'manufacturer', + 'model', [['Zigbee', '01.23.45.67.89']]) + assert entry.id == 'abcdefghijklm' From 2e6cb2235c29bbed8b8fe29262019de8cf132e2a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 22 Aug 2018 12:17:14 +0200 Subject: [PATCH 099/159] Check correctly if package is loadable (#16121) --- homeassistant/util/package.py | 16 +++++++++++----- tests/util/test_package.py | 30 ++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index 9433046e688..feefa65c0f6 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -32,7 +32,7 @@ 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): + if package_loadable(package): return True _LOGGER.info('Attempting install of %s', package) @@ -61,8 +61,8 @@ def install_package(package: str, upgrade: bool = True, return True -def check_package_exists(package: str) -> bool: - """Check if a package is installed globally or in lib_dir. +def package_loadable(package: str) -> bool: + """Check if a package is what will be loaded when we import it. Returns True when the requirement is met. Returns False when the package is not installed or doesn't meet req. @@ -73,8 +73,14 @@ def check_package_exists(package: str) -> bool: # This is a zip file req = pkg_resources.Requirement.parse(urlparse(package).fragment) - env = pkg_resources.Environment() - return any(dist in req for dist in env[req.project_name]) + for path in sys.path: + for dist in pkg_resources.find_distributions(path): + # If the project name is the same, it will be the one that is + # loaded when we import it. + if dist.project_name == req.project_name: + return dist in req + + return False async def async_get_user_site(deps_dir: str) -> str: diff --git a/tests/util/test_package.py b/tests/util/test_package.py index ab9f9f0ad2c..19e85a094ee 100644 --- a/tests/util/test_package.py +++ b/tests/util/test_package.py @@ -30,8 +30,8 @@ def mock_sys(): @pytest.fixture def mock_exists(): - """Mock check_package_exists.""" - with patch('homeassistant.util.package.check_package_exists') as mock: + """Mock package_loadable.""" + with patch('homeassistant.util.package.package_loadable') as mock: mock.return_value = False yield mock @@ -193,12 +193,12 @@ def test_install_constraint( 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) + assert package.package_loadable(installed_package) def test_check_package_zip(): """Test for an installed zip package.""" - assert not package.check_package_exists(TEST_ZIP_REQ) + assert not package.package_loadable(TEST_ZIP_REQ) @asyncio.coroutine @@ -217,3 +217,25 @@ def test_async_get_user_site(mock_env_copy): stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL, env=env) assert ret == os.path.join(deps_dir, 'lib_dir') + + +def test_package_loadable_installed_twice(): + """Test that a package is loadable when installed twice. + + If a package is installed twice, only the first version will be imported. + Test that package_loadable will only compare with the first package. + """ + v1 = pkg_resources.Distribution(project_name='hello', version='1.0.0') + v2 = pkg_resources.Distribution(project_name='hello', version='2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v1]]): + assert not package.package_loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v1], [v2]]): + assert not package.package_loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v2], [v1]]): + assert package.package_loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v2]]): + assert package.package_loadable('hello==2.0.0') From b0c2d2499791d3d49ad3142b55519686d866217b Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 22 Aug 2018 13:55:11 +0200 Subject: [PATCH 100/159] Upgrade numpy to 1.15.1 (#16126) --- homeassistant/components/binary_sensor/trend.py | 2 +- homeassistant/components/image_processing/opencv.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/binary_sensor/trend.py b/homeassistant/components/binary_sensor/trend.py index 78f471d125b..7165a0dbdf3 100644 --- a/homeassistant/components/binary_sensor/trend.py +++ b/homeassistant/components/binary_sensor/trend.py @@ -23,7 +23,7 @@ from homeassistant.helpers.entity import generate_entity_id from homeassistant.helpers.event import async_track_state_change from homeassistant.util import utcnow -REQUIREMENTS = ['numpy==1.15.0'] +REQUIREMENTS = ['numpy==1.15.1'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/image_processing/opencv.py b/homeassistant/components/image_processing/opencv.py index 00ae01f1123..e21ddbe2597 100644 --- a/homeassistant/components/image_processing/opencv.py +++ b/homeassistant/components/image_processing/opencv.py @@ -16,7 +16,7 @@ from homeassistant.components.image_processing import ( from homeassistant.core import split_entity_id import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['numpy==1.15.0'] +REQUIREMENTS = ['numpy==1.15.1'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 8bd39162d98..ccf5e57adba 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -613,7 +613,7 @@ nuheat==0.3.0 # homeassistant.components.binary_sensor.trend # homeassistant.components.image_processing.opencv -numpy==1.15.0 +numpy==1.15.1 # homeassistant.components.google oauth2client==4.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 73e5aa88e04..167155d688f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -102,7 +102,7 @@ mficlient==0.3.0 # homeassistant.components.binary_sensor.trend # homeassistant.components.image_processing.opencv -numpy==1.15.0 +numpy==1.15.1 # homeassistant.components.mqtt # homeassistant.components.shiftr From d8ae079757c3894f9c87a3b0939848c8716febcc Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 22 Aug 2018 13:55:48 +0200 Subject: [PATCH 101/159] Upgrade youtube_dl to 2018.08.22 (#16125) --- 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 793d33e52fa..8f2abb9be19 100644 --- a/homeassistant/components/media_extractor.py +++ b/homeassistant/components/media_extractor.py @@ -14,7 +14,7 @@ from homeassistant.components.media_player import ( SERVICE_PLAY_MEDIA) from homeassistant.helpers import config_validation as cv -REQUIREMENTS = ['youtube_dl==2018.08.04'] +REQUIREMENTS = ['youtube_dl==2018.08.22'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index ccf5e57adba..3732cb237c2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1489,7 +1489,7 @@ yeelight==0.4.0 yeelightsunflower==0.0.10 # homeassistant.components.media_extractor -youtube_dl==2018.08.04 +youtube_dl==2018.08.22 # homeassistant.components.light.zengge zengge==0.2 From 478eb48e93a44cb417e0b9cf446eb2d4ab28e7cb Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Wed, 22 Aug 2018 15:29:43 +0200 Subject: [PATCH 102/159] Fix the protocol v2 data_key of several aqara devices (#16112) * Fix the protocol v2 data_key of several aqara devices * Incorporate review --- .../components/binary_sensor/xiaomi_aqara.py | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/binary_sensor/xiaomi_aqara.py b/homeassistant/components/binary_sensor/xiaomi_aqara.py index f53d07f2995..c1641c5f1ec 100644 --- a/homeassistant/components/binary_sensor/xiaomi_aqara.py +++ b/homeassistant/components/binary_sensor/xiaomi_aqara.py @@ -28,11 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if model in ['motion', 'sensor_motion', 'sensor_motion.aq2']: devices.append(XiaomiMotionSensor(device, hass, gateway)) elif model in ['magnet', 'sensor_magnet', 'sensor_magnet.aq2']: - if 'proto' not in device or int(device['proto'][0:1]) == 1: - data_key = 'status' - else: - data_key = 'window_status' - devices.append(XiaomiDoorSensor(device, data_key, gateway)) + devices.append(XiaomiDoorSensor(device, gateway)) elif model == 'sensor_wleak.aq1': devices.append(XiaomiWaterLeakSensor(device, gateway)) elif model in ['smoke', 'sensor_smoke']: @@ -44,17 +40,27 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if 'proto' not in device or int(device['proto'][0:1]) == 1: data_key = 'status' else: - data_key = 'channel_0' + data_key = 'button_0' devices.append(XiaomiButton(device, 'Switch', data_key, hass, gateway)) elif model in ['86sw1', 'sensor_86sw1', 'sensor_86sw1.aq1']: - devices.append(XiaomiButton(device, 'Wall Switch', 'channel_0', + if 'proto' not in device or int(device['proto'][0:1]) == 1: + data_key = 'channel_0' + else: + data_key = 'button_0' + devices.append(XiaomiButton(device, 'Wall Switch', data_key, hass, gateway)) elif model in ['86sw2', 'sensor_86sw2', 'sensor_86sw2.aq1']: + if 'proto' not in device or int(device['proto'][0:1]) == 1: + data_key_left = 'channel_0' + data_key_right = 'channel_1' + else: + data_key_left = 'button_0' + data_key_right = 'button_1' devices.append(XiaomiButton(device, 'Wall Switch (Left)', - 'channel_0', hass, gateway)) + data_key_left, hass, gateway)) devices.append(XiaomiButton(device, 'Wall Switch (Right)', - 'channel_1', hass, gateway)) + data_key_right, hass, gateway)) devices.append(XiaomiButton(device, 'Wall Switch (Both)', 'dual_channel', hass, gateway)) elif model in ['cube', 'sensor_cube', 'sensor_cube.aqgl01']: @@ -119,7 +125,7 @@ class XiaomiNatgasSensor(XiaomiBinarySensor): if value is None: return False - if value == '1': + if value in ('1', '2'): if self._state: return False self._state = True @@ -194,9 +200,13 @@ class XiaomiMotionSensor(XiaomiBinarySensor): class XiaomiDoorSensor(XiaomiBinarySensor): """Representation of a XiaomiDoorSensor.""" - def __init__(self, device, data_key, xiaomi_hub): + def __init__(self, device, xiaomi_hub): """Initialize the XiaomiDoorSensor.""" self._open_since = 0 + if 'proto' not in device or int(device['proto'][0:1]) == 1: + data_key = 'status' + else: + data_key = 'window_status' XiaomiBinarySensor.__init__(self, device, 'Door Window Sensor', xiaomi_hub, data_key, 'opening') @@ -237,8 +247,12 @@ class XiaomiWaterLeakSensor(XiaomiBinarySensor): def __init__(self, device, xiaomi_hub): """Initialize the XiaomiWaterLeakSensor.""" + if 'proto' not in device or int(device['proto'][0:1]) == 1: + data_key = 'status' + else: + data_key = 'wleak_status' XiaomiBinarySensor.__init__(self, device, 'Water Leak Sensor', - xiaomi_hub, 'status', 'moisture') + xiaomi_hub, data_key, 'moisture') def parse_data(self, data, raw_data): """Parse data sent by gateway.""" @@ -285,7 +299,7 @@ class XiaomiSmokeSensor(XiaomiBinarySensor): if value is None: return False - if value == '1': + if value in ('1', '2'): if self._state: return False self._state = True @@ -359,6 +373,10 @@ class XiaomiCube(XiaomiBinarySensor): self._hass = hass self._last_action = None self._state = False + if 'proto' not in device or int(device['proto'][0:1]) == 1: + self._data_key = 'status' + else: + self._data_key = 'cube_status' XiaomiBinarySensor.__init__(self, device, 'Cube', xiaomi_hub, None, None) @@ -371,19 +389,12 @@ class XiaomiCube(XiaomiBinarySensor): def parse_data(self, data, raw_data): """Parse data sent by gateway.""" - if 'status' in data: + if self._data_key in data: self._hass.bus.fire('cube_action', { 'entity_id': self.entity_id, - 'action_type': data['status'] + 'action_type': data[self._data_key] }) - self._last_action = data['status'] - - if 'cube_status' in data: - self._hass.bus.fire('cube_action', { - 'entity_id': self.entity_id, - 'action_type': data['cube_status'] - }) - self._last_action = data['cube_status'] + self._last_action = data[self._data_key] if 'rotate' in data: self._hass.bus.fire('cube_action', { From 4ad76d8916d09294cb646332ab45f643a9a3777d Mon Sep 17 00:00:00 2001 From: Eduard van Valkenburg Date: Wed, 22 Aug 2018 20:12:54 +0200 Subject: [PATCH 103/159] Upgrade brunt package (#16130) * Bumped package version to fix a bug with Python before 3.6 * update of package version in requirements_all --- homeassistant/components/cover/brunt.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/cover/brunt.py b/homeassistant/components/cover/brunt.py index 713f06db735..bd27ea30637 100644 --- a/homeassistant/components/cover/brunt.py +++ b/homeassistant/components/cover/brunt.py @@ -18,7 +18,7 @@ from homeassistant.components.cover import ( ) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['brunt==0.1.2'] +REQUIREMENTS = ['brunt==0.1.3'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 3732cb237c2..0c0409612c8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -205,7 +205,7 @@ braviarc-homeassistant==0.3.7.dev0 broadlink==0.9.0 # homeassistant.components.cover.brunt -brunt==0.1.2 +brunt==0.1.3 # homeassistant.components.device_tracker.bluetooth_tracker bt_proximity==0.1.2 From 4155e8a31f0cf944820b4f2bb108b95175ad24b6 Mon Sep 17 00:00:00 2001 From: JC Connell Date: Wed, 22 Aug 2018 18:21:46 -0400 Subject: [PATCH 104/159] Add support for NOAA tide information (new PR) (#15947) * Adding noaa-tides changes to new branch. * Fix typo in .coverageac * Incorporate @MartinHjelmare and @fabaff changes. * Disable pylint error and add error message for unavailable station. * Two spaces before inline comments * Increment py_noaa version to 0.3.0 * Updated requirements.py * Minor changes --- .coveragerc | 1 + homeassistant/components/sensor/noaa_tides.py | 138 ++++++++++++++++++ requirements_all.txt | 3 + script/gen_requirements_all.py | 1 + 4 files changed, 143 insertions(+) create mode 100644 homeassistant/components/sensor/noaa_tides.py diff --git a/.coveragerc b/.coveragerc index 62f710f3680..ea30dec510a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -689,6 +689,7 @@ omit = homeassistant/components/sensor/netdata.py homeassistant/components/sensor/netdata_public.py homeassistant/components/sensor/neurio_energy.py + homeassistant/components/sensor/noaa_tides.py homeassistant/components/sensor/nsw_fuel_station.py homeassistant/components/sensor/nut.py homeassistant/components/sensor/nzbget.py diff --git a/homeassistant/components/sensor/noaa_tides.py b/homeassistant/components/sensor/noaa_tides.py new file mode 100644 index 00000000000..8527abf84aa --- /dev/null +++ b/homeassistant/components/sensor/noaa_tides.py @@ -0,0 +1,138 @@ +""" +Support for the NOAA Tides and Currents API. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.noaa_tides/ +""" +from datetime import datetime, timedelta +import logging + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + ATTR_ATTRIBUTION, CONF_NAME, CONF_TIME_ZONE, CONF_UNIT_SYSTEM) +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity + +REQUIREMENTS = ['py_noaa==0.3.0'] + +_LOGGER = logging.getLogger(__name__) + +CONF_STATION_ID = 'station_id' + +DEFAULT_ATTRIBUTION = "Data provided by NOAA" +DEFAULT_NAME = 'NOAA Tides' +DEFAULT_TIMEZONE = 'lst_ldt' + +SCAN_INTERVAL = timedelta(minutes=60) + +TIMEZONES = ['gmt', 'lst', 'lst_ldt'] +UNIT_SYSTEMS = ['english', 'metric'] + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_STATION_ID): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_TIME_ZONE, default=DEFAULT_TIMEZONE): vol.In(TIMEZONES), + vol.Optional(CONF_UNIT_SYSTEM): vol.In(UNIT_SYSTEMS), +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the NOAA Tides and Currents sensor.""" + station_id = config[CONF_STATION_ID] + name = config.get(CONF_NAME) + timezone = config.get(CONF_TIME_ZONE) + + if CONF_UNIT_SYSTEM in config: + unit_system = config[CONF_UNIT_SYSTEM] + elif hass.config.units.is_metric: + unit_system = UNIT_SYSTEMS[1] + else: + unit_system = UNIT_SYSTEMS[0] + + noaa_sensor = NOAATidesAndCurrentsSensor( + name, station_id, timezone, unit_system) + + noaa_sensor.update() + if noaa_sensor.data is None: + _LOGGER.error("Unable to setup NOAA Tides Sensor") + return + add_devices([noaa_sensor], True) + + +class NOAATidesAndCurrentsSensor(Entity): + """Representation of a NOAA Tides and Currents sensor.""" + + def __init__(self, name, station_id, timezone, unit_system): + """Initialize the sensor.""" + self._name = name + self._station_id = station_id + self._timezone = timezone + self._unit_system = unit_system + self.data = None + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def device_state_attributes(self): + """Return the state attributes of this device.""" + attr = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION} + if self.data is None: + return attr + if self.data['hi_lo'][1] == 'H': + attr['high_tide_time'] = \ + self.data.index[1].strftime('%Y-%m-%dT%H:%M') + attr['high_tide_height'] = self.data['predicted_wl'][1] + attr['low_tide_time'] = \ + self.data.index[2].strftime('%Y-%m-%dT%H:%M') + attr['low_tide_height'] = self.data['predicted_wl'][2] + elif self.data['hi_lo'][1] == 'L': + attr['low_tide_time'] = \ + self.data.index[1].strftime('%Y-%m-%dT%H:%M') + attr['low_tide_height'] = self.data['predicted_wl'][1] + attr['high_tide_time'] = \ + self.data.index[2].strftime('%Y-%m-%dT%H:%M') + attr['high_tide_height'] = self.data['predicted_wl'][2] + return attr + + @property + def state(self): + """Return the state of the device.""" + if self.data is None: + return None + api_time = self.data.index[0] + if self.data['hi_lo'][0] == 'H': + tidetime = api_time.strftime('%-I:%M %p') + return "High tide at {}".format(tidetime) + if self.data['hi_lo'][0] == 'L': + tidetime = api_time.strftime('%-I:%M %p') + return "Low tide at {}".format(tidetime) + return None + + def update(self): + """Get the latest data from NOAA Tides and Currents API.""" + from py_noaa import coops # pylint: disable=import-error + begin = datetime.now() + delta = timedelta(days=2) + end = begin + delta + try: + df_predictions = coops.get_data( + begin_date=begin.strftime("%Y%m%d %H:%M"), + end_date=end.strftime("%Y%m%d %H:%M"), + stationid=self._station_id, + product="predictions", + datum="MLLW", + interval="hilo", + units=self._unit_system, + time_zone=self._timezone) + self.data = df_predictions.head() + _LOGGER.debug("Data = %s", self.data) + _LOGGER.debug("Recent Tide data queried with start time set to %s", + begin.strftime("%m-%d-%Y %H:%M")) + except ValueError as err: + _LOGGER.error("Check NOAA Tides and Currents: %s", err.args) + self.data = None diff --git a/requirements_all.txt b/requirements_all.txt index 0c0409612c8..d29dff255a2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -738,6 +738,9 @@ pyTibber==0.4.1 # homeassistant.components.switch.dlink pyW215==0.6.0 +# homeassistant.components.sensor.noaa_tides +# py_noaa==0.3.0 + # homeassistant.components.cover.ryobi_gdo py_ryobi_gdo==0.0.10 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 61f39e3387f..e709abfc10b 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -34,6 +34,7 @@ COMMENT_REQUIREMENTS = ( 'credstash', 'bme680', 'homekit', + 'py_noaa', ) TEST_REQUIREMENTS = ( From ced5eeacc205164c4de3dfcfeb0d10814799bb6a Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Thu, 23 Aug 2018 09:54:02 +0100 Subject: [PATCH 105/159] Adds support for routers implementing IGDv2 (#16108) * Adds support for IGDv2 * bump pyupnp_async * bump pyupnp_async * better debug * fix test --- homeassistant/components/upnp.py | 14 +++++++++----- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/test_upnp.py | 9 +++++++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/upnp.py b/homeassistant/components/upnp.py index b4fe9d3fce9..5d7855f3959 100644 --- a/homeassistant/components/upnp.py +++ b/homeassistant/components/upnp.py @@ -15,7 +15,7 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers import discovery from homeassistant.util import get_local_ip -REQUIREMENTS = ['pyupnp-async==0.1.0.2'] +REQUIREMENTS = ['pyupnp-async==0.1.1.0'] DEPENDENCIES = ['http'] _LOGGER = logging.getLogger(__name__) @@ -37,6 +37,7 @@ NOTIFICATION_TITLE = 'UPnP Setup' IGD_DEVICE = 'urn:schemas-upnp-org:device:InternetGatewayDevice:1' PPP_SERVICE = 'urn:schemas-upnp-org:service:WANPPPConnection:1' IP_SERVICE = 'urn:schemas-upnp-org:service:WANIPConnection:1' +IP_SERVICE2 = 'urn:schemas-upnp-org:service:WANIPConnection:2' CIC_SERVICE = 'urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1' UNITS = { @@ -48,7 +49,7 @@ UNITS = { CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ - vol.Optional(CONF_ENABLE_PORT_MAPPING, default=True): cv.boolean, + vol.Optional(CONF_ENABLE_PORT_MAPPING, default=False): cv.boolean, vol.Optional(CONF_UNITS, default="MBytes"): vol.In(UNITS), vol.Optional(CONF_LOCAL_IP): vol.All(ip_address, cv.string), vol.Optional(CONF_PORTS): @@ -86,8 +87,10 @@ async def async_setup(hass, config): service = device.find_first_service(PPP_SERVICE) if _service['serviceType'] == IP_SERVICE: service = device.find_first_service(IP_SERVICE) + if _service['serviceType'] == IP_SERVICE2: + service = device.find_first_service(IP_SERVICE2) if _service['serviceType'] == CIC_SERVICE: - unit = config.get(CONF_UNITS) + unit = config[CONF_UNITS] hass.async_create_task(discovery.async_load_platform( hass, 'sensor', DOMAIN, {'unit': unit}, config)) except UpnpSoapError as error: @@ -98,7 +101,7 @@ async def async_setup(hass, config): _LOGGER.warning("Could not find any UPnP IGD") return False - port_mapping = config.get(CONF_ENABLE_PORT_MAPPING) + port_mapping = config[CONF_ENABLE_PORT_MAPPING] if not port_mapping: return True @@ -116,7 +119,8 @@ async def async_setup(hass, config): await service.add_port_mapping(internal, external, host, 'TCP', desc='Home Assistant') registered.append(external) - _LOGGER.debug("external %s -> %s @ %s", external, internal, host) + _LOGGER.debug("Mapping external TCP port %s -> %s @ %s", + external, internal, host) except UpnpSoapError as error: _LOGGER.error(error) hass.components.persistent_notification.create( diff --git a/requirements_all.txt b/requirements_all.txt index d29dff255a2..253263c6e3a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1167,7 +1167,7 @@ pytradfri[async]==5.5.1 pyunifi==2.13 # homeassistant.components.upnp -pyupnp-async==0.1.0.2 +pyupnp-async==0.1.1.0 # homeassistant.components.binary_sensor.uptimerobot pyuptimerobot==0.0.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 167155d688f..4b907f89b11 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -171,7 +171,7 @@ pytradfri[async]==5.5.1 pyunifi==2.13 # homeassistant.components.upnp -pyupnp-async==0.1.0.2 +pyupnp-async==0.1.1.0 # homeassistant.components.notify.html5 pywebpush==1.6.0 diff --git a/tests/components/test_upnp.py b/tests/components/test_upnp.py index 4956b8a6278..38575c411da 100644 --- a/tests/components/test_upnp.py +++ b/tests/components/test_upnp.py @@ -102,7 +102,8 @@ async def test_setup_succeeds_if_specify_ip(hass, mock_msearch_first): return_value='127.0.0.1'): result = await async_setup_component(hass, 'upnp', { 'upnp': { - 'local_ip': '192.168.0.10' + 'local_ip': '192.168.0.10', + 'port_mapping': 'True' } }) @@ -118,7 +119,9 @@ async def test_no_config_maps_hass_local_to_remote_port(hass, mock_msearch_first): """Test by default we map local to remote port.""" result = await async_setup_component(hass, 'upnp', { - 'upnp': {} + 'upnp': { + 'port_mapping': 'True' + } }) assert result @@ -134,6 +137,7 @@ async def test_map_hass_to_remote_port(hass, """Test mapping hass to remote port.""" result = await async_setup_component(hass, 'upnp', { 'upnp': { + 'port_mapping': 'True', 'ports': { 'hass': 1000 } @@ -157,6 +161,7 @@ async def test_map_internal_to_remote_ports(hass, result = await async_setup_component(hass, 'upnp', { 'upnp': { + 'port_mapping': 'True', 'ports': ports } }) From 8e173f16587f2df3c78348bfe99982f92daabe4f Mon Sep 17 00:00:00 2001 From: squidwardy Date: Thu, 23 Aug 2018 11:14:18 +0200 Subject: [PATCH 106/159] Add support for JS modules in custom panels (#16096) * Added backend support for JavaScript modules in custom panels. * Fixed test_panel_custom.py * Delete core.entity_registry * Update panel_custom.py * Corrected panel_custom.py with module_url. * Rebase * Missed elif * Add vol.Exclusive module_url * Correct vol.Exclusive usage * Test for js module * Corrected line continuation indentation * Added webcomponent path to exclusive group * Corrected line length * Line break * Test for conflicting url options * Self -> hass fix * Fix self -> hass again * Use assert_setup_component * Setup missing * Correct test * Fix again * Fix * Mising async * Fix * test real * Test real * Final * check * Final check * safety * Final commit and check * Removed unused dependencies * Test for multiple url options in config --- homeassistant/components/panel_custom.py | 29 ++++++++-- tests/components/test_panel_custom.py | 70 ++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/panel_custom.py b/homeassistant/components/panel_custom.py index 0444e7a5b53..740a28a9dec 100644 --- a/homeassistant/components/panel_custom.py +++ b/homeassistant/components/panel_custom.py @@ -22,8 +22,13 @@ CONF_URL_PATH = 'url_path' CONF_CONFIG = 'config' CONF_WEBCOMPONENT_PATH = 'webcomponent_path' CONF_JS_URL = 'js_url' +CONF_MODULE_URL = 'module_url' CONF_EMBED_IFRAME = 'embed_iframe' CONF_TRUST_EXTERNAL_SCRIPT = 'trust_external_script' +CONF_URL_EXCLUSIVE_GROUP = 'url_exclusive_group' + +MSG_URL_CONFLICT = \ + 'Pass in only one of webcomponent_path, module_url or js_url' DEFAULT_EMBED_IFRAME = False DEFAULT_TRUST_EXTERNAL = False @@ -40,8 +45,12 @@ CONFIG_SCHEMA = vol.Schema({ vol.Optional(CONF_SIDEBAR_ICON, default=DEFAULT_ICON): cv.icon, vol.Optional(CONF_URL_PATH): cv.string, vol.Optional(CONF_CONFIG): dict, - vol.Optional(CONF_WEBCOMPONENT_PATH): cv.isfile, - vol.Optional(CONF_JS_URL): cv.string, + vol.Exclusive(CONF_WEBCOMPONENT_PATH, CONF_URL_EXCLUSIVE_GROUP, + msg=MSG_URL_CONFLICT): cv.string, + vol.Exclusive(CONF_JS_URL, CONF_URL_EXCLUSIVE_GROUP, + msg=MSG_URL_CONFLICT): cv.string, + vol.Exclusive(CONF_MODULE_URL, CONF_URL_EXCLUSIVE_GROUP, + msg=MSG_URL_CONFLICT): cv.string, vol.Optional(CONF_EMBED_IFRAME, default=DEFAULT_EMBED_IFRAME): cv.boolean, vol.Optional(CONF_TRUST_EXTERNAL_SCRIPT, @@ -66,6 +75,8 @@ async def async_register_panel( html_url=None, # JS source of your panel js_url=None, + # JS module of your panel + module_url=None, # If your panel should be run inside an iframe embed_iframe=DEFAULT_EMBED_IFRAME, # Should user be asked for confirmation when loading external source @@ -73,10 +84,10 @@ async def async_register_panel( # Configuration to be passed to the panel config=None): """Register a new custom panel.""" - if js_url is None and html_url is None: - raise ValueError('Either js_url or html_url is required.') - elif js_url and html_url: - raise ValueError('Pass in either JS url or HTML url, not both.') + if js_url is None and html_url is None and module_url is None: + raise ValueError('Either js_url, module_url or html_url is required.') + elif (js_url and html_url) or (module_url and html_url): + raise ValueError('Pass in only one of JS url, Module url or HTML url.') if config is not None and not isinstance(config, dict): raise ValueError('Config needs to be a dictionary.') @@ -90,6 +101,9 @@ async def async_register_panel( if js_url is not None: custom_panel_config['js_url'] = js_url + if module_url is not None: + custom_panel_config['module_url'] = module_url + if html_url is not None: custom_panel_config['html_url'] = html_url @@ -136,6 +150,9 @@ async def async_setup(hass, config): if CONF_JS_URL in panel: kwargs['js_url'] = panel[CONF_JS_URL] + elif CONF_MODULE_URL in panel: + kwargs['module_url'] = panel[CONF_MODULE_URL] + elif not await hass.async_add_job(os.path.isfile, panel_path): _LOGGER.error('Unable to find webcomponent for %s: %s', name, panel_path) diff --git a/tests/components/test_panel_custom.py b/tests/components/test_panel_custom.py index 596aa1b3c0b..c265324179d 100644 --- a/tests/components/test_panel_custom.py +++ b/tests/components/test_panel_custom.py @@ -114,3 +114,73 @@ async def test_js_webcomponent(hass): assert panel.frontend_url_path == 'nice_url' assert panel.sidebar_icon == 'mdi:iconicon' assert panel.sidebar_title == 'Sidebar Title' + + +async def test_module_webcomponent(hass): + """Test if a js module is found in config panels dir.""" + config = { + 'panel_custom': { + 'name': 'todo-mvc', + 'module_url': '/local/bla.js', + 'sidebar_title': 'Sidebar Title', + 'sidebar_icon': 'mdi:iconicon', + 'url_path': 'nice_url', + 'config': { + 'hello': 'world', + }, + 'embed_iframe': True, + 'trust_external_script': True, + } + } + + result = await setup.async_setup_component( + hass, 'panel_custom', config + ) + assert result + + panels = hass.data.get(frontend.DATA_PANELS, []) + + assert panels + assert 'nice_url' in panels + + panel = panels['nice_url'] + + assert panel.config == { + 'hello': 'world', + '_panel_custom': { + 'module_url': '/local/bla.js', + 'name': 'todo-mvc', + 'embed_iframe': True, + 'trust_external': True, + } + } + assert panel.frontend_url_path == 'nice_url' + assert panel.sidebar_icon == 'mdi:iconicon' + assert panel.sidebar_title == 'Sidebar Title' + + +async def test_url_option_conflict(hass): + """Test config with multiple url options.""" + to_try = [ + {'panel_custom': { + 'name': 'todo-mvc', + 'module_url': '/local/bla.js', + 'js_url': '/local/bla.js', + } + }, {'panel_custom': { + 'name': 'todo-mvc', + 'webcomponent_path': '/local/bla.html', + 'js_url': '/local/bla.js', + }}, {'panel_custom': { + 'name': 'todo-mvc', + 'webcomponent_path': '/local/bla.html', + 'module_url': '/local/bla.js', + 'js_url': '/local/bla.js', + }} + ] + + for config in to_try: + result = await setup.async_setup_component( + hass, 'panel_custom', config + ) + assert not result From 249981de960af7a2297846b581649ed82b922592 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 23 Aug 2018 12:56:01 +0200 Subject: [PATCH 107/159] Prevent legacy api password with empty password (#16127) * Prevent legacy api password with empty password * Typing --- .../auth/providers/legacy_api_password.py | 13 ++--- .../providers/test_legacy_api_password.py | 55 +++++++++++++++---- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/homeassistant/auth/providers/legacy_api_password.py b/homeassistant/auth/providers/legacy_api_password.py index dffe458976c..1c91a18c4e5 100644 --- a/homeassistant/auth/providers/legacy_api_password.py +++ b/homeassistant/auth/providers/legacy_api_password.py @@ -46,13 +46,6 @@ class LegacyApiPasswordAuthProvider(AuthProvider): """Helper to validate a username and password.""" hass_http = getattr(self.hass, 'http', None) # type: HomeAssistantHTTP - if not hass_http: - raise ValueError('http component is not loaded') - - if hass_http.api_password is None: - raise ValueError('http component is not configured using' - ' api_password') - if not hmac.compare_digest(hass_http.api_password.encode('utf-8'), password.encode('utf-8')): raise InvalidAuthError @@ -87,6 +80,12 @@ class LegacyLoginFlow(LoginFlow): """Handle the step of the form.""" errors = {} + hass_http = getattr(self.hass, 'http', None) + if hass_http is None or not hass_http.api_password: + return self.async_abort( + reason='no_api_password_set' + ) + if user_input is not None: try: cast(LegacyApiPasswordAuthProvider, self._auth_provider)\ diff --git a/tests/auth/providers/test_legacy_api_password.py b/tests/auth/providers/test_legacy_api_password.py index 33178b06cb2..60916798d5b 100644 --- a/tests/auth/providers/test_legacy_api_password.py +++ b/tests/auth/providers/test_legacy_api_password.py @@ -3,7 +3,7 @@ from unittest.mock import Mock import pytest -from homeassistant import auth +from homeassistant import auth, data_entry_flow from homeassistant.auth import auth_store from homeassistant.auth.providers import legacy_api_password @@ -51,17 +51,6 @@ async def test_only_one_credentials(manager, provider): assert credentials2.is_new is False -async def test_verify_not_load(hass, provider): - """Test we raise if http module not load.""" - with pytest.raises(ValueError): - provider.async_validate_login('test-password') - hass.http = Mock(api_password=None) - with pytest.raises(ValueError): - provider.async_validate_login('test-password') - hass.http = Mock(api_password='test-password') - provider.async_validate_login('test-password') - - async def test_verify_login(hass, provider): """Test login using legacy api password auth provider.""" hass.http = Mock(api_password='test-password') @@ -69,3 +58,45 @@ async def test_verify_login(hass, provider): hass.http = Mock(api_password='test-password') with pytest.raises(legacy_api_password.InvalidAuthError): provider.async_validate_login('invalid-password') + + +async def test_login_flow_abort(hass, manager): + """Test wrong config.""" + for http in ( + None, + Mock(api_password=None), + Mock(api_password=''), + ): + hass.http = http + + result = await manager.login_flow.async_init( + handler=('legacy_api_password', None) + ) + assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT + assert result['reason'] == 'no_api_password_set' + + +async def test_login_flow_works(hass, manager): + """Test wrong config.""" + hass.http = Mock(api_password='hello') + result = await manager.login_flow.async_init( + handler=('legacy_api_password', None) + ) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + + result = await manager.login_flow.async_configure( + flow_id=result['flow_id'], + user_input={ + 'password': 'not-hello' + } + ) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_auth' + + result = await manager.login_flow.async_configure( + flow_id=result['flow_id'], + user_input={ + 'password': 'hello' + } + ) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY From d21d7cef4cbdefba0285660e15c2ba695641dfe7 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 23 Aug 2018 13:38:08 +0200 Subject: [PATCH 108/159] =?UTF-8?q?Enable=20auth=20by=20default=20?= =?UTF-8?q?=F0=9F=99=88=20(#16107)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enable auth by default * Only default legacy_api_password if api_password set * Tweak bool check * typing --- homeassistant/bootstrap.py | 4 +++- homeassistant/config.py | 14 +++++++++++-- tests/test_config.py | 41 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 5c85267ca44..41fa61964de 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -87,9 +87,11 @@ async def async_from_config_dict(config: Dict[str, Any], log_no_color) core_config = config.get(core.DOMAIN, {}) + has_api_password = bool((config.get('http') or {}).get('api_password')) try: - await conf_util.async_process_ha_core_config(hass, core_config) + await conf_util.async_process_ha_core_config( + hass, core_config, has_api_password) except vol.Invalid as ex: conf_util.async_log_exception(ex, 'homeassistant', core_config, hass) return None diff --git a/homeassistant/config.py b/homeassistant/config.py index cc4eef3f97e..1c47a5e036c 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -407,7 +407,8 @@ def _format_config_error(ex: vol.Invalid, domain: str, config: Dict) -> str: async def async_process_ha_core_config( - hass: HomeAssistant, config: Dict) -> None: + hass: HomeAssistant, config: Dict, + has_api_password: bool = False) -> None: """Process the [homeassistant] section from the configuration. This method is a coroutine. @@ -416,9 +417,18 @@ async def async_process_ha_core_config( # Only load auth during startup. if not hasattr(hass, 'auth'): + auth_conf = config.get(CONF_AUTH_PROVIDERS) + + if auth_conf is None: + auth_conf = [ + {'type': 'homeassistant'} + ] + if has_api_password: + auth_conf.append({'type': 'legacy_api_password'}) + setattr(hass, 'auth', await auth.auth_manager_from_config( hass, - config.get(CONF_AUTH_PROVIDERS, []), + auth_conf, config.get(CONF_AUTH_MFA_MODULES, []))) hac = hass.config diff --git a/tests/test_config.py b/tests/test_config.py index 435d3a00ec2..77a30fd771b 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -812,6 +812,47 @@ async def test_auth_provider_config(hass): await config_util.async_process_ha_core_config(hass, core_config) assert len(hass.auth.auth_providers) == 2 + assert hass.auth.auth_providers[0].type == 'homeassistant' + assert hass.auth.auth_providers[1].type == 'legacy_api_password' + assert hass.auth.active is True + + +async def test_auth_provider_config_default(hass): + """Test loading default auth provider config.""" + core_config = { + 'latitude': 60, + 'longitude': 50, + 'elevation': 25, + 'name': 'Huis', + CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, + 'time_zone': 'GMT', + } + if hasattr(hass, 'auth'): + del hass.auth + await config_util.async_process_ha_core_config(hass, core_config) + + assert len(hass.auth.auth_providers) == 1 + assert hass.auth.auth_providers[0].type == 'homeassistant' + assert hass.auth.active is True + + +async def test_auth_provider_config_default_api_password(hass): + """Test loading default auth provider config with api password.""" + core_config = { + 'latitude': 60, + 'longitude': 50, + 'elevation': 25, + 'name': 'Huis', + CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, + 'time_zone': 'GMT', + } + if hasattr(hass, 'auth'): + del hass.auth + await config_util.async_process_ha_core_config(hass, core_config, True) + + assert len(hass.auth.auth_providers) == 2 + assert hass.auth.auth_providers[0].type == 'homeassistant' + assert hass.auth.auth_providers[1].type == 'legacy_api_password' assert hass.auth.active is True From 156c6e2025649d1927390062f74cd8afd9c940a7 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 23 Aug 2018 22:16:31 +0200 Subject: [PATCH 109/159] Remove commented out API password from default config (#16147) --- homeassistant/config.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/homeassistant/config.py b/homeassistant/config.py index 1c47a5e036c..45505bbbc9b 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -75,11 +75,9 @@ frontend: # Enables configuration UI config: -http: - # Secrets are defined in the file secrets.yaml - # api_password: !secret http_password - # Uncomment this if you are using SSL/TLS, running in Docker container, etc. - # base_url: example.duckdns.org:8123 +# Uncomment this if you are using SSL/TLS, running in Docker container, etc. +# http: +# base_url: example.duckdns.org:8123 # Checks for available updates # Note: This component will send some information about your system to @@ -126,7 +124,7 @@ script: !include scripts.yaml DEFAULT_SECRETS = """ # Use this file to store secrets like usernames and passwords. # Learn more at https://home-assistant.io/docs/configuration/secrets/ -http_password: welcome +some_password: welcome """ From 89d856d147425122fcab0d0d1c582cdf8b3dc8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Thu, 23 Aug 2018 23:56:18 +0300 Subject: [PATCH 110/159] Spelling fixes (#16150) --- homeassistant/components/insteon_local.py | 6 +++--- homeassistant/components/insteon_plm.py | 6 +++--- tests/components/auth/__init__.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/insteon_local.py b/homeassistant/components/insteon_local.py index 1dfb0c6e4cb..003714d0f94 100644 --- a/homeassistant/components/insteon_local.py +++ b/homeassistant/components/insteon_local.py @@ -10,12 +10,12 @@ _LOGGER = logging.getLogger(__name__) def setup(hass, config): - """Setup the insteon_local component. + """Set up the insteon_local component. - This component is depreciated as of release 0.77 and should be removed in + This component is deprecated as of release 0.77 and should be removed in release 0.90. """ - _LOGGER.warning('The insteon_local comonent has been replaced by ' + _LOGGER.warning('The insteon_local component has been replaced by ' 'the insteon component') _LOGGER.warning('Please see https://home-assistant.io/components/insteon') diff --git a/homeassistant/components/insteon_plm.py b/homeassistant/components/insteon_plm.py index bd41819a0fa..b89e5679a63 100644 --- a/homeassistant/components/insteon_plm.py +++ b/homeassistant/components/insteon_plm.py @@ -12,12 +12,12 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine def async_setup(hass, config): - """Setup the insteon_plm component. + """Set up the insteon_plm component. - This component is depreciated as of release 0.77 and should be removed in + This component is deprecated as of release 0.77 and should be removed in release 0.90. """ - _LOGGER.warning('The insteon_plm comonent has been replaced by ' + _LOGGER.warning('The insteon_plm component has been replaced by ' 'the insteon component') _LOGGER.warning('Please see https://home-assistant.io/components/insteon') diff --git a/tests/components/auth/__init__.py b/tests/components/auth/__init__.py index 224f9b16403..4c357fc4db9 100644 --- a/tests/components/auth/__init__.py +++ b/tests/components/auth/__init__.py @@ -20,7 +20,7 @@ EMPTY_CONFIG = [] async def async_setup_auth(hass, aiohttp_client, provider_configs=BASE_CONFIG, module_configs=EMPTY_CONFIG, setup_api=False): - """Helper to set up authentication and create a HTTP client.""" + """Helper to set up authentication and create an HTTP client.""" hass.auth = await auth.auth_manager_from_config( hass, provider_configs, module_configs) ensure_auth_manager_loaded(hass.auth) From dd9d53c83e093a9549c4bf2ba471f75661e69b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Fri, 24 Aug 2018 11:28:43 +0300 Subject: [PATCH 111/159] Update pydocstyle to 2.1.1 and flake8-docstrings to 1.3.0 (#14557) * Update pydocstyle to 2.1.1 and flake8-docstrings to 1.3.0 * Pydocstyle D401 fixes --- homeassistant/auth/__init__.py | 2 +- homeassistant/auth/providers/homeassistant.py | 2 +- homeassistant/auth/providers/insecure_example.py | 2 +- .../auth/providers/legacy_api_password.py | 2 +- .../binary_sensor/bmw_connected_drive.py | 5 ++++- .../components/binary_sensor/egardia.py | 4 ++-- homeassistant/components/camera/onvif.py | 2 +- homeassistant/components/camera/push.py | 2 +- homeassistant/components/climate/melissa.py | 2 +- homeassistant/components/climate/nest.py | 2 +- homeassistant/components/climate/zhong_hong.py | 2 +- .../components/config/entity_registry.py | 2 +- homeassistant/components/config/zwave.py | 4 ++-- homeassistant/components/deconz/__init__.py | 2 +- .../components/device_tracker/xiaomi_miio.py | 5 ++++- homeassistant/components/doorbird.py | 6 +++--- homeassistant/components/egardia.py | 2 +- .../components/google_assistant/trait.py | 2 +- homeassistant/components/group/__init__.py | 4 ++-- homeassistant/components/homekit/accessories.py | 12 ++++++------ homeassistant/components/http/ban.py | 2 +- homeassistant/components/ihc/ihcdevice.py | 2 +- homeassistant/components/iota.py | 2 +- homeassistant/components/knx.py | 2 +- homeassistant/components/light/group.py | 2 +- homeassistant/components/light/ihc.py | 2 +- homeassistant/components/light/limitlessled.py | 2 +- homeassistant/components/light/lw12wifi.py | 2 +- homeassistant/components/media_player/cast.py | 12 ++++++------ .../components/media_player/channels.py | 2 +- .../components/media_player/dlna_dmr.py | 2 +- .../components/media_player/mediaroom.py | 2 +- homeassistant/components/remote/xiaomi_miio.py | 2 +- homeassistant/components/sabnzbd.py | 2 +- .../components/sensor/bmw_connected_drive.py | 5 ++++- homeassistant/components/sensor/fints.py | 16 +++++++++++----- homeassistant/components/sensor/ihc.py | 2 +- homeassistant/components/sensor/uscis.py | 2 +- homeassistant/components/sensor/wirelesstag.py | 2 +- homeassistant/components/switch/ihc.py | 2 +- homeassistant/components/switch/wemo.py | 2 +- homeassistant/components/wirelesstag.py | 9 ++++++--- homeassistant/components/zha/__init__.py | 2 +- homeassistant/components/zwave/node_entity.py | 2 +- homeassistant/helpers/device_registry.py | 2 +- homeassistant/helpers/entity.py | 2 +- homeassistant/helpers/entity_component.py | 4 ++-- homeassistant/helpers/entity_platform.py | 6 +++--- homeassistant/helpers/entity_registry.py | 2 +- homeassistant/helpers/storage.py | 8 ++++---- requirements_test.txt | 4 ++-- requirements_test_all.txt | 4 ++-- script/gen_requirements_all.py | 4 ++-- script/inspect_schemas.py | 2 +- script/lazytox.py | 2 +- script/translations_download_split.py | 2 +- script/translations_upload_merge.py | 2 +- tests/common.py | 4 ++-- tests/components/auth/__init__.py | 2 +- tests/components/auth/test_init_link_user.py | 2 +- tests/components/automation/test_event.py | 2 +- tests/components/automation/test_mqtt.py | 2 +- .../components/automation/test_numeric_state.py | 2 +- tests/components/automation/test_template.py | 2 +- tests/components/automation/test_time.py | 2 +- tests/components/automation/test_zone.py | 2 +- tests/components/device_tracker/test_init.py | 2 +- tests/components/device_tracker/test_locative.py | 2 +- tests/components/fan/test_demo.py | 2 +- tests/components/http/test_real_ip.py | 2 +- tests/components/media_player/test_cast.py | 2 +- tests/components/media_player/test_samsungtv.py | 2 +- tests/components/media_player/test_universal.py | 2 +- tests/components/mqtt/test_init.py | 4 ++-- tests/components/notify/test_demo.py | 2 +- tests/components/sensor/test_yweather.py | 2 +- tests/components/test_api.py | 12 ++++++------ tests/components/test_discovery.py | 2 +- tests/components/test_feedreader.py | 2 +- tests/components/test_pilight.py | 8 ++++---- tests/components/test_upnp.py | 4 ++-- tests/components/weather/test_yweather.py | 10 +++++----- tests/helpers/test_entity_platform.py | 2 +- tests/test_setup.py | 4 ++-- 84 files changed, 148 insertions(+), 130 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index c0beba1a227..b5ba869cdf1 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -390,7 +390,7 @@ class AuthManager: @callback def _async_get_auth_provider( self, credentials: models.Credentials) -> Optional[AuthProvider]: - """Helper to get auth provider from a set of credentials.""" + """Get auth provider from a set of credentials.""" auth_provider_key = (credentials.auth_provider_type, credentials.auth_provider_id) return self._providers.get(auth_provider_key) diff --git a/homeassistant/auth/providers/homeassistant.py b/homeassistant/auth/providers/homeassistant.py index 29be774cf8a..ce252497901 100644 --- a/homeassistant/auth/providers/homeassistant.py +++ b/homeassistant/auth/providers/homeassistant.py @@ -164,7 +164,7 @@ class HassAuthProvider(AuthProvider): return HassLoginFlow(self) async def async_validate_login(self, username: str, password: str) -> None: - """Helper to validate a username and password.""" + """Validate a username and password.""" if self.data is None: await self.async_initialize() assert self.data is not None diff --git a/homeassistant/auth/providers/insecure_example.py b/homeassistant/auth/providers/insecure_example.py index d267ccb7a1c..72e3dfe140a 100644 --- a/homeassistant/auth/providers/insecure_example.py +++ b/homeassistant/auth/providers/insecure_example.py @@ -38,7 +38,7 @@ class ExampleAuthProvider(AuthProvider): @callback def async_validate_login(self, username: str, password: str) -> None: - """Helper to validate a username and password.""" + """Validate a username and password.""" user = None # Compare all users to avoid timing attacks. diff --git a/homeassistant/auth/providers/legacy_api_password.py b/homeassistant/auth/providers/legacy_api_password.py index 1c91a18c4e5..f631f8e73cf 100644 --- a/homeassistant/auth/providers/legacy_api_password.py +++ b/homeassistant/auth/providers/legacy_api_password.py @@ -43,7 +43,7 @@ class LegacyApiPasswordAuthProvider(AuthProvider): @callback def async_validate_login(self, password: str) -> None: - """Helper to validate a username and password.""" + """Validate a username and password.""" hass_http = getattr(self.hass, 'http', None) # type: HomeAssistantHTTP if not hmac.compare_digest(hass_http.api_password.encode('utf-8'), diff --git a/homeassistant/components/binary_sensor/bmw_connected_drive.py b/homeassistant/components/binary_sensor/bmw_connected_drive.py index 308298d1bcd..d19deec4884 100644 --- a/homeassistant/components/binary_sensor/bmw_connected_drive.py +++ b/homeassistant/components/binary_sensor/bmw_connected_drive.py @@ -71,7 +71,10 @@ class BMWConnectedDriveSensor(BinarySensorDevice): @property def should_poll(self) -> bool: - """Data update is triggered from BMWConnectedDriveEntity.""" + """Return False. + + Data update is triggered from BMWConnectedDriveEntity. + """ return False @property diff --git a/homeassistant/components/binary_sensor/egardia.py b/homeassistant/components/binary_sensor/egardia.py index 76d90e78376..7d443dfafdf 100644 --- a/homeassistant/components/binary_sensor/egardia.py +++ b/homeassistant/components/binary_sensor/egardia.py @@ -58,7 +58,7 @@ class EgardiaBinarySensor(BinarySensorDevice): @property def name(self): - """The name of the device.""" + """Return the name of the device.""" return self._name @property @@ -74,5 +74,5 @@ class EgardiaBinarySensor(BinarySensorDevice): @property def device_class(self): - """The device class.""" + """Return the device class.""" return self._device_class diff --git a/homeassistant/components/camera/onvif.py b/homeassistant/components/camera/onvif.py index 32f8e15748d..251c44c146e 100644 --- a/homeassistant/components/camera/onvif.py +++ b/homeassistant/components/camera/onvif.py @@ -183,7 +183,7 @@ class ONVIFHassCamera(Camera): _LOGGER.debug("Camera '%s' doesn't support PTZ.", self._name) async def async_added_to_hass(self): - """Callback when entity is added to hass.""" + """Handle entity addition to hass.""" if ONVIF_DATA not in self.hass.data: self.hass.data[ONVIF_DATA] = {} self.hass.data[ONVIF_DATA][ENTITIES] = [] diff --git a/homeassistant/components/camera/push.py b/homeassistant/components/camera/push.py index f5ea336d576..d75f59fb038 100644 --- a/homeassistant/components/camera/push.py +++ b/homeassistant/components/camera/push.py @@ -113,7 +113,7 @@ class PushCamera(Camera): @property def state(self): - """Current state of the camera.""" + """Return current state of the camera.""" return self._state async def update_image(self, image, filename): diff --git a/homeassistant/components/climate/melissa.py b/homeassistant/components/climate/melissa.py index a0adc12bfbf..a4a8c76a39f 100644 --- a/homeassistant/components/climate/melissa.py +++ b/homeassistant/components/climate/melissa.py @@ -166,7 +166,7 @@ class MelissaClimate(ClimateDevice): self.send({self._api.STATE: self._api.STATE_OFF}) def send(self, value): - """Sending action to service.""" + """Send action to service.""" try: old_value = self._cur_settings.copy() self._cur_settings.update(value) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index 2fdb11866e0..04c598cbddb 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -124,7 +124,7 @@ class NestThermostat(ClimateDevice): @property def unique_id(self): - """Unique ID for this device.""" + """Return unique ID for this device.""" return self._device.serial @property diff --git a/homeassistant/components/climate/zhong_hong.py b/homeassistant/components/climate/zhong_hong.py index 7ff19871ee7..2b66af35224 100644 --- a/homeassistant/components/climate/zhong_hong.py +++ b/homeassistant/components/climate/zhong_hong.py @@ -100,7 +100,7 @@ class ZhongHongClimate(ClimateDevice): async_dispatcher_send(self.hass, SIGNAL_DEVICE_ADDED) def _after_update(self, climate): - """Callback to update state.""" + """Handle state update.""" _LOGGER.debug("async update ha state") if self._device.current_operation: self._current_operation = self._device.current_operation.lower() diff --git a/homeassistant/components/config/entity_registry.py b/homeassistant/components/config/entity_registry.py index 7c0867e3852..2fac420c39c 100644 --- a/homeassistant/components/config/entity_registry.py +++ b/homeassistant/components/config/entity_registry.py @@ -101,7 +101,7 @@ def websocket_update_entity(hass, connection, msg): @callback def _entry_dict(entry): - """Helper to convert entry to API format.""" + """Convert entry to API format.""" return { 'entity_id': entry.entity_id, 'name': entry.name diff --git a/homeassistant/components/config/zwave.py b/homeassistant/components/config/zwave.py index 84927712741..fcdab835052 100644 --- a/homeassistant/components/config/zwave.py +++ b/homeassistant/components/config/zwave.py @@ -212,7 +212,7 @@ class ZWaveProtectionView(HomeAssistantView): network = hass.data.get(const.DATA_NETWORK) def _fetch_protection(): - """Helper to get protection data.""" + """Get protection data.""" node = network.nodes.get(nodeid) if node is None: return self.json_message('Node not found', HTTP_NOT_FOUND) @@ -236,7 +236,7 @@ class ZWaveProtectionView(HomeAssistantView): protection_data = await request.json() def _set_protection(): - """Helper to get protection data.""" + """Set protection data.""" node = network.nodes.get(nodeid) selection = protection_data["selection"] value_id = int(protection_data[const.ATTR_VALUE_ID]) diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index a0b2b5a23cb..cf8d891661e 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -82,7 +82,7 @@ async def async_setup_entry(hass, config_entry): @callback def async_add_device_callback(device_type, device): - """Called when a new device has been created in deCONZ.""" + """Handle event of new device creation in deCONZ.""" async_dispatcher_send( hass, 'deconz_new_{}'.format(device_type), [device]) diff --git a/homeassistant/components/device_tracker/xiaomi_miio.py b/homeassistant/components/device_tracker/xiaomi_miio.py index f811631766e..b1cfc0aed4a 100644 --- a/homeassistant/components/device_tracker/xiaomi_miio.py +++ b/homeassistant/components/device_tracker/xiaomi_miio.py @@ -73,5 +73,8 @@ class XiaomiMiioDeviceScanner(DeviceScanner): return devices async def async_get_device_name(self, device): - """The repeater doesn't provide the name of the associated device.""" + """Return None. + + The repeater doesn't provide the name of the associated device. + """ return None diff --git a/homeassistant/components/doorbird.py b/homeassistant/components/doorbird.py index 6cd820816e2..c97289b9f07 100644 --- a/homeassistant/components/doorbird.py +++ b/homeassistant/components/doorbird.py @@ -139,17 +139,17 @@ class ConfiguredDoorbird(): @property def name(self): - """Custom device name.""" + """Get custom device name.""" return self._name @property def device(self): - """The configured device.""" + """Get the configured device.""" return self._device @property def custom_url(self): - """Custom url for device.""" + """Get custom url for device.""" return self._custom_url @property diff --git a/homeassistant/components/egardia.py b/homeassistant/components/egardia.py index b7da671bb15..3547f4fc76e 100644 --- a/homeassistant/components/egardia.py +++ b/homeassistant/components/egardia.py @@ -101,7 +101,7 @@ def setup(hass, config): server.start() def handle_stop_event(event): - """Callback function for HA stop event.""" + """Handle HA stop event.""" server.stop() # listen to home assistant stop event diff --git a/homeassistant/components/google_assistant/trait.py b/homeassistant/components/google_assistant/trait.py index d45a84caaa3..26e80e6f03b 100644 --- a/homeassistant/components/google_assistant/trait.py +++ b/homeassistant/components/google_assistant/trait.py @@ -49,7 +49,7 @@ TRAITS = [] def register_trait(trait): - """Decorator to register a trait.""" + """Decorate a function to register a trait.""" TRAITS.append(trait) return trait diff --git a/homeassistant/components/group/__init__.py b/homeassistant/components/group/__init__.py index a33e91f3aa9..eda65d1895d 100644 --- a/homeassistant/components/group/__init__.py +++ b/homeassistant/components/group/__init__.py @@ -550,12 +550,12 @@ class Group(Entity): self._async_update_group_state() async def async_added_to_hass(self): - """Callback when added to HASS.""" + """Handle addition to HASS.""" if self.tracking: self.async_start() async def async_will_remove_from_hass(self): - """Callback when removed from HASS.""" + """Handle removal from HASS.""" if self._async_unsub_state_changed: self._async_unsub_state_changed() self._async_unsub_state_changed = None diff --git a/homeassistant/components/homekit/accessories.py b/homeassistant/components/homekit/accessories.py index a7e895f49e2..adf5273b639 100644 --- a/homeassistant/components/homekit/accessories.py +++ b/homeassistant/components/homekit/accessories.py @@ -27,17 +27,17 @@ _LOGGER = logging.getLogger(__name__) def debounce(func): - """Decorator function. Debounce callbacks form HomeKit.""" + """Decorate function to debounce callbacks from HomeKit.""" @ha_callback def call_later_listener(self, *args): - """Callback listener called from call_later.""" + """Handle call_later callback.""" debounce_params = self.debounce.pop(func.__name__, None) if debounce_params: self.hass.async_add_job(func, self, *debounce_params[1:]) @wraps(func) def wrapper(self, *args): - """Wrapper starts async timer.""" + """Start async timer.""" debounce_params = self.debounce.pop(func.__name__, None) if debounce_params: debounce_params[0]() # remove listener @@ -88,7 +88,7 @@ class HomeAccessory(Accessory): CHAR_STATUS_LOW_BATTERY, value=0) async def run(self): - """Method called by accessory after driver is started. + """Handle accessory driver started event. Run inside the HAP-python event loop. """ @@ -100,7 +100,7 @@ class HomeAccessory(Accessory): @ha_callback def update_state_callback(self, entity_id=None, old_state=None, new_state=None): - """Callback from state change listener.""" + """Handle state change listener callback.""" _LOGGER.debug('New_state: %s', new_state) if new_state is None: return @@ -131,7 +131,7 @@ class HomeAccessory(Accessory): hk_charging) def update_state(self, new_state): - """Method called on state change to update HomeKit value. + """Handle state change to update HomeKit value. Overridden by accessory types. """ diff --git a/homeassistant/components/http/ban.py b/homeassistant/components/http/ban.py index ab582066a22..015c386e836 100644 --- a/homeassistant/components/http/ban.py +++ b/homeassistant/components/http/ban.py @@ -71,7 +71,7 @@ async def ban_middleware(request, handler): def log_invalid_auth(func): - """Decorator to handle invalid auth or failed login attempts.""" + """Decorate function to handle invalid auth or failed login attempts.""" async def handle_req(view, request, *args, **kwargs): """Try to log failed login attempts if response status >= 400.""" resp = await func(view, request, *args, **kwargs) diff --git a/homeassistant/components/ihc/ihcdevice.py b/homeassistant/components/ihc/ihcdevice.py index 2ccca366d90..93ab81850c9 100644 --- a/homeassistant/components/ihc/ihcdevice.py +++ b/homeassistant/components/ihc/ihcdevice.py @@ -57,7 +57,7 @@ class IHCDevice(Entity): } def on_ihc_change(self, ihc_id, value): - """Callback when IHC resource changes. + """Handle IHC resource change. Derived classes must overwrite this to do device specific stuff. """ diff --git a/homeassistant/components/iota.py b/homeassistant/components/iota.py index ada70f8a9eb..717213da9ac 100644 --- a/homeassistant/components/iota.py +++ b/homeassistant/components/iota.py @@ -57,7 +57,7 @@ class IotaDevice(Entity): """Representation of a IOTA device.""" def __init__(self, name, seed, iri, is_testnet=False): - """Initialisation of the IOTA device.""" + """Initialise the IOTA device.""" self._name = name self._seed = seed self.iri = iri diff --git a/homeassistant/components/knx.py b/homeassistant/components/knx.py index 5b3af3029b4..b15963fa6bd 100644 --- a/homeassistant/components/knx.py +++ b/homeassistant/components/knx.py @@ -334,7 +334,7 @@ class KNXExposeSensor: self.hass, self.entity_id, self._async_entity_changed) async def _async_entity_changed(self, entity_id, old_state, new_state): - """Callback after entity changed.""" + """Handle entity change.""" if new_state is None: return await self.device.set(float(new_state.state)) diff --git a/homeassistant/components/light/group.py b/homeassistant/components/light/group.py index b2fdd36abe7..c8b7e98160b 100644 --- a/homeassistant/components/light/group.py +++ b/homeassistant/components/light/group.py @@ -80,7 +80,7 @@ class LightGroup(light.Light): await self.async_update() async def async_will_remove_from_hass(self): - """Callback when removed from HASS.""" + """Handle removal from HASS.""" if self._async_unsub_state_changed is not None: self._async_unsub_state_changed() self._async_unsub_state_changed = None diff --git a/homeassistant/components/light/ihc.py b/homeassistant/components/light/ihc.py index aef50b12ad7..480cfa7ad94 100644 --- a/homeassistant/components/light/ihc.py +++ b/homeassistant/components/light/ihc.py @@ -109,7 +109,7 @@ class IhcLight(IHCDevice, Light): self.ihc_controller.set_runtime_value_bool(self.ihc_id, False) def on_ihc_change(self, ihc_id, value): - """Callback from IHC notifications.""" + """Handle IHC notifications.""" if isinstance(value, bool): self._dimmable = False self._state = value != 0 diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index 2263a865758..ded58248d8e 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -190,7 +190,7 @@ class LimitlessLEDGroup(Light): @asyncio.coroutine def async_added_to_hass(self): - """Called when entity is about to be added to hass.""" + """Handle entity about to be added to hass event.""" last_state = yield from async_get_last_state(self.hass, self.entity_id) if last_state: self._is_on = (last_state.state == STATE_ON) diff --git a/homeassistant/components/light/lw12wifi.py b/homeassistant/components/light/lw12wifi.py index 5b5a3b6f5c9..46bebe8086f 100644 --- a/homeassistant/components/light/lw12wifi.py +++ b/homeassistant/components/light/lw12wifi.py @@ -53,7 +53,7 @@ class LW12WiFi(Light): """LW-12 WiFi LED Controller.""" def __init__(self, name, lw12_light): - """Initialisation of LW-12 WiFi LED Controller. + """Initialise LW-12 WiFi LED Controller. Args: name: Friendly name for this platform to use. diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 099b365c50b..2c66d458095 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -146,7 +146,7 @@ def _setup_internal_discovery(hass: HomeAssistantType) -> None: import pychromecast def internal_callback(name): - """Called when zeroconf has discovered a new chromecast.""" + """Handle zeroconf discovery of a new chromecast.""" mdns = listener.services[name] _discover_chromecast(hass, ChromecastInfo(*mdns)) @@ -229,7 +229,7 @@ async def _async_setup_platform(hass: HomeAssistantType, config: ConfigType, @callback def async_cast_discovered(discover: ChromecastInfo) -> None: - """Callback for when a new chromecast is discovered.""" + """Handle discovery of a new chromecast.""" if info is not None and info.host_port != discover.host_port: # Not our requested cast device. return @@ -277,17 +277,17 @@ class CastStatusListener: chromecast.register_connection_listener(self) def new_cast_status(self, cast_status): - """Called when a new CastStatus is received.""" + """Handle reception of a new CastStatus.""" if self._valid: self._cast_device.new_cast_status(cast_status) def new_media_status(self, media_status): - """Called when a new MediaStatus is received.""" + """Handle reception of a new MediaStatus.""" if self._valid: self._cast_device.new_media_status(media_status) def new_connection_status(self, connection_status): - """Called when a new ConnectionStatus is received.""" + """Handle reception of a new ConnectionStatus.""" if self._valid: self._cast_device.new_connection_status(connection_status) @@ -321,7 +321,7 @@ class CastDevice(MediaPlayerDevice): """Create chromecast object when added to hass.""" @callback def async_cast_discovered(discover: ChromecastInfo): - """Callback for changing elected leaders / IP.""" + """Handle discovery of new Chromecast.""" if self._cast_info.uuid is None: # We can't handle empty UUIDs return diff --git a/homeassistant/components/media_player/channels.py b/homeassistant/components/media_player/channels.py index 16c768796c5..71ef5412d9e 100644 --- a/homeassistant/components/media_player/channels.py +++ b/homeassistant/components/media_player/channels.py @@ -70,7 +70,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass.data[DATA_CHANNELS].append(device) def service_handler(service): - """Handler for services.""" + """Handle service.""" entity_id = service.data.get(ATTR_ENTITY_ID) device = next((device for device in hass.data[DATA_CHANNELS] if diff --git a/homeassistant/components/media_player/dlna_dmr.py b/homeassistant/components/media_player/dlna_dmr.py index ebb1ab8d383..7a0049df867 100644 --- a/homeassistant/components/media_player/dlna_dmr.py +++ b/homeassistant/components/media_player/dlna_dmr.py @@ -180,7 +180,7 @@ class DlnaDmrDevice(MediaPlayerDevice): self._subscription_renew_time = None async def async_added_to_hass(self): - """Callback when added.""" + """Handle addition.""" self._device.on_event = self._on_event # register unsubscribe on stop diff --git a/homeassistant/components/media_player/mediaroom.py b/homeassistant/components/media_player/mediaroom.py index 32f1bb6e0ae..fd7229f79f5 100644 --- a/homeassistant/components/media_player/mediaroom.py +++ b/homeassistant/components/media_player/mediaroom.py @@ -103,7 +103,7 @@ class MediaroomDevice(MediaPlayerDevice): """Representation of a Mediaroom set-up-box on the network.""" def set_state(self, mediaroom_state): - """Helper method to map pymediaroom states to HA states.""" + """Map pymediaroom state to HA state.""" from pymediaroom import State state_map = { diff --git a/homeassistant/components/remote/xiaomi_miio.py b/homeassistant/components/remote/xiaomi_miio.py index caab75bc841..1cc48f7adb2 100644 --- a/homeassistant/components/remote/xiaomi_miio.py +++ b/homeassistant/components/remote/xiaomi_miio.py @@ -249,7 +249,7 @@ class XiaomiMiioRemote(RemoteDevice): payload, ex) def send_command(self, command, **kwargs): - """Wrapper for _send_command.""" + """Send a command.""" num_repeats = kwargs.get(ATTR_NUM_REPEATS) delay = kwargs.get(ATTR_DELAY_SECS, DEFAULT_DELAY_SECS) diff --git a/homeassistant/components/sabnzbd.py b/homeassistant/components/sabnzbd.py index f23831259a5..380867a3285 100644 --- a/homeassistant/components/sabnzbd.py +++ b/homeassistant/components/sabnzbd.py @@ -193,7 +193,7 @@ def async_request_configuration(hass, config, host): return def success(): - """Setup was successful.""" + """Signal successful setup.""" conf = load_json(hass.config.path(CONFIG_FILE)) conf[host] = {CONF_API_KEY: api_key} save_json(hass.config.path(CONFIG_FILE), conf) diff --git a/homeassistant/components/sensor/bmw_connected_drive.py b/homeassistant/components/sensor/bmw_connected_drive.py index e3331cdc763..deafacc288c 100644 --- a/homeassistant/components/sensor/bmw_connected_drive.py +++ b/homeassistant/components/sensor/bmw_connected_drive.py @@ -58,7 +58,10 @@ class BMWConnectedDriveSensor(Entity): @property def should_poll(self) -> bool: - """Data update is triggered from BMWConnectedDriveEntity.""" + """Return False. + + Data update is triggered from BMWConnectedDriveEntity. + """ return False @property diff --git a/homeassistant/components/sensor/fints.py b/homeassistant/components/sensor/fints.py index b30bdd4a30c..c573f0f0058 100644 --- a/homeassistant/components/sensor/fints.py +++ b/homeassistant/components/sensor/fints.py @@ -108,7 +108,7 @@ class FinTsClient: """ def __init__(self, credentials: BankCredentials, name: str): - """Constructor for class FinTsClient.""" + """Initialize a FinTsClient.""" self._credentials = credentials self.name = name @@ -158,7 +158,7 @@ class FinTsAccount(Entity): """ def __init__(self, client: FinTsClient, account, name: str) -> None: - """Constructor for class FinTsAccount.""" + """Initialize a FinTs balance account.""" self._client = client # type: FinTsClient self._account = account self._name = name # type: str @@ -167,7 +167,10 @@ class FinTsAccount(Entity): @property def should_poll(self) -> bool: - """Data needs to be polled from the bank servers.""" + """Return True. + + Data needs to be polled from the bank servers. + """ return True def update(self) -> None: @@ -218,7 +221,7 @@ class FinTsHoldingsAccount(Entity): """ def __init__(self, client: FinTsClient, account, name: str) -> None: - """Constructor for class FinTsHoldingsAccount.""" + """Initialize a FinTs holdings account.""" self._client = client # type: FinTsClient self._name = name # type: str self._account = account @@ -227,7 +230,10 @@ class FinTsHoldingsAccount(Entity): @property def should_poll(self) -> bool: - """Data needs to be polled from the bank servers.""" + """Return True. + + Data needs to be polled from the bank servers. + """ return True def update(self) -> None: diff --git a/homeassistant/components/sensor/ihc.py b/homeassistant/components/sensor/ihc.py index 7af034c4b93..547e6b52d9a 100644 --- a/homeassistant/components/sensor/ihc.py +++ b/homeassistant/components/sensor/ihc.py @@ -77,6 +77,6 @@ class IHCSensor(IHCDevice, Entity): return self._unit_of_measurement def on_ihc_change(self, ihc_id, value): - """Callback when IHC resource changes.""" + """Handle IHC resource change.""" self._state = value self.schedule_update_ha_state() diff --git a/homeassistant/components/sensor/uscis.py b/homeassistant/components/sensor/uscis.py index 167f12f66c0..f93a788092b 100644 --- a/homeassistant/components/sensor/uscis.py +++ b/homeassistant/components/sensor/uscis.py @@ -72,7 +72,7 @@ class UscisSensor(Entity): @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): - """Using Request to access USCIS website and fetch data.""" + """Fetch data from the USCIS website and update state attributes.""" import uscisstatus try: status = uscisstatus.get_case_status(self._case_id) diff --git a/homeassistant/components/sensor/wirelesstag.py b/homeassistant/components/sensor/wirelesstag.py index 8c3fae6e990..e5166173cb9 100644 --- a/homeassistant/components/sensor/wirelesstag.py +++ b/homeassistant/components/sensor/wirelesstag.py @@ -98,7 +98,7 @@ class WirelessTagSensor(WirelessTagBaseSensor): else all_sensors) def __init__(self, api, tag, sensor_type, config): - """Constructor with platform(api), tag and hass sensor type.""" + """Initialize a WirelessTag sensor.""" super().__init__(api, tag) self._sensor_type = sensor_type diff --git a/homeassistant/components/switch/ihc.py b/homeassistant/components/switch/ihc.py index c2fbeacef59..f744519e430 100644 --- a/homeassistant/components/switch/ihc.py +++ b/homeassistant/components/switch/ihc.py @@ -70,6 +70,6 @@ class IHCSwitch(IHCDevice, SwitchDevice): self.ihc_controller.set_runtime_value_bool(self.ihc_id, False) def on_ihc_change(self, ihc_id, value): - """Callback when the IHC resource changes.""" + """Handle IHC resource change.""" self._state = value self.schedule_update_ha_state() diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index 594f290273e..199156afc21 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -77,7 +77,7 @@ class WemoSwitch(SwitchDevice): self._async_locked_subscription_callback(not updated)) async def _async_locked_subscription_callback(self, force_update): - """Helper to handle an update from a subscription.""" + """Handle an update from a subscription.""" # If an update is in progress, we don't do anything if self._update_lock.locked(): return diff --git a/homeassistant/components/wirelesstag.py b/homeassistant/components/wirelesstag.py index 0afd976c9e3..19fb2d40b5d 100644 --- a/homeassistant/components/wirelesstag.py +++ b/homeassistant/components/wirelesstag.py @@ -80,7 +80,7 @@ class WirelessTagPlatform: # pylint: disable=no-self-use def make_push_notitication(self, name, url, content): - """Factory for notification config.""" + """Create notification config.""" from wirelesstagpy import NotificationConfig return NotificationConfig(name, { 'url': url, 'verb': 'POST', @@ -129,7 +129,7 @@ class WirelessTagPlatform: self.hass.config.api.base_url) def handle_update_tags_event(self, event): - """Main entry to handle push event from wireless tag manager.""" + """Handle push event from wireless tag manager.""" _LOGGER.info("push notification for update arrived: %s", event) dispatcher_send( self.hass, @@ -215,7 +215,10 @@ class WirelessTagBaseSensor(Entity): return 0 def updated_state_value(self): - """Default implementation formats princial value.""" + """Return formatted value. + + The default implementation formats principal value. + """ return self.decorate_value(self.principal_value) # pylint: disable=no-self-use diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index 030e342847d..f17e7f02344 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -341,7 +341,7 @@ class Entity(entity.Entity): application_listener.register_entity(ieee, self) async def async_added_to_hass(self): - """Callback once the entity is added to hass. + """Handle entity addition to hass. It is now safe to update the entity state """ diff --git a/homeassistant/components/zwave/node_entity.py b/homeassistant/components/zwave/node_entity.py index 2c6d26802bd..94de03686d3 100644 --- a/homeassistant/components/zwave/node_entity.py +++ b/homeassistant/components/zwave/node_entity.py @@ -107,7 +107,7 @@ class ZWaveNodeEntity(ZWaveBaseEntity): @property def unique_id(self): - """Unique ID of Z-wave node.""" + """Return unique ID of Z-wave node.""" return self._unique_id def network_node_changed(self, node=None, value=None, args=None): diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index 78b38afa438..3276763a967 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -87,7 +87,7 @@ class DeviceRegistry: @callback def _data_to_save(self): - """Data of device registry to store in a file.""" + """Return data of device registry to store in a file.""" data = {} data['devices'] = [ diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index 6d7392d00bf..78806e65ef1 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -378,7 +378,7 @@ class Entity: @callback def async_registry_updated(self, old, new): - """Called when the entity registry has been updated.""" + """Handle entity registry update.""" self.registry_name = new.name if new.entity_id == self.entity_id: diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 1f99c90eb00..09f8838b160 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -52,7 +52,7 @@ class EntityComponent: in self._platforms.values()) def get_entity(self, entity_id): - """Helper method to get an entity.""" + """Get an entity.""" for platform in self._platforms.values(): entity = platform.entities.get(entity_id) if entity is not None: @@ -243,7 +243,7 @@ class EntityComponent: def _async_init_entity_platform(self, platform_type, platform, scan_interval=None, entity_namespace=None): - """Helper to initialize an entity platform.""" + """Initialize an entity platform.""" if scan_interval is None: scan_interval = self.scan_interval diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index fa880b014ec..c65aa5e98c2 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -106,7 +106,7 @@ class EntityPlatform: return await self._async_setup_platform(async_create_setup_task) async def _async_setup_platform(self, async_create_setup_task, tries=0): - """Helper to set up a platform via config file or config entry. + """Set up a platform via config file or config entry. async_create_setup_task creates a coroutine that sets up platform. """ @@ -168,7 +168,7 @@ class EntityPlatform: warn_task.cancel() def _schedule_add_entities(self, new_entities, update_before_add=False): - """Synchronously schedule adding entities for a single platform.""" + """Schedule adding entities for a single platform, synchronously.""" run_callback_threadsafe( self.hass.loop, self._async_schedule_add_entities, list(new_entities), @@ -237,7 +237,7 @@ class EntityPlatform: async def _async_add_entity(self, entity, update_before_add, component_entities, entity_registry, device_registry): - """Helper method to add an entity to the platform.""" + """Add an entity to the platform.""" if entity is None: raise ValueError('Entity cannot be None') diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 9c478b0b848..804ee4235d0 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -234,7 +234,7 @@ class EntityRegistry: @callback def _data_to_save(self): - """Data of entity registry to store in a file.""" + """Return data of entity registry to store in a file.""" data = {} data['entities'] = [ diff --git a/homeassistant/helpers/storage.py b/homeassistant/helpers/storage.py index 8931341f1a2..95e6925b2a4 100644 --- a/homeassistant/helpers/storage.py +++ b/homeassistant/helpers/storage.py @@ -18,12 +18,12 @@ _LOGGER = logging.getLogger(__name__) async def async_migrator(hass, old_path, store, *, old_conf_load_func=json.load_json, old_conf_migrate_func=None): - """Helper function to migrate old data to a store and then load data. + """Migrate old data to a store and then load data. async def old_conf_migrate_func(old_data) """ def load_old_config(): - """Helper to load old config.""" + """Load old config.""" if not os.path.isfile(old_path): return None @@ -77,7 +77,7 @@ class Store: return await self._load_task async def _async_load(self): - """Helper to load the data.""" + """Load the data.""" # Check if we have a pending write if self._data is not None: data = self._data @@ -165,7 +165,7 @@ class Store: await self._async_handle_write_data() async def _async_handle_write_data(self, *_args): - """Handler to handle writing the config.""" + """Handle writing the config.""" data = self._data if 'data_func' in data: diff --git a/requirements_test.txt b/requirements_test.txt index 542c378c89f..e50ef699848 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -3,11 +3,11 @@ # new version asynctest==0.12.2 coveralls==1.2.0 -flake8-docstrings==1.0.3 +flake8-docstrings==1.3.0 flake8==3.5 mock-open==1.3.1 mypy==0.620 -pydocstyle==1.1.1 +pydocstyle==2.1.1 pylint==2.1.1 pytest-aiohttp==0.3.0 pytest-cov==2.5.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4b907f89b11..23fc37a3c68 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -4,11 +4,11 @@ # new version asynctest==0.12.2 coveralls==1.2.0 -flake8-docstrings==1.0.3 +flake8-docstrings==1.3.0 flake8==3.5 mock-open==1.3.1 mypy==0.620 -pydocstyle==1.1.1 +pydocstyle==2.1.1 pylint==2.1.1 pytest-aiohttp==0.3.0 pytest-cov==2.5.1 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index e709abfc10b..9a1eb172326 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -156,7 +156,7 @@ def core_requirements(): def comment_requirement(req): - """Some requirements don't install on all systems.""" + """Comment out requirement. Some don't install on all systems.""" return any(ign in req for ign in COMMENT_REQUIREMENTS) @@ -295,7 +295,7 @@ def validate_constraints_file(data): def main(validate): - """Main section of the script.""" + """Run the script.""" if not os.path.isfile('requirements_all.txt'): print('Run this from HA root dir') return 1 diff --git a/script/inspect_schemas.py b/script/inspect_schemas.py index f2fdff22f7a..46d5cf92ecc 100755 --- a/script/inspect_schemas.py +++ b/script/inspect_schemas.py @@ -18,7 +18,7 @@ def explore_module(package): def main(): - """Main section of the script.""" + """Run the script.""" if not os.path.isfile('requirements_all.txt'): print('Run this from HA root dir') return diff --git a/script/lazytox.py b/script/lazytox.py index f0388a0fdcb..7f2340c726f 100755 --- a/script/lazytox.py +++ b/script/lazytox.py @@ -153,7 +153,7 @@ async def lint(files): async def main(): - """The main loop.""" + """Run the main loop.""" # Ensure we are in the homeassistant root os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) diff --git a/script/translations_download_split.py b/script/translations_download_split.py index 03718cf7cab..180c7281a2f 100755 --- a/script/translations_download_split.py +++ b/script/translations_download_split.py @@ -88,7 +88,7 @@ def save_language_translations(lang, translations): def main(): - """Main section of the script.""" + """Run the script.""" if not os.path.isfile("requirements_all.txt"): print("Run this from HA root dir") return diff --git a/script/translations_upload_merge.py b/script/translations_upload_merge.py index ce0a14c85e6..c1a039363cd 100755 --- a/script/translations_upload_merge.py +++ b/script/translations_upload_merge.py @@ -73,7 +73,7 @@ def get_translation_dict(translations, component, platform): def main(): - """Main section of the script.""" + """Run the script.""" if not os.path.isfile("requirements_all.txt"): print("Run this from HA root dir") return diff --git a/tests/common.py b/tests/common.py index f39f9ca0a18..738c51fb3f0 100644 --- a/tests/common.py +++ b/tests/common.py @@ -360,7 +360,7 @@ class MockUser(auth_models.User): async def register_auth_provider(hass, config): - """Helper to register an auth provider.""" + """Register an auth provider.""" provider = await auth_providers.auth_provider_from_config( hass, hass.auth._store, config) assert provider is not None, 'Invalid config specified' @@ -749,7 +749,7 @@ class MockEntity(entity.Entity): return self._handle('available') def _handle(self, attr): - """Helper for the attributes.""" + """Return attribute value.""" if attr in self._values: return self._values[attr] return getattr(super(), attr) diff --git a/tests/components/auth/__init__.py b/tests/components/auth/__init__.py index 4c357fc4db9..799d31f3db8 100644 --- a/tests/components/auth/__init__.py +++ b/tests/components/auth/__init__.py @@ -20,7 +20,7 @@ EMPTY_CONFIG = [] async def async_setup_auth(hass, aiohttp_client, provider_configs=BASE_CONFIG, module_configs=EMPTY_CONFIG, setup_api=False): - """Helper to set up authentication and create an HTTP client.""" + """Set up authentication and create an HTTP client.""" hass.auth = await auth.auth_manager_from_config( hass, provider_configs, module_configs) ensure_auth_manager_loaded(hass.auth) diff --git a/tests/components/auth/test_init_link_user.py b/tests/components/auth/test_init_link_user.py index 5166f661491..6c9fdf3fbc2 100644 --- a/tests/components/auth/test_init_link_user.py +++ b/tests/components/auth/test_init_link_user.py @@ -5,7 +5,7 @@ from tests.common import CLIENT_ID, CLIENT_REDIRECT_URI async def async_get_code(hass, aiohttp_client): - """Helper for link user tests that returns authorization code.""" + """Return authorization code for link user tests.""" config = [{ 'name': 'Example', 'type': 'insecure_example', diff --git a/tests/components/automation/test_event.py b/tests/components/automation/test_event.py index 1b1ab440f5d..c52ea7b9d29 100644 --- a/tests/components/automation/test_event.py +++ b/tests/components/automation/test_event.py @@ -20,7 +20,7 @@ class TestAutomationEvent(unittest.TestCase): @callback def record_call(service): - """Helper for recording the call.""" + """Record the call.""" self.calls.append(service) self.hass.services.register('test', 'automation', record_call) diff --git a/tests/components/automation/test_mqtt.py b/tests/components/automation/test_mqtt.py index f4669e803b6..8ec5351af94 100644 --- a/tests/components/automation/test_mqtt.py +++ b/tests/components/automation/test_mqtt.py @@ -22,7 +22,7 @@ class TestAutomationMQTT(unittest.TestCase): @callback def record_call(service): - """Helper to record calls.""" + """Record calls.""" self.calls.append(service) self.hass.services.register('test', 'automation', record_call) diff --git a/tests/components/automation/test_numeric_state.py b/tests/components/automation/test_numeric_state.py index 0d73514f306..49565c37222 100644 --- a/tests/components/automation/test_numeric_state.py +++ b/tests/components/automation/test_numeric_state.py @@ -25,7 +25,7 @@ class TestAutomationNumericState(unittest.TestCase): @callback def record_call(service): - """Helper to record calls.""" + """Record calls.""" self.calls.append(service) self.hass.services.register('test', 'automation', record_call) diff --git a/tests/components/automation/test_template.py b/tests/components/automation/test_template.py index 5d75a273aea..ef064a2c1d8 100644 --- a/tests/components/automation/test_template.py +++ b/tests/components/automation/test_template.py @@ -22,7 +22,7 @@ class TestAutomationTemplate(unittest.TestCase): @callback def record_call(service): - """Helper to record calls.""" + """Record calls.""" self.calls.append(service) self.hass.services.register('test', 'automation', record_call) diff --git a/tests/components/automation/test_time.py b/tests/components/automation/test_time.py index 251acfa3431..5f928cf92a0 100644 --- a/tests/components/automation/test_time.py +++ b/tests/components/automation/test_time.py @@ -25,7 +25,7 @@ class TestAutomationTime(unittest.TestCase): @callback def record_call(service): - """Helper to record calls.""" + """Record calls.""" self.calls.append(service) self.hass.services.register('test', 'automation', record_call) diff --git a/tests/components/automation/test_zone.py b/tests/components/automation/test_zone.py index cca1c63e8c1..baa3bdc1d28 100644 --- a/tests/components/automation/test_zone.py +++ b/tests/components/automation/test_zone.py @@ -29,7 +29,7 @@ class TestAutomationZone(unittest.TestCase): @callback def record_call(service): - """Helper to record calls.""" + """Record calls.""" self.calls.append(service) self.hass.services.register('test', 'automation', record_call) diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index 97a4ea7c067..b1b68ff92df 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -323,7 +323,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): @callback def listener(event): - """Helper method that will verify our event got called.""" + """Record that our event got called.""" test_events.append(event) self.hass.bus.listen("device_tracker_new_device", listener) diff --git a/tests/components/device_tracker/test_locative.py b/tests/components/device_tracker/test_locative.py index 90adccf7703..7cfef8f5219 100644 --- a/tests/components/device_tracker/test_locative.py +++ b/tests/components/device_tracker/test_locative.py @@ -11,7 +11,7 @@ from homeassistant.components.device_tracker.locative import URL def _url(data=None): - """Helper method to generate URLs.""" + """Generate URL.""" data = data or {} data = "&".join(["{}={}".format(name, value) for name, value in data.items()]) diff --git a/tests/components/fan/test_demo.py b/tests/components/fan/test_demo.py index 0d066af8cf6..69680fb1cfd 100644 --- a/tests/components/fan/test_demo.py +++ b/tests/components/fan/test_demo.py @@ -15,7 +15,7 @@ class TestDemoFan(unittest.TestCase): """Test the fan demo platform.""" def get_entity(self): - """Helper method to get the fan entity.""" + """Get the fan entity.""" return self.hass.states.get(FAN_ENTITY_ID) def setUp(self): diff --git a/tests/components/http/test_real_ip.py b/tests/components/http/test_real_ip.py index 6cf6fec6bce..c28d810d41b 100644 --- a/tests/components/http/test_real_ip.py +++ b/tests/components/http/test_real_ip.py @@ -8,7 +8,7 @@ from homeassistant.components.http.const import KEY_REAL_IP async def mock_handler(request): - """Handler that returns the real IP as text.""" + """Return the real IP as text.""" return web.Response(text=str(request[KEY_REAL_IP])) diff --git a/tests/components/media_player/test_cast.py b/tests/components/media_player/test_cast.py index 8364d8c96ef..c3e777ea334 100644 --- a/tests/components/media_player/test_cast.py +++ b/tests/components/media_player/test_cast.py @@ -48,7 +48,7 @@ def get_fake_chromecast_info(host='192.168.178.42', port=8009, async def async_setup_cast(hass, config=None, discovery_info=None): - """Helper to set up the cast platform.""" + """Set up the cast platform.""" if config is None: config = {} add_devices = Mock() diff --git a/tests/components/media_player/test_samsungtv.py b/tests/components/media_player/test_samsungtv.py index 349067f7cd3..6dd61157851 100644 --- a/tests/components/media_player/test_samsungtv.py +++ b/tests/components/media_player/test_samsungtv.py @@ -52,7 +52,7 @@ class TestSamsungTv(unittest.TestCase): @MockDependency('samsungctl') @MockDependency('wakeonlan') def setUp(self, samsung_mock, wol_mock): - """Setting up test environment.""" + """Set up test environment.""" self.hass = tests.common.get_test_home_assistant() self.hass.start() self.hass.block_till_done() diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index ab8e316422a..99c16670764 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -94,7 +94,7 @@ class MockMediaPlayer(media_player.MediaPlayerDevice): @property def volume_level(self): - """The volume level of player.""" + """Return the volume level of player.""" return self._volume_level @property diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index 89836c34f22..ecbc7cb9b02 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -56,7 +56,7 @@ class TestMQTTComponent(unittest.TestCase): @callback def record_calls(self, *args): - """Helper for recording calls.""" + """Record calls.""" self.calls.append(args) def aiohttp_client_stops_on_home_assistant_start(self): @@ -199,7 +199,7 @@ class TestMQTTCallbacks(unittest.TestCase): @callback def record_calls(self, *args): - """Helper for recording calls.""" + """Record calls.""" self.calls.append(args) def aiohttp_client_starts_on_home_assistant_mqtt_setup(self): diff --git a/tests/components/notify/test_demo.py b/tests/components/notify/test_demo.py index f98fa258186..f9c107a447e 100644 --- a/tests/components/notify/test_demo.py +++ b/tests/components/notify/test_demo.py @@ -73,7 +73,7 @@ class TestNotifyDemo(unittest.TestCase): @callback def record_calls(self, *args): - """Helper for recording calls.""" + """Record calls.""" self.calls.append(args) def test_sending_none_message(self): diff --git a/tests/components/sensor/test_yweather.py b/tests/components/sensor/test_yweather.py index 8b3361a4360..2912229d712 100644 --- a/tests/components/sensor/test_yweather.py +++ b/tests/components/sensor/test_yweather.py @@ -100,7 +100,7 @@ class YahooWeatherMock(): @property def Now(self): # pylint: disable=invalid-name - """Current weather data.""" + """Return current weather data.""" if self.woeid == '111': raise ValueError return self._data['query']['results']['channel']['item']['condition'] diff --git a/tests/components/test_api.py b/tests/components/test_api.py index 2be1168b86a..6f6b4e93068 100644 --- a/tests/components/test_api.py +++ b/tests/components/test_api.py @@ -154,7 +154,7 @@ def test_api_fire_event_with_no_data(hass, mock_api_client): @ha.callback def listener(event): - """Helper method that will verify our event got called.""" + """Record that our event got called.""" test_value.append(1) hass.bus.async_listen_once("test.event_no_data", listener) @@ -174,7 +174,7 @@ def test_api_fire_event_with_data(hass, mock_api_client): @ha.callback def listener(event): - """Helper method that will verify that our event got called. + """Record that our event got called. Also test if our data came through. """ @@ -200,7 +200,7 @@ def test_api_fire_event_with_invalid_json(hass, mock_api_client): @ha.callback def listener(event): - """Helper method that will verify our event got called.""" + """Record that our event got called.""" test_value.append(1) hass.bus.async_listen_once("test_event_bad_data", listener) @@ -281,7 +281,7 @@ def test_api_call_service_no_data(hass, mock_api_client): @ha.callback def listener(service_call): - """Helper method that will verify that our service got called.""" + """Record that our service got called.""" test_value.append(1) hass.services.async_register("test_domain", "test_service", listener) @@ -300,7 +300,7 @@ def test_api_call_service_with_data(hass, mock_api_client): @ha.callback def listener(service_call): - """Helper method that will verify that our service got called. + """Record that our service got called. Also test if our data came through. """ @@ -440,7 +440,7 @@ async def test_api_fire_event_context(hass, mock_api_client, @ha.callback def listener(event): - """Helper method that will verify our event got called.""" + """Record that our event got called.""" test_value.append(event) hass.bus.async_listen("test.event", listener) diff --git a/tests/components/test_discovery.py b/tests/components/test_discovery.py index 8b997cb911c..d4566bc0b03 100644 --- a/tests/components/test_discovery.py +++ b/tests/components/test_discovery.py @@ -47,7 +47,7 @@ def netdisco_mock(): async def mock_discovery(hass, discoveries, config=BASE_CONFIG): - """Helper to mock discoveries.""" + """Mock discoveries.""" result = await async_setup_component(hass, 'discovery', config) assert result diff --git a/tests/components/test_feedreader.py b/tests/components/test_feedreader.py index 336d19664b4..dd98ebaf189 100644 --- a/tests/components/test_feedreader.py +++ b/tests/components/test_feedreader.py @@ -79,7 +79,7 @@ class TestFeedreaderComponent(unittest.TestCase): VALID_CONFIG_3)) def setup_manager(self, feed_data, max_entries=DEFAULT_MAX_ENTRIES): - """Generic test setup method.""" + """Set up feed manager.""" events = [] @callback diff --git a/tests/components/test_pilight.py b/tests/components/test_pilight.py index 9304463b6fd..e630a354f45 100644 --- a/tests/components/test_pilight.py +++ b/tests/components/test_pilight.py @@ -41,11 +41,11 @@ class PilightDaemonSim: pass def send_code(self, call): # pylint: disable=no-self-use - """Called pilight.send service is called.""" + """Handle pilight.send service callback.""" _LOGGER.error('PilightDaemonSim payload: ' + str(call)) def start(self): - """Called homeassistant.start is called. + """Handle homeassistant.start callback. Also sends one test message after start up """ @@ -56,11 +56,11 @@ class PilightDaemonSim: self.called = True def stop(self): # pylint: disable=no-self-use - """Called homeassistant.stop is called.""" + """Handle homeassistant.stop callback.""" _LOGGER.error('PilightDaemonSim stop') def set_callback(self, function): - """Callback called on event pilight.pilight_received.""" + """Handle pilight.pilight_received event callback.""" self.callback = function _LOGGER.error('PilightDaemonSim callback: ' + str(function)) diff --git a/tests/components/test_upnp.py b/tests/components/test_upnp.py index 38575c411da..6089e6859f2 100644 --- a/tests/components/test_upnp.py +++ b/tests/components/test_upnp.py @@ -47,7 +47,7 @@ class MockResp(MagicMock): @pytest.fixture def mock_msearch_first(*args, **kwargs): - """Wrapper to async mock function.""" + """Wrap async mock msearch_first.""" async def async_mock_msearch_first(*args, **kwargs): """Mock msearch_first.""" return MockResp(*args, **kwargs) @@ -58,7 +58,7 @@ def mock_msearch_first(*args, **kwargs): @pytest.fixture def mock_async_exception(*args, **kwargs): - """Wrapper to async mock function with exception.""" + """Wrap async mock exception.""" async def async_mock_exception(*args, **kwargs): return Exception diff --git a/tests/components/weather/test_yweather.py b/tests/components/weather/test_yweather.py index 8ecaa67535e..c36b4454c93 100644 --- a/tests/components/weather/test_yweather.py +++ b/tests/components/weather/test_yweather.py @@ -41,31 +41,31 @@ class YahooWeatherMock(): @property def RawData(self): # pylint: disable=invalid-name - """Raw Data.""" + """Return raw Data.""" if self.woeid == '12345': return json.loads('[]') return self._data @property def Now(self): # pylint: disable=invalid-name - """Current weather data.""" + """Return current weather data.""" if self.woeid == '111': raise ValueError return self._data['query']['results']['channel']['item']['condition'] @property def Atmosphere(self): # pylint: disable=invalid-name - """Atmosphere weather data.""" + """Return atmosphere weather data.""" return self._data['query']['results']['channel']['atmosphere'] @property def Wind(self): # pylint: disable=invalid-name - """Wind weather data.""" + """Return wind weather data.""" return self._data['query']['results']['channel']['wind'] @property def Forecast(self): # pylint: disable=invalid-name - """Forecast data 0-5 Days.""" + """Return forecast data 0-5 Days.""" if self.woeid == '123123': raise ValueError return self._data['query']['results']['channel']['item']['forecast'] diff --git a/tests/helpers/test_entity_platform.py b/tests/helpers/test_entity_platform.py index b52405aa8be..07901f7aad4 100644 --- a/tests/helpers/test_entity_platform.py +++ b/tests/helpers/test_entity_platform.py @@ -336,7 +336,7 @@ def test_raise_error_on_update(hass): entity2 = MockEntity(name='test_2') def _raise(): - """Helper to raise an exception.""" + """Raise an exception.""" raise AssertionError entity1.update = _raise diff --git a/tests/test_setup.py b/tests/test_setup.py index 1ced1206f65..29712f40ebc 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -257,7 +257,7 @@ class TestSetup: def test_component_exception_setup(self): """Test component that raises exception during setup.""" def exception_setup(hass, config): - """Setup that raises exception.""" + """Raise exception.""" raise Exception('fail!') loader.set_component( @@ -269,7 +269,7 @@ class TestSetup: def test_component_setup_with_validation_and_dependency(self): """Test all config is passed to dependencies.""" def config_check_setup(hass, config): - """Setup method that tests config is passed in.""" + """Test that config is passed in.""" if config.get('comp_a', {}).get('valid', False): return True raise Exception('Config not passed in: {}'.format(config)) From ef0eab0f40879f0e1aa13b815a916d47ab89091b Mon Sep 17 00:00:00 2001 From: Marcel Hoppe Date: Fri, 24 Aug 2018 10:39:35 +0200 Subject: [PATCH 112/159] Hangouts (#16049) * add a component for hangouts * add a notify component for hangouts * add an extra message as title * add support to listen to all conversations hangouts has * move hangouts to package and add parameter documentation * update .coveragerc and requirements_all.txt * makes linter happy again * bugfix * add conversations parameter to command words * Move the resolution of conversation names to conversations in own a function * typo * rename group of exclusion form 'id' to 'id or name' * refactoring and use config_flow * makes linter happy again * remove unused imports * fix not working regex commands * fix translations * cleanup * remove step_init * remove logging entry * clean up events * move constant * remove unsed import * add new files to .converagerc * isort imports * add hangouts_utils to ignored packages * upadte doc and format * fix I/O not in executor jon * rename SERVICE_UPDATE_USERS_AND_CONVERSATIONS to SERVICE_UPDATE * move EVENT_HANGOUTS_{CONNECTED,DISCONNECTED} to dispatcher * add config flow tests * Update tox.ini --- .coveragerc | 6 + .../components/hangouts/.translations/en.json | 31 +++ homeassistant/components/hangouts/__init__.py | 87 +++++++ .../components/hangouts/config_flow.py | 107 ++++++++ homeassistant/components/hangouts/const.py | 78 ++++++ .../components/hangouts/hangouts_bot.py | 229 ++++++++++++++++++ .../components/hangouts/hangups_utils.py | 81 +++++++ .../components/hangouts/services.yaml | 12 + .../components/hangouts/strings.json | 31 +++ homeassistant/components/notify/hangouts.py | 66 +++++ homeassistant/config_entries.py | 1 + requirements_all.txt | 3 + requirements_test_all.txt | 3 + script/gen_requirements_all.py | 4 +- tests/components/hangouts/__init__.py | 1 + tests/components/hangouts/test_config_flow.py | 92 +++++++ 16 files changed, 831 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/hangouts/.translations/en.json create mode 100644 homeassistant/components/hangouts/__init__.py create mode 100644 homeassistant/components/hangouts/config_flow.py create mode 100644 homeassistant/components/hangouts/const.py create mode 100644 homeassistant/components/hangouts/hangouts_bot.py create mode 100644 homeassistant/components/hangouts/hangups_utils.py create mode 100644 homeassistant/components/hangouts/services.yaml create mode 100644 homeassistant/components/hangouts/strings.json create mode 100644 homeassistant/components/notify/hangouts.py create mode 100644 tests/components/hangouts/__init__.py create mode 100644 tests/components/hangouts/test_config_flow.py diff --git a/.coveragerc b/.coveragerc index ea30dec510a..bb0be2d9433 100644 --- a/.coveragerc +++ b/.coveragerc @@ -116,6 +116,12 @@ omit = homeassistant/components/google.py homeassistant/components/*/google.py + homeassistant/components/hangouts/__init__.py + homeassistant/components/hangouts/const.py + homeassistant/components/hangouts/hangouts_bot.py + homeassistant/components/hangouts/hangups_utils.py + homeassistant/components/*/hangouts.py + homeassistant/components/hdmi_cec.py homeassistant/components/*/hdmi_cec.py diff --git a/homeassistant/components/hangouts/.translations/en.json b/homeassistant/components/hangouts/.translations/en.json new file mode 100644 index 00000000000..d8d160ad5ea --- /dev/null +++ b/homeassistant/components/hangouts/.translations/en.json @@ -0,0 +1,31 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts is already configured", + "unknown": "Unknown error occurred." + }, + "error": { + "invalid_2fa": "Invalid 2 Factor Authorization, please try again.", + "invalid_2fa_method": "Invalig 2FA Method (Verify on Phone).", + "invalid_login": "Invalid Login, please try again." + }, + "step": { + "2fa": { + "data": { + "2fa": "2FA Pin" + }, + "description": "", + "title": "2-Factor-Authorization" + }, + "user": { + "data": { + "email": "E-Mail Address", + "password": "Password" + }, + "description": "", + "title": "Google Hangouts Login" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/__init__.py b/homeassistant/components/hangouts/__init__.py new file mode 100644 index 00000000000..89649ecb8e1 --- /dev/null +++ b/homeassistant/components/hangouts/__init__.py @@ -0,0 +1,87 @@ +""" +The hangouts bot component. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/hangouts/ +""" +import logging + +import voluptuous as vol + +from homeassistant import config_entries +from homeassistant.const import EVENT_HOMEASSISTANT_STOP +from homeassistant.helpers import dispatcher + +from .config_flow import configured_hangouts +from .const import ( + CONF_BOT, CONF_COMMANDS, CONF_REFRESH_TOKEN, DOMAIN, + EVENT_HANGOUTS_CONNECTED, EVENT_HANGOUTS_CONVERSATIONS_CHANGED, + MESSAGE_SCHEMA, SERVICE_SEND_MESSAGE, + SERVICE_UPDATE) + +REQUIREMENTS = ['hangups==0.4.5'] + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup(hass, config): + """Set up the Hangouts bot component.""" + config = config.get(DOMAIN, []) + hass.data[DOMAIN] = {CONF_COMMANDS: config[CONF_COMMANDS]} + + if configured_hangouts(hass) is None: + hass.async_add_job(hass.config_entries.flow.async_init( + DOMAIN, context={'source': config_entries.SOURCE_IMPORT} + )) + + return True + + +async def async_setup_entry(hass, config): + """Set up a config entry.""" + from hangups.auth import GoogleAuthError + + try: + from .hangouts_bot import HangoutsBot + + bot = HangoutsBot( + hass, + config.data.get(CONF_REFRESH_TOKEN), + hass.data[DOMAIN][CONF_COMMANDS]) + hass.data[DOMAIN][CONF_BOT] = bot + except GoogleAuthError as exception: + _LOGGER.error("Hangouts failed to log in: %s", str(exception)) + return False + + dispatcher.async_dispatcher_connect( + hass, + EVENT_HANGOUTS_CONNECTED, + bot.async_handle_update_users_and_conversations) + + dispatcher.async_dispatcher_connect( + hass, + EVENT_HANGOUTS_CONVERSATIONS_CHANGED, + bot.async_update_conversation_commands) + + hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, + bot.async_handle_hass_stop) + + await bot.async_connect() + + hass.services.async_register(DOMAIN, SERVICE_SEND_MESSAGE, + bot.async_handle_send_message, + schema=MESSAGE_SCHEMA) + hass.services.async_register(DOMAIN, + SERVICE_UPDATE, + bot. + async_handle_update_users_and_conversations, + schema=vol.Schema({})) + + return True + + +async def async_unload_entry(hass, _): + """Unload a config entry.""" + bot = hass.data[DOMAIN].pop(CONF_BOT) + await bot.async_disconnect() + return True diff --git a/homeassistant/components/hangouts/config_flow.py b/homeassistant/components/hangouts/config_flow.py new file mode 100644 index 00000000000..bd81d5053c8 --- /dev/null +++ b/homeassistant/components/hangouts/config_flow.py @@ -0,0 +1,107 @@ +"""Config flow to configure Google Hangouts.""" +import voluptuous as vol + +from homeassistant import config_entries, data_entry_flow +from homeassistant.const import CONF_EMAIL, CONF_PASSWORD +from homeassistant.core import callback + +from .const import CONF_2FA, CONF_REFRESH_TOKEN +from .const import DOMAIN as HANGOUTS_DOMAIN + + +@callback +def configured_hangouts(hass): + """Return the configures Google Hangouts Account.""" + entries = hass.config_entries.async_entries(HANGOUTS_DOMAIN) + if entries: + return entries[0] + return None + + +@config_entries.HANDLERS.register(HANGOUTS_DOMAIN) +class HangoutsFlowHandler(data_entry_flow.FlowHandler): + """Config flow Google Hangouts.""" + + VERSION = 1 + + def __init__(self): + """Initialize Google Hangouts config flow.""" + self._credentials = None + self._refresh_token = None + + async def async_step_user(self, user_input=None): + """Handle a flow start.""" + errors = {} + + if configured_hangouts(self.hass) is not None: + return self.async_abort(reason="already_configured") + + if user_input is not None: + from hangups import get_auth + from .hangups_utils import (HangoutsCredentials, + HangoutsRefreshToken, + GoogleAuthError, Google2FAError) + self._credentials = HangoutsCredentials(user_input[CONF_EMAIL], + user_input[CONF_PASSWORD]) + self._refresh_token = HangoutsRefreshToken(None) + try: + await self.hass.async_add_executor_job(get_auth, + self._credentials, + self._refresh_token) + + return await self.async_step_final() + except GoogleAuthError as err: + if isinstance(err, Google2FAError): + return await self.async_step_2fa() + msg = str(err) + if msg == 'Unknown verification code input': + errors['base'] = 'invalid_2fa_method' + else: + errors['base'] = 'invalid_login' + + return self.async_show_form( + step_id='user', + data_schema=vol.Schema({ + vol.Required(CONF_EMAIL): str, + vol.Required(CONF_PASSWORD): str + }), + errors=errors + ) + + async def async_step_2fa(self, user_input=None): + """Handle the 2fa step, if needed.""" + errors = {} + + if user_input is not None: + from hangups import get_auth + from .hangups_utils import GoogleAuthError + self._credentials.set_verification_code(user_input[CONF_2FA]) + try: + await self.hass.async_add_executor_job(get_auth, + self._credentials, + self._refresh_token) + + return await self.async_step_final() + except GoogleAuthError: + errors['base'] = 'invalid_2fa' + + return self.async_show_form( + step_id=CONF_2FA, + data_schema=vol.Schema({ + vol.Required(CONF_2FA): str, + }), + errors=errors + ) + + async def async_step_final(self): + """Handle the final step, create the config entry.""" + return self.async_create_entry( + title=self._credentials.get_email(), + data={ + CONF_EMAIL: self._credentials.get_email(), + CONF_REFRESH_TOKEN: self._refresh_token.get() + }) + + async def async_step_import(self, _): + """Handle a flow import.""" + return self.async_abort(reason='already_configured') diff --git a/homeassistant/components/hangouts/const.py b/homeassistant/components/hangouts/const.py new file mode 100644 index 00000000000..7083307f3e2 --- /dev/null +++ b/homeassistant/components/hangouts/const.py @@ -0,0 +1,78 @@ +"""Constants for Google Hangouts Component.""" +import logging + +import voluptuous as vol + +from homeassistant.components.notify import ATTR_MESSAGE, ATTR_TARGET +from homeassistant.const import CONF_NAME +import homeassistant.helpers.config_validation as cv + +_LOGGER = logging.getLogger('homeassistant.components.hangouts') + + +DOMAIN = 'hangouts' + +CONF_2FA = '2fa' +CONF_REFRESH_TOKEN = 'refresh_token' +CONF_BOT = 'bot' + +CONF_CONVERSATIONS = 'conversations' +CONF_DEFAULT_CONVERSATIONS = 'default_conversations' + +CONF_COMMANDS = 'commands' +CONF_WORD = 'word' +CONF_EXPRESSION = 'expression' + +EVENT_HANGOUTS_COMMAND = 'hangouts_command' + +EVENT_HANGOUTS_CONNECTED = 'hangouts_connected' +EVENT_HANGOUTS_DISCONNECTED = 'hangouts_disconnected' +EVENT_HANGOUTS_USERS_CHANGED = 'hangouts_users_changed' +EVENT_HANGOUTS_CONVERSATIONS_CHANGED = 'hangouts_conversations_changed' + +CONF_CONVERSATION_ID = 'id' +CONF_CONVERSATION_NAME = 'name' + +SERVICE_SEND_MESSAGE = 'send_message' +SERVICE_UPDATE = 'update' + + +TARGETS_SCHEMA = vol.All( + vol.Schema({ + vol.Exclusive(CONF_CONVERSATION_ID, 'id or name'): cv.string, + vol.Exclusive(CONF_CONVERSATION_NAME, 'id or name'): cv.string + }), + cv.has_at_least_one_key(CONF_CONVERSATION_ID, CONF_CONVERSATION_NAME) +) +MESSAGE_SEGMENT_SCHEMA = vol.Schema({ + vol.Required('text'): cv.string, + vol.Optional('is_bold'): cv.boolean, + vol.Optional('is_italic'): cv.boolean, + vol.Optional('is_strikethrough'): cv.boolean, + vol.Optional('is_underline'): cv.boolean, + vol.Optional('parse_str'): cv.boolean, + vol.Optional('link_target'): cv.string +}) + +MESSAGE_SCHEMA = vol.Schema({ + vol.Required(ATTR_TARGET): [TARGETS_SCHEMA], + vol.Required(ATTR_MESSAGE): [MESSAGE_SEGMENT_SCHEMA] +}) + +COMMAND_SCHEMA = vol.All( + # Basic Schema + vol.Schema({ + vol.Exclusive(CONF_WORD, 'trigger'): cv.string, + vol.Exclusive(CONF_EXPRESSION, 'trigger'): cv.is_regex, + vol.Required(CONF_NAME): cv.string, + vol.Optional(CONF_CONVERSATIONS): [TARGETS_SCHEMA] + }), + # Make sure it's either a word or an expression command + cv.has_at_least_one_key(CONF_WORD, CONF_EXPRESSION) +) + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Optional(CONF_COMMANDS, default=[]): [COMMAND_SCHEMA] + }) +}, extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/components/hangouts/hangouts_bot.py b/homeassistant/components/hangouts/hangouts_bot.py new file mode 100644 index 00000000000..d4c5606799d --- /dev/null +++ b/homeassistant/components/hangouts/hangouts_bot.py @@ -0,0 +1,229 @@ +"""The Hangouts Bot.""" +import logging +import re + +from homeassistant.helpers import dispatcher + +from .const import ( + ATTR_MESSAGE, ATTR_TARGET, CONF_CONVERSATIONS, CONF_EXPRESSION, CONF_NAME, + CONF_WORD, DOMAIN, EVENT_HANGOUTS_COMMAND, EVENT_HANGOUTS_CONNECTED, + EVENT_HANGOUTS_CONVERSATIONS_CHANGED, EVENT_HANGOUTS_DISCONNECTED) + +_LOGGER = logging.getLogger(__name__) + + +class HangoutsBot: + """The Hangouts Bot.""" + + def __init__(self, hass, refresh_token, commands): + """Set up the client.""" + self.hass = hass + self._connected = False + + self._refresh_token = refresh_token + + self._commands = commands + + self._word_commands = None + self._expression_commands = None + self._client = None + self._user_list = None + self._conversation_list = None + + def _resolve_conversation_name(self, name): + for conv in self._conversation_list.get_all(): + if conv.name == name: + return conv + return None + + def async_update_conversation_commands(self, _): + """Refresh the commands for every conversation.""" + self._word_commands = {} + self._expression_commands = {} + + for command in self._commands: + if command.get(CONF_CONVERSATIONS): + conversations = [] + for conversation in command.get(CONF_CONVERSATIONS): + if 'id' in conversation: + conversations.append(conversation['id']) + elif 'name' in conversation: + conversations.append(self._resolve_conversation_name( + conversation['name']).id_) + command['_' + CONF_CONVERSATIONS] = conversations + else: + command['_' + CONF_CONVERSATIONS] = \ + [conv.id_ for conv in self._conversation_list.get_all()] + + if command.get(CONF_WORD): + for conv_id in command['_' + CONF_CONVERSATIONS]: + if conv_id not in self._word_commands: + self._word_commands[conv_id] = {} + word = command[CONF_WORD].lower() + self._word_commands[conv_id][word] = command + elif command.get(CONF_EXPRESSION): + command['_' + CONF_EXPRESSION] = re.compile( + command.get(CONF_EXPRESSION)) + + for conv_id in command['_' + CONF_CONVERSATIONS]: + if conv_id not in self._expression_commands: + self._expression_commands[conv_id] = [] + self._expression_commands[conv_id].append(command) + + try: + self._conversation_list.on_event.remove_observer( + self._handle_conversation_event) + except ValueError: + pass + self._conversation_list.on_event.add_observer( + self._handle_conversation_event) + + def _handle_conversation_event(self, event): + from hangups import ChatMessageEvent + if event.__class__ is ChatMessageEvent: + self._handle_conversation_message( + event.conversation_id, event.user_id, event) + + def _handle_conversation_message(self, conv_id, user_id, event): + """Handle a message sent to a conversation.""" + user = self._user_list.get_user(user_id) + if user.is_self: + return + + _LOGGER.debug("Handling message '%s' from %s", + event.text, user.full_name) + + event_data = None + + pieces = event.text.split(' ') + cmd = pieces[0].lower() + command = self._word_commands.get(conv_id, {}).get(cmd) + if command: + event_data = { + 'command': command[CONF_NAME], + 'conversation_id': conv_id, + 'user_id': user_id, + 'user_name': user.full_name, + 'data': pieces[1:] + } + else: + # After single-word commands, check all regex commands in the room + for command in self._expression_commands.get(conv_id, []): + match = command['_' + CONF_EXPRESSION].match(event.text) + if not match: + continue + event_data = { + 'command': command[CONF_NAME], + 'conversation_id': conv_id, + 'user_id': user_id, + 'user_name': user.full_name, + 'data': match.groupdict() + } + if event_data is not None: + self.hass.bus.fire(EVENT_HANGOUTS_COMMAND, event_data) + + async def async_connect(self): + """Login to the Google Hangouts.""" + from .hangups_utils import HangoutsRefreshToken, HangoutsCredentials + + from hangups import Client + from hangups import get_auth + session = await self.hass.async_add_executor_job( + get_auth, HangoutsCredentials(None, None, None), + HangoutsRefreshToken(self._refresh_token)) + + self._client = Client(session) + self._client.on_connect.add_observer(self._on_connect) + self._client.on_disconnect.add_observer(self._on_disconnect) + + self.hass.loop.create_task(self._client.connect()) + + def _on_connect(self): + _LOGGER.debug('Connected!') + self._connected = True + dispatcher.async_dispatcher_send(self.hass, EVENT_HANGOUTS_CONNECTED) + + def _on_disconnect(self): + """Handle disconnecting.""" + _LOGGER.debug('Connection lost!') + self._connected = False + dispatcher.async_dispatcher_send(self.hass, + EVENT_HANGOUTS_DISCONNECTED) + + async def async_disconnect(self): + """Disconnect the client if it is connected.""" + if self._connected: + await self._client.disconnect() + + async def async_handle_hass_stop(self, _): + """Run once when Home Assistant stops.""" + await self.async_disconnect() + + async def _async_send_message(self, message, targets): + conversations = [] + for target in targets: + conversation = None + if 'id' in target: + conversation = self._conversation_list.get(target['id']) + elif 'name' in target: + conversation = self._resolve_conversation_name(target['name']) + if conversation is not None: + conversations.append(conversation) + + if not conversations: + return False + + from hangups import ChatMessageSegment, hangouts_pb2 + messages = [] + for segment in message: + if 'parse_str' in segment and segment['parse_str']: + messages.extend(ChatMessageSegment.from_str(segment['text'])) + else: + if 'parse_str' in segment: + del segment['parse_str'] + messages.append(ChatMessageSegment(**segment)) + messages.append(ChatMessageSegment('', + segment_type=hangouts_pb2. + SEGMENT_TYPE_LINE_BREAK)) + + if not messages: + return False + for conv in conversations: + await conv.send_message(messages) + + async def _async_list_conversations(self): + import hangups + self._user_list, self._conversation_list = \ + (await hangups.build_user_conversation_list(self._client)) + users = {} + conversations = {} + for user in self._user_list.get_all(): + users[str(user.id_.chat_id)] = {'full_name': user.full_name, + 'is_self': user.is_self} + + for conv in self._conversation_list.get_all(): + users_in_conversation = {} + for user in conv.users: + users_in_conversation[str(user.id_.chat_id)] = \ + {'full_name': user.full_name, 'is_self': user.is_self} + conversations[str(conv.id_)] = \ + {'name': conv.name, 'users': users_in_conversation} + + self.hass.states.async_set("{}.users".format(DOMAIN), + len(self._user_list.get_all()), + attributes=users) + self.hass.states.async_set("{}.conversations".format(DOMAIN), + len(self._conversation_list.get_all()), + attributes=conversations) + dispatcher.async_dispatcher_send(self.hass, + EVENT_HANGOUTS_CONVERSATIONS_CHANGED, + conversations) + + async def async_handle_send_message(self, service): + """Handle the send_message service.""" + await self._async_send_message(service.data[ATTR_MESSAGE], + service.data[ATTR_TARGET]) + + async def async_handle_update_users_and_conversations(self, _=None): + """Handle the update_users_and_conversations service.""" + await self._async_list_conversations() diff --git a/homeassistant/components/hangouts/hangups_utils.py b/homeassistant/components/hangouts/hangups_utils.py new file mode 100644 index 00000000000..9aff7730201 --- /dev/null +++ b/homeassistant/components/hangouts/hangups_utils.py @@ -0,0 +1,81 @@ +"""Utils needed for Google Hangouts.""" + +from hangups import CredentialsPrompt, GoogleAuthError, RefreshTokenCache + + +class Google2FAError(GoogleAuthError): + """A Google authentication request failed.""" + + +class HangoutsCredentials(CredentialsPrompt): + """Google account credentials. + + This implementation gets the user data as params. + """ + + def __init__(self, email, password, pin=None): + """Google account credentials. + + :param email: Google account email address. + :param password: Google account password. + :param pin: Google account verification code. + """ + self._email = email + self._password = password + self._pin = pin + + def get_email(self): + """Return email. + + :return: Google account email address. + """ + return self._email + + def get_password(self): + """Return password. + + :return: Google account password. + """ + return self._password + + def get_verification_code(self): + """Return the verification code. + + :return: Google account verification code. + """ + if self._pin is None: + raise Google2FAError() + return self._pin + + def set_verification_code(self, pin): + """Set the verification code. + + :param pin: Google account verification code. + """ + self._pin = pin + + +class HangoutsRefreshToken(RefreshTokenCache): + """Memory-based cache for refresh token.""" + + def __init__(self, token): + """Memory-based cache for refresh token. + + :param token: Initial refresh token. + """ + super().__init__("") + self._token = token + + def get(self): + """Get cached refresh token. + + :return: Cached refresh token. + """ + return self._token + + def set(self, refresh_token): + """Cache a refresh token. + + :param refresh_token: Refresh token to cache. + """ + self._token = refresh_token diff --git a/homeassistant/components/hangouts/services.yaml b/homeassistant/components/hangouts/services.yaml new file mode 100644 index 00000000000..5d314bc2479 --- /dev/null +++ b/homeassistant/components/hangouts/services.yaml @@ -0,0 +1,12 @@ +update: + description: Updates the list of users and conversations. + +send_message: + description: Send a notification to a specific target. + fields: + target: + description: List of targets with id or name. [Required] + example: '[{"id": "UgxrXzVrARmjx_C6AZx4AaABAagBo-6UCw"}, {"name": "Test Conversation"}]' + message: + description: List of message segments, only the "text" field is required in every segment. [Required] + example: '[{"text":"test", "is_bold": false, "is_italic": false, "is_strikethrough": false, "is_underline": false, "parse_str": false, "link_target": "http://google.com"}, ...]' \ No newline at end of file diff --git a/homeassistant/components/hangouts/strings.json b/homeassistant/components/hangouts/strings.json new file mode 100644 index 00000000000..1b1ae54b41a --- /dev/null +++ b/homeassistant/components/hangouts/strings.json @@ -0,0 +1,31 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts is already configured", + "unknown": "Unknown error occurred." + }, + "error": { + "invalid_login": "Invalid Login, please try again.", + "invalid_2fa": "Invalid 2 Factor Authorization, please try again.", + "invalid_2fa_method": "Invalig 2FA Method (Verify on Phone)." + }, + "step": { + "user": { + "data": { + "email": "E-Mail Address", + "password": "Password" + }, + "description": "", + "title": "Google Hangouts Login" + }, + "2fa": { + "data": { + "2fa": "2FA Pin" + }, + "description": "", + "title": "2-Factor-Authorization" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/notify/hangouts.py b/homeassistant/components/notify/hangouts.py new file mode 100644 index 00000000000..eb2880e8a46 --- /dev/null +++ b/homeassistant/components/notify/hangouts.py @@ -0,0 +1,66 @@ +""" +Hangouts notification service. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.hangouts/ +""" +import logging + +import voluptuous as vol + +from homeassistant.components.notify import (ATTR_TARGET, PLATFORM_SCHEMA, + NOTIFY_SERVICE_SCHEMA, + BaseNotificationService, + ATTR_MESSAGE) + +from homeassistant.components.hangouts.const \ + import (DOMAIN, SERVICE_SEND_MESSAGE, + TARGETS_SCHEMA, CONF_DEFAULT_CONVERSATIONS) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = [DOMAIN] + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_DEFAULT_CONVERSATIONS): [TARGETS_SCHEMA] +}) + +NOTIFY_SERVICE_SCHEMA = NOTIFY_SERVICE_SCHEMA.extend({ + vol.Optional(ATTR_TARGET): [TARGETS_SCHEMA] +}) + + +def get_service(hass, config, discovery_info=None): + """Get the Hangouts notification service.""" + return HangoutsNotificationService(config.get(CONF_DEFAULT_CONVERSATIONS)) + + +class HangoutsNotificationService(BaseNotificationService): + """Send Notifications to Hangouts conversations.""" + + def __init__(self, default_conversations): + """Set up the notification service.""" + self._default_conversations = default_conversations + + def send_message(self, message="", **kwargs): + """Send the message to the Google Hangouts server.""" + target_conversations = None + if ATTR_TARGET in kwargs: + target_conversations = [] + for target in kwargs.get(ATTR_TARGET): + target_conversations.append({'id': target}) + else: + target_conversations = self._default_conversations + + messages = [] + if 'title' in kwargs: + messages.append({'text': kwargs['title'], 'is_bold': True}) + + messages.append({'text': message, 'parse_str': True}) + service_data = { + ATTR_TARGET: target_conversations, + ATTR_MESSAGE: messages + } + + return self.hass.services.call( + DOMAIN, SERVICE_SEND_MESSAGE, service_data=service_data) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 1858937ec82..8db09cdb8da 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -136,6 +136,7 @@ HANDLERS = Registry() # Components that have config flows. In future we will auto-generate this list. FLOWS = [ 'cast', + 'hangouts', 'deconz', 'homematicip_cloud', 'hue', diff --git a/requirements_all.txt b/requirements_all.txt index 253263c6e3a..73a59319b10 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -413,6 +413,9 @@ ha-ffmpeg==1.9 # homeassistant.components.media_player.philips_js ha-philipsjs==0.0.5 +# homeassistant.components.hangouts +hangups==0.4.5 + # homeassistant.components.sensor.geo_rss_events haversine==0.4.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 23fc37a3c68..f4f087bd6d4 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -71,6 +71,9 @@ gTTS-token==1.1.1 # homeassistant.components.ffmpeg ha-ffmpeg==1.9 +# homeassistant.components.hangouts +hangups==0.4.5 + # homeassistant.components.sensor.geo_rss_events haversine==0.4.5 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 9a1eb172326..e26393bb800 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -51,6 +51,7 @@ TEST_REQUIREMENTS = ( 'feedparser', 'foobot_async', 'gTTS-token', + 'hangups', 'HAP-python', 'ha-ffmpeg', 'haversine', @@ -105,7 +106,8 @@ TEST_REQUIREMENTS = ( IGNORE_PACKAGES = ( 'homeassistant.components.recorder.models', - 'homeassistant.components.homekit.*' + 'homeassistant.components.homekit.*', + 'homeassistant.components.hangouts.hangups_utils' ) IGNORE_PIN = ('colorlog>2.1,<3', 'keyring>=9.3,<10.0', 'urllib3') diff --git a/tests/components/hangouts/__init__.py b/tests/components/hangouts/__init__.py new file mode 100644 index 00000000000..81174356c2e --- /dev/null +++ b/tests/components/hangouts/__init__.py @@ -0,0 +1 @@ +"""Tests for the Hangouts Component.""" diff --git a/tests/components/hangouts/test_config_flow.py b/tests/components/hangouts/test_config_flow.py new file mode 100644 index 00000000000..af9bb018919 --- /dev/null +++ b/tests/components/hangouts/test_config_flow.py @@ -0,0 +1,92 @@ +"""Tests for the Google Hangouts config flow.""" + +from unittest.mock import patch + +from homeassistant import data_entry_flow +from homeassistant.components.hangouts import config_flow + + +async def test_flow_works(hass, aioclient_mock): + """Test config flow without 2fa.""" + flow = config_flow.HangoutsFlowHandler() + + flow.hass = hass + + with patch('hangups.get_auth'): + result = await flow.async_step_user( + {'email': 'test@test.com', 'password': '1232456'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['title'] == 'test@test.com' + + +async def test_flow_works_with_2fa(hass, aioclient_mock): + """Test config flow with 2fa.""" + from homeassistant.components.hangouts.hangups_utils import Google2FAError + + flow = config_flow.HangoutsFlowHandler() + + flow.hass = hass + + with patch('hangups.get_auth', side_effect=Google2FAError): + result = await flow.async_step_user( + {'email': 'test@test.com', 'password': '1232456'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['step_id'] == '2fa' + + with patch('hangups.get_auth'): + result = await flow.async_step_2fa({'2fa': 123456}) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['title'] == 'test@test.com' + + +async def test_flow_with_unknown_2fa(hass, aioclient_mock): + """Test config flow with invalid 2fa method.""" + from homeassistant.components.hangouts.hangups_utils import GoogleAuthError + + flow = config_flow.HangoutsFlowHandler() + + flow.hass = hass + + with patch('hangups.get_auth', + side_effect=GoogleAuthError('Unknown verification code input')): + result = await flow.async_step_user( + {'email': 'test@test.com', 'password': '1232456'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_2fa_method' + + +async def test_flow_invalid_login(hass, aioclient_mock): + """Test config flow with invalid 2fa method.""" + from homeassistant.components.hangouts.hangups_utils import GoogleAuthError + + flow = config_flow.HangoutsFlowHandler() + + flow.hass = hass + + with patch('hangups.get_auth', + side_effect=GoogleAuthError): + result = await flow.async_step_user( + {'email': 'test@test.com', 'password': '1232456'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_login' + + +async def test_flow_invalid_2fa(hass, aioclient_mock): + """Test config flow with 2fa.""" + from homeassistant.components.hangouts.hangups_utils import Google2FAError + + flow = config_flow.HangoutsFlowHandler() + + flow.hass = hass + + with patch('hangups.get_auth', side_effect=Google2FAError): + result = await flow.async_step_user( + {'email': 'test@test.com', 'password': '1232456'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['step_id'] == '2fa' + + with patch('hangups.get_auth', side_effect=Google2FAError): + result = await flow.async_step_2fa({'2fa': 123456}) + + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_2fa' From 6c5f98668e958c5aa4f12b06dd54af60b42fe52e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 24 Aug 2018 15:54:04 +0200 Subject: [PATCH 113/159] Bump frontend to 20180824.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index a436cc483ae..bfcf7322749 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180820.0'] +REQUIREMENTS = ['home-assistant-frontend==20180824.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 73a59319b10..25480a023ec 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -438,7 +438,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180820.0 +home-assistant-frontend==20180824.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f4f087bd6d4..71cbc724c59 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -84,7 +84,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180820.0 +home-assistant-frontend==20180824.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 3d5b3fb6fff948d8bd343eee34e8f2974707b488 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 24 Aug 2018 15:54:47 +0200 Subject: [PATCH 114/159] Update translations --- .../components/cast/.translations/da.json | 15 +++++++++ .../components/cast/.translations/en.json | 2 +- .../components/cast/.translations/es.json | 5 +++ .../components/cast/.translations/he.json | 15 +++++++++ .../components/deconz/.translations/da.json | 17 +++++++++- .../components/deconz/.translations/he.json | 32 ++++++++++++++++++ .../components/hangouts/.translations/ca.json | 29 ++++++++++++++++ .../components/hangouts/.translations/de.json | 28 ++++++++++++++++ .../components/hangouts/.translations/en.json | 2 -- .../components/hangouts/.translations/pl.json | 29 ++++++++++++++++ .../components/hangouts/.translations/ru.json | 24 ++++++++++++++ .../components/hangouts/.translations/sl.json | 31 +++++++++++++++++ .../homematicip_cloud/.translations/ca.json | 1 + .../homematicip_cloud/.translations/cs.json | 1 + .../homematicip_cloud/.translations/da.json | 7 ++++ .../homematicip_cloud/.translations/de.json | 1 + .../homematicip_cloud/.translations/en.json | 11 ++++--- .../homematicip_cloud/.translations/es.json | 19 +++++++++++ .../homematicip_cloud/.translations/he.json | 30 +++++++++++++++++ .../homematicip_cloud/.translations/ko.json | 1 + .../homematicip_cloud/.translations/lb.json | 1 + .../homematicip_cloud/.translations/nl.json | 1 + .../homematicip_cloud/.translations/no.json | 1 + .../homematicip_cloud/.translations/pl.json | 1 + .../homematicip_cloud/.translations/ru.json | 1 + .../homematicip_cloud/.translations/sl.json | 1 + .../components/hue/.translations/da.json | 12 ++++++- .../components/hue/.translations/he.json | 29 ++++++++++++++++ .../components/nest/.translations/da.json | 23 +++++++++++++ .../components/nest/.translations/es.json | 12 +++++++ .../components/nest/.translations/he.json | 33 +++++++++++++++++++ .../sensor/.translations/moon.cs.json | 12 +++++++ .../sensor/.translations/moon.es.json | 7 ++++ .../sensor/.translations/moon.he.json | 8 +++++ .../sensor/.translations/moon.lb.json | 12 +++++++ .../sensor/.translations/moon.pl.json | 12 +++++++ .../sensor/.translations/moon.sv.json | 12 +++++++ .../sensor/.translations/season.he.json | 8 +++++ .../components/sonos/.translations/da.json | 15 +++++++++ .../components/sonos/.translations/en.json | 2 +- .../components/sonos/.translations/es.json | 10 ++++++ .../components/sonos/.translations/he.json | 15 +++++++++ .../components/zone/.translations/da.json | 20 +++++++++++ .../components/zone/.translations/he.json | 21 ++++++++++++ 44 files changed, 558 insertions(+), 11 deletions(-) create mode 100644 homeassistant/components/cast/.translations/da.json create mode 100644 homeassistant/components/cast/.translations/es.json create mode 100644 homeassistant/components/cast/.translations/he.json create mode 100644 homeassistant/components/deconz/.translations/he.json create mode 100644 homeassistant/components/hangouts/.translations/ca.json create mode 100644 homeassistant/components/hangouts/.translations/de.json create mode 100644 homeassistant/components/hangouts/.translations/pl.json create mode 100644 homeassistant/components/hangouts/.translations/ru.json create mode 100644 homeassistant/components/hangouts/.translations/sl.json create mode 100644 homeassistant/components/homematicip_cloud/.translations/da.json create mode 100644 homeassistant/components/homematicip_cloud/.translations/es.json create mode 100644 homeassistant/components/homematicip_cloud/.translations/he.json create mode 100644 homeassistant/components/hue/.translations/he.json create mode 100644 homeassistant/components/nest/.translations/da.json create mode 100644 homeassistant/components/nest/.translations/es.json create mode 100644 homeassistant/components/nest/.translations/he.json create mode 100644 homeassistant/components/sensor/.translations/moon.cs.json create mode 100644 homeassistant/components/sensor/.translations/moon.es.json create mode 100644 homeassistant/components/sensor/.translations/moon.he.json create mode 100644 homeassistant/components/sensor/.translations/moon.lb.json create mode 100644 homeassistant/components/sensor/.translations/moon.pl.json create mode 100644 homeassistant/components/sensor/.translations/moon.sv.json create mode 100644 homeassistant/components/sensor/.translations/season.he.json create mode 100644 homeassistant/components/sonos/.translations/da.json create mode 100644 homeassistant/components/sonos/.translations/es.json create mode 100644 homeassistant/components/sonos/.translations/he.json create mode 100644 homeassistant/components/zone/.translations/da.json create mode 100644 homeassistant/components/zone/.translations/he.json diff --git a/homeassistant/components/cast/.translations/da.json b/homeassistant/components/cast/.translations/da.json new file mode 100644 index 00000000000..5d8ab236237 --- /dev/null +++ b/homeassistant/components/cast/.translations/da.json @@ -0,0 +1,15 @@ +{ + "config": { + "abort": { + "no_devices_found": "Ingen Google Cast enheder kunne findes p\u00e5 netv\u00e6rket.", + "single_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning af Google Cast" + }, + "step": { + "confirm": { + "description": "Vil du ops\u00e6tte Google Cast?", + "title": "Google Cast" + } + }, + "title": "Google Cast" + } +} \ No newline at end of file diff --git a/homeassistant/components/cast/.translations/en.json b/homeassistant/components/cast/.translations/en.json index 5222e4da3a1..f908f41e328 100644 --- a/homeassistant/components/cast/.translations/en.json +++ b/homeassistant/components/cast/.translations/en.json @@ -12,4 +12,4 @@ }, "title": "Google Cast" } -} +} \ No newline at end of file diff --git a/homeassistant/components/cast/.translations/es.json b/homeassistant/components/cast/.translations/es.json new file mode 100644 index 00000000000..9188055849c --- /dev/null +++ b/homeassistant/components/cast/.translations/es.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Google Cast" + } +} \ No newline at end of file diff --git a/homeassistant/components/cast/.translations/he.json b/homeassistant/components/cast/.translations/he.json new file mode 100644 index 00000000000..40d2514b59c --- /dev/null +++ b/homeassistant/components/cast/.translations/he.json @@ -0,0 +1,15 @@ +{ + "config": { + "abort": { + "no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05db\u05e9\u05d9\u05e8\u05d9 Google Cast \u05d1\u05e8\u05e9\u05ea.", + "single_instance_allowed": "\u05e8\u05e7 \u05d4\u05d2\u05d3\u05e8\u05d4 \u05d0\u05d7\u05ea \u05e9\u05dc Google Cast \u05e0\u05d7\u05d5\u05e6\u05d4." + }, + "step": { + "confirm": { + "description": "\u05d4\u05d0\u05dd \u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05d0\u05ea Google Cast?", + "title": "Google Cast" + } + }, + "title": "Google Cast" + } +} \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/da.json b/homeassistant/components/deconz/.translations/da.json index 698f55c59ec..7f9aad83160 100644 --- a/homeassistant/components/deconz/.translations/da.json +++ b/homeassistant/components/deconz/.translations/da.json @@ -1,10 +1,25 @@ { "config": { + "abort": { + "no_bridges": "Ingen deConz bridge fundet", + "one_instance_only": "Komponenten underst\u00f8tter kun \u00e9n deCONZ forekomst" + }, + "error": { + "no_key": "Kunne ikke f\u00e5 en API-n\u00f8gle" + }, "step": { "init": { "data": { - "host": "V\u00e6rt" + "host": "V\u00e6rt", + "port": "Port (standardv\u00e6rdi: '80')" } + }, + "options": { + "data": { + "allow_clip_sensor": "Tillad import af virtuelle sensorer", + "allow_deconz_groups": "Tillad importering af deCONZ grupper" + }, + "title": "Ekstra konfiguration valgmuligheder for deCONZ" } } } diff --git a/homeassistant/components/deconz/.translations/he.json b/homeassistant/components/deconz/.translations/he.json new file mode 100644 index 00000000000..b4b3d54e075 --- /dev/null +++ b/homeassistant/components/deconz/.translations/he.json @@ -0,0 +1,32 @@ +{ + "config": { + "abort": { + "already_configured": "\u05d4\u05de\u05d2\u05e9\u05e8 \u05db\u05d1\u05e8 \u05de\u05d5\u05d2\u05d3\u05e8", + "no_bridges": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05d2\u05e9\u05e8\u05d9 deCONZ" + }, + "error": { + "no_key": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05d4\u05d9\u05d4 \u05dc\u05e7\u05d1\u05dc \u05de\u05e4\u05ea\u05d7 API" + }, + "step": { + "init": { + "data": { + "host": "\u05de\u05d0\u05e8\u05d7", + "port": "\u05e4\u05d5\u05e8\u05d8 (\u05d1\u05e8\u05d9\u05e8\u05ea \u05de\u05d7\u05d3\u05dc: '80')" + }, + "title": "\u05d4\u05d2\u05d3\u05e8 \u05de\u05d2\u05e9\u05e8 deCONZ Zigbee" + }, + "link": { + "description": "\u05d1\u05d8\u05dc \u05d0\u05ea \u05e0\u05e2\u05d9\u05dc\u05ea \u05d4\u05de\u05e9\u05e8 deCONZ \u05e9\u05dc\u05da \u05db\u05d3\u05d9 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd Home Assistant.\n\n 1. \u05e2\u05d1\u05d5\u05e8 \u05d0\u05dc \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05de\u05e2\u05e8\u05db\u05ea deCONZ \n .2 \u05dc\u05d7\u05e5 \u05e2\u05dc \"Unlock Gateway\"", + "title": "\u05e7\u05e9\u05e8 \u05e2\u05dd deCONZ" + }, + "options": { + "data": { + "allow_clip_sensor": "\u05d0\u05e4\u05e9\u05e8 \u05dc\u05d9\u05d9\u05d1\u05d0 \u05d7\u05d9\u05d9\u05e9\u05e0\u05d9\u05dd \u05d5\u05d9\u05e8\u05d8\u05d5\u05d0\u05dc\u05d9\u05d9\u05dd", + "allow_deconz_groups": "\u05d0\u05e4\u05e9\u05e8 \u05dc\u05d9\u05d9\u05d1\u05d0 \u05e7\u05d1\u05d5\u05e6\u05d5\u05ea deCONZ" + }, + "title": "\u05d0\u05e4\u05e9\u05e8\u05d5\u05d9\u05d5\u05ea \u05ea\u05e6\u05d5\u05e8\u05d4 \u05e0\u05d5\u05e1\u05e4\u05d5\u05ea \u05e2\u05d1\u05d5\u05e8 deCONZ" + } + }, + "title": "\u05de\u05d2\u05e9\u05e8 deCONZ Zigbee" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/ca.json b/homeassistant/components/hangouts/.translations/ca.json new file mode 100644 index 00000000000..ca15e59ec19 --- /dev/null +++ b/homeassistant/components/hangouts/.translations/ca.json @@ -0,0 +1,29 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts ja est\u00e0 configurat", + "unknown": "S'ha produ\u00eft un error desconegut." + }, + "error": { + "invalid_2fa": "La verificaci\u00f3 en dos passos no \u00e9s v\u00e0lida, torna-ho a provar.", + "invalid_2fa_method": "El m\u00e8tode de verificaci\u00f3 en dos passos no \u00e9s v\u00e0lid (verifica-ho al m\u00f2bil).", + "invalid_login": "L'inici de sessi\u00f3 no \u00e9s v\u00e0lid, torna-ho a provar." + }, + "step": { + "2fa": { + "data": { + "2fa": "Pin 2FA" + }, + "title": "Verificaci\u00f3 en dos passos" + }, + "user": { + "data": { + "email": "Correu electr\u00f2nic", + "password": "Contrasenya" + }, + "title": "Inici de sessi\u00f3 de Google Hangouts" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/de.json b/homeassistant/components/hangouts/.translations/de.json new file mode 100644 index 00000000000..4222e7f5556 --- /dev/null +++ b/homeassistant/components/hangouts/.translations/de.json @@ -0,0 +1,28 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts ist bereits konfiguriert", + "unknown": "Ein unbekannter Fehler ist aufgetreten." + }, + "error": { + "invalid_2fa_method": "Ung\u00fcltige 2FA Methode (mit Telefon verifizieren)", + "invalid_login": "Ung\u00fcltige Daten, bitte erneut versuchen." + }, + "step": { + "2fa": { + "data": { + "2fa": "2FA PIN" + }, + "title": "2-Faktor-Authentifizierung" + }, + "user": { + "data": { + "email": "E-Mail-Adresse", + "password": "Passwort" + }, + "title": "Google Hangouts Login" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/en.json b/homeassistant/components/hangouts/.translations/en.json index d8d160ad5ea..eb278afaf7f 100644 --- a/homeassistant/components/hangouts/.translations/en.json +++ b/homeassistant/components/hangouts/.translations/en.json @@ -14,7 +14,6 @@ "data": { "2fa": "2FA Pin" }, - "description": "", "title": "2-Factor-Authorization" }, "user": { @@ -22,7 +21,6 @@ "email": "E-Mail Address", "password": "Password" }, - "description": "", "title": "Google Hangouts Login" } }, diff --git a/homeassistant/components/hangouts/.translations/pl.json b/homeassistant/components/hangouts/.translations/pl.json new file mode 100644 index 00000000000..9cbc02f126e --- /dev/null +++ b/homeassistant/components/hangouts/.translations/pl.json @@ -0,0 +1,29 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts jest ju\u017c skonfigurowany", + "unknown": "Wyst\u0105pi\u0142 nieznany b\u0142\u0105d." + }, + "error": { + "invalid_2fa": "Nieprawid\u0142owe uwierzytelnienie dwusk\u0142adnikowe, spr\u00f3buj ponownie.", + "invalid_2fa_method": "Nieprawid\u0142owa metoda uwierzytelniania dwusk\u0142adnikowego (u\u017cyj weryfikacji przez telefon).", + "invalid_login": "Nieprawid\u0142owy login, spr\u00f3buj ponownie." + }, + "step": { + "2fa": { + "data": { + "2fa": "PIN" + }, + "title": "Uwierzytelnianie dwusk\u0142adnikowe" + }, + "user": { + "data": { + "email": "Adres e-mail", + "password": "Has\u0142o" + }, + "title": "Login Google Hangouts" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/ru.json b/homeassistant/components/hangouts/.translations/ru.json new file mode 100644 index 00000000000..730d9404837 --- /dev/null +++ b/homeassistant/components/hangouts/.translations/ru.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d", + "unknown": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430" + }, + "error": { + "invalid_login": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430." + }, + "step": { + "2fa": { + "title": "\u0414\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f" + }, + "user": { + "data": { + "email": "\u0410\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b", + "password": "\u041f\u0430\u0440\u043e\u043b\u044c" + }, + "title": "\u0412\u0445\u043e\u0434 \u0432 Google Hangouts" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/sl.json b/homeassistant/components/hangouts/.translations/sl.json new file mode 100644 index 00000000000..d7555335820 --- /dev/null +++ b/homeassistant/components/hangouts/.translations/sl.json @@ -0,0 +1,31 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts je \u017ee konfiguriran", + "unknown": "Pri\u0161lo je do neznane napake" + }, + "error": { + "invalid_2fa": "Neveljavna 2FA avtorizacija, prosimo, poskusite znova.", + "invalid_2fa_method": "Neveljavna 2FA metoda (preveri na telefonu).", + "invalid_login": "Neveljavna Prijava, prosimo, poskusite znova." + }, + "step": { + "2fa": { + "data": { + "2fa": "2FA Pin" + }, + "description": "prazno", + "title": "2-faktorska avtorizacija" + }, + "user": { + "data": { + "email": "E-po\u0161tni naslov", + "password": "Geslo" + }, + "description": "prazno", + "title": "Prijava za Google Hangouts" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/.translations/ca.json b/homeassistant/components/homematicip_cloud/.translations/ca.json index 9d40bc2d241..aab974ba137 100644 --- a/homeassistant/components/homematicip_cloud/.translations/ca.json +++ b/homeassistant/components/homematicip_cloud/.translations/ca.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "El punt d'acc\u00e9s ja est\u00e0 configurat", "conection_aborted": "No s'ha pogut connectar al servidor HMIP", + "connection_aborted": "No s'ha pogut connectar al servidor HMIP", "unknown": "S'ha produ\u00eft un error desconegut." }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/cs.json b/homeassistant/components/homematicip_cloud/.translations/cs.json index 59f232edea4..4030450e51c 100644 --- a/homeassistant/components/homematicip_cloud/.translations/cs.json +++ b/homeassistant/components/homematicip_cloud/.translations/cs.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "P\u0159\u00edstupov\u00fd bod je ji\u017e nakonfigurov\u00e1n", "conection_aborted": "Nelze se p\u0159ipojit k serveru HMIP", + "connection_aborted": "Nelze se p\u0159ipojit k HMIP serveru", "unknown": "Do\u0161lo k nezn\u00e1m\u00e9 chyb\u011b" }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/da.json b/homeassistant/components/homematicip_cloud/.translations/da.json new file mode 100644 index 00000000000..b617130945a --- /dev/null +++ b/homeassistant/components/homematicip_cloud/.translations/da.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "invalid_pin": "Ugyldig PIN, pr\u00f8v igen." + } + } +} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/.translations/de.json b/homeassistant/components/homematicip_cloud/.translations/de.json index 61a9bd6eb40..fdccac0d229 100644 --- a/homeassistant/components/homematicip_cloud/.translations/de.json +++ b/homeassistant/components/homematicip_cloud/.translations/de.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Der Accesspoint ist bereits konfiguriert", "conection_aborted": "Keine Verbindung zum HMIP-Server m\u00f6glich", + "connection_aborted": "Konnte nicht mit HMIP Server verbinden", "unknown": "Ein unbekannter Fehler ist aufgetreten." }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/en.json b/homeassistant/components/homematicip_cloud/.translations/en.json index 0cf99cd2975..6fcfcddd75d 100644 --- a/homeassistant/components/homematicip_cloud/.translations/en.json +++ b/homeassistant/components/homematicip_cloud/.translations/en.json @@ -1,8 +1,9 @@ { "config": { "abort": { - "already_configured": "Accesspoint is already configured", + "already_configured": "Access point is already configured", "conection_aborted": "Could not connect to HMIP server", + "connection_aborted": "Could not connect to HMIP server", "unknown": "Unknown error occurred." }, "error": { @@ -14,15 +15,15 @@ "step": { "init": { "data": { - "hapid": "Accesspoint ID (SGTIN)", + "hapid": "Access point ID (SGTIN)", "name": "Name (optional, used as name prefix for all devices)", "pin": "Pin Code (optional)" }, - "title": "Pick HomematicIP Accesspoint" + "title": "Pick HomematicIP Access point" }, "link": { - "description": "Press the blue button on the accesspoint and the submit button to register HomematicIP with Home Assistant.\n\n![Location of button on bridge](/static/images/config_flows/config_homematicip_cloud.png)", - "title": "Link Accesspoint" + "description": "Press the blue button on the access point and the submit button to register HomematicIP with Home Assistant.\n\n![Location of button on bridge](/static/images/config_flows/config_homematicip_cloud.png)", + "title": "Link Access point" } }, "title": "HomematicIP Cloud" diff --git a/homeassistant/components/homematicip_cloud/.translations/es.json b/homeassistant/components/homematicip_cloud/.translations/es.json new file mode 100644 index 00000000000..3f16c45382b --- /dev/null +++ b/homeassistant/components/homematicip_cloud/.translations/es.json @@ -0,0 +1,19 @@ +{ + "config": { + "abort": { + "unknown": "Se ha producido un error desconocido." + }, + "error": { + "invalid_pin": "PIN no v\u00e1lido, por favor int\u00e9ntalo de nuevo.", + "press_the_button": "Por favor, pulsa el bot\u00f3n azul" + }, + "step": { + "init": { + "data": { + "name": "Nombre (opcional, utilizado como prefijo para todos los dispositivos)", + "pin": "C\u00f3digo PIN (opcional)" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/.translations/he.json b/homeassistant/components/homematicip_cloud/.translations/he.json new file mode 100644 index 00000000000..bdf1e436bad --- /dev/null +++ b/homeassistant/components/homematicip_cloud/.translations/he.json @@ -0,0 +1,30 @@ +{ + "config": { + "abort": { + "already_configured": "\u05e0\u05e7\u05d5\u05d3\u05ea \u05d4\u05d2\u05d9\u05e9\u05d4 \u05db\u05d1\u05e8 \u05de\u05d5\u05d2\u05d3\u05e8\u05ea", + "conection_aborted": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05dc\u05e9\u05e8\u05ea HMIP", + "unknown": "\u05d0\u05d9\u05e8\u05e2\u05d4 \u05e9\u05d2\u05d9\u05d0\u05d4 \u05dc\u05d0 \u05d9\u05d3\u05d5\u05e2\u05d4." + }, + "error": { + "invalid_pin": "PIN \u05dc\u05d0 \u05d7\u05d5\u05e7\u05d9, \u05e0\u05e1\u05d4 \u05e9\u05d5\u05d1.", + "press_the_button": "\u05dc\u05d7\u05e5 \u05e2\u05dc \u05d4\u05db\u05e4\u05ea\u05d5\u05e8 \u05d4\u05db\u05d7\u05d5\u05dc.", + "register_failed": "\u05d4\u05e8\u05d9\u05e9\u05d5\u05dd \u05e0\u05db\u05e9\u05dc, \u05e0\u05e1\u05d4 \u05e9\u05d5\u05d1.", + "timeout_button": "\u05e2\u05d1\u05e8 \u05d4\u05d6\u05de\u05df \u05d4\u05e7\u05e6\u05d5\u05d1 \u05dc\u05dc\u05d7\u05d9\u05e6\u05d4 \u05e2\u05dc \u05d4\u05db\u05e4\u05ea\u05d5\u05e8 \u05d4\u05db\u05d7\u05d5\u05dc, \u05e0\u05e1\u05d4 \u05e9\u05d5\u05d1" + }, + "step": { + "init": { + "data": { + "hapid": "\u05de\u05d6\u05d4\u05d4 \u05e0\u05e7\u05d5\u05d3\u05ea \u05d2\u05d9\u05e9\u05d4 (SGTIN)", + "name": "\u05e9\u05dd (\u05d0\u05d5\u05e4\u05e6\u05d9\u05d5\u05e0\u05dc\u05d9, \u05de\u05e9\u05de\u05e9 \u05db\u05e7\u05d9\u05d3\u05d5\u05de\u05ea \u05e2\u05d1\u05d5\u05e8 \u05db\u05dc \u05d4\u05de\u05db\u05e9\u05d9\u05e8\u05d9\u05dd)", + "pin": "\u05e7\u05d5\u05d3 PIN (\u05d0\u05d5\u05e4\u05e6\u05d9\u05d5\u05e0\u05dc\u05d9)" + }, + "title": "\u05d1\u05d7\u05e8 \u05e0\u05e7\u05d5\u05d3\u05ea \u05d2\u05d9\u05e9\u05d4 HomematicIP" + }, + "link": { + "description": "\u05dc\u05d7\u05e5 \u05e2\u05dc \u05d4\u05db\u05e4\u05ea\u05d5\u05e8 \u05d4\u05db\u05d7\u05d5\u05dc \u05d1\u05e0\u05e7\u05d5\u05d3\u05ea \u05d2\u05d9\u05e9\u05d4 \u05d5\u05e2\u05dc \u05db\u05e4\u05ea\u05d5\u05e8 \u05d4\u05e9\u05dc\u05d9\u05d7\u05d4 \u05db\u05d3\u05d9 \u05dc\u05d7\u05d1\u05e8 \u05d0\u05ea HomematicIP \u05e2\u05ddHome Assistant.\n\n![\u05de\u05d9\u05e7\u05d5\u05dd \u05d4\u05db\u05e4\u05ea\u05d5\u05e8 \u05d1\u05de\u05d2\u05e9\u05e8](/static/images/config_flows/config_homematicip_cloud.png)", + "title": "\u05d7\u05d1\u05e8 \u05e0\u05e7\u05d5\u05d3\u05ea \u05d2\u05d9\u05e9\u05d4" + } + }, + "title": "\u05e2\u05e0\u05df HomematicIP" + } +} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/.translations/ko.json b/homeassistant/components/homematicip_cloud/.translations/ko.json index e135873067e..617b65ff623 100644 --- a/homeassistant/components/homematicip_cloud/.translations/ko.json +++ b/homeassistant/components/homematicip_cloud/.translations/ko.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "\uc561\uc138\uc2a4 \ud3ec\uc778\ud2b8\uac00 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "conection_aborted": "HMIP \uc11c\ubc84\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", + "connection_aborted": "HMIP \uc11c\ubc84\uc5d0 \uc5f0\uacb0\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4", "unknown": "\uc54c \uc218\uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/lb.json b/homeassistant/components/homematicip_cloud/.translations/lb.json index 3dd3f1a5dca..a21767fc7d9 100644 --- a/homeassistant/components/homematicip_cloud/.translations/lb.json +++ b/homeassistant/components/homematicip_cloud/.translations/lb.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Acesspoint ass schon konfigur\u00e9iert", "conection_aborted": "Konnt sech net mam HMIP Server verbannen", + "connection_aborted": "Konnt sech net mam HMIP Server verbannen", "unknown": "Onbekannten Feeler opgetrueden" }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/nl.json b/homeassistant/components/homematicip_cloud/.translations/nl.json index 0559dae4bfd..23305a7e584 100644 --- a/homeassistant/components/homematicip_cloud/.translations/nl.json +++ b/homeassistant/components/homematicip_cloud/.translations/nl.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Accesspoint is reeds geconfigureerd", "conection_aborted": "Kon geen verbinding maken met de HMIP-server", + "connection_aborted": "Kon geen verbinding maken met de HMIP-server", "unknown": "Er is een onbekende fout opgetreden." }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/no.json b/homeassistant/components/homematicip_cloud/.translations/no.json index 650c921af31..a310a918f64 100644 --- a/homeassistant/components/homematicip_cloud/.translations/no.json +++ b/homeassistant/components/homematicip_cloud/.translations/no.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Tilgangspunktet er allerede konfigurert", "conection_aborted": "Kunne ikke koble til HMIP serveren", + "connection_aborted": "Kunne ikke koble til HMIP serveren", "unknown": "Ukjent feil oppstod." }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/pl.json b/homeassistant/components/homematicip_cloud/.translations/pl.json index c2ec6be4bd4..3fcbe7e69d1 100644 --- a/homeassistant/components/homematicip_cloud/.translations/pl.json +++ b/homeassistant/components/homematicip_cloud/.translations/pl.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Punkt dost\u0119pu jest ju\u017c skonfigurowany", "conection_aborted": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z serwerem HMIP", + "connection_aborted": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z serwerem HMIP", "unknown": "Wyst\u0105pi\u0142 nieznany b\u0142\u0105d" }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/ru.json b/homeassistant/components/homematicip_cloud/.translations/ru.json index 77c6469f64c..ed42daf19cd 100644 --- a/homeassistant/components/homematicip_cloud/.translations/ru.json +++ b/homeassistant/components/homematicip_cloud/.translations/ru.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "\u0422\u043e\u0447\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430", "conection_aborted": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 HMIP", + "connection_aborted": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 HMIP", "unknown": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430" }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/sl.json b/homeassistant/components/homematicip_cloud/.translations/sl.json index d9749480c0d..4c4a00e31e0 100644 --- a/homeassistant/components/homematicip_cloud/.translations/sl.json +++ b/homeassistant/components/homematicip_cloud/.translations/sl.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Dostopna to\u010dka je \u017ee konfigurirana", "conection_aborted": "Povezave s stre\u017enikom HMIP ni bila mogo\u010da", + "connection_aborted": "Povezava s stre\u017enikom HMIP ni bila mogo\u010da", "unknown": "Pri\u0161lo je do neznane napake" }, "error": { diff --git a/homeassistant/components/hue/.translations/da.json b/homeassistant/components/hue/.translations/da.json index 3e5e2b1d3d7..19e60b073d3 100644 --- a/homeassistant/components/hue/.translations/da.json +++ b/homeassistant/components/hue/.translations/da.json @@ -1,7 +1,16 @@ { "config": { "abort": { - "no_bridges": "Ingen Philips Hue bridge fundet" + "all_configured": "Alle Philips Hue brigdes er konfigureret", + "already_configured": "Bridgen er allerede konfigureret", + "cannot_connect": "Kunne ikke oprette forbindelse til bridgen", + "discover_timeout": "Ingen Philips Hue bridge fundet", + "no_bridges": "Ingen Philips Hue bridge fundet", + "unknown": "Ukendt fejl opstod" + }, + "error": { + "linking": "Ukendt sammenkoblings fejl opstod", + "register_failed": "Det lykkedes ikke at registrere, pr\u00f8v igen" }, "step": { "init": { @@ -11,6 +20,7 @@ "title": "V\u00e6lg Hue bridge" }, "link": { + "description": "Tryk p\u00e5 knappen p\u00e5 bridgen for at registrere Philips Hue med Home Assistant. \n\n ! [Placering af knap p\u00e5 bro] (/static/images/config_philips_hue.jpg)", "title": "Link Hub" } }, diff --git a/homeassistant/components/hue/.translations/he.json b/homeassistant/components/hue/.translations/he.json new file mode 100644 index 00000000000..ddc91ae2266 --- /dev/null +++ b/homeassistant/components/hue/.translations/he.json @@ -0,0 +1,29 @@ +{ + "config": { + "abort": { + "all_configured": "\u05db\u05dc \u05d4\u05de\u05d2\u05e9\u05e8\u05d9\u05dd \u05e9\u05dc Philips Hue \u05de\u05d5\u05d2\u05d3\u05e8\u05d9\u05dd \u05db\u05d1\u05e8", + "already_configured": "\u05d4\u05de\u05d2\u05e9\u05e8 \u05db\u05d1\u05e8 \u05de\u05d5\u05d2\u05d3\u05e8", + "cannot_connect": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05dc\u05de\u05d2\u05e9\u05e8", + "discover_timeout": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d2\u05dc\u05d5\u05ea \u05de\u05d2\u05e9\u05e8\u05d9\u05dd", + "no_bridges": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05d2\u05e9\u05e8\u05d9 Philips Hue", + "unknown": "\u05d0\u05d9\u05e8\u05e2\u05d4 \u05e9\u05d2\u05d9\u05d0\u05d4 \u05dc\u05d0 \u05d9\u05d3\u05d5\u05e2\u05d4." + }, + "error": { + "linking": "\u05d0\u05d9\u05e8\u05e2\u05d4 \u05e9\u05d2\u05d9\u05d0\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8 \u05dc\u05d0 \u05d9\u05d3\u05d5\u05e2\u05d4.", + "register_failed": "\u05d4\u05e8\u05d9\u05e9\u05d5\u05dd \u05e0\u05db\u05e9\u05dc, \u05e0\u05e1\u05d4 \u05e9\u05d5\u05d1." + }, + "step": { + "init": { + "data": { + "host": "\u05de\u05d0\u05e8\u05d7" + }, + "title": "\u05d1\u05d7\u05e8 \u05de\u05d2\u05e9\u05e8" + }, + "link": { + "description": "\u05dc\u05d7\u05e5 \u05e2\u05dc \u05d4\u05db\u05e4\u05ea\u05d5\u05e8 \u05e2\u05dc \u05d4\u05de\u05d2\u05e9\u05e8 \u05db\u05d3\u05d9 \u05dc\u05d7\u05d1\u05e8 \u05d1\u05d9\u05df \u05d0\u05ea Philips Hue \u05e2\u05dd Home Assistant. \n\n![\u05de\u05d9\u05e7\u05d5\u05dd \u05d4\u05db\u05e4\u05ea\u05d5\u05e8 \u05d1\u05e8\u05db\u05d6\u05ea](/static/images/config_philips_hue.jpg)", + "title": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05dc\u05e8\u05db\u05d6\u05ea" + } + }, + "title": "Philips Hue" + } +} \ No newline at end of file diff --git a/homeassistant/components/nest/.translations/da.json b/homeassistant/components/nest/.translations/da.json new file mode 100644 index 00000000000..4410f83d2ca --- /dev/null +++ b/homeassistant/components/nest/.translations/da.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "already_setup": "Du kan kun konfigurere en enkelt Nest konto." + }, + "error": { + "invalid_code": "Ugyldig kode" + }, + "step": { + "init": { + "data": { + "flow_impl": "Udbyder" + }, + "title": "Godkendelses udbyder" + }, + "link": { + "data": { + "code": "PIN-kode" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/nest/.translations/es.json b/homeassistant/components/nest/.translations/es.json new file mode 100644 index 00000000000..ceca4464e06 --- /dev/null +++ b/homeassistant/components/nest/.translations/es.json @@ -0,0 +1,12 @@ +{ + "config": { + "step": { + "link": { + "data": { + "code": "C\u00f3digo PIN" + } + } + }, + "title": "Nest" + } +} \ No newline at end of file diff --git a/homeassistant/components/nest/.translations/he.json b/homeassistant/components/nest/.translations/he.json new file mode 100644 index 00000000000..7f777f42b6d --- /dev/null +++ b/homeassistant/components/nest/.translations/he.json @@ -0,0 +1,33 @@ +{ + "config": { + "abort": { + "already_setup": "\u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05d7\u05e9\u05d1\u05d5\u05df Nest \u05d9\u05d7\u05d9\u05d3.", + "authorize_url_fail": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05dc\u05d0 \u05d9\u05d3\u05d5\u05e2\u05d4 \u05d1\u05d9\u05e6\u05d9\u05e8\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8 \u05d0\u05d9\u05de\u05d5\u05ea.", + "authorize_url_timeout": "\u05e2\u05d1\u05e8 \u05d4\u05d6\u05de\u05df \u05d4\u05e7\u05e6\u05d5\u05d1 \u05e2\u05d1\u05d5\u05e8 \u05d9\u05e6\u05d9\u05e8\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8 \u05d0\u05d9\u05de\u05d5\u05ea", + "no_flows": "\u05e2\u05dc\u05d9\u05da \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05d0\u05ea Nest \u05dc\u05e4\u05e0\u05d9 \u05e9\u05ea\u05d5\u05db\u05dc \u05dc\u05d0\u05de\u05ea \u05d0\u05ea\u05d5. [\u05d0\u05e0\u05d0 \u05e7\u05e8\u05d0 \u05d0\u05ea \u05d4\u05d4\u05d5\u05e8\u05d0\u05d5\u05ea] (https://www.home-assistant.io/components/nest/)." + }, + "error": { + "internal_error": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05e4\u05e0\u05d9\u05de\u05d9\u05ea \u05d1\u05d0\u05d9\u05de\u05d5\u05ea \u05d4\u05e7\u05d5\u05d3", + "invalid_code": "\u05e7\u05d5\u05d3 \u05dc\u05d0 \u05ea\u05e7\u05d9\u05df", + "timeout": "\u05e2\u05d1\u05e8 \u05d4\u05d6\u05de\u05df \u05d4\u05e7\u05e6\u05d5\u05d1 \u05dc\u05d0\u05d9\u05de\u05d5\u05ea \u05d4\u05e7\u05d5\u05d3", + "unknown": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05dc\u05d0 \u05d9\u05d3\u05d5\u05e2\u05d4 \u05d1\u05d0\u05d9\u05de\u05d5\u05ea \u05d4\u05e7\u05d5\u05d3" + }, + "step": { + "init": { + "data": { + "flow_impl": "\u05e1\u05e4\u05e7" + }, + "description": "\u05d1\u05d7\u05e8 \u05d1\u05d0\u05de\u05e6\u05e2\u05d5\u05ea \u05e1\u05e4\u05e7 \u05d4\u05d0\u05d9\u05de\u05d5\u05ea \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d0\u05de\u05ea \u05e2\u05dd Nest.", + "title": "\u05e1\u05e4\u05e7 \u05d0\u05d9\u05de\u05d5\u05ea" + }, + "link": { + "data": { + "code": "\u05e7\u05d5\u05d3 Pin" + }, + "description": "\u05db\u05d3\u05d9 \u05dc\u05e7\u05e9\u05e8 \u05d0\u05ea \u05d7\u05e9\u05d1\u05d5\u05df Nest \u05e9\u05dc\u05da, [\u05d0\u05de\u05ea \u05d4\u05d7\u05e9\u05d1\u05d5\u05df \u05e9\u05dc\u05da] ({url}). \n\n \u05dc\u05d0\u05d7\u05e8 \u05d4\u05d0\u05d9\u05e9\u05d5\u05e8, \u05d4\u05e2\u05ea\u05e7 \u05d0\u05ea \u05e7\u05d5\u05d3 \u05d4PIN \u05e9\u05e1\u05d5\u05e4\u05e7 \u05d5\u05d4\u05d3\u05d1\u05e7 \u05d0\u05d5\u05ea\u05d5 \u05dc\u05de\u05d8\u05d4.", + "title": "\u05e7\u05d9\u05e9\u05d5\u05e8 \u05d7\u05e9\u05d1\u05d5\u05df Nest" + } + }, + "title": "Nest" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.cs.json b/homeassistant/components/sensor/.translations/moon.cs.json new file mode 100644 index 00000000000..ef1d5bf5f13 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.cs.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Prvn\u00ed \u010dtvr\u0165", + "full_moon": "\u00dapln\u011bk", + "last_quarter": "Posledn\u00ed \u010dtvr\u0165", + "new_moon": "Nov", + "waning_crescent": "Couvaj\u00edc\u00ed srpek", + "waning_gibbous": "Couvaj\u00edc\u00ed m\u011bs\u00edc", + "waxing_crescent": "Dor\u016fstaj\u00edc\u00ed srpek", + "waxing_gibbous": "Dor\u016fstaj\u00edc\u00ed m\u011bs\u00edc" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.es.json b/homeassistant/components/sensor/.translations/moon.es.json new file mode 100644 index 00000000000..bbc03820b5b --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.es.json @@ -0,0 +1,7 @@ +{ + "state": { + "first_quarter": "Primer cuarto", + "full_moon": "Luna llena", + "new_moon": "Luna nueva" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.he.json b/homeassistant/components/sensor/.translations/moon.he.json new file mode 100644 index 00000000000..60999f83645 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.he.json @@ -0,0 +1,8 @@ +{ + "state": { + "first_quarter": "\u05e8\u05d1\u05e2\u05d5\u05df \u05e8\u05d0\u05e9\u05d5\u05df", + "full_moon": "\u05d9\u05e8\u05d7 \u05de\u05dc\u05d0", + "last_quarter": "\u05e8\u05d1\u05e2\u05d5\u05df \u05d0\u05d7\u05e8\u05d5\u05df", + "new_moon": "\u05e8\u05d0\u05e9 \u05d7\u05d5\u05d3\u05e9" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.lb.json b/homeassistant/components/sensor/.translations/moon.lb.json new file mode 100644 index 00000000000..2aa7ea03db7 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.lb.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "\u00c9ischt V\u00e9ierel", + "full_moon": "Vollmound", + "last_quarter": "L\u00e4scht V\u00e9ierel", + "new_moon": "Neimound", + "waning_crescent": "Ofhuelende Mound", + "waning_gibbous": "Dr\u00ebtt V\u00e9ierel", + "waxing_crescent": "Zouhuelende Mound", + "waxing_gibbous": "Zweet V\u00e9ierel" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.pl.json b/homeassistant/components/sensor/.translations/moon.pl.json new file mode 100644 index 00000000000..85dfe79bae4 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.pl.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "pierwsza kwadra", + "full_moon": "pe\u0142nia", + "last_quarter": "ostatnia kwadra", + "new_moon": "n\u00f3w", + "waning_crescent": "sierp ubywaj\u0105cy", + "waning_gibbous": "ubywaj\u0105cy garbaty", + "waxing_crescent": "sierp przybywaj\u0105cy", + "waxing_gibbous": "przybywaj\u0105cy garbaty" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.sv.json b/homeassistant/components/sensor/.translations/moon.sv.json new file mode 100644 index 00000000000..ae69c1c9654 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.sv.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "F\u00f6rsta kvartalet", + "full_moon": "Fullm\u00e5ne", + "last_quarter": "Sista kvartalet", + "new_moon": "Nym\u00e5ne", + "waning_crescent": "Avtagande halvm\u00e5ne", + "waning_gibbous": "Avtagande halvm\u00e5ne", + "waxing_crescent": "Tilltagande halvm\u00e5ne", + "waxing_gibbous": "Tilltagande halvm\u00e5ne" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/season.he.json b/homeassistant/components/sensor/.translations/season.he.json new file mode 100644 index 00000000000..282c24f3ad9 --- /dev/null +++ b/homeassistant/components/sensor/.translations/season.he.json @@ -0,0 +1,8 @@ +{ + "state": { + "autumn": "\u05e1\u05ea\u05d9\u05d5", + "spring": "\u05d0\u05d1\u05d9\u05d1", + "summer": "\u05e7\u05d9\u05e5", + "winter": "\u05d7\u05d5\u05e8\u05e3" + } +} \ No newline at end of file diff --git a/homeassistant/components/sonos/.translations/da.json b/homeassistant/components/sonos/.translations/da.json new file mode 100644 index 00000000000..c303bca0aa8 --- /dev/null +++ b/homeassistant/components/sonos/.translations/da.json @@ -0,0 +1,15 @@ +{ + "config": { + "abort": { + "no_devices_found": "Ingen Sonos-enheder kunne findes p\u00e5 netv\u00e6rket.", + "single_instance_allowed": "Det er kun n\u00f8dvendigt med en ops\u00e6tning af Sonos" + }, + "step": { + "confirm": { + "description": "Vil du ops\u00e6tte Sonos?", + "title": "Sonos" + } + }, + "title": "Sonos" + } +} \ No newline at end of file diff --git a/homeassistant/components/sonos/.translations/en.json b/homeassistant/components/sonos/.translations/en.json index 05c9d2fa780..df9e9d2239d 100644 --- a/homeassistant/components/sonos/.translations/en.json +++ b/homeassistant/components/sonos/.translations/en.json @@ -12,4 +12,4 @@ }, "title": "Sonos" } -} +} \ No newline at end of file diff --git a/homeassistant/components/sonos/.translations/es.json b/homeassistant/components/sonos/.translations/es.json new file mode 100644 index 00000000000..c91f9a78c29 --- /dev/null +++ b/homeassistant/components/sonos/.translations/es.json @@ -0,0 +1,10 @@ +{ + "config": { + "step": { + "confirm": { + "title": "Sonos" + } + }, + "title": "Sonos" + } +} \ No newline at end of file diff --git a/homeassistant/components/sonos/.translations/he.json b/homeassistant/components/sonos/.translations/he.json new file mode 100644 index 00000000000..54aa43c6151 --- /dev/null +++ b/homeassistant/components/sonos/.translations/he.json @@ -0,0 +1,15 @@ +{ + "config": { + "abort": { + "no_devices_found": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05de\u05db\u05e9\u05d9\u05e8\u05d9 Sonos \u05d1\u05e8\u05e9\u05ea.", + "single_instance_allowed": "\u05e8\u05e7 \u05ea\u05e6\u05d5\u05e8\u05d4 \u05d0\u05d7\u05ea \u05e9\u05dc Sonos \u05e0\u05d7\u05d5\u05e6\u05d4." + }, + "step": { + "confirm": { + "description": "\u05d4\u05d0\u05dd \u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05d2\u05d3\u05d9\u05e8 \u05d0\u05ea Sonos?", + "title": "Sonos" + } + }, + "title": "Sonos" + } +} \ No newline at end of file diff --git a/homeassistant/components/zone/.translations/da.json b/homeassistant/components/zone/.translations/da.json new file mode 100644 index 00000000000..908ef9dc43a --- /dev/null +++ b/homeassistant/components/zone/.translations/da.json @@ -0,0 +1,20 @@ +{ + "config": { + "error": { + "name_exists": "Navnet findes allerede" + }, + "step": { + "init": { + "data": { + "icon": "Ikon", + "latitude": "Breddegrad", + "longitude": "L\u00e6ngdegrad", + "name": "Navn", + "passive": "Passiv" + }, + "title": "Definer zoneparametre" + } + }, + "title": "Zone" + } +} \ No newline at end of file diff --git a/homeassistant/components/zone/.translations/he.json b/homeassistant/components/zone/.translations/he.json new file mode 100644 index 00000000000..b6a2a30b625 --- /dev/null +++ b/homeassistant/components/zone/.translations/he.json @@ -0,0 +1,21 @@ +{ + "config": { + "error": { + "name_exists": "\u05d4\u05e9\u05dd \u05db\u05d1\u05e8 \u05e7\u05d9\u05d9\u05dd" + }, + "step": { + "init": { + "data": { + "icon": "\u05e1\u05de\u05dc", + "latitude": "\u05e7\u05d5 \u05e8\u05d5\u05d7\u05d1", + "longitude": "\u05e7\u05d5 \u05d0\u05d5\u05e8\u05da", + "name": "\u05e9\u05dd", + "passive": "\u05e4\u05e1\u05d9\u05d1\u05d9", + "radius": "\u05e8\u05d3\u05d9\u05d5\u05e1" + }, + "title": "\u05d4\u05d2\u05d3\u05e8 \u05e4\u05e8\u05de\u05d8\u05e8\u05d9\u05dd \u05e9\u05dc \u05d0\u05d6\u05d5\u05e8" + } + }, + "title": "\u05d0\u05d6\u05d5\u05e8" + } +} \ No newline at end of file From 5e301dd5992751fa0ea4fc5fd28f208f159c9fa5 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Fri, 24 Aug 2018 10:13:58 -0400 Subject: [PATCH 115/159] Hangouts localization typo fix (#16174) --- homeassistant/components/hangouts/strings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/hangouts/strings.json b/homeassistant/components/hangouts/strings.json index 1b1ae54b41a..7e54586b810 100644 --- a/homeassistant/components/hangouts/strings.json +++ b/homeassistant/components/hangouts/strings.json @@ -7,7 +7,7 @@ "error": { "invalid_login": "Invalid Login, please try again.", "invalid_2fa": "Invalid 2 Factor Authorization, please try again.", - "invalid_2fa_method": "Invalig 2FA Method (Verify on Phone)." + "invalid_2fa_method": "Invalid 2FA Method (Verify on Phone)." }, "step": { "user": { @@ -28,4 +28,4 @@ }, "title": "Google Hangouts" } -} \ No newline at end of file +} From 37fd438717e1112ff8979138a72b7f5c068f5e35 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 24 Aug 2018 16:15:28 +0200 Subject: [PATCH 116/159] deCONZ - Allow sub second light transitions (#16170) Solves https://github.com/home-assistant/home-assistant/issues/16075 --- homeassistant/components/light/deconz.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/light/deconz.py b/homeassistant/components/light/deconz.py index 20160edf806..8aacac323b8 100644 --- a/homeassistant/components/light/deconz.py +++ b/homeassistant/components/light/deconz.py @@ -155,7 +155,7 @@ class DeconzLight(Light): data['bri'] = kwargs[ATTR_BRIGHTNESS] if ATTR_TRANSITION in kwargs: - data['transitiontime'] = int(kwargs[ATTR_TRANSITION]) * 10 + data['transitiontime'] = int(kwargs[ATTR_TRANSITION] * 10) if ATTR_FLASH in kwargs: if kwargs[ATTR_FLASH] == FLASH_SHORT: @@ -179,7 +179,7 @@ class DeconzLight(Light): if ATTR_TRANSITION in kwargs: data['bri'] = 0 - data['transitiontime'] = int(kwargs[ATTR_TRANSITION]) * 10 + data['transitiontime'] = int(kwargs[ATTR_TRANSITION] * 10) if ATTR_FLASH in kwargs: if kwargs[ATTR_FLASH] == FLASH_SHORT: From 994b829cb4b706d0103598b194da9a36910cd2f5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 24 Aug 2018 16:37:30 +0200 Subject: [PATCH 117/159] add_devices -> add_entities (#16171) * add_devices -> add_entities * Lint * PyLint * Revert external method in scsgate --- .../components/alarm_control_panel/abode.py | 4 +-- .../alarm_control_panel/alarmdecoder.py | 4 +-- .../alarm_control_panel/alarmdotcom.py | 5 +-- .../components/alarm_control_panel/arlo.py | 4 +-- .../components/alarm_control_panel/canary.py | 4 +-- .../alarm_control_panel/concord232.py | 4 +-- .../components/alarm_control_panel/demo.py | 4 +-- .../components/alarm_control_panel/egardia.py | 4 +-- .../alarm_control_panel/envisalink.py | 5 +-- .../alarm_control_panel/homematicip_cloud.py | 6 ++-- .../components/alarm_control_panel/ialarm.py | 4 +-- .../components/alarm_control_panel/ifttt.py | 4 +-- .../components/alarm_control_panel/manual.py | 4 +-- .../alarm_control_panel/manual_mqtt.py | 4 +-- .../components/alarm_control_panel/mqtt.py | 5 +-- .../components/alarm_control_panel/nx584.py | 4 +-- .../alarm_control_panel/satel_integra.py | 5 +-- .../alarm_control_panel/simplisafe.py | 4 +-- .../components/alarm_control_panel/spc.py | 5 +-- .../alarm_control_panel/totalconnect.py | 4 +-- .../alarm_control_panel/verisure.py | 4 +-- .../components/alarm_control_panel/wink.py | 4 +-- .../components/binary_sensor/abode.py | 4 +-- homeassistant/components/binary_sensor/ads.py | 4 +-- .../components/binary_sensor/alarmdecoder.py | 4 +-- .../binary_sensor/android_ip_webcam.py | 5 +-- .../components/binary_sensor/apcupsd.py | 4 +-- .../components/binary_sensor/arest.py | 4 +-- .../components/binary_sensor/august.py | 4 +-- .../components/binary_sensor/aurora.py | 4 +-- .../components/binary_sensor/axis.py | 4 +-- .../components/binary_sensor/bayesian.py | 5 +-- .../components/binary_sensor/bbb_gpio.py | 4 +-- .../components/binary_sensor/blink.py | 4 +-- .../components/binary_sensor/bloomsky.py | 4 +-- .../binary_sensor/bmw_connected_drive.py | 4 +-- .../components/binary_sensor/command_line.py | 4 +-- .../components/binary_sensor/concord232.py | 4 +-- .../components/binary_sensor/deconz.py | 6 ++-- .../components/binary_sensor/demo.py | 4 +-- .../components/binary_sensor/digital_ocean.py | 4 +-- .../components/binary_sensor/ecobee.py | 4 +-- .../components/binary_sensor/egardia.py | 5 +-- .../components/binary_sensor/eight_sleep.py | 4 +-- .../components/binary_sensor/enocean.py | 4 +-- .../components/binary_sensor/envisalink.py | 5 +-- .../components/binary_sensor/ffmpeg_motion.py | 5 +-- .../components/binary_sensor/ffmpeg_noise.py | 5 +-- .../components/binary_sensor/gc100.py | 4 +-- .../components/binary_sensor/hive.py | 4 +-- .../components/binary_sensor/homematic.py | 4 +-- .../binary_sensor/homematicip_cloud.py | 6 ++-- .../components/binary_sensor/hydrawise.py | 4 +-- homeassistant/components/binary_sensor/ihc.py | 4 +-- .../components/binary_sensor/insteon.py | 5 +-- homeassistant/components/binary_sensor/iss.py | 4 +-- .../components/binary_sensor/isy994.py | 4 +-- homeassistant/components/binary_sensor/knx.py | 14 ++++---- .../components/binary_sensor/konnected.py | 4 +-- .../components/binary_sensor/linode.py | 4 +-- .../components/binary_sensor/maxcube.py | 4 +-- .../components/binary_sensor/modbus.py | 4 +-- .../components/binary_sensor/mqtt.py | 5 +-- .../components/binary_sensor/mychevy.py | 5 +-- .../components/binary_sensor/mysensors.py | 4 +-- .../components/binary_sensor/mystrom.py | 11 ++++--- .../components/binary_sensor/nest.py | 6 ++-- .../components/binary_sensor/netatmo.py | 8 ++--- .../components/binary_sensor/nx584.py | 4 +-- .../components/binary_sensor/octoprint.py | 4 +-- .../components/binary_sensor/openuv.py | 4 +-- .../components/binary_sensor/pilight.py | 6 ++-- .../components/binary_sensor/ping.py | 4 +-- .../components/binary_sensor/qwikswitch.py | 4 +-- .../components/binary_sensor/rachio.py | 4 +-- .../components/binary_sensor/raincloud.py | 4 +-- .../components/binary_sensor/rainmachine.py | 4 +-- .../components/binary_sensor/random.py | 4 +-- .../components/binary_sensor/raspihats.py | 4 +-- .../components/binary_sensor/rest.py | 4 +-- .../components/binary_sensor/rfxtrx.py | 6 ++-- .../components/binary_sensor/ring.py | 4 +-- .../components/binary_sensor/rpi_gpio.py | 4 +-- .../components/binary_sensor/rpi_pfio.py | 4 +-- .../components/binary_sensor/satel_integra.py | 5 +-- .../components/binary_sensor/skybell.py | 4 +-- .../components/binary_sensor/sleepiq.py | 4 +-- homeassistant/components/binary_sensor/spc.py | 5 +-- .../components/binary_sensor/tahoma.py | 4 +-- .../components/binary_sensor/tapsaff.py | 4 +-- homeassistant/components/binary_sensor/tcp.py | 4 +-- .../components/binary_sensor/tellduslive.py | 4 +-- .../components/binary_sensor/template.py | 5 +-- .../components/binary_sensor/tesla.py | 4 +-- .../components/binary_sensor/threshold.py | 5 +-- .../components/binary_sensor/trend.py | 4 +-- .../components/binary_sensor/upcloud.py | 4 +-- .../components/binary_sensor/uptimerobot.py | 4 +-- .../components/binary_sensor/velbus.py | 4 +-- .../components/binary_sensor/vera.py | 4 +-- .../components/binary_sensor/verisure.py | 4 +-- .../components/binary_sensor/volvooncall.py | 4 +-- .../components/binary_sensor/vultr.py | 4 +-- .../components/binary_sensor/wemo.py | 4 +-- .../components/binary_sensor/wink.py | 20 ++++++------ .../components/binary_sensor/wirelesstag.py | 4 +-- .../components/binary_sensor/workday.py | 4 +-- .../components/binary_sensor/xiaomi_aqara.py | 4 +-- homeassistant/components/binary_sensor/zha.py | 15 +++++---- .../components/binary_sensor/zigbee.py | 4 +-- homeassistant/components/calendar/caldav.py | 4 +-- homeassistant/components/calendar/demo.py | 4 +-- homeassistant/components/calendar/google.py | 8 ++--- homeassistant/components/calendar/todoist.py | 4 +-- homeassistant/components/camera/abode.py | 4 +-- homeassistant/components/camera/amcrest.py | 5 +-- homeassistant/components/camera/arlo.py | 4 +-- homeassistant/components/camera/august.py | 4 +-- homeassistant/components/camera/axis.py | 4 +-- homeassistant/components/camera/blink.py | 4 +-- homeassistant/components/camera/bloomsky.py | 4 +-- homeassistant/components/camera/canary.py | 4 +-- homeassistant/components/camera/demo.py | 4 +-- homeassistant/components/camera/doorbird.py | 5 +-- homeassistant/components/camera/familyhub.py | 4 +-- homeassistant/components/camera/ffmpeg.py | 4 +-- homeassistant/components/camera/foscam.py | 4 +-- homeassistant/components/camera/generic.py | 5 +-- homeassistant/components/camera/local_file.py | 4 +-- homeassistant/components/camera/mjpeg.py | 5 +-- homeassistant/components/camera/mqtt.py | 5 +-- homeassistant/components/camera/neato.py | 4 +-- homeassistant/components/camera/nest.py | 6 ++-- homeassistant/components/camera/netatmo.py | 6 ++-- homeassistant/components/camera/onvif.py | 4 +-- homeassistant/components/camera/proxy.py | 4 +-- homeassistant/components/camera/push.py | 4 +-- homeassistant/components/camera/ring.py | 5 +-- homeassistant/components/camera/rpi_camera.py | 4 +-- homeassistant/components/camera/skybell.py | 4 +-- homeassistant/components/camera/synology.py | 5 +-- homeassistant/components/camera/usps.py | 4 +-- homeassistant/components/camera/uvc.py | 12 +++---- homeassistant/components/camera/verisure.py | 4 +-- homeassistant/components/camera/xeoma.py | 4 +-- homeassistant/components/camera/xiaomi.py | 4 +-- homeassistant/components/camera/yi.py | 4 +-- homeassistant/components/camera/zoneminder.py | 5 +-- homeassistant/components/climate/daikin.py | 4 +-- homeassistant/components/climate/demo.py | 4 +-- homeassistant/components/climate/ecobee.py | 4 +-- homeassistant/components/climate/econet.py | 4 +-- homeassistant/components/climate/ephember.py | 4 +-- .../components/climate/eq3btsmart.py | 4 +-- homeassistant/components/climate/flexit.py | 4 +-- homeassistant/components/climate/fritzbox.py | 4 +-- .../components/climate/generic_thermostat.py | 5 +-- homeassistant/components/climate/heatmiser.py | 4 +-- homeassistant/components/climate/hive.py | 4 +-- .../components/climate/homekit_controller.py | 4 +-- homeassistant/components/climate/homematic.py | 4 +-- .../components/climate/homematicip_cloud.py | 6 ++-- homeassistant/components/climate/honeywell.py | 24 +++++++------- homeassistant/components/climate/knx.py | 14 ++++---- homeassistant/components/climate/maxcube.py | 4 +-- homeassistant/components/climate/melissa.py | 4 +-- homeassistant/components/climate/modbus.py | 8 ++--- homeassistant/components/climate/mqtt.py | 5 +-- homeassistant/components/climate/mysensors.py | 4 +-- homeassistant/components/climate/nest.py | 6 ++-- homeassistant/components/climate/netatmo.py | 4 +-- homeassistant/components/climate/nuheat.py | 4 +-- homeassistant/components/climate/oem.py | 4 +-- homeassistant/components/climate/proliphix.py | 4 +-- .../components/climate/radiotherm.py | 4 +-- homeassistant/components/climate/sensibo.py | 5 +-- homeassistant/components/climate/spider.py | 4 +-- homeassistant/components/climate/tado.py | 4 +-- homeassistant/components/climate/tesla.py | 4 +-- homeassistant/components/climate/toon.py | 4 +-- homeassistant/components/climate/touchline.py | 4 +-- homeassistant/components/climate/tuya.py | 4 +-- homeassistant/components/climate/venstar.py | 4 +-- homeassistant/components/climate/vera.py | 4 +-- homeassistant/components/climate/wink.py | 8 ++--- .../components/climate/zhong_hong.py | 4 +-- homeassistant/components/cover/abode.py | 4 +-- .../components/cover/aladdin_connect.py | 4 +-- homeassistant/components/cover/brunt.py | 4 +-- .../components/cover/command_line.py | 4 +-- homeassistant/components/cover/demo.py | 4 +-- homeassistant/components/cover/garadget.py | 4 +-- homeassistant/components/cover/gogogate2.py | 4 +-- homeassistant/components/cover/group.py | 4 +-- homeassistant/components/cover/homematic.py | 4 +-- homeassistant/components/cover/isy994.py | 4 +-- homeassistant/components/cover/knx.py | 14 ++++---- homeassistant/components/cover/lutron.py | 4 +-- .../components/cover/lutron_caseta.py | 4 +-- homeassistant/components/cover/mqtt.py | 4 +-- homeassistant/components/cover/myq.py | 4 +-- homeassistant/components/cover/mysensors.py | 4 +-- homeassistant/components/cover/opengarage.py | 4 +-- homeassistant/components/cover/rflink.py | 4 +-- homeassistant/components/cover/rfxtrx.py | 6 ++-- homeassistant/components/cover/rpi_gpio.py | 4 +-- homeassistant/components/cover/ryobi_gdo.py | 4 +-- homeassistant/components/cover/scsgate.py | 4 +-- homeassistant/components/cover/tahoma.py | 4 +-- homeassistant/components/cover/tellduslive.py | 4 +-- homeassistant/components/cover/tellstick.py | 10 +++--- homeassistant/components/cover/template.py | 4 +-- homeassistant/components/cover/tuya.py | 4 +-- homeassistant/components/cover/velbus.py | 4 +-- homeassistant/components/cover/vera.py | 4 +-- homeassistant/components/cover/wink.py | 8 ++--- .../components/cover/xiaomi_aqara.py | 4 +-- homeassistant/components/fan/comfoconnect.py | 4 +-- homeassistant/components/fan/demo.py | 4 +-- homeassistant/components/fan/dyson.py | 4 +-- homeassistant/components/fan/insteon.py | 5 +-- homeassistant/components/fan/isy994.py | 4 +-- homeassistant/components/fan/mqtt.py | 4 +-- homeassistant/components/fan/template.py | 4 +-- homeassistant/components/fan/tuya.py | 4 +-- homeassistant/components/fan/wink.py | 4 +-- homeassistant/components/fan/xiaomi_miio.py | 4 +-- homeassistant/components/fan/zha.py | 5 +-- .../components/image_processing/demo.py | 4 +-- .../image_processing/dlib_face_detect.py | 4 +-- .../image_processing/dlib_face_identify.py | 4 +-- .../components/image_processing/facebox.py | 4 +-- .../image_processing/microsoft_face_detect.py | 5 +-- .../microsoft_face_identify.py | 5 +-- .../image_processing/openalpr_cloud.py | 5 +-- .../image_processing/openalpr_local.py | 5 +-- .../components/image_processing/opencv.py | 4 +-- .../image_processing/seven_segments.py | 5 +-- homeassistant/components/light/abode.py | 4 +-- homeassistant/components/light/ads.py | 6 ++-- homeassistant/components/light/avion.py | 4 +-- .../components/light/blinksticklight.py | 4 +-- homeassistant/components/light/blinkt.py | 4 +-- homeassistant/components/light/deconz.py | 8 ++--- homeassistant/components/light/decora.py | 4 +-- homeassistant/components/light/decora_wifi.py | 4 +-- homeassistant/components/light/demo.py | 4 +-- homeassistant/components/light/enocean.py | 4 +-- homeassistant/components/light/eufy.py | 4 +-- homeassistant/components/light/flux_led.py | 6 ++-- homeassistant/components/light/futurenow.py | 4 +-- homeassistant/components/light/greenwave.py | 6 ++-- homeassistant/components/light/group.py | 7 ++-- homeassistant/components/light/hive.py | 4 +-- .../components/light/homekit_controller.py | 4 +-- homeassistant/components/light/homematic.py | 4 +-- .../components/light/homematicip_cloud.py | 6 ++-- homeassistant/components/light/hue.py | 12 +++---- homeassistant/components/light/hyperion.py | 4 +-- homeassistant/components/light/iglo.py | 4 +-- homeassistant/components/light/ihc.py | 4 +-- homeassistant/components/light/insteon.py | 5 +-- homeassistant/components/light/isy994.py | 4 +-- homeassistant/components/light/knx.py | 14 ++++---- homeassistant/components/light/lifx.py | 10 +++--- homeassistant/components/light/lifx_legacy.py | 10 +++--- .../components/light/limitlessled.py | 4 +-- homeassistant/components/light/litejet.py | 4 +-- homeassistant/components/light/lutron.py | 4 +-- .../components/light/lutron_caseta.py | 5 +-- homeassistant/components/light/lw12wifi.py | 4 +-- homeassistant/components/light/mochad.py | 4 +-- homeassistant/components/light/mqtt.py | 4 +-- homeassistant/components/light/mqtt_json.py | 4 +-- .../components/light/mqtt_template.py | 4 +-- homeassistant/components/light/mysensors.py | 4 +-- homeassistant/components/light/mystrom.py | 4 +-- .../components/light/nanoleaf_aurora.py | 4 +-- .../components/light/osramlightify.py | 8 ++--- homeassistant/components/light/piglow.py | 4 +-- homeassistant/components/light/qwikswitch.py | 4 +-- homeassistant/components/light/rflink.py | 7 ++-- homeassistant/components/light/rfxtrx.py | 6 ++-- .../components/light/rpi_gpio_pwm.py | 4 +-- homeassistant/components/light/scsgate.py | 4 +-- homeassistant/components/light/sensehat.py | 4 +-- homeassistant/components/light/sisyphus.py | 4 +-- homeassistant/components/light/skybell.py | 4 +-- homeassistant/components/light/tellduslive.py | 4 +-- homeassistant/components/light/tellstick.py | 10 +++--- homeassistant/components/light/template.py | 5 +-- homeassistant/components/light/tikteck.py | 4 +-- homeassistant/components/light/tplink.py | 4 +-- homeassistant/components/light/tradfri.py | 6 ++-- homeassistant/components/light/tuya.py | 4 +-- homeassistant/components/light/vera.py | 4 +-- homeassistant/components/light/wemo.py | 10 +++--- homeassistant/components/light/wink.py | 6 ++-- homeassistant/components/light/x10.py | 4 +-- .../components/light/xiaomi_aqara.py | 4 +-- homeassistant/components/light/xiaomi_miio.py | 4 +-- homeassistant/components/light/yeelight.py | 4 +-- .../components/light/yeelightsunflower.py | 4 +-- homeassistant/components/light/zengge.py | 4 +-- homeassistant/components/light/zha.py | 4 +-- homeassistant/components/light/zigbee.py | 4 +-- homeassistant/components/lock/abode.py | 4 +-- homeassistant/components/lock/august.py | 4 +-- .../components/lock/bmw_connected_drive.py | 4 +-- homeassistant/components/lock/demo.py | 4 +-- homeassistant/components/lock/homematic.py | 4 +-- homeassistant/components/lock/isy994.py | 4 +-- homeassistant/components/lock/kiwi.py | 4 +-- homeassistant/components/lock/lockitron.py | 6 ++-- homeassistant/components/lock/mqtt.py | 5 +-- homeassistant/components/lock/nello.py | 4 +-- homeassistant/components/lock/nuki.py | 4 +-- homeassistant/components/lock/sesame.py | 8 ++--- homeassistant/components/lock/tesla.py | 4 +-- homeassistant/components/lock/vera.py | 4 +-- homeassistant/components/lock/verisure.py | 4 +-- homeassistant/components/lock/volvooncall.py | 4 +-- homeassistant/components/lock/wink.py | 4 +-- homeassistant/components/lock/xiaomi_aqara.py | 4 +-- homeassistant/components/lock/zwave.py | 5 +-- .../components/mailbox/asterisk_mbox.py | 2 +- .../components/media_player/anthemav.py | 5 +-- .../components/media_player/apple_tv.py | 5 +-- .../components/media_player/aquostv.py | 6 ++-- .../components/media_player/blackbird.py | 4 +-- .../components/media_player/bluesound.py | 10 +++--- .../components/media_player/braviatv.py | 18 +++++------ homeassistant/components/media_player/cast.py | 12 +++---- .../components/media_player/channels.py | 4 +-- .../components/media_player/clementine.py | 4 +-- homeassistant/components/media_player/cmus.py | 4 +-- homeassistant/components/media_player/demo.py | 4 +-- .../components/media_player/denon.py | 4 +-- .../components/media_player/denonavr.py | 4 +-- .../components/media_player/directv.py | 4 +-- .../components/media_player/dlna_dmr.py | 4 +-- .../components/media_player/dunehd.py | 4 +-- homeassistant/components/media_player/emby.py | 5 +-- .../components/media_player/epson.py | 4 +-- .../components/media_player/firetv.py | 4 +-- .../media_player/frontier_silicon.py | 7 ++-- .../components/media_player/gpmdp.py | 14 ++++---- .../components/media_player/gstreamer.py | 4 +-- .../components/media_player/hdmi_cec.py | 8 ++--- .../components/media_player/horizon.py | 4 +-- .../components/media_player/itunes.py | 12 +++---- homeassistant/components/media_player/kodi.py | 5 +-- .../components/media_player/lg_netcast.py | 4 +-- .../components/media_player/liveboxplaytv.py | 5 +-- .../components/media_player/mediaroom.py | 12 +++---- .../components/media_player/monoprice.py | 4 +-- .../components/media_player/mpchc.py | 4 +-- homeassistant/components/media_player/mpd.py | 4 +-- homeassistant/components/media_player/nad.py | 4 +-- .../components/media_player/nadtcp.py | 4 +-- .../components/media_player/onkyo.py | 4 +-- .../components/media_player/openhome.py | 4 +-- .../media_player/panasonic_viera.py | 6 ++-- .../components/media_player/pandora.py | 4 +-- .../components/media_player/philips_js.py | 4 +-- .../components/media_player/pioneer.py | 4 +-- .../components/media_player/pjlink.py | 4 +-- homeassistant/components/media_player/plex.py | 14 ++++---- homeassistant/components/media_player/roku.py | 4 +-- .../components/media_player/russound_rio.py | 5 +-- .../components/media_player/russound_rnet.py | 4 +-- .../components/media_player/samsungtv.py | 4 +-- .../components/media_player/sisyphus.py | 4 +-- .../components/media_player/snapcast.py | 5 +-- .../components/media_player/songpal.py | 4 +-- .../components/media_player/sonos.py | 16 +++++----- .../components/media_player/soundtouch.py | 6 ++-- .../components/media_player/spotify.py | 17 +++++----- .../components/media_player/squeezebox.py | 5 +-- .../components/media_player/ue_smart_radio.py | 4 +-- .../components/media_player/universal.py | 4 +-- .../components/media_player/vizio.py | 4 +-- homeassistant/components/media_player/vlc.py | 6 ++-- .../components/media_player/volumio.py | 5 +-- .../components/media_player/webostv.py | 16 +++++----- .../components/media_player/xiaomi_tv.py | 6 ++-- .../components/media_player/yamaha.py | 4 +-- .../media_player/yamaha_musiccast.py | 4 +-- .../media_player/ziggo_mediabox_xl.py | 4 +-- .../components/mysensors/__init__.py | 6 ++-- homeassistant/components/remote/apple_tv.py | 5 +-- homeassistant/components/remote/demo.py | 4 +-- homeassistant/components/remote/harmony.py | 4 +-- homeassistant/components/remote/itach.py | 4 +-- homeassistant/components/remote/kira.py | 4 +-- .../components/remote/xiaomi_miio.py | 5 +-- homeassistant/components/scene/deconz.py | 6 ++-- .../components/scene/homeassistant.py | 5 +-- .../scene/hunterdouglas_powerview.py | 5 +-- homeassistant/components/scene/knx.py | 14 ++++---- homeassistant/components/scene/lifx_cloud.py | 5 +-- homeassistant/components/scene/litejet.py | 4 +-- .../components/scene/lutron_caseta.py | 5 +-- homeassistant/components/scene/tahoma.py | 4 +-- homeassistant/components/scene/tuya.py | 4 +-- homeassistant/components/scene/velux.py | 4 +-- homeassistant/components/scene/vera.py | 4 +-- homeassistant/components/scene/wink.py | 4 +-- homeassistant/components/sensor/abode.py | 4 +-- homeassistant/components/sensor/ads.py | 4 +-- homeassistant/components/sensor/airvisual.py | 4 +-- .../components/sensor/alarmdecoder.py | 4 +-- .../components/sensor/alpha_vantage.py | 4 +-- homeassistant/components/sensor/amcrest.py | 5 +-- .../components/sensor/android_ip_webcam.py | 5 +-- .../components/sensor/api_streams.py | 5 +-- homeassistant/components/sensor/arduino.py | 4 +-- homeassistant/components/sensor/arest.py | 4 +-- homeassistant/components/sensor/arlo.py | 4 +-- homeassistant/components/sensor/arwn.py | 5 +-- homeassistant/components/sensor/bbox.py | 4 +-- homeassistant/components/sensor/bh1750.py | 5 +-- homeassistant/components/sensor/bitcoin.py | 4 +-- homeassistant/components/sensor/blink.py | 4 +-- homeassistant/components/sensor/blockchain.py | 4 +-- homeassistant/components/sensor/bloomsky.py | 4 +-- homeassistant/components/sensor/bme280.py | 5 +-- homeassistant/components/sensor/bme680.py | 5 +-- .../components/sensor/bmw_connected_drive.py | 4 +-- homeassistant/components/sensor/bom.py | 6 ++-- homeassistant/components/sensor/broadlink.py | 4 +-- homeassistant/components/sensor/buienradar.py | 5 +-- homeassistant/components/sensor/canary.py | 4 +-- .../components/sensor/cert_expiry.py | 6 ++-- homeassistant/components/sensor/citybikes.py | 4 +-- homeassistant/components/sensor/coinbase.py | 4 +-- .../components/sensor/coinmarketcap.py | 4 +-- .../components/sensor/comed_hourly_pricing.py | 5 +-- .../components/sensor/comfoconnect.py | 4 +-- .../components/sensor/command_line.py | 4 +-- homeassistant/components/sensor/cpuspeed.py | 4 +-- .../components/sensor/crimereports.py | 4 +-- homeassistant/components/sensor/cups.py | 4 +-- .../components/sensor/currencylayer.py | 4 +-- homeassistant/components/sensor/daikin.py | 4 +-- homeassistant/components/sensor/darksky.py | 4 +-- homeassistant/components/sensor/deconz.py | 6 ++-- homeassistant/components/sensor/deluge.py | 4 +-- homeassistant/components/sensor/demo.py | 4 +-- .../components/sensor/deutsche_bahn.py | 4 +-- homeassistant/components/sensor/dht.py | 4 +-- homeassistant/components/sensor/discogs.py | 5 +-- homeassistant/components/sensor/dnsip.py | 5 +-- homeassistant/components/sensor/dovado.py | 8 ++--- homeassistant/components/sensor/dsmr.py | 5 +-- .../components/sensor/dte_energy_bridge.py | 4 +-- .../components/sensor/dublin_bus_transport.py | 4 +-- .../components/sensor/duke_energy.py | 4 +-- .../components/sensor/dwd_weather_warnings.py | 4 +-- homeassistant/components/sensor/dweet.py | 4 +-- homeassistant/components/sensor/dyson.py | 4 +-- homeassistant/components/sensor/ebox.py | 4 +-- homeassistant/components/sensor/ecobee.py | 4 +-- .../sensor/eddystone_temperature.py | 4 +-- homeassistant/components/sensor/efergy.py | 4 +-- .../components/sensor/eight_sleep.py | 4 +-- homeassistant/components/sensor/eliqonline.py | 4 +-- homeassistant/components/sensor/emoncms.py | 4 +-- homeassistant/components/sensor/enocean.py | 4 +-- .../components/sensor/enphase_envoy.py | 6 ++-- homeassistant/components/sensor/envirophat.py | 4 +-- homeassistant/components/sensor/envisalink.py | 5 +-- homeassistant/components/sensor/etherscan.py | 4 +-- homeassistant/components/sensor/fail2ban.py | 5 +-- homeassistant/components/sensor/fastdotcom.py | 4 +-- homeassistant/components/sensor/fedex.py | 4 +-- homeassistant/components/sensor/fido.py | 5 +-- homeassistant/components/sensor/file.py | 5 +-- homeassistant/components/sensor/filesize.py | 4 +-- homeassistant/components/sensor/filter.py | 4 +-- homeassistant/components/sensor/fints.py | 4 +-- homeassistant/components/sensor/fitbit.py | 23 ++++++------- homeassistant/components/sensor/fixer.py | 4 +-- homeassistant/components/sensor/folder.py | 4 +-- homeassistant/components/sensor/foobot.py | 4 +-- .../components/sensor/fritzbox_callmonitor.py | 4 +-- .../components/sensor/fritzbox_netmonitor.py | 4 +-- homeassistant/components/sensor/gearbest.py | 4 +-- homeassistant/components/sensor/geizhals.py | 6 ++-- .../components/sensor/geo_rss_events.py | 4 +-- homeassistant/components/sensor/gitter.py | 4 +-- homeassistant/components/sensor/glances.py | 4 +-- .../components/sensor/google_travel_time.py | 4 +-- .../components/sensor/google_wifi.py | 4 +-- homeassistant/components/sensor/gpsd.py | 4 +-- homeassistant/components/sensor/gtfs.py | 5 +-- .../components/sensor/haveibeenpwned.py | 4 +-- homeassistant/components/sensor/hddtemp.py | 4 +-- .../components/sensor/history_stats.py | 6 ++-- homeassistant/components/sensor/hive.py | 4 +-- homeassistant/components/sensor/homematic.py | 4 +-- .../components/sensor/homematicip_cloud.py | 6 ++-- homeassistant/components/sensor/hp_ilo.py | 4 +-- homeassistant/components/sensor/htu21d.py | 5 +-- homeassistant/components/sensor/hydrawise.py | 4 +-- .../components/sensor/hydroquebec.py | 5 +-- homeassistant/components/sensor/ihc.py | 4 +-- homeassistant/components/sensor/imap.py | 4 +-- .../components/sensor/imap_email_content.py | 4 +-- homeassistant/components/sensor/influxdb.py | 4 +-- homeassistant/components/sensor/insteon.py | 5 +-- homeassistant/components/sensor/ios.py | 4 +-- homeassistant/components/sensor/iota.py | 4 +-- homeassistant/components/sensor/iperf3.py | 4 +-- .../components/sensor/irish_rail_transport.py | 4 +-- homeassistant/components/sensor/isy994.py | 4 +-- homeassistant/components/sensor/juicenet.py | 4 +-- homeassistant/components/sensor/kira.py | 4 +-- homeassistant/components/sensor/knx.py | 14 ++++---- homeassistant/components/sensor/kwb.py | 4 +-- homeassistant/components/sensor/lacrosse.py | 4 +-- homeassistant/components/sensor/lastfm.py | 4 +-- .../components/sensor/linux_battery.py | 4 +-- homeassistant/components/sensor/london_air.py | 4 +-- .../components/sensor/london_underground.py | 4 +-- homeassistant/components/sensor/loopenergy.py | 4 +-- homeassistant/components/sensor/luftdaten.py | 4 +-- homeassistant/components/sensor/lyft.py | 4 +-- .../components/sensor/magicseaweed.py | 4 +-- homeassistant/components/sensor/melissa.py | 4 +-- homeassistant/components/sensor/metoffice.py | 4 +-- homeassistant/components/sensor/mfi.py | 10 +++--- homeassistant/components/sensor/mhz19.py | 4 +-- homeassistant/components/sensor/miflora.py | 4 +-- homeassistant/components/sensor/min_max.py | 5 +-- homeassistant/components/sensor/mitemp_bt.py | 4 +-- homeassistant/components/sensor/modbus.py | 4 +-- .../components/sensor/modem_callerid.py | 4 +-- .../components/sensor/mold_indicator.py | 4 +-- homeassistant/components/sensor/moon.py | 4 +-- homeassistant/components/sensor/mopar.py | 6 ++-- homeassistant/components/sensor/mqtt.py | 4 +-- homeassistant/components/sensor/mqtt_room.py | 5 +-- homeassistant/components/sensor/mvglive.py | 4 +-- homeassistant/components/sensor/mychevy.py | 4 +-- homeassistant/components/sensor/mysensors.py | 4 +-- .../sensor/nederlandse_spoorwegen.py | 4 +-- homeassistant/components/sensor/nest.py | 6 ++-- homeassistant/components/sensor/netatmo.py | 4 +-- .../components/sensor/netatmo_public.py | 4 +-- homeassistant/components/sensor/netdata.py | 4 +-- .../components/sensor/netgear_lte.py | 4 +-- .../components/sensor/neurio_energy.py | 6 ++-- homeassistant/components/sensor/noaa_tides.py | 4 +-- .../components/sensor/nsw_fuel_station.py | 4 +-- homeassistant/components/sensor/nzbget.py | 4 +-- homeassistant/components/sensor/octoprint.py | 4 +-- homeassistant/components/sensor/ohmconnect.py | 4 +-- homeassistant/components/sensor/onewire.py | 4 +-- homeassistant/components/sensor/openevse.py | 4 +-- .../components/sensor/openexchangerates.py | 4 +-- .../components/sensor/openhardwaremonitor.py | 4 +-- homeassistant/components/sensor/opensky.py | 4 +-- homeassistant/components/sensor/openuv.py | 4 +-- .../components/sensor/openweathermap.py | 4 +-- homeassistant/components/sensor/otp.py | 5 +-- homeassistant/components/sensor/pi_hole.py | 4 +-- homeassistant/components/sensor/pilight.py | 4 +-- homeassistant/components/sensor/plex.py | 4 +-- .../components/sensor/pocketcasts.py | 4 +-- homeassistant/components/sensor/pollen.py | 4 +-- homeassistant/components/sensor/postnl.py | 4 +-- homeassistant/components/sensor/pushbullet.py | 4 +-- homeassistant/components/sensor/pvoutput.py | 4 +-- homeassistant/components/sensor/pyload.py | 4 +-- homeassistant/components/sensor/qnap.py | 4 +-- homeassistant/components/sensor/qwikswitch.py | 4 +-- homeassistant/components/sensor/radarr.py | 4 +-- homeassistant/components/sensor/rainbird.py | 4 +-- homeassistant/components/sensor/raincloud.py | 4 +-- .../components/sensor/rainmachine.py | 4 +-- homeassistant/components/sensor/random.py | 4 +-- homeassistant/components/sensor/rest.py | 4 +-- homeassistant/components/sensor/rflink.py | 7 ++-- homeassistant/components/sensor/rfxtrx.py | 6 ++-- homeassistant/components/sensor/ring.py | 4 +-- homeassistant/components/sensor/ripple.py | 4 +-- homeassistant/components/sensor/sabnzbd.py | 6 ++-- homeassistant/components/sensor/scrape.py | 4 +-- homeassistant/components/sensor/season.py | 4 +-- homeassistant/components/sensor/sense.py | 4 +-- homeassistant/components/sensor/sensehat.py | 4 +-- homeassistant/components/sensor/serial.py | 5 +-- homeassistant/components/sensor/serial_pm.py | 4 +-- homeassistant/components/sensor/shodan.py | 4 +-- homeassistant/components/sensor/sht31.py | 4 +-- homeassistant/components/sensor/sigfox.py | 4 +-- homeassistant/components/sensor/simulated.py | 4 +-- homeassistant/components/sensor/skybeacon.py | 6 ++-- homeassistant/components/sensor/skybell.py | 4 +-- homeassistant/components/sensor/sleepiq.py | 4 +-- homeassistant/components/sensor/sma.py | 5 +-- homeassistant/components/sensor/smappee.py | 4 +-- homeassistant/components/sensor/snmp.py | 4 +-- homeassistant/components/sensor/sochain.py | 5 +-- .../components/sensor/socialblade.py | 4 +-- homeassistant/components/sensor/sonarr.py | 4 +-- homeassistant/components/sensor/speedtest.py | 4 +-- homeassistant/components/sensor/spotcrime.py | 4 +-- homeassistant/components/sensor/sql.py | 4 +-- homeassistant/components/sensor/startca.py | 5 +-- homeassistant/components/sensor/statistics.py | 5 +-- .../components/sensor/steam_online.py | 4 +-- .../components/sensor/supervisord.py | 4 +-- .../sensor/swiss_hydrological_data.py | 4 +-- .../sensor/swiss_public_transport.py | 4 +-- homeassistant/components/sensor/syncthru.py | 4 +-- .../components/sensor/synologydsm.py | 4 +-- .../components/sensor/systemmonitor.py | 4 +-- homeassistant/components/sensor/sytadin.py | 4 +-- homeassistant/components/sensor/tado.py | 4 +-- homeassistant/components/sensor/tahoma.py | 4 +-- .../components/sensor/tank_utility.py | 4 +-- homeassistant/components/sensor/tcp.py | 4 +-- homeassistant/components/sensor/ted5000.py | 4 +-- homeassistant/components/sensor/teksavvy.py | 5 +-- .../components/sensor/tellduslive.py | 4 +-- homeassistant/components/sensor/tellstick.py | 4 +-- homeassistant/components/sensor/temper.py | 4 +-- homeassistant/components/sensor/template.py | 5 +-- homeassistant/components/sensor/tesla.py | 4 +-- .../components/sensor/thethingsnetwork.py | 5 +-- .../components/sensor/thinkingcleaner.py | 4 +-- homeassistant/components/sensor/tibber.py | 4 +-- homeassistant/components/sensor/time_date.py | 5 +-- homeassistant/components/sensor/toon.py | 4 +-- homeassistant/components/sensor/torque.py | 10 +++--- homeassistant/components/sensor/tradfri.py | 4 +-- .../sensor/trafikverket_weatherstation.py | 4 +-- .../components/sensor/transmission.py | 4 +-- homeassistant/components/sensor/travisci.py | 4 +-- homeassistant/components/sensor/twitch.py | 4 +-- homeassistant/components/sensor/uber.py | 4 +-- .../components/sensor/uk_transport.py | 4 +-- homeassistant/components/sensor/upnp.py | 4 +-- homeassistant/components/sensor/ups.py | 6 ++-- homeassistant/components/sensor/uptime.py | 4 +-- homeassistant/components/sensor/uscis.py | 4 +-- homeassistant/components/sensor/usps.py | 4 +-- homeassistant/components/sensor/vasttrafik.py | 4 +-- homeassistant/components/sensor/vera.py | 4 +-- homeassistant/components/sensor/verisure.py | 4 +-- homeassistant/components/sensor/version.py | 4 +-- .../components/sensor/viaggiatreno.py | 5 +-- .../components/sensor/volvooncall.py | 4 +-- homeassistant/components/sensor/vultr.py | 4 +-- homeassistant/components/sensor/waqi.py | 5 +-- .../components/sensor/waterfurnace.py | 4 +-- .../components/sensor/waze_travel_time.py | 4 +-- homeassistant/components/sensor/whois.py | 4 +-- homeassistant/components/sensor/wink.py | 10 +++--- .../components/sensor/wirelesstag.py | 4 +-- homeassistant/components/sensor/worldclock.py | 4 +-- .../components/sensor/worldtidesinfo.py | 4 +-- .../components/sensor/worxlandroid.py | 4 +-- homeassistant/components/sensor/wsdot.py | 4 +-- .../components/sensor/wunderground.py | 4 +-- homeassistant/components/sensor/xbox_live.py | 4 +-- .../components/sensor/xiaomi_aqara.py | 4 +-- .../components/sensor/xiaomi_miio.py | 4 +-- .../components/sensor/yahoo_finance.py | 4 +-- homeassistant/components/sensor/yr.py | 5 +-- homeassistant/components/sensor/yweather.py | 4 +-- homeassistant/components/sensor/zabbix.py | 4 +-- homeassistant/components/sensor/zamg.py | 6 ++-- homeassistant/components/sensor/zestimate.py | 4 +-- homeassistant/components/sensor/zha.py | 5 +-- homeassistant/components/sensor/zigbee.py | 4 +-- homeassistant/components/sensor/zoneminder.py | 4 +-- homeassistant/components/switch/abode.py | 4 +-- .../components/switch/acer_projector.py | 4 +-- homeassistant/components/switch/ads.py | 4 +-- homeassistant/components/switch/amcrest.py | 5 +-- .../components/switch/android_ip_webcam.py | 5 +-- .../components/switch/anel_pwrctrl.py | 4 +-- homeassistant/components/switch/arduino.py | 4 +-- homeassistant/components/switch/arest.py | 4 +-- homeassistant/components/switch/bbb_gpio.py | 4 +-- homeassistant/components/switch/broadlink.py | 4 +-- .../components/switch/command_line.py | 4 +-- homeassistant/components/switch/deconz.py | 6 ++-- homeassistant/components/switch/deluge.py | 4 +-- homeassistant/components/switch/demo.py | 4 +-- .../components/switch/digital_ocean.py | 4 +-- .../components/switch/digitalloggers.py | 4 +-- homeassistant/components/switch/dlink.py | 4 +-- homeassistant/components/switch/doorbird.py | 4 +-- homeassistant/components/switch/edimax.py | 4 +-- homeassistant/components/switch/enocean.py | 4 +-- homeassistant/components/switch/eufy.py | 4 +-- homeassistant/components/switch/flux.py | 4 +-- homeassistant/components/switch/fritzbox.py | 4 +-- homeassistant/components/switch/fritzdect.py | 4 +-- homeassistant/components/switch/gc100.py | 4 +-- homeassistant/components/switch/hdmi_cec.py | 8 ++--- .../components/switch/hikvisioncam.py | 4 +-- homeassistant/components/switch/hive.py | 4 +-- .../components/switch/homekit_controller.py | 4 +-- homeassistant/components/switch/homematic.py | 4 +-- .../components/switch/homematicip_cloud.py | 6 ++-- homeassistant/components/switch/hook.py | 5 +-- homeassistant/components/switch/hydrawise.py | 4 +-- homeassistant/components/switch/ihc.py | 4 +-- homeassistant/components/switch/insteon.py | 5 +-- homeassistant/components/switch/isy994.py | 4 +-- homeassistant/components/switch/kankun.py | 4 +-- homeassistant/components/switch/knx.py | 14 ++++---- homeassistant/components/switch/konnected.py | 4 +-- homeassistant/components/switch/linode.py | 4 +-- homeassistant/components/switch/litejet.py | 4 +-- .../components/switch/lutron_caseta.py | 5 +-- homeassistant/components/switch/mfi.py | 10 +++--- homeassistant/components/switch/mochad.py | 4 +-- homeassistant/components/switch/modbus.py | 4 +-- homeassistant/components/switch/mqtt.py | 4 +-- homeassistant/components/switch/mysensors.py | 4 +-- homeassistant/components/switch/mystrom.py | 4 +-- homeassistant/components/switch/neato.py | 4 +-- homeassistant/components/switch/netio.py | 4 +-- homeassistant/components/switch/orvibo.py | 4 +-- homeassistant/components/switch/pilight.py | 4 +-- .../components/switch/pulseaudio_loopback.py | 5 +-- homeassistant/components/switch/qwikswitch.py | 4 +-- homeassistant/components/switch/rachio.py | 4 +-- homeassistant/components/switch/rainbird.py | 4 +-- homeassistant/components/switch/raincloud.py | 4 +-- .../components/switch/rainmachine.py | 4 +-- homeassistant/components/switch/raspihats.py | 4 +-- homeassistant/components/switch/rest.py | 5 +-- homeassistant/components/switch/rflink.py | 5 +-- homeassistant/components/switch/rfxtrx.py | 6 ++-- homeassistant/components/switch/rpi_gpio.py | 4 +-- homeassistant/components/switch/rpi_pfio.py | 4 +-- homeassistant/components/switch/rpi_rf.py | 4 +-- homeassistant/components/switch/scsgate.py | 8 ++--- homeassistant/components/switch/skybell.py | 4 +-- homeassistant/components/switch/smappee.py | 4 +-- homeassistant/components/switch/snmp.py | 4 +-- homeassistant/components/switch/spider.py | 4 +-- homeassistant/components/switch/tahoma.py | 4 +-- .../components/switch/tellduslive.py | 4 +-- homeassistant/components/switch/tellstick.py | 10 +++--- homeassistant/components/switch/telnet.py | 4 +-- homeassistant/components/switch/template.py | 5 +-- homeassistant/components/switch/tesla.py | 4 +-- .../components/switch/thinkingcleaner.py | 4 +-- homeassistant/components/switch/toon.py | 4 +-- homeassistant/components/switch/tplink.py | 4 +-- .../components/switch/transmission.py | 4 +-- homeassistant/components/switch/tuya.py | 4 +-- homeassistant/components/switch/upcloud.py | 4 +-- homeassistant/components/switch/velbus.py | 4 +-- homeassistant/components/switch/vera.py | 4 +-- homeassistant/components/switch/verisure.py | 4 +-- homeassistant/components/switch/vesync.py | 4 +-- .../components/switch/volvooncall.py | 4 +-- homeassistant/components/switch/vultr.py | 4 +-- .../components/switch/wake_on_lan.py | 6 ++-- homeassistant/components/switch/wemo.py | 4 +-- homeassistant/components/switch/wink.py | 10 +++--- .../components/switch/wirelesstag.py | 4 +-- .../components/switch/xiaomi_aqara.py | 4 +-- .../components/switch/xiaomi_miio.py | 4 +-- homeassistant/components/switch/zha.py | 4 +-- homeassistant/components/switch/zigbee.py | 4 +-- homeassistant/components/switch/zoneminder.py | 4 +-- homeassistant/components/vacuum/demo.py | 4 +-- homeassistant/components/vacuum/dyson.py | 4 +-- homeassistant/components/vacuum/ecovacs.py | 4 +-- homeassistant/components/vacuum/mqtt.py | 5 +-- homeassistant/components/vacuum/neato.py | 4 +-- homeassistant/components/vacuum/roomba.py | 5 +-- .../components/vacuum/xiaomi_miio.py | 5 +-- homeassistant/components/weather/bom.py | 4 +-- .../components/weather/buienradar.py | 5 +-- homeassistant/components/weather/darksky.py | 4 +-- homeassistant/components/weather/demo.py | 4 +-- homeassistant/components/weather/ecobee.py | 4 +-- homeassistant/components/weather/ipma.py | 4 +-- homeassistant/components/weather/metoffice.py | 4 +-- .../components/weather/openweathermap.py | 4 +-- homeassistant/components/weather/yweather.py | 4 +-- homeassistant/components/weather/zamg.py | 4 +-- homeassistant/components/zwave/__init__.py | 4 +-- .../alarm_control_panel/test_manual.py | 6 ++-- .../alarm_control_panel/test_spc.py | 2 +- tests/components/binary_sensor/test_nx584.py | 18 +++++------ tests/components/binary_sensor/test_ring.py | 4 +-- .../components/binary_sensor/test_sleepiq.py | 4 +-- tests/components/binary_sensor/test_spc.py | 2 +- tests/components/binary_sensor/test_tcp.py | 10 +++--- tests/components/binary_sensor/test_vultr.py | 8 ++--- tests/components/climate/test_honeywell.py | 32 +++++++++---------- tests/components/climate/test_melissa.py | 6 ++-- tests/components/climate/test_nuheat.py | 6 ++-- tests/components/fan/test_dyson.py | 6 ++-- tests/components/light/test_group.py | 8 ++--- tests/components/media_player/test_cast.py | 26 +++++++-------- .../components/media_player/test_samsungtv.py | 14 ++++---- tests/components/media_player/test_sonos.py | 20 ++++++------ .../components/media_player/test_universal.py | 6 ++-- tests/components/remote/test_kira.py | 4 +-- tests/components/sensor/test_arlo.py | 8 ++--- tests/components/sensor/test_canary.py | 4 +-- tests/components/sensor/test_dyson.py | 6 ++-- tests/components/sensor/test_efergy.py | 2 +- tests/components/sensor/test_fido.py | 10 +++--- tests/components/sensor/test_foobot.py | 12 +++---- tests/components/sensor/test_hydroquebec.py | 6 ++-- tests/components/sensor/test_kira.py | 4 +-- tests/components/sensor/test_melissa.py | 4 +-- tests/components/sensor/test_radarr.py | 20 ++++++------ tests/components/sensor/test_ring.py | 4 +-- tests/components/sensor/test_season.py | 2 +- tests/components/sensor/test_sleepiq.py | 4 +-- tests/components/sensor/test_sonarr.py | 24 +++++++------- tests/components/sensor/test_tcp.py | 10 +++--- tests/components/sensor/test_time_date.py | 2 +- tests/components/sensor/test_vultr.py | 6 ++-- tests/components/switch/test_vultr.py | 8 ++--- tests/components/vacuum/test_dyson.py | 6 ++-- tests/components/weather/test_yweather.py | 2 +- tests/components/zwave/test_init.py | 18 +++++------ tests/helpers/test_discovery.py | 2 +- tests/helpers/test_entity_component.py | 8 ++--- tests/helpers/test_entity_platform.py | 8 ++--- .../image_processing/test.py | 4 +-- .../custom_components/light/test.py | 4 +-- .../custom_components/switch/test.py | 4 +-- 839 files changed, 2121 insertions(+), 2008 deletions(-) diff --git a/homeassistant/components/alarm_control_panel/abode.py b/homeassistant/components/alarm_control_panel/abode.py index 75eb9fd824d..c57666d4fe6 100644 --- a/homeassistant/components/alarm_control_panel/abode.py +++ b/homeassistant/components/alarm_control_panel/abode.py @@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__) ICON = 'mdi:security' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an alarm control panel for an Abode device.""" data = hass.data[ABODE_DOMAIN] @@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(alarm_devices) - add_devices(alarm_devices) + add_entities(alarm_devices) class AbodeAlarm(AbodeDevice, AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/alarmdecoder.py b/homeassistant/components/alarm_control_panel/alarmdecoder.py index 626022e362a..5606209d1e6 100644 --- a/homeassistant/components/alarm_control_panel/alarmdecoder.py +++ b/homeassistant/components/alarm_control_panel/alarmdecoder.py @@ -26,10 +26,10 @@ ALARM_TOGGLE_CHIME_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up for AlarmDecoder alarm panels.""" device = AlarmDecoderAlarmPanel() - add_devices([device]) + add_entities([device]) def alarm_toggle_chime_handler(service): """Register toggle chime handler.""" diff --git a/homeassistant/components/alarm_control_panel/alarmdotcom.py b/homeassistant/components/alarm_control_panel/alarmdotcom.py index 736334c956a..98766deb3b6 100644 --- a/homeassistant/components/alarm_control_panel/alarmdotcom.py +++ b/homeassistant/components/alarm_control_panel/alarmdotcom.py @@ -33,7 +33,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up a Alarm.com control panel.""" name = config.get(CONF_NAME) code = config.get(CONF_CODE) @@ -42,7 +43,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): alarmdotcom = AlarmDotCom(hass, name, code, username, password) yield from alarmdotcom.async_login() - async_add_devices([alarmdotcom]) + async_add_entities([alarmdotcom]) class AlarmDotCom(alarm.AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/arlo.py b/homeassistant/components/alarm_control_panel/arlo.py index 0f8913f85a0..8842c710a05 100644 --- a/homeassistant/components/alarm_control_panel/arlo.py +++ b/homeassistant/components/alarm_control_panel/arlo.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Arlo Alarm Control Panels.""" arlo = hass.data[DATA_ARLO] @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for base_station in arlo.base_stations: base_stations.append(ArloBaseStation(base_station, home_mode_name, away_mode_name)) - add_devices(base_stations, True) + add_entities(base_stations, True) class ArloBaseStation(AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/canary.py b/homeassistant/components/alarm_control_panel/canary.py index 3cd44dcc84c..b22a76fdb3b 100644 --- a/homeassistant/components/alarm_control_panel/canary.py +++ b/homeassistant/components/alarm_control_panel/canary.py @@ -16,7 +16,7 @@ DEPENDENCIES = ['canary'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Canary alarms.""" data = hass.data[DATA_CANARY] devices = [] @@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for location in data.locations: devices.append(CanaryAlarm(data, location.location_id)) - add_devices(devices, True) + add_entities(devices, True) class CanaryAlarm(AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/concord232.py b/homeassistant/components/alarm_control_panel/concord232.py index 9a65fdaff06..e3c2b4a7ec7 100644 --- a/homeassistant/components/alarm_control_panel/concord232.py +++ b/homeassistant/components/alarm_control_panel/concord232.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Concord232 alarm control panel platform.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): url = 'http://{}:{}'.format(host, port) try: - add_devices([Concord232Alarm(hass, url, name)]) + add_entities([Concord232Alarm(hass, url, name)]) except requests.exceptions.ConnectionError as ex: _LOGGER.error("Unable to connect to Concord232: %s", str(ex)) return diff --git a/homeassistant/components/alarm_control_panel/demo.py b/homeassistant/components/alarm_control_panel/demo.py index d2366e5836c..a3fbe49477e 100644 --- a/homeassistant/components/alarm_control_panel/demo.py +++ b/homeassistant/components/alarm_control_panel/demo.py @@ -13,9 +13,9 @@ from homeassistant.const import ( CONF_PENDING_TIME, CONF_TRIGGER_TIME) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo alarm control panel platform.""" - add_devices([ + add_entities([ manual.ManualAlarm(hass, 'Alarm', '1234', None, False, { STATE_ALARM_ARMED_AWAY: { CONF_DELAY_TIME: datetime.timedelta(seconds=0), diff --git a/homeassistant/components/alarm_control_panel/egardia.py b/homeassistant/components/alarm_control_panel/egardia.py index f0db378ec15..4e278c10e07 100644 --- a/homeassistant/components/alarm_control_panel/egardia.py +++ b/homeassistant/components/alarm_control_panel/egardia.py @@ -34,7 +34,7 @@ STATES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Egardia platform.""" if discovery_info is None: return @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): discovery_info.get(CONF_REPORT_SERVER_CODES), discovery_info[CONF_REPORT_SERVER_PORT]) # add egardia alarm device - add_devices([device], True) + add_entities([device], True) class EgardiaAlarm(alarm.AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/envisalink.py b/homeassistant/components/alarm_control_panel/envisalink.py index 25224484c79..df91884b32c 100644 --- a/homeassistant/components/alarm_control_panel/envisalink.py +++ b/homeassistant/components/alarm_control_panel/envisalink.py @@ -33,7 +33,8 @@ ALARM_KEYPRESS_SCHEMA = vol.Schema({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Perform the setup for Envisalink alarm panels.""" configured_partitions = discovery_info['partitions'] code = discovery_info[CONF_CODE] @@ -53,7 +54,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): ) devices.append(device) - async_add_devices(devices) + async_add_entities(devices) @callback def alarm_keypress_handler(service): diff --git a/homeassistant/components/alarm_control_panel/homematicip_cloud.py b/homeassistant/components/alarm_control_panel/homematicip_cloud.py index 9f5b52a31f4..8c483121650 100644 --- a/homeassistant/components/alarm_control_panel/homematicip_cloud.py +++ b/homeassistant/components/alarm_control_panel/homematicip_cloud.py @@ -24,12 +24,12 @@ HMIP_ZONE_HOME = 'INTERNAL' async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the HomematicIP Cloud alarm control devices.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP alarm control panel from a config entry.""" from homematicip.aio.group import AsyncSecurityZoneGroup @@ -40,7 +40,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): devices.append(HomematicipSecurityZone(home, group)) if devices: - async_add_devices(devices) + async_add_entities(devices) class HomematicipSecurityZone(HomematicipGenericDevice, AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/ialarm.py b/homeassistant/components/alarm_control_panel/ialarm.py index 2dc7e11d21e..3f41ee57902 100644 --- a/homeassistant/components/alarm_control_panel/ialarm.py +++ b/homeassistant/components/alarm_control_panel/ialarm.py @@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an iAlarm control panel.""" name = config.get(CONF_NAME) username = config.get(CONF_USERNAME) @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): url = 'http://{}'.format(host) ialarm = IAlarmPanel(name, username, password, url) - add_devices([ialarm], True) + add_entities([ialarm], True) class IAlarmPanel(alarm.AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/ifttt.py b/homeassistant/components/alarm_control_panel/ifttt.py index 9941f70a2e4..49c5dc488c0 100644 --- a/homeassistant/components/alarm_control_panel/ifttt.py +++ b/homeassistant/components/alarm_control_panel/ifttt.py @@ -59,7 +59,7 @@ PUSH_ALARM_STATE_SERVICE_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a control panel managed through IFTTT.""" if DATA_IFTTT_ALARM not in hass.data: hass.data[DATA_IFTTT_ALARM] = [] @@ -75,7 +75,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): alarmpanel = IFTTTAlarmPanel(name, code, event_away, event_home, event_night, event_disarm, optimistic) hass.data[DATA_IFTTT_ALARM].append(alarmpanel) - add_devices([alarmpanel]) + add_entities([alarmpanel]) async def push_state_update(service): """Set the service state as device state attribute.""" diff --git a/homeassistant/components/alarm_control_panel/manual.py b/homeassistant/components/alarm_control_panel/manual.py index b2b7c45d410..41f7d6988a8 100644 --- a/homeassistant/components/alarm_control_panel/manual.py +++ b/homeassistant/components/alarm_control_panel/manual.py @@ -103,9 +103,9 @@ PLATFORM_SCHEMA = vol.Schema(vol.All({ }, _state_validator)) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the manual alarm platform.""" - add_devices([ManualAlarm( + add_entities([ManualAlarm( hass, config[CONF_NAME], config.get(CONF_CODE), diff --git a/homeassistant/components/alarm_control_panel/manual_mqtt.py b/homeassistant/components/alarm_control_panel/manual_mqtt.py index 942d0dc159a..7bf9443424c 100644 --- a/homeassistant/components/alarm_control_panel/manual_mqtt.py +++ b/homeassistant/components/alarm_control_panel/manual_mqtt.py @@ -123,9 +123,9 @@ PLATFORM_SCHEMA = vol.Schema(vol.All(mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ }), _state_validator)) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the manual MQTT alarm platform.""" - add_devices([ManualMQTTAlarm( + add_entities([ManualMQTTAlarm( hass, config[CONF_NAME], config.get(CONF_CODE), diff --git a/homeassistant/components/alarm_control_panel/mqtt.py b/homeassistant/components/alarm_control_panel/mqtt.py index 54b85ffbe23..e5ad54c4147 100644 --- a/homeassistant/components/alarm_control_panel/mqtt.py +++ b/homeassistant/components/alarm_control_panel/mqtt.py @@ -47,12 +47,13 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the MQTT Alarm Control Panel platform.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) - async_add_devices([MqttAlarm( + async_add_entities([MqttAlarm( config.get(CONF_NAME), config.get(CONF_STATE_TOPIC), config.get(CONF_COMMAND_TOPIC), diff --git a/homeassistant/components/alarm_control_panel/nx584.py b/homeassistant/components/alarm_control_panel/nx584.py index ca6f1a44a6f..67ec73bceba 100644 --- a/homeassistant/components/alarm_control_panel/nx584.py +++ b/homeassistant/components/alarm_control_panel/nx584.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NX584 platform.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): url = 'http://{}:{}'.format(host, port) try: - add_devices([NX584Alarm(hass, url, name)]) + add_entities([NX584Alarm(hass, url, name)]) except requests.exceptions.ConnectionError as ex: _LOGGER.error("Unable to connect to NX584: %s", str(ex)) return False diff --git a/homeassistant/components/alarm_control_panel/satel_integra.py b/homeassistant/components/alarm_control_panel/satel_integra.py index 4ac3a93fff4..86603763396 100644 --- a/homeassistant/components/alarm_control_panel/satel_integra.py +++ b/homeassistant/components/alarm_control_panel/satel_integra.py @@ -19,14 +19,15 @@ DEPENDENCIES = ['satel_integra'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up for Satel Integra alarm panels.""" if not discovery_info: return device = SatelIntegraAlarmPanel( "Alarm Panel", discovery_info.get(CONF_ARM_HOME_MODE)) - async_add_devices([device]) + async_add_entities([device]) class SatelIntegraAlarmPanel(alarm.AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/simplisafe.py b/homeassistant/components/alarm_control_panel/simplisafe.py index 47b274875fc..2c3b25330d9 100644 --- a/homeassistant/components/alarm_control_panel/simplisafe.py +++ b/homeassistant/components/alarm_control_panel/simplisafe.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SimpliSafe platform.""" from simplipy.api import SimpliSafeApiInterface, SimpliSafeAPIException name = config.get(CONF_NAME) @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for system in simplisafe.get_systems(): systems.append(SimpliSafeAlarm(system, name, code)) - add_devices(systems) + add_entities(systems) class SimpliSafeAlarm(AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/spc.py b/homeassistant/components/alarm_control_panel/spc.py index 5d5b2284bab..2aa157a5cad 100644 --- a/homeassistant/components/alarm_control_panel/spc.py +++ b/homeassistant/components/alarm_control_panel/spc.py @@ -29,7 +29,8 @@ def _get_alarm_state(spc_mode): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the SPC alarm control panel platform.""" if (discovery_info is None or discovery_info[ATTR_DISCOVER_AREAS] is None): @@ -39,7 +40,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): devices = [SpcAlarm(api, area) for area in discovery_info[ATTR_DISCOVER_AREAS]] - async_add_devices(devices) + async_add_entities(devices) class SpcAlarm(alarm.AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/totalconnect.py b/homeassistant/components/alarm_control_panel/totalconnect.py index 674eac97f8c..f594a798dce 100644 --- a/homeassistant/components/alarm_control_panel/totalconnect.py +++ b/homeassistant/components/alarm_control_panel/totalconnect.py @@ -31,14 +31,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a TotalConnect control panel.""" name = config.get(CONF_NAME) username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) total_connect = TotalConnect(name, username, password) - add_devices([total_connect], True) + add_entities([total_connect], True) class TotalConnect(alarm.AlarmControlPanel): diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index 59bfe15fa9b..f5a631df390 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -17,13 +17,13 @@ from homeassistant.const import ( _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Verisure platform.""" alarms = [] if int(hub.config.get(CONF_ALARM, 1)): hub.update_overview() alarms.append(VerisureAlarm()) - add_devices(alarms) + add_entities(alarms) def set_arm_state(state, code=None): diff --git a/homeassistant/components/alarm_control_panel/wink.py b/homeassistant/components/alarm_control_panel/wink.py index 771d157efe0..d75fad30c96 100644 --- a/homeassistant/components/alarm_control_panel/wink.py +++ b/homeassistant/components/alarm_control_panel/wink.py @@ -20,7 +20,7 @@ DEPENDENCIES = ['wink'] STATE_ALARM_PRIVACY = 'Private' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink platform.""" import pywink @@ -32,7 +32,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except AttributeError: _id = camera.object_id() + camera.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkCameraDevice(camera, hass)]) + add_entities([WinkCameraDevice(camera, hass)]) class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanel): diff --git a/homeassistant/components/binary_sensor/abode.py b/homeassistant/components/binary_sensor/abode.py index 8ad40158958..a821abf445b 100644 --- a/homeassistant/components/binary_sensor/abode.py +++ b/homeassistant/components/binary_sensor/abode.py @@ -16,7 +16,7 @@ DEPENDENCIES = ['abode'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for an Abode device.""" import abodepy.helpers.constants as CONST import abodepy.helpers.timeline as TIMELINE @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(devices) - add_devices(devices) + add_entities(devices) class AbodeBinarySensor(AbodeDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/ads.py b/homeassistant/components/binary_sensor/ads.py index b7f0ebcc9d3..d46ff5ec2ee 100644 --- a/homeassistant/components/binary_sensor/ads.py +++ b/homeassistant/components/binary_sensor/ads.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Binary Sensor platform for ADS.""" ads_hub = hass.data.get(DATA_ADS) @@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device_class = config.get(CONF_DEVICE_CLASS) ads_sensor = AdsBinarySensor(ads_hub, name, ads_var, device_class) - add_devices([ads_sensor]) + add_entities([ads_sensor]) class AdsBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/alarmdecoder.py b/homeassistant/components/binary_sensor/alarmdecoder.py index fcc77d474e1..82bcc50259f 100644 --- a/homeassistant/components/binary_sensor/alarmdecoder.py +++ b/homeassistant/components/binary_sensor/alarmdecoder.py @@ -28,7 +28,7 @@ ATTR_RF_LOOP4 = 'rf_loop4' ATTR_RF_LOOP1 = 'rf_loop1' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the AlarmDecoder binary sensor devices.""" configured_zones = discovery_info[CONF_ZONES] @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): zone_num, zone_name, zone_type, zone_rfid, relay_addr, relay_chan) devices.append(device) - add_devices(devices) + add_entities(devices) return True diff --git a/homeassistant/components/binary_sensor/android_ip_webcam.py b/homeassistant/components/binary_sensor/android_ip_webcam.py index b1940f432ae..58de81c30e7 100644 --- a/homeassistant/components/binary_sensor/android_ip_webcam.py +++ b/homeassistant/components/binary_sensor/android_ip_webcam.py @@ -14,7 +14,8 @@ DEPENDENCIES = ['android_ip_webcam'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the IP Webcam binary sensors.""" if discovery_info is None: return @@ -23,7 +24,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): name = discovery_info[CONF_NAME] ipcam = hass.data[DATA_IP_WEBCAM][host] - async_add_devices( + async_add_entities( [IPWebcamBinarySensor(name, host, ipcam, 'motion_active')], True) diff --git a/homeassistant/components/binary_sensor/apcupsd.py b/homeassistant/components/binary_sensor/apcupsd.py index 412656a3b56..f876b8cc34b 100644 --- a/homeassistant/components/binary_sensor/apcupsd.py +++ b/homeassistant/components/binary_sensor/apcupsd.py @@ -20,9 +20,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an APCUPSd Online Status binary sensor.""" - add_devices([OnlineStatus(config, apcupsd.DATA)], True) + add_entities([OnlineStatus(config, apcupsd.DATA)], True) class OnlineStatus(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/arest.py b/homeassistant/components/binary_sensor/arest.py index 0366f753ba6..b70620df3e2 100644 --- a/homeassistant/components/binary_sensor/arest.py +++ b/homeassistant/components/binary_sensor/arest.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the aREST binary sensor.""" resource = config.get(CONF_RESOURCE) pin = config.get(CONF_PIN) @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): arest = ArestData(resource, pin) - add_devices([ArestBinarySensor( + add_entities([ArestBinarySensor( arest, resource, config.get(CONF_NAME, response[CONF_NAME]), device_class, pin)], True) diff --git a/homeassistant/components/binary_sensor/august.py b/homeassistant/components/binary_sensor/august.py index 8df50a1bfb6..7f5da390906 100644 --- a/homeassistant/components/binary_sensor/august.py +++ b/homeassistant/components/binary_sensor/august.py @@ -53,7 +53,7 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the August binary sensors.""" data = hass.data[DATA_AUGUST] devices = [] @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for sensor_type in SENSOR_TYPES: devices.append(AugustBinarySensor(data, sensor_type, doorbell)) - add_devices(devices, True) + add_entities(devices, True) class AugustBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/aurora.py b/homeassistant/components/binary_sensor/aurora.py index 0c33877854f..04b402722b2 100644 --- a/homeassistant/components/binary_sensor/aurora.py +++ b/homeassistant/components/binary_sensor/aurora.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the aurora sensor.""" if None in (hass.config.latitude, hass.config.longitude): _LOGGER.error("Lat. or long. not set in Home Assistant config") @@ -57,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): "Connection to aurora forecast service failed: %s", error) return False - add_devices([AuroraSensor(aurora_data, name)], True) + add_entities([AuroraSensor(aurora_data, name)], True) class AuroraSensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/axis.py b/homeassistant/components/binary_sensor/axis.py index 84137d95b06..b66a766ca4a 100644 --- a/homeassistant/components/binary_sensor/axis.py +++ b/homeassistant/components/binary_sensor/axis.py @@ -18,9 +18,9 @@ DEPENDENCIES = ['axis'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Axis binary devices.""" - add_devices([AxisBinarySensor(hass, discovery_info)], True) + add_entities([AxisBinarySensor(hass, discovery_info)], True) class AxisBinarySensor(AxisDeviceEvent, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/bayesian.py b/homeassistant/components/binary_sensor/bayesian.py index 75906e8ac5d..88669d67d80 100644 --- a/homeassistant/components/binary_sensor/bayesian.py +++ b/homeassistant/components/binary_sensor/bayesian.py @@ -75,7 +75,8 @@ def update_probability(prior, prob_true, prob_false): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Bayesian Binary sensor.""" name = config.get(CONF_NAME) observations = config.get(CONF_OBSERVATIONS) @@ -83,7 +84,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): probability_threshold = config.get(CONF_PROBABILITY_THRESHOLD) device_class = config.get(CONF_DEVICE_CLASS) - async_add_devices([ + async_add_entities([ BayesianBinarySensor( name, prior, observations, probability_threshold, device_class) ], True) diff --git a/homeassistant/components/binary_sensor/bbb_gpio.py b/homeassistant/components/binary_sensor/bbb_gpio.py index 690d1651db9..8968b680369 100644 --- a/homeassistant/components/binary_sensor/bbb_gpio.py +++ b/homeassistant/components/binary_sensor/bbb_gpio.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Beaglebone Black GPIO devices.""" pins = config.get(CONF_PINS) @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for pin, params in pins.items(): binary_sensors.append(BBBGPIOBinarySensor(pin, params)) - add_devices(binary_sensors) + add_entities(binary_sensors) class BBBGPIOBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/blink.py b/homeassistant/components/binary_sensor/blink.py index 4d8617b3811..6ade20b72b9 100644 --- a/homeassistant/components/binary_sensor/blink.py +++ b/homeassistant/components/binary_sensor/blink.py @@ -10,7 +10,7 @@ from homeassistant.components.binary_sensor import BinarySensorDevice DEPENDENCIES = ['blink'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the blink binary sensors.""" if discovery_info is None: return @@ -20,7 +20,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for name in data.cameras: devs.append(BlinkCameraMotionSensor(name, data)) devs.append(BlinkSystemSensor(data)) - add_devices(devs, True) + add_entities(devs, True) class BlinkCameraMotionSensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/bloomsky.py b/homeassistant/components/binary_sensor/bloomsky.py index 3080cc65532..ecffb3accf3 100644 --- a/homeassistant/components/binary_sensor/bloomsky.py +++ b/homeassistant/components/binary_sensor/bloomsky.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the available BloomSky weather binary sensors.""" bloomsky = hass.components.bloomsky # Default needed in case of discovery @@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in bloomsky.BLOOMSKY.devices.values(): for variable in sensors: - add_devices( + add_entities( [BloomSkySensor(bloomsky.BLOOMSKY, device, variable)], True) diff --git a/homeassistant/components/binary_sensor/bmw_connected_drive.py b/homeassistant/components/binary_sensor/bmw_connected_drive.py index d19deec4884..36229828d63 100644 --- a/homeassistant/components/binary_sensor/bmw_connected_drive.py +++ b/homeassistant/components/binary_sensor/bmw_connected_drive.py @@ -31,7 +31,7 @@ SENSOR_TYPES_ELEC = { SENSOR_TYPES_ELEC.update(SENSOR_TYPES) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the BMW sensors.""" accounts = hass.data[BMW_DOMAIN] _LOGGER.debug('Found BMW accounts: %s', @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device = BMWConnectedDriveSensor(account, vehicle, key, value[0], value[1]) devices.append(device) - add_devices(devices, True) + add_entities(devices, True) class BMWConnectedDriveSensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/command_line.py b/homeassistant/components/binary_sensor/command_line.py index c2045c2df5e..a3f1595787d 100644 --- a/homeassistant/components/binary_sensor/command_line.py +++ b/homeassistant/components/binary_sensor/command_line.py @@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Command line Binary Sensor.""" name = config.get(CONF_NAME) command = config.get(CONF_COMMAND) @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): value_template.hass = hass data = CommandSensorData(hass, command, command_timeout) - add_devices([CommandBinarySensor( + add_entities([CommandBinarySensor( hass, data, name, device_class, payload_on, payload_off, value_template)], True) diff --git a/homeassistant/components/binary_sensor/concord232.py b/homeassistant/components/binary_sensor/concord232.py index f2acef47e82..26f35d60305 100644 --- a/homeassistant/components/binary_sensor/concord232.py +++ b/homeassistant/components/binary_sensor/concord232.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Concord232 binary sensor platform.""" from concord232 import client as concord232_client @@ -79,7 +79,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) - add_devices(sensors, True) + add_entities(sensors, True) def get_opening_type(zone): diff --git a/homeassistant/components/binary_sensor/deconz.py b/homeassistant/components/binary_sensor/deconz.py index 0a370d754ee..d3d27c05333 100644 --- a/homeassistant/components/binary_sensor/deconz.py +++ b/homeassistant/components/binary_sensor/deconz.py @@ -15,13 +15,13 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect DEPENDENCIES = ['deconz'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ binary sensors.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ binary sensor.""" @callback def async_add_sensor(sensors): @@ -33,7 +33,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): if sensor.type in DECONZ_BINARY_SENSOR and \ not (not allow_clip_sensor and sensor.type.startswith('CLIP')): entities.append(DeconzBinarySensor(sensor)) - async_add_devices(entities, True) + async_add_entities(entities, True) hass.data[DATA_DECONZ_UNSUB].append( async_dispatcher_connect(hass, 'deconz_new_sensor', async_add_sensor)) diff --git a/homeassistant/components/binary_sensor/demo.py b/homeassistant/components/binary_sensor/demo.py index 10077c60ed1..d656b79e8ed 100644 --- a/homeassistant/components/binary_sensor/demo.py +++ b/homeassistant/components/binary_sensor/demo.py @@ -7,9 +7,9 @@ https://home-assistant.io/components/demo/ from homeassistant.components.binary_sensor import BinarySensorDevice -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo binary sensor platform.""" - add_devices([ + add_entities([ DemoBinarySensor('Basement Floor Wet', False, 'moisture'), DemoBinarySensor('Movement Backyard', True, 'motion'), ]) diff --git a/homeassistant/components/binary_sensor/digital_ocean.py b/homeassistant/components/binary_sensor/digital_ocean.py index 1eb86d4eb82..0f604c525e0 100644 --- a/homeassistant/components/binary_sensor/digital_ocean.py +++ b/homeassistant/components/binary_sensor/digital_ocean.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Digital Ocean droplet sensor.""" digital = hass.data.get(DATA_DIGITAL_OCEAN) if not digital: @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False dev.append(DigitalOceanBinarySensor(digital, droplet_id)) - add_devices(dev, True) + add_entities(dev, True) class DigitalOceanBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/ecobee.py b/homeassistant/components/binary_sensor/ecobee.py index 15efa21b226..37f25476bd0 100644 --- a/homeassistant/components/binary_sensor/ecobee.py +++ b/homeassistant/components/binary_sensor/ecobee.py @@ -12,7 +12,7 @@ DEPENDENCIES = ['ecobee'] ECOBEE_CONFIG_FILE = 'ecobee.conf' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ecobee sensors.""" if discovery_info is None: return @@ -26,7 +26,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(EcobeeBinarySensor(sensor['name'], index)) - add_devices(dev, True) + add_entities(dev, True) class EcobeeBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/egardia.py b/homeassistant/components/binary_sensor/egardia.py index 7d443dfafdf..0db2cac667f 100644 --- a/homeassistant/components/binary_sensor/egardia.py +++ b/homeassistant/components/binary_sensor/egardia.py @@ -19,7 +19,8 @@ EGARDIA_TYPE_TO_DEVICE_CLASS = {'IR Sensor': 'motion', @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Initialize the platform.""" if (discovery_info is None or discovery_info[ATTR_DISCOVER_DEVICES] is None): @@ -27,7 +28,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): disc_info = discovery_info[ATTR_DISCOVER_DEVICES] # multiple devices here! - async_add_devices( + async_add_entities( ( EgardiaBinarySensor( sensor_id=disc_info[sensor]['id'], diff --git a/homeassistant/components/binary_sensor/eight_sleep.py b/homeassistant/components/binary_sensor/eight_sleep.py index 40ca491e1f3..34d3a7a13ca 100644 --- a/homeassistant/components/binary_sensor/eight_sleep.py +++ b/homeassistant/components/binary_sensor/eight_sleep.py @@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['eight_sleep'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the eight sleep binary sensor.""" if discovery_info is None: @@ -30,7 +30,7 @@ async def async_setup_platform(hass, config, async_add_devices, for sensor in sensors: all_sensors.append(EightHeatSensor(name, eight, sensor)) - async_add_devices(all_sensors, True) + async_add_entities(all_sensors, True) class EightHeatSensor(EightSleepHeatEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/enocean.py b/homeassistant/components/binary_sensor/enocean.py index d2ecd5e17e1..c883897c2ea 100644 --- a/homeassistant/components/binary_sensor/enocean.py +++ b/homeassistant/components/binary_sensor/enocean.py @@ -27,13 +27,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Binary Sensor platform for EnOcean.""" dev_id = config.get(CONF_ID) devname = config.get(CONF_NAME) device_class = config.get(CONF_DEVICE_CLASS) - add_devices([EnOceanBinarySensor(dev_id, devname, device_class)]) + add_entities([EnOceanBinarySensor(dev_id, devname, device_class)]) class EnOceanBinarySensor(enocean.EnOceanDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/envisalink.py b/homeassistant/components/binary_sensor/envisalink.py index f358f814dc5..2568879bcc6 100644 --- a/homeassistant/components/binary_sensor/envisalink.py +++ b/homeassistant/components/binary_sensor/envisalink.py @@ -23,7 +23,8 @@ DEPENDENCIES = ['envisalink'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Envisalink binary sensor devices.""" configured_zones = discovery_info['zones'] @@ -40,7 +41,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): ) devices.append(device) - async_add_devices(devices) + async_add_entities(devices) class EnvisalinkBinarySensor(EnvisalinkDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/ffmpeg_motion.py b/homeassistant/components/binary_sensor/ffmpeg_motion.py index 75a9fa1d046..365bcafbd69 100644 --- a/homeassistant/components/binary_sensor/ffmpeg_motion.py +++ b/homeassistant/components/binary_sensor/ffmpeg_motion.py @@ -47,7 +47,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the FFmpeg binary motion sensor.""" manager = hass.data[DATA_FFMPEG] @@ -55,7 +56,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): return entity = FFmpegMotion(hass, manager, config) - async_add_devices([entity]) + async_add_entities([entity]) class FFmpegBinarySensor(FFmpegBase, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/ffmpeg_noise.py b/homeassistant/components/binary_sensor/ffmpeg_noise.py index db7647d9b2c..73c84ac336d 100644 --- a/homeassistant/components/binary_sensor/ffmpeg_noise.py +++ b/homeassistant/components/binary_sensor/ffmpeg_noise.py @@ -44,7 +44,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the FFmpeg noise binary sensor.""" manager = hass.data[DATA_FFMPEG] @@ -52,7 +53,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): return entity = FFmpegNoise(hass, manager, config) - async_add_devices([entity]) + async_add_entities([entity]) class FFmpegNoise(FFmpegBinarySensor): diff --git a/homeassistant/components/binary_sensor/gc100.py b/homeassistant/components/binary_sensor/gc100.py index 515d7e7123d..27466f64cfb 100644 --- a/homeassistant/components/binary_sensor/gc100.py +++ b/homeassistant/components/binary_sensor/gc100.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the GC100 devices.""" binary_sensors = [] ports = config.get(CONF_PORTS) @@ -31,7 +31,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for port_addr, port_name in port.items(): binary_sensors.append(GC100BinarySensor( port_name, port_addr, hass.data[DATA_GC100])) - add_devices(binary_sensors, True) + add_entities(binary_sensors, True) class GC100BinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/hive.py b/homeassistant/components/binary_sensor/hive.py index 46dd1b193e8..68f32641872 100644 --- a/homeassistant/components/binary_sensor/hive.py +++ b/homeassistant/components/binary_sensor/hive.py @@ -13,13 +13,13 @@ DEVICETYPE_DEVICE_CLASS = {'motionsensor': 'motion', 'contactsensor': 'opening'} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Hive sensor devices.""" if discovery_info is None: return session = hass.data.get(DATA_HIVE) - add_devices([HiveBinarySensorEntity(session, discovery_info)]) + add_entities([HiveBinarySensorEntity(session, discovery_info)]) class HiveBinarySensorEntity(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/homematic.py b/homeassistant/components/binary_sensor/homematic.py index a0ec359e048..9cfe4bbd6a7 100644 --- a/homeassistant/components/binary_sensor/homematic.py +++ b/homeassistant/components/binary_sensor/homematic.py @@ -30,7 +30,7 @@ SENSOR_TYPES_CLASS = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the HomeMatic binary sensor platform.""" if discovery_info is None: return @@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = HMBinarySensor(conf) devices.append(new_device) - add_devices(devices) + add_entities(devices) class HMBinarySensor(HMDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/homematicip_cloud.py b/homeassistant/components/binary_sensor/homematicip_cloud.py index 72dc2c8b462..dd22a835504 100644 --- a/homeassistant/components/binary_sensor/homematicip_cloud.py +++ b/homeassistant/components/binary_sensor/homematicip_cloud.py @@ -19,12 +19,12 @@ STATE_SMOKE_OFF = 'IDLE_OFF' async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the HomematicIP Cloud binary sensor devices.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP Cloud binary sensor from a config entry.""" from homematicip.aio.device import ( AsyncShutterContact, AsyncMotionDetectorIndoor, AsyncSmokeDetector) @@ -40,7 +40,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): devices.append(HomematicipSmokeDetector(home, device)) if devices: - async_add_devices(devices) + async_add_entities(devices) class HomematicipShutterContact(HomematicipGenericDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/hydrawise.py b/homeassistant/components/binary_sensor/hydrawise.py index a3e0ebd782d..38b660c506f 100644 --- a/homeassistant/components/binary_sensor/hydrawise.py +++ b/homeassistant/components/binary_sensor/hydrawise.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a Hydrawise device.""" hydrawise = hass.data[DATA_HYDRAWISE].data @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hydrawise.controller_status.get('running', False) sensors.append(HydrawiseBinarySensor(zone_data, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) class HydrawiseBinarySensor(HydrawiseEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/ihc.py b/homeassistant/components/binary_sensor/ihc.py index 25435d373fd..20937af6bfc 100644 --- a/homeassistant/components/binary_sensor/ihc.py +++ b/homeassistant/components/binary_sensor/ihc.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC binary sensor platform.""" ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] info = hass.data[IHC_DATA][IHC_INFO] @@ -56,7 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor_type, inverting) devices.append(sensor) - add_devices(devices) + add_entities(devices) class IHCBinarySensor(IHCDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/insteon.py b/homeassistant/components/binary_sensor/insteon.py index 789ad894a41..533ff2d76c0 100644 --- a/homeassistant/components/binary_sensor/insteon.py +++ b/homeassistant/components/binary_sensor/insteon.py @@ -23,7 +23,8 @@ SENSOR_TYPES = {'openClosedSensor': 'opening', @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the INSTEON device class for the hass platform.""" insteon_modem = hass.data['insteon'].get('modem') @@ -37,7 +38,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): new_entity = InsteonBinarySensor(device, state_key) - async_add_devices([new_entity]) + async_add_entities([new_entity]) class InsteonBinarySensor(InsteonEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/iss.py b/homeassistant/components/binary_sensor/iss.py index d0654317248..b986c51ddaa 100644 --- a/homeassistant/components/binary_sensor/iss.py +++ b/homeassistant/components/binary_sensor/iss.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ISS sensor.""" if None in (hass.config.latitude, hass.config.longitude): _LOGGER.error("Latitude or longitude not set in Home Assistant config") @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = config.get(CONF_NAME) show_on_map = config.get(CONF_SHOW_ON_MAP) - add_devices([IssBinarySensor(iss_data, name, show_on_map)], True) + add_entities([IssBinarySensor(iss_data, name, show_on_map)], True) class IssBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/isy994.py b/homeassistant/components/binary_sensor/isy994.py index b6d582b7793..36dacb06738 100644 --- a/homeassistant/components/binary_sensor/isy994.py +++ b/homeassistant/components/binary_sensor/isy994.py @@ -29,7 +29,7 @@ ISY_DEVICE_TYPES = { def setup_platform(hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the ISY994 binary sensor platform.""" devices = [] devices_by_nid = {} @@ -75,7 +75,7 @@ def setup_platform(hass, config: ConfigType, for name, status, _ in hass.data[ISY994_PROGRAMS][DOMAIN]: devices.append(ISYBinarySensorProgram(name, status)) - add_devices(devices) + add_entities(devices) def _detect_device_type(node) -> str: diff --git a/homeassistant/components/binary_sensor/knx.py b/homeassistant/components/binary_sensor/knx.py index 76142dc0af2..a7d1d597f67 100644 --- a/homeassistant/components/binary_sensor/knx.py +++ b/homeassistant/components/binary_sensor/knx.py @@ -54,27 +54,27 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up binary sensor(s) for KNX platform.""" if discovery_info is not None: - async_add_devices_discovery(hass, discovery_info, async_add_devices) + async_add_entities_discovery(hass, discovery_info, async_add_entities) else: - async_add_devices_config(hass, config, async_add_devices) + async_add_entities_config(hass, config, async_add_entities) @callback -def async_add_devices_discovery(hass, discovery_info, async_add_devices): +def async_add_entities_discovery(hass, discovery_info, async_add_entities): """Set up binary sensors for KNX platform configured via xknx.yaml.""" entities = [] for device_name in discovery_info[ATTR_DISCOVER_DEVICES]: device = hass.data[DATA_KNX].xknx.devices[device_name] entities.append(KNXBinarySensor(hass, device)) - async_add_devices(entities) + async_add_entities(entities) @callback -def async_add_devices_config(hass, config, async_add_devices): +def async_add_entities_config(hass, config, async_add_entities): """Set up binary senor for KNX platform configured within platform.""" name = config.get(CONF_NAME) import xknx @@ -97,7 +97,7 @@ def async_add_devices_config(hass, config, async_add_devices): entity.automations.append(KNXAutomation( hass=hass, device=binary_sensor, hook=hook, action=action, counter=counter)) - async_add_devices([entity]) + async_add_entities([entity]) class KNXBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/konnected.py b/homeassistant/components/binary_sensor/konnected.py index 9a16ca5e1ab..e91d3f6136a 100644 --- a/homeassistant/components/binary_sensor/konnected.py +++ b/homeassistant/components/binary_sensor/konnected.py @@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['konnected'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up binary sensors attached to a Konnected device.""" if discovery_info is None: @@ -31,7 +31,7 @@ async def async_setup_platform(hass, config, async_add_devices, sensors = [KonnectedBinarySensor(device_id, pin_num, pin_data) for pin_num, pin_data in data[CONF_DEVICES][device_id][CONF_BINARY_SENSORS].items()] - async_add_devices(sensors) + async_add_entities(sensors) class KonnectedBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/linode.py b/homeassistant/components/binary_sensor/linode.py index d4fc60696cd..24abc3dd8be 100644 --- a/homeassistant/components/binary_sensor/linode.py +++ b/homeassistant/components/binary_sensor/linode.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Linode droplet sensor.""" linode = hass.data.get(DATA_LINODE) nodes = config.get(CONF_NODES) @@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return dev.append(LinodeBinarySensor(linode, node_id)) - add_devices(dev, True) + add_entities(dev, True) class LinodeBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/maxcube.py b/homeassistant/components/binary_sensor/maxcube.py index c131de5420a..6bb9278d8d5 100644 --- a/homeassistant/components/binary_sensor/maxcube.py +++ b/homeassistant/components/binary_sensor/maxcube.py @@ -13,7 +13,7 @@ from homeassistant.const import STATE_UNKNOWN _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Iterate through all MAX! Devices and add window shutters.""" devices = [] for handler in hass.data[DATA_KEY].values(): @@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): MaxCubeShutter(handler, name, device.rf_address)) if devices: - add_devices(devices) + add_entities(devices) class MaxCubeShutter(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/modbus.py b/homeassistant/components/binary_sensor/modbus.py index 1a45235f15a..f9f2597593e 100644 --- a/homeassistant/components/binary_sensor/modbus.py +++ b/homeassistant/components/binary_sensor/modbus.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus binary sensors.""" sensors = [] for coil in config.get(CONF_COILS): @@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): coil.get(CONF_NAME), coil.get(CONF_SLAVE), coil.get(CONF_COIL))) - add_devices(sensors) + add_entities(sensors) class ModbusCoilSensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/mqtt.py b/homeassistant/components/binary_sensor/mqtt.py index cb943ac3f18..37a26a27214 100644 --- a/homeassistant/components/binary_sensor/mqtt.py +++ b/homeassistant/components/binary_sensor/mqtt.py @@ -45,7 +45,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the MQTT binary sensor.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -54,7 +55,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): if value_template is not None: value_template.hass = hass - async_add_devices([MqttBinarySensor( + async_add_entities([MqttBinarySensor( config.get(CONF_NAME), config.get(CONF_STATE_TOPIC), config.get(CONF_AVAILABILITY_TOPIC), diff --git a/homeassistant/components/binary_sensor/mychevy.py b/homeassistant/components/binary_sensor/mychevy.py index 905e60c34d9..d1438379da1 100644 --- a/homeassistant/components/binary_sensor/mychevy.py +++ b/homeassistant/components/binary_sensor/mychevy.py @@ -23,7 +23,8 @@ SENSORS = [ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the MyChevy sensors.""" if discovery_info is None: return @@ -34,7 +35,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for car in hub.cars: sensors.append(EVBinarySensor(hub, sconfig, car.vid)) - async_add_devices(sensors) + async_add_entities(sensors) class EVBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/mysensors.py b/homeassistant/components/binary_sensor/mysensors.py index abb19129d52..f0b7832cf25 100644 --- a/homeassistant/components/binary_sensor/mysensors.py +++ b/homeassistant/components/binary_sensor/mysensors.py @@ -22,11 +22,11 @@ SENSORS = { async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the mysensors platform for binary sensors.""" mysensors.setup_mysensors_platform( hass, DOMAIN, discovery_info, MySensorsBinarySensor, - async_add_devices=async_add_devices) + async_add_entities=async_add_entities) class MySensorsBinarySensor( diff --git a/homeassistant/components/binary_sensor/mystrom.py b/homeassistant/components/binary_sensor/mystrom.py index 5c1d9a576a6..23f40ce0a7f 100644 --- a/homeassistant/components/binary_sensor/mystrom.py +++ b/homeassistant/components/binary_sensor/mystrom.py @@ -17,9 +17,10 @@ DEPENDENCIES = ['http'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up myStrom Binary Sensor.""" - hass.http.register_view(MyStromView(async_add_devices)) + hass.http.register_view(MyStromView(async_add_entities)) return True @@ -31,10 +32,10 @@ class MyStromView(HomeAssistantView): name = 'api:mystrom' supported_actions = ['single', 'double', 'long', 'touch'] - def __init__(self, add_devices): + def __init__(self, add_entities): """Initialize the myStrom URL endpoint.""" self.buttons = {} - self.add_devices = add_devices + self.add_entities = add_entities @asyncio.coroutine def get(self, request): @@ -62,7 +63,7 @@ class MyStromView(HomeAssistantView): button_id, button_action) self.buttons[entity_id] = MyStromBinarySensor( '{}_{}'.format(button_id, button_action)) - hass.async_add_job(self.add_devices, [self.buttons[entity_id]]) + self.add_entities([self.buttons[entity_id]]) else: new_state = True if self.buttons[entity_id].state == 'off' \ else False diff --git a/homeassistant/components/binary_sensor/nest.py b/homeassistant/components/binary_sensor/nest.py index 03bc484983b..c952e7c8987 100644 --- a/homeassistant/components/binary_sensor/nest.py +++ b/homeassistant/components/binary_sensor/nest.py @@ -54,14 +54,14 @@ _VALID_BINARY_SENSOR_TYPES = {**BINARY_TYPES, **CLIMATE_BINARY_TYPES, _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Nest binary sensors. No longer used. """ -async def async_setup_entry(hass, entry, async_add_devices): +async def async_setup_entry(hass, entry, async_add_entities): """Set up a Nest binary sensor based on a config entry.""" nest = hass.data[DATA_NEST] @@ -112,7 +112,7 @@ async def async_setup_entry(hass, entry, async_add_devices): return sensors - async_add_devices(await hass.async_add_job(get_binary_sensors), True) + async_add_entities(await hass.async_add_job(get_binary_sensors), True) class NestBinarySensor(NestSensorDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/netatmo.py b/homeassistant/components/binary_sensor/netatmo.py index 73a373a15ff..2cafacf401c 100644 --- a/homeassistant/components/binary_sensor/netatmo.py +++ b/homeassistant/components/binary_sensor/netatmo.py @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the access to Netatmo binary sensor.""" netatmo = hass.components.netatmo home = config.get(CONF_HOME) @@ -89,7 +89,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): camera_name not in config[CONF_CAMERAS]: continue for variable in welcome_sensors: - add_devices([NetatmoBinarySensor( + add_entities([NetatmoBinarySensor( data, camera_name, module_name, home, timeout, camera_type, variable)], True) if camera_type == 'NOC': @@ -98,14 +98,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None): camera_name not in config[CONF_CAMERAS]: continue for variable in presence_sensors: - add_devices([NetatmoBinarySensor( + add_entities([NetatmoBinarySensor( data, camera_name, module_name, home, timeout, camera_type, variable)], True) for module_name in data.get_module_names(camera_name): for variable in tag_sensors: camera_type = None - add_devices([NetatmoBinarySensor( + add_entities([NetatmoBinarySensor( data, camera_name, module_name, home, timeout, camera_type, variable)], True) diff --git a/homeassistant/components/binary_sensor/nx584.py b/homeassistant/components/binary_sensor/nx584.py index 4dff263f79a..2929acc2709 100644 --- a/homeassistant/components/binary_sensor/nx584.py +++ b/homeassistant/components/binary_sensor/nx584.py @@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NX584 binary sensor platform.""" from nx584 import client as nx584_client @@ -68,7 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for zone in zones if zone['number'] not in exclude} if zone_sensors: - add_devices(zone_sensors.values()) + add_entities(zone_sensors.values()) watcher = NX584Watcher(client, zone_sensors) watcher.start() else: diff --git a/homeassistant/components/binary_sensor/octoprint.py b/homeassistant/components/binary_sensor/octoprint.py index 1a1967b9014..3dd1ee2be8c 100644 --- a/homeassistant/components/binary_sensor/octoprint.py +++ b/homeassistant/components/binary_sensor/octoprint.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the available OctoPrint binary sensors.""" octoprint_api = hass.data[DOMAIN]["api"] name = config.get(CONF_NAME) @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name, SENSOR_TYPES[octo_type][3], SENSOR_TYPES[octo_type][0], SENSOR_TYPES[octo_type][1], 'flags') devices.append(new_sensor) - add_devices(devices, True) + add_entities(devices, True) class OctoPrintBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/openuv.py b/homeassistant/components/binary_sensor/openuv.py index 3a2732d3be0..0b299529a46 100644 --- a/homeassistant/components/binary_sensor/openuv.py +++ b/homeassistant/components/binary_sensor/openuv.py @@ -25,7 +25,7 @@ ATTR_PROTECTION_WINDOW_ENDING_UV = 'end_uv' async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the OpenUV binary sensor platform.""" if discovery_info is None: return @@ -38,7 +38,7 @@ async def async_setup_platform( binary_sensors.append( OpenUvBinarySensor(openuv, sensor_type, name, icon)) - async_add_devices(binary_sensors, True) + async_add_entities(binary_sensors, True) class OpenUvBinarySensor(OpenUvEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/pilight.py b/homeassistant/components/binary_sensor/pilight.py index 69dc3b83485..abffffe8651 100644 --- a/homeassistant/components/binary_sensor/pilight.py +++ b/homeassistant/components/binary_sensor/pilight.py @@ -44,11 +44,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Pilight Binary Sensor.""" disarm = config.get(CONF_DISARM_AFTER_TRIGGER) if disarm: - add_devices([PilightTriggerSensor( + add_entities([PilightTriggerSensor( hass=hass, name=config.get(CONF_NAME), variable=config.get(CONF_VARIABLE), @@ -58,7 +58,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): rst_dly_sec=config.get(CONF_RESET_DELAY_SEC), )]) else: - add_devices([PilightBinarySensor( + add_entities([PilightBinarySensor( hass=hass, name=config.get(CONF_NAME), variable=config.get(CONF_VARIABLE), diff --git a/homeassistant/components/binary_sensor/ping.py b/homeassistant/components/binary_sensor/ping.py index bb597f208e6..4c597dd63e1 100644 --- a/homeassistant/components/binary_sensor/ping.py +++ b/homeassistant/components/binary_sensor/ping.py @@ -48,13 +48,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ping Binary sensor.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) count = config.get(CONF_PING_COUNT) - add_devices([PingBinarySensor(name, PingData(host, count))], True) + add_entities([PingBinarySensor(name, PingData(host, count))], True) class PingBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/qwikswitch.py b/homeassistant/components/binary_sensor/qwikswitch.py index 067021b0c7a..2fe14773d3a 100644 --- a/homeassistant/components/binary_sensor/qwikswitch.py +++ b/homeassistant/components/binary_sensor/qwikswitch.py @@ -15,7 +15,7 @@ DEPENDENCIES = [QWIKSWITCH] _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, _, add_devices, discovery_info=None): +async def async_setup_platform(hass, _, add_entities, discovery_info=None): """Add binary sensor from the main Qwikswitch component.""" if discovery_info is None: return @@ -24,7 +24,7 @@ async def async_setup_platform(hass, _, add_devices, discovery_info=None): _LOGGER.debug("Setup qwikswitch.binary_sensor %s, %s", qsusb, discovery_info) devs = [QSBinarySensor(sensor) for sensor in discovery_info[QWIKSWITCH]] - add_devices(devs) + add_entities(devs) class QSBinarySensor(QSEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/rachio.py b/homeassistant/components/binary_sensor/rachio.py index 59bf8a21064..798b6a754d1 100644 --- a/homeassistant/components/binary_sensor/rachio.py +++ b/homeassistant/components/binary_sensor/rachio.py @@ -24,13 +24,13 @@ DEPENDENCIES = ['rachio'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Rachio binary sensors.""" devices = [] for controller in hass.data[DOMAIN_RACHIO].controllers: devices.append(RachioControllerOnlineBinarySensor(hass, controller)) - add_devices(devices) + add_entities(devices) _LOGGER.info("%d Rachio binary sensor(s) added", len(devices)) diff --git a/homeassistant/components/binary_sensor/raincloud.py b/homeassistant/components/binary_sensor/raincloud.py index 3cbd179154f..810c7d201cb 100644 --- a/homeassistant/components/binary_sensor/raincloud.py +++ b/homeassistant/components/binary_sensor/raincloud.py @@ -25,7 +25,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a raincloud device.""" raincloud = hass.data[DATA_RAINCLOUD].data @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for zone in raincloud.controller.faucet.zones: sensors.append(RainCloudBinarySensor(zone, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) return True diff --git a/homeassistant/components/binary_sensor/rainmachine.py b/homeassistant/components/binary_sensor/rainmachine.py index b2f44696fbd..12c9b3e98f0 100644 --- a/homeassistant/components/binary_sensor/rainmachine.py +++ b/homeassistant/components/binary_sensor/rainmachine.py @@ -21,7 +21,7 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the RainMachine Switch platform.""" if discovery_info is None: return @@ -34,7 +34,7 @@ async def async_setup_platform( binary_sensors.append( RainMachineBinarySensor(rainmachine, sensor_type, name, icon)) - async_add_devices(binary_sensors, True) + async_add_entities(binary_sensors, True) class RainMachineBinarySensor(RainMachineEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/random.py b/homeassistant/components/binary_sensor/random.py index ab6c1e5d479..9bdc57c6e46 100644 --- a/homeassistant/components/binary_sensor/random.py +++ b/homeassistant/components/binary_sensor/random.py @@ -24,12 +24,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Random binary sensor.""" name = config.get(CONF_NAME) device_class = config.get(CONF_DEVICE_CLASS) - async_add_devices([RandomSensor(name, device_class)], True) + async_add_entities([RandomSensor(name, device_class)], True) class RandomSensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/raspihats.py b/homeassistant/components/binary_sensor/raspihats.py index 9ab56a5a20d..feef5396d88 100644 --- a/homeassistant/components/binary_sensor/raspihats.py +++ b/homeassistant/components/binary_sensor/raspihats.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the raspihats binary_sensor devices.""" I2CHatBinarySensor.I2C_HATS_MANAGER = hass.data[I2C_HATS_MANAGER] binary_sensors = [] @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except I2CHatsException as ex: _LOGGER.error("Failed to register %s I2CHat@%s %s", board, hex(address), str(ex)) - add_devices(binary_sensors) + add_entities(binary_sensors) class I2CHatBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/rest.py b/homeassistant/components/binary_sensor/rest.py index e9cb40f6747..412aeb46a3a 100644 --- a/homeassistant/components/binary_sensor/rest.py +++ b/homeassistant/components/binary_sensor/rest.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the REST binary sensor.""" name = config.get(CONF_NAME) resource = config.get(CONF_RESOURCE) @@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Unable to fetch REST data from %s", resource) return False - add_devices([RestBinarySensor( + add_entities([RestBinarySensor( hass, rest, name, device_class, value_template)], True) diff --git a/homeassistant/components/binary_sensor/rfxtrx.py b/homeassistant/components/binary_sensor/rfxtrx.py index 6ac604a4f1e..1e88c72e19d 100644 --- a/homeassistant/components/binary_sensor/rfxtrx.py +++ b/homeassistant/components/binary_sensor/rfxtrx.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }, extra=vol.ALLOW_EXTRA) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Binary Sensor platform to RFXtrx.""" import RFXtrx as rfxtrxmod sensors = [] @@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(device) rfxtrx.RFX_DEVICES[device_id] = device - add_devices(sensors) + add_entities(sensors) def binary_sensor_update(event): """Call for control updates from the RFXtrx gateway.""" @@ -101,7 +101,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor = RfxtrxBinarySensor(event, pkt_id) sensor.hass = hass rfxtrx.RFX_DEVICES[device_id] = sensor - add_devices([sensor]) + add_entities([sensor]) _LOGGER.info( "Added binary sensor %s (Device ID: %s Class: %s Sub: %s)", pkt_id, slugify(event.device.id_string.lower()), diff --git a/homeassistant/components/binary_sensor/ring.py b/homeassistant/components/binary_sensor/ring.py index 4f2ea408e7f..102e22cbe2d 100644 --- a/homeassistant/components/binary_sensor/ring.py +++ b/homeassistant/components/binary_sensor/ring.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a Ring device.""" ring = hass.data[DATA_RING] @@ -56,7 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(RingBinarySensor(hass, device, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) return True diff --git a/homeassistant/components/binary_sensor/rpi_gpio.py b/homeassistant/components/binary_sensor/rpi_gpio.py index 31a518dc1dc..2fe4e0766ed 100644 --- a/homeassistant/components/binary_sensor/rpi_gpio.py +++ b/homeassistant/components/binary_sensor/rpi_gpio.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Raspberry PI GPIO devices.""" pull_mode = config.get(CONF_PULL_MODE) bouncetime = config.get(CONF_BOUNCETIME) @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for port_num, port_name in ports.items(): binary_sensors.append(RPiGPIOBinarySensor( port_name, port_num, pull_mode, bouncetime, invert_logic)) - add_devices(binary_sensors, True) + add_entities(binary_sensors, True) class RPiGPIOBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/rpi_pfio.py b/homeassistant/components/binary_sensor/rpi_pfio.py index a1126bdd2f9..61d1f8ac285 100644 --- a/homeassistant/components/binary_sensor/rpi_pfio.py +++ b/homeassistant/components/binary_sensor/rpi_pfio.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PiFace Digital Input devices.""" binary_sensors = [] ports = config.get(CONF_PORTS) @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): binary_sensors.append(RPiPFIOBinarySensor( hass, port, name, settle_time, invert_logic)) - add_devices(binary_sensors, True) + add_entities(binary_sensors, True) rpi_pfio.activate_listener(hass) diff --git a/homeassistant/components/binary_sensor/satel_integra.py b/homeassistant/components/binary_sensor/satel_integra.py index f373809f7c0..3500f0a0576 100644 --- a/homeassistant/components/binary_sensor/satel_integra.py +++ b/homeassistant/components/binary_sensor/satel_integra.py @@ -21,7 +21,8 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Satel Integra binary sensor devices.""" if not discovery_info: return @@ -36,7 +37,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): device = SatelIntegraBinarySensor(zone_num, zone_name, zone_type) devices.append(device) - async_add_devices(devices) + async_add_entities(devices) class SatelIntegraBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/skybell.py b/homeassistant/components/binary_sensor/skybell.py index 44cad11e3f0..7d8b3a84a2a 100644 --- a/homeassistant/components/binary_sensor/skybell.py +++ b/homeassistant/components/binary_sensor/skybell.py @@ -37,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform for a Skybell device.""" skybell = hass.data.get(SKYBELL_DOMAIN) @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in skybell.get_devices(): sensors.append(SkybellBinarySensor(device, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) class SkybellBinarySensor(SkybellDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/sleepiq.py b/homeassistant/components/binary_sensor/sleepiq.py index 3a6c27db386..808eda4967d 100644 --- a/homeassistant/components/binary_sensor/sleepiq.py +++ b/homeassistant/components/binary_sensor/sleepiq.py @@ -10,7 +10,7 @@ from homeassistant.components.binary_sensor import BinarySensorDevice DEPENDENCIES = ['sleepiq'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SleepIQ sensors.""" if discovery_info is None: return @@ -22,7 +22,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for bed_id, _ in data.beds.items(): for side in sleepiq.SIDES: dev.append(IsInBedBinarySensor(data, bed_id, side)) - add_devices(dev) + add_entities(dev) class IsInBedBinarySensor(sleepiq.SleepIQSensor, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/spc.py b/homeassistant/components/binary_sensor/spc.py index 95723f93870..9afd4fe4015 100644 --- a/homeassistant/components/binary_sensor/spc.py +++ b/homeassistant/components/binary_sensor/spc.py @@ -45,13 +45,14 @@ def _create_sensor(hass, zone): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the SPC binary sensor.""" if (discovery_info is None or discovery_info[ATTR_DISCOVER_DEVICES] is None): return - async_add_devices( + async_add_entities( _create_sensor(hass, zone) for zone in discovery_info[ATTR_DISCOVER_DEVICES] if _get_device_class(zone['type'])) diff --git a/homeassistant/components/binary_sensor/tahoma.py b/homeassistant/components/binary_sensor/tahoma.py index efcfb629f39..7af5a730c43 100644 --- a/homeassistant/components/binary_sensor/tahoma.py +++ b/homeassistant/components/binary_sensor/tahoma.py @@ -21,14 +21,14 @@ _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=120) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tahoma controller devices.""" _LOGGER.debug("Setup Tahoma Binary sensor platform") controller = hass.data[TAHOMA_DOMAIN]['controller'] devices = [] for device in hass.data[TAHOMA_DOMAIN]['devices']['smoke']: devices.append(TahomaBinarySensor(device, controller)) - add_devices(devices, True) + add_entities(devices, True) class TahomaBinarySensor(TahomaDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/tapsaff.py b/homeassistant/components/binary_sensor/tapsaff.py index 5b8e133b5f4..1978a127c17 100644 --- a/homeassistant/components/binary_sensor/tapsaff.py +++ b/homeassistant/components/binary_sensor/tapsaff.py @@ -30,14 +30,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Taps Aff binary sensor.""" name = config.get(CONF_NAME) location = config.get(CONF_LOCATION) taps_aff_data = TapsAffData(location) - add_devices([TapsAffSensor(taps_aff_data, name)], True) + add_entities([TapsAffSensor(taps_aff_data, name)], True) class TapsAffSensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/tcp.py b/homeassistant/components/binary_sensor/tcp.py index cfaa8057798..764b6829c91 100644 --- a/homeassistant/components/binary_sensor/tcp.py +++ b/homeassistant/components/binary_sensor/tcp.py @@ -15,9 +15,9 @@ _LOGGER = logging.getLogger(__name__) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({}) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the TCP binary sensor.""" - add_devices([TcpBinarySensor(hass, config)]) + add_entities([TcpBinarySensor(hass, config)]) class TcpBinarySensor(BinarySensorDevice, TcpSensor): diff --git a/homeassistant/components/binary_sensor/tellduslive.py b/homeassistant/components/binary_sensor/tellduslive.py index 6746d532780..c412ec37e51 100644 --- a/homeassistant/components/binary_sensor/tellduslive.py +++ b/homeassistant/components/binary_sensor/tellduslive.py @@ -15,11 +15,11 @@ from homeassistant.components.binary_sensor import BinarySensorDevice _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tellstick sensors.""" if discovery_info is None: return - add_devices( + add_entities( TelldusLiveSensor(hass, binary_sensor) for binary_sensor in discovery_info ) diff --git a/homeassistant/components/binary_sensor/template.py b/homeassistant/components/binary_sensor/template.py index 68ffbf77af2..c5bfa593022 100644 --- a/homeassistant/components/binary_sensor/template.py +++ b/homeassistant/components/binary_sensor/template.py @@ -47,7 +47,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up template binary sensors.""" sensors = [] @@ -82,7 +83,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.error("No sensors added") return False - async_add_devices(sensors) + async_add_entities(sensors) return True diff --git a/homeassistant/components/binary_sensor/tesla.py b/homeassistant/components/binary_sensor/tesla.py index 3d494a28ea8..f7613d74dfb 100644 --- a/homeassistant/components/binary_sensor/tesla.py +++ b/homeassistant/components/binary_sensor/tesla.py @@ -15,13 +15,13 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['tesla'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tesla binary sensor.""" devices = [ TeslaBinarySensor( device, hass.data[TESLA_DOMAIN]['controller'], 'connectivity') for device in hass.data[TESLA_DOMAIN]['devices']['binary_sensor']] - add_devices(devices, True) + add_entities(devices, True) class TeslaBinarySensor(TeslaDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/threshold.py b/homeassistant/components/binary_sensor/threshold.py index 39681c894b3..fd7ead08822 100644 --- a/homeassistant/components/binary_sensor/threshold.py +++ b/homeassistant/components/binary_sensor/threshold.py @@ -55,7 +55,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Threshold sensor.""" entity_id = config.get(CONF_ENTITY_ID) name = config.get(CONF_NAME) @@ -64,7 +65,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hysteresis = config.get(CONF_HYSTERESIS) device_class = config.get(CONF_DEVICE_CLASS) - async_add_devices([ThresholdSensor( + async_add_entities([ThresholdSensor( hass, entity_id, name, lower, upper, hysteresis, device_class)], True) diff --git a/homeassistant/components/binary_sensor/trend.py b/homeassistant/components/binary_sensor/trend.py index 7165a0dbdf3..ae6fd5562bf 100644 --- a/homeassistant/components/binary_sensor/trend.py +++ b/homeassistant/components/binary_sensor/trend.py @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the trend sensors.""" sensors = [] @@ -80,7 +80,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not sensors: _LOGGER.error("No sensors added") return False - add_devices(sensors) + add_entities(sensors) return True diff --git a/homeassistant/components/binary_sensor/upcloud.py b/homeassistant/components/binary_sensor/upcloud.py index 868a2e8ddd0..c7b8a284dc9 100644 --- a/homeassistant/components/binary_sensor/upcloud.py +++ b/homeassistant/components/binary_sensor/upcloud.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the UpCloud server binary sensor.""" upcloud = hass.data[DATA_UPCLOUD] @@ -31,7 +31,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices = [UpCloudBinarySensor(upcloud, uuid) for uuid in servers] - add_devices(devices, True) + add_entities(devices, True) class UpCloudBinarySensor(UpCloudServerEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/uptimerobot.py b/homeassistant/components/binary_sensor/uptimerobot.py index 9e72d188c99..dbb83e53e9f 100644 --- a/homeassistant/components/binary_sensor/uptimerobot.py +++ b/homeassistant/components/binary_sensor/uptimerobot.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Uptime Robot binary_sensors.""" from pyuptimerobot import UptimeRobot @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): api_key, up_robot, monitor['id'], monitor['friendly_name'], monitor['url'])) - add_devices(devices, True) + add_entities(devices, True) class UptimeRobotBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/velbus.py b/homeassistant/components/binary_sensor/velbus.py index 8438be0d784..b123b958560 100644 --- a/homeassistant/components/binary_sensor/velbus.py +++ b/homeassistant/components/binary_sensor/velbus.py @@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['velbus'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up Velbus binary sensors.""" if discovery_info is None: @@ -25,7 +25,7 @@ async def async_setup_platform(hass, config, async_add_devices, module = hass.data[VELBUS_DOMAIN].get_module(sensor[0]) channel = sensor[1] sensors.append(VelbusBinarySensor(module, channel)) - async_add_devices(sensors) + async_add_entities(sensors) class VelbusBinarySensor(VelbusEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/vera.py b/homeassistant/components/binary_sensor/vera.py index 310e2289cbc..bb1e7331de8 100644 --- a/homeassistant/components/binary_sensor/vera.py +++ b/homeassistant/components/binary_sensor/vera.py @@ -16,9 +16,9 @@ DEPENDENCIES = ['vera'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Perform the setup for Vera controller devices.""" - add_devices( + add_entities( [VeraBinarySensor(device, hass.data[VERA_CONTROLLER]) for device in hass.data[VERA_DEVICES]['binary_sensor']], True) diff --git a/homeassistant/components/binary_sensor/verisure.py b/homeassistant/components/binary_sensor/verisure.py index 7068d51f6a3..e040da959ea 100644 --- a/homeassistant/components/binary_sensor/verisure.py +++ b/homeassistant/components/binary_sensor/verisure.py @@ -13,7 +13,7 @@ from homeassistant.components.verisure import HUB as hub _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Verisure binary sensors.""" sensors = [] hub.update_overview() @@ -23,7 +23,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): VerisureDoorWindowSensor(device_label) for device_label in hub.get( "$.doorWindow.doorWindowDevice[*].deviceLabel")]) - add_devices(sensors) + add_entities(sensors) class VerisureDoorWindowSensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/volvooncall.py b/homeassistant/components/binary_sensor/volvooncall.py index 402feefa99f..e70d3098874 100644 --- a/homeassistant/components/binary_sensor/volvooncall.py +++ b/homeassistant/components/binary_sensor/volvooncall.py @@ -12,11 +12,11 @@ from homeassistant.components.binary_sensor import BinarySensorDevice _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Volvo sensors.""" if discovery_info is None: return - add_devices([VolvoSensor(hass, *discovery_info)]) + add_entities([VolvoSensor(hass, *discovery_info)]) class VolvoSensor(VolvoEntity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/vultr.py b/homeassistant/components/binary_sensor/vultr.py index eecd3f87c40..149a6c28290 100644 --- a/homeassistant/components/binary_sensor/vultr.py +++ b/homeassistant/components/binary_sensor/vultr.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vultr subscription (server) binary sensor.""" vultr = hass.data[DATA_VULTR] @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Subscription %s not found", subscription) return - add_devices([VultrBinarySensor(vultr, subscription, name)], True) + add_entities([VultrBinarySensor(vultr, subscription, name)], True) class VultrBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/wemo.py b/homeassistant/components/binary_sensor/wemo.py index bde6accf421..1071aae50dd 100644 --- a/homeassistant/components/binary_sensor/wemo.py +++ b/homeassistant/components/binary_sensor/wemo.py @@ -15,7 +15,7 @@ DEPENDENCIES = ['wemo'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Register discovered WeMo binary sensors.""" from pywemo import discovery @@ -31,7 +31,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): raise PlatformNotReady if device: - add_devices_callback([WemoBinarySensor(hass, device)]) + add_entities_callback([WemoBinarySensor(hass, device)]) class WemoBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/wink.py b/homeassistant/components/binary_sensor/wink.py index 575507cd047..1976e49f446 100644 --- a/homeassistant/components/binary_sensor/wink.py +++ b/homeassistant/components/binary_sensor/wink.py @@ -31,7 +31,7 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink binary sensor platform.""" import pywink @@ -39,49 +39,49 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _id = sensor.object_id() + sensor.name() if _id not in hass.data[DOMAIN]['unique_ids']: if sensor.capability() in SENSOR_TYPES: - add_devices([WinkBinarySensorDevice(sensor, hass)]) + add_entities([WinkBinarySensorDevice(sensor, hass)]) for key in pywink.get_keys(): _id = key.object_id() + key.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkBinarySensorDevice(key, hass)]) + add_entities([WinkBinarySensorDevice(key, hass)]) for sensor in pywink.get_smoke_and_co_detectors(): _id = sensor.object_id() + sensor.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkSmokeDetector(sensor, hass)]) + add_entities([WinkSmokeDetector(sensor, hass)]) for hub in pywink.get_hubs(): _id = hub.object_id() + hub.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkHub(hub, hass)]) + add_entities([WinkHub(hub, hass)]) for remote in pywink.get_remotes(): _id = remote.object_id() + remote.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkRemote(remote, hass)]) + add_entities([WinkRemote(remote, hass)]) for button in pywink.get_buttons(): _id = button.object_id() + button.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkButton(button, hass)]) + add_entities([WinkButton(button, hass)]) for gang in pywink.get_gangs(): _id = gang.object_id() + gang.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkGang(gang, hass)]) + add_entities([WinkGang(gang, hass)]) for door_bell_sensor in pywink.get_door_bells(): _id = door_bell_sensor.object_id() + door_bell_sensor.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkBinarySensorDevice(door_bell_sensor, hass)]) + add_entities([WinkBinarySensorDevice(door_bell_sensor, hass)]) for camera_sensor in pywink.get_cameras(): _id = camera_sensor.object_id() + camera_sensor.name() if _id not in hass.data[DOMAIN]['unique_ids']: try: if camera_sensor.capability() in SENSOR_TYPES: - add_devices([WinkBinarySensorDevice(camera_sensor, hass)]) + add_entities([WinkBinarySensorDevice(camera_sensor, hass)]) except AttributeError: _LOGGER.info("Device isn't a sensor, skipping") diff --git a/homeassistant/components/binary_sensor/wirelesstag.py b/homeassistant/components/binary_sensor/wirelesstag.py index bfc2d44fc6e..4bec3a824c3 100644 --- a/homeassistant/components/binary_sensor/wirelesstag.py +++ b/homeassistant/components/binary_sensor/wirelesstag.py @@ -107,7 +107,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform for a WirelessTags.""" platform = hass.data.get(WIRELESSTAG_DOMAIN) @@ -120,7 +120,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(WirelessTagBinarySensor(platform, tag, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) hass.add_job(platform.install_push_notifications, sensors) diff --git a/homeassistant/components/binary_sensor/workday.py b/homeassistant/components/binary_sensor/workday.py index 4a9809e9974..3fb2d7f7f86 100644 --- a/homeassistant/components/binary_sensor/workday.py +++ b/homeassistant/components/binary_sensor/workday.py @@ -58,7 +58,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Workday sensor.""" import holidays @@ -92,7 +92,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for date, name in sorted(obj_holidays.items()): _LOGGER.debug("%s %s", date, name) - add_devices([IsWorkdaySensor( + add_entities([IsWorkdaySensor( obj_holidays, workdays, excludes, days_offset, sensor_name)], True) diff --git a/homeassistant/components/binary_sensor/xiaomi_aqara.py b/homeassistant/components/binary_sensor/xiaomi_aqara.py index c1641c5f1ec..c42090e3b7a 100644 --- a/homeassistant/components/binary_sensor/xiaomi_aqara.py +++ b/homeassistant/components/binary_sensor/xiaomi_aqara.py @@ -19,7 +19,7 @@ DENSITY = 'density' ATTR_DENSITY = 'Density' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Perform the setup for Xiaomi devices.""" devices = [] for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): 'dual_channel', hass, gateway)) elif model in ['cube', 'sensor_cube', 'sensor_cube.aqgl01']: devices.append(XiaomiCube(device, hass, gateway)) - add_devices(devices) + add_entities(devices) class XiaomiBinarySensor(XiaomiDevice, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/zha.py b/homeassistant/components/binary_sensor/zha.py index 224d694e0f5..cabbbd704a0 100644 --- a/homeassistant/components/binary_sensor/zha.py +++ b/homeassistant/components/binary_sensor/zha.py @@ -24,7 +24,7 @@ CLASS_MAPPING = { } -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Zigbee Home Automation binary sensors.""" discovery_info = zha.get_discovery_info(hass, discovery_info) @@ -34,14 +34,14 @@ async def async_setup_platform(hass, config, async_add_devices, from zigpy.zcl.clusters.general import OnOff from zigpy.zcl.clusters.security import IasZone if IasZone.cluster_id in discovery_info['in_clusters']: - await _async_setup_iaszone(hass, config, async_add_devices, + await _async_setup_iaszone(hass, config, async_add_entities, discovery_info) elif OnOff.cluster_id in discovery_info['out_clusters']: - await _async_setup_remote(hass, config, async_add_devices, + await _async_setup_remote(hass, config, async_add_entities, discovery_info) -async def _async_setup_iaszone(hass, config, async_add_devices, +async def _async_setup_iaszone(hass, config, async_add_entities, discovery_info): device_class = None from zigpy.zcl.clusters.security import IasZone @@ -59,10 +59,11 @@ async def _async_setup_iaszone(hass, config, async_add_devices, pass sensor = BinarySensor(device_class, **discovery_info) - async_add_devices([sensor], update_before_add=True) + async_add_entities([sensor], update_before_add=True) -async def _async_setup_remote(hass, config, async_add_devices, discovery_info): +async def _async_setup_remote(hass, config, async_add_entities, + discovery_info): async def safe(coro): """Run coro, catching ZigBee delivery errors, and ignoring them.""" @@ -85,7 +86,7 @@ async def _async_setup_remote(hass, config, async_add_devices, discovery_info): await safe(cluster.configure_reporting(0, 1, 600, 1)) sensor = Switch(**discovery_info) - async_add_devices([sensor], update_before_add=True) + async_add_entities([sensor], update_before_add=True) class BinarySensor(zha.Entity, BinarySensorDevice): diff --git a/homeassistant/components/binary_sensor/zigbee.py b/homeassistant/components/binary_sensor/zigbee.py index 659d82f809b..6b89258209e 100644 --- a/homeassistant/components/binary_sensor/zigbee.py +++ b/homeassistant/components/binary_sensor/zigbee.py @@ -22,9 +22,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZigBee binary sensor platform.""" - add_devices( + add_entities( [ZigBeeBinarySensor(hass, ZigBeeDigitalInConfig(config))], True) diff --git a/homeassistant/components/calendar/caldav.py b/homeassistant/components/calendar/caldav.py index 3db24790aaf..cb8874a817c 100644 --- a/homeassistant/components/calendar/caldav.py +++ b/homeassistant/components/calendar/caldav.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15) -def setup_platform(hass, config, add_devices, disc_info=None): +def setup_platform(hass, config, add_entities, disc_info=None): """Set up the WebDav Calendar platform.""" import caldav @@ -98,7 +98,7 @@ def setup_platform(hass, config, add_devices, disc_info=None): WebDavCalendarEventDevice(hass, device_data, calendar) ) - add_devices(calendar_devices) + add_entities(calendar_devices) class WebDavCalendarEventDevice(CalendarEventDevice): diff --git a/homeassistant/components/calendar/demo.py b/homeassistant/components/calendar/demo.py index 0bf09f6f2c7..bf9d4abeb58 100644 --- a/homeassistant/components/calendar/demo.py +++ b/homeassistant/components/calendar/demo.py @@ -11,11 +11,11 @@ from homeassistant.components.calendar import CalendarEventDevice, get_date from homeassistant.components.google import CONF_DEVICE_ID, CONF_NAME -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo Calendar platform.""" calendar_data_future = DemoGoogleCalendarDataFuture() calendar_data_current = DemoGoogleCalendarDataCurrent() - add_devices([ + add_entities([ DemoGoogleCalendar(hass, calendar_data_future, { CONF_NAME: 'Calendar 1', CONF_DEVICE_ID: 'calendar_1', diff --git a/homeassistant/components/calendar/google.py b/homeassistant/components/calendar/google.py index 9b14f773c22..041b98dc24b 100644 --- a/homeassistant/components/calendar/google.py +++ b/homeassistant/components/calendar/google.py @@ -25,7 +25,7 @@ DEFAULT_GOOGLE_SEARCH_PARAMS = { MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15) -def setup_platform(hass, config, add_devices, disc_info=None): +def setup_platform(hass, config, add_entities, disc_info=None): """Set up the calendar platform for event devices.""" if disc_info is None: return @@ -34,9 +34,9 @@ def setup_platform(hass, config, add_devices, disc_info=None): return calendar_service = GoogleCalendarService(hass.config.path(TOKEN_FILE)) - add_devices([GoogleCalendarEventDevice(hass, calendar_service, - disc_info[CONF_CAL_ID], data) - for data in disc_info[CONF_ENTITIES] if data[CONF_TRACK]]) + add_entities([GoogleCalendarEventDevice(hass, calendar_service, + disc_info[CONF_CAL_ID], data) + for data in disc_info[CONF_ENTITIES] if data[CONF_TRACK]]) class GoogleCalendarEventDevice(CalendarEventDevice): diff --git a/homeassistant/components/calendar/todoist.py b/homeassistant/components/calendar/todoist.py index ba1f60027ba..b5eaed4e6c9 100644 --- a/homeassistant/components/calendar/todoist.py +++ b/homeassistant/components/calendar/todoist.py @@ -116,7 +116,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Todoist platform.""" token = config.get(CONF_TOKEN) @@ -178,7 +178,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) - add_devices(project_devices) + add_entities(project_devices) def handle_new_task(call): """Call when a user creates a new Todoist Task from HASS.""" diff --git a/homeassistant/components/camera/abode.py b/homeassistant/components/camera/abode.py index ee739810a61..fbab1620a39 100644 --- a/homeassistant/components/camera/abode.py +++ b/homeassistant/components/camera/abode.py @@ -22,7 +22,7 @@ MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90) _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Abode camera devices.""" import abodepy.helpers.constants as CONST import abodepy.helpers.timeline as TIMELINE @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(devices) - add_devices(devices) + add_entities(devices) class AbodeCamera(AbodeDevice, Camera): diff --git a/homeassistant/components/camera/amcrest.py b/homeassistant/components/camera/amcrest.py index 4cb218bc019..9f4b84db2cc 100644 --- a/homeassistant/components/camera/amcrest.py +++ b/homeassistant/components/camera/amcrest.py @@ -22,7 +22,8 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up an Amcrest IP Camera.""" if discovery_info is None: return @@ -30,7 +31,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): device_name = discovery_info[CONF_NAME] amcrest = hass.data[DATA_AMCREST][device_name] - async_add_devices([AmcrestCam(hass, amcrest)], True) + async_add_entities([AmcrestCam(hass, amcrest)], True) return True diff --git a/homeassistant/components/camera/arlo.py b/homeassistant/components/camera/arlo.py index 1a98ade5518..af931c74cfa 100644 --- a/homeassistant/components/camera/arlo.py +++ b/homeassistant/components/camera/arlo.py @@ -47,7 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an Arlo IP Camera.""" arlo = hass.data[DATA_ARLO] @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for camera in arlo.cameras: cameras.append(ArloCam(hass, camera, config)) - add_devices(cameras) + add_entities(cameras) class ArloCam(Camera): diff --git a/homeassistant/components/camera/august.py b/homeassistant/components/camera/august.py index d3bc080bfc6..dcce5e13588 100644 --- a/homeassistant/components/camera/august.py +++ b/homeassistant/components/camera/august.py @@ -16,7 +16,7 @@ DEPENDENCIES = ['august'] SCAN_INTERVAL = timedelta(seconds=5) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up August cameras.""" data = hass.data[DATA_AUGUST] devices = [] @@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for doorbell in data.doorbells: devices.append(AugustCamera(data, doorbell, DEFAULT_TIMEOUT)) - add_devices(devices, True) + add_entities(devices, True) class AugustCamera(Camera): diff --git a/homeassistant/components/camera/axis.py b/homeassistant/components/camera/axis.py index 5b39718939a..5630759a7f8 100644 --- a/homeassistant/components/camera/axis.py +++ b/homeassistant/components/camera/axis.py @@ -27,7 +27,7 @@ def _get_image_url(host, port, mode): return 'http://{}:{}/axis-cgi/jpg/image.cgi'.format(host, port) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Axis camera.""" camera_config = { CONF_NAME: discovery_info[CONF_NAME], @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): 'single'), CONF_AUTHENTICATION: HTTP_DIGEST_AUTHENTICATION, } - add_devices([AxisCamera( + add_entities([AxisCamera( hass, camera_config, str(discovery_info[CONF_PORT]))]) diff --git a/homeassistant/components/camera/blink.py b/homeassistant/components/camera/blink.py index 8475ca8fd1e..217849138c3 100644 --- a/homeassistant/components/camera/blink.py +++ b/homeassistant/components/camera/blink.py @@ -20,7 +20,7 @@ DEPENDENCIES = ['blink'] MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=90) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Blink Camera.""" if discovery_info is None: return @@ -30,7 +30,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for name in data.cameras: devs.append(BlinkCamera(hass, config, data, name)) - add_devices(devs) + add_entities(devs) class BlinkCamera(Camera): diff --git a/homeassistant/components/camera/bloomsky.py b/homeassistant/components/camera/bloomsky.py index 77528992674..01e20e3ccd3 100644 --- a/homeassistant/components/camera/bloomsky.py +++ b/homeassistant/components/camera/bloomsky.py @@ -13,11 +13,11 @@ from homeassistant.components.camera import Camera DEPENDENCIES = ['bloomsky'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up access to BloomSky cameras.""" bloomsky = hass.components.bloomsky for device in bloomsky.BLOOMSKY.devices.values(): - add_devices([BloomSkyCamera(bloomsky.BLOOMSKY, device)]) + add_entities([BloomSkyCamera(bloomsky.BLOOMSKY, device)]) class BloomSkyCamera(Camera): diff --git a/homeassistant/components/camera/canary.py b/homeassistant/components/camera/canary.py index a230e0f6d4a..9031c27b1a9 100644 --- a/homeassistant/components/camera/canary.py +++ b/homeassistant/components/camera/canary.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Canary sensors.""" data = hass.data[DATA_CANARY] devices = [] @@ -42,7 +42,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): CanaryCamera(hass, data, location, device, DEFAULT_TIMEOUT, config.get(CONF_FFMPEG_ARGUMENTS))) - add_devices(devices, True) + add_entities(devices, True) class CanaryCamera(Camera): diff --git a/homeassistant/components/camera/demo.py b/homeassistant/components/camera/demo.py index 0e77e6e95ad..f950edb5c6c 100644 --- a/homeassistant/components/camera/demo.py +++ b/homeassistant/components/camera/demo.py @@ -12,10 +12,10 @@ from homeassistant.components.camera import Camera, SUPPORT_ON_OFF _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Demo camera platform.""" - async_add_devices([ + async_add_entities([ DemoCamera('Demo camera') ]) diff --git a/homeassistant/components/camera/doorbird.py b/homeassistant/components/camera/doorbird.py index 6680258d95d..7af3e7634d0 100644 --- a/homeassistant/components/camera/doorbird.py +++ b/homeassistant/components/camera/doorbird.py @@ -28,11 +28,12 @@ _TIMEOUT = 10 # seconds @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the DoorBird camera platform.""" for doorstation in hass.data[DOORBIRD_DOMAIN]: device = doorstation.device - async_add_devices([ + async_add_entities([ DoorBirdCamera( device.live_image_url, _CAMERA_LIVE.format(doorstation.name), diff --git a/homeassistant/components/camera/familyhub.py b/homeassistant/components/camera/familyhub.py index e78d341713b..f3dd8b6d0c9 100644 --- a/homeassistant/components/camera/familyhub.py +++ b/homeassistant/components/camera/familyhub.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Family Hub Camera.""" from pyfamilyhublocal import FamilyHubCam address = config.get(CONF_IP_ADDRESS) @@ -36,7 +36,7 @@ async def async_setup_platform( session = async_get_clientsession(hass) family_hub_cam = FamilyHubCam(address, hass.loop, session) - async_add_devices([FamilyHubCamera(name, family_hub_cam)], True) + async_add_entities([FamilyHubCamera(name, family_hub_cam)], True) class FamilyHubCamera(Camera): diff --git a/homeassistant/components/camera/ffmpeg.py b/homeassistant/components/camera/ffmpeg.py index 3da0f19fbf0..c458188695a 100644 --- a/homeassistant/components/camera/ffmpeg.py +++ b/homeassistant/components/camera/ffmpeg.py @@ -29,12 +29,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up a FFmpeg camera.""" if not hass.data[DATA_FFMPEG].async_run_test(config.get(CONF_INPUT)): return - async_add_devices([FFmpegCamera(hass, config)]) + async_add_entities([FFmpegCamera(hass, config)]) class FFmpegCamera(Camera): diff --git a/homeassistant/components/camera/foscam.py b/homeassistant/components/camera/foscam.py index 4ea733139a9..ceec57f7755 100644 --- a/homeassistant/components/camera/foscam.py +++ b/homeassistant/components/camera/foscam.py @@ -33,9 +33,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Foscam IP Camera.""" - add_devices([FoscamCam(config)]) + add_entities([FoscamCam(config)]) class FoscamCam(Camera): diff --git a/homeassistant/components/camera/generic.py b/homeassistant/components/camera/generic.py index d1b5c7214fc..b707c913435 100644 --- a/homeassistant/components/camera/generic.py +++ b/homeassistant/components/camera/generic.py @@ -47,9 +47,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up a generic IP Camera.""" - async_add_devices([GenericCamera(hass, config)]) + async_add_entities([GenericCamera(hass, config)]) class GenericCamera(Camera): diff --git a/homeassistant/components/camera/local_file.py b/homeassistant/components/camera/local_file.py index 95eade48568..d306509b762 100644 --- a/homeassistant/components/camera/local_file.py +++ b/homeassistant/components/camera/local_file.py @@ -31,7 +31,7 @@ CAMERA_SERVICE_UPDATE_FILE_PATH = CAMERA_SERVICE_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Camera that works with local files.""" file_path = config[CONF_FILE_PATH] camera = LocalFile(config[CONF_NAME], file_path) @@ -48,7 +48,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): update_file_path_service, schema=CAMERA_SERVICE_UPDATE_FILE_PATH) - add_devices([camera]) + add_entities([camera]) class LocalFile(Camera): diff --git a/homeassistant/components/camera/mjpeg.py b/homeassistant/components/camera/mjpeg.py index 757a1b5fc09..ed7d58658ed 100644 --- a/homeassistant/components/camera/mjpeg.py +++ b/homeassistant/components/camera/mjpeg.py @@ -42,11 +42,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up a MJPEG IP Camera.""" if discovery_info: config = PLATFORM_SCHEMA(discovery_info) - async_add_devices([MjpegCamera(hass, config)]) + async_add_entities([MjpegCamera(hass, config)]) def extract_image_from_mjpeg(stream): diff --git a/homeassistant/components/camera/mqtt.py b/homeassistant/components/camera/mqtt.py index dc991644b8e..cf5c969c650 100644 --- a/homeassistant/components/camera/mqtt.py +++ b/homeassistant/components/camera/mqtt.py @@ -30,12 +30,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the MQTT Camera.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) - async_add_devices([MqttCamera( + async_add_entities([MqttCamera( config.get(CONF_NAME), config.get(CONF_TOPIC) )]) diff --git a/homeassistant/components/camera/neato.py b/homeassistant/components/camera/neato.py index 3a8a137c1fe..b080dbbae10 100644 --- a/homeassistant/components/camera/neato.py +++ b/homeassistant/components/camera/neato.py @@ -18,14 +18,14 @@ DEPENDENCIES = ['neato'] SCAN_INTERVAL = timedelta(minutes=10) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Neato Camera.""" dev = [] for robot in hass.data[NEATO_ROBOTS]: if 'maps' in robot.traits: dev.append(NeatoCleaningMap(hass, robot)) _LOGGER.debug("Adding robots for cleaning maps %s", dev) - add_devices(dev, True) + add_entities(dev, True) class NeatoCleaningMap(Camera): diff --git a/homeassistant/components/camera/nest.py b/homeassistant/components/camera/nest.py index 3f09bc9ee1c..175dbcd2267 100644 --- a/homeassistant/components/camera/nest.py +++ b/homeassistant/components/camera/nest.py @@ -23,20 +23,20 @@ NEST_BRAND = 'Nest' PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({}) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Nest Cam. No longer in use. """ -async def async_setup_entry(hass, entry, async_add_devices): +async def async_setup_entry(hass, entry, async_add_entities): """Set up a Nest sensor based on a config entry.""" camera_devices = \ await hass.async_add_job(hass.data[nest.DATA_NEST].cameras) cameras = [NestCamera(structure, device) for structure, device in camera_devices] - async_add_devices(cameras, True) + async_add_entities(cameras, True) class NestCamera(Camera): diff --git a/homeassistant/components/camera/netatmo.py b/homeassistant/components/camera/netatmo.py index 1c7dc4c7ce0..93ad2cd055b 100644 --- a/homeassistant/components/camera/netatmo.py +++ b/homeassistant/components/camera/netatmo.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up access to Netatmo cameras.""" netatmo = hass.components.netatmo home = config.get(CONF_HOME) @@ -43,8 +43,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if config[CONF_CAMERAS] != [] and \ camera_name not in config[CONF_CAMERAS]: continue - add_devices([NetatmoCamera(data, camera_name, home, - camera_type, verify_ssl)]) + add_entities([NetatmoCamera(data, camera_name, home, + camera_type, verify_ssl)]) except pyatmo.NoDevice: return None diff --git a/homeassistant/components/camera/onvif.py b/homeassistant/components/camera/onvif.py index 251c44c146e..9cf21dca9f9 100644 --- a/homeassistant/components/camera/onvif.py +++ b/homeassistant/components/camera/onvif.py @@ -71,7 +71,7 @@ SERVICE_PTZ_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a ONVIF camera.""" if not hass.data[DATA_FFMPEG].async_run_test(config.get(CONF_HOST)): return @@ -94,7 +94,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass.services.async_register(DOMAIN, SERVICE_PTZ, handle_ptz, schema=SERVICE_PTZ_SCHEMA) - add_devices([ONVIFHassCamera(hass, config)]) + add_entities([ONVIFHassCamera(hass, config)]) class ONVIFHassCamera(Camera): diff --git a/homeassistant/components/camera/proxy.py b/homeassistant/components/camera/proxy.py index a695848d1fa..a19efcfb1af 100644 --- a/homeassistant/components/camera/proxy.py +++ b/homeassistant/components/camera/proxy.py @@ -48,9 +48,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Proxy camera platform.""" - async_add_devices([ProxyCamera(hass, config)]) + async_add_entities([ProxyCamera(hass, config)]) def _resize_image(image, opts): diff --git a/homeassistant/components/camera/push.py b/homeassistant/components/camera/push.py index d75f59fb038..305e29d62d3 100644 --- a/homeassistant/components/camera/push.py +++ b/homeassistant/components/camera/push.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Push Camera platform.""" if PUSH_CAMERA_DATA not in hass.data: @@ -55,7 +55,7 @@ async def async_setup_platform(hass, config, async_add_devices, hass.http.register_view(CameraPushReceiver(hass, config[CONF_IMAGE_FIELD])) - async_add_devices(cameras) + async_add_entities(cameras) class CameraPushReceiver(HomeAssistantView): diff --git a/homeassistant/components/camera/ring.py b/homeassistant/components/camera/ring.py index 96956d24eec..f629b501819 100644 --- a/homeassistant/components/camera/ring.py +++ b/homeassistant/components/camera/ring.py @@ -40,7 +40,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up a Ring Door Bell and StickUp Camera.""" ring = hass.data[DATA_RING] @@ -73,7 +74,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) - async_add_devices(cams, True) + async_add_entities(cams, True) return True diff --git a/homeassistant/components/camera/rpi_camera.py b/homeassistant/components/camera/rpi_camera.py index 91edf7d1053..ba6f5e93304 100644 --- a/homeassistant/components/camera/rpi_camera.py +++ b/homeassistant/components/camera/rpi_camera.py @@ -62,7 +62,7 @@ def kill_raspistill(*args): stderr=subprocess.STDOUT) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Raspberry Camera.""" if shutil.which("raspistill") is None: _LOGGER.error("'raspistill' was not found") @@ -106,7 +106,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("'%s' is not a whitelisted directory", file_path) return False - add_devices([RaspberryCamera(setup_config)]) + add_entities([RaspberryCamera(setup_config)]) class RaspberryCamera(Camera): diff --git a/homeassistant/components/camera/skybell.py b/homeassistant/components/camera/skybell.py index be3504dab78..9a7d7a06944 100644 --- a/homeassistant/components/camera/skybell.py +++ b/homeassistant/components/camera/skybell.py @@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=90) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform for a Skybell device.""" skybell = hass.data.get(SKYBELL_DOMAIN) @@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in skybell.get_devices(): sensors.append(SkybellCamera(device)) - add_devices(sensors, True) + add_entities(sensors, True) class SkybellCamera(SkybellDevice, Camera): diff --git a/homeassistant/components/camera/synology.py b/homeassistant/components/camera/synology.py index 8bbb3e8c632..3e587fff234 100644 --- a/homeassistant/components/camera/synology.py +++ b/homeassistant/components/camera/synology.py @@ -39,7 +39,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up a Synology IP Camera.""" verify_ssl = config.get(CONF_VERIFY_SSL) timeout = config.get(CONF_TIMEOUT) @@ -66,7 +67,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): device = SynologyCamera(surveillance, camera.camera_id, verify_ssl) devices.append(device) - async_add_devices(devices) + async_add_entities(devices) class SynologyCamera(Camera): diff --git a/homeassistant/components/camera/usps.py b/homeassistant/components/camera/usps.py index 6c76d0d66d8..d23359d8c57 100644 --- a/homeassistant/components/camera/usps.py +++ b/homeassistant/components/camera/usps.py @@ -17,13 +17,13 @@ DEPENDENCIES = ['usps'] SCAN_INTERVAL = timedelta(seconds=10) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up USPS mail camera.""" if discovery_info is None: return usps = hass.data[DATA_USPS] - add_devices([USPSCamera(usps)]) + add_entities([USPSCamera(usps)]) class USPSCamera(Camera): diff --git a/homeassistant/components/camera/uvc.py b/homeassistant/components/camera/uvc.py index b5306c31c84..0e65ac77c1f 100644 --- a/homeassistant/components/camera/uvc.py +++ b/homeassistant/components/camera/uvc.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Discover cameras on a Unifi NVR.""" addr = config[CONF_NVR] key = config[CONF_KEY] @@ -63,11 +63,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Unable to connect to NVR: %s", str(ex)) raise PlatformNotReady - add_devices([UnifiVideoCamera(nvrconn, - camera[identifier], - camera['name'], - password) - for camera in cameras]) + add_entities([UnifiVideoCamera(nvrconn, + camera[identifier], + camera['name'], + password) + for camera in cameras]) return True diff --git a/homeassistant/components/camera/verisure.py b/homeassistant/components/camera/verisure.py index 554f877d0bd..01e4e82f3bc 100644 --- a/homeassistant/components/camera/verisure.py +++ b/homeassistant/components/camera/verisure.py @@ -16,7 +16,7 @@ from homeassistant.components.verisure import CONF_SMARTCAM _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Verisure Camera.""" if not int(hub.config.get(CONF_SMARTCAM, 1)): return False @@ -30,7 +30,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): VerisureSmartcam(hass, device_label, directory_path) for device_label in hub.get( "$.customerImageCameras[*].deviceLabel")]) - add_devices(smartcams) + add_entities(smartcams) class VerisureSmartcam(Camera): diff --git a/homeassistant/components/camera/xeoma.py b/homeassistant/components/camera/xeoma.py index 2a4d1526818..c268c3533e0 100644 --- a/homeassistant/components/camera/xeoma.py +++ b/homeassistant/components/camera/xeoma.py @@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Discover and setup Xeoma Cameras.""" from pyxeoma.xeoma import Xeoma, XeomaError @@ -78,7 +78,7 @@ async def async_setup_platform(hass, config, async_add_devices, camera[CONF_HIDE] = cam[CONF_HIDE] cameras = list(filter(lambda c: not c[CONF_HIDE], discovered_cameras)) - async_add_devices( + async_add_entities( [XeomaCamera(xeoma, camera[CONF_IMAGE_NAME], camera[CONF_NAME], camera[CONF_VIEWER_USERNAME], camera[CONF_VIEWER_PASSWORD]) for camera in cameras]) diff --git a/homeassistant/components/camera/xiaomi.py b/homeassistant/components/camera/xiaomi.py index e80f4b7532a..da36299a209 100644 --- a/homeassistant/components/camera/xiaomi.py +++ b/homeassistant/components/camera/xiaomi.py @@ -45,11 +45,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform(hass, config, - async_add_devices, + async_add_entities, discovery_info=None): """Set up a Xiaomi Camera.""" _LOGGER.debug('Received configuration for model %s', config[CONF_MODEL]) - async_add_devices([XiaomiCamera(hass, config)]) + async_add_entities([XiaomiCamera(hass, config)]) class XiaomiCamera(Camera): diff --git a/homeassistant/components/camera/yi.py b/homeassistant/components/camera/yi.py index 4efc2c7d8ba..eb26c1cc887 100644 --- a/homeassistant/components/camera/yi.py +++ b/homeassistant/components/camera/yi.py @@ -41,9 +41,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up a Yi Camera.""" - async_add_devices([YiCamera(hass, config)], True) + async_add_entities([YiCamera(hass, config)], True) class YiCamera(Camera): diff --git a/homeassistant/components/camera/zoneminder.py b/homeassistant/components/camera/zoneminder.py index be59a1c1f50..e48caa42a34 100644 --- a/homeassistant/components/camera/zoneminder.py +++ b/homeassistant/components/camera/zoneminder.py @@ -49,7 +49,8 @@ def _get_image_url(hass, monitor, mode): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the ZoneMinder cameras.""" cameras = [] monitors = zoneminder.get_state('api/monitors.json') @@ -77,7 +78,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.warning("No active cameras found") return - async_add_devices(cameras) + async_add_entities(cameras) class ZoneMinderCamera(MjpegCamera): diff --git a/homeassistant/components/climate/daikin.py b/homeassistant/components/climate/daikin.py index 50501025f0c..6743bf034dc 100644 --- a/homeassistant/components/climate/daikin.py +++ b/homeassistant/components/climate/daikin.py @@ -50,7 +50,7 @@ HA_ATTR_TO_DAIKIN = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Daikin HVAC platform.""" if discovery_info is not None: host = discovery_info.get('ip') @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.debug("Added Daikin AC on %s", host) api = daikin_api_setup(hass, host, name) - add_devices([DaikinClimate(api)], True) + add_entities([DaikinClimate(api)], True) class DaikinClimate(ClimateDevice): diff --git a/homeassistant/components/climate/demo.py b/homeassistant/components/climate/demo.py index 44491b8cd21..bc0b9bd52ee 100644 --- a/homeassistant/components/climate/demo.py +++ b/homeassistant/components/climate/demo.py @@ -17,9 +17,9 @@ from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, ATTR_TEMPERATURE SUPPORT_FLAGS = SUPPORT_TARGET_HUMIDITY_LOW | SUPPORT_TARGET_HUMIDITY_HIGH -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo climate devices.""" - add_devices([ + add_entities([ DemoClimate('HeatPump', 68, TEMP_FAHRENHEIT, None, None, 77, None, None, None, None, 'heat', None, None, None, True), diff --git a/homeassistant/components/climate/ecobee.py b/homeassistant/components/climate/ecobee.py index 71878827153..46fc5c29752 100644 --- a/homeassistant/components/climate/ecobee.py +++ b/homeassistant/components/climate/ecobee.py @@ -53,7 +53,7 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_AWAY_MODE | SUPPORT_TARGET_TEMPERATURE_LOW | SUPPORT_FAN_MODE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ecobee Thermostat Platform.""" if discovery_info is None: return @@ -64,7 +64,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hold_temp) devices = [Thermostat(data, index, hold_temp) for index in range(len(data.ecobee.thermostats))] - add_devices(devices) + add_entities(devices) def fan_min_on_time_set_service(service): """Set the minimum fan on time on the target thermostats.""" diff --git a/homeassistant/components/climate/econet.py b/homeassistant/components/climate/econet.py index 0591178391a..9350b8f853d 100644 --- a/homeassistant/components/climate/econet.py +++ b/homeassistant/components/climate/econet.py @@ -66,7 +66,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the EcoNet water heaters.""" from pyeconet.api import PyEcoNet @@ -80,7 +80,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): water_heaters = econet.get_water_heaters() hass_water_heaters = [ EcoNetWaterHeater(water_heater) for water_heater in water_heaters] - add_devices(hass_water_heaters) + add_entities(hass_water_heaters) hass.data[ECONET_DATA]['water_heaters'].extend(hass_water_heaters) def service_handle(service): diff --git a/homeassistant/components/climate/ephember.py b/homeassistant/components/climate/ephember.py index f8fb3d3d522..cd410cf3be4 100644 --- a/homeassistant/components/climate/ephember.py +++ b/homeassistant/components/climate/ephember.py @@ -39,7 +39,7 @@ EPH_TO_HA_STATE = { HA_STATE_TO_EPH = {value: key for key, value in EPH_TO_HA_STATE.items()} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ephember thermostat.""" from pyephember.pyephember import EphEmber @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ember = EphEmber(username, password) zones = ember.get_zones() for zone in zones: - add_devices([EphEmberThermostat(ember, zone)]) + add_entities([EphEmberThermostat(ember, zone)]) except RuntimeError: _LOGGER.error("Cannot connect to EphEmber") return diff --git a/homeassistant/components/climate/eq3btsmart.py b/homeassistant/components/climate/eq3btsmart.py index 10fd879e386..904d8222e88 100644 --- a/homeassistant/components/climate/eq3btsmart.py +++ b/homeassistant/components/climate/eq3btsmart.py @@ -42,7 +42,7 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | SUPPORT_AWAY_MODE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the eQ-3 BLE thermostats.""" devices = [] @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): mac = device_cfg[CONF_MAC] devices.append(EQ3BTSmartThermostat(mac, name)) - add_devices(devices) + add_entities(devices) # pylint: disable=import-error diff --git a/homeassistant/components/climate/flexit.py b/homeassistant/components/climate/flexit.py index 6c340e4a5f0..de74d2facb5 100644 --- a/homeassistant/components/climate/flexit.py +++ b/homeassistant/components/climate/flexit.py @@ -36,11 +36,11 @@ _LOGGER = logging.getLogger(__name__) SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Flexit Platform.""" modbus_slave = config.get(CONF_SLAVE, None) name = config.get(CONF_NAME, None) - add_devices([Flexit(modbus_slave, name)], True) + add_entities([Flexit(modbus_slave, name)], True) class Flexit(ClimateDevice): diff --git a/homeassistant/components/climate/fritzbox.py b/homeassistant/components/climate/fritzbox.py index fa3ca31c770..3eedb89a3b7 100644 --- a/homeassistant/components/climate/fritzbox.py +++ b/homeassistant/components/climate/fritzbox.py @@ -35,7 +35,7 @@ ON_REPORT_SET_TEMPERATURE = 30.0 OFF_REPORT_SET_TEMPERATURE = 0.0 -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Fritzbox smarthome thermostat platform.""" devices = [] fritz_list = hass.data[FRITZBOX_DOMAIN] @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device.has_thermostat: devices.append(FritzboxThermostat(device, fritz)) - add_devices(devices) + add_entities(devices) class FritzboxThermostat(ClimateDevice): diff --git a/homeassistant/components/climate/generic_thermostat.py b/homeassistant/components/climate/generic_thermostat.py index 9e5ff3bbf20..fec18329878 100644 --- a/homeassistant/components/climate/generic_thermostat.py +++ b/homeassistant/components/climate/generic_thermostat.py @@ -68,7 +68,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the generic thermostat platform.""" name = config.get(CONF_NAME) heater_entity_id = config.get(CONF_HEATER) @@ -84,7 +85,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): initial_operation_mode = config.get(CONF_INITIAL_OPERATION_MODE) away_temp = config.get(CONF_AWAY_TEMP) - async_add_devices([GenericThermostat( + async_add_entities([GenericThermostat( hass, name, heater_entity_id, sensor_entity_id, min_temp, max_temp, target_temp, ac_mode, min_cycle_duration, cold_tolerance, hot_tolerance, keep_alive, initial_operation_mode, away_temp)]) diff --git a/homeassistant/components/climate/heatmiser.py b/homeassistant/components/climate/heatmiser.py index 116545afc15..a03d1567e01 100644 --- a/homeassistant/components/climate/heatmiser.py +++ b/homeassistant/components/climate/heatmiser.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the heatmiser thermostat.""" from heatmiserV3 import heatmiser, connection @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): serport.open() for tstat in tstats.values(): - add_devices([ + add_entities([ HeatmiserV3Thermostat( heatmiser, tstat.get(CONF_ID), tstat.get(CONF_NAME), serport) ]) diff --git a/homeassistant/components/climate/hive.py b/homeassistant/components/climate/hive.py index eb3aecae3a1..37289d45c45 100644 --- a/homeassistant/components/climate/hive.py +++ b/homeassistant/components/climate/hive.py @@ -21,13 +21,13 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_AUX_HEAT) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Hive climate devices.""" if discovery_info is None: return session = hass.data.get(DATA_HIVE) - add_devices([HiveClimateEntity(session, discovery_info)]) + add_entities([HiveClimateEntity(session, discovery_info)]) class HiveClimateEntity(ClimateDevice): diff --git a/homeassistant/components/climate/homekit_controller.py b/homeassistant/components/climate/homekit_controller.py index f9178c2e0d5..f720fb60277 100644 --- a/homeassistant/components/climate/homekit_controller.py +++ b/homeassistant/components/climate/homekit_controller.py @@ -28,11 +28,11 @@ MODE_HOMEKIT_TO_HASS = { MODE_HASS_TO_HOMEKIT = {v: k for k, v in MODE_HOMEKIT_TO_HASS.items()} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Homekit climate.""" if discovery_info is not None: accessory = hass.data[KNOWN_ACCESSORIES][discovery_info['serial']] - add_devices([HomeKitClimateDevice(accessory, discovery_info)], True) + add_entities([HomeKitClimateDevice(accessory, discovery_info)], True) class HomeKitClimateDevice(HomeKitEntity, ClimateDevice): diff --git a/homeassistant/components/climate/homematic.py b/homeassistant/components/climate/homematic.py index dd773bcd993..5b741a87b45 100644 --- a/homeassistant/components/climate/homematic.py +++ b/homeassistant/components/climate/homematic.py @@ -46,7 +46,7 @@ HM_IP_CONTROL_MODE = 'SET_POINT_MODE' SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Homematic thermostat platform.""" if discovery_info is None: return @@ -56,7 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = HMThermostat(conf) devices.append(new_device) - add_devices(devices) + add_entities(devices) class HMThermostat(HMDevice, ClimateDevice): diff --git a/homeassistant/components/climate/homematicip_cloud.py b/homeassistant/components/climate/homematicip_cloud.py index 6b47096df1b..966cd95ade1 100644 --- a/homeassistant/components/climate/homematicip_cloud.py +++ b/homeassistant/components/climate/homematicip_cloud.py @@ -27,12 +27,12 @@ HMIP_STATE_TO_HA = {value: key for key, value in HA_STATE_TO_HMIP.items()} async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the HomematicIP Cloud climate devices.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP climate from a config entry.""" from homematicip.group import HeatingGroup @@ -43,7 +43,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): devices.append(HomematicipHeatingGroup(home, device)) if devices: - async_add_devices(devices) + async_add_entities(devices) class HomematicipHeatingGroup(HomematicipGenericDevice, ClimateDevice): diff --git a/homeassistant/components/climate/honeywell.py b/homeassistant/components/climate/honeywell.py index 04d705d6b49..6d54695fa7a 100644 --- a/homeassistant/components/climate/honeywell.py +++ b/homeassistant/components/climate/honeywell.py @@ -51,19 +51,19 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Honeywell thermostat.""" username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) region = config.get(CONF_REGION) if region == 'us': - return _setup_us(username, password, config, add_devices) + return _setup_us(username, password, config, add_entities) - return _setup_round(username, password, config, add_devices) + return _setup_round(username, password, config, add_entities) -def _setup_round(username, password, config, add_devices): +def _setup_round(username, password, config, add_entities): """Set up the rounding function.""" from evohomeclient import EvohomeClient @@ -73,7 +73,7 @@ def _setup_round(username, password, config, add_devices): try: zones = evo_api.temperatures(force_refresh=True) for i, zone in enumerate(zones): - add_devices( + add_entities( [RoundThermostat(evo_api, zone['id'], i == 0, away_temp)], True ) @@ -85,7 +85,7 @@ def _setup_round(username, password, config, add_devices): # config will be used later -def _setup_us(username, password, config, add_devices): +def _setup_us(username, password, config, add_entities): """Set up the user.""" import somecomfort @@ -103,12 +103,12 @@ def _setup_us(username, password, config, add_devices): cool_away_temp = config.get(CONF_COOL_AWAY_TEMPERATURE) heat_away_temp = config.get(CONF_HEAT_AWAY_TEMPERATURE) - add_devices([HoneywellUSThermostat(client, device, cool_away_temp, - heat_away_temp, username, password) - for location in client.locations_by_id.values() - for device in location.devices_by_id.values() - if ((not loc_id or location.locationid == loc_id) and - (not dev_id or device.deviceid == dev_id))]) + add_entities([HoneywellUSThermostat(client, device, cool_away_temp, + heat_away_temp, username, password) + for location in client.locations_by_id.values() + for device in location.devices_by_id.values() + if ((not loc_id or location.locationid == loc_id) and + (not dev_id or device.deviceid == dev_id))]) return True diff --git a/homeassistant/components/climate/knx.py b/homeassistant/components/climate/knx.py index a9d26288433..ed197f57ab3 100644 --- a/homeassistant/components/climate/knx.py +++ b/homeassistant/components/climate/knx.py @@ -60,27 +60,27 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up climate(s) for KNX platform.""" if discovery_info is not None: - async_add_devices_discovery(hass, discovery_info, async_add_devices) + async_add_entities_discovery(hass, discovery_info, async_add_entities) else: - async_add_devices_config(hass, config, async_add_devices) + async_add_entities_config(hass, config, async_add_entities) @callback -def async_add_devices_discovery(hass, discovery_info, async_add_devices): +def async_add_entities_discovery(hass, discovery_info, async_add_entities): """Set up climates for KNX platform configured within platform.""" entities = [] for device_name in discovery_info[ATTR_DISCOVER_DEVICES]: device = hass.data[DATA_KNX].xknx.devices[device_name] entities.append(KNXClimate(hass, device)) - async_add_devices(entities) + async_add_entities(entities) @callback -def async_add_devices_config(hass, config, async_add_devices): +def async_add_entities_config(hass, config, async_add_entities): """Set up climate for KNX platform configured within platform.""" import xknx @@ -110,7 +110,7 @@ def async_add_devices_config(hass, config, async_add_devices): group_address_operation_mode_comfort=config.get( CONF_OPERATION_MODE_COMFORT_ADDRESS)) hass.data[DATA_KNX].xknx.devices.add(climate) - async_add_devices([KNXClimate(hass, climate)]) + async_add_entities([KNXClimate(hass, climate)]) class KNXClimate(ClimateDevice): diff --git a/homeassistant/components/climate/maxcube.py b/homeassistant/components/climate/maxcube.py index 204d5a3649c..328cdabde62 100644 --- a/homeassistant/components/climate/maxcube.py +++ b/homeassistant/components/climate/maxcube.py @@ -22,7 +22,7 @@ STATE_VACATION = 'vacation' SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Iterate through all MAX! Devices and add thermostats.""" devices = [] for handler in hass.data[DATA_KEY].values(): @@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): MaxCubeClimate(handler, name, device.rf_address)) if devices: - add_devices(devices) + add_entities(devices) class MaxCubeClimate(ClimateDevice): diff --git a/homeassistant/components/climate/melissa.py b/homeassistant/components/climate/melissa.py index a4a8c76a39f..c8e67c14835 100644 --- a/homeassistant/components/climate/melissa.py +++ b/homeassistant/components/climate/melissa.py @@ -34,7 +34,7 @@ FAN_MODES = [ ] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Iterate through and add all Melissa devices.""" api = hass.data[DATA_MELISSA] devices = api.fetch_devices().values() @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): all_devices.append(MelissaClimate( api, device['serial_number'], device)) - add_devices(all_devices) + add_entities(all_devices) class MelissaClimate(ClimateDevice): diff --git a/homeassistant/components/climate/modbus.py b/homeassistant/components/climate/modbus.py index e567340efc9..1c5c03e4502 100644 --- a/homeassistant/components/climate/modbus.py +++ b/homeassistant/components/climate/modbus.py @@ -50,7 +50,7 @@ _LOGGER = logging.getLogger(__name__) SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus Thermostat Platform.""" name = config.get(CONF_NAME) modbus_slave = config.get(CONF_SLAVE) @@ -60,9 +60,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): count = config.get(CONF_COUNT) precision = config.get(CONF_PRECISION) - add_devices([ModbusThermostat(name, modbus_slave, - target_temp_register, current_temp_register, - data_type, count, precision)], True) + add_entities([ModbusThermostat(name, modbus_slave, + target_temp_register, current_temp_register, + data_type, count, precision)], True) class ModbusThermostat(ClimateDevice): diff --git a/homeassistant/components/climate/mqtt.py b/homeassistant/components/climate/mqtt.py index 1426ff31af9..9e227e002b5 100644 --- a/homeassistant/components/climate/mqtt.py +++ b/homeassistant/components/climate/mqtt.py @@ -127,7 +127,8 @@ PLATFORM_SCHEMA = SCHEMA_BASE.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the MQTT climate devices.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -152,7 +153,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): value_templates[key] = config.get(key) value_templates[key].hass = hass - async_add_devices([ + async_add_entities([ MqttClimate( hass, config.get(CONF_NAME), diff --git a/homeassistant/components/climate/mysensors.py b/homeassistant/components/climate/mysensors.py index a2043c2434b..66c634d8cd9 100644 --- a/homeassistant/components/climate/mysensors.py +++ b/homeassistant/components/climate/mysensors.py @@ -31,11 +31,11 @@ OPERATION_LIST = [STATE_OFF, STATE_AUTO, STATE_COOL, STATE_HEAT] async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the mysensors climate.""" mysensors.setup_mysensors_platform( hass, DOMAIN, discovery_info, MySensorsHVAC, - async_add_devices=async_add_devices) + async_add_entities=async_add_entities) class MySensorsHVAC(mysensors.device.MySensorsEntity, ClimateDevice): diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index 04c598cbddb..81c5fb3c2aa 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -31,14 +31,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ NEST_MODE_HEAT_COOL = 'heat-cool' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Nest thermostat. No longer in use. """ -async def async_setup_entry(hass, entry, async_add_devices): +async def async_setup_entry(hass, entry, async_add_entities): """Set up the Nest climate device based on a config entry.""" temp_unit = hass.config.units.temperature_unit @@ -47,7 +47,7 @@ async def async_setup_entry(hass, entry, async_add_devices): all_devices = [NestThermostat(structure, device, temp_unit) for structure, device in thermostats] - async_add_devices(all_devices, True) + async_add_entities(all_devices, True) class NestThermostat(ClimateDevice): diff --git a/homeassistant/components/climate/netatmo.py b/homeassistant/components/climate/netatmo.py index b4bed367878..8849ada5ccc 100644 --- a/homeassistant/components/climate/netatmo.py +++ b/homeassistant/components/climate/netatmo.py @@ -39,7 +39,7 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | SUPPORT_AWAY_MODE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NetAtmo Thermostat.""" netatmo = hass.components.netatmo device = config.get(CONF_RELAY) @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if config[CONF_THERMOSTAT] != [] and \ module_name not in config[CONF_THERMOSTAT]: continue - add_devices([NetatmoThermostat(data, module_name)], True) + add_entities([NetatmoThermostat(data, module_name)], True) except pyatmo.NoDevice: return None diff --git a/homeassistant/components/climate/nuheat.py b/homeassistant/components/climate/nuheat.py index 39c66ff94f2..d0bfe5add58 100644 --- a/homeassistant/components/climate/nuheat.py +++ b/homeassistant/components/climate/nuheat.py @@ -56,7 +56,7 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_HOLD_MODE | SUPPORT_OPERATION_MODE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NuHeat thermostat(s).""" if discovery_info is None: return @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): NuHeatThermostat(api, serial_number, temperature_unit) for serial_number in serial_numbers ] - add_devices(thermostats, True) + add_entities(thermostats, True) def resume_program_set_service(service): """Resume the program on the target thermostats.""" diff --git a/homeassistant/components/climate/oem.py b/homeassistant/components/climate/oem.py index 59f8db03318..e006242331c 100644 --- a/homeassistant/components/climate/oem.py +++ b/homeassistant/components/climate/oem.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_AWAY_MODE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the oemthermostat platform.""" from oemthermostat import Thermostat @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except (ValueError, AssertionError, requests.RequestException): return False - add_devices((ThermostatDevice(hass, therm, name, away_temp), ), True) + add_entities((ThermostatDevice(hass, therm, name, away_temp), ), True) class ThermostatDevice(ClimateDevice): diff --git a/homeassistant/components/climate/proliphix.py b/homeassistant/components/climate/proliphix.py index 9338c219fe5..76160a28c6e 100644 --- a/homeassistant/components/climate/proliphix.py +++ b/homeassistant/components/climate/proliphix.py @@ -24,7 +24,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Proliphix thermostats.""" username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) @@ -34,7 +34,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): pdp = proliphix.PDP(host, username, password) - add_devices([ProliphixThermostat(pdp)]) + add_entities([ProliphixThermostat(pdp)]) class ProliphixThermostat(ClimateDevice): diff --git a/homeassistant/components/climate/radiotherm.py b/homeassistant/components/climate/radiotherm.py index d158eb52a9d..3d1d8e6a53e 100644 --- a/homeassistant/components/climate/radiotherm.py +++ b/homeassistant/components/climate/radiotherm.py @@ -83,7 +83,7 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | SUPPORT_FAN_MODE | SUPPORT_AWAY_MODE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Radio Thermostat.""" import radiotherm @@ -112,7 +112,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.exception("Unable to connect to Radio Thermostat: %s", host) - add_devices(tstats, True) + add_entities(tstats, True) class RadioThermostat(ClimateDevice): diff --git a/homeassistant/components/climate/sensibo.py b/homeassistant/components/climate/sensibo.py index a2c4ea0ba99..ef33ee8495e 100644 --- a/homeassistant/components/climate/sensibo.py +++ b/homeassistant/components/climate/sensibo.py @@ -59,7 +59,8 @@ FIELD_TO_FLAG = { @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up Sensibo devices.""" import pysensibo @@ -79,7 +80,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): raise PlatformNotReady if devices: - async_add_devices(devices) + async_add_entities(devices) @asyncio.coroutine def async_assume_state(service): diff --git a/homeassistant/components/climate/spider.py b/homeassistant/components/climate/spider.py index a6916b22a25..a9d966bd499 100644 --- a/homeassistant/components/climate/spider.py +++ b/homeassistant/components/climate/spider.py @@ -31,14 +31,14 @@ SPIDER_STATE_TO_HA = {value: key for key, value in HA_STATE_TO_SPIDER.items()} _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Spider thermostat.""" if discovery_info is None: return devices = [SpiderThermostat(hass.data[SPIDER_DOMAIN]['controller'], device) for device in hass.data[SPIDER_DOMAIN]['thermostats']] - add_devices(devices, True) + add_entities(devices, True) class SpiderThermostat(ClimateDevice): diff --git a/homeassistant/components/climate/tado.py b/homeassistant/components/climate/tado.py index b3734e020e0..1e52c163624 100644 --- a/homeassistant/components/climate/tado.py +++ b/homeassistant/components/climate/tado.py @@ -48,7 +48,7 @@ OPERATION_LIST = { SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tado climate platform.""" tado = hass.data[DATA_TADO] @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): climate_devices.append(device) if climate_devices: - add_devices(climate_devices, True) + add_entities(climate_devices, True) def create_climate_device(tado, hass, zone, name, zone_id): diff --git a/homeassistant/components/climate/tesla.py b/homeassistant/components/climate/tesla.py index 225c13d975d..ef5f2227c11 100644 --- a/homeassistant/components/climate/tesla.py +++ b/homeassistant/components/climate/tesla.py @@ -23,11 +23,11 @@ OPERATION_LIST = [STATE_ON, STATE_OFF] SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tesla climate platform.""" devices = [TeslaThermostat(device, hass.data[TESLA_DOMAIN]['controller']) for device in hass.data[TESLA_DOMAIN]['devices']['climate']] - add_devices(devices, True) + add_entities(devices, True) class TeslaThermostat(TeslaDevice, ClimateDevice): diff --git a/homeassistant/components/climate/toon.py b/homeassistant/components/climate/toon.py index 330801fc231..e759e922ee1 100644 --- a/homeassistant/components/climate/toon.py +++ b/homeassistant/components/climate/toon.py @@ -16,9 +16,9 @@ from homeassistant.const import TEMP_CELSIUS SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Toon climate device.""" - add_devices([ThermostatDevice(hass)], True) + add_entities([ThermostatDevice(hass)], True) class ThermostatDevice(ClimateDevice): diff --git a/homeassistant/components/climate/touchline.py b/homeassistant/components/climate/touchline.py index f9c5676629b..641f6e9a1d8 100644 --- a/homeassistant/components/climate/touchline.py +++ b/homeassistant/components/climate/touchline.py @@ -24,7 +24,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Touchline devices.""" from pytouchline import PyTouchline host = config[CONF_HOST] @@ -33,7 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices = [] for device_id in range(0, number_of_devices): devices.append(Touchline(PyTouchline(device_id))) - add_devices(devices, True) + add_entities(devices, True) class Touchline(ClimateDevice): diff --git a/homeassistant/components/climate/tuya.py b/homeassistant/components/climate/tuya.py index 19267d693a0..2da46fee15d 100644 --- a/homeassistant/components/climate/tuya.py +++ b/homeassistant/components/climate/tuya.py @@ -37,7 +37,7 @@ TUYA_STATE_TO_HA = {value: key for key, value in HA_STATE_TO_TUYA.items()} FAN_MODES = {SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tuya Climate devices.""" if discovery_info is None: return @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device is None: continue devices.append(TuyaClimateDevice(device)) - add_devices(devices) + add_entities(devices) class TuyaClimateDevice(TuyaDevice, ClimateDevice): diff --git a/homeassistant/components/climate/venstar.py b/homeassistant/components/climate/venstar.py index 4bacf64cf9e..16c0b206154 100644 --- a/homeassistant/components/climate/venstar.py +++ b/homeassistant/components/climate/venstar.py @@ -50,7 +50,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Venstar thermostat.""" import venstarcolortouch @@ -69,7 +69,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): addr=host, timeout=timeout, user=username, password=password, proto=proto) - add_devices([VenstarThermostat(client, humidifier)], True) + add_entities([VenstarThermostat(client, humidifier)], True) class VenstarThermostat(ClimateDevice): diff --git a/homeassistant/components/climate/vera.py b/homeassistant/components/climate/vera.py index 0f89b15e5a1..e97bd6cd8ad 100644 --- a/homeassistant/components/climate/vera.py +++ b/homeassistant/components/climate/vera.py @@ -29,9 +29,9 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | SUPPORT_FAN_MODE) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up of Vera thermostats.""" - add_devices_callback( + add_entities_callback( [VeraThermostat(device, hass.data[VERA_CONTROLLER]) for device in hass.data[VERA_DEVICES]['climate']], True) diff --git a/homeassistant/components/climate/wink.py b/homeassistant/components/climate/wink.py index 15e555db8b9..d8e6843bec8 100644 --- a/homeassistant/components/climate/wink.py +++ b/homeassistant/components/climate/wink.py @@ -67,21 +67,21 @@ SUPPORT_FLAGS_HEATER = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | SUPPORT_AWAY_MODE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink climate devices.""" import pywink for climate in pywink.get_thermostats(): _id = climate.object_id() + climate.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkThermostat(climate, hass)]) + add_entities([WinkThermostat(climate, hass)]) for climate in pywink.get_air_conditioners(): _id = climate.object_id() + climate.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkAC(climate, hass)]) + add_entities([WinkAC(climate, hass)]) for water_heater in pywink.get_water_heaters(): _id = water_heater.object_id() + water_heater.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkWaterHeater(water_heater, hass)]) + add_entities([WinkWaterHeater(water_heater, hass)]) class WinkThermostat(WinkDevice, ClimateDevice): diff --git a/homeassistant/components/climate/zhong_hong.py b/homeassistant/components/climate/zhong_hong.py index 2b66af35224..46d590a9412 100644 --- a/homeassistant/components/climate/zhong_hong.py +++ b/homeassistant/components/climate/zhong_hong.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZhongHong HVAC platform.""" from zhong_hong_hvac.hub import ZhongHongGateway host = config.get(CONF_HOST) @@ -69,7 +69,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): async_dispatcher_connect(hass, SIGNAL_DEVICE_ADDED, startup) # add devices after SIGNAL_DEVICE_SETTED_UP event is listend - add_devices(devices) + add_entities(devices) def stop_listen(event): """Stop ZhongHongHub socket.""" diff --git a/homeassistant/components/cover/abode.py b/homeassistant/components/cover/abode.py index 6eb0369aa3f..3ba3fb118f3 100644 --- a/homeassistant/components/cover/abode.py +++ b/homeassistant/components/cover/abode.py @@ -15,7 +15,7 @@ DEPENDENCIES = ['abode'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Abode cover devices.""" import abodepy.helpers.constants as CONST @@ -30,7 +30,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(devices) - add_devices(devices) + add_entities(devices) class AbodeCover(AbodeDevice, CoverDevice): diff --git a/homeassistant/components/cover/aladdin_connect.py b/homeassistant/components/cover/aladdin_connect.py index ef1f94d1bcd..4627ba77781 100644 --- a/homeassistant/components/cover/aladdin_connect.py +++ b/homeassistant/components/cover/aladdin_connect.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Aladdin Connect platform.""" from aladdin_connect import AladdinConnectClient @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): try: if not acc.login(): raise ValueError("Username or Password is incorrect") - add_devices(AladdinDevice(acc, door) for door in acc.get_doors()) + add_entities(AladdinDevice(acc, door) for door in acc.get_doors()) except (TypeError, KeyError, NameError, ValueError) as ex: _LOGGER.error("%s", ex) hass.components.persistent_notification.create( diff --git a/homeassistant/components/cover/brunt.py b/homeassistant/components/cover/brunt.py index bd27ea30637..746f3840a01 100644 --- a/homeassistant/components/cover/brunt.py +++ b/homeassistant/components/cover/brunt.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the brunt platform.""" # pylint: disable=no-name-in-module from brunt import BruntAPI @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not things: _LOGGER.error("No things present in account.") else: - add_devices([BruntDevice( + add_entities([BruntDevice( bapi, thing['NAME'], thing['thingUri']) for thing in things], True) except (TypeError, KeyError, NameError, ValueError) as ex: diff --git a/homeassistant/components/cover/command_line.py b/homeassistant/components/cover/command_line.py index 6d43b1d2166..bebf78b1db6 100644 --- a/homeassistant/components/cover/command_line.py +++ b/homeassistant/components/cover/command_line.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up cover controlled by shell commands.""" devices = config.get(CONF_COVERS, {}) covers = [] @@ -57,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("No covers added") return False - add_devices(covers) + add_entities(covers) class CommandCover(CoverDevice): diff --git a/homeassistant/components/cover/demo.py b/homeassistant/components/cover/demo.py index b81ac4e45e1..21add0a6c62 100644 --- a/homeassistant/components/cover/demo.py +++ b/homeassistant/components/cover/demo.py @@ -10,9 +10,9 @@ from homeassistant.components.cover import ( from homeassistant.helpers.event import track_utc_time_change -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo covers.""" - add_devices([ + add_entities([ DemoCover(hass, 'Kitchen Window'), DemoCover(hass, 'Hall Window', 10), DemoCover(hass, 'Living Room Window', 70, 50), diff --git a/homeassistant/components/cover/garadget.py b/homeassistant/components/cover/garadget.py index 70f69568109..7a04aa4c71a 100644 --- a/homeassistant/components/cover/garadget.py +++ b/homeassistant/components/cover/garadget.py @@ -51,7 +51,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Garadget covers.""" covers = [] devices = config.get(CONF_COVERS) @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): covers.append(GaradgetCover(hass, args)) - add_devices(covers) + add_entities(covers) class GaradgetCover(CoverDevice): diff --git a/homeassistant/components/cover/gogogate2.py b/homeassistant/components/cover/gogogate2.py index 2b91591e71b..accc4f9ec98 100644 --- a/homeassistant/components/cover/gogogate2.py +++ b/homeassistant/components/cover/gogogate2.py @@ -32,7 +32,7 @@ COVER_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Gogogate2 component.""" from pygogogate2 import Gogogate2API as pygogogate2 @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): raise ValueError( "Username or Password is incorrect or no devices found") - add_devices(MyGogogate2Device( + add_entities(MyGogogate2Device( mygogogate2, door, name) for door in devices) except (TypeError, KeyError, NameError, ValueError) as ex: diff --git a/homeassistant/components/cover/group.py b/homeassistant/components/cover/group.py index c1ea33a9cc7..0424c900747 100644 --- a/homeassistant/components/cover/group.py +++ b/homeassistant/components/cover/group.py @@ -39,10 +39,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Group Cover platform.""" - async_add_devices( + async_add_entities( [CoverGroup(config[CONF_NAME], config[CONF_ENTITIES])]) diff --git a/homeassistant/components/cover/homematic.py b/homeassistant/components/cover/homematic.py index 9975b426558..93574321203 100644 --- a/homeassistant/components/cover/homematic.py +++ b/homeassistant/components/cover/homematic.py @@ -16,7 +16,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['homematic'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform.""" if discovery_info is None: return @@ -26,7 +26,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = HMCover(conf) devices.append(new_device) - add_devices(devices) + add_entities(devices) class HMCover(HMDevice, CoverDevice): diff --git a/homeassistant/components/cover/isy994.py b/homeassistant/components/cover/isy994.py index 0ccfe267989..428c1f326e4 100644 --- a/homeassistant/components/cover/isy994.py +++ b/homeassistant/components/cover/isy994.py @@ -26,7 +26,7 @@ VALUE_TO_STATE = { def setup_platform(hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the ISY994 cover platform.""" devices = [] for node in hass.data[ISY994_NODES][DOMAIN]: @@ -35,7 +35,7 @@ def setup_platform(hass, config: ConfigType, for name, status, actions in hass.data[ISY994_PROGRAMS][DOMAIN]: devices.append(ISYCoverProgram(name, status, actions)) - add_devices(devices) + add_entities(devices) class ISYCoverDevice(ISYDevice, CoverDevice): diff --git a/homeassistant/components/cover/knx.py b/homeassistant/components/cover/knx.py index 59195d73a2f..74ac80a476d 100644 --- a/homeassistant/components/cover/knx.py +++ b/homeassistant/components/cover/knx.py @@ -49,27 +49,27 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up cover(s) for KNX platform.""" if discovery_info is not None: - async_add_devices_discovery(hass, discovery_info, async_add_devices) + async_add_entities_discovery(hass, discovery_info, async_add_entities) else: - async_add_devices_config(hass, config, async_add_devices) + async_add_entities_config(hass, config, async_add_entities) @callback -def async_add_devices_discovery(hass, discovery_info, async_add_devices): +def async_add_entities_discovery(hass, discovery_info, async_add_entities): """Set up covers for KNX platform configured via xknx.yaml.""" entities = [] for device_name in discovery_info[ATTR_DISCOVER_DEVICES]: device = hass.data[DATA_KNX].xknx.devices[device_name] entities.append(KNXCover(hass, device)) - async_add_devices(entities) + async_add_entities(entities) @callback -def async_add_devices_config(hass, config, async_add_devices): +def async_add_entities_config(hass, config, async_add_entities): """Set up cover for KNX platform configured within platform.""" import xknx cover = xknx.devices.Cover( @@ -88,7 +88,7 @@ def async_add_devices_config(hass, config, async_add_devices): invert_angle=config.get(CONF_INVERT_ANGLE)) hass.data[DATA_KNX].xknx.devices.add(cover) - async_add_devices([KNXCover(hass, cover)]) + async_add_entities([KNXCover(hass, cover)]) class KNXCover(CoverDevice): diff --git a/homeassistant/components/cover/lutron.py b/homeassistant/components/cover/lutron.py index 599bdb1ceba..7ea7abf882d 100644 --- a/homeassistant/components/cover/lutron.py +++ b/homeassistant/components/cover/lutron.py @@ -17,14 +17,14 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['lutron'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Lutron shades.""" devs = [] for (area_name, device) in hass.data[LUTRON_DEVICES]['cover']: dev = LutronCover(area_name, device, hass.data[LUTRON_CONTROLLER]) devs.append(dev) - add_devices(devs, True) + add_entities(devs, True) return True diff --git a/homeassistant/components/cover/lutron_caseta.py b/homeassistant/components/cover/lutron_caseta.py index 87821b802ba..37b7c1be42c 100644 --- a/homeassistant/components/cover/lutron_caseta.py +++ b/homeassistant/components/cover/lutron_caseta.py @@ -17,7 +17,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['lutron_caseta'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Lutron Caseta shades as a cover device.""" devs = [] @@ -27,7 +27,7 @@ async def async_setup_platform(hass, config, async_add_devices, dev = LutronCasetaCover(cover_device, bridge) devs.append(dev) - async_add_devices(devs, True) + async_add_entities(devs, True) class LutronCasetaCover(LutronCasetaDevice, CoverDevice): diff --git a/homeassistant/components/cover/mqtt.py b/homeassistant/components/cover/mqtt.py index e1775e2f968..977353cb318 100644 --- a/homeassistant/components/cover/mqtt.py +++ b/homeassistant/components/cover/mqtt.py @@ -92,7 +92,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the MQTT Cover.""" if discovery_info is not None: @@ -105,7 +105,7 @@ async def async_setup_platform(hass, config, async_add_devices, if set_position_template is not None: set_position_template.hass = hass - async_add_devices([MqttCover( + async_add_entities([MqttCover( config.get(CONF_NAME), config.get(CONF_STATE_TOPIC), config.get(CONF_COMMAND_TOPIC), diff --git a/homeassistant/components/cover/myq.py b/homeassistant/components/cover/myq.py index a4682172fee..bedc041fccc 100644 --- a/homeassistant/components/cover/myq.py +++ b/homeassistant/components/cover/myq.py @@ -29,7 +29,7 @@ COVER_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the MyQ component.""" from pymyq import MyQAPI as pymyq @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not myq.is_login_valid(): raise ValueError("Username or Password is incorrect") - add_devices(MyQDevice(myq, door) for door in myq.get_garage_doors()) + add_entities(MyQDevice(myq, door) for door in myq.get_garage_doors()) return True except (TypeError, KeyError, NameError, ValueError) as ex: diff --git a/homeassistant/components/cover/mysensors.py b/homeassistant/components/cover/mysensors.py index c815cf44df2..60ff7aeef1d 100644 --- a/homeassistant/components/cover/mysensors.py +++ b/homeassistant/components/cover/mysensors.py @@ -10,11 +10,11 @@ from homeassistant.const import STATE_OFF, STATE_ON async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the mysensors platform for covers.""" mysensors.setup_mysensors_platform( hass, DOMAIN, discovery_info, MySensorsCover, - async_add_devices=async_add_devices) + async_add_entities=async_add_entities) class MySensorsCover(mysensors.device.MySensorsEntity, CoverDevice): diff --git a/homeassistant/components/cover/opengarage.py b/homeassistant/components/cover/opengarage.py index fe6c7763cc7..19a87c5bf7c 100644 --- a/homeassistant/components/cover/opengarage.py +++ b/homeassistant/components/cover/opengarage.py @@ -50,7 +50,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the OpenGarage covers.""" covers = [] devices = config.get(CONF_COVERS) @@ -66,7 +66,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): covers.append(OpenGarageCover(hass, args)) - add_devices(covers, True) + add_entities(covers, True) class OpenGarageCover(CoverDevice): diff --git a/homeassistant/components/cover/rflink.py b/homeassistant/components/cover/rflink.py index 3357bf2d204..e50fa488b92 100644 --- a/homeassistant/components/cover/rflink.py +++ b/homeassistant/components/cover/rflink.py @@ -78,10 +78,10 @@ def devices_from_config(domain_config, hass=None): return devices -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Rflink cover platform.""" - async_add_devices(devices_from_config(config, hass)) + async_add_entities(devices_from_config(config, hass)) class RflinkCover(RflinkCommand, CoverDevice): diff --git a/homeassistant/components/cover/rfxtrx.py b/homeassistant/components/cover/rfxtrx.py index 5079a3b60c2..d486b601977 100644 --- a/homeassistant/components/cover/rfxtrx.py +++ b/homeassistant/components/cover/rfxtrx.py @@ -29,12 +29,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the RFXtrx cover.""" import RFXtrx as rfxtrxmod covers = rfxtrx.get_devices_from_config(config, RfxtrxCover) - add_devices(covers) + add_entities(covers) def cover_update(event): """Handle cover updates from the RFXtrx gateway.""" @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = rfxtrx.get_new_device(event, config, RfxtrxCover) if new_device: - add_devices([new_device]) + add_entities([new_device]) rfxtrx.apply_received_command(event) diff --git a/homeassistant/components/cover/rpi_gpio.py b/homeassistant/components/cover/rpi_gpio.py index 2f6951cfc0d..828f5e8e0fe 100644 --- a/homeassistant/components/cover/rpi_gpio.py +++ b/homeassistant/components/cover/rpi_gpio.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the RPi cover platform.""" relay_time = config.get(CONF_RELAY_TIME) state_pull_mode = config.get(CONF_STATE_PULL_MODE) @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): covers.append(RPiGPIOCover( cover[CONF_NAME], cover[CONF_RELAY_PIN], cover[CONF_STATE_PIN], state_pull_mode, relay_time, invert_state, invert_relay)) - add_devices(covers) + add_entities(covers) class RPiGPIOCover(CoverDevice): diff --git a/homeassistant/components/cover/ryobi_gdo.py b/homeassistant/components/cover/ryobi_gdo.py index a11d70dd3ad..fec91f843fd 100644 --- a/homeassistant/components/cover/ryobi_gdo.py +++ b/homeassistant/components/cover/ryobi_gdo.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ SUPPORTED_FEATURES = (SUPPORT_OPEN | SUPPORT_CLOSE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ryobi covers.""" from py_ryobi_gdo import RyobiGDO as ryobi_door covers = [] @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): covers.append(RyobiCover(hass, my_door)) if covers: _LOGGER.debug("Adding covers") - add_devices(covers, True) + add_entities(covers, True) class RyobiCover(CoverDevice): diff --git a/homeassistant/components/cover/scsgate.py b/homeassistant/components/cover/scsgate.py index 04bf0ef1d32..a6f09c7237d 100644 --- a/homeassistant/components/cover/scsgate.py +++ b/homeassistant/components/cover/scsgate.py @@ -22,7 +22,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SCSGate cover.""" devices = config.get(CONF_DEVICES) covers = [] @@ -42,7 +42,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): scsgate.SCSGATE.add_device(cover) covers.append(cover) - add_devices(covers) + add_entities(covers) class SCSGateCover(CoverDevice): diff --git a/homeassistant/components/cover/tahoma.py b/homeassistant/components/cover/tahoma.py index b38a863ebe0..baf32073c44 100644 --- a/homeassistant/components/cover/tahoma.py +++ b/homeassistant/components/cover/tahoma.py @@ -24,13 +24,13 @@ ATTR_LOCK_LEVEL = 'lock_level' ATTR_LOCK_ORIG = 'lock_originator' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tahoma covers.""" controller = hass.data[TAHOMA_DOMAIN]['controller'] devices = [] for device in hass.data[TAHOMA_DOMAIN]['devices']['cover']: devices.append(TahomaCover(device, controller)) - add_devices(devices, True) + add_entities(devices, True) class TahomaCover(TahomaDevice, CoverDevice): diff --git a/homeassistant/components/cover/tellduslive.py b/homeassistant/components/cover/tellduslive.py index b4bde037a12..fc352aa8482 100644 --- a/homeassistant/components/cover/tellduslive.py +++ b/homeassistant/components/cover/tellduslive.py @@ -14,12 +14,12 @@ from homeassistant.components.tellduslive import TelldusLiveEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Telldus Live covers.""" if discovery_info is None: return - add_devices(TelldusLiveCover(hass, cover) for cover in discovery_info) + add_entities(TelldusLiveCover(hass, cover) for cover in discovery_info) class TelldusLiveCover(TelldusLiveEntity, CoverDevice): diff --git a/homeassistant/components/cover/tellstick.py b/homeassistant/components/cover/tellstick.py index 56a5a24b409..88608ac42e9 100644 --- a/homeassistant/components/cover/tellstick.py +++ b/homeassistant/components/cover/tellstick.py @@ -12,7 +12,7 @@ from homeassistant.components.tellstick import ( DATA_TELLSTICK, TellstickDevice) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tellstick covers.""" if (discovery_info is None or discovery_info[ATTR_DISCOVER_DEVICES] is None): @@ -21,10 +21,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): signal_repetitions = discovery_info.get( ATTR_DISCOVER_CONFIG, DEFAULT_SIGNAL_REPETITIONS) - add_devices([TellstickCover(hass.data[DATA_TELLSTICK][tellcore_id], - signal_repetitions) - for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]], - True) + add_entities([TellstickCover(hass.data[DATA_TELLSTICK][tellcore_id], + signal_repetitions) + for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]], + True) class TellstickCover(TellstickDevice, CoverDevice): diff --git a/homeassistant/components/cover/template.py b/homeassistant/components/cover/template.py index d9d0d61c77a..e02cdc32319 100644 --- a/homeassistant/components/cover/template.py +++ b/homeassistant/components/cover/template.py @@ -71,7 +71,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Template cover.""" covers = [] @@ -141,7 +141,7 @@ async def async_setup_platform(hass, config, async_add_devices, _LOGGER.error("No covers added") return False - async_add_devices(covers) + async_add_entities(covers) return True diff --git a/homeassistant/components/cover/tuya.py b/homeassistant/components/cover/tuya.py index 7b5fefee58a..6ab8581602f 100644 --- a/homeassistant/components/cover/tuya.py +++ b/homeassistant/components/cover/tuya.py @@ -11,7 +11,7 @@ from homeassistant.components.tuya import DATA_TUYA, TuyaDevice DEPENDENCIES = ['tuya'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tuya cover devices.""" if discovery_info is None: return @@ -23,7 +23,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device is None: continue devices.append(TuyaCover(device)) - add_devices(devices) + add_entities(devices) class TuyaCover(TuyaDevice, CoverDevice): diff --git a/homeassistant/components/cover/velbus.py b/homeassistant/components/cover/velbus.py index fd060e7a7e1..a8501778884 100644 --- a/homeassistant/components/cover/velbus.py +++ b/homeassistant/components/cover/velbus.py @@ -32,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ DEPENDENCIES = ['velbus'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up cover controlled by Velbus.""" devices = config.get(CONF_COVERS, {}) covers = [] @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("No covers added") return False - add_devices(covers) + add_entities(covers) class VelbusCover(CoverDevice): diff --git a/homeassistant/components/cover/vera.py b/homeassistant/components/cover/vera.py index 9b2e8f3aad0..279e4a4307d 100644 --- a/homeassistant/components/cover/vera.py +++ b/homeassistant/components/cover/vera.py @@ -16,9 +16,9 @@ DEPENDENCIES = ['vera'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vera covers.""" - add_devices( + add_entities( [VeraCover(device, hass.data[VERA_CONTROLLER]) for device in hass.data[VERA_DEVICES]['cover']], True) diff --git a/homeassistant/components/cover/wink.py b/homeassistant/components/cover/wink.py index 2206de05041..857283b9b6c 100644 --- a/homeassistant/components/cover/wink.py +++ b/homeassistant/components/cover/wink.py @@ -11,22 +11,22 @@ from homeassistant.components.wink import WinkDevice, DOMAIN DEPENDENCIES = ['wink'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink cover platform.""" import pywink for shade in pywink.get_shades(): _id = shade.object_id() + shade.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkCoverDevice(shade, hass)]) + add_entities([WinkCoverDevice(shade, hass)]) for shade in pywink.get_shade_groups(): _id = shade.object_id() + shade.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkCoverDevice(shade, hass)]) + add_entities([WinkCoverDevice(shade, hass)]) for door in pywink.get_garage_doors(): _id = door.object_id() + door.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkCoverDevice(door, hass)]) + add_entities([WinkCoverDevice(door, hass)]) class WinkCoverDevice(WinkDevice, CoverDevice): diff --git a/homeassistant/components/cover/xiaomi_aqara.py b/homeassistant/components/cover/xiaomi_aqara.py index 14321149148..3ed0a70b1e0 100644 --- a/homeassistant/components/cover/xiaomi_aqara.py +++ b/homeassistant/components/cover/xiaomi_aqara.py @@ -10,7 +10,7 @@ _LOGGER = logging.getLogger(__name__) ATTR_CURTAIN_LEVEL = 'curtain_level' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Perform the setup for Xiaomi devices.""" devices = [] for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): @@ -21,7 +21,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): {'status': 'status', 'pos': 'curtain_level'}, gateway)) - add_devices(devices) + add_entities(devices) class XiaomiGenericCover(XiaomiDevice, CoverDevice): diff --git a/homeassistant/components/fan/comfoconnect.py b/homeassistant/components/fan/comfoconnect.py index fd3265b8230..a1f13da6c09 100644 --- a/homeassistant/components/fan/comfoconnect.py +++ b/homeassistant/components/fan/comfoconnect.py @@ -26,11 +26,11 @@ SPEED_MAPPING = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ComfoConnect fan platform.""" ccb = hass.data[DOMAIN] - add_devices([ComfoConnectFan(hass, name=ccb.name, ccb=ccb)], True) + add_entities([ComfoConnectFan(hass, name=ccb.name, ccb=ccb)], True) class ComfoConnectFan(FanEntity): diff --git a/homeassistant/components/fan/demo.py b/homeassistant/components/fan/demo.py index c03c492c834..840196c8bf0 100644 --- a/homeassistant/components/fan/demo.py +++ b/homeassistant/components/fan/demo.py @@ -13,9 +13,9 @@ FULL_SUPPORT = SUPPORT_SET_SPEED | SUPPORT_OSCILLATE | SUPPORT_DIRECTION LIMITED_SUPPORT = SUPPORT_SET_SPEED -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up the demo fan platform.""" - add_devices_callback([ + add_entities_callback([ DemoFan(hass, "Living Room Fan", FULL_SUPPORT), DemoFan(hass, "Ceiling Fan", LIMITED_SUPPORT), ]) diff --git a/homeassistant/components/fan/dyson.py b/homeassistant/components/fan/dyson.py index 3eb4646e6dc..9f505c87b3d 100644 --- a/homeassistant/components/fan/dyson.py +++ b/homeassistant/components/fan/dyson.py @@ -32,7 +32,7 @@ DYSON_SET_NIGHT_MODE_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dyson fan components.""" from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dyson_entity = DysonPureCoolLinkDevice(hass, device) hass.data[DYSON_FAN_DEVICES].append(dyson_entity) - add_devices(hass.data[DYSON_FAN_DEVICES]) + add_entities(hass.data[DYSON_FAN_DEVICES]) def service_handle(service): """Handle the Dyson services.""" diff --git a/homeassistant/components/fan/insteon.py b/homeassistant/components/fan/insteon.py index 62fa48935ec..f938ae7aec1 100644 --- a/homeassistant/components/fan/insteon.py +++ b/homeassistant/components/fan/insteon.py @@ -29,7 +29,8 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the INSTEON device class for the hass platform.""" insteon_modem = hass.data['insteon'].get('modem') @@ -42,7 +43,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): new_entity = InsteonFan(device, state_key) - async_add_devices([new_entity]) + async_add_entities([new_entity]) class InsteonFan(InsteonEntity, FanEntity): diff --git a/homeassistant/components/fan/isy994.py b/homeassistant/components/fan/isy994.py index 97a5f9c3bd6..314200ba1c4 100644 --- a/homeassistant/components/fan/isy994.py +++ b/homeassistant/components/fan/isy994.py @@ -31,7 +31,7 @@ for key in VALUE_TO_STATE: def setup_platform(hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the ISY994 fan platform.""" devices = [] @@ -41,7 +41,7 @@ def setup_platform(hass, config: ConfigType, for name, status, actions in hass.data[ISY994_PROGRAMS][DOMAIN]: devices.append(ISYFanProgram(name, status, actions)) - add_devices(devices) + add_entities(devices) class ISYFanDevice(ISYDevice, FanEntity): diff --git a/homeassistant/components/fan/mqtt.py b/homeassistant/components/fan/mqtt.py index 5faa735801d..db3cfab3608 100644 --- a/homeassistant/components/fan/mqtt.py +++ b/homeassistant/components/fan/mqtt.py @@ -78,12 +78,12 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info=None): + async_add_entities, discovery_info=None): """Set up the MQTT fan platform.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) - async_add_devices([MqttFan( + async_add_entities([MqttFan( config.get(CONF_NAME), { key: config.get(key) for key in ( diff --git a/homeassistant/components/fan/template.py b/homeassistant/components/fan/template.py index 74fb73dae1d..ff25afb792a 100644 --- a/homeassistant/components/fan/template.py +++ b/homeassistant/components/fan/template.py @@ -67,7 +67,7 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None + hass, config, async_add_entities, discovery_info=None ): """Set up the Template Fans.""" fans = [] @@ -123,7 +123,7 @@ async def async_setup_platform( ) ) - async_add_devices(fans) + async_add_entities(fans) class TemplateFan(FanEntity): diff --git a/homeassistant/components/fan/tuya.py b/homeassistant/components/fan/tuya.py index f19a9e5a5f7..9cb7cdc3f2c 100644 --- a/homeassistant/components/fan/tuya.py +++ b/homeassistant/components/fan/tuya.py @@ -13,7 +13,7 @@ from homeassistant.const import STATE_OFF DEPENDENCIES = ['tuya'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tuya fan platform.""" if discovery_info is None: return @@ -25,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device is None: continue devices.append(TuyaFanDevice(device)) - add_devices(devices) + add_entities(devices) class TuyaFanDevice(TuyaDevice, FanEntity): diff --git a/homeassistant/components/fan/wink.py b/homeassistant/components/fan/wink.py index 4eebacbbbf2..480801c48c0 100644 --- a/homeassistant/components/fan/wink.py +++ b/homeassistant/components/fan/wink.py @@ -21,13 +21,13 @@ SPEED_LOWEST = 'lowest' SUPPORTED_FEATURES = SUPPORT_DIRECTION + SUPPORT_SET_SPEED -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink platform.""" import pywink for fan in pywink.get_fans(): if fan.object_id() + fan.name() not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkFanDevice(fan, hass)]) + add_entities([WinkFanDevice(fan, hass)]) class WinkFanDevice(WinkDevice, FanEntity): diff --git a/homeassistant/components/fan/xiaomi_miio.py b/homeassistant/components/fan/xiaomi_miio.py index ee8f49f897a..a66e833b4b2 100644 --- a/homeassistant/components/fan/xiaomi_miio.py +++ b/homeassistant/components/fan/xiaomi_miio.py @@ -314,7 +314,7 @@ SERVICE_TO_METHOD = { } -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the miio fan device from config.""" from miio import Device, DeviceException @@ -358,7 +358,7 @@ async def async_setup_platform(hass, config, async_add_devices, return False hass.data[DATA_KEY][host] = device - async_add_devices([device], update_before_add=True) + async_add_entities([device], update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiAirPurifier.""" diff --git a/homeassistant/components/fan/zha.py b/homeassistant/components/fan/zha.py index 983bc3a79d7..2612c065393 100644 --- a/homeassistant/components/fan/zha.py +++ b/homeassistant/components/fan/zha.py @@ -39,13 +39,14 @@ SPEED_TO_VALUE = {speed: i for i, speed in enumerate(SPEED_LIST)} @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Zigbee Home Automation fans.""" discovery_info = zha.get_discovery_info(hass, discovery_info) if discovery_info is None: return - async_add_devices([ZhaFan(**discovery_info)], update_before_add=True) + async_add_entities([ZhaFan(**discovery_info)], update_before_add=True) class ZhaFan(zha.Entity, FanEntity): diff --git a/homeassistant/components/image_processing/demo.py b/homeassistant/components/image_processing/demo.py index e225113b5b1..42ba7b4c05f 100644 --- a/homeassistant/components/image_processing/demo.py +++ b/homeassistant/components/image_processing/demo.py @@ -12,9 +12,9 @@ from homeassistant.components.image_processing.openalpr_local import ( ImageProcessingAlprEntity) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the demo image processing platform.""" - add_devices([ + add_entities([ DemoImageProcessingAlpr('camera.demo_camera', "Demo Alpr"), DemoImageProcessingFace( 'camera.demo_camera', "Demo Face") diff --git a/homeassistant/components/image_processing/dlib_face_detect.py b/homeassistant/components/image_processing/dlib_face_detect.py index d4a20da253c..d3b4e14f4de 100644 --- a/homeassistant/components/image_processing/dlib_face_detect.py +++ b/homeassistant/components/image_processing/dlib_face_detect.py @@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__) ATTR_LOCATION = 'location' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dlib Face detection platform.""" entities = [] for camera in config[CONF_SOURCE]: @@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): camera[CONF_ENTITY_ID], camera.get(CONF_NAME) )) - add_devices(entities) + add_entities(entities) class DlibFaceDetectEntity(ImageProcessingFaceEntity): diff --git a/homeassistant/components/image_processing/dlib_face_identify.py b/homeassistant/components/image_processing/dlib_face_identify.py index bf34eb4c2da..d8c3f5f621f 100644 --- a/homeassistant/components/image_processing/dlib_face_identify.py +++ b/homeassistant/components/image_processing/dlib_face_identify.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dlib Face detection platform.""" entities = [] for camera in config[CONF_SOURCE]: @@ -35,7 +35,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): camera[CONF_ENTITY_ID], config[CONF_FACES], camera.get(CONF_NAME) )) - add_devices(entities) + add_entities(entities) class DlibFaceIdentifyEntity(ImageProcessingFaceEntity): diff --git a/homeassistant/components/image_processing/facebox.py b/homeassistant/components/image_processing/facebox.py index e5ce0b825d0..2fbd1c5c81c 100644 --- a/homeassistant/components/image_processing/facebox.py +++ b/homeassistant/components/image_processing/facebox.py @@ -152,7 +152,7 @@ def valid_file_path(file_path): return False -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the classifier.""" if DATA_FACEBOX not in hass.data: hass.data[DATA_FACEBOX] = [] @@ -173,7 +173,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): camera[CONF_ENTITY_ID], camera.get(CONF_NAME)) entities.append(facebox) hass.data[DATA_FACEBOX].append(facebox) - add_devices(entities) + add_entities(entities) def service_handle(service): """Handle for services.""" diff --git a/homeassistant/components/image_processing/microsoft_face_detect.py b/homeassistant/components/image_processing/microsoft_face_detect.py index 0b57dba8bca..7e10d05c5b6 100644 --- a/homeassistant/components/image_processing/microsoft_face_detect.py +++ b/homeassistant/components/image_processing/microsoft_face_detect.py @@ -46,7 +46,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Microsoft Face detection platform.""" api = hass.data[DATA_MICROSOFT_FACE] attributes = config[CONF_ATTRIBUTES] @@ -57,7 +58,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): camera[CONF_ENTITY_ID], api, attributes, camera.get(CONF_NAME) )) - async_add_devices(entities) + async_add_entities(entities) class MicrosoftFaceDetectEntity(ImageProcessingFaceEntity): diff --git a/homeassistant/components/image_processing/microsoft_face_identify.py b/homeassistant/components/image_processing/microsoft_face_identify.py index 9479a804a44..fae11a3dfa9 100644 --- a/homeassistant/components/image_processing/microsoft_face_identify.py +++ b/homeassistant/components/image_processing/microsoft_face_identify.py @@ -30,7 +30,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Microsoft Face identify platform.""" api = hass.data[DATA_MICROSOFT_FACE] face_group = config[CONF_GROUP] @@ -43,7 +44,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): camera.get(CONF_NAME) )) - async_add_devices(entities) + async_add_entities(entities) class MicrosoftFaceIdentifyEntity(ImageProcessingFaceEntity): diff --git a/homeassistant/components/image_processing/openalpr_cloud.py b/homeassistant/components/image_processing/openalpr_cloud.py index dbf36dcd86e..3daaeb6fa01 100644 --- a/homeassistant/components/image_processing/openalpr_cloud.py +++ b/homeassistant/components/image_processing/openalpr_cloud.py @@ -49,7 +49,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the OpenALPR cloud API platform.""" confidence = config[CONF_CONFIDENCE] params = { @@ -65,7 +66,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): camera[CONF_ENTITY_ID], params, confidence, camera.get(CONF_NAME) )) - async_add_devices(entities) + async_add_entities(entities) class OpenAlprCloudEntity(ImageProcessingAlprEntity): diff --git a/homeassistant/components/image_processing/openalpr_local.py b/homeassistant/components/image_processing/openalpr_local.py index 227e3269628..901533d1da4 100644 --- a/homeassistant/components/image_processing/openalpr_local.py +++ b/homeassistant/components/image_processing/openalpr_local.py @@ -56,7 +56,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the OpenALPR local platform.""" command = [config[CONF_ALPR_BIN], '-c', config[CONF_REGION], '-'] confidence = config[CONF_CONFIDENCE] @@ -67,7 +68,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): camera[CONF_ENTITY_ID], command, confidence, camera.get(CONF_NAME) )) - async_add_devices(entities) + async_add_entities(entities) class ImageProcessingAlprEntity(ImageProcessingEntity): diff --git a/homeassistant/components/image_processing/opencv.py b/homeassistant/components/image_processing/opencv.py index e21ddbe2597..1e5d38b638e 100644 --- a/homeassistant/components/image_processing/opencv.py +++ b/homeassistant/components/image_processing/opencv.py @@ -80,7 +80,7 @@ def _get_default_classifier(dest_path): fil.write(chunk) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the OpenCV image processing platform.""" try: # Verify that the OpenCV python package is pre-installed @@ -105,7 +105,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass, camera[CONF_ENTITY_ID], camera.get(CONF_NAME), config[CONF_CLASSIFIER])) - add_devices(entities) + add_entities(entities) class OpenCVImageProcessor(ImageProcessingEntity): diff --git a/homeassistant/components/image_processing/seven_segments.py b/homeassistant/components/image_processing/seven_segments.py index b49739bcec3..fb6f41b4a49 100644 --- a/homeassistant/components/image_processing/seven_segments.py +++ b/homeassistant/components/image_processing/seven_segments.py @@ -45,7 +45,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Seven segments OCR platform.""" entities = [] for camera in config[CONF_SOURCE]: @@ -53,7 +54,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass, camera[CONF_ENTITY_ID], config, camera.get(CONF_NAME) )) - async_add_devices(entities) + async_add_entities(entities) class ImageProcessingSsocr(ImageProcessingEntity): diff --git a/homeassistant/components/light/abode.py b/homeassistant/components/light/abode.py index 431f5d12ff0..69314b63a4b 100644 --- a/homeassistant/components/light/abode.py +++ b/homeassistant/components/light/abode.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['abode'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Abode light devices.""" import abodepy.helpers.constants as CONST @@ -37,7 +37,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(devices) - add_devices(devices) + add_entities(devices) class AbodeLight(AbodeDevice, Light): diff --git a/homeassistant/components/light/ads.py b/homeassistant/components/light/ads.py index 41709a4692b..65569f6b2d5 100644 --- a/homeassistant/components/light/ads.py +++ b/homeassistant/components/light/ads.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the light platform for ADS.""" ads_hub = hass.data.get(DATA_ADS) @@ -34,8 +34,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ads_var_brightness = config.get(CONF_ADS_VAR_BRIGHTNESS) name = config.get(CONF_NAME) - add_devices([AdsLight(ads_hub, ads_var_enable, ads_var_brightness, - name)], True) + add_entities([AdsLight(ads_hub, ads_var_enable, ads_var_brightness, + name)], True) class AdsLight(Light): diff --git a/homeassistant/components/light/avion.py b/homeassistant/components/light/avion.py index be608ea4776..d6e6776ea41 100644 --- a/homeassistant/components/light/avion.py +++ b/homeassistant/components/light/avion.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an Avion switch.""" # pylint: disable=no-member import avion @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device['address'] = address lights.append(AvionLight(device)) - add_devices(lights) + add_entities(lights) class AvionLight(Light): diff --git a/homeassistant/components/light/blinksticklight.py b/homeassistant/components/light/blinksticklight.py index bca587074b0..e145005a5a7 100644 --- a/homeassistant/components/light/blinksticklight.py +++ b/homeassistant/components/light/blinksticklight.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Blinkstick device specified by serial number.""" from blinkstick import blinkstick @@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): stick = blinkstick.find_by_serial(serial) - add_devices([BlinkStickLight(stick, name)], True) + add_entities([BlinkStickLight(stick, name)], True) class BlinkStickLight(Light): diff --git a/homeassistant/components/light/blinkt.py b/homeassistant/components/light/blinkt.py index 7035320945a..d8f819492a5 100644 --- a/homeassistant/components/light/blinkt.py +++ b/homeassistant/components/light/blinkt.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Blinkt Light platform.""" # pylint: disable=no-member import blinkt @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = config.get(CONF_NAME) - add_devices([ + add_entities([ BlinktLight(blinkt, name, index) for index in range(blinkt.NUM_PIXELS) ]) diff --git a/homeassistant/components/light/deconz.py b/homeassistant/components/light/deconz.py index 8aacac323b8..6dce6b7fdb8 100644 --- a/homeassistant/components/light/deconz.py +++ b/homeassistant/components/light/deconz.py @@ -19,13 +19,13 @@ import homeassistant.util.color as color_util DEPENDENCIES = ['deconz'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ lights and group.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ lights and groups from a config entry.""" @callback def async_add_light(lights): @@ -34,7 +34,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): for light in lights: if light.type not in SWITCH_TYPES: entities.append(DeconzLight(light)) - async_add_devices(entities, True) + async_add_entities(entities, True) hass.data[DATA_DECONZ_UNSUB].append( async_dispatcher_connect(hass, 'deconz_new_light', async_add_light)) @@ -47,7 +47,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): for group in groups: if group.lights and allow_group: entities.append(DeconzLight(group)) - async_add_devices(entities, True) + async_add_entities(entities, True) hass.data[DATA_DECONZ_UNSUB].append( async_dispatcher_connect(hass, 'deconz_new_group', async_add_group)) diff --git a/homeassistant/components/light/decora.py b/homeassistant/components/light/decora.py index 85d9180c59b..5de8e03aea5 100644 --- a/homeassistant/components/light/decora.py +++ b/homeassistant/components/light/decora.py @@ -56,7 +56,7 @@ def retry(method): return wrapper_retry -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an Decora switch.""" lights = [] for address, device_config in config[CONF_DEVICES].items(): @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): light = DecoraLight(device) lights.append(light) - add_devices(lights) + add_entities(lights) class DecoraLight(Light): diff --git a/homeassistant/components/light/decora_wifi.py b/homeassistant/components/light/decora_wifi.py index 17003d51610..da7ccfb2db2 100644 --- a/homeassistant/components/light/decora_wifi.py +++ b/homeassistant/components/light/decora_wifi.py @@ -34,7 +34,7 @@ NOTIFICATION_ID = 'leviton_notification' NOTIFICATION_TITLE = 'myLeviton Decora Setup' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Decora WiFi platform.""" # pylint: disable=import-error, no-name-in-module from decora_wifi import DecoraWiFiSession @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for switch in residence.get_iot_switches(): all_switches.append(switch) - add_devices(DecoraWifiLight(sw) for sw in all_switches) + add_entities(DecoraWifiLight(sw) for sw in all_switches) except ValueError: _LOGGER.error('Failed to communicate with myLeviton Service.') diff --git a/homeassistant/components/light/demo.py b/homeassistant/components/light/demo.py index ba27cbd3ac5..980d8491744 100644 --- a/homeassistant/components/light/demo.py +++ b/homeassistant/components/light/demo.py @@ -24,9 +24,9 @@ SUPPORT_DEMO = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_EFFECT | SUPPORT_COLOR | SUPPORT_WHITE_VALUE) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up the demo light platform.""" - add_devices_callback([ + add_entities_callback([ DemoLight(1, "Bed Light", False, True, effect_list=LIGHT_EFFECT_LIST, effect=LIGHT_EFFECT_LIST[0]), DemoLight(2, "Ceiling Lights", True, True, diff --git a/homeassistant/components/light/enocean.py b/homeassistant/components/light/enocean.py index beb9094b1cb..ebe2c409796 100644 --- a/homeassistant/components/light/enocean.py +++ b/homeassistant/components/light/enocean.py @@ -32,13 +32,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the EnOcean light platform.""" sender_id = config.get(CONF_SENDER_ID) devname = config.get(CONF_NAME) dev_id = config.get(CONF_ID) - add_devices([EnOceanLight(sender_id, devname, dev_id)]) + add_entities([EnOceanLight(sender_id, devname, dev_id)]) class EnOceanLight(enocean.EnOceanDevice, Light): diff --git a/homeassistant/components/light/eufy.py b/homeassistant/components/light/eufy.py index 2e7370cb336..7a44a58cd81 100644 --- a/homeassistant/components/light/eufy.py +++ b/homeassistant/components/light/eufy.py @@ -24,11 +24,11 @@ EUFY_MAX_KELVIN = 6500 EUFY_MIN_KELVIN = 2700 -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Eufy bulbs.""" if discovery_info is None: return - add_devices([EufyLight(discovery_info)], True) + add_entities([EufyLight(discovery_info)], True) class EufyLight(Light): diff --git a/homeassistant/components/light/flux_led.py b/homeassistant/components/light/flux_led.py index 2b53fb65054..f389d34cd5d 100644 --- a/homeassistant/components/light/flux_led.py +++ b/homeassistant/components/light/flux_led.py @@ -99,7 +99,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Flux lights.""" import flux_led lights = [] @@ -116,7 +116,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): light_ips.append(ipaddr) if not config.get(CONF_AUTOMATIC_ADD, False): - add_devices(lights, True) + add_entities(lights, True) return # Find the bulbs on the LAN @@ -132,7 +132,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): light = FluxLight(device) lights.append(light) - add_devices(lights, True) + add_entities(lights, True) class FluxLight(Light): diff --git a/homeassistant/components/light/futurenow.py b/homeassistant/components/light/futurenow.py index 1777376881e..8b0a809b667 100644 --- a/homeassistant/components/light/futurenow.py +++ b/homeassistant/components/light/futurenow.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the light platform for each FutureNow unit.""" lights = [] for channel, device_config in config[CONF_DEVICES].items(): @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device['port'] = config[CONF_PORT] lights.append(FutureNowLight(device)) - add_devices(lights, True) + add_entities(lights, True) def to_futurenow_level(level): diff --git a/homeassistant/components/light/greenwave.py b/homeassistant/components/light/greenwave.py index 52a70532005..0c484a0e3f4 100644 --- a/homeassistant/components/light/greenwave.py +++ b/homeassistant/components/light/greenwave.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Greenwave Reality Platform.""" import greenwavereality as greenwave import os @@ -51,8 +51,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): else: token = None bulbs = greenwave.grab_bulbs(host, token) - add_devices(GreenwaveLight(device, host, token, GatewayData(host, token)) - for device in bulbs.values()) + add_entities(GreenwaveLight(device, host, token, GatewayData(host, token)) + for device in bulbs.values()) class GreenwaveLight(Light): diff --git a/homeassistant/components/light/group.py b/homeassistant/components/light/group.py index c8b7e98160b..bf54d3ecf29 100644 --- a/homeassistant/components/light/group.py +++ b/homeassistant/components/light/group.py @@ -41,10 +41,11 @@ SUPPORT_GROUP_LIGHT = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_EFFECT async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info=None) -> None: + async_add_entities, + discovery_info=None) -> None: """Initialize light.group platform.""" - async_add_devices([LightGroup(config.get(CONF_NAME), - config[CONF_ENTITIES])]) + async_add_entities([LightGroup(config.get(CONF_NAME), + config[CONF_ENTITIES])]) class LightGroup(light.Light): diff --git a/homeassistant/components/light/hive.py b/homeassistant/components/light/hive.py index 1fd9e8aaaca..eada16bbab9 100644 --- a/homeassistant/components/light/hive.py +++ b/homeassistant/components/light/hive.py @@ -15,13 +15,13 @@ import homeassistant.util.color as color_util DEPENDENCIES = ['hive'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Hive light devices.""" if discovery_info is None: return session = hass.data.get(DATA_HIVE) - add_devices([HiveDeviceLight(session, discovery_info)]) + add_entities([HiveDeviceLight(session, discovery_info)]) class HiveDeviceLight(Light): diff --git a/homeassistant/components/light/homekit_controller.py b/homeassistant/components/light/homekit_controller.py index 8d77cb05236..dd24e3cfb2e 100644 --- a/homeassistant/components/light/homekit_controller.py +++ b/homeassistant/components/light/homekit_controller.py @@ -17,11 +17,11 @@ DEPENDENCIES = ['homekit_controller'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Homekit lighting.""" if discovery_info is not None: accessory = hass.data[KNOWN_ACCESSORIES][discovery_info['serial']] - add_devices([HomeKitLight(accessory, discovery_info)], True) + add_entities([HomeKitLight(accessory, discovery_info)], True) class HomeKitLight(HomeKitEntity, Light): diff --git a/homeassistant/components/light/homematic.py b/homeassistant/components/light/homematic.py index 2d7c855c538..9a7baa713a3 100644 --- a/homeassistant/components/light/homematic.py +++ b/homeassistant/components/light/homematic.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['homematic'] SUPPORT_HOMEMATIC = SUPPORT_BRIGHTNESS -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Homematic light platform.""" if discovery_info is None: return @@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = HMLight(conf) devices.append(new_device) - add_devices(devices) + add_entities(devices) class HMLight(HMDevice, Light): diff --git a/homeassistant/components/light/homematicip_cloud.py b/homeassistant/components/light/homematicip_cloud.py index f958879386d..764ead62169 100644 --- a/homeassistant/components/light/homematicip_cloud.py +++ b/homeassistant/components/light/homematicip_cloud.py @@ -22,12 +22,12 @@ ATTR_PROFILE_MODE = 'profile_mode' async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Old way of setting up HomematicIP Cloud lights.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP Cloud lights from a config entry.""" from homematicip.aio.device import AsyncBrandSwitchMeasuring, AsyncDimmer @@ -40,7 +40,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): devices.append(HomematicipDimmer(home, device)) if devices: - async_add_devices(devices) + async_add_entities(devices) class HomematicipLight(HomematicipGenericDevice, Light): diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 0da59b6f100..2a51423a7a8 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -47,7 +47,7 @@ ATTR_IS_HUE_GROUP = 'is_hue_group' GROUP_MIN_API_VERSION = (1, 13, 0) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up Hue lights. @@ -57,7 +57,7 @@ async def async_setup_platform(hass, config, async_add_devices, pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the Hue lights from a config entry.""" bridge = hass.data[hue.DOMAIN][config_entry.data['host']] cur_lights = {} @@ -137,13 +137,13 @@ async def async_setup_entry(hass, config_entry, async_add_devices): """ tasks = [] tasks.append(async_update_items( - hass, bridge, async_add_devices, request_update, + hass, bridge, async_add_entities, request_update, False, cur_lights, light_progress )) if allow_groups: tasks.append(async_update_items( - hass, bridge, async_add_devices, request_update, + hass, bridge, async_add_entities, request_update, True, cur_groups, group_progress )) @@ -152,7 +152,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): await update_bridge() -async def async_update_items(hass, bridge, async_add_devices, +async def async_update_items(hass, bridge, async_add_entities, request_bridge_update, is_group, current, progress_waiting): """Update either groups or lights from the bridge.""" @@ -195,7 +195,7 @@ async def async_update_items(hass, bridge, async_add_devices, current[item_id].async_schedule_update_ha_state() if new_lights: - async_add_devices(new_lights) + async_add_entities(new_lights) class HueLight(Light): diff --git a/homeassistant/components/light/hyperion.py b/homeassistant/components/light/hyperion.py index cbac8cf4e20..16be7d45825 100644 --- a/homeassistant/components/light/hyperion.py +++ b/homeassistant/components/light/hyperion.py @@ -59,7 +59,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Hyperion server remote.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -72,7 +72,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): default_color, hdmi_priority, effect_list) if device.setup(): - add_devices([device]) + add_entities([device]) return True return False diff --git a/homeassistant/components/light/iglo.py b/homeassistant/components/light/iglo.py index f40dc2ce84e..9dca5f8e5f5 100644 --- a/homeassistant/components/light/iglo.py +++ b/homeassistant/components/light/iglo.py @@ -31,12 +31,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the iGlo lights.""" host = config.get(CONF_HOST) name = config.get(CONF_NAME) port = config.get(CONF_PORT) - add_devices([IGloLamp(name, host, port)], True) + add_entities([IGloLamp(name, host, port)], True) class IGloLamp(Light): diff --git a/homeassistant/components/light/ihc.py b/homeassistant/components/light/ihc.py index 480cfa7ad94..da90a53c848 100644 --- a/homeassistant/components/light/ihc.py +++ b/homeassistant/components/light/ihc.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC lights platform.""" ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] info = hass.data[IHC_DATA][IHC_INFO] @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device = IhcLight(ihc_controller, name, ihc_id, info, dimmable) devices.append(device) - add_devices(devices) + add_entities(devices) class IhcLight(IHCDevice, Light): diff --git a/homeassistant/components/light/insteon.py b/homeassistant/components/light/insteon.py index 88a9ab01de5..82f455c821e 100644 --- a/homeassistant/components/light/insteon.py +++ b/homeassistant/components/light/insteon.py @@ -19,7 +19,8 @@ MAX_BRIGHTNESS = 255 @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Insteon component.""" insteon_modem = hass.data['insteon'].get('modem') @@ -32,7 +33,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): new_entity = InsteonDimmerDevice(device, state_key) - async_add_devices([new_entity]) + async_add_entities([new_entity]) class InsteonDimmerDevice(InsteonEntity, Light): diff --git a/homeassistant/components/light/isy994.py b/homeassistant/components/light/isy994.py index ce358d0a974..06507eaeca6 100644 --- a/homeassistant/components/light/isy994.py +++ b/homeassistant/components/light/isy994.py @@ -16,13 +16,13 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the ISY994 light platform.""" devices = [] for node in hass.data[ISY994_NODES][DOMAIN]: devices.append(ISYLightDevice(node)) - add_devices(devices) + add_entities(devices) class ISYLightDevice(ISYDevice, Light): diff --git a/homeassistant/components/light/knx.py b/homeassistant/components/light/knx.py index ee8389fbb71..23929db8626 100644 --- a/homeassistant/components/light/knx.py +++ b/homeassistant/components/light/knx.py @@ -37,27 +37,27 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up lights for KNX platform.""" if discovery_info is not None: - async_add_devices_discovery(hass, discovery_info, async_add_devices) + async_add_entities_discovery(hass, discovery_info, async_add_entities) else: - async_add_devices_config(hass, config, async_add_devices) + async_add_entities_config(hass, config, async_add_entities) @callback -def async_add_devices_discovery(hass, discovery_info, async_add_devices): +def async_add_entities_discovery(hass, discovery_info, async_add_entities): """Set up lights for KNX platform configured via xknx.yaml.""" entities = [] for device_name in discovery_info[ATTR_DISCOVER_DEVICES]: device = hass.data[DATA_KNX].xknx.devices[device_name] entities.append(KNXLight(hass, device)) - async_add_devices(entities) + async_add_entities(entities) @callback -def async_add_devices_config(hass, config, async_add_devices): +def async_add_entities_config(hass, config, async_add_entities): """Set up light for KNX platform configured within platform.""" import xknx light = xknx.devices.Light( @@ -71,7 +71,7 @@ def async_add_devices_config(hass, config, async_add_devices): group_address_color=config.get(CONF_COLOR_ADDRESS), group_address_color_state=config.get(CONF_COLOR_STATE_ADDRESS)) hass.data[DATA_KNX].xknx.devices.add(light) - async_add_devices([KNXLight(hass, light)]) + async_add_entities([KNXLight(hass, light)]) class KNXLight(Light): diff --git a/homeassistant/components/light/lifx.py b/homeassistant/components/light/lifx.py index 8547d7a985d..cf5d6fef704 100644 --- a/homeassistant/components/light/lifx.py +++ b/homeassistant/components/light/lifx.py @@ -136,7 +136,7 @@ def aiolifx_effects(): async def async_setup_platform(hass, config, - async_add_devices, + async_add_entities, discovery_info=None): """Set up the LIFX platform.""" if sys.platform == 'win32': @@ -145,7 +145,7 @@ async def async_setup_platform(hass, server_addr = config.get(CONF_SERVER) - lifx_manager = LIFXManager(hass, async_add_devices) + lifx_manager = LIFXManager(hass, async_add_entities) lifx_discovery = aiolifx().LifxDiscovery( hass.loop, lifx_manager, @@ -207,11 +207,11 @@ def merge_hsbk(base, change): class LIFXManager: """Representation of all known LIFX entities.""" - def __init__(self, hass, async_add_devices): + def __init__(self, hass, async_add_entities): """Initialize the light.""" self.entities = {} self.hass = hass - self.async_add_devices = async_add_devices + self.async_add_entities = async_add_entities self.effects_conductor = aiolifx_effects().Conductor(loop=hass.loop) self.register_set_state() @@ -335,7 +335,7 @@ class LIFXManager: _LOGGER.debug("%s register READY", entity.who) self.entities[device.mac_addr] = entity - self.async_add_devices([entity], True) + self.async_add_entities([entity], True) @callback def unregister(self, device): diff --git a/homeassistant/components/light/lifx_legacy.py b/homeassistant/components/light/lifx_legacy.py index 3ad75a1cea4..6c5f68937f8 100644 --- a/homeassistant/components/light/lifx_legacy.py +++ b/homeassistant/components/light/lifx_legacy.py @@ -45,12 +45,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LIFX platform.""" server_addr = config.get(CONF_SERVER) broadcast_addr = config.get(CONF_BROADCAST) - lifx_library = LIFX(add_devices, server_addr, broadcast_addr) + lifx_library = LIFX(add_entities, server_addr, broadcast_addr) # Register our poll service track_time_change(hass, lifx_library.poll, second=[10, 40]) @@ -61,14 +61,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class LIFX: """Representation of a LIFX light.""" - def __init__(self, add_devices_callback, server_addr=None, + def __init__(self, add_entities_callback, server_addr=None, broadcast_addr=None): """Initialize the light.""" import liffylights self._devices = [] - self._add_devices_callback = add_devices_callback + self._add_entities_callback = add_entities_callback self._liffylights = liffylights.LiffyLights( self.on_device, self.on_power, self.on_color, server_addr, @@ -93,7 +93,7 @@ class LIFX: bulb = LIFXLight( self._liffylights, ipaddr, name, power, hue, sat, bri, kel) self._devices.append(bulb) - self._add_devices_callback([bulb]) + self._add_entities_callback([bulb]) else: _LOGGER.debug("update bulb %s %s %d %d %d %d %d", ipaddr, name, power, hue, sat, bri, kel) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index ded58248d8e..9400932802a 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -104,7 +104,7 @@ def rewrite_legacy(config): return {'bridges': new_bridges} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LimitlessLED lights.""" from limitlessled.bridge import Bridge @@ -126,7 +126,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): lights.append(LimitlessLEDGroup(group, { 'fade': group_conf[CONF_FADE] })) - add_devices(lights) + add_entities(lights) def state(new_state): diff --git a/homeassistant/components/light/litejet.py b/homeassistant/components/light/litejet.py index b8491b6f0f5..8662afc668e 100644 --- a/homeassistant/components/light/litejet.py +++ b/homeassistant/components/light/litejet.py @@ -17,7 +17,7 @@ DEPENDENCIES = ['litejet'] ATTR_NUMBER = 'number' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up lights for the LiteJet platform.""" litejet_ = hass.data['litejet_system'] @@ -26,7 +26,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = litejet_.get_load_name(i) if not litejet.is_ignored(hass, name): devices.append(LiteJetLight(hass, litejet_, i, name)) - add_devices(devices, True) + add_entities(devices, True) class LiteJetLight(Light): diff --git a/homeassistant/components/light/lutron.py b/homeassistant/components/light/lutron.py index 24744110c6f..6c4047e2314 100644 --- a/homeassistant/components/light/lutron.py +++ b/homeassistant/components/light/lutron.py @@ -16,14 +16,14 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['lutron'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Lutron lights.""" devs = [] for (area_name, device) in hass.data[LUTRON_DEVICES]['light']: dev = LutronLight(area_name, device, hass.data[LUTRON_CONTROLLER]) devs.append(dev) - add_devices(devs, True) + add_entities(devs, True) return True diff --git a/homeassistant/components/light/lutron_caseta.py b/homeassistant/components/light/lutron_caseta.py index 29186b8fcd2..f345748683b 100644 --- a/homeassistant/components/light/lutron_caseta.py +++ b/homeassistant/components/light/lutron_caseta.py @@ -20,7 +20,8 @@ DEPENDENCIES = ['lutron_caseta'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Lutron Caseta lights.""" devs = [] bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] @@ -29,7 +30,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): dev = LutronCasetaLight(light_device, bridge) devs.append(dev) - async_add_devices(devs, True) + async_add_entities(devs, True) class LutronCasetaLight(LutronCasetaDevice, Light): diff --git a/homeassistant/components/light/lw12wifi.py b/homeassistant/components/light/lw12wifi.py index 46bebe8086f..71716b4130d 100644 --- a/homeassistant/components/light/lw12wifi.py +++ b/homeassistant/components/light/lw12wifi.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up LW-12 WiFi LED Controller platform.""" import lw12 @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): port = config.get(CONF_PORT) # Add devices lw12_light = lw12.LW12Controller(host, port) - add_devices([LW12WiFi(name, lw12_light)]) + add_entities([LW12WiFi(name, lw12_light)]) class LW12WiFi(Light): diff --git a/homeassistant/components/light/mochad.py b/homeassistant/components/light/mochad.py index 4aeb2c2c79b..2e68c369ba6 100644 --- a/homeassistant/components/light/mochad.py +++ b/homeassistant/components/light/mochad.py @@ -34,10 +34,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up X10 dimmers over a mochad controller.""" devs = config.get(CONF_DEVICES) - add_devices([MochadLight( + add_entities([MochadLight( hass, mochad.CONTROLLER.ctrl, dev) for dev in devs]) return True diff --git a/homeassistant/components/light/mqtt.py b/homeassistant/components/light/mqtt.py index 09fa094c1b2..225f0f510ad 100644 --- a/homeassistant/components/light/mqtt.py +++ b/homeassistant/components/light/mqtt.py @@ -100,7 +100,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up a MQTT Light.""" if discovery_info is not None: @@ -109,7 +109,7 @@ async def async_setup_platform(hass, config, async_add_devices, config.setdefault( CONF_STATE_VALUE_TEMPLATE, config.get(CONF_VALUE_TEMPLATE)) - async_add_devices([MqttLight( + async_add_entities([MqttLight( config.get(CONF_NAME), config.get(CONF_EFFECT_LIST), { diff --git a/homeassistant/components/light/mqtt_json.py b/homeassistant/components/light/mqtt_json.py index d17c7dd73bf..239c924ed2b 100644 --- a/homeassistant/components/light/mqtt_json.py +++ b/homeassistant/components/light/mqtt_json.py @@ -81,11 +81,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info=None): + async_add_entities, discovery_info=None): """Set up a MQTT JSON Light.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) - async_add_devices([MqttJson( + async_add_entities([MqttJson( config.get(CONF_NAME), config.get(CONF_EFFECT_LIST), { diff --git a/homeassistant/components/light/mqtt_template.py b/homeassistant/components/light/mqtt_template.py index ffa73aca915..72cfd6b678c 100644 --- a/homeassistant/components/light/mqtt_template.py +++ b/homeassistant/components/light/mqtt_template.py @@ -66,13 +66,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up a MQTT Template light.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) - async_add_devices([MqttTemplate( + async_add_entities([MqttTemplate( hass, config.get(CONF_NAME), config.get(CONF_EFFECT_LIST), diff --git a/homeassistant/components/light/mysensors.py b/homeassistant/components/light/mysensors.py index 4139abd40fa..23d602c5d40 100644 --- a/homeassistant/components/light/mysensors.py +++ b/homeassistant/components/light/mysensors.py @@ -16,7 +16,7 @@ SUPPORT_MYSENSORS_RGBW = SUPPORT_COLOR | SUPPORT_WHITE_VALUE async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the mysensors platform for lights.""" device_class_map = { 'S_DIMMER': MySensorsLightDimmer, @@ -25,7 +25,7 @@ async def async_setup_platform( } mysensors.setup_mysensors_platform( hass, DOMAIN, discovery_info, device_class_map, - async_add_devices=async_add_devices) + async_add_entities=async_add_entities) class MySensorsLight(mysensors.device.MySensorsEntity, Light): diff --git a/homeassistant/components/light/mystrom.py b/homeassistant/components/light/mystrom.py index 5d4cdcc17d4..8060bef0fa8 100644 --- a/homeassistant/components/light/mystrom.py +++ b/homeassistant/components/light/mystrom.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the myStrom Light platform.""" from pymystrom.bulb import MyStromBulb from pymystrom.exceptions import MyStromConnectionError @@ -58,7 +58,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except MyStromConnectionError: _LOGGER.warning("No route to device: %s", host) - add_devices([MyStromLight(bulb, name)], True) + add_entities([MyStromLight(bulb, name)], True) class MyStromLight(Light): diff --git a/homeassistant/components/light/nanoleaf_aurora.py b/homeassistant/components/light/nanoleaf_aurora.py index 6a0d3c36e9f..6d9c1a50f79 100644 --- a/homeassistant/components/light/nanoleaf_aurora.py +++ b/homeassistant/components/light/nanoleaf_aurora.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Nanoleaf Aurora device.""" import nanoleaf import nanoleaf.setup @@ -83,7 +83,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return hass.data[DATA_NANOLEAF_AURORA][host] = aurora_light - add_devices([AuroraLight(aurora_light, name)], True) + add_entities([AuroraLight(aurora_light, name)], True) class AuroraLight(Light): diff --git a/homeassistant/components/light/osramlightify.py b/homeassistant/components/light/osramlightify.py index 939d0fe6988..244a233c517 100644 --- a/homeassistant/components/light/osramlightify.py +++ b/homeassistant/components/light/osramlightify.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Osram Lightify lights.""" import lightify @@ -65,10 +65,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.exception(msg) return - setup_bridge(bridge, add_devices, add_nodes, add_groups) + setup_bridge(bridge, add_entities, add_nodes, add_groups) -def setup_bridge(bridge, add_devices, add_nodes, add_groups): +def setup_bridge(bridge, add_entities, add_nodes, add_groups): """Set up the Lightify bridge.""" lights = {} @@ -106,7 +106,7 @@ def setup_bridge(bridge, add_devices, add_nodes, add_groups): lights[group_name].group = group if new_lights: - add_devices(new_lights) + add_entities(new_lights) update_lights() diff --git a/homeassistant/components/light/piglow.py b/homeassistant/components/light/piglow.py index 755cf9dca66..56c72e01fdf 100644 --- a/homeassistant/components/light/piglow.py +++ b/homeassistant/components/light/piglow.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Piglow Light platform.""" import piglow @@ -39,7 +39,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = config.get(CONF_NAME) - add_devices([PiglowLight(piglow, name)]) + add_entities([PiglowLight(piglow, name)]) class PiglowLight(Light): diff --git a/homeassistant/components/light/qwikswitch.py b/homeassistant/components/light/qwikswitch.py index 9d6e8f9169a..fa986ff09f2 100644 --- a/homeassistant/components/light/qwikswitch.py +++ b/homeassistant/components/light/qwikswitch.py @@ -11,14 +11,14 @@ from homeassistant.components.light import SUPPORT_BRIGHTNESS, Light DEPENDENCIES = [QWIKSWITCH] -async def async_setup_platform(hass, _, add_devices, discovery_info=None): +async def async_setup_platform(hass, _, add_entities, discovery_info=None): """Add lights from the main Qwikswitch component.""" if discovery_info is None: return qsusb = hass.data[QWIKSWITCH] devs = [QSLight(qsid, qsusb) for qsid in discovery_info[QWIKSWITCH]] - add_devices(devs) + add_entities(devs) class QSLight(QSToggleEntity, Light): diff --git a/homeassistant/components/light/rflink.py b/homeassistant/components/light/rflink.py index a05822ed8d1..b410fdceff7 100644 --- a/homeassistant/components/light/rflink.py +++ b/homeassistant/components/light/rflink.py @@ -156,9 +156,10 @@ def devices_from_config(domain_config, hass=None): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Rflink light platform.""" - async_add_devices(devices_from_config(config, hass)) + async_add_entities(devices_from_config(config, hass)) @asyncio.coroutine def add_new_device(event): @@ -170,7 +171,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): device_config = config[CONF_DEVICE_DEFAULTS] device = entity_class(device_id, hass, **device_config) - async_add_devices([device]) + async_add_entities([device]) # Register entity to listen to incoming Rflink events hass.data[DATA_ENTITY_LOOKUP][ diff --git a/homeassistant/components/light/rfxtrx.py b/homeassistant/components/light/rfxtrx.py index 293783ee3ab..10288773486 100644 --- a/homeassistant/components/light/rfxtrx.py +++ b/homeassistant/components/light/rfxtrx.py @@ -36,12 +36,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ SUPPORT_RFXTRX = SUPPORT_BRIGHTNESS -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the RFXtrx platform.""" import RFXtrx as rfxtrxmod lights = rfxtrx.get_devices_from_config(config, RfxtrxLight) - add_devices(lights) + add_entities(lights) def light_update(event): """Handle light updates from the RFXtrx gateway.""" @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = rfxtrx.get_new_device(event, config, RfxtrxLight) if new_device: - add_devices([new_device]) + add_entities([new_device]) rfxtrx.apply_received_command(event) diff --git a/homeassistant/components/light/rpi_gpio_pwm.py b/homeassistant/components/light/rpi_gpio_pwm.py index 9385c4bfb80..5a0e0546b1f 100644 --- a/homeassistant/components/light/rpi_gpio_pwm.py +++ b/homeassistant/components/light/rpi_gpio_pwm.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PWM LED lights.""" from pwmled.led import SimpleLed from pwmled.led.rgb import RgbLed @@ -92,7 +92,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return leds.append(led) - add_devices(leds) + add_entities(leds) class PwmSimpleLed(Light): diff --git a/homeassistant/components/light/scsgate.py b/homeassistant/components/light/scsgate.py index 3d567afe09e..4a18bc99672 100644 --- a/homeassistant/components/light/scsgate.py +++ b/homeassistant/components/light/scsgate.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SCSGate switches.""" devices = config.get(CONF_DEVICES) lights = [] @@ -42,7 +42,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): light = SCSGateLight(name=name, scs_id=scs_id, logger=logger) lights.append(light) - add_devices(lights) + add_entities(lights) scsgate.SCSGATE.add_devices_to_register(lights) diff --git a/homeassistant/components/light/sensehat.py b/homeassistant/components/light/sensehat.py index 6ab2592cedf..86153fffef8 100644 --- a/homeassistant/components/light/sensehat.py +++ b/homeassistant/components/light/sensehat.py @@ -28,14 +28,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sense Hat Light platform.""" from sense_hat import SenseHat sensehat = SenseHat() name = config.get(CONF_NAME) - add_devices([SenseHatLight(sensehat, name)]) + add_entities([SenseHatLight(sensehat, name)]) class SenseHatLight(Light): diff --git a/homeassistant/components/light/sisyphus.py b/homeassistant/components/light/sisyphus.py index ded78716317..75cc86a0154 100644 --- a/homeassistant/components/light/sisyphus.py +++ b/homeassistant/components/light/sisyphus.py @@ -17,10 +17,10 @@ DEPENDENCIES = ['sisyphus'] SUPPORTED_FEATURES = SUPPORT_BRIGHTNESS -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a single Sisyphus table.""" name = discovery_info[CONF_NAME] - add_devices( + add_entities( [SisyphusLight(name, hass.data[DATA_SISYPHUS][name])], update_before_add=True) diff --git a/homeassistant/components/light/skybell.py b/homeassistant/components/light/skybell.py index d32183f1468..ecb240f2ef3 100644 --- a/homeassistant/components/light/skybell.py +++ b/homeassistant/components/light/skybell.py @@ -19,7 +19,7 @@ DEPENDENCIES = ['skybell'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform for a Skybell device.""" skybell = hass.data.get(SKYBELL_DOMAIN) @@ -27,7 +27,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in skybell.get_devices(): sensors.append(SkybellLight(device)) - add_devices(sensors, True) + add_entities(sensors, True) def _to_skybell_level(level): diff --git a/homeassistant/components/light/tellduslive.py b/homeassistant/components/light/tellduslive.py index 3908d43f62d..6f39fb3b318 100644 --- a/homeassistant/components/light/tellduslive.py +++ b/homeassistant/components/light/tellduslive.py @@ -15,11 +15,11 @@ from homeassistant.components.tellduslive import TelldusLiveEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tellstick Net lights.""" if discovery_info is None: return - add_devices(TelldusLiveLight(hass, light) for light in discovery_info) + add_entities(TelldusLiveLight(hass, light) for light in discovery_info) class TelldusLiveLight(TelldusLiveEntity, Light): diff --git a/homeassistant/components/light/tellstick.py b/homeassistant/components/light/tellstick.py index 44e5e40b3b7..cf9dd545e99 100644 --- a/homeassistant/components/light/tellstick.py +++ b/homeassistant/components/light/tellstick.py @@ -15,7 +15,7 @@ from homeassistant.components.tellstick import ( SUPPORT_TELLSTICK = SUPPORT_BRIGHTNESS -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tellstick lights.""" if (discovery_info is None or discovery_info[ATTR_DISCOVER_DEVICES] is None): @@ -24,10 +24,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): signal_repetitions = discovery_info.get( ATTR_DISCOVER_CONFIG, DEFAULT_SIGNAL_REPETITIONS) - add_devices([TellstickLight(hass.data[DATA_TELLSTICK][tellcore_id], - signal_repetitions) - for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]], - True) + add_entities([TellstickLight(hass.data[DATA_TELLSTICK][tellcore_id], + signal_repetitions) + for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]], + True) class TellstickLight(TellstickDevice, Light): diff --git a/homeassistant/components/light/template.py b/homeassistant/components/light/template.py index ad77b734fbb..9be6eb99acc 100644 --- a/homeassistant/components/light/template.py +++ b/homeassistant/components/light/template.py @@ -50,7 +50,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Template Lights.""" lights = [] @@ -103,7 +104,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.error("No lights added") return False - async_add_devices(lights) + async_add_entities(lights) return True diff --git a/homeassistant/components/light/tikteck.py b/homeassistant/components/light/tikteck.py index c21da57ea96..64b4069d98e 100644 --- a/homeassistant/components/light/tikteck.py +++ b/homeassistant/components/light/tikteck.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tikteck platform.""" lights = [] for address, device_config in config[CONF_DEVICES].items(): @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if light.is_valid: lights.append(light) - add_devices(lights) + add_entities(lights) class TikteckLight(Light): diff --git a/homeassistant/components/light/tplink.py b/homeassistant/components/light/tplink.py index 9374c1418f0..a1e46c07d7d 100644 --- a/homeassistant/components/light/tplink.py +++ b/homeassistant/components/light/tplink.py @@ -35,12 +35,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, 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) + add_entities([TPLinkSmartBulb(SmartBulb(host), name)], True) def brightness_to_percentage(byt): diff --git a/homeassistant/components/light/tradfri.py b/homeassistant/components/light/tradfri.py index c30745239ea..0d12d095bb6 100644 --- a/homeassistant/components/light/tradfri.py +++ b/homeassistant/components/light/tradfri.py @@ -32,7 +32,7 @@ SUPPORTED_GROUP_FEATURES = SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION async def async_setup_platform(hass, config, - async_add_devices, discovery_info=None): + async_add_entities, discovery_info=None): """Set up the IKEA Tradfri Light platform.""" if discovery_info is None: return @@ -46,7 +46,7 @@ async def async_setup_platform(hass, config, devices = await api(devices_commands) lights = [dev for dev in devices if dev.has_light_control] if lights: - async_add_devices( + async_add_entities( TradfriLight(light, api, gateway_id) for light in lights) allow_tradfri_groups = hass.data[KEY_TRADFRI_GROUPS][gateway_id] @@ -55,7 +55,7 @@ async def async_setup_platform(hass, config, groups_commands = await api(groups_command) groups = await api(groups_commands) if groups: - async_add_devices( + async_add_entities( TradfriGroup(group, api, gateway_id) for group in groups) diff --git a/homeassistant/components/light/tuya.py b/homeassistant/components/light/tuya.py index d7691cea011..0dc2cacc1e0 100644 --- a/homeassistant/components/light/tuya.py +++ b/homeassistant/components/light/tuya.py @@ -14,7 +14,7 @@ from homeassistant.util import color as colorutil DEPENDENCIES = ['tuya'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tuya light platform.""" if discovery_info is None: return @@ -26,7 +26,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device is None: continue devices.append(TuyaLight(device)) - add_devices(devices) + add_entities(devices) class TuyaLight(TuyaDevice, Light): diff --git a/homeassistant/components/light/vera.py b/homeassistant/components/light/vera.py index e62ffaecdff..702236ac748 100644 --- a/homeassistant/components/light/vera.py +++ b/homeassistant/components/light/vera.py @@ -18,9 +18,9 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['vera'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vera lights.""" - add_devices( + add_entities( [VeraLight(device, hass.data[VERA_CONTROLLER]) for device in hass.data[VERA_DEVICES]['light']], True) diff --git a/homeassistant/components/light/wemo.py b/homeassistant/components/light/wemo.py index f07865473d1..72279fbe1a4 100644 --- a/homeassistant/components/light/wemo.py +++ b/homeassistant/components/light/wemo.py @@ -27,7 +27,7 @@ SUPPORT_WEMO = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_COLOR | SUPPORT_TRANSITION) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up discovered WeMo switches.""" from pywemo import discovery @@ -43,12 +43,12 @@ def setup_platform(hass, config, add_devices, discovery_info=None): raise PlatformNotReady if device.model_name == 'Dimmer': - add_devices([WemoDimmer(device)]) + add_entities([WemoDimmer(device)]) else: - setup_bridge(device, add_devices) + setup_bridge(device, add_entities) -def setup_bridge(bridge, add_devices): +def setup_bridge(bridge, add_entities): """Set up a WeMo link.""" lights = {} @@ -65,7 +65,7 @@ def setup_bridge(bridge, add_devices): new_lights.append(lights[light_id]) if new_lights: - add_devices(new_lights) + add_entities(new_lights) update_lights() diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py index a2cc4fd7aeb..ee8c2aca8b5 100644 --- a/homeassistant/components/light/wink.py +++ b/homeassistant/components/light/wink.py @@ -17,18 +17,18 @@ from homeassistant.util.color import \ DEPENDENCIES = ['wink'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink lights.""" import pywink for light in pywink.get_light_bulbs(): _id = light.object_id() + light.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkLight(light, hass)]) + add_entities([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)]) + add_entities([WinkLight(light, hass)]) class WinkLight(WinkDevice, Light): diff --git a/homeassistant/components/light/x10.py b/homeassistant/components/light/x10.py index e782e664801..ef2211a4469 100644 --- a/homeassistant/components/light/x10.py +++ b/homeassistant/components/light/x10.py @@ -39,7 +39,7 @@ def get_unit_status(code): return int(output.decode('utf-8')[0]) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the x10 Light platform.""" try: x10_command('info') @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error(err.output) return False - add_devices(X10Light(light) for light in config[CONF_DEVICES]) + add_entities(X10Light(light) for light in config[CONF_DEVICES]) class X10Light(Light): diff --git a/homeassistant/components/light/xiaomi_aqara.py b/homeassistant/components/light/xiaomi_aqara.py index 75c85a4bfcf..8ad0f2522d2 100644 --- a/homeassistant/components/light/xiaomi_aqara.py +++ b/homeassistant/components/light/xiaomi_aqara.py @@ -12,7 +12,7 @@ import homeassistant.util.color as color_util _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Perform the setup for Xiaomi devices.""" devices = [] for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): @@ -21,7 +21,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if model in ['gateway', 'gateway.v3']: devices.append(XiaomiGatewayLight(device, 'Gateway Light', gateway)) - add_devices(devices) + add_entities(devices) class XiaomiGatewayLight(XiaomiDevice, Light): diff --git a/homeassistant/components/light/xiaomi_miio.py b/homeassistant/components/light/xiaomi_miio.py index 2171d084bf0..51c36fc2dd0 100644 --- a/homeassistant/components/light/xiaomi_miio.py +++ b/homeassistant/components/light/xiaomi_miio.py @@ -100,7 +100,7 @@ SERVICE_TO_METHOD = { } -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the light from config.""" from miio import Device, DeviceException @@ -164,7 +164,7 @@ async def async_setup_platform(hass, config, async_add_devices, 'and provide the following data: %s', model) return False - async_add_devices(devices, update_before_add=True) + async_add_entities(devices, update_before_add=True) async def async_service_handler(service): """Map services to methods on Xiaomi Philips Lights.""" diff --git a/homeassistant/components/light/yeelight.py b/homeassistant/components/light/yeelight.py index 791de291b48..a08ebe459b4 100644 --- a/homeassistant/components/light/yeelight.py +++ b/homeassistant/components/light/yeelight.py @@ -120,7 +120,7 @@ def _cmd(func): return _wrap -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yeelight bulbs.""" from yeelight.enums import PowerMode @@ -150,7 +150,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): lights.append(light) hass.data[DATA_KEY][host] = light - add_devices(lights, True) + add_entities(lights, True) def service_handler(service): """Dispatch service calls to target entities.""" diff --git a/homeassistant/components/light/yeelightsunflower.py b/homeassistant/components/light/yeelightsunflower.py index 96cce67b1bb..2250a85c55c 100644 --- a/homeassistant/components/light/yeelightsunflower.py +++ b/homeassistant/components/light/yeelightsunflower.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yeelight Sunflower Light platform.""" import yeelightsunflower @@ -37,7 +37,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Could not connect to Yeelight Sunflower hub") return False - add_devices(SunflowerBulb(light) for light in hub.get_lights()) + add_entities(SunflowerBulb(light) for light in hub.get_lights()) class SunflowerBulb(Light): diff --git a/homeassistant/components/light/zengge.py b/homeassistant/components/light/zengge.py index 35d2bf2388c..b283b8611dc 100644 --- a/homeassistant/components/light/zengge.py +++ b/homeassistant/components/light/zengge.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Zengge platform.""" lights = [] for address, device_config in config[CONF_DEVICES].items(): @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if light.is_valid: lights.append(light) - add_devices(lights, True) + add_entities(lights, True) class ZenggeLight(Light): diff --git a/homeassistant/components/light/zha.py b/homeassistant/components/light/zha.py index bd01a513e0b..dc5c4977944 100644 --- a/homeassistant/components/light/zha.py +++ b/homeassistant/components/light/zha.py @@ -20,7 +20,7 @@ CAPABILITIES_COLOR_TEMP = 0x10 UNSUPPORTED_ATTRIBUTE = 0x86 -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Zigbee Home Automation lights.""" discovery_info = zha.get_discovery_info(hass, discovery_info) @@ -42,7 +42,7 @@ async def async_setup_platform(hass, config, async_add_devices, if result.get('color_temperature') is not UNSUPPORTED_ATTRIBUTE: discovery_info['color_capabilities'] |= CAPABILITIES_COLOR_TEMP - async_add_devices([Light(**discovery_info)], update_before_add=True) + async_add_entities([Light(**discovery_info)], update_before_add=True) class Light(zha.Entity, light.Light): diff --git a/homeassistant/components/light/zigbee.py b/homeassistant/components/light/zigbee.py index f4406abf7bd..42dc95d1163 100644 --- a/homeassistant/components/light/zigbee.py +++ b/homeassistant/components/light/zigbee.py @@ -22,9 +22,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Create and add an entity based on the configuration.""" - add_devices([ZigBeeLight(hass, ZigBeeDigitalOutConfig(config))]) + add_entities([ZigBeeLight(hass, ZigBeeDigitalOutConfig(config))]) class ZigBeeLight(ZigBeeDigitalOut, Light): diff --git a/homeassistant/components/lock/abode.py b/homeassistant/components/lock/abode.py index 2d342326636..a8777ccb503 100644 --- a/homeassistant/components/lock/abode.py +++ b/homeassistant/components/lock/abode.py @@ -15,7 +15,7 @@ DEPENDENCIES = ['abode'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Abode lock devices.""" import abodepy.helpers.constants as CONST @@ -30,7 +30,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(devices) - add_devices(devices) + add_entities(devices) class AbodeLock(AbodeDevice, LockDevice): diff --git a/homeassistant/components/lock/august.py b/homeassistant/components/lock/august.py index 9ca63cb493b..7aec3c78690 100644 --- a/homeassistant/components/lock/august.py +++ b/homeassistant/components/lock/august.py @@ -15,7 +15,7 @@ DEPENDENCIES = ['august'] SCAN_INTERVAL = timedelta(seconds=5) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up August locks.""" data = hass.data[DATA_AUGUST] devices = [] @@ -23,7 +23,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for lock in data.locks: devices.append(AugustLock(data, lock)) - add_devices(devices, True) + add_entities(devices, True) class AugustLock(LockDevice): diff --git a/homeassistant/components/lock/bmw_connected_drive.py b/homeassistant/components/lock/bmw_connected_drive.py index e48fd1af3c3..c84df54cfba 100644 --- a/homeassistant/components/lock/bmw_connected_drive.py +++ b/homeassistant/components/lock/bmw_connected_drive.py @@ -16,7 +16,7 @@ DEPENDENCIES = ['bmw_connected_drive'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the BMW Connected Drive lock.""" accounts = hass.data[BMW_DOMAIN] _LOGGER.debug('Found BMW accounts: %s', @@ -27,7 +27,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for vehicle in account.account.vehicles: device = BMWLock(account, vehicle, 'lock', 'BMW lock') devices.append(device) - add_devices(devices, True) + add_entities(devices, True) class BMWLock(LockDevice): diff --git a/homeassistant/components/lock/demo.py b/homeassistant/components/lock/demo.py index 8da53a9ef11..a0cc45991c8 100644 --- a/homeassistant/components/lock/demo.py +++ b/homeassistant/components/lock/demo.py @@ -8,9 +8,9 @@ from homeassistant.components.lock import LockDevice, SUPPORT_OPEN from homeassistant.const import (STATE_LOCKED, STATE_UNLOCKED) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo lock platform.""" - add_devices([ + add_entities([ DemoLock('Front Door', STATE_LOCKED), DemoLock('Kitchen Door', STATE_UNLOCKED), DemoLock('Openable Lock', STATE_LOCKED, True) diff --git a/homeassistant/components/lock/homematic.py b/homeassistant/components/lock/homematic.py index 7c4195d7c8b..9d9f2a28b4f 100644 --- a/homeassistant/components/lock/homematic.py +++ b/homeassistant/components/lock/homematic.py @@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['homematic'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Homematic lock platform.""" if discovery_info is None: return @@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for conf in discovery_info[ATTR_DISCOVER_DEVICES]: devices.append(HMLock(conf)) - add_devices(devices) + add_entities(devices) class HMLock(HMDevice, LockDevice): diff --git a/homeassistant/components/lock/isy994.py b/homeassistant/components/lock/isy994.py index 9bcf5a86d08..9481e619a61 100644 --- a/homeassistant/components/lock/isy994.py +++ b/homeassistant/components/lock/isy994.py @@ -22,7 +22,7 @@ VALUE_TO_STATE = { def setup_platform(hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the ISY994 lock platform.""" devices = [] for node in hass.data[ISY994_NODES][DOMAIN]: @@ -31,7 +31,7 @@ def setup_platform(hass, config: ConfigType, for name, status, actions in hass.data[ISY994_PROGRAMS][DOMAIN]: devices.append(ISYLockProgram(name, status, actions)) - add_devices(devices) + add_entities(devices) class ISYLockDevice(ISYDevice, LockDevice): diff --git a/homeassistant/components/lock/kiwi.py b/homeassistant/components/lock/kiwi.py index 78ea45525f2..5d217796767 100644 --- a/homeassistant/components/lock/kiwi.py +++ b/homeassistant/components/lock/kiwi.py @@ -32,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the KIWI lock platform.""" from kiwiki import KiwiClient, KiwiException try: @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): # No locks found; abort setup routine. _LOGGER.info("No KIWI locks found in your account.") return - add_devices([KiwiLock(lock, kiwi) for lock in available_locks], True) + add_entities([KiwiLock(lock, kiwi) for lock in available_locks], True) class KiwiLock(LockDevice): diff --git a/homeassistant/components/lock/lockitron.py b/homeassistant/components/lock/lockitron.py index 6bf445ba477..b190a5cd2cd 100644 --- a/homeassistant/components/lock/lockitron.py +++ b/homeassistant/components/lock/lockitron.py @@ -26,15 +26,15 @@ API_STATE_URL = BASE_URL + '/v2/locks/{}?access_token={}' API_ACTION_URL = BASE_URL + '/v2/locks/{}?access_token={}&state={}' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Lockitron platform.""" access_token = config.get(CONF_ACCESS_TOKEN) device_id = config.get(CONF_ID) response = requests.get( API_STATE_URL.format(device_id, access_token), timeout=5) if response.status_code == 200: - add_devices([Lockitron(response.json()['state'], access_token, - device_id)]) + add_entities([Lockitron(response.json()['state'], access_token, + device_id)]) else: _LOGGER.error( "Error retrieving lock status during init: %s", response.text) diff --git a/homeassistant/components/lock/mqtt.py b/homeassistant/components/lock/mqtt.py index 45029e679a5..103864a6bfd 100644 --- a/homeassistant/components/lock/mqtt.py +++ b/homeassistant/components/lock/mqtt.py @@ -42,7 +42,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the MQTT lock.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -51,7 +52,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): if value_template is not None: value_template.hass = hass - async_add_devices([MqttLock( + async_add_entities([MqttLock( config.get(CONF_NAME), config.get(CONF_STATE_TOPIC), config.get(CONF_COMMAND_TOPIC), diff --git a/homeassistant/components/lock/nello.py b/homeassistant/components/lock/nello.py index f67243415c5..4fd9faafcbe 100644 --- a/homeassistant/components/lock/nello.py +++ b/homeassistant/components/lock/nello.py @@ -27,11 +27,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Nello lock platform.""" from pynello import Nello nello = Nello(config.get(CONF_USERNAME), config.get(CONF_PASSWORD)) - add_devices([NelloLock(lock) for lock in nello.locations], True) + add_entities([NelloLock(lock) for lock in nello.locations], True) class NelloLock(LockDevice): diff --git a/homeassistant/components/lock/nuki.py b/homeassistant/components/lock/nuki.py index 536c8f2abeb..6cf58dda04c 100644 --- a/homeassistant/components/lock/nuki.py +++ b/homeassistant/components/lock/nuki.py @@ -50,11 +50,11 @@ UNLATCH_SERVICE_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Nuki lock platform.""" from pynuki import NukiBridge bridge = NukiBridge(config.get(CONF_HOST), config.get(CONF_TOKEN)) - add_devices([NukiLock(lock) for lock in bridge.locks]) + add_entities([NukiLock(lock) for lock in bridge.locks]) def service_handler(service): """Service handler for nuki services.""" diff --git a/homeassistant/components/lock/sesame.py b/homeassistant/components/lock/sesame.py index 8d9c05e3f26..44a6cfb265c 100644 --- a/homeassistant/components/lock/sesame.py +++ b/homeassistant/components/lock/sesame.py @@ -26,16 +26,16 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform( hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the Sesame platform.""" import pysesame email = config.get(CONF_EMAIL) password = config.get(CONF_PASSWORD) - add_devices([SesameDevice(sesame) for sesame in - pysesame.get_sesames(email, password)], - update_before_add=True) + add_entities([SesameDevice(sesame) for sesame in + pysesame.get_sesames(email, password)], + update_before_add=True) class SesameDevice(LockDevice): diff --git a/homeassistant/components/lock/tesla.py b/homeassistant/components/lock/tesla.py index 4d24ed20003..2ffb996aec3 100644 --- a/homeassistant/components/lock/tesla.py +++ b/homeassistant/components/lock/tesla.py @@ -16,11 +16,11 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['tesla'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tesla lock platform.""" devices = [TeslaLock(device, hass.data[TESLA_DOMAIN]['controller']) for device in hass.data[TESLA_DOMAIN]['devices']['lock']] - add_devices(devices, True) + add_entities(devices, True) class TeslaLock(TeslaDevice, LockDevice): diff --git a/homeassistant/components/lock/vera.py b/homeassistant/components/lock/vera.py index e6e277cdee1..21287b6328e 100644 --- a/homeassistant/components/lock/vera.py +++ b/homeassistant/components/lock/vera.py @@ -16,9 +16,9 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['vera'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return Vera locks.""" - add_devices( + add_entities( [VeraLock(device, hass.data[VERA_CONTROLLER]) for device in hass.data[VERA_DEVICES]['lock']], True) diff --git a/homeassistant/components/lock/verisure.py b/homeassistant/components/lock/verisure.py index 4af19f52611..877c8a1ddf6 100644 --- a/homeassistant/components/lock/verisure.py +++ b/homeassistant/components/lock/verisure.py @@ -16,7 +16,7 @@ from homeassistant.const import ( _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Verisure platform.""" locks = [] if int(hub.config.get(CONF_LOCKS, 1)): @@ -26,7 +26,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device_label in hub.get( "$.doorLockStatusList[*].deviceLabel")]) - add_devices(locks) + add_entities(locks) class VerisureDoorlock(LockDevice): diff --git a/homeassistant/components/lock/volvooncall.py b/homeassistant/components/lock/volvooncall.py index b6e7383b138..58fa83cef30 100644 --- a/homeassistant/components/lock/volvooncall.py +++ b/homeassistant/components/lock/volvooncall.py @@ -12,12 +12,12 @@ from homeassistant.components.volvooncall import VolvoEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Volvo On Call lock.""" if discovery_info is None: return - add_devices([VolvoLock(hass, *discovery_info)]) + add_entities([VolvoLock(hass, *discovery_info)]) class VolvoLock(VolvoEntity, LockDevice): diff --git a/homeassistant/components/lock/wink.py b/homeassistant/components/lock/wink.py index 1c42e427a00..03de8fc5919 100644 --- a/homeassistant/components/lock/wink.py +++ b/homeassistant/components/lock/wink.py @@ -66,14 +66,14 @@ ADD_KEY_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink platform.""" import pywink for lock in pywink.get_locks(): _id = lock.object_id() + lock.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkLockDevice(lock, hass)]) + add_entities([WinkLockDevice(lock, hass)]) def service_handle(service): """Handle for services.""" diff --git a/homeassistant/components/lock/xiaomi_aqara.py b/homeassistant/components/lock/xiaomi_aqara.py index 9b084a2bc55..15415a73284 100644 --- a/homeassistant/components/lock/xiaomi_aqara.py +++ b/homeassistant/components/lock/xiaomi_aqara.py @@ -24,7 +24,7 @@ ATTR_VERIFIED_WRONG_TIMES = 'verified_wrong_times' UNLOCK_MAINTAIN_TIME = 5 -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Perform the setup for Xiaomi devices.""" devices = [] @@ -34,7 +34,7 @@ async def async_setup_platform(hass, config, async_add_devices, model = device['model'] if model == 'lock.aq1': devices.append(XiaomiAqaraLock(device, 'Lock', gateway)) - async_add_devices(devices) + async_add_entities(devices) class XiaomiAqaraLock(LockDevice, XiaomiDevice): diff --git a/homeassistant/components/lock/zwave.py b/homeassistant/components/lock/zwave.py index b7bc9f15e19..5ee88f053b5 100644 --- a/homeassistant/components/lock/zwave.py +++ b/homeassistant/components/lock/zwave.py @@ -120,10 +120,11 @@ CLEAR_USERCODE_SCHEMA = vol.Schema({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Z-Wave Lock platform.""" yield from zwave.async_setup_platform( - hass, config, async_add_devices, discovery_info) + hass, config, async_add_entities, discovery_info) network = hass.data[zwave.const.DATA_NETWORK] diff --git a/homeassistant/components/mailbox/asterisk_mbox.py b/homeassistant/components/mailbox/asterisk_mbox.py index 2e807058edf..47d59234d7d 100644 --- a/homeassistant/components/mailbox/asterisk_mbox.py +++ b/homeassistant/components/mailbox/asterisk_mbox.py @@ -21,7 +21,7 @@ SIGNAL_MESSAGE_REQUEST = 'asterisk_mbox.message_request' @asyncio.coroutine -def async_get_handler(hass, config, async_add_devices, discovery_info=None): +def async_get_handler(hass, config, async_add_entities, discovery_info=None): """Set up the Asterix VM platform.""" return AsteriskMailbox(hass, DOMAIN) diff --git a/homeassistant/components/media_player/anthemav.py b/homeassistant/components/media_player/anthemav.py index a74629917b3..359ee0a9254 100644 --- a/homeassistant/components/media_player/anthemav.py +++ b/homeassistant/components/media_player/anthemav.py @@ -36,7 +36,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up our socket to the AVR.""" import anthemav @@ -63,7 +64,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.debug("dump_rawdata: %s", avr.protocol.dump_rawdata) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, device.avr.close) - async_add_devices([device]) + async_add_entities([device]) class AnthemAVR(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/apple_tv.py b/homeassistant/components/media_player/apple_tv.py index d4a7ad19807..360ccd0f522 100644 --- a/homeassistant/components/media_player/apple_tv.py +++ b/homeassistant/components/media_player/apple_tv.py @@ -31,7 +31,8 @@ SUPPORT_APPLE_TV = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PLAY_MEDIA | \ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Apple TV platform.""" if not discovery_info: return @@ -56,7 +57,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): if entity not in hass.data[DATA_ENTITIES]: hass.data[DATA_ENTITIES].append(entity) - async_add_devices([entity]) + async_add_entities([entity]) class AppleTvDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/aquostv.py b/homeassistant/components/media_player/aquostv.py index 93daf5b2f89..6e8cc727121 100644 --- a/homeassistant/components/media_player/aquostv.py +++ b/homeassistant/components/media_player/aquostv.py @@ -59,7 +59,7 @@ SOURCES = {0: 'TV / Antenna', 8: 'PC_IN'} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sharp Aquos TV platform.""" import sharp_aquos_rc @@ -77,13 +77,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): host = vals[0] remote = sharp_aquos_rc.TV(host, port, username, password, timeout=20) - add_devices([SharpAquosTVDevice(name, remote, power_on_enabled)]) + add_entities([SharpAquosTVDevice(name, remote, power_on_enabled)]) return True host = config.get(CONF_HOST) remote = sharp_aquos_rc.TV(host, port, username, password, 15, 1) - add_devices([SharpAquosTVDevice(name, remote, power_on_enabled)]) + add_entities([SharpAquosTVDevice(name, remote, power_on_enabled)]) return True diff --git a/homeassistant/components/media_player/blackbird.py b/homeassistant/components/media_player/blackbird.py index 3d8e1fde687..7869093138c 100644 --- a/homeassistant/components/media_player/blackbird.py +++ b/homeassistant/components/media_player/blackbird.py @@ -61,7 +61,7 @@ PLATFORM_SCHEMA = vol.All( })) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Monoprice Blackbird 4k 8x8 HDBaseT Matrix platform.""" if DATA_BLACKBIRD not in hass.data: hass.data[DATA_BLACKBIRD] = {} @@ -100,7 +100,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass.data[DATA_BLACKBIRD][unique_id] = device devices.append(device) - add_devices(devices, True) + add_entities(devices, True) def service_handle(service): """Handle for services.""" diff --git a/homeassistant/components/media_player/bluesound.py b/homeassistant/components/media_player/bluesound.py index 5631ec06cf1..1fe939b34ef 100644 --- a/homeassistant/components/media_player/bluesound.py +++ b/homeassistant/components/media_player/bluesound.py @@ -88,7 +88,7 @@ SERVICE_TO_METHOD = { } -def _add_player(hass, async_add_devices, host, port=None, name=None): +def _add_player(hass, async_add_entities, host, port=None, name=None): """Add Bluesound players.""" if host in [x.host for x in hass.data[DATA_BLUESOUND]]: return @@ -111,7 +111,7 @@ def _add_player(hass, async_add_devices, host, port=None, name=None): @callback def _add_player_cb(): """Add player after first sync fetch.""" - async_add_devices([player]) + async_add_entities([player]) _LOGGER.info("Added device with name: %s", player.name) if hass.is_running: @@ -132,13 +132,13 @@ def _add_player(hass, async_add_devices, host, port=None, name=None): async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Bluesound platforms.""" if DATA_BLUESOUND not in hass.data: hass.data[DATA_BLUESOUND] = [] if discovery_info: - _add_player(hass, async_add_devices, discovery_info.get(CONF_HOST), + _add_player(hass, async_add_entities, discovery_info.get(CONF_HOST), discovery_info.get(CONF_PORT, None)) return @@ -146,7 +146,7 @@ async def async_setup_platform( if hosts: for host in hosts: _add_player( - hass, async_add_devices, host.get(CONF_HOST), + hass, async_add_entities, host.get(CONF_HOST), host.get(CONF_PORT), host.get(CONF_NAME)) async def async_service_handler(service): diff --git a/homeassistant/components/media_player/braviatv.py b/homeassistant/components/media_player/braviatv.py index 07a379db45c..9f4496582ad 100644 --- a/homeassistant/components/media_player/braviatv.py +++ b/homeassistant/components/media_player/braviatv.py @@ -58,7 +58,7 @@ def _get_mac_address(ip_address): return None -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sony Bravia TV platform.""" host = config.get(CONF_HOST) @@ -74,19 +74,19 @@ def setup_platform(hass, config, add_devices, discovery_info=None): pin = host_config['pin'] mac = host_config['mac'] name = config.get(CONF_NAME) - add_devices([BraviaTVDevice(host, mac, name, pin)]) + add_entities([BraviaTVDevice(host, mac, name, pin)]) return - setup_bravia(config, pin, hass, add_devices) + setup_bravia(config, pin, hass, add_entities) -def setup_bravia(config, pin, hass, add_devices): +def setup_bravia(config, pin, hass, add_entities): """Set up a Sony Bravia TV based on host parameter.""" host = config.get(CONF_HOST) name = config.get(CONF_NAME) if pin is None: - request_configuration(config, hass, add_devices) + request_configuration(config, hass, add_entities) return mac = _get_mac_address(host) @@ -104,10 +104,10 @@ def setup_bravia(config, pin, hass, add_devices): hass.config.path(BRAVIA_CONFIG_FILE), {host: {'pin': pin, 'host': host, 'mac': mac}}) - add_devices([BraviaTVDevice(host, mac, name, pin)]) + add_entities([BraviaTVDevice(host, mac, name, pin)]) -def request_configuration(config, hass, add_devices): +def request_configuration(config, hass, add_entities): """Request configuration steps from the user.""" host = config.get(CONF_HOST) name = config.get(CONF_NAME) @@ -128,9 +128,9 @@ def request_configuration(config, hass, add_devices): braviarc = braviarc.BraviaRC(host) braviarc.connect(pin, CLIENTID_PREFIX, NICKNAME) if braviarc.is_connected(): - setup_bravia(config, pin, hass, add_devices) + setup_bravia(config, pin, hass, add_entities) else: - request_configuration(config, hass, add_devices) + request_configuration(config, hass, add_entities) _CONFIGURING[host] = configurator.request_config( name, bravia_configuration_callback, diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 2c66d458095..ae9589c7886 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -186,7 +186,7 @@ def _async_create_cast_device(hass: HomeAssistantType, async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info=None): + async_add_entities, discovery_info=None): """Set up thet Cast platform. Deprecated. @@ -195,22 +195,22 @@ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, 'Setting configuration for Cast via platform is deprecated. ' 'Configure via Cast component instead.') await _async_setup_platform( - hass, config, async_add_devices, discovery_info) + hass, config, async_add_entities, discovery_info) -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up Cast from a config entry.""" config = hass.data[CAST_DOMAIN].get('media_player', {}) if not isinstance(config, list): config = [config] await asyncio.wait([ - _async_setup_platform(hass, cfg, async_add_devices, None) + _async_setup_platform(hass, cfg, async_add_entities, None) for cfg in config]) async def _async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info): + async_add_entities, discovery_info): """Set up the cast platform.""" import pychromecast @@ -236,7 +236,7 @@ async def _async_setup_platform(hass: HomeAssistantType, config: ConfigType, cast_device = _async_create_cast_device(hass, discover) if cast_device is not None: - async_add_devices([cast_device]) + async_add_entities([cast_device]) async_dispatcher_connect(hass, SIGNAL_CAST_DISCOVERED, async_cast_discovered) diff --git a/homeassistant/components/media_player/channels.py b/homeassistant/components/media_player/channels.py index 71ef5412d9e..fcfa16b33ac 100644 --- a/homeassistant/components/media_player/channels.py +++ b/homeassistant/components/media_player/channels.py @@ -55,7 +55,7 @@ CHANNELS_SEEK_BY_SCHEMA = CHANNELS_SCHEMA.extend({ REQUIREMENTS = ['pychannels==1.0.0'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Channels platform.""" device = ChannelsPlayer( config.get('name'), @@ -66,7 +66,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if DATA_CHANNELS not in hass.data: hass.data[DATA_CHANNELS] = [] - add_devices([device], True) + add_entities([device], True) hass.data[DATA_CHANNELS].append(device) def service_handler(service): diff --git a/homeassistant/components/media_player/clementine.py b/homeassistant/components/media_player/clementine.py index 1ee18576ab8..fab2bef73f0 100644 --- a/homeassistant/components/media_player/clementine.py +++ b/homeassistant/components/media_player/clementine.py @@ -43,7 +43,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Clementine platform.""" from clementineremote import ClementineRemote host = config.get(CONF_HOST) @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): client = ClementineRemote(host, port, token, reconnect=True) - add_devices([ClementineDevice(client, config[CONF_NAME])]) + add_entities([ClementineDevice(client, config[CONF_NAME])]) class ClementineDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/cmus.py b/homeassistant/components/media_player/cmus.py index 978a1088aa6..6f579fd9791 100644 --- a/homeassistant/components/media_player/cmus.py +++ b/homeassistant/components/media_player/cmus.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discover_info=None): +def setup_platform(hass, config, add_entities, discover_info=None): """Set up the CMUS platform.""" from pycmus import exceptions @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discover_info=None): except exceptions.InvalidPassword: _LOGGER.error("The provided password was rejected by cmus") return False - add_devices([cmus_remote], True) + add_entities([cmus_remote], True) class CmusDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/demo.py b/homeassistant/components/media_player/demo.py index 9edf69cd9c6..06f2a3f1155 100644 --- a/homeassistant/components/media_player/demo.py +++ b/homeassistant/components/media_player/demo.py @@ -14,9 +14,9 @@ from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING import homeassistant.util.dt as dt_util -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the media player demo platform.""" - add_devices([ + add_entities([ DemoYoutubePlayer( 'Living Room', 'eyU3bRy2x44', '♥♥ The Best Fireplace Video (3 hours)', 300), diff --git a/homeassistant/components/media_player/denon.py b/homeassistant/components/media_player/denon.py index d85bd51e7fb..320211e700f 100644 --- a/homeassistant/components/media_player/denon.py +++ b/homeassistant/components/media_player/denon.py @@ -49,12 +49,12 @@ MEDIA_MODES = {'Tuner': 'TUNER', 'Media server': 'SERVER', # 'Favorites': 'FVP'} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Denon platform.""" denon = DenonDevice(config.get(CONF_NAME), config.get(CONF_HOST)) if denon.update(): - add_devices([denon]) + add_entities([denon]) class DenonDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/denonavr.py b/homeassistant/components/media_player/denonavr.py index 604fb91451e..14839590bee 100644 --- a/homeassistant/components/media_player/denonavr.py +++ b/homeassistant/components/media_player/denonavr.py @@ -61,7 +61,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ NewHost = namedtuple('NewHost', ['host', 'name']) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Denon platform.""" import denonavr @@ -124,7 +124,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): # Add all freshly discovered receivers if receivers: - add_devices(receivers) + add_entities(receivers) class DenonDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/directv.py b/homeassistant/components/media_player/directv.py index 89547892550..e03474cdb38 100644 --- a/homeassistant/components/media_player/directv.py +++ b/homeassistant/components/media_player/directv.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the DirecTV platform.""" known_devices = hass.data.get(DATA_DIRECTV) if not known_devices: @@ -75,7 +75,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dtvs.append(DirecTvDevice(*host)) known_devices.append(host[-1]) - add_devices(dtvs) + add_entities(dtvs) hass.data[DATA_DIRECTV] = known_devices return True diff --git a/homeassistant/components/media_player/dlna_dmr.py b/homeassistant/components/media_player/dlna_dmr.py index 7a0049df867..6c970ec197e 100644 --- a/homeassistant/components/media_player/dlna_dmr.py +++ b/homeassistant/components/media_player/dlna_dmr.py @@ -118,7 +118,7 @@ async def async_start_event_handler(hass, server_host, server_port, requester): async def async_setup_platform(hass: HomeAssistant, config, - async_add_devices, + async_add_entities, discovery_info=None): """Set up DLNA DMR platform.""" if config.get(CONF_URL) is not None: @@ -165,7 +165,7 @@ async def async_setup_platform(hass: HomeAssistant, # create our own device device = DlnaDmrDevice(dlna_device, name) _LOGGER.debug("Adding device: %s", device) - async_add_devices([device], True) + async_add_entities([device], True) class DlnaDmrDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/dunehd.py b/homeassistant/components/media_player/dunehd.py index ed20ac25cf9..f582ceefe5f 100644 --- a/homeassistant/components/media_player/dunehd.py +++ b/homeassistant/components/media_player/dunehd.py @@ -32,7 +32,7 @@ DUNEHD_PLAYER_SUPPORT = \ SUPPORT_PLAY -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the DuneHD media player platform.""" from pdunehd import DuneHDPlayer @@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): host = config.get(CONF_HOST) name = config.get(CONF_NAME) - add_devices([DuneHDPlayerEntity(DuneHDPlayer(host), name, sources)], True) + add_entities([DuneHDPlayerEntity(DuneHDPlayer(host), name, sources)], True) class DuneHDPlayerEntity(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/emby.py b/homeassistant/components/media_player/emby.py index 8dd4ebcb120..b64aad38b3e 100644 --- a/homeassistant/components/media_player/emby.py +++ b/homeassistant/components/media_player/emby.py @@ -51,7 +51,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Emby platform.""" from pyemby import EmbyServer @@ -94,7 +95,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): if new_devices: _LOGGER.debug("Adding new devices: %s", new_devices) - async_add_devices(new_devices, update_before_add=True) + async_add_entities(new_devices, update_before_add=True) @callback def device_removal_callback(data): diff --git a/homeassistant/components/media_player/epson.py b/homeassistant/components/media_player/epson.py index b22234a4094..23bbf685004 100644 --- a/homeassistant/components/media_player/epson.py +++ b/homeassistant/components/media_player/epson.py @@ -40,7 +40,7 @@ SUPPORT_EPSON = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE |\ _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Epson media player platform.""" if DATA_EPSON not in hass.data: @@ -52,7 +52,7 @@ async def async_setup_platform(hass, config, async_add_devices, name, host, config.get(CONF_PORT), config.get(CONF_SSL)) hass.data[DATA_EPSON].append(epson) - async_add_devices([epson], update_before_add=True) + async_add_entities([epson], update_before_add=True) async def async_service_handler(service): """Handle for services.""" diff --git a/homeassistant/components/media_player/firetv.py b/homeassistant/components/media_player/firetv.py index 979aec57c74..0594b603a0c 100644 --- a/homeassistant/components/media_player/firetv.py +++ b/homeassistant/components/media_player/firetv.py @@ -45,7 +45,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the FireTV platform.""" name = config.get(CONF_NAME) ssl = config.get(CONF_SSL) @@ -58,7 +58,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): response = requests.get( DEVICE_LIST_URL.format(proto, host, port)).json() if device_id in response[CONF_DEVICES].keys(): - add_devices([FireTVDevice(proto, host, port, device_id, name)]) + add_entities([FireTVDevice(proto, host, port, device_id, name)]) _LOGGER.info("Device %s accessible and ready for control", device_id) else: diff --git a/homeassistant/components/media_player/frontier_silicon.py b/homeassistant/components/media_player/frontier_silicon.py index b59c9a199b8..6dc4e73b1c0 100644 --- a/homeassistant/components/media_player/frontier_silicon.py +++ b/homeassistant/components/media_player/frontier_silicon.py @@ -42,12 +42,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Frontier Silicon platform.""" import requests if discovery_info is not None: - async_add_devices( + async_add_entities( [AFSAPIDevice(discovery_info['ssdp_description'], DEFAULT_PASSWORD)], update_before_add=True) @@ -58,7 +59,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): password = config.get(CONF_PASSWORD) try: - async_add_devices( + async_add_entities( [AFSAPIDevice(DEVICE_URL.format(host, port), password)], update_before_add=True) _LOGGER.debug("FSAPI device %s:%s -> %s", host, port, password) diff --git a/homeassistant/components/media_player/gpmdp.py b/homeassistant/components/media_player/gpmdp.py index 4a0ec1fa87f..200191ad77a 100644 --- a/homeassistant/components/media_player/gpmdp.py +++ b/homeassistant/components/media_player/gpmdp.py @@ -45,7 +45,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def request_configuration(hass, config, url, add_devices_callback): +def request_configuration(hass, config, url, add_entities_callback): """Request configuration steps from the user.""" configurator = hass.components.configurator if 'gpmdp' in _CONFIGURING: @@ -84,7 +84,7 @@ def request_configuration(hass, config, url, add_devices_callback): if code == 'CODE_REQUIRED': continue setup_gpmdp(hass, config, code, - add_devices_callback) + add_entities_callback) save_json(hass.config.path(GPMDP_CONFIG_FILE), {"CODE": code}) websocket.send(json.dumps({'namespace': 'connect', 'method': 'connect', @@ -102,7 +102,7 @@ def request_configuration(hass, config, url, add_devices_callback): ) -def setup_gpmdp(hass, config, code, add_devices): +def setup_gpmdp(hass, config, code, add_entities): """Set up gpmdp.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -110,17 +110,17 @@ def setup_gpmdp(hass, config, code, add_devices): url = 'ws://{}:{}'.format(host, port) if not code: - request_configuration(hass, config, url, add_devices) + request_configuration(hass, config, url, add_entities) return if 'gpmdp' in _CONFIGURING: configurator = hass.components.configurator configurator.request_done(_CONFIGURING.pop('gpmdp')) - add_devices([GPMDP(name, url, code)], True) + add_entities([GPMDP(name, url, code)], True) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the GPMDP platform.""" codeconfig = load_json(hass.config.path(GPMDP_CONFIG_FILE)) if codeconfig: @@ -131,7 +131,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): code = None else: code = None - setup_gpmdp(hass, config, code, add_devices) + setup_gpmdp(hass, config, code, add_entities) class GPMDP(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/gstreamer.py b/homeassistant/components/media_player/gstreamer.py index 91cd8d19cc4..e2477f0a4cd 100644 --- a/homeassistant/components/media_player/gstreamer.py +++ b/homeassistant/components/media_player/gstreamer.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Gstreamer platform.""" from gsp import GstreamerPlayer name = config.get(CONF_NAME) @@ -46,7 +46,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): player.quit() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, _shutdown) - add_devices([GstreamerDevice(player, name)]) + add_entities([GstreamerDevice(player, name)]) class GstreamerDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/hdmi_cec.py b/homeassistant/components/media_player/hdmi_cec.py index f5b4cbd4854..9198e4dec88 100644 --- a/homeassistant/components/media_player/hdmi_cec.py +++ b/homeassistant/components/media_player/hdmi_cec.py @@ -22,13 +22,13 @@ _LOGGER = logging.getLogger(__name__) ENTITY_ID_FORMAT = DOMAIN + '.{}' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return HDMI devices as +switches.""" if ATTR_NEW in discovery_info: _LOGGER.info("Setting up HDMI devices %s", discovery_info[ATTR_NEW]) - add_devices(CecPlayerDevice(hass, hass.data.get(device), - hass.data.get(device).logical_address) for - device in discovery_info[ATTR_NEW]) + add_entities(CecPlayerDevice(hass, hass.data.get(device), + hass.data.get(device).logical_address) for + device in discovery_info[ATTR_NEW]) class CecPlayerDevice(CecDevice, MediaPlayerDevice): diff --git a/homeassistant/components/media_player/horizon.py b/homeassistant/components/media_player/horizon.py index 9be4143ef2b..4fa97cb5537 100644 --- a/homeassistant/components/media_player/horizon.py +++ b/homeassistant/components/media_player/horizon.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Horizon platform.""" from einder import Client, keys from einder.exceptions import AuthenticationError @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.info("Connection to %s at %s established", name, host) - add_devices([HorizonDevice(client, name, keys)], True) + add_entities([HorizonDevice(client, name, keys)], True) class HorizonDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/itunes.py b/homeassistant/components/media_player/itunes.py index e5f7a2f9432..31df74dbeaf 100644 --- a/homeassistant/components/media_player/itunes.py +++ b/homeassistant/components/media_player/itunes.py @@ -157,16 +157,16 @@ class Itunes: return self._request('PUT', path, {'level': level}) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the iTunes platform.""" - add_devices([ + add_entities([ ItunesDevice( config.get(CONF_NAME), config.get(CONF_HOST), config.get(CONF_PORT), config.get(CONF_SSL), - add_devices + add_entities ) ]) @@ -174,13 +174,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class ItunesDevice(MediaPlayerDevice): """Representation of an iTunes API instance.""" - def __init__(self, name, host, port, use_ssl, add_devices): + def __init__(self, name, host, port, use_ssl, add_entities): """Initialize the iTunes device.""" self._name = name self._host = host self._port = port self._use_ssl = use_ssl - self._add_devices = add_devices + self._add_entities = add_entities self.client = Itunes(self._host, self._port, self._use_ssl) @@ -257,7 +257,7 @@ class ItunesDevice(MediaPlayerDevice): new_devices.append(airplay_device) if new_devices: - self._add_devices(new_devices) + self._add_entities(new_devices) @property def is_volume_muted(self): diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index 08de2d00835..b36512e7c65 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -155,7 +155,8 @@ def _check_deprecated_turn_off(hass, turn_off_action): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Kodi platform.""" if DATA_KODI not in hass.data: hass.data[DATA_KODI] = dict() @@ -206,7 +207,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): unique_id=unique_id) hass.data[DATA_KODI][ip_addr] = entity - async_add_devices([entity], update_before_add=True) + async_add_entities([entity], update_before_add=True) @asyncio.coroutine def async_service_handler(service): diff --git a/homeassistant/components/media_player/lg_netcast.py b/homeassistant/components/media_player/lg_netcast.py index 955ba7ccb32..cbc15af91b6 100644 --- a/homeassistant/components/media_player/lg_netcast.py +++ b/homeassistant/components/media_player/lg_netcast.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LG TV platform.""" from pylgnetcast import LgNetCastClient host = config.get(CONF_HOST) @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): client = LgNetCastClient(host, access_token) - add_devices([LgTVDevice(client, name)], True) + add_entities([LgTVDevice(client, name)], True) class LgTVDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/liveboxplaytv.py b/homeassistant/components/media_player/liveboxplaytv.py index 1b5948c964a..d5b1bcd78fe 100644 --- a/homeassistant/components/media_player/liveboxplaytv.py +++ b/homeassistant/components/media_player/liveboxplaytv.py @@ -45,7 +45,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Orange Livebox Play TV platform.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -59,7 +60,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): except IOError: _LOGGER.error("Failed to connect to Livebox Play TV at %s:%s. " "Please check your configuration", host, port) - async_add_devices(livebox_devices, True) + async_add_entities(livebox_devices, True) class LiveboxPlayTvDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/mediaroom.py b/homeassistant/components/media_player/mediaroom.py index fd7229f79f5..f0b5365cf83 100644 --- a/homeassistant/components/media_player/mediaroom.py +++ b/homeassistant/components/media_player/mediaroom.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Mediaroom platform.""" known_hosts = hass.data.get(DATA_MEDIAROOM) @@ -57,10 +57,10 @@ async def async_setup_platform(hass, config, async_add_devices, known_hosts = hass.data[DATA_MEDIAROOM] = [] host = config.get(CONF_HOST, None) if host: - async_add_devices([MediaroomDevice(host=host, - device_id=None, - optimistic=config[CONF_OPTIMISTIC], - timeout=config[CONF_TIMEOUT])]) + async_add_entities([MediaroomDevice(host=host, + device_id=None, + optimistic=config[CONF_OPTIMISTIC], + timeout=config[CONF_TIMEOUT])]) hass.data[DATA_MEDIAROOM].append(host) _LOGGER.debug("Trying to discover Mediaroom STB") @@ -77,7 +77,7 @@ async def async_setup_platform(hass, config, async_add_devices, host=notify.ip_address, device_id=notify.device_uuid, optimistic=False ) - async_add_devices([new_stb]) + async_add_entities([new_stb]) if not config[CONF_OPTIMISTIC]: from pymediaroom import install_mediaroom_protocol diff --git a/homeassistant/components/media_player/monoprice.py b/homeassistant/components/media_player/monoprice.py index a951356500f..96b8dcbcf26 100644 --- a/homeassistant/components/media_player/monoprice.py +++ b/homeassistant/components/media_player/monoprice.py @@ -55,7 +55,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Monoprice 6-zone amplifier platform.""" port = config.get(CONF_PORT) @@ -76,7 +76,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass.data[DATA_MONOPRICE].append(MonopriceZone( monoprice, sources, zone_id, extra[CONF_NAME])) - add_devices(hass.data[DATA_MONOPRICE], True) + add_entities(hass.data[DATA_MONOPRICE], True) def service_handle(service): """Handle for services.""" diff --git a/homeassistant/components/media_player/mpchc.py b/homeassistant/components/media_player/mpchc.py index 773825e0d57..840429ef3d4 100644 --- a/homeassistant/components/media_player/mpchc.py +++ b/homeassistant/components/media_player/mpchc.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the MPC-HC platform.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): url = '{}:{}'.format(host, port) - add_devices([MpcHcDevice(name, url)], True) + add_entities([MpcHcDevice(name, url)], True) class MpcHcDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/mpd.py b/homeassistant/components/media_player/mpd.py index be9dfa77377..8953215f44e 100644 --- a/homeassistant/components/media_player/mpd.py +++ b/homeassistant/components/media_player/mpd.py @@ -45,7 +45,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the MPD platform.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): password = config.get(CONF_PASSWORD) device = MpdDevice(host, port, password, name) - add_devices([device], True) + add_entities([device], True) class MpdDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/nad.py b/homeassistant/components/media_player/nad.py index 2f0c49b2583..d30c5815d3f 100644 --- a/homeassistant/components/media_player/nad.py +++ b/homeassistant/components/media_player/nad.py @@ -47,10 +47,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NAD platform.""" from nad_receiver import NADReceiver - add_devices([NAD( + add_entities([NAD( config.get(CONF_NAME), NADReceiver(config.get(CONF_SERIAL_PORT)), config.get(CONF_MIN_VOLUME), diff --git a/homeassistant/components/media_player/nadtcp.py b/homeassistant/components/media_player/nadtcp.py index 06ec3c04cbe..dd3c5e26d7a 100644 --- a/homeassistant/components/media_player/nadtcp.py +++ b/homeassistant/components/media_player/nadtcp.py @@ -40,10 +40,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NAD platform.""" from nad_receiver import NADReceiverTCP - add_devices([NADtcp( + add_entities([NADtcp( NADReceiverTCP(config.get(CONF_HOST)), config.get(CONF_NAME), config.get(CONF_MIN_VOLUME), diff --git a/homeassistant/components/media_player/onkyo.py b/homeassistant/components/media_player/onkyo.py index 92443ca2b42..af9a6ef54ce 100644 --- a/homeassistant/components/media_player/onkyo.py +++ b/homeassistant/components/media_player/onkyo.py @@ -80,7 +80,7 @@ def determine_zones(receiver): return out -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Onkyo platform.""" import eiscp from eiscp import eISCP @@ -122,7 +122,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if receiver.host not in KNOWN_HOSTS: hosts.append(OnkyoDevice(receiver, config.get(CONF_SOURCES))) KNOWN_HOSTS.append(receiver.host) - add_devices(hosts, True) + add_entities(hosts, True) class OnkyoDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/openhome.py b/homeassistant/components/media_player/openhome.py index 5d9c7bd14c5..1ffe0ef82df 100644 --- a/homeassistant/components/media_player/openhome.py +++ b/homeassistant/components/media_player/openhome.py @@ -25,7 +25,7 @@ _LOGGER = logging.getLogger(__name__) DEVICES = [] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Openhome platform.""" from openhomedevice.Device import Device @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device = OpenhomeDevice(hass, device) - add_devices([device], True) + add_entities([device], True) DEVICES.append(device) return True diff --git a/homeassistant/components/media_player/panasonic_viera.py b/homeassistant/components/media_player/panasonic_viera.py index 549071fde8e..937a72c80ff 100644 --- a/homeassistant/components/media_player/panasonic_viera.py +++ b/homeassistant/components/media_player/panasonic_viera.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Panasonic Viera TV platform.""" from panasonic_viera import RemoteControl @@ -61,13 +61,13 @@ def setup_platform(hass, config, add_devices, discovery_info=None): else: uuid = None remote = RemoteControl(host, port) - add_devices([PanasonicVieraTVDevice(mac, name, remote, uuid)]) + add_entities([PanasonicVieraTVDevice(mac, name, remote, uuid)]) return True host = config.get(CONF_HOST) remote = RemoteControl(host, port) - add_devices([PanasonicVieraTVDevice(mac, name, remote)]) + add_entities([PanasonicVieraTVDevice(mac, name, remote)]) return True diff --git a/homeassistant/components/media_player/pandora.py b/homeassistant/components/media_player/pandora.py index c4d8b778095..5295bfc40eb 100644 --- a/homeassistant/components/media_player/pandora.py +++ b/homeassistant/components/media_player/pandora.py @@ -43,7 +43,7 @@ CURRENT_SONG_PATTERN = re.compile(r'"(.*?)"\s+by\s+"(.*?)"\son\s+"(.*?)"', STATION_PATTERN = re.compile(r'Station\s"(.+?)"', re.MULTILINE) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Pandora media player platform.""" if not _pianobar_exists(): return False @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): pandora.turn_off() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, _stop_pianobar) - add_devices([pandora]) + add_entities([pandora]) class PandoraMediaPlayer(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/philips_js.py b/homeassistant/components/media_player/philips_js.py index 06f054a03f7..9c7418d4c80 100644 --- a/homeassistant/components/media_player/philips_js.py +++ b/homeassistant/components/media_player/philips_js.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Philips TV platform.""" import haphilipsjs @@ -60,7 +60,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): tvapi = haphilipsjs.PhilipsTV(host, api_version) on_script = Script(hass, turn_on_action) if turn_on_action else None - add_devices([PhilipsTV(tvapi, name, on_script)]) + add_entities([PhilipsTV(tvapi, name, on_script)]) class PhilipsTV(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/pioneer.py b/homeassistant/components/media_player/pioneer.py index 25424224c70..71ccf9a460d 100644 --- a/homeassistant/components/media_player/pioneer.py +++ b/homeassistant/components/media_player/pioneer.py @@ -39,14 +39,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Pioneer platform.""" pioneer = PioneerDevice( config.get(CONF_NAME), config.get(CONF_HOST), config.get(CONF_PORT), config.get(CONF_TIMEOUT)) if pioneer.update(): - add_devices([pioneer]) + add_entities([pioneer]) class PioneerDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/pjlink.py b/homeassistant/components/media_player/pjlink.py index 5d3122256ea..42884cdce09 100644 --- a/homeassistant/components/media_player/pjlink.py +++ b/homeassistant/components/media_player/pjlink.py @@ -37,7 +37,7 @@ SUPPORT_PJLINK = SUPPORT_VOLUME_MUTE | \ SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PJLink platform.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device = PjLinkDevice(host, port, name, encoding, password) hass_data[device_label] = device - add_devices([device], True) + add_entities([device], True) def format_input_source(input_source_name, input_source_number): diff --git a/homeassistant/components/media_player/plex.py b/homeassistant/components/media_player/plex.py index 05947b3d67b..3c916860818 100644 --- a/homeassistant/components/media_player/plex.py +++ b/homeassistant/components/media_player/plex.py @@ -59,7 +59,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLEX_DATA = "plex" -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up the Plex platform.""" if PLEX_DATA not in hass.data: hass.data[PLEX_DATA] = {} @@ -98,12 +98,12 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): setup_plexserver( host, token, has_ssl, verify_ssl, - hass, config, add_devices_callback + hass, config, add_entities_callback ) def setup_plexserver( - host, token, has_ssl, verify_ssl, hass, config, add_devices_callback): + host, token, has_ssl, verify_ssl, hass, config, add_entities_callback): """Set up a plexserver based on host parameter.""" import plexapi.server import plexapi.exceptions @@ -124,7 +124,7 @@ def setup_plexserver( plexapi.exceptions.NotFound) as error: _LOGGER.info(error) # No token or wrong token - request_configuration(host, hass, config, add_devices_callback) + request_configuration(host, hass, config, add_entities_callback) return # If we came here and configuring this host, mark as done @@ -214,7 +214,7 @@ def setup_plexserver( del plex_clients[clients_to_remove.pop()] if new_plex_clients: - add_devices_callback(new_plex_clients) + add_entities_callback(new_plex_clients) @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update_sessions(): @@ -238,7 +238,7 @@ def setup_plexserver( update_devices() -def request_configuration(host, hass, config, add_devices_callback): +def request_configuration(host, hass, config, add_entities_callback): """Request configuration steps from the user.""" configurator = hass.components.configurator # We got an error if this method is called while we are configuring @@ -254,7 +254,7 @@ def request_configuration(host, hass, config, add_devices_callback): host, data.get('token'), cv.boolean(data.get('has_ssl')), cv.boolean(data.get('do_not_verify')), - hass, config, add_devices_callback + hass, config, add_entities_callback ) _CONFIGURING[host] = configurator.request_config( diff --git a/homeassistant/components/media_player/roku.py b/homeassistant/components/media_player/roku.py index 5f28660f4bd..fa1120db98c 100644 --- a/homeassistant/components/media_player/roku.py +++ b/homeassistant/components/media_player/roku.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Roku platform.""" hosts = [] @@ -73,7 +73,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID) - add_devices(rokus) + add_entities(rokus) class RokuDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/russound_rio.py b/homeassistant/components/media_player/russound_rio.py index e9f8ab5f199..cf946945cf2 100644 --- a/homeassistant/components/media_player/russound_rio.py +++ b/homeassistant/components/media_player/russound_rio.py @@ -35,7 +35,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Russound RIO platform.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -65,7 +66,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_stop) - async_add_devices(devices) + async_add_entities(devices) class RussoundZoneDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/russound_rnet.py b/homeassistant/components/media_player/russound_rnet.py index 932872467bd..8aef15e02af 100644 --- a/homeassistant/components/media_player/russound_rnet.py +++ b/homeassistant/components/media_player/russound_rnet.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Russound RNET platform.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -63,7 +63,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if russ.is_connected(): for zone_id, extra in config[CONF_ZONES].items(): - add_devices([RussoundRNETDevice( + add_entities([RussoundRNETDevice( hass, russ, sources, zone_id, extra)], True) else: _LOGGER.error('Not connected to %s:%s', host, port) diff --git a/homeassistant/components/media_player/samsungtv.py b/homeassistant/components/media_player/samsungtv.py index 55b3fb0ea4f..72c3ab2c621 100644 --- a/homeassistant/components/media_player/samsungtv.py +++ b/homeassistant/components/media_player/samsungtv.py @@ -50,7 +50,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Samsung TV platform.""" known_devices = hass.data.get(KNOWN_DEVICES_KEY) if known_devices is None: @@ -81,7 +81,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ip_addr = socket.gethostbyname(host) if ip_addr not in known_devices: known_devices.add(ip_addr) - add_devices([SamsungTVDevice(host, port, name, timeout, mac)]) + add_entities([SamsungTVDevice(host, port, name, timeout, mac)]) _LOGGER.info("Samsung TV %s:%d added as '%s'", host, port, name) else: _LOGGER.info("Ignoring duplicate Samsung TV %s:%d", host, port) diff --git a/homeassistant/components/media_player/sisyphus.py b/homeassistant/components/media_player/sisyphus.py index 9a94da158a1..36f28769b12 100644 --- a/homeassistant/components/media_player/sisyphus.py +++ b/homeassistant/components/media_player/sisyphus.py @@ -39,11 +39,11 @@ SUPPORTED_FEATURES = SUPPORT_VOLUME_MUTE \ # pylint: disable=unused-argument -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a media player entity for a Sisyphus table.""" name = discovery_info[CONF_NAME] host = discovery_info[CONF_HOST] - add_devices( + add_entities( [SisyphusPlayer(name, host, hass.data[DATA_SISYPHUS][name])], update_before_add=True) diff --git a/homeassistant/components/media_player/snapcast.py b/homeassistant/components/media_player/snapcast.py index a880d3c920d..84864caeed1 100644 --- a/homeassistant/components/media_player/snapcast.py +++ b/homeassistant/components/media_player/snapcast.py @@ -47,7 +47,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Snapcast platform.""" import snapcast.control from snapcast.control.server import CONTROL_PORT @@ -86,7 +87,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): clients = [SnapcastClientDevice(client, hpid) for client in server.clients] devices = groups + clients hass.data[DATA_KEY] = devices - async_add_devices(devices) + async_add_entities(devices) class SnapcastGroupDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/songpal.py b/homeassistant/components/media_player/songpal.py index 5d0962775f0..c1bfbbe59cd 100644 --- a/homeassistant/components/media_player/songpal.py +++ b/homeassistant/components/media_player/songpal.py @@ -47,7 +47,7 @@ SET_SOUND_SCHEMA = vol.Schema({ async def async_setup_platform(hass, config, - async_add_devices, discovery_info=None): + async_add_entities, discovery_info=None): """Set up the Songpal platform.""" from songpal import SongpalException if PLATFORM not in hass.data: @@ -72,7 +72,7 @@ async def async_setup_platform(hass, config, hass.data[PLATFORM][endpoint] = device - async_add_devices([device], True) + async_add_entities([device], True) async def async_service_handler(service): """Service handler.""" diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 96038e7bb2b..c4309519e36 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -121,27 +121,27 @@ class SonosData: self.topology_lock = threading.Lock() -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sonos platform. Deprecated. """ _LOGGER.warning('Loading Sonos via platform config is deprecated.') - _setup_platform(hass, config, add_devices, discovery_info) + _setup_platform(hass, config, add_entities, discovery_info) -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up Sonos from a config entry.""" - def add_devices(devices, update_before_add=False): + def add_entities(devices, update_before_add=False): """Sync version of async add devices.""" - hass.add_job(async_add_devices, devices, update_before_add) + hass.add_job(async_add_entities, devices, update_before_add) hass.add_job(_setup_platform, hass, hass.data[SONOS_DOMAIN].get('media_player', {}), - add_devices, None) + add_entities, None) -def _setup_platform(hass, config, add_devices, discovery_info): +def _setup_platform(hass, config, add_entities, discovery_info): """Set up the Sonos platform.""" import soco @@ -186,7 +186,7 @@ def _setup_platform(hass, config, add_devices, discovery_info): return hass.data[DATA_SONOS].uids.update(p.uid for p in players) - add_devices(SonosDevice(p) for p in players) + add_entities(SonosDevice(p) for p in players) _LOGGER.debug("Added %s Sonos speakers", len(players)) def service_handle(service): diff --git a/homeassistant/components/media_player/soundtouch.py b/homeassistant/components/media_player/soundtouch.py index 703c9a963ee..f2ac45a996f 100644 --- a/homeassistant/components/media_player/soundtouch.py +++ b/homeassistant/components/media_player/soundtouch.py @@ -71,7 +71,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Bose Soundtouch platform.""" if DATA_SOUNDTOUCH not in hass.data: hass.data[DATA_SOUNDTOUCH] = [] @@ -92,7 +92,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): } soundtouch_device = SoundTouchDevice(None, remote_config) hass.data[DATA_SOUNDTOUCH].append(soundtouch_device) - add_devices([soundtouch_device]) + add_entities([soundtouch_device]) else: name = config.get(CONF_NAME) remote_config = { @@ -102,7 +102,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): } soundtouch_device = SoundTouchDevice(name, remote_config) hass.data[DATA_SOUNDTOUCH].append(soundtouch_device) - add_devices([soundtouch_device]) + add_entities([soundtouch_device]) def service_handle(service): """Handle the applying of a service.""" diff --git a/homeassistant/components/media_player/spotify.py b/homeassistant/components/media_player/spotify.py index 73ec8a175b1..9fc200c67fd 100644 --- a/homeassistant/components/media_player/spotify.py +++ b/homeassistant/components/media_player/spotify.py @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ SCAN_INTERVAL = timedelta(seconds=30) -def request_configuration(hass, config, add_devices, oauth): +def request_configuration(hass, config, add_entities, oauth): """Request Spotify authorization.""" configurator = hass.components.configurator hass.data[DOMAIN] = configurator.request_config( @@ -68,7 +68,7 @@ def request_configuration(hass, config, add_devices, oauth): submit_caption=CONFIGURATOR_SUBMIT_CAPTION) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Spotify platform.""" import spotipy.oauth2 callback_url = '{}{}'.format(hass.config.api.base_url, AUTH_CALLBACK_PATH) @@ -81,8 +81,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not token_info: _LOGGER.info("no token; requesting authorization") hass.http.register_view(SpotifyAuthCallbackView( - config, add_devices, oauth)) - request_configuration(hass, config, add_devices, oauth) + config, add_entities, oauth)) + request_configuration(hass, config, add_entities, oauth) return if hass.data.get(DOMAIN): configurator = hass.components.configurator @@ -90,7 +90,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): del hass.data[DOMAIN] player = SpotifyMediaPlayer(oauth, config.get(CONF_NAME, DEFAULT_NAME), config[CONF_ALIASES]) - add_devices([player], True) + add_entities([player], True) class SpotifyAuthCallbackView(HomeAssistantView): @@ -100,10 +100,10 @@ class SpotifyAuthCallbackView(HomeAssistantView): url = AUTH_CALLBACK_PATH name = AUTH_CALLBACK_NAME - def __init__(self, config, add_devices, oauth): + def __init__(self, config, add_entities, oauth): """Initialize.""" self.config = config - self.add_devices = add_devices + self.add_entities = add_entities self.oauth = oauth @callback @@ -111,7 +111,8 @@ class SpotifyAuthCallbackView(HomeAssistantView): """Receive authorization token.""" hass = request.app['hass'] self.oauth.get_access_token(request.query['code']) - hass.async_add_job(setup_platform, hass, self.config, self.add_devices) + hass.async_add_job( + setup_platform, hass, self.config, self.add_entities) class SpotifyMediaPlayer(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/squeezebox.py b/homeassistant/components/media_player/squeezebox.py index 8eb4c85f6b2..a2732b5f849 100644 --- a/homeassistant/components/media_player/squeezebox.py +++ b/homeassistant/components/media_player/squeezebox.py @@ -65,7 +65,8 @@ SERVICE_TO_METHOD = { @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the squeezebox platform.""" import socket @@ -108,7 +109,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): players = yield from lms.create_players() hass.data[DATA_SQUEEZEBOX].extend(players) - async_add_devices(players) + async_add_entities(players) @asyncio.coroutine def async_service_handler(service): diff --git a/homeassistant/components/media_player/ue_smart_radio.py b/homeassistant/components/media_player/ue_smart_radio.py index 2684a819417..ae7617ead24 100644 --- a/homeassistant/components/media_player/ue_smart_radio.py +++ b/homeassistant/components/media_player/ue_smart_radio.py @@ -53,7 +53,7 @@ def send_request(payload, session): return request.json() -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Logitech UE Smart Radio platform.""" email = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): player_id = player_request["result"]["players_loop"][0]["playerid"] player_name = player_request["result"]["players_loop"][0]["name"] - add_devices([UERadioDevice(session, player_id, player_name)]) + add_entities([UERadioDevice(session, player_id, player_name)]) class UERadioDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/universal.py b/homeassistant/components/media_player/universal.py index 66d12190320..1572e2df89b 100644 --- a/homeassistant/components/media_player/universal.py +++ b/homeassistant/components/media_player/universal.py @@ -62,7 +62,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }, extra=vol.REMOVE_EXTRA) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the universal media players.""" player = UniversalMediaPlayer( @@ -74,7 +74,7 @@ async def async_setup_platform(hass, config, async_add_devices, config.get(CONF_STATE_TEMPLATE) ) - async_add_devices([player]) + async_add_entities([player]) class UniversalMediaPlayer(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/vizio.py b/homeassistant/components/media_player/vizio.py index 40ad0ef209c..673be3074de 100644 --- a/homeassistant/components/media_player/vizio.py +++ b/homeassistant/components/media_player/vizio.py @@ -53,7 +53,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the VizioTV media player platform.""" host = config.get(CONF_HOST) token = config.get(CONF_ACCESS_TOKEN) @@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.warning("InsecureRequestWarning is disabled " "because of Vizio platform configuration") urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) - add_devices([device], True) + add_entities([device], True) class VizioDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/vlc.py b/homeassistant/components/media_player/vlc.py index 45e1a91c510..075a533e372 100644 --- a/homeassistant/components/media_player/vlc.py +++ b/homeassistant/components/media_player/vlc.py @@ -34,10 +34,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the vlc platform.""" - add_devices([VlcDevice(config.get(CONF_NAME, DEFAULT_NAME), - config.get(CONF_ARGUMENTS))]) + add_entities([VlcDevice(config.get(CONF_NAME, DEFAULT_NAME), + config.get(CONF_ARGUMENTS))]) class VlcDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/volumio.py b/homeassistant/components/media_player/volumio.py index c4ddd38fc4f..00f5d25362f 100644 --- a/homeassistant/components/media_player/volumio.py +++ b/homeassistant/components/media_player/volumio.py @@ -51,7 +51,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Volumio platform.""" if DATA_VOLUMIO not in hass.data: hass.data[DATA_VOLUMIO] = dict() @@ -75,7 +76,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): entity = Volumio(name, host, port, hass) hass.data[DATA_VOLUMIO][ip_addr] = entity - async_add_devices([entity]) + async_add_entities([entity]) class Volumio(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/webostv.py b/homeassistant/components/media_player/webostv.py index 362095daee6..fd6b1c6d96e 100644 --- a/homeassistant/components/media_player/webostv.py +++ b/homeassistant/components/media_player/webostv.py @@ -61,7 +61,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LG WebOS TV platform.""" if discovery_info is not None: host = urlparse(discovery_info[1]).hostname @@ -84,11 +84,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None): config = hass.config.path(config.get(CONF_FILENAME)) setup_tv(host, name, customize, config, timeout, hass, - add_devices, turn_on_action) + add_entities, turn_on_action) def setup_tv(host, name, customize, config, timeout, hass, - add_devices, turn_on_action): + add_entities, turn_on_action): """Set up a LG WebOS TV based on host parameter.""" from pylgtv import WebOsClient from pylgtv import PyLGTVPairException @@ -113,7 +113,7 @@ def setup_tv(host, name, customize, config, timeout, hass, _LOGGER.warning("LG webOS TV %s needs to be paired", host) request_configuration( host, name, customize, config, timeout, hass, - add_devices, turn_on_action) + add_entities, turn_on_action) return # If we came here and configuring this host, mark as done. @@ -122,13 +122,13 @@ def setup_tv(host, name, customize, config, timeout, hass, configurator = hass.components.configurator configurator.request_done(request_id) - add_devices([LgWebOSDevice(host, name, customize, config, timeout, - hass, turn_on_action)], True) + add_entities([LgWebOSDevice(host, name, customize, config, timeout, + hass, turn_on_action)], True) def request_configuration( host, name, customize, config, timeout, hass, - add_devices, turn_on_action): + add_entities, turn_on_action): """Request configuration steps from the user.""" configurator = hass.components.configurator @@ -141,7 +141,7 @@ def request_configuration( def lgtv_configuration_callback(data): """Handle actions when configuration callback is called.""" setup_tv(host, name, customize, config, timeout, hass, - add_devices, turn_on_action) + add_entities, turn_on_action) _CONFIGURING[host] = configurator.request_config( name, lgtv_configuration_callback, diff --git a/homeassistant/components/media_player/xiaomi_tv.py b/homeassistant/components/media_player/xiaomi_tv.py index d44ac138e41..ad66ae855bd 100644 --- a/homeassistant/components/media_player/xiaomi_tv.py +++ b/homeassistant/components/media_player/xiaomi_tv.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Xiaomi TV platform.""" from pymitv import Discover @@ -45,10 +45,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) else: # Register TV with Home Assistant. - add_devices([XiaomiTV(host, name)]) + add_entities([XiaomiTV(host, name)]) else: # Otherwise, discover TVs on network. - add_devices(XiaomiTV(tv, DEFAULT_NAME) for tv in Discover().scan()) + add_entities(XiaomiTV(tv, DEFAULT_NAME) for tv in Discover().scan()) class XiaomiTV(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/yamaha.py b/homeassistant/components/media_player/yamaha.py index cf363458067..2ffe58b02af 100644 --- a/homeassistant/components/media_player/yamaha.py +++ b/homeassistant/components/media_player/yamaha.py @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yamaha platform.""" import rxv # Keep track of configured receivers so that we don't end up @@ -126,7 +126,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): DOMAIN, SERVICE_ENABLE_OUTPUT, service_handler, schema=ENABLE_OUTPUT_SCHEMA) - add_devices(devices) + add_entities(devices) class YamahaDevice(MediaPlayerDevice): diff --git a/homeassistant/components/media_player/yamaha_musiccast.py b/homeassistant/components/media_player/yamaha_musiccast.py index b42a5ae474c..135bf4d0aef 100644 --- a/homeassistant/components/media_player/yamaha_musiccast.py +++ b/homeassistant/components/media_player/yamaha_musiccast.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yamaha MusicCast platform.""" import socket import pymusiccast @@ -93,7 +93,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.debug( "receiver: %s / Port: %d / Zone: %s", receiver, port, zone) - add_devices( + add_entities( [YamahaDevice(receiver, receiver.zones[zone])], True) else: diff --git a/homeassistant/components/media_player/ziggo_mediabox_xl.py b/homeassistant/components/media_player/ziggo_mediabox_xl.py index 1886cd751ea..376b9e7c426 100644 --- a/homeassistant/components/media_player/ziggo_mediabox_xl.py +++ b/homeassistant/components/media_player/ziggo_mediabox_xl.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ziggo Mediabox XL platform.""" from ziggo_mediabox_xl import ZiggoMediaboxXL @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Can't connect to %s: %s", host, error) else: _LOGGER.info("Ignoring duplicate Ziggo Mediabox XL %s", host) - add_devices(hosts, True) + add_entities(hosts, True) class ZiggoMediaboxXLDevice(MediaPlayerDevice): diff --git a/homeassistant/components/mysensors/__init__.py b/homeassistant/components/mysensors/__init__.py index 7ca9ea9f9ea..725494cd197 100644 --- a/homeassistant/components/mysensors/__init__.py +++ b/homeassistant/components/mysensors/__init__.py @@ -130,7 +130,7 @@ def _get_mysensors_name(gateway, node_id, child_id): @callback def setup_mysensors_platform( hass, domain, discovery_info, device_class, device_args=None, - async_add_devices=None): + async_add_entities=None): """Set up a MySensors platform.""" # Only act if called via MySensors by discovery event. # Otherwise gateway is not set up. @@ -161,6 +161,6 @@ def setup_mysensors_platform( new_devices.append(devices[dev_id]) if new_devices: _LOGGER.info("Adding new devices: %s", new_devices) - if async_add_devices is not None: - async_add_devices(new_devices, True) + if async_add_entities is not None: + async_add_entities(new_devices, True) return new_devices diff --git a/homeassistant/components/remote/apple_tv.py b/homeassistant/components/remote/apple_tv.py index 7d11c931a65..d8eac11372c 100644 --- a/homeassistant/components/remote/apple_tv.py +++ b/homeassistant/components/remote/apple_tv.py @@ -16,7 +16,8 @@ DEPENDENCIES = ['apple_tv'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Apple TV remote platform.""" if not discovery_info: return @@ -25,7 +26,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): host = discovery_info[CONF_HOST] atv = hass.data[DATA_APPLE_TV][host][ATTR_ATV] power = hass.data[DATA_APPLE_TV][host][ATTR_POWER] - async_add_devices([AppleTVRemote(atv, power, name)]) + async_add_entities([AppleTVRemote(atv, power, name)]) class AppleTVRemote(remote.RemoteDevice): diff --git a/homeassistant/components/remote/demo.py b/homeassistant/components/remote/demo.py index d959d74574f..f44061ac8f9 100644 --- a/homeassistant/components/remote/demo.py +++ b/homeassistant/components/remote/demo.py @@ -8,9 +8,9 @@ from homeassistant.components.remote import RemoteDevice from homeassistant.const import DEVICE_DEFAULT_NAME -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up the demo remotes.""" - add_devices_callback([ + add_entities_callback([ DemoRemote('Remote One', False, None), DemoRemote('Remote Two', True, 'mdi:remote'), ]) diff --git a/homeassistant/components/remote/harmony.py b/homeassistant/components/remote/harmony.py index a63b7325035..5b7d0d1df78 100644 --- a/homeassistant/components/remote/harmony.py +++ b/homeassistant/components/remote/harmony.py @@ -44,7 +44,7 @@ HARMONY_SYNC_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Harmony platform.""" host = None activity = None @@ -96,7 +96,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device = HarmonyRemote( name, address, port, activity, harmony_conf_file, delay_secs) DEVICES.append(device) - add_devices([device]) + add_entities([device]) register_services(hass) except (ValueError, AttributeError): raise PlatformNotReady diff --git a/homeassistant/components/remote/itach.py b/homeassistant/components/remote/itach.py index 829a038953c..e7f23dfcd13 100644 --- a/homeassistant/components/remote/itach.py +++ b/homeassistant/components/remote/itach.py @@ -44,7 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ITach connection and devices.""" import pyitachip2ir itachip2ir = pyitachip2ir.ITachIP2IR( @@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): cmddatas += "{}\n{}\n".format(cmdname, cmddata) itachip2ir.addDevice(name, modaddr, connaddr, cmddatas) devices.append(ITachIP2IRRemote(itachip2ir, name)) - add_devices(devices, True) + add_entities(devices, True) return True diff --git a/homeassistant/components/remote/kira.py b/homeassistant/components/remote/kira.py index dc37eb760f7..24fc54ee78c 100644 --- a/homeassistant/components/remote/kira.py +++ b/homeassistant/components/remote/kira.py @@ -18,14 +18,14 @@ _LOGGER = logging.getLogger(__name__) CONF_REMOTE = "remote" -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Kira platform.""" if discovery_info: name = discovery_info.get(CONF_NAME) device = discovery_info.get(CONF_DEVICE) kira = hass.data[DOMAIN][CONF_REMOTE][name] - add_devices([KiraRemote(device, kira)]) + add_entities([KiraRemote(device, kira)]) return True diff --git a/homeassistant/components/remote/xiaomi_miio.py b/homeassistant/components/remote/xiaomi_miio.py index 1cc48f7adb2..7fbcba5a26e 100644 --- a/homeassistant/components/remote/xiaomi_miio.py +++ b/homeassistant/components/remote/xiaomi_miio.py @@ -62,7 +62,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Xiaomi IR Remote (Chuangmi IR) platform.""" from miio import ChuangmiIr, DeviceException @@ -106,7 +107,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass.data[DATA_KEY][host] = xiaomi_miio_remote - async_add_devices([xiaomi_miio_remote]) + async_add_entities([xiaomi_miio_remote]) @asyncio.coroutine def async_service_handler(service): diff --git a/homeassistant/components/scene/deconz.py b/homeassistant/components/scene/deconz.py index 3eb73736717..dde78dadc49 100644 --- a/homeassistant/components/scene/deconz.py +++ b/homeassistant/components/scene/deconz.py @@ -11,20 +11,20 @@ from homeassistant.components.scene import Scene DEPENDENCIES = ['deconz'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ scenes.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up scenes for deCONZ component.""" scenes = hass.data[DATA_DECONZ].scenes entities = [] for scene in scenes.values(): entities.append(DeconzScene(scene)) - async_add_devices(entities) + async_add_entities(entities) class DeconzScene(Scene): diff --git a/homeassistant/components/scene/homeassistant.py b/homeassistant/components/scene/homeassistant.py index 57c56e8b2f6..7e1d670ca69 100644 --- a/homeassistant/components/scene/homeassistant.py +++ b/homeassistant/components/scene/homeassistant.py @@ -36,11 +36,12 @@ SCENECONFIG = namedtuple('SceneConfig', [CONF_NAME, STATES]) @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up home assistant scene entries.""" scene_config = config.get(STATES) - async_add_devices(HomeAssistantScene( + async_add_entities(HomeAssistantScene( hass, _process_config(scene)) for scene in scene_config) return True diff --git a/homeassistant/components/scene/hunterdouglas_powerview.py b/homeassistant/components/scene/hunterdouglas_powerview.py index 4f5ac5725a3..40534b68635 100644 --- a/homeassistant/components/scene/hunterdouglas_powerview.py +++ b/homeassistant/components/scene/hunterdouglas_powerview.py @@ -37,7 +37,8 @@ STATE_ATTRIBUTE_ROOM_NAME = 'roomName' @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up home assistant scene entries.""" # from aiopvapi.hub import Hub from aiopvapi.scenes import Scenes @@ -60,7 +61,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): PvScene(_raw_scene, hub_address, hass.loop, websession), _rooms) for _raw_scene in _scenes[SCENE_DATA]) - async_add_devices(pvscenes) + async_add_entities(pvscenes) class PowerViewScene(Scene): diff --git a/homeassistant/components/scene/knx.py b/homeassistant/components/scene/knx.py index 901e25aea82..cd333ba79b4 100644 --- a/homeassistant/components/scene/knx.py +++ b/homeassistant/components/scene/knx.py @@ -26,27 +26,27 @@ PLATFORM_SCHEMA = vol.Schema({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the scenes for KNX platform.""" if discovery_info is not None: - async_add_devices_discovery(hass, discovery_info, async_add_devices) + async_add_entities_discovery(hass, discovery_info, async_add_entities) else: - async_add_devices_config(hass, config, async_add_devices) + async_add_entities_config(hass, config, async_add_entities) @callback -def async_add_devices_discovery(hass, discovery_info, async_add_devices): +def async_add_entities_discovery(hass, discovery_info, async_add_entities): """Set up scenes for KNX platform configured via xknx.yaml.""" entities = [] for device_name in discovery_info[ATTR_DISCOVER_DEVICES]: device = hass.data[DATA_KNX].xknx.devices[device_name] entities.append(KNXScene(device)) - async_add_devices(entities) + async_add_entities(entities) @callback -def async_add_devices_config(hass, config, async_add_devices): +def async_add_entities_config(hass, config, async_add_entities): """Set up scene for KNX platform configured within platform.""" import xknx scene = xknx.devices.Scene( @@ -55,7 +55,7 @@ def async_add_devices_config(hass, config, async_add_devices): group_address=config.get(CONF_ADDRESS), scene_number=config.get(CONF_SCENE_NUMBER)) hass.data[DATA_KNX].xknx.devices.add(scene) - async_add_devices([KNXScene(scene)]) + async_add_entities([KNXScene(scene)]) class KNXScene(Scene): diff --git a/homeassistant/components/scene/lifx_cloud.py b/homeassistant/components/scene/lifx_cloud.py index a9ec1ef679c..3169acb3a31 100644 --- a/homeassistant/components/scene/lifx_cloud.py +++ b/homeassistant/components/scene/lifx_cloud.py @@ -30,7 +30,8 @@ PLATFORM_SCHEMA = vol.Schema({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the scenes stored in the LIFX Cloud.""" token = config.get(CONF_TOKEN) timeout = config.get(CONF_TIMEOUT) @@ -56,7 +57,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): devices = [] for scene in data: devices.append(LifxCloudScene(hass, headers, timeout, scene)) - async_add_devices(devices) + async_add_entities(devices) return True if status == 401: _LOGGER.error("Unauthorized (bad token?) on %s", url) diff --git a/homeassistant/components/scene/litejet.py b/homeassistant/components/scene/litejet.py index 87539e2dded..e12643fa651 100644 --- a/homeassistant/components/scene/litejet.py +++ b/homeassistant/components/scene/litejet.py @@ -16,7 +16,7 @@ ATTR_NUMBER = 'number' _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up scenes for the LiteJet platform.""" litejet_ = hass.data['litejet_system'] @@ -25,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = litejet_.get_scene_name(i) if not litejet.is_ignored(hass, name): devices.append(LiteJetScene(litejet_, i, name)) - add_devices(devices) + add_entities(devices) class LiteJetScene(Scene): diff --git a/homeassistant/components/scene/lutron_caseta.py b/homeassistant/components/scene/lutron_caseta.py index 0d9024d194e..0f9173663a9 100644 --- a/homeassistant/components/scene/lutron_caseta.py +++ b/homeassistant/components/scene/lutron_caseta.py @@ -16,7 +16,8 @@ DEPENDENCIES = ['lutron_caseta'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Lutron Caseta lights.""" devs = [] bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] @@ -25,7 +26,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): dev = LutronCasetaScene(scenes[scene], bridge) devs.append(dev) - async_add_devices(devs, True) + async_add_entities(devs, True) class LutronCasetaScene(Scene): diff --git a/homeassistant/components/scene/tahoma.py b/homeassistant/components/scene/tahoma.py index 39206623901..5846d97c7f9 100644 --- a/homeassistant/components/scene/tahoma.py +++ b/homeassistant/components/scene/tahoma.py @@ -15,13 +15,13 @@ DEPENDENCIES = ['tahoma'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tahoma scenes.""" controller = hass.data[TAHOMA_DOMAIN]['controller'] scenes = [] for scene in hass.data[TAHOMA_DOMAIN]['scenes']: scenes.append(TahomaScene(scene, controller)) - add_devices(scenes, True) + add_entities(scenes, True) class TahomaScene(Scene): diff --git a/homeassistant/components/scene/tuya.py b/homeassistant/components/scene/tuya.py index 3990a7da206..2e03e5dba9a 100644 --- a/homeassistant/components/scene/tuya.py +++ b/homeassistant/components/scene/tuya.py @@ -12,7 +12,7 @@ DEPENDENCIES = ['tuya'] ENTITY_ID_FORMAT = DOMAIN + '.{}' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tuya scenes.""" if discovery_info is None: return @@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device is None: continue devices.append(TuyaScene(device)) - add_devices(devices) + add_entities(devices) class TuyaScene(TuyaDevice, Scene): diff --git a/homeassistant/components/scene/velux.py b/homeassistant/components/scene/velux.py index 63bb23b1086..77ba30158e4 100644 --- a/homeassistant/components/scene/velux.py +++ b/homeassistant/components/scene/velux.py @@ -12,13 +12,13 @@ from homeassistant.components.velux import _LOGGER, DATA_VELUX DEPENDENCIES = ['velux'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the scenes for velux platform.""" entities = [] for scene in hass.data[DATA_VELUX].pyvlx.scenes: entities.append(VeluxScene(scene)) - async_add_devices(entities) + async_add_entities(entities) class VeluxScene(Scene): diff --git a/homeassistant/components/scene/vera.py b/homeassistant/components/scene/vera.py index 4f580356fbb..6cae1195f87 100644 --- a/homeassistant/components/scene/vera.py +++ b/homeassistant/components/scene/vera.py @@ -16,9 +16,9 @@ DEPENDENCIES = ['vera'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vera scenes.""" - add_devices( + add_entities( [VeraScene(scene, hass.data[VERA_CONTROLLER]) for scene in hass.data[VERA_SCENES]], True) diff --git a/homeassistant/components/scene/wink.py b/homeassistant/components/scene/wink.py index 5bd053bdd39..62da668694b 100644 --- a/homeassistant/components/scene/wink.py +++ b/homeassistant/components/scene/wink.py @@ -15,14 +15,14 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['wink'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink platform.""" import pywink for scene in pywink.get_scenes(): _id = scene.object_id() + scene.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkScene(scene, hass)]) + add_entities([WinkScene(scene, hass)]) class WinkScene(WinkDevice, Scene): diff --git a/homeassistant/components/sensor/abode.py b/homeassistant/components/sensor/abode.py index 26247c77454..4695a5f0471 100644 --- a/homeassistant/components/sensor/abode.py +++ b/homeassistant/components/sensor/abode.py @@ -22,7 +22,7 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for an Abode device.""" import abodepy.helpers.constants as CONST @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(devices) - add_devices(devices) + add_entities(devices) class AbodeSensor(AbodeDevice): diff --git a/homeassistant/components/sensor/ads.py b/homeassistant/components/sensor/ads.py index 659ac6d7e5d..5d5cbb379bf 100644 --- a/homeassistant/components/sensor/ads.py +++ b/homeassistant/components/sensor/ads.py @@ -32,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an ADS sensor device.""" ads_hub = hass.data.get(ads.DATA_ADS) @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): entity = AdsSensor( ads_hub, ads_var, ads_type, name, unit_of_measurement, factor) - add_devices([entity]) + add_entities([entity]) class AdsSensor(Entity): diff --git a/homeassistant/components/sensor/airvisual.py b/homeassistant/components/sensor/airvisual.py index 403722c7b6a..dcd89ccb78a 100644 --- a/homeassistant/components/sensor/airvisual.py +++ b/homeassistant/components/sensor/airvisual.py @@ -117,7 +117,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Configure the platform and add the sensors.""" from pyairvisual import Client @@ -161,7 +161,7 @@ async def async_setup_platform( AirVisualSensor( data, kind, name, icon, unit, locale, location_id)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class AirVisualSensor(Entity): diff --git a/homeassistant/components/sensor/alarmdecoder.py b/homeassistant/components/sensor/alarmdecoder.py index ce709eee94c..51e166bfce6 100644 --- a/homeassistant/components/sensor/alarmdecoder.py +++ b/homeassistant/components/sensor/alarmdecoder.py @@ -15,13 +15,13 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['alarmdecoder'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up for AlarmDecoder sensor devices.""" _LOGGER.debug("AlarmDecoderSensor: setup_platform") device = AlarmDecoderSensor(hass) - add_devices([device]) + add_entities([device]) class AlarmDecoderSensor(Entity): diff --git a/homeassistant/components/sensor/alpha_vantage.py b/homeassistant/components/sensor/alpha_vantage.py index a7e6f6d2622..c0b280d2d69 100644 --- a/homeassistant/components/sensor/alpha_vantage.py +++ b/homeassistant/components/sensor/alpha_vantage.py @@ -63,7 +63,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Alpha Vantage sensor.""" from alpha_vantage.timeseries import TimeSeries from alpha_vantage.foreignexchange import ForeignExchange @@ -107,7 +107,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.debug(str(error)) dev.append(AlphaVantageForeignExchange(forex, conversion)) - add_devices(dev, True) + add_entities(dev, True) _LOGGER.debug("Setup completed") diff --git a/homeassistant/components/sensor/amcrest.py b/homeassistant/components/sensor/amcrest.py index 99a4371f6a2..53a8c663f21 100644 --- a/homeassistant/components/sensor/amcrest.py +++ b/homeassistant/components/sensor/amcrest.py @@ -20,7 +20,8 @@ SCAN_INTERVAL = timedelta(seconds=10) @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up a sensor for an Amcrest IP Camera.""" if discovery_info is None: return @@ -34,7 +35,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): amcrest_sensors.append( AmcrestSensor(amcrest.name, amcrest.device, sensor_type)) - async_add_devices(amcrest_sensors, True) + async_add_entities(amcrest_sensors, True) return True diff --git a/homeassistant/components/sensor/android_ip_webcam.py b/homeassistant/components/sensor/android_ip_webcam.py index f25056d5a0f..333bf12ec21 100644 --- a/homeassistant/components/sensor/android_ip_webcam.py +++ b/homeassistant/components/sensor/android_ip_webcam.py @@ -15,7 +15,8 @@ DEPENDENCIES = ['android_ip_webcam'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the IP Webcam Sensor.""" if discovery_info is None: return @@ -30,7 +31,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for sensor in sensors: all_sensors.append(IPWebcamSensor(name, host, ipcam, sensor)) - async_add_devices(all_sensors, True) + async_add_entities(all_sensors, True) class IPWebcamSensor(AndroidIPCamEntity): diff --git a/homeassistant/components/sensor/api_streams.py b/homeassistant/components/sensor/api_streams.py index 0d193dee79b..1ecae1e753e 100644 --- a/homeassistant/components/sensor/api_streams.py +++ b/homeassistant/components/sensor/api_streams.py @@ -49,7 +49,8 @@ class StreamHandler(logging.Handler): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the API stream platform.""" entity = APICount() handler = StreamHandler(entity) @@ -65,7 +66,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, remove_logger) - async_add_devices([entity]) + async_add_entities([entity]) class APICount(Entity): diff --git a/homeassistant/components/sensor/arduino.py b/homeassistant/components/sensor/arduino.py index d4d8ea09d29..f46eebce1b2 100644 --- a/homeassistant/components/sensor/arduino.py +++ b/homeassistant/components/sensor/arduino.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Arduino platform.""" if arduino.BOARD is None: _LOGGER.error("A connection has not been made to the Arduino board") @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors = [] for pinnum, pin in pins.items(): sensors.append(ArduinoSensor(pin.get(CONF_NAME), pinnum, CONF_TYPE)) - add_devices(sensors) + add_entities(sensors) class ArduinoSensor(Entity): diff --git a/homeassistant/components/sensor/arest.py b/homeassistant/components/sensor/arest.py index 751f0f11171..3d85a331f6f 100644 --- a/homeassistant/components/sensor/arest.py +++ b/homeassistant/components/sensor/arest.py @@ -44,7 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the aREST sensor.""" resource = config.get(CONF_RESOURCE) var_conf = config.get(CONF_MONITORED_VARIABLES) @@ -102,7 +102,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): pin=pinnum, unit_of_measurement=pin.get( CONF_UNIT_OF_MEASUREMENT), renderer=renderer)) - add_devices(dev, True) + add_entities(dev, True) class ArestSensor(Entity): diff --git a/homeassistant/components/sensor/arlo.py b/homeassistant/components/sensor/arlo.py index 6d764b1c916..be940cc4f51 100644 --- a/homeassistant/components/sensor/arlo.py +++ b/homeassistant/components/sensor/arlo.py @@ -43,7 +43,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an Arlo IP sensor.""" arlo = hass.data.get(DATA_ARLO) if not arlo: @@ -70,7 +70,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): SENSOR_TYPES[sensor_type][0], base_station.name) sensors.append(ArloSensor(name, base_station, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) class ArloSensor(Entity): diff --git a/homeassistant/components/sensor/arwn.py b/homeassistant/components/sensor/arwn.py index 6b0d3e569d7..580701490a6 100644 --- a/homeassistant/components/sensor/arwn.py +++ b/homeassistant/components/sensor/arwn.py @@ -59,7 +59,8 @@ def _slug(name): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the ARWN platform.""" @callback def async_sensor_event_received(topic, payload, qos): @@ -97,7 +98,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): store[sensor.name] = sensor _LOGGER.debug("Registering new sensor %(name)s => %(event)s", dict(name=sensor.name, event=event)) - async_add_devices((sensor,), True) + async_add_entities((sensor,), True) else: store[sensor.name].set_event(event) diff --git a/homeassistant/components/sensor/bbox.py b/homeassistant/components/sensor/bbox.py index d24621becc9..c81160dc2ae 100644 --- a/homeassistant/components/sensor/bbox.py +++ b/homeassistant/components/sensor/bbox.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Bbox sensor.""" # Create a data fetcher to support all of the configured sensors. Then make # the first call to init the data. @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_MONITORED_VARIABLES]: sensors.append(BboxSensor(bbox_data, variable, name)) - add_devices(sensors, True) + add_entities(sensors, True) class BboxSensor(Entity): diff --git a/homeassistant/components/sensor/bh1750.py b/homeassistant/components/sensor/bh1750.py index 6d34d4ea9f8..6230ae8a74d 100644 --- a/homeassistant/components/sensor/bh1750.py +++ b/homeassistant/components/sensor/bh1750.py @@ -67,7 +67,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=import-error @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the BH1750 sensor.""" import smbus from i2csense.bh1750 import BH1750 @@ -95,7 +96,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.info("Setup of BH1750 light sensor at %s in mode %s is complete", i2c_address, operation_mode) - async_add_devices(dev, True) + async_add_entities(dev, True) class BH1750Sensor(Entity): diff --git a/homeassistant/components/sensor/bitcoin.py b/homeassistant/components/sensor/bitcoin.py index f51b7dcd5bd..34855d19104 100644 --- a/homeassistant/components/sensor/bitcoin.py +++ b/homeassistant/components/sensor/bitcoin.py @@ -58,7 +58,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Bitcoin sensors.""" from blockchain import exchangerates @@ -73,7 +73,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_DISPLAY_OPTIONS]: dev.append(BitcoinSensor(data, variable, currency)) - add_devices(dev, True) + add_entities(dev, True) class BitcoinSensor(Entity): diff --git a/homeassistant/components/sensor/blink.py b/homeassistant/components/sensor/blink.py index db7ab7c2e9e..97356b6fc61 100644 --- a/homeassistant/components/sensor/blink.py +++ b/homeassistant/components/sensor/blink.py @@ -21,7 +21,7 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Blink sensor.""" if discovery_info is None: return @@ -35,7 +35,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devs.append(BlinkSensor(name, 'notifications', index, data)) index += 1 - add_devices(devs, True) + add_entities(devs, True) class BlinkSensor(Entity): diff --git a/homeassistant/components/sensor/blockchain.py b/homeassistant/components/sensor/blockchain.py index 2276f5fc1b7..e51db7edcad 100644 --- a/homeassistant/components/sensor/blockchain.py +++ b/homeassistant/components/sensor/blockchain.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Blockchain.info sensors.""" from pyblockchain import validate_address @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Bitcoin address is not valid: %s", address) return False - add_devices([BlockchainSensor(name, addresses)], True) + add_entities([BlockchainSensor(name, addresses)], True) class BlockchainSensor(Entity): diff --git a/homeassistant/components/sensor/bloomsky.py b/homeassistant/components/sensor/bloomsky.py index d33796d04cc..8926848102c 100644 --- a/homeassistant/components/sensor/bloomsky.py +++ b/homeassistant/components/sensor/bloomsky.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the available BloomSky weather sensors.""" bloomsky = hass.components.bloomsky # Default needed in case of discovery @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in bloomsky.BLOOMSKY.devices.values(): for variable in sensors: - add_devices( + add_entities( [BloomSkySensor(bloomsky.BLOOMSKY, device, variable)], True) diff --git a/homeassistant/components/sensor/bme280.py b/homeassistant/components/sensor/bme280.py index 1685d34c0ec..676800c1069 100644 --- a/homeassistant/components/sensor/bme280.py +++ b/homeassistant/components/sensor/bme280.py @@ -82,7 +82,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=import-error @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the BME280 sensor.""" import smbus from i2csense.bme280 import BME280 @@ -117,7 +118,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): except KeyError: pass - async_add_devices(dev, True) + async_add_entities(dev, True) class BME280Handler: diff --git a/homeassistant/components/sensor/bme680.py b/homeassistant/components/sensor/bme680.py index 2dbda26ac32..65d486ada36 100644 --- a/homeassistant/components/sensor/bme680.py +++ b/homeassistant/components/sensor/bme680.py @@ -98,7 +98,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the BME680 sensor.""" SENSOR_TYPES[SENSOR_TEMP][1] = hass.config.units.temperature_unit name = config.get(CONF_NAME) @@ -112,7 +113,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): dev.append(BME680Sensor( sensor_handler, variable, SENSOR_TYPES[variable][1], name)) - async_add_devices(dev) + async_add_entities(dev) return diff --git a/homeassistant/components/sensor/bmw_connected_drive.py b/homeassistant/components/sensor/bmw_connected_drive.py index deafacc288c..ff80100e21d 100644 --- a/homeassistant/components/sensor/bmw_connected_drive.py +++ b/homeassistant/components/sensor/bmw_connected_drive.py @@ -27,7 +27,7 @@ ATTR_TO_HA = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the BMW sensors.""" accounts = hass.data[BMW_DOMAIN] _LOGGER.debug('Found BMW accounts: %s', @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(device) device = BMWConnectedDriveSensor(account, vehicle, 'mileage') devices.append(device) - add_devices(devices, True) + add_entities(devices, True) class BMWConnectedDriveSensor(Entity): diff --git a/homeassistant/components/sensor/bom.py b/homeassistant/components/sensor/bom.py index eb63e116254..11685c7ff68 100644 --- a/homeassistant/components/sensor/bom.py +++ b/homeassistant/components/sensor/bom.py @@ -99,7 +99,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the BOM sensor.""" station = config.get(CONF_STATION) zone_id, wmo_id = config.get(CONF_ZONE_ID), config.get(CONF_WMO_ID) @@ -127,8 +127,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Received error from BOM Current: %s", err) return - add_devices([BOMCurrentSensor(bom_data, variable, config.get(CONF_NAME)) - for variable in config[CONF_MONITORED_CONDITIONS]]) + add_entities([BOMCurrentSensor(bom_data, variable, config.get(CONF_NAME)) + for variable in config[CONF_MONITORED_CONDITIONS]]) class BOMCurrentSensor(Entity): diff --git a/homeassistant/components/sensor/broadlink.py b/homeassistant/components/sensor/broadlink.py index 06d7f512c9f..21e5b0ee1d9 100644 --- a/homeassistant/components/sensor/broadlink.py +++ b/homeassistant/components/sensor/broadlink.py @@ -47,7 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Broadlink device sensors.""" host = config.get(CONF_HOST) mac = config.get(CONF_MAC).encode().replace(b':', b'') @@ -59,7 +59,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev = [] for variable in config[CONF_MONITORED_CONDITIONS]: dev.append(BroadlinkSensor(name, broadlink_data, variable)) - add_devices(dev, True) + add_entities(dev, True) class BroadlinkSensor(Entity): diff --git a/homeassistant/components/sensor/buienradar.py b/homeassistant/components/sensor/buienradar.py index 992c27bbe2e..c7ca0c097ff 100644 --- a/homeassistant/components/sensor/buienradar.py +++ b/homeassistant/components/sensor/buienradar.py @@ -141,7 +141,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Create the buienradar sensor.""" from homeassistant.components.weather.buienradar import DEFAULT_TIMEFRAME @@ -163,7 +164,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for sensor_type in config[CONF_MONITORED_CONDITIONS]: dev.append(BrSensor(sensor_type, config.get(CONF_NAME, 'br'), coordinates)) - async_add_devices(dev) + async_add_entities(dev) data = BrData(hass, coordinates, timeframe, dev) # schedule the first update in 1 minute from now: diff --git a/homeassistant/components/sensor/canary.py b/homeassistant/components/sensor/canary.py index 51fe1d4dd7a..015c6b378e0 100644 --- a/homeassistant/components/sensor/canary.py +++ b/homeassistant/components/sensor/canary.py @@ -30,7 +30,7 @@ STATE_AIR_QUALITY_ABNORMAL = "abnormal" STATE_AIR_QUALITY_VERY_ABNORMAL = "very_abnormal" -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Canary sensors.""" data = hass.data[DATA_CANARY] devices = [] @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(CanarySensor(data, sensor_type, location, device)) - add_devices(devices, True) + add_entities(devices, True) class CanarySensor(Entity): diff --git a/homeassistant/components/sensor/cert_expiry.py b/homeassistant/components/sensor/cert_expiry.py index 00139a30620..df48ebbf41c 100644 --- a/homeassistant/components/sensor/cert_expiry.py +++ b/homeassistant/components/sensor/cert_expiry.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up certificate expiry sensor.""" def run_setup(event): """Wait until Home Assistant is fully initialized before creating. @@ -44,8 +44,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): server_port = config.get(CONF_PORT) sensor_name = config.get(CONF_NAME) - add_devices([SSLCertificate(sensor_name, server_name, server_port)], - True) + add_entities([SSLCertificate(sensor_name, server_name, server_port)], + True) # To allow checking of the HA certificate we must first be running. hass.bus.listen_once(EVENT_HOMEASSISTANT_START, run_setup) diff --git a/homeassistant/components/sensor/citybikes.py b/homeassistant/components/sensor/citybikes.py index c9a69923135..8003a77a452 100644 --- a/homeassistant/components/sensor/citybikes.py +++ b/homeassistant/components/sensor/citybikes.py @@ -126,7 +126,7 @@ def async_citybikes_request(hass, uri, schema): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, +def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the CityBikes platform.""" if PLATFORM not in hass.data: @@ -167,7 +167,7 @@ def async_setup_platform(hass, config, async_add_devices, (station_id, station_uid)): devices.append(CityBikesStation(hass, network, station_id, name)) - async_add_devices(devices, True) + async_add_entities(devices, True) class CityBikesNetwork: diff --git a/homeassistant/components/sensor/coinbase.py b/homeassistant/components/sensor/coinbase.py index 32e1d8f211a..40444dee93c 100644 --- a/homeassistant/components/sensor/coinbase.py +++ b/homeassistant/components/sensor/coinbase.py @@ -21,7 +21,7 @@ DEPENDENCIES = ['coinbase'] ETH_ICON = 'mdi:currency-eth' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Coinbase sensors.""" if discovery_info is None: return @@ -35,7 +35,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass.data[DATA_COINBASE], discovery_info['exchange_currency'], discovery_info['native_currency']) - add_devices([sensor], True) + add_entities([sensor], True) class AccountSensor(Entity): diff --git a/homeassistant/components/sensor/coinmarketcap.py b/homeassistant/components/sensor/coinmarketcap.py index c4f38b1be02..18d3f0a3d00 100644 --- a/homeassistant/components/sensor/coinmarketcap.py +++ b/homeassistant/components/sensor/coinmarketcap.py @@ -56,7 +56,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the CoinMarketCap sensor.""" currency_id = config.get(CONF_CURRENCY_ID) display_currency = config.get(CONF_DISPLAY_CURRENCY).upper() @@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): currency_id = DEFAULT_CURRENCY_ID display_currency = DEFAULT_DISPLAY_CURRENCY - add_devices([CoinMarketCapSensor( + add_entities([CoinMarketCapSensor( CoinMarketCapData( currency_id, display_currency), display_currency_decimals)], True) diff --git a/homeassistant/components/sensor/comed_hourly_pricing.py b/homeassistant/components/sensor/comed_hourly_pricing.py index c0c477ade0b..3595bcaa227 100644 --- a/homeassistant/components/sensor/comed_hourly_pricing.py +++ b/homeassistant/components/sensor/comed_hourly_pricing.py @@ -50,7 +50,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the ComEd Hourly Pricing sensor.""" websession = async_get_clientsession(hass) dev = [] @@ -60,7 +61,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass.loop, websession, variable[CONF_SENSOR_TYPE], variable[CONF_OFFSET], variable.get(CONF_NAME))) - async_add_devices(dev, True) + async_add_entities(dev, True) class ComedHourlyPricingSensor(Entity): diff --git a/homeassistant/components/sensor/comfoconnect.py b/homeassistant/components/sensor/comfoconnect.py index ad6b07fb3da..b13c8d8d263 100644 --- a/homeassistant/components/sensor/comfoconnect.py +++ b/homeassistant/components/sensor/comfoconnect.py @@ -23,7 +23,7 @@ DEPENDENCIES = ['comfoconnect'] SENSOR_TYPES = {} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ComfoConnect fan platform.""" from pycomfoconnect import ( SENSOR_TEMPERATURE_EXTRACT, SENSOR_HUMIDITY_EXTRACT, @@ -90,7 +90,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) - add_devices(sensors, True) + add_entities(sensors, True) class ComfoConnectSensor(Entity): diff --git a/homeassistant/components/sensor/command_line.py b/homeassistant/components/sensor/command_line.py index 846604a9ff5..e1d151410b1 100644 --- a/homeassistant/components/sensor/command_line.py +++ b/homeassistant/components/sensor/command_line.py @@ -43,7 +43,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Command Sensor.""" name = config.get(CONF_NAME) command = config.get(CONF_COMMAND) @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): json_attributes = config.get(CONF_JSON_ATTRIBUTES) data = CommandSensorData(hass, command, command_timeout) - add_devices([CommandSensor( + add_entities([CommandSensor( hass, data, name, unit, value_template, json_attributes)], True) diff --git a/homeassistant/components/sensor/cpuspeed.py b/homeassistant/components/sensor/cpuspeed.py index c6a7106663f..e97972dae3b 100644 --- a/homeassistant/components/sensor/cpuspeed.py +++ b/homeassistant/components/sensor/cpuspeed.py @@ -30,11 +30,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the CPU speed sensor.""" name = config.get(CONF_NAME) - add_devices([CpuSpeedSensor(name)], True) + add_entities([CpuSpeedSensor(name)], True) class CpuSpeedSensor(Entity): diff --git a/homeassistant/components/sensor/crimereports.py b/homeassistant/components/sensor/crimereports.py index adf7e3c0fa9..2f1db42a127 100644 --- a/homeassistant/components/sensor/crimereports.py +++ b/homeassistant/components/sensor/crimereports.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Crime Reports platform.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): include = config.get(CONF_INCLUDE) exclude = config.get(CONF_EXCLUDE) - add_devices([CrimeReportsSensor( + add_entities([CrimeReportsSensor( hass, name, latitude, longitude, radius, include, exclude)], True) diff --git a/homeassistant/components/sensor/cups.py b/homeassistant/components/sensor/cups.py index 846b109afca..b002d39352a 100644 --- a/homeassistant/components/sensor/cups.py +++ b/homeassistant/components/sensor/cups.py @@ -50,7 +50,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the CUPS sensor.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Printer is not present: %s", printer) continue - add_devices(dev, True) + add_entities(dev, True) class CupsSensor(Entity): diff --git a/homeassistant/components/sensor/currencylayer.py b/homeassistant/components/sensor/currencylayer.py index 4a7face0156..67c9c7bbf19 100644 --- a/homeassistant/components/sensor/currencylayer.py +++ b/homeassistant/components/sensor/currencylayer.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Currencylayer sensor.""" base = config.get(CONF_BASE) api_key = config.get(CONF_API_KEY) @@ -54,7 +54,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(CurrencylayerSensor(rest, base, variable)) if 'error' in response.json(): return False - add_devices(sensors, True) + add_entities(sensors, True) class CurrencylayerSensor(Entity): diff --git a/homeassistant/components/sensor/daikin.py b/homeassistant/components/sensor/daikin.py index 2da5cb5cdf0..3445eb531aa 100644 --- a/homeassistant/components/sensor/daikin.py +++ b/homeassistant/components/sensor/daikin.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Daikin sensors.""" if discovery_info is not None: host = discovery_info.get('ip') @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for monitored_state in monitored_conditions: sensors.append(DaikinClimateSensor(api, monitored_state, units, name)) - add_devices(sensors, True) + add_entities(sensors, True) class DaikinClimateSensor(Entity): diff --git a/homeassistant/components/sensor/darksky.py b/homeassistant/components/sensor/darksky.py index b2bb7bb4da2..7ce51454ee5 100644 --- a/homeassistant/components/sensor/darksky.py +++ b/homeassistant/components/sensor/darksky.py @@ -170,7 +170,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dark Sky sensor.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) @@ -211,7 +211,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(DarkSkySensor( forecast_data, variable, name, forecast_day)) - add_devices(sensors, True) + add_entities(sensors, True) class DarkSkySensor(Entity): diff --git a/homeassistant/components/sensor/deconz.py b/homeassistant/components/sensor/deconz.py index 7c492fd496d..a32f1e5e210 100644 --- a/homeassistant/components/sensor/deconz.py +++ b/homeassistant/components/sensor/deconz.py @@ -21,13 +21,13 @@ ATTR_DAYLIGHT = 'daylight' ATTR_EVENT_ID = 'event_id' -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ sensors.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ sensors.""" @callback def async_add_sensor(sensors): @@ -43,7 +43,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): entities.append(DeconzBattery(sensor)) else: entities.append(DeconzSensor(sensor)) - async_add_devices(entities, True) + async_add_entities(entities, True) hass.data[DATA_DECONZ_UNSUB].append( async_dispatcher_connect(hass, 'deconz_new_sensor', async_add_sensor)) diff --git a/homeassistant/components/sensor/deluge.py b/homeassistant/components/sensor/deluge.py index b9109f6428c..f56b3ac4b97 100644 --- a/homeassistant/components/sensor/deluge.py +++ b/homeassistant/components/sensor/deluge.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Deluge sensors.""" from deluge_client import DelugeRPCClient @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_MONITORED_VARIABLES]: dev.append(DelugeSensor(variable, deluge_api, name)) - add_devices(dev) + add_entities(dev) class DelugeSensor(Entity): diff --git a/homeassistant/components/sensor/demo.py b/homeassistant/components/sensor/demo.py index 15cc0ec46ae..7921181b742 100644 --- a/homeassistant/components/sensor/demo.py +++ b/homeassistant/components/sensor/demo.py @@ -10,9 +10,9 @@ from homeassistant.const import ( from homeassistant.helpers.entity import Entity -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo sensors.""" - add_devices([ + add_entities([ DemoSensor('Outside Temperature', 15.6, DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, 12), DemoSensor('Outside Humidity', 54, DEVICE_CLASS_HUMIDITY, '%', None), diff --git a/homeassistant/components/sensor/deutsche_bahn.py b/homeassistant/components/sensor/deutsche_bahn.py index 0e6ab164d4f..2cbf9a6d691 100644 --- a/homeassistant/components/sensor/deutsche_bahn.py +++ b/homeassistant/components/sensor/deutsche_bahn.py @@ -34,13 +34,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Deutsche Bahn Sensor.""" start = config.get(CONF_START) destination = config.get(CONF_DESTINATION) only_direct = config.get(CONF_ONLY_DIRECT) - add_devices([DeutscheBahnSensor(start, destination, only_direct)], True) + add_entities([DeutscheBahnSensor(start, destination, only_direct)], True) class DeutscheBahnSensor(Entity): diff --git a/homeassistant/components/sensor/dht.py b/homeassistant/components/sensor/dht.py index e3aaf2f8484..0aae10fde64 100644 --- a/homeassistant/components/sensor/dht.py +++ b/homeassistant/components/sensor/dht.py @@ -51,7 +51,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the DHT sensor.""" # pylint: disable=import-error import Adafruit_DHT @@ -83,7 +83,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except KeyError: pass - add_devices(dev, True) + add_entities(dev, True) class DHTSensor(Entity): diff --git a/homeassistant/components/sensor/discogs.py b/homeassistant/components/sensor/discogs.py index 2920dc025d7..6e85c41ac6e 100644 --- a/homeassistant/components/sensor/discogs.py +++ b/homeassistant/components/sensor/discogs.py @@ -37,7 +37,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Discogs sensor.""" import discogs_client @@ -51,7 +52,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.error("API token is not valid") return - async_add_devices([DiscogsSensor(identity, name)], True) + async_add_entities([DiscogsSensor(identity, name)], True) class DiscogsSensor(Entity): diff --git a/homeassistant/components/sensor/dnsip.py b/homeassistant/components/sensor/dnsip.py index 7b792d179c5..ac681dc691a 100644 --- a/homeassistant/components/sensor/dnsip.py +++ b/homeassistant/components/sensor/dnsip.py @@ -40,7 +40,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the DNS IP sensor.""" hostname = config.get(CONF_HOSTNAME) ipv6 = config.get(CONF_IPV6) @@ -49,7 +50,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): else: resolver = config.get(CONF_RESOLVER) - async_add_devices([WanIpSensor( + async_add_entities([WanIpSensor( hass, hostname, resolver, ipv6)], True) diff --git a/homeassistant/components/sensor/dovado.py b/homeassistant/components/sensor/dovado.py index 2a78d4ad864..03c2ad601df 100644 --- a/homeassistant/components/sensor/dovado.py +++ b/homeassistant/components/sensor/dovado.py @@ -54,9 +54,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dovado platform for sensors.""" - return Dovado().setup(hass, config, add_devices) + return Dovado().setup(hass, config, add_entities) class Dovado: @@ -67,7 +67,7 @@ class Dovado: self.state = {} self._dovado = None - def setup(self, hass, config, add_devices): + def setup(self, hass, config, add_entities): """Set up the connection.""" import dovado self._dovado = dovado.Dovado( @@ -90,7 +90,7 @@ class Dovado: for sensor in SENSORS: if sensor in config.get(CONF_SENSORS, [sensor]): - add_devices([DovadoSensor(self, sensor)]) + add_entities([DovadoSensor(self, sensor)]) return True diff --git a/homeassistant/components/sensor/dsmr.py b/homeassistant/components/sensor/dsmr.py index 3a1bf1da39e..13b13114150 100644 --- a/homeassistant/components/sensor/dsmr.py +++ b/homeassistant/components/sensor/dsmr.py @@ -49,7 +49,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the DSMR sensor.""" # Suppress logging logging.getLogger('dsmr_parser').setLevel(logging.ERROR) @@ -160,7 +161,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): DerivativeDSMREntity('Hourly Gas Consumption', gas_obis), ] - async_add_devices(devices) + async_add_entities(devices) def update_entities_telegram(telegram): """Update entities with latest telegram and trigger state update.""" diff --git a/homeassistant/components/sensor/dte_energy_bridge.py b/homeassistant/components/sensor/dte_energy_bridge.py index c1687b6025b..629b21e4944 100644 --- a/homeassistant/components/sensor/dte_energy_bridge.py +++ b/homeassistant/components/sensor/dte_energy_bridge.py @@ -31,13 +31,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the DTE energy bridge sensor.""" name = config.get(CONF_NAME) ip_address = config.get(CONF_IP_ADDRESS) version = config.get(CONF_VERSION, 1) - add_devices([DteEnergyBridgeSensor(ip_address, name, version)], True) + add_entities([DteEnergyBridgeSensor(ip_address, name, version)], True) class DteEnergyBridgeSensor(Entity): diff --git a/homeassistant/components/sensor/dublin_bus_transport.py b/homeassistant/components/sensor/dublin_bus_transport.py index a443c78b2b1..0fccf7da5a8 100644 --- a/homeassistant/components/sensor/dublin_bus_transport.py +++ b/homeassistant/components/sensor/dublin_bus_transport.py @@ -56,14 +56,14 @@ def due_in_minutes(timestamp): return str(int(diff.total_seconds() / 60)) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dublin public transport sensor.""" name = config.get(CONF_NAME) stop = config.get(CONF_STOP_ID) route = config.get(CONF_ROUTE) data = PublicTransportData(stop, route) - add_devices([DublinPublicTransportSensor(data, stop, route, name)], True) + add_entities([DublinPublicTransportSensor(data, stop, route, name)], True) class DublinPublicTransportSensor(Entity): diff --git a/homeassistant/components/sensor/duke_energy.py b/homeassistant/components/sensor/duke_energy.py index 17f118e3cb4..41d3e5706de 100644 --- a/homeassistant/components/sensor/duke_energy.py +++ b/homeassistant/components/sensor/duke_energy.py @@ -27,7 +27,7 @@ LAST_BILL_AVERAGE_USAGE = "last_bills_average_usage" LAST_BILL_DAYS_BILLED = "last_bills_days_billed" -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up all Duke Energy meters.""" from pydukeenergy.api import DukeEnergy, DukeEnergyException @@ -39,7 +39,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Failed to set up Duke Energy") return - add_devices([DukeEnergyMeter(meter) for meter in duke.get_meters()]) + add_entities([DukeEnergyMeter(meter) for meter in duke.get_meters()]) class DukeEnergyMeter(Entity): diff --git a/homeassistant/components/sensor/dwd_weather_warnings.py b/homeassistant/components/sensor/dwd_weather_warnings.py index 4f9664617a3..4b7e07d4f3a 100644 --- a/homeassistant/components/sensor/dwd_weather_warnings.py +++ b/homeassistant/components/sensor/dwd_weather_warnings.py @@ -53,7 +53,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the DWD-Weather-Warnings sensor.""" name = config.get(CONF_NAME) region_name = config.get(CONF_REGION_NAME) @@ -63,7 +63,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors = [DwdWeatherWarningsSensor(api, name, condition) for condition in config[CONF_MONITORED_CONDITIONS]] - add_devices(sensors, True) + add_entities(sensors, True) class DwdWeatherWarningsSensor(Entity): diff --git a/homeassistant/components/sensor/dweet.py b/homeassistant/components/sensor/dweet.py index 065c88d8332..25bcaa18bab 100644 --- a/homeassistant/components/sensor/dweet.py +++ b/homeassistant/components/sensor/dweet.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dweet sensor.""" import dweepy @@ -57,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dweet = DweetData(device) - add_devices([DweetSensor(hass, dweet, name, value_template, unit)], True) + add_entities([DweetSensor(hass, dweet, name, value_template, unit)], True) class DweetSensor(Entity): diff --git a/homeassistant/components/sensor/dyson.py b/homeassistant/components/sensor/dyson.py index 91629a18f68..0619e3f6069 100644 --- a/homeassistant/components/sensor/dyson.py +++ b/homeassistant/components/sensor/dyson.py @@ -23,7 +23,7 @@ SENSOR_UNITS = { _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dyson Sensors.""" _LOGGER.debug("Creating new Dyson fans") devices = [] @@ -37,7 +37,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(DysonHumiditySensor(hass, device)) devices.append(DysonTemperatureSensor(hass, device, unit)) devices.append(DysonAirQualitySensor(hass, device)) - add_devices(devices) + add_entities(devices) class DysonSensor(Entity): diff --git a/homeassistant/components/sensor/ebox.py b/homeassistant/components/sensor/ebox.py index 218968ecee8..24458e444dc 100644 --- a/homeassistant/components/sensor/ebox.py +++ b/homeassistant/components/sensor/ebox.py @@ -64,7 +64,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the EBox sensor.""" username = config.get(CONF_USERNAME) @@ -86,7 +86,7 @@ async def async_setup_platform(hass, config, async_add_devices, for variable in config[CONF_MONITORED_VARIABLES]: sensors.append(EBoxSensor(ebox_data, variable, name)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class EBoxSensor(Entity): diff --git a/homeassistant/components/sensor/ecobee.py b/homeassistant/components/sensor/ecobee.py index a478f964f5a..ae22401a618 100644 --- a/homeassistant/components/sensor/ecobee.py +++ b/homeassistant/components/sensor/ecobee.py @@ -19,7 +19,7 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ecobee sensors.""" if discovery_info is None: return @@ -33,7 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(EcobeeSensor(sensor['name'], item['type'], index)) - add_devices(dev, True) + add_entities(dev, True) class EcobeeSensor(Entity): diff --git a/homeassistant/components/sensor/eddystone_temperature.py b/homeassistant/components/sensor/eddystone_temperature.py index 4c209d17d07..9e8dc33314a 100644 --- a/homeassistant/components/sensor/eddystone_temperature.py +++ b/homeassistant/components/sensor/eddystone_temperature.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Validate configuration, create devices and start monitoring thread.""" bt_device_id = config.get("bt_device_id") @@ -70,7 +70,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.info("Starting scanner for Eddystone beacons") mon.start() - add_devices(devices) + add_entities(devices) mon.start() hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, monitor_stop) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, monitor_start) diff --git a/homeassistant/components/sensor/efergy.py b/homeassistant/components/sensor/efergy.py index b9fe2941463..54666c74f96 100644 --- a/homeassistant/components/sensor/efergy.py +++ b/homeassistant/components/sensor/efergy.py @@ -56,7 +56,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Efergy sensor.""" app_token = config.get(CONF_APPTOKEN) utc_offset = str(config.get(CONF_UTC_OFFSET)) @@ -76,7 +76,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): variable[CONF_SENSOR_TYPE], app_token, utc_offset, variable[CONF_PERIOD], variable[CONF_CURRENCY])) - add_devices(dev, True) + add_entities(dev, True) class EfergySensor(Entity): diff --git a/homeassistant/components/sensor/eight_sleep.py b/homeassistant/components/sensor/eight_sleep.py index 5899ef267cb..0fc793d31ca 100644 --- a/homeassistant/components/sensor/eight_sleep.py +++ b/homeassistant/components/sensor/eight_sleep.py @@ -35,7 +35,7 @@ ATTR_SESSION_START = 'Session Start' _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the eight sleep sensors.""" if discovery_info is None: @@ -60,7 +60,7 @@ async def async_setup_platform(hass, config, async_add_devices, else: all_sensors.append(EightUserSensor(name, eight, sensor, units)) - async_add_devices(all_sensors, True) + async_add_entities(all_sensors, True) class EightHeatSensor(EightSleepHeatEntity): diff --git a/homeassistant/components/sensor/eliqonline.py b/homeassistant/components/sensor/eliqonline.py index 6405c707536..a2b1a4071c1 100644 --- a/homeassistant/components/sensor/eliqonline.py +++ b/homeassistant/components/sensor/eliqonline.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ELIQ Online sensor.""" import eliqonline @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Could not access the ELIQ Online API: %s", error) return False - add_devices([EliqSensor(api, channel_id, name)], True) + add_entities([EliqSensor(api, channel_id, name)], True) class EliqSensor(Entity): diff --git a/homeassistant/components/sensor/emoncms.py b/homeassistant/components/sensor/emoncms.py index a62eaba7df8..7546224d4c5 100644 --- a/homeassistant/components/sensor/emoncms.py +++ b/homeassistant/components/sensor/emoncms.py @@ -61,7 +61,7 @@ def get_id(sensorid, feedtag, feedname, feedid, feeduserid): sensorid, feedtag, feedname, feedid, feeduserid) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Emoncms sensor.""" apikey = config.get(CONF_API_KEY) url = config.get(CONF_URL) @@ -102,7 +102,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(EmonCmsSensor(hass, data, name, value_template, unit_of_measurement, str(sensorid), elem)) - add_devices(sensors) + add_entities(sensors) class EmonCmsSensor(Entity): diff --git a/homeassistant/components/sensor/enocean.py b/homeassistant/components/sensor/enocean.py index 6b0207c2488..02e6812d5d5 100644 --- a/homeassistant/components/sensor/enocean.py +++ b/homeassistant/components/sensor/enocean.py @@ -25,12 +25,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an EnOcean sensor device.""" dev_id = config.get(CONF_ID) devname = config.get(CONF_NAME) - add_devices([EnOceanSensor(dev_id, devname)]) + add_entities([EnOceanSensor(dev_id, devname)]) class EnOceanSensor(enocean.EnOceanDevice, Entity): diff --git a/homeassistant/components/sensor/enphase_envoy.py b/homeassistant/components/sensor/enphase_envoy.py index 3c132fcf7df..6afe887537c 100644 --- a/homeassistant/components/sensor/enphase_envoy.py +++ b/homeassistant/components/sensor/enphase_envoy.py @@ -37,15 +37,15 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.All(cv.ensure_list, [vol.In(list(SENSORS))])}) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Enphase Envoy sensor.""" ip_address = config[CONF_IP_ADDRESS] monitored_conditions = config[CONF_MONITORED_CONDITIONS] # Iterate through the list of sensors for condition in monitored_conditions: - add_devices([Envoy(ip_address, condition, SENSORS[condition][0], - SENSORS[condition][1])], True) + add_entities([Envoy(ip_address, condition, SENSORS[condition][0], + SENSORS[condition][1])], True) class Envoy(Entity): diff --git a/homeassistant/components/sensor/envirophat.py b/homeassistant/components/sensor/envirophat.py index bf4ee55c446..1c90f5998e8 100644 --- a/homeassistant/components/sensor/envirophat.py +++ b/homeassistant/components/sensor/envirophat.py @@ -52,7 +52,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sense HAT sensor platform.""" try: import envirophat @@ -66,7 +66,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_DISPLAY_OPTIONS]: dev.append(EnvirophatSensor(data, variable)) - add_devices(dev, True) + add_entities(dev, True) class EnvirophatSensor(Entity): diff --git a/homeassistant/components/sensor/envisalink.py b/homeassistant/components/sensor/envisalink.py index 24cb224570c..91f99e31b48 100644 --- a/homeassistant/components/sensor/envisalink.py +++ b/homeassistant/components/sensor/envisalink.py @@ -20,7 +20,8 @@ DEPENDENCIES = ['envisalink'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Perform the setup for Envisalink sensor devices.""" configured_partitions = discovery_info['partitions'] @@ -35,7 +36,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass.data[DATA_EVL]) devices.append(device) - async_add_devices(devices) + async_add_entities(devices) class EnvisalinkSensor(EnvisalinkDevice, Entity): diff --git a/homeassistant/components/sensor/etherscan.py b/homeassistant/components/sensor/etherscan.py index 360ca4516ce..24cf046cca0 100644 --- a/homeassistant/components/sensor/etherscan.py +++ b/homeassistant/components/sensor/etherscan.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Etherscan.io sensors.""" address = config.get(CONF_ADDRESS) name = config.get(CONF_NAME) @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not name: name = "ETH Balance" - add_devices([EtherscanSensor(name, address, token, token_address)], True) + add_entities([EtherscanSensor(name, address, token, token_address)], True) class EtherscanSensor(Entity): diff --git a/homeassistant/components/sensor/fail2ban.py b/homeassistant/components/sensor/fail2ban.py index bf868d49201..0f018af819d 100644 --- a/homeassistant/components/sensor/fail2ban.py +++ b/homeassistant/components/sensor/fail2ban.py @@ -40,7 +40,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the fail2ban sensor.""" name = config.get(CONF_NAME) jails = config.get(CONF_JAILS) @@ -52,7 +53,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for jail in jails: device_list.append(BanSensor(name, jail, log_parser)) - async_add_devices(device_list, True) + async_add_entities(device_list, True) class BanSensor(Entity): diff --git a/homeassistant/components/sensor/fastdotcom.py b/homeassistant/components/sensor/fastdotcom.py index 65474cd4bf6..6624265f60c 100644 --- a/homeassistant/components/sensor/fastdotcom.py +++ b/homeassistant/components/sensor/fastdotcom.py @@ -41,11 +41,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Fast.com sensor.""" data = SpeedtestData(hass, config) sensor = SpeedtestSensor(data) - add_devices([sensor]) + add_entities([sensor]) def update(call=None): """Update service for manual updates.""" diff --git a/homeassistant/components/sensor/fedex.py b/homeassistant/components/sensor/fedex.py index 991588f07f3..7d5f47b3631 100644 --- a/homeassistant/components/sensor/fedex.py +++ b/homeassistant/components/sensor/fedex.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Fedex platform.""" import fedexdeliverymanager @@ -57,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.exception("Could not connect to Fedex Delivery Manager") return False - add_devices([FedexSensor(session, name, update_interval)], True) + add_entities([FedexSensor(session, name, update_interval)], True) class FedexSensor(Entity): diff --git a/homeassistant/components/sensor/fido.py b/homeassistant/components/sensor/fido.py index 4f724b5b851..4c027b906a2 100644 --- a/homeassistant/components/sensor/fido.py +++ b/homeassistant/components/sensor/fido.py @@ -71,7 +71,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Fido sensor.""" username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) @@ -89,7 +90,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for variable in config[CONF_MONITORED_VARIABLES]: sensors.append(FidoSensor(fido_data, variable, name, number)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class FidoSensor(Entity): diff --git a/homeassistant/components/sensor/file.py b/homeassistant/components/sensor/file.py index cbdd4eef227..1839b3566ee 100644 --- a/homeassistant/components/sensor/file.py +++ b/homeassistant/components/sensor/file.py @@ -33,7 +33,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the file sensor.""" file_path = config.get(CONF_FILE_PATH) name = config.get(CONF_NAME) @@ -44,7 +45,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): value_template.hass = hass if hass.config.is_allowed_path(file_path): - async_add_devices( + async_add_entities( [FileSensor(name, file_path, unit, value_template)], True) else: _LOGGER.error("'%s' is not a whitelisted directory", file_path) diff --git a/homeassistant/components/sensor/filesize.py b/homeassistant/components/sensor/filesize.py index a5a65f9bb5e..4df858fda23 100644 --- a/homeassistant/components/sensor/filesize.py +++ b/homeassistant/components/sensor/filesize.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the file size sensor.""" sensors = [] for path in config.get(CONF_FILE_PATHS): @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(Filesize(path)) if sensors: - add_devices(sensors, True) + add_entities(sensors, True) class Filesize(Entity): diff --git a/homeassistant/components/sensor/filter.py b/homeassistant/components/sensor/filter.py index 15059b08a17..1c6e857b92b 100644 --- a/homeassistant/components/sensor/filter.py +++ b/homeassistant/components/sensor/filter.py @@ -114,7 +114,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template sensors.""" name = config.get(CONF_NAME) @@ -124,7 +124,7 @@ async def async_setup_platform(hass, config, async_add_devices, entity=entity_id, **_filter) for _filter in config[CONF_FILTERS]] - async_add_devices([SensorFilter(name, entity_id, filters)]) + async_add_entities([SensorFilter(name, entity_id, filters)]) class SensorFilter(Entity): diff --git a/homeassistant/components/sensor/fints.py b/homeassistant/components/sensor/fints.py index c573f0f0058..1704c13b5aa 100644 --- a/homeassistant/components/sensor/fints.py +++ b/homeassistant/components/sensor/fints.py @@ -50,7 +50,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sensors. Login to the bank and get a list of existing accounts. Create a @@ -98,7 +98,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.debug('Creating holdings %s for bank %s', account.accountnumber, fints_name) - add_devices(accounts, True) + add_entities(accounts, True) class FinTsClient: diff --git a/homeassistant/components/sensor/fitbit.py b/homeassistant/components/sensor/fitbit.py index 87bd735a03d..f5b44d577a7 100644 --- a/homeassistant/components/sensor/fitbit.py +++ b/homeassistant/components/sensor/fitbit.py @@ -151,7 +151,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def request_app_setup(hass, config, add_devices, config_path, +def request_app_setup(hass, config, add_entities, config_path, discovery_info=None): """Assist user with configuring the Fitbit dev application.""" configurator = hass.components.configurator @@ -167,9 +167,9 @@ def request_app_setup(hass, config, add_devices, config_path, configurator.notify_errors(_CONFIGURING['fitbit'], error_msg) else: - setup_platform(hass, config, add_devices, discovery_info) + setup_platform(hass, config, add_entities, discovery_info) else: - setup_platform(hass, config, add_devices, discovery_info) + setup_platform(hass, config, add_entities, discovery_info) start_url = "{}{}".format(hass.config.api.base_url, FITBIT_AUTH_CALLBACK_PATH) @@ -215,19 +215,19 @@ def request_oauth_completion(hass): ) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Fitbit sensor.""" config_path = hass.config.path(FITBIT_CONFIG_FILE) if os.path.isfile(config_path): config_file = load_json(config_path) if config_file == DEFAULT_CONFIG: request_app_setup( - hass, config, add_devices, config_path, discovery_info=None) + hass, config, add_entities, config_path, discovery_info=None) return False else: save_json(config_path, DEFAULT_CONFIG) request_app_setup( - hass, config, add_devices, config_path, discovery_info=None) + hass, config, add_entities, config_path, discovery_info=None) return False if "fitbit" in _CONFIGURING: @@ -276,7 +276,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(FitbitSensor( authd_client, config_path, resource, hass.config.units.is_metric, clock_format)) - add_devices(dev, True) + add_entities(dev, True) else: oauth = fitbit.api.FitbitOauth2Client( @@ -293,7 +293,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass.http.register_redirect(FITBIT_AUTH_START, fitbit_auth_start_url) hass.http.register_view(FitbitAuthCallbackView( - config, add_devices, oauth)) + config, add_entities, oauth)) request_oauth_completion(hass) @@ -305,10 +305,10 @@ class FitbitAuthCallbackView(HomeAssistantView): url = FITBIT_AUTH_CALLBACK_PATH name = 'api:fitbit:callback' - def __init__(self, config, add_devices, oauth): + def __init__(self, config, add_entities, oauth): """Initialize the OAuth callback view.""" self.config = config - self.add_devices = add_devices + self.add_entities = add_entities self.oauth = oauth @callback @@ -368,7 +368,8 @@ class FitbitAuthCallbackView(HomeAssistantView): } save_json(hass.config.path(FITBIT_CONFIG_FILE), config_contents) - hass.async_add_job(setup_platform, hass, self.config, self.add_devices) + hass.async_add_job(setup_platform, hass, self.config, + self.add_entities) return html_response diff --git a/homeassistant/components/sensor/fixer.py b/homeassistant/components/sensor/fixer.py index 5a6f8da79b2..1bdd9e71272 100644 --- a/homeassistant/components/sensor/fixer.py +++ b/homeassistant/components/sensor/fixer.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Fixer.io sensor.""" from fixerio import Fixerio, exceptions @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return data = ExchangeData(target, api_key) - add_devices([ExchangeRateSensor(data, name, target)], True) + add_entities([ExchangeRateSensor(data, name, target)], True) class ExchangeRateSensor(Entity): diff --git a/homeassistant/components/sensor/folder.py b/homeassistant/components/sensor/folder.py index 2b5f3dd4309..8101bbd059a 100644 --- a/homeassistant/components/sensor/folder.py +++ b/homeassistant/components/sensor/folder.py @@ -42,7 +42,7 @@ def get_size(files_list): return sum(size_list) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the folder sensor.""" path = config.get(CONF_FOLDER_PATHS) @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("folder %s is not valid or allowed", path) else: folder = Folder(path, config.get(CONF_FILTER)) - add_devices([folder], True) + add_entities([folder], True) class Folder(Entity): diff --git a/homeassistant/components/sensor/foobot.py b/homeassistant/components/sensor/foobot.py index d247a90e93a..62139c53c4b 100644 --- a/homeassistant/components/sensor/foobot.py +++ b/homeassistant/components/sensor/foobot.py @@ -52,7 +52,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the devices associated with the account.""" from foobot_async import FoobotClient @@ -82,7 +82,7 @@ async def async_setup_platform(hass, config, async_add_devices, except FoobotClient.ClientError: _LOGGER.error('Failed to fetch data from foobot servers.') return - async_add_devices(dev, True) + async_add_entities(dev, True) class FoobotSensor(Entity): diff --git a/homeassistant/components/sensor/fritzbox_callmonitor.py b/homeassistant/components/sensor/fritzbox_callmonitor.py index 3da9c512ebd..c60d06da039 100644 --- a/homeassistant/components/sensor/fritzbox_callmonitor.py +++ b/homeassistant/components/sensor/fritzbox_callmonitor.py @@ -56,7 +56,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Fritz!Box call monitor sensor platform.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -77,7 +77,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor = FritzBoxCallSensor(name=name, phonebook=phonebook) - add_devices([sensor]) + add_entities([sensor]) monitor = FritzBoxCallMonitor(host=host, port=port, sensor=sensor) monitor.connect() diff --git a/homeassistant/components/sensor/fritzbox_netmonitor.py b/homeassistant/components/sensor/fritzbox_netmonitor.py index b980323abe1..356c1424012 100644 --- a/homeassistant/components/sensor/fritzbox_netmonitor.py +++ b/homeassistant/components/sensor/fritzbox_netmonitor.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the FRITZ!Box monitor sensors.""" # pylint: disable=import-error import fritzconnection as fc @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return 1 _LOGGER.info("Successfully connected to FRITZ!Box") - add_devices([FritzboxMonitorSensor(name, fstatus)], True) + add_entities([FritzboxMonitorSensor(name, fstatus)], True) class FritzboxMonitorSensor(Entity): diff --git a/homeassistant/components/sensor/gearbest.py b/homeassistant/components/sensor/gearbest.py index d71419ba79e..5521e9a644c 100644 --- a/homeassistant/components/sensor/gearbest.py +++ b/homeassistant/components/sensor/gearbest.py @@ -43,7 +43,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Gearbest sensor.""" from gearbest_parser import CurrencyConverter currency = config.get(CONF_CURRENCY) @@ -68,7 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): currency_update, MIN_TIME_BETWEEN_CURRENCY_UPDATES) - add_devices(sensors, True) + add_entities(sensors, True) class GearbestSensor(Entity): diff --git a/homeassistant/components/sensor/geizhals.py b/homeassistant/components/sensor/geizhals.py index 0458c2022af..2c7325866ac 100644 --- a/homeassistant/components/sensor/geizhals.py +++ b/homeassistant/components/sensor/geizhals.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Geizwatch sensor.""" name = config.get(CONF_NAME) description = config.get(CONF_DESCRIPTION) @@ -49,8 +49,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): domain = config.get(CONF_DOMAIN) regex = config.get(CONF_REGEX) - add_devices([Geizwatch(name, description, product_id, domain, regex)], - True) + add_entities([Geizwatch(name, description, product_id, domain, regex)], + True) class Geizwatch(Entity): diff --git a/homeassistant/components/sensor/geo_rss_events.py b/homeassistant/components/sensor/geo_rss_events.py index b79e6e69adf..1ba0ce2e065 100644 --- a/homeassistant/components/sensor/geo_rss_events.py +++ b/homeassistant/components/sensor/geo_rss_events.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the GeoRSS component.""" home_latitude = hass.config.latitude home_longitude = hass.config.longitude @@ -81,7 +81,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): device = GeoRssServiceSensor(category, data, name, unit_of_measurement) devices.append(device) - add_devices(devices, True) + add_entities(devices, True) class GeoRssServiceSensor(Entity): diff --git a/homeassistant/components/sensor/gitter.py b/homeassistant/components/sensor/gitter.py index 907af07a2db..97cd3f662d5 100644 --- a/homeassistant/components/sensor/gitter.py +++ b/homeassistant/components/sensor/gitter.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Gitter sensor.""" from gitterpy.client import GitterClient from gitterpy.errors import GitterTokenError @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Token is not valid") return - add_devices([GitterSensor(gitter, room, name, username)], True) + add_entities([GitterSensor(gitter, room, name, username)], True) class GitterSensor(Entity): diff --git a/homeassistant/components/sensor/glances.py b/homeassistant/components/sensor/glances.py index c2a6607334d..c2127827ebd 100644 --- a/homeassistant/components/sensor/glances.py +++ b/homeassistant/components/sensor/glances.py @@ -63,7 +63,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Glances sensors.""" from glances_api import Glances @@ -86,7 +86,7 @@ async def async_setup_platform( for resource in var_conf: dev.append(GlancesSensor(glances, name, resource)) - async_add_devices(dev, True) + async_add_entities(dev, True) class GlancesSensor(Entity): diff --git a/homeassistant/components/sensor/google_travel_time.py b/homeassistant/components/sensor/google_travel_time.py index d14a70ecc84..a69b865f30b 100644 --- a/homeassistant/components/sensor/google_travel_time.py +++ b/homeassistant/components/sensor/google_travel_time.py @@ -79,7 +79,7 @@ def convert_time_to_utc(timestr): return dt_util.as_timestamp(combined) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up the Google travel time platform.""" def run_setup(event): """Delay the setup until Home Assistant is fully initialized. @@ -112,7 +112,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): hass, name, api_key, origin, destination, options) if sensor.valid_api_connection: - add_devices_callback([sensor]) + add_entities_callback([sensor]) # Wait until start event is sent to load this component. hass.bus.listen_once(EVENT_HOMEASSISTANT_START, run_setup) diff --git a/homeassistant/components/sensor/google_wifi.py b/homeassistant/components/sensor/google_wifi.py index cc5461ed548..35db8f7c9e8 100644 --- a/homeassistant/components/sensor/google_wifi.py +++ b/homeassistant/components/sensor/google_wifi.py @@ -76,7 +76,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Google Wifi sensor.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -87,7 +87,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for condition in conditions: dev.append(GoogleWifiSensor(api, name, condition)) - add_devices(dev, True) + add_entities(dev, True) class GoogleWifiSensor(Entity): diff --git a/homeassistant/components/sensor/gpsd.py b/homeassistant/components/sensor/gpsd.py index f463d0fb8d1..0504cf7a511 100644 --- a/homeassistant/components/sensor/gpsd.py +++ b/homeassistant/components/sensor/gpsd.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the GPSD component.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Not able to connect to GPSD") return False - add_devices([GpsdSensor(hass, name, host, port)]) + add_entities([GpsdSensor(hass, name, host, port)]) class GpsdSensor(Entity): diff --git a/homeassistant/components/sensor/gtfs.py b/homeassistant/components/sensor/gtfs.py index 120fe8fdb22..633a50f15c1 100644 --- a/homeassistant/components/sensor/gtfs.py +++ b/homeassistant/components/sensor/gtfs.py @@ -151,7 +151,7 @@ def get_next_departure(sched, start_station_id, end_station_id, offset): } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the GTFS sensor.""" gtfs_dir = hass.config.path(DEFAULT_PATH) data = config.get(CONF_DATA) @@ -179,7 +179,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not gtfs.feeds: pygtfs.append_feed(gtfs, os.path.join(gtfs_dir, data)) - add_devices([GTFSDepartureSensor(gtfs, name, origin, destination, offset)]) + add_entities([ + GTFSDepartureSensor(gtfs, name, origin, destination, offset)]) class GTFSDepartureSensor(Entity): diff --git a/homeassistant/components/sensor/haveibeenpwned.py b/homeassistant/components/sensor/haveibeenpwned.py index bc79c4d0c1d..9428eaea00e 100644 --- a/homeassistant/components/sensor/haveibeenpwned.py +++ b/homeassistant/components/sensor/haveibeenpwned.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the HaveIBeenPwned sensor.""" emails = config.get(CONF_EMAIL) data = HaveIBeenPwnedData(emails) @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for email in emails: devices.append(HaveIBeenPwnedSensor(data, hass, email)) - add_devices(devices) + add_entities(devices) # To make sure we get initial data for the sensors ignoring the normal # throttle of 15 minutes but using an update throttle of 5 seconds diff --git a/homeassistant/components/sensor/hddtemp.py b/homeassistant/components/sensor/hddtemp.py index f8afe9c7637..52514a2de39 100644 --- a/homeassistant/components/sensor/hddtemp.py +++ b/homeassistant/components/sensor/hddtemp.py @@ -37,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the HDDTemp sensor.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -54,7 +54,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for disk in disks: dev.append(HddTempSensor(name, disk, hddtemp)) - add_devices(dev, True) + add_entities(dev, True) class HddTempSensor(Entity): diff --git a/homeassistant/components/sensor/history_stats.py b/homeassistant/components/sensor/history_stats.py index c3d0fe8f1b6..c76d2cefca0 100644 --- a/homeassistant/components/sensor/history_stats.py +++ b/homeassistant/components/sensor/history_stats.py @@ -67,7 +67,7 @@ PLATFORM_SCHEMA = vol.All(PLATFORM_SCHEMA.extend({ # noinspection PyUnusedLocal -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the History Stats sensor.""" entity_id = config.get(CONF_ENTITY_ID) entity_state = config.get(CONF_STATE) @@ -81,8 +81,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if template is not None: template.hass = hass - add_devices([HistoryStatsSensor(hass, entity_id, entity_state, start, end, - duration, sensor_type, name)]) + add_entities([HistoryStatsSensor(hass, entity_id, entity_state, start, end, + duration, sensor_type, name)]) return True diff --git a/homeassistant/components/sensor/hive.py b/homeassistant/components/sensor/hive.py index 2d609070415..3f900320801 100644 --- a/homeassistant/components/sensor/hive.py +++ b/homeassistant/components/sensor/hive.py @@ -16,7 +16,7 @@ DEVICETYPE_ICONS = {'Hub_OnlineStatus': 'mdi:switch', 'Hive_OutsideTemperature': 'mdi:thermometer'} -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Hive sensor devices.""" if discovery_info is None: return @@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if (discovery_info["HA_DeviceType"] == "Hub_OnlineStatus" or discovery_info["HA_DeviceType"] == "Hive_OutsideTemperature"): - add_devices([HiveSensorEntity(session, discovery_info)]) + add_entities([HiveSensorEntity(session, discovery_info)]) class HiveSensorEntity(Entity): diff --git a/homeassistant/components/sensor/homematic.py b/homeassistant/components/sensor/homematic.py index 0303525abcf..8495286c143 100644 --- a/homeassistant/components/sensor/homematic.py +++ b/homeassistant/components/sensor/homematic.py @@ -70,7 +70,7 @@ HM_ICON_HA_CAST = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the HomeMatic sensor platform.""" if discovery_info is None: return @@ -80,7 +80,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = HMSensor(conf) devices.append(new_device) - add_devices(devices) + add_entities(devices) class HMSensor(HMDevice): diff --git a/homeassistant/components/sensor/homematicip_cloud.py b/homeassistant/components/sensor/homematicip_cloud.py index 7d4944f5f5f..2b8365b8f64 100644 --- a/homeassistant/components/sensor/homematicip_cloud.py +++ b/homeassistant/components/sensor/homematicip_cloud.py @@ -25,12 +25,12 @@ ATTR_HUMIDITY = 'humidity' async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the HomematicIP Cloud sensors devices.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP Cloud sensors from a config entry.""" from homematicip.device import ( HeatingThermostat, TemperatureHumiditySensorWithoutDisplay, @@ -49,7 +49,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): devices.append(HomematicipIlluminanceSensor(home, device)) if devices: - async_add_devices(devices) + async_add_entities(devices) class HomematicipAccesspointStatus(HomematicipGenericDevice): diff --git a/homeassistant/components/sensor/hp_ilo.py b/homeassistant/components/sensor/hp_ilo.py index 98ee83f8958..ac2d5ccb109 100644 --- a/homeassistant/components/sensor/hp_ilo.py +++ b/homeassistant/components/sensor/hp_ilo.py @@ -59,7 +59,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the HP ILO sensor.""" hostname = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -89,7 +89,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): CONF_UNIT_OF_MEASUREMENT)) devices.append(new_device) - add_devices(devices, True) + add_entities(devices, True) class HpIloSensor(Entity): diff --git a/homeassistant/components/sensor/htu21d.py b/homeassistant/components/sensor/htu21d.py index 870ca0ca160..28ab933ff6c 100644 --- a/homeassistant/components/sensor/htu21d.py +++ b/homeassistant/components/sensor/htu21d.py @@ -41,7 +41,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=import-error @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the HTU21D sensor.""" import smbus from i2csense.htu21d import HTU21D @@ -63,7 +64,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): dev = [HTU21DSensor(sensor_handler, name, SENSOR_TEMPERATURE, temp_unit), HTU21DSensor(sensor_handler, name, SENSOR_HUMIDITY, '%')] - async_add_devices(dev) + async_add_entities(dev) class HTU21DHandler: diff --git a/homeassistant/components/sensor/hydrawise.py b/homeassistant/components/sensor/hydrawise.py index fea2780da07..bff99ddc501 100644 --- a/homeassistant/components/sensor/hydrawise.py +++ b/homeassistant/components/sensor/hydrawise.py @@ -24,7 +24,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a Hydrawise device.""" hydrawise = hass.data[DATA_HYDRAWISE].data @@ -33,7 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for zone in hydrawise.relays: sensors.append(HydrawiseSensor(zone, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) class HydrawiseSensor(HydrawiseEntity): diff --git a/homeassistant/components/sensor/hydroquebec.py b/homeassistant/components/sensor/hydroquebec.py index db75d51fbad..44b96bab1e9 100644 --- a/homeassistant/components/sensor/hydroquebec.py +++ b/homeassistant/components/sensor/hydroquebec.py @@ -94,7 +94,8 @@ DAILY_MAP = (('yesterday_total_consumption', 'consoTotalQuot'), @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the HydroQuebec sensor.""" # Create a data fetcher to support all of the configured sensors. Then make # the first call to init the data. @@ -118,7 +119,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for variable in config[CONF_MONITORED_VARIABLES]: sensors.append(HydroQuebecSensor(hydroquebec_data, variable, name)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class HydroQuebecSensor(Entity): diff --git a/homeassistant/components/sensor/ihc.py b/homeassistant/components/sensor/ihc.py index 547e6b52d9a..f5140838a7a 100644 --- a/homeassistant/components/sensor/ihc.py +++ b/homeassistant/components/sensor/ihc.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC sensor platform.""" ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] info = hass.data[IHC_DATA][IHC_INFO] @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor = IHCSensor(ihc_controller, name, ihc_id, info, unit) devices.append(sensor) - add_devices(devices) + add_entities(devices) class IHCSensor(IHCDevice, Entity): diff --git a/homeassistant/components/sensor/imap.py b/homeassistant/components/sensor/imap.py index 647a40295ac..2ea1fd576e6 100644 --- a/homeassistant/components/sensor/imap.py +++ b/homeassistant/components/sensor/imap.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform(hass, config, - async_add_devices, + async_add_entities, discovery_info=None): """Set up the IMAP platform.""" sensor = ImapSensor(config.get(CONF_NAME), @@ -54,7 +54,7 @@ async def async_setup_platform(hass, raise PlatformNotReady hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, sensor.shutdown()) - async_add_devices([sensor], True) + async_add_entities([sensor], True) class ImapSensor(Entity): diff --git a/homeassistant/components/sensor/imap_email_content.py b/homeassistant/components/sensor/imap_email_content.py index a1a604df3e4..ed535b69a1d 100644 --- a/homeassistant/components/sensor/imap_email_content.py +++ b/homeassistant/components/sensor/imap_email_content.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Email sensor platform.""" reader = EmailReader( config.get(CONF_USERNAME), config.get(CONF_PASSWORD), @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): config.get(CONF_SENDERS), value_template) if sensor.connected: - add_devices([sensor], True) + add_entities([sensor], True) else: return False diff --git a/homeassistant/components/sensor/influxdb.py b/homeassistant/components/sensor/influxdb.py index 8bfbaf49837..87e2bdb5c9c 100644 --- a/homeassistant/components/sensor/influxdb.py +++ b/homeassistant/components/sensor/influxdb.py @@ -63,7 +63,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the InfluxDB component.""" influx_conf = { 'host': config[CONF_HOST], @@ -81,7 +81,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if sensor.connected: dev.append(sensor) - add_devices(dev, True) + add_entities(dev, True) class InfluxSensor(Entity): diff --git a/homeassistant/components/sensor/insteon.py b/homeassistant/components/sensor/insteon.py index 59c0fee7617..5b8a6b9a977 100644 --- a/homeassistant/components/sensor/insteon.py +++ b/homeassistant/components/sensor/insteon.py @@ -16,7 +16,8 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the INSTEON device class for the hass platform.""" insteon_modem = hass.data['insteon'].get('modem') @@ -29,7 +30,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): new_entity = InsteonSensorDevice(device, state_key) - async_add_devices([new_entity]) + async_add_entities([new_entity]) class InsteonSensorDevice(InsteonEntity, Entity): diff --git a/homeassistant/components/sensor/ios.py b/homeassistant/components/sensor/ios.py index 1fd556b17c0..f775381c4ec 100644 --- a/homeassistant/components/sensor/ios.py +++ b/homeassistant/components/sensor/ios.py @@ -19,7 +19,7 @@ DEFAULT_ICON_LEVEL = 'mdi:battery' DEFAULT_ICON_STATE = 'mdi:power-plug' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the iOS sensor.""" if discovery_info is None: return @@ -28,7 +28,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for sensor_type in ('level', 'state'): dev.append(IOSSensor(sensor_type, device_name, device)) - add_devices(dev, True) + add_entities(dev, True) class IOSSensor(Entity): diff --git a/homeassistant/components/sensor/iota.py b/homeassistant/components/sensor/iota.py index 2e3e58a18f3..961cd119d78 100644 --- a/homeassistant/components/sensor/iota.py +++ b/homeassistant/components/sensor/iota.py @@ -24,7 +24,7 @@ DEPENDENCIES = ['iota'] SCAN_INTERVAL = timedelta(minutes=3) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IOTA sensor.""" # Add sensors for wallet balance iota_config = discovery_info @@ -34,7 +34,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): # Add sensor for node information sensors.append(IotaNodeSensor(iota_config=iota_config)) - add_devices(sensors) + add_entities(sensors) class IotaBalanceSensor(IotaDevice): diff --git a/homeassistant/components/sensor/iperf3.py b/homeassistant/components/sensor/iperf3.py index 8e030390f50..0eb6dfaa00c 100644 --- a/homeassistant/components/sensor/iperf3.py +++ b/homeassistant/components/sensor/iperf3.py @@ -64,7 +64,7 @@ SERVICE_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Iperf3 sensor.""" if hass.data.get(IPERF3_DATA) is None: hass.data[IPERF3_DATA] = {} @@ -81,7 +81,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor)) hass.data[IPERF3_DATA]['sensors'].extend(dev) - add_devices(dev) + add_entities(dev) def _service_handler(service): """Update service for manual updates.""" diff --git a/homeassistant/components/sensor/irish_rail_transport.py b/homeassistant/components/sensor/irish_rail_transport.py index 38fd910260a..10f4004ae74 100644 --- a/homeassistant/components/sensor/irish_rail_transport.py +++ b/homeassistant/components/sensor/irish_rail_transport.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Irish Rail transport sensor.""" from pyirishrail.pyirishrail import IrishRailRTPI station = config.get(CONF_STATION) @@ -61,7 +61,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): irish_rail = IrishRailRTPI() data = IrishRailTransportData( irish_rail, station, direction, destination, stops_at) - add_devices([IrishRailTransportSensor( + add_entities([IrishRailTransportSensor( data, station, direction, destination, stops_at, name)], True) diff --git a/homeassistant/components/sensor/isy994.py b/homeassistant/components/sensor/isy994.py index 19dcfc87014..eca7e88a17e 100644 --- a/homeassistant/components/sensor/isy994.py +++ b/homeassistant/components/sensor/isy994.py @@ -236,7 +236,7 @@ UOM_TO_STATES = { def setup_platform(hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the ISY994 sensor platform.""" devices = [] @@ -247,7 +247,7 @@ def setup_platform(hass, config: ConfigType, for node in hass.data[ISY994_WEATHER]: devices.append(ISYWeatherDevice(node)) - add_devices(devices) + add_entities(devices) class ISYSensorDevice(ISYDevice): diff --git a/homeassistant/components/sensor/juicenet.py b/homeassistant/components/sensor/juicenet.py index 033e2d7acad..b8ef38981e8 100644 --- a/homeassistant/components/sensor/juicenet.py +++ b/homeassistant/components/sensor/juicenet.py @@ -25,7 +25,7 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Juicenet sensor.""" api = hass.data[DOMAIN]['api'] @@ -34,7 +34,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in SENSOR_TYPES: dev.append(JuicenetSensorDevice(device, variable, hass)) - add_devices(dev) + add_entities(dev) class JuicenetSensorDevice(JuicenetDevice, Entity): diff --git a/homeassistant/components/sensor/kira.py b/homeassistant/components/sensor/kira.py index 19566100f99..ced17281cc8 100644 --- a/homeassistant/components/sensor/kira.py +++ b/homeassistant/components/sensor/kira.py @@ -18,14 +18,14 @@ ICON = 'mdi:remote' CONF_SENSOR = 'sensor' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Kira sensor.""" if discovery_info is not None: name = discovery_info.get(CONF_NAME) device = discovery_info.get(CONF_DEVICE) kira = hass.data[DOMAIN][CONF_SENSOR][name] - add_devices([KiraReceiver(device, kira)]) + add_entities([KiraReceiver(device, kira)]) class KiraReceiver(Entity): diff --git a/homeassistant/components/sensor/knx.py b/homeassistant/components/sensor/knx.py index b4d1f6653c0..b8b55a1cc7c 100644 --- a/homeassistant/components/sensor/knx.py +++ b/homeassistant/components/sensor/knx.py @@ -27,27 +27,27 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up sensor(s) for KNX platform.""" if discovery_info is not None: - async_add_devices_discovery(hass, discovery_info, async_add_devices) + async_add_entities_discovery(hass, discovery_info, async_add_entities) else: - async_add_devices_config(hass, config, async_add_devices) + async_add_entities_config(hass, config, async_add_entities) @callback -def async_add_devices_discovery(hass, discovery_info, async_add_devices): +def async_add_entities_discovery(hass, discovery_info, async_add_entities): """Set up sensors for KNX platform configured via xknx.yaml.""" entities = [] for device_name in discovery_info[ATTR_DISCOVER_DEVICES]: device = hass.data[DATA_KNX].xknx.devices[device_name] entities.append(KNXSensor(hass, device)) - async_add_devices(entities) + async_add_entities(entities) @callback -def async_add_devices_config(hass, config, async_add_devices): +def async_add_entities_config(hass, config, async_add_entities): """Set up sensor for KNX platform configured within platform.""" import xknx sensor = xknx.devices.Sensor( @@ -56,7 +56,7 @@ def async_add_devices_config(hass, config, async_add_devices): group_address=config.get(CONF_ADDRESS), value_type=config.get(CONF_TYPE)) hass.data[DATA_KNX].xknx.devices.add(sensor) - async_add_devices([KNXSensor(hass, sensor)]) + async_add_entities([KNXSensor(hass, sensor)]) class KNXSensor(Entity): diff --git a/homeassistant/components/sensor/kwb.py b/homeassistant/components/sensor/kwb.py index f307b0f6102..20e5bc7f4ac 100644 --- a/homeassistant/components/sensor/kwb.py +++ b/homeassistant/components/sensor/kwb.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = vol.Schema( ) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the KWB component.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -77,7 +77,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, lambda event: easyfire.stop_thread()) - add_devices(sensors) + add_entities(sensors) class KWBSensor(Entity): diff --git a/homeassistant/components/sensor/lacrosse.py b/homeassistant/components/sensor/lacrosse.py index 034f0be49f6..a2dbaa8f324 100644 --- a/homeassistant/components/sensor/lacrosse.py +++ b/homeassistant/components/sensor/lacrosse.py @@ -56,7 +56,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LaCrosse sensors.""" import pylacrosse from serial import SerialException @@ -103,7 +103,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) - add_devices(sensors) + add_entities(sensors) class LaCrosseSensor(Entity): diff --git a/homeassistant/components/sensor/lastfm.py b/homeassistant/components/sensor/lastfm.py index 45eddee9f7e..338adc7d501 100644 --- a/homeassistant/components/sensor/lastfm.py +++ b/homeassistant/components/sensor/lastfm.py @@ -29,12 +29,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Last.fm platform.""" import pylast as lastfm network = lastfm.LastFMNetwork(api_key=config.get(CONF_API_KEY)) - add_devices( + add_entities( [LastfmSensor( username, network) for username in config.get(CONF_USERS)], True) diff --git a/homeassistant/components/sensor/linux_battery.py b/homeassistant/components/sensor/linux_battery.py index e7b8bf600a4..69fc145a4a5 100644 --- a/homeassistant/components/sensor/linux_battery.py +++ b/homeassistant/components/sensor/linux_battery.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Linux Battery sensor.""" name = config.get(CONF_NAME) battery_id = config.get(CONF_BATTERY) @@ -69,7 +69,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("No battery found") return False - add_devices([LinuxBatterySensor(name, battery_id, system)], True) + add_entities([LinuxBatterySensor(name, battery_id, system)], True) class LinuxBatterySensor(Entity): diff --git a/homeassistant/components/sensor/london_air.py b/homeassistant/components/sensor/london_air.py index bbb5993b064..6c96bb48e97 100644 --- a/homeassistant/components/sensor/london_air.py +++ b/homeassistant/components/sensor/london_air.py @@ -60,7 +60,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the London Air sensor.""" data = APIData() data.update() @@ -68,7 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for name in config.get(CONF_LOCATIONS): sensors.append(AirSensor(name, data)) - add_devices(sensors, True) + add_entities(sensors, True) class APIData: diff --git a/homeassistant/components/sensor/london_underground.py b/homeassistant/components/sensor/london_underground.py index 4619eda0611..a0617469cba 100644 --- a/homeassistant/components/sensor/london_underground.py +++ b/homeassistant/components/sensor/london_underground.py @@ -43,7 +43,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tube sensor.""" data = TubeData() data.update() @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for line in config.get(CONF_LINE): sensors.append(LondonTubeSensor(line, data)) - add_devices(sensors, True) + add_entities(sensors, True) class LondonTubeSensor(Entity): diff --git a/homeassistant/components/sensor/loopenergy.py b/homeassistant/components/sensor/loopenergy.py index d888a6c634d..0f2362ca33c 100644 --- a/homeassistant/components/sensor/loopenergy.py +++ b/homeassistant/components/sensor/loopenergy.py @@ -56,7 +56,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Loop Energy sensors.""" import pyloopenergy @@ -84,7 +84,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if gas_config.get(CONF_GAS_SERIAL): sensors.append(LoopEnergyGas(controller)) - add_devices(sensors) + add_entities(sensors) class LoopEnergyDevice(Entity): diff --git a/homeassistant/components/sensor/luftdaten.py b/homeassistant/components/sensor/luftdaten.py index c9bc7205ce6..445ccb7214e 100644 --- a/homeassistant/components/sensor/luftdaten.py +++ b/homeassistant/components/sensor/luftdaten.py @@ -59,7 +59,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Luftdaten sensor.""" from luftdaten import Luftdaten @@ -84,7 +84,7 @@ async def async_setup_platform( devices.append( LuftdatenSensor(luftdaten, name, variable, sensor_id, show_on_map)) - async_add_devices(devices) + async_add_entities(devices) class LuftdatenSensor(Entity): diff --git a/homeassistant/components/sensor/lyft.py b/homeassistant/components/sensor/lyft.py index 57e5f1c6b02..671308871e5 100644 --- a/homeassistant/components/sensor/lyft.py +++ b/homeassistant/components/sensor/lyft.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Lyft sensor.""" from lyft_rides.auth import ClientCredentialGrant from lyft_rides.errors import APIError @@ -74,7 +74,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if product.get('estimate') is not None: dev.append(LyftSensor( 'price', timeandpriceest, product_id, product)) - add_devices(dev, True) + add_entities(dev, True) class LyftSensor(Entity): diff --git a/homeassistant/components/sensor/magicseaweed.py b/homeassistant/components/sensor/magicseaweed.py index 02c61024e30..59f38553d79 100644 --- a/homeassistant/components/sensor/magicseaweed.py +++ b/homeassistant/components/sensor/magicseaweed.py @@ -56,7 +56,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Magicseaweed sensor.""" name = config.get(CONF_NAME) spot_id = config[CONF_SPOT_ID] @@ -88,7 +88,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for hour in hours: sensors.append(MagicSeaweedSensor( forecast_data, variable, name, units, hour)) - add_devices(sensors, True) + add_entities(sensors, True) class MagicSeaweedSensor(Entity): diff --git a/homeassistant/components/sensor/melissa.py b/homeassistant/components/sensor/melissa.py index 634ef4ad810..df4800cbbd0 100644 --- a/homeassistant/components/sensor/melissa.py +++ b/homeassistant/components/sensor/melissa.py @@ -15,7 +15,7 @@ DEPENDENCIES = ['melissa'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the melissa sensor platform.""" sensors = [] api = hass.data[DATA_MELISSA] @@ -25,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device['type'] == 'melissa': sensors.append(MelissaTemperatureSensor(device, api)) sensors.append(MelissaHumiditySensor(device, api)) - add_devices(sensors) + add_entities(sensors) class MelissaSensor(Entity): diff --git a/homeassistant/components/sensor/metoffice.py b/homeassistant/components/sensor/metoffice.py index ec3d3f47ba7..8cebecb7124 100644 --- a/homeassistant/components/sensor/metoffice.py +++ b/homeassistant/components/sensor/metoffice.py @@ -86,7 +86,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Met Office sensor platform.""" import datapoint as dp @@ -121,7 +121,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_MONITORED_CONDITIONS]: sensors.append(MetOfficeCurrentSensor(site, data, variable, name)) - add_devices(sensors, True) + add_entities(sensors, True) class MetOfficeCurrentSensor(Entity): diff --git a/homeassistant/components/sensor/mfi.py b/homeassistant/components/sensor/mfi.py index f575768b505..44e5dbda84f 100644 --- a/homeassistant/components/sensor/mfi.py +++ b/homeassistant/components/sensor/mfi.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up mFi sensors.""" host = config.get(CONF_HOST) username = config.get(CONF_USERNAME) @@ -68,10 +68,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Unable to connect to mFi: %s", str(ex)) return False - add_devices(MfiSensor(port, hass) - for device in client.get_devices() - for port in device.ports.values() - if port.model in SENSOR_MODELS) + add_entities(MfiSensor(port, hass) + for device in client.get_devices() + for port in device.ports.values() + if port.model in SENSOR_MODELS) class MfiSensor(Entity): diff --git a/homeassistant/components/sensor/mhz19.py b/homeassistant/components/sensor/mhz19.py index 60f6598ab21..dd8a0395088 100644 --- a/homeassistant/components/sensor/mhz19.py +++ b/homeassistant/components/sensor/mhz19.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the available CO2 sensors.""" from pmsensor import co2sensor @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append( MHZ19Sensor(data, variable, SENSOR_TYPES[variable][1], name)) - add_devices(dev, True) + add_entities(dev, True) return True diff --git a/homeassistant/components/sensor/miflora.py b/homeassistant/components/sensor/miflora.py index 6f50a57b3ab..ced17512089 100644 --- a/homeassistant/components/sensor/miflora.py +++ b/homeassistant/components/sensor/miflora.py @@ -58,7 +58,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the MiFlora sensor.""" from miflora import miflora_poller try: @@ -92,7 +92,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devs.append(MiFloraSensor( poller, parameter, name, unit, force_update, median)) - add_devices(devs) + add_entities(devs) class MiFloraSensor(Entity): diff --git a/homeassistant/components/sensor/min_max.py b/homeassistant/components/sensor/min_max.py index f3a30724732..7956dd97b5e 100644 --- a/homeassistant/components/sensor/min_max.py +++ b/homeassistant/components/sensor/min_max.py @@ -55,14 +55,15 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the min/max/mean sensor.""" entity_ids = config.get(CONF_ENTITY_IDS) name = config.get(CONF_NAME) sensor_type = config.get(CONF_TYPE) round_digits = config.get(CONF_ROUND_DIGITS) - async_add_devices( + async_add_entities( [MinMaxSensor(hass, entity_ids, name, sensor_type, round_digits)], True) return True diff --git a/homeassistant/components/sensor/mitemp_bt.py b/homeassistant/components/sensor/mitemp_bt.py index 249a69578db..2ae5c29b043 100644 --- a/homeassistant/components/sensor/mitemp_bt.py +++ b/homeassistant/components/sensor/mitemp_bt.py @@ -56,7 +56,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the MiTempBt sensor.""" from mitemp_bt import mitemp_bt_poller try: @@ -90,7 +90,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devs.append(MiTempBtSensor( poller, parameter, name, unit, force_update, median)) - add_devices(devs) + add_entities(devs) class MiTempBtSensor(Entity): diff --git a/homeassistant/components/sensor/modbus.py b/homeassistant/components/sensor/modbus.py index 5f404ccd5f7..833cb0c5a62 100644 --- a/homeassistant/components/sensor/modbus.py +++ b/homeassistant/components/sensor/modbus.py @@ -59,7 +59,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Modbus sensors.""" sensors = [] data_types = {DATA_TYPE_INT: {1: 'h', 2: 'i', 4: 'q'}} @@ -108,7 +108,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not sensors: return False - add_devices(sensors) + add_entities(sensors) class ModbusRegisterSensor(Entity): diff --git a/homeassistant/components/sensor/modem_callerid.py b/homeassistant/components/sensor/modem_callerid.py index 58e8becd6bb..2da7953c12a 100644 --- a/homeassistant/components/sensor/modem_callerid.py +++ b/homeassistant/components/sensor/modem_callerid.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up modem caller ID sensor platform.""" from basicmodem.basicmodem import BasicModem as bm name = config.get(CONF_NAME) @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error('Unable to initialize modem.') return - add_devices([ModemCalleridSensor(hass, name, port, modem)]) + add_entities([ModemCalleridSensor(hass, name, port, modem)]) class ModemCalleridSensor(Entity): diff --git a/homeassistant/components/sensor/mold_indicator.py b/homeassistant/components/sensor/mold_indicator.py index 319185923cd..e5794ab1314 100644 --- a/homeassistant/components/sensor/mold_indicator.py +++ b/homeassistant/components/sensor/mold_indicator.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up MoldIndicator sensor.""" name = config.get(CONF_NAME, DEFAULT_NAME) indoor_temp_sensor = config.get(CONF_INDOOR_TEMP) @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): indoor_humidity_sensor = config.get(CONF_INDOOR_HUMIDITY) calib_factor = config.get(CONF_CALIBRATION_FACTOR) - add_devices([MoldIndicator( + add_entities([MoldIndicator( hass, name, indoor_temp_sensor, outdoor_temp_sensor, indoor_humidity_sensor, calib_factor)], True) diff --git a/homeassistant/components/sensor/moon.py b/homeassistant/components/sensor/moon.py index 50f4f72078c..a019d21fd78 100644 --- a/homeassistant/components/sensor/moon.py +++ b/homeassistant/components/sensor/moon.py @@ -26,11 +26,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Moon sensor.""" name = config.get(CONF_NAME) - async_add_devices([MoonSensor(name)], True) + async_add_entities([MoonSensor(name)], True) class MoonSensor(Entity): diff --git a/homeassistant/components/sensor/mopar.py b/homeassistant/components/sensor/mopar.py index 81c48555cfc..6b2b3776557 100644 --- a/homeassistant/components/sensor/mopar.py +++ b/homeassistant/components/sensor/mopar.py @@ -41,7 +41,7 @@ REMOTE_COMMAND_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Mopar platform.""" import motorparts cookie = hass.config.path(COOKIE_FILE) @@ -66,8 +66,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): schema=REMOTE_COMMAND_SCHEMA) data = MoparData(session) - add_devices([MoparSensor(data, index) - for index, _ in enumerate(data.vehicles)], True) + add_entities([MoparSensor(data, index) + for index, _ in enumerate(data.vehicles)], True) class MoparData: diff --git a/homeassistant/components/sensor/mqtt.py b/homeassistant/components/sensor/mqtt.py index 0e29c55d39d..6cf2d55755d 100644 --- a/homeassistant/components/sensor/mqtt.py +++ b/homeassistant/components/sensor/mqtt.py @@ -51,7 +51,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info=None): + async_add_entities, discovery_info=None): """Set up MQTT Sensor.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -60,7 +60,7 @@ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, if value_template is not None: value_template.hass = hass - async_add_devices([MqttSensor( + async_add_entities([MqttSensor( config.get(CONF_NAME), config.get(CONF_STATE_TOPIC), config.get(CONF_QOS), diff --git a/homeassistant/components/sensor/mqtt_room.py b/homeassistant/components/sensor/mqtt_room.py index 2a61c1143ee..e12e8e033ac 100644 --- a/homeassistant/components/sensor/mqtt_room.py +++ b/homeassistant/components/sensor/mqtt_room.py @@ -53,9 +53,10 @@ MQTT_PAYLOAD = vol.Schema(vol.All(json.loads, vol.Schema({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up MQTT room Sensor.""" - async_add_devices([MQTTRoomSensor( + async_add_entities([MQTTRoomSensor( config.get(CONF_NAME), config.get(CONF_STATE_TOPIC), config.get(CONF_DEVICE_ID), diff --git a/homeassistant/components/sensor/mvglive.py b/homeassistant/components/sensor/mvglive.py index e066bb5e0b9..a7a4b592664 100644 --- a/homeassistant/components/sensor/mvglive.py +++ b/homeassistant/components/sensor/mvglive.py @@ -59,7 +59,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the MVGLive sensor.""" sensors = [] for nextdeparture in config.get(CONF_NEXT_DEPARTURE): @@ -73,7 +73,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): nextdeparture.get(CONF_TIMEOFFSET), nextdeparture.get(CONF_NUMBER), nextdeparture.get(CONF_NAME))) - add_devices(sensors, True) + add_entities(sensors, True) class MVGLiveSensor(Entity): diff --git a/homeassistant/components/sensor/mychevy.py b/homeassistant/components/sensor/mychevy.py index ef7c7ba8608..fa3343d7791 100644 --- a/homeassistant/components/sensor/mychevy.py +++ b/homeassistant/components/sensor/mychevy.py @@ -31,7 +31,7 @@ SENSORS = [ _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the MyChevy sensors.""" if discovery_info is None: return @@ -42,7 +42,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for car in hub.cars: sensors.append(EVSensor(hub, sconfig, car.vid)) - add_devices(sensors) + add_entities(sensors) class MyChevyStatus(Entity): diff --git a/homeassistant/components/sensor/mysensors.py b/homeassistant/components/sensor/mysensors.py index 2fbfc0e97a4..160d4b4784b 100644 --- a/homeassistant/components/sensor/mysensors.py +++ b/homeassistant/components/sensor/mysensors.py @@ -35,11 +35,11 @@ SENSORS = { async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the MySensors platform for sensors.""" mysensors.setup_mysensors_platform( hass, DOMAIN, discovery_info, MySensorsSensor, - async_add_devices=async_add_devices) + async_add_entities=async_add_entities) class MySensorsSensor(mysensors.device.MySensorsEntity): diff --git a/homeassistant/components/sensor/nederlandse_spoorwegen.py b/homeassistant/components/sensor/nederlandse_spoorwegen.py index 431a44c56e3..81cfada25f6 100644 --- a/homeassistant/components/sensor/nederlandse_spoorwegen.py +++ b/homeassistant/components/sensor/nederlandse_spoorwegen.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the departure sensor.""" import ns_api nsapi = ns_api.NSAPI( @@ -72,7 +72,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): nsapi, departure.get(CONF_NAME), departure.get(CONF_FROM), departure.get(CONF_TO), departure.get(CONF_VIA))) if sensors: - add_devices(sensors, True) + add_entities(sensors, True) def valid_stations(stations, given_stations): diff --git a/homeassistant/components/sensor/nest.py b/homeassistant/components/sensor/nest.py index bb1f3e67d4d..d51b0ab4053 100644 --- a/homeassistant/components/sensor/nest.py +++ b/homeassistant/components/sensor/nest.py @@ -55,14 +55,14 @@ _SENSOR_TYPES_DEPRECATED = SENSOR_TYPES_DEPRECATED + DEPRECATED_WEATHER_VARS _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Nest Sensor. No longer used. """ -async def async_setup_entry(hass, entry, async_add_devices): +async def async_setup_entry(hass, entry, async_add_entities): """Set up a Nest sensor based on a config entry.""" nest = hass.data[DATA_NEST] @@ -119,7 +119,7 @@ async def async_setup_entry(hass, entry, async_add_devices): return all_sensors - async_add_devices(await hass.async_add_job(get_sensors), True) + async_add_entities(await hass.async_add_job(get_sensors), True) class NestBasicSensor(NestSensorDevice): diff --git a/homeassistant/components/sensor/netatmo.py b/homeassistant/components/sensor/netatmo.py index 3e3f7ce9486..5216913528a 100644 --- a/homeassistant/components/sensor/netatmo.py +++ b/homeassistant/components/sensor/netatmo.py @@ -64,7 +64,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the available Netatmo weather sensors.""" netatmo = hass.components.netatmo data = NetAtmoData(netatmo.NETATMO_AUTH, config.get(CONF_STATION, None)) @@ -95,7 +95,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except pyatmo.NoDevice: return None - add_devices(dev, True) + add_entities(dev, True) class NetAtmoSensor(Entity): diff --git a/homeassistant/components/sensor/netatmo_public.py b/homeassistant/components/sensor/netatmo_public.py index 4d2364ffb7c..d1c6e03d1b0 100644 --- a/homeassistant/components/sensor/netatmo_public.py +++ b/homeassistant/components/sensor/netatmo_public.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the access to Netatmo binary sensor.""" netatmo = hass.components.netatmo @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): lon_sw=area_conf.get(CONF_LON_SW), calculation=area_conf.get(CONF_TYPE)) sensors.append(NetatmoPublicSensor(area_conf.get(CONF_NAME), data)) - add_devices(sensors) + add_entities(sensors) class NetatmoPublicSensor(Entity): diff --git a/homeassistant/components/sensor/netdata.py b/homeassistant/components/sensor/netdata.py index 488b1611399..79fb59b4f7b 100644 --- a/homeassistant/components/sensor/netdata.py +++ b/homeassistant/components/sensor/netdata.py @@ -47,7 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Netdata sensor.""" from netdata import Netdata @@ -82,7 +82,7 @@ async def async_setup_platform( dev.append(NetdataSensor( netdata, name, sensor, sensor_name, element, icon, unit)) - async_add_devices(dev, True) + async_add_entities(dev, True) class NetdataSensor(Entity): diff --git a/homeassistant/components/sensor/netgear_lte.py b/homeassistant/components/sensor/netgear_lte.py index dac1f81ad23..2ecf545aa4e 100644 --- a/homeassistant/components/sensor/netgear_lte.py +++ b/homeassistant/components/sensor/netgear_lte.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info): + hass, config, async_add_entities, discovery_info): """Set up Netgear LTE sensor devices.""" modem_data = hass.data[DATA_KEY].get_modem_data(config) @@ -38,7 +38,7 @@ async def async_setup_platform( elif sensor_type == SENSOR_USAGE: sensors.append(UsageSensor(modem_data, sensor_type)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) @attr.s diff --git a/homeassistant/components/sensor/neurio_energy.py b/homeassistant/components/sensor/neurio_energy.py index fd8b8d2aeec..addb7925bc2 100644 --- a/homeassistant/components/sensor/neurio_energy.py +++ b/homeassistant/components/sensor/neurio_energy.py @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Neurio sensor.""" api_key = config.get(CONF_API_KEY) api_secret = config.get(CONF_API_SECRET) @@ -64,9 +64,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): update_active() # Active power sensor - add_devices([NeurioEnergy(data, ACTIVE_NAME, ACTIVE_TYPE, update_active)]) + add_entities([NeurioEnergy(data, ACTIVE_NAME, ACTIVE_TYPE, update_active)]) # Daily power sensor - add_devices([NeurioEnergy(data, DAILY_NAME, DAILY_TYPE, update_daily)]) + add_entities([NeurioEnergy(data, DAILY_NAME, DAILY_TYPE, update_daily)]) class NeurioData: diff --git a/homeassistant/components/sensor/noaa_tides.py b/homeassistant/components/sensor/noaa_tides.py index 8527abf84aa..6a72fdf8f2a 100644 --- a/homeassistant/components/sensor/noaa_tides.py +++ b/homeassistant/components/sensor/noaa_tides.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NOAA Tides and Currents sensor.""" station_id = config[CONF_STATION_ID] name = config.get(CONF_NAME) @@ -58,7 +58,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if noaa_sensor.data is None: _LOGGER.error("Unable to setup NOAA Tides Sensor") return - add_devices([noaa_sensor], True) + add_entities([noaa_sensor], True) class NOAATidesAndCurrentsSensor(Entity): diff --git a/homeassistant/components/sensor/nsw_fuel_station.py b/homeassistant/components/sensor/nsw_fuel_station.py index 5f677d39888..60ad83a82f2 100644 --- a/homeassistant/components/sensor/nsw_fuel_station.py +++ b/homeassistant/components/sensor/nsw_fuel_station.py @@ -42,7 +42,7 @@ NOTIFICATION_ID = 'nsw_fuel_station_notification' NOTIFICATION_TITLE = 'NSW Fuel Station Sensor Setup' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NSW Fuel Station sensor.""" from nsw_fuel import FuelCheckClient @@ -66,7 +66,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): available_fuel_types = station_data.get_available_fuel_types() - add_devices([ + add_entities([ StationPriceSensor(station_data, fuel_type) for fuel_type in fuel_types if fuel_type in available_fuel_types diff --git a/homeassistant/components/sensor/nzbget.py b/homeassistant/components/sensor/nzbget.py index a6fee5a69e8..2ee8e37a57a 100644 --- a/homeassistant/components/sensor/nzbget.py +++ b/homeassistant/components/sensor/nzbget.py @@ -50,7 +50,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the NZBGet sensors.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -78,7 +78,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): client_name=name) devices.append(new_sensor) - add_devices(devices) + add_entities(devices) class NZBGetSensor(Entity): diff --git a/homeassistant/components/sensor/octoprint.py b/homeassistant/components/sensor/octoprint.py index 9e62846e4d3..d42828c9f55 100644 --- a/homeassistant/components/sensor/octoprint.py +++ b/homeassistant/components/sensor/octoprint.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the available OctoPrint sensors.""" octoprint_api = hass.data[DOMAIN]["api"] name = config.get(CONF_NAME) @@ -74,7 +74,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name, SENSOR_TYPES[octo_type][3], SENSOR_TYPES[octo_type][0], SENSOR_TYPES[octo_type][1]) devices.append(new_sensor) - add_devices(devices, True) + add_entities(devices, True) class OctoPrintSensor(Entity): diff --git a/homeassistant/components/sensor/ohmconnect.py b/homeassistant/components/sensor/ohmconnect.py index d323a21a521..be73cbcf042 100644 --- a/homeassistant/components/sensor/ohmconnect.py +++ b/homeassistant/components/sensor/ohmconnect.py @@ -31,12 +31,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the OhmConnect sensor.""" name = config.get(CONF_NAME) ohmid = config.get(CONF_ID) - add_devices([OhmconnectSensor(name, ohmid)], True) + add_entities([OhmconnectSensor(name, ohmid)], True) class OhmconnectSensor(Entity): diff --git a/homeassistant/components/sensor/onewire.py b/homeassistant/components/sensor/onewire.py index 95ad5f1713d..d39ab24230c 100644 --- a/homeassistant/components/sensor/onewire.py +++ b/homeassistant/components/sensor/onewire.py @@ -47,7 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the one wire Sensors.""" base_dir = config.get(CONF_MOUNT_DIR) devs = [] @@ -85,7 +85,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): "Check the mount_dir parameter if it's defined") return - add_devices(devs, True) + add_entities(devs, True) class OneWire(Entity): diff --git a/homeassistant/components/sensor/openevse.py b/homeassistant/components/sensor/openevse.py index 9086f37f8b2..eabf1739c4f 100644 --- a/homeassistant/components/sensor/openevse.py +++ b/homeassistant/components/sensor/openevse.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the OpenEVSE sensor.""" import openevsewifi @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in monitored_variables: dev.append(OpenEVSESensor(variable, charger)) - add_devices(dev, True) + add_entities(dev, True) class OpenEVSESensor(Entity): diff --git a/homeassistant/components/sensor/openexchangerates.py b/homeassistant/components/sensor/openexchangerates.py index 5e8231bb124..01c84c63034 100644 --- a/homeassistant/components/sensor/openexchangerates.py +++ b/homeassistant/components/sensor/openexchangerates.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Open Exchange Rates sensor.""" name = config.get(CONF_NAME) api_key = config.get(CONF_API_KEY) @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False rest.update() - add_devices([OpenexchangeratesSensor(rest, name, quote)], True) + add_entities([OpenexchangeratesSensor(rest, name, quote)], True) class OpenexchangeratesSensor(Entity): diff --git a/homeassistant/components/sensor/openhardwaremonitor.py b/homeassistant/components/sensor/openhardwaremonitor.py index 1b345c752ff..d429cad9d97 100644 --- a/homeassistant/components/sensor/openhardwaremonitor.py +++ b/homeassistant/components/sensor/openhardwaremonitor.py @@ -41,10 +41,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Open Hardware Monitor platform.""" data = OpenHardwareMonitorData(config, hass) - add_devices(data.devices, True) + add_entities(data.devices, True) class OpenHardwareMonitorDevice(Entity): diff --git a/homeassistant/components/sensor/opensky.py b/homeassistant/components/sensor/opensky.py index 9178b46c488..5ee11af4e60 100644 --- a/homeassistant/components/sensor/opensky.py +++ b/homeassistant/components/sensor/opensky.py @@ -56,11 +56,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Open Sky platform.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) - add_devices([OpenSkySensor( + add_entities([OpenSkySensor( hass, config.get(CONF_NAME, DOMAIN), latitude, longitude, config.get(CONF_RADIUS), config.get(CONF_ALTITUDE))], True) diff --git a/homeassistant/components/sensor/openuv.py b/homeassistant/components/sensor/openuv.py index 42ff999bdd5..aaa04590b3f 100644 --- a/homeassistant/components/sensor/openuv.py +++ b/homeassistant/components/sensor/openuv.py @@ -39,7 +39,7 @@ UV_LEVEL_LOW = "Low" async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the OpenUV binary sensor platform.""" if discovery_info is None: return @@ -51,7 +51,7 @@ async def async_setup_platform( name, icon, unit = SENSORS[sensor_type] sensors.append(OpenUvSensor(openuv, sensor_type, name, icon, unit)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class OpenUvSensor(OpenUvEntity): diff --git a/homeassistant/components/sensor/openweathermap.py b/homeassistant/components/sensor/openweathermap.py index ba7fc4f9095..2dbbb581741 100644 --- a/homeassistant/components/sensor/openweathermap.py +++ b/homeassistant/components/sensor/openweathermap.py @@ -51,7 +51,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the OpenWeatherMap sensor.""" from pyowm import OWM @@ -85,7 +85,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(OpenWeatherMapSensor( name, data, 'forecast', SENSOR_TYPES['temperature'][1])) - add_devices(dev, True) + add_entities(dev, True) class OpenWeatherMapSensor(Entity): diff --git a/homeassistant/components/sensor/otp.py b/homeassistant/components/sensor/otp.py index 6ceed11a6b9..2e3a13928e1 100644 --- a/homeassistant/components/sensor/otp.py +++ b/homeassistant/components/sensor/otp.py @@ -33,12 +33,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the OTP sensor.""" name = config.get(CONF_NAME) token = config.get(CONF_TOKEN) - async_add_devices([TOTPSensor(name, token)], True) + async_add_entities([TOTPSensor(name, token)], True) return True diff --git a/homeassistant/components/sensor/pi_hole.py b/homeassistant/components/sensor/pi_hole.py index 363ada725ba..a318618724e 100644 --- a/homeassistant/components/sensor/pi_hole.py +++ b/homeassistant/components/sensor/pi_hole.py @@ -71,7 +71,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Pi-hole sensor.""" from hole import Hole @@ -94,7 +94,7 @@ async def async_setup_platform( sensors = [PiHoleSensor(pi_hole, name, condition) for condition in config[CONF_MONITORED_CONDITIONS]] - async_add_devices(sensors, True) + async_add_entities(sensors, True) class PiHoleSensor(Entity): diff --git a/homeassistant/components/sensor/pilight.py b/homeassistant/components/sensor/pilight.py index c30f1575049..85843018c01 100644 --- a/homeassistant/components/sensor/pilight.py +++ b/homeassistant/components/sensor/pilight.py @@ -30,9 +30,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Pilight Sensor.""" - add_devices([PilightSensor( + add_entities([PilightSensor( hass=hass, name=config.get(CONF_NAME), variable=config.get(CONF_VARIABLE), diff --git a/homeassistant/components/sensor/plex.py b/homeassistant/components/sensor/plex.py index 5aa156a0ac6..46766d75010 100644 --- a/homeassistant/components/sensor/plex.py +++ b/homeassistant/components/sensor/plex.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Plex sensor.""" name = config.get(CONF_NAME) plex_user = config.get(CONF_USERNAME) @@ -57,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): import plexapi.exceptions try: - add_devices([PlexSensor( + add_entities([PlexSensor( name, plex_url, plex_user, plex_password, plex_server, plex_token)], True) except (plexapi.exceptions.BadRequest, plexapi.exceptions.Unauthorized, diff --git a/homeassistant/components/sensor/pocketcasts.py b/homeassistant/components/sensor/pocketcasts.py index 85fbf7b5a16..9d5b837bba9 100644 --- a/homeassistant/components/sensor/pocketcasts.py +++ b/homeassistant/components/sensor/pocketcasts.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the pocketcasts platform for sensors.""" import pocketcasts @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): try: api = pocketcasts.Api(username, password) _LOGGER.debug("Found %d podcasts", len(api.my_podcasts())) - add_devices([PocketCastsSensor(api)], True) + add_entities([PocketCastsSensor(api)], True) except OSError as err: _LOGGER.error("Connection to server failed: %s", err) return False diff --git a/homeassistant/components/sensor/pollen.py b/homeassistant/components/sensor/pollen.py index 27750c9ac61..6df7047b353 100644 --- a/homeassistant/components/sensor/pollen.py +++ b/homeassistant/components/sensor/pollen.py @@ -94,7 +94,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Configure the platform and add the sensors.""" from pypollencom import Client @@ -113,7 +113,7 @@ async def async_setup_platform( PollencomSensor( data, config[CONF_ZIP_CODE], kind, category, name, icon, unit)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) def calculate_average_rating(indices): diff --git a/homeassistant/components/sensor/postnl.py b/homeassistant/components/sensor/postnl.py index 9b35c1fdc7e..5c70ca035cf 100644 --- a/homeassistant/components/sensor/postnl.py +++ b/homeassistant/components/sensor/postnl.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PostNL sensor platform.""" from postnl_api import PostNL_API, UnauthorizedException @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.exception("Can't connect to the PostNL webservice") return - add_devices([PostNLSensor(api, name)], True) + add_entities([PostNLSensor(api, name)], True) class PostNLSensor(Entity): diff --git a/homeassistant/components/sensor/pushbullet.py b/homeassistant/components/sensor/pushbullet.py index 415174ac273..9b26bdfbbe9 100644 --- a/homeassistant/components/sensor/pushbullet.py +++ b/homeassistant/components/sensor/pushbullet.py @@ -37,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Pushbullet Sensor platform.""" from pushbullet import PushBullet from pushbullet import InvalidKeyError @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices = [] for sensor_type in config[CONF_MONITORED_CONDITIONS]: devices.append(PushBulletNotificationSensor(pbprovider, sensor_type)) - add_devices(devices) + add_entities(devices) class PushBulletNotificationSensor(Entity): diff --git a/homeassistant/components/sensor/pvoutput.py b/homeassistant/components/sensor/pvoutput.py index d4307d50228..a12093099c4 100644 --- a/homeassistant/components/sensor/pvoutput.py +++ b/homeassistant/components/sensor/pvoutput.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PVOutput sensor.""" name = config.get(CONF_NAME) api_key = config.get(CONF_API_KEY) @@ -61,7 +61,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Unable to fetch data from PVOutput") return False - add_devices([PvoutputSensor(rest, name)], True) + add_entities([PvoutputSensor(rest, name)], True) class PvoutputSensor(Entity): diff --git a/homeassistant/components/sensor/pyload.py b/homeassistant/components/sensor/pyload.py index 4aa121e0895..78a191c16f4 100644 --- a/homeassistant/components/sensor/pyload.py +++ b/homeassistant/components/sensor/pyload.py @@ -43,7 +43,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the pyLoad sensors.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -70,7 +70,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): client_name=name) devices.append(new_sensor) - add_devices(devices, True) + add_entities(devices, True) class PyLoadSensor(Entity): diff --git a/homeassistant/components/sensor/qnap.py b/homeassistant/components/sensor/qnap.py index 8b25eb3de31..22f8d4c37c0 100644 --- a/homeassistant/components/sensor/qnap.py +++ b/homeassistant/components/sensor/qnap.py @@ -102,7 +102,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the QNAP NAS sensor.""" api = QNAPStatsAPI(config) api.update() @@ -151,7 +151,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_MONITORED_CONDITIONS] if variable in _VOLUME_MON_COND] - add_devices(sensors) + add_entities(sensors) def round_nicely(number): diff --git a/homeassistant/components/sensor/qwikswitch.py b/homeassistant/components/sensor/qwikswitch.py index 1497b4ad5cc..c8d33de4baf 100644 --- a/homeassistant/components/sensor/qwikswitch.py +++ b/homeassistant/components/sensor/qwikswitch.py @@ -14,7 +14,7 @@ DEPENDENCIES = [QWIKSWITCH] _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, _, add_devices, discovery_info=None): +async def async_setup_platform(hass, _, add_entities, discovery_info=None): """Add sensor from the main Qwikswitch component.""" if discovery_info is None: return @@ -22,7 +22,7 @@ async def async_setup_platform(hass, _, add_devices, discovery_info=None): qsusb = hass.data[QWIKSWITCH] _LOGGER.debug("Setup qwikswitch.sensor %s, %s", qsusb, discovery_info) devs = [QSSensor(sensor) for sensor in discovery_info[QWIKSWITCH]] - add_devices(devs) + add_entities(devs) class QSSensor(QSEntity): diff --git a/homeassistant/components/sensor/radarr.py b/homeassistant/components/sensor/radarr.py index 8adaeb3c71b..67695ae0e32 100644 --- a/homeassistant/components/sensor/radarr.py +++ b/homeassistant/components/sensor/radarr.py @@ -66,10 +66,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Radarr platform.""" conditions = config.get(CONF_MONITORED_CONDITIONS) - add_devices( + add_entities( [RadarrSensor(hass, config, sensor) for sensor in conditions], True) diff --git a/homeassistant/components/sensor/rainbird.py b/homeassistant/components/sensor/rainbird.py index 875e9c37bd3..1af2b771014 100644 --- a/homeassistant/components/sensor/rainbird.py +++ b/homeassistant/components/sensor/rainbird.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a Rain Bird sensor.""" controller = hass.data[DATA_RAINBIRD] @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append( RainBirdSensor(controller, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) class RainBirdSensor(Entity): diff --git a/homeassistant/components/sensor/raincloud.py b/homeassistant/components/sensor/raincloud.py index c03aa0a2aec..15a346880f3 100644 --- a/homeassistant/components/sensor/raincloud.py +++ b/homeassistant/components/sensor/raincloud.py @@ -25,7 +25,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a raincloud device.""" raincloud = hass.data[DATA_RAINCLOUD].data @@ -40,7 +40,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for zone in raincloud.controller.faucet.zones: sensors.append(RainCloudSensor(zone, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) return True diff --git a/homeassistant/components/sensor/rainmachine.py b/homeassistant/components/sensor/rainmachine.py index f747a26df39..20e95f0e98f 100644 --- a/homeassistant/components/sensor/rainmachine.py +++ b/homeassistant/components/sensor/rainmachine.py @@ -18,7 +18,7 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the RainMachine Switch platform.""" if discovery_info is None: return @@ -31,7 +31,7 @@ async def async_setup_platform( sensors.append( RainMachineSensor(rainmachine, sensor_type, name, icon, unit)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class RainMachineSensor(RainMachineEntity): diff --git a/homeassistant/components/sensor/random.py b/homeassistant/components/sensor/random.py index c3ff08a5781..4dec96bec2e 100644 --- a/homeassistant/components/sensor/random.py +++ b/homeassistant/components/sensor/random.py @@ -34,14 +34,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Random number sensor.""" name = config.get(CONF_NAME) minimum = config.get(CONF_MINIMUM) maximum = config.get(CONF_MAXIMUM) unit = config.get(CONF_UNIT_OF_MEASUREMENT) - async_add_devices([RandomSensor(name, minimum, maximum, unit)], True) + async_add_entities([RandomSensor(name, minimum, maximum, unit)], True) class RandomSensor(Entity): diff --git a/homeassistant/components/sensor/rest.py b/homeassistant/components/sensor/rest.py index 8db48719a37..53aab3f1ff7 100644 --- a/homeassistant/components/sensor/rest.py +++ b/homeassistant/components/sensor/rest.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the RESTful sensor.""" name = config.get(CONF_NAME) resource = config.get(CONF_RESOURCE) @@ -77,7 +77,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): rest = RestData(method, resource, auth, headers, payload, verify_ssl) rest.update() - add_devices([RestSensor( + add_entities([RestSensor( hass, rest, name, unit, value_template, json_attrs, force_update )], True) diff --git a/homeassistant/components/sensor/rflink.py b/homeassistant/components/sensor/rflink.py index 80d77033bbb..3952c815dca 100644 --- a/homeassistant/components/sensor/rflink.py +++ b/homeassistant/components/sensor/rflink.py @@ -75,9 +75,10 @@ def devices_from_config(domain_config, hass=None): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Rflink platform.""" - async_add_devices(devices_from_config(config, hass)) + async_add_entities(devices_from_config(config, hass)) @asyncio.coroutine def add_new_device(event): @@ -87,7 +88,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): rflinksensor = partial(RflinkSensor, device_id, hass) device = rflinksensor(event[EVENT_KEY_SENSOR], event[EVENT_KEY_UNIT]) # Add device entity - async_add_devices([device]) + async_add_entities([device]) # Register entity to listen to incoming rflink events hass.data[DATA_ENTITY_LOOKUP][ diff --git a/homeassistant/components/sensor/rfxtrx.py b/homeassistant/components/sensor/rfxtrx.py index b410e7e860a..c2eff8d7c5d 100644 --- a/homeassistant/components/sensor/rfxtrx.py +++ b/homeassistant/components/sensor/rfxtrx.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }, extra=vol.ALLOW_EXTRA) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the RFXtrx platform.""" from RFXtrx import SensorEvent sensors = [] @@ -60,7 +60,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(new_sensor) sub_sensors[_data_type] = new_sensor rfxtrx.RFX_DEVICES[device_id] = sub_sensors - add_devices(sensors) + add_entities(sensors) def sensor_update(event): """Handle sensor updates from the RFXtrx gateway.""" @@ -104,7 +104,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sub_sensors = {} sub_sensors[new_sensor.data_type] = new_sensor rfxtrx.RFX_DEVICES[device_id] = sub_sensors - add_devices([new_sensor]) + add_entities([new_sensor]) if sensor_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS: rfxtrx.RECEIVED_EVT_SUBSCRIBERS.append(sensor_update) diff --git a/homeassistant/components/sensor/ring.py b/homeassistant/components/sensor/ring.py index cae7690103d..31c0360cc23 100644 --- a/homeassistant/components/sensor/ring.py +++ b/homeassistant/components/sensor/ring.py @@ -61,7 +61,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a Ring device.""" ring = hass.data[DATA_RING] @@ -79,7 +79,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if 'stickup_cams' in SENSOR_TYPES[sensor_type][1]: sensors.append(RingSensor(hass, device, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) return True diff --git a/homeassistant/components/sensor/ripple.py b/homeassistant/components/sensor/ripple.py index d516706fdc0..beb7bf22269 100644 --- a/homeassistant/components/sensor/ripple.py +++ b/homeassistant/components/sensor/ripple.py @@ -28,12 +28,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ripple.com sensors.""" address = config.get(CONF_ADDRESS) name = config.get(CONF_NAME) - add_devices([RippleSensor(name, address)], True) + add_entities([RippleSensor(name, address)], True) class RippleSensor(Entity): diff --git a/homeassistant/components/sensor/sabnzbd.py b/homeassistant/components/sensor/sabnzbd.py index 185f83c9405..7e94f9026a8 100644 --- a/homeassistant/components/sensor/sabnzbd.py +++ b/homeassistant/components/sensor/sabnzbd.py @@ -16,7 +16,7 @@ DEPENDENCIES = ['sabnzbd'] _LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the SABnzbd sensors.""" if discovery_info is None: @@ -25,8 +25,8 @@ async def async_setup_platform(hass, config, async_add_devices, sab_api_data = hass.data[DATA_SABNZBD] sensors = sab_api_data.sensors client_name = sab_api_data.name - async_add_devices([SabnzbdSensor(sensor, sab_api_data, client_name) - for sensor in sensors]) + async_add_entities([SabnzbdSensor(sensor, sab_api_data, client_name) + for sensor in sensors]) class SabnzbdSensor(Entity): diff --git a/homeassistant/components/sensor/scrape.py b/homeassistant/components/sensor/scrape.py index 0b57528c519..e702c52e06a 100644 --- a/homeassistant/components/sensor/scrape.py +++ b/homeassistant/components/sensor/scrape.py @@ -44,7 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Web scrape sensor.""" name = config.get(CONF_NAME) resource = config.get(CONF_RESOURCE) @@ -74,7 +74,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Unable to fetch data from %s", resource) return False - add_devices([ + add_entities([ ScrapeSensor(rest, name, select, attr, value_template, unit)], True) diff --git a/homeassistant/components/sensor/season.py b/homeassistant/components/sensor/season.py index f06f6a896e7..3b14c3854cd 100644 --- a/homeassistant/components/sensor/season.py +++ b/homeassistant/components/sensor/season.py @@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Display the current season.""" if None in (hass.config.latitude, hass.config.longitude): _LOGGER.error("Latitude or longitude not set in Home Assistant config") @@ -57,7 +57,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): hemisphere = EQUATOR _LOGGER.debug(_type) - add_devices([Season(hass, hemisphere, _type)]) + add_entities([Season(hass, hemisphere, _type)]) return True diff --git a/homeassistant/components/sensor/sense.py b/homeassistant/components/sensor/sense.py index 89e0d15bf48..3da022dc3b5 100644 --- a/homeassistant/components/sensor/sense.py +++ b/homeassistant/components/sensor/sense.py @@ -64,7 +64,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sense sensor.""" from sense_energy import Senseable @@ -96,7 +96,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(Sense(data, name, sensor_type, is_production, update_call)) - add_devices(devices) + add_entities(devices) class Sense(Entity): diff --git a/homeassistant/components/sensor/sensehat.py b/homeassistant/components/sensor/sensehat.py index f0e566f718f..15c73d990e1 100644 --- a/homeassistant/components/sensor/sensehat.py +++ b/homeassistant/components/sensor/sensehat.py @@ -58,14 +58,14 @@ def get_average(temp_base): return temp_avg -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sense HAT sensor platform.""" data = SenseHatData(config.get(CONF_IS_HAT_ATTACHED)) dev = [] for variable in config[CONF_DISPLAY_OPTIONS]: dev.append(SenseHatSensor(data, variable)) - add_devices(dev, True) + add_entities(dev, True) class SenseHatSensor(Entity): diff --git a/homeassistant/components/sensor/serial.py b/homeassistant/components/sensor/serial.py index 521dbce7df2..39b69e0a8c4 100644 --- a/homeassistant/components/sensor/serial.py +++ b/homeassistant/components/sensor/serial.py @@ -36,7 +36,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Serial sensor platform.""" name = config.get(CONF_NAME) port = config.get(CONF_SERIAL_PORT) @@ -50,7 +51,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass.bus.async_listen_once( EVENT_HOMEASSISTANT_STOP, sensor.stop_serial_read()) - async_add_devices([sensor], True) + async_add_entities([sensor], True) class SerialSensor(Entity): diff --git a/homeassistant/components/sensor/serial_pm.py b/homeassistant/components/sensor/serial_pm.py index d2157066625..46dfc9fae75 100644 --- a/homeassistant/components/sensor/serial_pm.py +++ b/homeassistant/components/sensor/serial_pm.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the available PM sensors.""" from pmsensor import serial_pm as pm @@ -54,7 +54,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = 'PM{}'.format(pmname) dev.append(ParticulateMatterSensor(coll, name, pmname)) - add_devices(dev) + add_entities(dev) class ParticulateMatterSensor(Entity): diff --git a/homeassistant/components/sensor/shodan.py b/homeassistant/components/sensor/shodan.py index b94d0cc011c..fd462d6811c 100644 --- a/homeassistant/components/sensor/shodan.py +++ b/homeassistant/components/sensor/shodan.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Shodan sensor.""" import shodan @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.warning("Unable to connect to Shodan.io: %s", error) return False - add_devices([ShodanSensor(data, name)], True) + add_entities([ShodanSensor(data, name)], True) class ShodanSensor(Entity): diff --git a/homeassistant/components/sensor/sht31.py b/homeassistant/components/sensor/sht31.py index 04b78c283c7..4b849849771 100644 --- a/homeassistant/components/sensor/sht31.py +++ b/homeassistant/components/sensor/sht31.py @@ -46,7 +46,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sensor platform.""" from Adafruit_SHT31 import SHT31 @@ -72,7 +72,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = "{} {}".format(config.get(CONF_NAME), sensor_type.capitalize()) devs.append(sensor_class(sensor_client, name)) - add_devices(devs) + add_entities(devs) class SHTClient: diff --git a/homeassistant/components/sensor/sigfox.py b/homeassistant/components/sensor/sigfox.py index 191b3f54f35..5e2a56cadc3 100644 --- a/homeassistant/components/sensor/sigfox.py +++ b/homeassistant/components/sensor/sigfox.py @@ -32,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sigfox sensor.""" api_login = config[CONF_API_LOGIN] api_password = config[CONF_API_PASSWORD] @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors = [] for device in devices: sensors.append(SigfoxDevice(device, auth, name)) - add_devices(sensors, True) + add_entities(sensors, True) def epoch_to_datetime(epoch_time): diff --git a/homeassistant/components/sensor/simulated.py b/homeassistant/components/sensor/simulated.py index 419ca7c13fb..8f2c3dd36e0 100644 --- a/homeassistant/components/sensor/simulated.py +++ b/homeassistant/components/sensor/simulated.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the simulated sensor.""" name = config.get(CONF_NAME) unit = config.get(CONF_UNIT) @@ -68,7 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor = SimulatedSensor(name, unit, amp, mean, period, phase, fwhm, seed, relative_to_epoch) - add_devices([sensor], True) + add_entities([sensor], True) class SimulatedSensor(Entity): diff --git a/homeassistant/components/sensor/skybeacon.py b/homeassistant/components/sensor/skybeacon.py index 2731587ed71..441053a7e7e 100644 --- a/homeassistant/components/sensor/skybeacon.py +++ b/homeassistant/components/sensor/skybeacon.py @@ -39,15 +39,15 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Skybeacon sensor.""" name = config.get(CONF_NAME) mac = config.get(CONF_MAC) _LOGGER.debug("Setting up...") mon = Monitor(hass, mac, name) - add_devices([SkybeaconTemp(name, mon)]) - add_devices([SkybeaconHumid(name, mon)]) + add_entities([SkybeaconTemp(name, mon)]) + add_entities([SkybeaconHumid(name, mon)]) def monitor_stop(_service_or_event): """Stop the monitor thread.""" diff --git a/homeassistant/components/sensor/skybell.py b/homeassistant/components/sensor/skybell.py index dc7295f463a..de8c3a5694d 100644 --- a/homeassistant/components/sensor/skybell.py +++ b/homeassistant/components/sensor/skybell.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform for a Skybell device.""" skybell = hass.data.get(SKYBELL_DOMAIN) @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in skybell.get_devices(): sensors.append(SkybellSensor(device, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) class SkybellSensor(SkybellDevice): diff --git a/homeassistant/components/sensor/sleepiq.py b/homeassistant/components/sensor/sleepiq.py index cf35a400e47..2c97d7eb1e1 100644 --- a/homeassistant/components/sensor/sleepiq.py +++ b/homeassistant/components/sensor/sleepiq.py @@ -10,7 +10,7 @@ DEPENDENCIES = ['sleepiq'] ICON = 'mdi:hotel' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SleepIQ sensors.""" if discovery_info is None: return @@ -22,7 +22,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for bed_id, _ in data.beds.items(): for side in sleepiq.SIDES: dev.append(SleepNumberSensor(data, bed_id, side)) - add_devices(dev) + add_entities(dev) class SleepNumberSensor(sleepiq.SleepIQSensor): diff --git a/homeassistant/components/sensor/sma.py b/homeassistant/components/sensor/sma.py index 2be46da0bdb..945c3873bb6 100644 --- a/homeassistant/components/sensor/sma.py +++ b/homeassistant/components/sensor/sma.py @@ -64,7 +64,8 @@ PLATFORM_SCHEMA = vol.All(PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up SMA WebConnect sensor.""" import pysma @@ -93,7 +94,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): sensor_defs = {name: val for name, val in sensor_defs.items() if name in used_sensors} - async_add_devices(hass_sensors) + async_add_entities(hass_sensors) # Init the SMA interface session = async_get_clientsession(hass) diff --git a/homeassistant/components/sensor/smappee.py b/homeassistant/components/sensor/smappee.py index 783c2aad469..65f21815960 100644 --- a/homeassistant/components/sensor/smappee.py +++ b/homeassistant/components/sensor/smappee.py @@ -49,7 +49,7 @@ SENSOR_TYPES = { SCAN_INTERVAL = timedelta(seconds=30) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Smappee sensor.""" smappee = hass.data[DATA_SMAPPEE] @@ -80,7 +80,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(SmappeeSensor(smappee, None, sensor, SENSOR_TYPES[sensor])) - add_devices(dev, True) + add_entities(dev, True) class SmappeeSensor(Entity): diff --git a/homeassistant/components/sensor/snmp.py b/homeassistant/components/sensor/snmp.py index e6119ab80b6..f7d160ecf2f 100644 --- a/homeassistant/components/sensor/snmp.py +++ b/homeassistant/components/sensor/snmp.py @@ -53,7 +53,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SNMP sensor.""" from pysnmp.hlapi import ( getCmd, CommunityData, SnmpEngine, UdpTransportTarget, ContextData, @@ -86,7 +86,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data = SnmpData( host, port, community, baseoid, version, accept_errors, default_value) - add_devices([SnmpSensor(data, name, unit, value_template)], True) + add_entities([SnmpSensor(data, name, unit, value_template)], True) class SnmpSensor(Entity): diff --git a/homeassistant/components/sensor/sochain.py b/homeassistant/components/sensor/sochain.py index 572d0f52921..9f8982f871f 100644 --- a/homeassistant/components/sensor/sochain.py +++ b/homeassistant/components/sensor/sochain.py @@ -36,7 +36,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the sochain sensors.""" from pysochain import ChainSo address = config.get(CONF_ADDRESS) @@ -46,7 +47,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): session = async_get_clientsession(hass) chainso = ChainSo(network, address, hass.loop, session) - async_add_devices([SochainSensor(name, network.upper(), chainso)], True) + async_add_entities([SochainSensor(name, network.upper(), chainso)], True) class SochainSensor(Entity): diff --git a/homeassistant/components/sensor/socialblade.py b/homeassistant/components/sensor/socialblade.py index 1e0084e1404..9a73e9cdd68 100644 --- a/homeassistant/components/sensor/socialblade.py +++ b/homeassistant/components/sensor/socialblade.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Social Blade sensor.""" social_blade = SocialBladeSensor( config[CHANNEL_ID], config[CONF_NAME]) @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if social_blade.valid_channel_id is False: return - add_devices([social_blade]) + add_entities([social_blade]) class SocialBladeSensor(Entity): diff --git a/homeassistant/components/sensor/sonarr.py b/homeassistant/components/sensor/sonarr.py index c2fd6c80663..b0e87992e39 100644 --- a/homeassistant/components/sensor/sonarr.py +++ b/homeassistant/components/sensor/sonarr.py @@ -67,10 +67,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Sonarr platform.""" conditions = config.get(CONF_MONITORED_CONDITIONS) - add_devices( + add_entities( [SonarrSensor(hass, config, sensor) for sensor in conditions], True) diff --git a/homeassistant/components/sensor/speedtest.py b/homeassistant/components/sensor/speedtest.py index 8c1ffc03786..8da7374f231 100644 --- a/homeassistant/components/sensor/speedtest.py +++ b/homeassistant/components/sensor/speedtest.py @@ -61,7 +61,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Speedtest sensor.""" data = SpeedtestData(hass, config) @@ -69,7 +69,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for sensor in config[CONF_MONITORED_CONDITIONS]: dev.append(SpeedtestSensor(data, sensor)) - add_devices(dev) + add_entities(dev) def update(call=None): """Update service for manual updates.""" diff --git a/homeassistant/components/sensor/spotcrime.py b/homeassistant/components/sensor/spotcrime.py index daa520f2ede..46f5fdc1c85 100644 --- a/homeassistant/components/sensor/spotcrime.py +++ b/homeassistant/components/sensor/spotcrime.py @@ -44,7 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Crime Reports platform.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) @@ -55,7 +55,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): include = config.get(CONF_INCLUDE) exclude = config.get(CONF_EXCLUDE) - add_devices([SpotCrimeSensor( + add_entities([SpotCrimeSensor( name, latitude, longitude, radius, include, exclude, api_key, days)], True) diff --git a/homeassistant/components/sensor/sql.py b/homeassistant/components/sensor/sql.py index 83f5478867f..a2e9549a117 100644 --- a/homeassistant/components/sensor/sql.py +++ b/homeassistant/components/sensor/sql.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SQL sensor platform.""" db_url = config.get(CONF_DB_URL, None) if not db_url: @@ -87,7 +87,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) queries.append(sensor) - add_devices(queries, True) + add_entities(queries, True) class SQLSensor(Entity): diff --git a/homeassistant/components/sensor/startca.py b/homeassistant/components/sensor/startca.py index 374e14c5ac2..d9a52e4aa23 100644 --- a/homeassistant/components/sensor/startca.py +++ b/homeassistant/components/sensor/startca.py @@ -58,7 +58,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the sensor platform.""" websession = async_get_clientsession(hass) apikey = config.get(CONF_API_KEY) @@ -74,7 +75,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): sensors = [] for variable in config[CONF_MONITORED_VARIABLES]: sensors.append(StartcaSensor(ts_data, variable, name)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class StartcaSensor(Entity): diff --git a/homeassistant/components/sensor/statistics.py b/homeassistant/components/sensor/statistics.py index 35333090910..b1cfd447f0e 100644 --- a/homeassistant/components/sensor/statistics.py +++ b/homeassistant/components/sensor/statistics.py @@ -54,14 +54,15 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Statistics sensor.""" entity_id = config.get(CONF_ENTITY_ID) name = config.get(CONF_NAME) sampling_size = config.get(CONF_SAMPLING_SIZE) max_age = config.get(CONF_MAX_AGE, None) - async_add_devices( + async_add_entities( [StatisticsSensor(hass, entity_id, name, sampling_size, max_age)], True) return True diff --git a/homeassistant/components/sensor/steam_online.py b/homeassistant/components/sensor/steam_online.py index 7521b74cd28..861a5958dd3 100644 --- a/homeassistant/components/sensor/steam_online.py +++ b/homeassistant/components/sensor/steam_online.py @@ -36,14 +36,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Steam platform.""" import steam as steamod steamod.api.key.set(config.get(CONF_API_KEY)) # Initialize steammods app list before creating sensors # to benefit from internal caching of the list. steam_app_list = steamod.apps.app_list() - add_devices( + add_entities( [SteamSensor(account, steamod, steam_app_list) diff --git a/homeassistant/components/sensor/supervisord.py b/homeassistant/components/sensor/supervisord.py index 5a302462bbf..894881dad86 100644 --- a/homeassistant/components/sensor/supervisord.py +++ b/homeassistant/components/sensor/supervisord.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Supervisord platform.""" url = config.get(CONF_URL) try: @@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Could not connect to Supervisord") return False - add_devices( + add_entities( [SupervisorProcessSensor(info, supervisor_server) for info in processes], True) diff --git a/homeassistant/components/sensor/swiss_hydrological_data.py b/homeassistant/components/sensor/swiss_hydrological_data.py index b4536b48c9e..fb55c22b2e8 100644 --- a/homeassistant/components/sensor/swiss_hydrological_data.py +++ b/homeassistant/components/sensor/swiss_hydrological_data.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Swiss hydrological sensor.""" import xmltodict @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False data = HydrologicalData(station) - add_devices([SwissHydrologicalDataSensor(name, data)], True) + add_entities([SwissHydrologicalDataSensor(name, data)], True) class SwissHydrologicalDataSensor(Entity): diff --git a/homeassistant/components/sensor/swiss_public_transport.py b/homeassistant/components/sensor/swiss_public_transport.py index 72c6aa2e1a3..6f44350c5cf 100644 --- a/homeassistant/components/sensor/swiss_public_transport.py +++ b/homeassistant/components/sensor/swiss_public_transport.py @@ -48,7 +48,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Swiss public transport sensor.""" from opendata_transport import OpendataTransport, exceptions @@ -67,7 +67,7 @@ async def async_setup_platform( "if your station names are valid") return - async_add_devices( + async_add_entities( [SwissPublicTransportSensor(opendata, start, destination, name)]) diff --git a/homeassistant/components/sensor/syncthru.py b/homeassistant/components/sensor/syncthru.py index a24482bda01..45a529012e3 100644 --- a/homeassistant/components/sensor/syncthru.py +++ b/homeassistant/components/sensor/syncthru.py @@ -60,7 +60,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SyncThru component.""" from pysyncthru import SyncThru, test_syncthru @@ -101,7 +101,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if 'output_tray_{}'.format(key) in monitored: devices.append(SyncThruOutputTraySensor(printer, name, key)) - add_devices(devices, True) + add_entities(devices, True) class SyncThruSensor(Entity): diff --git a/homeassistant/components/sensor/synologydsm.py b/homeassistant/components/sensor/synologydsm.py index d431805ab19..39a9e75c47b 100644 --- a/homeassistant/components/sensor/synologydsm.py +++ b/homeassistant/components/sensor/synologydsm.py @@ -86,7 +86,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Synology NAS Sensor.""" def run_setup(event): """Wait until Home Assistant is fully initialized before creating. @@ -123,7 +123,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in monitored_conditions if variable in _STORAGE_DSK_MON_COND] - add_devices(sensors, True) + add_entities(sensors, True) # Wait until start event is sent to load this component. hass.bus.listen_once(EVENT_HOMEASSISTANT_START, run_setup) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index b9a04e546d3..aa448ddf56e 100644 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -67,7 +67,7 @@ IF_ADDRS = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the system monitor sensors.""" dev = [] for resource in config[CONF_RESOURCES]: @@ -76,7 +76,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(SystemMonitorSensor( resource[CONF_TYPE], resource[CONF_ARG])) - add_devices(dev, True) + add_entities(dev, True) class SystemMonitorSensor(Entity): diff --git a/homeassistant/components/sensor/sytadin.py b/homeassistant/components/sensor/sytadin.py index 4aeb0cca32f..18fa73f2341 100644 --- a/homeassistant/components/sensor/sytadin.py +++ b/homeassistant/components/sensor/sytadin.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up of the Sytadin Traffic sensor platform.""" name = config.get(CONF_NAME) @@ -61,7 +61,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(SytadinSensor( sytadin, name, option, SENSOR_TYPES[option][0], SENSOR_TYPES[option][1])) - add_devices(dev, True) + add_entities(dev, True) class SytadinSensor(Entity): diff --git a/homeassistant/components/sensor/tado.py b/homeassistant/components/sensor/tado.py index aa6314b8c5b..46ad6206fff 100644 --- a/homeassistant/components/sensor/tado.py +++ b/homeassistant/components/sensor/tado.py @@ -22,7 +22,7 @@ CLIMATE_SENSOR_TYPES = ['temperature', 'humidity', 'power', HOT_WATER_SENSOR_TYPES = ['power', 'link', 'tado mode', 'overlay'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sensor platform.""" tado = hass.data[DATA_TADO] @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): me_data['homes'][0]['id'], "tado bridge status")) if sensor_items: - add_devices(sensor_items, True) + add_entities(sensor_items, True) def create_zone_sensor(tado, zone, name, zone_id, variable): diff --git a/homeassistant/components/sensor/tahoma.py b/homeassistant/components/sensor/tahoma.py index 6c6c296652a..eafc6fdf616 100644 --- a/homeassistant/components/sensor/tahoma.py +++ b/homeassistant/components/sensor/tahoma.py @@ -19,13 +19,13 @@ _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=10) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tahoma controller devices.""" controller = hass.data[TAHOMA_DOMAIN]['controller'] devices = [] for device in hass.data[TAHOMA_DOMAIN]['devices']['sensor']: devices.append(TahomaSensor(device, controller)) - add_devices(devices, True) + add_entities(devices, True) class TahomaSensor(TahomaDevice, Entity): diff --git a/homeassistant/components/sensor/tank_utility.py b/homeassistant/components/sensor/tank_utility.py index 1f565d44325..c3cc75dac0c 100644 --- a/homeassistant/components/sensor/tank_utility.py +++ b/homeassistant/components/sensor/tank_utility.py @@ -47,7 +47,7 @@ SENSOR_ATTRS = [ ] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tank Utility sensor.""" from tank_utility import auth email = config.get(CONF_EMAIL) @@ -66,7 +66,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in devices: sensor = TankUtilitySensor(email, password, token, device) all_sensors.append(sensor) - add_devices(all_sensors, True) + add_entities(all_sensors, True) class TankUtilitySensor(Entity): diff --git a/homeassistant/components/sensor/tcp.py b/homeassistant/components/sensor/tcp.py index 30ceba776e9..19197c06295 100644 --- a/homeassistant/components/sensor/tcp.py +++ b/homeassistant/components/sensor/tcp.py @@ -41,9 +41,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the TCP Sensor.""" - add_devices([TcpSensor(hass, config)]) + add_entities([TcpSensor(hass, config)]) class TcpSensor(Entity): diff --git a/homeassistant/components/sensor/ted5000.py b/homeassistant/components/sensor/ted5000.py index 7298181796a..a6ea7cbd534 100644 --- a/homeassistant/components/sensor/ted5000.py +++ b/homeassistant/components/sensor/ted5000.py @@ -32,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ted5000 sensor.""" host = config.get(CONF_HOST) port = config.get(CONF_PORT) @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(Ted5000Sensor(gateway, name, mtu, 'W')) dev.append(Ted5000Sensor(gateway, name, mtu, 'V')) - add_devices(dev) + add_entities(dev) return True diff --git a/homeassistant/components/sensor/teksavvy.py b/homeassistant/components/sensor/teksavvy.py index 68a1cfc4fe1..87b89074cfb 100644 --- a/homeassistant/components/sensor/teksavvy.py +++ b/homeassistant/components/sensor/teksavvy.py @@ -59,7 +59,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the sensor platform.""" websession = async_get_clientsession(hass) apikey = config.get(CONF_API_KEY) @@ -75,7 +76,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): sensors = [] for variable in config[CONF_MONITORED_VARIABLES]: sensors.append(TekSavvySensor(ts_data, variable, name)) - async_add_devices(sensors, True) + async_add_entities(sensors, True) class TekSavvySensor(Entity): diff --git a/homeassistant/components/sensor/tellduslive.py b/homeassistant/components/sensor/tellduslive.py index 9d5a21b37c4..34908595951 100644 --- a/homeassistant/components/sensor/tellduslive.py +++ b/homeassistant/components/sensor/tellduslive.py @@ -44,11 +44,11 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tellstick sensors.""" if discovery_info is None: return - add_devices(TelldusLiveSensor(hass, sensor) for sensor in discovery_info) + add_entities(TelldusLiveSensor(hass, sensor) for sensor in discovery_info) class TelldusLiveSensor(TelldusLiveEntity): diff --git a/homeassistant/components/sensor/tellstick.py b/homeassistant/components/sensor/tellstick.py index 2fc67e57162..aac97580f2c 100644 --- a/homeassistant/components/sensor/tellstick.py +++ b/homeassistant/components/sensor/tellstick.py @@ -37,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tellstick sensors.""" from tellcore import telldus import tellcore.constants as tellcore_constants @@ -89,7 +89,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(TellstickSensor( sensor_name, tellcore_sensor, datatype, sensor_info)) - add_devices(sensors) + add_entities(sensors) class TellstickSensor(Entity): diff --git a/homeassistant/components/sensor/temper.py b/homeassistant/components/sensor/temper.py index f0a3e15834c..72184df7c8f 100644 --- a/homeassistant/components/sensor/temper.py +++ b/homeassistant/components/sensor/temper.py @@ -33,7 +33,7 @@ def get_temper_devices(): return TemperHandler().get_devices() -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Temper sensors.""" temp_unit = hass.config.units.temperature_unit name = config.get(CONF_NAME) @@ -47,7 +47,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if idx != 0: name = name + '_' + str(idx) TEMPER_SENSORS.append(TemperSensor(dev, temp_unit, name, scaling)) - add_devices(TEMPER_SENSORS) + add_entities(TEMPER_SENSORS) def reset_devices(): diff --git a/homeassistant/components/sensor/template.py b/homeassistant/components/sensor/template.py index 23c7c13f0ed..f64e8b122ca 100644 --- a/homeassistant/components/sensor/template.py +++ b/homeassistant/components/sensor/template.py @@ -42,7 +42,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the template sensors.""" sensors = [] @@ -96,7 +97,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.error("No sensors added") return False - async_add_devices(sensors) + async_add_entities(sensors) return True diff --git a/homeassistant/components/sensor/tesla.py b/homeassistant/components/sensor/tesla.py index 3233ebb1780..51b7ea2325d 100644 --- a/homeassistant/components/sensor/tesla.py +++ b/homeassistant/components/sensor/tesla.py @@ -21,7 +21,7 @@ DEPENDENCIES = ['tesla'] SCAN_INTERVAL = timedelta(minutes=5) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tesla sensor platform.""" controller = hass.data[TESLA_DOMAIN]['devices']['controller'] devices = [] @@ -32,7 +32,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(TeslaSensor(device, controller, 'outside')) else: devices.append(TeslaSensor(device, controller)) - add_devices(devices, True) + add_entities(devices, True) class TeslaSensor(TeslaDevice, Entity): diff --git a/homeassistant/components/sensor/thethingsnetwork.py b/homeassistant/components/sensor/thethingsnetwork.py index 0f27b656404..02661f2211d 100644 --- a/homeassistant/components/sensor/thethingsnetwork.py +++ b/homeassistant/components/sensor/thethingsnetwork.py @@ -39,7 +39,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up The Things Network Data storage sensors.""" ttn = hass.data.get(DATA_TTN) device_id = config.get(CONF_DEVICE_ID) @@ -58,7 +59,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for value, unit_of_measurement in values.items(): devices.append(TtnDataSensor( ttn_data_storage, device_id, value, unit_of_measurement)) - async_add_devices(devices, True) + async_add_entities(devices, True) class TtnDataSensor(Entity): diff --git a/homeassistant/components/sensor/thinkingcleaner.py b/homeassistant/components/sensor/thinkingcleaner.py index 0b936d8c8c7..17e2f717f5a 100644 --- a/homeassistant/components/sensor/thinkingcleaner.py +++ b/homeassistant/components/sensor/thinkingcleaner.py @@ -51,7 +51,7 @@ STATES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ThinkingCleaner platform.""" from pythinkingcleaner import Discovery @@ -70,7 +70,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(ThinkingCleanerSensor(device, type_name, update_devices)) - add_devices(dev) + add_entities(dev) class ThinkingCleanerSensor(Entity): diff --git a/homeassistant/components/sensor/tibber.py b/homeassistant/components/sensor/tibber.py index c75c40dd929..3670a5a59bd 100644 --- a/homeassistant/components/sensor/tibber.py +++ b/homeassistant/components/sensor/tibber.py @@ -34,7 +34,7 @@ SCAN_INTERVAL = timedelta(minutes=1) MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Tibber sensor.""" import tibber @@ -50,7 +50,7 @@ async def async_setup_platform(hass, config, async_add_devices, except (asyncio.TimeoutError, aiohttp.ClientError): raise PlatformNotReady() - async_add_devices(dev, True) + async_add_entities(dev, True) class TibberSensor(Entity): diff --git a/homeassistant/components/sensor/time_date.py b/homeassistant/components/sensor/time_date.py index 0668b5bdbce..e4c719acd0d 100644 --- a/homeassistant/components/sensor/time_date.py +++ b/homeassistant/components/sensor/time_date.py @@ -38,7 +38,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Time and Date sensor.""" if hass.config.time_zone is None: _LOGGER.error("Timezone is not set in Home Assistant configuration") @@ -51,7 +52,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): hass, device.point_in_time_listener, device.get_next_interval()) devices.append(device) - async_add_devices(devices, True) + async_add_entities(devices, True) class TimeDateSensor(Entity): diff --git a/homeassistant/components/sensor/toon.py b/homeassistant/components/sensor/toon.py index a8875f6904c..fb057603a1a 100644 --- a/homeassistant/components/sensor/toon.py +++ b/homeassistant/components/sensor/toon.py @@ -16,7 +16,7 @@ STATE_ATTR_DEVICE_TYPE = 'device_type' STATE_ATTR_LAST_CONNECTED_CHANGE = 'last_connected_change' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Toon sensors.""" _toon_main = hass.data[toon_main.TOON_HANDLE] @@ -58,7 +58,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): smokedetector.device_uuid, 'alarm-bell', '%') ) - add_devices(sensor_items) + add_entities(sensor_items) class ToonSensor(Entity): diff --git a/homeassistant/components/sensor/torque.py b/homeassistant/components/sensor/torque.py index 4ed1b5907cf..4941633677c 100644 --- a/homeassistant/components/sensor/torque.py +++ b/homeassistant/components/sensor/torque.py @@ -46,14 +46,14 @@ def convert_pid(value): return int(value, 16) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Torque platform.""" vehicle = config.get(CONF_NAME) email = config.get(CONF_EMAIL) sensors = {} hass.http.register_view(TorqueReceiveDataView( - email, vehicle, sensors, add_devices)) + email, vehicle, sensors, add_entities)) return True @@ -63,12 +63,12 @@ class TorqueReceiveDataView(HomeAssistantView): url = API_PATH name = 'api:torque' - def __init__(self, email, vehicle, sensors, add_devices): + def __init__(self, email, vehicle, sensors, add_entities): """Initialize a Torque view.""" self.email = email self.vehicle = vehicle self.sensors = sensors - self.add_devices = add_devices + self.add_entities = add_entities @callback def get(self, request): @@ -102,7 +102,7 @@ class TorqueReceiveDataView(HomeAssistantView): self.sensors[pid] = TorqueSensor( ENTITY_NAME_FORMAT.format(self.vehicle, names[pid]), units.get(pid, None)) - hass.async_add_job(self.add_devices, [self.sensors[pid]]) + hass.async_add_job(self.add_entities, [self.sensors[pid]]) return "OK!" diff --git a/homeassistant/components/sensor/tradfri.py b/homeassistant/components/sensor/tradfri.py index df931770cf2..0849169b747 100644 --- a/homeassistant/components/sensor/tradfri.py +++ b/homeassistant/components/sensor/tradfri.py @@ -19,7 +19,7 @@ DEPENDENCIES = ['tradfri'] SCAN_INTERVAL = timedelta(minutes=5) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the IKEA Tradfri device platform.""" if discovery_info is None: @@ -33,7 +33,7 @@ async def async_setup_platform(hass, config, async_add_devices, devices_commands = await api(devices_command) all_devices = await api(devices_commands) devices = [dev for dev in all_devices if not dev.has_light_control] - async_add_devices(TradfriDevice(device, api) for device in devices) + async_add_entities(TradfriDevice(device, api) for device in devices) class TradfriDevice(Entity): diff --git a/homeassistant/components/sensor/trafikverket_weatherstation.py b/homeassistant/components/sensor/trafikverket_weatherstation.py index 77a2b0e7338..a8ce6917dd3 100644 --- a/homeassistant/components/sensor/trafikverket_weatherstation.py +++ b/homeassistant/components/sensor/trafikverket_weatherstation.py @@ -36,14 +36,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Trafikverket sensor platform.""" sensor_name = config.get(CONF_NAME) sensor_api = config.get(CONF_API_KEY) sensor_station = config.get(CONF_STATION) sensor_type = config.get(CONF_TYPE) - add_devices([TrafikverketWeatherStation( + add_entities([TrafikverketWeatherStation( sensor_name, sensor_api, sensor_station, sensor_type)], True) diff --git a/homeassistant/components/sensor/transmission.py b/homeassistant/components/sensor/transmission.py index 3e74b454913..a669db0e5be 100644 --- a/homeassistant/components/sensor/transmission.py +++ b/homeassistant/components/sensor/transmission.py @@ -47,7 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Transmission sensors.""" import transmissionrpc from transmissionrpc.error import TransmissionError @@ -75,7 +75,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_MONITORED_VARIABLES]: dev.append(TransmissionSensor(variable, transmission_api, name)) - add_devices(dev, True) + add_entities(dev, True) class TransmissionSensor(Entity): diff --git a/homeassistant/components/sensor/travisci.py b/homeassistant/components/sensor/travisci.py index 1ca08e7c0aa..40ae130d150 100644 --- a/homeassistant/components/sensor/travisci.py +++ b/homeassistant/components/sensor/travisci.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Travis CI sensor.""" from travispy import TravisPy from travispy.errors import TravisError @@ -92,7 +92,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append( TravisCISensor(travis, repo, user, branch, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) return True diff --git a/homeassistant/components/sensor/twitch.py b/homeassistant/components/sensor/twitch.py index 250911b49b1..3763aa30fb4 100644 --- a/homeassistant/components/sensor/twitch.py +++ b/homeassistant/components/sensor/twitch.py @@ -31,11 +31,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Twitch platform.""" channels = config.get(CONF_CHANNELS, []) - add_devices([TwitchSensor(channel) for channel in channels], True) + add_entities([TwitchSensor(channel) for channel in channels], True) class TwitchSensor(Entity): diff --git a/homeassistant/components/sensor/uber.py b/homeassistant/components/sensor/uber.py index cd476a1a226..a97ccaffed0 100644 --- a/homeassistant/components/sensor/uber.py +++ b/homeassistant/components/sensor/uber.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Uber sensor.""" from uber_rides.session import Session @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(UberSensor( 'price', timeandpriceest, product_id, product)) - add_devices(dev, True) + add_entities(dev, True) class UberSensor(Entity): diff --git a/homeassistant/components/sensor/uk_transport.py b/homeassistant/components/sensor/uk_transport.py index 72d34411d5c..a7aba9a566b 100644 --- a/homeassistant/components/sensor/uk_transport.py +++ b/homeassistant/components/sensor/uk_transport.py @@ -47,7 +47,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Get the uk_transport sensor.""" sensors = [] number_sensors = len(config.get(CONF_QUERIES)) @@ -76,7 +76,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): calling_at, interval)) - add_devices(sensors, True) + add_entities(sensors, True) class UkTransportSensor(Entity): diff --git a/homeassistant/components/sensor/upnp.py b/homeassistant/components/sensor/upnp.py index 07b63553fcb..d021312d15c 100644 --- a/homeassistant/components/sensor/upnp.py +++ b/homeassistant/components/sensor/upnp.py @@ -27,7 +27,7 @@ SENSOR_TYPES = { } -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the IGD sensors.""" if discovery_info is None: @@ -36,7 +36,7 @@ async def async_setup_platform(hass, config, async_add_devices, device = hass.data[DATA_UPNP] service = device.find_first_service(CIC_SERVICE) unit = discovery_info['unit'] - async_add_devices([ + async_add_entities([ IGDSensor(service, t, unit if SENSOR_TYPES[t][1] else '#') for t in SENSOR_TYPES], True) diff --git a/homeassistant/components/sensor/ups.py b/homeassistant/components/sensor/ups.py index a864df384ad..aa6ce930619 100644 --- a/homeassistant/components/sensor/ups.py +++ b/homeassistant/components/sensor/ups.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the UPS platform.""" import upsmychoice try: @@ -50,8 +50,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.exception("Could not connect to UPS My Choice") return False - add_devices([UPSSensor(session, config.get(CONF_NAME), - config.get(CONF_UPDATE_INTERVAL))], True) + add_entities([UPSSensor(session, config.get(CONF_NAME), + config.get(CONF_UPDATE_INTERVAL))], True) class UPSSensor(Entity): diff --git a/homeassistant/components/sensor/uptime.py b/homeassistant/components/sensor/uptime.py index 7e893899815..197233461fb 100644 --- a/homeassistant/components/sensor/uptime.py +++ b/homeassistant/components/sensor/uptime.py @@ -28,12 +28,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the uptime sensor platform.""" name = config.get(CONF_NAME) units = config.get(CONF_UNIT_OF_MEASUREMENT) - async_add_devices([UptimeSensor(name, units)], True) + async_add_entities([UptimeSensor(name, units)], True) class UptimeSensor(Entity): diff --git a/homeassistant/components/sensor/uscis.py b/homeassistant/components/sensor/uscis.py index f93a788092b..e3a917b0a5a 100644 --- a/homeassistant/components/sensor/uscis.py +++ b/homeassistant/components/sensor/uscis.py @@ -28,12 +28,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform in HASS and Case Information.""" uscis = UscisSensor(config['case_id'], config[CONF_FRIENDLY_NAME]) uscis.update() if uscis.valid_case_id: - add_devices([uscis]) + add_entities([uscis]) else: _LOGGER.error("Setup USCIS Sensor Fail" " check if your Case ID is Valid") diff --git a/homeassistant/components/sensor/usps.py b/homeassistant/components/sensor/usps.py index 6ca18442883..17fa11fe8d3 100644 --- a/homeassistant/components/sensor/usps.py +++ b/homeassistant/components/sensor/usps.py @@ -20,13 +20,13 @@ DEPENDENCIES = ['usps'] STATUS_DELIVERED = 'delivered' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the USPS platform.""" if discovery_info is None: return usps = hass.data[DATA_USPS] - add_devices([USPSPackageSensor(usps), USPSMailSensor(usps)], True) + add_entities([USPSPackageSensor(usps), USPSMailSensor(usps)], True) class USPSPackageSensor(Entity): diff --git a/homeassistant/components/sensor/vasttrafik.py b/homeassistant/components/sensor/vasttrafik.py index 8cd084e1b71..7ef4170dd5a 100644 --- a/homeassistant/components/sensor/vasttrafik.py +++ b/homeassistant/components/sensor/vasttrafik.py @@ -53,7 +53,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the departure sensor.""" import vasttrafik planner = vasttrafik.JournyPlanner( @@ -65,7 +65,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): vasttrafik, planner, departure.get(CONF_NAME), departure.get(CONF_FROM), departure.get(CONF_HEADING), departure.get(CONF_LINES), departure.get(CONF_DELAY))) - add_devices(sensors, True) + add_entities(sensors, True) class VasttrafikDepartureSensor(Entity): diff --git a/homeassistant/components/sensor/vera.py b/homeassistant/components/sensor/vera.py index eaef3dcf7f7..c9b5a36afa3 100644 --- a/homeassistant/components/sensor/vera.py +++ b/homeassistant/components/sensor/vera.py @@ -22,9 +22,9 @@ _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(seconds=5) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vera controller devices.""" - add_devices( + add_entities( [VeraSensor(device, hass.data[VERA_CONTROLLER]) for device in hass.data[VERA_DEVICES]['sensor']], True) diff --git a/homeassistant/components/sensor/verisure.py b/homeassistant/components/sensor/verisure.py index 187a9bd7935..b6ea75ae8cc 100644 --- a/homeassistant/components/sensor/verisure.py +++ b/homeassistant/components/sensor/verisure.py @@ -15,7 +15,7 @@ from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Verisure platform.""" sensors = [] hub.update_overview() @@ -38,7 +38,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device_label in hub.get( "$.eventCounts[?(@.deviceType=='MOUSE1')].deviceLabel")]) - add_devices(sensors) + add_entities(sensors) class VerisureThermometer(Entity): diff --git a/homeassistant/components/sensor/version.py b/homeassistant/components/sensor/version.py index db61d059783..eba4b1b8350 100644 --- a/homeassistant/components/sensor/version.py +++ b/homeassistant/components/sensor/version.py @@ -23,11 +23,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the Version sensor platform.""" name = config.get(CONF_NAME) - async_add_devices([VersionSensor(name)]) + async_add_entities([VersionSensor(name)]) class VersionSensor(Entity): diff --git a/homeassistant/components/sensor/viaggiatreno.py b/homeassistant/components/sensor/viaggiatreno.py index 43ba80d2630..1dd8523eb4b 100644 --- a/homeassistant/components/sensor/viaggiatreno.py +++ b/homeassistant/components/sensor/viaggiatreno.py @@ -57,14 +57,15 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the ViaggiaTreno platform.""" train_id = config.get(CONF_TRAIN_ID) station_id = config.get(CONF_STATION_ID) name = config.get(CONF_NAME) if not name: name = DEFAULT_NAME.format(train_id) - async_add_devices([ViaggiaTrenoSensor(train_id, station_id, name)]) + async_add_entities([ViaggiaTrenoSensor(train_id, station_id, name)]) @asyncio.coroutine diff --git a/homeassistant/components/sensor/volvooncall.py b/homeassistant/components/sensor/volvooncall.py index 78e8a7e76c6..a3f0c55b954 100644 --- a/homeassistant/components/sensor/volvooncall.py +++ b/homeassistant/components/sensor/volvooncall.py @@ -14,11 +14,11 @@ from homeassistant.components.volvooncall import ( _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Volvo sensors.""" if discovery_info is None: return - add_devices([VolvoSensor(hass, *discovery_info)]) + add_entities([VolvoSensor(hass, *discovery_info)]) class VolvoSensor(VolvoEntity): diff --git a/homeassistant/components/sensor/vultr.py b/homeassistant/components/sensor/vultr.py index 291639c81d6..a727e5bd2ec 100644 --- a/homeassistant/components/sensor/vultr.py +++ b/homeassistant/components/sensor/vultr.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vultr subscription (server) sensor.""" vultr = hass.data[DATA_VULTR] @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for condition in monitored_conditions: sensors.append(VultrSensor(vultr, subscription, condition, name)) - add_devices(sensors, True) + add_entities(sensors, True) class VultrSensor(Entity): diff --git a/homeassistant/components/sensor/waqi.py b/homeassistant/components/sensor/waqi.py index bf2e263a0bb..9f90f465fb2 100644 --- a/homeassistant/components/sensor/waqi.py +++ b/homeassistant/components/sensor/waqi.py @@ -60,7 +60,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the requested World Air Quality Index locations.""" import waqiasync @@ -86,7 +87,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): asyncio.TimeoutError): _LOGGER.exception('Failed to connect to WAQI servers.') raise PlatformNotReady - async_add_devices(dev, True) + async_add_entities(dev, True) class WaqiSensor(Entity): diff --git a/homeassistant/components/sensor/waterfurnace.py b/homeassistant/components/sensor/waterfurnace.py index 76c5d2f648e..806b40551df 100644 --- a/homeassistant/components/sensor/waterfurnace.py +++ b/homeassistant/components/sensor/waterfurnace.py @@ -46,7 +46,7 @@ SENSORS = [ ] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Waterfurnace sensor.""" if discovery_info is None: return @@ -56,7 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for sconfig in SENSORS: sensors.append(WaterFurnaceSensor(client, sconfig)) - add_devices(sensors) + add_entities(sensors) class WaterFurnaceSensor(Entity): diff --git a/homeassistant/components/sensor/waze_travel_time.py b/homeassistant/components/sensor/waze_travel_time.py index 023da72299b..8d046b0de0d 100644 --- a/homeassistant/components/sensor/waze_travel_time.py +++ b/homeassistant/components/sensor/waze_travel_time.py @@ -55,7 +55,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Waze travel time sensor platform.""" destination = config.get(CONF_DESTINATION) name = config.get(CONF_NAME) @@ -68,7 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor = WazeTravelTime(name, origin, destination, region, incl_filter, excl_filter, realtime) - add_devices([sensor]) + add_entities([sensor]) # Wait until start event is sent to load this component. hass.bus.listen_once(EVENT_HOMEASSISTANT_START, sensor.update) diff --git a/homeassistant/components/sensor/whois.py b/homeassistant/components/sensor/whois.py index 21b1b99ca13..b589caddc79 100644 --- a/homeassistant/components/sensor/whois.py +++ b/homeassistant/components/sensor/whois.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the WHOIS sensor.""" from pythonwhois import get_whois from pythonwhois.shared import WhoisException @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): try: if 'expiration_date' in get_whois(domain, normalized=True): - add_devices([WhoisSensor(name, domain)], True) + add_entities([WhoisSensor(name, domain)], True) else: _LOGGER.error( "WHOIS lookup for %s didn't contain expiration_date", diff --git a/homeassistant/components/sensor/wink.py b/homeassistant/components/sensor/wink.py index 75751bbbf8a..8e11b054b24 100644 --- a/homeassistant/components/sensor/wink.py +++ b/homeassistant/components/sensor/wink.py @@ -18,7 +18,7 @@ DEPENDENCIES = ['wink'] SENSOR_TYPES = ['temperature', 'humidity', 'balance', 'proximity'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink platform.""" import pywink @@ -26,24 +26,24 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _id = sensor.object_id() + sensor.name() if _id not in hass.data[DOMAIN]['unique_ids']: if sensor.capability() in SENSOR_TYPES: - add_devices([WinkSensorDevice(sensor, hass)]) + add_entities([WinkSensorDevice(sensor, hass)]) for eggtray in pywink.get_eggtrays(): _id = eggtray.object_id() + eggtray.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkSensorDevice(eggtray, hass)]) + add_entities([WinkSensorDevice(eggtray, hass)]) for tank in pywink.get_propane_tanks(): _id = tank.object_id() + tank.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkSensorDevice(tank, hass)]) + add_entities([WinkSensorDevice(tank, hass)]) for piggy_bank in pywink.get_piggy_banks(): _id = piggy_bank.object_id() + piggy_bank.name() if _id not in hass.data[DOMAIN]['unique_ids']: try: if piggy_bank.capability() in SENSOR_TYPES: - add_devices([WinkSensorDevice(piggy_bank, hass)]) + add_entities([WinkSensorDevice(piggy_bank, hass)]) except AttributeError: _LOGGER.info("Device is not a sensor") diff --git a/homeassistant/components/sensor/wirelesstag.py b/homeassistant/components/sensor/wirelesstag.py index e5166173cb9..a68fb5d0caf 100644 --- a/homeassistant/components/sensor/wirelesstag.py +++ b/homeassistant/components/sensor/wirelesstag.py @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the sensor platform.""" platform = hass.data.get(WIRELESSTAG_DOMAIN) sensors = [] @@ -68,7 +68,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensors.append(WirelessTagSensor( platform, tag, sensor_type, hass.config)) - add_devices(sensors, True) + add_entities(sensors, True) class WirelessTagSensor(WirelessTagBaseSensor): diff --git a/homeassistant/components/sensor/worldclock.py b/homeassistant/components/sensor/worldclock.py index 1240480d4a3..6bb5d1fee2e 100644 --- a/homeassistant/components/sensor/worldclock.py +++ b/homeassistant/components/sensor/worldclock.py @@ -29,12 +29,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the World clock sensor.""" name = config.get(CONF_NAME) time_zone = dt_util.get_time_zone(config.get(CONF_TIME_ZONE)) - async_add_devices([WorldClockSensor(time_zone, name)], True) + async_add_entities([WorldClockSensor(time_zone, name)], True) class WorldClockSensor(Entity): diff --git a/homeassistant/components/sensor/worldtidesinfo.py b/homeassistant/components/sensor/worldtidesinfo.py index adaa327d39a..fea3e92a140 100644 --- a/homeassistant/components/sensor/worldtidesinfo.py +++ b/homeassistant/components/sensor/worldtidesinfo.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the WorldTidesInfo sensor.""" name = config.get(CONF_NAME) @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Location not available") return - add_devices([tides]) + add_entities([tides]) class WorldTidesInfoSensor(Entity): diff --git a/homeassistant/components/sensor/worxlandroid.py b/homeassistant/components/sensor/worxlandroid.py index 8963bb135e0..f6593f4b1c5 100644 --- a/homeassistant/components/sensor/worxlandroid.py +++ b/homeassistant/components/sensor/worxlandroid.py @@ -51,11 +51,11 @@ ERROR_STATE = [ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, +def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Worx Landroid sensors.""" for typ in ('battery', 'state'): - async_add_devices([WorxLandroidSensor(typ, config)]) + async_add_entities([WorxLandroidSensor(typ, config)]) class WorxLandroidSensor(Entity): diff --git a/homeassistant/components/sensor/wsdot.py b/homeassistant/components/sensor/wsdot.py index 0cd5ba44349..84f2e8622c6 100644 --- a/homeassistant/components/sensor/wsdot.py +++ b/homeassistant/components/sensor/wsdot.py @@ -45,7 +45,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the WSDOT sensor.""" sensors = [] for travel_time in config.get(CONF_TRAVEL_TIMES): @@ -54,7 +54,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): WashingtonStateTravelTimeSensor( name, config.get(CONF_API_KEY), travel_time.get(CONF_ID))) - add_devices(sensors, True) + add_entities(sensors, True) class WashingtonStateTransportSensor(Entity): diff --git a/homeassistant/components/sensor/wunderground.py b/homeassistant/components/sensor/wunderground.py index 24ae2d0068f..a14d4b94789 100644 --- a/homeassistant/components/sensor/wunderground.py +++ b/homeassistant/components/sensor/wunderground.py @@ -632,7 +632,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info=None): + async_add_entities, discovery_info=None): """Set up the WUnderground sensor.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) @@ -656,7 +656,7 @@ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, if not rest.data: raise PlatformNotReady - async_add_devices(sensors, True) + async_add_entities(sensors, True) class WUndergroundSensor(Entity): diff --git a/homeassistant/components/sensor/xbox_live.py b/homeassistant/components/sensor/xbox_live.py index 250c74ee493..3432927dda0 100644 --- a/homeassistant/components/sensor/xbox_live.py +++ b/homeassistant/components/sensor/xbox_live.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Xbox platform.""" from xboxapi import xbox_api api = xbox_api.XboxApi(config.get(CONF_API_KEY)) @@ -48,7 +48,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(new_device) if devices: - add_devices(devices, True) + add_entities(devices, True) class XboxSensor(Entity): diff --git a/homeassistant/components/sensor/xiaomi_aqara.py b/homeassistant/components/sensor/xiaomi_aqara.py index 32139b21976..8a3a11db051 100644 --- a/homeassistant/components/sensor/xiaomi_aqara.py +++ b/homeassistant/components/sensor/xiaomi_aqara.py @@ -18,7 +18,7 @@ SENSOR_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Perform the setup for Xiaomi devices.""" devices = [] for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): elif device['model'] in ['gateway', 'gateway.v3', 'acpartner.v3']: devices.append(XiaomiSensor(device, 'Illumination', 'illumination', gateway)) - add_devices(devices) + add_entities(devices) class XiaomiSensor(XiaomiDevice): diff --git a/homeassistant/components/sensor/xiaomi_miio.py b/homeassistant/components/sensor/xiaomi_miio.py index 6fb89c5109e..15af57bf46b 100644 --- a/homeassistant/components/sensor/xiaomi_miio.py +++ b/homeassistant/components/sensor/xiaomi_miio.py @@ -40,7 +40,7 @@ ATTR_MODEL = 'model' SUCCESS = ['ok'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the sensor from config.""" from miio import AirQualityMonitor, DeviceException @@ -68,7 +68,7 @@ async def async_setup_platform(hass, config, async_add_devices, raise PlatformNotReady hass.data[DATA_KEY][host] = device - async_add_devices([device], update_before_add=True) + async_add_entities([device], update_before_add=True) class XiaomiAirQualityMonitor(Entity): diff --git a/homeassistant/components/sensor/yahoo_finance.py b/homeassistant/components/sensor/yahoo_finance.py index 82cb7f845dc..4358dba2b25 100644 --- a/homeassistant/components/sensor/yahoo_finance.py +++ b/homeassistant/components/sensor/yahoo_finance.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yahoo Finance sensor.""" from yahoo_finance import Share @@ -52,7 +52,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data = YahooFinanceData(symbol) dev.append(YahooFinanceSensor(data, symbol)) - add_devices(dev, True) + add_entities(dev, True) class YahooFinanceSensor(Entity): diff --git a/homeassistant/components/sensor/yr.py b/homeassistant/components/sensor/yr.py index fcddf41af97..16ae98f9141 100644 --- a/homeassistant/components/sensor/yr.py +++ b/homeassistant/components/sensor/yr.py @@ -67,7 +67,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Yr.no sensor.""" elevation = config.get(CONF_ELEVATION, hass.config.elevation or 0) forecast = config.get(CONF_FORECAST) @@ -88,7 +89,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): dev = [] for sensor_type in config[CONF_MONITORED_CONDITIONS]: dev.append(YrSensor(name, sensor_type)) - async_add_devices(dev) + async_add_entities(dev) weather = YrData(hass, coordinates, forecast, dev) async_track_utc_time_change(hass, weather.updating_devices, minute=31) diff --git a/homeassistant/components/sensor/yweather.py b/homeassistant/components/sensor/yweather.py index b2279e107da..e84a77b7bb6 100644 --- a/homeassistant/components/sensor/yweather.py +++ b/homeassistant/components/sensor/yweather.py @@ -51,7 +51,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yahoo! weather sensor.""" from yahooweather import get_woeid, UNIT_C, UNIT_F @@ -88,7 +88,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for variable in config[CONF_MONITORED_CONDITIONS]: dev.append(YahooWeatherSensor(yahoo_api, name, forecast, variable)) - add_devices(dev, True) + add_entities(dev, True) class YahooWeatherSensor(Entity): diff --git a/homeassistant/components/sensor/zabbix.py b/homeassistant/components/sensor/zabbix.py index 21a3030b79b..7a468a9b906 100644 --- a/homeassistant/components/sensor/zabbix.py +++ b/homeassistant/components/sensor/zabbix.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Zabbix sensor platform.""" sensors = [] @@ -83,7 +83,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor = ZabbixTriggerCountSensor(zapi) sensors.append(sensor) - add_devices(sensors) + add_entities(sensors) class ZabbixTriggerCountSensor(Entity): diff --git a/homeassistant/components/sensor/zamg.py b/homeassistant/components/sensor/zamg.py index e8e5fdec4d8..c101e4da920 100644 --- a/homeassistant/components/sensor/zamg.py +++ b/homeassistant/components/sensor/zamg.py @@ -71,7 +71,7 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZAMG sensor platform.""" name = config.get(CONF_NAME) latitude = config.get(CONF_LATITUDE, hass.config.latitude) @@ -91,8 +91,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Received error from ZAMG: %s", err) return False - add_devices([ZamgSensor(probe, variable, name) - for variable in config[CONF_MONITORED_CONDITIONS]], True) + add_entities([ZamgSensor(probe, variable, name) + for variable in config[CONF_MONITORED_CONDITIONS]], True) class ZamgSensor(Entity): diff --git a/homeassistant/components/sensor/zestimate.py b/homeassistant/components/sensor/zestimate.py index d8c759f1727..a04df22cf07 100644 --- a/homeassistant/components/sensor/zestimate.py +++ b/homeassistant/components/sensor/zestimate.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=30) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Zestimate sensor.""" name = config.get(CONF_NAME) properties = config[CONF_ZPID] @@ -59,7 +59,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for zpid in properties: params['zpid'] = zpid sensors.append(ZestimateDataSensor(name, params)) - add_devices(sensors, True) + add_entities(sensors, True) class ZestimateDataSensor(Entity): diff --git a/homeassistant/components/sensor/zha.py b/homeassistant/components/sensor/zha.py index 53e0e8d0329..6202f8cb7ef 100644 --- a/homeassistant/components/sensor/zha.py +++ b/homeassistant/components/sensor/zha.py @@ -18,14 +18,15 @@ DEPENDENCIES = ['zha'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up Zigbee Home Automation sensors.""" discovery_info = zha.get_discovery_info(hass, discovery_info) if discovery_info is None: return sensor = yield from make_sensor(discovery_info) - async_add_devices([sensor], update_before_add=True) + async_add_entities([sensor], update_before_add=True) @asyncio.coroutine diff --git a/homeassistant/components/sensor/zigbee.py b/homeassistant/components/sensor/zigbee.py index 37cc6fabe2e..a0a1b8bb7fd 100644 --- a/homeassistant/components/sensor/zigbee.py +++ b/homeassistant/components/sensor/zigbee.py @@ -30,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZigBee platform. Uses the 'type' config value to work out which type of ZigBee sensor we're @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.exception("Unknown ZigBee sensor type: %s", typ) return - add_devices([sensor_class(hass, config_class(config))], True) + add_entities([sensor_class(hass, config_class(config))], True) class ZigBeeTemperatureSensor(Entity): diff --git a/homeassistant/components/sensor/zoneminder.py b/homeassistant/components/sensor/zoneminder.py index 60b6a018fc2..80f8529d847 100644 --- a/homeassistant/components/sensor/zoneminder.py +++ b/homeassistant/components/sensor/zoneminder.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZoneMinder sensor platform.""" include_archived = config.get(CONF_INCLUDE_ARCHIVED) @@ -58,7 +58,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): include_archived, sensor) ) - add_devices(sensors) + add_entities(sensors) class ZMSensorMonitors(Entity): diff --git a/homeassistant/components/switch/abode.py b/homeassistant/components/switch/abode.py index 0ce1ddc59f8..e3f993e5413 100644 --- a/homeassistant/components/switch/abode.py +++ b/homeassistant/components/switch/abode.py @@ -16,7 +16,7 @@ DEPENDENCIES = ['abode'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Abode switch devices.""" import abodepy.helpers.constants as CONST import abodepy.helpers.timeline as TIMELINE @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data.devices.extend(devices) - add_devices(devices) + add_entities(devices) class AbodeSwitch(AbodeDevice, SwitchDevice): diff --git a/homeassistant/components/switch/acer_projector.py b/homeassistant/components/switch/acer_projector.py index 527456d6d19..7abb3d1edbc 100644 --- a/homeassistant/components/switch/acer_projector.py +++ b/homeassistant/components/switch/acer_projector.py @@ -57,14 +57,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Connect with serial port and return Acer Projector.""" serial_port = config.get(CONF_FILENAME) name = config.get(CONF_NAME) timeout = config.get(CONF_TIMEOUT) write_timeout = config.get(CONF_WRITE_TIMEOUT) - add_devices([AcerSwitch(serial_port, name, timeout, write_timeout)], True) + add_entities([AcerSwitch(serial_port, name, timeout, write_timeout)], True) class AcerSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/ads.py b/homeassistant/components/switch/ads.py index b58c4d325e7..8c13e9a8960 100644 --- a/homeassistant/components/switch/ads.py +++ b/homeassistant/components/switch/ads.py @@ -27,14 +27,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up switch platform for ADS.""" ads_hub = hass.data.get(DATA_ADS) name = config.get(CONF_NAME) ads_var = config.get(CONF_ADS_VAR) - add_devices([AdsSwitch(ads_hub, name, ads_var)], True) + add_entities([AdsSwitch(ads_hub, name, ads_var)], True) class AdsSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/amcrest.py b/homeassistant/components/switch/amcrest.py index cfe33562f9f..0805793fe95 100644 --- a/homeassistant/components/switch/amcrest.py +++ b/homeassistant/components/switch/amcrest.py @@ -18,7 +18,8 @@ DEPENDENCIES = ['amcrest'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the IP Amcrest camera switch platform.""" if discovery_info is None: return @@ -32,7 +33,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for setting in switches: all_switches.append(AmcrestSwitch(setting, camera, name)) - async_add_devices(all_switches, True) + async_add_entities(all_switches, True) class AmcrestSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/android_ip_webcam.py b/homeassistant/components/switch/android_ip_webcam.py index 8de2ce593af..92e52c21caa 100644 --- a/homeassistant/components/switch/android_ip_webcam.py +++ b/homeassistant/components/switch/android_ip_webcam.py @@ -15,7 +15,8 @@ DEPENDENCIES = ['android_ip_webcam'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the IP Webcam switch platform.""" if discovery_info is None: return @@ -30,7 +31,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for setting in switches: all_switches.append(IPWebcamSettingsSwitch(name, host, ipcam, setting)) - async_add_devices(all_switches, True) + async_add_entities(all_switches, True) class IPWebcamSettingsSwitch(AndroidIPCamEntity, SwitchDevice): diff --git a/homeassistant/components/switch/anel_pwrctrl.py b/homeassistant/components/switch/anel_pwrctrl.py index 01d27b8abcd..fadb3cd96ff 100644 --- a/homeassistant/components/switch/anel_pwrctrl.py +++ b/homeassistant/components/switch/anel_pwrctrl.py @@ -33,7 +33,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up PwrCtrl devices/switches.""" host = config.get(CONF_HOST, None) username = config.get(CONF_USERNAME) @@ -60,7 +60,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for switch in device.switches.values() ) - add_devices(devices) + add_entities(devices) class PwrCtrlSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/arduino.py b/homeassistant/components/switch/arduino.py index 2bcb04c566e..ee8f0e878a3 100644 --- a/homeassistant/components/switch/arduino.py +++ b/homeassistant/components/switch/arduino.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Arduino platform.""" # Verify that Arduino board is present if arduino.BOARD is None: @@ -48,7 +48,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): switches = [] for pinnum, pin in pins.items(): switches.append(ArduinoSwitch(pinnum, pin)) - add_devices(switches) + add_entities(switches) class ArduinoSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/arest.py b/homeassistant/components/switch/arest.py index fd72d0728a0..ab445db10d8 100644 --- a/homeassistant/components/switch/arest.py +++ b/homeassistant/components/switch/arest.py @@ -37,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the aREST switches.""" resource = config.get(CONF_RESOURCE) @@ -64,7 +64,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): resource, config.get(CONF_NAME, response.json()[CONF_NAME]), func.get(CONF_NAME), funcname)) - add_devices(dev) + add_entities(dev) class ArestSwitchBase(SwitchDevice): diff --git a/homeassistant/components/switch/bbb_gpio.py b/homeassistant/components/switch/bbb_gpio.py index 94952ac736b..9e120beb442 100644 --- a/homeassistant/components/switch/bbb_gpio.py +++ b/homeassistant/components/switch/bbb_gpio.py @@ -34,14 +34,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the BeagleBone Black GPIO devices.""" pins = config.get(CONF_PINS) switches = [] for pin, params in pins.items(): switches.append(BBBGPIOSwitch(pin, params)) - add_devices(switches) + add_entities(switches) class BBBGPIOSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/broadlink.py b/homeassistant/components/switch/broadlink.py index 6b754effaf1..3dd8eafcf1f 100644 --- a/homeassistant/components/switch/broadlink.py +++ b/homeassistant/components/switch/broadlink.py @@ -69,7 +69,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Broadlink switches.""" import broadlink devices = config.get(CONF_SWITCHES) @@ -179,7 +179,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except socket.timeout: _LOGGER.error("Failed to connect to device") - add_devices(switches) + add_entities(switches) class BroadlinkRMSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/command_line.py b/homeassistant/components/switch/command_line.py index 127c7578940..d25c5708316 100644 --- a/homeassistant/components/switch/command_line.py +++ b/homeassistant/components/switch/command_line.py @@ -32,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return switches controlled by shell commands.""" devices = config.get(CONF_SWITCHES, {}) switches = [] @@ -59,7 +59,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("No switches added") return False - add_devices(switches) + add_entities(switches) class CommandSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/deconz.py b/homeassistant/components/switch/deconz.py index d5fb22e97c4..11f7f42c6c9 100644 --- a/homeassistant/components/switch/deconz.py +++ b/homeassistant/components/switch/deconz.py @@ -14,13 +14,13 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect DEPENDENCIES = ['deconz'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ switches.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up switches for deCONZ component. Switches are based same device class as lights in deCONZ. @@ -34,7 +34,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): entities.append(DeconzPowerPlug(light)) elif light.type in SIRENS: entities.append(DeconzSiren(light)) - async_add_devices(entities, True) + async_add_entities(entities, True) hass.data[DATA_DECONZ_UNSUB].append( async_dispatcher_connect(hass, 'deconz_new_light', async_add_switch)) diff --git a/homeassistant/components/switch/deluge.py b/homeassistant/components/switch/deluge.py index c71c3865f5d..0ece742aa03 100644 --- a/homeassistant/components/switch/deluge.py +++ b/homeassistant/components/switch/deluge.py @@ -32,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Deluge switch.""" from deluge_client import DelugeRPCClient @@ -49,7 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Connection to Deluge Daemon failed") raise PlatformNotReady - add_devices([DelugeSwitch(deluge_api, name)]) + add_entities([DelugeSwitch(deluge_api, name)]) class DelugeSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/demo.py b/homeassistant/components/switch/demo.py index 7e22f962330..0ac2011a6dc 100644 --- a/homeassistant/components/switch/demo.py +++ b/homeassistant/components/switch/demo.py @@ -8,9 +8,9 @@ from homeassistant.components.switch import SwitchDevice from homeassistant.const import DEVICE_DEFAULT_NAME -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up the demo switches.""" - add_devices_callback([ + add_entities_callback([ DemoSwitch('Decorative Lights', True, None, True), DemoSwitch('AC', False, 'mdi:air-conditioner', False) ]) diff --git a/homeassistant/components/switch/digital_ocean.py b/homeassistant/components/switch/digital_ocean.py index 12a6aabb170..c17df81abba 100644 --- a/homeassistant/components/switch/digital_ocean.py +++ b/homeassistant/components/switch/digital_ocean.py @@ -27,7 +27,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Digital Ocean droplet switch.""" digital = hass.data.get(DATA_DIGITAL_OCEAN) if not digital: @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return False dev.append(DigitalOceanSwitch(digital, droplet_id)) - add_devices(dev, True) + add_entities(dev, True) class DigitalOceanSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/digitalloggers.py b/homeassistant/components/switch/digitalloggers.py index 29e6771d1d5..7bb2be19899 100644 --- a/homeassistant/components/switch/digitalloggers.py +++ b/homeassistant/components/switch/digitalloggers.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return DIN III Relay switch.""" import dlipower @@ -69,7 +69,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for outlet in power_switch[0:] ) - add_devices(outlets) + add_entities(outlets) class DINRelay(SwitchDevice): diff --git a/homeassistant/components/switch/dlink.py b/homeassistant/components/switch/dlink.py index 9ce324ef6bb..f4eaefcae20 100644 --- a/homeassistant/components/switch/dlink.py +++ b/homeassistant/components/switch/dlink.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a D-Link Smart Plug.""" from pyW215.pyW215 import SmartPlug @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): username, use_legacy_protocol)) - add_devices([SmartPlugSwitch(hass, data, name)], True) + add_entities([SmartPlugSwitch(hass, data, name)], True) class SmartPlugSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/doorbird.py b/homeassistant/components/switch/doorbird.py index 92ba3640237..17a4757d4ac 100644 --- a/homeassistant/components/switch/doorbird.py +++ b/homeassistant/components/switch/doorbird.py @@ -46,7 +46,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the DoorBird switch platform.""" switches = [] @@ -60,7 +60,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): SWITCHES[switch]["name"].format(doorstation.name)) switches.append(DoorBirdSwitch(device, switch, doorstation.name)) - add_devices(switches) + add_entities(switches) class DoorBirdSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/edimax.py b/homeassistant/components/switch/edimax.py index 9cd7c484886..90ad3fff57f 100644 --- a/homeassistant/components/switch/edimax.py +++ b/homeassistant/components/switch/edimax.py @@ -29,7 +29,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return Edimax Smart Plugs.""" from pyedimax.smartplug import SmartPlug @@ -37,7 +37,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): auth = (config.get(CONF_USERNAME), config.get(CONF_PASSWORD)) name = config.get(CONF_NAME) - add_devices([SmartPlugSwitch(SmartPlug(host, auth), name)]) + add_entities([SmartPlugSwitch(SmartPlug(host, auth), name)]) class SmartPlugSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/enocean.py b/homeassistant/components/switch/enocean.py index 986744aeec1..ab979604f50 100644 --- a/homeassistant/components/switch/enocean.py +++ b/homeassistant/components/switch/enocean.py @@ -27,13 +27,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the EnOcean switch platform.""" dev_id = config.get(CONF_ID) devname = config.get(CONF_NAME) channel = config.get(CONF_CHANNEL) - add_devices([EnOceanSwitch(dev_id, devname, channel)]) + add_entities([EnOceanSwitch(dev_id, devname, channel)]) class EnOceanSwitch(enocean.EnOceanDevice, ToggleEntity): diff --git a/homeassistant/components/switch/eufy.py b/homeassistant/components/switch/eufy.py index 7320ea8d557..a226797c0f8 100644 --- a/homeassistant/components/switch/eufy.py +++ b/homeassistant/components/switch/eufy.py @@ -13,11 +13,11 @@ DEPENDENCIES = ['eufy'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Eufy switches.""" if discovery_info is None: return - add_devices([EufySwitch(discovery_info)], True) + add_entities([EufySwitch(discovery_info)], True) class EufySwitch(SwitchDevice): diff --git a/homeassistant/components/switch/flux.py b/homeassistant/components/switch/flux.py index 7df8f0e1aa6..15fdee59eaf 100644 --- a/homeassistant/components/switch/flux.py +++ b/homeassistant/components/switch/flux.py @@ -95,7 +95,7 @@ def set_lights_rgb(hass, lights, rgb, transition): transition=transition) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Flux switches.""" name = config.get(CONF_NAME) lights = config.get(CONF_LIGHTS) @@ -113,7 +113,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): start_colortemp, sunset_colortemp, stop_colortemp, brightness, disable_brightness_adjust, mode, interval, transition) - add_devices([flux]) + add_entities([flux]) def update(call=None): """Update lights.""" diff --git a/homeassistant/components/switch/fritzbox.py b/homeassistant/components/switch/fritzbox.py index 65a1aa6aabc..55fa8a04796 100644 --- a/homeassistant/components/switch/fritzbox.py +++ b/homeassistant/components/switch/fritzbox.py @@ -25,7 +25,7 @@ ATTR_TOTAL_CONSUMPTION_UNIT_VALUE = 'kWh' ATTR_TEMPERATURE_UNIT = 'temperature_unit' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Fritzbox smarthome switch platform.""" devices = [] fritz_list = hass.data[FRITZBOX_DOMAIN] @@ -36,7 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device.has_switch: devices.append(FritzboxSwitch(device, fritz)) - add_devices(devices) + add_entities(devices) class FritzboxSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/fritzdect.py b/homeassistant/components/switch/fritzdect.py index 36a53edefc9..a04de7618af 100644 --- a/homeassistant/components/switch/fritzdect.py +++ b/homeassistant/components/switch/fritzdect.py @@ -40,7 +40,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Add all switches connected to Fritz Box.""" from fritzhome.fritz import FritzBox @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if actor.has_switch: data = FritzDectSwitchData(fritz, actor.actor_id) data.is_online = True - add_devices([FritzDectSwitch(hass, data, actor.name)], True) + add_entities([FritzDectSwitch(hass, data, actor.name)], True) class FritzDectSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/gc100.py b/homeassistant/components/switch/gc100.py index 34a29483d3c..2a8e7eaa847 100644 --- a/homeassistant/components/switch/gc100.py +++ b/homeassistant/components/switch/gc100.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the GC100 devices.""" switches = [] ports = config.get(CONF_PORTS) @@ -31,7 +31,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for port_addr, port_name in port.items(): switches.append(GC100Switch( port_name, port_addr, hass.data[DATA_GC100])) - add_devices(switches, True) + add_entities(switches, True) class GC100Switch(ToggleEntity): diff --git a/homeassistant/components/switch/hdmi_cec.py b/homeassistant/components/switch/hdmi_cec.py index e81c09894ab..b2697b4a2c4 100644 --- a/homeassistant/components/switch/hdmi_cec.py +++ b/homeassistant/components/switch/hdmi_cec.py @@ -18,13 +18,13 @@ _LOGGER = logging.getLogger(__name__) ENTITY_ID_FORMAT = DOMAIN + '.{}' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return HDMI devices as switches.""" if ATTR_NEW in discovery_info: _LOGGER.info("Setting up HDMI devices %s", discovery_info[ATTR_NEW]) - add_devices(CecSwitchDevice(hass, hass.data.get(device), - hass.data.get(device).logical_address) for - device in discovery_info[ATTR_NEW]) + add_entities(CecSwitchDevice(hass, hass.data.get(device), + hass.data.get(device).logical_address) for + device in discovery_info[ATTR_NEW]) class CecSwitchDevice(CecDevice, SwitchDevice): diff --git a/homeassistant/components/switch/hikvisioncam.py b/homeassistant/components/switch/hikvisioncam.py index c3e065abc0e..3a3dec26e1d 100644 --- a/homeassistant/components/switch/hikvisioncam.py +++ b/homeassistant/components/switch/hikvisioncam.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Hikvision camera.""" import hikvision.api from hikvision.error import HikvisionError, MissingParamError @@ -56,7 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGING.error("Unable to connect: %s", conn_err) return False - add_devices([HikvisionMotionSwitch(name, hikvision_cam)]) + add_entities([HikvisionMotionSwitch(name, hikvision_cam)]) class HikvisionMotionSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/hive.py b/homeassistant/components/switch/hive.py index 49fc9696b5e..1927df28e97 100644 --- a/homeassistant/components/switch/hive.py +++ b/homeassistant/components/switch/hive.py @@ -10,13 +10,13 @@ from homeassistant.components.hive import DATA_HIVE DEPENDENCIES = ['hive'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Hive switches.""" if discovery_info is None: return session = hass.data.get(DATA_HIVE) - add_devices([HiveDevicePlug(session, discovery_info)]) + add_entities([HiveDevicePlug(session, discovery_info)]) class HiveDevicePlug(SwitchDevice): diff --git a/homeassistant/components/switch/homekit_controller.py b/homeassistant/components/switch/homekit_controller.py index 3293c8fe195..a3db6060fcf 100644 --- a/homeassistant/components/switch/homekit_controller.py +++ b/homeassistant/components/switch/homekit_controller.py @@ -15,11 +15,11 @@ DEPENDENCIES = ['homekit_controller'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Homekit switch support.""" if discovery_info is not None: accessory = hass.data[KNOWN_ACCESSORIES][discovery_info['serial']] - add_devices([HomeKitSwitch(accessory, discovery_info)], True) + add_entities([HomeKitSwitch(accessory, discovery_info)], True) class HomeKitSwitch(HomeKitEntity, SwitchDevice): diff --git a/homeassistant/components/switch/homematic.py b/homeassistant/components/switch/homematic.py index 2cd4145e87a..b5921819ea4 100644 --- a/homeassistant/components/switch/homematic.py +++ b/homeassistant/components/switch/homematic.py @@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['homematic'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the HomeMatic switch platform.""" if discovery_info is None: return @@ -25,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): new_device = HMSwitch(conf) devices.append(new_device) - add_devices(devices) + add_entities(devices) class HMSwitch(HMDevice, SwitchDevice): diff --git a/homeassistant/components/switch/homematicip_cloud.py b/homeassistant/components/switch/homematicip_cloud.py index 3211cecabfc..e066c861dfb 100644 --- a/homeassistant/components/switch/homematicip_cloud.py +++ b/homeassistant/components/switch/homematicip_cloud.py @@ -21,12 +21,12 @@ ATTR_PROFILE_MODE = 'profile_mode' async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the HomematicIP Cloud switch devices.""" pass -async def async_setup_entry(hass, config_entry, async_add_devices): +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the HomematicIP switch from a config entry.""" from homematicip.device import ( PlugableSwitch, PlugableSwitchMeasuring, BrandSwitchMeasuring) @@ -45,7 +45,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices): devices.append(HomematicipSwitch(home, device)) if devices: - async_add_devices(devices) + async_add_entities(devices) class HomematicipSwitch(HomematicipGenericDevice, SwitchDevice): diff --git a/homeassistant/components/switch/hook.py b/homeassistant/components/switch/hook.py index 07425840b9a..5a86346aa76 100644 --- a/homeassistant/components/switch/hook.py +++ b/homeassistant/components/switch/hook.py @@ -32,7 +32,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up Hook by getting the access token and list of actions.""" username = config.get(CONF_USERNAME) password = config.get(CONF_PASSWORD) @@ -70,7 +71,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.error("Failed getting devices: %s", error) return False - async_add_devices( + async_add_entities( HookSmartHome( hass, token, diff --git a/homeassistant/components/switch/hydrawise.py b/homeassistant/components/switch/hydrawise.py index d0abe5febf5..6b73333431d 100644 --- a/homeassistant/components/switch/hydrawise.py +++ b/homeassistant/components/switch/hydrawise.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a Hydrawise device.""" hydrawise = hass.data[DATA_HYDRAWISE].data @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): zone, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) class HydrawiseSwitch(HydrawiseEntity, SwitchDevice): diff --git a/homeassistant/components/switch/ihc.py b/homeassistant/components/switch/ihc.py index f744519e430..4ddafa228a7 100644 --- a/homeassistant/components/switch/ihc.py +++ b/homeassistant/components/switch/ihc.py @@ -25,7 +25,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the IHC switch platform.""" ihc_controller = hass.data[IHC_DATA][IHC_CONTROLLER] info = hass.data[IHC_DATA][IHC_INFO] @@ -44,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): sensor = IHCSwitch(ihc_controller, name, ihc_id, info) devices.append(sensor) - add_devices(devices) + add_entities(devices) class IHCSwitch(IHCDevice, SwitchDevice): diff --git a/homeassistant/components/switch/insteon.py b/homeassistant/components/switch/insteon.py index 8575b16c69b..744d278d394 100644 --- a/homeassistant/components/switch/insteon.py +++ b/homeassistant/components/switch/insteon.py @@ -16,7 +16,8 @@ _LOGGER = logging.getLogger(__name__) @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the INSTEON device class for the hass platform.""" insteon_modem = hass.data['insteon'].get('modem') @@ -36,7 +37,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): new_entity = InsteonSwitchDevice(device, state_key) if new_entity is not None: - async_add_devices([new_entity]) + async_add_entities([new_entity]) class InsteonSwitchDevice(InsteonEntity, SwitchDevice): diff --git a/homeassistant/components/switch/isy994.py b/homeassistant/components/switch/isy994.py index 2a7dee87747..6bb9c07de5b 100644 --- a/homeassistant/components/switch/isy994.py +++ b/homeassistant/components/switch/isy994.py @@ -16,7 +16,7 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config: ConfigType, - add_devices: Callable[[list], None], discovery_info=None): + add_entities: Callable[[list], None], discovery_info=None): """Set up the ISY994 switch platform.""" devices = [] for node in hass.data[ISY994_NODES][DOMAIN]: @@ -26,7 +26,7 @@ def setup_platform(hass, config: ConfigType, for name, status, actions in hass.data[ISY994_PROGRAMS][DOMAIN]: devices.append(ISYSwitchProgram(name, status, actions)) - add_devices(devices) + add_entities(devices) class ISYSwitchDevice(ISYDevice, SwitchDevice): diff --git a/homeassistant/components/switch/kankun.py b/homeassistant/components/switch/kankun.py index c830e2299f6..59966739b91 100644 --- a/homeassistant/components/switch/kankun.py +++ b/homeassistant/components/switch/kankun.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up Kankun Wifi switches.""" switches = config.get('switches', {}) devices = [] @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): properties.get(CONF_USERNAME, None), properties.get(CONF_PASSWORD))) - add_devices_callback(devices) + add_entities_callback(devices) class KankunSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/knx.py b/homeassistant/components/switch/knx.py index 4e0b29301fb..af60cee127a 100644 --- a/homeassistant/components/switch/knx.py +++ b/homeassistant/components/switch/knx.py @@ -26,27 +26,27 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up switch(es) for KNX platform.""" if discovery_info is not None: - async_add_devices_discovery(hass, discovery_info, async_add_devices) + async_add_entities_discovery(hass, discovery_info, async_add_entities) else: - async_add_devices_config(hass, config, async_add_devices) + async_add_entities_config(hass, config, async_add_entities) @callback -def async_add_devices_discovery(hass, discovery_info, async_add_devices): +def async_add_entities_discovery(hass, discovery_info, async_add_entities): """Set up switches for KNX platform configured via xknx.yaml.""" entities = [] for device_name in discovery_info[ATTR_DISCOVER_DEVICES]: device = hass.data[DATA_KNX].xknx.devices[device_name] entities.append(KNXSwitch(hass, device)) - async_add_devices(entities) + async_add_entities(entities) @callback -def async_add_devices_config(hass, config, async_add_devices): +def async_add_entities_config(hass, config, async_add_entities): """Set up switch for KNX platform configured within platform.""" import xknx switch = xknx.devices.Switch( @@ -55,7 +55,7 @@ def async_add_devices_config(hass, config, async_add_devices): group_address=config.get(CONF_ADDRESS), group_address_state=config.get(CONF_STATE_ADDRESS)) hass.data[DATA_KNX].xknx.devices.add(switch) - async_add_devices([KNXSwitch(hass, switch)]) + async_add_entities([KNXSwitch(hass, switch)]) class KNXSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/konnected.py b/homeassistant/components/switch/konnected.py index 06d3385f567..c085d0bb0a5 100644 --- a/homeassistant/components/switch/konnected.py +++ b/homeassistant/components/switch/konnected.py @@ -19,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['konnected'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set switches attached to a Konnected device.""" if discovery_info is None: @@ -31,7 +31,7 @@ async def async_setup_platform(hass, config, async_add_devices, switches = [ KonnectedSwitch(device_id, pin_data.get(CONF_PIN), pin_data, client) for pin_data in data[CONF_DEVICES][device_id][CONF_SWITCHES]] - async_add_devices(switches) + async_add_entities(switches) class KonnectedSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/linode.py b/homeassistant/components/switch/linode.py index 43f4bdc31b4..47bba280e1c 100644 --- a/homeassistant/components/switch/linode.py +++ b/homeassistant/components/switch/linode.py @@ -26,7 +26,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Linode Node switch.""" linode = hass.data.get(DATA_LINODE) nodes = config.get(CONF_NODES) @@ -39,7 +39,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): return dev.append(LinodeSwitch(linode, node_id)) - add_devices(dev, True) + add_entities(dev, True) class LinodeSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/litejet.py b/homeassistant/components/switch/litejet.py index 79ef4a5fd7f..b9755569fd2 100644 --- a/homeassistant/components/switch/litejet.py +++ b/homeassistant/components/switch/litejet.py @@ -16,7 +16,7 @@ ATTR_NUMBER = 'number' _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the LiteJet switch platform.""" litejet_ = hass.data['litejet_system'] @@ -25,7 +25,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): name = litejet_.get_switch_name(i) if not litejet.is_ignored(hass, name): devices.append(LiteJetSwitch(hass, litejet_, i, name)) - add_devices(devices, True) + add_entities(devices, True) class LiteJetSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/lutron_caseta.py b/homeassistant/components/switch/lutron_caseta.py index f5e7cf2836f..8587c78a5d5 100644 --- a/homeassistant/components/switch/lutron_caseta.py +++ b/homeassistant/components/switch/lutron_caseta.py @@ -17,7 +17,8 @@ DEPENDENCIES = ['lutron_caseta'] @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up Lutron switch.""" devs = [] bridge = hass.data[LUTRON_CASETA_SMARTBRIDGE] @@ -27,7 +28,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): dev = LutronCasetaLight(switch_device, bridge) devs.append(dev) - async_add_devices(devs, True) + async_add_entities(devs, True) return True diff --git a/homeassistant/components/switch/mfi.py b/homeassistant/components/switch/mfi.py index 2c547fa210f..521230ccbd5 100644 --- a/homeassistant/components/switch/mfi.py +++ b/homeassistant/components/switch/mfi.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up mFi sensors.""" host = config.get(CONF_HOST) username = config.get(CONF_USERNAME) @@ -58,10 +58,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Unable to connect to mFi: %s", str(ex)) return False - add_devices(MfiSwitch(port) - for device in client.get_devices() - for port in device.ports.values() - if port.model in SWITCH_MODELS) + add_entities(MfiSwitch(port) + for device in client.get_devices() + for port in device.ports.values() + if port.model in SWITCH_MODELS) class MfiSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/mochad.py b/homeassistant/components/switch/mochad.py index bb3b9c0ea65..b703d91be34 100644 --- a/homeassistant/components/switch/mochad.py +++ b/homeassistant/components/switch/mochad.py @@ -29,10 +29,10 @@ PLATFORM_SCHEMA = vol.Schema({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up X10 switches over a mochad controller.""" devs = config.get(CONF_DEVICES) - add_devices([MochadSwitch( + add_entities([MochadSwitch( hass, mochad.CONTROLLER.ctrl, dev) for dev in devs]) return True diff --git a/homeassistant/components/switch/modbus.py b/homeassistant/components/switch/modbus.py index 94e1d7ea6d6..a8c8358f0cf 100644 --- a/homeassistant/components/switch/modbus.py +++ b/homeassistant/components/switch/modbus.py @@ -59,7 +59,7 @@ PLATFORM_SCHEMA = vol.All( })) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Read configuration and create Modbus devices.""" switches = [] if CONF_COILS in config: @@ -81,7 +81,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): register.get(CONF_REGISTER_TYPE), register.get(CONF_STATE_ON), register.get(CONF_STATE_OFF))) - add_devices(switches) + add_entities(switches) class ModbusCoilSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index eb91f8d846a..f6075d5e49f 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -46,7 +46,7 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the MQTT switch.""" if discovery_info is not None: @@ -56,7 +56,7 @@ async def async_setup_platform(hass, config, async_add_devices, if value_template is not None: value_template.hass = hass - async_add_devices([MqttSwitch( + async_add_entities([MqttSwitch( config.get(CONF_NAME), config.get(CONF_ICON), config.get(CONF_STATE_TOPIC), diff --git a/homeassistant/components/switch/mysensors.py b/homeassistant/components/switch/mysensors.py index 340eed83b56..20e50518df8 100644 --- a/homeassistant/components/switch/mysensors.py +++ b/homeassistant/components/switch/mysensors.py @@ -21,7 +21,7 @@ SEND_IR_CODE_SERVICE_SCHEMA = vol.Schema({ async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the mysensors platform for switches.""" device_class_map = { 'S_DOOR': MySensorsSwitch, @@ -40,7 +40,7 @@ async def async_setup_platform( } mysensors.setup_mysensors_platform( hass, DOMAIN, discovery_info, device_class_map, - async_add_devices=async_add_devices) + async_add_entities=async_add_entities) async def async_send_ir_code_service(service): """Set IR code as device state attribute.""" diff --git a/homeassistant/components/switch/mystrom.py b/homeassistant/components/switch/mystrom.py index 85fc546d00e..a0058cb925c 100644 --- a/homeassistant/components/switch/mystrom.py +++ b/homeassistant/components/switch/mystrom.py @@ -24,7 +24,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return myStrom switch.""" from pymystrom.switch import MyStromPlug, exceptions @@ -37,7 +37,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("No route to device: %s", host) return - add_devices([MyStromSwitch(name, host)]) + add_entities([MyStromSwitch(name, host)]) class MyStromSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/neato.py b/homeassistant/components/switch/neato.py index 34dad9bb581..d9850c1589a 100644 --- a/homeassistant/components/switch/neato.py +++ b/homeassistant/components/switch/neato.py @@ -24,14 +24,14 @@ SWITCH_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Neato switches.""" dev = [] for robot in hass.data[NEATO_ROBOTS]: for type_name in SWITCH_TYPES: dev.append(NeatoConnectedSwitch(hass, robot, type_name)) _LOGGER.debug("Adding switches %s", dev) - add_devices(dev) + add_entities(dev) class NeatoConnectedSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/netio.py b/homeassistant/components/switch/netio.py index 365bbaa3679..2ccb4501d73 100644 --- a/homeassistant/components/switch/netio.py +++ b/homeassistant/components/switch/netio.py @@ -49,7 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Netio platform.""" from pynetio import Netio @@ -73,7 +73,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): DEVICES[host].netio, key, config[CONF_OUTLETS][key]) DEVICES[host].entities.append(switch) - add_devices(DEVICES[host].entities) + add_entities(DEVICES[host].entities) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, dispose) return True diff --git a/homeassistant/components/switch/orvibo.py b/homeassistant/components/switch/orvibo.py index fdb4752f594..9e6686ca3ae 100644 --- a/homeassistant/components/switch/orvibo.py +++ b/homeassistant/components/switch/orvibo.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up S20 switches.""" from orvibo.s20 import discover, S20, S20Exception @@ -54,7 +54,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): except S20Exception: _LOGGER.error("S20 at %s couldn't be initialized", host) - add_devices_callback(switches) + add_entities_callback(switches) class S20Switch(SwitchDevice): diff --git a/homeassistant/components/switch/pilight.py b/homeassistant/components/switch/pilight.py index 7ffce13ff6a..8ae8e64c2ff 100644 --- a/homeassistant/components/switch/pilight.py +++ b/homeassistant/components/switch/pilight.py @@ -60,7 +60,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Pilight platform.""" switches = config.get(CONF_SWITCHES) devices = [] @@ -77,7 +77,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) - add_devices(devices) + add_entities(devices) class _ReceiveHandle: diff --git a/homeassistant/components/switch/pulseaudio_loopback.py b/homeassistant/components/switch/pulseaudio_loopback.py index 06f2ee5f550..f112608d760 100644 --- a/homeassistant/components/switch/pulseaudio_loopback.py +++ b/homeassistant/components/switch/pulseaudio_loopback.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Read in all of our configuration, and initialize the loopback switch.""" name = config.get(CONF_NAME) sink_name = config.get(CONF_SINK_NAME) @@ -72,7 +72,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): server = PAServer(host, port, buffer_size, tcp_timeout) _PULSEAUDIO_SERVERS[server_id] = server - add_devices([PALoopbackSwitch(hass, name, server, sink_name, source_name)]) + add_entities([ + PALoopbackSwitch(hass, name, server, sink_name, source_name)]) class PAServer(): diff --git a/homeassistant/components/switch/qwikswitch.py b/homeassistant/components/switch/qwikswitch.py index 193c2722534..3b8e6d74df2 100644 --- a/homeassistant/components/switch/qwikswitch.py +++ b/homeassistant/components/switch/qwikswitch.py @@ -11,14 +11,14 @@ from homeassistant.components.switch import SwitchDevice DEPENDENCIES = [QWIKSWITCH] -async def async_setup_platform(hass, _, add_devices, discovery_info=None): +async def async_setup_platform(hass, _, add_entities, discovery_info=None): """Add switches from the main Qwikswitch component.""" if discovery_info is None: return qsusb = hass.data[QWIKSWITCH] devs = [QSSwitch(qsid, qsusb) for qsid in discovery_info[QWIKSWITCH]] - add_devices(devs) + add_entities(devs) class QSSwitch(QSToggleEntity, SwitchDevice): diff --git a/homeassistant/components/switch/rachio.py b/homeassistant/components/switch/rachio.py index 5f0ca995c90..956befeeb9f 100644 --- a/homeassistant/components/switch/rachio.py +++ b/homeassistant/components/switch/rachio.py @@ -47,7 +47,7 @@ ATTR_ZONE_SUMMARY = 'Summary' ATTR_ZONE_NUMBER = 'Zone number' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Rachio switches.""" manual_run_time = timedelta(minutes=config.get(CONF_MANUAL_RUN_MINS)) _LOGGER.info("Rachio run time is %s", str(manual_run_time)) @@ -60,7 +60,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for zone in controller.list_zones(): devices.append(RachioZone(hass, controller, zone, manual_run_time)) - add_devices(devices) + add_entities(devices) _LOGGER.info("%d Rachio switch(es) added", len(devices)) diff --git a/homeassistant/components/switch/rainbird.py b/homeassistant/components/switch/rainbird.py index 9aa24b9360b..86f25102f70 100644 --- a/homeassistant/components/switch/rainbird.py +++ b/homeassistant/components/switch/rainbird.py @@ -33,14 +33,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Rain Bird switches over a Rain Bird controller.""" controller = hass.data[DATA_RAINBIRD] devices = [] for dev_id, switch in config.get(CONF_SWITCHES).items(): devices.append(RainBirdSwitch(controller, switch, dev_id)) - add_devices(devices, True) + add_entities(devices, True) class RainBirdSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/raincloud.py b/homeassistant/components/switch/raincloud.py index a4bac8fee1c..969169edc64 100644 --- a/homeassistant/components/switch/raincloud.py +++ b/homeassistant/components/switch/raincloud.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a raincloud device.""" raincloud = hass.data[DATA_RAINCLOUD].data default_watering_timer = config.get(CONF_WATERING_TIME) @@ -42,7 +42,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): zone, sensor_type)) - add_devices(sensors, True) + add_entities(sensors, True) return True diff --git a/homeassistant/components/switch/rainmachine.py b/homeassistant/components/switch/rainmachine.py index b0cdf334cfa..633a3e50a09 100644 --- a/homeassistant/components/switch/rainmachine.py +++ b/homeassistant/components/switch/rainmachine.py @@ -100,7 +100,7 @@ VEGETATION_MAP = { async def async_setup_platform( - hass, config, async_add_devices, discovery_info=None): + hass, config, async_add_entities, discovery_info=None): """Set up the RainMachine Switch platform.""" if discovery_info is None: return @@ -129,7 +129,7 @@ async def async_setup_platform( _LOGGER.debug('Adding zone: %s', zone) entities.append(RainMachineZone(rainmachine, zone, zone_run_time)) - async_add_devices(entities, True) + async_add_entities(entities, True) class RainMachineSwitch(RainMachineEntity, SwitchDevice): diff --git a/homeassistant/components/switch/raspihats.py b/homeassistant/components/switch/raspihats.py index 7173ad35daf..c697d7042a6 100644 --- a/homeassistant/components/switch/raspihats.py +++ b/homeassistant/components/switch/raspihats.py @@ -39,7 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the raspihats switch devices.""" I2CHatSwitch.I2C_HATS_MANAGER = hass.data[I2C_HATS_MANAGER] switches = [] @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error( "Failed to register %s I2CHat@%s %s", board, hex(address), str(ex)) - add_devices(switches) + add_entities(switches) class I2CHatSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/rest.py b/homeassistant/components/switch/rest.py index 914408406a9..0e00bfe7844 100644 --- a/homeassistant/components/switch/rest.py +++ b/homeassistant/components/switch/rest.py @@ -48,7 +48,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the RESTful switch.""" body_off = config.get(CONF_BODY_OFF) body_on = config.get(CONF_BODY_ON) @@ -80,7 +81,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): if req.status >= 400: _LOGGER.error("Got non-ok response from resource: %s", req.status) else: - async_add_devices([switch]) + async_add_entities([switch]) except (TypeError, ValueError): _LOGGER.error("Missing resource or schema in configuration. " "Add http:// or https:// to your URL") diff --git a/homeassistant/components/switch/rflink.py b/homeassistant/components/switch/rflink.py index 366cb397d5b..370436b3184 100644 --- a/homeassistant/components/switch/rflink.py +++ b/homeassistant/components/switch/rflink.py @@ -86,9 +86,10 @@ def devices_from_config(domain_config, hass=None): @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Rflink platform.""" - async_add_devices(devices_from_config(config, hass)) + async_add_entities(devices_from_config(config, hass)) class RflinkSwitch(SwitchableRflinkDevice, SwitchDevice): diff --git a/homeassistant/components/switch/rfxtrx.py b/homeassistant/components/switch/rfxtrx.py index 17b5c8e40d5..c0f057da138 100644 --- a/homeassistant/components/switch/rfxtrx.py +++ b/homeassistant/components/switch/rfxtrx.py @@ -33,13 +33,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up the RFXtrx platform.""" import RFXtrx as rfxtrxmod # Add switch from config file switches = rfxtrx.get_devices_from_config(config, RfxtrxSwitch) - add_devices_callback(switches) + add_entities_callback(switches) def switch_update(event): """Handle sensor updates from the RFXtrx gateway.""" @@ -50,7 +50,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): new_device = rfxtrx.get_new_device(event, config, RfxtrxSwitch) if new_device: - add_devices_callback([new_device]) + add_entities_callback([new_device]) rfxtrx.apply_received_command(event) diff --git a/homeassistant/components/switch/rpi_gpio.py b/homeassistant/components/switch/rpi_gpio.py index 300af4be61d..3dec1135ec8 100644 --- a/homeassistant/components/switch/rpi_gpio.py +++ b/homeassistant/components/switch/rpi_gpio.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Raspberry PI GPIO devices.""" invert_logic = config.get(CONF_INVERT_LOGIC) @@ -42,7 +42,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ports = config.get(CONF_PORTS) for port, name in ports.items(): switches.append(RPiGPIOSwitch(name, port, invert_logic)) - add_devices(switches) + add_entities(switches) class RPiGPIOSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/rpi_pfio.py b/homeassistant/components/switch/rpi_pfio.py index dad0c7c59ba..8b0871ca800 100644 --- a/homeassistant/components/switch/rpi_pfio.py +++ b/homeassistant/components/switch/rpi_pfio.py @@ -36,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the PiFace Digital Output devices.""" switches = [] ports = config.get(CONF_PORTS) @@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): invert_logic = port_entity[ATTR_INVERT_LOGIC] switches.append(RPiPFIOSwitch(port, name, invert_logic)) - add_devices(switches) + add_entities(switches) class RPiPFIOSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/rpi_rf.py b/homeassistant/components/switch/rpi_rf.py index 03f11de21f7..ffadc0d38de 100644 --- a/homeassistant/components/switch/rpi_rf.py +++ b/homeassistant/components/switch/rpi_rf.py @@ -45,7 +45,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=no-member -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return switches controlled by a generic RF device via GPIO.""" import rpi_rf from threading import RLock @@ -72,7 +72,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if devices: rfdevice.enable_tx() - add_devices(devices) + add_entities(devices) hass.bus.listen_once( EVENT_HOMEASSISTANT_STOP, lambda event: rfdevice.cleanup()) diff --git a/homeassistant/components/switch/scsgate.py b/homeassistant/components/switch/scsgate.py index b549f351afc..bb8c067ebd9 100644 --- a/homeassistant/components/switch/scsgate.py +++ b/homeassistant/components/switch/scsgate.py @@ -28,17 +28,17 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SCSGate switches.""" logger = logging.getLogger(__name__) _setup_traditional_switches( - logger=logger, config=config, add_devices_callback=add_devices) + logger=logger, config=config, add_entities_callback=add_entities) _setup_scenario_switches(logger=logger, config=config, hass=hass) -def _setup_traditional_switches(logger, config, add_devices_callback): +def _setup_traditional_switches(logger, config, add_entities_callback): """Add traditional SCSGate switches.""" traditional = config.get(CONF_TRADITIONAL) switches = [] @@ -56,7 +56,7 @@ def _setup_traditional_switches(logger, config, add_devices_callback): switch = SCSGateSwitch(name=name, scs_id=scs_id, logger=logger) switches.append(switch) - add_devices_callback(switches) + add_entities_callback(switches) scsgate.SCSGATE.add_devices_to_register(switches) diff --git a/homeassistant/components/switch/skybell.py b/homeassistant/components/switch/skybell.py index 726a5e7446e..9d791aa3df3 100644 --- a/homeassistant/components/switch/skybell.py +++ b/homeassistant/components/switch/skybell.py @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the platform for a Skybell device.""" skybell = hass.data.get(SKYBELL_DOMAIN) @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for device in skybell.get_devices(): sensors.append(SkybellSwitch(device, switch_type)) - add_devices(sensors, True) + add_entities(sensors, True) class SkybellSwitch(SkybellDevice, SwitchDevice): diff --git a/homeassistant/components/switch/smappee.py b/homeassistant/components/switch/smappee.py index fd8f141500b..fc2716b8019 100644 --- a/homeassistant/components/switch/smappee.py +++ b/homeassistant/components/switch/smappee.py @@ -16,7 +16,7 @@ _LOGGER = logging.getLogger(__name__) ICON = 'mdi:power-plug' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Smappee Comfort Plugs.""" smappee = hass.data[DATA_SMAPPEE] @@ -37,7 +37,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): items.get('value'), None, items.get('key'))) - add_devices(dev) + add_entities(dev) class SmappeeSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/snmp.py b/homeassistant/components/switch/snmp.py index 9c84584e833..f208c24286d 100644 --- a/homeassistant/components/switch/snmp.py +++ b/homeassistant/components/switch/snmp.py @@ -52,7 +52,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the SNMP switch.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -66,7 +66,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): payload_on = config.get(CONF_PAYLOAD_ON) payload_off = config.get(CONF_PAYLOAD_OFF) - add_devices( + add_entities( [SnmpSwitch(name, host, port, community, baseoid, command_oid, version, payload_on, payload_off, command_payload_on, command_payload_off)], True) diff --git a/homeassistant/components/switch/spider.py b/homeassistant/components/switch/spider.py index 94b7db8f1e5..f4bf74ad010 100644 --- a/homeassistant/components/switch/spider.py +++ b/homeassistant/components/switch/spider.py @@ -15,7 +15,7 @@ DEPENDENCIES = ['spider'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Spider thermostat.""" if discovery_info is None: return @@ -23,7 +23,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices = [SpiderPowerPlug(hass.data[SPIDER_DOMAIN]['controller'], device) for device in hass.data[SPIDER_DOMAIN]['power_plugs']] - add_devices(devices, True) + add_entities(devices, True) class SpiderPowerPlug(SwitchDevice): diff --git a/homeassistant/components/switch/tahoma.py b/homeassistant/components/switch/tahoma.py index aa3554a494c..2904f06b432 100644 --- a/homeassistant/components/switch/tahoma.py +++ b/homeassistant/components/switch/tahoma.py @@ -18,13 +18,13 @@ DEPENDENCIES = ['tahoma'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tahoma switches.""" controller = hass.data[TAHOMA_DOMAIN]['controller'] devices = [] for switch in hass.data[TAHOMA_DOMAIN]['devices']['switch']: devices.append(TahomaSwitch(switch, controller)) - add_devices(devices, True) + add_entities(devices, True) class TahomaSwitch(TahomaDevice, SwitchDevice): diff --git a/homeassistant/components/switch/tellduslive.py b/homeassistant/components/switch/tellduslive.py index ac2b569f81c..c1134fc21c1 100644 --- a/homeassistant/components/switch/tellduslive.py +++ b/homeassistant/components/switch/tellduslive.py @@ -15,11 +15,11 @@ from homeassistant.helpers.entity import ToggleEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tellstick switches.""" if discovery_info is None: return - add_devices(TelldusLiveSwitch(hass, switch) for switch in discovery_info) + add_entities(TelldusLiveSwitch(hass, switch) for switch in discovery_info) class TelldusLiveSwitch(TelldusLiveEntity, ToggleEntity): diff --git a/homeassistant/components/switch/tellstick.py b/homeassistant/components/switch/tellstick.py index 5f7930a8a7c..51a04e9f5b3 100644 --- a/homeassistant/components/switch/tellstick.py +++ b/homeassistant/components/switch/tellstick.py @@ -10,7 +10,7 @@ from homeassistant.components.tellstick import ( from homeassistant.helpers.entity import ToggleEntity -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tellstick switches.""" if (discovery_info is None or discovery_info[ATTR_DISCOVER_DEVICES] is None): @@ -20,10 +20,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None): signal_repetitions = discovery_info.get(ATTR_DISCOVER_CONFIG, DEFAULT_SIGNAL_REPETITIONS) - add_devices([TellstickSwitch(hass.data[DATA_TELLSTICK][tellcore_id], - signal_repetitions) - for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]], - True) + add_entities([TellstickSwitch(hass.data[DATA_TELLSTICK][tellcore_id], + signal_repetitions) + for tellcore_id in discovery_info[ATTR_DISCOVER_DEVICES]], + True) class TellstickSwitch(TellstickDevice, ToggleEntity): diff --git a/homeassistant/components/switch/telnet.py b/homeassistant/components/switch/telnet.py index 381f2ec9bec..440279a70a8 100644 --- a/homeassistant/components/switch/telnet.py +++ b/homeassistant/components/switch/telnet.py @@ -38,7 +38,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ SCAN_INTERVAL = timedelta(seconds=10) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Find and return switches controlled by telnet commands.""" devices = config.get(CONF_SWITCHES, {}) switches = [] @@ -67,7 +67,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("No switches added") return - add_devices(switches) + add_entities(switches) class TelnetSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/template.py b/homeassistant/components/switch/template.py index a6fa8241940..7461aa2a720 100644 --- a/homeassistant/components/switch/template.py +++ b/homeassistant/components/switch/template.py @@ -44,7 +44,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Template switch.""" switches = [] @@ -77,7 +78,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): _LOGGER.error("No switches added") return False - async_add_devices(switches) + async_add_entities(switches) return True diff --git a/homeassistant/components/switch/tesla.py b/homeassistant/components/switch/tesla.py index 0e1b7e819f7..30972b1014b 100644 --- a/homeassistant/components/switch/tesla.py +++ b/homeassistant/components/switch/tesla.py @@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['tesla'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Tesla switch platform.""" controller = hass.data[TESLA_DOMAIN]['devices']['controller'] devices = [] @@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices.append(ChargerSwitch(device, controller)) elif device.bin_type == 0x9: devices.append(RangeSwitch(device, controller)) - add_devices(devices, True) + add_entities(devices, True) class ChargerSwitch(TeslaDevice, SwitchDevice): diff --git a/homeassistant/components/switch/thinkingcleaner.py b/homeassistant/components/switch/thinkingcleaner.py index 0753435cfba..89586465b43 100644 --- a/homeassistant/components/switch/thinkingcleaner.py +++ b/homeassistant/components/switch/thinkingcleaner.py @@ -29,7 +29,7 @@ SWITCH_TYPES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ThinkingCleaner platform.""" from pythinkingcleaner import Discovery @@ -48,7 +48,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dev.append(ThinkingCleanerSwitch(device, type_name, update_devices)) - add_devices(dev) + add_entities(dev) class ThinkingCleanerSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/toon.py b/homeassistant/components/switch/toon.py index 94086d819e2..087ca673e85 100644 --- a/homeassistant/components/switch/toon.py +++ b/homeassistant/components/switch/toon.py @@ -12,14 +12,14 @@ import homeassistant.components.toon as toon_main _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the discovered Toon Smart Plugs.""" _toon_main = hass.data[toon_main.TOON_HANDLE] switch_items = [] for plug in _toon_main.toon.smartplugs: switch_items.append(EnecoSmartPlug(hass, plug)) - add_devices(switch_items) + add_entities(switch_items) class EnecoSmartPlug(SwitchDevice): diff --git a/homeassistant/components/switch/tplink.py b/homeassistant/components/switch/tplink.py index 0cacdfe1539..a68ad2bf37d 100644 --- a/homeassistant/components/switch/tplink.py +++ b/homeassistant/components/switch/tplink.py @@ -32,14 +32,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the TPLink switch platform.""" from pyHS100 import SmartPlug host = config.get(CONF_HOST) name = config.get(CONF_NAME) leds_on = config.get(CONF_LEDS) - add_devices([SmartPlugSwitch(SmartPlug(host), name, leds_on)], True) + add_entities([SmartPlugSwitch(SmartPlug(host), name, leds_on)], True) class SmartPlugSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/transmission.py b/homeassistant/components/switch/transmission.py index ffe285a23f3..10ab0903dcf 100644 --- a/homeassistant/components/switch/transmission.py +++ b/homeassistant/components/switch/transmission.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Transmission switch.""" import transmissionrpc from transmissionrpc.error import TransmissionError @@ -53,7 +53,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) return False - add_devices([TransmissionSwitch(transmission_api, name)]) + add_entities([TransmissionSwitch(transmission_api, name)]) class TransmissionSwitch(ToggleEntity): diff --git a/homeassistant/components/switch/tuya.py b/homeassistant/components/switch/tuya.py index 4f69e76f954..9fc1f92016e 100644 --- a/homeassistant/components/switch/tuya.py +++ b/homeassistant/components/switch/tuya.py @@ -10,7 +10,7 @@ from homeassistant.components.tuya import DATA_TUYA, TuyaDevice DEPENDENCIES = ['tuya'] -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tuya Switch device.""" if discovery_info is None: return @@ -22,7 +22,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if device is None: continue devices.append(TuyaSwitch(device)) - add_devices(devices) + add_entities(devices) class TuyaSwitch(TuyaDevice, SwitchDevice): diff --git a/homeassistant/components/switch/upcloud.py b/homeassistant/components/switch/upcloud.py index 5c3af45bede..f2818e59a9b 100644 --- a/homeassistant/components/switch/upcloud.py +++ b/homeassistant/components/switch/upcloud.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the UpCloud server switch.""" upcloud = hass.data[DATA_UPCLOUD] @@ -31,7 +31,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): devices = [UpCloudSwitch(upcloud, uuid) for uuid in servers] - add_devices(devices, True) + add_entities(devices, True) class UpCloudSwitch(UpCloudServerEntity, SwitchDevice): diff --git a/homeassistant/components/switch/velbus.py b/homeassistant/components/switch/velbus.py index 46f6e893c97..300ff43d676 100644 --- a/homeassistant/components/switch/velbus.py +++ b/homeassistant/components/switch/velbus.py @@ -15,7 +15,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['velbus'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Velbus Switch platform.""" if discovery_info is None: @@ -25,7 +25,7 @@ async def async_setup_platform(hass, config, async_add_devices, module = hass.data[VELBUS_DOMAIN].get_module(switch[0]) channel = switch[1] switches.append(VelbusSwitch(module, channel)) - async_add_devices(switches) + async_add_entities(switches) class VelbusSwitch(VelbusEntity, SwitchDevice): diff --git a/homeassistant/components/switch/vera.py b/homeassistant/components/switch/vera.py index 82e2756c230..4742b755944 100644 --- a/homeassistant/components/switch/vera.py +++ b/homeassistant/components/switch/vera.py @@ -16,9 +16,9 @@ DEPENDENCIES = ['vera'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vera switches.""" - add_devices( + add_entities( [VeraSwitch(device, hass.data[VERA_CONTROLLER]) for device in hass.data[VERA_DEVICES]['switch']], True) diff --git a/homeassistant/components/switch/verisure.py b/homeassistant/components/switch/verisure.py index 4b126e5d332..11ccd82696e 100644 --- a/homeassistant/components/switch/verisure.py +++ b/homeassistant/components/switch/verisure.py @@ -14,7 +14,7 @@ from homeassistant.components.switch import SwitchDevice _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Verisure switch platform.""" if not int(hub.config.get(CONF_SMARTPLUGS, 1)): return False @@ -24,7 +24,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): switches.extend([ VerisureSmartplug(device_label) for device_label in hub.get('$.smartPlugs[*].deviceLabel')]) - add_devices(switches) + add_entities(switches) class VerisureSmartplug(SwitchDevice): diff --git a/homeassistant/components/switch/vesync.py b/homeassistant/components/switch/vesync.py index d8579a508e2..382096ad5e4 100644 --- a/homeassistant/components/switch/vesync.py +++ b/homeassistant/components/switch/vesync.py @@ -21,7 +21,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the VeSync switch platform.""" from pyvesync.vesync import VeSync @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): else: _LOGGER.info("No VeSync devices found") - add_devices(switches) + add_entities(switches) class VeSyncSwitchHA(SwitchDevice): diff --git a/homeassistant/components/switch/volvooncall.py b/homeassistant/components/switch/volvooncall.py index c1b18a11795..96091a725a1 100644 --- a/homeassistant/components/switch/volvooncall.py +++ b/homeassistant/components/switch/volvooncall.py @@ -14,11 +14,11 @@ from homeassistant.helpers.entity import ToggleEntity _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up Tellstick switches.""" if discovery_info is None: return - add_devices([VolvoSwitch(hass, *discovery_info)]) + add_entities([VolvoSwitch(hass, *discovery_info)]) class VolvoSwitch(VolvoEntity, ToggleEntity): diff --git a/homeassistant/components/switch/vultr.py b/homeassistant/components/switch/vultr.py index fe3d67470d7..874d1979d7d 100644 --- a/homeassistant/components/switch/vultr.py +++ b/homeassistant/components/switch/vultr.py @@ -28,7 +28,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Vultr subscription switch.""" vultr = hass.data[DATA_VULTR] @@ -39,7 +39,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Subscription %s not found", subscription) return False - add_devices([VultrSwitch(vultr, subscription, name)], True) + add_entities([VultrSwitch(vultr, subscription, name)], True) class VultrSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/wake_on_lan.py b/homeassistant/components/switch/wake_on_lan.py index 80102621f7d..06f86865064 100644 --- a/homeassistant/components/switch/wake_on_lan.py +++ b/homeassistant/components/switch/wake_on_lan.py @@ -35,7 +35,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a wake on lan switch.""" name = config.get(CONF_NAME) host = config.get(CONF_HOST) @@ -43,8 +43,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): broadcast_address = config.get(CONF_BROADCAST_ADDRESS) off_action = config.get(CONF_OFF_ACTION) - add_devices([WOLSwitch(hass, name, host, mac_address, - off_action, broadcast_address)], True) + add_entities([WOLSwitch(hass, name, host, mac_address, + off_action, broadcast_address)], True) class WOLSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index 199156afc21..94b86377b8d 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -35,7 +35,7 @@ WEMO_OFF = 0 WEMO_STANDBY = 8 -def setup_platform(hass, config, add_devices_callback, discovery_info=None): +def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up discovered WeMo switches.""" from pywemo import discovery @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): raise PlatformNotReady if device: - add_devices_callback([WemoSwitch(device)]) + add_entities_callback([WemoSwitch(device)]) class WemoSwitch(SwitchDevice): diff --git a/homeassistant/components/switch/wink.py b/homeassistant/components/switch/wink.py index 6a244615065..0df59d6b51c 100644 --- a/homeassistant/components/switch/wink.py +++ b/homeassistant/components/switch/wink.py @@ -15,26 +15,26 @@ DEPENDENCIES = ['wink'] _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Wink platform.""" import pywink for switch in pywink.get_switches(): _id = switch.object_id() + switch.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkToggleDevice(switch, hass)]) + add_entities([WinkToggleDevice(switch, hass)]) for switch in pywink.get_powerstrips(): _id = switch.object_id() + switch.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkToggleDevice(switch, hass)]) + add_entities([WinkToggleDevice(switch, hass)]) for sprinkler in pywink.get_sprinklers(): _id = sprinkler.object_id() + sprinkler.name() if _id not in hass.data[DOMAIN]['unique_ids']: - add_devices([WinkToggleDevice(sprinkler, hass)]) + add_entities([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)]) + add_entities([WinkToggleDevice(switch, hass)]) class WinkToggleDevice(WinkDevice, ToggleEntity): diff --git a/homeassistant/components/switch/wirelesstag.py b/homeassistant/components/switch/wirelesstag.py index cce8c349a31..5796216d50f 100644 --- a/homeassistant/components/switch/wirelesstag.py +++ b/homeassistant/components/switch/wirelesstag.py @@ -45,7 +45,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up switches for a Wireless Sensor Tags.""" platform = hass.data.get(WIRELESSTAG_DOMAIN) @@ -56,7 +56,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if switch_type in WirelessTagSwitch.allowed_switches(tag): switches.append(WirelessTagSwitch(platform, tag, switch_type)) - add_devices(switches, True) + add_entities(switches, True) class WirelessTagSwitch(WirelessTagBaseSensor, SwitchDevice): diff --git a/homeassistant/components/switch/xiaomi_aqara.py b/homeassistant/components/switch/xiaomi_aqara.py index 4c44d6b2592..a29a3c74a2e 100644 --- a/homeassistant/components/switch/xiaomi_aqara.py +++ b/homeassistant/components/switch/xiaomi_aqara.py @@ -19,7 +19,7 @@ POWER_CONSUMED = 'power_consumed' IN_USE = 'inuse' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Perform the setup for Xiaomi devices.""" devices = [] for (_, gateway) in hass.data[PY_XIAOMI_GATEWAY].gateways.items(): @@ -59,7 +59,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): elif model in ['86plug', 'ctrl_86plug', 'ctrl_86plug.aq1']: devices.append(XiaomiGenericSwitch(device, 'Wall Plug', 'status', True, gateway)) - add_devices(devices) + add_entities(devices) class XiaomiGenericSwitch(XiaomiDevice, SwitchDevice): diff --git a/homeassistant/components/switch/xiaomi_miio.py b/homeassistant/components/switch/xiaomi_miio.py index 56203c0552a..821de5bf647 100644 --- a/homeassistant/components/switch/xiaomi_miio.py +++ b/homeassistant/components/switch/xiaomi_miio.py @@ -97,7 +97,7 @@ SERVICE_TO_METHOD = { } -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the switch from config.""" from miio import Device, DeviceException @@ -158,7 +158,7 @@ async def async_setup_platform(hass, config, async_add_devices, 'and provide the following data: %s', model) return False - async_add_devices(devices, update_before_add=True) + async_add_entities(devices, update_before_add=True) async def async_service_handler(service): """Map services to methods on XiaomiPlugGenericSwitch.""" diff --git a/homeassistant/components/switch/zha.py b/homeassistant/components/switch/zha.py index 6109dc192f3..9f780b631b6 100644 --- a/homeassistant/components/switch/zha.py +++ b/homeassistant/components/switch/zha.py @@ -14,7 +14,7 @@ _LOGGER = logging.getLogger(__name__) DEPENDENCIES = ['zha'] -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Zigbee Home Automation switches.""" discovery_info = zha.get_discovery_info(hass, discovery_info) @@ -27,7 +27,7 @@ async def async_setup_platform(hass, config, async_add_devices, await cluster.bind() await cluster.configure_reporting(0, 0, 600, 1,) - async_add_devices([Switch(**discovery_info)], update_before_add=True) + async_add_entities([Switch(**discovery_info)], update_before_add=True) class Switch(zha.Entity, SwitchDevice): diff --git a/homeassistant/components/switch/zigbee.py b/homeassistant/components/switch/zigbee.py index a0db5685a90..8d54892399a 100644 --- a/homeassistant/components/switch/zigbee.py +++ b/homeassistant/components/switch/zigbee.py @@ -24,9 +24,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZigBee switch platform.""" - add_devices([ZigBeeSwitch(hass, ZigBeeDigitalOutConfig(config))]) + add_entities([ZigBeeSwitch(hass, ZigBeeDigitalOutConfig(config))]) class ZigBeeSwitch(ZigBeeDigitalOut, SwitchDevice): diff --git a/homeassistant/components/switch/zoneminder.py b/homeassistant/components/switch/zoneminder.py index fa32843eb4b..496e7549aaa 100644 --- a/homeassistant/components/switch/zoneminder.py +++ b/homeassistant/components/switch/zoneminder.py @@ -23,7 +23,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZoneMinder switch platform.""" on_state = config.get(CONF_COMMAND_ON) off_state = config.get(CONF_COMMAND_OFF) @@ -41,7 +41,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): ) ) - add_devices(switches) + add_entities(switches) class ZMSwitchMonitors(SwitchDevice): diff --git a/homeassistant/components/vacuum/demo.py b/homeassistant/components/vacuum/demo.py index 5d4c6856a4d..12507683f51 100644 --- a/homeassistant/components/vacuum/demo.py +++ b/homeassistant/components/vacuum/demo.py @@ -43,9 +43,9 @@ DEMO_VACUUM_NONE = '4_Fourth_floor' DEMO_VACUUM_STATE = '5_Fifth_floor' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo vacuums.""" - add_devices([ + add_entities([ DemoVacuum(DEMO_VACUUM_COMPLETE, SUPPORT_ALL_SERVICES), DemoVacuum(DEMO_VACUUM_MOST, SUPPORT_MOST_SERVICES), DemoVacuum(DEMO_VACUUM_BASIC, SUPPORT_BASIC_SERVICES), diff --git a/homeassistant/components/vacuum/dyson.py b/homeassistant/components/vacuum/dyson.py index d423a8dacf5..943b97f6360 100644 --- a/homeassistant/components/vacuum/dyson.py +++ b/homeassistant/components/vacuum/dyson.py @@ -29,7 +29,7 @@ SUPPORT_DYSON = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PAUSE | \ SUPPORT_BATTERY | SUPPORT_STOP -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dyson 360 Eye robot vacuum platform.""" from libpurecoollink.dyson_360_eye import Dyson360Eye @@ -43,7 +43,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dyson_entity = Dyson360EyeDevice(device) hass.data[DYSON_360_EYE_DEVICES].append(dyson_entity) - add_devices(hass.data[DYSON_360_EYE_DEVICES]) + add_entities(hass.data[DYSON_360_EYE_DEVICES]) return True diff --git a/homeassistant/components/vacuum/ecovacs.py b/homeassistant/components/vacuum/ecovacs.py index e0870a48861..ac01d8e7a20 100644 --- a/homeassistant/components/vacuum/ecovacs.py +++ b/homeassistant/components/vacuum/ecovacs.py @@ -27,13 +27,13 @@ ATTR_ERROR = 'error' ATTR_COMPONENT_PREFIX = 'component_' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ecovacs vacuums.""" vacuums = [] for device in hass.data[ECOVACS_DEVICES]: vacuums.append(EcovacsVacuum(device)) _LOGGER.debug("Adding Ecovacs Vacuums to Hass: %s", vacuums) - add_devices(vacuums, True) + add_entities(vacuums, True) class EcovacsVacuum(VacuumDevice): diff --git a/homeassistant/components/vacuum/mqtt.py b/homeassistant/components/vacuum/mqtt.py index fd80f4cdbfb..47617277773 100644 --- a/homeassistant/components/vacuum/mqtt.py +++ b/homeassistant/components/vacuum/mqtt.py @@ -140,7 +140,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the vacuum.""" name = config.get(CONF_NAME) supported_feature_strings = config.get(CONF_SUPPORTED_FEATURES) @@ -192,7 +193,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): payload_available = config.get(mqtt.CONF_PAYLOAD_AVAILABLE) payload_not_available = config.get(mqtt.CONF_PAYLOAD_NOT_AVAILABLE) - async_add_devices([ + async_add_entities([ MqttVacuum( name, supported_features, qos, retain, command_topic, payload_turn_on, payload_turn_off, payload_return_to_base, diff --git a/homeassistant/components/vacuum/neato.py b/homeassistant/components/vacuum/neato.py index 82c5187f7b0..dd27b2a33d2 100644 --- a/homeassistant/components/vacuum/neato.py +++ b/homeassistant/components/vacuum/neato.py @@ -36,13 +36,13 @@ ATTR_CLEAN_SUSP_COUNT = 'clean_suspension_count' ATTR_CLEAN_SUSP_TIME = 'clean_suspension_time' -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Neato vacuum.""" dev = [] for robot in hass.data[NEATO_ROBOTS]: dev.append(NeatoConnectedVacuum(hass, robot)) _LOGGER.debug("Adding vacuums %s", dev) - add_devices(dev, True) + add_entities(dev, True) class NeatoConnectedVacuum(StateVacuumDevice): diff --git a/homeassistant/components/vacuum/roomba.py b/homeassistant/components/vacuum/roomba.py index 750c2c0ae0a..487fd573f37 100644 --- a/homeassistant/components/vacuum/roomba.py +++ b/homeassistant/components/vacuum/roomba.py @@ -69,7 +69,8 @@ SUPPORT_ROOMBA_CARPET_BOOST = SUPPORT_ROOMBA | SUPPORT_FAN_SPEED @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the iRobot Roomba vacuum cleaner platform.""" from roomba import Roomba if PLATFORM not in hass.data: @@ -102,7 +103,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): roomba_vac = RoombaVacuum(name, roomba) hass.data[PLATFORM][host] = roomba_vac - async_add_devices([roomba_vac], update_before_add=True) + async_add_entities([roomba_vac], update_before_add=True) class RoombaVacuum(VacuumDevice): diff --git a/homeassistant/components/vacuum/xiaomi_miio.py b/homeassistant/components/vacuum/xiaomi_miio.py index 5be594e55a2..a6d8fccdee0 100644 --- a/homeassistant/components/vacuum/xiaomi_miio.py +++ b/homeassistant/components/vacuum/xiaomi_miio.py @@ -102,7 +102,8 @@ STATE_CODE_TO_STATE = { @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the Xiaomi vacuum cleaner robot platform.""" from miio import Vacuum if DATA_KEY not in hass.data: @@ -119,7 +120,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): mirobo = MiroboVacuum(name, vacuum) hass.data[DATA_KEY][host] = mirobo - async_add_devices([mirobo], update_before_add=True) + async_add_entities([mirobo], update_before_add=True) @asyncio.coroutine def async_service_handler(service): diff --git a/homeassistant/components/weather/bom.py b/homeassistant/components/weather/bom.py index ad74bb4fb77..4c517824bca 100644 --- a/homeassistant/components/weather/bom.py +++ b/homeassistant/components/weather/bom.py @@ -24,7 +24,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the BOM weather platform.""" station = config.get(CONF_STATION) or closest_station( config.get(CONF_LATITUDE), @@ -39,7 +39,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): except ValueError as err: _LOGGER.error("Received error from BOM_Current: %s", err) return False - add_devices([BOMWeather(bom_data, config.get(CONF_NAME))], True) + add_entities([BOMWeather(bom_data, config.get(CONF_NAME))], True) class BOMWeather(WeatherEntity): diff --git a/homeassistant/components/weather/buienradar.py b/homeassistant/components/weather/buienradar.py index 9b9707e87f6..6b92eb97c9e 100644 --- a/homeassistant/components/weather/buienradar.py +++ b/homeassistant/components/weather/buienradar.py @@ -56,7 +56,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): """Set up the buienradar platform.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) @@ -82,7 +83,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): for condi in condlst: hass.data[DATA_CONDITION][condi] = cond - async_add_devices([BrWeather(data, config)]) + async_add_entities([BrWeather(data, config)]) # schedule the first update in 1 minute from now: yield from data.schedule_update(1) diff --git a/homeassistant/components/weather/darksky.py b/homeassistant/components/weather/darksky.py index 6dac22bc941..34a6fd3d6f6 100644 --- a/homeassistant/components/weather/darksky.py +++ b/homeassistant/components/weather/darksky.py @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=3) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Dark Sky weather.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude) @@ -70,7 +70,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): dark_sky = DarkSkyData( config.get(CONF_API_KEY), latitude, longitude, units) - add_devices([DarkSkyWeather(name, dark_sky)], True) + add_entities([DarkSkyWeather(name, dark_sky)], True) class DarkSkyWeather(WeatherEntity): diff --git a/homeassistant/components/weather/demo.py b/homeassistant/components/weather/demo.py index fffdf03d07d..6bcb8918504 100644 --- a/homeassistant/components/weather/demo.py +++ b/homeassistant/components/weather/demo.py @@ -29,9 +29,9 @@ CONDITION_CLASSES = { } -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Demo weather.""" - add_devices([ + add_entities([ DemoWeather('South', 'Sunshine', 21.6414, 92, 1099, 0.5, TEMP_CELSIUS, [['rainy', 1, 22, 15], ['rainy', 5, 19, 8], ['cloudy', 0, 15, 9], ['sunny', 0, 12, 6], diff --git a/homeassistant/components/weather/ecobee.py b/homeassistant/components/weather/ecobee.py index 59737c578a5..5a191aa7af1 100644 --- a/homeassistant/components/weather/ecobee.py +++ b/homeassistant/components/weather/ecobee.py @@ -23,7 +23,7 @@ ATTR_FORECAST_HUMIDITY = 'humidity' MISSING_DATA = -5002 -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Ecobee weather component.""" if discovery_info is None: return @@ -34,7 +34,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if 'weather' in thermostat: dev.append(EcobeeWeather(thermostat['name'], index)) - add_devices(dev, True) + add_entities(dev, True) class EcobeeWeather(WeatherEntity): diff --git a/homeassistant/components/weather/ipma.py b/homeassistant/components/weather/ipma.py index ef4f1b349d7..02d94e47558 100644 --- a/homeassistant/components/weather/ipma.py +++ b/homeassistant/components/weather/ipma.py @@ -54,7 +54,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the ipma platform.""" latitude = config.get(CONF_LATITUDE, hass.config.latitude) @@ -74,7 +74,7 @@ async def async_setup_platform(hass, config, async_add_devices, _LOGGER.debug("Initializing ipma weather: coordinates %s, %s", latitude, longitude) - async_add_devices([IPMAWeather(station, config)], True) + async_add_entities([IPMAWeather(station, config)], True) class IPMAWeather(WeatherEntity): diff --git a/homeassistant/components/weather/metoffice.py b/homeassistant/components/weather/metoffice.py index d43d1d3c996..7382319e7a4 100644 --- a/homeassistant/components/weather/metoffice.py +++ b/homeassistant/components/weather/metoffice.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Met Office weather platform.""" import datapoint as dp @@ -63,7 +63,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Received error from Met Office Datapoint: %s", err) return - add_devices([MetOfficeWeather(site, data, name)], True) + add_entities([MetOfficeWeather(site, data, name)], True) class MetOfficeWeather(WeatherEntity): diff --git a/homeassistant/components/weather/openweathermap.py b/homeassistant/components/weather/openweathermap.py index 46a0b3ecc14..b300fcbcbec 100644 --- a/homeassistant/components/weather/openweathermap.py +++ b/homeassistant/components/weather/openweathermap.py @@ -61,7 +61,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the OpenWeatherMap weather platform.""" import pyowm @@ -78,7 +78,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): data = WeatherData(owm, latitude, longitude, mode) - add_devices([OpenWeatherMapWeather( + add_entities([OpenWeatherMapWeather( name, data, hass.config.units.temperature_unit, mode)], True) diff --git a/homeassistant/components/weather/yweather.py b/homeassistant/components/weather/yweather.py index 3f12195d6bf..505c287a99e 100644 --- a/homeassistant/components/weather/yweather.py +++ b/homeassistant/components/weather/yweather.py @@ -55,7 +55,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Yahoo! weather platform.""" from yahooweather import get_woeid, UNIT_C, UNIT_F @@ -85,7 +85,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): for condi in condlst: hass.data[DATA_CONDITION][condi] = cond - add_devices([YahooWeatherWeather(yahoo_api, name, unit)], True) + add_entities([YahooWeatherWeather(yahoo_api, name, unit)], True) class YahooWeatherWeather(WeatherEntity): diff --git a/homeassistant/components/weather/zamg.py b/homeassistant/components/weather/zamg.py index 389b966ee7d..f76b733ef0b 100644 --- a/homeassistant/components/weather/zamg.py +++ b/homeassistant/components/weather/zamg.py @@ -31,7 +31,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -def setup_platform(hass, config, add_devices, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the ZAMG weather platform.""" name = config.get(CONF_NAME) latitude = config.get(CONF_LATITUDE, hass.config.latitude) @@ -51,7 +51,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None): _LOGGER.error("Received error from ZAMG: %s", err) return False - add_devices([ZamgWeather(probe, name)], True) + add_entities([ZamgWeather(probe, name)], True) class ZamgWeather(WeatherEntity): diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 8cf69e72702..4cb2f6b0f7b 100644 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -203,7 +203,7 @@ def get_config_value(node, value_index, tries=5): return None -async def async_setup_platform(hass, config, async_add_devices, +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Z-Wave platform (generic part).""" if discovery_info is None or DATA_NETWORK not in hass.data: @@ -214,7 +214,7 @@ async def async_setup_platform(hass, config, async_add_devices, if device is None: return False - async_add_devices([device]) + async_add_entities([device]) return True diff --git a/tests/components/alarm_control_panel/test_manual.py b/tests/components/alarm_control_panel/test_manual.py index 02e528db914..29f630093d9 100644 --- a/tests/components/alarm_control_panel/test_manual.py +++ b/tests/components/alarm_control_panel/test_manual.py @@ -32,9 +32,9 @@ class TestAlarmControlPanelManual(unittest.TestCase): def test_setup_demo_platform(self): """Test setup.""" mock = MagicMock() - add_devices = mock.MagicMock() - demo.setup_platform(self.hass, {}, add_devices) - self.assertEqual(add_devices.call_count, 1) + add_entities = mock.MagicMock() + demo.setup_platform(self.hass, {}, add_entities) + self.assertEqual(add_entities.call_count, 1) def test_arm_home_no_pending(self): """Test arm home method.""" diff --git a/tests/components/alarm_control_panel/test_spc.py b/tests/components/alarm_control_panel/test_spc.py index 63b79781404..0a4ba0916ea 100644 --- a/tests/components/alarm_control_panel/test_spc.py +++ b/tests/components/alarm_control_panel/test_spc.py @@ -54,7 +54,7 @@ def test_setup_platform(hass): yield from spc.async_setup_platform(hass=hass, config={}, - async_add_devices=add_entities, + async_add_entities=add_entities, discovery_info=areas) assert len(added_entities) == 2 diff --git a/tests/components/binary_sensor/test_nx584.py b/tests/components/binary_sensor/test_nx584.py index 117c32203eb..252996201bb 100644 --- a/tests/components/binary_sensor/test_nx584.py +++ b/tests/components/binary_sensor/test_nx584.py @@ -45,17 +45,17 @@ class TestNX584SensorSetup(unittest.TestCase): @mock.patch('homeassistant.components.binary_sensor.nx584.NX584ZoneSensor') def test_setup_defaults(self, mock_nx, mock_watcher): """Test the setup with no configuration.""" - add_devices = mock.MagicMock() + add_entities = mock.MagicMock() config = { 'host': nx584.DEFAULT_HOST, 'port': nx584.DEFAULT_PORT, 'exclude_zones': [], 'zone_types': {}, } - self.assertTrue(nx584.setup_platform(self.hass, config, add_devices)) + self.assertTrue(nx584.setup_platform(self.hass, config, add_entities)) mock_nx.assert_has_calls( [mock.call(zone, 'opening') for zone in self.fake_zones]) - self.assertTrue(add_devices.called) + self.assertTrue(add_entities.called) self.assertEqual(nx584_client.Client.call_count, 1) self.assertEqual( nx584_client.Client.call_args, mock.call('http://localhost:5007') @@ -71,13 +71,13 @@ class TestNX584SensorSetup(unittest.TestCase): 'exclude_zones': [2], 'zone_types': {3: 'motion'}, } - add_devices = mock.MagicMock() - self.assertTrue(nx584.setup_platform(self.hass, config, add_devices)) + add_entities = mock.MagicMock() + self.assertTrue(nx584.setup_platform(self.hass, config, add_entities)) mock_nx.assert_has_calls([ mock.call(self.fake_zones[0], 'opening'), mock.call(self.fake_zones[2], 'motion'), ]) - self.assertTrue(add_devices.called) + self.assertTrue(add_entities.called) self.assertEqual(nx584_client.Client.call_count, 1) self.assertEqual( nx584_client.Client.call_args, mock.call('http://foo:123') @@ -120,9 +120,9 @@ class TestNX584SensorSetup(unittest.TestCase): def test_setup_no_zones(self): """Test the setup with no zones.""" nx584_client.Client.return_value.list_zones.return_value = [] - add_devices = mock.MagicMock() - self.assertTrue(nx584.setup_platform(self.hass, {}, add_devices)) - self.assertFalse(add_devices.called) + add_entities = mock.MagicMock() + self.assertTrue(nx584.setup_platform(self.hass, {}, add_entities)) + self.assertFalse(add_entities.called) class TestNX584ZoneSensor(unittest.TestCase): diff --git a/tests/components/binary_sensor/test_ring.py b/tests/components/binary_sensor/test_ring.py index e557050ae48..b7564dff464 100644 --- a/tests/components/binary_sensor/test_ring.py +++ b/tests/components/binary_sensor/test_ring.py @@ -16,7 +16,7 @@ class TestRingBinarySensorSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices, action): + def add_entities(self, devices, action): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -58,7 +58,7 @@ class TestRingBinarySensorSetup(unittest.TestCase): base_ring.setup(self.hass, VALID_CONFIG) ring.setup_platform(self.hass, self.config, - self.add_devices, + self.add_entities, None) for device in self.DEVICES: diff --git a/tests/components/binary_sensor/test_sleepiq.py b/tests/components/binary_sensor/test_sleepiq.py index 40e0aa35e03..9cd5dfa7f2e 100644 --- a/tests/components/binary_sensor/test_sleepiq.py +++ b/tests/components/binary_sensor/test_sleepiq.py @@ -16,7 +16,7 @@ class TestSleepIQBinarySensorSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices): + def add_entities(self, devices): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -45,7 +45,7 @@ class TestSleepIQBinarySensorSetup(unittest.TestCase): sleepiq.setup_platform(self.hass, self.config, - self.add_devices, + self.add_entities, MagicMock()) self.assertEqual(2, len(self.DEVICES)) diff --git a/tests/components/binary_sensor/test_spc.py b/tests/components/binary_sensor/test_spc.py index d2299874527..0a91b59e14d 100644 --- a/tests/components/binary_sensor/test_spc.py +++ b/tests/components/binary_sensor/test_spc.py @@ -54,7 +54,7 @@ def test_setup_platform(hass): yield from spc.async_setup_platform(hass=hass, config={}, - async_add_devices=add_entities, + async_add_entities=add_entities, discovery_info=zones) assert len(added_entities) == 3 diff --git a/tests/components/binary_sensor/test_tcp.py b/tests/components/binary_sensor/test_tcp.py index 69673f09a46..cb21d7d2c71 100644 --- a/tests/components/binary_sensor/test_tcp.py +++ b/tests/components/binary_sensor/test_tcp.py @@ -38,13 +38,13 @@ class TestTCPBinarySensor(unittest.TestCase): @patch('homeassistant.components.sensor.tcp.TcpSensor.update') def test_setup_platform_devices(self, mock_update): - """Check the supplied config and call add_devices with sensor.""" - add_devices = Mock() - ret = bin_tcp.setup_platform(None, test_tcp.TEST_CONFIG, add_devices) + """Check the supplied config and call add_entities with sensor.""" + add_entities = Mock() + ret = bin_tcp.setup_platform(None, test_tcp.TEST_CONFIG, add_entities) assert ret is None - assert add_devices.called + assert add_entities.called assert isinstance( - add_devices.call_args[0][0][0], bin_tcp.TcpBinarySensor) + add_entities.call_args[0][0][0], bin_tcp.TcpBinarySensor) @patch('homeassistant.components.sensor.tcp.TcpSensor.update') def test_is_on_true(self, mock_update): diff --git a/tests/components/binary_sensor/test_vultr.py b/tests/components/binary_sensor/test_vultr.py index a13944aef9f..f356149ddde 100644 --- a/tests/components/binary_sensor/test_vultr.py +++ b/tests/components/binary_sensor/test_vultr.py @@ -26,7 +26,7 @@ class TestVultrBinarySensorSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices, action): + def add_entities(self, devices, action): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -71,7 +71,7 @@ class TestVultrBinarySensorSetup(unittest.TestCase): for config in self.configs: vultr.setup_platform(self.hass, config, - self.add_devices, + self.add_entities, None) self.assertEqual(len(self.DEVICES), 3) @@ -147,7 +147,7 @@ class TestVultrBinarySensorSetup(unittest.TestCase): no_subs_setup = vultr.setup_platform(self.hass, bad_conf, - self.add_devices, + self.add_entities, None) self.assertFalse(no_subs_setup) @@ -159,7 +159,7 @@ class TestVultrBinarySensorSetup(unittest.TestCase): wrong_subs_setup = vultr.setup_platform(self.hass, bad_conf, - self.add_devices, + self.add_entities, None) self.assertFalse(wrong_subs_setup) diff --git a/tests/components/climate/test_honeywell.py b/tests/components/climate/test_honeywell.py index 69df11715e9..7072090591b 100644 --- a/tests/components/climate/test_honeywell.py +++ b/tests/components/climate/test_honeywell.py @@ -56,7 +56,7 @@ class TestHoneywell(unittest.TestCase): honeywell.PLATFORM_SCHEMA(bad_region_config) hass = mock.MagicMock() - add_devices = mock.MagicMock() + add_entities = mock.MagicMock() locations = [ mock.MagicMock(), @@ -69,7 +69,7 @@ class TestHoneywell(unittest.TestCase): locations[0].devices_by_id.values.return_value = devices_1 locations[1].devices_by_id.values.return_value = devices_2 - result = honeywell.setup_platform(hass, config, add_devices) + result = honeywell.setup_platform(hass, config, add_entities) self.assertTrue(result) self.assertEqual(mock_sc.call_count, 1) self.assertEqual(mock_sc.call_args, mock.call('user', 'pass')) @@ -86,7 +86,7 @@ class TestHoneywell(unittest.TestCase): def test_setup_us_failures(self, mock_sc): """Test the US setup.""" hass = mock.MagicMock() - add_devices = mock.MagicMock() + add_entities = mock.MagicMock() config = { CONF_USERNAME: 'user', CONF_PASSWORD: 'pass', @@ -94,14 +94,14 @@ class TestHoneywell(unittest.TestCase): } mock_sc.side_effect = somecomfort.AuthError - result = honeywell.setup_platform(hass, config, add_devices) + result = honeywell.setup_platform(hass, config, add_entities) self.assertFalse(result) - self.assertFalse(add_devices.called) + self.assertFalse(add_entities.called) mock_sc.side_effect = somecomfort.SomeComfortError - result = honeywell.setup_platform(hass, config, add_devices) + result = honeywell.setup_platform(hass, config, add_entities) self.assertFalse(result) - self.assertFalse(add_devices.called) + self.assertFalse(add_entities.called) @mock.patch('somecomfort.SomeComfort') @mock.patch('homeassistant.components.climate.' @@ -136,9 +136,9 @@ class TestHoneywell(unittest.TestCase): } mock_sc.return_value = mock.MagicMock(locations_by_id=locations) hass = mock.MagicMock() - add_devices = mock.MagicMock() + add_entities = mock.MagicMock() self.assertEqual(True, - honeywell.setup_platform(hass, config, add_devices)) + honeywell.setup_platform(hass, config, add_entities)) return mock_ht.call_args_list, mock_sc @@ -185,8 +185,8 @@ class TestHoneywell(unittest.TestCase): mock_evo.return_value.temperatures.return_value = [ {'id': 'foo'}, {'id': 'bar'}] hass = mock.MagicMock() - add_devices = mock.MagicMock() - self.assertTrue(honeywell.setup_platform(hass, config, add_devices)) + add_entities = mock.MagicMock() + self.assertTrue(honeywell.setup_platform(hass, config, add_entities)) self.assertEqual(mock_evo.call_count, 1) self.assertEqual(mock_evo.call_args, mock.call('user', 'pass')) self.assertEqual(mock_evo.return_value.temperatures.call_count, 1) @@ -198,7 +198,7 @@ class TestHoneywell(unittest.TestCase): mock.call(mock_evo.return_value, 'foo', True, 20.0), mock.call(mock_evo.return_value, 'bar', False, 20.0), ]) - self.assertEqual(2, add_devices.call_count) + self.assertEqual(2, add_entities.call_count) @mock.patch('evohomeclient.EvohomeClient') @mock.patch('homeassistant.components.climate.honeywell.' @@ -217,8 +217,8 @@ class TestHoneywell(unittest.TestCase): honeywell.DEFAULT_AWAY_TEMPERATURE hass = mock.MagicMock() - add_devices = mock.MagicMock() - self.assertTrue(honeywell.setup_platform(hass, config, add_devices)) + add_entities = mock.MagicMock() + self.assertTrue(honeywell.setup_platform(hass, config, add_entities)) mock_round.assert_has_calls([ mock.call(mock_evo.return_value, 'foo', True, 16), mock.call(mock_evo.return_value, 'bar', False, 16), @@ -251,9 +251,9 @@ class TestHoneywell(unittest.TestCase): honeywell.CONF_REGION: 'eu', } mock_evo.return_value.temperatures.side_effect = socket.error - add_devices = mock.MagicMock() + add_entities = mock.MagicMock() hass = mock.MagicMock() - self.assertFalse(honeywell.setup_platform(hass, config, add_devices)) + self.assertFalse(honeywell.setup_platform(hass, config, add_entities)) class TestHoneywellRound(unittest.TestCase): diff --git a/tests/components/climate/test_melissa.py b/tests/components/climate/test_melissa.py index 5022c556b7d..563f74383e5 100644 --- a/tests/components/climate/test_melissa.py +++ b/tests/components/climate/test_melissa.py @@ -76,11 +76,11 @@ class TestMelissa(unittest.TestCase): self.hass.data[DATA_MELISSA] = self.api config = {} - add_devices = Mock() + add_entities = Mock() discovery_info = {} - melissa.setup_platform(self.hass, config, add_devices, discovery_info) - add_devices.assert_called_once_with(thermostats) + melissa.setup_platform(self.hass, config, add_entities, discovery_info) + add_entities.assert_called_once_with(thermostats) def test_get_name(self): """Test name property.""" diff --git a/tests/components/climate/test_nuheat.py b/tests/components/climate/test_nuheat.py index 6ec63646bec..5b47a5a75af 100644 --- a/tests/components/climate/test_nuheat.py +++ b/tests/components/climate/test_nuheat.py @@ -67,11 +67,11 @@ class TestNuHeat(unittest.TestCase): self.hass.data[nuheat.NUHEAT_DOMAIN] = (self.api, ["12345"]) config = {} - add_devices = Mock() + add_entities = Mock() discovery_info = {} - nuheat.setup_platform(self.hass, config, add_devices, discovery_info) - add_devices.assert_called_once_with(thermostats, True) + nuheat.setup_platform(self.hass, config, add_entities, discovery_info) + add_entities.assert_called_once_with(thermostats, True) @patch("homeassistant.components.climate.nuheat.NuHeatThermostat") def test_resume_program_service(self, mocked_thermostat): diff --git a/tests/components/fan/test_dyson.py b/tests/components/fan/test_dyson.py index a935210784b..452f8e199eb 100644 --- a/tests/components/fan/test_dyson.py +++ b/tests/components/fan/test_dyson.py @@ -78,9 +78,9 @@ class DysonTest(unittest.TestCase): def test_setup_component_with_no_devices(self): """Test setup component with no devices.""" self.hass.data[dyson.DYSON_DEVICES] = [] - add_devices = mock.MagicMock() - dyson.setup_platform(self.hass, None, add_devices) - add_devices.assert_called_with([]) + add_entities = mock.MagicMock() + dyson.setup_platform(self.hass, None, add_entities) + add_entities.assert_called_with([]) def test_setup_component(self): """Test setup component with devices.""" diff --git a/tests/components/light/test_group.py b/tests/components/light/test_group.py index 901535c5465..4619e9fb9bd 100644 --- a/tests/components/light/test_group.py +++ b/tests/components/light/test_group.py @@ -346,13 +346,13 @@ async def test_service_calls(hass): async def test_invalid_service_calls(hass): """Test invalid service call arguments get discarded.""" - add_devices = MagicMock() + add_entities = MagicMock() await group.async_setup_platform(hass, { 'entities': ['light.test1', 'light.test2'] - }, add_devices) + }, add_entities) - assert add_devices.call_count == 1 - grouped_light = add_devices.call_args[0][0][0] + assert add_entities.call_count == 1 + grouped_light = add_entities.call_args[0][0][0] grouped_light.hass = hass with asynctest.patch.object(hass.services, 'async_call') as mock_call: diff --git a/tests/components/media_player/test_cast.py b/tests/components/media_player/test_cast.py index c3e777ea334..8fe285a59cd 100644 --- a/tests/components/media_player/test_cast.py +++ b/tests/components/media_player/test_cast.py @@ -51,13 +51,13 @@ async def async_setup_cast(hass, config=None, discovery_info=None): """Set up the cast platform.""" if config is None: config = {} - add_devices = Mock() + add_entities = Mock() - await cast.async_setup_platform(hass, config, add_devices, + await cast.async_setup_platform(hass, config, add_entities, discovery_info=discovery_info) await hass.async_block_till_done() - return add_devices + return add_entities async def async_setup_cast_internal_discovery(hass, config=None, @@ -67,7 +67,7 @@ async def async_setup_cast_internal_discovery(hass, config=None, with patch('pychromecast.start_discovery', return_value=(listener, None)) as start_discovery: - add_devices = await async_setup_cast(hass, config, discovery_info) + add_entities = await async_setup_cast(hass, config, discovery_info) await hass.async_block_till_done() await hass.async_block_till_done() @@ -80,7 +80,7 @@ async def async_setup_cast_internal_discovery(hass, config=None, listener.services[service_name] = attr.astuple(info) discovery_callback(service_name) - return discover_chromecast, add_devices + return discover_chromecast, add_entities async def async_setup_media_player_cast(hass: HomeAssistantType, @@ -214,30 +214,30 @@ async def test_normal_chromecast_not_starting_discovery(hass): with patch('homeassistant.components.media_player.cast.' '_setup_internal_discovery') as setup_discovery: # normal (non-group) chromecast shouldn't start discovery. - add_devices = await async_setup_cast(hass, {'host': 'host1'}) + add_entities = await async_setup_cast(hass, {'host': 'host1'}) await hass.async_block_till_done() - assert add_devices.call_count == 1 + assert add_entities.call_count == 1 assert setup_discovery.call_count == 0 # Same entity twice - add_devices = await async_setup_cast(hass, {'host': 'host1'}) + add_entities = await async_setup_cast(hass, {'host': 'host1'}) await hass.async_block_till_done() - assert add_devices.call_count == 0 + assert add_entities.call_count == 0 assert setup_discovery.call_count == 0 hass.data[cast.ADDED_CAST_DEVICES_KEY] = set() - add_devices = await async_setup_cast( + add_entities = await async_setup_cast( hass, discovery_info={'host': 'host1', 'port': 8009}) await hass.async_block_till_done() - assert add_devices.call_count == 1 + assert add_entities.call_count == 1 assert setup_discovery.call_count == 0 # group should start discovery. hass.data[cast.ADDED_CAST_DEVICES_KEY] = set() - add_devices = await async_setup_cast( + add_entities = await async_setup_cast( hass, discovery_info={'host': 'host1', 'port': 42}) await hass.async_block_till_done() - assert add_devices.call_count == 0 + assert add_entities.call_count == 0 assert setup_discovery.call_count == 1 diff --git a/tests/components/media_player/test_samsungtv.py b/tests/components/media_player/test_samsungtv.py index 6dd61157851..2fedfb6a65e 100644 --- a/tests/components/media_player/test_samsungtv.py +++ b/tests/components/media_player/test_samsungtv.py @@ -72,9 +72,9 @@ class TestSamsungTv(unittest.TestCase): """Testing setup of platform.""" with mock.patch( 'homeassistant.components.media_player.samsungtv.socket'): - add_devices = mock.Mock() + add_entities = mock.Mock() setup_platform( - self.hass, WORKING_CONFIG, add_devices) + self.hass, WORKING_CONFIG, add_entities) @MockDependency('samsungctl') @MockDependency('wakeonlan') @@ -82,8 +82,8 @@ class TestSamsungTv(unittest.TestCase): """Testing setup of platform with discovery.""" with mock.patch( 'homeassistant.components.media_player.samsungtv.socket'): - add_devices = mock.Mock() - setup_platform(self.hass, {}, add_devices, + add_entities = mock.Mock() + setup_platform(self.hass, {}, add_entities, discovery_info=DISCOVERY_INFO) @MockDependency('samsungctl') @@ -94,11 +94,11 @@ class TestSamsungTv(unittest.TestCase): """Testing setup of platform with no data.""" with mock.patch( 'homeassistant.components.media_player.samsungtv.socket'): - add_devices = mock.Mock() - setup_platform(self.hass, {}, add_devices, + add_entities = mock.Mock() + setup_platform(self.hass, {}, add_entities, discovery_info=None) mocked_warn.assert_called_once_with("Cannot determine device") - add_devices.assert_not_called() + add_entities.assert_not_called() @mock.patch( 'homeassistant.components.media_player.samsungtv.subprocess.Popen' diff --git a/tests/components/media_player/test_sonos.py b/tests/components/media_player/test_sonos.py index cd2ce2b9707..5a845738fa3 100644 --- a/tests/components/media_player/test_sonos.py +++ b/tests/components/media_player/test_sonos.py @@ -121,13 +121,13 @@ class SoCoMock(): return -def add_devices_factory(hass): +def add_entities_factory(hass): """Add devices factory.""" - def add_devices(devices, update_befor_add=False): + def add_entities(devices, update_befor_add=False): """Fake add device.""" hass.data[sonos.DATA_SONOS].devices = devices - return add_devices + return add_entities class TestSonosMediaPlayer(unittest.TestCase): @@ -157,7 +157,7 @@ class TestSonosMediaPlayer(unittest.TestCase): @mock.patch('socket.create_connection', side_effect=socket.error()) def test_ensure_setup_discovery(self, *args): """Test a single device using the autodiscovery provided by HASS.""" - sonos.setup_platform(self.hass, {}, add_devices_factory(self.hass), { + sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) @@ -240,7 +240,7 @@ class TestSonosMediaPlayer(unittest.TestCase): @mock.patch('socket.create_connection', side_effect=socket.error()) def test_ensure_setup_sonos_discovery(self, *args): """Test a single device using the autodiscovery provided by Sonos.""" - sonos.setup_platform(self.hass, {}, add_devices_factory(self.hass)) + sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass)) devices = list(self.hass.data[sonos.DATA_SONOS].devices) self.assertEqual(len(devices), 1) self.assertEqual(devices[0].name, 'Kitchen') @@ -250,7 +250,7 @@ class TestSonosMediaPlayer(unittest.TestCase): @mock.patch.object(SoCoMock, 'set_sleep_timer') def test_sonos_set_sleep_timer(self, set_sleep_timerMock, *args): """Ensuring soco methods called for sonos_set_sleep_timer service.""" - sonos.setup_platform(self.hass, {}, add_devices_factory(self.hass), { + sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] @@ -264,7 +264,7 @@ class TestSonosMediaPlayer(unittest.TestCase): @mock.patch.object(SoCoMock, 'set_sleep_timer') def test_sonos_clear_sleep_timer(self, set_sleep_timerMock, *args): """Ensuring soco methods called for sonos_clear_sleep_timer service.""" - sonos.setup_platform(self.hass, {}, add_devices_factory(self.hass), { + sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] @@ -278,7 +278,7 @@ class TestSonosMediaPlayer(unittest.TestCase): @mock.patch('socket.create_connection', side_effect=socket.error()) def test_set_alarm(self, soco_mock, alarm_mock, *args): """Ensuring soco methods called for sonos_set_sleep_timer service.""" - sonos.setup_platform(self.hass, {}, add_devices_factory(self.hass), { + sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] @@ -308,7 +308,7 @@ class TestSonosMediaPlayer(unittest.TestCase): @mock.patch.object(soco.snapshot.Snapshot, 'snapshot') def test_sonos_snapshot(self, snapshotMock, *args): """Ensuring soco methods called for sonos_snapshot service.""" - sonos.setup_platform(self.hass, {}, add_devices_factory(self.hass), { + sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] @@ -326,7 +326,7 @@ class TestSonosMediaPlayer(unittest.TestCase): """Ensuring soco methods called for sonos_restor service.""" from soco.snapshot import Snapshot - sonos.setup_platform(self.hass, {}, add_devices_factory(self.hass), { + sonos.setup_platform(self.hass, {}, add_entities_factory(self.hass), { 'host': '192.0.2.1' }) device = list(self.hass.data[sonos.DATA_SONOS].devices)[-1] diff --git a/tests/components/media_player/test_universal.py b/tests/components/media_player/test_universal.py index 99c16670764..279809a283f 100644 --- a/tests/components/media_player/test_universal.py +++ b/tests/components/media_player/test_universal.py @@ -279,7 +279,7 @@ class TestMediaPlayer(unittest.TestCase): bad_config = {'platform': 'universal'} entities = [] - def add_devices(new_entities): + def add_entities(new_entities): """Add devices to list.""" for dev in new_entities: entities.append(dev) @@ -288,7 +288,7 @@ class TestMediaPlayer(unittest.TestCase): try: run_coroutine_threadsafe( universal.async_setup_platform( - self.hass, validate_config(bad_config), add_devices), + self.hass, validate_config(bad_config), add_entities), self.hass.loop).result() except MultipleInvalid: setup_ok = False @@ -297,7 +297,7 @@ class TestMediaPlayer(unittest.TestCase): run_coroutine_threadsafe( universal.async_setup_platform( - self.hass, validate_config(config), add_devices), + self.hass, validate_config(config), add_entities), self.hass.loop).result() self.assertEqual(1, len(entities)) self.assertEqual('test', entities[0].name) diff --git a/tests/components/remote/test_kira.py b/tests/components/remote/test_kira.py index eaa78d44a60..74c8e2854d0 100644 --- a/tests/components/remote/test_kira.py +++ b/tests/components/remote/test_kira.py @@ -24,7 +24,7 @@ class TestKiraSensor(unittest.TestCase): # pylint: disable=invalid-name DEVICES = [] - def add_devices(self, devices): + def add_entities(self, devices): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -42,7 +42,7 @@ class TestKiraSensor(unittest.TestCase): def test_service_call(self): """Test Kira's ability to send commands.""" - kira.setup_platform(self.hass, TEST_CONFIG, self.add_devices, + kira.setup_platform(self.hass, TEST_CONFIG, self.add_entities, DISCOVERY_INFO) assert len(self.DEVICES) == 1 remote = self.DEVICES[0] diff --git a/tests/components/sensor/test_arlo.py b/tests/components/sensor/test_arlo.py index d31490ab2af..732e47099c4 100644 --- a/tests/components/sensor/test_arlo.py +++ b/tests/components/sensor/test_arlo.py @@ -64,14 +64,14 @@ def captured_sensor(): class PlatformSetupFixture(): - """Fixture for testing platform setup call to add_devices().""" + """Fixture for testing platform setup call to add_entities().""" def __init__(self): """Instantiate the platform setup fixture.""" self.sensors = None self.update = False - def add_devices(self, sensors, update): + def add_entities(self, sensors, update): """Mock method for adding devices.""" self.sensors = sensors self.update = update @@ -101,7 +101,7 @@ def mock_dispatch(): def test_setup_with_no_data(platform_setup, hass): """Test setup_platform with no data.""" - arlo.setup_platform(hass, None, platform_setup.add_devices) + arlo.setup_platform(hass, None, platform_setup.add_entities) assert platform_setup.sensors is None assert not platform_setup.update @@ -132,7 +132,7 @@ def test_setup_with_valid_data(platform_setup, hass): })] }) - arlo.setup_platform(hass, config, platform_setup.add_devices) + arlo.setup_platform(hass, config, platform_setup.add_entities) assert len(platform_setup.sensors) == 8 assert platform_setup.update diff --git a/tests/components/sensor/test_canary.py b/tests/components/sensor/test_canary.py index 346929a4685..47a1f330d05 100644 --- a/tests/components/sensor/test_canary.py +++ b/tests/components/sensor/test_canary.py @@ -24,7 +24,7 @@ class TestCanarySensorSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices, action): + def add_entities(self, devices, action): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -51,7 +51,7 @@ class TestCanarySensorSetup(unittest.TestCase): mock_location("Work", True, devices=[online_device_at_work]), ] - canary.setup_platform(self.hass, self.config, self.add_devices, None) + canary.setup_platform(self.hass, self.config, self.add_entities, None) self.assertEqual(6, len(self.DEVICES)) diff --git a/tests/components/sensor/test_dyson.py b/tests/components/sensor/test_dyson.py index cc32872e6f0..5b5be4a587d 100644 --- a/tests/components/sensor/test_dyson.py +++ b/tests/components/sensor/test_dyson.py @@ -62,9 +62,9 @@ class DysonTest(unittest.TestCase): def test_setup_component_with_no_devices(self): """Test setup component with no devices.""" self.hass.data[dyson.DYSON_DEVICES] = [] - add_devices = mock.MagicMock() - dyson.setup_platform(self.hass, None, add_devices) - add_devices.assert_called_with([]) + add_entities = mock.MagicMock() + dyson.setup_platform(self.hass, None, add_entities) + add_entities.assert_called_with([]) def test_setup_component(self): """Test setup component with devices.""" diff --git a/tests/components/sensor/test_efergy.py b/tests/components/sensor/test_efergy.py index 9a79ab5b81c..fdcaa415483 100644 --- a/tests/components/sensor/test_efergy.py +++ b/tests/components/sensor/test_efergy.py @@ -61,7 +61,7 @@ class TestEfergySensor(unittest.TestCase): DEVICES = [] @requests_mock.Mocker() - def add_devices(self, devices, mock): + def add_entities(self, devices, mock): """Mock add devices.""" mock_responses(mock) for device in devices: diff --git a/tests/components/sensor/test_fido.py b/tests/components/sensor/test_fido.py index 1eca7be7544..c0bbadc043b 100644 --- a/tests/components/sensor/test_fido.py +++ b/tests/components/sensor/test_fido.py @@ -59,8 +59,8 @@ class PyFidoFakeModule(): FidoClient = FidoClientMockError -def fake_async_add_devices(component, update_before_add=False): - """Fake async_add_devices function.""" +def fake_async_add_entities(component, update_before_add=False): + """Fake async_add_entities function.""" pass @@ -103,7 +103,7 @@ def test_error(hass, caplog): sys.modules['pyfido.client'] = PyFidoClientFakeModule() config = {} - fake_async_add_devices = MagicMock() + fake_async_add_entities = MagicMock() yield from fido.async_setup_platform(hass, config, - fake_async_add_devices) - assert fake_async_add_devices.called is False + fake_async_add_entities) + assert fake_async_add_entities.called is False diff --git a/tests/components/sensor/test_foobot.py b/tests/components/sensor/test_foobot.py index 322f2b3f2a8..f9382a04b6b 100644 --- a/tests/components/sensor/test_foobot.py +++ b/tests/components/sensor/test_foobot.py @@ -44,18 +44,18 @@ async def test_default_setup(hass, aioclient_mock): async def test_setup_timeout_error(hass, aioclient_mock): """Expected failures caused by a timeout in API response.""" - fake_async_add_devices = MagicMock() + fake_async_add_entities = MagicMock() aioclient_mock.get(re.compile('api.foobot.io/v2/owner/.*'), exc=asyncio.TimeoutError()) with pytest.raises(PlatformNotReady): await foobot.async_setup_platform(hass, {'sensor': VALID_CONFIG}, - fake_async_add_devices) + fake_async_add_entities) async def test_setup_permanent_error(hass, aioclient_mock): """Expected failures caused by permanent errors in API response.""" - fake_async_add_devices = MagicMock() + fake_async_add_entities = MagicMock() errors = [400, 401, 403] for error in errors: @@ -63,13 +63,13 @@ async def test_setup_permanent_error(hass, aioclient_mock): status=error) result = await foobot.async_setup_platform(hass, {'sensor': VALID_CONFIG}, - fake_async_add_devices) + fake_async_add_entities) assert result is None async def test_setup_temporary_error(hass, aioclient_mock): """Expected failures caused by temporary errors in API response.""" - fake_async_add_devices = MagicMock() + fake_async_add_entities = MagicMock() errors = [429, 500] for error in errors: @@ -78,4 +78,4 @@ async def test_setup_temporary_error(hass, aioclient_mock): with pytest.raises(PlatformNotReady): await foobot.async_setup_platform(hass, {'sensor': VALID_CONFIG}, - fake_async_add_devices) + fake_async_add_entities) diff --git a/tests/components/sensor/test_hydroquebec.py b/tests/components/sensor/test_hydroquebec.py index debd6ef6167..eed5ab4a6a6 100644 --- a/tests/components/sensor/test_hydroquebec.py +++ b/tests/components/sensor/test_hydroquebec.py @@ -99,7 +99,7 @@ def test_error(hass, caplog): sys.modules['pyhydroquebec.client'] = PyHydroQuebecClientFakeModule() config = {} - fake_async_add_devices = MagicMock() + fake_async_add_entities = MagicMock() yield from hydroquebec.async_setup_platform(hass, config, - fake_async_add_devices) - assert fake_async_add_devices.called is False + fake_async_add_entities) + assert fake_async_add_entities.called is False diff --git a/tests/components/sensor/test_kira.py b/tests/components/sensor/test_kira.py index 093158cb25c..76aba46d514 100644 --- a/tests/components/sensor/test_kira.py +++ b/tests/components/sensor/test_kira.py @@ -22,7 +22,7 @@ class TestKiraSensor(unittest.TestCase): # pylint: disable=invalid-name DEVICES = [] - def add_devices(self, devices): + def add_entities(self, devices): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -41,7 +41,7 @@ class TestKiraSensor(unittest.TestCase): # pylint: disable=protected-access def test_kira_sensor_callback(self): """Ensure Kira sensor properly updates its attributes from callback.""" - kira.setup_platform(self.hass, TEST_CONFIG, self.add_devices, + kira.setup_platform(self.hass, TEST_CONFIG, self.add_entities, DISCOVERY_INFO) assert len(self.DEVICES) == 1 sensor = self.DEVICES[0] diff --git a/tests/components/sensor/test_melissa.py b/tests/components/sensor/test_melissa.py index 55b3e7f70f4..7ac90221f16 100644 --- a/tests/components/sensor/test_melissa.py +++ b/tests/components/sensor/test_melissa.py @@ -42,10 +42,10 @@ class TestMelissa(unittest.TestCase): self.hass.data[DATA_MELISSA] = self.api config = {} - add_devices = Mock() + add_entities = Mock() discovery_info = {} - melissa.setup_platform(self.hass, config, add_devices, discovery_info) + melissa.setup_platform(self.hass, config, add_entities, discovery_info) def test_name(self): """Test name property.""" diff --git a/tests/components/sensor/test_radarr.py b/tests/components/sensor/test_radarr.py index 0d6aca9d0b7..30195b73a13 100644 --- a/tests/components/sensor/test_radarr.py +++ b/tests/components/sensor/test_radarr.py @@ -193,7 +193,7 @@ class TestRadarrSetup(unittest.TestCase): # pylint: disable=invalid-name DEVICES = [] - def add_devices(self, devices, update): + def add_entities(self, devices, update): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -221,7 +221,7 @@ class TestRadarrSetup(unittest.TestCase): 'diskspace' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual('263.10', device.state) @@ -248,7 +248,7 @@ class TestRadarrSetup(unittest.TestCase): 'diskspace' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual('263.10', device.state) @@ -275,7 +275,7 @@ class TestRadarrSetup(unittest.TestCase): 'commands' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -302,7 +302,7 @@ class TestRadarrSetup(unittest.TestCase): 'movies' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -329,7 +329,7 @@ class TestRadarrSetup(unittest.TestCase): 'upcoming' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -360,7 +360,7 @@ class TestRadarrSetup(unittest.TestCase): 'upcoming' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -387,7 +387,7 @@ class TestRadarrSetup(unittest.TestCase): 'status' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual('0.2.0.210', device.state) @@ -413,7 +413,7 @@ class TestRadarrSetup(unittest.TestCase): ], "ssl": "true" } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -441,7 +441,7 @@ class TestRadarrSetup(unittest.TestCase): 'upcoming' ] } - radarr.setup_platform(self.hass, config, self.add_devices, None) + radarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(None, device.state) diff --git a/tests/components/sensor/test_ring.py b/tests/components/sensor/test_ring.py index 4d34018ce52..05685376ef9 100644 --- a/tests/components/sensor/test_ring.py +++ b/tests/components/sensor/test_ring.py @@ -16,7 +16,7 @@ class TestRingSensorSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices, action): + def add_entities(self, devices, action): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -66,7 +66,7 @@ class TestRingSensorSetup(unittest.TestCase): base_ring.setup(self.hass, VALID_CONFIG) ring.setup_platform(self.hass, self.config, - self.add_devices, + self.add_entities, None) for device in self.DEVICES: diff --git a/tests/components/sensor/test_season.py b/tests/components/sensor/test_season.py index 4c82399648e..21e18a00c14 100644 --- a/tests/components/sensor/test_season.py +++ b/tests/components/sensor/test_season.py @@ -60,7 +60,7 @@ class TestSeason(unittest.TestCase): CONFIG_ASTRONOMICAL = {'type': 'astronomical'} CONFIG_METEOROLOGICAL = {'type': 'meteorological'} - def add_devices(self, devices): + def add_entities(self, devices): """Mock add devices.""" for device in devices: self.DEVICE = device diff --git a/tests/components/sensor/test_sleepiq.py b/tests/components/sensor/test_sleepiq.py index a79db86dc79..646f8e5d888 100644 --- a/tests/components/sensor/test_sleepiq.py +++ b/tests/components/sensor/test_sleepiq.py @@ -16,7 +16,7 @@ class TestSleepIQSensorSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices): + def add_entities(self, devices): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -49,7 +49,7 @@ class TestSleepIQSensorSetup(unittest.TestCase): sleepiq.setup_platform(self.hass, self.config, - self.add_devices, + self.add_entities, MagicMock()) self.assertEqual(2, len(self.DEVICES)) diff --git a/tests/components/sensor/test_sonarr.py b/tests/components/sensor/test_sonarr.py index 275bb4a1e8b..e44d3d9a99f 100644 --- a/tests/components/sensor/test_sonarr.py +++ b/tests/components/sensor/test_sonarr.py @@ -579,7 +579,7 @@ class TestSonarrSetup(unittest.TestCase): # pylint: disable=invalid-name DEVICES = [] - def add_devices(self, devices, update): + def add_entities(self, devices, update): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -607,7 +607,7 @@ class TestSonarrSetup(unittest.TestCase): 'diskspace' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual('263.10', device.state) @@ -634,7 +634,7 @@ class TestSonarrSetup(unittest.TestCase): 'diskspace' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual('263.10', device.state) @@ -661,7 +661,7 @@ class TestSonarrSetup(unittest.TestCase): 'commands' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -688,7 +688,7 @@ class TestSonarrSetup(unittest.TestCase): 'queue' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -715,7 +715,7 @@ class TestSonarrSetup(unittest.TestCase): 'series' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -742,7 +742,7 @@ class TestSonarrSetup(unittest.TestCase): 'wanted' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -769,7 +769,7 @@ class TestSonarrSetup(unittest.TestCase): 'upcoming' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -800,7 +800,7 @@ class TestSonarrSetup(unittest.TestCase): 'upcoming' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -827,7 +827,7 @@ class TestSonarrSetup(unittest.TestCase): 'status' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual('2.0.0.1121', device.state) @@ -854,7 +854,7 @@ class TestSonarrSetup(unittest.TestCase): ], "ssl": "true" } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(1, device.state) @@ -882,7 +882,7 @@ class TestSonarrSetup(unittest.TestCase): 'upcoming' ] } - sonarr.setup_platform(self.hass, config, self.add_devices, None) + sonarr.setup_platform(self.hass, config, self.add_entities, None) for device in self.DEVICES: device.update() self.assertEqual(None, device.state) diff --git a/tests/components/sensor/test_tcp.py b/tests/components/sensor/test_tcp.py index cbc097955c8..e89e8db861a 100644 --- a/tests/components/sensor/test_tcp.py +++ b/tests/components/sensor/test_tcp.py @@ -48,14 +48,14 @@ class TestTCPSensor(unittest.TestCase): @patch('homeassistant.components.sensor.tcp.TcpSensor.update') def test_setup_platform_valid_config(self, mock_update): - """Check a valid configuration and call add_devices with sensor.""" + """Check a valid configuration and call add_entities with sensor.""" with assert_setup_component(0, 'sensor'): assert setup_component(self.hass, 'sensor', TEST_CONFIG) - add_devices = Mock() - tcp.setup_platform(None, TEST_CONFIG['sensor'], add_devices) - assert add_devices.called - assert isinstance(add_devices.call_args[0][0][0], tcp.TcpSensor) + add_entities = Mock() + tcp.setup_platform(None, TEST_CONFIG['sensor'], add_entities) + assert add_entities.called + assert isinstance(add_entities.call_args[0][0][0], tcp.TcpSensor) def test_setup_platform_invalid_config(self): """Check an invalid configuration.""" diff --git a/tests/components/sensor/test_time_date.py b/tests/components/sensor/test_time_date.py index 1b3ab68988e..98368e997d5 100644 --- a/tests/components/sensor/test_time_date.py +++ b/tests/components/sensor/test_time_date.py @@ -14,7 +14,7 @@ class TestTimeDateSensor(unittest.TestCase): # pylint: disable=invalid-name DEVICES = [] - def add_devices(self, devices): + def add_entities(self, devices): """Mock add devices.""" for device in devices: self.DEVICES.append(device) diff --git a/tests/components/sensor/test_vultr.py b/tests/components/sensor/test_vultr.py index 6b2e2341c52..ee2dd35dc8f 100644 --- a/tests/components/sensor/test_vultr.py +++ b/tests/components/sensor/test_vultr.py @@ -23,7 +23,7 @@ class TestVultrSensorSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices, action): + def add_entities(self, devices, action): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -71,7 +71,7 @@ class TestVultrSensorSetup(unittest.TestCase): for config in self.configs: setup = vultr.setup_platform( - self.hass, config, self.add_devices, None) + self.hass, config, self.add_entities, None) self.assertIsNone(setup) @@ -160,7 +160,7 @@ class TestVultrSensorSetup(unittest.TestCase): } # No subs at all no_sub_setup = vultr.setup_platform( - self.hass, bad_conf, self.add_devices, None) + self.hass, bad_conf, self.add_entities, None) self.assertIsNone(no_sub_setup) self.assertEqual(0, len(self.DEVICES)) diff --git a/tests/components/switch/test_vultr.py b/tests/components/switch/test_vultr.py index 222a044a523..ce8740e9bff 100644 --- a/tests/components/switch/test_vultr.py +++ b/tests/components/switch/test_vultr.py @@ -26,7 +26,7 @@ class TestVultrSwitchSetup(unittest.TestCase): DEVICES = [] - def add_devices(self, devices, action): + def add_entities(self, devices, action): """Mock add devices.""" for device in devices: self.DEVICES.append(device) @@ -71,7 +71,7 @@ class TestVultrSwitchSetup(unittest.TestCase): for config in self.configs: vultr.setup_platform(self.hass, config, - self.add_devices, + self.add_entities, None) self.assertEqual(len(self.DEVICES), 3) @@ -181,7 +181,7 @@ class TestVultrSwitchSetup(unittest.TestCase): no_subs_setup = vultr.setup_platform(self.hass, bad_conf, - self.add_devices, + self.add_entities, None) self.assertIsNotNone(no_subs_setup) @@ -193,7 +193,7 @@ class TestVultrSwitchSetup(unittest.TestCase): wrong_subs_setup = vultr.setup_platform(self.hass, bad_conf, - self.add_devices, + self.add_entities, None) self.assertIsNotNone(wrong_subs_setup) diff --git a/tests/components/vacuum/test_dyson.py b/tests/components/vacuum/test_dyson.py index 5e32fc9daef..e9e6aaa1b35 100644 --- a/tests/components/vacuum/test_dyson.py +++ b/tests/components/vacuum/test_dyson.py @@ -77,9 +77,9 @@ class DysonTest(unittest.TestCase): def test_setup_component_with_no_devices(self): """Test setup component with no devices.""" self.hass.data[dyson.DYSON_DEVICES] = [] - add_devices = mock.MagicMock() - dyson.setup_platform(self.hass, {}, add_devices) - add_devices.assert_called_with([]) + add_entities = mock.MagicMock() + dyson.setup_platform(self.hass, {}, add_entities) + add_entities.assert_called_with([]) def test_setup_component(self): """Test setup component with devices.""" diff --git a/tests/components/weather/test_yweather.py b/tests/components/weather/test_yweather.py index c36b4454c93..a808eb4e468 100644 --- a/tests/components/weather/test_yweather.py +++ b/tests/components/weather/test_yweather.py @@ -76,7 +76,7 @@ class TestWeather(unittest.TestCase): DEVICES = [] - def add_devices(self, devices): + def add_entities(self, devices): """Mock add devices.""" for device in devices: device.update() diff --git a/tests/components/zwave/test_init.py b/tests/components/zwave/test_init.py index 39abf6f588f..c9224885bbc 100644 --- a/tests/components/zwave/test_init.py +++ b/tests/components/zwave/test_init.py @@ -128,24 +128,24 @@ def test_setup_platform(hass, mock_openzwave): mock_device = MagicMock() hass.data[DATA_NETWORK] = MagicMock() hass.data[zwave.DATA_DEVICES] = {456: mock_device} - async_add_devices = MagicMock() + async_add_entities = MagicMock() result = yield from zwave.async_setup_platform( - hass, None, async_add_devices, None) + hass, None, async_add_entities, None) assert not result - assert not async_add_devices.called + assert not async_add_entities.called result = yield from zwave.async_setup_platform( - hass, None, async_add_devices, {const.DISCOVERY_DEVICE: 123}) + hass, None, async_add_entities, {const.DISCOVERY_DEVICE: 123}) assert not result - assert not async_add_devices.called + assert not async_add_entities.called result = yield from zwave.async_setup_platform( - hass, None, async_add_devices, {const.DISCOVERY_DEVICE: 456}) + hass, None, async_add_entities, {const.DISCOVERY_DEVICE: 456}) assert result - assert async_add_devices.called - assert len(async_add_devices.mock_calls) == 1 - assert async_add_devices.mock_calls[0][1][0] == [mock_device] + assert async_add_entities.called + assert len(async_add_entities.mock_calls) == 1 + assert async_add_entities.mock_calls[0][1][0] == [mock_device] @asyncio.coroutine diff --git a/tests/helpers/test_discovery.py b/tests/helpers/test_discovery.py index 8ee8d4596fe..a8d78bde1f4 100644 --- a/tests/helpers/test_discovery.py +++ b/tests/helpers/test_discovery.py @@ -123,7 +123,7 @@ class TestHelpersDiscovery: component_calls.append(1) return True - def setup_platform(hass, config, add_devices_callback, + def setup_platform(hass, config, add_entities_callback, discovery_info=None): """Set up mock platform.""" platform_calls.append('disc' if discovery_info else 'component') diff --git a/tests/helpers/test_entity_component.py b/tests/helpers/test_entity_component.py index 1ce12e0b9ad..1a0c248383b 100644 --- a/tests/helpers/test_entity_component.py +++ b/tests/helpers/test_entity_component.py @@ -143,9 +143,9 @@ class TestHelpersEntityComponent(unittest.TestCase): 'async_track_time_interval') def test_set_scan_interval_via_config(self, mock_track): """Test the setting of the scan interval via configuration.""" - def platform_setup(hass, config, add_devices, discovery_info=None): + def platform_setup(hass, config, add_entities, discovery_info=None): """Test the platform setup.""" - add_devices([MockEntity(should_poll=True)]) + add_entities([MockEntity(should_poll=True)]) loader.set_component(self.hass, 'test_domain.platform', MockPlatform(platform_setup)) @@ -165,9 +165,9 @@ class TestHelpersEntityComponent(unittest.TestCase): def test_set_entity_namespace_via_config(self): """Test setting an entity namespace.""" - def platform_setup(hass, config, add_devices, discovery_info=None): + def platform_setup(hass, config, add_entities, discovery_info=None): """Test the platform setup.""" - add_devices([ + add_entities([ MockEntity(name='beer'), MockEntity(name=None), ]) diff --git a/tests/helpers/test_entity_platform.py b/tests/helpers/test_entity_platform.py index 07901f7aad4..b51219ddbed 100644 --- a/tests/helpers/test_entity_platform.py +++ b/tests/helpers/test_entity_platform.py @@ -142,9 +142,9 @@ class TestHelpersEntityPlatform(unittest.TestCase): 'async_track_time_interval') def test_set_scan_interval_via_platform(self, mock_track): """Test the setting of the scan interval via platform.""" - def platform_setup(hass, config, add_devices, discovery_info=None): + def platform_setup(hass, config, add_entities, discovery_info=None): """Test the platform setup.""" - add_devices([MockEntity(should_poll=True)]) + add_entities([MockEntity(should_poll=True)]) platform = MockPlatform(platform_setup) platform.SCAN_INTERVAL = timedelta(seconds=30) @@ -520,9 +520,9 @@ async def test_setup_entry(hass): """Test we can setup an entry.""" registry = mock_registry(hass) - async def async_setup_entry(hass, config_entry, async_add_devices): + async def async_setup_entry(hass, config_entry, async_add_entities): """Mock setup entry method.""" - async_add_devices([ + async_add_entities([ MockEntity(name='test1', unique_id='unique') ]) return True diff --git a/tests/testing_config/custom_components/image_processing/test.py b/tests/testing_config/custom_components/image_processing/test.py index b50050ed68e..c8cdc998ea0 100644 --- a/tests/testing_config/custom_components/image_processing/test.py +++ b/tests/testing_config/custom_components/image_processing/test.py @@ -3,10 +3,10 @@ from homeassistant.components.image_processing import ImageProcessingEntity -async def async_setup_platform(hass, config, async_add_devices_callback, +async def async_setup_platform(hass, config, async_add_entities_callback, discovery_info=None): """Set up the test image_processing platform.""" - async_add_devices_callback([ + async_add_entities_callback([ TestImageProcessing('camera.demo_camera', "Test")]) diff --git a/tests/testing_config/custom_components/light/test.py b/tests/testing_config/custom_components/light/test.py index fbf79f9e770..798051ef90c 100644 --- a/tests/testing_config/custom_components/light/test.py +++ b/tests/testing_config/custom_components/light/test.py @@ -21,7 +21,7 @@ def init(empty=False): ] -async def async_setup_platform(hass, config, async_add_devices_callback, +async def async_setup_platform(hass, config, async_add_entities_callback, discovery_info=None): """Return mock devices.""" - async_add_devices_callback(DEVICES) + async_add_entities_callback(DEVICES) diff --git a/tests/testing_config/custom_components/switch/test.py b/tests/testing_config/custom_components/switch/test.py index 79126b7b52a..33d607e011b 100644 --- a/tests/testing_config/custom_components/switch/test.py +++ b/tests/testing_config/custom_components/switch/test.py @@ -21,7 +21,7 @@ def init(empty=False): ] -async def async_setup_platform(hass, config, async_add_devices_callback, +async def async_setup_platform(hass, config, async_add_entities_callback, discovery_info=None): """Find and return test switches.""" - async_add_devices_callback(DEVICES) + async_add_entities_callback(DEVICES) From 4f8fec6494b707061acd5a11a4ad40c35ab7433e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 24 Aug 2018 17:03:05 +0200 Subject: [PATCH 118/159] Bumped version to 0.77.0b0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index d72bde548d3..b11354e0064 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 77 -PATCH_VERSION = '0.dev0' +PATCH_VERSION = '0b0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From bb6567f84c7bf75f09bcc8ebaa02078a2309fc96 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 25 Aug 2018 11:15:01 +0200 Subject: [PATCH 119/159] Bump frontend to 20180825.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index bfcf7322749..c475ea55974 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180824.0'] +REQUIREMENTS = ['home-assistant-frontend==20180825.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 25480a023ec..4d0e02ac0c2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -438,7 +438,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180824.0 +home-assistant-frontend==20180825.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 71cbc724c59..8b6fc0fcd64 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -84,7 +84,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180824.0 +home-assistant-frontend==20180825.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From e567b2281d83909d5a093b84cf3731f56fd9b933 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 24 Aug 2018 19:37:22 +0200 Subject: [PATCH 120/159] deCONZ - Support device registry (#16115) Add support for device registry in deCONZ component --- .../components/binary_sensor/deconz.py | 19 ++++++- homeassistant/components/deconz/__init__.py | 11 +++- homeassistant/components/deconz/const.py | 1 + homeassistant/components/light/deconz.py | 19 ++++++- homeassistant/components/sensor/deconz.py | 35 ++++++++++++- homeassistant/components/switch/deconz.py | 19 ++++++- homeassistant/helpers/device_registry.py | 13 +++-- homeassistant/helpers/entity_platform.py | 7 ++- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/deconz/test_init.py | 50 +++++++++++++------ tests/helpers/test_device_registry.py | 20 +++++--- 12 files changed, 162 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/binary_sensor/deconz.py b/homeassistant/components/binary_sensor/deconz.py index d3d27c05333..9aa0c446f2b 100644 --- a/homeassistant/components/binary_sensor/deconz.py +++ b/homeassistant/components/binary_sensor/deconz.py @@ -7,9 +7,10 @@ https://home-assistant.io/components/binary_sensor.deconz/ from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.components.deconz.const import ( ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DATA_DECONZ, - DATA_DECONZ_ID, DATA_DECONZ_UNSUB) + DATA_DECONZ_ID, DATA_DECONZ_UNSUB, DECONZ_DOMAIN) from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.core import callback +from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect DEPENDENCIES = ['deconz'] @@ -113,3 +114,19 @@ class DeconzBinarySensor(BinarySensorDevice): if self._sensor.type in PRESENCE and self._sensor.dark is not None: attr[ATTR_DARK] = self._sensor.dark return attr + + @property + def device(self): + """Return a device description for device registry.""" + if (self._sensor.uniqueid is None or + self._sensor.uniqueid.count(':') != 7): + return None + serial = self._sensor.uniqueid.split('-', 1)[0] + return { + 'connection': [[CONNECTION_ZIGBEE, serial]], + 'identifiers': [[DECONZ_DOMAIN, serial]], + 'manufacturer': self._sensor.manufacturer, + 'model': self._sensor.modelid, + 'name': self._sensor.name, + 'sw_version': self._sensor.swversion, + } diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index cf8d891661e..d435e9e3c04 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -12,6 +12,7 @@ from homeassistant.const import ( CONF_ID, CONF_PORT, EVENT_HOMEASSISTANT_STOP) from homeassistant.core import EventOrigin, callback from homeassistant.helpers import aiohttp_client, config_validation as cv +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, async_dispatcher_send) from homeassistant.util import slugify @@ -23,7 +24,7 @@ from .const import ( CONF_ALLOW_CLIP_SENSOR, CONFIG_FILE, DATA_DECONZ_EVENT, DATA_DECONZ_ID, DATA_DECONZ_UNSUB, DOMAIN, _LOGGER) -REQUIREMENTS = ['pydeconz==43'] +REQUIREMENTS = ['pydeconz==44'] CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ @@ -119,6 +120,14 @@ async def async_setup_entry(hass, config_entry): deconz.start() + device_registry = await \ + hass.helpers.device_registry.async_get_registry() + device_registry.async_get_or_create( + connection=[[CONNECTION_NETWORK_MAC, deconz.config.mac]], + identifiers=[[DOMAIN, deconz.config.bridgeid]], + manufacturer='Dresden Elektronik', model=deconz.config.modelid, + name=deconz.config.name, sw_version=deconz.config.swversion) + async def async_configure(call): """Set attribute of device in deCONZ. diff --git a/homeassistant/components/deconz/const.py b/homeassistant/components/deconz/const.py index e7bc5605aee..e629d57f201 100644 --- a/homeassistant/components/deconz/const.py +++ b/homeassistant/components/deconz/const.py @@ -8,6 +8,7 @@ CONFIG_FILE = 'deconz.conf' DATA_DECONZ_EVENT = 'deconz_events' DATA_DECONZ_ID = 'deconz_entities' DATA_DECONZ_UNSUB = 'deconz_dispatchers' +DECONZ_DOMAIN = 'deconz' CONF_ALLOW_CLIP_SENSOR = 'allow_clip_sensor' CONF_ALLOW_DECONZ_GROUPS = 'allow_deconz_groups' diff --git a/homeassistant/components/light/deconz.py b/homeassistant/components/light/deconz.py index 6dce6b7fdb8..067f1474f96 100644 --- a/homeassistant/components/light/deconz.py +++ b/homeassistant/components/light/deconz.py @@ -6,13 +6,14 @@ https://home-assistant.io/components/light.deconz/ """ from homeassistant.components.deconz.const import ( CONF_ALLOW_DECONZ_GROUPS, DOMAIN as DATA_DECONZ, - DATA_DECONZ_ID, DATA_DECONZ_UNSUB, SWITCH_TYPES) + DATA_DECONZ_ID, DATA_DECONZ_UNSUB, DECONZ_DOMAIN, SWITCH_TYPES) from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_HS_COLOR, ATTR_TRANSITION, EFFECT_COLORLOOP, FLASH_LONG, FLASH_SHORT, SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_EFFECT, SUPPORT_FLASH, SUPPORT_TRANSITION, Light) from homeassistant.core import callback +from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect import homeassistant.util.color as color_util @@ -199,3 +200,19 @@ class DeconzLight(Light): if self._light.type == 'LightGroup': attributes['all_on'] = self._light.all_on return attributes + + @property + def device(self): + """Return a device description for device registry.""" + if (self._light.uniqueid is None or + self._light.uniqueid.count(':') != 7): + return None + serial = self._light.uniqueid.split('-', 1)[0] + return { + 'connection': [[CONNECTION_ZIGBEE, serial]], + 'identifiers': [[DECONZ_DOMAIN, serial]], + 'manufacturer': self._light.manufacturer, + 'model': self._light.modelid, + 'name': self._light.name, + 'sw_version': self._light.swversion, + } diff --git a/homeassistant/components/sensor/deconz.py b/homeassistant/components/sensor/deconz.py index a32f1e5e210..45c604a74ee 100644 --- a/homeassistant/components/sensor/deconz.py +++ b/homeassistant/components/sensor/deconz.py @@ -6,10 +6,11 @@ https://home-assistant.io/components/sensor.deconz/ """ from homeassistant.components.deconz.const import ( ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DATA_DECONZ, - DATA_DECONZ_ID, DATA_DECONZ_UNSUB) + DATA_DECONZ_ID, DATA_DECONZ_UNSUB, DECONZ_DOMAIN) from homeassistant.const import ( ATTR_BATTERY_LEVEL, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY) from homeassistant.core import callback +from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity import Entity from homeassistant.util import slugify @@ -134,6 +135,22 @@ class DeconzSensor(Entity): attr[ATTR_DAYLIGHT] = self._sensor.daylight return attr + @property + def device(self): + """Return a device description for device registry.""" + if (self._sensor.uniqueid is None or + self._sensor.uniqueid.count(':') != 7): + return None + serial = self._sensor.uniqueid.split('-', 1)[0] + return { + 'connection': [[CONNECTION_ZIGBEE, serial]], + 'identifiers': [[DECONZ_DOMAIN, serial]], + 'manufacturer': self._sensor.manufacturer, + 'model': self._sensor.modelid, + 'name': self._sensor.name, + 'sw_version': self._sensor.swversion, + } + class DeconzBattery(Entity): """Battery class for when a device is only represented as an event.""" @@ -192,3 +209,19 @@ class DeconzBattery(Entity): ATTR_EVENT_ID: slugify(self._device.name), } return attr + + @property + def device(self): + """Return a device description for device registry.""" + if (self._device.uniqueid is None or + self._device.uniqueid.count(':') != 7): + return None + serial = self._device.uniqueid.split('-', 1)[0] + return { + 'connection': [[CONNECTION_ZIGBEE, serial]], + 'identifiers': [[DECONZ_DOMAIN, serial]], + 'manufacturer': self._device.manufacturer, + 'model': self._device.modelid, + 'name': self._device.name, + 'sw_version': self._device.swversion, + } diff --git a/homeassistant/components/switch/deconz.py b/homeassistant/components/switch/deconz.py index 11f7f42c6c9..7d861e4c29c 100644 --- a/homeassistant/components/switch/deconz.py +++ b/homeassistant/components/switch/deconz.py @@ -6,9 +6,10 @@ https://home-assistant.io/components/switch.deconz/ """ from homeassistant.components.deconz.const import ( DOMAIN as DATA_DECONZ, DATA_DECONZ_ID, DATA_DECONZ_UNSUB, - POWER_PLUGS, SIRENS) + DECONZ_DOMAIN, POWER_PLUGS, SIRENS) from homeassistant.components.switch import SwitchDevice from homeassistant.core import callback +from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect DEPENDENCIES = ['deconz'] @@ -79,6 +80,22 @@ class DeconzSwitch(SwitchDevice): """No polling needed.""" return False + @property + def device(self): + """Return a device description for device registry.""" + if (self._switch.uniqueid is None or + self._switch.uniqueid.count(':') != 7): + return None + serial = self._switch.uniqueid.split('-', 1)[0] + return { + 'connection': [[CONNECTION_ZIGBEE, serial]], + 'identifiers': [[DECONZ_DOMAIN, serial]], + 'manufacturer': self._switch.manufacturer, + 'model': self._switch.modelid, + 'name': self._switch.name, + 'sw_version': self._switch.swversion, + } + class DeconzPowerPlug(DeconzSwitch): """Representation of power plugs from deCONZ.""" diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index 3276763a967..19a6eaa62dc 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -15,15 +15,18 @@ STORAGE_KEY = 'core.device_registry' STORAGE_VERSION = 1 SAVE_DELAY = 10 +CONNECTION_NETWORK_MAC = 'mac' +CONNECTION_ZIGBEE = 'zigbee' + @attr.s(slots=True, frozen=True) class DeviceEntry: """Device Registry Entry.""" + connection = attr.ib(type=list) identifiers = attr.ib(type=list) manufacturer = attr.ib(type=str) model = attr.ib(type=str) - connection = attr.ib(type=list) name = attr.ib(type=str, default=None) sw_version = attr.ib(type=str, default=None) id = attr.ib(type=str, default=attr.Factory(lambda: uuid.uuid4().hex)) @@ -48,8 +51,8 @@ class DeviceRegistry: return None @callback - def async_get_or_create(self, identifiers, manufacturer, model, - connection, *, name=None, sw_version=None): + def async_get_or_create(self, *, connection, identifiers, manufacturer, + model, name=None, sw_version=None): """Get device. Create if it doesn't exist.""" device = self.async_get_device(identifiers, connection) @@ -57,10 +60,10 @@ class DeviceRegistry: return device device = DeviceEntry( + connection=connection, identifiers=identifiers, manufacturer=manufacturer, model=model, - connection=connection, name=name, sw_version=sw_version ) @@ -93,10 +96,10 @@ class DeviceRegistry: data['devices'] = [ { 'id': entry.id, + 'connection': entry.connection, 'identifiers': entry.identifiers, 'manufacturer': entry.manufacturer, 'model': entry.model, - 'connection': entry.connection, 'name': entry.name, 'sw_version': entry.sw_version, } for entry in self.devices diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index c65aa5e98c2..ffac68c5f07 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -275,8 +275,11 @@ class EntityPlatform: device = entity.device if device is not None: device = device_registry.async_get_or_create( - device['identifiers'], device['manufacturer'], - device['model'], device['connection'], + connection=device['connection'], + identifiers=device['identifiers'], + manufacturer=device['manufacturer'], + model=device['model'], + name=device.get('name'), sw_version=device.get('sw_version')) device_id = device.id else: diff --git a/requirements_all.txt b/requirements_all.txt index 4d0e02ac0c2..a5cfe9e402a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -810,7 +810,7 @@ pycsspeechtts==1.0.2 pydaikin==0.4 # homeassistant.components.deconz -pydeconz==43 +pydeconz==44 # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8b6fc0fcd64..7b9dc1d1eb3 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -139,7 +139,7 @@ py-canary==0.5.0 pyblackbird==0.5 # homeassistant.components.deconz -pydeconz==43 +pydeconz==44 # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/tests/components/deconz/test_init.py b/tests/components/deconz/test_init.py index c6fc130a4a4..049a3b961b6 100644 --- a/tests/components/deconz/test_init.py +++ b/tests/components/deconz/test_init.py @@ -7,6 +7,16 @@ from homeassistant.components import deconz from tests.common import mock_coro +CONFIG = { + "config": { + "bridgeid": "0123456789ABCDEF", + "mac": "12:34:56:78:90:ab", + "modelid": "deCONZ", + "name": "Phoscon", + "swversion": "2.05.35" + } +} + async def test_config_with_host_passed_to_config_entry(hass): """Test that configured options for a host are loaded via config entry.""" @@ -93,8 +103,11 @@ async def test_setup_entry_successful(hass): entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'} with patch.object(hass, 'async_create_task') as mock_add_job, \ patch.object(hass, 'config_entries') as mock_config_entries, \ - patch('pydeconz.DeconzSession.async_load_parameters', - return_value=mock_coro(True)): + patch('pydeconz.DeconzSession.async_get_state', + return_value=mock_coro(CONFIG)), \ + patch('pydeconz.DeconzSession.start', return_value=True), \ + patch('homeassistant.helpers.device_registry.async_get_registry', + return_value=mock_coro(Mock())): assert await deconz.async_setup_entry(hass, entry) is True assert hass.data[deconz.DOMAIN] assert hass.data[deconz.DATA_DECONZ_ID] == {} @@ -117,10 +130,15 @@ async def test_unload_entry(hass): """Test being able to unload an entry.""" entry = Mock() entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'} - with patch('pydeconz.DeconzSession.async_load_parameters', - return_value=mock_coro(True)): + entry.async_unload.return_value = mock_coro(True) + deconzmock = Mock() + deconzmock.async_load_parameters.return_value = mock_coro(True) + deconzmock.sensors = {} + with patch('pydeconz.DeconzSession', return_value=deconzmock): assert await deconz.async_setup_entry(hass, entry) is True + assert deconz.DATA_DECONZ_EVENT in hass.data + hass.data[deconz.DATA_DECONZ_EVENT].append(Mock()) hass.data[deconz.DATA_DECONZ_ID] = {'id': 'deconzid'} assert await deconz.async_unload_entry(hass, entry) @@ -132,6 +150,9 @@ async def test_unload_entry(hass): async def test_add_new_device(hass): """Test adding a new device generates a signal for platforms.""" + entry = Mock() + entry.data = {'host': '1.2.3.4', 'port': 80, + 'api_key': '1234567890ABCDEF', 'allow_clip_sensor': False} new_event = { "t": "event", "e": "added", @@ -147,11 +168,10 @@ async def test_add_new_device(hass): "type": "ZHASwitch" } } - entry = Mock() - entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'} with patch.object(deconz, 'async_dispatcher_send') as mock_dispatch_send, \ - patch('pydeconz.DeconzSession.async_load_parameters', - return_value=mock_coro(True)): + patch('pydeconz.DeconzSession.async_get_state', + return_value=mock_coro(CONFIG)), \ + patch('pydeconz.DeconzSession.start', return_value=True): assert await deconz.async_setup_entry(hass, entry) is True hass.data[deconz.DOMAIN].async_event_handler(new_event) await hass.async_block_till_done() @@ -162,15 +182,16 @@ async def test_add_new_device(hass): async def test_add_new_remote(hass): """Test new added device creates a new remote.""" entry = Mock() - entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'} + entry.data = {'host': '1.2.3.4', 'port': 80, + 'api_key': '1234567890ABCDEF', 'allow_clip_sensor': False} remote = Mock() remote.name = 'name' remote.type = 'ZHASwitch' remote.register_async_callback = Mock() - with patch('pydeconz.DeconzSession.async_load_parameters', - return_value=mock_coro(True)): + with patch('pydeconz.DeconzSession.async_get_state', + return_value=mock_coro(CONFIG)), \ + patch('pydeconz.DeconzSession.start', return_value=True): assert await deconz.async_setup_entry(hass, entry) is True - async_dispatcher_send(hass, 'deconz_new_sensor', [remote]) await hass.async_block_till_done() assert len(hass.data[deconz.DATA_DECONZ_EVENT]) == 1 @@ -185,8 +206,9 @@ async def test_do_not_allow_clip_sensor(hass): remote.name = 'name' remote.type = 'CLIPSwitch' remote.register_async_callback = Mock() - with patch('pydeconz.DeconzSession.async_load_parameters', - return_value=mock_coro(True)): + with patch('pydeconz.DeconzSession.async_get_state', + return_value=mock_coro(CONFIG)), \ + patch('pydeconz.DeconzSession.start', return_value=True): assert await deconz.async_setup_entry(hass, entry) is True async_dispatcher_send(hass, 'deconz_new_sensor', [remote]) diff --git a/tests/helpers/test_device_registry.py b/tests/helpers/test_device_registry.py index 41e7d39e977..f7792eb5250 100644 --- a/tests/helpers/test_device_registry.py +++ b/tests/helpers/test_device_registry.py @@ -26,14 +26,17 @@ def registry(hass): async def test_get_or_create_returns_same_entry(registry): """Make sure we do not duplicate entries.""" entry = registry.async_get_or_create( - [['bridgeid', '0123']], 'manufacturer', 'model', - [['ethernet', '12:34:56:78:90:AB:CD:EF']]) + connection=[['ethernet', '12:34:56:78:90:AB:CD:EF']], + identifiers=[['bridgeid', '0123']], + manufacturer='manufacturer', model='model') entry2 = registry.async_get_or_create( - [['bridgeid', '0123']], 'manufacturer', 'model', - [['ethernet', '11:22:33:44:55:66:77:88']]) + connection=[['ethernet', '11:22:33:44:55:66:77:88']], + identifiers=[['bridgeid', '0123']], + manufacturer='manufacturer', model='model') entry3 = registry.async_get_or_create( - [['bridgeid', '1234']], 'manufacturer', 'model', - [['ethernet', '12:34:56:78:90:AB:CD:EF']]) + connection=[['ethernet', '12:34:56:78:90:AB:CD:EF']], + identifiers=[['bridgeid', '1234']], + manufacturer='manufacturer', model='model') assert len(registry.devices) == 1 assert entry is entry2 @@ -73,6 +76,7 @@ async def test_loading_from_storage(hass, hass_storage): registry = await device_registry.async_get_registry(hass) entry = registry.async_get_or_create( - [['serial', '12:34:56:78:90:AB:CD:EF']], 'manufacturer', - 'model', [['Zigbee', '01.23.45.67.89']]) + connection=[['Zigbee', '01.23.45.67.89']], + identifiers=[['serial', '12:34:56:78:90:AB:CD:EF']], + manufacturer='manufacturer', model='model') assert entry.id == 'abcdefghijklm' From 914d90a2bc8d4ad2f7f457c4976dcd9053f8f912 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Fri, 24 Aug 2018 10:17:43 -0700 Subject: [PATCH 121/159] Add multi-factor auth module setup flow (#16141) * Add mfa setup flow * Lint * Address code review comment * Fix unit test * Add assertion for WS response ordering * Missed a return * Remove setup_schema from MFA base class * Move auth.util.validate_current_user -> webscoket_api.ws_require_user --- homeassistant/auth/__init__.py | 9 -- homeassistant/auth/mfa_modules/__init__.py | 49 ++++++- .../auth/mfa_modules/insecure_example.py | 15 +- homeassistant/components/auth/__init__.py | 40 ++++-- .../components/auth/mfa_setup_flow.py | 134 ++++++++++++++++++ homeassistant/components/websocket_api.py | 58 +++++++- .../auth/mfa_modules/test_insecure_example.py | 18 +++ tests/components/auth/test_mfa_setup_flow.py | 99 +++++++++++++ 8 files changed, 386 insertions(+), 36 deletions(-) create mode 100644 homeassistant/components/auth/mfa_setup_flow.py create mode 100644 tests/components/auth/test_mfa_setup_flow.py diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index b5ba869cdf1..e0b7b377b1f 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -6,8 +6,6 @@ from typing import Any, Dict, List, Optional, Tuple, cast import jwt -import voluptuous as vol - from homeassistant import data_entry_flow from homeassistant.core import callback, HomeAssistant from homeassistant.util import dt as dt_util @@ -235,13 +233,6 @@ class AuthManager: raise ValueError('Unable find multi-factor auth module: {}' .format(mfa_module_id)) - if module.setup_schema is not None: - try: - # pylint: disable=not-callable - data = module.setup_schema(data) - except vol.Invalid as err: - raise ValueError('Data does not match schema: {}'.format(err)) - await module.async_setup_user(user.id, data) async def async_disable_user_mfa(self, user: models.User, diff --git a/homeassistant/auth/mfa_modules/__init__.py b/homeassistant/auth/mfa_modules/__init__.py index d0707c4a745..cb0758e3ef8 100644 --- a/homeassistant/auth/mfa_modules/__init__.py +++ b/homeassistant/auth/mfa_modules/__init__.py @@ -8,7 +8,7 @@ from typing import Any, Dict, Optional import voluptuous as vol from voluptuous.humanize import humanize_error -from homeassistant import requirements +from homeassistant import requirements, data_entry_flow from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE from homeassistant.core import HomeAssistant from homeassistant.util.decorator import Registry @@ -64,15 +64,14 @@ class MultiFactorAuthModule: """Return a voluptuous schema to define mfa auth module's input.""" raise NotImplementedError - @property - def setup_schema(self) -> Optional[vol.Schema]: - """Return a vol schema to validate mfa auth module's setup input. + async def async_setup_flow(self, user_id: str) -> 'SetupFlow': + """Return a data entry flow handler for setup module. - Optional + Mfa module should extend SetupFlow """ - return None + raise NotImplementedError - async def async_setup_user(self, user_id: str, setup_data: Any) -> None: + async def async_setup_user(self, user_id: str, setup_data: Any) -> Any: """Set up user for mfa auth module.""" raise NotImplementedError @@ -90,6 +89,42 @@ class MultiFactorAuthModule: raise NotImplementedError +class SetupFlow(data_entry_flow.FlowHandler): + """Handler for the setup flow.""" + + def __init__(self, auth_module: MultiFactorAuthModule, + setup_schema: vol.Schema, + user_id: str) -> None: + """Initialize the setup flow.""" + self._auth_module = auth_module + self._setup_schema = setup_schema + self._user_id = user_id + + async def async_step_init( + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: + """Handle the first step of setup flow. + + Return self.async_show_form(step_id='init') if user_input == None. + Return self.async_create_entry(data={'result': result}) if finish. + """ + errors = {} # type: Dict[str, str] + + if user_input: + result = await self._auth_module.async_setup_user( + self._user_id, user_input) + return self.async_create_entry( + title=self._auth_module.name, + data={'result': result} + ) + + return self.async_show_form( + step_id='init', + data_schema=self._setup_schema, + errors=errors + ) + + async def auth_mfa_module_from_config( hass: HomeAssistant, config: Dict[str, Any]) \ -> Optional[MultiFactorAuthModule]: diff --git a/homeassistant/auth/mfa_modules/insecure_example.py b/homeassistant/auth/mfa_modules/insecure_example.py index 59b3f64d2e0..9c72111ef96 100644 --- a/homeassistant/auth/mfa_modules/insecure_example.py +++ b/homeassistant/auth/mfa_modules/insecure_example.py @@ -1,13 +1,13 @@ """Example auth module.""" import logging -from typing import Any, Dict, Optional +from typing import Any, Dict import voluptuous as vol from homeassistant.core import HomeAssistant from . import MultiFactorAuthModule, MULTI_FACTOR_AUTH_MODULES, \ - MULTI_FACTOR_AUTH_MODULE_SCHEMA + MULTI_FACTOR_AUTH_MODULE_SCHEMA, SetupFlow CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({ vol.Required('data'): [vol.Schema({ @@ -36,11 +36,18 @@ class InsecureExampleModule(MultiFactorAuthModule): return vol.Schema({'pin': str}) @property - def setup_schema(self) -> Optional[vol.Schema]: + def setup_schema(self) -> vol.Schema: """Validate async_setup_user input data.""" return vol.Schema({'pin': str}) - async def async_setup_user(self, user_id: str, setup_data: Any) -> None: + async def async_setup_flow(self, user_id: str) -> SetupFlow: + """Return a data entry flow handler for setup module. + + Mfa module should extend SetupFlow + """ + return SetupFlow(self, self.setup_schema, user_id) + + async def async_setup_user(self, user_id: str, setup_data: Any) -> Any: """Set up user to use mfa module.""" # data shall has been validate in caller pin = setup_data['pin'] diff --git a/homeassistant/components/auth/__init__.py b/homeassistant/components/auth/__init__.py index 4251b23e514..a87e646761c 100644 --- a/homeassistant/components/auth/__init__.py +++ b/homeassistant/components/auth/__init__.py @@ -68,10 +68,12 @@ from homeassistant.components import websocket_api from homeassistant.components.http.ban import log_invalid_auth from homeassistant.components.http.data_validator import RequestDataValidator from homeassistant.components.http.view import HomeAssistantView -from homeassistant.core import callback +from homeassistant.core import callback, HomeAssistant from homeassistant.util import dt as dt_util + from . import indieauth from . import login_flow +from . import mfa_setup_flow DOMAIN = 'auth' DEPENDENCIES = ['http'] @@ -100,6 +102,7 @@ async def async_setup(hass, config): ) await login_flow.async_setup(hass, store_result) + await mfa_setup_flow.async_setup(hass) return True @@ -315,21 +318,28 @@ def _create_auth_code_store(): return store_result, retrieve_result +@websocket_api.ws_require_user() @callback -def websocket_current_user(hass, connection, msg): +def websocket_current_user( + hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): """Return the current user.""" - user = connection.request.get('hass_user') + async def async_get_current_user(user): + """Get current user.""" + enabled_modules = await hass.auth.async_get_enabled_mfa(user) - if user is None: - connection.to_write.put_nowait(websocket_api.error_message( - msg['id'], 'no_user', 'Not authenticated as a user')) - return + connection.send_message_outside( + websocket_api.result_message(msg['id'], { + 'id': user.id, + 'name': user.name, + 'is_owner': user.is_owner, + 'credentials': [{'auth_provider_type': c.auth_provider_type, + 'auth_provider_id': c.auth_provider_id} + for c in user.credentials], + 'mfa_modules': [{ + 'id': module.id, + 'name': module.name, + 'enabled': module.id in enabled_modules, + } for module in hass.auth.auth_mfa_modules], + })) - connection.to_write.put_nowait(websocket_api.result_message(msg['id'], { - 'id': user.id, - 'name': user.name, - 'is_owner': user.is_owner, - 'credentials': [{'auth_provider_type': c.auth_provider_type, - 'auth_provider_id': c.auth_provider_id} - for c in user.credentials] - })) + hass.async_create_task(async_get_current_user(connection.user)) diff --git a/homeassistant/components/auth/mfa_setup_flow.py b/homeassistant/components/auth/mfa_setup_flow.py new file mode 100644 index 00000000000..82eb913d890 --- /dev/null +++ b/homeassistant/components/auth/mfa_setup_flow.py @@ -0,0 +1,134 @@ +"""Helpers to setup multi-factor auth module.""" +import logging + +import voluptuous as vol + +from homeassistant import data_entry_flow +from homeassistant.components import websocket_api +from homeassistant.core import callback, HomeAssistant + +WS_TYPE_SETUP_MFA = 'auth/setup_mfa' +SCHEMA_WS_SETUP_MFA = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ + vol.Required('type'): WS_TYPE_SETUP_MFA, + vol.Exclusive('mfa_module_id', 'module_or_flow_id'): str, + vol.Exclusive('flow_id', 'module_or_flow_id'): str, + vol.Optional('user_input'): object, +}) + +WS_TYPE_DEPOSE_MFA = 'auth/depose_mfa' +SCHEMA_WS_DEPOSE_MFA = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ + vol.Required('type'): WS_TYPE_DEPOSE_MFA, + vol.Required('mfa_module_id'): str, +}) + +DATA_SETUP_FLOW_MGR = 'auth_mfa_setup_flow_manager' + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup(hass): + """Init mfa setup flow manager.""" + async def _async_create_setup_flow(handler, context, data): + """Create a setup flow. hanlder is a mfa module.""" + mfa_module = hass.auth.get_auth_mfa_module(handler) + if mfa_module is None: + raise ValueError('Mfa module {} is not found'.format(handler)) + + user_id = data.pop('user_id') + return await mfa_module.async_setup_flow(user_id) + + async def _async_finish_setup_flow(flow, flow_result): + _LOGGER.debug('flow_result: %s', flow_result) + return flow_result + + hass.data[DATA_SETUP_FLOW_MGR] = data_entry_flow.FlowManager( + hass, _async_create_setup_flow, _async_finish_setup_flow) + + hass.components.websocket_api.async_register_command( + WS_TYPE_SETUP_MFA, websocket_setup_mfa, SCHEMA_WS_SETUP_MFA) + + hass.components.websocket_api.async_register_command( + WS_TYPE_DEPOSE_MFA, websocket_depose_mfa, SCHEMA_WS_DEPOSE_MFA) + + +@callback +@websocket_api.ws_require_user(allow_system_user=False) +def websocket_setup_mfa( + hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): + """Return a setup flow for mfa auth module.""" + async def async_setup_flow(msg): + """Return a setup flow for mfa auth module.""" + flow_manager = hass.data[DATA_SETUP_FLOW_MGR] + + flow_id = msg.get('flow_id') + if flow_id is not None: + result = await flow_manager.async_configure( + flow_id, msg.get('user_input')) + connection.send_message_outside( + websocket_api.result_message( + msg['id'], _prepare_result_json(result))) + return + + mfa_module_id = msg.get('mfa_module_id') + mfa_module = hass.auth.get_auth_mfa_module(mfa_module_id) + if mfa_module is None: + connection.send_message_outside(websocket_api.error_message( + msg['id'], 'no_module', + 'MFA module {} is not found'.format(mfa_module_id))) + return + + result = await flow_manager.async_init( + mfa_module_id, data={'user_id': connection.user.id}) + + connection.send_message_outside( + websocket_api.result_message( + msg['id'], _prepare_result_json(result))) + + hass.async_create_task(async_setup_flow(msg)) + + +@callback +@websocket_api.ws_require_user(allow_system_user=False) +def websocket_depose_mfa( + hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg): + """Remove user from mfa module.""" + async def async_depose(msg): + """Remove user from mfa auth module.""" + mfa_module_id = msg['mfa_module_id'] + try: + await hass.auth.async_disable_user_mfa( + connection.user, msg['mfa_module_id']) + except ValueError as err: + connection.send_message_outside(websocket_api.error_message( + msg['id'], 'disable_failed', + 'Cannot disable MFA Module {}: {}'.format( + mfa_module_id, err))) + return + + connection.send_message_outside( + websocket_api.result_message( + msg['id'], 'done')) + + hass.async_create_task(async_depose(msg)) + + +def _prepare_result_json(result): + """Convert result to JSON.""" + if result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY: + data = result.copy() + return data + + if result['type'] != data_entry_flow.RESULT_TYPE_FORM: + return result + + import voluptuous_serialize + + data = result.copy() + + schema = data['data_schema'] + if schema is None: + data['data_schema'] = [] + else: + data['data_schema'] = voluptuous_serialize.convert(schema) + + return data diff --git a/homeassistant/components/websocket_api.py b/homeassistant/components/websocket_api.py index 1ba0e20d553..0c9ab366534 100644 --- a/homeassistant/components/websocket_api.py +++ b/homeassistant/components/websocket_api.py @@ -18,7 +18,7 @@ from voluptuous.humanize import humanize_error from homeassistant.const import ( MATCH_ALL, EVENT_TIME_CHANGED, EVENT_HOMEASSISTANT_STOP, __version__) -from homeassistant.core import Context, callback +from homeassistant.core import Context, callback, HomeAssistant from homeassistant.loader import bind_hass from homeassistant.helpers.json import JSONEncoder from homeassistant.helpers import config_validation as cv @@ -576,3 +576,59 @@ def handle_ping(hass, connection, msg): Async friendly. """ connection.to_write.put_nowait(pong_message(msg['id'])) + + +def ws_require_user( + only_owner=False, only_system_user=False, allow_system_user=True, + only_active_user=True, only_inactive_user=False): + """Decorate function validating login user exist in current WS connection. + + Will write out error message if not authenticated. + """ + def validator(func): + """Decorate func.""" + @wraps(func) + def check_current_user(hass: HomeAssistant, + connection: ActiveConnection, + msg): + """Check current user.""" + def output_error(message_id, message): + """Output error message.""" + connection.send_message_outside(error_message( + msg['id'], message_id, message)) + + if connection.user is None: + output_error('no_user', 'Not authenticated as a user') + return + + if only_owner and not connection.user.is_owner: + output_error('only_owner', 'Only allowed as owner') + return + + if (only_system_user and + not connection.user.system_generated): + output_error('only_system_user', + 'Only allowed as system user') + return + + if (not allow_system_user + and connection.user.system_generated): + output_error('not_system_user', 'Not allowed as system user') + return + + if (only_active_user and + not connection.user.is_active): + output_error('only_active_user', + 'Only allowed as active user') + return + + if only_inactive_user and connection.user.is_active: + output_error('only_inactive_user', + 'Not allowed as active user') + return + + return func(hass, connection, msg) + + return check_current_user + + return validator diff --git a/tests/auth/mfa_modules/test_insecure_example.py b/tests/auth/mfa_modules/test_insecure_example.py index 9d90532728a..e6f83762cd7 100644 --- a/tests/auth/mfa_modules/test_insecure_example.py +++ b/tests/auth/mfa_modules/test_insecure_example.py @@ -125,3 +125,21 @@ async def test_login(hass): result['flow_id'], {'pin': '123456'}) assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result['data'].id == 'mock-user' + + +async def test_setup_flow(hass): + """Test validating pin.""" + auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'insecure_example', + 'data': [{'user_id': 'test-user', 'pin': '123456'}] + }) + + flow = await auth_module.async_setup_flow('new-user') + + result = await flow.async_step_init() + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + + result = await flow.async_step_init({'pin': 'abcdefg'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert auth_module._data[1]['user_id'] == 'new-user' + assert auth_module._data[1]['pin'] == 'abcdefg' diff --git a/tests/components/auth/test_mfa_setup_flow.py b/tests/components/auth/test_mfa_setup_flow.py new file mode 100644 index 00000000000..93b5cdf7bb9 --- /dev/null +++ b/tests/components/auth/test_mfa_setup_flow.py @@ -0,0 +1,99 @@ +"""Tests for the mfa setup flow.""" +from homeassistant import data_entry_flow +from homeassistant.auth import auth_manager_from_config +from homeassistant.components.auth import mfa_setup_flow +from homeassistant.setup import async_setup_component + +from tests.common import MockUser, CLIENT_ID, ensure_auth_manager_loaded + + +async def test_ws_setup_depose_mfa(hass, hass_ws_client): + """Test set up mfa module for current user.""" + hass.auth = await auth_manager_from_config( + hass, provider_configs=[{ + 'type': 'insecure_example', + 'users': [{ + 'username': 'test-user', + 'password': 'test-pass', + 'name': 'Test Name', + }] + }], module_configs=[{ + 'type': 'insecure_example', + 'id': 'example_module', + 'data': [{'user_id': 'mock-user', 'pin': '123456'}] + }]) + ensure_auth_manager_loaded(hass.auth) + await async_setup_component(hass, 'auth', {'http': {}}) + + user = MockUser(id='mock-user').add_to_hass(hass) + cred = await hass.auth.auth_providers[0].async_get_or_create_credentials( + {'username': 'test-user'}) + await hass.auth.async_link_user(user, cred) + refresh_token = await hass.auth.async_create_refresh_token(user, CLIENT_ID) + access_token = hass.auth.async_create_access_token(refresh_token) + + client = await hass_ws_client(hass, access_token) + + await client.send_json({ + 'id': 10, + 'type': mfa_setup_flow.WS_TYPE_SETUP_MFA, + }) + + result = await client.receive_json() + assert result['id'] == 10 + assert result['success'] is False + assert result['error']['code'] == 'no_module' + + await client.send_json({ + 'id': 11, + 'type': mfa_setup_flow.WS_TYPE_SETUP_MFA, + 'mfa_module_id': 'example_module', + }) + + result = await client.receive_json() + assert result['id'] == 11 + assert result['success'] + + flow = result['result'] + assert flow['type'] == data_entry_flow.RESULT_TYPE_FORM + assert flow['handler'] == 'example_module' + assert flow['step_id'] == 'init' + assert flow['data_schema'][0] == {'type': 'string', 'name': 'pin'} + + await client.send_json({ + 'id': 12, + 'type': mfa_setup_flow.WS_TYPE_SETUP_MFA, + 'flow_id': flow['flow_id'], + 'user_input': {'pin': '654321'}, + }) + + result = await client.receive_json() + assert result['id'] == 12 + assert result['success'] + + flow = result['result'] + assert flow['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert flow['handler'] == 'example_module' + assert flow['data']['result'] is None + + await client.send_json({ + 'id': 13, + 'type': mfa_setup_flow.WS_TYPE_DEPOSE_MFA, + 'mfa_module_id': 'invalid_id', + }) + + result = await client.receive_json() + assert result['id'] == 13 + assert result['success'] is False + assert result['error']['code'] == 'disable_failed' + + await client.send_json({ + 'id': 14, + 'type': mfa_setup_flow.WS_TYPE_DEPOSE_MFA, + 'mfa_module_id': 'example_module', + }) + + result = await client.receive_json() + assert result['id'] == 14 + assert result['success'] + assert result['result'] == 'done' From 90b2257347f8736450a6fef780c573dec3e125c0 Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Fri, 24 Aug 2018 17:29:25 -0400 Subject: [PATCH 122/159] Decouple Konnected entity setup from discovery (#16146) * decouple entity setup from discovery * validate that device_id is a full MAC address --- homeassistant/components/konnected.py | 151 ++++++++++--------- homeassistant/components/switch/konnected.py | 17 ++- 2 files changed, 94 insertions(+), 74 deletions(-) diff --git a/homeassistant/components/konnected.py b/homeassistant/components/konnected.py index 9e85e85818d..3df28586313 100644 --- a/homeassistant/components/konnected.py +++ b/homeassistant/components/konnected.py @@ -16,7 +16,7 @@ from homeassistant.components.binary_sensor import DEVICE_CLASSES_SCHEMA from homeassistant.components.discovery import SERVICE_KONNECTED from homeassistant.components.http import HomeAssistantView from homeassistant.const import ( - HTTP_BAD_REQUEST, HTTP_INTERNAL_SERVER_ERROR, HTTP_UNAUTHORIZED, + HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_UNAUTHORIZED, CONF_DEVICES, CONF_BINARY_SENSORS, CONF_SWITCHES, CONF_HOST, CONF_PORT, CONF_ID, CONF_NAME, CONF_TYPE, CONF_PIN, CONF_ZONE, CONF_ACCESS_TOKEN, ATTR_ENTITY_ID, ATTR_STATE) @@ -74,7 +74,7 @@ CONFIG_SCHEMA = vol.Schema( vol.Required(CONF_ACCESS_TOKEN): cv.string, vol.Optional(CONF_API_HOST): vol.Url(), vol.Required(CONF_DEVICES): [{ - vol.Required(CONF_ID): cv.string, + vol.Required(CONF_ID): cv.matches_regex("[0-9a-f]{12}"), vol.Optional(CONF_BINARY_SENSORS): vol.All( cv.ensure_list, [_BINARY_SENSOR_SCHEMA]), vol.Optional(CONF_SWITCHES): vol.All( @@ -107,12 +107,18 @@ async def async_setup(hass, config): def device_discovered(service, info): """Call when a Konnected device has been discovered.""" - _LOGGER.debug("Discovered a new Konnected device: %s", info) host = info.get(CONF_HOST) port = info.get(CONF_PORT) + discovered = DiscoveredDevice(hass, host, port) + if discovered.is_configured: + discovered.setup() + else: + _LOGGER.warning("Konnected device %s was discovered on the network" + " but not specified in configuration.yaml", + discovered.device_id) - device = KonnectedDevice(hass, host, port, cfg) - device.setup() + for device in cfg.get(CONF_DEVICES): + ConfiguredDevice(hass, device).save_data() discovery.async_listen( hass, @@ -124,98 +130,51 @@ async def async_setup(hass, config): return True -class KonnectedDevice: - """A representation of a single Konnected device.""" +class ConfiguredDevice: + """A representation of a configured Konnected device.""" - def __init__(self, hass, host, port, config): + def __init__(self, hass, config): """Initialize the Konnected device.""" self.hass = hass - self.host = host - self.port = port - self.user_config = config - - import konnected - self.client = konnected.Client(host, str(port)) - self.status = self.client.get_status() - _LOGGER.info('Initialized Konnected device %s', self.device_id) - - def setup(self): - """Set up a newly discovered Konnected device.""" - user_config = self.config() - if user_config: - _LOGGER.debug('Configuring Konnected device %s', self.device_id) - self.save_data() - self.sync_device_config() - discovery.load_platform( - self.hass, 'binary_sensor', - DOMAIN, {'device_id': self.device_id}) - discovery.load_platform( - self.hass, 'switch', DOMAIN, - {'device_id': self.device_id}) + self.config = config @property def device_id(self): """Device id is the MAC address as string with punctuation removed.""" - return self.status['mac'].replace(':', '') - - def config(self): - """Return an object representing the user defined configuration.""" - device_id = self.device_id - valid_keys = [device_id, device_id.upper(), - device_id[6:], device_id.upper()[6:]] - configured_devices = self.user_config[CONF_DEVICES] - return next((device for device in - configured_devices if device[CONF_ID] in valid_keys), - None) + return self.config.get(CONF_ID) def save_data(self): """Save the device configuration to `hass.data`.""" sensors = {} - for entity in self.config().get(CONF_BINARY_SENSORS) or []: + for entity in self.config.get(CONF_BINARY_SENSORS) or []: if CONF_ZONE in entity: pin = ZONE_TO_PIN[entity[CONF_ZONE]] else: pin = entity[CONF_PIN] - sensor_status = next((sensor for sensor in - self.status.get('sensors') if - sensor.get(CONF_PIN) == pin), {}) - if sensor_status.get(ATTR_STATE): - initial_state = bool(int(sensor_status.get(ATTR_STATE))) - else: - initial_state = None - sensors[pin] = { CONF_TYPE: entity[CONF_TYPE], CONF_NAME: entity.get(CONF_NAME, 'Konnected {} Zone {}'.format( self.device_id[6:], PIN_TO_ZONE[pin])), - ATTR_STATE: initial_state + ATTR_STATE: None } _LOGGER.debug('Set up sensor %s (initial state: %s)', sensors[pin].get('name'), sensors[pin].get(ATTR_STATE)) actuators = [] - for entity in self.config().get(CONF_SWITCHES) or []: + for entity in self.config.get(CONF_SWITCHES) or []: if 'zone' in entity: pin = ZONE_TO_PIN[entity['zone']] else: pin = entity['pin'] - actuator_status = next((actuator for actuator in - self.status.get('actuators') if - actuator.get('pin') == pin), {}) - if actuator_status.get(ATTR_STATE): - initial_state = bool(int(actuator_status.get(ATTR_STATE))) - else: - initial_state = None - act = { CONF_PIN: pin, CONF_NAME: entity.get( CONF_NAME, 'Konnected {} Actuator {}'.format( self.device_id[6:], PIN_TO_ZONE[pin])), - ATTR_STATE: initial_state, + ATTR_STATE: None, CONF_ACTIVATION: entity[CONF_ACTIVATION], CONF_MOMENTARY: entity.get(CONF_MOMENTARY), CONF_PAUSE: entity.get(CONF_PAUSE), @@ -224,23 +183,67 @@ class KonnectedDevice: _LOGGER.debug('Set up actuator %s', act) device_data = { - 'client': self.client, CONF_BINARY_SENSORS: sensors, CONF_SWITCHES: actuators, - CONF_HOST: self.host, - CONF_PORT: self.port, } if CONF_DEVICES not in self.hass.data[DOMAIN]: self.hass.data[DOMAIN][CONF_DEVICES] = {} - _LOGGER.debug('Storing data in hass.data[konnected]: %s', device_data) + _LOGGER.debug('Storing data in hass.data[%s][%s][%s]: %s', + DOMAIN, CONF_DEVICES, self.device_id, device_data) self.hass.data[DOMAIN][CONF_DEVICES][self.device_id] = device_data + discovery.load_platform( + self.hass, 'binary_sensor', + DOMAIN, {'device_id': self.device_id}) + discovery.load_platform( + self.hass, 'switch', DOMAIN, + {'device_id': self.device_id}) + + +class DiscoveredDevice: + """A representation of a discovered Konnected device.""" + + def __init__(self, hass, host, port): + """Initialize the Konnected device.""" + self.hass = hass + self.host = host + self.port = port + + import konnected + self.client = konnected.Client(host, str(port)) + self.status = self.client.get_status() + + def setup(self): + """Set up a newly discovered Konnected device.""" + _LOGGER.info('Discovered Konnected device %s. Open http://%s:%s in a ' + 'web browser to view device status.', + self.device_id, self.host, self.port) + self.save_data() + self.update_initial_states() + self.sync_device_config() + + def save_data(self): + """Save the discovery information to `hass.data`.""" + self.stored_configuration['client'] = self.client + self.stored_configuration['host'] = self.host + self.stored_configuration['port'] = self.port + + @property + def device_id(self): + """Device id is the MAC address as string with punctuation removed.""" + return self.status['mac'].replace(':', '') + + @property + def is_configured(self): + """Return true if device_id is specified in the configuration.""" + return bool(self.hass.data[DOMAIN][CONF_DEVICES].get(self.device_id)) + @property def stored_configuration(self): """Return the configuration stored in `hass.data` for this device.""" - return self.hass.data[DOMAIN][CONF_DEVICES][self.device_id] + return self.hass.data[DOMAIN][CONF_DEVICES].get(self.device_id) def sensor_configuration(self): """Return the configuration map for syncing sensors.""" @@ -254,6 +257,18 @@ class KonnectedDevice: else 1)} for data in self.stored_configuration[CONF_SWITCHES]] + def update_initial_states(self): + """Update the initial state of each sensor from status poll.""" + for sensor in self.status.get('sensors'): + entity_id = self.stored_configuration[CONF_BINARY_SENSORS]. \ + get(sensor.get(CONF_PIN), {}). \ + get(ATTR_ENTITY_ID) + + async_dispatcher_send( + self.hass, + SIGNAL_SENSOR_UPDATE.format(entity_id), + bool(sensor.get(ATTR_STATE))) + def sync_device_config(self): """Sync the new pin configuration to the Konnected device.""" desired_sensor_configuration = self.sensor_configuration() @@ -285,7 +300,7 @@ class KonnectedDevice: if (desired_sensor_configuration != current_sensor_configuration) or \ (current_actuator_config != desired_actuator_config) or \ (current_api_endpoint != desired_api_endpoint): - _LOGGER.debug('pushing settings to device %s', self.device_id) + _LOGGER.info('pushing settings to device %s', self.device_id) self.client.put_settings( desired_sensor_configuration, desired_actuator_config, @@ -340,7 +355,7 @@ class KonnectedView(HomeAssistantView): entity_id = pin_data.get(ATTR_ENTITY_ID) if entity_id is None: return self.json_message('uninitialized sensor/actuator', - status_code=HTTP_INTERNAL_SERVER_ERROR) + status_code=HTTP_NOT_FOUND) async_dispatcher_send( hass, SIGNAL_SENSOR_UPDATE.format(entity_id), state) diff --git a/homeassistant/components/switch/konnected.py b/homeassistant/components/switch/konnected.py index c085d0bb0a5..20774accbd5 100644 --- a/homeassistant/components/switch/konnected.py +++ b/homeassistant/components/switch/konnected.py @@ -27,9 +27,8 @@ async def async_setup_platform(hass, config, async_add_entities, data = hass.data[KONNECTED_DOMAIN] device_id = discovery_info['device_id'] - client = data[CONF_DEVICES][device_id]['client'] switches = [ - KonnectedSwitch(device_id, pin_data.get(CONF_PIN), pin_data, client) + KonnectedSwitch(device_id, pin_data.get(CONF_PIN), pin_data) for pin_data in data[CONF_DEVICES][device_id][CONF_SWITCHES]] async_add_entities(switches) @@ -37,7 +36,7 @@ async def async_setup_platform(hass, config, async_add_entities, class KonnectedSwitch(ToggleEntity): """Representation of a Konnected switch.""" - def __init__(self, device_id, pin_num, data, client): + def __init__(self, device_id, pin_num, data): """Initialize the switch.""" self._data = data self._device_id = device_id @@ -50,7 +49,6 @@ class KonnectedSwitch(ToggleEntity): self._name = self._data.get( 'name', 'Konnected {} Actuator {}'.format( device_id, PIN_TO_ZONE[pin_num])) - self._client = client _LOGGER.debug('Created new switch: %s', self._name) @property @@ -63,9 +61,16 @@ class KonnectedSwitch(ToggleEntity): """Return the status of the sensor.""" return self._state + @property + def client(self): + """Return the Konnected HTTP client.""" + return \ + self.hass.data[KONNECTED_DOMAIN][CONF_DEVICES][self._device_id].\ + get('client') + def turn_on(self, **kwargs): """Send a command to turn on the switch.""" - resp = self._client.put_device( + resp = self.client.put_device( self._pin_num, int(self._activation == STATE_HIGH), self._momentary, @@ -82,7 +87,7 @@ class KonnectedSwitch(ToggleEntity): def turn_off(self, **kwargs): """Send a command to turn off the switch.""" - resp = self._client.put_device( + resp = self.client.put_device( self._pin_num, int(self._activation == STATE_LOW)) if resp.get(ATTR_STATE) is not None: From cf8bd92d4d1ab1e2a619c034f4327662a442673c Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sat, 25 Aug 2018 10:59:28 +0200 Subject: [PATCH 123/159] Device registry store config entry (#16152) * Allow device registry to optionally store config entries * Connections and identifiers are now sets with tupels * Make config entries mandatory * Fix duplicate keys in test * Rename device to device_info * Entity platform should only create device entries if config_entry_id exists * Fix Soundtouch tests * Revert soundtouch to use self.device * Fix baloobs comments * Correct type in test --- .../components/binary_sensor/deconz.py | 6 +- homeassistant/components/deconz/__init__.py | 5 +- homeassistant/components/light/deconz.py | 6 +- homeassistant/components/media_player/roku.py | 12 +-- .../components/media_player/soundtouch.py | 17 ++-- homeassistant/components/sensor/deconz.py | 12 +-- homeassistant/components/switch/deconz.py | 6 +- homeassistant/helpers/device_registry.py | 42 +++++++--- homeassistant/helpers/entity.py | 2 +- homeassistant/helpers/entity_platform.py | 17 ++-- tests/helpers/test_device_registry.py | 78 ++++++++++++++++--- 11 files changed, 142 insertions(+), 61 deletions(-) diff --git a/homeassistant/components/binary_sensor/deconz.py b/homeassistant/components/binary_sensor/deconz.py index 9aa0c446f2b..1fb62124407 100644 --- a/homeassistant/components/binary_sensor/deconz.py +++ b/homeassistant/components/binary_sensor/deconz.py @@ -116,15 +116,15 @@ class DeconzBinarySensor(BinarySensorDevice): return attr @property - def device(self): + def device_info(self): """Return a device description for device registry.""" if (self._sensor.uniqueid is None or self._sensor.uniqueid.count(':') != 7): return None serial = self._sensor.uniqueid.split('-', 1)[0] return { - 'connection': [[CONNECTION_ZIGBEE, serial]], - 'identifiers': [[DECONZ_DOMAIN, serial]], + 'connections': {(CONNECTION_ZIGBEE, serial)}, + 'identifiers': {(DECONZ_DOMAIN, serial)}, 'manufacturer': self._sensor.manufacturer, 'model': self._sensor.modelid, 'name': self._sensor.name, diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index d435e9e3c04..a4edc009ea1 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -123,8 +123,9 @@ async def async_setup_entry(hass, config_entry): device_registry = await \ hass.helpers.device_registry.async_get_registry() device_registry.async_get_or_create( - connection=[[CONNECTION_NETWORK_MAC, deconz.config.mac]], - identifiers=[[DOMAIN, deconz.config.bridgeid]], + config_entry=config_entry.entry_id, + connections={(CONNECTION_NETWORK_MAC, deconz.config.mac)}, + identifiers={(DOMAIN, deconz.config.bridgeid)}, manufacturer='Dresden Elektronik', model=deconz.config.modelid, name=deconz.config.name, sw_version=deconz.config.swversion) diff --git a/homeassistant/components/light/deconz.py b/homeassistant/components/light/deconz.py index 067f1474f96..412cf8693e5 100644 --- a/homeassistant/components/light/deconz.py +++ b/homeassistant/components/light/deconz.py @@ -202,15 +202,15 @@ class DeconzLight(Light): return attributes @property - def device(self): + def device_info(self): """Return a device description for device registry.""" if (self._light.uniqueid is None or self._light.uniqueid.count(':') != 7): return None serial = self._light.uniqueid.split('-', 1)[0] return { - 'connection': [[CONNECTION_ZIGBEE, serial]], - 'identifiers': [[DECONZ_DOMAIN, serial]], + 'connections': {(CONNECTION_ZIGBEE, serial)}, + 'identifiers': {(DECONZ_DOMAIN, serial)}, 'manufacturer': self._light.manufacturer, 'model': self._light.modelid, 'name': self._light.name, diff --git a/homeassistant/components/media_player/roku.py b/homeassistant/components/media_player/roku.py index fa1120db98c..fca7b29d2ec 100644 --- a/homeassistant/components/media_player/roku.py +++ b/homeassistant/components/media_player/roku.py @@ -87,7 +87,7 @@ class RokuDevice(MediaPlayerDevice): self.ip_address = host self.channels = [] self.current_app = None - self.device_info = {} + self._device_info = {} self.update() @@ -96,7 +96,7 @@ class RokuDevice(MediaPlayerDevice): import requests.exceptions try: - self.device_info = self.roku.device_info + self._device_info = self.roku.device_info self.ip_address = self.roku.host self.channels = self.get_source_list() @@ -121,9 +121,9 @@ class RokuDevice(MediaPlayerDevice): @property def name(self): """Return the name of the device.""" - if self.device_info.userdevicename: - return self.device_info.userdevicename - return "Roku {}".format(self.device_info.sernum) + if self._device_info.userdevicename: + return self._device_info.userdevicename + return "Roku {}".format(self._device_info.sernum) @property def state(self): @@ -149,7 +149,7 @@ class RokuDevice(MediaPlayerDevice): @property def unique_id(self): """Return a unique, HASS-friendly identifier for this entity.""" - return self.device_info.sernum + return self._device_info.sernum @property def media_content_type(self): diff --git a/homeassistant/components/media_player/soundtouch.py b/homeassistant/components/media_player/soundtouch.py index f2ac45a996f..489d028aad4 100644 --- a/homeassistant/components/media_player/soundtouch.py +++ b/homeassistant/components/media_player/soundtouch.py @@ -166,6 +166,11 @@ class SoundTouchDevice(MediaPlayerDevice): """Return specific soundtouch configuration.""" return self._config + @property + def device(self): + """Return Soundtouch device.""" + return self._device + def update(self): """Retrieve the latest data.""" self._status = self._device.status() @@ -318,8 +323,8 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to create zone without slaves") else: _LOGGER.info("Creating zone with master %s", - self._device.config.name) - self._device.create_zone([slave.device for slave in slaves]) + self.device.config.name) + self.device.create_zone([slave.device for slave in slaves]) def remove_zone_slave(self, slaves): """ @@ -336,8 +341,8 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to find slaves to remove") else: _LOGGER.info("Removing slaves from zone with master %s", - self._device.config.name) - self._device.remove_zone_slave([slave.device for slave in slaves]) + self.device.config.name) + self.device.remove_zone_slave([slave.device for slave in slaves]) def add_zone_slave(self, slaves): """ @@ -352,5 +357,5 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to find slaves to add") else: _LOGGER.info("Adding slaves to zone with master %s", - self._device.config.name) - self._device.add_zone_slave([slave.device for slave in slaves]) + self.device.config.name) + self.device.add_zone_slave([slave.device for slave in slaves]) diff --git a/homeassistant/components/sensor/deconz.py b/homeassistant/components/sensor/deconz.py index 45c604a74ee..8cb3915dc46 100644 --- a/homeassistant/components/sensor/deconz.py +++ b/homeassistant/components/sensor/deconz.py @@ -136,15 +136,15 @@ class DeconzSensor(Entity): return attr @property - def device(self): + def device_info(self): """Return a device description for device registry.""" if (self._sensor.uniqueid is None or self._sensor.uniqueid.count(':') != 7): return None serial = self._sensor.uniqueid.split('-', 1)[0] return { - 'connection': [[CONNECTION_ZIGBEE, serial]], - 'identifiers': [[DECONZ_DOMAIN, serial]], + 'connections': {(CONNECTION_ZIGBEE, serial)}, + 'identifiers': {(DECONZ_DOMAIN, serial)}, 'manufacturer': self._sensor.manufacturer, 'model': self._sensor.modelid, 'name': self._sensor.name, @@ -211,15 +211,15 @@ class DeconzBattery(Entity): return attr @property - def device(self): + def device_info(self): """Return a device description for device registry.""" if (self._device.uniqueid is None or self._device.uniqueid.count(':') != 7): return None serial = self._device.uniqueid.split('-', 1)[0] return { - 'connection': [[CONNECTION_ZIGBEE, serial]], - 'identifiers': [[DECONZ_DOMAIN, serial]], + 'connections': {(CONNECTION_ZIGBEE, serial)}, + 'identifiers': {(DECONZ_DOMAIN, serial)}, 'manufacturer': self._device.manufacturer, 'model': self._device.modelid, 'name': self._device.name, diff --git a/homeassistant/components/switch/deconz.py b/homeassistant/components/switch/deconz.py index 7d861e4c29c..35dbc3ef782 100644 --- a/homeassistant/components/switch/deconz.py +++ b/homeassistant/components/switch/deconz.py @@ -81,15 +81,15 @@ class DeconzSwitch(SwitchDevice): return False @property - def device(self): + def device_info(self): """Return a device description for device registry.""" if (self._switch.uniqueid is None or self._switch.uniqueid.count(':') != 7): return None serial = self._switch.uniqueid.split('-', 1)[0] return { - 'connection': [[CONNECTION_ZIGBEE, serial]], - 'identifiers': [[DECONZ_DOMAIN, serial]], + 'connections': {(CONNECTION_ZIGBEE, serial)}, + 'identifiers': {(DECONZ_DOMAIN, serial)}, 'manufacturer': self._switch.manufacturer, 'model': self._switch.modelid, 'name': self._switch.name, diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index 19a6eaa62dc..31da40134a5 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -23,8 +23,9 @@ CONNECTION_ZIGBEE = 'zigbee' class DeviceEntry: """Device Registry Entry.""" - connection = attr.ib(type=list) - identifiers = attr.ib(type=list) + config_entries = attr.ib(type=set, converter=set) + connections = attr.ib(type=set, converter=set) + identifiers = attr.ib(type=set, converter=set) manufacturer = attr.ib(type=str) model = attr.ib(type=str) name = attr.ib(type=str, default=None) @@ -46,29 +47,36 @@ class DeviceRegistry: """Check if device is registered.""" for device in self.devices: if any(iden in device.identifiers for iden in identifiers) or \ - any(conn in device.connection for conn in connections): + any(conn in device.connections for conn in connections): return device return None @callback - def async_get_or_create(self, *, connection, identifiers, manufacturer, - model, name=None, sw_version=None): + def async_get_or_create(self, *, config_entry, connections, identifiers, + manufacturer, model, name=None, sw_version=None): """Get device. Create if it doesn't exist.""" - device = self.async_get_device(identifiers, connection) + if not identifiers and not connections: + return None + + device = self.async_get_device(identifiers, connections) if device is not None: + if config_entry not in device.config_entries: + device.config_entries.add(config_entry) + self.async_schedule_save() return device device = DeviceEntry( - connection=connection, + config_entries=[config_entry], + connections=connections, identifiers=identifiers, manufacturer=manufacturer, model=model, name=name, sw_version=sw_version ) - self.devices.append(device) + self.async_schedule_save() return device @@ -81,7 +89,16 @@ class DeviceRegistry: self.devices = [] return - self.devices = [DeviceEntry(**device) for device in devices['devices']] + self.devices = [DeviceEntry( + config_entries=device['config_entries'], + connections={tuple(conn) for conn in device['connections']}, + identifiers={tuple(iden) for iden in device['identifiers']}, + manufacturer=device['manufacturer'], + model=device['model'], + name=device['name'], + sw_version=device['sw_version'], + id=device['id'], + ) for device in devices['devices']] @callback def async_schedule_save(self): @@ -95,13 +112,14 @@ class DeviceRegistry: data['devices'] = [ { - 'id': entry.id, - 'connection': entry.connection, - 'identifiers': entry.identifiers, + 'config_entries': list(entry.config_entries), + 'connections': list(entry.connections), + 'identifiers': list(entry.identifiers), 'manufacturer': entry.manufacturer, 'model': entry.model, 'name': entry.name, 'sw_version': entry.sw_version, + 'id': entry.id, } for entry in self.devices ] diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index 78806e65ef1..695da5bce9c 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -131,7 +131,7 @@ class Entity: return None @property - def device(self): + def device_info(self): """Return device specific attributes. Implemented by platform classes. diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index ffac68c5f07..083a2946122 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -272,15 +272,16 @@ class EntityPlatform: else: config_entry_id = None - device = entity.device - if device is not None: + device_info = entity.device_info + if config_entry_id is not None and device_info is not None: device = device_registry.async_get_or_create( - connection=device['connection'], - identifiers=device['identifiers'], - manufacturer=device['manufacturer'], - model=device['model'], - name=device.get('name'), - sw_version=device.get('sw_version')) + config_entry=config_entry_id, + connections=device_info.get('connections', []), + identifiers=device_info.get('identifiers', []), + manufacturer=device_info.get('manufacturer'), + model=device_info.get('model'), + name=device_info.get('name'), + sw_version=device_info.get('sw_version')) device_id = device.id else: device_id = None diff --git a/tests/helpers/test_device_registry.py b/tests/helpers/test_device_registry.py index f7792eb5250..b2e73071823 100644 --- a/tests/helpers/test_device_registry.py +++ b/tests/helpers/test_device_registry.py @@ -26,22 +26,73 @@ def registry(hass): async def test_get_or_create_returns_same_entry(registry): """Make sure we do not duplicate entries.""" entry = registry.async_get_or_create( - connection=[['ethernet', '12:34:56:78:90:AB:CD:EF']], - identifiers=[['bridgeid', '0123']], + config_entry='1234', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers={('bridgeid', '0123')}, manufacturer='manufacturer', model='model') entry2 = registry.async_get_or_create( - connection=[['ethernet', '11:22:33:44:55:66:77:88']], - identifiers=[['bridgeid', '0123']], + config_entry='1234', + connections={('ethernet', '11:22:33:44:55:66:77:88')}, + identifiers={('bridgeid', '0123')}, manufacturer='manufacturer', model='model') entry3 = registry.async_get_or_create( - connection=[['ethernet', '12:34:56:78:90:AB:CD:EF']], - identifiers=[['bridgeid', '1234']], + config_entry='1234', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers={('bridgeid', '1234')}, manufacturer='manufacturer', model='model') assert len(registry.devices) == 1 assert entry is entry2 assert entry is entry3 - assert entry.identifiers == [['bridgeid', '0123']] + assert entry.identifiers == {('bridgeid', '0123')} + + +async def test_requirement_for_identifier_or_connection(registry): + """Make sure we do require some descriptor of device.""" + entry = registry.async_get_or_create( + config_entry='1234', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers=set(), + manufacturer='manufacturer', model='model') + entry2 = registry.async_get_or_create( + config_entry='1234', + connections=set(), + identifiers={('bridgeid', '0123')}, + manufacturer='manufacturer', model='model') + entry3 = registry.async_get_or_create( + config_entry='1234', + connections=set(), + identifiers=set(), + manufacturer='manufacturer', model='model') + + assert len(registry.devices) == 2 + assert entry + assert entry2 + assert entry3 is None + + +async def test_multiple_config_entries(registry): + """Make sure we do not get duplicate entries.""" + entry = registry.async_get_or_create( + config_entry='123', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers={('bridgeid', '0123')}, + manufacturer='manufacturer', model='model') + entry2 = registry.async_get_or_create( + config_entry='456', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers={('bridgeid', '0123')}, + manufacturer='manufacturer', model='model') + entry3 = registry.async_get_or_create( + config_entry='123', + connections={('ethernet', '12:34:56:78:90:AB:CD:EF')}, + identifiers={('bridgeid', '0123')}, + manufacturer='manufacturer', model='model') + + assert len(registry.devices) == 1 + assert entry is entry2 + assert entry is entry3 + assert entry.config_entries == {'123', '456'} async def test_loading_from_storage(hass, hass_storage): @@ -51,7 +102,10 @@ async def test_loading_from_storage(hass, hass_storage): 'data': { 'devices': [ { - 'connection': [ + 'config_entries': [ + '1234' + ], + 'connections': [ [ 'Zigbee', '01.23.45.67.89' @@ -67,7 +121,7 @@ async def test_loading_from_storage(hass, hass_storage): 'manufacturer': 'manufacturer', 'model': 'model', 'name': 'name', - 'sw_version': 'version' + 'sw_version': 'version', } ] } @@ -76,7 +130,9 @@ async def test_loading_from_storage(hass, hass_storage): registry = await device_registry.async_get_registry(hass) entry = registry.async_get_or_create( - connection=[['Zigbee', '01.23.45.67.89']], - identifiers=[['serial', '12:34:56:78:90:AB:CD:EF']], + config_entry='1234', + connections={('Zigbee', '01.23.45.67.89')}, + identifiers={('serial', '12:34:56:78:90:AB:CD:EF')}, manufacturer='manufacturer', model='model') assert entry.id == 'abcdefghijklm' + assert isinstance(entry.config_entries, set) From 4cb9ac72b4ebe09c7c969d8efdf9e8bdcc8166c2 Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Fri, 24 Aug 2018 17:27:12 -0400 Subject: [PATCH 124/159] fix error message for cv.matches_regex (#16175) --- homeassistant/helpers/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index bbd863b5693..90098a677a1 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -92,7 +92,7 @@ def matches_regex(regex): if not regex.match(value): raise vol.Invalid('value {} does not match regular expression {}' - .format(regex.pattern, value)) + .format(value, regex.pattern)) return value return validator From b8c272258e6f4778327d2f3fbe60846019341b6c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 25 Aug 2018 11:01:32 +0200 Subject: [PATCH 125/159] Fix hangouts (#16180) --- homeassistant/components/hangouts/__init__.py | 4 ++-- homeassistant/components/hangouts/config_flow.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/hangouts/__init__.py b/homeassistant/components/hangouts/__init__.py index 89649ecb8e1..8ebacc3736b 100644 --- a/homeassistant/components/hangouts/__init__.py +++ b/homeassistant/components/hangouts/__init__.py @@ -26,8 +26,8 @@ _LOGGER = logging.getLogger(__name__) async def async_setup(hass, config): """Set up the Hangouts bot component.""" - config = config.get(DOMAIN, []) - hass.data[DOMAIN] = {CONF_COMMANDS: config[CONF_COMMANDS]} + config = config.get(DOMAIN, {}) + hass.data[DOMAIN] = {CONF_COMMANDS: config.get(CONF_COMMANDS, [])} if configured_hangouts(hass) is None: hass.async_add_job(hass.config_entries.flow.async_init( diff --git a/homeassistant/components/hangouts/config_flow.py b/homeassistant/components/hangouts/config_flow.py index bd81d5053c8..74eb14b050d 100644 --- a/homeassistant/components/hangouts/config_flow.py +++ b/homeassistant/components/hangouts/config_flow.py @@ -104,4 +104,4 @@ class HangoutsFlowHandler(data_entry_flow.FlowHandler): async def async_step_import(self, _): """Handle a flow import.""" - return self.async_abort(reason='already_configured') + return await self.async_step_user() From c2891b9905687abc483bd179745b74feae56110f Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Fri, 24 Aug 2018 22:57:36 -0700 Subject: [PATCH 126/159] Tweak log level for bearer token warning (#16182) --- homeassistant/components/http/auth.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/http/auth.py b/homeassistant/components/http/auth.py index d01d1b50c5a..7adcc43f4af 100644 --- a/homeassistant/components/http/auth.py +++ b/homeassistant/components/http/auth.py @@ -30,8 +30,10 @@ def setup_auth(app, trusted_networks, use_auth, if use_auth and (HTTP_HEADER_HA_AUTH in request.headers or DATA_API_PASSWORD in request.query): if request.path not in old_auth_warning: - _LOGGER.warning('Please change to use bearer token access %s', - request.path) + _LOGGER.log( + logging.INFO if support_legacy else logging.WARNING, + 'Please change to use bearer token access %s from %s', + request.path, request[KEY_REAL_IP]) old_auth_warning.add(request.path) legacy_auth = (not use_auth or support_legacy) and api_password From 66a8bede128cd7b1a32114b10c145b2aa31c9128 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 25 Aug 2018 02:09:48 -0700 Subject: [PATCH 127/159] Default load trusted_network auth provider if configured trusted networks (#16184) --- homeassistant/bootstrap.py | 4 +++- homeassistant/config.py | 5 ++++- tests/test_config.py | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 41fa61964de..c10964e2da3 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -88,10 +88,12 @@ async def async_from_config_dict(config: Dict[str, Any], core_config = config.get(core.DOMAIN, {}) has_api_password = bool((config.get('http') or {}).get('api_password')) + has_trusted_networks = bool((config.get('http') or {}) + .get('trusted_networks')) try: await conf_util.async_process_ha_core_config( - hass, core_config, has_api_password) + hass, core_config, has_api_password, has_trusted_networks) except vol.Invalid as ex: conf_util.async_log_exception(ex, 'homeassistant', core_config, hass) return None diff --git a/homeassistant/config.py b/homeassistant/config.py index 45505bbbc9b..fe8f8ef0f60 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -406,7 +406,8 @@ def _format_config_error(ex: vol.Invalid, domain: str, config: Dict) -> str: async def async_process_ha_core_config( hass: HomeAssistant, config: Dict, - has_api_password: bool = False) -> None: + has_api_password: bool = False, + has_trusted_networks: bool = False) -> None: """Process the [homeassistant] section from the configuration. This method is a coroutine. @@ -423,6 +424,8 @@ async def async_process_ha_core_config( ] if has_api_password: auth_conf.append({'type': 'legacy_api_password'}) + if has_trusted_networks: + auth_conf.append({'type': 'trusted_networks'}) setattr(hass, 'auth', await auth.auth_manager_from_config( hass, diff --git a/tests/test_config.py b/tests/test_config.py index 77a30fd771b..76ea576ac28 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -856,6 +856,27 @@ async def test_auth_provider_config_default_api_password(hass): assert hass.auth.active is True +async def test_auth_provider_config_default_trusted_networks(hass): + """Test loading default auth provider config with trusted networks.""" + core_config = { + 'latitude': 60, + 'longitude': 50, + 'elevation': 25, + 'name': 'Huis', + CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, + 'time_zone': 'GMT', + } + if hasattr(hass, 'auth'): + del hass.auth + await config_util.async_process_ha_core_config(hass, core_config, + has_trusted_networks=True) + + assert len(hass.auth.auth_providers) == 2 + assert hass.auth.auth_providers[0].type == 'homeassistant' + assert hass.auth.auth_providers[1].type == 'trusted_networks' + assert hass.auth.active is True + + async def test_disallowed_auth_provider_config(hass): """Test loading insecure example auth provider is disallowed.""" core_config = { From 9ffcd2d86a95c2fd502be407f7a9bde0244b2e41 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 25 Aug 2018 11:16:01 +0200 Subject: [PATCH 128/159] Bumped version to 0.77.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index b11354e0064..c299b5a2a73 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 77 -PATCH_VERSION = '0b0' +PATCH_VERSION = '0b1' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 3783d1ce908672000408dc6c5562762e550f36b0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 21:30:14 +0200 Subject: [PATCH 129/159] Update frontend to 20180826.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index c475ea55974..4622f80948e 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180825.0'] +REQUIREMENTS = ['home-assistant-frontend==20180826.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index a5cfe9e402a..39deea61056 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -438,7 +438,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180825.0 +home-assistant-frontend==20180826.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7b9dc1d1eb3..3dbbb1f399c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -84,7 +84,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180825.0 +home-assistant-frontend==20180826.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From c13e5fcb9289ba01f78ef6a698d01767aaee9721 Mon Sep 17 00:00:00 2001 From: Matt Hamilton Date: Sun, 26 Aug 2018 16:50:31 -0400 Subject: [PATCH 130/159] Replace pbkdf2 with bcrypt (#16071) * Replace pbkdf2 with bcrypt bcrypt isn't inherently better than pbkdf2, but everything "just works" out of the box. * the hash verification routine now only computes one hash per call * a per-user salt is built into the hash as opposed to the current global salt * bcrypt.checkpw() is immune to timing attacks regardless of input * hash strength is a function of real time benchmarks and a "difficulty" level, meaning we won't have to ever update the iteration count * WIP: add hash upgrade mechanism * WIP: clarify decode issue * remove stale testing code * Fix test * Ensure incorrect legacy passwords fail * Add better invalid legacy password test * Lint * Run tests in async scope --- homeassistant/auth/providers/homeassistant.py | 51 +++++++++-- homeassistant/package_constraints.txt | 1 + requirements_all.txt | 1 + setup.py | 1 + tests/auth/providers/test_homeassistant.py | 89 +++++++++++++++++++ 5 files changed, 135 insertions(+), 8 deletions(-) diff --git a/homeassistant/auth/providers/homeassistant.py b/homeassistant/auth/providers/homeassistant.py index ce252497901..c743a5b7f65 100644 --- a/homeassistant/auth/providers/homeassistant.py +++ b/homeassistant/auth/providers/homeassistant.py @@ -5,13 +5,16 @@ import hashlib import hmac from typing import Any, Dict, List, Optional, cast +import bcrypt import voluptuous as vol from homeassistant.const import CONF_ID from homeassistant.core import callback, HomeAssistant from homeassistant.exceptions import HomeAssistantError +from homeassistant.util.async_ import run_coroutine_threadsafe from . import AuthProvider, AUTH_PROVIDER_SCHEMA, AUTH_PROVIDERS, LoginFlow + from ..models import Credentials, UserMeta from ..util import generate_secret @@ -74,8 +77,7 @@ class Data: Raises InvalidAuth if auth invalid. """ - hashed = self.hash_password(password) - + dummy = b'$2b$12$CiuFGszHx9eNHxPuQcwBWez4CwDTOcLTX5CbOpV6gef2nYuXkY7BO' found = None # Compare all users to avoid timing attacks. @@ -84,22 +86,55 @@ class Data: found = user if found is None: - # Do one more compare to make timing the same as if user was found. - hmac.compare_digest(hashed, hashed) + # check a hash to make timing the same as if user was found + bcrypt.checkpw(b'foo', + dummy) raise InvalidAuth - if not hmac.compare_digest(hashed, - base64.b64decode(found['password'])): + user_hash = base64.b64decode(found['password']) + + # if the hash is not a bcrypt hash... + # provide a transparant upgrade for old pbkdf2 hash format + if not (user_hash.startswith(b'$2a$') + or user_hash.startswith(b'$2b$') + or user_hash.startswith(b'$2x$') + or user_hash.startswith(b'$2y$')): + # IMPORTANT! validate the login, bail if invalid + hashed = self.legacy_hash_password(password) + if not hmac.compare_digest(hashed, user_hash): + raise InvalidAuth + # then re-hash the valid password with bcrypt + self.change_password(found['username'], password) + run_coroutine_threadsafe( + self.async_save(), self.hass.loop + ).result() + user_hash = base64.b64decode(found['password']) + + # bcrypt.checkpw is timing-safe + if not bcrypt.checkpw(password.encode(), + user_hash): raise InvalidAuth - def hash_password(self, password: str, for_storage: bool = False) -> bytes: - """Encode a password.""" + def legacy_hash_password(self, password: str, + for_storage: bool = False) -> bytes: + """LEGACY password encoding.""" + # We're no longer storing salts in data, but if one exists we + # should be able to retrieve it. salt = self._data['salt'].encode() # type: ignore hashed = hashlib.pbkdf2_hmac('sha512', password.encode(), salt, 100000) if for_storage: hashed = base64.b64encode(hashed) return hashed + # pylint: disable=no-self-use + def hash_password(self, password: str, for_storage: bool = False) -> bytes: + """Encode a password.""" + hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12)) \ + # type: bytes + if for_storage: + hashed = base64.b64encode(hashed) + return hashed + def add_auth(self, username: str, password: str) -> None: """Add a new authenticated user/pass.""" if any(user['username'] == username for user in self.users): diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 26628d7fe62..1b9447c32e6 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -2,6 +2,7 @@ aiohttp==3.3.2 astral==1.6.1 async_timeout==3.0.0 attrs==18.1.0 +bcrypt==3.1.4 certifi>=2018.04.16 jinja2>=2.10 PyJWT==1.6.4 diff --git a/requirements_all.txt b/requirements_all.txt index 39deea61056..22fa8219f9d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -3,6 +3,7 @@ aiohttp==3.3.2 astral==1.6.1 async_timeout==3.0.0 attrs==18.1.0 +bcrypt==3.1.4 certifi>=2018.04.16 jinja2>=2.10 PyJWT==1.6.4 diff --git a/setup.py b/setup.py index 7484dc286e6..1f1beaf6f06 100755 --- a/setup.py +++ b/setup.py @@ -36,6 +36,7 @@ REQUIRES = [ 'astral==1.6.1', 'async_timeout==3.0.0', 'attrs==18.1.0', + 'bcrypt==3.1.4', 'certifi>=2018.04.16', 'jinja2>=2.10', 'PyJWT==1.6.4', diff --git a/tests/auth/providers/test_homeassistant.py b/tests/auth/providers/test_homeassistant.py index c92f8539b17..935c5e50dd5 100644 --- a/tests/auth/providers/test_homeassistant.py +++ b/tests/auth/providers/test_homeassistant.py @@ -1,6 +1,7 @@ """Test the Home Assistant local auth provider.""" from unittest.mock import Mock +import base64 import pytest from homeassistant import data_entry_flow @@ -132,3 +133,91 @@ async def test_new_users_populate_values(hass, data): user = await manager.async_get_or_create_user(credentials) assert user.name == 'hello' assert user.is_active + + +async def test_new_hashes_are_bcrypt(data, hass): + """Test that newly created hashes are using bcrypt.""" + data.add_auth('newuser', 'newpass') + found = None + for user in data.users: + if user['username'] == 'newuser': + found = user + assert found is not None + user_hash = base64.b64decode(found['password']) + assert (user_hash.startswith(b'$2a$') + or user_hash.startswith(b'$2b$') + or user_hash.startswith(b'$2x$') + or user_hash.startswith(b'$2y$')) + + +async def test_pbkdf2_to_bcrypt_hash_upgrade(hass_storage, hass): + """Test migrating user from pbkdf2 hash to bcrypt hash.""" + hass_storage[hass_auth.STORAGE_KEY] = { + 'version': hass_auth.STORAGE_VERSION, + 'key': hass_auth.STORAGE_KEY, + 'data': { + 'salt': '09c52f0b120eaa7dea5f73f9a9b985f3d493b30a08f3f2945ef613' + '0b08e6a3ea', + 'users': [ + { + 'password': 'L5PAbehB8LAQI2Ixu+d+PDNJKmljqLnBcYWYw35onC/8D' + 'BM1SpvT6A8ZFael5+deCt+s+43J08IcztnguouHSw==', + 'username': 'legacyuser' + } + ] + }, + } + data = hass_auth.Data(hass) + await data.async_load() + + # verify the correct (pbkdf2) password successfuly authenticates the user + await hass.async_add_executor_job( + data.validate_login, 'legacyuser', 'beer') + + # ...and that the hashes are now bcrypt hashes + user_hash = base64.b64decode( + hass_storage[hass_auth.STORAGE_KEY]['data']['users'][0]['password']) + assert (user_hash.startswith(b'$2a$') + or user_hash.startswith(b'$2b$') + or user_hash.startswith(b'$2x$') + or user_hash.startswith(b'$2y$')) + + +async def test_pbkdf2_to_bcrypt_hash_upgrade_with_incorrect_pass(hass_storage, + hass): + """Test migrating user from pbkdf2 hash to bcrypt hash.""" + hass_storage[hass_auth.STORAGE_KEY] = { + 'version': hass_auth.STORAGE_VERSION, + 'key': hass_auth.STORAGE_KEY, + 'data': { + 'salt': '09c52f0b120eaa7dea5f73f9a9b985f3d493b30a08f3f2945ef613' + '0b08e6a3ea', + 'users': [ + { + 'password': 'L5PAbehB8LAQI2Ixu+d+PDNJKmljqLnBcYWYw35onC/8D' + 'BM1SpvT6A8ZFael5+deCt+s+43J08IcztnguouHSw==', + 'username': 'legacyuser' + } + ] + }, + } + data = hass_auth.Data(hass) + await data.async_load() + + orig_user_hash = base64.b64decode( + hass_storage[hass_auth.STORAGE_KEY]['data']['users'][0]['password']) + + # Make sure invalid legacy passwords fail + with pytest.raises(hass_auth.InvalidAuth): + await hass.async_add_executor_job( + data.validate_login, 'legacyuser', 'wine') + + # Make sure we don't change the password/hash when password is incorrect + with pytest.raises(hass_auth.InvalidAuth): + await hass.async_add_executor_job( + data.validate_login, 'legacyuser', 'wine') + + same_user_hash = base64.b64decode( + hass_storage[hass_auth.STORAGE_KEY]['data']['users'][0]['password']) + + assert orig_user_hash == same_user_hash From 2ece671bfd77a5a99e7475f957d53356ba76dcdb Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sun, 26 Aug 2018 13:38:52 -0700 Subject: [PATCH 131/159] Add Time-based Onetime Password Multi-factor Authentication Module (#16129) * Add Time-based Onetime Password Multi-factor Auth Add TOTP setup flow, generate QR code * Resolve rebase issue * Use svg instead png for QR code * Lint and typing * Fix translation * Load totp auth module by default * use tag instead markdown image * Update strings * Cleanup --- homeassistant/auth/__init__.py | 8 +- homeassistant/auth/mfa_modules/totp.py | 212 ++++++++++++++++++ homeassistant/auth/providers/__init__.py | 4 +- .../components/auth/.translations/en.json | 16 ++ homeassistant/components/auth/strings.json | 16 ++ homeassistant/config.py | 6 +- requirements_all.txt | 4 + requirements_test_all.txt | 4 + script/gen_requirements_all.py | 1 + tests/auth/mfa_modules/test_totp.py | 130 +++++++++++ tests/test_config.py | 11 +- 11 files changed, 404 insertions(+), 8 deletions(-) create mode 100644 homeassistant/auth/mfa_modules/totp.py create mode 100644 homeassistant/components/auth/.translations/en.json create mode 100644 homeassistant/components/auth/strings.json create mode 100644 tests/auth/mfa_modules/test_totp.py diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index e0b7b377b1f..952bb3b8352 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -249,13 +249,13 @@ class AuthManager: await module.async_depose_user(user.id) - async def async_get_enabled_mfa(self, user: models.User) -> List[str]: + async def async_get_enabled_mfa(self, user: models.User) -> Dict[str, str]: """List enabled mfa modules for user.""" - module_ids = [] + modules = OrderedDict() # type: Dict[str, str] for module_id, module in self._mfa_modules.items(): if await module.async_is_user_setup(user.id): - module_ids.append(module_id) - return module_ids + modules[module_id] = module.name + return modules async def async_create_refresh_token(self, user: models.User, client_id: Optional[str] = None) \ diff --git a/homeassistant/auth/mfa_modules/totp.py b/homeassistant/auth/mfa_modules/totp.py new file mode 100644 index 00000000000..48531863c1a --- /dev/null +++ b/homeassistant/auth/mfa_modules/totp.py @@ -0,0 +1,212 @@ +"""Time-based One Time Password auth module.""" +import logging +from io import BytesIO +from typing import Any, Dict, Optional, Tuple # noqa: F401 + +import voluptuous as vol + +from homeassistant.auth.models import User +from homeassistant.core import HomeAssistant + +from . import MultiFactorAuthModule, MULTI_FACTOR_AUTH_MODULES, \ + MULTI_FACTOR_AUTH_MODULE_SCHEMA, SetupFlow + +REQUIREMENTS = ['pyotp==2.2.6', 'PyQRCode==1.2.1'] + +CONFIG_SCHEMA = MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({ +}, extra=vol.PREVENT_EXTRA) + +STORAGE_VERSION = 1 +STORAGE_KEY = 'auth_module.totp' +STORAGE_USERS = 'users' +STORAGE_USER_ID = 'user_id' +STORAGE_OTA_SECRET = 'ota_secret' + +INPUT_FIELD_CODE = 'code' + +DUMMY_SECRET = 'FPPTH34D4E3MI2HG' + +_LOGGER = logging.getLogger(__name__) + + +def _generate_qr_code(data: str) -> str: + """Generate a base64 PNG string represent QR Code image of data.""" + import pyqrcode + + qr_code = pyqrcode.create(data) + + with BytesIO() as buffer: + qr_code.svg(file=buffer, scale=4) + return '{}'.format( + buffer.getvalue().decode("ascii").replace('\n', '') + .replace('' + ' Tuple[str, str, str]: + """Generate a secret, url, and QR code.""" + import pyotp + + ota_secret = pyotp.random_base32() + url = pyotp.totp.TOTP(ota_secret).provisioning_uri( + username, issuer_name="Home Assistant") + image = _generate_qr_code(url) + return ota_secret, url, image + + +@MULTI_FACTOR_AUTH_MODULES.register('totp') +class TotpAuthModule(MultiFactorAuthModule): + """Auth module validate time-based one time password.""" + + DEFAULT_TITLE = 'Time-based One Time Password' + + def __init__(self, hass: HomeAssistant, config: Dict[str, Any]) -> None: + """Initialize the user data store.""" + super().__init__(hass, config) + self._users = None # type: Optional[Dict[str, str]] + self._user_store = hass.helpers.storage.Store( + STORAGE_VERSION, STORAGE_KEY) + + @property + def input_schema(self) -> vol.Schema: + """Validate login flow input data.""" + return vol.Schema({INPUT_FIELD_CODE: str}) + + async def _async_load(self) -> None: + """Load stored data.""" + data = await self._user_store.async_load() + + if data is None: + data = {STORAGE_USERS: {}} + + self._users = data.get(STORAGE_USERS, {}) + + async def _async_save(self) -> None: + """Save data.""" + await self._user_store.async_save({STORAGE_USERS: self._users}) + + def _add_ota_secret(self, user_id: str, + secret: Optional[str] = None) -> str: + """Create a ota_secret for user.""" + import pyotp + + ota_secret = secret or pyotp.random_base32() # type: str + + self._users[user_id] = ota_secret # type: ignore + return ota_secret + + async def async_setup_flow(self, user_id: str) -> SetupFlow: + """Return a data entry flow handler for setup module. + + Mfa module should extend SetupFlow + """ + user = await self.hass.auth.async_get_user(user_id) # type: ignore + return TotpSetupFlow(self, self.input_schema, user) + + async def async_setup_user(self, user_id: str, setup_data: Any) -> str: + """Set up auth module for user.""" + if self._users is None: + await self._async_load() + + result = await self.hass.async_add_executor_job( + self._add_ota_secret, user_id, setup_data.get('secret')) + + await self._async_save() + return result + + async def async_depose_user(self, user_id: str) -> None: + """Depose auth module for user.""" + if self._users is None: + await self._async_load() + + if self._users.pop(user_id, None): # type: ignore + await self._async_save() + + async def async_is_user_setup(self, user_id: str) -> bool: + """Return whether user is setup.""" + if self._users is None: + await self._async_load() + + return user_id in self._users # type: ignore + + async def async_validation( + self, user_id: str, user_input: Dict[str, Any]) -> bool: + """Return True if validation passed.""" + if self._users is None: + await self._async_load() + + # user_input has been validate in caller + return await self.hass.async_add_executor_job( + self._validate_2fa, user_id, user_input[INPUT_FIELD_CODE]) + + def _validate_2fa(self, user_id: str, code: str) -> bool: + """Validate two factor authentication code.""" + import pyotp + + ota_secret = self._users.get(user_id) # type: ignore + if ota_secret is None: + # even we cannot find user, we still do verify + # to make timing the same as if user was found. + pyotp.TOTP(DUMMY_SECRET).verify(code) + return False + + return bool(pyotp.TOTP(ota_secret).verify(code)) + + +class TotpSetupFlow(SetupFlow): + """Handler for the setup flow.""" + + def __init__(self, auth_module: TotpAuthModule, + setup_schema: vol.Schema, + user: User) -> None: + """Initialize the setup flow.""" + super().__init__(auth_module, setup_schema, user.id) + # to fix typing complaint + self._auth_module = auth_module # type: TotpAuthModule + self._user = user + self._ota_secret = None # type: Optional[str] + self._url = None # type Optional[str] + self._image = None # type Optional[str] + + async def async_step_init( + self, user_input: Optional[Dict[str, str]] = None) \ + -> Dict[str, Any]: + """Handle the first step of setup flow. + + Return self.async_show_form(step_id='init') if user_input == None. + Return self.async_create_entry(data={'result': result}) if finish. + """ + import pyotp + + errors = {} # type: Dict[str, str] + + if user_input: + verified = await self.hass.async_add_executor_job( # type: ignore + pyotp.TOTP(self._ota_secret).verify, user_input['code']) + if verified: + result = await self._auth_module.async_setup_user( + self._user_id, {'secret': self._ota_secret}) + return self.async_create_entry( + title=self._auth_module.name, + data={'result': result} + ) + + errors['base'] = 'invalid_code' + + else: + hass = self._auth_module.hass + self._ota_secret, self._url, self._image = \ + await hass.async_add_executor_job( # type: ignore + _generate_secret_and_qr_code, str(self._user.name)) + + return self.async_show_form( + step_id='init', + data_schema=self._setup_schema, + description_placeholders={ + 'code': self._ota_secret, + 'url': self._url, + 'qr_code': self._image + }, + errors=errors + ) diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index e8ef7cbf3d4..0bcb47d4af9 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -168,7 +168,7 @@ class LoginFlow(data_entry_flow.FlowHandler): self._auth_provider = auth_provider self._auth_module_id = None # type: Optional[str] self._auth_manager = auth_provider.hass.auth # type: ignore - self.available_mfa_modules = [] # type: List + self.available_mfa_modules = {} # type: Dict[str, str] self.created_at = dt_util.utcnow() self.user = None # type: Optional[User] @@ -196,7 +196,7 @@ class LoginFlow(data_entry_flow.FlowHandler): errors['base'] = 'invalid_auth_module' if len(self.available_mfa_modules) == 1: - self._auth_module_id = self.available_mfa_modules[0] + self._auth_module_id = list(self.available_mfa_modules.keys())[0] return await self.async_step_mfa() return self.async_show_form( diff --git a/homeassistant/components/auth/.translations/en.json b/homeassistant/components/auth/.translations/en.json new file mode 100644 index 00000000000..5c1af67b120 --- /dev/null +++ b/homeassistant/components/auth/.translations/en.json @@ -0,0 +1,16 @@ +{ + "mfa_setup": { + "totp": { + "error": { + "invalid_code": "Invalid code, please try again. If you get this error consistently, please make sure the clock on Home Assistant system is accurate." + }, + "step": { + "init": { + "description": "Scan the QR code with your authentication app, such as **Google Authenticator** or **Authy**. If you have problem to scan the QR code, using **`{code}`** to manual setup. \n\n{qr_code}\n\nEnter the six digi code appeared in your app below to verify the setup:", + "title": "Scan this QR code with your app" + } + }, + "title": "TOTP" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/auth/strings.json b/homeassistant/components/auth/strings.json new file mode 100644 index 00000000000..b0083ab577b --- /dev/null +++ b/homeassistant/components/auth/strings.json @@ -0,0 +1,16 @@ +{ + "mfa_setup":{ + "totp": { + "title": "TOTP", + "step": { + "init": { + "title": "Set up two-factor authentication using TOTP", + "description": "To activate two factor authentication using time-based one-time passwords, scan the QR code with your authentication app. If you don't have one, we recommend either [Google Authenticator](https://support.google.com/accounts/answer/1066447) or [Authy](https://authy.com/).\n\n{qr_code}\n\nAfter scanning the code, enter the six digit code from your app to verify the setup. If you have problems scanning the QR code, do a manual setup with code **`{code}`**." + } + }, + "error": { + "invalid_code": "Invalid code, please try again. If you get this error consistently, please make sure the clock of your Home Assistant system is accurate." + } + } + } +} diff --git a/homeassistant/config.py b/homeassistant/config.py index fe8f8ef0f60..a799094c94d 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -427,10 +427,14 @@ async def async_process_ha_core_config( if has_trusted_networks: auth_conf.append({'type': 'trusted_networks'}) + mfa_conf = config.get(CONF_AUTH_MFA_MODULES, [ + {'type': 'totp', 'id': 'totp', 'name': 'Authenticator app'} + ]) + setattr(hass, 'auth', await auth.auth_manager_from_config( hass, auth_conf, - config.get(CONF_AUTH_MFA_MODULES, []))) + mfa_conf)) hac = hass.config diff --git a/requirements_all.txt b/requirements_all.txt index 22fa8219f9d..559bfdf7856 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -47,6 +47,9 @@ PyMVGLive==1.1.4 # homeassistant.components.arduino PyMata==2.14 +# homeassistant.auth.mfa_modules.totp +PyQRCode==1.2.1 + # homeassistant.components.sensor.rmvtransport PyRMVtransport==0.0.7 @@ -986,6 +989,7 @@ pyopenuv==1.0.1 # homeassistant.components.iota pyota==2.0.5 +# homeassistant.auth.mfa_modules.totp # homeassistant.components.sensor.otp pyotp==2.2.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3dbbb1f399c..05d449a5eb2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -154,6 +154,10 @@ pymonoprice==0.3 # homeassistant.components.binary_sensor.nx584 pynx584==0.4 +# homeassistant.auth.mfa_modules.totp +# homeassistant.components.sensor.otp +pyotp==2.2.6 + # homeassistant.components.qwikswitch pyqwikswitch==0.8 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index e26393bb800..fe23e638e5b 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -78,6 +78,7 @@ TEST_REQUIREMENTS = ( 'pylitejet', 'pymonoprice', 'pynx584', + 'pyotp', 'pyqwikswitch', 'PyRMVtransport', 'python-forecastio', diff --git a/tests/auth/mfa_modules/test_totp.py b/tests/auth/mfa_modules/test_totp.py new file mode 100644 index 00000000000..28e6c949bc4 --- /dev/null +++ b/tests/auth/mfa_modules/test_totp.py @@ -0,0 +1,130 @@ +"""Test the Time-based One Time Password (MFA) auth module.""" +from unittest.mock import patch + +from homeassistant import data_entry_flow +from homeassistant.auth import models as auth_models, auth_manager_from_config +from homeassistant.auth.mfa_modules import auth_mfa_module_from_config +from tests.common import MockUser + +MOCK_CODE = '123456' + + +async def test_validating_mfa(hass): + """Test validating mfa code.""" + totp_auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'totp' + }) + await totp_auth_module.async_setup_user('test-user', {}) + + with patch('pyotp.TOTP.verify', return_value=True): + assert await totp_auth_module.async_validation( + 'test-user', {'code': MOCK_CODE}) + + +async def test_validating_mfa_invalid_code(hass): + """Test validating an invalid mfa code.""" + totp_auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'totp' + }) + await totp_auth_module.async_setup_user('test-user', {}) + + with patch('pyotp.TOTP.verify', return_value=False): + assert await totp_auth_module.async_validation( + 'test-user', {'code': MOCK_CODE}) is False + + +async def test_validating_mfa_invalid_user(hass): + """Test validating an mfa code with invalid user.""" + totp_auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'totp' + }) + await totp_auth_module.async_setup_user('test-user', {}) + + assert await totp_auth_module.async_validation( + 'invalid-user', {'code': MOCK_CODE}) is False + + +async def test_setup_depose_user(hass): + """Test despose user.""" + totp_auth_module = await auth_mfa_module_from_config(hass, { + 'type': 'totp' + }) + result = await totp_auth_module.async_setup_user('test-user', {}) + assert len(totp_auth_module._users) == 1 + result2 = await totp_auth_module.async_setup_user('test-user', {}) + assert len(totp_auth_module._users) == 1 + assert result != result2 + + await totp_auth_module.async_depose_user('test-user') + assert len(totp_auth_module._users) == 0 + + result = await totp_auth_module.async_setup_user( + 'test-user2', {'secret': 'secret-code'}) + assert result == 'secret-code' + assert len(totp_auth_module._users) == 1 + + +async def test_login_flow_validates_mfa(hass): + """Test login flow with mfa enabled.""" + hass.auth = await auth_manager_from_config(hass, [{ + 'type': 'insecure_example', + 'users': [{'username': 'test-user', 'password': 'test-pass'}], + }], [{ + 'type': 'totp', + }]) + user = MockUser( + id='mock-user', + is_owner=False, + is_active=False, + name='Paulus', + ).add_to_auth_manager(hass.auth) + await hass.auth.async_link_user(user, auth_models.Credentials( + id='mock-id', + auth_provider_type='insecure_example', + auth_provider_id=None, + data={'username': 'test-user'}, + is_new=False, + )) + + await hass.auth.async_enable_user_mfa(user, 'totp', {}) + + provider = hass.auth.auth_providers[0] + + result = await hass.auth.login_flow.async_init( + (provider.type, provider.id)) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + + result = await hass.auth.login_flow.async_configure(result['flow_id'], { + 'username': 'incorrect-user', + 'password': 'test-pass', + }) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_auth' + + result = await hass.auth.login_flow.async_configure(result['flow_id'], { + 'username': 'test-user', + 'password': 'incorrect-pass', + }) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['errors']['base'] == 'invalid_auth' + + result = await hass.auth.login_flow.async_configure(result['flow_id'], { + 'username': 'test-user', + 'password': 'test-pass', + }) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['step_id'] == 'mfa' + assert result['data_schema'].schema.get('code') == str + + with patch('pyotp.TOTP.verify', return_value=False): + result = await hass.auth.login_flow.async_configure( + result['flow_id'], {'code': 'invalid-code'}) + assert result['type'] == data_entry_flow.RESULT_TYPE_FORM + assert result['step_id'] == 'mfa' + assert result['errors']['base'] == 'invalid_auth' + + with patch('pyotp.TOTP.verify', return_value=True): + result = await hass.auth.login_flow.async_configure( + result['flow_id'], {'code': MOCK_CODE}) + assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result['data'].id == 'mock-user' diff --git a/tests/test_config.py b/tests/test_config.py index 76ea576ac28..3cfe67f70b1 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -16,7 +16,7 @@ from homeassistant.const import ( CONF_LATITUDE, CONF_LONGITUDE, CONF_UNIT_SYSTEM, CONF_NAME, CONF_TIME_ZONE, CONF_ELEVATION, CONF_CUSTOMIZE, __version__, CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT, - CONF_AUTH_PROVIDERS) + CONF_AUTH_PROVIDERS, CONF_AUTH_MFA_MODULES) from homeassistant.util import location as location_util, dt as dt_util from homeassistant.util.yaml import SECRET_YAML from homeassistant.util.async_ import run_coroutine_threadsafe @@ -805,6 +805,10 @@ async def test_auth_provider_config(hass): CONF_AUTH_PROVIDERS: [ {'type': 'homeassistant'}, {'type': 'legacy_api_password'}, + ], + CONF_AUTH_MFA_MODULES: [ + {'type': 'totp'}, + {'type': 'totp', 'id': 'second'}, ] } if hasattr(hass, 'auth'): @@ -815,6 +819,9 @@ async def test_auth_provider_config(hass): assert hass.auth.auth_providers[0].type == 'homeassistant' assert hass.auth.auth_providers[1].type == 'legacy_api_password' assert hass.auth.active is True + assert len(hass.auth.auth_mfa_modules) == 2 + assert hass.auth.auth_mfa_modules[0].id == 'totp' + assert hass.auth.auth_mfa_modules[1].id == 'second' async def test_auth_provider_config_default(hass): @@ -834,6 +841,8 @@ async def test_auth_provider_config_default(hass): assert len(hass.auth.auth_providers) == 1 assert hass.auth.auth_providers[0].type == 'homeassistant' assert hass.auth.active is True + assert len(hass.auth.auth_mfa_modules) == 1 + assert hass.auth.auth_mfa_modules[0].id == 'totp' async def test_auth_provider_config_default_api_password(hass): From 6992a6fe6d11aa5799ac5bcadf7a99bf42ae0ae0 Mon Sep 17 00:00:00 2001 From: PhracturedBlue Date: Sun, 26 Aug 2018 12:29:15 -0700 Subject: [PATCH 132/159] Handle exception from pillow (#16190) --- homeassistant/components/camera/proxy.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/camera/proxy.py b/homeassistant/components/camera/proxy.py index a19efcfb1af..6c245ffdf43 100644 --- a/homeassistant/components/camera/proxy.py +++ b/homeassistant/components/camera/proxy.py @@ -64,7 +64,10 @@ def _resize_image(image, opts): quality = opts.quality or DEFAULT_QUALITY new_width = opts.max_width - img = Image.open(io.BytesIO(image)) + try: + img = Image.open(io.BytesIO(image)) + except IOError: + return image imgfmt = str(img.format) if imgfmt not in ('PNG', 'JPEG'): _LOGGER.debug("Image is of unsupported type: %s", imgfmt) From c8449d8f8a18f1566274a598ca18e4aad9ca1655 Mon Sep 17 00:00:00 2001 From: Marcel Hoppe Date: Sun, 26 Aug 2018 21:28:42 +0200 Subject: [PATCH 133/159] remove hangouts.users state, simplifies hangouts.conversations (#16191) --- .../components/hangouts/hangouts_bot.py | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/hangouts/hangouts_bot.py b/homeassistant/components/hangouts/hangouts_bot.py index d4c5606799d..d9ffb4cbace 100644 --- a/homeassistant/components/hangouts/hangouts_bot.py +++ b/homeassistant/components/hangouts/hangouts_bot.py @@ -195,23 +195,15 @@ class HangoutsBot: import hangups self._user_list, self._conversation_list = \ (await hangups.build_user_conversation_list(self._client)) - users = {} conversations = {} - for user in self._user_list.get_all(): - users[str(user.id_.chat_id)] = {'full_name': user.full_name, - 'is_self': user.is_self} - - for conv in self._conversation_list.get_all(): - users_in_conversation = {} + for i, conv in enumerate(self._conversation_list.get_all()): + users_in_conversation = [] for user in conv.users: - users_in_conversation[str(user.id_.chat_id)] = \ - {'full_name': user.full_name, 'is_self': user.is_self} - conversations[str(conv.id_)] = \ - {'name': conv.name, 'users': users_in_conversation} + users_in_conversation.append(user.full_name) + conversations[str(i)] = {'id': str(conv.id_), + 'name': conv.name, + 'users': users_in_conversation} - self.hass.states.async_set("{}.users".format(DOMAIN), - len(self._user_list.get_all()), - attributes=users) self.hass.states.async_set("{}.conversations".format(DOMAIN), len(self._conversation_list.get_all()), attributes=conversations) From 969b15a297f23c1b811697176705fc3f9a6c6f66 Mon Sep 17 00:00:00 2001 From: Penny Wood Date: Mon, 27 Aug 2018 03:35:06 +0800 Subject: [PATCH 134/159] Update aiohttp to version 3.4.0. (#16198) --- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 1b9447c32e6..70fb519eef4 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -1,4 +1,4 @@ -aiohttp==3.3.2 +aiohttp==3.4.0 astral==1.6.1 async_timeout==3.0.0 attrs==18.1.0 diff --git a/requirements_all.txt b/requirements_all.txt index 559bfdf7856..3c505a2f1e3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1,5 +1,5 @@ # Home Assistant core -aiohttp==3.3.2 +aiohttp==3.4.0 astral==1.6.1 async_timeout==3.0.0 attrs==18.1.0 diff --git a/setup.py b/setup.py index 1f1beaf6f06..b1b0af70319 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ PROJECT_URLS = { PACKAGES = find_packages(exclude=['tests', 'tests.*']) REQUIRES = [ - 'aiohttp==3.3.2', + 'aiohttp==3.4.0', 'astral==1.6.1', 'async_timeout==3.0.0', 'attrs==18.1.0', From 2ad938ed4401fbce13ff5d83612916d153eef1c4 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sun, 26 Aug 2018 21:25:39 +0200 Subject: [PATCH 135/159] Revert changes to platforms using self.device (#16209) * Revert tank_utility * Fix Soundtouch * Fix Plex * Fix Emby * Fix Radiotherm * Fix Juicenet * Fix Qwikswitch * Fix Xiaomi miio * Fix Nest * Fix Tellduslive * Fix KNX --- homeassistant/components/binary_sensor/knx.py | 10 +-- .../components/binary_sensor/nest.py | 5 +- .../components/binary_sensor/tellduslive.py | 2 +- homeassistant/components/camera/nest.py | 18 +++--- homeassistant/components/climate/knx.py | 30 ++++----- homeassistant/components/climate/nest.py | 44 ++++++------- .../components/climate/radiotherm.py | 32 +++++----- homeassistant/components/cover/knx.py | 34 +++++----- homeassistant/components/cover/tellduslive.py | 8 +-- homeassistant/components/juicenet.py | 12 ++-- homeassistant/components/light/knx.py | 32 +++++----- homeassistant/components/light/qwikswitch.py | 4 +- homeassistant/components/light/tellduslive.py | 8 +-- homeassistant/components/media_player/emby.py | 52 +++++++-------- homeassistant/components/media_player/plex.py | 63 ++++++++++--------- .../components/media_player/soundtouch.py | 12 ++-- homeassistant/components/nest/__init__.py | 6 +- homeassistant/components/notify/knx.py | 8 +-- homeassistant/components/qwikswitch.py | 6 +- .../components/remote/xiaomi_miio.py | 9 ++- homeassistant/components/sensor/juicenet.py | 20 +++--- homeassistant/components/sensor/knx.py | 10 +-- homeassistant/components/sensor/nest.py | 10 +-- .../components/sensor/tank_utility.py | 11 +++- .../components/sensor/tellduslive.py | 2 +- homeassistant/components/switch/knx.py | 12 ++-- .../components/switch/tellduslive.py | 6 +- homeassistant/components/tellduslive.py | 27 ++++---- 28 files changed, 256 insertions(+), 237 deletions(-) diff --git a/homeassistant/components/binary_sensor/knx.py b/homeassistant/components/binary_sensor/knx.py index a7d1d597f67..d0707b0f067 100644 --- a/homeassistant/components/binary_sensor/knx.py +++ b/homeassistant/components/binary_sensor/knx.py @@ -105,7 +105,7 @@ class KNXBinarySensor(BinarySensorDevice): def __init__(self, hass, device): """Initialize of KNX binary sensor.""" - self._device = device + self.device = device self.hass = hass self.async_register_callbacks() self.automations = [] @@ -116,12 +116,12 @@ class KNXBinarySensor(BinarySensorDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self._device.register_device_updated_cb(after_update_callback) + self.device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self._device.name + return self.device.name @property def available(self): @@ -136,9 +136,9 @@ class KNXBinarySensor(BinarySensorDevice): @property def device_class(self): """Return the class of this sensor.""" - return self._device.device_class + return self.device.device_class @property def is_on(self): """Return true if the binary sensor is on.""" - return self._device.is_on() + return self.device.is_on() diff --git a/homeassistant/components/binary_sensor/nest.py b/homeassistant/components/binary_sensor/nest.py index c952e7c8987..c60463a8663 100644 --- a/homeassistant/components/binary_sensor/nest.py +++ b/homeassistant/components/binary_sensor/nest.py @@ -130,7 +130,7 @@ class NestBinarySensor(NestSensorDevice, BinarySensorDevice): def update(self): """Retrieve latest state.""" - value = getattr(self._device, self.variable) + value = getattr(self.device, self.variable) if self.variable in STRUCTURE_BINARY_TYPES: self._state = bool(STRUCTURE_BINARY_STATE_MAP [self.variable].get(value)) @@ -154,5 +154,4 @@ class NestActivityZoneSensor(NestBinarySensor): def update(self): """Retrieve latest state.""" - self._state = self._device.has_ongoing_motion_in_zone( - self.zone.zone_id) + self._state = self.device.has_ongoing_motion_in_zone(self.zone.zone_id) diff --git a/homeassistant/components/binary_sensor/tellduslive.py b/homeassistant/components/binary_sensor/tellduslive.py index c412ec37e51..450a5e580bd 100644 --- a/homeassistant/components/binary_sensor/tellduslive.py +++ b/homeassistant/components/binary_sensor/tellduslive.py @@ -31,4 +31,4 @@ class TelldusLiveSensor(TelldusLiveEntity, BinarySensorDevice): @property def is_on(self): """Return true if switch is on.""" - return self._device.is_on + return self.device.is_on diff --git a/homeassistant/components/camera/nest.py b/homeassistant/components/camera/nest.py index 175dbcd2267..e1d26371984 100644 --- a/homeassistant/components/camera/nest.py +++ b/homeassistant/components/camera/nest.py @@ -46,7 +46,7 @@ class NestCamera(Camera): """Initialize a Nest Camera.""" super(NestCamera, self).__init__() self.structure = structure - self._device = device + self.device = device self._location = None self._name = None self._online = None @@ -93,7 +93,7 @@ class NestCamera(Camera): # Calling Nest API in is_streaming setter. # device.is_streaming would not immediately change until the process # finished in Nest Cam. - self._device.is_streaming = False + self.device.is_streaming = False def turn_on(self): """Turn on camera.""" @@ -105,15 +105,15 @@ class NestCamera(Camera): # Calling Nest API in is_streaming setter. # device.is_streaming would not immediately change until the process # finished in Nest Cam. - self._device.is_streaming = True + self.device.is_streaming = True def update(self): """Cache value from Python-nest.""" - self._location = self._device.where - self._name = self._device.name - self._online = self._device.online - self._is_streaming = self._device.is_streaming - self._is_video_history_enabled = self._device.is_video_history_enabled + self._location = self.device.where + self._name = self.device.name + self._online = self.device.online + self._is_streaming = self.device.is_streaming + self._is_video_history_enabled = self.device.is_video_history_enabled if self._is_video_history_enabled: # NestAware allowed 10/min @@ -130,7 +130,7 @@ class NestCamera(Camera): """Return a still image response from the camera.""" now = utcnow() if self._ready_for_snapshot(now): - url = self._device.snapshot_url + url = self.device.snapshot_url try: response = requests.get(url) diff --git a/homeassistant/components/climate/knx.py b/homeassistant/components/climate/knx.py index ed197f57ab3..4eada356653 100644 --- a/homeassistant/components/climate/knx.py +++ b/homeassistant/components/climate/knx.py @@ -118,7 +118,7 @@ class KNXClimate(ClimateDevice): def __init__(self, hass, device): """Initialize of a KNX climate device.""" - self._device = device + self.device = device self.hass = hass self.async_register_callbacks() @@ -126,7 +126,7 @@ class KNXClimate(ClimateDevice): def supported_features(self): """Return the list of supported features.""" support = SUPPORT_TARGET_TEMPERATURE - if self._device.supports_operation_mode: + if self.device.supports_operation_mode: support |= SUPPORT_OPERATION_MODE return support @@ -135,12 +135,12 @@ class KNXClimate(ClimateDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self._device.register_device_updated_cb(after_update_callback) + self.device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self._device.name + return self.device.name @property def available(self): @@ -160,41 +160,41 @@ class KNXClimate(ClimateDevice): @property def current_temperature(self): """Return the current temperature.""" - return self._device.temperature.value + return self.device.temperature.value @property def target_temperature_step(self): """Return the supported step of target temperature.""" - return self._device.setpoint_shift_step + return self.device.setpoint_shift_step @property def target_temperature(self): """Return the temperature we try to reach.""" - return self._device.target_temperature.value + return self.device.target_temperature.value @property def min_temp(self): """Return the minimum temperature.""" - return self._device.target_temperature_min + return self.device.target_temperature_min @property def max_temp(self): """Return the maximum temperature.""" - return self._device.target_temperature_max + return self.device.target_temperature_max async def async_set_temperature(self, **kwargs): """Set new target temperature.""" temperature = kwargs.get(ATTR_TEMPERATURE) if temperature is None: return - await self._device.set_target_temperature(temperature) + await self.device.set_target_temperature(temperature) await self.async_update_ha_state() @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" - if self._device.supports_operation_mode: - return self._device.operation_mode.value + if self.device.supports_operation_mode: + return self.device.operation_mode.value return None @property @@ -202,11 +202,11 @@ class KNXClimate(ClimateDevice): """Return the list of available operation modes.""" return [operation_mode.value for operation_mode in - self._device.get_supported_operation_modes()] + self.device.get_supported_operation_modes()] async def async_set_operation_mode(self, operation_mode): """Set operation mode.""" - if self._device.supports_operation_mode: + if self.device.supports_operation_mode: from xknx.knx import HVACOperationMode knx_operation_mode = HVACOperationMode(operation_mode) - await self._device.set_operation_mode(knx_operation_mode) + await self.device.set_operation_mode(knx_operation_mode) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index 81c5fb3c2aa..321559f10ee 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -57,7 +57,7 @@ class NestThermostat(ClimateDevice): """Initialize the thermostat.""" self._unit = temp_unit self.structure = structure - self._device = device + self.device = device self._fan_list = [STATE_ON, STATE_AUTO] # Set the default supported features @@ -68,13 +68,13 @@ class NestThermostat(ClimateDevice): self._operation_list = [STATE_OFF] # Add supported nest thermostat features - if self._device.can_heat: + if self.device.can_heat: self._operation_list.append(STATE_HEAT) - if self._device.can_cool: + if self.device.can_cool: self._operation_list.append(STATE_COOL) - if self._device.can_heat and self._device.can_cool: + if self.device.can_heat and self.device.can_cool: self._operation_list.append(STATE_AUTO) self._support_flags = (self._support_flags | SUPPORT_TARGET_TEMPERATURE_HIGH | @@ -83,7 +83,7 @@ class NestThermostat(ClimateDevice): self._operation_list.append(STATE_ECO) # feature of device - self._has_fan = self._device.has_fan + self._has_fan = self.device.has_fan if self._has_fan: self._support_flags = (self._support_flags | SUPPORT_FAN_MODE) @@ -125,7 +125,7 @@ class NestThermostat(ClimateDevice): @property def unique_id(self): """Return unique ID for this device.""" - return self._device.serial + return self.device.serial @property def name(self): @@ -202,7 +202,7 @@ class NestThermostat(ClimateDevice): _LOGGER.debug("Nest set_temperature-output-value=%s", temp) try: if temp is not None: - self._device.target = temp + self.device.target = temp except nest.nest.APIError as api_error: _LOGGER.error("An error occurred while setting temperature: %s", api_error) @@ -220,7 +220,7 @@ class NestThermostat(ClimateDevice): _LOGGER.error( "An error occurred while setting device mode. " "Invalid operation mode: %s", operation_mode) - self._device.mode = device_mode + self.device.mode = device_mode @property def operation_list(self): @@ -254,7 +254,7 @@ class NestThermostat(ClimateDevice): def set_fan_mode(self, fan_mode): """Turn fan on/off.""" if self._has_fan: - self._device.fan = fan_mode.lower() + self.device.fan = fan_mode.lower() @property def min_temp(self): @@ -268,20 +268,20 @@ class NestThermostat(ClimateDevice): def update(self): """Cache value from Python-nest.""" - self._location = self._device.where - self._name = self._device.name - self._humidity = self._device.humidity - self._temperature = self._device.temperature - self._mode = self._device.mode - self._target_temperature = self._device.target - self._fan = self._device.fan + self._location = self.device.where + self._name = self.device.name + self._humidity = self.device.humidity + self._temperature = self.device.temperature + self._mode = self.device.mode + self._target_temperature = self.device.target + self._fan = self.device.fan self._away = self.structure.away == 'away' - self._eco_temperature = self._device.eco_temperature - self._locked_temperature = self._device.locked_temperature - self._min_temperature = self._device.min_temperature - self._max_temperature = self._device.max_temperature - self._is_locked = self._device.is_locked - if self._device.temperature_scale == 'C': + self._eco_temperature = self.device.eco_temperature + self._locked_temperature = self.device.locked_temperature + self._min_temperature = self.device.min_temperature + self._max_temperature = self.device.max_temperature + self._is_locked = self.device.is_locked + if self.device.temperature_scale == 'C': self._temperature_scale = TEMP_CELSIUS else: self._temperature_scale = TEMP_FAHRENHEIT diff --git a/homeassistant/components/climate/radiotherm.py b/homeassistant/components/climate/radiotherm.py index 3d1d8e6a53e..429b544aefc 100644 --- a/homeassistant/components/climate/radiotherm.py +++ b/homeassistant/components/climate/radiotherm.py @@ -120,7 +120,7 @@ class RadioThermostat(ClimateDevice): def __init__(self, device, hold_temp, away_temps): """Initialize the thermostat.""" - self._device = device + self.device = device self._target_temperature = None self._current_temperature = None self._current_operation = STATE_IDLE @@ -138,7 +138,7 @@ class RadioThermostat(ClimateDevice): # Fan circulate mode is only supported by the CT80 models. import radiotherm self._is_model_ct80 = isinstance( - self._device, radiotherm.thermostat.CT80) + self.device, radiotherm.thermostat.CT80) @property def supported_features(self): @@ -194,7 +194,7 @@ class RadioThermostat(ClimateDevice): """Turn fan on/off.""" code = FAN_MODE_TO_CODE.get(fan_mode, None) if code is not None: - self._device.fmode = code + self.device.fmode = code @property def current_temperature(self): @@ -234,15 +234,15 @@ class RadioThermostat(ClimateDevice): # First time - get the name from the thermostat. This is # normally set in the radio thermostat web app. if self._name is None: - self._name = self._device.name['raw'] + self._name = self.device.name['raw'] # Request the current state from the thermostat. - data = self._device.tstat['raw'] + data = self.device.tstat['raw'] current_temp = data['temp'] if current_temp == -1: _LOGGER.error('%s (%s) was busy (temp == -1)', self._name, - self._device.host) + self.device.host) return # Map thermostat values into various STATE_ flags. @@ -277,30 +277,30 @@ class RadioThermostat(ClimateDevice): temperature = round_temp(temperature) if self._current_operation == STATE_COOL: - self._device.t_cool = temperature + self.device.t_cool = temperature elif self._current_operation == STATE_HEAT: - self._device.t_heat = temperature + self.device.t_heat = temperature elif self._current_operation == STATE_AUTO: if self._tstate == STATE_COOL: - self._device.t_cool = temperature + self.device.t_cool = temperature elif self._tstate == STATE_HEAT: - self._device.t_heat = temperature + self.device.t_heat = temperature # Only change the hold if requested or if hold mode was turned # on and we haven't set it yet. if kwargs.get('hold_changed', False) or not self._hold_set: if self._hold_temp or self._away: - self._device.hold = 1 + self.device.hold = 1 self._hold_set = True else: - self._device.hold = 0 + self.device.hold = 0 def set_time(self): """Set device time.""" # Calling this clears any local temperature override and # reverts to the scheduled temperature. now = datetime.datetime.now() - self._device.time = { + self.device.time = { 'day': now.weekday(), 'hour': now.hour, 'minute': now.minute @@ -309,13 +309,13 @@ class RadioThermostat(ClimateDevice): def set_operation_mode(self, operation_mode): """Set operation mode (auto, cool, heat, off).""" if operation_mode in (STATE_OFF, STATE_AUTO): - self._device.tmode = TEMP_MODE_TO_CODE[operation_mode] + self.device.tmode = TEMP_MODE_TO_CODE[operation_mode] # Setting t_cool or t_heat automatically changes tmode. elif operation_mode == STATE_COOL: - self._device.t_cool = self._target_temperature + self.device.t_cool = self._target_temperature elif operation_mode == STATE_HEAT: - self._device.t_heat = self._target_temperature + self.device.t_heat = self._target_temperature def turn_away_mode_on(self): """Turn away on. diff --git a/homeassistant/components/cover/knx.py b/homeassistant/components/cover/knx.py index 74ac80a476d..43a87fab367 100644 --- a/homeassistant/components/cover/knx.py +++ b/homeassistant/components/cover/knx.py @@ -96,7 +96,7 @@ class KNXCover(CoverDevice): def __init__(self, hass, device): """Initialize the cover.""" - self._device = device + self.device = device self.hass = hass self.async_register_callbacks() @@ -108,12 +108,12 @@ class KNXCover(CoverDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self._device.register_device_updated_cb(after_update_callback) + self.device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self._device.name + return self.device.name @property def available(self): @@ -130,56 +130,56 @@ class KNXCover(CoverDevice): """Flag supported features.""" supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | \ SUPPORT_SET_POSITION | SUPPORT_STOP - if self._device.supports_angle: + if self.device.supports_angle: supported_features |= SUPPORT_SET_TILT_POSITION return supported_features @property def current_cover_position(self): """Return the current position of the cover.""" - return self._device.current_position() + return self.device.current_position() @property def is_closed(self): """Return if the cover is closed.""" - return self._device.is_closed() + return self.device.is_closed() async def async_close_cover(self, **kwargs): """Close the cover.""" - if not self._device.is_closed(): - await self._device.set_down() + if not self.device.is_closed(): + await self.device.set_down() self.start_auto_updater() async def async_open_cover(self, **kwargs): """Open the cover.""" - if not self._device.is_open(): - await self._device.set_up() + if not self.device.is_open(): + await self.device.set_up() self.start_auto_updater() async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" if ATTR_POSITION in kwargs: position = kwargs[ATTR_POSITION] - await self._device.set_position(position) + await self.device.set_position(position) self.start_auto_updater() async def async_stop_cover(self, **kwargs): """Stop the cover.""" - await self._device.stop() + await self.device.stop() self.stop_auto_updater() @property def current_cover_tilt_position(self): """Return current tilt position of cover.""" - if not self._device.supports_angle: + if not self.device.supports_angle: return None - return self._device.current_angle() + return self.device.current_angle() async def async_set_cover_tilt_position(self, **kwargs): """Move the cover tilt to a specific position.""" if ATTR_TILT_POSITION in kwargs: tilt_position = kwargs[ATTR_TILT_POSITION] - await self._device.set_angle(tilt_position) + await self.device.set_angle(tilt_position) def start_auto_updater(self): """Start the autoupdater to update HASS while cover is moving.""" @@ -197,7 +197,7 @@ class KNXCover(CoverDevice): def auto_updater_hook(self, now): """Call for the autoupdater.""" self.async_schedule_update_ha_state() - if self._device.position_reached(): + if self.device.position_reached(): self.stop_auto_updater() - self.hass.add_job(self._device.auto_stop_if_necessary()) + self.hass.add_job(self.device.auto_stop_if_necessary()) diff --git a/homeassistant/components/cover/tellduslive.py b/homeassistant/components/cover/tellduslive.py index fc352aa8482..9d292d9e8b5 100644 --- a/homeassistant/components/cover/tellduslive.py +++ b/homeassistant/components/cover/tellduslive.py @@ -28,19 +28,19 @@ class TelldusLiveCover(TelldusLiveEntity, CoverDevice): @property def is_closed(self): """Return the current position of the cover.""" - return self._device.is_down + return self.device.is_down def close_cover(self, **kwargs): """Close the cover.""" - self._device.down() + self.device.down() self.changed() def open_cover(self, **kwargs): """Open the cover.""" - self._device.up() + self.device.up() self.changed() def stop_cover(self, **kwargs): """Stop the cover.""" - self._device.stop() + self.device.stop() self.changed() diff --git a/homeassistant/components/juicenet.py b/homeassistant/components/juicenet.py index 2ed32521f1d..55567d45879 100644 --- a/homeassistant/components/juicenet.py +++ b/homeassistant/components/juicenet.py @@ -46,29 +46,29 @@ class JuicenetDevice(Entity): def __init__(self, device, sensor_type, hass): """Initialise the sensor.""" self.hass = hass - self._device = device + self.device = device self.type = sensor_type @property def name(self): """Return the name of the device.""" - return self._device.name() + return self.device.name() def update(self): """Update state of the device.""" - self._device.update_state() + self.device.update_state() @property def _manufacturer_device_id(self): """Return the manufacturer device id.""" - return self._device.id() + return self.device.id() @property def _token(self): """Return the device API token.""" - return self._device.token() + return self.device.token() @property def unique_id(self): """Return a unique ID.""" - return "{}-{}".format(self._device.id(), self.type) + return "{}-{}".format(self.device.id(), self.type) diff --git a/homeassistant/components/light/knx.py b/homeassistant/components/light/knx.py index 23929db8626..778d2fac59c 100644 --- a/homeassistant/components/light/knx.py +++ b/homeassistant/components/light/knx.py @@ -79,7 +79,7 @@ class KNXLight(Light): def __init__(self, hass, device): """Initialize of KNX light.""" - self._device = device + self.device = device self.hass = hass self.async_register_callbacks() @@ -89,12 +89,12 @@ class KNXLight(Light): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self._device.register_device_updated_cb(after_update_callback) + self.device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self._device.name + return self.device.name @property def available(self): @@ -109,15 +109,15 @@ class KNXLight(Light): @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self._device.current_brightness \ - if self._device.supports_brightness else \ + return self.device.current_brightness \ + if self.device.supports_brightness else \ None @property def hs_color(self): """Return the HS color value.""" - if self._device.supports_color: - return color_util.color_RGB_to_hs(*self._device.current_color) + if self.device.supports_color: + return color_util.color_RGB_to_hs(*self.device.current_color) return None @property @@ -143,30 +143,30 @@ class KNXLight(Light): @property def is_on(self): """Return true if light is on.""" - return self._device.state + return self.device.state @property def supported_features(self): """Flag supported features.""" flags = 0 - if self._device.supports_brightness: + if self.device.supports_brightness: flags |= SUPPORT_BRIGHTNESS - if self._device.supports_color: + if self.device.supports_color: flags |= SUPPORT_COLOR return flags async def async_turn_on(self, **kwargs): """Turn the light on.""" if ATTR_BRIGHTNESS in kwargs: - if self._device.supports_brightness: - await self._device.set_brightness(int(kwargs[ATTR_BRIGHTNESS])) + if self.device.supports_brightness: + await self.device.set_brightness(int(kwargs[ATTR_BRIGHTNESS])) elif ATTR_HS_COLOR in kwargs: - if self._device.supports_color: - await self._device.set_color(color_util.color_hs_to_RGB( + if self.device.supports_color: + await self.device.set_color(color_util.color_hs_to_RGB( *kwargs[ATTR_HS_COLOR])) else: - await self._device.set_on() + await self.device.set_on() async def async_turn_off(self, **kwargs): """Turn the light off.""" - await self._device.set_off() + await self.device.set_off() diff --git a/homeassistant/components/light/qwikswitch.py b/homeassistant/components/light/qwikswitch.py index fa986ff09f2..413358d9cee 100644 --- a/homeassistant/components/light/qwikswitch.py +++ b/homeassistant/components/light/qwikswitch.py @@ -27,9 +27,9 @@ class QSLight(QSToggleEntity, Light): @property def brightness(self): """Return the brightness of this light (0-255).""" - return self._device.value if self._device.is_dimmer else None + return self.device.value if self.device.is_dimmer else None @property def supported_features(self): """Flag supported features.""" - return SUPPORT_BRIGHTNESS if self._device.is_dimmer else 0 + return SUPPORT_BRIGHTNESS if self.device.is_dimmer else 0 diff --git a/homeassistant/components/light/tellduslive.py b/homeassistant/components/light/tellduslive.py index 6f39fb3b318..07b5458fa45 100644 --- a/homeassistant/components/light/tellduslive.py +++ b/homeassistant/components/light/tellduslive.py @@ -38,7 +38,7 @@ class TelldusLiveLight(TelldusLiveEntity, Light): @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self._device.dim_level + return self.device.dim_level @property def supported_features(self): @@ -48,15 +48,15 @@ class TelldusLiveLight(TelldusLiveEntity, Light): @property def is_on(self): """Return true if light is on.""" - return self._device.is_on + return self.device.is_on def turn_on(self, **kwargs): """Turn the light on.""" brightness = kwargs.get(ATTR_BRIGHTNESS, self._last_brightness) - self._device.dim(level=brightness) + self.device.dim(level=brightness) self.changed() def turn_off(self, **kwargs): """Turn the light off.""" - self._device.turn_off() + self.device.turn_off() self.changed() diff --git a/homeassistant/components/media_player/emby.py b/homeassistant/components/media_player/emby.py index b64aad38b3e..809db228d02 100644 --- a/homeassistant/components/media_player/emby.py +++ b/homeassistant/components/media_player/emby.py @@ -133,7 +133,7 @@ class EmbyDevice(MediaPlayerDevice): _LOGGER.debug("New Emby Device initialized with ID: %s", device_id) self.emby = emby self.device_id = device_id - self._device = self.emby.devices[self.device_id] + self.device = self.emby.devices[self.device_id] self._hidden = False self._available = True @@ -151,11 +151,11 @@ class EmbyDevice(MediaPlayerDevice): def async_update_callback(self, msg): """Handle device updates.""" # Check if we should update progress - if self._device.media_position: - if self._device.media_position != self.media_status_last_position: - self.media_status_last_position = self._device.media_position + if self.device.media_position: + if self.device.media_position != self.media_status_last_position: + self.media_status_last_position = self.device.media_position self.media_status_received = dt_util.utcnow() - elif not self._device.is_nowplaying: + elif not self.device.is_nowplaying: # No position, but we have an old value and are still playing self.media_status_last_position = None self.media_status_received = None @@ -188,12 +188,12 @@ class EmbyDevice(MediaPlayerDevice): @property def supports_remote_control(self): """Return control ability.""" - return self._device.supports_remote_control + return self.device.supports_remote_control @property def name(self): """Return the name of the device.""" - return ('Emby - {} - {}'.format(self._device.client, self._device.name) + return ('Emby - {} - {}'.format(self.device.client, self.device.name) or DEVICE_DEFAULT_NAME) @property @@ -204,7 +204,7 @@ class EmbyDevice(MediaPlayerDevice): @property def state(self): """Return the state of the device.""" - state = self._device.state + state = self.device.state if state == 'Paused': return STATE_PAUSED if state == 'Playing': @@ -218,17 +218,17 @@ class EmbyDevice(MediaPlayerDevice): def app_name(self): """Return current user as app_name.""" # Ideally the media_player object would have a user property. - return self._device.username + return self.device.username @property def media_content_id(self): """Content ID of current playing media.""" - return self._device.media_id + return self.device.media_id @property def media_content_type(self): """Content type of current playing media.""" - media_type = self._device.media_type + media_type = self.device.media_type if media_type == 'Episode': return MEDIA_TYPE_TVSHOW if media_type == 'Movie': @@ -246,7 +246,7 @@ class EmbyDevice(MediaPlayerDevice): @property def media_duration(self): """Return the duration of current playing media in seconds.""" - return self._device.media_runtime + return self.device.media_runtime @property def media_position(self): @@ -265,42 +265,42 @@ class EmbyDevice(MediaPlayerDevice): @property def media_image_url(self): """Return the image URL of current playing media.""" - return self._device.media_image_url + return self.device.media_image_url @property def media_title(self): """Return the title of current playing media.""" - return self._device.media_title + return self.device.media_title @property def media_season(self): """Season of current playing media (TV Show only).""" - return self._device.media_season + return self.device.media_season @property def media_series_title(self): """Return the title of the series of current playing media (TV).""" - return self._device.media_series_title + return self.device.media_series_title @property def media_episode(self): """Return the episode of current playing media (TV only).""" - return self._device.media_episode + return self.device.media_episode @property def media_album_name(self): """Return the album name of current playing media (Music only).""" - return self._device.media_album_name + return self.device.media_album_name @property def media_artist(self): """Return the artist of current playing media (Music track only).""" - return self._device.media_artist + return self.device.media_artist @property def media_album_artist(self): """Return the album artist of current playing media (Music only).""" - return self._device.media_album_artist + return self.device.media_album_artist @property def supported_features(self): @@ -314,39 +314,39 @@ class EmbyDevice(MediaPlayerDevice): This method must be run in the event loop and returns a coroutine. """ - return self._device.media_play() + return self.device.media_play() def async_media_pause(self): """Pause the media player. This method must be run in the event loop and returns a coroutine. """ - return self._device.media_pause() + return self.device.media_pause() def async_media_stop(self): """Stop the media player. This method must be run in the event loop and returns a coroutine. """ - return self._device.media_stop() + return self.device.media_stop() def async_media_next_track(self): """Send next track command. This method must be run in the event loop and returns a coroutine. """ - return self._device.media_next() + return self.device.media_next() def async_media_previous_track(self): """Send next track command. This method must be run in the event loop and returns a coroutine. """ - return self._device.media_previous() + return self.device.media_previous() def async_media_seek(self, position): """Send seek command. This method must be run in the event loop and returns a coroutine. """ - return self._device.media_seek(position) + return self.device.media_seek(position) diff --git a/homeassistant/components/media_player/plex.py b/homeassistant/components/media_player/plex.py index 3c916860818..35906cf5023 100644 --- a/homeassistant/components/media_player/plex.py +++ b/homeassistant/components/media_player/plex.py @@ -454,7 +454,7 @@ class PlexClient(MediaPlayerDevice): elif self._player_state == 'paused': self._is_player_active = True self._state = STATE_PAUSED - elif self._device: + elif self.device: self._is_player_active = False self._state = STATE_IDLE else: @@ -528,6 +528,11 @@ class PlexClient(MediaPlayerDevice): """Return the library name of playing media.""" return self._app_name + @property + def device(self): + """Return the device, if any.""" + return self.device + @property def marked_unavailable(self): """Return time device was marked unavailable.""" @@ -666,7 +671,7 @@ class PlexClient(MediaPlayerDevice): SUPPORT_TURN_OFF) # Not all devices support playback functionality # Playback includes volume, stop/play/pause, etc. - if self._device and 'playback' in self._device_protocol_capabilities: + if self.device and 'playback' in self._device_protocol_capabilities: return (SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | SUPPORT_STOP | SUPPORT_VOLUME_SET | SUPPORT_PLAY | @@ -676,22 +681,22 @@ class PlexClient(MediaPlayerDevice): def set_volume_level(self, volume): """Set volume level, range 0..1.""" - if self._device and 'playback' in self._device_protocol_capabilities: - self._device.setVolume( + if self.device and 'playback' in self._device_protocol_capabilities: + self.device.setVolume( int(volume * 100), self._active_media_plexapi_type) self._volume_level = volume # store since we can't retrieve @property def volume_level(self): """Return the volume level of the client (0..1).""" - if (self._is_player_active and self._device and + if (self._is_player_active and self.device and 'playback' in self._device_protocol_capabilities): return self._volume_level @property def is_volume_muted(self): """Return boolean if volume is currently muted.""" - if self._is_player_active and self._device: + if self._is_player_active and self.device: return self._volume_muted def mute_volume(self, mute): @@ -701,7 +706,7 @@ class PlexClient(MediaPlayerDevice): - On mute, store volume and set volume to 0 - On unmute, set volume to previously stored volume """ - if not (self._device and + if not (self.device and 'playback' in self._device_protocol_capabilities): return @@ -714,18 +719,18 @@ class PlexClient(MediaPlayerDevice): def media_play(self): """Send play command.""" - if self._device and 'playback' in self._device_protocol_capabilities: - self._device.play(self._active_media_plexapi_type) + if self.device and 'playback' in self._device_protocol_capabilities: + self.device.play(self._active_media_plexapi_type) def media_pause(self): """Send pause command.""" - if self._device and 'playback' in self._device_protocol_capabilities: - self._device.pause(self._active_media_plexapi_type) + if self.device and 'playback' in self._device_protocol_capabilities: + self.device.pause(self._active_media_plexapi_type) def media_stop(self): """Send stop command.""" - if self._device and 'playback' in self._device_protocol_capabilities: - self._device.stop(self._active_media_plexapi_type) + if self.device and 'playback' in self._device_protocol_capabilities: + self.device.stop(self._active_media_plexapi_type) def turn_off(self): """Turn the client off.""" @@ -734,17 +739,17 @@ class PlexClient(MediaPlayerDevice): def media_next_track(self): """Send next track command.""" - if self._device and 'playback' in self._device_protocol_capabilities: - self._device.skipNext(self._active_media_plexapi_type) + if self.device and 'playback' in self._device_protocol_capabilities: + self.device.skipNext(self._active_media_plexapi_type) def media_previous_track(self): """Send previous track command.""" - if self._device and 'playback' in self._device_protocol_capabilities: - self._device.skipPrevious(self._active_media_plexapi_type) + if self.device and 'playback' in self._device_protocol_capabilities: + self.device.skipPrevious(self._active_media_plexapi_type) def play_media(self, media_type, media_id, **kwargs): """Play a piece of media.""" - if not (self._device and + if not (self.device and 'playback' in self._device_protocol_capabilities): return @@ -752,7 +757,7 @@ class PlexClient(MediaPlayerDevice): media = None if media_type == 'MUSIC': - media = self._device.server.library.section( + media = self.device.server.library.section( src['library_name']).get(src['artist_name']).album( src['album_name']).get(src['track_name']) elif media_type == 'EPISODE': @@ -760,9 +765,9 @@ class PlexClient(MediaPlayerDevice): src['library_name'], src['show_name'], src['season_number'], src['episode_number']) elif media_type == 'PLAYLIST': - media = self._device.server.playlist(src['playlist_name']) + media = self.device.server.playlist(src['playlist_name']) elif media_type == 'VIDEO': - media = self._device.server.library.section( + media = self.device.server.library.section( src['library_name']).get(src['video_name']) import plexapi.playlist @@ -780,13 +785,13 @@ class PlexClient(MediaPlayerDevice): target_season = None target_episode = None - show = self._device.server.library.section(library_name).get( + show = self.device.server.library.section(library_name).get( show_name) if not season_number: playlist_name = "{} - {} Episodes".format( self.entity_id, show_name) - return self._device.server.createPlaylist( + return self.device.server.createPlaylist( playlist_name, show.episodes()) for season in show.seasons(): @@ -803,7 +808,7 @@ class PlexClient(MediaPlayerDevice): if not episode_number: playlist_name = "{} - {} Season {} Episodes".format( self.entity_id, show_name, str(season_number)) - return self._device.server.createPlaylist( + return self.device.server.createPlaylist( playlist_name, target_season.episodes()) for episode in target_season.episodes(): @@ -821,22 +826,22 @@ class PlexClient(MediaPlayerDevice): def _client_play_media(self, media, delete=False, **params): """Instruct Plex client to play a piece of media.""" - if not (self._device and + if not (self.device and 'playback' in self._device_protocol_capabilities): _LOGGER.error("Client cannot play media: %s", self.entity_id) return import plexapi.playqueue playqueue = plexapi.playqueue.PlayQueue.create( - self._device.server, media, **params) + self.device.server, media, **params) # Delete dynamic playlists used to build playqueue (ex. play tv season) if delete: media.delete() - server_url = self._device.server.baseurl.split(':') - self._device.sendCommand('playback/playMedia', **dict({ - 'machineIdentifier': self._device.server.machineIdentifier, + server_url = self.device.server.baseurl.split(':') + self.device.sendCommand('playback/playMedia', **dict({ + 'machineIdentifier': self.device.server.machineIdentifier, 'address': server_url[1].strip('/'), 'port': server_url[-1], 'key': media.key, diff --git a/homeassistant/components/media_player/soundtouch.py b/homeassistant/components/media_player/soundtouch.py index 489d028aad4..4e26af9dcc2 100644 --- a/homeassistant/components/media_player/soundtouch.py +++ b/homeassistant/components/media_player/soundtouch.py @@ -323,8 +323,8 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to create zone without slaves") else: _LOGGER.info("Creating zone with master %s", - self.device.config.name) - self.device.create_zone([slave.device for slave in slaves]) + self._device.config.name) + self._device.create_zone([slave.device for slave in slaves]) def remove_zone_slave(self, slaves): """ @@ -341,8 +341,8 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to find slaves to remove") else: _LOGGER.info("Removing slaves from zone with master %s", - self.device.config.name) - self.device.remove_zone_slave([slave.device for slave in slaves]) + self._device.config.name) + self._device.remove_zone_slave([slave.device for slave in slaves]) def add_zone_slave(self, slaves): """ @@ -357,5 +357,5 @@ class SoundTouchDevice(MediaPlayerDevice): _LOGGER.warning("Unable to find slaves to add") else: _LOGGER.info("Adding slaves to zone with master %s", - self.device.config.name) - self.device.add_zone_slave([slave.device for slave in slaves]) + self._device.config.name) + self._device.add_zone_slave([slave.device for slave in slaves]) diff --git a/homeassistant/components/nest/__init__.py b/homeassistant/components/nest/__init__.py index 04163f1ca13..57111350396 100644 --- a/homeassistant/components/nest/__init__.py +++ b/homeassistant/components/nest/__init__.py @@ -282,12 +282,12 @@ class NestSensorDevice(Entity): if device is not None: # device specific - self._device = device - self._name = "{} {}".format(self._device.name_long, + self.device = device + self._name = "{} {}".format(self.device.name_long, self.variable.replace('_', ' ')) else: # structure only - self._device = structure + self.device = structure self._name = "{} {}".format(self.structure.name, self.variable.replace('_', ' ')) diff --git a/homeassistant/components/notify/knx.py b/homeassistant/components/notify/knx.py index f9a6a4b25f2..750e3945569 100644 --- a/homeassistant/components/notify/knx.py +++ b/homeassistant/components/notify/knx.py @@ -61,13 +61,13 @@ class KNXNotificationService(BaseNotificationService): def __init__(self, devices): """Initialize the service.""" - self._devices = devices + self.devices = devices @property def targets(self): """Return a dictionary of registered targets.""" ret = {} - for device in self._devices: + for device in self.devices: ret[device.name] = device.name return ret @@ -80,11 +80,11 @@ class KNXNotificationService(BaseNotificationService): async def _async_send_to_all_devices(self, message): """Send a notification to knx bus to all connected devices.""" - for device in self._devices: + for device in self.devices: await device.set(message) async def _async_send_to_device(self, message, names): """Send a notification to knx bus to device with given names.""" - for device in self._devices: + for device in self.devices: if device.name in names: await device.set(message) diff --git a/homeassistant/components/qwikswitch.py b/homeassistant/components/qwikswitch.py index 8af0e8db28d..63e30a9491e 100644 --- a/homeassistant/components/qwikswitch.py +++ b/homeassistant/components/qwikswitch.py @@ -98,13 +98,13 @@ class QSToggleEntity(QSEntity): def __init__(self, qsid, qsusb): """Initialize the ToggleEntity.""" - self._device = qsusb.devices[qsid] - super().__init__(qsid, self._device.name) + self.device = qsusb.devices[qsid] + super().__init__(qsid, self.device.name) @property def is_on(self): """Check if device is on (non-zero).""" - return self._device.value > 0 + return self.device.value > 0 async def async_turn_on(self, **kwargs): """Turn the device on.""" diff --git a/homeassistant/components/remote/xiaomi_miio.py b/homeassistant/components/remote/xiaomi_miio.py index 7fbcba5a26e..723f575ba34 100644 --- a/homeassistant/components/remote/xiaomi_miio.py +++ b/homeassistant/components/remote/xiaomi_miio.py @@ -188,6 +188,11 @@ class XiaomiMiioRemote(RemoteDevice): """Return the name of the remote.""" return self._name + @property + def device(self): + """Return the remote object.""" + return self._device + @property def hidden(self): """Return if we should hide entity.""" @@ -208,7 +213,7 @@ class XiaomiMiioRemote(RemoteDevice): """Return False if device is unreachable, else True.""" from miio import DeviceException try: - self._device.info() + self.device.info() return True except DeviceException: return False @@ -243,7 +248,7 @@ class XiaomiMiioRemote(RemoteDevice): _LOGGER.debug("Sending payload: '%s'", payload) try: - self._device.play(payload) + self.device.play(payload) except DeviceException as ex: _LOGGER.error( "Transmit of IR command failed, %s, exception: %s", diff --git a/homeassistant/components/sensor/juicenet.py b/homeassistant/components/sensor/juicenet.py index b8ef38981e8..18725394a1f 100644 --- a/homeassistant/components/sensor/juicenet.py +++ b/homeassistant/components/sensor/juicenet.py @@ -49,14 +49,14 @@ class JuicenetSensorDevice(JuicenetDevice, Entity): @property def name(self): """Return the name of the device.""" - return '{} {}'.format(self._device.name(), self._name) + return '{} {}'.format(self.device.name(), self._name) @property def icon(self): """Return the icon of the sensor.""" icon = None if self.type == 'status': - status = self._device.getStatus() + status = self.device.getStatus() if status == 'standby': icon = 'mdi:power-plug-off' elif status == 'plugged': @@ -87,19 +87,19 @@ class JuicenetSensorDevice(JuicenetDevice, Entity): """Return the state.""" state = None if self.type == 'status': - state = self._device.getStatus() + state = self.device.getStatus() elif self.type == 'temperature': - state = self._device.getTemperature() + state = self.device.getTemperature() elif self.type == 'voltage': - state = self._device.getVoltage() + state = self.device.getVoltage() elif self.type == 'amps': - state = self._device.getAmps() + state = self.device.getAmps() elif self.type == 'watts': - state = self._device.getWatts() + state = self.device.getWatts() elif self.type == 'charge_time': - state = self._device.getChargeTime() + state = self.device.getChargeTime() elif self.type == 'energy_added': - state = self._device.getEnergyAdded() + state = self.device.getEnergyAdded() else: state = 'Unknown' return state @@ -109,7 +109,7 @@ class JuicenetSensorDevice(JuicenetDevice, Entity): """Return the state attributes.""" attributes = {} if self.type == 'status': - man_dev_id = self._device.id() + man_dev_id = self.device.id() if man_dev_id: attributes["manufacturer_device_id"] = man_dev_id return attributes diff --git a/homeassistant/components/sensor/knx.py b/homeassistant/components/sensor/knx.py index b8b55a1cc7c..ec506189c12 100644 --- a/homeassistant/components/sensor/knx.py +++ b/homeassistant/components/sensor/knx.py @@ -64,7 +64,7 @@ class KNXSensor(Entity): def __init__(self, hass, device): """Initialize of a KNX sensor.""" - self._device = device + self.device = device self.hass = hass self.async_register_callbacks() @@ -74,12 +74,12 @@ class KNXSensor(Entity): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self._device.register_device_updated_cb(after_update_callback) + self.device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self._device.name + return self.device.name @property def available(self): @@ -94,12 +94,12 @@ class KNXSensor(Entity): @property def state(self): """Return the state of the sensor.""" - return self._device.resolve_state() + return self.device.resolve_state() @property def unit_of_measurement(self): """Return the unit this state is expressed in.""" - return self._device.unit_of_measurement() + return self.device.unit_of_measurement() @property def device_state_attributes(self): diff --git a/homeassistant/components/sensor/nest.py b/homeassistant/components/sensor/nest.py index d51b0ab4053..738bc53d880 100644 --- a/homeassistant/components/sensor/nest.py +++ b/homeassistant/components/sensor/nest.py @@ -140,15 +140,15 @@ class NestBasicSensor(NestSensorDevice): self._unit = SENSOR_UNITS.get(self.variable) if self.variable in VARIABLE_NAME_MAPPING: - self._state = getattr(self._device, + self._state = getattr(self.device, VARIABLE_NAME_MAPPING[self.variable]) elif self.variable in PROTECT_SENSOR_TYPES \ and self.variable != 'color_status': # keep backward compatibility - state = getattr(self._device, self.variable) + state = getattr(self.device, self.variable) self._state = state.capitalize() if state is not None else None else: - self._state = getattr(self._device, self.variable) + self._state = getattr(self.device, self.variable) class NestTempSensor(NestSensorDevice): @@ -166,12 +166,12 @@ class NestTempSensor(NestSensorDevice): def update(self): """Retrieve latest state.""" - if self._device.temperature_scale == 'C': + if self.device.temperature_scale == 'C': self._unit = TEMP_CELSIUS else: self._unit = TEMP_FAHRENHEIT - temp = getattr(self._device, self.variable) + temp = getattr(self.device, self.variable) if temp is None: self._state = None diff --git a/homeassistant/components/sensor/tank_utility.py b/homeassistant/components/sensor/tank_utility.py index c3cc75dac0c..55928a80f13 100644 --- a/homeassistant/components/sensor/tank_utility.py +++ b/homeassistant/components/sensor/tank_utility.py @@ -79,10 +79,15 @@ class TankUtilitySensor(Entity): self._token = token self._device = device self._state = STATE_UNKNOWN - self._name = "Tank Utility " + self._device + self._name = "Tank Utility " + self.device self._unit_of_measurement = SENSOR_UNIT_OF_MEASUREMENT self._attributes = {} + @property + def device(self): + """Return the device identifier.""" + return self._device + @property def state(self): """Return the state of the device.""" @@ -112,14 +117,14 @@ class TankUtilitySensor(Entity): from tank_utility import auth, device data = {} try: - data = device.get_device_data(self._token, self._device) + data = device.get_device_data(self._token, self.device) except requests.exceptions.HTTPError as http_error: if (http_error.response.status_code == requests.codes.unauthorized): # pylint: disable=no-member _LOGGER.info("Getting new token") self._token = auth.get_token(self._email, self._password, force=True) - data = device.get_device_data(self._token, self._device) + data = device.get_device_data(self._token, self.device) else: raise http_error data.update(data.pop("device", {})) diff --git a/homeassistant/components/sensor/tellduslive.py b/homeassistant/components/sensor/tellduslive.py index 34908595951..4676e08a247 100644 --- a/homeassistant/components/sensor/tellduslive.py +++ b/homeassistant/components/sensor/tellduslive.py @@ -67,7 +67,7 @@ class TelldusLiveSensor(TelldusLiveEntity): @property def _value(self): """Return value of the sensor.""" - return self._device.value(*self._id[1:]) + return self.device.value(*self._id[1:]) @property def _value_as_temperature(self): diff --git a/homeassistant/components/switch/knx.py b/homeassistant/components/switch/knx.py index af60cee127a..678a8d4775f 100644 --- a/homeassistant/components/switch/knx.py +++ b/homeassistant/components/switch/knx.py @@ -63,7 +63,7 @@ class KNXSwitch(SwitchDevice): def __init__(self, hass, device): """Initialize of KNX switch.""" - self._device = device + self.device = device self.hass = hass self.async_register_callbacks() @@ -73,12 +73,12 @@ class KNXSwitch(SwitchDevice): async def after_update_callback(device): """Call after device was updated.""" await self.async_update_ha_state() - self._device.register_device_updated_cb(after_update_callback) + self.device.register_device_updated_cb(after_update_callback) @property def name(self): """Return the name of the KNX device.""" - return self._device.name + return self.device.name @property def available(self): @@ -93,12 +93,12 @@ class KNXSwitch(SwitchDevice): @property def is_on(self): """Return true if device is on.""" - return self._device.state + return self.device.state async def async_turn_on(self, **kwargs): """Turn the device on.""" - await self._device.set_on() + await self.device.set_on() async def async_turn_off(self, **kwargs): """Turn the device off.""" - await self._device.set_off() + await self.device.set_off() diff --git a/homeassistant/components/switch/tellduslive.py b/homeassistant/components/switch/tellduslive.py index c1134fc21c1..0263dfd8198 100644 --- a/homeassistant/components/switch/tellduslive.py +++ b/homeassistant/components/switch/tellduslive.py @@ -28,14 +28,14 @@ class TelldusLiveSwitch(TelldusLiveEntity, ToggleEntity): @property def is_on(self): """Return true if switch is on.""" - return self._device.is_on + return self.device.is_on def turn_on(self, **kwargs): """Turn the switch on.""" - self._device.turn_on() + self.device.turn_on() self.changed() def turn_off(self, **kwargs): """Turn the switch off.""" - self._device.turn_off() + self.device.turn_off() self.changed() diff --git a/homeassistant/components/tellduslive.py b/homeassistant/components/tellduslive.py index 58be267bbbc..693499510ad 100644 --- a/homeassistant/components/tellduslive.py +++ b/homeassistant/components/tellduslive.py @@ -287,14 +287,14 @@ class TelldusLiveEntity(Entity): self._id = device_id self._client = hass.data[DOMAIN] self._client.entities.append(self) - self._device = self._client.device(device_id) - self._name = self._device.name + self.device = self._client.device(device_id) + self._name = self.device.name _LOGGER.debug('Created device %s', self) def changed(self): """Return the property of the device might have changed.""" - if self._device.name: - self._name = self._device.name + if self.device.name: + self._name = self.device.name self.schedule_update_ha_state() @property @@ -302,10 +302,15 @@ class TelldusLiveEntity(Entity): """Return the id of the device.""" return self._id + @property + def device(self): + """Return the representation of the device.""" + return self._client.device(self.device_id) + @property def _state(self): """Return the state of the device.""" - return self._device.state + return self.device.state @property def should_poll(self): @@ -343,16 +348,16 @@ class TelldusLiveEntity(Entity): from tellduslive import (BATTERY_LOW, BATTERY_UNKNOWN, BATTERY_OK) - if self._device.battery == BATTERY_LOW: + if self.device.battery == BATTERY_LOW: return 1 - if self._device.battery == BATTERY_UNKNOWN: + if self.device.battery == BATTERY_UNKNOWN: return None - if self._device.battery == BATTERY_OK: + if self.device.battery == BATTERY_OK: return 100 - return self._device.battery # Percentage + return self.device.battery # Percentage @property def _last_updated(self): """Return the last update of a device.""" - return str(datetime.fromtimestamp(self._device.lastUpdated)) \ - if self._device.lastUpdated else None + return str(datetime.fromtimestamp(self.device.lastUpdated)) \ + if self.device.lastUpdated else None From 16ad9c2ae64780104529ba95dee23c2730a3f1da Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 22:52:21 +0200 Subject: [PATCH 136/159] Update translations --- homeassistant/components/hangouts/.translations/en.json | 2 +- homeassistant/components/hangouts/.translations/pl.json | 2 +- homeassistant/components/hangouts/.translations/ru.json | 5 +++++ .../components/homematicip_cloud/.translations/pt-BR.json | 1 + .../components/homematicip_cloud/.translations/zh-Hant.json | 1 + homeassistant/components/hue/.translations/pt-BR.json | 2 +- 6 files changed, 10 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/hangouts/.translations/en.json b/homeassistant/components/hangouts/.translations/en.json index eb278afaf7f..6e70a1f4310 100644 --- a/homeassistant/components/hangouts/.translations/en.json +++ b/homeassistant/components/hangouts/.translations/en.json @@ -6,7 +6,7 @@ }, "error": { "invalid_2fa": "Invalid 2 Factor Authorization, please try again.", - "invalid_2fa_method": "Invalig 2FA Method (Verify on Phone).", + "invalid_2fa_method": "Invalid 2FA Method (Verify on Phone).", "invalid_login": "Invalid Login, please try again." }, "step": { diff --git a/homeassistant/components/hangouts/.translations/pl.json b/homeassistant/components/hangouts/.translations/pl.json index 9cbc02f126e..a8314761f8d 100644 --- a/homeassistant/components/hangouts/.translations/pl.json +++ b/homeassistant/components/hangouts/.translations/pl.json @@ -21,7 +21,7 @@ "email": "Adres e-mail", "password": "Has\u0142o" }, - "title": "Login Google Hangouts" + "title": "Logowanie do Google Hangouts" } }, "title": "Google Hangouts" diff --git a/homeassistant/components/hangouts/.translations/ru.json b/homeassistant/components/hangouts/.translations/ru.json index 730d9404837..c3363215201 100644 --- a/homeassistant/components/hangouts/.translations/ru.json +++ b/homeassistant/components/hangouts/.translations/ru.json @@ -5,10 +5,15 @@ "unknown": "\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430" }, "error": { + "invalid_2fa": "\u041d\u0435\u0432\u0435\u0440\u043d\u0430\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430.", + "invalid_2fa_method": "\u041d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 (\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435).", "invalid_login": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043b\u043e\u0433\u0438\u043d, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430." }, "step": { "2fa": { + "data": { + "2fa": "\u041f\u0438\u043d-\u043a\u043e\u0434 \u0434\u043b\u044f \u0434\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438" + }, "title": "\u0414\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f" }, "user": { diff --git a/homeassistant/components/homematicip_cloud/.translations/pt-BR.json b/homeassistant/components/homematicip_cloud/.translations/pt-BR.json index 6e5af1c26cc..d4ecbe50107 100644 --- a/homeassistant/components/homematicip_cloud/.translations/pt-BR.json +++ b/homeassistant/components/homematicip_cloud/.translations/pt-BR.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "O Accesspoint j\u00e1 est\u00e1 configurado", "conection_aborted": "N\u00e3o foi poss\u00edvel conectar ao servidor HMIP", + "connection_aborted": "N\u00e3o foi poss\u00edvel conectar ao servidor HMIP", "unknown": "Ocorreu um erro desconhecido." }, "error": { diff --git a/homeassistant/components/homematicip_cloud/.translations/zh-Hant.json b/homeassistant/components/homematicip_cloud/.translations/zh-Hant.json index d8c6cff9b0c..9340070d9a3 100644 --- a/homeassistant/components/homematicip_cloud/.translations/zh-Hant.json +++ b/homeassistant/components/homematicip_cloud/.translations/zh-Hant.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "Accesspoint \u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210", "conection_aborted": "\u7121\u6cd5\u9023\u7dda\u81f3 HMIP \u4f3a\u670d\u5668", + "connection_aborted": "\u7121\u6cd5\u9023\u7dda\u81f3 HMIP \u4f3a\u670d\u5668", "unknown": "\u767c\u751f\u672a\u77e5\u932f\u8aa4\u3002" }, "error": { diff --git a/homeassistant/components/hue/.translations/pt-BR.json b/homeassistant/components/hue/.translations/pt-BR.json index 5c6e409245c..b30764c9239 100644 --- a/homeassistant/components/hue/.translations/pt-BR.json +++ b/homeassistant/components/hue/.translations/pt-BR.json @@ -24,6 +24,6 @@ "title": "Hub de links" } }, - "title": "Philips Hue" + "title": "" } } \ No newline at end of file From 8fb66c351e9c9edcf75eccfcc6aecbdb2ea6382a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 22:52:58 +0200 Subject: [PATCH 137/159] Add new translations --- .../components/hangouts/.translations/it.json | 5 +++ .../components/hangouts/.translations/no.json | 13 ++++++++ .../hangouts/.translations/pt-BR.json | 28 +++++++++++++++++ .../hangouts/.translations/zh-Hant.json | 31 +++++++++++++++++++ .../homematicip_cloud/.translations/it.json | 11 +++++++ .../sensor/.translations/moon.it.json | 8 +++++ .../sensor/.translations/moon.pt-BR.json | 12 +++++++ 7 files changed, 108 insertions(+) create mode 100644 homeassistant/components/hangouts/.translations/it.json create mode 100644 homeassistant/components/hangouts/.translations/no.json create mode 100644 homeassistant/components/hangouts/.translations/pt-BR.json create mode 100644 homeassistant/components/hangouts/.translations/zh-Hant.json create mode 100644 homeassistant/components/homematicip_cloud/.translations/it.json create mode 100644 homeassistant/components/sensor/.translations/moon.it.json create mode 100644 homeassistant/components/sensor/.translations/moon.pt-BR.json diff --git a/homeassistant/components/hangouts/.translations/it.json b/homeassistant/components/hangouts/.translations/it.json new file mode 100644 index 00000000000..0c609b3430a --- /dev/null +++ b/homeassistant/components/hangouts/.translations/it.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/no.json b/homeassistant/components/hangouts/.translations/no.json new file mode 100644 index 00000000000..7ea074470c7 --- /dev/null +++ b/homeassistant/components/hangouts/.translations/no.json @@ -0,0 +1,13 @@ +{ + "config": { + "step": { + "user": { + "data": { + "email": "E-postadresse", + "password": "Passord" + } + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/pt-BR.json b/homeassistant/components/hangouts/.translations/pt-BR.json new file mode 100644 index 00000000000..4dffe492c4d --- /dev/null +++ b/homeassistant/components/hangouts/.translations/pt-BR.json @@ -0,0 +1,28 @@ +{ + "config": { + "abort": { + "already_configured": "Hangouts do Google j\u00e1 est\u00e1 configurado.", + "unknown": "Ocorreu um erro desconhecido." + }, + "error": { + "invalid_2fa_method": "M\u00e9todo 2FA inv\u00e1lido (verificar no telefone).", + "invalid_login": "Login inv\u00e1lido, por favor, tente novamente." + }, + "step": { + "2fa": { + "data": { + "2fa": "Pin 2FA" + }, + "title": "" + }, + "user": { + "data": { + "email": "Endere\u00e7o de e-mail", + "password": "Senha" + }, + "title": "Login do Hangouts do Google" + } + }, + "title": "Hangouts do Google" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/zh-Hant.json b/homeassistant/components/hangouts/.translations/zh-Hant.json new file mode 100644 index 00000000000..0920e0325d2 --- /dev/null +++ b/homeassistant/components/hangouts/.translations/zh-Hant.json @@ -0,0 +1,31 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts \u5df2\u7d93\u8a2d\u5b9a", + "unknown": "\u767c\u751f\u672a\u77e5\u932f\u8aa4\u3002" + }, + "error": { + "invalid_2fa": "\u5169\u968e\u6bb5\u9a57\u8b49\u7121\u6548\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", + "invalid_2fa_method": "\u8a8d\u8b49\u65b9\u5f0f\u7121\u6548\uff08\u65bc\u96fb\u8a71\u4e0a\u9a57\u8b49\uff09\u3002", + "invalid_login": "\u767b\u5165\u5931\u6557\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002" + }, + "step": { + "2fa": { + "data": { + "2fa": "\u8a8d\u8b49\u78bc" + }, + "description": "\u7a7a\u767d", + "title": "\u5169\u968e\u6bb5\u8a8d\u8b49" + }, + "user": { + "data": { + "email": "\u96fb\u5b50\u90f5\u4ef6", + "password": "\u5bc6\u78bc" + }, + "description": "\u7a7a\u767d", + "title": "\u767b\u5165 Google Hangouts" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/.translations/it.json b/homeassistant/components/homematicip_cloud/.translations/it.json new file mode 100644 index 00000000000..2566eb25570 --- /dev/null +++ b/homeassistant/components/homematicip_cloud/.translations/it.json @@ -0,0 +1,11 @@ +{ + "config": { + "step": { + "init": { + "data": { + "pin": "Codice Pin (opzionale)" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.it.json b/homeassistant/components/sensor/.translations/moon.it.json new file mode 100644 index 00000000000..fce5152b3f9 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.it.json @@ -0,0 +1,8 @@ +{ + "state": { + "first_quarter": "Primo quarto", + "full_moon": "Luna piena", + "last_quarter": "Ultimo quarto", + "new_moon": "Nuova luna" + } +} \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/moon.pt-BR.json b/homeassistant/components/sensor/.translations/moon.pt-BR.json new file mode 100644 index 00000000000..af4cefff6e5 --- /dev/null +++ b/homeassistant/components/sensor/.translations/moon.pt-BR.json @@ -0,0 +1,12 @@ +{ + "state": { + "first_quarter": "Quarto crescente", + "full_moon": "Cheia", + "last_quarter": "Quarto minguante", + "new_moon": "Nova", + "waning_crescent": "Minguante", + "waning_gibbous": "Minguante gibosa", + "waxing_crescent": "Crescente", + "waxing_gibbous": "Crescente gibosa" + } +} \ No newline at end of file From 84131011489def5f55924f396561d07033d380c7 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 22:53:20 +0200 Subject: [PATCH 138/159] Bumped version to 0.77.0b2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index c299b5a2a73..cc0c9294506 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 77 -PATCH_VERSION = '0b1' +PATCH_VERSION = '0b2' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From adb5579690366cd80943a1744ac0266f52cc3cf9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 10:16:59 +0200 Subject: [PATCH 139/159] Update translations --- .../components/auth/.translations/ca.json | 16 ++++++++++++++++ .../components/auth/.translations/en.json | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 homeassistant/components/auth/.translations/ca.json diff --git a/homeassistant/components/auth/.translations/ca.json b/homeassistant/components/auth/.translations/ca.json new file mode 100644 index 00000000000..1b3b25dbcff --- /dev/null +++ b/homeassistant/components/auth/.translations/ca.json @@ -0,0 +1,16 @@ +{ + "mfa_setup": { + "totp": { + "error": { + "invalid_code": "Codi no v\u00e0lid, si us plau torni a provar-ho. Si obteniu aquest error repetidament, assegureu-vos que la data i hora de Home Assistant sigui correcta i precisa." + }, + "step": { + "init": { + "description": "Per activar la verificaci\u00f3 en dos passos mitjan\u00e7ant contrasenyes d'un sol \u00fas basades en temps, escanegeu el codi QR amb la vostre aplicaci\u00f3 de verificaci\u00f3. Si no en teniu cap, us recomanem [Google Authenticator](https://support.google.com/accounts/answer/1066447) o b\u00e9 [Authy](https://authy.com/). \n\n {qr_code} \n \nDespr\u00e9s d'escanejar el codi QR, introdu\u00efu el codi de sis d\u00edgits proporcionat per l'aplicaci\u00f3. Si teniu problemes per escanejar el codi QR, feu una configuraci\u00f3 manual amb el codi **`{code}`**.", + "title": "Configureu la verificaci\u00f3 en dos passos utilitzant TOTP" + } + }, + "title": "TOTP" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/auth/.translations/en.json b/homeassistant/components/auth/.translations/en.json index 5c1af67b120..a0fd20e9d08 100644 --- a/homeassistant/components/auth/.translations/en.json +++ b/homeassistant/components/auth/.translations/en.json @@ -2,12 +2,12 @@ "mfa_setup": { "totp": { "error": { - "invalid_code": "Invalid code, please try again. If you get this error consistently, please make sure the clock on Home Assistant system is accurate." + "invalid_code": "Invalid code, please try again. If you get this error consistently, please make sure the clock of your Home Assistant system is accurate." }, "step": { "init": { - "description": "Scan the QR code with your authentication app, such as **Google Authenticator** or **Authy**. If you have problem to scan the QR code, using **`{code}`** to manual setup. \n\n{qr_code}\n\nEnter the six digi code appeared in your app below to verify the setup:", - "title": "Scan this QR code with your app" + "description": "To activate two factor authentication using time-based one-time passwords, scan the QR code with your authentication app. If you don't have one, we recommend either [Google Authenticator](https://support.google.com/accounts/answer/1066447) or [Authy](https://authy.com/).\n\n{qr_code}\n\nAfter scanning the code, enter the six digit code from your app to verify the setup. If you have problems scanning the QR code, do a manual setup with code **`{code}`**.", + "title": "Set up two-factor authentication using TOTP" } }, "title": "TOTP" From 914436f3d5149d4f3542c6df8c308745e5db0938 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 22:28:17 +0200 Subject: [PATCH 140/159] Bump frontend to 20180827.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 4622f80948e..f0976c78224 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180826.0'] +REQUIREMENTS = ['home-assistant-frontend==20180827.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 3c505a2f1e3..fe3e64cd62e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -442,7 +442,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180826.0 +home-assistant-frontend==20180827.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 05d449a5eb2..9f732f84b55 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -84,7 +84,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180826.0 +home-assistant-frontend==20180827.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 9c7d4381a1b337cb11dd2305643b034044f26a2f Mon Sep 17 00:00:00 2001 From: Dan Klaffenbach Date: Sun, 26 Aug 2018 12:00:20 +0200 Subject: [PATCH 141/159] homematic: Make device avilable again when UNREACH becomes False (#16202) --- homeassistant/components/homematic/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/homematic/__init__.py b/homeassistant/components/homematic/__init__.py index 527b8c8f018..53c8e267016 100644 --- a/homeassistant/components/homematic/__init__.py +++ b/homeassistant/components/homematic/__init__.py @@ -869,7 +869,7 @@ class HMDevice(Entity): # Availability has changed if attribute == 'UNREACH': - self._available = bool(value) + self._available = not bool(value) has_changed = True elif not self.available: self._available = False From 2744702f9bc15b9a23e7982f40e55eee476264d3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 10:37:03 +0200 Subject: [PATCH 142/159] Change auth warning (#16216) --- homeassistant/components/http/__init__.py | 16 ++++------------ homeassistant/components/http/auth.py | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index ac08c26229c..6909a0e4664 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -200,18 +200,10 @@ class HomeAssistantHTTP: if is_ban_enabled: setup_bans(hass, app, login_threshold) - if hass.auth.active: - if hass.auth.support_legacy: - _LOGGER.warning("Experimental auth api enabled and " - "legacy_api_password support enabled. Please " - "use access_token instead api_password, " - "although you can still use legacy " - "api_password") - else: - _LOGGER.warning("Experimental auth api enabled. Please use " - "access_token instead api_password.") - elif api_password is None: - _LOGGER.warning("You have been advised to set http.api_password.") + if hass.auth.active and hass.auth.support_legacy: + _LOGGER.warning( + "legacy_api_password support has been enabled. If you don't" + "require it, remove the 'api_password' from your http config.") setup_auth(app, trusted_networks, hass.auth.active, support_legacy=hass.auth.support_legacy, diff --git a/homeassistant/components/http/auth.py b/homeassistant/components/http/auth.py index 7adcc43f4af..a18b4de7a10 100644 --- a/homeassistant/components/http/auth.py +++ b/homeassistant/components/http/auth.py @@ -32,7 +32,7 @@ def setup_auth(app, trusted_networks, use_auth, if request.path not in old_auth_warning: _LOGGER.log( logging.INFO if support_legacy else logging.WARNING, - 'Please change to use bearer token access %s from %s', + 'You need to use a bearer token to access %s from %s', request.path, request[KEY_REAL_IP]) old_auth_warning.add(request.path) From a953601abdfe6ab1fc5b1026ec9fb72530201fcd Mon Sep 17 00:00:00 2001 From: Marcel Hoppe Date: Tue, 28 Aug 2018 00:20:12 +0200 Subject: [PATCH 143/159] rewrite hangouts to use intents instead of commands (#16220) * rewrite hangouts to use intents instead of commands * small fixes * remove configured_hangouts check and CONFIG_SCHEMA * Lint * add import from .config_flow --- .../components/conversation/__init__.py | 38 +--- homeassistant/components/conversation/util.py | 35 ++++ homeassistant/components/hangouts/__init__.py | 53 +++++- homeassistant/components/hangouts/const.py | 26 +-- .../components/hangouts/hangouts_bot.py | 174 ++++++++++-------- tests/components/test_conversation.py | 12 +- 6 files changed, 196 insertions(+), 142 deletions(-) create mode 100644 homeassistant/components/conversation/util.py diff --git a/homeassistant/components/conversation/__init__.py b/homeassistant/components/conversation/__init__.py index 9cb00a84583..d8d386f5ca0 100644 --- a/homeassistant/components/conversation/__init__.py +++ b/homeassistant/components/conversation/__init__.py @@ -11,6 +11,7 @@ import voluptuous as vol from homeassistant import core from homeassistant.components import http +from homeassistant.components.conversation.util import create_matcher from homeassistant.components.http.data_validator import ( RequestDataValidator) from homeassistant.components.cover import (INTENT_OPEN_COVER, @@ -74,7 +75,7 @@ def async_register(hass, intent_type, utterances): if isinstance(utterance, REGEX_TYPE): conf.append(utterance) else: - conf.append(_create_matcher(utterance)) + conf.append(create_matcher(utterance)) async def async_setup(hass, config): @@ -91,7 +92,7 @@ async def async_setup(hass, config): if conf is None: conf = intents[intent_type] = [] - conf.extend(_create_matcher(utterance) for utterance in utterances) + conf.extend(create_matcher(utterance) for utterance in utterances) async def process(service): """Parse text into commands.""" @@ -146,39 +147,6 @@ async def async_setup(hass, config): return True -def _create_matcher(utterance): - """Create a regex that matches the utterance.""" - # Split utterance into parts that are type: NORMAL, GROUP or OPTIONAL - # Pattern matches (GROUP|OPTIONAL): Change light to [the color] {name} - parts = re.split(r'({\w+}|\[[\w\s]+\] *)', utterance) - # Pattern to extract name from GROUP part. Matches {name} - group_matcher = re.compile(r'{(\w+)}') - # Pattern to extract text from OPTIONAL part. Matches [the color] - optional_matcher = re.compile(r'\[([\w ]+)\] *') - - pattern = ['^'] - for part in parts: - group_match = group_matcher.match(part) - optional_match = optional_matcher.match(part) - - # Normal part - if group_match is None and optional_match is None: - pattern.append(part) - continue - - # Group part - if group_match is not None: - pattern.append( - r'(?P<{}>[\w ]+?)\s*'.format(group_match.groups()[0])) - - # Optional part - elif optional_match is not None: - pattern.append(r'(?:{} *)?'.format(optional_match.groups()[0])) - - pattern.append('$') - return re.compile(''.join(pattern), re.I) - - async def _process(hass, text): """Process a line of text.""" intents = hass.data.get(DOMAIN, {}) diff --git a/homeassistant/components/conversation/util.py b/homeassistant/components/conversation/util.py new file mode 100644 index 00000000000..60d861afdbe --- /dev/null +++ b/homeassistant/components/conversation/util.py @@ -0,0 +1,35 @@ +"""Util for Conversation.""" +import re + + +def create_matcher(utterance): + """Create a regex that matches the utterance.""" + # Split utterance into parts that are type: NORMAL, GROUP or OPTIONAL + # Pattern matches (GROUP|OPTIONAL): Change light to [the color] {name} + parts = re.split(r'({\w+}|\[[\w\s]+\] *)', utterance) + # Pattern to extract name from GROUP part. Matches {name} + group_matcher = re.compile(r'{(\w+)}') + # Pattern to extract text from OPTIONAL part. Matches [the color] + optional_matcher = re.compile(r'\[([\w ]+)\] *') + + pattern = ['^'] + for part in parts: + group_match = group_matcher.match(part) + optional_match = optional_matcher.match(part) + + # Normal part + if group_match is None and optional_match is None: + pattern.append(part) + continue + + # Group part + if group_match is not None: + pattern.append( + r'(?P<{}>[\w ]+?)\s*'.format(group_match.groups()[0])) + + # Optional part + elif optional_match is not None: + pattern.append(r'(?:{} *)?'.format(optional_match.groups()[0])) + + pattern.append('$') + return re.compile(''.join(pattern), re.I) diff --git a/homeassistant/components/hangouts/__init__.py b/homeassistant/components/hangouts/__init__.py index 8ebacc3736b..72a7e015a22 100644 --- a/homeassistant/components/hangouts/__init__.py +++ b/homeassistant/components/hangouts/__init__.py @@ -11,28 +11,56 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.helpers import dispatcher +import homeassistant.helpers.config_validation as cv -from .config_flow import configured_hangouts from .const import ( - CONF_BOT, CONF_COMMANDS, CONF_REFRESH_TOKEN, DOMAIN, + CONF_BOT, CONF_INTENTS, CONF_REFRESH_TOKEN, DOMAIN, EVENT_HANGOUTS_CONNECTED, EVENT_HANGOUTS_CONVERSATIONS_CHANGED, MESSAGE_SCHEMA, SERVICE_SEND_MESSAGE, - SERVICE_UPDATE) + SERVICE_UPDATE, CONF_SENTENCES, CONF_MATCHERS, + CONF_ERROR_SUPPRESSED_CONVERSATIONS, INTENT_SCHEMA, TARGETS_SCHEMA) + +# We need an import from .config_flow, without it .config_flow is never loaded. +from .config_flow import HangoutsFlowHandler # noqa: F401 + REQUIREMENTS = ['hangups==0.4.5'] _LOGGER = logging.getLogger(__name__) +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Optional(CONF_INTENTS, default={}): vol.Schema({ + cv.string: INTENT_SCHEMA + }), + vol.Optional(CONF_ERROR_SUPPRESSED_CONVERSATIONS, default=[]): + [TARGETS_SCHEMA] + }) +}, extra=vol.ALLOW_EXTRA) + async def async_setup(hass, config): """Set up the Hangouts bot component.""" - config = config.get(DOMAIN, {}) - hass.data[DOMAIN] = {CONF_COMMANDS: config.get(CONF_COMMANDS, [])} + from homeassistant.components.conversation import create_matcher - if configured_hangouts(hass) is None: - hass.async_add_job(hass.config_entries.flow.async_init( - DOMAIN, context={'source': config_entries.SOURCE_IMPORT} - )) + config = config.get(DOMAIN) + if config is None: + return True + + hass.data[DOMAIN] = {CONF_INTENTS: config.get(CONF_INTENTS), + CONF_ERROR_SUPPRESSED_CONVERSATIONS: + config.get(CONF_ERROR_SUPPRESSED_CONVERSATIONS)} + + for data in hass.data[DOMAIN][CONF_INTENTS].values(): + matchers = [] + for sentence in data[CONF_SENTENCES]: + matchers.append(create_matcher(sentence)) + + data[CONF_MATCHERS] = matchers + + hass.async_add_job(hass.config_entries.flow.async_init( + DOMAIN, context={'source': config_entries.SOURCE_IMPORT} + )) return True @@ -47,7 +75,8 @@ async def async_setup_entry(hass, config): bot = HangoutsBot( hass, config.data.get(CONF_REFRESH_TOKEN), - hass.data[DOMAIN][CONF_COMMANDS]) + hass.data[DOMAIN][CONF_INTENTS], + hass.data[DOMAIN][CONF_ERROR_SUPPRESSED_CONVERSATIONS]) hass.data[DOMAIN][CONF_BOT] = bot except GoogleAuthError as exception: _LOGGER.error("Hangouts failed to log in: %s", str(exception)) @@ -62,6 +91,10 @@ async def async_setup_entry(hass, config): hass, EVENT_HANGOUTS_CONVERSATIONS_CHANGED, bot.async_update_conversation_commands) + dispatcher.async_dispatcher_connect( + hass, + EVENT_HANGOUTS_CONVERSATIONS_CHANGED, + bot.async_handle_update_error_suppressed_conversations) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, bot.async_handle_hass_stop) diff --git a/homeassistant/components/hangouts/const.py b/homeassistant/components/hangouts/const.py index 7083307f3e2..3b96edf93a2 100644 --- a/homeassistant/components/hangouts/const.py +++ b/homeassistant/components/hangouts/const.py @@ -4,7 +4,6 @@ import logging import voluptuous as vol from homeassistant.components.notify import ATTR_MESSAGE, ATTR_TARGET -from homeassistant.const import CONF_NAME import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger('homeassistant.components.hangouts') @@ -18,17 +17,18 @@ CONF_BOT = 'bot' CONF_CONVERSATIONS = 'conversations' CONF_DEFAULT_CONVERSATIONS = 'default_conversations' +CONF_ERROR_SUPPRESSED_CONVERSATIONS = 'error_suppressed_conversations' -CONF_COMMANDS = 'commands' -CONF_WORD = 'word' -CONF_EXPRESSION = 'expression' - -EVENT_HANGOUTS_COMMAND = 'hangouts_command' +CONF_INTENTS = 'intents' +CONF_INTENT_TYPE = 'intent_type' +CONF_SENTENCES = 'sentences' +CONF_MATCHERS = 'matchers' EVENT_HANGOUTS_CONNECTED = 'hangouts_connected' EVENT_HANGOUTS_DISCONNECTED = 'hangouts_disconnected' EVENT_HANGOUTS_USERS_CHANGED = 'hangouts_users_changed' EVENT_HANGOUTS_CONVERSATIONS_CHANGED = 'hangouts_conversations_changed' +EVENT_HANGOUTS_MESSAGE_RECEIVED = 'hangouts_message_received' CONF_CONVERSATION_ID = 'id' CONF_CONVERSATION_NAME = 'name' @@ -59,20 +59,10 @@ MESSAGE_SCHEMA = vol.Schema({ vol.Required(ATTR_MESSAGE): [MESSAGE_SEGMENT_SCHEMA] }) -COMMAND_SCHEMA = vol.All( +INTENT_SCHEMA = vol.All( # Basic Schema vol.Schema({ - vol.Exclusive(CONF_WORD, 'trigger'): cv.string, - vol.Exclusive(CONF_EXPRESSION, 'trigger'): cv.is_regex, - vol.Required(CONF_NAME): cv.string, + vol.Required(CONF_SENTENCES): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_CONVERSATIONS): [TARGETS_SCHEMA] }), - # Make sure it's either a word or an expression command - cv.has_at_least_one_key(CONF_WORD, CONF_EXPRESSION) ) - -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Optional(CONF_COMMANDS, default=[]): [COMMAND_SCHEMA] - }) -}, extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/components/hangouts/hangouts_bot.py b/homeassistant/components/hangouts/hangouts_bot.py index d9ffb4cbace..15f4156d374 100644 --- a/homeassistant/components/hangouts/hangouts_bot.py +++ b/homeassistant/components/hangouts/hangouts_bot.py @@ -1,13 +1,14 @@ """The Hangouts Bot.""" import logging -import re -from homeassistant.helpers import dispatcher +from homeassistant.helpers import dispatcher, intent from .const import ( - ATTR_MESSAGE, ATTR_TARGET, CONF_CONVERSATIONS, CONF_EXPRESSION, CONF_NAME, - CONF_WORD, DOMAIN, EVENT_HANGOUTS_COMMAND, EVENT_HANGOUTS_CONNECTED, - EVENT_HANGOUTS_CONVERSATIONS_CHANGED, EVENT_HANGOUTS_DISCONNECTED) + ATTR_MESSAGE, ATTR_TARGET, CONF_CONVERSATIONS, DOMAIN, + EVENT_HANGOUTS_CONNECTED, EVENT_HANGOUTS_CONVERSATIONS_CHANGED, + EVENT_HANGOUTS_DISCONNECTED, EVENT_HANGOUTS_MESSAGE_RECEIVED, + CONF_MATCHERS, CONF_CONVERSATION_ID, + CONF_CONVERSATION_NAME) _LOGGER = logging.getLogger(__name__) @@ -15,20 +16,34 @@ _LOGGER = logging.getLogger(__name__) class HangoutsBot: """The Hangouts Bot.""" - def __init__(self, hass, refresh_token, commands): + def __init__(self, hass, refresh_token, intents, error_suppressed_convs): """Set up the client.""" self.hass = hass self._connected = False self._refresh_token = refresh_token - self._commands = commands + self._intents = intents + self._conversation_intents = None - self._word_commands = None - self._expression_commands = None self._client = None self._user_list = None self._conversation_list = None + self._error_suppressed_convs = error_suppressed_convs + self._error_suppressed_conv_ids = None + + dispatcher.async_dispatcher_connect( + self.hass, EVENT_HANGOUTS_MESSAGE_RECEIVED, + self._async_handle_conversation_message) + + def _resolve_conversation_id(self, obj): + if CONF_CONVERSATION_ID in obj: + return obj[CONF_CONVERSATION_ID] + if CONF_CONVERSATION_NAME in obj: + conv = self._resolve_conversation_name(obj[CONF_CONVERSATION_NAME]) + if conv is not None: + return conv.id_ + return None def _resolve_conversation_name(self, name): for conv in self._conversation_list.get_all(): @@ -38,89 +53,100 @@ class HangoutsBot: def async_update_conversation_commands(self, _): """Refresh the commands for every conversation.""" - self._word_commands = {} - self._expression_commands = {} + self._conversation_intents = {} - for command in self._commands: - if command.get(CONF_CONVERSATIONS): + for intent_type, data in self._intents.items(): + if data.get(CONF_CONVERSATIONS): conversations = [] - for conversation in command.get(CONF_CONVERSATIONS): - if 'id' in conversation: - conversations.append(conversation['id']) - elif 'name' in conversation: - conversations.append(self._resolve_conversation_name( - conversation['name']).id_) - command['_' + CONF_CONVERSATIONS] = conversations + for conversation in data.get(CONF_CONVERSATIONS): + conv_id = self._resolve_conversation_id(conversation) + if conv_id is not None: + conversations.append(conv_id) + data['_' + CONF_CONVERSATIONS] = conversations else: - command['_' + CONF_CONVERSATIONS] = \ + data['_' + CONF_CONVERSATIONS] = \ [conv.id_ for conv in self._conversation_list.get_all()] - if command.get(CONF_WORD): - for conv_id in command['_' + CONF_CONVERSATIONS]: - if conv_id not in self._word_commands: - self._word_commands[conv_id] = {} - word = command[CONF_WORD].lower() - self._word_commands[conv_id][word] = command - elif command.get(CONF_EXPRESSION): - command['_' + CONF_EXPRESSION] = re.compile( - command.get(CONF_EXPRESSION)) + for conv_id in data['_' + CONF_CONVERSATIONS]: + if conv_id not in self._conversation_intents: + self._conversation_intents[conv_id] = {} - for conv_id in command['_' + CONF_CONVERSATIONS]: - if conv_id not in self._expression_commands: - self._expression_commands[conv_id] = [] - self._expression_commands[conv_id].append(command) + self._conversation_intents[conv_id][intent_type] = data try: self._conversation_list.on_event.remove_observer( - self._handle_conversation_event) + self._async_handle_conversation_event) except ValueError: pass self._conversation_list.on_event.add_observer( - self._handle_conversation_event) + self._async_handle_conversation_event) - def _handle_conversation_event(self, event): + def async_handle_update_error_suppressed_conversations(self, _): + """Resolve the list of error suppressed conversations.""" + self._error_suppressed_conv_ids = [] + for conversation in self._error_suppressed_convs: + conv_id = self._resolve_conversation_id(conversation) + if conv_id is not None: + self._error_suppressed_conv_ids.append(conv_id) + + async def _async_handle_conversation_event(self, event): from hangups import ChatMessageEvent - if event.__class__ is ChatMessageEvent: - self._handle_conversation_message( - event.conversation_id, event.user_id, event) + if isinstance(event, ChatMessageEvent): + dispatcher.async_dispatcher_send(self.hass, + EVENT_HANGOUTS_MESSAGE_RECEIVED, + event.conversation_id, + event.user_id, event) - def _handle_conversation_message(self, conv_id, user_id, event): + async def _async_handle_conversation_message(self, + conv_id, user_id, event): """Handle a message sent to a conversation.""" user = self._user_list.get_user(user_id) if user.is_self: return + message = event.text _LOGGER.debug("Handling message '%s' from %s", - event.text, user.full_name) + message, user.full_name) - event_data = None + intents = self._conversation_intents.get(conv_id) + if intents is not None: + is_error = False + try: + intent_result = await self._async_process(intents, message) + except (intent.UnknownIntent, intent.IntentHandleError) as err: + is_error = True + intent_result = intent.IntentResponse() + intent_result.async_set_speech(str(err)) + + if intent_result is None: + is_error = True + intent_result = intent.IntentResponse() + intent_result.async_set_speech( + "Sorry, I didn't understand that") + + message = intent_result.as_dict().get('speech', {})\ + .get('plain', {}).get('speech') + + if (message is not None) and not ( + is_error and conv_id in self._error_suppressed_conv_ids): + await self._async_send_message( + [{'text': message, 'parse_str': True}], + [{CONF_CONVERSATION_ID: conv_id}]) + + async def _async_process(self, intents, text): + """Detect a matching intent.""" + for intent_type, data in intents.items(): + for matcher in data.get(CONF_MATCHERS, []): + match = matcher.match(text) - pieces = event.text.split(' ') - cmd = pieces[0].lower() - command = self._word_commands.get(conv_id, {}).get(cmd) - if command: - event_data = { - 'command': command[CONF_NAME], - 'conversation_id': conv_id, - 'user_id': user_id, - 'user_name': user.full_name, - 'data': pieces[1:] - } - else: - # After single-word commands, check all regex commands in the room - for command in self._expression_commands.get(conv_id, []): - match = command['_' + CONF_EXPRESSION].match(event.text) if not match: continue - event_data = { - 'command': command[CONF_NAME], - 'conversation_id': conv_id, - 'user_id': user_id, - 'user_name': user.full_name, - 'data': match.groupdict() - } - if event_data is not None: - self.hass.bus.fire(EVENT_HANGOUTS_COMMAND, event_data) + + response = await self.hass.helpers.intent.async_handle( + DOMAIN, intent_type, + {key: {'value': value} for key, value + in match.groupdict().items()}, text) + return response async def async_connect(self): """Login to the Google Hangouts.""" @@ -163,10 +189,12 @@ class HangoutsBot: conversations = [] for target in targets: conversation = None - if 'id' in target: - conversation = self._conversation_list.get(target['id']) - elif 'name' in target: - conversation = self._resolve_conversation_name(target['name']) + if CONF_CONVERSATION_ID in target: + conversation = self._conversation_list.get( + target[CONF_CONVERSATION_ID]) + elif CONF_CONVERSATION_NAME in target: + conversation = self._resolve_conversation_name( + target[CONF_CONVERSATION_NAME]) if conversation is not None: conversations.append(conversation) @@ -200,8 +228,8 @@ class HangoutsBot: users_in_conversation = [] for user in conv.users: users_in_conversation.append(user.full_name) - conversations[str(i)] = {'id': str(conv.id_), - 'name': conv.name, + conversations[str(i)] = {CONF_CONVERSATION_ID: str(conv.id_), + CONF_CONVERSATION_NAME: conv.name, 'users': users_in_conversation} self.hass.states.async_set("{}.conversations".format(DOMAIN), diff --git a/tests/components/test_conversation.py b/tests/components/test_conversation.py index 6a1d5a55c47..61247b5bdde 100644 --- a/tests/components/test_conversation.py +++ b/tests/components/test_conversation.py @@ -290,11 +290,11 @@ async def test_http_api_wrong_data(hass, aiohttp_client): def test_create_matcher(): """Test the create matcher method.""" # Basic sentence - pattern = conversation._create_matcher('Hello world') + pattern = conversation.create_matcher('Hello world') assert pattern.match('Hello world') is not None # Match a part - pattern = conversation._create_matcher('Hello {name}') + pattern = conversation.create_matcher('Hello {name}') match = pattern.match('hello world') assert match is not None assert match.groupdict()['name'] == 'world' @@ -302,7 +302,7 @@ def test_create_matcher(): assert no_match is None # Optional and matching part - pattern = conversation._create_matcher('Turn on [the] {name}') + pattern = conversation.create_matcher('Turn on [the] {name}') match = pattern.match('turn on the kitchen lights') assert match is not None assert match.groupdict()['name'] == 'kitchen lights' @@ -313,7 +313,7 @@ def test_create_matcher(): assert match is None # Two different optional parts, 1 matching part - pattern = conversation._create_matcher('Turn on [the] [a] {name}') + pattern = conversation.create_matcher('Turn on [the] [a] {name}') match = pattern.match('turn on the kitchen lights') assert match is not None assert match.groupdict()['name'] == 'kitchen lights' @@ -325,13 +325,13 @@ def test_create_matcher(): assert match.groupdict()['name'] == 'kitchen light' # Strip plural - pattern = conversation._create_matcher('Turn {name}[s] on') + pattern = conversation.create_matcher('Turn {name}[s] on') match = pattern.match('turn kitchen lights on') assert match is not None assert match.groupdict()['name'] == 'kitchen light' # Optional 2 words - pattern = conversation._create_matcher('Turn [the great] {name} on') + pattern = conversation.create_matcher('Turn [the great] {name} on') match = pattern.match('turn the great kitchen lights on') assert match is not None assert match.groupdict()['name'] == 'kitchen lights' From 3e65009ea9b8bb38a1a8da55240afba91fad422c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 21:56:28 +0200 Subject: [PATCH 144/159] Fix device telldus (#16224) --- homeassistant/components/tellduslive.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/tellduslive.py b/homeassistant/components/tellduslive.py index 693499510ad..c2b7ba9ba0f 100644 --- a/homeassistant/components/tellduslive.py +++ b/homeassistant/components/tellduslive.py @@ -287,7 +287,6 @@ class TelldusLiveEntity(Entity): self._id = device_id self._client = hass.data[DOMAIN] self._client.entities.append(self) - self.device = self._client.device(device_id) self._name = self.device.name _LOGGER.debug('Created device %s', self) From 9b01972b414add949755fb93618264ee88d24470 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 00:37:15 +0200 Subject: [PATCH 145/159] Update trusted networks flow (#16227) * Update the trusted networks flow * Fix tests * Remove errors --- .../auth/providers/trusted_networks.py | 20 ++++--------------- tests/auth/providers/test_trusted_networks.py | 13 ++++-------- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/homeassistant/auth/providers/trusted_networks.py b/homeassistant/auth/providers/trusted_networks.py index 37e032e58d7..8a7e1d67c6d 100644 --- a/homeassistant/auth/providers/trusted_networks.py +++ b/homeassistant/auth/providers/trusted_networks.py @@ -111,31 +111,19 @@ class TrustedNetworksLoginFlow(LoginFlow): self, user_input: Optional[Dict[str, str]] = None) \ -> Dict[str, Any]: """Handle the step of the form.""" - errors = {} try: cast(TrustedNetworksAuthProvider, self._auth_provider)\ .async_validate_access(self._ip_address) except InvalidAuthError: - errors['base'] = 'invalid_auth' - return self.async_show_form( - step_id='init', - data_schema=None, - errors=errors, + return self.async_abort( + reason='not_whitelisted' ) if user_input is not None: - user_id = user_input['user'] - if user_id not in self._available_users: - errors['base'] = 'invalid_auth' - - if not errors: - return await self.async_finish(user_input) - - schema = {'user': vol.In(self._available_users)} + return await self.async_finish(user_input) return self.async_show_form( step_id='init', - data_schema=vol.Schema(schema), - errors=errors, + data_schema=vol.Schema({'user': vol.In(self._available_users)}), ) diff --git a/tests/auth/providers/test_trusted_networks.py b/tests/auth/providers/test_trusted_networks.py index 4839c72a86a..0ca302f8273 100644 --- a/tests/auth/providers/test_trusted_networks.py +++ b/tests/auth/providers/test_trusted_networks.py @@ -74,16 +74,16 @@ async def test_login_flow(manager, provider): # trusted network didn't loaded flow = await provider.async_login_flow({'ip_address': '127.0.0.1'}) step = await flow.async_step_init() - assert step['step_id'] == 'init' - assert step['errors']['base'] == 'invalid_auth' + assert step['type'] == 'abort' + assert step['reason'] == 'not_whitelisted' provider.hass.http = Mock(trusted_networks=['192.168.0.1']) # not from trusted network flow = await provider.async_login_flow({'ip_address': '127.0.0.1'}) step = await flow.async_step_init() - assert step['step_id'] == 'init' - assert step['errors']['base'] == 'invalid_auth' + assert step['type'] == 'abort' + assert step['reason'] == 'not_whitelisted' # from trusted network, list users flow = await provider.async_login_flow({'ip_address': '192.168.0.1'}) @@ -95,11 +95,6 @@ async def test_login_flow(manager, provider): with pytest.raises(vol.Invalid): assert schema({'user': 'invalid-user'}) - # login with invalid user - step = await flow.async_step_init({'user': 'invalid-user'}) - assert step['step_id'] == 'init' - assert step['errors']['base'] == 'invalid_auth' - # login with valid user step = await flow.async_step_init({'user': user.id}) assert step['type'] == 'create_entry' From e9cc359abeff6224311057fe22fa19a1bcf942ce Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 00:38:23 +0200 Subject: [PATCH 146/159] Bumped version to 0.77.0b3 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index cc0c9294506..be0bd814775 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 77 -PATCH_VERSION = '0b2' +PATCH_VERSION = '0b3' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 11fcffda4cfde5b1a170921681b33dca698352cb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 20:55:58 +0200 Subject: [PATCH 147/159] Update translations --- .../components/auth/.translations/lb.json | 16 ++++++++++ .../auth/.translations/zh-Hans.json | 16 ++++++++++ .../auth/.translations/zh-Hant.json | 16 ++++++++++ .../components/hangouts/.translations/lb.json | 31 +++++++++++++++++++ .../hangouts/.translations/zh-Hans.json | 29 +++++++++++++++++ .../hangouts/.translations/zh-Hant.json | 4 +-- .../.translations/zh-Hans.json | 1 + 7 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 homeassistant/components/auth/.translations/lb.json create mode 100644 homeassistant/components/auth/.translations/zh-Hans.json create mode 100644 homeassistant/components/auth/.translations/zh-Hant.json create mode 100644 homeassistant/components/hangouts/.translations/lb.json create mode 100644 homeassistant/components/hangouts/.translations/zh-Hans.json diff --git a/homeassistant/components/auth/.translations/lb.json b/homeassistant/components/auth/.translations/lb.json new file mode 100644 index 00000000000..f55ae4b97ba --- /dev/null +++ b/homeassistant/components/auth/.translations/lb.json @@ -0,0 +1,16 @@ +{ + "mfa_setup": { + "totp": { + "error": { + "invalid_code": "Ong\u00ebltege Login, prob\u00e9iert w.e.g. nach emol. Falls d\u00ebse Feeler Message \u00ebmmer er\u00ebm optr\u00ebtt dann iwwerpr\u00e9ift op d'Z\u00e4it vum Home Assistant System richteg ass." + }, + "step": { + "init": { + "description": "Fir d'Zwee-Faktor-Authentifikatioun m\u00ebttels engem Z\u00e4it bas\u00e9ierten eemolege Passwuert z'aktiv\u00e9ieren, scannt de QR Code mat enger Authentifikatioun's App.\nFalls dir keng hutt, recommand\u00e9iere mir entweder [Google Authenticator](https://support.google.com/accounts/answer/1066447) oder [Authy](https://authy.com/).\n\n{qr_code}\n\nNodeems de Code gescannt ass, gitt de sechs stellege Code vun der App a fir d'Konfiguratioun z'iwwerpr\u00e9iwen. Am Fall vu Problemer fir de QR Code ze scannen, gitt de folgende Code **`{code}`** a fir ee manuelle Setup.", + "title": "Zwee Faktor Authentifikatioun mat TOTP konfigur\u00e9ieren" + } + }, + "title": "TOTP" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/auth/.translations/zh-Hans.json b/homeassistant/components/auth/.translations/zh-Hans.json new file mode 100644 index 00000000000..c5b397a8e12 --- /dev/null +++ b/homeassistant/components/auth/.translations/zh-Hans.json @@ -0,0 +1,16 @@ +{ + "mfa_setup": { + "totp": { + "error": { + "invalid_code": "\u53e3\u4ee4\u65e0\u6548\uff0c\u8bf7\u91cd\u65b0\u8f93\u5165\u3002\u5982\u679c\u9519\u8bef\u53cd\u590d\u51fa\u73b0\uff0c\u8bf7\u786e\u4fdd Home Assistant \u7cfb\u7edf\u7684\u65f6\u95f4\u51c6\u786e\u65e0\u8bef\u3002" + }, + "step": { + "init": { + "description": "\u8981\u6fc0\u6d3b\u57fa\u4e8e\u65f6\u95f4\u52a8\u6001\u53e3\u4ee4\u7684\u53cc\u91cd\u8ba4\u8bc1\uff0c\u8bf7\u7528\u8eab\u4efd\u9a8c\u8bc1\u5e94\u7528\u626b\u63cf\u4ee5\u4e0b\u4e8c\u7ef4\u7801\u3002\u5982\u679c\u60a8\u8fd8\u6ca1\u6709\u8eab\u4efd\u9a8c\u8bc1\u5e94\u7528\uff0c\u63a8\u8350\u4f7f\u7528 [Google \u8eab\u4efd\u9a8c\u8bc1\u5668](https://support.google.com/accounts/answer/1066447) \u6216 [Authy](https://authy.com/)\u3002\n\n{qr_code}\n\n\u626b\u63cf\u4e8c\u7ef4\u7801\u4ee5\u540e\uff0c\u8f93\u5165\u5e94\u7528\u4e0a\u7684\u516d\u4f4d\u6570\u5b57\u53e3\u4ee4\u6765\u9a8c\u8bc1\u914d\u7f6e\u3002\u5982\u679c\u5728\u626b\u63cf\u4e8c\u7ef4\u7801\u65f6\u9047\u5230\u95ee\u9898\uff0c\u8bf7\u4f7f\u7528\u4ee3\u7801 **`{code}`** \u624b\u52a8\u914d\u7f6e\u3002", + "title": "\u7528\u65f6\u95f4\u52a8\u6001\u53e3\u4ee4\u8bbe\u7f6e\u53cc\u91cd\u8ba4\u8bc1" + } + }, + "title": "\u65f6\u95f4\u52a8\u6001\u53e3\u4ee4" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/auth/.translations/zh-Hant.json b/homeassistant/components/auth/.translations/zh-Hant.json new file mode 100644 index 00000000000..ef41ea87248 --- /dev/null +++ b/homeassistant/components/auth/.translations/zh-Hant.json @@ -0,0 +1,16 @@ +{ + "mfa_setup": { + "totp": { + "error": { + "invalid_code": "\u9a57\u8b49\u78bc\u7121\u6548\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002\u5047\u5982\u932f\u8aa4\u6301\u7e8c\u767c\u751f\uff0c\u8acb\u5148\u78ba\u5b9a\u60a8\u7684 Home Assistant \u7cfb\u7d71\u4e0a\u7684\u6642\u9593\u8a2d\u5b9a\u6b63\u78ba\u5f8c\uff0c\u518d\u8a66\u4e00\u6b21\u3002" + }, + "step": { + "init": { + "description": "\u6b32\u555f\u7528\u4e00\u6b21\u6027\u4e14\u5177\u6642\u6548\u6027\u7684\u5bc6\u78bc\u4e4b\u5169\u6b65\u9a5f\u9a57\u8b49\u529f\u80fd\uff0c\u8acb\u4f7f\u7528\u60a8\u7684\u9a57\u8b49 App \u6383\u7784\u4e0b\u65b9\u7684 QR code \u3002\u5018\u82e5\u60a8\u5c1a\u672a\u5b89\u88dd\u4efb\u4f55 App\uff0c\u63a8\u85a6\u60a8\u4f7f\u7528 [Google Authenticator](https://support.google.com/accounts/answer/1066447) \u6216 [Authy](https://authy.com/)\u3002\n\n{qr_code}\n\n\u65bc\u6383\u63cf\u4e4b\u5f8c\uff0c\u8f38\u5165 App \u4e2d\u7684\u516d\u4f4d\u6578\u5b57\u9032\u884c\u8a2d\u5b9a\u9a57\u8b49\u3002\u5047\u5982\u6383\u63cf\u51fa\u73fe\u554f\u984c\uff0c\u8acb\u624b\u52d5\u8f38\u5165\u4ee5\u4e0b\u9a57\u8b49\u78bc **`{code}`**\u3002", + "title": "\u4f7f\u7528 TOTP \u8a2d\u5b9a\u5169\u6b65\u9a5f\u9a57\u8b49" + } + }, + "title": "TOTP" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/lb.json b/homeassistant/components/hangouts/.translations/lb.json new file mode 100644 index 00000000000..426ab689626 --- /dev/null +++ b/homeassistant/components/hangouts/.translations/lb.json @@ -0,0 +1,31 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts ass scho konfigur\u00e9iert", + "unknown": "Onbekannten Fehler opgetrueden" + }, + "error": { + "invalid_2fa": "Ong\u00eblteg 2-Faktor Authentifikatioun, prob\u00e9iert w.e.g. nach emol.", + "invalid_2fa_method": "Ong\u00eblteg 2FA Methode (Iwwerpr\u00e9ift et um Telefon)", + "invalid_login": "Ong\u00ebltege Login, prob\u00e9iert w.e.g. nach emol." + }, + "step": { + "2fa": { + "data": { + "2fa": "2FA Pin" + }, + "description": "Eidel", + "title": "2-Faktor-Authentifikatioun" + }, + "user": { + "data": { + "email": "E-Mail Adress", + "password": "Passwuert" + }, + "description": "Eidel", + "title": "Google Hangouts Login" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/zh-Hans.json b/homeassistant/components/hangouts/.translations/zh-Hans.json new file mode 100644 index 00000000000..bee6bf753db --- /dev/null +++ b/homeassistant/components/hangouts/.translations/zh-Hans.json @@ -0,0 +1,29 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts \u5df2\u914d\u7f6e\u5b8c\u6210", + "unknown": "\u53d1\u751f\u672a\u77e5\u9519\u8bef\u3002" + }, + "error": { + "invalid_2fa": "\u53cc\u91cd\u8ba4\u8bc1\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5\u3002", + "invalid_2fa_method": "\u65e0\u6548\u7684\u53cc\u91cd\u8ba4\u8bc1\u65b9\u6cd5\uff08\u7535\u8bdd\u9a8c\u8bc1\uff09\u3002", + "invalid_login": "\u767b\u9646\u5931\u8d25\uff0c\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002" + }, + "step": { + "2fa": { + "data": { + "2fa": "2FA Pin" + }, + "title": "\u53cc\u91cd\u8ba4\u8bc1" + }, + "user": { + "data": { + "email": "\u7535\u5b50\u90ae\u4ef6\u5730\u5740", + "password": "\u5bc6\u7801" + }, + "title": "\u767b\u5f55 Google Hangouts" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/zh-Hant.json b/homeassistant/components/hangouts/.translations/zh-Hant.json index 0920e0325d2..16234acb193 100644 --- a/homeassistant/components/hangouts/.translations/zh-Hant.json +++ b/homeassistant/components/hangouts/.translations/zh-Hant.json @@ -5,7 +5,7 @@ "unknown": "\u767c\u751f\u672a\u77e5\u932f\u8aa4\u3002" }, "error": { - "invalid_2fa": "\u5169\u968e\u6bb5\u9a57\u8b49\u7121\u6548\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", + "invalid_2fa": "\u5169\u6b65\u9a5f\u9a57\u8b49\u7121\u6548\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002", "invalid_2fa_method": "\u8a8d\u8b49\u65b9\u5f0f\u7121\u6548\uff08\u65bc\u96fb\u8a71\u4e0a\u9a57\u8b49\uff09\u3002", "invalid_login": "\u767b\u5165\u5931\u6557\uff0c\u8acb\u518d\u8a66\u4e00\u6b21\u3002" }, @@ -15,7 +15,7 @@ "2fa": "\u8a8d\u8b49\u78bc" }, "description": "\u7a7a\u767d", - "title": "\u5169\u968e\u6bb5\u8a8d\u8b49" + "title": "\u5169\u6b65\u9a5f\u9a57\u8b49" }, "user": { "data": { diff --git a/homeassistant/components/homematicip_cloud/.translations/zh-Hans.json b/homeassistant/components/homematicip_cloud/.translations/zh-Hans.json index 38970e4a97c..930b649bceb 100644 --- a/homeassistant/components/homematicip_cloud/.translations/zh-Hans.json +++ b/homeassistant/components/homematicip_cloud/.translations/zh-Hans.json @@ -3,6 +3,7 @@ "abort": { "already_configured": "\u63a5\u5165\u70b9\u5df2\u7ecf\u914d\u7f6e\u5b8c\u6210", "conection_aborted": "\u65e0\u6cd5\u8fde\u63a5\u5230 HMIP \u670d\u52a1\u5668", + "connection_aborted": "\u65e0\u6cd5\u8fde\u63a5\u5230 HMIP \u670d\u52a1\u5668", "unknown": "\u53d1\u751f\u672a\u77e5\u9519\u8bef\u3002" }, "error": { From c50a7deb92097437e763425d5d7ad350a8586a63 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 15:44:06 +0200 Subject: [PATCH 148/159] Fix hangouts (#16232) --- homeassistant/components/hangouts/__init__.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/hangouts/__init__.py b/homeassistant/components/hangouts/__init__.py index 72a7e015a22..ebadff57be3 100644 --- a/homeassistant/components/hangouts/__init__.py +++ b/homeassistant/components/hangouts/__init__.py @@ -45,11 +45,17 @@ async def async_setup(hass, config): config = config.get(DOMAIN) if config is None: + hass.data[DOMAIN] = { + CONF_INTENTS: {}, + CONF_ERROR_SUPPRESSED_CONVERSATIONS: [], + } return True - hass.data[DOMAIN] = {CONF_INTENTS: config.get(CONF_INTENTS), - CONF_ERROR_SUPPRESSED_CONVERSATIONS: - config.get(CONF_ERROR_SUPPRESSED_CONVERSATIONS)} + hass.data[DOMAIN] = { + CONF_INTENTS: config[CONF_INTENTS], + CONF_ERROR_SUPPRESSED_CONVERSATIONS: + config[CONF_ERROR_SUPPRESSED_CONVERSATIONS], + } for data in hass.data[DOMAIN][CONF_INTENTS].values(): matchers = [] @@ -58,7 +64,7 @@ async def async_setup(hass, config): data[CONF_MATCHERS] = matchers - hass.async_add_job(hass.config_entries.flow.async_init( + hass.async_create_task(hass.config_entries.flow.async_init( DOMAIN, context={'source': config_entries.SOURCE_IMPORT} )) From f708292015d6fbc33e53f3bd80742ab42871eaed Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 09:32:50 +0200 Subject: [PATCH 149/159] Warning missed a space (#16233) --- homeassistant/components/http/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/http/__init__.py b/homeassistant/components/http/__init__.py index 6909a0e4664..1b22f8e62d4 100644 --- a/homeassistant/components/http/__init__.py +++ b/homeassistant/components/http/__init__.py @@ -202,7 +202,7 @@ class HomeAssistantHTTP: if hass.auth.active and hass.auth.support_legacy: _LOGGER.warning( - "legacy_api_password support has been enabled. If you don't" + "legacy_api_password support has been enabled. If you don't " "require it, remove the 'api_password' from your http config.") setup_auth(app, trusted_networks, hass.auth.active, From 667f9c6fe432ba908635e964e146849f0ba70194 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 10:53:12 +0200 Subject: [PATCH 150/159] Package loadable: compare case insensitive (#16234) --- homeassistant/util/package.py | 4 +++- tests/util/test_package.py | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index feefa65c0f6..3f12fc223b8 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -73,11 +73,13 @@ def package_loadable(package: str) -> bool: # This is a zip file req = pkg_resources.Requirement.parse(urlparse(package).fragment) + req_proj_name = req.project_name.lower() + for path in sys.path: for dist in pkg_resources.find_distributions(path): # If the project name is the same, it will be the one that is # loaded when we import it. - if dist.project_name == req.project_name: + if dist.project_name.lower() == req_proj_name: return dist in req return False diff --git a/tests/util/test_package.py b/tests/util/test_package.py index 19e85a094ee..1e93a078bd9 100644 --- a/tests/util/test_package.py +++ b/tests/util/test_package.py @@ -239,3 +239,6 @@ def test_package_loadable_installed_twice(): with patch('pkg_resources.find_distributions', side_effect=[[v2]]): assert package.package_loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v2]]): + assert package.package_loadable('Hello==2.0.0') From 573f5de14873780a072bb63bd0333163a6118e99 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 12:49:50 +0200 Subject: [PATCH 151/159] Avoid insecure pycryptodome (#16238) --- homeassistant/package_constraints.txt | 2 ++ script/gen_requirements_all.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 70fb519eef4..3e9a763181a 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -13,6 +13,8 @@ pyyaml>=3.13,<4 requests==2.19.1 voluptuous==0.11.5 +pycryptodome>=3.6.6 + # Breaks Python 3.6 and is not needed for our supported Python versions enum34==1000000000.0.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index fe23e638e5b..4b694ec7ec0 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -124,6 +124,8 @@ URL_PIN = ('https://home-assistant.io/developers/code_review_platform/' CONSTRAINT_PATH = os.path.join(os.path.dirname(__file__), '../homeassistant/package_constraints.txt') CONSTRAINT_BASE = """ +pycryptodome>=3.6.6 + # Breaks Python 3.6 and is not needed for our supported Python versions enum34==1000000000.0.0 From d994d6bfad7167ef639e8683a70b8e0892bbc1fd Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 28 Aug 2018 02:23:58 -0700 Subject: [PATCH 152/159] Change log level to error when auth provider failed loading (#16235) --- homeassistant/auth/mfa_modules/__init__.py | 4 ++-- homeassistant/auth/providers/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/auth/mfa_modules/__init__.py b/homeassistant/auth/mfa_modules/__init__.py index cb0758e3ef8..a669f8bb5f0 100644 --- a/homeassistant/auth/mfa_modules/__init__.py +++ b/homeassistant/auth/mfa_modules/__init__.py @@ -152,8 +152,8 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) \ try: module = importlib.import_module(module_path) - except ImportError: - _LOGGER.warning('Unable to find %s', module_path) + except ImportError as err: + _LOGGER.error('Unable to load mfa module %s: %s', module_name, err) return None if hass.config.skip_pip or not hasattr(module, 'REQUIREMENTS'): diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index 0bcb47d4af9..d8ec04e9072 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -134,8 +134,8 @@ async def load_auth_provider_module( try: module = importlib.import_module( 'homeassistant.auth.providers.{}'.format(provider)) - except ImportError: - _LOGGER.warning('Unable to find auth provider %s', provider) + except ImportError as err: + _LOGGER.error('Unable to load auth provider %s: %s', provider, err) return None if hass.config.skip_pip or not hasattr(module, 'REQUIREMENTS'): From 8d38016b0cc02b28d4af2621205edd2d0b35c8de Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 28 Aug 2018 11:54:01 -0700 Subject: [PATCH 153/159] Blow up startup if init auth providers or modules failed (#16240) * Blow up startup if init auth providers or modules failed * Delete core.entity_registry --- homeassistant/auth/__init__.py | 25 ++------ homeassistant/auth/mfa_modules/__init__.py | 17 +++--- homeassistant/auth/providers/__init__.py | 17 +++--- homeassistant/bootstrap.py | 12 ++-- homeassistant/config.py | 56 +++++++++++++++-- tests/auth/providers/test_homeassistant.py | 11 ++-- tests/auth/test_init.py | 58 +++++++++++------- tests/test_config.py | 70 +++++++++++++++++++++- 8 files changed, 194 insertions(+), 72 deletions(-) diff --git a/homeassistant/auth/__init__.py b/homeassistant/auth/__init__.py index 952bb3b8352..4ef8440de62 100644 --- a/homeassistant/auth/__init__.py +++ b/homeassistant/auth/__init__.py @@ -24,7 +24,11 @@ async def auth_manager_from_config( hass: HomeAssistant, provider_configs: List[Dict[str, Any]], module_configs: List[Dict[str, Any]]) -> 'AuthManager': - """Initialize an auth manager from config.""" + """Initialize an auth manager from config. + + CORE_CONFIG_SCHEMA will make sure do duplicated auth providers or + mfa modules exist in configs. + """ store = auth_store.AuthStore(hass) if provider_configs: providers = await asyncio.gather( @@ -35,17 +39,7 @@ async def auth_manager_from_config( # So returned auth providers are in same order as config provider_hash = OrderedDict() # type: _ProviderDict for provider in providers: - if provider is None: - continue - key = (provider.type, provider.id) - - if key in provider_hash: - _LOGGER.error( - 'Found duplicate provider: %s. Please add unique IDs if you ' - 'want to have the same provider twice.', key) - continue - provider_hash[key] = provider if module_configs: @@ -57,15 +51,6 @@ async def auth_manager_from_config( # So returned auth modules are in same order as config module_hash = OrderedDict() # type: _MfaModuleDict for module in modules: - if module is None: - continue - - if module.id in module_hash: - _LOGGER.error( - 'Found duplicate multi-factor module: %s. Please add unique ' - 'IDs if you want to have the same module twice.', module.id) - continue - module_hash[module.id] = module manager = AuthManager(hass, store, provider_hash, module_hash) diff --git a/homeassistant/auth/mfa_modules/__init__.py b/homeassistant/auth/mfa_modules/__init__.py index a669f8bb5f0..603ca6ff3b1 100644 --- a/homeassistant/auth/mfa_modules/__init__.py +++ b/homeassistant/auth/mfa_modules/__init__.py @@ -11,6 +11,7 @@ from voluptuous.humanize import humanize_error from homeassistant import requirements, data_entry_flow from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.util.decorator import Registry MULTI_FACTOR_AUTH_MODULES = Registry() @@ -127,26 +128,23 @@ class SetupFlow(data_entry_flow.FlowHandler): async def auth_mfa_module_from_config( hass: HomeAssistant, config: Dict[str, Any]) \ - -> Optional[MultiFactorAuthModule]: + -> MultiFactorAuthModule: """Initialize an auth module from a config.""" module_name = config[CONF_TYPE] module = await _load_mfa_module(hass, module_name) - if module is None: - return None - try: config = module.CONFIG_SCHEMA(config) # type: ignore except vol.Invalid as err: _LOGGER.error('Invalid configuration for multi-factor module %s: %s', module_name, humanize_error(config, err)) - return None + raise return MULTI_FACTOR_AUTH_MODULES[module_name](hass, config) # type: ignore async def _load_mfa_module(hass: HomeAssistant, module_name: str) \ - -> Optional[types.ModuleType]: + -> types.ModuleType: """Load an mfa auth module.""" module_path = 'homeassistant.auth.mfa_modules.{}'.format(module_name) @@ -154,7 +152,8 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) \ module = importlib.import_module(module_path) except ImportError as err: _LOGGER.error('Unable to load mfa module %s: %s', module_name, err) - return None + raise HomeAssistantError('Unable to load mfa module {}: {}'.format( + module_name, err)) if hass.config.skip_pip or not hasattr(module, 'REQUIREMENTS'): return module @@ -170,7 +169,9 @@ async def _load_mfa_module(hass: HomeAssistant, module_name: str) \ hass, module_path, module.REQUIREMENTS) # type: ignore if not req_success: - return None + raise HomeAssistantError( + 'Unable to process requirements of mfa module {}'.format( + module_name)) processed.add(module_name) return module diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index d8ec04e9072..370391d57cd 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -10,6 +10,7 @@ from voluptuous.humanize import humanize_error from homeassistant import data_entry_flow, requirements from homeassistant.core import callback, HomeAssistant from homeassistant.const import CONF_ID, CONF_NAME, CONF_TYPE +from homeassistant.exceptions import HomeAssistantError from homeassistant.util import dt as dt_util from homeassistant.util.decorator import Registry @@ -110,33 +111,31 @@ class AuthProvider: async def auth_provider_from_config( hass: HomeAssistant, store: AuthStore, - config: Dict[str, Any]) -> Optional[AuthProvider]: + config: Dict[str, Any]) -> AuthProvider: """Initialize an auth provider from a config.""" provider_name = config[CONF_TYPE] module = await load_auth_provider_module(hass, provider_name) - if module is None: - return None - try: config = module.CONFIG_SCHEMA(config) # type: ignore except vol.Invalid as err: _LOGGER.error('Invalid configuration for auth provider %s: %s', provider_name, humanize_error(config, err)) - return None + raise return AUTH_PROVIDERS[provider_name](hass, store, config) # type: ignore async def load_auth_provider_module( - hass: HomeAssistant, provider: str) -> Optional[types.ModuleType]: + hass: HomeAssistant, provider: str) -> types.ModuleType: """Load an auth provider.""" try: module = importlib.import_module( 'homeassistant.auth.providers.{}'.format(provider)) except ImportError as err: _LOGGER.error('Unable to load auth provider %s: %s', provider, err) - return None + raise HomeAssistantError('Unable to load auth provider {}: {}'.format( + provider, err)) if hass.config.skip_pip or not hasattr(module, 'REQUIREMENTS'): return module @@ -154,7 +153,9 @@ async def load_auth_provider_module( hass, 'auth provider {}'.format(provider), reqs) if not req_success: - return None + raise HomeAssistantError( + 'Unable to process requirements of auth provider {}'.format( + provider)) processed.add(provider) return module diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index c10964e2da3..2051359c0ba 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -61,7 +61,6 @@ def from_config_dict(config: Dict[str, Any], config, hass, config_dir, enable_log, verbose, skip_pip, log_rotate_days, log_file, log_no_color) ) - return hass @@ -94,8 +93,13 @@ async def async_from_config_dict(config: Dict[str, Any], try: await conf_util.async_process_ha_core_config( hass, core_config, has_api_password, has_trusted_networks) - except vol.Invalid as ex: - conf_util.async_log_exception(ex, 'homeassistant', core_config, hass) + except vol.Invalid as config_err: + conf_util.async_log_exception( + config_err, 'homeassistant', core_config, hass) + return None + except HomeAssistantError: + _LOGGER.error("Home Assistant core failed to initialize. " + "Further initialization aborted") return None await hass.async_add_executor_job( @@ -130,7 +134,7 @@ async def async_from_config_dict(config: Dict[str, Any], res = await core_components.async_setup(hass, config) if not res: _LOGGER.error("Home Assistant core failed to initialize. " - "further initialization aborted") + "Further initialization aborted") return hass await persistent_notification.async_setup(hass, config) diff --git a/homeassistant/config.py b/homeassistant/config.py index a799094c94d..d742e62660b 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -8,7 +8,7 @@ import re import shutil # pylint: disable=unused-import from typing import ( # noqa: F401 - Any, Tuple, Optional, Dict, List, Union, Callable) + Any, Tuple, Optional, Dict, List, Union, Callable, Sequence, Set) from types import ModuleType import voluptuous as vol from voluptuous.humanize import humanize_error @@ -23,7 +23,7 @@ from homeassistant.const import ( CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT, TEMP_CELSIUS, __version__, CONF_CUSTOMIZE, CONF_CUSTOMIZE_DOMAIN, CONF_CUSTOMIZE_GLOB, CONF_WHITELIST_EXTERNAL_DIRS, CONF_AUTH_PROVIDERS, CONF_AUTH_MFA_MODULES, - CONF_TYPE) + CONF_TYPE, CONF_ID) from homeassistant.core import callback, DOMAIN as CONF_CORE, HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.loader import get_component, get_platform @@ -128,6 +128,48 @@ some_password: welcome """ +def _no_duplicate_auth_provider(configs: Sequence[Dict[str, Any]]) \ + -> Sequence[Dict[str, Any]]: + """No duplicate auth provider config allowed in a list. + + Each type of auth provider can only have one config without optional id. + Unique id is required if same type of auth provider used multiple times. + """ + config_keys = set() # type: Set[Tuple[str, Optional[str]]] + for config in configs: + key = (config[CONF_TYPE], config.get(CONF_ID)) + if key in config_keys: + raise vol.Invalid( + 'Duplicate auth provider {} found. Please add unique IDs if ' + 'you want to have the same auth provider twice'.format( + config[CONF_TYPE] + )) + config_keys.add(key) + return configs + + +def _no_duplicate_auth_mfa_module(configs: Sequence[Dict[str, Any]]) \ + -> Sequence[Dict[str, Any]]: + """No duplicate auth mfa module item allowed in a list. + + Each type of mfa module can only have one config without optional id. + A global unique id is required if same type of mfa module used multiple + times. + Note: this is different than auth provider + """ + config_keys = set() # type: Set[str] + for config in configs: + key = config.get(CONF_ID, config[CONF_TYPE]) + if key in config_keys: + raise vol.Invalid( + 'Duplicate mfa module {} found. Please add unique IDs if ' + 'you want to have the same mfa module twice'.format( + config[CONF_TYPE] + )) + config_keys.add(key) + return configs + + PACKAGES_CONFIG_SCHEMA = vol.Schema({ cv.slug: vol.Schema( # Package names are slugs {cv.slug: vol.Any(dict, list, None)}) # Only slugs for component names @@ -166,10 +208,16 @@ CORE_CONFIG_SCHEMA = CUSTOMIZE_CONFIG_SCHEMA.extend({ CONF_TYPE: vol.NotIn(['insecure_example'], 'The insecure_example auth provider' ' is for testing only.') - })]), + })], + _no_duplicate_auth_provider), vol.Optional(CONF_AUTH_MFA_MODULES): vol.All(cv.ensure_list, - [auth_mfa_modules.MULTI_FACTOR_AUTH_MODULE_SCHEMA]), + [auth_mfa_modules.MULTI_FACTOR_AUTH_MODULE_SCHEMA.extend({ + CONF_TYPE: vol.NotIn(['insecure_example'], + 'The insecure_example mfa module' + ' is for testing only.') + })], + _no_duplicate_auth_mfa_module), }) diff --git a/tests/auth/providers/test_homeassistant.py b/tests/auth/providers/test_homeassistant.py index 935c5e50dd5..84beb8cdd3f 100644 --- a/tests/auth/providers/test_homeassistant.py +++ b/tests/auth/providers/test_homeassistant.py @@ -3,6 +3,7 @@ from unittest.mock import Mock import base64 import pytest +import voluptuous as vol from homeassistant import data_entry_flow from homeassistant.auth import auth_manager_from_config, auth_store @@ -111,11 +112,11 @@ async def test_saving_loading(data, hass): async def test_not_allow_set_id(): """Test we are not allowed to set an ID in config.""" hass = Mock() - provider = await auth_provider_from_config(hass, None, { - 'type': 'homeassistant', - 'id': 'invalid', - }) - assert provider is None + with pytest.raises(vol.Invalid): + await auth_provider_from_config(hass, None, { + 'type': 'homeassistant', + 'id': 'invalid', + }) async def test_new_users_populate_values(hass, data): diff --git a/tests/auth/test_init.py b/tests/auth/test_init.py index f724b40a71f..d9e7a50410f 100644 --- a/tests/auth/test_init.py +++ b/tests/auth/test_init.py @@ -3,6 +3,7 @@ from datetime import timedelta from unittest.mock import Mock, patch import pytest +import voluptuous as vol from homeassistant import auth, data_entry_flow from homeassistant.auth import ( @@ -21,33 +22,36 @@ def mock_hass(loop): return hass -async def test_auth_manager_from_config_validates_config_and_id(mock_hass): +async def test_auth_manager_from_config_validates_config(mock_hass): """Test get auth providers.""" + with pytest.raises(vol.Invalid): + manager = await auth.auth_manager_from_config(mock_hass, [{ + 'name': 'Test Name', + 'type': 'insecure_example', + 'users': [], + }, { + 'name': 'Invalid config because no users', + 'type': 'insecure_example', + 'id': 'invalid_config', + }], []) + manager = await auth.auth_manager_from_config(mock_hass, [{ 'name': 'Test Name', 'type': 'insecure_example', 'users': [], - }, { - 'name': 'Invalid config because no users', - 'type': 'insecure_example', - 'id': 'invalid_config', }, { 'name': 'Test Name 2', 'type': 'insecure_example', 'id': 'another', 'users': [], - }, { - 'name': 'Wrong because duplicate ID', - 'type': 'insecure_example', - 'id': 'another', - 'users': [], }], []) providers = [{ - 'name': provider.name, - 'id': provider.id, - 'type': provider.type, - } for provider in manager.auth_providers] + 'name': provider.name, + 'id': provider.id, + 'type': provider.type, + } for provider in manager.auth_providers] + assert providers == [{ 'name': 'Test Name', 'type': 'insecure_example', @@ -61,6 +65,26 @@ async def test_auth_manager_from_config_validates_config_and_id(mock_hass): async def test_auth_manager_from_config_auth_modules(mock_hass): """Test get auth modules.""" + with pytest.raises(vol.Invalid): + manager = await auth.auth_manager_from_config(mock_hass, [{ + 'name': 'Test Name', + 'type': 'insecure_example', + 'users': [], + }, { + 'name': 'Test Name 2', + 'type': 'insecure_example', + 'id': 'another', + 'users': [], + }], [{ + 'name': 'Module 1', + 'type': 'insecure_example', + 'data': [], + }, { + 'name': 'Invalid config because no data', + 'type': 'insecure_example', + 'id': 'another', + }]) + manager = await auth.auth_manager_from_config(mock_hass, [{ 'name': 'Test Name', 'type': 'insecure_example', @@ -79,13 +103,7 @@ async def test_auth_manager_from_config_auth_modules(mock_hass): 'type': 'insecure_example', 'id': 'another', 'data': [], - }, { - 'name': 'Duplicate ID', - 'type': 'insecure_example', - 'id': 'another', - 'data': [], }]) - providers = [{ 'name': provider.name, 'type': provider.type, diff --git a/tests/test_config.py b/tests/test_config.py index 3cfe67f70b1..e4a6798093f 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -895,9 +895,73 @@ async def test_disallowed_auth_provider_config(hass): 'name': 'Huis', CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, 'time_zone': 'GMT', - CONF_AUTH_PROVIDERS: [ - {'type': 'insecure_example'}, - ] + CONF_AUTH_PROVIDERS: [{ + 'type': 'insecure_example', + 'users': [{ + 'username': 'test-user', + 'password': 'test-pass', + 'name': 'Test Name' + }], + }] + } + with pytest.raises(Invalid): + await config_util.async_process_ha_core_config(hass, core_config) + + +async def test_disallowed_duplicated_auth_provider_config(hass): + """Test loading insecure example auth provider is disallowed.""" + core_config = { + 'latitude': 60, + 'longitude': 50, + 'elevation': 25, + 'name': 'Huis', + CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, + 'time_zone': 'GMT', + CONF_AUTH_PROVIDERS: [{ + 'type': 'homeassistant', + }, { + 'type': 'homeassistant', + }] + } + with pytest.raises(Invalid): + await config_util.async_process_ha_core_config(hass, core_config) + + +async def test_disallowed_auth_mfa_module_config(hass): + """Test loading insecure example auth mfa module is disallowed.""" + core_config = { + 'latitude': 60, + 'longitude': 50, + 'elevation': 25, + 'name': 'Huis', + CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, + 'time_zone': 'GMT', + CONF_AUTH_MFA_MODULES: [{ + 'type': 'insecure_example', + 'data': [{ + 'user_id': 'mock-user', + 'pin': 'test-pin' + }] + }] + } + with pytest.raises(Invalid): + await config_util.async_process_ha_core_config(hass, core_config) + + +async def test_disallowed_duplicated_auth_mfa_module_config(hass): + """Test loading insecure example auth mfa module is disallowed.""" + core_config = { + 'latitude': 60, + 'longitude': 50, + 'elevation': 25, + 'name': 'Huis', + CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, + 'time_zone': 'GMT', + CONF_AUTH_MFA_MODULES: [{ + 'type': 'totp', + }, { + 'type': 'totp', + }] } with pytest.raises(Invalid): await config_util.async_process_ha_core_config(hass, core_config) From 2ea2bcab7747a5482947f0d35c32c0222233cbe6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 20:59:38 +0200 Subject: [PATCH 154/159] Bumped version to 0.77.0b4 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index be0bd814775..ad39aa1ab39 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 77 -PATCH_VERSION = '0b3' +PATCH_VERSION = '0b4' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 8ec109d255ed3fc44a93ca4c462231996ba02a2f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 10:27:34 +0200 Subject: [PATCH 155/159] Bump frontend to 20180829.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index f0976c78224..0156a8b2cd6 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass from homeassistant.util.yaml import load_yaml -REQUIREMENTS = ['home-assistant-frontend==20180827.0'] +REQUIREMENTS = ['home-assistant-frontend==20180829.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index fe3e64cd62e..98f8a336cfc 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -442,7 +442,7 @@ hole==0.3.0 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180827.0 +home-assistant-frontend==20180829.0 # homeassistant.components.homekit_controller # homekit==0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9f732f84b55..31c43319ea7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -84,7 +84,7 @@ hbmqtt==0.9.2 holidays==0.9.6 # homeassistant.components.frontend -home-assistant-frontend==20180827.0 +home-assistant-frontend==20180829.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 9238261e17681154a38206a33996e2661b480eba Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 10:28:34 +0200 Subject: [PATCH 156/159] Update translations --- .../components/auth/.translations/ko.json | 16 ++++++++++ .../components/auth/.translations/ru.json | 16 ++++++++++ .../components/hangouts/.translations/ko.json | 31 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 homeassistant/components/auth/.translations/ko.json create mode 100644 homeassistant/components/auth/.translations/ru.json create mode 100644 homeassistant/components/hangouts/.translations/ko.json diff --git a/homeassistant/components/auth/.translations/ko.json b/homeassistant/components/auth/.translations/ko.json new file mode 100644 index 00000000000..726fa6a6cd1 --- /dev/null +++ b/homeassistant/components/auth/.translations/ko.json @@ -0,0 +1,16 @@ +{ + "mfa_setup": { + "totp": { + "error": { + "invalid_code": "\uc798\ubabb\ub41c \ucf54\ub4dc \uc785\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694. \uc774 \uc624\ub958\uac00 \uc9c0\uc18d\uc801\uc73c\ub85c \ubc1c\uc0dd\ud55c\ub2e4\uba74 Home Assistant \uc758 \uc2dc\uacc4\uac00 \uc815\ud655\ud55c\uc9c0 \ud655\uc778\ud574\ubcf4\uc138\uc694." + }, + "step": { + "init": { + "description": "\uc2dc\uac04 \uae30\ubc18\uc758 \uc77c\ud68c\uc6a9 \ube44\ubc00\ubc88\ud638\ub97c \uc0ac\uc6a9\ud558\ub294 2\ub2e8\uacc4 \uc778\uc99d\uc744 \ud558\ub824\uba74 \uc778\uc99d\uc6a9 \uc571\uc744 \uc774\uc6a9\ud574\uc11c QR \ucf54\ub4dc\ub97c \uc2a4\uce94\ud574 \uc8fc\uc138\uc694. \uc778\uc99d\uc6a9 \uc571\uc740 [Google Authenticator](https://support.google.com/accounts/answer/1066447) \ub098 [Authy](https://authy.com/) \ub97c \ucd94\ucc9c\ub4dc\ub9bd\ub2c8\ub2e4.\n\n{qr_code}\n\n\uc2a4\uce94 \ud6c4\uc5d0 \uc0dd\uc131\ub41c 6\uc790\ub9ac \ucf54\ub4dc\ub97c \uc785\ub825\ud574\uc11c \uc124\uc815\uc744 \ud655\uc778\ud558\uc138\uc694. QR \ucf54\ub4dc \uc2a4\uce94\uc5d0 \ubb38\uc81c\uac00 \uc788\ub2e4\uba74, **`{code}`** \ucf54\ub4dc\ub85c \uc9c1\uc811 \uc124\uc815\ud574\ubcf4\uc138\uc694.", + "title": "TOTP \ub97c \uc0ac\uc6a9\ud558\uc5ec 2 \ub2e8\uacc4 \uc778\uc99d \uad6c\uc131" + } + }, + "title": "TOTP (\uc2dc\uac04 \uae30\ubc18 OTP)" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/auth/.translations/ru.json b/homeassistant/components/auth/.translations/ru.json new file mode 100644 index 00000000000..b4b5b58f9fa --- /dev/null +++ b/homeassistant/components/auth/.translations/ru.json @@ -0,0 +1,16 @@ +{ + "mfa_setup": { + "totp": { + "error": { + "invalid_code": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043a\u043e\u0434. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430. \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0435 \u044d\u0442\u0443 \u043e\u0448\u0438\u0431\u043a\u0443, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0447\u0430\u0441\u044b \u0432 \u0432\u0430\u0448\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 Home Assistant \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f." + }, + "step": { + "init": { + "description": "\u0427\u0442\u043e\u0431\u044b \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u0443\u044e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u0430\u0440\u043e\u043b\u0435\u0439, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043e\u0442\u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0439\u0442\u0435 QR-\u043a\u043e\u0434 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u0434\u043b\u0438\u043d\u043d\u043e\u0441\u0442\u0438. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0433\u043e \u043d\u0435\u0442, \u043c\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0431\u043e [Google Authenticator] (https://support.google.com/accounts/answer/1066447), \u043b\u0438\u0431\u043e [Authy] (https://authy.com/). \n\n {qr_code} \n \n \u041f\u043e\u0441\u043b\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f QR-\u043a\u043e\u0434\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0448\u0435\u0441\u0442\u0438\u0437\u043d\u0430\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438\u0437 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441\u043e \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c QR-\u043a\u043e\u0434\u0430, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0440\u0443\u0447\u043d\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0441 \u043a\u043e\u0434\u043e\u043c ** ` {code} ` **.", + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u0432\u0443\u0445\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c TOTP" + } + }, + "title": "TOTP" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/hangouts/.translations/ko.json b/homeassistant/components/hangouts/.translations/ko.json new file mode 100644 index 00000000000..aabf977a8cc --- /dev/null +++ b/homeassistant/components/hangouts/.translations/ko.json @@ -0,0 +1,31 @@ +{ + "config": { + "abort": { + "already_configured": "Google Hangouts \uc740 \uc774\ubbf8 \uc124\uc815\ub41c \uc0c1\ud0dc\uc785\ub2c8\ub2e4", + "unknown": "\uc54c \uc218\uc5c6\ub294 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4" + }, + "error": { + "invalid_2fa": "2\ub2e8\uacc4 \uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574 \uc8fc\uc138\uc694.", + "invalid_2fa_method": "2\ub2e8\uacc4 \uc778\uc99d \ubc29\ubc95\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4. (\uc804\ud654\uae30\uc5d0\uc11c \ud655\uc778)", + "invalid_login": "\uc798\ubabb\ub41c \ub85c\uadf8\uc778\uc785\ub2c8\ub2e4. \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694." + }, + "step": { + "2fa": { + "data": { + "2fa": "2\ub2e8\uacc4 \uc778\uc99d PIN" + }, + "description": "\uc8c4\uc1a1\ud569\ub2c8\ub2e4. \uad00\ub828 \ub0b4\uc6a9\uc774 \uc544\uc9c1 \uc5c5\ub370\uc774\ud2b8 \ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \ucd94\ud6c4\uc5d0 \ubc18\uc601\ub420 \uc608\uc815\uc774\ub2c8 \uc870\uae08\ub9cc \uae30\ub2e4\ub824\uc8fc\uc138\uc694.", + "title": "2\ub2e8\uacc4 \uc778\uc99d" + }, + "user": { + "data": { + "email": "\uc774\uba54\uc77c \uc8fc\uc18c", + "password": "\ube44\ubc00\ubc88\ud638" + }, + "description": "\uc8c4\uc1a1\ud569\ub2c8\ub2e4. \uad00\ub828 \ub0b4\uc6a9\uc774 \uc544\uc9c1 \uc5c5\ub370\uc774\ud2b8 \ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \ucd94\ud6c4\uc5d0 \ubc18\uc601\ub420 \uc608\uc815\uc774\ub2c8 \uc870\uae08\ub9cc \uae30\ub2e4\ub824\uc8fc\uc138\uc694.", + "title": "Google Hangouts \ub85c\uadf8\uc778" + } + }, + "title": "Google Hangouts" + } +} \ No newline at end of file From f9b1fb5906d5ac56fb55523bd0368d20a343766e Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 29 Aug 2018 01:16:54 -0700 Subject: [PATCH 157/159] Tweak MFA login flow (#16254) * Tweak MFA login flow * Fix typo --- homeassistant/auth/mfa_modules/totp.py | 3 ++- homeassistant/auth/providers/__init__.py | 20 +++++++++++++------ .../auth/mfa_modules/test_insecure_example.py | 2 +- tests/auth/mfa_modules/test_totp.py | 2 +- tests/auth/test_init.py | 19 +++++------------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/homeassistant/auth/mfa_modules/totp.py b/homeassistant/auth/mfa_modules/totp.py index 48531863c1a..0914658a655 100644 --- a/homeassistant/auth/mfa_modules/totp.py +++ b/homeassistant/auth/mfa_modules/totp.py @@ -137,8 +137,9 @@ class TotpAuthModule(MultiFactorAuthModule): await self._async_load() # user_input has been validate in caller + # set INPUT_FIELD_CODE as vol.Required is not user friendly return await self.hass.async_add_executor_job( - self._validate_2fa, user_id, user_input[INPUT_FIELD_CODE]) + self._validate_2fa, user_id, user_input.get(INPUT_FIELD_CODE, '')) def _validate_2fa(self, user_id: str, code: str) -> bool: """Validate two factor authentication code.""" diff --git a/homeassistant/auth/providers/__init__.py b/homeassistant/auth/providers/__init__.py index 370391d57cd..3cb1c6b121e 100644 --- a/homeassistant/auth/providers/__init__.py +++ b/homeassistant/auth/providers/__init__.py @@ -224,19 +224,27 @@ class LoginFlow(data_entry_flow.FlowHandler): if user_input is not None: expires = self.created_at + SESSION_EXPIRATION if dt_util.utcnow() > expires: - errors['base'] = 'login_expired' - else: - result = await auth_module.async_validation( - self.user.id, user_input) # type: ignore - if not result: - errors['base'] = 'invalid_auth' + return self.async_abort( + reason='login_expired' + ) + + result = await auth_module.async_validation( + self.user.id, user_input) # type: ignore + if not result: + errors['base'] = 'invalid_code' if not errors: return await self.async_finish(self.user) + description_placeholders = { + 'mfa_module_name': auth_module.name, + 'mfa_module_id': auth_module.id + } # type: Dict[str, str] + return self.async_show_form( step_id='mfa', data_schema=auth_module.input_schema, + description_placeholders=description_placeholders, errors=errors, ) diff --git a/tests/auth/mfa_modules/test_insecure_example.py b/tests/auth/mfa_modules/test_insecure_example.py index e6f83762cd7..80109627140 100644 --- a/tests/auth/mfa_modules/test_insecure_example.py +++ b/tests/auth/mfa_modules/test_insecure_example.py @@ -119,7 +119,7 @@ async def test_login(hass): result = await hass.auth.login_flow.async_configure( result['flow_id'], {'pin': 'invalid-code'}) assert result['type'] == data_entry_flow.RESULT_TYPE_FORM - assert result['errors']['base'] == 'invalid_auth' + assert result['errors']['base'] == 'invalid_code' result = await hass.auth.login_flow.async_configure( result['flow_id'], {'pin': '123456'}) diff --git a/tests/auth/mfa_modules/test_totp.py b/tests/auth/mfa_modules/test_totp.py index 28e6c949bc4..6e3558ec549 100644 --- a/tests/auth/mfa_modules/test_totp.py +++ b/tests/auth/mfa_modules/test_totp.py @@ -121,7 +121,7 @@ async def test_login_flow_validates_mfa(hass): result['flow_id'], {'code': 'invalid-code'}) assert result['type'] == data_entry_flow.RESULT_TYPE_FORM assert result['step_id'] == 'mfa' - assert result['errors']['base'] == 'invalid_auth' + assert result['errors']['base'] == 'invalid_code' with patch('pyotp.TOTP.verify', return_value=True): result = await hass.auth.login_flow.async_configure( diff --git a/tests/auth/test_init.py b/tests/auth/test_init.py index d9e7a50410f..63b2b4408dd 100644 --- a/tests/auth/test_init.py +++ b/tests/auth/test_init.py @@ -428,10 +428,10 @@ async def test_login_with_auth_module(mock_hass): 'pin': 'invalid-pin', }) - # Invalid auth error + # Invalid code error assert step['type'] == data_entry_flow.RESULT_TYPE_FORM assert step['step_id'] == 'mfa' - assert step['errors'] == {'base': 'invalid_auth'} + assert step['errors'] == {'base': 'invalid_code'} step = await manager.login_flow.async_configure(step['flow_id'], { 'pin': 'test-pin', @@ -571,18 +571,9 @@ async def test_auth_module_expired_session(mock_hass): step = await manager.login_flow.async_configure(step['flow_id'], { 'pin': 'test-pin', }) - # Invalid auth due session timeout - assert step['type'] == data_entry_flow.RESULT_TYPE_FORM - assert step['step_id'] == 'mfa' - assert step['errors']['base'] == 'login_expired' - - # The second try will fail as well - step = await manager.login_flow.async_configure(step['flow_id'], { - 'pin': 'test-pin', - }) - assert step['type'] == data_entry_flow.RESULT_TYPE_FORM - assert step['step_id'] == 'mfa' - assert step['errors']['base'] == 'login_expired' + # login flow abort due session timeout + assert step['type'] == data_entry_flow.RESULT_TYPE_ABORT + assert step['reason'] == 'login_expired' async def test_enable_mfa_for_user(hass, hass_storage): From b5919ce92ca1f96a0506c883c44380bb46db0006 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Wed, 29 Aug 2018 10:07:32 +0200 Subject: [PATCH 158/159] def device shouldnt call it self but self._device (#16255) --- homeassistant/components/media_player/plex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/media_player/plex.py b/homeassistant/components/media_player/plex.py index 35906cf5023..46dacd98aad 100644 --- a/homeassistant/components/media_player/plex.py +++ b/homeassistant/components/media_player/plex.py @@ -531,7 +531,7 @@ class PlexClient(MediaPlayerDevice): @property def device(self): """Return the device, if any.""" - return self.device + return self._device @property def marked_unavailable(self): From f01e1ef0aab4090cda346dd51fb87721d21e6777 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 10:29:51 +0200 Subject: [PATCH 159/159] Version bump to 0.77.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index ad39aa1ab39..6587e13b727 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 77 -PATCH_VERSION = '0b4' +PATCH_VERSION = '0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3)