"""Config flow for Baby Tracker.""" from __future__ import annotations import logging import uuid from typing import Any, Mapping import requests from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.const import CONF_EMAIL, CONF_PASSWORD from homeassistant.helpers.selector import TextSelector, TextSelectorConfig, TextSelectorType from .babytracker_api import AccountStateError, AuthenticationError, BabyTrackerClient, BabyTrackerError from .compat import vol from .const import CONF_DEVICE_UUID, DEVICE_NAME, DOMAIN _LOGGER = logging.getLogger(__name__) _PASSWORD_SELECTOR = TextSelector(TextSelectorConfig(type=TextSelectorType.PASSWORD)) USER_SCHEMA = vol.Schema( { vol.Required(CONF_EMAIL): TextSelector(TextSelectorConfig(type=TextSelectorType.EMAIL)), vol.Required(CONF_PASSWORD): _PASSWORD_SELECTOR, } ) REAUTH_SCHEMA = vol.Schema({vol.Required(CONF_PASSWORD): _PASSWORD_SELECTOR}) class BabyTrackerConfigFlow(ConfigFlow, domain=DOMAIN): VERSION = 1 async def _async_login(self, email: str, password: str, device_uuid: str) -> tuple[int | None, dict[str, str]]: client = BabyTrackerClient( email, password, device_uuid=device_uuid, device_name=DEVICE_NAME, device_os_info=DEVICE_NAME ) try: return await self.hass.async_add_executor_job(client.login), {} except AuthenticationError: return None, {"base": "invalid_auth"} except AccountStateError: return None, {"base": "account_state"} except (BabyTrackerError, requests.RequestException): return None, {"base": "cannot_connect"} except Exception: _LOGGER.exception("Unexpected error logging in") return None, {"base": "unknown"} async def async_step_user(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult: errors: dict[str, str] = {} if user_input is not None: # This ID stays with the entry for good. The server treats each new # value as a new device on the account. device_uuid = str(uuid.uuid4()) account_id, errors = await self._async_login( user_input[CONF_EMAIL], user_input[CONF_PASSWORD], device_uuid ) if not errors: await self.async_set_unique_id(str(account_id)) self._abort_if_unique_id_configured() return self.async_create_entry( title=user_input[CONF_EMAIL], data={**user_input, CONF_DEVICE_UUID: device_uuid}, ) return self.async_show_form(step_id="user", data_schema=USER_SCHEMA, errors=errors) async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> ConfigFlowResult: return await self.async_step_reauth_confirm() async def async_step_reauth_confirm(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult: errors: dict[str, str] = {} entry = self._get_reauth_entry() if user_input is not None: account_id, errors = await self._async_login( entry.data[CONF_EMAIL], user_input[CONF_PASSWORD], entry.data[CONF_DEVICE_UUID] ) if not errors: await self.async_set_unique_id(str(account_id)) self._abort_if_unique_id_mismatch(reason="wrong_account") return self.async_update_reload_and_abort(entry, data_updates=user_input) return self.async_show_form( step_id="reauth_confirm", data_schema=REAUTH_SCHEMA, errors=errors, description_placeholders={"email": entry.data[CONF_EMAIL]}, )