async def async_step_process(self, step_id, user_input=None): """Handle the input processing of the config flow.""" _LOGGER.debug( "Processing input for %s: %s", step_id, obfuscate(user_input), ) self._save_user_input_to_config(user_input=user_input) if user_input and user_input.get(CONF_PROXY): return await self.async_step_user(user_input=None) if user_input: try: await self.login.login(data=user_input) except AlexapyConnectionError: self.automatic_steps = 0 return self.async_show_form( step_id=step_id, errors={"base": "connection_error"}, description_placeholders={"message": ""}, ) except BaseException as ex: # pylint: disable=broad-except _LOGGER.warning("Unknown error: %s", ex) if self.config[CONF_DEBUG]: raise self.automatic_steps = 0 return self.async_show_form( step_id=step_id, errors={"base": "unknown_error"}, description_placeholders={"message": ""}, ) return await self._test_login()
async def async_step_reauth(self, user_input=None): """Handle reauth processing for the config flow.""" self._save_user_input_to_config(user_input) self.config["reauth"] = True reauth_schema = self._update_schema_defaults() _LOGGER.debug( "Creating reauth form with %s", obfuscate(self.config), ) self.automatic_steps = 0 if self.login is None: try: self.login = self.hass.data[DATA_ALEXAMEDIA]["accounts"][ self.config[CONF_EMAIL] ].get("login_obj") except KeyError: self.login = None seconds_since_login: int = ( datetime.datetime.now() - self.login.stats["login_timestamp"] ).seconds if self.login else 60 if seconds_since_login < 60: _LOGGER.debug( "Relogin requested within %s seconds; manual login required", seconds_since_login, ) return self.async_show_form( step_id="user", data_schema=vol.Schema(reauth_schema), description_placeholders={"message": "REAUTH"}, ) _LOGGER.debug("Attempting automatic relogin") await sleep(15) return await self.async_step_user(self.config)
async def test_login_status(hass, config_entry, login) -> bool: """Test the login status and spawn requests for info.""" _LOGGER.debug("Testing login status: %s", login.status) if login.status and login.status.get("login_successful"): return True account = config_entry.data _LOGGER.debug("Logging in: %s %s", obfuscate(account), in_progess_instances(hass)) _LOGGER.debug("Login stats: %s", login.stats) message: Text = ( "Reauthenticate on the [Integrations](/config/integrations) page. " ) if login.stats.get("login_timestamp") != datetime(1, 1, 1): elaspsed_time: str = str(datetime.now() - login.stats.get("login_timestamp")) api_calls: int = login.stats.get("api_calls") message += f"Relogin required after {elaspsed_time} and {api_calls} api calls." hass.components.persistent_notification.async_create( title="Alexa Media Reauthentication Required", message=message, notification_id="alexa_media_relogin_required", ) flow = hass.data[DATA_ALEXAMEDIA]["config_flows"].get( f"{account[CONF_EMAIL]} - {account[CONF_URL]}" ) if flow: if flow.get("flow_id") in in_progess_instances(hass): _LOGGER.debug("Existing config flow detected") return False _LOGGER.debug("Stopping orphaned config flow %s", flow.get("flow_id")) try: hass.config_entries.flow.async_abort(flow.get("flow_id")) except UnknownFlow: pass hass.data[DATA_ALEXAMEDIA]["config_flows"][ f"{account[CONF_EMAIL]} - {account[CONF_URL]}" ] = None _LOGGER.debug("Creating new config flow to login") hass.data[DATA_ALEXAMEDIA]["config_flows"][ f"{account[CONF_EMAIL]} - {account[CONF_URL]}" ] = await hass.config_entries.flow.async_init( DOMAIN, context={"source": "reauth"}, data={ CONF_EMAIL: account[CONF_EMAIL], CONF_PASSWORD: account[CONF_PASSWORD], CONF_URL: account[CONF_URL], CONF_DEBUG: account[CONF_DEBUG], CONF_INCLUDE_DEVICES: account[CONF_INCLUDE_DEVICES], CONF_EXCLUDE_DEVICES: account[CONF_EXCLUDE_DEVICES], CONF_SCAN_INTERVAL: account[CONF_SCAN_INTERVAL].total_seconds() if isinstance(account[CONF_SCAN_INTERVAL], timedelta) else account[CONF_SCAN_INTERVAL], CONF_COOKIES_TXT: account.get(CONF_COOKIES_TXT, ""), CONF_OTPSECRET: account.get(CONF_OTPSECRET, ""), }, ) return False
async def async_step_process(self, step_id, user_input=None): """Handle the input processing of the config flow.""" _LOGGER.debug( "Processing input for %s: %s", step_id, obfuscate(user_input), ) self._save_user_input_to_config(user_input=user_input) if user_input: return await self.async_step_user(user_input=None) return await self._test_login()
async def async_step_reauth(self, user_input=None): """Handle reauth processing for the config flow.""" self._save_user_input_to_config(user_input) reauth_schema = self._update_schema_defaults() _LOGGER.debug( "Creating reauth form with %s", obfuscate(self.config), ) self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(reauth_schema), description_placeholders={"message": "REAUTH"}, )
async def _test_login(self): login = self.login email = login.email _LOGGER.debug("Testing login status: %s", login.status) if login.status and login.status.get("login_successful"): existing_entry = await self.async_set_unique_id( f"{email} - {login.url}") self.config.pop(CONF_COOKIES_TXT) if existing_entry: self.hass.config_entries.async_update_entry(existing_entry, data=self.config) _LOGGER.debug("Reauth successful for %s", hide_email(email)) self.hass.bus.async_fire( "alexa_media_relogin_success", event_data={ "email": hide_email(email), "url": login.url }, ) self.hass.components.persistent_notification.async_dismiss( "alexa_media_relogin_required") self.hass.data[DATA_ALEXAMEDIA]["accounts"][ self.config[CONF_EMAIL]]["login_obj"] = self.login self.hass.data[DATA_ALEXAMEDIA]["config_flows"][ f"{email} - {login.url}"] = None return self.async_abort(reason="reauth_successful") _LOGGER.debug("Setting up Alexa devices with %s", dict(obfuscate(self.config))) self._abort_if_unique_id_configured(self.config) return self.async_create_entry( title=f"{login.email} - {login.url}", data=self.config) if login.status and login.status.get("captcha_required"): new_schema = self._update_ord_dict( self.captcha_schema, { vol.Required(CONF_PASSWORD, default=self.config[CONF_PASSWORD]): str, vol.Optional( CONF_SECURITYCODE, default=self.securitycode if self.securitycode else "", ): str, }, ) _LOGGER.debug("Creating config_flow to request captcha") self.automatic_steps = 0 return self.async_show_form( step_id="captcha", data_schema=vol.Schema(new_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "captcha_image": "[![captcha]({0})]({0})".format( login.status["captcha_image_url"]), "message": f" \n> {login.status.get('error_message','')}", }, ) if login.status and login.status.get("securitycode_required"): _LOGGER.debug( "Creating config_flow to request 2FA. Saved security code %s", self.securitycode, ) if self.securitycode and self.automatic_steps < 1: _LOGGER.debug("Automatically submitting securitycode %s", self.securitycode) self.automatic_steps += 1 await sleep(1) return await self.async_step_twofactor( user_input={CONF_SECURITYCODE: self.securitycode}) self.twofactor_schema = OrderedDict([( vol.Required(CONF_SECURITYCODE, ), str, )]) self.automatic_steps = 0 return self.async_show_form( step_id="twofactor", data_schema=vol.Schema(self.twofactor_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "message": f" \n> {login.status.get('error_message','')}", }, ) if login.status and login.status.get("claimspicker_required"): error_message = f" \n> {login.status.get('error_message', '')}" _LOGGER.debug("Creating config_flow to select verification method") claimspicker_message = login.status["claimspicker_message"] self.automatic_steps = 0 return self.async_show_form( step_id="claimspicker", data_schema=vol.Schema(self.claimspicker_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "message": " \n> {0} \n> {1}".format(claimspicker_message, error_message), }, ) if login.status and login.status.get("authselect_required"): _LOGGER.debug("Creating config_flow to select OTA method") error_message = login.status.get("error_message", "") authselect_message = login.status["authselect_message"] self.automatic_steps = 0 return self.async_show_form( step_id="authselect", data_schema=vol.Schema(self.authselect_schema), description_placeholders={ "email": login.email, "url": login.url, "message": " \n> {0} \n> {1}".format(authselect_message, error_message), }, ) if login.status and login.status.get("verificationcode_required"): _LOGGER.debug("Creating config_flow to enter verification code") self.automatic_steps = 0 return self.async_show_form( step_id="verificationcode", data_schema=vol.Schema(self.verificationcode_schema), ) if login.status and login.status.get("force_get"): _LOGGER.debug("Creating config_flow to wait for user action") self.automatic_steps = 0 return self.async_show_form( step_id="action_required", data_schema=vol.Schema(OrderedDict()), description_placeholders={ "email": login.email, "url": login.url, "message": f" \n>{login.status.get('message','')} \n", }, ) if login.status and login.status.get("login_failed"): _LOGGER.debug("Login failed: %s", login.status.get("login_failed")) await login.close() self.hass.components.persistent_notification.async_dismiss( "alexa_media_relogin_required") return self.async_abort(reason=login.status.get("login_failed"), ) new_schema = self._update_schema_defaults() if login.status and login.status.get("error_message"): _LOGGER.debug("Login error detected: %s", login.status.get("error_message")) if login.status.get("error_message") in { "There was a problem\n Enter a valid email or mobile number\n " }: _LOGGER.debug( "Trying automatic resubmission for error_message 'valid email'" ) self.automatic_steps += 1 await sleep(1) return await self.async_step_user(user_input=self.config) self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(new_schema), description_placeholders={ "message": f" \n> {login.status.get('error_message','')}" }, ) self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(new_schema), description_placeholders={ "message": f" \n> {login.status.get('error_message','')}" }, )
async def _test_login(self): # pylint: disable=too-many-statements, too-many-return-statements login = self.login email = login.email _LOGGER.debug("Testing login status: %s", login.status) if login.status and login.status.get("login_successful"): existing_entry = await self.async_set_unique_id( f"{email} - {login.url}") if self.config.get("reauth"): self.config.pop("reauth") if self.config.get(CONF_SECURITYCODE): self.config.pop(CONF_SECURITYCODE) if self.config.get("hass_url"): self.config.pop("hass_url") self.config[CONF_OAUTH] = { "access_token": login.access_token, "refresh_token": login.refresh_token, "expires_in": login.expires_in, "mac_dms": login.mac_dms } self.hass.data.setdefault( DATA_ALEXAMEDIA, { "accounts": {}, "config_flows": {}, "notify_service": None }, ) self.hass.data[DATA_ALEXAMEDIA].setdefault("accounts", {}) self.hass.data[DATA_ALEXAMEDIA].setdefault("config_flows", {}) if existing_entry: self.hass.config_entries.async_update_entry(existing_entry, data=self.config) _LOGGER.debug("Reauth successful for %s", hide_email(email)) self.hass.bus.async_fire( "alexa_media_relogin_success", event_data={ "email": hide_email(email), "url": login.url }, ) self.hass.components.persistent_notification.async_dismiss( f"alexa_media_{slugify(email)}{slugify(login.url[7:])}") if not self.hass.data[DATA_ALEXAMEDIA]["accounts"].get( self.config[CONF_EMAIL]): self.hass.data[DATA_ALEXAMEDIA]["accounts"][ self.config[CONF_EMAIL]] = {} self.hass.data[DATA_ALEXAMEDIA]["accounts"][ self.config[CONF_EMAIL]]["login_obj"] = self.login self.hass.data[DATA_ALEXAMEDIA]["config_flows"][ f"{email} - {login.url}"] = None return self.async_abort(reason="reauth_successful") _LOGGER.debug("Setting up Alexa devices with %s", dict(obfuscate(self.config))) self._abort_if_unique_id_configured(self.config) return self.async_create_entry( title=f"{login.email} - {login.url}", data=self.config) if login.status and login.status.get("securitycode_required"): _LOGGER.debug( "Creating config_flow to request 2FA. Saved security code %s", self.securitycode, ) generated_securitycode: str = login.get_totp_token() if (self.securitycode or generated_securitycode) and self.automatic_steps < 2: if self.securitycode: _LOGGER.debug("Automatically submitting securitycode %s", self.securitycode) else: _LOGGER.debug( "Automatically submitting generated securitycode %s", generated_securitycode, ) self.automatic_steps += 1 await sleep(5) if generated_securitycode: return await self.async_step_twofactor( user_input={CONF_SECURITYCODE: generated_securitycode}) return await self.async_step_twofactor( user_input={CONF_SECURITYCODE: self.securitycode}) if login.status and (login.status.get("login_failed")): _LOGGER.debug("Login failed: %s", login.status.get("login_failed")) await login.close() self.hass.components.persistent_notification.async_dismiss( f"alexa_media_{slugify(email)}{slugify(login.url[7:])}") return self.async_abort(reason="login_failed") new_schema = self._update_schema_defaults() if login.status and login.status.get("error_message"): _LOGGER.debug("Login error detected: %s", login.status.get("error_message")) if (login.status.get("error_message") in { "There was a problem\n Enter a valid email or mobile number\n " } and self.automatic_steps < 2): _LOGGER.debug( "Trying automatic resubmission %s for error_message 'valid email'", self.automatic_steps, ) self.automatic_steps += 1 await sleep(5) return await self.async_step_user_legacy(user_input=self.config ) _LOGGER.debug( "Done with automatic resubmission for error_message 'valid email'; returning error message", ) self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(new_schema), description_placeholders={ "message": f" \n> {login.status.get('error_message','')}" }, )
async def _test_login(self): # pylint: disable=too-many-statements, too-many-return-statements login = self.login email = login.email _LOGGER.debug("Testing login status: %s", login.status) if login.status and login.status.get("login_successful"): existing_entry = await self.async_set_unique_id(f"{email} - {login.url}") if self.config.get("reauth"): self.config.pop("reauth") if self.config.get(CONF_SECURITYCODE): self.config.pop(CONF_SECURITYCODE) if self.config.get(CONF_PROXY): self.config.pop(CONF_PROXY) if self.config.get("hass_url"): self.config.pop("hass_url") self.config[CONF_OAUTH] = { "access_token": login.access_token, "refresh_token": login.refresh_token, "expires_in": login.expires_in, } self.hass.data.setdefault( DATA_ALEXAMEDIA, {"accounts": {}, "config_flows": {}}, ) if existing_entry: self.hass.config_entries.async_update_entry( existing_entry, data=self.config ) _LOGGER.debug("Reauth successful for %s", hide_email(email)) self.hass.bus.async_fire( "alexa_media_relogin_success", event_data={"email": hide_email(email), "url": login.url}, ) self.hass.components.persistent_notification.async_dismiss( f"alexa_media_{slugify(email)}{slugify(login.url[7:])}" ) self.hass.data[DATA_ALEXAMEDIA]["accounts"][self.config[CONF_EMAIL]][ "login_obj" ] = self.login self.hass.data[DATA_ALEXAMEDIA]["config_flows"][ f"{email} - {login.url}" ] = None return self.async_abort(reason="reauth_successful") _LOGGER.debug( "Setting up Alexa devices with %s", dict(obfuscate(self.config)) ) self._abort_if_unique_id_configured(self.config) return self.async_create_entry( title=f"{login.email} - {login.url}", data=self.config ) if login.status and login.status.get("captcha_required"): new_schema = self._update_ord_dict( self.captcha_schema, { vol.Required( CONF_PASSWORD, default=self.config[CONF_PASSWORD] ): str, vol.Optional( CONF_SECURITYCODE, default=self.securitycode if self.securitycode else "", ): str, }, ) _LOGGER.debug("Creating config_flow to request captcha") self.automatic_steps = 0 return self.async_show_form( step_id="captcha", data_schema=vol.Schema(new_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "captcha_image": "[![captcha]({0})]({0})".format( login.status["captcha_image_url"] ), "message": f" \n> {login.status.get('error_message','')}", }, ) if login.status and login.status.get("securitycode_required"): _LOGGER.debug( "Creating config_flow to request 2FA. Saved security code %s", self.securitycode, ) generated_securitycode: Text = login.get_totp_token() if ( self.securitycode or generated_securitycode ) and self.automatic_steps < 2: if self.securitycode: _LOGGER.debug( "Automatically submitting securitycode %s", self.securitycode ) else: _LOGGER.debug( "Automatically submitting generated securitycode %s", generated_securitycode, ) self.automatic_steps += 1 await sleep(5) if generated_securitycode: return await self.async_step_twofactor( user_input={CONF_SECURITYCODE: generated_securitycode} ) return await self.async_step_twofactor( user_input={CONF_SECURITYCODE: self.securitycode} ) self.twofactor_schema = OrderedDict( [ (vol.Optional(CONF_PROXY, default=False), bool), ( vol.Required( CONF_SECURITYCODE, default=self.securitycode if self.securitycode else "", ), str, ), ] ) self.automatic_steps = 0 return self.async_show_form( step_id="twofactor", data_schema=vol.Schema(self.twofactor_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "message": f" \n> {login.status.get('error_message','')}", }, ) if login.status and login.status.get("claimspicker_required"): error_message = f" \n> {login.status.get('error_message', '')}" _LOGGER.debug("Creating config_flow to select verification method") claimspicker_message = login.status["claimspicker_message"] self.automatic_steps = 0 return self.async_show_form( step_id="claimspicker", data_schema=vol.Schema(self.claimspicker_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "message": " \n> {} \n> {}".format( claimspicker_message, error_message ), }, ) if login.status and login.status.get("authselect_required"): _LOGGER.debug("Creating config_flow to select OTA method") error_message = login.status.get("error_message", "") authselect_message = login.status["authselect_message"] self.automatic_steps = 0 return self.async_show_form( step_id="authselect", data_schema=vol.Schema(self.authselect_schema), description_placeholders={ "email": login.email, "url": login.url, "message": " \n> {} \n> {}".format( authselect_message, error_message ), }, ) if login.status and login.status.get("verificationcode_required"): _LOGGER.debug("Creating config_flow to enter verification code") self.automatic_steps = 0 return self.async_show_form( step_id="verificationcode", data_schema=vol.Schema(self.verificationcode_schema), ) if ( login.status and login.status.get("force_get") and not login.status.get("ap_error_href") ): _LOGGER.debug("Creating config_flow to wait for user action") self.automatic_steps = 0 return self.async_show_form( step_id="action_required", data_schema=vol.Schema( OrderedDict([(vol.Optional(CONF_PROXY, default=False), bool)]) ), description_placeholders={ "email": login.email, "url": login.url, "message": f" \n>{login.status.get('message','')} \n", }, ) if login.status and (login.status.get("login_failed")): if login.oauth_login: _LOGGER.debug("Trying non-oauth login") await login.reset() login.oauth_login = False await login.login() return await self._test_login() _LOGGER.debug("Login failed: %s", login.status.get("login_failed")) await login.close() self.hass.components.persistent_notification.async_dismiss( f"alexa_media_{slugify(email)}{slugify(login.url[7:])}" ) return self.async_abort(reason="login_failed") new_schema = self._update_schema_defaults() if login.status and login.status.get("error_message"): _LOGGER.debug("Login error detected: %s", login.status.get("error_message")) if ( login.status.get("error_message") in { "There was a problem\n Enter a valid email or mobile number\n " } and self.automatic_steps < 2 ): _LOGGER.debug( "Trying automatic resubmission %s for error_message 'valid email'", self.automatic_steps, ) self.automatic_steps += 1 await sleep(5) return await self.async_step_user_legacy(user_input=self.config) _LOGGER.debug( "Done with automatic resubmission for error_message 'valid email'; returning error message", ) self.automatic_steps = 0 return self.async_show_form( step_id="user_legacy", data_schema=vol.Schema(new_schema), description_placeholders={ "message": f" \n> {login.status.get('error_message','')}" }, ) self.automatic_steps = 0 return self.async_show_form( step_id="user_legacy", data_schema=vol.Schema(new_schema), description_placeholders={ "message": f" \n> {login.status.get('error_message','')}" }, )
async def _test_login(self): login = self.login email = login.email _LOGGER.debug("Testing login status: %s", login.status) if login.status and login.status.get("login_successful"): existing_entry = await self.async_set_unique_id( f"{email} - {login.url}") if existing_entry: self.hass.config_entries.async_update_entry(existing_entry, data=self.config) _LOGGER.debug("Reauth successful for %s", hide_email(email)) self.hass.bus.async_fire( "alexa_media_player_relogin_success", event_data={ "email": hide_email(email), "url": login.url }, ) self.hass.components.persistent_notification.async_dismiss( "alexa_media_player_relogin_required") self.hass.data[DATA_ALEXAMEDIA]["accounts"][ self.config[CONF_EMAIL]]["login_obj"] = self.login return self.async_abort(reason="reauth_successful") _LOGGER.debug("Setting up Alexa devices with %s", dict(obfuscate(self.config))) self._abort_if_unique_id_configured(self.config) return self.async_create_entry( title=f"{login.email} - {login.url}", data=self.config) if login.status and login.status.get("captcha_required"): new_schema = self._update_ord_dict( self.captcha_schema, { vol.Required(CONF_PASSWORD, default=self.config[CONF_PASSWORD]): str }, ) _LOGGER.debug("Creating config_flow to request captcha") return self.async_show_form( step_id="captcha", data_schema=vol.Schema(new_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "captcha_image": "[![captcha]({0})]({0})".format( login.status["captcha_image_url"]), "message": f"\n> {login.status.get('error_message','')}", }, ) if login.status and login.status.get("securitycode_required"): _LOGGER.debug("Creating config_flow to request 2FA") return self.async_show_form( step_id="twofactor", data_schema=vol.Schema(self.twofactor_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "message": f"\n> {login.status.get('error_message','')}", }, ) if login.status and login.status.get("claimspicker_required"): error_message = f"\n> {login.status.get('error_message', '')}" _LOGGER.debug("Creating config_flow to select verification method") claimspicker_message = login.status["claimspicker_message"] return self.async_show_form( step_id="claimspicker", data_schema=vol.Schema(self.claimspicker_schema), errors={}, description_placeholders={ "email": login.email, "url": login.url, "message": "\n> {0}\n> {1}".format(claimspicker_message, error_message), }, ) if login.status and login.status.get("authselect_required"): _LOGGER.debug("Creating config_flow to select OTA method") error_message = login.status.get("error_message", "") authselect_message = login.status["authselect_message"] return self.async_show_form( step_id="authselect", data_schema=vol.Schema(self.authselect_schema), description_placeholders={ "email": login.email, "url": login.url, "message": "\n> {0}\n> {1}".format(authselect_message, error_message), }, ) if login.status and login.status.get("verificationcode_required"): _LOGGER.debug("Creating config_flow to enter verification code") return self.async_show_form( step_id="verificationcode", data_schema=vol.Schema(self.verificationcode_schema), ) if login.status and login.status.get("force_get"): _LOGGER.debug("Creating config_flow to wait for user action") return self.async_show_form( step_id="action_required", data_schema=vol.Schema(OrderedDict()), description_placeholders={ "email": login.email, "url": login.url, "message": f"```text\n{login.status.get('message','')}\n```", }, ) if login.status and login.status.get("login_failed"): _LOGGER.debug("Login failed: %s", login.status.get("login_failed")) await login.close() return self.async_abort(reason=login.status.get("login_failed"), ) new_schema = self._update_ord_dict( self.data_schema, { vol.Required(CONF_EMAIL, default=self.config[CONF_EMAIL]): str, vol.Required(CONF_PASSWORD, default=self.config[CONF_PASSWORD]): str, vol.Optional("securitycode"): str, vol.Required(CONF_URL, default=self.config[CONF_URL]): str, vol.Optional(CONF_DEBUG, default=self.config[CONF_DEBUG]): bool, vol.Optional( CONF_INCLUDE_DEVICES, default=(self.config[CONF_INCLUDE_DEVICES] if isinstance( self.config[CONF_INCLUDE_DEVICES], str) else ",".join( map(str, self.config[CONF_INCLUDE_DEVICES]))), ): str, vol.Optional( CONF_EXCLUDE_DEVICES, default=(self.config[CONF_EXCLUDE_DEVICES] if isinstance( self.config[CONF_EXCLUDE_DEVICES], str) else ",".join( map(str, self.config[CONF_EXCLUDE_DEVICES]))), ): str, vol.Optional(CONF_SCAN_INTERVAL, default=self.config[CONF_SCAN_INTERVAL]): int, }, ) if login.status and login.status.get("error_message"): _LOGGER.debug("Login error detected: %s", login.status.get("error_message")) return self.async_show_form( step_id="user", data_schema=vol.Schema(new_schema), description_placeholders={ "message": f"\n> {login.status.get('error_message','')}" }, ) return self.async_show_form( step_id="user", data_schema=vol.Schema(new_schema), description_placeholders={ "message": f"\n> {login.status.get('error_message','')}" }, )