mirror of
https://github.com/cyberjunky/home-assistant-garmin_connect.git
synced 2026-01-08 20:38:00 -05:00
Migrate from old config flow to new config flow
Catch authentication errors and show them in the UI Limit last activity to 5 in attributes
This commit is contained in:
@@ -15,9 +15,9 @@ from garminconnect import (
|
|||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_TOKEN
|
from homeassistant.const import CONF_TOKEN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
import binascii
|
||||||
from .const import (
|
from .const import (
|
||||||
DATA_COORDINATOR,
|
DATA_COORDINATOR,
|
||||||
DAY_TO_NUMBER,
|
DAY_TO_NUMBER,
|
||||||
@@ -84,11 +84,15 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
async def async_login(self) -> bool:
|
async def async_login(self) -> bool:
|
||||||
"""Login to Garmin Connect."""
|
"""Login to Garmin Connect."""
|
||||||
try:
|
try:
|
||||||
|
# Check if the token exists in the entry data
|
||||||
|
if CONF_TOKEN not in self.entry.data:
|
||||||
|
raise KeyError("Token not found, migrating config entry")
|
||||||
|
|
||||||
await self.hass.async_add_executor_job(self.api.login, self.entry.data[CONF_TOKEN])
|
await self.hass.async_add_executor_job(self.api.login, self.entry.data[CONF_TOKEN])
|
||||||
except GarminConnectAuthenticationError as err:
|
except GarminConnectAuthenticationError as err:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Authentication error occurred during login: %s", err.response.text)
|
"Authentication error occurred during login: %s", err.response.text)
|
||||||
return False
|
raise ConfigEntryAuthFailed from err
|
||||||
except GarminConnectTooManyRequestsError as err:
|
except GarminConnectTooManyRequestsError as err:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Too many request error occurred during login: %s", err)
|
"Too many request error occurred during login: %s", err)
|
||||||
@@ -101,7 +105,7 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
if err.response.status_code == 401:
|
if err.response.status_code == 401:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Authentication error occurred during login: %s", err.response.text)
|
"Authentication error occurred during login: %s", err.response.text)
|
||||||
return False
|
raise ConfigEntryAuthFailed from err
|
||||||
if err.response.status_code == 429:
|
if err.response.status_code == 429:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Too many requests error occurred during login: %s", err.response.text)
|
"Too many requests error occurred during login: %s", err.response.text)
|
||||||
@@ -109,6 +113,10 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Unknown HTTP error occurred during login: %s", err)
|
"Unknown HTTP error occurred during login: %s", err)
|
||||||
return False
|
return False
|
||||||
|
except KeyError as err:
|
||||||
|
_LOGGER.error(
|
||||||
|
"Found old config during login: %s", err)
|
||||||
|
raise ConfigEntryAuthFailed from err
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
"Unknown error occurred during login: %s", err)
|
"Unknown error occurred during login: %s", err)
|
||||||
@@ -254,7 +262,7 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
except GarminConnectAuthenticationError as err:
|
except GarminConnectAuthenticationError as err:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Authentication error occurred during update: %s", err.response.text)
|
"Authentication error occurred during update: %s", err.response.text)
|
||||||
return False
|
raise ConfigEntryAuthFailed from err
|
||||||
except GarminConnectTooManyRequestsError as err:
|
except GarminConnectTooManyRequestsError as err:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Too many request error occurred during update: %s", err)
|
"Too many request error occurred during update: %s", err)
|
||||||
@@ -267,7 +275,7 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
if err.response.status_code == 401:
|
if err.response.status_code == 401:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Authentication error occurred during update: %s", err.response.text)
|
"Authentication error occurred during update: %s", err.response.text)
|
||||||
return False
|
raise ConfigEntryAuthFailed from err
|
||||||
if err.response.status_code == 429:
|
if err.response.status_code == 429:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Too many requests error occurred during update: %s", err.response.text)
|
"Too many requests error occurred during update: %s", err.response.text)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from garminconnect import (
|
|||||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||||
from homeassistant.const import CONF_ID, CONF_TOKEN, CONF_PASSWORD, CONF_USERNAME
|
from homeassistant.const import CONF_ID, CONF_TOKEN, CONF_PASSWORD, CONF_USERNAME
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
import garth
|
||||||
|
|
||||||
from .const import CONF_MFA, DOMAIN
|
from .const import CONF_MFA, DOMAIN
|
||||||
|
|
||||||
@@ -57,8 +58,6 @@ class GarminConnectConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
try:
|
try:
|
||||||
self._login_result1, self._login_result2 = await self.hass.async_add_executor_job(self._api.login)
|
self._login_result1, self._login_result2 = await self.hass.async_add_executor_job(self._api.login)
|
||||||
|
|
||||||
_LOGGER.debug(f"Login result1: {self._login_result1}")
|
|
||||||
_LOGGER.debug(f"Login result2: {self._login_result2}")
|
|
||||||
if self._login_result1 == "needs_mfa": # MFA is required
|
if self._login_result1 == "needs_mfa": # MFA is required
|
||||||
return await self.async_step_mfa()
|
return await self.async_step_mfa()
|
||||||
|
|
||||||
@@ -89,12 +88,10 @@ class GarminConnectConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||||||
async def _async_garmin_connect_mfa_login(self) -> ConfigFlowResult:
|
async def _async_garmin_connect_mfa_login(self) -> ConfigFlowResult:
|
||||||
"""Handle multi-factor authentication (MFA) login with Garmin Connect."""
|
"""Handle multi-factor authentication (MFA) login with Garmin Connect."""
|
||||||
try:
|
try:
|
||||||
|
await self.hass.async_add_executor_job(self._api.resume_login, self._login_result2, self._mfa_code)
|
||||||
|
|
||||||
oauth1, oauth2 = await self.hass.async_add_executor_job(self._api.resume_login, self._login_result2, self._mfa_code)
|
except garth.exc.GarthException as err:
|
||||||
|
_LOGGER.error(f"Error during MFA login: {err}")
|
||||||
_LOGGER.info(f"Oauth1: {oauth1}, Oauth2: {oauth2}")
|
|
||||||
|
|
||||||
except GarminConnectAuthenticationError:
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="mfa",
|
step_id="mfa",
|
||||||
data_schema=vol.Schema(self.mfa_data_schema),
|
data_schema=vol.Schema(self.mfa_data_schema),
|
||||||
|
|||||||
@@ -8,5 +8,5 @@
|
|||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"issue_tracker": "https://github.com/cyberjunky/home-assistant-garmin_connect/issues",
|
"issue_tracker": "https://github.com/cyberjunky/home-assistant-garmin_connect/issues",
|
||||||
"requirements": ["garminconnect>=0.2.26"],
|
"requirements": ["garminconnect>=0.2.26"],
|
||||||
"version": "0.2.31-beta-03"
|
"version": "0.2.31-beta-04"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ class GarminConnectSensor(CoordinatorEntity, SensorEntity):
|
|||||||
activities = self.coordinator.data.get(self._type, [])
|
activities = self.coordinator.data.get(self._type, [])
|
||||||
sorted_activities = sorted(
|
sorted_activities = sorted(
|
||||||
activities, key=lambda x: x["activityId"])
|
activities, key=lambda x: x["activityId"])
|
||||||
attributes["last_activities"] = sorted_activities[-10:]
|
attributes["last_activities"] = sorted_activities[-5:]
|
||||||
|
|
||||||
if self._type == "lastActivity":
|
if self._type == "lastActivity":
|
||||||
attributes = {**attributes, **self.coordinator.data[self._type]}
|
attributes = {**attributes, **self.coordinator.data[self._type]}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||||
"too_many_requests": "Too many requests, retry later.",
|
"too_many_requests": "Too many requests, retry later",
|
||||||
"unknown": "[%key:common::config_flow::error::unknown%]",
|
"unknown": "[%key:common::config_flow::error::unknown%]",
|
||||||
"invalid_mfa_code": "Invalid MFA code"
|
"invalid_mfa_code": "Invalid MFA code"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,13 +24,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "Account is already configured"
|
"already_configured": "Account is already configured",
|
||||||
|
"reauth_successful": "Reauthentication successful"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "Failed to connect",
|
"cannot_connect": "Failed to connect",
|
||||||
"invalid_auth": "Invalid authentication",
|
"invalid_auth": "Invalid authentication",
|
||||||
"too_many_requests": "Too many requests, retry later.",
|
"too_many_requests": "Too many requests, retry later",
|
||||||
"unknown": "Unexpected error"
|
"unknown": "Unexpected error",
|
||||||
|
"invalid_mfa_code": "Invalid MFA code"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user