From 5a5cde690fdc61d63bcf9e09914f4c5a9368877d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 5 May 2022 01:13:23 -0400 Subject: [PATCH] Ensure rachio retries setup later when cloud service is broken (#71300) --- homeassistant/components/rachio/__init__.py | 6 +++++- homeassistant/components/rachio/device.py | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/rachio/__init__.py b/homeassistant/components/rachio/__init__.py index ea8b8fe59cb..e75d7117d73 100644 --- a/homeassistant/components/rachio/__init__.py +++ b/homeassistant/components/rachio/__init__.py @@ -9,7 +9,7 @@ from homeassistant.components import cloud from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, Platform from homeassistant.core import HomeAssistant -from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from .const import CONF_CLOUDHOOK_URL, CONF_MANUAL_RUN_MINS, CONF_WEBHOOK_ID, DOMAIN @@ -73,6 +73,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # Get the API user try: await person.async_setup(hass) + except ConfigEntryAuthFailed as error: + # Reauth is not yet implemented + _LOGGER.error("Authentication failed: %s", error) + return False except ConnectTimeout as error: _LOGGER.error("Could not reach the Rachio API: %s", error) raise ConfigEntryNotReady from error diff --git a/homeassistant/components/rachio/device.py b/homeassistant/components/rachio/device.py index ff7c0535295..911049883d9 100644 --- a/homeassistant/components/rachio/device.py +++ b/homeassistant/components/rachio/device.py @@ -8,6 +8,7 @@ import voluptuous as vol from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.core import ServiceCall +from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from .const import ( @@ -125,12 +126,18 @@ class RachioPerson: rachio = self.rachio response = rachio.person.info() - assert int(response[0][KEY_STATUS]) == HTTPStatus.OK, "API key error" + if is_invalid_auth_code(int(response[0][KEY_STATUS])): + raise ConfigEntryAuthFailed(f"API key error: {response}") + if int(response[0][KEY_STATUS]) != HTTPStatus.OK: + raise ConfigEntryNotReady(f"API Error: {response}") self._id = response[1][KEY_ID] # Use user ID to get user data data = rachio.person.get(self._id) - assert int(data[0][KEY_STATUS]) == HTTPStatus.OK, "User ID error" + if is_invalid_auth_code(int(data[0][KEY_STATUS])): + raise ConfigEntryAuthFailed(f"User ID error: {data}") + if int(data[0][KEY_STATUS]) != HTTPStatus.OK: + raise ConfigEntryNotReady(f"API Error: {data}") self.username = data[1][KEY_USERNAME] devices = data[1][KEY_DEVICES] for controller in devices: @@ -297,3 +304,11 @@ class RachioIro: """Resume paused watering on this controller.""" self.rachio.device.resume_zone_run(self.controller_id) _LOGGER.debug("Resuming watering on %s", self) + + +def is_invalid_auth_code(http_status_code): + """HTTP status codes that mean invalid auth.""" + if http_status_code in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN): + return True + + return False