From 51aa773acf1f994f5eeea7fc74f9596b40604757 Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Wed, 17 Apr 2019 18:51:43 -0700 Subject: [PATCH 01/89] Bump skybellpy to 0.4.0 --- homeassistant/components/skybell/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/skybell/manifest.json b/homeassistant/components/skybell/manifest.json index 6a22a698b4ca2b..843fd3d13b0b9f 100644 --- a/homeassistant/components/skybell/manifest.json +++ b/homeassistant/components/skybell/manifest.json @@ -3,7 +3,7 @@ "name": "Skybell", "documentation": "https://www.home-assistant.io/components/skybell", "requirements": [ - "skybellpy==0.3.0" + "skybellpy==0.4.0" ], "dependencies": [], "codeowners": [] From e18b4d29228ce99e9ca5c13bbee0a397cc416752 Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Sun, 21 Apr 2019 21:32:14 -0700 Subject: [PATCH 02/89] Bump skybellpy to 0.4.0 in requirements_all.txt --- requirements_all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_all.txt b/requirements_all.txt index b861e8e2a49416..d604d5cdf00ded 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1579,7 +1579,7 @@ simplisafe-python==3.4.1 sisyphus-control==2.1 # homeassistant.components.skybell -skybellpy==0.3.0 +skybellpy==0.4.0 # homeassistant.components.slack slacker==0.12.0 From d74156a2d50f7df9a1efd77119120afbe786ca1b Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 26 Apr 2019 15:41:42 -0700 Subject: [PATCH 03/89] Added extra states for STATE_ALARM_TRIGGERED to allow users to know if it is a burglar or fire or carbon monoxide so automations can take appropriate actions. Updated TotalConnect component to handle these new states. --- .../components/totalconnect/alarm_control_panel.py | 7 +++++++ homeassistant/const.py | 2 ++ 2 files changed, 9 insertions(+) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 848202d6ce1445..72463c7ee07e6d 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -77,7 +77,14 @@ def update(self): state = STATE_ALARM_ARMING elif status == self._client.DISARMING: state = STATE_ALARM_DISARMING + elif status == self._client.ALARMING: + state = STATE_ALARM_TRIGGERED + elif status == self._client.ALARMING_FIRE_SMOKE: + state = STATE_ALARM_TRIGGERED_FIRE_SMOKE + elif status == self._client.ALARMING_CARBON_MONOXIDE: + state = STATE_ALARM_TRIGGERED_CARBON_MONOXIDE else: + logging.info("Total Connect Client returned unknown status code: " + str(status)) state = None self._state = state diff --git a/homeassistant/const.py b/homeassistant/const.py index e4f1ac95af49d7..89a4ddd8cb1c0d 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -209,6 +209,8 @@ STATE_ALARM_ARMING = 'arming' STATE_ALARM_DISARMING = 'disarming' STATE_ALARM_TRIGGERED = 'triggered' +STATE_ALARM_TRIGGERED_FIRE_SMOKE = 'triggered_fire_smoke' +STATE_ALARM_TRIGGERED_CARBON_MONOXIDE = 'triggered_carbon_monoxide' STATE_LOCKED = 'locked' STATE_UNLOCKED = 'unlocked' STATE_UNAVAILABLE = 'unavailable' From abcc85abc8bb6e911f97d341ef6a205833006104 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 27 Apr 2019 20:25:18 -0700 Subject: [PATCH 04/89] Fix const import --- homeassistant/components/totalconnect/alarm_control_panel.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 72463c7ee07e6d..175b38bec1ba53 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -9,8 +9,9 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, - STATE_ALARM_ARMING, STATE_ALARM_DISARMING, CONF_NAME, - STATE_ALARM_ARMED_CUSTOM_BYPASS) + STATE_ALARM_ARMING, STATE_ALARM_DISARMING, STATE_ALARM_TRIGGERED, + STATE_ALARM_TRIGGERED_FIRE_SMOKE, STATE_ALARM_TRIGGERED_CARBON_MONOXIDE, + CONF_NAME, STATE_ALARM_ARMED_CUSTOM_BYPASS) _LOGGER = logging.getLogger(__name__) From d3030916d9fbee835c463b542ae3422d00ad314e Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 27 Apr 2019 20:27:11 -0700 Subject: [PATCH 05/89] Fix const import From 73f38ebbd0a5dcf4d2a31d4e7971790c97787486 Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Sat, 27 Apr 2019 21:37:26 -0700 Subject: [PATCH 06/89] Fix const imports --- homeassistant/components/totalconnect/alarm_control_panel.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 72463c7ee07e6d..175b38bec1ba53 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -9,8 +9,9 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, - STATE_ALARM_ARMING, STATE_ALARM_DISARMING, CONF_NAME, - STATE_ALARM_ARMED_CUSTOM_BYPASS) + STATE_ALARM_ARMING, STATE_ALARM_DISARMING, STATE_ALARM_TRIGGERED, + STATE_ALARM_TRIGGERED_FIRE_SMOKE, STATE_ALARM_TRIGGERED_CARBON_MONOXIDE, + CONF_NAME, STATE_ALARM_ARMED_CUSTOM_BYPASS) _LOGGER = logging.getLogger(__name__) From 5bec7e4f4bd13359afe33fa208db8721a77c201d Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Sun, 5 May 2019 13:14:52 -0700 Subject: [PATCH 07/89] Bump total-connect-client to 0.26. --- .../components/totalconnect/alarm_control_panel.py | 7 ++++--- homeassistant/components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 175b38bec1ba53..25e14417f0955a 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -9,7 +9,7 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, - STATE_ALARM_ARMING, STATE_ALARM_DISARMING, STATE_ALARM_TRIGGERED, + STATE_ALARM_ARMING, STATE_ALARM_DISARMING, STATE_ALARM_TRIGGERED, STATE_ALARM_TRIGGERED_FIRE_SMOKE, STATE_ALARM_TRIGGERED_CARBON_MONOXIDE, CONF_NAME, STATE_ALARM_ARMED_CUSTOM_BYPASS) @@ -83,9 +83,10 @@ def update(self): elif status == self._client.ALARMING_FIRE_SMOKE: state = STATE_ALARM_TRIGGERED_FIRE_SMOKE elif status == self._client.ALARMING_CARBON_MONOXIDE: - state = STATE_ALARM_TRIGGERED_CARBON_MONOXIDE + state = STATE_ALARM_TRIGGERED_CARBON_MONOXIDE else: - logging.info("Total Connect Client returned unknown status code: " + str(status)) + logging.info("Total Connect Client returned " + "unknown status code: %s", status) state = None self._state = state diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index adb60599ae533c..3447b9b9cb03fb 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -3,7 +3,7 @@ "name": "Totalconnect", "documentation": "https://www.home-assistant.io/components/totalconnect", "requirements": [ - "total_connect_client==0.25" + "total_connect_client==0.26" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index d841baa54f953e..dcae06ae606c51 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1713,7 +1713,7 @@ todoist-python==7.0.17 toonapilib==3.2.2 # homeassistant.components.totalconnect -total_connect_client==0.25 +total_connect_client==0.26 # homeassistant.components.tplink_lte tp-connected==0.0.4 From 4862ff516b5a4a68c836362238ea716d2f50d19f Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 25 May 2019 07:55:31 -0700 Subject: [PATCH 08/89] Catch details of alarm trigger in state attributes. Also bumps total_connect_client to 0.27. --- .../totalconnect/alarm_control_panel.py | 22 ++++++++++++++----- .../components/totalconnect/manifest.json | 2 +- homeassistant/const.py | 2 -- requirements_all.txt | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 175b38bec1ba53..7d5ffda9804cf4 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -9,11 +9,9 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, - STATE_ALARM_ARMING, STATE_ALARM_DISARMING, STATE_ALARM_TRIGGERED, - STATE_ALARM_TRIGGERED_FIRE_SMOKE, STATE_ALARM_TRIGGERED_CARBON_MONOXIDE, + STATE_ALARM_ARMING, STATE_ALARM_DISARMING, STATE_ALARM_TRIGGERED, CONF_NAME, STATE_ALARM_ARMED_CUSTOM_BYPASS) - _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = 'Total Connect' @@ -47,6 +45,7 @@ def __init__(self, name, username, password): self._username = username self._password = password self._state = None + self._state_attributes = {} self._client = TotalConnectClient.TotalConnectClient( username, password) @@ -60,9 +59,15 @@ def state(self): """Return the state of the device.""" return self._state + @property + def state_attributes(self): + """Return the state attributes of the device.""" + return self._state_attributes + def update(self): """Return the state of the device.""" status = self._client.get_armed_status() + attr = {'triggered_source': None, 'triggered_zone': None} if status == self._client.DISARMED: state = STATE_ALARM_DISARMED @@ -80,15 +85,20 @@ def update(self): state = STATE_ALARM_DISARMING elif status == self._client.ALARMING: state = STATE_ALARM_TRIGGERED + attr['triggered_source'] = 'Police/Medical' elif status == self._client.ALARMING_FIRE_SMOKE: - state = STATE_ALARM_TRIGGERED_FIRE_SMOKE + state = STATE_ALARM_TRIGGERED + attr['triggered_source'] = 'Fire/Smoke' elif status == self._client.ALARMING_CARBON_MONOXIDE: - state = STATE_ALARM_TRIGGERED_CARBON_MONOXIDE + state = STATE_ALARM_TRIGGERED + attr['triggered_source'] = 'Carbon Monoxide' else: - logging.info("Total Connect Client returned unknown status code: " + str(status)) + logging.info("Total Connect Client returned unknown " + "status code: %s", status) state = None self._state = state + self._state_attributes = attr def alarm_disarm(self, code=None): """Send disarm command.""" diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index adb60599ae533c..3ff3b5c5b46436 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -3,7 +3,7 @@ "name": "Totalconnect", "documentation": "https://www.home-assistant.io/components/totalconnect", "requirements": [ - "total_connect_client==0.25" + "total_connect_client==0.27" ], "dependencies": [], "codeowners": [] diff --git a/homeassistant/const.py b/homeassistant/const.py index 5ead7b8407a28f..9176c1b8939240 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -209,8 +209,6 @@ STATE_ALARM_ARMING = 'arming' STATE_ALARM_DISARMING = 'disarming' STATE_ALARM_TRIGGERED = 'triggered' -STATE_ALARM_TRIGGERED_FIRE_SMOKE = 'triggered_fire_smoke' -STATE_ALARM_TRIGGERED_CARBON_MONOXIDE = 'triggered_carbon_monoxide' STATE_LOCKED = 'locked' STATE_UNLOCKED = 'unlocked' STATE_UNAVAILABLE = 'unavailable' diff --git a/requirements_all.txt b/requirements_all.txt index d604d5cdf00ded..9eadca7f4220ca 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1710,7 +1710,7 @@ todoist-python==7.0.17 toonapilib==3.2.2 # homeassistant.components.totalconnect -total_connect_client==0.25 +total_connect_client==0.27 # homeassistant.components.tplink_lte tp-connected==0.0.4 From e7a13d44ce701b592ef75fbb8e54f5851a56f3e0 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Wed, 29 May 2019 20:30:32 -0700 Subject: [PATCH 09/89] Change state_attributes() to device_state_attributes() --- .../components/totalconnect/alarm_control_panel.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 7d5ffda9804cf4..6d4c7a9671a87e 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -45,7 +45,7 @@ def __init__(self, name, username, password): self._username = username self._password = password self._state = None - self._state_attributes = {} + self._device_state_attributes = {} self._client = TotalConnectClient.TotalConnectClient( username, password) @@ -60,9 +60,9 @@ def state(self): return self._state @property - def state_attributes(self): + def device_state_attributes(self): """Return the state attributes of the device.""" - return self._state_attributes + return self._device_state_attributes def update(self): """Return the state of the device.""" @@ -98,7 +98,7 @@ def update(self): state = None self._state = state - self._state_attributes = attr + self._device_state_attributes = attr def alarm_disarm(self, code=None): """Send disarm command.""" From 6a50e8047e38d1294c7947231f4e3be3b3234a8c Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Sat, 8 Jun 2019 16:24:40 -0700 Subject: [PATCH 10/89] Move totalconnect component toward being a multi-platform integration. Bump total_connect_client to 0.28. --- .../components/totalconnect/__init__.py | 60 +++++++++++++++++ .../totalconnect/alarm_control_panel.py | 67 +++++++++---------- .../components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- 4 files changed, 93 insertions(+), 38 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 084846a8b8575b..adc9ebb9c6ba5b 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -1 +1,61 @@ """The totalconnect component.""" +import logging + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers import discovery +from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME) + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = 'Total Connect' + +DOMAIN = 'totalconnect' + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + }), +}, extra=vol.ALLOW_EXTRA) + +TOTALCONNECT_PLATFORMS = ['alarm_control_panel'] + + +class TotalConnectSystem: + """TotalConnect System class.""" + + def __init__(self, username, password): + """Initialize the TotalConnect system.""" + from total_connect_client import TotalConnectClient + + _LOGGER.debug("Setting up TotalConnectSystem...") + self._username = username + self._password = password + self._client = TotalConnectClient.TotalConnectClient(username, + password) + + @property + def client(self): + """Return the client.""" + return self._client + + +def setup(hass, config): + """Set up TotalConnect component.""" + conf = config.get(DOMAIN) + if conf is not None: + + username = conf.get(CONF_USERNAME) + password = conf.get(CONF_PASSWORD) + + hass.data[DOMAIN] = TotalConnectSystem(username, password) + + for platform in TOTALCONNECT_PLATFORMS: + discovery.load_platform(hass, platform, DOMAIN, {}, config) + + return True + + _LOGGER.critical("TotalConnect configuration is missing.") + return False diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 6d4c7a9671a87e..213393c07c80b7 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -1,53 +1,41 @@ """Interfaces with TotalConnect alarm control panels.""" import logging -import voluptuous as vol - -import homeassistant.helpers.config_validation as cv import homeassistant.components.alarm_control_panel as alarm -from homeassistant.components.alarm_control_panel import PLATFORM_SCHEMA from homeassistant.const import ( - CONF_PASSWORD, CONF_USERNAME, STATE_ALARM_ARMED_AWAY, - STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, - STATE_ALARM_ARMING, STATE_ALARM_DISARMING, STATE_ALARM_TRIGGERED, - CONF_NAME, STATE_ALARM_ARMED_CUSTOM_BYPASS) - -_LOGGER = logging.getLogger(__name__) + STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_DISARMED, STATE_ALARM_ARMING, STATE_ALARM_DISARMING, + STATE_ALARM_TRIGGERED, STATE_ALARM_ARMED_CUSTOM_BYPASS) -DEFAULT_NAME = 'Total Connect' +from . import DOMAIN as TOTALCONNECT_DOMAIN -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_PASSWORD): cv.string, - vol.Required(CONF_USERNAME): cv.string, - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, -}) +_LOGGER = logging.getLogger(__name__) 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) + """Set up an alarm control panel for a TotalConnect device.""" + alarms = [] + + client = hass.data[TOTALCONNECT_DOMAIN].client - total_connect = TotalConnect(name, username, password) - add_entities([total_connect], True) + for location in client.locations: + location_id = location.get('LocationID') + name = location.get('LocationName') + alarms.append(TotalConnectAlarm(name, location_id, client)) + add_entities(alarms) -class TotalConnect(alarm.AlarmControlPanel): +class TotalConnectAlarm(alarm.AlarmControlPanel): """Represent an TotalConnect status.""" - def __init__(self, name, username, password): + def __init__(self, name, location_id, client): """Initialize the TotalConnect status.""" - from total_connect_client import TotalConnectClient - _LOGGER.debug("Setting up TotalConnect...") self._name = name - self._username = username - self._password = password + self._location_id = location_id + self._client = client self._state = None self._device_state_attributes = {} - self._client = TotalConnectClient.TotalConnectClient( - username, password) @property def name(self): @@ -66,8 +54,15 @@ def device_state_attributes(self): def update(self): """Return the state of the device.""" - status = self._client.get_armed_status() - attr = {'triggered_source': None, 'triggered_zone': None} + status = self._client.get_armed_status(self._name) + attr = { + 'location_name': self._name, + 'location_id': self._location_id, + 'ac_loss': self._client.ac_loss, + 'low_battery': self._client.low_battery, + 'triggered_source': None, + 'triggered_zone': None + } if status == self._client.DISARMED: state = STATE_ALARM_DISARMED @@ -102,16 +97,16 @@ def update(self): def alarm_disarm(self, code=None): """Send disarm command.""" - self._client.disarm() + self._client.disarm(self._name) def alarm_arm_home(self, code=None): """Send arm home command.""" - self._client.arm_stay() + self._client.arm_stay(self._name) def alarm_arm_away(self, code=None): """Send arm away command.""" - self._client.arm_away() + self._client.arm_away(self._name) def alarm_arm_night(self, code=None): """Send arm night command.""" - self._client.arm_stay_night() + self._client.arm_stay_night(self._name) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 3ff3b5c5b46436..e6bcd6dd00a3ae 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -3,7 +3,7 @@ "name": "Totalconnect", "documentation": "https://www.home-assistant.io/components/totalconnect", "requirements": [ - "total_connect_client==0.27" + "total_connect_client==0.28" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index b547735156638f..7689d8fb3f99d3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1773,7 +1773,7 @@ todoist-python==7.0.17 toonapilib==3.2.2 # homeassistant.components.totalconnect -total_connect_client==0.27 +total_connect_client==0.28 # homeassistant.components.tplink_lte tp-connected==0.0.4 From ad4c4c97cba6c3d0c3075b1c33479f924b125fba Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 29 Jun 2019 16:31:06 -0700 Subject: [PATCH 11/89] add missing total-connect alarm state mappings --- .../totalconnect/alarm_control_panel.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 213393c07c80b7..fc38f7e6e81526 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -66,12 +66,24 @@ def update(self): if status == self._client.DISARMED: state = STATE_ALARM_DISARMED + elif status == self._client.DISARMED_BYPASS: + state = STATE_ALARM_DISARMED elif status == self._client.ARMED_STAY: state = STATE_ALARM_ARMED_HOME - elif status == self._client.ARMED_AWAY: - state = STATE_ALARM_ARMED_AWAY + elif status == self._client.ARMED_STAY_INSTANT: + state = STATE_ALARM_ARMED_HOME + elif status == self._client.ARMED_STAY_INSTANT_BYPASS: + state = STATE_ALARM_ARMED_HOME elif status == self._client.ARMED_STAY_NIGHT: state = STATE_ALARM_ARMED_NIGHT + elif status == self._client.ARMED_AWAY: + state = STATE_ALARM_ARMED_AWAY + elif status == self._client.ARMED_AWAY_BYPASS: + state = STATE_ALARM_ARMED_AWAY + elif status == self._client.ARMED_AWAY_INSTANT: + state = STATE_ALARM_ARMED_AWAY + elif status == self._client.ARMED_AWAY_INSTANT_BYPASS: + state = STATE_ALARM_ARMED_AWAY elif status == self._client.ARMED_CUSTOM_BYPASS: state = STATE_ALARM_ARMED_CUSTOM_BYPASS elif status == self._client.ARMING: From e58931715b5f41b06343c747e25055d3915075ea Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 30 Jun 2019 14:10:34 -0700 Subject: [PATCH 12/89] Made recommended changes of MartinHjelmare at https://github.com/home-assistant/home-assistant/pull/24427 --- .coveragerc | 2 +- .../components/totalconnect/__init__.py | 50 ++++++++----------- .../totalconnect/alarm_control_panel.py | 5 +- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/.coveragerc b/.coveragerc index 7bc58a9cec13ab..41c5575f3eaa0c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -627,7 +627,7 @@ omit = homeassistant/components/tomato/device_tracker.py homeassistant/components/toon/* homeassistant/components/torque/sensor.py - homeassistant/components/totalconnect/alarm_control_panel.py + homeassistant/components/totalconnect/* homeassistant/components/touchline/climate.py homeassistant/components/tplink/device_tracker.py homeassistant/components/tplink/light.py diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index adc9ebb9c6ba5b..f17e24698dbd99 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -1,16 +1,13 @@ """The totalconnect component.""" import logging - import voluptuous as vol - import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME) +from total_connect_client import TotalConnectClient _LOGGER = logging.getLogger(__name__) -DEFAULT_NAME = 'Total Connect' - DOMAIN = 'totalconnect' CONFIG_SCHEMA = vol.Schema({ @@ -23,39 +20,32 @@ TOTALCONNECT_PLATFORMS = ['alarm_control_panel'] -class TotalConnectSystem: - """TotalConnect System class.""" +def setup(hass, config): + """Set up TotalConnect component.""" + conf = config[DOMAIN] - def __init__(self, username, password): - """Initialize the TotalConnect system.""" - from total_connect_client import TotalConnectClient + username = conf[CONF_USERNAME] + password = conf[CONF_PASSWORD] - _LOGGER.debug("Setting up TotalConnectSystem...") - self._username = username - self._password = password - self._client = TotalConnectClient.TotalConnectClient(username, - password) + client = TotalConnectClient.TotalConnectClient(username, password) - @property - def client(self): - """Return the client.""" - return self._client + if client.token is False: + return False + hass.data[DOMAIN] = TotalConnectSystem(username, password, client) -def setup(hass, config): - """Set up TotalConnect component.""" - conf = config.get(DOMAIN) - if conf is not None: + for platform in TOTALCONNECT_PLATFORMS: + discovery.load_platform(hass, platform, DOMAIN, {}, config) - username = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) + return True - hass.data[DOMAIN] = TotalConnectSystem(username, password) - for platform in TOTALCONNECT_PLATFORMS: - discovery.load_platform(hass, platform, DOMAIN, {}, config) +class TotalConnectSystem: + """TotalConnect System class.""" - return True + def __init__(self, username, password, client): + """Initialize the TotalConnect system.""" - _LOGGER.critical("TotalConnect configuration is missing.") - return False + self._username = username + self._password = password + self._client = client diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index fc38f7e6e81526..28ff790b298779 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -14,9 +14,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an alarm control panel for a TotalConnect device.""" + if discovery_info is None: + return + alarms = [] - client = hass.data[TOTALCONNECT_DOMAIN].client + client = hass.data[TOTALCONNECT_DOMAIN]._client for location in client.locations: location_id = location.get('LocationID') From aa2244082016886dde1a8d1ecaa6501cb1076c13 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Tue, 2 Jul 2019 19:04:48 -0400 Subject: [PATCH 13/89] Update __init__.py --- homeassistant/components/totalconnect/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index f17e24698dbd99..4ad5762fb2ce83 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -1,9 +1,11 @@ """The totalconnect component.""" import logging import voluptuous as vol + import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME) + from total_connect_client import TotalConnectClient _LOGGER = logging.getLogger(__name__) From 5cbfc987743ca327dbb1b609ec4f679ae6f32a9c Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 13 Jul 2019 11:04:06 -0700 Subject: [PATCH 14/89] Updates per MartinHjelmare comments --- homeassistant/components/totalconnect/__init__.py | 5 ++++- homeassistant/components/totalconnect/alarm_control_panel.py | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index f17e24698dbd99..a3e5aa652a4986 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -1,9 +1,11 @@ """The totalconnect component.""" import logging import voluptuous as vol + import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME) + from total_connect_client import TotalConnectClient _LOGGER = logging.getLogger(__name__) @@ -30,6 +32,7 @@ def setup(hass, config): client = TotalConnectClient.TotalConnectClient(username, password) if client.token is False: + _LOGGER.error("TotalConnect authentication failed.") return False hass.data[DOMAIN] = TotalConnectSystem(username, password, client) @@ -48,4 +51,4 @@ def __init__(self, username, password, client): self._username = username self._password = password - self._client = client + self.client = client diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 28ff790b298779..c3fb8e9eedc87e 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -19,7 +19,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): alarms = [] - client = hass.data[TOTALCONNECT_DOMAIN]._client + client = hass.data[TOTALCONNECT_DOMAIN].client for location in client.locations: location_id = location.get('LocationID') @@ -33,7 +33,6 @@ class TotalConnectAlarm(alarm.AlarmControlPanel): def __init__(self, name, location_id, client): """Initialize the TotalConnect status.""" - _LOGGER.debug("Setting up TotalConnect...") self._name = name self._location_id = location_id self._client = client From eb440cc5c492f18e580ac48be8e262416bb96f03 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 13 Jul 2019 11:24:14 -0700 Subject: [PATCH 15/89] flake8/pydocstyle fixes --- homeassistant/components/totalconnect/__init__.py | 1 - .../components/totalconnect/alarm_control_panel.py | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index a3e5aa652a4986..3bedbc59941df4 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -48,7 +48,6 @@ class TotalConnectSystem: def __init__(self, username, password, client): """Initialize the TotalConnect system.""" - self._username = username self._password = password self.client = client diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index c3fb8e9eedc87e..cfe3ad6b565f79 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -16,7 +16,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up an alarm control panel for a TotalConnect device.""" if discovery_info is None: return - + alarms = [] client = hass.data[TOTALCONNECT_DOMAIN].client @@ -64,7 +64,7 @@ def update(self): 'low_battery': self._client.low_battery, 'triggered_source': None, 'triggered_zone': None - } + } if status == self._client.DISARMED: state = STATE_ALARM_DISARMED @@ -109,18 +109,18 @@ def update(self): self._state = state self._device_state_attributes = attr - def alarm_disarm(self, code=None): + def alarm_disarm(self): """Send disarm command.""" self._client.disarm(self._name) - def alarm_arm_home(self, code=None): + def alarm_arm_home(self): """Send arm home command.""" self._client.arm_stay(self._name) - def alarm_arm_away(self, code=None): + def alarm_arm_away(self): """Send arm away command.""" self._client.arm_away(self._name) - def alarm_arm_night(self, code=None): + def alarm_arm_night(self): """Send arm night command.""" self._client.arm_stay_night(self._name) From 117ed1bb9e21ec21b7476899e91f5bbdb93451ee Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 13 Jul 2019 12:48:02 -0700 Subject: [PATCH 16/89] removed . at end of log message --- homeassistant/components/totalconnect/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 3bedbc59941df4..cff0f78320035f 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -32,7 +32,7 @@ def setup(hass, config): client = TotalConnectClient.TotalConnectClient(username, password) if client.token is False: - _LOGGER.error("TotalConnect authentication failed.") + _LOGGER.error("TotalConnect authentication failed") return False hass.data[DOMAIN] = TotalConnectSystem(username, password, client) From 14d3e2eaa3f80479c2ddbfba01d12d9084bbe7d2 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 13 Jul 2019 16:17:46 -0700 Subject: [PATCH 17/89] added blank line between logging and voluptuous --- homeassistant/components/totalconnect/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index cff0f78320035f..6b680de35448cd 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -1,5 +1,6 @@ """The totalconnect component.""" import logging + import voluptuous as vol import homeassistant.helpers.config_validation as cv From cd2b563a19134b653c16e6e5a70dbf31275dd99d Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 13 Jul 2019 18:27:10 -0700 Subject: [PATCH 18/89] more fixes --- homeassistant/components/totalconnect/__init__.py | 2 +- .../components/totalconnect/alarm_control_panel.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 6b680de35448cd..f8926a79f4b5b8 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -2,12 +2,12 @@ import logging import voluptuous as vol +from total_connect_client import TotalConnectClient import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME) -from total_connect_client import TotalConnectClient _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index cfe3ad6b565f79..981711d148b0e8 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -109,18 +109,18 @@ def update(self): self._state = state self._device_state_attributes = attr - def alarm_disarm(self): + def alarm_disarm(self, code=None): """Send disarm command.""" self._client.disarm(self._name) - def alarm_arm_home(self): + def alarm_arm_home(self, code=None): """Send arm home command.""" self._client.arm_stay(self._name) - def alarm_arm_away(self): + def alarm_arm_away(self, code=None): """Send arm away command.""" self._client.arm_away(self._name) - def alarm_arm_night(self): + def alarm_arm_night(self, code=None): """Send arm night command.""" self._client.arm_stay_night(self._name) From db6336b788cdc7884d13b7e23ede40af5ef69e6c Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 9 Nov 2019 16:48:33 -0800 Subject: [PATCH 19/89] Adding totalconnect zones as HA binary_sensors --- .../components/totalconnect/__init__.py | 27 ++--- .../totalconnect/alarm_control_panel.py | 76 +++++------- .../components/totalconnect/binary_sensor.py | 110 ++++++++++++++++++ .../components/totalconnect/manifest.json | 4 +- requirements_all.txt | 2 +- 5 files changed, 155 insertions(+), 64 deletions(-) create mode 100644 homeassistant/components/totalconnect/binary_sensor.py diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index c14ac36057e2ff..f8496fb1a8ada0 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -6,26 +6,21 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME) _LOGGER = logging.getLogger(__name__) -DOMAIN = "totalconnect" - -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: vol.Schema( - { - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - } - ) - }, - extra=vol.ALLOW_EXTRA, -) - -TOTALCONNECT_PLATFORMS = ["alarm_control_panel"] +DOMAIN = 'totalconnect' + +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + }), +}, extra=vol.ALLOW_EXTRA) + +TOTALCONNECT_PLATFORMS = ['alarm_control_panel', 'binary_sensor'] def setup(hass, config): diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index e5f0b0c8279350..34365ae817200e 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -3,15 +3,9 @@ import homeassistant.components.alarm_control_panel as alarm from homeassistant.const import ( - STATE_ALARM_ARMED_AWAY, - STATE_ALARM_ARMED_HOME, - STATE_ALARM_ARMED_NIGHT, - STATE_ALARM_DISARMED, - STATE_ALARM_ARMING, - STATE_ALARM_DISARMING, - STATE_ALARM_TRIGGERED, - STATE_ALARM_ARMED_CUSTOM_BYPASS, -) + STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_DISARMED, STATE_ALARM_ARMING, STATE_ALARM_DISARMING, + STATE_ALARM_TRIGGERED, STATE_ALARM_ARMED_CUSTOM_BYPASS) from . import DOMAIN as TOTALCONNECT_DOMAIN @@ -27,10 +21,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client = hass.data[TOTALCONNECT_DOMAIN].client - for location in client.locations: - location_id = location.get("LocationID") - name = location.get("LocationName") - alarms.append(TotalConnectAlarm(name, location_id, client)) + for k in client.locations: + alarms.append(TotalConnectAlarm(client.locations[k].location_name, + k, client)) add_entities(alarms) @@ -62,35 +55,29 @@ def device_state_attributes(self): def update(self): """Return the state of the device.""" - status = self._client.get_armed_status(self._name) + status = self._client.get_armed_status(self._location_id) attr = { - "location_name": self._name, - "location_id": self._location_id, - "ac_loss": self._client.ac_loss, - "low_battery": self._client.low_battery, - "triggered_source": None, - "triggered_zone": None, + 'location_name': self._client.locations[self._location_id].location_name, + 'location_id': self._location_id, + 'ac_loss': self._client.locations[self._location_id].ac_loss, + 'low_battery': self._client.locations[self._location_id].low_battery, + 'cover_tampered': self._client.locations[self._location_id].is_cover_tampered, + 'triggered_source': None, + 'triggered_zone': None } - if status == self._client.DISARMED: + if status in (self._client.DISARMED, self._client.DISARMED_BYPASS): state = STATE_ALARM_DISARMED - elif status == self._client.DISARMED_BYPASS: - state = STATE_ALARM_DISARMED - elif status == self._client.ARMED_STAY: - state = STATE_ALARM_ARMED_HOME - elif status == self._client.ARMED_STAY_INSTANT: - state = STATE_ALARM_ARMED_HOME - elif status == self._client.ARMED_STAY_INSTANT_BYPASS: + elif status in (self._client.ARMED_STAY, + self._client.ARMED_STAY_INSTANT, + self._client.ARMED_STAY_INSTANT_BYPASS): state = STATE_ALARM_ARMED_HOME elif status == self._client.ARMED_STAY_NIGHT: state = STATE_ALARM_ARMED_NIGHT - elif status == self._client.ARMED_AWAY: - state = STATE_ALARM_ARMED_AWAY - elif status == self._client.ARMED_AWAY_BYPASS: - state = STATE_ALARM_ARMED_AWAY - elif status == self._client.ARMED_AWAY_INSTANT: - state = STATE_ALARM_ARMED_AWAY - elif status == self._client.ARMED_AWAY_INSTANT_BYPASS: + elif status in (self._client.ARMED_AWAY, + self._client.ARMED_AWAY_BYPASS, + self._client.ARMED_AWAY_INSTANT, + self._client.ARMED_AWAY_INSTANT_BYPASS): state = STATE_ALARM_ARMED_AWAY elif status == self._client.ARMED_CUSTOM_BYPASS: state = STATE_ALARM_ARMED_CUSTOM_BYPASS @@ -100,17 +87,16 @@ def update(self): state = STATE_ALARM_DISARMING elif status == self._client.ALARMING: state = STATE_ALARM_TRIGGERED - attr["triggered_source"] = "Police/Medical" + attr['triggered_source'] = 'Police/Medical' elif status == self._client.ALARMING_FIRE_SMOKE: state = STATE_ALARM_TRIGGERED - attr["triggered_source"] = "Fire/Smoke" + attr['triggered_source'] = 'Fire/Smoke' elif status == self._client.ALARMING_CARBON_MONOXIDE: state = STATE_ALARM_TRIGGERED - attr["triggered_source"] = "Carbon Monoxide" + attr['triggered_source'] = 'Carbon Monoxide' else: - logging.info( - "Total Connect Client returned unknown " "status code: %s", status - ) + logging.info("Total Connect Client returned unknown " + "status code: %s", status) state = None self._state = state @@ -118,16 +104,16 @@ def update(self): def alarm_disarm(self, code=None): """Send disarm command.""" - self._client.disarm(self._name) + self._client.disarm(self._location_id) def alarm_arm_home(self, code=None): """Send arm home command.""" - self._client.arm_stay(self._name) + self._client.arm_stay(self._location_id) def alarm_arm_away(self, code=None): """Send arm away command.""" - self._client.arm_away(self._name) + self._client.arm_away(self._location_id) def alarm_arm_night(self, code=None): """Send arm night command.""" - self._client.arm_stay_night(self._name) + self._client.arm_stay_night(self._location_id) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py new file mode 100644 index 00000000000000..d4709ffa2ba64b --- /dev/null +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -0,0 +1,110 @@ +"""Interfaces with TotalConnect sensors.""" +import logging + +from homeassistant.components.binary_sensor import (BinarySensorDevice, + DEVICE_CLASS_DOOR, DEVICE_CLASS_SMOKE, DEVICE_CLASS_GAS) + +from total_connect_client.TotalConnectClient import (ZONE_TYPE_SECURITY, + ZONE_TYPE_FIRE_SMOKE, ZONE_TYPE_CARBON_MONOXIDE, + ZONE_STATUS_NORMAL, ZONE_STATUS_BYPASSED, ZONE_STATUS_FAULT, + ZONE_STATUS_TAMPER, ZONE_STATUS_TROUBLE_LOW_BATTERY, + ZONE_STATUS_TRIGGERED) + +from . import DOMAIN as TOTALCONNECT_DOMAIN + +_LOGGER = logging.getLogger(__name__) + +# total_connect zone types mapped to binary_sensor class +SENSOR_TYPES = { + ZONE_TYPE_SECURITY: DEVICE_CLASS_DOOR, + ZONE_TYPE_FIRE_SMOKE: DEVICE_CLASS_SMOKE, + ZONE_TYPE_CARBON_MONOXIDE: DEVICE_CLASS_GAS, +} + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up a sensor for a TotalConnect device.""" + if discovery_info is None: + return + + sensors = [] + + client_locations = hass.data[TOTALCONNECT_DOMAIN].client.locations + + for k in client_locations: + for zone in client_locations[k].zones: + sensors.append(TotalConnectBinarySensor(zone, k, client_locations)) + add_entities(sensors) + + +class TotalConnectBinarySensor(BinarySensorDevice): + """Represent an TotalConnect zone.""" + + def __init__(self, zone_id, location_id, locations): + """Initialize the TotalConnect status.""" + self._zone_id = zone_id + self._location_id = location_id + self._locations = locations + self._name = 'TC {} zone {}'.format( + locations[location_id].location_name, zone_id) + self._state = locations[location_id].zones[zone_id].status + self._unique_id = 'TC {} zone {}'.format( + locations[location_id].location_name, zone_id) + self._device_class = locations[location_id].zones[zone_id].zone_type_id + self._is_low_battery = False + self._is_tampered = False + self._is_on = False + self.update() + + @property + def unique_id(self) -> str: + """Return the unique id.""" + return self._unique_id + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def state(self): + """Return the state of the device.""" + return self._state + + def update(self): + """Return the state of the device.""" + status = self._locations[self._location_id].zones[self._zone_id].status + + self._is_on = not status == ZONE_STATUS_BYPASSED + self._is_tampered = (status == ZONE_STATUS_TAMPER) + self._is_low_battery = (status == ZONE_STATUS_TROUBLE_LOW_BATTERY) + + if status == ZONE_STATUS_NORMAL: + self._state = False + elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED): + self._state = True + else: + self._state = False + _LOGGER.info('Unknown Total Connect zone status %s returned.', + status) + + @property + def is_on(self): + """Return true if the binary sensor is on.""" + return self._is_on + + @property + def device_class(self): + """Return the class of this device, from component DEVICE_CLASSES.""" + return SENSOR_TYPES.get(self._device_class) + + @property + def device_state_attributes(self): + """Return the state attributes.""" + attributes = {} + attributes["zone_id"] = self._zone_id + attributes["zone_description"] = self._name + attributes["location_id"] = self._location_id + attributes["low_battery"] = self._is_low_battery + attributes["tampered"] = self._is_tampered + return attributes diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 39cd0e0f1e6ca3..c345a7d5178baf 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -1,9 +1,9 @@ { "domain": "totalconnect", "name": "Totalconnect", - "documentation": "https://www.home-assistant.io/integrations/totalconnect", + "documentation": "https://www.home-assistant.io/components/totalconnect", "requirements": [ - "total_connect_client==0.28" + "total_connect_client==0.30" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index ee331d1a32058e..de200a45ad1853 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1916,7 +1916,7 @@ todoist-python==8.0.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.28 +total_connect_client==0.30 # homeassistant.components.tplink_lte tp-connected==0.0.4 From e9a0e699a90c1e79571bda6c6366219047259cc2 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 9 Nov 2019 16:54:17 -0800 Subject: [PATCH 20/89] fix manifest.json --- homeassistant/components/totalconnect/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index c345a7d5178baf..478c9a7e3e7d66 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -1,7 +1,7 @@ { "domain": "totalconnect", "name": "Totalconnect", - "documentation": "https://www.home-assistant.io/components/totalconnect", + "documentation": "https://www.home-assistant.io/integrations/totalconnect", "requirements": [ "total_connect_client==0.30" ], From 1bc164d6c2aa9cb478597a771d49c2a113a7b5aa Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 11 Nov 2019 17:51:31 -0800 Subject: [PATCH 21/89] flake8/pydocstyle fixes. Added codeowner. --- .../components/totalconnect/alarm_control_panel.py | 2 +- homeassistant/components/totalconnect/manifest.json | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 34365ae817200e..86d1dc48a309d3 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -68,7 +68,7 @@ def update(self): if status in (self._client.DISARMED, self._client.DISARMED_BYPASS): state = STATE_ALARM_DISARMED - elif status in (self._client.ARMED_STAY, + elif status in (self._client.ARMED_STAY, self._client.ARMED_STAY_INSTANT, self._client.ARMED_STAY_INSTANT_BYPASS): state = STATE_ALARM_ARMED_HOME diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 478c9a7e3e7d66..cdd003b769e5ab 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -1,10 +1,12 @@ { "domain": "totalconnect", "name": "Totalconnect", - "documentation": "https://www.home-assistant.io/integrations/totalconnect", + "documentation": "https://www.home-assistant.io/components/totalconnect", "requirements": [ "total_connect_client==0.30" ], "dependencies": [], - "codeowners": [] + "codeowners": [ + "@austinmroczek" + ] } From 932e5b0f575173a101d79ea48d031420591c5f84 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 15 Nov 2019 17:50:05 -0800 Subject: [PATCH 22/89] Update formatting per @springstan guidance. --- CODEOWNERS | 1 + .../components/totalconnect/__init__.py | 27 +++++---- .../totalconnect/alarm_control_panel.py | 60 +++++++++++-------- .../components/totalconnect/binary_sensor.py | 43 ++++++++----- 4 files changed, 80 insertions(+), 51 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index cb3d0817d59fea..4b13cf7ce7aad3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -308,6 +308,7 @@ homeassistant/components/tile/* @bachya homeassistant/components/time_date/* @fabaff homeassistant/components/todoist/* @boralyl homeassistant/components/toon/* @frenck +homeassistant/components/totalconnect/* @austinmroczek homeassistant/components/tplink/* @rytilahti homeassistant/components/traccar/* @ludeeus homeassistant/components/tradfri/* @ggravlingen diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index f8496fb1a8ada0..bad65af9c7a3c5 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -6,21 +6,26 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers import discovery -from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME) +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME _LOGGER = logging.getLogger(__name__) -DOMAIN = 'totalconnect' - -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - }), -}, extra=vol.ALLOW_EXTRA) - -TOTALCONNECT_PLATFORMS = ['alarm_control_panel', 'binary_sensor'] +DOMAIN = "totalconnect" + +CONFIG_SCHEMA = vol.Schema( + { + DOMAIN: vol.Schema( + { + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + } + ), + }, + extra=vol.ALLOW_EXTRA, +) + +TOTALCONNECT_PLATFORMS = ["alarm_control_panel", "binary_sensor"] def setup(hass, config): diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 86d1dc48a309d3..ef24c54c311e8d 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -3,9 +3,15 @@ import homeassistant.components.alarm_control_panel as alarm from homeassistant.const import ( - STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, - STATE_ALARM_DISARMED, STATE_ALARM_ARMING, STATE_ALARM_DISARMING, - STATE_ALARM_TRIGGERED, STATE_ALARM_ARMED_CUSTOM_BYPASS) + STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_DISARMED, + STATE_ALARM_ARMING, + STATE_ALARM_DISARMING, + STATE_ALARM_TRIGGERED, + STATE_ALARM_ARMED_CUSTOM_BYPASS, +) from . import DOMAIN as TOTALCONNECT_DOMAIN @@ -22,8 +28,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client = hass.data[TOTALCONNECT_DOMAIN].client for k in client.locations: - alarms.append(TotalConnectAlarm(client.locations[k].location_name, - k, client)) + alarms.append(TotalConnectAlarm(client.locations[k].location_name, k, client)) add_entities(alarms) @@ -57,27 +62,33 @@ def update(self): """Return the state of the device.""" status = self._client.get_armed_status(self._location_id) attr = { - 'location_name': self._client.locations[self._location_id].location_name, - 'location_id': self._location_id, - 'ac_loss': self._client.locations[self._location_id].ac_loss, - 'low_battery': self._client.locations[self._location_id].low_battery, - 'cover_tampered': self._client.locations[self._location_id].is_cover_tampered, - 'triggered_source': None, - 'triggered_zone': None + "location_name": self._client.locations[self._location_id].location_name, + "location_id": self._location_id, + "ac_loss": self._client.locations[self._location_id].ac_loss, + "low_battery": self._client.locations[self._location_id].low_battery, + "cover_tampered": self._client.locations[ + self._location_id + ].is_cover_tampered, + "triggered_source": None, + "triggered_zone": None, } if status in (self._client.DISARMED, self._client.DISARMED_BYPASS): state = STATE_ALARM_DISARMED - elif status in (self._client.ARMED_STAY, - self._client.ARMED_STAY_INSTANT, - self._client.ARMED_STAY_INSTANT_BYPASS): + elif status in ( + self._client.ARMED_STAY, + self._client.ARMED_STAY_INSTANT, + self._client.ARMED_STAY_INSTANT_BYPASS, + ): state = STATE_ALARM_ARMED_HOME elif status == self._client.ARMED_STAY_NIGHT: state = STATE_ALARM_ARMED_NIGHT - elif status in (self._client.ARMED_AWAY, - self._client.ARMED_AWAY_BYPASS, - self._client.ARMED_AWAY_INSTANT, - self._client.ARMED_AWAY_INSTANT_BYPASS): + elif status in ( + self._client.ARMED_AWAY, + self._client.ARMED_AWAY_BYPASS, + self._client.ARMED_AWAY_INSTANT, + self._client.ARMED_AWAY_INSTANT_BYPASS, + ): state = STATE_ALARM_ARMED_AWAY elif status == self._client.ARMED_CUSTOM_BYPASS: state = STATE_ALARM_ARMED_CUSTOM_BYPASS @@ -87,16 +98,17 @@ def update(self): state = STATE_ALARM_DISARMING elif status == self._client.ALARMING: state = STATE_ALARM_TRIGGERED - attr['triggered_source'] = 'Police/Medical' + attr["triggered_source"] = "Police/Medical" elif status == self._client.ALARMING_FIRE_SMOKE: state = STATE_ALARM_TRIGGERED - attr['triggered_source'] = 'Fire/Smoke' + attr["triggered_source"] = "Fire/Smoke" elif status == self._client.ALARMING_CARBON_MONOXIDE: state = STATE_ALARM_TRIGGERED - attr['triggered_source'] = 'Carbon Monoxide' + attr["triggered_source"] = "Carbon Monoxide" else: - logging.info("Total Connect Client returned unknown " - "status code: %s", status) + logging.info( + "Total Connect Client returned unknown " "status code: %s", status + ) state = None self._state = state diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index d4709ffa2ba64b..310d86c25f22b6 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -1,14 +1,24 @@ """Interfaces with TotalConnect sensors.""" import logging -from homeassistant.components.binary_sensor import (BinarySensorDevice, - DEVICE_CLASS_DOOR, DEVICE_CLASS_SMOKE, DEVICE_CLASS_GAS) - -from total_connect_client.TotalConnectClient import (ZONE_TYPE_SECURITY, - ZONE_TYPE_FIRE_SMOKE, ZONE_TYPE_CARBON_MONOXIDE, - ZONE_STATUS_NORMAL, ZONE_STATUS_BYPASSED, ZONE_STATUS_FAULT, - ZONE_STATUS_TAMPER, ZONE_STATUS_TROUBLE_LOW_BATTERY, - ZONE_STATUS_TRIGGERED) +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, + DEVICE_CLASS_DOOR, + DEVICE_CLASS_SMOKE, + DEVICE_CLASS_GAS, +) + +from total_connect_client.TotalConnectClient import ( + ZONE_TYPE_SECURITY, + ZONE_TYPE_FIRE_SMOKE, + ZONE_TYPE_CARBON_MONOXIDE, + ZONE_STATUS_NORMAL, + ZONE_STATUS_BYPASSED, + ZONE_STATUS_FAULT, + ZONE_STATUS_TAMPER, + ZONE_STATUS_TROUBLE_LOW_BATTERY, + ZONE_STATUS_TRIGGERED, +) from . import DOMAIN as TOTALCONNECT_DOMAIN @@ -45,11 +55,13 @@ def __init__(self, zone_id, location_id, locations): self._zone_id = zone_id self._location_id = location_id self._locations = locations - self._name = 'TC {} zone {}'.format( - locations[location_id].location_name, zone_id) + self._name = "TC {} zone {}".format( + locations[location_id].location_name, zone_id + ) self._state = locations[location_id].zones[zone_id].status - self._unique_id = 'TC {} zone {}'.format( - locations[location_id].location_name, zone_id) + self._unique_id = "TC {} zone {}".format( + locations[location_id].location_name, zone_id + ) self._device_class = locations[location_id].zones[zone_id].zone_type_id self._is_low_battery = False self._is_tampered = False @@ -76,8 +88,8 @@ def update(self): status = self._locations[self._location_id].zones[self._zone_id].status self._is_on = not status == ZONE_STATUS_BYPASSED - self._is_tampered = (status == ZONE_STATUS_TAMPER) - self._is_low_battery = (status == ZONE_STATUS_TROUBLE_LOW_BATTERY) + self._is_tampered = status == ZONE_STATUS_TAMPER + self._is_low_battery = status == ZONE_STATUS_TROUBLE_LOW_BATTERY if status == ZONE_STATUS_NORMAL: self._state = False @@ -85,8 +97,7 @@ def update(self): self._state = True else: self._state = False - _LOGGER.info('Unknown Total Connect zone status %s returned.', - status) + _LOGGER.info("Unknown Total Connect zone status %s returned.", status) @property def is_on(self): From bf7be02a4a10c46f41bcc29065f295d7191ba820 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 15 Nov 2019 22:02:10 -0800 Subject: [PATCH 23/89] Fixed pylint --- .../components/totalconnect/binary_sensor.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 310d86c25f22b6..860d30899a8cf8 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -1,13 +1,6 @@ """Interfaces with TotalConnect sensors.""" import logging -from homeassistant.components.binary_sensor import ( - BinarySensorDevice, - DEVICE_CLASS_DOOR, - DEVICE_CLASS_SMOKE, - DEVICE_CLASS_GAS, -) - from total_connect_client.TotalConnectClient import ( ZONE_TYPE_SECURITY, ZONE_TYPE_FIRE_SMOKE, @@ -20,6 +13,13 @@ ZONE_STATUS_TRIGGERED, ) +from homeassistant.components.binary_sensor import ( + BinarySensorDevice, + DEVICE_CLASS_DOOR, + DEVICE_CLASS_SMOKE, + DEVICE_CLASS_GAS, +) + from . import DOMAIN as TOTALCONNECT_DOMAIN _LOGGER = logging.getLogger(__name__) From fcadf8037fca377ec095c48eda3c6550606ef6ed Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 15 Dec 2019 12:31:22 -0800 Subject: [PATCH 24/89] Add zone ID to log message for easier troubleshooting --- homeassistant/components/totalconnect/binary_sensor.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 860d30899a8cf8..b47f44c01fffe5 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -97,7 +97,11 @@ def update(self): self._state = True else: self._state = False - _LOGGER.info("Unknown Total Connect zone status %s returned.", status) + _LOGGER.info( + "Unknown Total Connect zone status %s returned by zone %s.", + status, + self._zone_id, + ) @property def is_on(self): From a68576e61cc0862f7c2558e5e36c269c84ee7f9d Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Wed, 18 Dec 2019 22:05:14 -0800 Subject: [PATCH 25/89] Account for bypassed zones in update() --- homeassistant/components/totalconnect/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index b47f44c01fffe5..9a6518e47f5bf4 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -91,7 +91,7 @@ def update(self): self._is_tampered = status == ZONE_STATUS_TAMPER self._is_low_battery = status == ZONE_STATUS_TROUBLE_LOW_BATTERY - if status == ZONE_STATUS_NORMAL: + if status in (ZONE_STATUS_NORMAL, ZONE_STATUS_BYPASSED): self._state = False elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED): self._state = True From a15b4de206cc859a1af131dc64cc8d44b5f78c55 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 20 Dec 2019 23:13:24 -0800 Subject: [PATCH 26/89] More status handling fixes. --- homeassistant/components/totalconnect/binary_sensor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 9a6518e47f5bf4..a06f85efd00de2 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -91,9 +91,14 @@ def update(self): self._is_tampered = status == ZONE_STATUS_TAMPER self._is_low_battery = status == ZONE_STATUS_TROUBLE_LOW_BATTERY - if status in (ZONE_STATUS_NORMAL, ZONE_STATUS_BYPASSED): + if status in ( + ZONE_STATUS_NORMAL, + ZONE_STATUS_BYPASSED, + ZONE_STATUS_LOW_BATTERY, + ZONE_STATUS_TROUBLE_LOW_BATTERY, + ): self._state = False - elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED): + elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED, ZONE_STATUS_TAMPER): self._state = True else: self._state = False From ea1510fece482bad3b36aa5d54d93f5f03e8298c Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 20 Dec 2019 23:35:58 -0800 Subject: [PATCH 27/89] Fixed flake8 error --- .../totalconnect/alarm_control_panel.py | 21 +++++++------------ .../components/totalconnect/binary_sensor.py | 7 ++++++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 724ed6af36951b..1f6dec357f7a54 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -3,20 +3,13 @@ import homeassistant.components.alarm_control_panel as alarm from homeassistant.components.alarm_control_panel.const import ( - SUPPORT_ALARM_ARM_AWAY, - SUPPORT_ALARM_ARM_HOME, - SUPPORT_ALARM_ARM_NIGHT, -) -from homeassistant.const import ( - STATE_ALARM_ARMED_AWAY, - STATE_ALARM_ARMED_CUSTOM_BYPASS, - STATE_ALARM_ARMED_HOME, - STATE_ALARM_ARMED_NIGHT, - STATE_ALARM_ARMING, - STATE_ALARM_DISARMED, - STATE_ALARM_DISARMING, - STATE_ALARM_TRIGGERED, -) + SUPPORT_ALARM_ARM_AWAY, SUPPORT_ALARM_ARM_HOME, SUPPORT_ALARM_ARM_NIGHT) +from homeassistant.const import (STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_CUSTOM_BYPASS, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_NIGHT, STATE_ALARM_ARMING, + STATE_ALARM_DISARMED, STATE_ALARM_DISARMING, + STATE_ALARM_TRIGGERED) from . import DOMAIN as TOTALCONNECT_DOMAIN diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index a06f85efd00de2..e2888f047a77f8 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -9,6 +9,7 @@ ZONE_STATUS_BYPASSED, ZONE_STATUS_FAULT, ZONE_STATUS_TAMPER, + ZONE_STATUS_LOW_BATTERY, ZONE_STATUS_TROUBLE_LOW_BATTERY, ZONE_STATUS_TRIGGERED, ) @@ -98,7 +99,11 @@ def update(self): ZONE_STATUS_TROUBLE_LOW_BATTERY, ): self._state = False - elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED, ZONE_STATUS_TAMPER): + elif status in ( + ZONE_STATUS_FAULT, + ZONE_STATUS_TRIGGERED, + ZONE_STATUS_TAMPER + ): self._state = True else: self._state = False From 7f7ec1ca8c6d58677f59d4e204997eebeca67467 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 21 Dec 2019 08:30:04 -0800 Subject: [PATCH 28/89] Another attempt at black/isort fixes. --- .../components/totalconnect/binary_sensor.py | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index e2888f047a77f8..cd71ade155eda8 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -1,25 +1,15 @@ """Interfaces with TotalConnect sensors.""" import logging +from homeassistant.components.binary_sensor import (DEVICE_CLASS_DOOR, + DEVICE_CLASS_GAS, + DEVICE_CLASS_SMOKE, + BinarySensorDevice) from total_connect_client.TotalConnectClient import ( - ZONE_TYPE_SECURITY, - ZONE_TYPE_FIRE_SMOKE, - ZONE_TYPE_CARBON_MONOXIDE, - ZONE_STATUS_NORMAL, - ZONE_STATUS_BYPASSED, - ZONE_STATUS_FAULT, - ZONE_STATUS_TAMPER, - ZONE_STATUS_LOW_BATTERY, - ZONE_STATUS_TROUBLE_LOW_BATTERY, - ZONE_STATUS_TRIGGERED, -) - -from homeassistant.components.binary_sensor import ( - BinarySensorDevice, - DEVICE_CLASS_DOOR, - DEVICE_CLASS_SMOKE, - DEVICE_CLASS_GAS, -) + ZONE_STATUS_BYPASSED, ZONE_STATUS_FAULT, ZONE_STATUS_LOW_BATTERY, + ZONE_STATUS_NORMAL, ZONE_STATUS_TAMPER, ZONE_STATUS_TRIGGERED, + ZONE_STATUS_TROUBLE_LOW_BATTERY, ZONE_TYPE_CARBON_MONOXIDE, + ZONE_TYPE_FIRE_SMOKE, ZONE_TYPE_SECURITY) from . import DOMAIN as TOTALCONNECT_DOMAIN @@ -99,11 +89,7 @@ def update(self): ZONE_STATUS_TROUBLE_LOW_BATTERY, ): self._state = False - elif status in ( - ZONE_STATUS_FAULT, - ZONE_STATUS_TRIGGERED, - ZONE_STATUS_TAMPER - ): + elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED, ZONE_STATUS_TAMPER): self._state = True else: self._state = False From 4de1bcf63fdf3ea436db59541aef92a5148e2334 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 13 Jan 2020 22:21:52 -0800 Subject: [PATCH 29/89] Bump total-connect-client to 0.50. Simplify code using new functions in total-connect-client package instead of importing constants. Run black and isort. --- .../components/totalconnect/__init__.py | 2 +- .../totalconnect/alarm_control_panel.py | 21 ++++-- .../components/totalconnect/binary_sensor.py | 67 +++++++------------ .../components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- 5 files changed, 42 insertions(+), 52 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index d1a4f89c66ecac..e6cfbbc629aa26 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -19,7 +19,7 @@ vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, } - ), + ) }, extra=vol.ALLOW_EXTRA, ) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 1f6dec357f7a54..724ed6af36951b 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -3,13 +3,20 @@ import homeassistant.components.alarm_control_panel as alarm from homeassistant.components.alarm_control_panel.const import ( - SUPPORT_ALARM_ARM_AWAY, SUPPORT_ALARM_ARM_HOME, SUPPORT_ALARM_ARM_NIGHT) -from homeassistant.const import (STATE_ALARM_ARMED_AWAY, - STATE_ALARM_ARMED_CUSTOM_BYPASS, - STATE_ALARM_ARMED_HOME, - STATE_ALARM_ARMED_NIGHT, STATE_ALARM_ARMING, - STATE_ALARM_DISARMED, STATE_ALARM_DISARMING, - STATE_ALARM_TRIGGERED) + SUPPORT_ALARM_ARM_AWAY, + SUPPORT_ALARM_ARM_HOME, + SUPPORT_ALARM_ARM_NIGHT, +) +from homeassistant.const import ( + STATE_ALARM_ARMED_AWAY, + STATE_ALARM_ARMED_CUSTOM_BYPASS, + STATE_ALARM_ARMED_HOME, + STATE_ALARM_ARMED_NIGHT, + STATE_ALARM_ARMING, + STATE_ALARM_DISARMED, + STATE_ALARM_DISARMING, + STATE_ALARM_TRIGGERED, +) from . import DOMAIN as TOTALCONNECT_DOMAIN diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index cd71ade155eda8..cbbce5a253f27e 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -1,27 +1,17 @@ """Interfaces with TotalConnect sensors.""" import logging -from homeassistant.components.binary_sensor import (DEVICE_CLASS_DOOR, - DEVICE_CLASS_GAS, - DEVICE_CLASS_SMOKE, - BinarySensorDevice) -from total_connect_client.TotalConnectClient import ( - ZONE_STATUS_BYPASSED, ZONE_STATUS_FAULT, ZONE_STATUS_LOW_BATTERY, - ZONE_STATUS_NORMAL, ZONE_STATUS_TAMPER, ZONE_STATUS_TRIGGERED, - ZONE_STATUS_TROUBLE_LOW_BATTERY, ZONE_TYPE_CARBON_MONOXIDE, - ZONE_TYPE_FIRE_SMOKE, ZONE_TYPE_SECURITY) +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_DOOR, + DEVICE_CLASS_GAS, + DEVICE_CLASS_SMOKE, + BinarySensorDevice, +) from . import DOMAIN as TOTALCONNECT_DOMAIN _LOGGER = logging.getLogger(__name__) -# total_connect zone types mapped to binary_sensor class -SENSOR_TYPES = { - ZONE_TYPE_SECURITY: DEVICE_CLASS_DOOR, - ZONE_TYPE_FIRE_SMOKE: DEVICE_CLASS_SMOKE, - ZONE_TYPE_CARBON_MONOXIDE: DEVICE_CLASS_GAS, -} - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a TotalConnect device.""" @@ -45,18 +35,13 @@ def __init__(self, zone_id, location_id, locations): """Initialize the TotalConnect status.""" self._zone_id = zone_id self._location_id = location_id - self._locations = locations self._name = "TC {} zone {}".format( locations[location_id].location_name, zone_id ) - self._state = locations[location_id].zones[zone_id].status self._unique_id = "TC {} zone {}".format( locations[location_id].location_name, zone_id ) - self._device_class = locations[location_id].zones[zone_id].zone_type_id - self._is_low_battery = False - self._is_tampered = False - self._is_on = False + self._zone = locations[location_id].zones[zone_id] self.update() @property @@ -76,28 +61,14 @@ def state(self): def update(self): """Return the state of the device.""" - status = self._locations[self._location_id].zones[self._zone_id].status - - self._is_on = not status == ZONE_STATUS_BYPASSED - self._is_tampered = status == ZONE_STATUS_TAMPER - self._is_low_battery = status == ZONE_STATUS_TROUBLE_LOW_BATTERY - - if status in ( - ZONE_STATUS_NORMAL, - ZONE_STATUS_BYPASSED, - ZONE_STATUS_LOW_BATTERY, - ZONE_STATUS_TROUBLE_LOW_BATTERY, - ): - self._state = False - elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED, ZONE_STATUS_TAMPER): + self._is_on = not self._zone.is_bypassed() + self._is_tampered = self._zone.is_tampered() + self._is_low_battery = self._zone.is_low_battery() + + if self._zone.is_faulted() or self._zone.is_triggered(): self._state = True else: self._state = False - _LOGGER.info( - "Unknown Total Connect zone status %s returned by zone %s.", - status, - self._zone_id, - ) @property def is_on(self): @@ -107,7 +78,19 @@ def is_on(self): @property def device_class(self): """Return the class of this device, from component DEVICE_CLASSES.""" - return SENSOR_TYPES.get(self._device_class) + if self._zone.is_type_security(): + return DEVICE_CLASS_DOOR + elif self._zone.is_type_fire(): + return DEVICE_CLASS_SMOKE + elif self._zone.is_type_carbon_monoxide(): + return DEVICE_CLASS_GAS + else: + _LOGGER.info( + "Unknown Total Connect zone type %s returned by zone %s.", + self._zone.zone_type_id, + self._zone_id, + ) + return None @property def device_state_attributes(self): diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index cdd003b769e5ab..8863a7fb8cf2f6 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -3,7 +3,7 @@ "name": "Totalconnect", "documentation": "https://www.home-assistant.io/components/totalconnect", "requirements": [ - "total_connect_client==0.30" + "total_connect_client==0.50" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index 995d866e2dcc70..c5619063260ce3 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1952,7 +1952,7 @@ todoist-python==8.0.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.30 +total_connect_client==0.50 # homeassistant.components.tplink_lte tp-connected==0.0.4 From b66ba1fb6f850e38f00f60fa8b5f15c4f3a7f6a7 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 13 Jan 2020 22:27:46 -0800 Subject: [PATCH 30/89] Fix manifest file --- homeassistant/components/totalconnect/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 8863a7fb8cf2f6..757012f5b675ca 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -1,7 +1,7 @@ { "domain": "totalconnect", "name": "Totalconnect", - "documentation": "https://www.home-assistant.io/components/totalconnect", + "documentation": "https://www.home-assistant.io/integrations/totalconnect", "requirements": [ "total_connect_client==0.50" ], From 4027382fafd20c0d4a45b181a064f792ff25614f Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 13 Jan 2020 22:33:18 -0800 Subject: [PATCH 31/89] Another manifest fix --- homeassistant/components/totalconnect/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 757012f5b675ca..1ab1e4d265f4e5 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -1,6 +1,6 @@ { "domain": "totalconnect", - "name": "Totalconnect", + "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", "requirements": [ "total_connect_client==0.50" From 656e88daeeeadfa3d68bcd65f4b44ec4579cf12a Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 13 Jan 2020 22:34:56 -0800 Subject: [PATCH 32/89] one more manifest fix --- homeassistant/components/totalconnect/manifest.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 1ab1e4d265f4e5..967115e721a26a 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -2,11 +2,7 @@ "domain": "totalconnect", "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", - "requirements": [ - "total_connect_client==0.50" - ], + "requirements": ["total_connect_client==0.50"], "dependencies": [], - "codeowners": [ - "@austinmroczek" - ] + "codeowners": ["@austinmroczek"] } From eca1045d7bf6778963ec9d6fc00745338029cfb6 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 13 Jan 2020 22:41:03 -0800 Subject: [PATCH 33/89] more manifest changes. --- homeassistant/components/totalconnect/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 967115e721a26a..2c75dd2863c07f 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -5,4 +5,4 @@ "requirements": ["total_connect_client==0.50"], "dependencies": [], "codeowners": ["@austinmroczek"] -} +} \ No newline at end of file From 750fc0beea2181de15ffad7981a3d26c1cc3b185 Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Wed, 15 Jan 2020 04:01:50 +0000 Subject: [PATCH 34/89] sync up --- .../components/totalconnect/__init__.py | 2 +- .../components/totalconnect/binary_sensor.py | 57 +++++++------------ .../components/totalconnect/manifest.json | 12 ++-- 3 files changed, 25 insertions(+), 46 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index d1a4f89c66ecac..e6cfbbc629aa26 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -19,7 +19,7 @@ vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, } - ), + ) }, extra=vol.ALLOW_EXTRA, ) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 860d30899a8cf8..cbbce5a253f27e 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -1,36 +1,17 @@ """Interfaces with TotalConnect sensors.""" import logging -from total_connect_client.TotalConnectClient import ( - ZONE_TYPE_SECURITY, - ZONE_TYPE_FIRE_SMOKE, - ZONE_TYPE_CARBON_MONOXIDE, - ZONE_STATUS_NORMAL, - ZONE_STATUS_BYPASSED, - ZONE_STATUS_FAULT, - ZONE_STATUS_TAMPER, - ZONE_STATUS_TROUBLE_LOW_BATTERY, - ZONE_STATUS_TRIGGERED, -) - from homeassistant.components.binary_sensor import ( - BinarySensorDevice, DEVICE_CLASS_DOOR, - DEVICE_CLASS_SMOKE, DEVICE_CLASS_GAS, + DEVICE_CLASS_SMOKE, + BinarySensorDevice, ) from . import DOMAIN as TOTALCONNECT_DOMAIN _LOGGER = logging.getLogger(__name__) -# total_connect zone types mapped to binary_sensor class -SENSOR_TYPES = { - ZONE_TYPE_SECURITY: DEVICE_CLASS_DOOR, - ZONE_TYPE_FIRE_SMOKE: DEVICE_CLASS_SMOKE, - ZONE_TYPE_CARBON_MONOXIDE: DEVICE_CLASS_GAS, -} - def setup_platform(hass, config, add_entities, discovery_info=None): """Set up a sensor for a TotalConnect device.""" @@ -54,18 +35,13 @@ def __init__(self, zone_id, location_id, locations): """Initialize the TotalConnect status.""" self._zone_id = zone_id self._location_id = location_id - self._locations = locations self._name = "TC {} zone {}".format( locations[location_id].location_name, zone_id ) - self._state = locations[location_id].zones[zone_id].status self._unique_id = "TC {} zone {}".format( locations[location_id].location_name, zone_id ) - self._device_class = locations[location_id].zones[zone_id].zone_type_id - self._is_low_battery = False - self._is_tampered = False - self._is_on = False + self._zone = locations[location_id].zones[zone_id] self.update() @property @@ -85,19 +61,14 @@ def state(self): def update(self): """Return the state of the device.""" - status = self._locations[self._location_id].zones[self._zone_id].status - - self._is_on = not status == ZONE_STATUS_BYPASSED - self._is_tampered = status == ZONE_STATUS_TAMPER - self._is_low_battery = status == ZONE_STATUS_TROUBLE_LOW_BATTERY + self._is_on = not self._zone.is_bypassed() + self._is_tampered = self._zone.is_tampered() + self._is_low_battery = self._zone.is_low_battery() - if status == ZONE_STATUS_NORMAL: - self._state = False - elif status in (ZONE_STATUS_FAULT, ZONE_STATUS_TRIGGERED): + if self._zone.is_faulted() or self._zone.is_triggered(): self._state = True else: self._state = False - _LOGGER.info("Unknown Total Connect zone status %s returned.", status) @property def is_on(self): @@ -107,7 +78,19 @@ def is_on(self): @property def device_class(self): """Return the class of this device, from component DEVICE_CLASSES.""" - return SENSOR_TYPES.get(self._device_class) + if self._zone.is_type_security(): + return DEVICE_CLASS_DOOR + elif self._zone.is_type_fire(): + return DEVICE_CLASS_SMOKE + elif self._zone.is_type_carbon_monoxide(): + return DEVICE_CLASS_GAS + else: + _LOGGER.info( + "Unknown Total Connect zone type %s returned by zone %s.", + self._zone.zone_type_id, + self._zone_id, + ) + return None @property def device_state_attributes(self): diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index cdd003b769e5ab..967115e721a26a 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -1,12 +1,8 @@ { "domain": "totalconnect", - "name": "Totalconnect", - "documentation": "https://www.home-assistant.io/components/totalconnect", - "requirements": [ - "total_connect_client==0.30" - ], + "name": "Honeywell Total Connect Alarm", + "documentation": "https://www.home-assistant.io/integrations/totalconnect", + "requirements": ["total_connect_client==0.50"], "dependencies": [], - "codeowners": [ - "@austinmroczek" - ] + "codeowners": ["@austinmroczek"] } From 25f530b1f992d3adf681e1db20d56a5719b69b1f Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Fri, 17 Jan 2020 04:04:57 +0000 Subject: [PATCH 35/89] fix indent --- homeassistant/components/totalconnect/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index cbbce5a253f27e..aed9e248975f5d 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -90,7 +90,7 @@ def device_class(self): self._zone.zone_type_id, self._zone_id, ) - return None + return None @property def device_state_attributes(self): From d9700f8ef5943545d01a6e4563077bf8cb8e9b0d Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Fri, 17 Jan 2020 19:21:28 +0000 Subject: [PATCH 36/89] one more pylint fix --- .../components/totalconnect/binary_sensor.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index aed9e248975f5d..902b0c05dff0e7 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -84,13 +84,12 @@ def device_class(self): return DEVICE_CLASS_SMOKE elif self._zone.is_type_carbon_monoxide(): return DEVICE_CLASS_GAS - else: - _LOGGER.info( - "Unknown Total Connect zone type %s returned by zone %s.", - self._zone.zone_type_id, - self._zone_id, - ) - return None + _LOGGER.info( + "Unknown Total Connect zone type %s returned by zone %s.", + self._zone.zone_type_id, + self._zone_id, + ) + return None @property def device_state_attributes(self): From 81f4cef1b1ba91ff40f6f2f63ef83f84636d0f3a Mon Sep 17 00:00:00 2001 From: austinmroczek Date: Fri, 17 Jan 2020 21:30:33 +0000 Subject: [PATCH 37/89] Hopefully the last pylint fix --- homeassistant/components/totalconnect/binary_sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 902b0c05dff0e7..a380942101a472 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -80,9 +80,9 @@ def device_class(self): """Return the class of this device, from component DEVICE_CLASSES.""" if self._zone.is_type_security(): return DEVICE_CLASS_DOOR - elif self._zone.is_type_fire(): + if self._zone.is_type_fire(): return DEVICE_CLASS_SMOKE - elif self._zone.is_type_carbon_monoxide(): + if self._zone.is_type_carbon_monoxide(): return DEVICE_CLASS_GAS _LOGGER.info( "Unknown Total Connect zone type %s returned by zone %s.", From 6f0e7792c84e9230aabaac84ee10abfe791469bc Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 18 Jan 2020 12:56:41 -0800 Subject: [PATCH 38/89] make variable names understandable --- homeassistant/components/totalconnect/binary_sensor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index a380942101a472..ebe25f1b4c5a6a 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -22,9 +22,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client_locations = hass.data[TOTALCONNECT_DOMAIN].client.locations - for k in client_locations: - for zone in client_locations[k].zones: - sensors.append(TotalConnectBinarySensor(zone, k, client_locations)) + for location_id in client_locations: + for zone in client_locations[location_id].zones: + sensors.append(TotalConnectBinarySensor(zone, location_id, client_locations)) add_entities(sensors) From c654941756c893b3030410437e8fde0ee288f819 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 18 Jan 2020 13:02:08 -0800 Subject: [PATCH 39/89] create and fill dict in one step --- .../components/totalconnect/binary_sensor.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index ebe25f1b4c5a6a..6a8533e061a689 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -94,10 +94,11 @@ def device_class(self): @property def device_state_attributes(self): """Return the state attributes.""" - attributes = {} - attributes["zone_id"] = self._zone_id - attributes["zone_description"] = self._name - attributes["location_id"] = self._location_id - attributes["low_battery"] = self._is_low_battery - attributes["tampered"] = self._is_tampered + attributes = { + "zone_id": self._zone_id, + "zone_description": self._name, + "location_id": self._location_id, + "low_battery": self._is_low_battery, + "tampered": self._is_tampered + } return attributes From 1c32671f283e605de1dca4ecd63b1e42fb8709da Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 18 Jan 2020 13:30:36 -0800 Subject: [PATCH 40/89] Fix name and attributes --- .../components/totalconnect/binary_sensor.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 6a8533e061a689..73e86399cb38e1 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -24,7 +24,9 @@ def setup_platform(hass, config, add_entities, discovery_info=None): for location_id in client_locations: for zone in client_locations[location_id].zones: - sensors.append(TotalConnectBinarySensor(zone, location_id, client_locations)) + sensors.append( + TotalConnectBinarySensor(zone, location_id, client_locations) + ) add_entities(sensors) @@ -35,13 +37,9 @@ def __init__(self, zone_id, location_id, locations): """Initialize the TotalConnect status.""" self._zone_id = zone_id self._location_id = location_id - self._name = "TC {} zone {}".format( - locations[location_id].location_name, zone_id - ) - self._unique_id = "TC {} zone {}".format( - locations[location_id].location_name, zone_id - ) self._zone = locations[location_id].zones[zone_id] + self._name = self._zone.description + self._unique_id = "TC Location {} zone {}".format(location_id, zone_id) self.update() @property @@ -96,9 +94,8 @@ def device_state_attributes(self): """Return the state attributes.""" attributes = { "zone_id": self._zone_id, - "zone_description": self._name, "location_id": self._location_id, "low_battery": self._is_low_battery, - "tampered": self._is_tampered + "tampered": self._is_tampered, } return attributes From 35d30850c9be2202e8d6c88316ae0d8c10f413a6 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 18 Jan 2020 14:47:29 -0800 Subject: [PATCH 41/89] rename to logical variable in alarm_control_panel --- .../components/totalconnect/alarm_control_panel.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 99112e8176a6b6..1ae2eee3588b34 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -32,8 +32,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client = hass.data[TOTALCONNECT_DOMAIN].client - for k in client.locations: - alarms.append(TotalConnectAlarm(client.locations[k].location_name, k, client)) + for location_id in client.locations: + alarms.append( + TotalConnectAlarm( + client.locations[location_id].location_name, location_id, client + ) + ) add_entities(alarms) From c9b208de65ac17165f2196d9641c1a7ddf9ce7c9 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 18 Jan 2020 17:04:39 -0800 Subject: [PATCH 42/89] Remove location_name from alarm_control_panel attributes since it is already the name of the alarm. --- homeassistant/components/totalconnect/alarm_control_panel.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 1ae2eee3588b34..1018a9bcaafe8d 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -76,7 +76,6 @@ def update(self): """Return the state of the device.""" status = self._client.get_armed_status(self._location_id) attr = { - "location_name": self._client.locations[self._location_id].location_name, "location_id": self._location_id, "ac_loss": self._client.locations[self._location_id].ac_loss, "low_battery": self._client.locations[self._location_id].low_battery, From 10b555ef6979c85258600ae5b200801e09b3ba06 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 18 Jan 2020 17:33:24 -0800 Subject: [PATCH 43/89] Multiple fixes to improve code per @springstan suggestions --- .../totalconnect/alarm_control_panel.py | 7 ++----- .../components/totalconnect/binary_sensor.py | 16 +++++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 1018a9bcaafe8d..eecf7d34655fdb 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -33,11 +33,8 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client = hass.data[TOTALCONNECT_DOMAIN].client for location_id in client.locations: - alarms.append( - TotalConnectAlarm( - client.locations[location_id].location_name, location_id, client - ) - ) + location_name = client.locations[location_id].location_name + alarms.append(TotalConnectAlarm(location_name, location_id, client)) add_entities(alarms) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 73e86399cb38e1..f655ed87e28551 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -23,27 +23,29 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client_locations = hass.data[TOTALCONNECT_DOMAIN].client.locations for location_id in client_locations: - for zone in client_locations[location_id].zones: - sensors.append( - TotalConnectBinarySensor(zone, location_id, client_locations) - ) + for zone_id in client_locations[location_id].zones: + zone = client_locations[location_id].zones[zone_id] + sensors.append(TotalConnectBinarySensor(zone_id, location_id, zone)) add_entities(sensors) class TotalConnectBinarySensor(BinarySensorDevice): """Represent an TotalConnect zone.""" - def __init__(self, zone_id, location_id, locations): + def __init__(self, zone_id, location_id, zone): """Initialize the TotalConnect status.""" self._zone_id = zone_id self._location_id = location_id - self._zone = locations[location_id].zones[zone_id] + self._zone = zone self._name = self._zone.description self._unique_id = "TC Location {} zone {}".format(location_id, zone_id) + self._is_on = None + self._is_tampered = None + self._is_low_battery = None self.update() @property - def unique_id(self) -> str: + def unique_id(self): """Return the unique id.""" return self._unique_id From 19b0c63233680626fbb33b7617e9e72d0d117358 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Tue, 21 Jan 2020 21:49:20 -0800 Subject: [PATCH 44/89] Update homeassistant/components/totalconnect/binary_sensor.py Co-Authored-By: springstan <46536646+springstan@users.noreply.github.com> --- homeassistant/components/totalconnect/binary_sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index f655ed87e28551..97225435e1a103 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -84,7 +84,7 @@ def device_class(self): return DEVICE_CLASS_SMOKE if self._zone.is_type_carbon_monoxide(): return DEVICE_CLASS_GAS - _LOGGER.info( + _LOGGER.warning( "Unknown Total Connect zone type %s returned by zone %s.", self._zone.zone_type_id, self._zone_id, From 471b01ad0868dcf32d2f0d2af636c15077b83b2d Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 30 Jan 2020 22:21:33 -0800 Subject: [PATCH 45/89] Multiple changes per @MartinHjelmare review --- .../totalconnect/alarm_control_panel.py | 1 + .../components/totalconnect/binary_sensor.py | 15 ++++----------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index eecf7d34655fdb..fe78a6aae4e741 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -73,6 +73,7 @@ def update(self): """Return the state of the device.""" status = self._client.get_armed_status(self._location_id) attr = { + "location_name": self._name, "location_id": self._location_id, "ac_loss": self._client.locations[self._location_id].ac_loss, "low_battery": self._client.locations[self._location_id].low_battery, diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 97225435e1a103..030de0e6733f7c 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -22,11 +22,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client_locations = hass.data[TOTALCONNECT_DOMAIN].client.locations - for location_id in client_locations: - for zone_id in client_locations[location_id].zones: - zone = client_locations[location_id].zones[zone_id] + for location_id, location in client_locations.items(): + for zone_id, zone in location.zones.items(): sensors.append(TotalConnectBinarySensor(zone_id, location_id, zone)) - add_entities(sensors) + add_entities(sensors, True) class TotalConnectBinarySensor(BinarySensorDevice): @@ -38,11 +37,10 @@ def __init__(self, zone_id, location_id, zone): self._location_id = location_id self._zone = zone self._name = self._zone.description - self._unique_id = "TC Location {} zone {}".format(location_id, zone_id) + self._unique_id = f"TC {location_id} {zone_id}" self._is_on = None self._is_tampered = None self._is_low_battery = None - self.update() @property def unique_id(self): @@ -84,11 +82,6 @@ def device_class(self): return DEVICE_CLASS_SMOKE if self._zone.is_type_carbon_monoxide(): return DEVICE_CLASS_GAS - _LOGGER.warning( - "Unknown Total Connect zone type %s returned by zone %s.", - self._zone.zone_type_id, - self._zone_id, - ) return None @property From ef0645360293c5ec9100bf5b4404d8ad6438fca8 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 30 Jan 2020 22:28:49 -0800 Subject: [PATCH 46/89] simplify alarm adding --- homeassistant/components/totalconnect/alarm_control_panel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index fe78a6aae4e741..b255132a36582c 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -32,8 +32,8 @@ def setup_platform(hass, config, add_entities, discovery_info=None): client = hass.data[TOTALCONNECT_DOMAIN].client - for location_id in client.locations: - location_name = client.locations[location_id].location_name + for location_id, location in client.locations.items(): + location_name = location.location_name alarms.append(TotalConnectAlarm(location_name, location_id, client)) add_entities(alarms) From 0c1234e434797c372fefd21f0e3adbdd3a13456f Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 31 Jan 2020 11:28:05 -0800 Subject: [PATCH 47/89] Fix binary_sensor.py is_on --- .../components/totalconnect/binary_sensor.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 030de0e6733f7c..28bd58cfff88b2 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -37,7 +37,7 @@ def __init__(self, zone_id, location_id, zone): self._location_id = location_id self._zone = zone self._name = self._zone.description - self._unique_id = f"TC {location_id} {zone_id}" + self._unique_id = f"{location_id} {zone_id}" self._is_on = None self._is_tampered = None self._is_low_battery = None @@ -52,21 +52,15 @@ def name(self): """Return the name of the device.""" return self._name - @property - def state(self): - """Return the state of the device.""" - return self._state - def update(self): """Return the state of the device.""" - self._is_on = not self._zone.is_bypassed() self._is_tampered = self._zone.is_tampered() self._is_low_battery = self._zone.is_low_battery() if self._zone.is_faulted() or self._zone.is_triggered(): - self._state = True + self._is_on = True else: - self._state = False + self._is_on = False @property def is_on(self): From f9e6a69580868dd59dc2dd3860a24f0f925edf4e Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 14 Feb 2020 16:33:57 -0800 Subject: [PATCH 48/89] Move DOMAIN to .const in line with examples. --- homeassistant/components/totalconnect/__init__.py | 8 ++++---- .../components/totalconnect/alarm_control_panel.py | 4 ++-- homeassistant/components/totalconnect/binary_sensor.py | 4 ++-- homeassistant/components/totalconnect/const.py | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 homeassistant/components/totalconnect/const.py diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index e6cfbbc629aa26..f8f9a857a67ce3 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -1,16 +1,16 @@ """The totalconnect component.""" import logging -from total_connect_client import TotalConnectClient +import homeassistant.helpers.config_validation as cv import voluptuous as vol - from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.helpers import discovery -import homeassistant.helpers.config_validation as cv +from total_connect_client import TotalConnectClient + +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -DOMAIN = "totalconnect" CONFIG_SCHEMA = vol.Schema( { diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index b255132a36582c..0d4ab54c70c72a 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -18,7 +18,7 @@ STATE_ALARM_TRIGGERED, ) -from . import DOMAIN as TOTALCONNECT_DOMAIN +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) @@ -30,7 +30,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): alarms = [] - client = hass.data[TOTALCONNECT_DOMAIN].client + client = hass.data[DOMAIN].client for location_id, location in client.locations.items(): location_name = location.location_name diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 28bd58cfff88b2..6b54f989589ded 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -8,7 +8,7 @@ BinarySensorDevice, ) -from . import DOMAIN as TOTALCONNECT_DOMAIN +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) @@ -20,7 +20,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): sensors = [] - client_locations = hass.data[TOTALCONNECT_DOMAIN].client.locations + client_locations = hass.data[DOMAIN].client.locations for location_id, location in client_locations.items(): for zone_id, zone in location.zones.items(): diff --git a/homeassistant/components/totalconnect/const.py b/homeassistant/components/totalconnect/const.py new file mode 100644 index 00000000000000..b83cf170ec109d --- /dev/null +++ b/homeassistant/components/totalconnect/const.py @@ -0,0 +1 @@ +DOMAIN = "totalconnect" From 464f3f827b8afa1d6da559b1c7dbb7291b8de763 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 14 Feb 2020 17:01:35 -0800 Subject: [PATCH 49/89] Move to async_setup --- homeassistant/components/totalconnect/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index f8f9a857a67ce3..b9d7ffeca6fd96 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -1,9 +1,12 @@ """The totalconnect component.""" +import asyncio import logging import homeassistant.helpers.config_validation as cv import voluptuous as vol +from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.core import HomeAssistant from homeassistant.helpers import discovery from total_connect_client import TotalConnectClient @@ -24,10 +27,10 @@ extra=vol.ALLOW_EXTRA, ) -TOTALCONNECT_PLATFORMS = ["alarm_control_panel", "binary_sensor"] +PLATFORMS = ["alarm_control_panel", "binary_sensor"] -def setup(hass, config): +async def async_setup(hass: HomeAssistant, config: dict): """Set up TotalConnect component.""" conf = config[DOMAIN] @@ -42,7 +45,7 @@ def setup(hass, config): hass.data[DOMAIN] = TotalConnectSystem(username, password, client) - for platform in TOTALCONNECT_PLATFORMS: + for platform in PLATFORMS: discovery.load_platform(hass, platform, DOMAIN, {}, config) return True From 28f4bd41a4576242d2123b3dcbd2879027ee9842 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 15 Feb 2020 20:24:12 -0800 Subject: [PATCH 50/89] Simplify code using new features of total-connect-client 0.51 --- .../totalconnect/alarm_control_panel.py | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 0d4ab54c70c72a..9c62221fc99e8d 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -71,7 +71,7 @@ def device_state_attributes(self): def update(self): """Return the state of the device.""" - status = self._client.get_armed_status(self._location_id) + self._client.get_armed_status(self._location_id) attr = { "location_name": self._name, "location_id": self._location_id, @@ -84,42 +84,31 @@ def update(self): "triggered_zone": None, } - if status in (self._client.DISARMED, self._client.DISARMED_BYPASS): + if self._client.locations[self._location_id].is_disarmed(): state = STATE_ALARM_DISARMED - elif status in ( - self._client.ARMED_STAY, - self._client.ARMED_STAY_INSTANT, - self._client.ARMED_STAY_INSTANT_BYPASS, - ): + elif self._client.locations[self._location_id].is_armed_home(): state = STATE_ALARM_ARMED_HOME - elif status == self._client.ARMED_STAY_NIGHT: + elif self._client.locations[self._location_id].is_armed_night(): state = STATE_ALARM_ARMED_NIGHT - elif status in ( - self._client.ARMED_AWAY, - self._client.ARMED_AWAY_BYPASS, - self._client.ARMED_AWAY_INSTANT, - self._client.ARMED_AWAY_INSTANT_BYPASS, - ): + elif self._client.locations[self._location_id].is_armed_away(): state = STATE_ALARM_ARMED_AWAY - elif status == self._client.ARMED_CUSTOM_BYPASS: + elif self._client.locations[self._location_id].is_armed_custom_bypass(): state = STATE_ALARM_ARMED_CUSTOM_BYPASS - elif status == self._client.ARMING: + elif self._client.locations[self._location_id].is_arming(): state = STATE_ALARM_ARMING - elif status == self._client.DISARMING: + elif self._client.locations[self._location_id].is_disarming(): state = STATE_ALARM_DISARMING - elif status == self._client.ALARMING: + elif self._client.locations[self._location_id].is_triggered_police(): state = STATE_ALARM_TRIGGERED attr["triggered_source"] = "Police/Medical" - elif status == self._client.ALARMING_FIRE_SMOKE: + elif self._client.locations[self._location_id].is_triggered_fire(): state = STATE_ALARM_TRIGGERED attr["triggered_source"] = "Fire/Smoke" - elif status == self._client.ALARMING_CARBON_MONOXIDE: + elif self._client.locations[self._location_id].is_triggered_gas(): state = STATE_ALARM_TRIGGERED attr["triggered_source"] = "Carbon Monoxide" else: - logging.info( - "Total Connect Client returned unknown status code: %s", status - ) + logging.info("Total Connect Client returned unknown status.") state = None self._state = state From d3c8d24117402bbeaeede1d664640019431defe8 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 17 Feb 2020 15:59:34 -0800 Subject: [PATCH 51/89] First crack at config flow for totalconnect --- .../components/totalconnect/__init__.py | 42 ++++++++++++-- .../totalconnect/alarm_control_panel.py | 2 +- .../components/totalconnect/config_flow.py | 57 +++++++++++++++++++ .../components/totalconnect/manifest.json | 5 +- .../components/totalconnect/strings.json | 20 +++++++ 5 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 homeassistant/components/totalconnect/config_flow.py create mode 100644 homeassistant/components/totalconnect/strings.json diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index b9d7ffeca6fd96..b3ddd5b17f61bc 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -10,6 +10,8 @@ from homeassistant.helpers import discovery from total_connect_client import TotalConnectClient +from pprint import pprint + from .const import DOMAIN _LOGGER = logging.getLogger(__name__) @@ -31,12 +33,35 @@ async def async_setup(hass: HomeAssistant, config: dict): - """Set up TotalConnect component.""" - conf = config[DOMAIN] + """Setup from existing/saved configuration.""" + conf = config.get(DOMAIN) + if conf is None: + return True + + username = conf.get(CONF_USERNAME) + password = conf.get(CONF_PASSWORD) + client = TotalConnectClient.TotalConnectClient(username, password) + + if client.token is False: + _LOGGER.error("TotalConnect authentication failed") + return False + + hass.data[DOMAIN] = TotalConnectSystem(username, password, client) + + for platform in PLATFORMS: + hass.async_create_task(discovery.async_load_platform(hass, platform, DOMAIN, {}, config)) + + return True - username = conf[CONF_USERNAME] - password = conf[CONF_PASSWORD] +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): + """Setup upon config entry in user interface.""" + + _LOGGER.info("TotalConnect async_setup_entry") + + conf = entry.data + username = conf.get(CONF_USERNAME) + password = conf.get(CONF_PASSWORD) client = TotalConnectClient.TotalConnectClient(username, password) if client.token is False: @@ -46,11 +71,18 @@ async def async_setup(hass: HomeAssistant, config: dict): hass.data[DOMAIN] = TotalConnectSystem(username, password, client) for platform in PLATFORMS: - discovery.load_platform(hass, platform, DOMAIN, {}, config) + hass.async_create_task(discovery.async_load_platform(hass, platform, DOMAIN, {}, entry)) + + #Pretty sure we don't do this because the component itself doesn't need the configuration data +# for component in PLATFORMS: +# hass.async_create_task( +# hass.config_entries.async_forward_entry_setup(entry, component) +# ) return True + class TotalConnectSystem: """TotalConnect System class.""" diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 9c62221fc99e8d..eccf69fef19a2a 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -79,7 +79,7 @@ def update(self): "low_battery": self._client.locations[self._location_id].low_battery, "cover_tampered": self._client.locations[ self._location_id - ].is_cover_tampered, + ].is_cover_tampered(), "triggered_source": None, "triggered_zone": None, } diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py new file mode 100644 index 00000000000000..18b24e57557fd4 --- /dev/null +++ b/homeassistant/components/totalconnect/config_flow.py @@ -0,0 +1,57 @@ +"""Config flow for the Total Connect component.""" +import logging + +import voluptuous as vol +from homeassistant import config_entries +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from total_connect_client import TotalConnectClient + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + + +@config_entries.HANDLERS.register(DOMAIN) +class TotalConnectConfigFlow(config_entries.ConfigFlow): + """Total Connect config flow.""" + + VERSION = 1 + + async def async_step_user(self, user_input=None): + """Handle a flow initiated by the user.""" + errors = {} + + if user_input is not None: + # Validate user input + username = user_input.get(CONF_USERNAME) + password = user_input.get(CONF_PASSWORD) + + await self.async_set_unique_id(username) + self._abort_if_unique_id_configured() + + valid = await self.is_valid(username, password) + + if valid: + # authentication success / valid + return self.async_create_entry( + title="Total Connect", + data={"Username": username, "Password": password}, + ) + # authentication failed / invalid + errors["base"] = "login" + + data_schema=vol.Schema( + { + vol.Required(CONF_USERNAME): str, + vol.Required(CONF_PASSWORD): str, + } + ) + + return self.async_show_form( + step_id="user", data_schema=data_schema, errors=errors + ) + + async def is_valid(self, username="", password=""): + """Return true if the given username and password are valid.""" + client = TotalConnectClient.TotalConnectClient(username, password) + return client.token is not False diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 967115e721a26a..4023e22a97b9bd 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -2,7 +2,8 @@ "domain": "totalconnect", "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", - "requirements": ["total_connect_client==0.50"], + "requirements": ["total_connect_client==0.51"], "dependencies": [], - "codeowners": ["@austinmroczek"] + "codeowners": ["@austinmroczek"], + "config_flow": true } diff --git a/homeassistant/components/totalconnect/strings.json b/homeassistant/components/totalconnect/strings.json new file mode 100644 index 00000000000000..eb4d9badb39f60 --- /dev/null +++ b/homeassistant/components/totalconnect/strings.json @@ -0,0 +1,20 @@ +{ + "config": { + "title": "Total Connect", + "step": { + "user": { + "title": "Fill in your Total Connect login information", + "data": { + "username": "Username", + "password": "Password" + } + } + }, + "error": { + "login": "Login error: please check your username & password" + }, + "abort": { + "already_configured": "Account already configured" + } + } +} \ No newline at end of file From c7985496984eb7b16c458e4538cd42f4176c55e4 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Wed, 19 Feb 2020 21:42:20 -0800 Subject: [PATCH 52/89] bump totalconnect to 0.52 --- homeassistant/components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 4023e22a97b9bd..a350ebba7cc842 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -2,7 +2,7 @@ "domain": "totalconnect", "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", - "requirements": ["total_connect_client==0.51"], + "requirements": ["total_connect_client==0.52"], "dependencies": [], "codeowners": ["@austinmroczek"], "config_flow": true diff --git a/requirements_all.txt b/requirements_all.txt index e386e49e559648..a08d0b220972ba 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1989,7 +1989,7 @@ todoist-python==8.0.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.50 +total_connect_client==0.52 # homeassistant.components.tplink_lte tp-connected==0.0.4 From e37fb889dce5acf4ab26c1b0ba1a8edfa6bc743a Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Wed, 19 Feb 2020 21:46:52 -0800 Subject: [PATCH 53/89] use client.is_logged_in() to avoid total-connect-client details. --- homeassistant/components/totalconnect/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index b3ddd5b17f61bc..857f87a4174855 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -42,7 +42,7 @@ async def async_setup(hass: HomeAssistant, config: dict): password = conf.get(CONF_PASSWORD) client = TotalConnectClient.TotalConnectClient(username, password) - if client.token is False: + if not client.is_logged_in(): _LOGGER.error("TotalConnect authentication failed") return False @@ -64,7 +64,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): password = conf.get(CONF_PASSWORD) client = TotalConnectClient.TotalConnectClient(username, password) - if client.token is False: + if not client.is_logged_in(): _LOGGER.error("TotalConnect authentication failed") return False From 97590a079b17c1aaedcb2cb3372b6d8229378e58 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Wed, 19 Feb 2020 22:06:29 -0800 Subject: [PATCH 54/89] updated generated/config_flow.py --- homeassistant/generated/config_flows.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py index 39a9bccf607fb2..2b62b2be5881ef 100644 --- a/homeassistant/generated/config_flows.py +++ b/homeassistant/generated/config_flows.py @@ -91,6 +91,7 @@ "tellduslive", "tesla", "toon", + "totalconnect", "tplink", "traccar", "tradfri", From 6c192e4b2b88cec94b6aa88e4cfaa57ab17895e7 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Wed, 19 Feb 2020 22:29:07 -0800 Subject: [PATCH 55/89] use is_logged_in() --- .../components/totalconnect/config_flow.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 18b24e57557fd4..40a74f88b9365a 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -1,10 +1,11 @@ """Config flow for the Total Connect component.""" import logging +from total_connect_client import TotalConnectClient import voluptuous as vol + from homeassistant import config_entries from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from total_connect_client import TotalConnectClient from .const import DOMAIN @@ -30,7 +31,7 @@ async def async_step_user(self, user_input=None): self._abort_if_unique_id_configured() valid = await self.is_valid(username, password) - + if valid: # authentication success / valid return self.async_create_entry( @@ -40,11 +41,8 @@ async def async_step_user(self, user_input=None): # authentication failed / invalid errors["base"] = "login" - data_schema=vol.Schema( - { - vol.Required(CONF_USERNAME): str, - vol.Required(CONF_PASSWORD): str, - } + data_schema = vol.Schema( + {vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str} ) return self.async_show_form( @@ -54,4 +52,4 @@ async def async_step_user(self, user_input=None): async def is_valid(self, username="", password=""): """Return true if the given username and password are valid.""" client = TotalConnectClient.TotalConnectClient(username, password) - return client.token is not False + return client.is_logged_in() From 139c4f5f33bdb570dc317a979c00c5ce60c3c940 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 22 Feb 2020 11:17:58 -0800 Subject: [PATCH 56/89] Hopefully final touches for config flow --- .../totalconnect/.translations/en.json | 20 ++++++ .../components/totalconnect/__init__.py | 64 ++++++++++--------- .../totalconnect/alarm_control_panel.py | 14 ++-- .../components/totalconnect/binary_sensor.py | 14 ++-- .../components/totalconnect/config_flow.py | 8 ++- 5 files changed, 73 insertions(+), 47 deletions(-) create mode 100644 homeassistant/components/totalconnect/.translations/en.json diff --git a/homeassistant/components/totalconnect/.translations/en.json b/homeassistant/components/totalconnect/.translations/en.json new file mode 100644 index 00000000000000..5d56d45c97aacb --- /dev/null +++ b/homeassistant/components/totalconnect/.translations/en.json @@ -0,0 +1,20 @@ +{ + "config": { + "abort": { + "already_configured": "Account already configured" + }, + "error": { + "login": "Login error: please check your username & password" + }, + "step": { + "user": { + "data": { + "password": "Password", + "username": "Username" + }, + "title": "Fill in your Total Connect login information" + } + }, + "title": "Total Connect" + } +} \ No newline at end of file diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 857f87a4174855..7601ea31c24fb8 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -2,15 +2,13 @@ import asyncio import logging -import homeassistant.helpers.config_validation as cv +from total_connect_client import TotalConnectClient import voluptuous as vol -from homeassistant.config_entries import ConfigEntry + +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant -from homeassistant.helpers import discovery -from total_connect_client import TotalConnectClient - -from pprint import pprint +import homeassistant.helpers.config_validation as cv from .const import DOMAIN @@ -33,55 +31,59 @@ async def async_setup(hass: HomeAssistant, config: dict): - """Setup from existing/saved configuration.""" + """Set up from existing/saved configuration.""" conf = config.get(DOMAIN) if conf is None: return True - - username = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) - client = TotalConnectClient.TotalConnectClient(username, password) - - if not client.is_logged_in(): - _LOGGER.error("TotalConnect authentication failed") - return False - - hass.data[DOMAIN] = TotalConnectSystem(username, password, client) - for platform in PLATFORMS: - hass.async_create_task(discovery.async_load_platform(hass, platform, DOMAIN, {}, config)) + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=conf + ) + ) return True async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): - """Setup upon config entry in user interface.""" - - _LOGGER.info("TotalConnect async_setup_entry") + """Set up upon config entry in user interface.""" + hass.data.setdefault(DOMAIN, {}) conf = entry.data username = conf.get(CONF_USERNAME) password = conf.get(CONF_PASSWORD) + client = TotalConnectClient.TotalConnectClient(username, password) if not client.is_logged_in(): _LOGGER.error("TotalConnect authentication failed") return False - hass.data[DOMAIN] = TotalConnectSystem(username, password, client) + hass.data[DOMAIN][username] = TotalConnectSystem(username, password, client) - for platform in PLATFORMS: - hass.async_create_task(discovery.async_load_platform(hass, platform, DOMAIN, {}, entry)) - - #Pretty sure we don't do this because the component itself doesn't need the configuration data -# for component in PLATFORMS: -# hass.async_create_task( -# hass.config_entries.async_forward_entry_setup(entry, component) -# ) + for component in PLATFORMS: + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(entry, component) + ) return True +async def async_unload_entry(hass, entry: ConfigEntry): + """Unload a config entry.""" + unload_ok = all( + await asyncio.gather( + *[ + hass.config_entries.async_forward_entry_unload(entry, platform) + for platform in PLATFORMS + ] + ) + ) + if unload_ok: + hass.data[DOMAIN].pop(entry.data[CONF_USERNAME]) + + return unload_ok + class TotalConnectSystem: """TotalConnect System class.""" diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index eccf69fef19a2a..f4d71f473b0f11 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -8,6 +8,7 @@ SUPPORT_ALARM_ARM_NIGHT, ) from homeassistant.const import ( + CONF_USERNAME, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, @@ -23,19 +24,18 @@ _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up an alarm control panel for a TotalConnect device.""" - if discovery_info is None: - return - +async def async_setup_entry(hass, entry, async_add_entities) -> None: + """Set up TotalConnect alarm panels based on a config entry.""" + username = entry.data[CONF_USERNAME] alarms = [] - client = hass.data[DOMAIN].client + client = hass.data[DOMAIN][username].client for location_id, location in client.locations.items(): location_name = location.location_name alarms.append(TotalConnectAlarm(location_name, location_id, client)) - add_entities(alarms) + + async_add_entities(alarms, True) class TotalConnectAlarm(alarm.AlarmControlPanel): diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 6b54f989589ded..e3effafb8412b1 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -7,25 +7,25 @@ DEVICE_CLASS_SMOKE, BinarySensorDevice, ) +from homeassistant.const import CONF_USERNAME from .const import DOMAIN _LOGGER = logging.getLogger(__name__) -def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up a sensor for a TotalConnect device.""" - if discovery_info is None: - return - +async def async_setup_entry(hass, entry, async_add_entities) -> None: + """Set up TotalConnect device sensors based on a config entry.""" + username = entry.data[CONF_USERNAME] sensors = [] - client_locations = hass.data[DOMAIN].client.locations + client_locations = hass.data[DOMAIN][username].client.locations for location_id, location in client_locations.items(): for zone_id, zone in location.zones.items(): sensors.append(TotalConnectBinarySensor(zone_id, location_id, zone)) - add_entities(sensors, True) + + async_add_entities(sensors, True) class TotalConnectBinarySensor(BinarySensorDevice): diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 40a74f88b9365a..c5bb5991580016 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -13,7 +13,7 @@ @config_entries.HANDLERS.register(DOMAIN) -class TotalConnectConfigFlow(config_entries.ConfigFlow): +class TotalConnectConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Total Connect config flow.""" VERSION = 1 @@ -36,7 +36,7 @@ async def async_step_user(self, user_input=None): # authentication success / valid return self.async_create_entry( title="Total Connect", - data={"Username": username, "Password": password}, + data={CONF_USERNAME: username, CONF_PASSWORD: password}, ) # authentication failed / invalid errors["base"] = "login" @@ -49,6 +49,10 @@ async def async_step_user(self, user_input=None): step_id="user", data_schema=data_schema, errors=errors ) + async def async_step_import(self, user_input): + """Import a config entry.""" + return await self.async_step_user(user_input) + async def is_valid(self, username="", password=""): """Return true if the given username and password are valid.""" client = TotalConnectClient.TotalConnectClient(username, password) From 425b89010ca71b4bb8c333b815f25e9098ad6502 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 23 Feb 2020 10:14:41 -0800 Subject: [PATCH 57/89] Add tests for config flow --- tests/components/totalconnect/__init__.py | 1 + .../totalconnect/test_config_flow.py | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 tests/components/totalconnect/__init__.py create mode 100644 tests/components/totalconnect/test_config_flow.py diff --git a/tests/components/totalconnect/__init__.py b/tests/components/totalconnect/__init__.py new file mode 100644 index 00000000000000..180a00188cddfe --- /dev/null +++ b/tests/components/totalconnect/__init__.py @@ -0,0 +1 @@ +"""Tests for the totalconnect component.""" diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py new file mode 100644 index 00000000000000..fca4c18c3be1be --- /dev/null +++ b/tests/components/totalconnect/test_config_flow.py @@ -0,0 +1,86 @@ +"""Tests for the iCloud config flow.""" +from unittest.mock import MagicMock + +from homeassistant import data_entry_flow +from homeassistant.components.totalconnect.const import DOMAIN +from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.helpers.typing import HomeAssistantType + +from tests.common import MockConfigEntry + +USERNAME = "username@me.com" +USERNAME_2 = "second_username@icloud.com" +PASSWORD = "password" + + +async def test_user(hass: HomeAssistantType, service: MagicMock): + """Test user config.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER}, data=None + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == "user" + + # test with all provided + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + + +# assert result["step_id"] == CONF_TRUSTED_DEVICE + + +async def test_import(hass: HomeAssistantType, service: MagicMock): + """Test import step.""" + # import with username and password + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + + +# assert result["step_id"] == "trusted_device" + + +async def test_abort_if_already_setup(hass: HomeAssistantType): + """Test we abort if the account is already setup.""" + MockConfigEntry( + domain=DOMAIN, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + unique_id=USERNAME, + ).add_to_hass(hass) + + # Should fail, same USERNAME (import) + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + + # Should fail, same USERNAME (flow) + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "already_configured" + + +async def test_login_failed(hass: HomeAssistantType): + """Test when we have errors during login.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["errors"] == {CONF_USERNAME: "login"} From bcdc06089731e3de1671e91ce207acbb061f7a6a Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 23 Feb 2020 10:40:55 -0800 Subject: [PATCH 58/89] Updated requirements for test --- requirements_test_all.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 5aff12f6ac9531..1d86682887132b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -671,6 +671,9 @@ teslajsonpy==0.3.0 # homeassistant.components.toon toonapilib==3.2.4 +# homeassistant.components.totalconnect +total_connect_client==0.52 + # homeassistant.components.transmission transmissionrpc==0.11 From b6123882d8608230c301ab93c42ff041830d79bc Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 23 Feb 2020 15:33:03 -0800 Subject: [PATCH 59/89] Fixes to test_config_flow --- tests/components/totalconnect/test_config_flow.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index fca4c18c3be1be..5cb95453d031fa 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -1,11 +1,10 @@ """Tests for the iCloud config flow.""" -from unittest.mock import MagicMock +# from unittest.mock import MagicMock from homeassistant import data_entry_flow from homeassistant.components.totalconnect.const import DOMAIN from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from homeassistant.helpers.typing import HomeAssistantType from tests.common import MockConfigEntry @@ -14,7 +13,7 @@ PASSWORD = "password" -async def test_user(hass: HomeAssistantType, service: MagicMock): +async def test_user(hass): """Test user config.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=None @@ -34,7 +33,7 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): # assert result["step_id"] == CONF_TRUSTED_DEVICE -async def test_import(hass: HomeAssistantType, service: MagicMock): +async def test_import(hass): """Test import step.""" # import with username and password result = await hass.config_entries.flow.async_init( @@ -48,7 +47,7 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): # assert result["step_id"] == "trusted_device" -async def test_abort_if_already_setup(hass: HomeAssistantType): +async def test_abort_if_already_setup(hass): """Test we abort if the account is already setup.""" MockConfigEntry( domain=DOMAIN, @@ -75,7 +74,7 @@ async def test_abort_if_already_setup(hass: HomeAssistantType): assert result["reason"] == "already_configured" -async def test_login_failed(hass: HomeAssistantType): +async def test_login_failed(hass): """Test when we have errors during login.""" result = await hass.config_entries.flow.async_init( DOMAIN, @@ -83,4 +82,4 @@ async def test_login_failed(hass: HomeAssistantType): data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - assert result["errors"] == {CONF_USERNAME: "login"} + assert result["errors"] == {"base": "login"} From e6e832550d6f77efa3b03f7177d49f0f7c303c66 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 23 Feb 2020 15:44:40 -0800 Subject: [PATCH 60/89] Removed leftover comments and code --- tests/components/totalconnect/test_config_flow.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index 5cb95453d031fa..a9689f5058d5fc 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -30,9 +30,6 @@ async def test_user(hass): assert result["type"] == data_entry_flow.RESULT_TYPE_FORM -# assert result["step_id"] == CONF_TRUSTED_DEVICE - - async def test_import(hass): """Test import step.""" # import with username and password @@ -44,9 +41,6 @@ async def test_import(hass): assert result["type"] == data_entry_flow.RESULT_TYPE_FORM -# assert result["step_id"] == "trusted_device" - - async def test_abort_if_already_setup(hass): """Test we abort if the account is already setup.""" MockConfigEntry( From 1feab1e37a8bf2ca8bb69b15dc0d415c9d238322 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 23 Feb 2020 16:02:03 -0800 Subject: [PATCH 61/89] fix const.py flake8 error --- homeassistant/components/totalconnect/const.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/totalconnect/const.py b/homeassistant/components/totalconnect/const.py index b83cf170ec109d..6c19bf0a217a22 100644 --- a/homeassistant/components/totalconnect/const.py +++ b/homeassistant/components/totalconnect/const.py @@ -1 +1,3 @@ +"""TotalConnect constants.""" + DOMAIN = "totalconnect" From 736e80046cd00f12768cb8b8009c2f34f7557a5c Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 29 Feb 2020 11:00:23 -0800 Subject: [PATCH 62/89] Simplify text per @Kane610 https://github.com/home-assistant/home-assistant/pull/32126#pullrequestreview-364652949 --- homeassistant/components/totalconnect/.translations/en.json | 4 ++-- homeassistant/components/totalconnect/strings.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/totalconnect/.translations/en.json b/homeassistant/components/totalconnect/.translations/en.json index 5d56d45c97aacb..5aca06df513ded 100644 --- a/homeassistant/components/totalconnect/.translations/en.json +++ b/homeassistant/components/totalconnect/.translations/en.json @@ -12,9 +12,9 @@ "password": "Password", "username": "Username" }, - "title": "Fill in your Total Connect login information" + "title": "Total Connect" } }, "title": "Total Connect" } -} \ No newline at end of file +} diff --git a/homeassistant/components/totalconnect/strings.json b/homeassistant/components/totalconnect/strings.json index eb4d9badb39f60..893aba77368eec 100644 --- a/homeassistant/components/totalconnect/strings.json +++ b/homeassistant/components/totalconnect/strings.json @@ -3,7 +3,7 @@ "title": "Total Connect", "step": { "user": { - "title": "Fill in your Total Connect login information", + "title": "Total Connect", "data": { "username": "Username", "password": "Password" @@ -17,4 +17,4 @@ "already_configured": "Account already configured" } } -} \ No newline at end of file +} From 8ae81b28a603babfed1f37a98a052a7cdcb6049e Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 29 Feb 2020 11:08:19 -0800 Subject: [PATCH 63/89] Remove .get() to speed things up since the required items should always be available. --- homeassistant/components/totalconnect/__init__.py | 6 +++--- homeassistant/components/totalconnect/config_flow.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 7601ea31c24fb8..30f2ff227d7f33 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -32,7 +32,7 @@ async def async_setup(hass: HomeAssistant, config: dict): """Set up from existing/saved configuration.""" - conf = config.get(DOMAIN) + conf = config[DOMAIN] if conf is None: return True @@ -50,8 +50,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): hass.data.setdefault(DOMAIN, {}) conf = entry.data - username = conf.get(CONF_USERNAME) - password = conf.get(CONF_PASSWORD) + username = conf[CONF_USERNAME] + password = conf[CONF_PASSWORD] client = TotalConnectClient.TotalConnectClient(username, password) diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index c5bb5991580016..f2b6c38f9ed3fc 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -24,8 +24,8 @@ async def async_step_user(self, user_input=None): if user_input is not None: # Validate user input - username = user_input.get(CONF_USERNAME) - password = user_input.get(CONF_PASSWORD) + username = user_input[CONF_USERNAME] + password = user_input[CONF_PASSWORD] await self.async_set_unique_id(username) self._abort_if_unique_id_configured() From 825cd86864a2d942b046de6d150419f5e09c292f Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sat, 29 Feb 2020 11:17:59 -0800 Subject: [PATCH 64/89] Move CONF_USERNAME and CONF_PASSWORD into .const to eliminate extra I/O to import from homeassistant.const --- homeassistant/components/totalconnect/__init__.py | 3 +-- homeassistant/components/totalconnect/alarm_control_panel.py | 3 +-- homeassistant/components/totalconnect/binary_sensor.py | 3 +-- homeassistant/components/totalconnect/config_flow.py | 3 +-- homeassistant/components/totalconnect/const.py | 2 ++ tests/components/totalconnect/test_config_flow.py | 3 +-- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 30f2ff227d7f33..55d2533b3c7fe0 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -6,11 +6,10 @@ import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv -from .const import DOMAIN +from .const import DOMAIN, CONF_PASSWORD, CONF_USERNAME _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index f4d71f473b0f11..101ad8d920e476 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -8,7 +8,6 @@ SUPPORT_ALARM_ARM_NIGHT, ) from homeassistant.const import ( - CONF_USERNAME, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_CUSTOM_BYPASS, STATE_ALARM_ARMED_HOME, @@ -19,7 +18,7 @@ STATE_ALARM_TRIGGERED, ) -from .const import DOMAIN +from .const import DOMAIN, CONF_USERNAME _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index e3effafb8412b1..3c2151e1e36a16 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -7,9 +7,8 @@ DEVICE_CLASS_SMOKE, BinarySensorDevice, ) -from homeassistant.const import CONF_USERNAME -from .const import DOMAIN +from .const import DOMAIN, CONF_USERNAME _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index f2b6c38f9ed3fc..e901efd9763f16 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -5,9 +5,8 @@ import voluptuous as vol from homeassistant import config_entries -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from .const import DOMAIN +from .const import DOMAIN, CONF_PASSWORD, CONF_USERNAME _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/const.py b/homeassistant/components/totalconnect/const.py index 6c19bf0a217a22..371c047056d666 100644 --- a/homeassistant/components/totalconnect/const.py +++ b/homeassistant/components/totalconnect/const.py @@ -1,3 +1,5 @@ """TotalConnect constants.""" DOMAIN = "totalconnect" +CONF_PASSWORD = "password" +CONF_USERNAME = "username" \ No newline at end of file diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index a9689f5058d5fc..3ce59c0598c394 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -2,9 +2,8 @@ # from unittest.mock import MagicMock from homeassistant import data_entry_flow -from homeassistant.components.totalconnect.const import DOMAIN +from homeassistant.components.totalconnect.const import DOMAIN, CONF_PASSWORD, CONF_USERNAME from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from tests.common import MockConfigEntry From 0eb730e327d7e3be9d68d3b5bd9273cc0f903b3a Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 2 Mar 2020 15:31:42 -0800 Subject: [PATCH 65/89] Fix I/O async issues --- .../components/totalconnect/__init__.py | 16 ++++------------ .../components/totalconnect/config_flow.py | 4 +++- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 55d2533b3c7fe0..429567c90d49bc 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -30,17 +30,7 @@ async def async_setup(hass: HomeAssistant, config: dict): - """Set up from existing/saved configuration.""" - conf = config[DOMAIN] - if conf is None: - return True - - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_IMPORT}, data=conf - ) - ) - + """Old way to set up.""" return True @@ -52,7 +42,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): username = conf[CONF_USERNAME] password = conf[CONF_PASSWORD] - client = TotalConnectClient.TotalConnectClient(username, password) + client = await hass.async_add_executor_job( + TotalConnectClient.TotalConnectClient, username, password + ) if not client.is_logged_in(): _LOGGER.error("TotalConnect authentication failed") diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index e901efd9763f16..e1b2fe493b783a 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -54,5 +54,7 @@ async def async_step_import(self, user_input): async def is_valid(self, username="", password=""): """Return true if the given username and password are valid.""" - client = TotalConnectClient.TotalConnectClient(username, password) + client = await self.hass.async_add_executor_job( + TotalConnectClient.TotalConnectClient, username, password + ) return client.is_logged_in() From dc541e5d0e0ab63ee0d505a7f21488d621c0bca3 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 2 Mar 2020 16:36:25 -0800 Subject: [PATCH 66/89] Fix flake8 and black errors --- homeassistant/components/totalconnect/__init__.py | 2 +- homeassistant/components/totalconnect/const.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 429567c90d49bc..cdbd37bd6c20de 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -5,7 +5,7 @@ from total_connect_client import TotalConnectClient import voluptuous as vol -from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry +from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv diff --git a/homeassistant/components/totalconnect/const.py b/homeassistant/components/totalconnect/const.py index 371c047056d666..6628d11bfe6a79 100644 --- a/homeassistant/components/totalconnect/const.py +++ b/homeassistant/components/totalconnect/const.py @@ -2,4 +2,4 @@ DOMAIN = "totalconnect" CONF_PASSWORD = "password" -CONF_USERNAME = "username" \ No newline at end of file +CONF_USERNAME = "username" From ecf3881c295311ba797c9f8091b970d502151f58 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 2 Mar 2020 21:14:23 -0800 Subject: [PATCH 67/89] Mock the I/O in tests. --- .../totalconnect/test_config_flow.py | 98 ++++++++++++------- 1 file changed, 64 insertions(+), 34 deletions(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index 3ce59c0598c394..fa942843a389c7 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -1,11 +1,15 @@ """Tests for the iCloud config flow.""" -# from unittest.mock import MagicMock +from unittest.mock import patch from homeassistant import data_entry_flow -from homeassistant.components.totalconnect.const import DOMAIN, CONF_PASSWORD, CONF_USERNAME +from homeassistant.components.totalconnect.const import ( + DOMAIN, + CONF_PASSWORD, + CONF_USERNAME, +) from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, mock_coro USERNAME = "username@me.com" USERNAME_2 = "second_username@icloud.com" @@ -14,34 +18,45 @@ async def test_user(hass): """Test user config.""" + # no data provided so show the form result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=None ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" - # test with all provided - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, - data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, - ) - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + # now data is provided, so check if login is correct and create the entry + with patch( + "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", + return_value=mock_coro(True), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY async def test_import(hass): - """Test import step.""" - # import with username and password - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, - ) - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + """Test import step with good username and password.""" + with patch( + "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", + return_value=mock_coro(True), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY async def test_abort_if_already_setup(hass): - """Test we abort if the account is already setup.""" + """Test abort if the account is already setup.""" MockConfigEntry( domain=DOMAIN, data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, @@ -49,30 +64,45 @@ async def test_abort_if_already_setup(hass): ).add_to_hass(hass) # Should fail, same USERNAME (import) - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_IMPORT}, - data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, - ) + with patch( + "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", + return_value=mock_coro(True), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_IMPORT}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "already_configured" # Should fail, same USERNAME (flow) - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, - data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, - ) + with patch( + "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", + return_value=mock_coro(True), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "already_configured" async def test_login_failed(hass): """Test when we have errors during login.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - context={"source": SOURCE_USER}, - data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, - ) + with patch( + "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", + return_value=mock_coro(False), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": SOURCE_USER}, + data={CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {"base": "login"} From 74e65d7f8a470ce84a6566a7ce0a06aea0ea142e Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 2 Mar 2020 21:33:17 -0800 Subject: [PATCH 68/89] Fix isort error --- homeassistant/components/totalconnect/__init__.py | 2 +- homeassistant/components/totalconnect/alarm_control_panel.py | 2 +- homeassistant/components/totalconnect/binary_sensor.py | 2 +- homeassistant/components/totalconnect/config_flow.py | 2 +- tests/components/totalconnect/test_config_flow.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index cdbd37bd6c20de..d2419e2593fdc3 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -9,7 +9,7 @@ from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv -from .const import DOMAIN, CONF_PASSWORD, CONF_USERNAME +from .const import CONF_PASSWORD, CONF_USERNAME, DOMAIN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 101ad8d920e476..d796e8b7d4637a 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -18,7 +18,7 @@ STATE_ALARM_TRIGGERED, ) -from .const import DOMAIN, CONF_USERNAME +from .const import CONF_USERNAME, DOMAIN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 3c2151e1e36a16..dc970e87e0dac3 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -8,7 +8,7 @@ BinarySensorDevice, ) -from .const import DOMAIN, CONF_USERNAME +from .const import CONF_USERNAME, DOMAIN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index e1b2fe493b783a..1680dae6ad60c5 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -6,7 +6,7 @@ from homeassistant import config_entries -from .const import DOMAIN, CONF_PASSWORD, CONF_USERNAME +from .const import CONF_PASSWORD, CONF_USERNAME, DOMAIN _LOGGER = logging.getLogger(__name__) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index fa942843a389c7..9783dd8d64c084 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -3,9 +3,9 @@ from homeassistant import data_entry_flow from homeassistant.components.totalconnect.const import ( - DOMAIN, CONF_PASSWORD, CONF_USERNAME, + DOMAIN, ) from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER From 9f064542f579d7b3e7ad2efadd2ffdcb40b924be Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Tue, 3 Mar 2020 19:08:33 -0800 Subject: [PATCH 69/89] Empty commit to re-start azure pipelines (per discord) From 9bcd05fc99842e19d2b8f26770c9388feb11425a Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Tue, 3 Mar 2020 19:23:09 -0800 Subject: [PATCH 70/89] bump total-connect-client to 0.53 --- homeassistant/components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index a350ebba7cc842..2b581a6abd3d49 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -2,7 +2,7 @@ "domain": "totalconnect", "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", - "requirements": ["total_connect_client==0.52"], + "requirements": ["total_connect_client==0.53"], "dependencies": [], "codeowners": ["@austinmroczek"], "config_flow": true diff --git a/requirements_all.txt b/requirements_all.txt index 26868697d8b981..2a8d40c0a43d1b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1989,7 +1989,7 @@ todoist-python==8.0.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.52 +total_connect_client==0.53 # homeassistant.components.tplink_lte tp-connected==0.0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2a99ddc67977ec..d22130aacff663 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -675,7 +675,7 @@ teslajsonpy==0.3.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.52 +total_connect_client==0.53 # homeassistant.components.transmission transmissionrpc==0.11 From a5c4c5625b8b7709f212ab181de48ddc4cb02690 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 5 Mar 2020 18:47:49 -0800 Subject: [PATCH 71/89] Update homeassistant/components/totalconnect/__init__.py Co-Authored-By: Paulus Schoutsen --- homeassistant/components/totalconnect/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index d2419e2593fdc3..69dd2862b26405 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -50,7 +50,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): _LOGGER.error("TotalConnect authentication failed") return False - hass.data[DOMAIN][username] = TotalConnectSystem(username, password, client) + hass.data[DOMAIN][entry.entry_id] = TotalConnectSystem(username, password, client) for component in PLATFORMS: hass.async_create_task( From a93bfefcb3cf76293b21b2d7a230c2c529b40dea Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 5 Mar 2020 18:48:29 -0800 Subject: [PATCH 72/89] Update homeassistant/components/totalconnect/config_flow.py Co-Authored-By: Paulus Schoutsen --- homeassistant/components/totalconnect/config_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 1680dae6ad60c5..680c4d0f28ab47 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -34,7 +34,7 @@ async def async_step_user(self, user_input=None): if valid: # authentication success / valid return self.async_create_entry( - title="Total Connect", + title=username, data={CONF_USERNAME: username, CONF_PASSWORD: password}, ) # authentication failed / invalid From 4e7e98c227454631d871b0161097938a5638c3dd Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 5 Mar 2020 19:30:36 -0800 Subject: [PATCH 73/89] Fixes per @balloob comments --- homeassistant/components/totalconnect/__init__.py | 3 ++- homeassistant/components/totalconnect/alarm_control_panel.py | 5 ++--- homeassistant/components/totalconnect/binary_sensor.py | 5 ++--- homeassistant/components/totalconnect/config_flow.py | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 69dd2862b26405..b9f283148c2b95 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -8,8 +8,9 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from .const import CONF_PASSWORD, CONF_USERNAME, DOMAIN +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index d796e8b7d4637a..0483c75db7af19 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -18,17 +18,16 @@ STATE_ALARM_TRIGGERED, ) -from .const import CONF_USERNAME, DOMAIN +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass, entry, async_add_entities) -> None: """Set up TotalConnect alarm panels based on a config entry.""" - username = entry.data[CONF_USERNAME] alarms = [] - client = hass.data[DOMAIN][username].client + client = hass.data[DOMAIN][entry.entry_id].client for location_id, location in client.locations.items(): location_name = location.location_name diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index dc970e87e0dac3..5c31308223c0dc 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -8,17 +8,16 @@ BinarySensorDevice, ) -from .const import CONF_USERNAME, DOMAIN +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass, entry, async_add_entities) -> None: """Set up TotalConnect device sensors based on a config entry.""" - username = entry.data[CONF_USERNAME] sensors = [] - client_locations = hass.data[DOMAIN][username].client.locations + client_locations = hass.data[DOMAIN][entry.entry_id].client.locations for location_id, location in client_locations.items(): for zone_id, zone in location.zones.items(): diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 680c4d0f28ab47..1680dae6ad60c5 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -34,7 +34,7 @@ async def async_step_user(self, user_input=None): if valid: # authentication success / valid return self.async_create_entry( - title=username, + title="Total Connect", data={CONF_USERNAME: username, CONF_PASSWORD: password}, ) # authentication failed / invalid From 75ab1aed4c0b606f32190271f4a7d3b75851439d Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 5 Mar 2020 19:32:33 -0800 Subject: [PATCH 74/89] Fix imports --- homeassistant/components/totalconnect/config_flow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 1680dae6ad60c5..3cc3bf26bb3956 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -5,8 +5,9 @@ import voluptuous as vol from homeassistant import config_entries +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from .const import CONF_PASSWORD, CONF_USERNAME, DOMAIN +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) From 9ed27adf2f3e1874f5cb92b62a0712f3ceb9d429 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 5 Mar 2020 20:58:52 -0800 Subject: [PATCH 75/89] fix isort error --- homeassistant/components/totalconnect/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index b9f283148c2b95..19fa20e73e4727 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -6,9 +6,9 @@ import voluptuous as vol from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from .const import DOMAIN From 872130b72bd9dea6e012683e666c6a239b5308e9 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Thu, 5 Mar 2020 21:32:46 -0800 Subject: [PATCH 76/89] Fix async_unload_entry It still referenced CONF_USERNAME instead of entry.entity_id --- homeassistant/components/totalconnect/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 19fa20e73e4727..9f85d78faaa016 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -72,7 +72,7 @@ async def async_unload_entry(hass, entry: ConfigEntry): ) ) if unload_ok: - hass.data[DOMAIN].pop(entry.data[CONF_USERNAME]) + hass.data[DOMAIN].pop(entry.entry_id) return unload_ok From 234d805861e1661493752c9621ddc92e4500fbb2 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Fri, 6 Mar 2020 16:16:57 -0800 Subject: [PATCH 77/89] Added async_setup so not breaking change. Fixed imports. --- .../components/totalconnect/__init__.py | 24 ++++++++++++++----- .../components/totalconnect/const.py | 2 -- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 9f85d78faaa016..990051e072b2a1 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -3,18 +3,21 @@ import logging from total_connect_client import TotalConnectClient -import voluptuous as vol -from homeassistant.config_entries import ConfigEntry +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant -import homeassistant.helpers.config_validation as cv from .const import DOMAIN -_LOGGER = logging.getLogger(__name__) +# import voluptuous as vol + +# import homeassistant.helpers.config_validation as cv +_LOGGER = logging.getLogger(__name__) + +""" CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( @@ -26,12 +29,21 @@ }, extra=vol.ALLOW_EXTRA, ) - +""" PLATFORMS = ["alarm_control_panel", "binary_sensor"] async def async_setup(hass: HomeAssistant, config: dict): - """Old way to set up.""" + """Set up by configuration file.""" + if DOMAIN not in config: + return True + + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_IMPORT}, data=config[DOMAIN], + ) + ) + return True diff --git a/homeassistant/components/totalconnect/const.py b/homeassistant/components/totalconnect/const.py index 6628d11bfe6a79..6c19bf0a217a22 100644 --- a/homeassistant/components/totalconnect/const.py +++ b/homeassistant/components/totalconnect/const.py @@ -1,5 +1,3 @@ """TotalConnect constants.""" DOMAIN = "totalconnect" -CONF_PASSWORD = "password" -CONF_USERNAME = "username" From 9e3a9a661ad48af66a0964bb77270f102010c458 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 8 Mar 2020 09:50:58 -0700 Subject: [PATCH 78/89] Update tests/components/totalconnect/test_config_flow.py Co-Authored-By: Martin Hjelmare --- tests/components/totalconnect/test_config_flow.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index 9783dd8d64c084..946e6aa15d0dc3 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -28,9 +28,9 @@ async def test_user(hass): # now data is provided, so check if login is correct and create the entry with patch( - "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", - return_value=mock_coro(True), - ): + "homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient" + ) as client_mock: + client_mock.return_value.is_logged_in.return_value = True result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, From f5d1af58dd5656a6e7cb6e44f26dbfd862f9b7eb Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 8 Mar 2020 10:04:08 -0700 Subject: [PATCH 79/89] Remove TotalConnectSystem() per @MartinHjelmare suggestion --- homeassistant/components/totalconnect/__init__.py | 12 +----------- .../components/totalconnect/alarm_control_panel.py | 2 +- .../components/totalconnect/binary_sensor.py | 2 +- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index 990051e072b2a1..e2a2a675a449d4 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -63,7 +63,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): _LOGGER.error("TotalConnect authentication failed") return False - hass.data[DOMAIN][entry.entry_id] = TotalConnectSystem(username, password, client) + hass.data[DOMAIN][entry.entry_id] = client for component in PLATFORMS: hass.async_create_task( @@ -87,13 +87,3 @@ async def async_unload_entry(hass, entry: ConfigEntry): hass.data[DOMAIN].pop(entry.entry_id) return unload_ok - - -class TotalConnectSystem: - """TotalConnect System class.""" - - def __init__(self, username, password, client): - """Initialize the TotalConnect system.""" - self._username = username - self._password = password - self.client = client diff --git a/homeassistant/components/totalconnect/alarm_control_panel.py b/homeassistant/components/totalconnect/alarm_control_panel.py index 0483c75db7af19..160e258fb8b239 100644 --- a/homeassistant/components/totalconnect/alarm_control_panel.py +++ b/homeassistant/components/totalconnect/alarm_control_panel.py @@ -27,7 +27,7 @@ async def async_setup_entry(hass, entry, async_add_entities) -> None: """Set up TotalConnect alarm panels based on a config entry.""" alarms = [] - client = hass.data[DOMAIN][entry.entry_id].client + client = hass.data[DOMAIN][entry.entry_id] for location_id, location in client.locations.items(): location_name = location.location_name diff --git a/homeassistant/components/totalconnect/binary_sensor.py b/homeassistant/components/totalconnect/binary_sensor.py index 5c31308223c0dc..48d9a96a483838 100644 --- a/homeassistant/components/totalconnect/binary_sensor.py +++ b/homeassistant/components/totalconnect/binary_sensor.py @@ -17,7 +17,7 @@ async def async_setup_entry(hass, entry, async_add_entities) -> None: """Set up TotalConnect device sensors based on a config entry.""" sensors = [] - client_locations = hass.data[DOMAIN][entry.entry_id].client.locations + client_locations = hass.data[DOMAIN][entry.entry_id].locations for location_id, location in client_locations.items(): for zone_id, zone in location.zones.items(): From bd20b20b717f5085968315443b954a16d8be5812 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 8 Mar 2020 10:08:58 -0700 Subject: [PATCH 80/89] Moved from is_logged_in() to is_valid_credentials() The second is more accurate for what we are checking for, because is_logged_in() could return False due to connection error. --- homeassistant/components/totalconnect/__init__.py | 2 +- homeassistant/components/totalconnect/config_flow.py | 2 +- tests/components/totalconnect/test_config_flow.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index e2a2a675a449d4..c91b6688783442 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -59,7 +59,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): TotalConnectClient.TotalConnectClient, username, password ) - if not client.is_logged_in(): + if not client.is_valid_credentials(): _LOGGER.error("TotalConnect authentication failed") return False diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 3cc3bf26bb3956..7a678daa5a72aa 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -58,4 +58,4 @@ async def is_valid(self, username="", password=""): client = await self.hass.async_add_executor_job( TotalConnectClient.TotalConnectClient, username, password ) - return client.is_logged_in() + return client.is_valid_credentials() diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index 946e6aa15d0dc3..0c917e9e692d7d 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -30,7 +30,7 @@ async def test_user(hass): with patch( "homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient" ) as client_mock: - client_mock.return_value.is_logged_in.return_value = True + client_mock.return_value.is_valid_credentials.return_value = True result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, From 0fe927cc87e87e965b89a0518b218332c2daadc6 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Sun, 8 Mar 2020 15:19:01 -0700 Subject: [PATCH 81/89] Fix import in test --- tests/components/totalconnect/test_config_flow.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index 0c917e9e692d7d..6706ce839f103e 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -2,12 +2,9 @@ from unittest.mock import patch from homeassistant import data_entry_flow -from homeassistant.components.totalconnect.const import ( - CONF_PASSWORD, - CONF_USERNAME, - DOMAIN, -) +from homeassistant.components.totalconnect.const import DOMAIN from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from tests.common import MockConfigEntry, mock_coro From 70ecea57a4f859bc7ae8000d93691477f7be5177 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 9 Mar 2020 21:14:51 -0700 Subject: [PATCH 82/89] remove commented code and decorator --- .../components/totalconnect/__init__.py | 18 ------------------ .../components/totalconnect/config_flow.py | 1 - 2 files changed, 19 deletions(-) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index c91b6688783442..ee206a205de233 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -10,26 +10,8 @@ from .const import DOMAIN -# import voluptuous as vol - -# import homeassistant.helpers.config_validation as cv - - _LOGGER = logging.getLogger(__name__) -""" -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: vol.Schema( - { - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - } - ) - }, - extra=vol.ALLOW_EXTRA, -) -""" PLATFORMS = ["alarm_control_panel", "binary_sensor"] diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 7a678daa5a72aa..29bfd5e223e2b0 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -12,7 +12,6 @@ _LOGGER = logging.getLogger(__name__) -@config_entries.HANDLERS.register(DOMAIN) class TotalConnectConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Total Connect config flow.""" From 2b4ba2e037510ebc6e0fbaede459d984a50043fc Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 9 Mar 2020 21:17:09 -0700 Subject: [PATCH 83/89] Update tests/components/totalconnect/test_config_flow.py Co-Authored-By: Martin Hjelmare --- tests/components/totalconnect/test_config_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index 6706ce839f103e..f3e120e2e057bb 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -17,7 +17,7 @@ async def test_user(hass): """Test user config.""" # no data provided so show the form result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": SOURCE_USER}, data=None + DOMAIN, context={"source": SOURCE_USER} ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM From 339685920f809184e62f1303bb0739d3b777ab66 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 9 Mar 2020 21:24:37 -0700 Subject: [PATCH 84/89] fix test_config_flow.py --- .../totalconnect/test_config_flow.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index f3e120e2e057bb..a3704af64d42ea 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -9,7 +9,6 @@ from tests.common import MockConfigEntry, mock_coro USERNAME = "username@me.com" -USERNAME_2 = "second_username@icloud.com" PASSWORD = "password" @@ -40,9 +39,9 @@ async def test_user(hass): async def test_import(hass): """Test import step with good username and password.""" with patch( - "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", - return_value=mock_coro(True), - ): + "homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient" + ) as client_mock: + client_mock.return_value.is_valid_credentials.return_value = True result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_IMPORT}, @@ -62,9 +61,9 @@ async def test_abort_if_already_setup(hass): # Should fail, same USERNAME (import) with patch( - "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", - return_value=mock_coro(True), - ): + "homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient" + ) as client_mock: + client_mock.return_value.is_valid_credentials.return_value = True result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_IMPORT}, @@ -76,9 +75,9 @@ async def test_abort_if_already_setup(hass): # Should fail, same USERNAME (flow) with patch( - "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", - return_value=mock_coro(True), - ): + "homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient" + ) as client_mock: + client_mock.return_value.is_valid_credentials.return_value = True result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, @@ -92,9 +91,9 @@ async def test_abort_if_already_setup(hass): async def test_login_failed(hass): """Test when we have errors during login.""" with patch( - "homeassistant.components.totalconnect.config_flow.TotalConnectConfigFlow.is_valid", - return_value=mock_coro(False), - ): + "homeassistant.components.totalconnect.config_flow.TotalConnectClient.TotalConnectClient" + ) as client_mock: + client_mock.return_value.is_valid_credentials.return_value = False result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, From f9afffc68fed7e8ef92c4a670123a8233da2e5e9 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 9 Mar 2020 21:45:40 -0700 Subject: [PATCH 85/89] bump total-connect-client to 0.54 --- homeassistant/components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 2b581a6abd3d49..8231f7c07f85f4 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -2,7 +2,7 @@ "domain": "totalconnect", "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", - "requirements": ["total_connect_client==0.53"], + "requirements": ["total_connect_client==0.54"], "dependencies": [], "codeowners": ["@austinmroczek"], "config_flow": true diff --git a/requirements_all.txt b/requirements_all.txt index 5a8199f2c14f5d..dbfa4c85a90641 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2011,7 +2011,7 @@ todoist-python==8.0.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.53 +total_connect_client==0.54 # homeassistant.components.tplink_lte tp-connected==0.0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 328386d03f5901..51e8ba95a1cd4a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -687,7 +687,7 @@ teslajsonpy==0.4.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.53 +total_connect_client==0.54 # homeassistant.components.transmission transmissionrpc==0.11 From dd623475b3bd25cc7d6296c97080d6d005bf82a5 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 9 Mar 2020 22:05:19 -0700 Subject: [PATCH 86/89] remove un-needed import of mock_coro --- tests/components/totalconnect/test_config_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/totalconnect/test_config_flow.py b/tests/components/totalconnect/test_config_flow.py index a3704af64d42ea..b77198fa9b203f 100644 --- a/tests/components/totalconnect/test_config_flow.py +++ b/tests/components/totalconnect/test_config_flow.py @@ -6,7 +6,7 @@ from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from tests.common import MockConfigEntry, mock_coro +from tests.common import MockConfigEntry USERNAME = "username@me.com" PASSWORD = "password" From 1115ec903a20e24f293cd7d2ae1a4a8250bb6e2d Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Mon, 9 Mar 2020 23:34:18 -0700 Subject: [PATCH 87/89] bump to total-connect-client 0.54.1 --- homeassistant/components/totalconnect/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/totalconnect/manifest.json b/homeassistant/components/totalconnect/manifest.json index 8231f7c07f85f4..fc19c889d8b7f7 100644 --- a/homeassistant/components/totalconnect/manifest.json +++ b/homeassistant/components/totalconnect/manifest.json @@ -2,7 +2,7 @@ "domain": "totalconnect", "name": "Honeywell Total Connect Alarm", "documentation": "https://www.home-assistant.io/integrations/totalconnect", - "requirements": ["total_connect_client==0.54"], + "requirements": ["total_connect_client==0.54.1"], "dependencies": [], "codeowners": ["@austinmroczek"], "config_flow": true diff --git a/requirements_all.txt b/requirements_all.txt index dbfa4c85a90641..1f2b568b61c783 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2011,7 +2011,7 @@ todoist-python==8.0.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.54 +total_connect_client==0.54.1 # homeassistant.components.tplink_lte tp-connected==0.0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 51e8ba95a1cd4a..84b760dd0b05db 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -687,7 +687,7 @@ teslajsonpy==0.4.0 toonapilib==3.2.4 # homeassistant.components.totalconnect -total_connect_client==0.54 +total_connect_client==0.54.1 # homeassistant.components.transmission transmissionrpc==0.11 From c5f4ddfe4a0728c9b745f75aea3e7095fbe423a1 Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Tue, 10 Mar 2020 07:09:32 -0700 Subject: [PATCH 88/89] re-add CONFIG_SCHEMA --- homeassistant/components/totalconnect/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/homeassistant/components/totalconnect/__init__.py b/homeassistant/components/totalconnect/__init__.py index ee206a205de233..fce67f71b24059 100644 --- a/homeassistant/components/totalconnect/__init__.py +++ b/homeassistant/components/totalconnect/__init__.py @@ -3,10 +3,12 @@ import logging from total_connect_client import TotalConnectClient +import voluptuous as vol from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant +import homeassistant.helpers.config_validation as cv from .const import DOMAIN @@ -14,6 +16,17 @@ PLATFORMS = ["alarm_control_panel", "binary_sensor"] +CONFIG_SCHEMA = vol.Schema( + { + DOMAIN: vol.Schema( + { + vol.Required(CONF_USERNAME): cv.string, + vol.Required(CONF_PASSWORD): cv.string, + } + ) + } +) + async def async_setup(hass: HomeAssistant, config: dict): """Set up by configuration file.""" From ae483af1019a38f6d5ef34c6b2d7e2c1da75d8ff Mon Sep 17 00:00:00 2001 From: Austin Mroczek Date: Wed, 11 Mar 2020 17:03:37 -0700 Subject: [PATCH 89/89] disable pylint on line 10 to avoid pylint bug --- homeassistant/components/totalconnect/config_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/totalconnect/config_flow.py b/homeassistant/components/totalconnect/config_flow.py index 29bfd5e223e2b0..03ddd0a432a145 100644 --- a/homeassistant/components/totalconnect/config_flow.py +++ b/homeassistant/components/totalconnect/config_flow.py @@ -7,7 +7,7 @@ from homeassistant import config_entries from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from .const import DOMAIN +from .const import DOMAIN # pylint: disable=unused-import _LOGGER = logging.getLogger(__name__)