Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config flow for fitbit."""
2 
3 from collections.abc import Mapping
4 import logging
5 from typing import Any
6 
7 from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlowResult
8 from homeassistant.const import CONF_TOKEN
9 from homeassistant.helpers import config_entry_oauth2_flow
10 
11 from . import api
12 from .const import DOMAIN, OAUTH_SCOPES
13 from .exceptions import FitbitApiException, FitbitAuthException
14 
15 _LOGGER = logging.getLogger(__name__)
16 
17 
19  config_entry_oauth2_flow.AbstractOAuth2FlowHandler, domain=DOMAIN
20 ):
21  """Config flow to handle fitbit OAuth2 authentication."""
22 
23  DOMAIN = DOMAIN
24 
25  @property
26  def logger(self) -> logging.Logger:
27  """Return logger."""
28  return logging.getLogger(__name__)
29 
30  @property
31  def extra_authorize_data(self) -> dict[str, str]:
32  """Extra data that needs to be appended to the authorize url."""
33  return {
34  "scope": " ".join(OAUTH_SCOPES),
35  "prompt": "consent" if self.sourcesource != SOURCE_REAUTH else "none",
36  }
37 
38  async def async_step_reauth(
39  self, entry_data: Mapping[str, Any]
40  ) -> ConfigFlowResult:
41  """Perform reauth upon an API authentication error."""
42  return await self.async_step_reauth_confirmasync_step_reauth_confirm()
43 
45  self, user_input: dict[str, Any] | None = None
46  ) -> ConfigFlowResult:
47  """Confirm reauth dialog."""
48  if user_input is None:
49  return self.async_show_form(step_id="reauth_confirm")
50  return await self.async_step_user()
51 
53  self, user_input: dict[str, Any] | None = None
54  ) -> ConfigFlowResult:
55  """Create config entry from external data with Fitbit specific error handling."""
56  try:
57  return await super().async_step_creation()
58  except FitbitAuthException as err:
59  _LOGGER.error(
60  "Failed to authenticate when creating Fitbit credentials: %s", err
61  )
62  return self.async_abort(reason="invalid_auth")
63  except FitbitApiException as err:
64  _LOGGER.error("Failed to create Fitbit credentials: %s", err)
65  return self.async_abort(reason="cannot_connect")
66 
67  async def async_oauth_create_entry(self, data: dict[str, Any]) -> ConfigFlowResult:
68  """Create an entry for the flow, or update existing entry."""
69 
70  client = api.ConfigFlowFitbitApi(self.hass, data[CONF_TOKEN])
71  try:
72  profile = await client.async_get_user_profile()
73  except FitbitAuthException as err:
74  _LOGGER.error("Failed to authenticate with Fitbit API: %s", err)
75  return self.async_abort(reason="invalid_access_token")
76  except FitbitApiException as err:
77  _LOGGER.error("Failed to fetch user profile for Fitbit API: %s", err)
78  return self.async_abort(reason="cannot_connect")
79 
80  await self.async_set_unique_id(profile.encoded_id)
81  if self.sourcesource == SOURCE_REAUTH:
82  self._abort_if_unique_id_mismatch(reason="wrong_account")
83  return self.async_update_reload_and_abort(
84  self._get_reauth_entry(), data=data
85  )
86 
87  self._abort_if_unique_id_configured()
88  return self.async_create_entry(title=profile.display_name, data=data)
ConfigFlowResult async_step_creation(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:54
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
Definition: config_flow.py:40
ConfigFlowResult async_oauth_create_entry(self, dict[str, Any] data)
Definition: config_flow.py:67
ConfigFlowResult async_step_reauth_confirm(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:46