1 """Config flow for Monarch Money integration."""
3 from __future__
import annotations
8 from monarchmoney
import LoginFailedException, RequireMFAException
9 from monarchmoney.monarchmoney
import SESSION_FILE
10 from typedmonarchmoney
import TypedMonarchMoney
11 from typedmonarchmoney.models
import MonarchSubscription
12 import voluptuous
as vol
24 from .const
import CONF_MFA_CODE, DOMAIN, LOGGER
26 _LOGGER = logging.getLogger(__name__)
29 STEP_USER_DATA_SCHEMA = vol.Schema(
33 type=TextSelectorType.EMAIL,
38 type=TextSelectorType.PASSWORD,
44 STEP_MFA_DATA_SCHEMA = vol.Schema(
46 vol.Required(CONF_MFA_CODE): str,
54 email: str |
None =
None,
55 password: str |
None =
None,
57 """Validate the user input allows us to connect.
59 Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user. Upon success a session will be saved
63 email = data[CONF_EMAIL]
65 password = data[CONF_PASSWORD]
66 monarch_client = TypedMonarchMoney()
67 if CONF_MFA_CODE
in data:
68 mfa_code = data[CONF_MFA_CODE]
69 LOGGER.debug(
"Attempting to authenticate with MFA code")
71 await monarch_client.multi_factor_authenticate(email, password, mfa_code)
72 except KeyError
as err:
74 LOGGER.debug(
"Bad MFA Code")
77 LOGGER.debug(
"Attempting to authenticate")
79 await monarch_client.login(
83 use_saved_session=
False,
85 except RequireMFAException:
87 except LoginFailedException
as err:
88 raise InvalidAuth
from err
90 LOGGER.debug(f
"Connection successful - saving session to file {SESSION_FILE}")
91 LOGGER.debug(
"Obtaining subscription id")
92 subs: MonarchSubscription = await monarch_client.get_subscription_details()
93 assert subs
is not None
94 subscription_id = subs.id
96 CONF_TOKEN: monarch_client.token,
97 CONF_ID: subscription_id,
102 """Handle a config flow for Monarch Money."""
107 """Initialize config flow."""
108 self.
emailemail: str |
None =
None
109 self.
passwordpassword: str |
None =
None
112 self, user_input: dict[str, Any] |
None =
None
113 ) -> ConfigFlowResult:
114 """Handle the initial step."""
115 errors: dict[str, str] = {}
117 if user_input
is not None:
120 self.hass, user_input, email=self.
emailemail, password=self.
passwordpassword
122 except RequireMFAException:
123 self.
emailemail = user_input[CONF_EMAIL]
128 data_schema=STEP_MFA_DATA_SCHEMA,
129 errors={
"base":
"mfa_required"},
134 data_schema=STEP_MFA_DATA_SCHEMA,
135 errors={
"base":
"bad_mfa"},
138 errors[
"base"] =
"invalid_auth"
144 title=
"Monarch Money",
145 data={CONF_TOKEN: info[CONF_TOKEN]},
148 step_id=
"user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
153 """Error to indicate there is invalid auth."""
156 class BadMFA(HomeAssistantError):
157 """Error to indicate the MFA code was bad."""
ConfigFlowResult async_step_user(self, dict[str, Any]|None user_input=None)
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_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_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)
dict[str, Any] validate_login(HomeAssistant hass, dict[str, Any] data, str|None email=None, str|None password=None)