1 """Config flow for fritzbox_callmonitor."""
3 from __future__
import annotations
5 from collections.abc
import Mapping
6 from enum
import StrEnum
7 from typing
import Any, cast
9 from fritzconnection
import FritzConnection
10 from fritzconnection.core.exceptions
import FritzConnectionException, FritzSecurityError
11 from requests.exceptions
import ConnectionError
as RequestsConnectionError
12 import voluptuous
as vol
30 from .base
import FritzBoxPhonebook
40 FRITZ_ATTR_SERIAL_NUMBER,
44 DATA_SCHEMA_USER = vol.Schema(
46 vol.Required(CONF_HOST, default=DEFAULT_HOST): str,
47 vol.Required(CONF_PORT, default=DEFAULT_PORT): vol.Coerce(int),
48 vol.Required(CONF_USERNAME, default=DEFAULT_USERNAME): str,
49 vol.Required(CONF_PASSWORD): str,
55 """FritzBoxPhonebook connection result."""
57 INVALID_AUTH =
"invalid_auth"
58 INSUFFICIENT_PERMISSIONS =
"insufficient_permissions"
59 MALFORMED_PREFIXES =
"malformed_prefixes"
60 NO_DEVIES_FOUND =
"no_devices_found"
65 """Handle a fritzbox_callmonitor config flow."""
76 _phonebook_ids: list[int]
77 _fritzbox_phonebook: FritzBoxPhonebook
81 """Initialize flow."""
85 """Create and return an config entry."""
89 CONF_HOST: self.
_host_host,
90 CONF_PORT: self.
_port_port,
99 """Try to connect and check auth."""
101 host=self.
_host_host,
110 fritz_connection = FritzConnection(
113 info = fritz_connection.updatecheck
114 except RequestsConnectionError:
115 return ConnectResult.NO_DEVIES_FOUND
116 except FritzSecurityError:
117 return ConnectResult.INSUFFICIENT_PERMISSIONS
118 except FritzConnectionException:
119 return ConnectResult.INVALID_AUTH
122 return ConnectResult.SUCCESS
125 """Return name of phonebook for given phonebook_id."""
126 phonebook_info = await self.hass.async_add_executor_job(
129 return cast(str, phonebook_info[FRITZ_ATTR_NAME])
132 """Return list of names for all available phonebooks."""
141 config_entry: ConfigEntry,
142 ) -> FritzBoxCallMonitorOptionsFlowHandler:
143 """Get the options flow for this handler."""
147 self, user_input: dict[str, Any] |
None =
None
148 ) -> ConfigFlowResult:
149 """Handle a flow initialized by the user."""
151 if user_input
is None:
153 step_id=
"user", data_schema=DATA_SCHEMA_USER, errors={}
156 self.
_host_host = user_input[CONF_HOST]
157 self.
_port_port = user_input[CONF_PORT]
161 result = await self.hass.async_add_executor_job(self.
_try_connect_try_connect)
163 if result == ConnectResult.INVALID_AUTH:
166 data_schema=DATA_SCHEMA_USER,
167 errors={
"base": ConnectResult.INVALID_AUTH},
170 if result != ConnectResult.SUCCESS:
173 if self.context[
"source"] == SOURCE_IMPORT:
184 await self.
async_set_unique_idasync_set_unique_id(f
"{self._serial_number}-{self._phonebook_id}")
190 self, user_input: dict[str, Any] |
None =
None
191 ) -> ConfigFlowResult:
192 """Handle a flow to chose one of multiple available phonebooks."""
197 if user_input
is None:
200 data_schema=vol.Schema(
201 {vol.Required(CONF_PHONEBOOK): vol.In(self.
_phonebook_names_phonebook_names)}
209 await self.
async_set_unique_idasync_set_unique_id(f
"{self._serial_number}-{self._phonebook_id}")
215 self, entry_data: Mapping[str, Any]
216 ) -> ConfigFlowResult:
217 """Handle flow upon an API authentication error."""
219 self.
_host_host = entry_data[CONF_HOST]
220 self.
_port_port = entry_data[CONF_PORT]
221 self.
_username_username = entry_data[CONF_USERNAME]
222 self.
_password_password = entry_data[CONF_PASSWORD]
228 self, user_input: dict[str, Any], errors: dict[str, str] |
None =
None
229 ) -> ConfigFlowResult:
230 """Show the reauth form to the user."""
231 default_username = user_input.get(CONF_USERNAME)
233 step_id=
"reauth_confirm",
234 data_schema=vol.Schema(
236 vol.Required(CONF_USERNAME, default=default_username): str,
237 vol.Required(CONF_PASSWORD): str,
240 description_placeholders={
"host": self.
_host_host},
245 self, user_input: dict[str, Any] |
None =
None
246 ) -> ConfigFlowResult:
247 """Dialog that informs the user that reauth is required."""
248 if user_input
is None:
250 user_input={CONF_USERNAME: self.
_username_username}
253 self.
_username_username = user_input[CONF_USERNAME]
254 self.
_password_password = user_input[CONF_PASSWORD]
257 error := await self.hass.async_add_executor_job(self.
_try_connect_try_connect)
258 )
is not ConnectResult.SUCCESS:
260 user_input=user_input, errors={
"base": error}
263 self.hass.config_entries.async_update_entry(
266 CONF_HOST: self.
_host_host,
267 CONF_PORT: self.
_port_port,
274 await self.hass.config_entries.async_reload(self.
_entry_entry.entry_id)
279 """Handle a fritzbox_callmonitor options flow."""
283 """Check if prefixes are valid."""
284 return bool(prefixes.strip())
if prefixes
else prefixes
is None
288 """Get list of prefixes."""
291 return [prefix.strip()
for prefix
in prefixes.split(
",")]
294 """Get option schema for entering prefixes."""
307 self, user_input: dict[str, Any] |
None =
None
308 ) -> ConfigFlowResult:
309 """Manage the options."""
313 if user_input
is None:
316 data_schema=option_schema_prefixes,
320 prefixes: str |
None = user_input.get(CONF_PREFIXES)
325 data_schema=option_schema_prefixes,
326 errors={
"base": ConnectResult.MALFORMED_PREFIXES},
list[str] _get_list_of_phonebook_names(self)
str _get_name_of_phonebook(self, int phonebook_id)
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
ConfigFlowResult async_step_reauth(self, Mapping[str, Any] entry_data)
ConfigFlowResult async_step_reauth_confirm(self, dict[str, Any]|None user_input=None)
ConfigFlowResult _show_setup_form_reauth_confirm(self, dict[str, Any] user_input, dict[str, str]|None errors=None)
FritzBoxCallMonitorOptionsFlowHandler async_get_options_flow(ConfigEntry config_entry)
ConfigFlowResult async_step_phonebook(self, dict[str, Any]|None user_input=None)
ConnectResult _try_connect(self)
ConfigFlowResult _get_config_entry(self)
bool _are_prefixes_valid(cls, str|None prefixes)
list[str]|None _get_list_of_prefixes(cls, str|None prefixes)
ConfigFlowResult async_step_init(self, dict[str, Any]|None user_input=None)
vol.Schema _get_option_schema_prefixes(self)
None _abort_if_unique_id_configured(self, dict[str, Any]|None updates=None, bool reload_on_update=True, *str error="already_configured")
ConfigEntry _get_reauth_entry(self)
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_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)
ConfigEntry config_entry(self)
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)