async def async_setup_entry(hass, config_entry): """Set up Alexa Media Player as config entry.""" async def close_alexa_media(event=None) -> None: """Clean up Alexa connections.""" _LOGGER.debug("Received shutdown request: %s", event) for email, _ in (hass.data[DATA_ALEXAMEDIA]['accounts'].items()): await close_connections(hass, email) _verify_domain_control = verify_domain_control(hass, DOMAIN) if DATA_ALEXAMEDIA not in hass.data: hass.data[DATA_ALEXAMEDIA] = {} hass.data[DATA_ALEXAMEDIA]['accounts'] = {} from alexapy import AlexaLogin, __version__ as alexapy_version _LOGGER.info(STARTUP) _LOGGER.info("Loaded alexapy==%s", alexapy_version) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_alexa_media) account = config_entry.data email = account.get(CONF_EMAIL) password = account.get(CONF_PASSWORD) url = account.get(CONF_URL) login = AlexaLogin(url, email, password, hass.config.path, account.get(CONF_DEBUG)) if email not in hass.data[DATA_ALEXAMEDIA]['accounts']: hass.data[DATA_ALEXAMEDIA]['accounts'][email] = {} (hass.data[DATA_ALEXAMEDIA]['accounts'][email]['login_obj']) = login await login.login_with_cookie() await test_login_status(hass, config_entry, login, setup_platform_callback) return True
async def relogin(event=None) -> None: """Relogin to Alexa.""" for email, _ in hass.data[DATA_ALEXAMEDIA]["accounts"].items(): if hide_email(email) == event.data.get("email"): _LOGGER.debug("Received relogin request: %s", event) email = account.get(CONF_EMAIL) login_obj: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][ email].get("login_obj") if login_obj is None: login_obj = AlexaLogin( url=url, email=email, password=password, outputpath=hass.config.path, debug=account.get(CONF_DEBUG), otp_secret=account.get(CONF_OTPSECRET, ""), oauth=account.get(CONF_OAUTH, {}), uuid=await hass.helpers.instance_id.async_get(), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email][ "login_obj"] = login_obj await login_obj.reset() # await login_obj.login() if await test_login_status(hass, config_entry, login_obj): await setup_alexa(hass, config_entry, login_obj) break
async def relogin(event=None) -> None: """Relogin to Alexa.""" if hide_email(email) == event.data.get("email"): _LOGGER.debug("%s: Received relogin request: %s", hide_email(email), event) login_obj: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][ email].get("login_obj") uuid = (await calculate_uuid(hass, email, url))["uuid"] if login_obj is None: login_obj = AlexaLogin( url=url, email=email, password=password, outputpath=hass.config.path, debug=account.get(CONF_DEBUG), otp_secret=account.get(CONF_OTPSECRET, ""), oauth=account.get(CONF_OAUTH, {}), uuid=uuid, oauth_login=bool( account.get(CONF_OAUTH, {}).get("access_token") or account.get(CONF_OAUTH_LOGIN)), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email][ "login_obj"] = login_obj await login_obj.reset() # await login_obj.login() if await test_login_status(hass, config_entry, login_obj): await setup_alexa(hass, config_entry, login_obj)
async def relogin(event=None) -> None: """Relogin to Alexa.""" for email, _ in hass.data[DATA_ALEXAMEDIA]["accounts"].items(): if hide_email(email) == event.data.get("email"): _LOGGER.debug("Received relogin request: %s", event) email = account.get(CONF_EMAIL) login_obj = hass.data[DATA_ALEXAMEDIA]["accounts"][email].get( "login_obj" ) if login_obj is None: login_obj = AlexaLogin( url, email, password, hass.config.path, account.get(CONF_DEBUG), account.get(CONF_OTPSECRET, ""), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email][ "login_obj" ] = login_obj await login_obj.reset() # await login_obj.login() if await test_login_status(hass, config_entry, login_obj): await setup_alexa(hass, config_entry, login_obj) break
async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" from alexapy import AlexaLogin if not user_input: return await self._show_form( data_schema=vol.Schema(self.data_schema)) if "{} - {}".format(user_input[CONF_EMAIL], user_input[CONF_URL]) in configured_instances( self.hass): return await self._show_form( errors={CONF_EMAIL: "identifier_exists"}) self.config[CONF_EMAIL] = user_input[CONF_EMAIL] self.config[CONF_PASSWORD] = user_input[CONF_PASSWORD] self.config[CONF_URL] = user_input[CONF_URL] self.config[CONF_DEBUG] = user_input[CONF_DEBUG] from datetime import timedelta self.config[CONF_SCAN_INTERVAL] = ( user_input[CONF_SCAN_INTERVAL] if not isinstance(user_input[CONF_SCAN_INTERVAL], timedelta) else user_input[CONF_SCAN_INTERVAL].total_seconds()) if isinstance(user_input[CONF_INCLUDE_DEVICES], str): self.config[CONF_INCLUDE_DEVICES] = ( user_input[CONF_INCLUDE_DEVICES].split(",") if "CONF_INCLUDE_DEVICES" in user_input else []) else: self.config[CONF_INCLUDE_DEVICES] = user_input[ CONF_INCLUDE_DEVICES] if isinstance(user_input[CONF_EXCLUDE_DEVICES], str): self.config[CONF_EXCLUDE_DEVICES] = ( user_input[CONF_EXCLUDE_DEVICES].split(",") if "CONF_EXCLUDE_DEVICES" in user_input else []) else: self.config[CONF_EXCLUDE_DEVICES] = user_input[ CONF_EXCLUDE_DEVICES] if not self.login: _LOGGER.debug("Creating new login") try: self.login = AlexaLogin( self.config[CONF_URL], self.config[CONF_EMAIL], self.config[CONF_PASSWORD], self.hass.config.path, self.config[CONF_DEBUG], ) await self.login.login_with_cookie() return await self._test_login() except BaseException: raise return await self._show_form( errors={"base": "invalid_credentials"}) else: _LOGGER.debug("Using existing login") await self.login.login(data=user_input) return await self._test_login()
async def async_setup_entry(hass, config_entry): """Set up Alexa Media Player as config entry.""" async def close_alexa_media(event=None) -> None: """Clean up Alexa connections.""" _LOGGER.debug("Received shutdown request: %s", event) for email, _ in hass.data[DATA_ALEXAMEDIA]["accounts"].items(): await close_connections(hass, email) hass.data.setdefault(DATA_ALEXAMEDIA, {"accounts": {}}) from alexapy import AlexaLogin, __version__ as alexapy_version _LOGGER.info(STARTUP) _LOGGER.info("Loaded alexapy==%s", alexapy_version) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_alexa_media) account = config_entry.data email = account.get(CONF_EMAIL) password = account.get(CONF_PASSWORD) url = account.get(CONF_URL) hass.data[DATA_ALEXAMEDIA]["accounts"].setdefault( email, { "config_entry": config_entry, "setup_platform_callback": setup_platform_callback, "test_login_status": test_login_status, "devices": { "media_player": {}, "switch": {} }, "entities": { "media_player": {}, "switch": {} }, "excluded": {}, "new_devices": True, "websocket_lastattempt": 0, "websocketerror": 0, "websocket_commands": {}, "websocket_activity": { "serials": {}, "refreshed": {} }, "websocket": None, "auth_info": None, "configurator": [], }, ) login = hass.data[DATA_ALEXAMEDIA]["accounts"][email].get( "login_obj", AlexaLogin(url, email, password, hass.config.path, account.get(CONF_DEBUG)), ) await login.login_with_cookie() await test_login_status(hass, config_entry, login, setup_platform_callback) return True
def setup(hass, config, discovery_info=None): """Set up the Alexa domain.""" if DATA_ALEXAMEDIA not in hass.data: hass.data[DATA_ALEXAMEDIA] = {} hass.data[DATA_ALEXAMEDIA]['accounts'] = {} from alexapy import AlexaLogin config = config.get(DOMAIN) for account in config[CONF_ACCOUNTS]: # if account[CONF_EMAIL] in configured_instances(hass): # continue email = account.get(CONF_EMAIL) password = account.get(CONF_PASSWORD) url = account.get(CONF_URL) hass.data[DOMAIN]['accounts'][email] = {"config": []} login = AlexaLogin(url, email, password, hass.config.path, account.get(CONF_DEBUG)) test_login_status(hass, account, login, setup_platform_callback) return True
async def async_setup(hass, config, discovery_info=None): """Set up the Alexa domain.""" async def close_alexa_media(event) -> None: """Clean up Alexa connections.""" _LOGGER.debug("Received shutdown request: %s", event) for email, account_dict in (hass.data [DATA_ALEXAMEDIA]['accounts'].items()): login_obj = account_dict['login_obj'] if not login_obj._session.closed: if login_obj._session._connector_owner: await login_obj._session._connector.close() login_obj._session._connector = None _LOGGER.debug("%s: Connection closed: %s", hide_email(email), login_obj._session.closed) if DATA_ALEXAMEDIA not in hass.data: hass.data[DATA_ALEXAMEDIA] = {} hass.data[DATA_ALEXAMEDIA]['accounts'] = {} from alexapy import AlexaLogin, __version__ as alexapy_version _LOGGER.info(STARTUP) _LOGGER.info("Loaded alexapy==%s", alexapy_version) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_alexa_media) domainconfig = config.get(DOMAIN) for account in domainconfig[CONF_ACCOUNTS]: # if account[CONF_EMAIL] in configured_instances(hass): # continue email = account.get(CONF_EMAIL) password = account.get(CONF_PASSWORD) url = account.get(CONF_URL) hass.data[DATA_ALEXAMEDIA]['accounts'][email] = {"config": []} login = AlexaLogin(url, email, password, hass.config.path, account.get(CONF_DEBUG)) (hass.data[DATA_ALEXAMEDIA]['accounts'][email]['login_obj']) = login await login.login_with_cookie() await test_login_status(hass, account, login, setup_platform_callback) return True
async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" self._save_user_input_to_config(user_input=user_input) self.data_schema = self._update_schema_defaults() if not user_input: self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(self.data_schema), description_placeholders={"message": ""}, ) if f"{user_input[CONF_EMAIL]} - {user_input[CONF_URL]}" in configured_instances( self.hass ) and not self.hass.data[DATA_ALEXAMEDIA]["config_flows"].get( f"{user_input[CONF_EMAIL]} - {user_input[CONF_URL]}"): _LOGGER.debug("Existing account found") self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(self.data_schema), errors={CONF_EMAIL: "identifier_exists"}, description_placeholders={"message": ""}, ) 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 try: if not self.login: _LOGGER.debug("Creating new login") self.login = AlexaLogin( self.config[CONF_URL], self.config[CONF_EMAIL], self.config[CONF_PASSWORD], self.hass.config.path, self.config[CONF_DEBUG], ) else: _LOGGER.debug("Using existing login") await self.login.login( cookies=await self.login.load_cookie( cookies_txt=self.config[CONF_COOKIES_TXT]), data=self.config, ) return await self._test_login() except AlexapyConnectionError: self.automatic_steps = 0 return self.async_show_form( step_id="user", errors={"base": "connection_error"}, description_placeholders={"message": ""}, ) except BaseException as ex: _LOGGER.warning("Unknown error: %s", ex) if self.config[CONF_DEBUG]: raise self.automatic_steps = 0 return self.async_show_form( step_id="user", errors={"base": "unknown_error"}, description_placeholders={"message": ""}, )
async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" self._save_user_input_to_config(user_input=user_input) self.data_schema = self._update_schema_defaults() if not user_input: self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(self.data_schema), description_placeholders={"message": ""}, ) if ( not self.config.get("reauth") and f"{self.config[CONF_EMAIL]} - {self.config[CONF_URL]}" in configured_instances(self.hass) and not self.hass.data[DATA_ALEXAMEDIA]["config_flows"].get( f"{self.config[CONF_EMAIL]} - {self.config[CONF_URL]}" ) ): _LOGGER.debug("Existing account found") self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(self.data_schema), errors={CONF_EMAIL: "identifier_exists"}, description_placeholders={"message": ""}, ) 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 try: if not self.login: _LOGGER.debug("Creating new login") self.login = AlexaLogin( url=self.config[CONF_URL], email=self.config[CONF_EMAIL], password=self.config[CONF_PASSWORD], outputpath=self.hass.config.path, debug=self.config[CONF_DEBUG], otp_secret=self.config.get(CONF_OTPSECRET, ""), uuid=await self.hass.helpers.instance_id.async_get(), ) else: _LOGGER.debug("Using existing login") if ( not self.config.get("reauth") and user_input and user_input.get(CONF_OTPSECRET) and user_input.get(CONF_OTPSECRET).replace(" ", "") ): otp: Text = self.login.get_totp_token() if otp: _LOGGER.debug("Generating OTP from %s", otp) return self.async_show_form( step_id="totp_register", data_schema=vol.Schema(self.totp_register), errors={}, description_placeholders={ "email": self.login.email, "url": self.login.url, "message": otp, }, ) return self.async_show_form( step_id="user", errors={"base": "2fa_key_invalid"}, description_placeholders={"message": ""}, ) await self.login.login( cookies=await self.login.load_cookie( cookies_txt=self.config.get(CONF_COOKIES_TXT, "") ), data=self.config, ) return await self._test_login() except AlexapyConnectionError: self.automatic_steps = 0 return self.async_show_form( step_id="user", errors={"base": "connection_error"}, description_placeholders={"message": ""}, ) except AlexapyPyotpInvalidKey: self.automatic_steps = 0 return self.async_show_form( step_id="user", errors={"base": "2fa_key_invalid"}, description_placeholders={"message": ""}, ) except BaseException as ex: _LOGGER.warning("Unknown error: %s", ex) if self.config[CONF_DEBUG]: raise self.automatic_steps = 0 return self.async_show_form( step_id="user", errors={"base": "unknown_error"}, description_placeholders={"message": ""}, )
async def async_setup_entry(hass, config_entry): """Set up Alexa Media Player as config entry.""" async def close_alexa_media(event=None) -> None: """Clean up Alexa connections.""" _LOGGER.debug("Received shutdown request: %s", event) for email, _ in hass.data[DATA_ALEXAMEDIA]["accounts"].items(): await close_connections(hass, email) async def relogin(event=None) -> None: """Relogin to Alexa.""" for email, _ in hass.data[DATA_ALEXAMEDIA]["accounts"].items(): if hide_email(email) == event.data.get("email"): _LOGGER.debug("Received relogin request: %s", event) email = account.get(CONF_EMAIL) login_obj: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][ email].get("login_obj") if login_obj is None: login_obj = AlexaLogin( url=url, email=email, password=password, outputpath=hass.config.path, debug=account.get(CONF_DEBUG), otp_secret=account.get(CONF_OTPSECRET, ""), oauth=account.get(CONF_OAUTH, {}), uuid=await hass.helpers.instance_id.async_get(), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email][ "login_obj"] = login_obj await login_obj.reset() # await login_obj.login() if await test_login_status(hass, config_entry, login_obj): await setup_alexa(hass, config_entry, login_obj) break async def login_success(event=None) -> None: """Relogin to Alexa.""" for email, _ in hass.data[DATA_ALEXAMEDIA]["accounts"].items(): if hide_email(email) == event.data.get("email"): _LOGGER.debug("Received Login success: %s", event) email = account.get(CONF_EMAIL) login_obj: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][ email].get("login_obj") await setup_alexa(hass, config_entry, login_obj) break hass.data.setdefault(DATA_ALEXAMEDIA, {"accounts": {}, "config_flows": {}}) _LOGGER.info(STARTUP) _LOGGER.info("Loaded alexapy==%s", alexapy_version) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_alexa_media) hass.bus.async_listen("alexa_media_relogin_required", relogin) hass.bus.async_listen("alexa_media_relogin_success", login_success) account = config_entry.data email = account.get(CONF_EMAIL) password = account.get(CONF_PASSWORD) url = account.get(CONF_URL) hass.data[DATA_ALEXAMEDIA]["accounts"].setdefault( email, { "coordinator": None, "config_entry": config_entry, "setup_alexa": setup_alexa, "devices": { "media_player": {}, "switch": {} }, "entities": { "media_player": {}, "switch": {} }, "excluded": {}, "new_devices": True, "websocket_lastattempt": 0, "websocketerror": 0, "websocket_commands": {}, "websocket_activity": { "serials": {}, "refreshed": {} }, "websocket": None, "auth_info": None, "options": { CONF_QUEUE_DELAY: config_entry.options.get(CONF_QUEUE_DELAY, DEFAULT_QUEUE_DELAY) }, DATA_LISTENER: [config_entry.add_update_listener(update_listener)], }, ) login: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][email].get( "login_obj", AlexaLogin( url=url, email=email, password=password, outputpath=hass.config.path, debug=account.get(CONF_DEBUG), otp_secret=account.get(CONF_OTPSECRET, ""), oauth=account.get(CONF_OAUTH, {}), uuid=await hass.helpers.instance_id.async_get(), ), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email]["login_obj"] = login await login.login(cookies=await login.load_cookie()) if await test_login_status(hass, config_entry, login): await setup_alexa(hass, config_entry, login) return True await login.reset() return False
async def async_step_user_legacy(self, user_input=None): """Handle legacy input for the config flow.""" # pylint: disable=too-many-return-statements self._save_user_input_to_config(user_input=user_input) self.data_schema = self._update_schema_defaults() if not user_input: self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(self.data_schema), description_placeholders={"message": ""}, ) if (not self.config.get("reauth") and f"{self.config[CONF_EMAIL]} - {self.config[CONF_URL]}" in configured_instances(self.hass) and not self.hass.data[DATA_ALEXAMEDIA]["config_flows"].get( f"{self.config[CONF_EMAIL]} - {self.config[CONF_URL]}")): _LOGGER.debug("Existing account found") self.automatic_steps = 0 return self.async_show_form( step_id="user", data_schema=vol.Schema(self.data_schema), errors={CONF_EMAIL: "identifier_exists"}, description_placeholders={"message": ""}, ) 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 try: if not self.login or self.login.session.closed: _LOGGER.debug("Creating new login") uuid_dict = await calculate_uuid(self.hass, self.config.get(CONF_EMAIL), self.config[CONF_URL]) uuid = uuid_dict["uuid"] self.login = AlexaLogin( url=self.config[CONF_URL], email=self.config[CONF_EMAIL], password=self.config[CONF_PASSWORD], outputpath=self.hass.config.path, debug=self.config[CONF_DEBUG], otp_secret=self.config.get(CONF_OTPSECRET, ""), uuid=uuid, oauth_login=True, ) else: _LOGGER.debug("Using existing login") if (not self.config.get("reauth") and user_input and user_input.get(CONF_OTPSECRET) and user_input.get(CONF_OTPSECRET).replace(" ", "")): otp: str = self.login.get_totp_token() if otp: _LOGGER.debug("Generating OTP from %s", otp) return self.async_show_form( step_id="totp_register", data_schema=vol.Schema(self.totp_register), errors={}, description_placeholders={ "email": self.login.email, "url": self.login.url, "message": otp, }, ) return self.async_show_form( step_id="user", errors={"base": "2fa_key_invalid"}, description_placeholders={"message": ""}, ) if self.login.status: _LOGGER.debug("Resuming existing flow") return await self._test_login() _LOGGER.debug("Trying to login %s", self.login.status) await self.login.login(data=self.config, ) return await self._test_login() except AlexapyConnectionError: self.automatic_steps = 0 return self.async_show_form( step_id="user_legacy", errors={"base": "connection_error"}, description_placeholders={"message": ""}, ) except AlexapyPyotpInvalidKey: self.automatic_steps = 0 return self.async_show_form( step_id="user_legacy", errors={"base": "2fa_key_invalid"}, description_placeholders={"message": ""}, ) except BaseException as ex: # pylyint: 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="user_legacy", errors={"base": "unknown_error"}, description_placeholders={"message": ""}, )
async def async_step_user(self, user_input=None): """Provide a proxy for login.""" self._save_user_input_to_config(user_input=user_input) try: hass_url: str = get_url(self.hass, prefer_external=True) except NoURLAvailableError: hass_url = "" self.proxy_schema = OrderedDict([ ( vol.Required(CONF_EMAIL, default=self.config.get(CONF_EMAIL, "")), str, ), ( vol.Required(CONF_PASSWORD, default=self.config.get(CONF_PASSWORD, "")), str, ), ( vol.Required(CONF_URL, default=self.config.get(CONF_URL, "amazon.com")), str, ), ( vol.Required( CONF_HASS_URL, default=self.config.get(CONF_HASS_URL, hass_url), ), str, ), ( vol.Optional(CONF_OTPSECRET, default=self.config.get(CONF_OTPSECRET, "")), str, ), ( vol.Optional(CONF_DEBUG, default=self.config.get(CONF_DEBUG, False)), bool, ), ( vol.Optional( CONF_INCLUDE_DEVICES, default=self.config.get(CONF_INCLUDE_DEVICES, ""), ), str, ), ( vol.Optional( CONF_EXCLUDE_DEVICES, default=self.config.get(CONF_EXCLUDE_DEVICES, ""), ), str, ), ( vol.Optional( CONF_SCAN_INTERVAL, default=self.config.get(CONF_SCAN_INTERVAL, 60), ), int, ), ]) if not user_input: return self.async_show_form( step_id="user", data_schema=vol.Schema(self.proxy_schema), description_placeholders={"message": ""}, ) 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 try: if not self.login or self.login.session.closed: _LOGGER.debug("Creating new login") uuid_dict = await calculate_uuid(self.hass, self.config.get(CONF_EMAIL), self.config[CONF_URL]) uuid = uuid_dict["uuid"] self.login = AlexaLogin( url=self.config[CONF_URL], email=self.config.get(CONF_EMAIL, ""), password=self.config.get(CONF_PASSWORD, ""), outputpath=self.hass.config.path, debug=self.config[CONF_DEBUG], otp_secret=self.config.get(CONF_OTPSECRET, ""), oauth=self.config.get(CONF_OAUTH, {}), uuid=uuid, oauth_login=True, ) else: _LOGGER.debug("Using existing login") if self.config.get(CONF_EMAIL): self.login.email = self.config.get(CONF_EMAIL) if self.config.get(CONF_PASSWORD): self.login.password = self.config.get(CONF_PASSWORD) if self.config.get(CONF_OTPSECRET): self.login.set_totp(self.config.get(CONF_OTPSECRET, "")) except AlexapyPyotpInvalidKey: return self.async_show_form( step_id="user", errors={"base": "2fa_key_invalid"}, description_placeholders={"message": ""}, ) hass_url: str = user_input.get(CONF_HASS_URL) hass_url_valid: bool = False async with ClientSession() as session: try: async with session.get(hass_url) as resp: hass_url_valid = resp.status == 200 except ClientConnectionError: hass_url_valid = False if not hass_url_valid: _LOGGER.debug( "Unable to connect to provided Home Assistant url: %s", hass_url) return self.async_show_form( step_id="user", errors={"base": "hass_url_invalid"}, description_placeholders={"message": ""}, ) if not self.proxy: self.proxy = AlexaProxy( self.login, str(URL(hass_url).with_path(AUTH_PROXY_PATH))) # Swap the login object self.proxy.change_login(self.login) if (user_input and user_input.get(CONF_OTPSECRET) and user_input.get(CONF_OTPSECRET).replace(" ", "")): otp: str = self.login.get_totp_token() if otp: _LOGGER.debug("Generating OTP from %s", otp) return self.async_show_form( step_id="totp_register", data_schema=vol.Schema(self.totp_register), errors={}, description_placeholders={ "email": self.login.email, "url": self.login.url, "message": otp, }, ) return await self.async_step_start_proxy(user_input)
async def async_setup_entry(hass, config_entry): """Set up Alexa Media Player as config entry.""" async def close_alexa_media(event=None) -> None: """Clean up Alexa connections.""" _LOGGER.debug("Received shutdown request: %s", event) if hass.data.get(DATA_ALEXAMEDIA, {}).get("accounts"): for email, _ in hass.data[DATA_ALEXAMEDIA]["accounts"].items(): await close_connections(hass, email) async def complete_startup(event=None) -> None: """Run final tasks after startup.""" _LOGGER.debug("Completing remaining startup tasks.") await asyncio.sleep(10) if hass.data[DATA_ALEXAMEDIA].get("notify_service"): notify = hass.data[DATA_ALEXAMEDIA].get("notify_service") _LOGGER.debug("Refreshing notify targets") await notify.async_register_services() async def relogin(event=None) -> None: """Relogin to Alexa.""" if hide_email(email) == event.data.get("email"): _LOGGER.debug("%s: Received relogin request: %s", hide_email(email), event) login_obj: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][ email].get("login_obj") uuid = (await calculate_uuid(hass, email, url))["uuid"] if login_obj is None: login_obj = AlexaLogin( url=url, email=email, password=password, outputpath=hass.config.path, debug=account.get(CONF_DEBUG), otp_secret=account.get(CONF_OTPSECRET, ""), oauth=account.get(CONF_OAUTH, {}), uuid=uuid, oauth_login=bool( account.get(CONF_OAUTH, {}).get("access_token") or account.get(CONF_OAUTH_LOGIN)), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email][ "login_obj"] = login_obj await login_obj.reset() # await login_obj.login() if await test_login_status(hass, config_entry, login_obj): await setup_alexa(hass, config_entry, login_obj) async def login_success(event=None) -> None: """Relogin to Alexa.""" if hide_email(email) == event.data.get("email"): _LOGGER.debug("Received Login success: %s", event) login_obj: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][ email].get("login_obj") await setup_alexa(hass, config_entry, login_obj) if not hass.data.get(DATA_ALEXAMEDIA): _LOGGER.info(STARTUP) _LOGGER.info("Loaded alexapy==%s", alexapy_version) hass.data.setdefault(DATA_ALEXAMEDIA, { "accounts": {}, "config_flows": {}, "notify_service": None }) if not hass.data[DATA_ALEXAMEDIA].get("accounts"): hass.data[DATA_ALEXAMEDIA] = { "accounts": {}, "config_flows": {}, } account = config_entry.data email = account.get(CONF_EMAIL) password = account.get(CONF_PASSWORD) url = account.get(CONF_URL) hass.data[DATA_ALEXAMEDIA]["accounts"].setdefault( email, { "coordinator": None, "config_entry": config_entry, "setup_alexa": setup_alexa, "devices": { "media_player": {}, "switch": {} }, "entities": { "media_player": {}, "switch": {}, "sensor": {}, "alarm_control_panel": {}, }, "excluded": {}, "new_devices": True, "websocket_lastattempt": 0, "websocketerror": 0, "websocket_commands": {}, "websocket_activity": { "serials": {}, "refreshed": {} }, "websocket": None, "auth_info": None, "second_account_index": 0, "options": { CONF_QUEUE_DELAY: config_entry.options.get(CONF_QUEUE_DELAY, DEFAULT_QUEUE_DELAY) }, DATA_LISTENER: [config_entry.add_update_listener(update_listener)], }, ) uuid_dict = await calculate_uuid(hass, email, url) uuid = uuid_dict["uuid"] hass.data[DATA_ALEXAMEDIA]["accounts"][email][ "second_account_index"] = uuid_dict["index"] login: AlexaLogin = hass.data[DATA_ALEXAMEDIA]["accounts"][email].get( "login_obj", AlexaLogin( url=url, email=email, password=password, outputpath=hass.config.path, debug=account.get(CONF_DEBUG), otp_secret=account.get(CONF_OTPSECRET, ""), oauth=account.get(CONF_OAUTH, {}), uuid=uuid, oauth_login=bool( account.get(CONF_OAUTH, {}).get("access_token") or account.get(CONF_OAUTH_LOGIN)), ), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email]["login_obj"] = login if not hass.data[DATA_ALEXAMEDIA]["accounts"][email][ "second_account_index"]: hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, close_alexa_media) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, complete_startup) hass.bus.async_listen("alexa_media_relogin_required", relogin) hass.bus.async_listen("alexa_media_relogin_success", login_success) await login.login(cookies=await login.load_cookie()) if await test_login_status(hass, config_entry, login): await setup_alexa(hass, config_entry, login) return True return False
async def async_step_user(self, user_input=None): """Provide a proxy for login.""" self._save_user_input_to_config(user_input=user_input) self.proxy_schema = OrderedDict( [ ( vol.Required(CONF_EMAIL, default=self.config.get(CONF_EMAIL, "")), str, ), ( vol.Required( CONF_PASSWORD, default=self.config.get(CONF_PASSWORD, "") ), str, ), ( vol.Required( CONF_URL, default=self.config.get(CONF_URL, "amazon.com") ), str, ), ( vol.Required( CONF_HASS_URL, default=self.config.get(CONF_HASS_URL, get_url(self.hass)), ), str, ), ( vol.Optional( CONF_OTPSECRET, default=self.config.get(CONF_OTPSECRET, "") ), str, ), ( vol.Optional( CONF_DEBUG, default=self.config.get(CONF_DEBUG, False) ), bool, ), ( vol.Optional( CONF_INCLUDE_DEVICES, default=self.config.get(CONF_INCLUDE_DEVICES, ""), ), str, ), ( vol.Optional( CONF_EXCLUDE_DEVICES, default=self.config.get(CONF_EXCLUDE_DEVICES, ""), ), str, ), ( vol.Optional( CONF_SCAN_INTERVAL, default=self.config.get(CONF_SCAN_INTERVAL, 60), ), int, ), ( vol.Optional(CONF_PROXY, default=self.config.get(CONF_PROXY, True)), bool, ), ( vol.Optional( CONF_OAUTH_LOGIN, default=self.config.get(CONF_OAUTH_LOGIN, True), ), bool, ), ] ) if not user_input: return self.async_show_form( step_id="user", data_schema=vol.Schema(self.proxy_schema), description_placeholders={"message": ""}, ) if user_input and not user_input.get(CONF_PROXY): return self.async_show_form( step_id="user_legacy", data_schema=vol.Schema(self._update_schema_defaults()), description_placeholders={"message": ""}, ) 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 if not self.login or self.login.session.closed: _LOGGER.debug("Creating new login") uuid_dict = await calculate_uuid( self.hass, self.config.get(CONF_EMAIL), self.config[CONF_URL] ) uuid = uuid_dict["uuid"] self.login = AlexaLogin( url=self.config[CONF_URL], email=self.config.get(CONF_EMAIL, ""), password=self.config.get(CONF_PASSWORD, ""), outputpath=self.hass.config.path, debug=self.config[CONF_DEBUG], otp_secret=self.config.get(CONF_OTPSECRET, ""), uuid=uuid, oauth_login=self.config.get(CONF_OAUTH_LOGIN, True), ) else: _LOGGER.debug("Using existing login") if self.config.get(CONF_EMAIL): self.login.email = self.config.get(CONF_EMAIL) if self.config.get(CONF_PASSWORD): self.login.password = self.config.get(CONF_PASSWORD) if self.config.get(CONF_OTPSECRET): self.login.set_totp(self.config.get(CONF_OTPSECRET, "")) hass_url: Text = user_input.get(CONF_HASS_URL) self.proxy = AlexaProxy(self.login, hass_url) await self.proxy.start_proxy() self.hass.http.register_view(AlexaMediaAuthorizationCallbackView) callback_url = f"{hass_url}{AUTH_CALLBACK_PATH}?flow_id={self.flow_id}" proxy_url = f"{self.proxy.access_url()}?config_flow_id={self.flow_id}&callback_url={callback_url}" if self.login.lastreq: proxy_url = f"{self.proxy.access_url()}/resume?config_flow_id={self.flow_id}&callback_url={callback_url}" return self.async_external_step(step_id="check_proxy", url=proxy_url)
async def async_step_user(self, user_input=None): """Handle the start of the config flow.""" if not user_input: return self.async_show_form( step_id="user", data_schema=vol.Schema(self.data_schema), description_placeholders={"message": ""}, ) if (f"{user_input[CONF_EMAIL]} - {user_input[CONF_URL]}" in configured_instances(self.hass)): return self.async_show_form( step_id="user", errors={CONF_EMAIL: "identifier_exists"}, description_placeholders={"message": f""}, ) self.config[CONF_EMAIL] = user_input[CONF_EMAIL] self.config[CONF_PASSWORD] = user_input[CONF_PASSWORD] self.config[CONF_URL] = user_input[CONF_URL] self.config[CONF_DEBUG] = user_input[CONF_DEBUG] self.config[CONF_SCAN_INTERVAL] = ( user_input[CONF_SCAN_INTERVAL] if not isinstance(user_input[CONF_SCAN_INTERVAL], timedelta) else user_input[CONF_SCAN_INTERVAL].total_seconds()) if isinstance(user_input[CONF_INCLUDE_DEVICES], str): self.config[CONF_INCLUDE_DEVICES] = ( user_input[CONF_INCLUDE_DEVICES].split(",") if CONF_INCLUDE_DEVICES in user_input and user_input[CONF_INCLUDE_DEVICES] != "" else []) else: self.config[CONF_INCLUDE_DEVICES] = user_input[ CONF_INCLUDE_DEVICES] if isinstance(user_input[CONF_EXCLUDE_DEVICES], str): self.config[CONF_EXCLUDE_DEVICES] = ( user_input[CONF_EXCLUDE_DEVICES].split(",") if CONF_EXCLUDE_DEVICES in user_input and user_input[CONF_EXCLUDE_DEVICES] != "" else []) else: self.config[CONF_EXCLUDE_DEVICES] = user_input[ CONF_EXCLUDE_DEVICES] 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 try: if not self.login: _LOGGER.debug("Creating new login") self.login = AlexaLogin( self.config[CONF_URL], self.config[CONF_EMAIL], self.config[CONF_PASSWORD], self.hass.config.path, self.config[CONF_DEBUG], ) await self.login.login(data=self.config) else: _LOGGER.debug("Using existing login") await self.login.login(data=self.config) return await self._test_login() except AlexapyConnectionError: return self.async_show_form(step_id="user", errors={"base": "connection_error"}) except BaseException as ex: _LOGGER.warning("Unknown error: %s", ex) if self.config[CONF_DEBUG]: raise return self.async_show_form(step_id="user", errors={"base": "unknown_error"})