"""SFR Box config flow.""" from __future__ import annotations from collections.abc import Mapping from typing import Any from sfrbox_api.bridge import SFRBox from sfrbox_api.exceptions import SFRBoxAuthenticationError, SFRBoxError import voluptuous as vol from homeassistant.config_entries import ConfigEntry, ConfigFlow from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers import selector from homeassistant.helpers.httpx_client import get_async_client from .const import DEFAULT_HOST, DEFAULT_USERNAME, DOMAIN DATA_SCHEMA = vol.Schema( { vol.Required(CONF_HOST, default=DEFAULT_HOST): selector.TextSelector(), } ) AUTH_SCHEMA = vol.Schema( { vol.Required(CONF_USERNAME, default=DEFAULT_USERNAME): selector.TextSelector(), vol.Required(CONF_PASSWORD): selector.TextSelector( selector.TextSelectorConfig(type=selector.TextSelectorType.PASSWORD) ), } ) class SFRBoxFlowHandler(ConfigFlow, domain=DOMAIN): """SFR Box config flow.""" VERSION = 1 _box: SFRBox _config: dict[str, Any] = {} _reauth_entry: ConfigEntry | None = None async def async_step_user( self, user_input: dict[str, str] | None = None ) -> FlowResult: """Handle a flow initialized by the user.""" errors = {} if user_input is not None: box = SFRBox(ip=user_input[CONF_HOST], client=get_async_client(self.hass)) try: system_info = await box.system_get_info() except SFRBoxError: errors["base"] = "cannot_connect" else: await self.async_set_unique_id(system_info.mac_addr) self._abort_if_unique_id_configured() self._async_abort_entries_match({CONF_HOST: user_input[CONF_HOST]}) self._box = box self._config.update(user_input) return await self.async_step_choose_auth() data_schema = self.add_suggested_values_to_schema(DATA_SCHEMA, user_input) return self.async_show_form( step_id="user", data_schema=data_schema, errors=errors ) async def async_step_choose_auth( self, user_input: dict[str, str] | None = None ) -> FlowResult: """Handle a flow initialized by the user.""" return self.async_show_menu( step_id="choose_auth", menu_options=["auth", "skip_auth"], ) async def async_step_auth( self, user_input: dict[str, str] | None = None ) -> FlowResult: """Check authentication.""" errors = {} if user_input is not None: try: await self._box.authenticate( username=user_input[CONF_USERNAME], password=user_input[CONF_PASSWORD], ) except SFRBoxAuthenticationError: errors["base"] = "invalid_auth" else: if reauth_entry := self._reauth_entry: data = {**reauth_entry.data, **user_input} self.hass.config_entries.async_update_entry(reauth_entry, data=data) self.hass.async_create_task( self.hass.config_entries.async_reload(reauth_entry.entry_id) ) return self.async_abort(reason="reauth_successful") self._config.update(user_input) return self.async_create_entry(title="SFR Box", data=self._config) suggested_values: Mapping[str, Any] | None = user_input if self._reauth_entry and not suggested_values: suggested_values = self._reauth_entry.data data_schema = self.add_suggested_values_to_schema(AUTH_SCHEMA, suggested_values) return self.async_show_form( step_id="auth", data_schema=data_schema, errors=errors ) async def async_step_skip_auth( self, user_input: dict[str, str] | None = None ) -> FlowResult: """Skip authentication.""" return self.async_create_entry(title="SFR Box", data=self._config) async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult: """Handle failed credentials.""" self._reauth_entry = self.hass.config_entries.async_get_entry( self.context["entry_id"] ) self._box = SFRBox(ip=entry_data[CONF_HOST], client=get_async_client(self.hass)) return await self.async_step_auth()