Home Assistant Unofficial Reference 2024.12.1
config_flow.py
Go to the documentation of this file.
1 """Config Flow for Hive."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Mapping
6 from typing import Any
7 
8 from apyhiveapi import Auth
9 from apyhiveapi.helper.hive_exceptions import (
10  HiveApiError,
11  HiveInvalid2FACode,
12  HiveInvalidPassword,
13  HiveInvalidUsername,
14 )
15 import voluptuous as vol
16 
17 from homeassistant.config_entries import (
18  SOURCE_REAUTH,
19  ConfigEntry,
20  ConfigFlow,
21  ConfigFlowResult,
22  OptionsFlow,
23 )
24 from homeassistant.const import CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_USERNAME
25 from homeassistant.core import callback
26 
27 from .const import CONF_CODE, CONF_DEVICE_NAME, CONFIG_ENTRY_VERSION, DOMAIN
28 
29 
30 class HiveFlowHandler(ConfigFlow, domain=DOMAIN):
31  """Handle a Hive config flow."""
32 
33  VERSION = CONFIG_ENTRY_VERSION
34  hive_auth: Auth
35 
36  def __init__(self) -> None:
37  """Initialize the config flow."""
38  self.data: dict[str, Any] = {}
39  self.tokenstokens: dict[str, str] = {}
40  self.entryentry: ConfigEntry | None = None
41  self.device_registrationdevice_registration: bool = False
42  self.device_namedevice_name = "Home Assistant"
43 
44  async def async_step_user(
45  self, user_input: dict[str, Any] | None = None
46  ) -> ConfigFlowResult:
47  """Prompt user input. Create or edit entry."""
48  errors: dict[str, str] = {}
49  # Login to Hive with user data.
50  if user_input is not None:
51  self.data.update(user_input)
52  self.hive_authhive_auth = Auth(
53  username=self.data[CONF_USERNAME], password=self.data[CONF_PASSWORD]
54  )
55 
56  # Get user from existing entry and abort if already setup
57  self.entryentry = await self.async_set_unique_idasync_set_unique_id(self.data[CONF_USERNAME])
58  if self.context["source"] != SOURCE_REAUTH:
59  self._abort_if_unique_id_configured_abort_if_unique_id_configured()
60 
61  # Login to the Hive.
62  try:
63  self.tokenstokens = await self.hive_authhive_auth.login()
64  except HiveInvalidUsername:
65  errors["base"] = "invalid_username"
66  except HiveInvalidPassword:
67  errors["base"] = "invalid_password"
68  except HiveApiError:
69  errors["base"] = "no_internet_available"
70 
71  if self.tokenstokens.get("ChallengeName") == "SMS_MFA":
72  # Complete SMS 2FA.
73  return await self.async_step_2faasync_step_2fa()
74 
75  if not errors:
76  # Complete the entry.
77  try:
78  return await self.async_setup_hive_entryasync_setup_hive_entry()
79  except UnknownHiveError:
80  errors["base"] = "unknown"
81 
82  # Show User Input form.
83  schema = vol.Schema(
84  {vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
85  )
86  return self.async_show_formasync_show_formasync_show_form(step_id="user", data_schema=schema, errors=errors)
87 
88  async def async_step_2fa(
89  self, user_input: dict[str, Any] | None = None
90  ) -> ConfigFlowResult:
91  """Handle 2fa step."""
92  errors = {}
93 
94  if user_input and user_input["2fa"] == "0000":
95  self.tokenstokens = await self.hive_authhive_auth.login()
96  elif user_input:
97  try:
98  self.tokenstokens = await self.hive_authhive_auth.sms_2fa(
99  user_input["2fa"], self.tokenstokens
100  )
101  except HiveInvalid2FACode:
102  errors["base"] = "invalid_code"
103  except HiveApiError:
104  errors["base"] = "no_internet_available"
105 
106  if not errors:
107  if self.context["source"] == SOURCE_REAUTH:
108  return await self.async_setup_hive_entryasync_setup_hive_entry()
109  self.device_registrationdevice_registration = True
110  return await self.async_step_configurationasync_step_configuration()
111 
112  schema = vol.Schema({vol.Required(CONF_CODE): str})
113  return self.async_show_formasync_show_formasync_show_form(step_id="2fa", data_schema=schema, errors=errors)
114 
116  self, user_input: dict[str, Any] | None = None
117  ) -> ConfigFlowResult:
118  """Handle hive configuration step."""
119  errors = {}
120 
121  if user_input:
122  if self.device_registrationdevice_registration:
123  self.device_namedevice_name = user_input["device_name"]
124  await self.hive_authhive_auth.device_registration(user_input["device_name"])
125  self.data["device_data"] = await self.hive_authhive_auth.get_device_data()
126 
127  try:
128  return await self.async_setup_hive_entryasync_setup_hive_entry()
129  except UnknownHiveError:
130  errors["base"] = "unknown"
131 
132  schema = vol.Schema(
133  {vol.Optional(CONF_DEVICE_NAME, default=self.device_namedevice_name): str}
134  )
135  return self.async_show_formasync_show_formasync_show_form(
136  step_id="configuration", data_schema=schema, errors=errors
137  )
138 
139  async def async_setup_hive_entry(self) -> ConfigFlowResult:
140  """Finish setup and create the config entry."""
141 
142  if "AuthenticationResult" not in self.tokenstokens:
143  raise UnknownHiveError
144 
145  # Setup the config entry
146  self.data["tokens"] = self.tokenstokens
147  if self.context["source"] == SOURCE_REAUTH:
148  assert self.entryentry
149  self.hass.config_entries.async_update_entry(
150  self.entryentry, title=self.data["username"], data=self.data
151  )
152  await self.hass.config_entries.async_reload(self.entryentry.entry_id)
153  return self.async_abortasync_abortasync_abort(reason="reauth_successful")
154  return self.async_create_entryasync_create_entryasync_create_entry(title=self.data["username"], data=self.data)
155 
156  async def async_step_reauth(
157  self, entry_data: Mapping[str, Any]
158  ) -> ConfigFlowResult:
159  """Re Authenticate a user."""
160  data = {
161  CONF_USERNAME: entry_data[CONF_USERNAME],
162  CONF_PASSWORD: entry_data[CONF_PASSWORD],
163  }
164  return await self.async_step_userasync_step_userasync_step_user(data)
165 
166  async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
167  """Import user."""
168  return await self.async_step_userasync_step_userasync_step_user(import_data)
169 
170  @staticmethod
171  @callback
173  config_entry: ConfigEntry,
174  ) -> HiveOptionsFlowHandler:
175  """Hive options callback."""
176  return HiveOptionsFlowHandler(config_entry)
177 
178 
180  """Config flow options for Hive."""
181 
182  def __init__(self, config_entry: ConfigEntry) -> None:
183  """Initialize Hive options flow."""
184  self.hivehive = None
185  self.intervalinterval = config_entry.options.get(CONF_SCAN_INTERVAL, 120)
186 
187  async def async_step_init(
188  self, user_input: dict[str, Any] | None = None
189  ) -> ConfigFlowResult:
190  """Manage the options."""
191  return await self.async_step_userasync_step_user()
192 
193  async def async_step_user(
194  self, user_input: dict[str, Any] | None = None
195  ) -> ConfigFlowResult:
196  """Handle a flow initialized by the user."""
197  self.hivehive = self.hass.data["hive"][self.config_entryconfig_entryconfig_entry.entry_id]
198  errors: dict[str, str] = {}
199  if user_input is not None:
200  new_interval = user_input.get(CONF_SCAN_INTERVAL)
201  assert self.hivehive
202  await self.hivehive.updateInterval(new_interval)
203  return self.async_create_entryasync_create_entry(title="", data=user_input)
204 
205  schema = vol.Schema(
206  {
207  vol.Optional(CONF_SCAN_INTERVAL, default=self.intervalinterval): vol.All(
208  vol.Coerce(int), vol.Range(min=30)
209  )
210  }
211  )
212  return self.async_show_formasync_show_form(step_id="user", data_schema=schema, errors=errors)
213 
214 
215 class UnknownHiveError(Exception):
216  """Catch unknown hive error."""
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:46
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
Definition: config_flow.py:158
ConfigFlowResult async_step_configuration(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:117
ConfigFlowResult async_step_import(self, dict[str, Any] import_data)
Definition: config_flow.py:166
ConfigFlowResult async_step_2fa(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:90
HiveOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
Definition: config_flow.py:174
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:195
ConfigFlowResult async_step_init(self, dict[str, Any]|None user_input=None)
Definition: config_flow.py:189
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry|None async_set_unique_id(self, str|None unique_id=None, *bool raise_on_progress=True)
ConfigFlowResult async_create_entry(self, *str title, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None, Mapping[str, Any]|None options=None)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
ConfigFlowResult async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
None config_entry(self, ConfigEntry value)
_FlowResultT async_show_form(self, *str|None step_id=None, vol.Schema|None data_schema=None, dict[str, str]|None errors=None, Mapping[str, str]|None description_placeholders=None, bool|None last_step=None, str|None preview=None)
_FlowResultT async_create_entry(self, *str|None title=None, Mapping[str, Any] data, str|None description=None, Mapping[str, str]|None description_placeholders=None)
_FlowResultT async_abort(self, *str reason, Mapping[str, str]|None description_placeholders=None)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
IssData update(pyiss.ISS iss)
Definition: __init__.py:33