Beispiel #1
0
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
Beispiel #2
0
 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
Beispiel #3
0
 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
Beispiel #5
0
    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
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
    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": ""},
            )
Beispiel #11
0
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
Beispiel #12
0
 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": ""},
         )
Beispiel #13
0
 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)
Beispiel #14
0
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
Beispiel #15
0
 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"})