From 69934a9598c3fcd56153852e4d894734d5691ae1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 11 Aug 2018 08:58:52 +0200 Subject: [PATCH 001/147] Bumped version to 0.76.0b0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 1b9dc8986a5..65505bf30ec 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -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 e0229b799d59e37f9f29c2600fb37e8046b38678 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 Aug 2018 21:27:34 +0200 Subject: [PATCH 002/147] 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 7f4521e3522..2f31b4359bd 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 985f96662e3a8cc3783e647268f8ee2ede5eb5d2 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sun, 12 Aug 2018 20:22:54 +0200 Subject: [PATCH 003/147] 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 2f31b4359bd..5a2235df870 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 c0830f1c20d27f770a833f5fa4c99d1066cdf908 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 Aug 2018 22:39:13 +0200 Subject: [PATCH 004/147] 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 9e217651730d2baac909aa6ca6112060f1ebcb64 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 13 Aug 2018 23:17:30 +0200 Subject: [PATCH 005/147] Bumped version to 0.76.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 65505bf30ec..52175c2b4e9 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -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 6d432d19fe751f533c7fb1341f9cfee7d32925ff Mon Sep 17 00:00:00 2001 From: kbickar Date: Tue, 14 Aug 2018 09:50:44 -0400 Subject: [PATCH 006/147] 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 5a2235df870..0e6d7e1ac07 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 34e1f1b6da4d748976dbd535297d1b3ef56ec176 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 13 Aug 2018 02:27:18 -0700 Subject: [PATCH 007/147] 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 d0e4c95bbc3a95aa4db17f504db454c86403bdc2 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 13 Aug 2018 02:26:06 -0700 Subject: [PATCH 008/147] 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 d393380122d0092a7b2b127e7722dbd8e27972af Mon Sep 17 00:00:00 2001 From: Khalid Date: Tue, 14 Aug 2018 12:55:40 +0300 Subject: [PATCH 009/147] 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 f4e84fbf84f1526b5e4a0a47a16a51797eb9961d Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Tue, 14 Aug 2018 10:53:08 +0100 Subject: [PATCH 010/147] 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 1b384c322a4fd60404bf344cdd352e571e213e20 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Mon, 13 Aug 2018 00:26:20 -0700 Subject: [PATCH 011/147] 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 899c2057b739977974ad72995d4d7e385a25c307 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 08:20:17 +0200 Subject: [PATCH 012/147] 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 c1d80667983..9ba977f92f5 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]) @@ -221,6 +229,7 @@ class HomeAssistantHTTP: self.server_host = server_host self.server_port = server_port self.is_ban_enabled = is_ban_enabled + self.ssl_profile = ssl_profile self._handler = None self.server = None @@ -307,7 +316,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 f5df567d099f6bdef1e0b53b38d36e48e9f58c0e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 21:14:12 +0200 Subject: [PATCH 013/147] 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 d9c92fa357f..532f3672df4 100644 --- a/homeassistant/components/websocket_api.py +++ b/homeassistant/components/websocket_api.py @@ -352,11 +352,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 0e6d7e1ac07..3f50e50d19a 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 1777270aa2044f0468b877ceee2c3861e463a921 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 22:02:01 +0200 Subject: [PATCH 014/147] 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 3f50e50d19a..5289db61f62 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 e64e84ad7af2bf5578e08977732a576e4f9a48e5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 14 Aug 2018 22:06:57 +0200 Subject: [PATCH 015/147] Bumped version to 0.76.0b2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 52175c2b4e9..200b58461b4 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -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 4035880003243abcb6d4a9e3623c3f3a1b8d9773 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 15 Aug 2018 10:50:11 +0200 Subject: [PATCH 016/147] 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 2306d14b5dd4d5f115c8e4b7ac233287edb66c7f Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 14 Aug 2018 23:09:19 -0700 Subject: [PATCH 017/147] 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 f8051a56987dc6569640c196406d40b52c863bc6 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 15 Aug 2018 00:56:05 -0700 Subject: [PATCH 018/147] 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 6da0ae4d231052aad4c5f3e1677e3df050c73fdc Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 15 Aug 2018 10:55:03 +0200 Subject: [PATCH 019/147] Bumped version to 0.76.0b3 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 200b58461b4..5e7d6f9585b 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -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 11eb29f520191d20a9b777d0f30c434d77bd0677 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 14:21:43 +0200 Subject: [PATCH 020/147] 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 5289db61f62..475f19f3dd0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -432,7 +432,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 d540a084dd07e01b7170e1be1843f87607d61526 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Thu, 16 Aug 2018 14:19:42 +0200 Subject: [PATCH 021/147] 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 2469bc7e2ed6b6b64e5fc8071e631b0c726f3b65 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 13:46:43 +0200 Subject: [PATCH 022/147] 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 5eccfc2604ff72580a9bec6a0bab789ff4a09b9f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 14:26:52 +0200 Subject: [PATCH 023/147] Bumped version to 0.76.0b4 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 5e7d6f9585b..8914a6ba76c 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -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 e41ce1d6ecb8c2b4497a1f6e1eda3b13d596fa88 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 22:15:39 +0200 Subject: [PATCH 024/147] 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 475f19f3dd0..aad64d205f3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -432,7 +432,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 061859cc4decd3745724fc35222d71af3c180871 Mon Sep 17 00:00:00 2001 From: Steven Looman Date: Thu, 16 Aug 2018 22:42:11 +0200 Subject: [PATCH 025/147] 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 aad64d205f3..d65ef4fce18 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 92e26495da9dad9359fcef426e37b5f510f30d8e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 22:41:44 +0200 Subject: [PATCH 026/147] 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 c09e7e620f092fb400e0d6e3e39feb85e2e4b44c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 16 Aug 2018 23:02:34 +0200 Subject: [PATCH 027/147] Bumped version to 0.76.0b5 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 8914a6ba76c..7a9dbaff042 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -PATCH_VERSION = '0b4' +PATCH_VERSION = '0b5' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From e4425e6a37eb8a311221de5942f4d8ef20a89443 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 17 Aug 2018 17:23:20 +0200 Subject: [PATCH 028/147] Version 0.76.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 7a9dbaff042..5a481e0a8c1 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -PATCH_VERSION = '0b5' +PATCH_VERSION = '0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 6827256586773d337aedda349037884da52a6c17 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 18 Aug 2018 11:15:33 +0200 Subject: [PATCH 029/147] 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 d65ef4fce18..bcbcd649805 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -432,7 +432,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 8b153494025..24aa79587ad 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 1c8ef4e196eb5930f90f5491d19f53bd4cf8cf98 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Aug 2018 17:22:09 +0200 Subject: [PATCH 030/147] 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 cb44607e96f7dff29ec18d39119e0e909a6fb7e1 Mon Sep 17 00:00:00 2001 From: huangyupeng Date: Mon, 20 Aug 2018 00:55:10 +0800 Subject: [PATCH 031/147] 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 bcbcd649805..a2b640cae1e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1389,7 +1389,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 9c3251b5f0d287c95afeef88ed7ed57d3c790026 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Aug 2018 18:56:31 +0200 Subject: [PATCH 032/147] 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 3be301fac9b213b6b252ec92cffcd1d62d3cc960 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Aug 2018 18:58:21 +0200 Subject: [PATCH 033/147] Bumped version to 0.76.1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 5a481e0a8c1..855f973554b 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -PATCH_VERSION = '0' +PATCH_VERSION = '1' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 3c5e62d47eeded341b41cbe769f3e29b7b6f1614 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 19 Aug 2018 18:57:06 +0200 Subject: [PATCH 034/147] 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 1be388c5874a1880455a0a1d50935791c1ee72a3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 20 Aug 2018 11:52:23 +0200 Subject: [PATCH 035/147] 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 a2b640cae1e..fe728bf2e02 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -432,7 +432,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 24aa79587ad..7119259304e 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 bd776c84bc2cd0cb31b86f99b1f3d17eb889fe1b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 21 Aug 2018 11:41:52 +0200 Subject: [PATCH 036/147] 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 977d86e7ca88def52d5137ef7fc326f72ae5e9de Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 21 Aug 2018 11:43:14 +0200 Subject: [PATCH 037/147] Bumped version to 0.76.2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 855f973554b..14054e44663 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 76 -PATCH_VERSION = '1' +PATCH_VERSION = '2' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 6c5f98668e958c5aa4f12b06dd54af60b42fe52e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 24 Aug 2018 15:54:04 +0200 Subject: [PATCH 038/147] 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 039/147] 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 040/147] 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 041/147] 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 042/147] 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 043/147] 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 e8775ba2b4c27018872b977d6874bc177d9cb186 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Fri, 24 Aug 2018 10:17:43 -0700 Subject: [PATCH 044/147] 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 e91a1529e43a9ce08a9858d4fce59f4bcc7607e0 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 24 Aug 2018 19:37:22 +0200 Subject: [PATCH 045/147] 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 25480a023ec..447c6348500 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 71cbc724c59..52688beaa26 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 84365cde077d6a927947793bd5f8a4790f16c852 Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Fri, 24 Aug 2018 17:27:12 -0400 Subject: [PATCH 046/147] 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 647b3ff0feea7ec5e48e8ae81f185d777ee4a15f Mon Sep 17 00:00:00 2001 From: Nate Clark Date: Fri, 24 Aug 2018 17:29:25 -0400 Subject: [PATCH 047/147] 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 69cea6001ffd93ae9aeecbc671ef5b00eb992c79 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sat, 25 Aug 2018 01:05:53 +0200 Subject: [PATCH 048/147] Add 'moon_phase' to Dark Sky sensor (#16179) --- homeassistant/components/sensor/darksky.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/sensor/darksky.py b/homeassistant/components/sensor/darksky.py index 7ce51454ee5..a6c602602f4 100644 --- a/homeassistant/components/sensor/darksky.py +++ b/homeassistant/components/sensor/darksky.py @@ -33,10 +33,12 @@ DEFAULT_LANGUAGE = 'en' DEFAULT_NAME = 'Dark Sky' -DEPRECATED_SENSOR_TYPES = {'apparent_temperature_max', - 'apparent_temperature_min', - 'temperature_max', - 'temperature_min'} +DEPRECATED_SENSOR_TYPES = { + 'apparent_temperature_max', + 'apparent_temperature_min', + 'temperature_max', + 'temperature_min', +} # Sensor types are defined like so: # Name, si unit, us unit, ca unit, uk unit, uk2 unit @@ -125,6 +127,8 @@ SENSOR_TYPES = { UNIT_UV_INDEX, UNIT_UV_INDEX, UNIT_UV_INDEX, UNIT_UV_INDEX, UNIT_UV_INDEX, 'mdi:weather-sunny', ['currently', 'hourly', 'daily']], + 'moon_phase': ['Moon Phase', None, None, None, None, None, + 'mdi:weather-night', ['daily']], } CONDITION_PICTURES = { @@ -203,7 +207,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): sensors = [] for variable in config[CONF_MONITORED_CONDITIONS]: if variable in DEPRECATED_SENSOR_TYPES: - _LOGGER.warning("Monitored condition %s is deprecated.", + _LOGGER.warning("Monitored condition %s is deprecated", variable) sensors.append(DarkSkySensor(forecast_data, variable, name)) if forecast is not None and 'daily' in SENSOR_TYPES[variable][7]: @@ -316,7 +320,8 @@ class DarkSkySensor(Entity): 'apparent_temperature_max', 'apparent_temperature_high', 'precip_intensity_max', - 'precip_accumulation']): + 'precip_accumulation', + 'moon_phase']): self.forecast_data.update_daily() daily = self.forecast_data.data_daily if self.type == 'daily_summary': @@ -407,7 +412,7 @@ class DarkSkyData: self._api_key, self.latitude, self.longitude, units=self.units, lang=self.language) except (ConnectError, HTTPError, Timeout, ValueError) as error: - _LOGGER.error("Unable to connect to Dark Sky. %s", error) + _LOGGER.error("Unable to connect to Dark Sky: %s", error) self.data = None self.unit_system = self.data and self.data.json['flags']['units'] From 24a8d60566fb5cf62942d042d38965a705d1bc65 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Fri, 24 Aug 2018 22:57:36 -0700 Subject: [PATCH 049/147] 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 97173f495c78b7add5e747857d988969be0e1ae6 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sat, 25 Aug 2018 10:59:28 +0200 Subject: [PATCH 050/147] 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 456aa5a2b227ee4553b6d302a8a194fccff1c5f1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 25 Aug 2018 11:01:32 +0200 Subject: [PATCH 051/147] 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 26a485d43c8ba2bafa2e989ab65524fc427416ad Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sat, 25 Aug 2018 02:09:48 -0700 Subject: [PATCH 052/147] 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 617802653fe44de57fb4dd41d21955d5dfd50427 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 25 Aug 2018 11:15:01 +0200 Subject: [PATCH 053/147] 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 447c6348500..a5cfe9e402a 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 52688beaa26..7b9dc1d1eb3 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 bb6567f84c7bf75f09bcc8ebaa02078a2309fc96 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 25 Aug 2018 11:15:01 +0200 Subject: [PATCH 054/147] 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 055/147] 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 056/147] 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 057/147] 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 058/147] 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 059/147] 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 060/147] 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 061/147] 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 062/147] 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 063/147] 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 f929c38e980d728bc74055043310bdc4c24211a1 Mon Sep 17 00:00:00 2001 From: djm300 Date: Sat, 25 Aug 2018 11:21:57 +0200 Subject: [PATCH 064/147] Zoneminder SSL fix (#16157) * Update zoneminder.py Added a verify_ssl parameter for zoneminder * PEP8 fixup * PEP8 indenting fix * Fix lint issue * Remove whitespace --- homeassistant/components/zoneminder.py | 28 +++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/zoneminder.py b/homeassistant/components/zoneminder.py index 471c1c6e82c..5c045544456 100644 --- a/homeassistant/components/zoneminder.py +++ b/homeassistant/components/zoneminder.py @@ -11,16 +11,19 @@ import requests import voluptuous as vol from homeassistant.const import ( - CONF_PATH, CONF_HOST, CONF_SSL, CONF_PASSWORD, CONF_USERNAME) + CONF_HOST, CONF_PASSWORD, CONF_PATH, CONF_SSL, CONF_USERNAME, + CONF_VERIFY_SSL) import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) CONF_PATH_ZMS = 'path_zms' + DEFAULT_PATH = '/zm/' DEFAULT_PATH_ZMS = '/zm/cgi-bin/nph-zms' DEFAULT_SSL = False DEFAULT_TIMEOUT = 10 +DEFAULT_VERIFY_SSL = True DOMAIN = 'zoneminder' LOGIN_RETRIES = 2 @@ -30,12 +33,12 @@ ZM = {} CONFIG_SCHEMA = vol.Schema({ DOMAIN: vol.Schema({ vol.Required(CONF_HOST): cv.string, - vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, + vol.Optional(CONF_PASSWORD): cv.string, vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string, - # This should match PATH_ZMS in ZoneMinder settings. vol.Optional(CONF_PATH_ZMS, default=DEFAULT_PATH_ZMS): cv.string, + vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, vol.Optional(CONF_USERNAME): cv.string, - vol.Optional(CONF_PASSWORD): cv.string + vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean, }) }, extra=vol.ALLOW_EXTRA) @@ -56,11 +59,14 @@ def setup(hass, config): username = conf.get(CONF_USERNAME, None) password = conf.get(CONF_PASSWORD, None) + ssl_verification = conf.get(CONF_VERIFY_SSL) + ZM['server_origin'] = server_origin ZM['url'] = url ZM['username'] = username ZM['password'] = password ZM['path_zms'] = conf.get(CONF_PATH_ZMS) + ZM['ssl_verification'] = ssl_verification hass.data[DOMAIN] = ZM @@ -77,14 +83,16 @@ def login(): if ZM['password']: login_post['password'] = ZM['password'] - req = requests.post(ZM['url'] + '/index.php', data=login_post) + req = requests.post(ZM['url'] + '/index.php', data=login_post, + verify=ZM['ssl_verification'], timeout=DEFAULT_TIMEOUT) + ZM['cookies'] = req.cookies # Login calls returns a 200 response on both failure and success. # The only way to tell if you logged in correctly is to issue an api call. req = requests.get( ZM['url'] + 'api/host/getVersion.json', cookies=ZM['cookies'], - timeout=DEFAULT_TIMEOUT) + timeout=DEFAULT_TIMEOUT, verify=ZM['ssl_verification']) if not req.ok: _LOGGER.error("Connection error logging into ZoneMinder") @@ -100,7 +108,8 @@ def _zm_request(method, api_url, data=None): for _ in range(LOGIN_RETRIES): req = requests.request( method, urljoin(ZM['url'], api_url), data=data, - cookies=ZM['cookies'], timeout=DEFAULT_TIMEOUT) + cookies=ZM['cookies'], timeout=DEFAULT_TIMEOUT, + verify=ZM['ssl_verification']) if not req.ok: login() @@ -113,8 +122,9 @@ def _zm_request(method, api_url, data=None): try: return req.json() except ValueError: - _LOGGER.exception('JSON decode exception caught while attempting to ' - 'decode "%s"', req.text) + _LOGGER.exception( + "JSON decode exception caught while attempting to decode: %s", + req.text) def get_state(api_url): From 2f2bcf0058e9ce2e56cc06e8cf6786b44fa6c866 Mon Sep 17 00:00:00 2001 From: Thomas Delaet Date: Sat, 25 Aug 2018 20:42:26 +0200 Subject: [PATCH 065/147] update python-velbus library version (#16194) --- homeassistant/components/velbus.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/velbus.py b/homeassistant/components/velbus.py index 8c944916905..a6cdcc7cf90 100644 --- a/homeassistant/components/velbus.py +++ b/homeassistant/components/velbus.py @@ -12,7 +12,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_STOP, CONF_PORT from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['python-velbus==2.0.17'] +REQUIREMENTS = ['python-velbus==2.0.18'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index a5cfe9e402a..c150ac482bf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1134,7 +1134,7 @@ python-telegram-bot==10.1.0 python-twitch==1.3.0 # homeassistant.components.velbus -python-velbus==2.0.17 +python-velbus==2.0.18 # homeassistant.components.media_player.vlc python-vlc==1.1.2 From a1ce14e70f4061873d471acce9aff03f82a67a51 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sun, 26 Aug 2018 10:04:51 +0200 Subject: [PATCH 066/147] MQTT: Log transmitted as well as received messages (#16195) --- homeassistant/components/mqtt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/mqtt/__init__.py b/homeassistant/components/mqtt/__init__.py index 19bacbc8d4c..71be9c2435e 100644 --- a/homeassistant/components/mqtt/__init__.py +++ b/homeassistant/components/mqtt/__init__.py @@ -550,6 +550,7 @@ class MQTT: This method must be run in the event loop and returns a coroutine. """ async with self._paho_lock: + _LOGGER.debug("Transmitting message on %s: %s", topic, payload) await self.hass.async_add_job( self._mqttc.publish, topic, payload, qos, retain) From 0a7055d47551944f1319a0302302db60c9589879 Mon Sep 17 00:00:00 2001 From: Dan Klaffenbach Date: Sun, 26 Aug 2018 12:00:20 +0200 Subject: [PATCH 067/147] 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 0da3e737651a150c17016f43b5f9144deff7ddd7 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 26 Aug 2018 12:28:44 +0200 Subject: [PATCH 068/147] Upgrade sqlalchemy to 1.2.11 (#16192) --- homeassistant/components/recorder/__init__.py | 2 +- homeassistant/components/sensor/sql.py | 4 ++-- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index f3d8e269a42..47d6e181c8f 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -35,7 +35,7 @@ from . import migration, purge from .const import DATA_INSTANCE from .util import session_scope -REQUIREMENTS = ['sqlalchemy==1.2.10'] +REQUIREMENTS = ['sqlalchemy==1.2.11'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/sensor/sql.py b/homeassistant/components/sensor/sql.py index a2e9549a117..53821275d42 100644 --- a/homeassistant/components/sensor/sql.py +++ b/homeassistant/components/sensor/sql.py @@ -20,7 +20,7 @@ from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) -REQUIREMENTS = ['sqlalchemy==1.2.10'] +REQUIREMENTS = ['sqlalchemy==1.2.11'] CONF_COLUMN_NAME = 'column' CONF_QUERIES = 'queries' @@ -62,7 +62,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): engine = sqlalchemy.create_engine(db_url) sessionmaker = scoped_session(sessionmaker(bind=engine)) - # run a dummy query just to test the db_url + # Run a dummy query just to test the db_url sess = sessionmaker() sess.execute("SELECT 1;") diff --git a/requirements_all.txt b/requirements_all.txt index c150ac482bf..41d716c28f1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1334,7 +1334,7 @@ spotipy-homeassistant==2.4.4.dev1 # homeassistant.components.recorder # homeassistant.scripts.db_migrator # homeassistant.components.sensor.sql -sqlalchemy==1.2.10 +sqlalchemy==1.2.11 # homeassistant.components.statsd statsd==3.2.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7b9dc1d1eb3..af68edbd632 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -200,7 +200,7 @@ somecomfort==0.5.2 # homeassistant.components.recorder # homeassistant.scripts.db_migrator # homeassistant.components.sensor.sql -sqlalchemy==1.2.10 +sqlalchemy==1.2.11 # homeassistant.components.statsd statsd==3.2.1 From 289b1802fdd7670bfa563cdf3062d1186ab4f942 Mon Sep 17 00:00:00 2001 From: Martin Fuchs <39280548+fucm@users.noreply.github.com> Date: Sun, 26 Aug 2018 21:20:34 +0200 Subject: [PATCH 069/147] Add battery warning, rssi level and check for availability (#16193) --- homeassistant/components/sensor/tahoma.py | 32 ++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sensor/tahoma.py b/homeassistant/components/sensor/tahoma.py index eafc6fdf616..a59eb705498 100644 --- a/homeassistant/components/sensor/tahoma.py +++ b/homeassistant/components/sensor/tahoma.py @@ -11,12 +11,15 @@ from datetime import timedelta from homeassistant.helpers.entity import Entity from homeassistant.components.tahoma import ( DOMAIN as TAHOMA_DOMAIN, TahomaDevice) +from homeassistant.const import ATTR_BATTERY_LEVEL DEPENDENCIES = ['tahoma'] _LOGGER = logging.getLogger(__name__) -SCAN_INTERVAL = timedelta(seconds=10) +SCAN_INTERVAL = timedelta(seconds=60) + +ATTR_RSSI_LEVEL = 'rssi_level' def setup_platform(hass, config, add_entities, discovery_info=None): @@ -34,6 +37,7 @@ class TahomaSensor(TahomaDevice, Entity): def __init__(self, tahoma_device, controller): """Initialize the sensor.""" self.current_value = None + self._available = False super().__init__(tahoma_device, controller) @property @@ -62,3 +66,29 @@ class TahomaSensor(TahomaDevice, Entity): if self.tahoma_device.type == 'io:SomfyContactIOSystemSensor': self.current_value = self.tahoma_device.active_states[ 'core:ContactState'] + + self._available = bool(self.tahoma_device.active_states.get( + 'core:StatusState') == 'available') + + _LOGGER.debug("Update %s, value: %d", self._name, self.current_value) + + @property + def device_state_attributes(self): + """Return the device state attributes.""" + attr = {} + super_attr = super().device_state_attributes + if super_attr is not None: + attr.update(super_attr) + + if 'core:RSSILevelState' in self.tahoma_device.active_states: + attr[ATTR_RSSI_LEVEL] = \ + self.tahoma_device.active_states['core:RSSILevelState'] + if 'core:SensorDefectState' in self.tahoma_device.active_states: + attr[ATTR_BATTERY_LEVEL] = \ + self.tahoma_device.active_states['core:SensorDefectState'] + return attr + + @property + def available(self): + """Return True if entity is available.""" + return self._available From 5341785aaec8471599ea4110c5c6d2271d4dacdd Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sun, 26 Aug 2018 21:25:39 +0200 Subject: [PATCH 070/147] 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 3032de1dc1f4f8ca12aa7eab965fcc5873b21061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20GR=C3=89A?= Date: Sun, 26 Aug 2018 21:27:03 +0200 Subject: [PATCH 071/147] Inconsistent entity_id when multiple sensors (#16205) * Inconsistent entity_id when multiple sensors I am submitting a change to fix a [bug](https://github.com/home-assistant/home-assistant/issues/16204) for when there are several sensors for the same hostname. For example I want to track my IPv4 and IPv6 address. It creates two entities that regularly switch ids based on the order they get initialized. To fix this I comform to the way other componnents have addressed the issue by adding an optional `name` attribute. * Line too long * Removing trailing whitespace --- homeassistant/components/sensor/dnsip.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/sensor/dnsip.py b/homeassistant/components/sensor/dnsip.py index ac681dc691a..3027b6f8ca6 100644 --- a/homeassistant/components/sensor/dnsip.py +++ b/homeassistant/components/sensor/dnsip.py @@ -19,11 +19,13 @@ REQUIREMENTS = ['aiodns==1.1.1'] _LOGGER = logging.getLogger(__name__) +CONF_NAME = 'name' CONF_HOSTNAME = 'hostname' CONF_RESOLVER = 'resolver' CONF_RESOLVER_IPV6 = 'resolver_ipv6' CONF_IPV6 = 'ipv6' +DEFAULT_NAME = 'myip' DEFAULT_HOSTNAME = 'myip.opendns.com' DEFAULT_RESOLVER = '208.67.222.222' DEFAULT_RESOLVER_IPV6 = '2620:0:ccc::2' @@ -32,6 +34,7 @@ DEFAULT_IPV6 = False SCAN_INTERVAL = timedelta(seconds=120) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_HOSTNAME, default=DEFAULT_HOSTNAME): cv.string, vol.Optional(CONF_RESOLVER, default=DEFAULT_RESOLVER): cv.string, vol.Optional(CONF_RESOLVER_IPV6, default=DEFAULT_RESOLVER_IPV6): cv.string, @@ -40,28 +43,34 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ @asyncio.coroutine -def async_setup_platform(hass, config, async_add_entities, - discovery_info=None): +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): """Set up the DNS IP sensor.""" hostname = config.get(CONF_HOSTNAME) + name = config.get(CONF_NAME) + if not name: + if hostname == DEFAULT_HOSTNAME: + name = DEFAULT_NAME + else: + name = hostname ipv6 = config.get(CONF_IPV6) if ipv6: resolver = config.get(CONF_RESOLVER_IPV6) else: resolver = config.get(CONF_RESOLVER) - async_add_entities([WanIpSensor( - hass, hostname, resolver, ipv6)], True) + async_add_devices([WanIpSensor( + hass, name, hostname, resolver, ipv6)], True) class WanIpSensor(Entity): """Implementation of a DNS IP sensor.""" - def __init__(self, hass, hostname, resolver, ipv6): + def __init__(self, hass, name, hostname, resolver, ipv6): """Initialize the sensor.""" import aiodns self.hass = hass - self._name = hostname + self._name = name + self.hostname = hostname self.resolver = aiodns.DNSResolver(loop=self.hass.loop) self.resolver.nameservers = [resolver] self.querytype = 'AAAA' if ipv6 else 'A' @@ -80,7 +89,8 @@ class WanIpSensor(Entity): @asyncio.coroutine def async_update(self): """Get the current DNS IP address for hostname.""" - response = yield from self.resolver.query(self._name, self.querytype) + response = yield from self.resolver.query(self.hostname, + self.querytype) if response: self._state = response[0].host else: From d166f2da80d400f3bde6f4b4f3f656a711ab6728 Mon Sep 17 00:00:00 2001 From: Marcel Hoppe Date: Sun, 26 Aug 2018 21:28:42 +0200 Subject: [PATCH 072/147] 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 499bb3f4a29e0f2bc647116e1180f02c424d6d7d Mon Sep 17 00:00:00 2001 From: PhracturedBlue Date: Sun, 26 Aug 2018 12:29:15 -0700 Subject: [PATCH 073/147] 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 b043ac0f7fdb0c8a4dead6755ac8daf85ce1dfa5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 21:30:14 +0200 Subject: [PATCH 074/147] 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 41d716c28f1..2cd19d58ce6 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 af68edbd632..69a02d5900d 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 3783d1ce908672000408dc6c5562762e550f36b0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 21:30:14 +0200 Subject: [PATCH 075/147] 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 69d104bcb6faa05a022f84c4a1e867374bd03330 Mon Sep 17 00:00:00 2001 From: Penny Wood Date: Mon, 27 Aug 2018 03:35:06 +0800 Subject: [PATCH 076/147] 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 26628d7fe62..fdff380301f 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 2cd19d58ce6..2f27662b2e7 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 7484dc286e6..8e2ad008cc6 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 47755fb1e98cfda79ac4d354ae0b9a78073c97f4 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Sun, 26 Aug 2018 13:38:52 -0700 Subject: [PATCH 077/147] 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 2f27662b2e7..691bbf62246 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -46,6 +46,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 @@ -985,6 +988,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 69a02d5900d..5fa4af21a62 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 bacecb4249209d4db4fd0beb45da06d2e0fd5591 Mon Sep 17 00:00:00 2001 From: Matt Hamilton Date: Sun, 26 Aug 2018 16:50:31 -0400 Subject: [PATCH 078/147] 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 fdff380301f..70fb519eef4 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -2,6 +2,7 @@ aiohttp==3.4.0 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 691bbf62246..e1b5b1c70ec 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -3,6 +3,7 @@ aiohttp==3.4.0 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 8e2ad008cc6..b1b0af70319 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 c13e5fcb9289ba01f78ef6a698d01767aaee9721 Mon Sep 17 00:00:00 2001 From: Matt Hamilton Date: Sun, 26 Aug 2018 16:50:31 -0400 Subject: [PATCH 079/147] 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 080/147] 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 081/147] 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 082/147] 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 083/147] 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 084/147] 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 4da719f43cdc3ff747a58291e0e5a721a9bb772d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 22:52:21 +0200 Subject: [PATCH 085/147] 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 16ad9c2ae64780104529ba95dee23c2730a3f1da Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 22:52:21 +0200 Subject: [PATCH 086/147] 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 087/147] 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 088/147] 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 5d7a2f92df7a17900baadfde426e26ff9fb2aa1e Mon Sep 17 00:00:00 2001 From: Maikel Punie Date: Mon, 27 Aug 2018 06:06:46 +0200 Subject: [PATCH 089/147] Add temperature sensors to the velbus component (#16203) * Added support for velbus temperature sensors * Bumped the required version * updated requirements_all.txt * Auto review comments fixed * Updated after comments * Updated after comments * Fix travis * Fix travis --- homeassistant/components/sensor/velbus.py | 48 +++++++++++++++++++++++ homeassistant/components/velbus.py | 7 +++- requirements_all.txt | 2 +- 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 homeassistant/components/sensor/velbus.py diff --git a/homeassistant/components/sensor/velbus.py b/homeassistant/components/sensor/velbus.py new file mode 100644 index 00000000000..ea4af320add --- /dev/null +++ b/homeassistant/components/sensor/velbus.py @@ -0,0 +1,48 @@ +""" +Velbus sensors. + +For more details about this platform, please refer to the documentation +https://home-assistant.io/components/sensor.velbus/ +""" +import logging + +from homeassistant.const import ( + TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE) +from homeassistant.components.velbus import ( + DOMAIN as VELBUS_DOMAIN, VelbusEntity) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ['velbus'] + + +async def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): + """Set up the Velbus temp sensor platform.""" + if discovery_info is None: + return + sensors = [] + for sensor in discovery_info: + module = hass.data[VELBUS_DOMAIN].get_module(sensor[0]) + channel = sensor[1] + sensors.append(VelbusTempSensor(module, channel)) + async_add_entities(sensors) + + +class VelbusTempSensor(VelbusEntity): + """Representation of a temperature sensor.""" + + @property + def device_class(self): + """Return the device class of the sensor.""" + return DEVICE_CLASS_TEMPERATURE + + @property + def state(self): + """Return the state of the sensor.""" + return self._module.getCurTemp() + + @property + def unit_of_measurement(self): + """Return the unit this state is expressed in.""" + return TEMP_CELSIUS diff --git a/homeassistant/components/velbus.py b/homeassistant/components/velbus.py index a6cdcc7cf90..d2def6f96bc 100644 --- a/homeassistant/components/velbus.py +++ b/homeassistant/components/velbus.py @@ -12,7 +12,7 @@ from homeassistant.const import EVENT_HOMEASSISTANT_STOP, CONF_PORT from homeassistant.helpers.discovery import load_platform from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['python-velbus==2.0.18'] +REQUIREMENTS = ['python-velbus==2.0.19'] _LOGGER = logging.getLogger(__name__) @@ -47,7 +47,8 @@ async def async_setup(hass, config): modules = controller.get_modules() discovery_info = { 'switch': [], - 'binary_sensor': [] + 'binary_sensor': [], + 'temp_sensor': [] } for module in modules: for channel in range(1, module.number_of_channels() + 1): @@ -61,6 +62,8 @@ async def async_setup(hass, config): discovery_info['switch'], config) load_platform(hass, 'binary_sensor', DOMAIN, discovery_info['binary_sensor'], config) + load_platform(hass, 'sensor', DOMAIN, + discovery_info['temp_sensor'], config) controller.scan(callback) diff --git a/requirements_all.txt b/requirements_all.txt index e1b5b1c70ec..959fd21732f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1139,7 +1139,7 @@ python-telegram-bot==10.1.0 python-twitch==1.3.0 # homeassistant.components.velbus -python-velbus==2.0.18 +python-velbus==2.0.19 # homeassistant.components.media_player.vlc python-vlc==1.1.2 From a439690bd793392fa79151601425ce322fb4497d Mon Sep 17 00:00:00 2001 From: Jonas Karlsson <1937941+endor-force@users.noreply.github.com> Date: Mon, 27 Aug 2018 06:19:51 +0200 Subject: [PATCH 090/147] Rewrite of Trafikverket weather - Multiple sensor types supported (#15935) * Added precipitation type from API Enables users to see type of precipitation. Value returned from API is a string in swedish. * Corrected tox verification errors Correction of tox findings * Missed in tox - fixed * Hound witespace fix * Updated comment to trigger travis rebuild Travis tox failed due to problem with tox build process. Correcting in a comment to trigger retry in travis.. * Try to retrigger travis/tox successful rebuild * Cleaning * Cleaning more * Trafikverket rebuilt for library Extended pytrafikverket with weather sensor collction Changed behaviour of sensor component to use pytrafikverket. Added more sensors. User need to change config to use new version. [] Documentation needs to be updated * Cleaned up based on Martins input Appreciate the feedback --- .../sensor/trafikverket_weatherstation.py | 126 +++++++++--------- requirements_all.txt | 3 + 2 files changed, 64 insertions(+), 65 deletions(-) diff --git a/homeassistant/components/sensor/trafikverket_weatherstation.py b/homeassistant/components/sensor/trafikverket_weatherstation.py index a8ce6917dd3..433bb8e9ed1 100644 --- a/homeassistant/components/sensor/trafikverket_weatherstation.py +++ b/homeassistant/components/sensor/trafikverket_weatherstation.py @@ -4,119 +4,115 @@ Weather information for air and road temperature, provided by Trafikverket. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.trafikverket_weatherstation/ """ + +import asyncio from datetime import timedelta -import json import logging -import requests +import aiohttp import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( - ATTR_ATTRIBUTION, CONF_API_KEY, CONF_NAME, CONF_TYPE, TEMP_CELSIUS) + ATTR_ATTRIBUTION, CONF_API_KEY, CONF_MONITORED_CONDITIONS, CONF_NAME) +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 = ['pytrafikverket==0.1.5.8'] + _LOGGER = logging.getLogger(__name__) -CONF_ATTRIBUTION = "Data provided by Trafikverket API" +SCAN_INTERVAL = timedelta(seconds=300) +MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10) +CONF_ATTRIBUTION = "Data provided by Trafikverket API" CONF_STATION = 'station' -MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) -SCAN_INTERVAL = timedelta(seconds=300) +SENSOR_TYPES = { + 'air_temp': ['Air temperature', '°C', 'air_temp'], + 'road_temp': ['Road temperature', '°C', 'road_temp'], + 'precipitation': ['Precipitation type', None, 'precipitationtype'], + 'wind_direction': ['Wind direction', '°', 'winddirection'], + 'wind_direction_text': ['Wind direction text', None, 'winddirectiontext'], + 'wind_speed': ['Wind speed', 'm/s', 'windforce'], + 'humidity': ['Humidity', '%', 'humidity'], +} PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_NAME): cv.string, vol.Required(CONF_API_KEY): cv.string, vol.Required(CONF_STATION): cv.string, - vol.Required(CONF_TYPE): vol.In(['air', 'road']), + vol.Required(CONF_MONITORED_CONDITIONS, default=[]): + [vol.In(SENSOR_TYPES)], }) -def setup_platform(hass, config, add_entities, discovery_info=None): +async def async_setup_platform(hass, config, async_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) + from pytrafikverket.trafikverket_weather import TrafikverketWeather - add_entities([TrafikverketWeatherStation( - sensor_name, sensor_api, sensor_station, sensor_type)], True) + sensor_name = config[CONF_NAME] + sensor_api = config[CONF_API_KEY] + sensor_station = config[CONF_STATION] + + web_session = async_get_clientsession(hass) + + weather_api = TrafikverketWeather(web_session, sensor_api) + + dev = [] + for condition in config[CONF_MONITORED_CONDITIONS]: + dev.append(TrafikverketWeatherStation( + weather_api, sensor_name, condition, sensor_station)) + + if dev: + async_add_entities(dev, True) class TrafikverketWeatherStation(Entity): """Representation of a Trafikverket sensor.""" - def __init__(self, sensor_name, sensor_api, sensor_station, sensor_type): - """Initialize the Trafikverket sensor.""" - self._name = sensor_name - self._api = sensor_api - self._station = sensor_station + def __init__(self, weather_api, name, sensor_type, sensor_station): + """Initialize the sensor.""" + self._client = name + self._name = SENSOR_TYPES[sensor_type][0] self._type = sensor_type self._state = None + self._unit = SENSOR_TYPES[sensor_type][1] + self._station = sensor_station + self._weather_api = weather_api self._attributes = { ATTR_ATTRIBUTION: CONF_ATTRIBUTION, } + self._weather = None @property def name(self): """Return the name of the sensor.""" - return self._name + return '{} {}'.format(self._client, self._name) @property def state(self): - """Return the state of the sensor.""" + """Return the state of the device.""" return self._state @property def unit_of_measurement(self): - """Return the unit of measurement.""" - return TEMP_CELSIUS - - @property - def device_state_attributes(self): - """Return the state attributes.""" - return self._attributes + """Return the unit of measurement of this entity, if any.""" + return self._unit @Throttle(MIN_TIME_BETWEEN_UPDATES) - def update(self): - """Fetch new state data for the sensor.""" - url = 'http://api.trafikinfo.trafikverket.se/v1.3/data.json' - - if self._type == 'road': - air_vs_road = 'Road' - else: - air_vs_road = 'Air' - - xml = """ - - - - - - - Measurement.""" + air_vs_road + """.Temp - - """ - - # Testing JSON post request. + async def async_update(self): + """Get the latest data from Trafikverket and updates the states.""" try: - post = requests.post(url, data=xml.encode('utf-8'), timeout=5) - except requests.exceptions.RequestException as err: - _LOGGER.error("Please check network connection: %s", err) - return - - # Checking JSON respons. - try: - data = json.loads(post.text) - result = data["RESPONSE"]["RESULT"][0] - final = result["WeatherStation"][0]["Measurement"] - except KeyError: - _LOGGER.error("Incorrect weather station or API key") - return - - # air_vs_road contains "Air" or "Road" depending on user input. - self._state = final[air_vs_road]["Temp"] + self._weather = await self._weather_api.async_get_weather( + self._station) + self._state = getattr( + self._weather, + SENSOR_TYPES[self._type][2]) + except (asyncio.TimeoutError, + aiohttp.ClientError, ValueError) as error: + _LOGGER.error("Couldn't fetch weather data: %s", error) diff --git a/requirements_all.txt b/requirements_all.txt index 959fd21732f..92aeec6aefe 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1171,6 +1171,9 @@ pytrackr==0.0.5 # homeassistant.components.tradfri pytradfri[async]==5.5.1 +# homeassistant.components.sensor.trafikverket_weatherstation +pytrafikverket==0.1.5.8 + # homeassistant.components.device_tracker.unifi pyunifi==2.13 From dec2d8d5b0d93d3a0ded66ed4847f86e839850fc Mon Sep 17 00:00:00 2001 From: Hunter Horsman Date: Mon, 27 Aug 2018 03:08:23 -0400 Subject: [PATCH 091/147] Add device_tracker.bluetooth_update service (#15252) * Add device_tracker.bluetooth_update service Will immediately scan for Bluetooth devices outside of the interval timer. Allows for less frequent scanning, with scanning on demand via automation. * remove excess whitespace per bot comments * Refactored update_bluetooth to call new function update_bluetooth_once * Change service name to bluetooth_tracker_update to reflect platform name * Reformat for line length * Linting fix, pydoc, first line should end with a period * Fixed a method call, and removed some more unsused parameters --- .../device_tracker/bluetooth_tracker.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/device_tracker/bluetooth_tracker.py b/homeassistant/components/device_tracker/bluetooth_tracker.py index 2ca519d225c..217df0aacd4 100644 --- a/homeassistant/components/device_tracker/bluetooth_tracker.py +++ b/homeassistant/components/device_tracker/bluetooth_tracker.py @@ -12,7 +12,8 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.event import track_point_in_utc_time from homeassistant.components.device_tracker import ( YAML_DEVICES, CONF_TRACK_NEW, CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL, - load_config, PLATFORM_SCHEMA, DEFAULT_TRACK_NEW, SOURCE_TYPE_BLUETOOTH) + load_config, PLATFORM_SCHEMA, DEFAULT_TRACK_NEW, SOURCE_TYPE_BLUETOOTH, + DOMAIN) import homeassistant.util.dt as dt_util _LOGGER = logging.getLogger(__name__) @@ -79,7 +80,13 @@ def setup_scanner(hass, config, see, discovery_info=None): request_rssi = config.get(CONF_REQUEST_RSSI, False) - def update_bluetooth(now): + def update_bluetooth(): + """Update Bluetooth and set timer for the next update.""" + update_bluetooth_once() + track_point_in_utc_time( + hass, update_bluetooth, dt_util.utcnow() + interval) + + def update_bluetooth_once(): """Lookup Bluetooth device and update status.""" try: if track_new: @@ -99,9 +106,14 @@ def setup_scanner(hass, config, see, discovery_info=None): see_device(mac, result, rssi) except bluetooth.BluetoothError: _LOGGER.exception("Error looking up Bluetooth device") - track_point_in_utc_time( - hass, update_bluetooth, dt_util.utcnow() + interval) - update_bluetooth(dt_util.utcnow()) + def handle_update_bluetooth(call): + """Update bluetooth devices on demand.""" + update_bluetooth_once() + + update_bluetooth() + + hass.services.register( + DOMAIN, "bluetooth_tracker_update", handle_update_bluetooth) return True From 2e9db1f5c4df8d8acd05daa112fc1b27110de28a Mon Sep 17 00:00:00 2001 From: Julian Kahnert Date: Mon, 27 Aug 2018 09:39:11 +0200 Subject: [PATCH 092/147] Fix geizhals price parsing (#15990) * fix geizhals price parsing * Fix lint issue * switch to the geizhals pypi package * throttle updates * update geizhals version * initialize empty device * minor changes to trigger another TravisCI test * device => _device * bump geizhals version --- homeassistant/components/sensor/geizhals.py | 109 ++++++-------------- requirements_all.txt | 4 +- 2 files changed, 35 insertions(+), 78 deletions(-) diff --git a/homeassistant/components/sensor/geizhals.py b/homeassistant/components/sensor/geizhals.py index 2c7325866ac..7d215fb6baf 100644 --- a/homeassistant/components/sensor/geizhals.py +++ b/homeassistant/components/sensor/geizhals.py @@ -13,15 +13,15 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA import homeassistant.helpers.config_validation as cv from homeassistant.util import Throttle from homeassistant.helpers.entity import Entity -from homeassistant.const import (CONF_DOMAIN, CONF_NAME) +from homeassistant.const import CONF_NAME -REQUIREMENTS = ['beautifulsoup4==4.6.3'] +REQUIREMENTS = ['geizhals==0.0.7'] _LOGGER = logging.getLogger(__name__) CONF_DESCRIPTION = 'description' CONF_PRODUCT_ID = 'product_id' -CONF_REGEX = 'regex' +CONF_LOCALE = 'locale' ICON = 'mdi:coin' @@ -31,13 +31,12 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_NAME): cv.string, vol.Required(CONF_PRODUCT_ID): cv.positive_int, vol.Optional(CONF_DESCRIPTION, default='Price'): cv.string, - vol.Optional(CONF_DOMAIN, default='geizhals.de'): vol.In( - ['geizhals.at', - 'geizhals.eu', - 'geizhals.de', - 'skinflint.co.uk', - 'cenowarka.pl']), - vol.Optional(CONF_REGEX, default=r'\D\s(\d*)[\,|\.](\d*)'): cv.string, + vol.Optional(CONF_LOCALE, default='DE'): vol.In( + ['AT', + 'EU', + 'DE', + 'UK', + 'PL']), }) @@ -46,22 +45,27 @@ def setup_platform(hass, config, add_entities, discovery_info=None): name = config.get(CONF_NAME) description = config.get(CONF_DESCRIPTION) product_id = config.get(CONF_PRODUCT_ID) - domain = config.get(CONF_DOMAIN) - regex = config.get(CONF_REGEX) + domain = config.get(CONF_LOCALE) - add_entities([Geizwatch(name, description, product_id, domain, regex)], + add_entities([Geizwatch(name, description, product_id, domain)], True) class Geizwatch(Entity): """Implementation of Geizwatch.""" - def __init__(self, name, description, product_id, domain, regex): + def __init__(self, name, description, product_id, domain): """Initialize the sensor.""" + from geizhals import Device, Geizhals + + # internal self._name = name + self._geizhals = Geizhals(product_id, domain) + self._device = Device() + + # external self.description = description - self.data = GeizParser(product_id, domain, regex) - self._state = None + self.product_id = product_id @property def name(self): @@ -76,73 +80,24 @@ class Geizwatch(Entity): @property def state(self): """Return the best price of the selected product.""" - return self._state + return self._device.prices[0] @property def device_state_attributes(self): """Return the state attributes.""" - while len(self.data.prices) < 4: - self.data.prices.append("None") - attrs = {'device_name': self.data.device_name, + while len(self._device.prices) < 4: + self._device.prices.append('None') + attrs = {'device_name': self._device.name, 'description': self.description, - 'unit_of_measurement': self.data.unit_of_measurement, - 'product_id': self.data.product_id, - 'price1': self.data.prices[0], - 'price2': self.data.prices[1], - 'price3': self.data.prices[2], - 'price4': self.data.prices[3]} + 'unit_of_measurement': self._device.price_currency, + 'product_id': self.product_id, + 'price1': self._device.prices[0], + 'price2': self._device.prices[1], + 'price3': self._device.prices[2], + 'price4': self._device.prices[3]} return attrs - def update(self): - """Get the latest price from geizhals and updates the state.""" - self.data.update() - self._state = self.data.prices[0] - - -class GeizParser: - """Pull data from the geizhals website.""" - - def __init__(self, product_id, domain, regex): - """Initialize the sensor.""" - # parse input arguments - self.product_id = product_id - self.domain = domain - self.regex = regex - - # set some empty default values - self.device_name = '' - self.prices = [None, None, None, None] - self.unit_of_measurement = '' - @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): - """Update the device prices.""" - import bs4 - import requests - import re - - sess = requests.session() - request = sess.get('https://{}/{}'.format(self.domain, - self.product_id), - allow_redirects=True, - timeout=1) - soup = bs4.BeautifulSoup(request.text, 'html.parser') - - # parse name - raw = soup.find_all('span', attrs={'itemprop': 'name'}) - self.device_name = raw[1].string - - # parse prices - prices = [] - for tmp in soup.find_all('span', attrs={'class': 'gh_price'}): - matches = re.search(self.regex, tmp.string) - raw = '{}.{}'.format(matches.group(1), - matches.group(2)) - prices += [float(raw)] - prices.sort() - self.prices = prices[1:] - - # parse unit - price_match = soup.find('span', attrs={'class': 'gh_price'}) - matches = re.search(r'€|£|PLN', price_match.string) - self.unit_of_measurement = matches.group() + """Get the latest price from geizhals and updates the state.""" + self._device = self._geizhals.parse() diff --git a/requirements_all.txt b/requirements_all.txt index 92aeec6aefe..2a238a933b8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -163,7 +163,6 @@ batinfo==0.4.2 # beacontools[scan]==1.2.3 # homeassistant.components.device_tracker.linksys_ap -# homeassistant.components.sensor.geizhals # homeassistant.components.sensor.scrape # homeassistant.components.sensor.sytadin beautifulsoup4==4.6.3 @@ -387,6 +386,9 @@ gTTS-token==1.1.1 # homeassistant.components.sensor.gearbest gearbest_parser==1.0.7 +# homeassistant.components.sensor.geizhals +geizhals==0.0.7 + # homeassistant.components.sensor.gitter gitterpy==0.1.7 From f1e378bff8eeeced2c86ef7a046ce8e526787df5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 26 Aug 2018 22:52:58 +0200 Subject: [PATCH 093/147] 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 94662620e214ef30d01d7e6661fa2fd874154b86 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 10:16:59 +0200 Subject: [PATCH 094/147] 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 adb5579690366cd80943a1744ac0266f52cc3cf9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 10:16:59 +0200 Subject: [PATCH 095/147] 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 9d491f532297a49399201beccd602d6643ac5e29 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 10:37:03 +0200 Subject: [PATCH 096/147] 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 c51170ef6de4c58c065b2db060bafc5cecba053e Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 27 Aug 2018 15:05:36 +0200 Subject: [PATCH 097/147] Add Volkszaehler sensor (#16188) * Add Volkszaehler sensor * Update icons * Improve code --- .coveragerc | 1 + .../components/sensor/volkszaehler.py | 138 ++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 142 insertions(+) create mode 100644 homeassistant/components/sensor/volkszaehler.py diff --git a/.coveragerc b/.coveragerc index bb0be2d9433..449883265f6 100644 --- a/.coveragerc +++ b/.coveragerc @@ -759,6 +759,7 @@ omit = homeassistant/components/sensor/uscis.py homeassistant/components/sensor/vasttrafik.py homeassistant/components/sensor/viaggiatreno.py + homeassistant/components/sensor/volkszaehler.py homeassistant/components/sensor/waqi.py homeassistant/components/sensor/waze_travel_time.py homeassistant/components/sensor/whois.py diff --git a/homeassistant/components/sensor/volkszaehler.py b/homeassistant/components/sensor/volkszaehler.py new file mode 100644 index 00000000000..47aa580e3d4 --- /dev/null +++ b/homeassistant/components/sensor/volkszaehler.py @@ -0,0 +1,138 @@ +""" +Support for consuming values for the Volkszaehler API. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.volkszaehler/ +""" +from datetime import timedelta +import logging + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + CONF_HOST, CONF_NAME, CONF_PORT, CONF_MONITORED_CONDITIONS) +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 = ['volkszaehler==0.1.2'] + +_LOGGER = logging.getLogger(__name__) + +CONF_UUID = 'uuid' + +DEFAULT_HOST = 'localhost' +DEFAULT_NAME = 'Volkszaehler' +DEFAULT_PORT = 80 + +MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1) + +SENSOR_TYPES = { + 'average': ['Average', 'W', 'mdi:power-off'], + 'consumption': ['Consumption', 'Wh', 'mdi:power-plug'], + 'max': ['Max', 'W', 'mdi:arrow-up'], + 'min': ['Min', 'W', 'mdi:arrow-down'], +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_UUID): cv.string, + vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + vol.Optional(CONF_MONITORED_CONDITIONS, default=['average']): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), +}) + + +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): + """Set up the Volkszaehler sensors.""" + from volkszaehler import Volkszaehler + + host = config[CONF_HOST] + name = config[CONF_NAME] + port = config[CONF_PORT] + uuid = config[CONF_UUID] + conditions = config[CONF_MONITORED_CONDITIONS] + + session = async_get_clientsession(hass) + vz_api = VolkszaehlerData( + Volkszaehler(hass.loop, session, uuid, host=host, port=port)) + + await vz_api.async_update() + + if vz_api.api.data is None: + raise PlatformNotReady + + dev = [] + for condition in conditions: + dev.append(VolkszaehlerSensor(vz_api, name, condition)) + + async_add_entities(dev, True) + + +class VolkszaehlerSensor(Entity): + """Implementation of a Volkszaehler sensor.""" + + def __init__(self, vz_api, name, sensor_type): + """Initialize the Volkszaehler sensor.""" + self.vz_api = vz_api + self._name = name + self.type = sensor_type + self._state = None + + @property + def name(self): + """Return the name of the sensor.""" + return '{} {}'.format(self._name, SENSOR_TYPES[self.type][0]) + + @property + def icon(self): + """Icon to use in the frontend, if any.""" + return SENSOR_TYPES[self.type][2] + + @property + def unit_of_measurement(self): + """Return the unit the value is expressed in.""" + return SENSOR_TYPES[self.type][1] + + @property + def available(self): + """Could the device be accessed during the last update call.""" + return self.vz_api.available + + @property + def state(self): + """Return the state of the resources.""" + return self._state + + async def async_update(self): + """Get the latest data from REST API.""" + await self.vz_api.async_update() + + if self.vz_api.api.data is not None: + self._state = round(getattr(self.vz_api.api, self.type), 2) + + +class VolkszaehlerData: + """The class for handling the data retrieval from the Volkszaehler API.""" + + def __init__(self, api): + """Initialize the data object.""" + self.api = api + self.available = True + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + async def async_update(self): + """Get the latest data from the Volkszaehler REST API.""" + from volkszaehler.exceptions import VolkszaehlerApiConnectionError + + try: + await self.api.get_data() + self.available = True + except VolkszaehlerApiConnectionError: + _LOGGER.error("Unable to fetch data from the Volkszaehler API") + self.available = False diff --git a/requirements_all.txt b/requirements_all.txt index 2a238a933b8..81de7219b60 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1431,6 +1431,9 @@ uvcclient==0.10.1 # homeassistant.components.climate.venstar venstarcolortouch==0.6 +# homeassistant.components.sensor.volkszaehler +volkszaehler==0.1.2 + # homeassistant.components.config.config_entries voluptuous-serialize==2.0.0 From 8435d2f53d787c2b3e07229a6273bb68d6e81d13 Mon Sep 17 00:00:00 2001 From: Daniel Bowman Date: Mon, 27 Aug 2018 16:17:43 +0100 Subject: [PATCH 098/147] openalpr flag `WITH_TEST` should be `WITH_TESTS` (#16218) Removes warning from openalpr build and saves a few seconds from build time as tests weren't being bypassed as intended --- virtualization/Docker/scripts/openalpr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtualization/Docker/scripts/openalpr b/virtualization/Docker/scripts/openalpr index b9e403710f1..38669f8175b 100755 --- a/virtualization/Docker/scripts/openalpr +++ b/virtualization/Docker/scripts/openalpr @@ -23,7 +23,7 @@ mkdir -p build cd build # Setup the compile environment -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 .. +cmake -DWITH_TESTS=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 -j$(nproc) From 24aa580b63c676b1dd4809d1057aa9f1f287e9a0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 21:56:28 +0200 Subject: [PATCH 099/147] 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 943260fcd6644fcfec4b4af03402adfc5edb38e4 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Mon, 27 Aug 2018 22:00:20 +0200 Subject: [PATCH 100/147] Upgrade alpha_vantage to 2.1.0 (#16217) --- homeassistant/components/sensor/alpha_vantage.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sensor/alpha_vantage.py b/homeassistant/components/sensor/alpha_vantage.py index c0b280d2d69..79943a8b084 100644 --- a/homeassistant/components/sensor/alpha_vantage.py +++ b/homeassistant/components/sensor/alpha_vantage.py @@ -15,7 +15,7 @@ from homeassistant.const import ( import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity -REQUIREMENTS = ['alpha_vantage==2.0.0'] +REQUIREMENTS = ['alpha_vantage==2.1.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 81de7219b60..42fdb321857 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -121,7 +121,7 @@ aladdin_connect==0.3 alarmdecoder==1.13.2 # homeassistant.components.sensor.alpha_vantage -alpha_vantage==2.0.0 +alpha_vantage==2.1.0 # homeassistant.components.amcrest amcrest==1.2.3 From 6f0c30ff8419c949ac1ebd79b4cfafaadb4bd1b2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 22:28:17 +0200 Subject: [PATCH 101/147] 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 42fdb321857..85af517bb29 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -444,7 +444,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 5fa4af21a62..5dcf0550aba 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 914436f3d5149d4f3542c6df8c308745e5db0938 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 27 Aug 2018 22:28:17 +0200 Subject: [PATCH 102/147] 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 45649824ca65b49cc676393d660e8c18dd488acf Mon Sep 17 00:00:00 2001 From: Marcel Hoppe Date: Tue, 28 Aug 2018 00:20:12 +0200 Subject: [PATCH 103/147] 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 8ab31fe13939278cb9f6237cb22b2eb485d75066 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Tue, 28 Aug 2018 00:37:04 +0200 Subject: [PATCH 104/147] Store devices as dict instead of list (#16229) * Store devices as dict instead of list * Use OrderedDict --- homeassistant/helpers/device_registry.py | 14 ++++++++------ tests/helpers/test_device_registry.py | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/homeassistant/helpers/device_registry.py b/homeassistant/helpers/device_registry.py index 31da40134a5..504448b948d 100644 --- a/homeassistant/helpers/device_registry.py +++ b/homeassistant/helpers/device_registry.py @@ -2,6 +2,8 @@ import logging import uuid +from collections import OrderedDict + import attr from homeassistant.core import callback @@ -45,7 +47,7 @@ class DeviceRegistry: @callback def async_get_device(self, identifiers: str, connections: tuple): """Check if device is registered.""" - for device in self.devices: + for device in self.devices.values(): if any(iden in device.identifiers for iden in identifiers) or \ any(conn in device.connections for conn in connections): return device @@ -75,7 +77,7 @@ class DeviceRegistry: name=name, sw_version=sw_version ) - self.devices.append(device) + self.devices[device.id] = device self.async_schedule_save() @@ -86,10 +88,10 @@ class DeviceRegistry: devices = await self._store.async_load() if devices is None: - self.devices = [] + self.devices = OrderedDict() return - self.devices = [DeviceEntry( + self.devices = {device['id']: DeviceEntry( config_entries=device['config_entries'], connections={tuple(conn) for conn in device['connections']}, identifiers={tuple(iden) for iden in device['identifiers']}, @@ -98,7 +100,7 @@ class DeviceRegistry: name=device['name'], sw_version=device['sw_version'], id=device['id'], - ) for device in devices['devices']] + ) for device in devices['devices']} @callback def async_schedule_save(self): @@ -120,7 +122,7 @@ class DeviceRegistry: 'name': entry.name, 'sw_version': entry.sw_version, 'id': entry.id, - } for entry in self.devices + } for entry in self.devices.values() ] return data diff --git a/tests/helpers/test_device_registry.py b/tests/helpers/test_device_registry.py index b2e73071823..84ad54f7b82 100644 --- a/tests/helpers/test_device_registry.py +++ b/tests/helpers/test_device_registry.py @@ -1,13 +1,15 @@ """Tests for the Device Registry.""" import pytest +from collections import OrderedDict + 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 [] + registry.devices = mock_entries or OrderedDict() async def _get_reg(): return registry From 5397c0d73a7ee02f357a8c4d2ef4c942968bc39f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 00:37:15 +0200 Subject: [PATCH 105/147] 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 9c7d4381a1b337cb11dd2305643b034044f26a2f Mon Sep 17 00:00:00 2001 From: Dan Klaffenbach Date: Sun, 26 Aug 2018 12:00:20 +0200 Subject: [PATCH 106/147] 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 107/147] 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 108/147] 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 109/147] 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 110/147] 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 111/147] 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 376d4e4fa0bbcbfa07646f49f9d8fd56c8c0df3c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 09:32:50 +0200 Subject: [PATCH 112/147] 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 a14980716d0752b6c0367fe2eee06369e8c70168 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 10:53:12 +0200 Subject: [PATCH 113/147] 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 67df162bcc1d9eb84dfbc43e108cad4a81d67130 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 28 Aug 2018 02:23:58 -0700 Subject: [PATCH 114/147] 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 12709ceaa3b4f3151a670ae878898687608863bb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 12:49:50 +0200 Subject: [PATCH 115/147] 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 09dc4d663d3e3189156c38a592f96ee98ecbb8d7 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 12:52:18 +0200 Subject: [PATCH 116/147] Improve package loadable (#16237) * Add caching to package loadable * Fix tests * Improve package loadable * Lint * Typing --- homeassistant/requirements.py | 60 +++++++++++++++++++++++ homeassistant/util/package.py | 80 +++++++++--------------------- tests/test_requirements.py | 92 +++++++++++++++++++++++++++++------ tests/util/test_package.py | 78 +++-------------------------- 4 files changed, 166 insertions(+), 144 deletions(-) diff --git a/homeassistant/requirements.py b/homeassistant/requirements.py index b9b5e137d5c..a3d168d22e7 100644 --- a/homeassistant/requirements.py +++ b/homeassistant/requirements.py @@ -3,12 +3,17 @@ import asyncio from functools import partial import logging import os +import sys from typing import Any, Dict, List, Optional +from urllib.parse import urlparse + +import pkg_resources import homeassistant.util.package as pkg_util from homeassistant.core import HomeAssistant DATA_PIP_LOCK = 'pip_lock' +DATA_PKG_CACHE = 'pkg_cache' CONSTRAINT_FILE = 'package_constraints.txt' _LOGGER = logging.getLogger(__name__) @@ -23,12 +28,20 @@ async def async_process_requirements(hass: HomeAssistant, name: str, if pip_lock is None: pip_lock = hass.data[DATA_PIP_LOCK] = asyncio.Lock(loop=hass.loop) + pkg_cache = hass.data.get(DATA_PKG_CACHE) + if pkg_cache is None: + pkg_cache = hass.data[DATA_PKG_CACHE] = PackageLoadable(hass) + pip_install = partial(pkg_util.install_package, **pip_kwargs(hass.config.config_dir)) async with pip_lock: for req in requirements: + if await pkg_cache.loadable(req): + continue + ret = await hass.async_add_executor_job(pip_install, req) + if not ret: _LOGGER.error("Not initializing %s because could not install " "requirement %s", name, req) @@ -45,3 +58,50 @@ def pip_kwargs(config_dir: Optional[str]) -> Dict[str, Any]: if not (config_dir is None or pkg_util.is_virtual_env()): kwargs['target'] = os.path.join(config_dir, 'deps') return kwargs + + +class PackageLoadable: + """Class to check if a package is loadable, with built-in cache.""" + + def __init__(self, hass: HomeAssistant) -> None: + """Initialize the PackageLoadable class.""" + self.dist_cache = {} # type: Dict[str, pkg_resources.Distribution] + self.hass = hass + + async def loadable(self, 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. + """ + dist_cache = self.dist_cache + + try: + req = pkg_resources.Requirement.parse(package) + except ValueError: + # This is a zip file. We no longer use this in Home Assistant, + # leaving it in for custom components. + req = pkg_resources.Requirement.parse(urlparse(package).fragment) + + req_proj_name = req.project_name.lower() + dist = dist_cache.get(req_proj_name) + + if dist is not None: + return dist in req + + for path in sys.path: + # We read the whole mount point as we're already here + # Caching it on first call makes subsequent calls a lot faster. + await self.hass.async_add_executor_job(self._fill_cache, path) + + dist = dist_cache.get(req_proj_name) + if dist is not None: + return dist in req + + return False + + def _fill_cache(self, path: str) -> None: + """Add packages from a path to the cache.""" + dist_cache = self.dist_cache + for dist in pkg_resources.find_distributions(path): + dist_cache.setdefault(dist.project_name.lower(), dist) diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index 3f12fc223b8..422809f7594 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -4,17 +4,11 @@ import logging import os from subprocess import PIPE, Popen import sys -import threading -from urllib.parse import urlparse from typing import Optional -import pkg_resources - _LOGGER = logging.getLogger(__name__) -INSTALL_LOCK = threading.Lock() - def is_virtual_env() -> bool: """Return if we run in a virtual environtment.""" @@ -31,58 +25,30 @@ def install_package(package: str, upgrade: bool = True, Return boolean if install successful. """ # Not using 'import pip; pip.main([])' because it breaks the logger - with INSTALL_LOCK: - if package_loadable(package): - return True + _LOGGER.info('Attempting install of %s', package) + env = os.environ.copy() + args = [sys.executable, '-m', 'pip', 'install', '--quiet', package] + if upgrade: + args.append('--upgrade') + if constraints is not None: + args += ['--constraint', constraints] + if target: + assert not is_virtual_env() + # This only works if not running in venv + args += ['--user'] + env['PYTHONUSERBASE'] = os.path.abspath(target) + if sys.platform != 'win32': + # Workaround for incompatible prefix setting + # See http://stackoverflow.com/a/4495175 + args += ['--prefix='] + process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) + _, stderr = process.communicate() + if process.returncode != 0: + _LOGGER.error("Unable to install package %s: %s", + package, stderr.decode('utf-8').lstrip().strip()) + return False - _LOGGER.info('Attempting install of %s', package) - env = os.environ.copy() - args = [sys.executable, '-m', 'pip', 'install', '--quiet', package] - if upgrade: - args.append('--upgrade') - if constraints is not None: - args += ['--constraint', constraints] - if target: - assert not is_virtual_env() - # This only works if not running in venv - args += ['--user'] - env['PYTHONUSERBASE'] = os.path.abspath(target) - if sys.platform != 'win32': - # Workaround for incompatible prefix setting - # See http://stackoverflow.com/a/4495175 - args += ['--prefix='] - process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) - _, stderr = process.communicate() - if process.returncode != 0: - _LOGGER.error("Unable to install package %s: %s", - package, stderr.decode('utf-8').lstrip().strip()) - return False - - return True - - -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. - """ - try: - req = pkg_resources.Requirement.parse(package) - except ValueError: - # 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.lower() == req_proj_name: - return dist in req - - return False + return True async def async_get_user_site(deps_dir: str) -> str: diff --git a/tests/test_requirements.py b/tests/test_requirements.py index e3ef797df4d..71ae80f22e4 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -1,11 +1,22 @@ """Test requirements module.""" import os -from unittest import mock +from unittest.mock import patch, call from homeassistant import loader, setup -from homeassistant.requirements import CONSTRAINT_FILE +from homeassistant.requirements import ( + CONSTRAINT_FILE, PackageLoadable, async_process_requirements) -from tests.common import get_test_home_assistant, MockModule +import pkg_resources + +from tests.common import get_test_home_assistant, MockModule, mock_coro + +RESOURCE_DIR = os.path.abspath( + os.path.join(os.path.dirname(__file__), '..', 'resources')) + +TEST_NEW_REQ = 'pyhelloworld3==1.0.0' + +TEST_ZIP_REQ = 'file://{}#{}' \ + .format(os.path.join(RESOURCE_DIR, 'pyhelloworld3.zip'), TEST_NEW_REQ) class TestRequirements: @@ -23,11 +34,9 @@ class TestRequirements: """Clean up.""" self.hass.stop() - @mock.patch('os.path.dirname') - @mock.patch('homeassistant.util.package.is_virtual_env', - return_value=True) - @mock.patch('homeassistant.util.package.install_package', - return_value=True) + @patch('os.path.dirname') + @patch('homeassistant.util.package.is_virtual_env', return_value=True) + @patch('homeassistant.util.package.install_package', return_value=True) def test_requirement_installed_in_venv( self, mock_install, mock_venv, mock_dirname): """Test requirement installed in virtual environment.""" @@ -39,15 +48,13 @@ class TestRequirements: MockModule('comp', requirements=['package==0.0.1'])) assert setup.setup_component(self.hass, 'comp') assert 'comp' in self.hass.config.components - assert mock_install.call_args == mock.call( + assert mock_install.call_args == call( 'package==0.0.1', constraints=os.path.join('ha_package_path', CONSTRAINT_FILE)) - @mock.patch('os.path.dirname') - @mock.patch('homeassistant.util.package.is_virtual_env', - return_value=False) - @mock.patch('homeassistant.util.package.install_package', - return_value=True) + @patch('os.path.dirname') + @patch('homeassistant.util.package.is_virtual_env', return_value=False) + @patch('homeassistant.util.package.install_package', return_value=True) def test_requirement_installed_in_deps( self, mock_install, mock_venv, mock_dirname): """Test requirement installed in deps directory.""" @@ -58,6 +65,61 @@ class TestRequirements: MockModule('comp', requirements=['package==0.0.1'])) assert setup.setup_component(self.hass, 'comp') assert 'comp' in self.hass.config.components - assert mock_install.call_args == mock.call( + assert mock_install.call_args == call( 'package==0.0.1', target=self.hass.config.path('deps'), constraints=os.path.join('ha_package_path', CONSTRAINT_FILE)) + + +async def test_install_existing_package(hass): + """Test an install attempt on an existing package.""" + with patch('homeassistant.util.package.install_package', + return_value=mock_coro(True)) as mock_inst: + assert await async_process_requirements( + hass, 'test_component', ['hello==1.0.0']) + + assert len(mock_inst.mock_calls) == 1 + + with patch('homeassistant.requirements.PackageLoadable.loadable', + return_value=mock_coro(True)), \ + patch( + 'homeassistant.util.package.install_package') as mock_inst: + assert await async_process_requirements( + hass, 'test_component', ['hello==1.0.0']) + + assert len(mock_inst.mock_calls) == 0 + + +async def test_check_package_global(hass): + """Test for an installed package.""" + installed_package = list(pkg_resources.working_set)[0].project_name + assert await PackageLoadable(hass).loadable(installed_package) + + +async def test_check_package_zip(hass): + """Test for an installed zip package.""" + assert not await PackageLoadable(hass).loadable(TEST_ZIP_REQ) + + +async def test_package_loadable_installed_twice(hass): + """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 await PackageLoadable(hass).loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v1], [v2]]): + assert not await PackageLoadable(hass).loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v2], [v1]]): + assert await PackageLoadable(hass).loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v2]]): + assert await PackageLoadable(hass).loadable('hello==2.0.0') + + with patch('pkg_resources.find_distributions', side_effect=[[v2]]): + assert await PackageLoadable(hass).loadable('Hello==2.0.0') diff --git a/tests/util/test_package.py b/tests/util/test_package.py index 1e93a078bd9..5422140c232 100644 --- a/tests/util/test_package.py +++ b/tests/util/test_package.py @@ -6,18 +6,12 @@ import sys from subprocess import PIPE from unittest.mock import MagicMock, call, patch -import pkg_resources import pytest import homeassistant.util.package as package -RESOURCE_DIR = os.path.abspath( - os.path.join(os.path.dirname(__file__), '..', 'resources')) -TEST_EXIST_REQ = 'pip>=7.0.0' TEST_NEW_REQ = 'pyhelloworld3==1.0.0' -TEST_ZIP_REQ = 'file://{}#{}' \ - .format(os.path.join(RESOURCE_DIR, 'pyhelloworld3.zip'), TEST_NEW_REQ) @pytest.fixture @@ -28,14 +22,6 @@ def mock_sys(): yield sys_mock -@pytest.fixture -def mock_exists(): - """Mock package_loadable.""" - with patch('homeassistant.util.package.package_loadable') as mock: - mock.return_value = False - yield mock - - @pytest.fixture def deps_dir(): """Return path to deps directory.""" @@ -89,20 +75,10 @@ def mock_async_subprocess(): return async_popen -def test_install_existing_package(mock_exists, mock_popen): - """Test an install attempt on an existing package.""" - mock_exists.return_value = True - assert package.install_package(TEST_EXIST_REQ) - assert mock_exists.call_count == 1 - assert mock_exists.call_args == call(TEST_EXIST_REQ) - assert mock_popen.return_value.communicate.call_count == 0 - - -def test_install(mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): +def test_install(mock_sys, mock_popen, mock_env_copy, mock_venv): """Test an install attempt on a package that doesn't exist.""" env = mock_env_copy() assert package.install_package(TEST_NEW_REQ, False) - assert mock_exists.call_count == 1 assert mock_popen.call_count == 1 assert ( mock_popen.call_args == @@ -115,11 +91,10 @@ def test_install(mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): def test_install_upgrade( - mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): + mock_sys, mock_popen, mock_env_copy, mock_venv): """Test an upgrade attempt on a package.""" env = mock_env_copy() assert package.install_package(TEST_NEW_REQ) - assert mock_exists.call_count == 1 assert mock_popen.call_count == 1 assert ( mock_popen.call_args == @@ -131,8 +106,7 @@ def test_install_upgrade( assert mock_popen.return_value.communicate.call_count == 1 -def test_install_target( - mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): +def test_install_target(mock_sys, mock_popen, mock_env_copy, mock_venv): """Test an install with a target.""" target = 'target_folder' env = mock_env_copy() @@ -144,7 +118,6 @@ def test_install_target( TEST_NEW_REQ, '--user', '--prefix='] assert package.install_package(TEST_NEW_REQ, False, target=target) - assert mock_exists.call_count == 1 assert mock_popen.call_count == 1 assert ( mock_popen.call_args == @@ -153,15 +126,14 @@ def test_install_target( assert mock_popen.return_value.communicate.call_count == 1 -def test_install_target_venv( - mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): +def test_install_target_venv(mock_sys, mock_popen, mock_env_copy, mock_venv): """Test an install with a target in a virtual environment.""" target = 'target_folder' with pytest.raises(AssertionError): package.install_package(TEST_NEW_REQ, False, target=target) -def test_install_error(caplog, mock_sys, mock_exists, mock_popen, mock_venv): +def test_install_error(caplog, mock_sys, mock_popen, mock_venv): """Test an install with a target.""" caplog.set_level(logging.WARNING) mock_popen.return_value.returncode = 1 @@ -171,14 +143,12 @@ def test_install_error(caplog, mock_sys, mock_exists, mock_popen, mock_venv): assert record.levelname == 'ERROR' -def test_install_constraint( - mock_sys, mock_exists, mock_popen, mock_env_copy, mock_venv): +def test_install_constraint(mock_sys, mock_popen, mock_env_copy, mock_venv): """Test install with constraint file on not installed package.""" env = mock_env_copy() constraints = 'constraints_file.txt' assert package.install_package( TEST_NEW_REQ, False, constraints=constraints) - assert mock_exists.call_count == 1 assert mock_popen.call_count == 1 assert ( mock_popen.call_args == @@ -190,17 +160,6 @@ def test_install_constraint( assert mock_popen.return_value.communicate.call_count == 1 -def test_check_package_global(): - """Test for an installed package.""" - installed_package = list(pkg_resources.working_set)[0].project_name - assert package.package_loadable(installed_package) - - -def test_check_package_zip(): - """Test for an installed zip package.""" - assert not package.package_loadable(TEST_ZIP_REQ) - - @asyncio.coroutine def test_async_get_user_site(mock_env_copy): """Test async get user site directory.""" @@ -217,28 +176,3 @@ 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') - - with patch('pkg_resources.find_distributions', side_effect=[[v2]]): - assert package.package_loadable('Hello==2.0.0') From 9a786e449b2a4ad598ad80da57b3f664d14b4204 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 15:44:06 +0200 Subject: [PATCH 117/147] 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 257b8b9b8018ceeb50d5371d6b31bbb83d7bc2c5 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Tue, 28 Aug 2018 11:54:01 -0700 Subject: [PATCH 118/147] 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 f891d0f5be80e711f46536bf0a763d581544bdf4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 20:55:58 +0200 Subject: [PATCH 119/147] 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 11fcffda4cfde5b1a170921681b33dca698352cb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 28 Aug 2018 20:55:58 +0200 Subject: [PATCH 120/147] 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 121/147] 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 122/147] 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 123/147] 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 124/147] 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 125/147] 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 126/147] 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 127/147] 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 63614a477a40479de51fb0d253f8b51e2a8f9edb Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Wed, 29 Aug 2018 10:07:32 +0200 Subject: [PATCH 128/147] 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 563588651c48fb39d2ff9c95beeaecc995c85ebd Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 29 Aug 2018 01:16:54 -0700 Subject: [PATCH 129/147] 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 74c04294373ae14ce679e2fce18c3e4533ed092c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 10:27:34 +0200 Subject: [PATCH 130/147] 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 85af517bb29..5868e6df5ad 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -444,7 +444,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 5dcf0550aba..94c35c30ddf 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 8ec109d255ed3fc44a93ca4c462231996ba02a2f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 10:27:34 +0200 Subject: [PATCH 131/147] 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 e8801ee22f1e13554390cba3669da24055fab019 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 10:28:34 +0200 Subject: [PATCH 132/147] 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 9238261e17681154a38206a33996e2661b480eba Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 10:28:34 +0200 Subject: [PATCH 133/147] 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 134/147] 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 135/147] 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 136/147] 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) From 3df8840fee2fdc1eae5da96f59597fc5c49b9335 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 12:20:05 +0200 Subject: [PATCH 137/147] Version bump to 0.78.0.dev0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index d72bde548d3..3bb468c1b1e 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 = 77 +MINOR_VERSION = 78 PATCH_VERSION = '0.dev0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) From 18ba50bc2de8d56a26c902cbafb0665afc8f3fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Wed, 29 Aug 2018 12:56:15 +0200 Subject: [PATCH 138/147] Switchmate (#15535) * Switchmate * switchmate * swithcmate * switchmate * switchmate * fix comments * Update switchmate.py * change error log --- .coveragerc | 1 + homeassistant/components/switch/switchmate.py | 83 +++++++++++++++++++ requirements_all.txt | 1 + 3 files changed, 85 insertions(+) create mode 100644 homeassistant/components/switch/switchmate.py diff --git a/.coveragerc b/.coveragerc index 449883265f6..0c4a1f7d569 100644 --- a/.coveragerc +++ b/.coveragerc @@ -790,6 +790,7 @@ omit = homeassistant/components/switch/rest.py homeassistant/components/switch/rpi_rf.py homeassistant/components/switch/snmp.py + homeassistant/components/switch/switchmate.py homeassistant/components/switch/telnet.py homeassistant/components/switch/tplink.py homeassistant/components/switch/transmission.py diff --git a/homeassistant/components/switch/switchmate.py b/homeassistant/components/switch/switchmate.py new file mode 100644 index 00000000000..6ce4421ebc8 --- /dev/null +++ b/homeassistant/components/switch/switchmate.py @@ -0,0 +1,83 @@ +""" +Support for Switchmate. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/switch.switchmate/ +""" +import logging +from datetime import timedelta + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA +from homeassistant.const import CONF_NAME, CONF_MAC +from homeassistant.exceptions import PlatformNotReady + +REQUIREMENTS = ['bluepy==1.1.4'] + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'Switchmate' +HANDLE = 0x2e +ON_KEY = b'\x00' +OFF_KEY = b'\x01' + +SCAN_INTERVAL = timedelta(minutes=30) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_MAC): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + + +def setup_platform(hass, config, add_devices, discovery_info=None) -> None: + """Perform the setup for Switchmate devices.""" + name = config.get(CONF_NAME) + mac_addr = config.get(CONF_MAC) + add_devices([Switchmate(mac_addr, name)], True) + + +class Switchmate(SwitchDevice): + """Representation of a Switchmate.""" + + def __init__(self, mac, name) -> None: + """Initialize the Switchmate.""" + # pylint: disable=import-error + import bluepy + self._state = False + self._name = name + self._mac = mac + try: + self._device = bluepy.btle.Peripheral(self._mac, + bluepy.btle.ADDR_TYPE_RANDOM) + except bluepy.btle.BTLEException: + _LOGGER.error("Failed to set up switchmate") + raise PlatformNotReady() + + @property + def unique_id(self) -> str: + """Return a unique, HASS-friendly identifier for this entity.""" + return self._mac.replace(':', '') + + @property + def name(self) -> str: + """Return the name of the switch.""" + return self._name + + def update(self) -> None: + """Synchronize state with switch.""" + self._state = self._device.readCharacteristic(HANDLE) == ON_KEY + + @property + def is_on(self) -> bool: + """Return true if it is on.""" + return self._state + + def turn_on(self, **kwargs) -> None: + """Turn the switch on.""" + self._device.writeCharacteristic(HANDLE, ON_KEY, True) + + def turn_off(self, **kwargs) -> None: + """Turn the switch off.""" + self._device.writeCharacteristic(HANDLE, OFF_KEY, True) diff --git a/requirements_all.txt b/requirements_all.txt index 5868e6df5ad..16c67016780 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -186,6 +186,7 @@ blinkstick==1.1.8 blockchain==1.4.4 # homeassistant.components.light.decora +# homeassistant.components.switch.switchmate # bluepy==1.1.4 # homeassistant.components.sensor.bme680 From aaa1ebeed54a06f739413d90f904f72b932de7e3 Mon Sep 17 00:00:00 2001 From: Matt Schmitt Date: Wed, 29 Aug 2018 08:33:09 -0400 Subject: [PATCH 139/147] Add support for discrete states to MyQ cover (#16251) * Add discrete states and update dependency * Add translation dict --- homeassistant/components/cover/myq.py | 31 +++++++++++++++++++++++---- requirements_all.txt | 2 +- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/cover/myq.py b/homeassistant/components/cover/myq.py index bedc041fccc..6a17345188a 100644 --- a/homeassistant/components/cover/myq.py +++ b/homeassistant/components/cover/myq.py @@ -8,17 +8,25 @@ import logging import voluptuous as vol -from homeassistant.components.cover import CoverDevice +from homeassistant.components.cover import ( + CoverDevice, SUPPORT_CLOSE, SUPPORT_OPEN) from homeassistant.const import ( - CONF_USERNAME, CONF_PASSWORD, CONF_TYPE, STATE_CLOSED) + CONF_PASSWORD, CONF_TYPE, CONF_USERNAME, STATE_CLOSED, STATE_CLOSING, + STATE_OPENING) import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['pymyq==0.0.11'] +REQUIREMENTS = ['pymyq==0.0.15'] _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = 'myq' +MYQ_TO_HASS = { + 'closed': STATE_CLOSED, + 'closing': STATE_CLOSING, + 'opening': STATE_OPENING +} + NOTIFICATION_ID = 'myq_notification' NOTIFICATION_TITLE = 'MyQ Cover Setup' @@ -87,7 +95,17 @@ class MyQDevice(CoverDevice): @property def is_closed(self): """Return true if cover is closed, else False.""" - return self._status == STATE_CLOSED + return MYQ_TO_HASS[self._status] == STATE_CLOSED + + @property + def is_closing(self): + """Return if the cover is closing or not.""" + return MYQ_TO_HASS[self._status] == STATE_CLOSING + + @property + def is_opening(self): + """Return if the cover is opening or not.""" + return MYQ_TO_HASS[self._status] == STATE_OPENING def close_cover(self, **kwargs): """Issue close command to cover.""" @@ -97,6 +115,11 @@ class MyQDevice(CoverDevice): """Issue open command to cover.""" self.myq.open_device(self.device_id) + @property + def supported_features(self): + """Flag supported features.""" + return SUPPORT_OPEN | SUPPORT_CLOSE + def update(self): """Update status of cover.""" self._status = self.myq.get_status(self.device_id) diff --git a/requirements_all.txt b/requirements_all.txt index 16c67016780..e31a2349dcf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -962,7 +962,7 @@ pymonoprice==0.3 pymusiccast==0.1.6 # homeassistant.components.cover.myq -pymyq==0.0.11 +pymyq==0.0.15 # homeassistant.components.mysensors pymysensors==0.17.0 From d46a1a266d19c30cd4d3e33e99751f77de517083 Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Wed, 29 Aug 2018 14:32:47 +0100 Subject: [PATCH 140/147] bump version (#16262) --- homeassistant/components/upnp.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/upnp.py b/homeassistant/components/upnp.py index 5d7855f3959..2bf0572d498 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.1.0'] +REQUIREMENTS = ['pyupnp-async==0.1.1.1'] DEPENDENCIES = ['http'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index e31a2349dcf..ba0da439cbd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1181,7 +1181,7 @@ pytrafikverket==0.1.5.8 pyunifi==2.13 # homeassistant.components.upnp -pyupnp-async==0.1.1.0 +pyupnp-async==0.1.1.1 # homeassistant.components.binary_sensor.uptimerobot pyuptimerobot==0.0.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 94c35c30ddf..2415d661e29 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -178,7 +178,7 @@ pytradfri[async]==5.5.1 pyunifi==2.13 # homeassistant.components.upnp -pyupnp-async==0.1.1.0 +pyupnp-async==0.1.1.1 # homeassistant.components.notify.html5 pywebpush==1.6.0 From 96cf6d59a3d2a8a8275d9c3ad0fc8d52ba1ae081 Mon Sep 17 00:00:00 2001 From: cgtobi Date: Wed, 29 Aug 2018 15:43:01 +0200 Subject: [PATCH 141/147] Replace Authorization by Authentication (#16259) --- 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 7e54586b810..dd421fee57a 100644 --- a/homeassistant/components/hangouts/strings.json +++ b/homeassistant/components/hangouts/strings.json @@ -6,7 +6,7 @@ }, "error": { "invalid_login": "Invalid Login, please try again.", - "invalid_2fa": "Invalid 2 Factor Authorization, please try again.", + "invalid_2fa": "Invalid 2 Factor Authentication, please try again.", "invalid_2fa_method": "Invalid 2FA Method (Verify on Phone)." }, "step": { @@ -23,7 +23,7 @@ "2fa": "2FA Pin" }, "description": "", - "title": "2-Factor-Authorization" + "title": "2-Factor-Authentication" } }, "title": "Google Hangouts" From 3934f7bf3a6a0b9f70ff719c5e5336063caa009c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 15:46:09 +0200 Subject: [PATCH 142/147] Add device info to Chromecast (#16261) --- homeassistant/components/media_player/cast.py | 34 +++++++++++++++++-- tests/components/media_player/test_cast.py | 11 +++--- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index ae9589c7886..2954e427ed5 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -73,7 +73,8 @@ class ChromecastInfo: port = attr.ib(type=int) uuid = attr.ib(type=Optional[str], converter=attr.converters.optional(str), default=None) # always convert UUID to string if not None - model_name = attr.ib(type=str, default='') # needed for cast type + manufacturer = attr.ib(type=str, default='') + model_name = attr.ib(type=str, default='') friendly_name = attr.ib(type=Optional[str], default=None) @property @@ -111,6 +112,7 @@ def _fill_out_missing_chromecast_info(info: ChromecastInfo) -> ChromecastInfo: host=info.host, port=info.port, uuid=(info.uuid or http_device_status.uuid), friendly_name=(info.friendly_name or http_device_status.friendly_name), + manufacturer=(info.manufacturer or http_device_status.manufacturer), model_name=(info.model_name or http_device_status.model_name) ) @@ -148,7 +150,13 @@ def _setup_internal_discovery(hass: HomeAssistantType) -> None: def internal_callback(name): """Handle zeroconf discovery of a new chromecast.""" mdns = listener.services[name] - _discover_chromecast(hass, ChromecastInfo(*mdns)) + _discover_chromecast(hass, ChromecastInfo( + host=mdns[0], + port=mdns[1], + uuid=mdns[2], + model_name=mdns[3], + friendly_name=mdns[4], + )) _LOGGER.debug("Starting internal pychromecast discovery.") listener, browser = pychromecast.start_discovery(internal_callback) @@ -365,7 +373,10 @@ class CastDevice(MediaPlayerDevice): # pylint: disable=protected-access _LOGGER.debug("Connecting to cast device %s", cast_info) chromecast = await self.hass.async_add_job( - pychromecast._get_chromecast_from_host, attr.astuple(cast_info)) + pychromecast._get_chromecast_from_host, ( + cast_info.host, cast_info.port, cast_info.uuid, + cast_info.model_name, cast_info.friendly_name + )) self._chromecast = chromecast self._status_listener = CastStatusListener(self, chromecast) # Initialise connection status as connected because we can only @@ -494,6 +505,23 @@ class CastDevice(MediaPlayerDevice): """Return the name of the device.""" return self._cast_info.friendly_name + @property + def device_info(self): + """Return information about the device.""" + cast_info = self._cast_info + + if cast_info.model_name == "Google Cast Group": + return None + + return { + 'name': cast_info.friendly_name, + 'identifiers': { + (CAST_DOMAIN, cast_info.uuid.replace('-', '')) + }, + 'model': cast_info.model_name, + 'manufacturer': cast_info.manufacturer, + } + @property def state(self): """Return the state of the player.""" diff --git a/tests/components/media_player/test_cast.py b/tests/components/media_player/test_cast.py index 8fe285a59cd..7345fd0c158 100644 --- a/tests/components/media_player/test_cast.py +++ b/tests/components/media_player/test_cast.py @@ -77,7 +77,10 @@ async def async_setup_cast_internal_discovery(hass, config=None, def discover_chromecast(service_name: str, info: ChromecastInfo) -> None: """Discover a chromecast device.""" - listener.services[service_name] = attr.astuple(info) + listener.services[service_name] = ( + info.host, info.port, info.uuid, info.model_name, + info.friendly_name + ) discovery_callback(service_name) return discover_chromecast, add_entities @@ -152,8 +155,7 @@ async def test_internal_discovery_callback_only_generates_once(hass): discover_cast('the-service', info) await hass.async_block_till_done() discover = signal.mock_calls[0][1][0] - # attr's __eq__ somehow breaks here, use tuples instead - assert attr.astuple(discover) == attr.astuple(info) + assert discover == info signal.reset_mock() # discovering it a second time shouldn't @@ -183,8 +185,7 @@ async def test_internal_discovery_callback_fill_out(hass): # when called with incomplete info, it should use HTTP to get missing discover = signal.mock_calls[0][1][0] - # attr's __eq__ somehow breaks here, use tuples instead - assert attr.astuple(discover) == attr.astuple(full_info) + assert discover == full_info async def test_create_cast_device_without_uuid(hass): From 16a885824ded8c928cd7f45f63c988832c926ba9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 16:27:08 +0200 Subject: [PATCH 143/147] Add device info for sonos (#16263) * Add device info for sonos * Sets --- homeassistant/components/media_player/sonos.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index c4309519e36..4fc6b8b0954 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -388,6 +388,18 @@ class SonosDevice(MediaPlayerDevice): """Return the name of the device.""" return self._name + @property + def device_info(self): + """Return information about the device.""" + return { + 'identifiers': { + (SONOS_DOMAIN, self._unique_id) + }, + 'name': self._name, + 'model': self._model.replace("Sonos ", ""), + 'manufacturer': 'Sonos', + } + @property @soco_coordinator def state(self): From 7751dd7535d98604ddc976533c13f849cdc6a0ee Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 16:44:10 +0200 Subject: [PATCH 144/147] Add device info Nest (#16265) * Add device info Nest * Sets --- homeassistant/components/climate/nest.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index 321559f10ee..f81736b3a52 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -8,7 +8,8 @@ import logging import voluptuous as vol -from homeassistant.components.nest import DATA_NEST, SIGNAL_NEST_UPDATE +from homeassistant.components.nest import ( + DATA_NEST, SIGNAL_NEST_UPDATE, DOMAIN as NEST_DOMAIN) from homeassistant.components.climate import ( STATE_AUTO, STATE_COOL, STATE_HEAT, STATE_ECO, ClimateDevice, PLATFORM_SCHEMA, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW, @@ -127,6 +128,18 @@ class NestThermostat(ClimateDevice): """Return unique ID for this device.""" return self.device.serial + @property + def device_info(self): + """Return information about the device.""" + return { + 'identifiers': { + (NEST_DOMAIN, self.device.device_id), + }, + 'name': self.device.name_long, + 'manufacturer': 'Nest Labs', + 'model': "Thermostat", + } + @property def name(self): """Return the name of the nest, if any.""" From 867d17b03d71662098d1de4dfcb490959d1fa0de Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 29 Aug 2018 17:04:04 +0200 Subject: [PATCH 145/147] Add Hue device info (#16267) * Add Hue device info * Set with tuples * Fix tests --- homeassistant/components/hue/__init__.py | 26 ++++++++++++++-- homeassistant/components/light/hue.py | 19 ++++++++++++ tests/components/hue/test_init.py | 38 +++++++++++++++++++++--- 3 files changed, 77 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/hue/__init__.py b/homeassistant/components/hue/__init__.py index c04380e1303..38b521078f4 100644 --- a/homeassistant/components/hue/__init__.py +++ b/homeassistant/components/hue/__init__.py @@ -11,7 +11,8 @@ import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_FILENAME, CONF_HOST -from homeassistant.helpers import aiohttp_client, config_validation as cv +from homeassistant.helpers import ( + aiohttp_client, config_validation as cv, device_registry as dr) from .const import DOMAIN, API_NUPNP from .bridge import HueBridge @@ -132,7 +133,28 @@ async def async_setup_entry(hass, entry): bridge = HueBridge(hass, entry, allow_unreachable, allow_groups) hass.data[DOMAIN][host] = bridge - return await bridge.async_setup() + + if not await bridge.async_setup(): + return False + + config = bridge.api.config + device_registry = await dr.async_get_registry(hass) + device_registry.async_get_or_create( + config_entry=entry.entry_id, + connections={ + (dr.CONNECTION_NETWORK_MAC, config.mac) + }, + identifiers={ + (DOMAIN, config.bridgeid) + }, + manufacturer='Signify', + name=config.name, + # Not yet exposed as properties in aiohue + model=config.raw['modelid'], + sw_version=config.raw['swversion'], + ) + + return True async def async_unload_entry(hass, entry): diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 2a51423a7a8..6f6e0ed617e 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -285,6 +285,25 @@ class HueLight(Light): """Return the list of supported effects.""" return [EFFECT_COLORLOOP, EFFECT_RANDOM] + @property + def device_info(self): + """Return the device info.""" + if self.light.type in ('LightGroup', 'Room'): + return None + + return { + 'identifiers': { + (hue.DOMAIN, self.unique_id) + }, + 'name': self.name, + 'manufacturer': self.light.manufacturername, + # productname added in Hue Bridge API 1.24 + # (published 03/05/2018) + 'model': self.light.productname or self.light.modelid, + # Not yet exposed as properties in aiohue + 'sw_version': self.light.raw['swversion'], + } + async def async_turn_on(self, **kwargs): """Turn the specified or all lights on.""" command = {'on': True} diff --git a/tests/components/hue/test_init.py b/tests/components/hue/test_init.py index d12270cd908..1c4768746d5 100644 --- a/tests/components/hue/test_init.py +++ b/tests/components/hue/test_init.py @@ -1,5 +1,5 @@ """Test Hue setup process.""" -from unittest.mock import patch +from unittest.mock import Mock, patch from homeassistant.setup import async_setup_component from homeassistant.components import hue @@ -145,9 +145,21 @@ async def test_config_passed_to_config_entry(hass): 'host': '0.0.0.0', }) entry.add_to_hass(hass) - - with patch.object(hue, 'HueBridge') as mock_bridge: + mock_registry = Mock() + with patch.object(hue, 'HueBridge') as mock_bridge, \ + patch('homeassistant.helpers.device_registry.async_get_registry', + return_value=mock_coro(mock_registry)): mock_bridge.return_value.async_setup.return_value = mock_coro(True) + mock_bridge.return_value.api.config = Mock( + mac='mock-mac', + bridgeid='mock-bridgeid', + raw={ + 'modelid': 'mock-modelid', + 'swversion': 'mock-swversion', + } + ) + # Can't set name via kwargs + mock_bridge.return_value.api.config.name = 'mock-name' assert await async_setup_component(hass, hue.DOMAIN, { hue.DOMAIN: { hue.CONF_BRIDGES: { @@ -168,6 +180,21 @@ async def test_config_passed_to_config_entry(hass): assert p_allow_unreachable is True assert p_allow_groups is False + assert len(mock_registry.mock_calls) == 1 + assert mock_registry.mock_calls[0][2] == { + 'config_entry': entry.entry_id, + 'connections': { + ('mac', 'mock-mac') + }, + 'identifiers': { + ('hue', 'mock-bridgeid') + }, + 'manufacturer': 'Signify', + 'name': 'mock-name', + 'model': 'mock-modelid', + 'sw_version': 'mock-swversion' + } + async def test_unload_entry(hass): """Test being able to unload an entry.""" @@ -176,8 +203,11 @@ async def test_unload_entry(hass): }) entry.add_to_hass(hass) - with patch.object(hue, 'HueBridge') as mock_bridge: + with patch.object(hue, 'HueBridge') as mock_bridge, \ + patch('homeassistant.helpers.device_registry.async_get_registry', + return_value=mock_coro(Mock())): mock_bridge.return_value.async_setup.return_value = mock_coro(True) + mock_bridge.return_value.api.config = Mock() assert await async_setup_component(hass, hue.DOMAIN, {}) is True assert len(mock_bridge.return_value.mock_calls) == 1 From 5681fa8f07a6db5d77d343429d5ec4f73cf9f139 Mon Sep 17 00:00:00 2001 From: Jason Hu Date: Wed, 29 Aug 2018 12:00:40 -0700 Subject: [PATCH 146/147] Nest Thermostat has software version (#16275) --- homeassistant/components/climate/nest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index f81736b3a52..bc63512fcf3 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -138,6 +138,7 @@ class NestThermostat(ClimateDevice): 'name': self.device.name_long, 'manufacturer': 'Nest Labs', 'model': "Thermostat", + 'sw_version': self.device.software_version, } @property From 99d48795b9be6be2dc1bbfd92e375285cba508e6 Mon Sep 17 00:00:00 2001 From: Pavel Pletenev Date: Wed, 29 Aug 2018 21:13:01 +0200 Subject: [PATCH 147/147] Add support for Habitica (#15744) * Added support for Habitica Second refactoring Moved all config to component. Sensors are autodiscovered. Signed-off-by: delphi * Apply requested changes Signed-off-by: delphi * Made event fire async. Made `sensors` config implicit and opt-out-style. Signed-off-by: delphi * Removed unneeded check and await. Signed-off-by: delphi * Moved into separate component package and added service.yaml Signed-off-by: delphi * Fix coveralls Signed-off-by: delphi --- .coveragerc | 3 + homeassistant/components/habitica/__init__.py | 158 ++++++++++++++++++ .../components/habitica/services.yaml | 15 ++ homeassistant/components/sensor/habitica.py | 96 +++++++++++ requirements_all.txt | 3 + 5 files changed, 275 insertions(+) create mode 100644 homeassistant/components/habitica/__init__.py create mode 100644 homeassistant/components/habitica/services.yaml create mode 100644 homeassistant/components/sensor/habitica.py diff --git a/.coveragerc b/.coveragerc index 0c4a1f7d569..39c31e4e40b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -116,6 +116,9 @@ omit = homeassistant/components/google.py homeassistant/components/*/google.py + homeassistant/components/habitica/* + homeassistant/components/*/habitica.py + homeassistant/components/hangouts/__init__.py homeassistant/components/hangouts/const.py homeassistant/components/hangouts/hangouts_bot.py diff --git a/homeassistant/components/habitica/__init__.py b/homeassistant/components/habitica/__init__.py new file mode 100644 index 00000000000..44b9e392157 --- /dev/null +++ b/homeassistant/components/habitica/__init__.py @@ -0,0 +1,158 @@ +""" +The Habitica API component. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/habitica/ +""" + +import logging +from collections import namedtuple + +import voluptuous as vol +from homeassistant.const import \ + CONF_NAME, CONF_URL, CONF_SENSORS, CONF_PATH, CONF_API_KEY +from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers import \ + config_validation as cv, discovery + +REQUIREMENTS = ['habitipy==0.2.0'] +_LOGGER = logging.getLogger(__name__) +DOMAIN = "habitica" + +CONF_API_USER = "api_user" + +ST = SensorType = namedtuple('SensorType', [ + "name", "icon", "unit", "path" +]) + +SENSORS_TYPES = { + 'name': ST('Name', None, '', ["profile", "name"]), + 'hp': ST('HP', 'mdi:heart', 'HP', ["stats", "hp"]), + 'maxHealth': ST('max HP', 'mdi:heart', 'HP', ["stats", "maxHealth"]), + 'mp': ST('Mana', 'mdi:auto-fix', 'MP', ["stats", "mp"]), + 'maxMP': ST('max Mana', 'mdi:auto-fix', 'MP', ["stats", "maxMP"]), + 'exp': ST('EXP', 'mdi:star', 'EXP', ["stats", "exp"]), + 'toNextLevel': ST( + 'Next Lvl', 'mdi:star', 'EXP', ["stats", "toNextLevel"]), + 'lvl': ST( + 'Lvl', 'mdi:arrow-up-bold-circle-outline', 'Lvl', ["stats", "lvl"]), + 'gp': ST('Gold', 'mdi:coin', 'Gold', ["stats", "gp"]), + 'class': ST('Class', 'mdi:sword', '', ["stats", "class"]) +} + +INSTANCE_SCHEMA = vol.Schema({ + vol.Optional(CONF_URL, default='https://habitica.com'): cv.url, + vol.Optional(CONF_NAME): cv.string, + vol.Required(CONF_API_USER): cv.string, + vol.Required(CONF_API_KEY): cv.string, + vol.Optional(CONF_SENSORS, default=list(SENSORS_TYPES)): + vol.All( + cv.ensure_list, + vol.Unique(), + [vol.In(list(SENSORS_TYPES))]) +}) + +has_unique_values = vol.Schema(vol.Unique()) # pylint: disable=invalid-name +# because we want a handy alias + + +def has_all_unique_users(value): + """Validate that all `api_user`s are unique.""" + api_users = [user[CONF_API_USER] for user in value] + has_unique_values(api_users) + return value + + +def has_all_unique_users_names(value): + """Validate that all user's names are unique and set if any is set.""" + names = [user.get(CONF_NAME) for user in value] + if None in names and any(name is not None for name in names): + raise vol.Invalid( + 'user names of all users must be set if any is set') + if not all(name is None for name in names): + has_unique_values(names) + return value + + +INSTANCE_LIST_SCHEMA = vol.All( + cv.ensure_list, + has_all_unique_users, + has_all_unique_users_names, + [INSTANCE_SCHEMA]) + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: INSTANCE_LIST_SCHEMA +}, extra=vol.ALLOW_EXTRA) + +SERVICE_API_CALL = 'api_call' +ATTR_NAME = CONF_NAME +ATTR_PATH = CONF_PATH +ATTR_ARGS = "args" +EVENT_API_CALL_SUCCESS = "{0}_{1}_{2}".format( + DOMAIN, SERVICE_API_CALL, "success") + +SERVICE_API_CALL_SCHEMA = vol.Schema({ + vol.Required(ATTR_NAME): str, + vol.Required(ATTR_PATH): vol.All(cv.ensure_list, [str]), + vol.Optional(ATTR_ARGS): dict +}) + + +async def async_setup(hass, config): + """Set up the habitica service.""" + conf = config[DOMAIN] + data = hass.data[DOMAIN] = {} + websession = async_get_clientsession(hass) + from habitipy.aio import HabitipyAsync + + class HAHabitipyAsync(HabitipyAsync): + """Closure API class to hold session.""" + + def __call__(self, **kwargs): + return super().__call__(websession, **kwargs) + + for instance in conf: + url = instance[CONF_URL] + username = instance[CONF_API_USER] + password = instance[CONF_API_KEY] + name = instance.get(CONF_NAME) + config_dict = {"url": url, "login": username, "password": password} + api = HAHabitipyAsync(config_dict) + user = await api.user.get() + if name is None: + name = user['profile']['name'] + data[name] = api + if CONF_SENSORS in instance: + hass.async_create_task( + discovery.async_load_platform( + hass, "sensor", DOMAIN, + {"name": name, "sensors": instance[CONF_SENSORS]}, + config)) + + async def handle_api_call(call): + name = call.data[ATTR_NAME] + path = call.data[ATTR_PATH] + api = hass.data[DOMAIN].get(name) + if api is None: + _LOGGER.error( + "API_CALL: User '%s' not configured", name) + return + try: + for element in path: + api = api[element] + except KeyError: + _LOGGER.error( + "API_CALL: Path %s is invalid" + " for api on '{%s}' element", path, element) + return + kwargs = call.data.get(ATTR_ARGS, {}) + data = await api(**kwargs) + hass.bus.async_fire(EVENT_API_CALL_SUCCESS, { + "name": name, "path": path, "data": data + }) + + hass.services.async_register( + DOMAIN, SERVICE_API_CALL, + handle_api_call, + schema=SERVICE_API_CALL_SCHEMA) + return True diff --git a/homeassistant/components/habitica/services.yaml b/homeassistant/components/habitica/services.yaml new file mode 100644 index 00000000000..a063b1577f5 --- /dev/null +++ b/homeassistant/components/habitica/services.yaml @@ -0,0 +1,15 @@ +# Describes the format for Habitica service + +--- +api_call: + description: Call Habitica api + fields: + name: + description: Habitica's username to call for + example: 'xxxNotAValidNickxxx' + path: + description: "Items from API URL in form of an array with method attached at the end. Consult https://habitica.com/apidoc/. Example uses https://habitica.com/apidoc/#api-Task-CreateUserTasks" + example: '["tasks", "user", "post"]' + args: + description: Any additional json or url parameter arguments. See apidoc mentioned for path. Example uses same api endpoint + example: '{"text": "Use API from Home Assistant", "type": "todo"}' diff --git a/homeassistant/components/sensor/habitica.py b/homeassistant/components/sensor/habitica.py new file mode 100644 index 00000000000..d2f13eb30e6 --- /dev/null +++ b/homeassistant/components/sensor/habitica.py @@ -0,0 +1,96 @@ +""" +The Habitica sensor. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.habitica/ +""" + +import logging +from datetime import timedelta + +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle +from homeassistant.components import habitica + +_LOGGER = logging.getLogger(__name__) +MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15) + + +async def async_setup_platform( + hass, config, async_add_devices, discovery_info=None): + """Set up the habitica platform.""" + if discovery_info is None: + return + + name = discovery_info[habitica.CONF_NAME] + sensors = discovery_info[habitica.CONF_SENSORS] + sensor_data = HabitipyData(hass.data[habitica.DOMAIN][name]) + await sensor_data.update() + async_add_devices([ + HabitipySensor(name, sensor, sensor_data) + for sensor in sensors + ], True) + + +class HabitipyData: + """Habitica API user data cache.""" + + def __init__(self, api): + """ + Habitica API user data cache. + + api - HAHabitipyAsync object + """ + self.api = api + self.data = None + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + async def update(self): + """Get a new fix from Habitica servers.""" + self.data = await self.api.user.get() + + +class HabitipySensor(Entity): + """A generic Habitica sensor.""" + + def __init__(self, name, sensor_name, updater): + """ + Init a generic Habitica sensor. + + name - Habitica platform name + sensor_name - one of the names from ALL_SENSOR_TYPES + """ + self._name = name + self._sensor_name = sensor_name + self._sensor_type = habitica.SENSORS_TYPES[sensor_name] + self._state = None + self._updater = updater + + async def async_update(self): + """Update Condition and Forecast.""" + await self._updater.update() + data = self._updater.data + for element in self._sensor_type.path: + data = data[element] + self._state = data + + @property + def icon(self): + """Return the icon to use in the frontend, if any.""" + return self._sensor_type.icon + + @property + def name(self): + """Return the name of the sensor.""" + return "{0}_{1}_{2}".format( + habitica.DOMAIN, self._name, self._sensor_name) + + @property + def state(self): + """Return the state of the device.""" + return self._state + + @property + def unit_of_measurement(self): + """Return the unit the value is expressed in.""" + return self._sensor_type.unit diff --git a/requirements_all.txt b/requirements_all.txt index ba0da439cbd..ef89fb096da 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -420,6 +420,9 @@ ha-ffmpeg==1.9 # homeassistant.components.media_player.philips_js ha-philipsjs==0.0.5 +# homeassistant.components.habitica +habitipy==0.2.0 + # homeassistant.components.hangouts hangups==0.4.5