mirror of
https://github.com/cyberjunky/home-assistant-garmin_connect.git
synced 2026-01-09 21:08:06 -05:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
160a1b96e9 | ||
|
|
355f9d7732 | ||
|
|
1776cb4037 |
@@ -40,45 +40,67 @@ async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
if entry.version == 1:
|
||||
# Check if we need to migrate (old entries have username/password, new ones have token)
|
||||
if CONF_TOKEN not in entry.data and CONF_USERNAME in entry.data and CONF_PASSWORD in entry.data:
|
||||
_LOGGER.info(
|
||||
"Migrating Garmin Connect config entry to token-based authentication")
|
||||
if CONF_TOKEN not in entry.data:
|
||||
# Missing token - check if we have username/password to migrate
|
||||
if CONF_USERNAME in entry.data and CONF_PASSWORD in entry.data:
|
||||
_LOGGER.info(
|
||||
"Migrating Garmin Connect config entry to token-based authentication")
|
||||
|
||||
username = entry.data[CONF_USERNAME]
|
||||
password = entry.data[CONF_PASSWORD]
|
||||
username = entry.data[CONF_USERNAME]
|
||||
password = entry.data[CONF_PASSWORD]
|
||||
|
||||
# Determine if user is in China
|
||||
in_china = hass.config.country == "CN"
|
||||
# Determine if user is in China
|
||||
in_china = hass.config.country == "CN"
|
||||
|
||||
# Create temporary API client to get token
|
||||
api = Garmin(email=username, password=password, is_cn=in_china)
|
||||
# Create temporary API client to get token
|
||||
api = Garmin(email=username, password=password, is_cn=in_china)
|
||||
|
||||
try:
|
||||
# Login to get the token
|
||||
await hass.async_add_executor_job(api.login)
|
||||
try:
|
||||
# Login to get the token
|
||||
await hass.async_add_executor_job(api.login)
|
||||
|
||||
# Get the OAuth tokens
|
||||
tokens = api.garth.dumps()
|
||||
# Get the OAuth tokens
|
||||
tokens = api.garth.dumps()
|
||||
|
||||
# Create new data with token, keeping the ID
|
||||
new_data = {
|
||||
CONF_ID: entry.data.get(CONF_ID, username),
|
||||
CONF_TOKEN: tokens,
|
||||
}
|
||||
# Create new data with token, ensuring we have a CONF_ID
|
||||
new_data = {
|
||||
CONF_ID: entry.data.get(CONF_ID, username),
|
||||
CONF_TOKEN: tokens,
|
||||
}
|
||||
|
||||
# Update the config entry
|
||||
hass.config_entries.async_update_entry(entry, data=new_data)
|
||||
# Update the config entry
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, data=new_data)
|
||||
|
||||
_LOGGER.info(
|
||||
"Successfully migrated Garmin Connect config entry")
|
||||
return True
|
||||
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
_LOGGER.error(
|
||||
"Failed to migrate Garmin Connect config entry. "
|
||||
"Please re-authenticate. Error: %s", err
|
||||
)
|
||||
return False
|
||||
else:
|
||||
# No token and no username/password - config entry is incomplete/corrupted
|
||||
# Add a placeholder CONF_ID if missing to allow reauth to work properly
|
||||
if CONF_ID not in entry.data:
|
||||
_LOGGER.info(
|
||||
"Config entry missing CONF_ID, adding placeholder for reauth flow")
|
||||
new_data = {
|
||||
**entry.data,
|
||||
CONF_ID: entry.entry_id, # Use entry_id as fallback
|
||||
}
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, data=new_data)
|
||||
|
||||
_LOGGER.info(
|
||||
"Successfully migrated Garmin Connect config entry")
|
||||
return True
|
||||
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
_LOGGER.error(
|
||||
"Failed to migrate Garmin Connect config entry. "
|
||||
"Please re-add the integration. Error: %s", err
|
||||
"Garmin Connect config entry is incomplete (missing token). "
|
||||
"Reauthentication will be required to complete setup."
|
||||
)
|
||||
return False
|
||||
# Return True to allow setup to proceed, which will trigger reauth via ConfigEntryAuthFailed
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
@@ -152,12 +174,13 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
try:
|
||||
# Check if the token exists in the entry data
|
||||
if CONF_TOKEN not in self.entry.data:
|
||||
_LOGGER.error(
|
||||
"Token not found in config entry. This may be an old config entry that needs migration. "
|
||||
"Please remove and re-add the Garmin Connect integration."
|
||||
_LOGGER.info(
|
||||
"Token not found in config entry. Reauthentication required."
|
||||
)
|
||||
raise ConfigEntryAuthFailed(
|
||||
"Token not found, please re-add the integration")
|
||||
"Token not found in config entry. This may be an old or incomplete configuration. "
|
||||
"A reauthentication flow will be initiated. Please check your notifications."
|
||||
)
|
||||
|
||||
await self.hass.async_add_executor_job(self.api.login, self.entry.data[CONF_TOKEN])
|
||||
except GarminConnectAuthenticationError as err:
|
||||
|
||||
@@ -126,13 +126,15 @@ class GarminConnectConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""
|
||||
config_data = {
|
||||
CONF_ID: self._username,
|
||||
CONF_USERNAME: self._username,
|
||||
CONF_TOKEN: self._api.garth.dumps(),
|
||||
}
|
||||
existing_entry = await self.async_set_unique_id(self._username)
|
||||
|
||||
if existing_entry:
|
||||
return self.async_update_reload_and_abort(existing_entry, data=config_data)
|
||||
self.hass.config_entries.async_update_entry(
|
||||
existing_entry, data=config_data)
|
||||
await self.hass.config_entries.async_reload(existing_entry.entry_id)
|
||||
return self.async_abort(reason="reauth_successful")
|
||||
|
||||
return self.async_create_entry(
|
||||
title=cast(str, self._username), data=config_data
|
||||
@@ -180,9 +182,11 @@ class GarminConnectConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""
|
||||
Start the reauthorization process using existing configuration entry data.
|
||||
|
||||
Extracts the username from the entry data and advances to the reauthorization confirmation step.
|
||||
Extracts the username from the entry data (using CONF_ID if CONF_USERNAME is not available for migrated entries) and advances to the reauthorization confirmation step.
|
||||
"""
|
||||
self._username = entry_data[CONF_USERNAME]
|
||||
# For backward compatibility: try CONF_USERNAME first, fall back to CONF_ID
|
||||
self._username = entry_data.get(
|
||||
CONF_USERNAME) or entry_data.get(CONF_ID)
|
||||
|
||||
return await self.async_step_reauth_confirm()
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"issue_tracker": "https://github.com/cyberjunky/home-assistant-garmin_connect/issues",
|
||||
"requirements": ["garminconnect>=0.2.31"],
|
||||
"version": "0.2.33"
|
||||
"version": "0.2.36"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user