Skip to content

Commit

Permalink
Improve internet/API error handling for BMW (home-assistant/core#90274)
Browse files Browse the repository at this point in the history
  • Loading branch information
rikroe committed May 3, 2023
1 parent dc25be3 commit 84d540b
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 20 deletions.
13 changes: 11 additions & 2 deletions custom_components/bmw_connected_drive/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

from bimmer_connected.api.authentication import MyBMWAuthentication
from bimmer_connected.api.regions import get_region_from_name
from httpx import HTTPError
from bimmer_connected.models import MyBMWAPIError, MyBMWAuthError
from httpx import RequestError
import voluptuous as vol

from homeassistant import config_entries, core, exceptions
Expand Down Expand Up @@ -41,7 +42,9 @@ async def validate_input(

try:
await auth.login()
except HTTPError as ex:
except MyBMWAuthError as ex:
raise InvalidAuth from ex
except (MyBMWAPIError, RequestError) as ex:
raise CannotConnect from ex

# Return info that you want to store in the config entry.
Expand Down Expand Up @@ -80,6 +83,8 @@ async def async_step_user(
}
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
errors["base"] = "invalid_auth"

if info:
if self._reauth_entry:
Expand Down Expand Up @@ -160,3 +165,7 @@ async def async_step_account_options(

class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""


class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""
35 changes: 17 additions & 18 deletions custom_components/bmw_connected_drive/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

from bimmer_connected.account import MyBMWAccount
from bimmer_connected.api.regions import get_region_from_name
from bimmer_connected.models import GPSPosition
from httpx import HTTPError, HTTPStatusError, TimeoutException
from bimmer_connected.models import GPSPosition, MyBMWAPIError, MyBMWAuthError
from httpx import RequestError

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_REGION, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import CONF_READ_ONLY, CONF_REFRESH_TOKEN, DOMAIN

Expand Down Expand Up @@ -56,20 +56,19 @@ async def _async_update_data(self) -> None:

try:
await self.account.get_vehicles()
except (HTTPError, HTTPStatusError, TimeoutException) as err:
if isinstance(err, HTTPStatusError) and err.response.status_code == 429:
# Increase scan interval to not jump to not bring up the issue next time
self.update_interval = timedelta(
seconds=DEFAULT_SCAN_INTERVAL_SECONDS * 3
except MyBMWAuthError as err:
# Clear refresh token and trigger reauth
self._update_config_entry_refresh_token(None)
raise ConfigEntryAuthFailed(str(err)) from err

except (MyBMWAPIError, RequestError) as err:
if self.last_update_success is True:
_LOGGER.warning(
"Error communicating with BMW API (%s): %s",
type(err).__name__,
err,
)
if isinstance(err, HTTPStatusError) and err.response.status_code in (
401,
403,
):
# Clear refresh token only and trigger reauth
self._update_config_entry_refresh_token(None)
raise ConfigEntryAuthFailed(str(err)) from err
raise UpdateFailed(f"Error communicating with BMW API: {err}") from err
self.last_update_success = False

if self.account.refresh_token != old_refresh_token:
self._update_config_entry_refresh_token(self.account.refresh_token)
Expand All @@ -79,8 +78,8 @@ async def _async_update_data(self) -> None:
self.account.refresh_token,
)

# Reset scan interval after successful update
self.update_interval = timedelta(seconds=DEFAULT_SCAN_INTERVAL_SECONDS)
if self.last_update_success is False:
_LOGGER.info("Reconnected to BMW API")

def _update_config_entry_refresh_token(self, refresh_token: str | None) -> None:
"""Update or delete the refresh_token in the Config Entry."""
Expand Down

0 comments on commit 84d540b

Please sign in to comment.