예제 #1
0
 def __init__(
     self,
     hass: HomeAssistant,
     logger: Logger,
     username: str,
     password: str,
     panel_id: str,
     panel_pin: str,
     name: str,
     update_interval: timedelta,
 ) -> None:
     """Instantiate the object."""
     self._client = Elmax(username=username, password=password)
     self._panel_id = panel_id
     self._panel_pin = panel_pin
     self._panel_entry = None
     self._state_by_endpoint = None
     super().__init__(hass=hass,
                      logger=logger,
                      name=name,
                      update_interval=update_interval)
예제 #2
0
    async def async_step_user(self,
                              user_input: dict[str, Any] | None = None
                              ) -> FlowResult:
        """Handle a flow initialized by the user."""
        # When invokes without parameters, show the login form.
        if user_input is None:
            return self.async_show_form(step_id="user",
                                        data_schema=LOGIN_FORM_SCHEMA)

        errors: dict[str, str] = {}
        username = user_input[CONF_ELMAX_USERNAME]
        password = user_input[CONF_ELMAX_PASSWORD]

        # Otherwise, it means we are handling now the "submission" of the user form.
        # In this case, let's try to log in to the Elmax cloud and retrieve the available panels.
        try:
            client = Elmax(username=username, password=password)
            await client.login()

            # If the login succeeded, retrieve the list of available panels and filter the online ones
            online_panels = [
                x for x in await client.list_control_panels() if x.online
            ]

            # If no online panel was found, we display an error in the next UI.
            panels = list(online_panels)
            if len(panels) < 1:
                raise NoOnlinePanelsError()

            # Show the panel selection.
            # We want the user to choose the panel using the associated name, we set up a mapping
            # dictionary to handle that case.
            panel_names: dict[str, str] = {}
            username = client.get_authenticated_username()
            for panel in panels:
                _store_panel_by_name(panel=panel,
                                     username=username,
                                     panel_names=panel_names)

            self._client = client
            self._panel_names = panel_names
            schema = vol.Schema({
                vol.Required(CONF_ELMAX_PANEL_NAME):
                vol.In(self._panel_names.keys()),
                vol.Required(CONF_ELMAX_PANEL_PIN, default="000000"):
                str,
            })
            self._panels_schema = schema
            self._username = username
            self._password = password
            return self.async_show_form(step_id="panels",
                                        data_schema=schema,
                                        errors=errors)

        except ElmaxBadLoginError:
            _LOGGER.error("Wrong credentials or failed login")
            errors["base"] = "bad_auth"
        except NoOnlinePanelsError:
            _LOGGER.warning("No online device panel was found")
            errors["base"] = "no_panel_online"
        except ElmaxNetworkError:
            _LOGGER.exception("A network error occurred")
            errors["base"] = "network_error"

        # If an error occurred, show back the login form.
        return self.async_show_form(step_id="user",
                                    data_schema=LOGIN_FORM_SCHEMA,
                                    errors=errors)
예제 #3
0
 async def _async_login(username: str, password: str) -> Elmax:
     """Log in to the Elmax cloud and return the http client."""
     client = Elmax(username=username, password=password)
     await client.login()
     return client
예제 #4
0
    async def async_step_reauth_confirm(self, user_input=None):
        """Handle reauthorization flow."""
        errors = {}
        if user_input is not None:
            panel_pin = user_input.get(CONF_ELMAX_PANEL_PIN)
            password = user_input.get(CONF_ELMAX_PASSWORD)
            entry = await self.async_set_unique_id(self._reauth_panelid)

            # Handle authentication, make sure the panel we are re-authenticating against is listed among results
            # and verify its pin is correct.
            try:
                # Test login.
                client = Elmax(username=self._reauth_username,
                               password=password)
                await client.login()

                # Make sure the panel we are authenticating to is still available.
                panels = [
                    p for p in await client.list_control_panels()
                    if p.hash == self._reauth_panelid
                ]
                if len(panels) < 1:
                    raise NoOnlinePanelsError()

                # Verify the pin is still valid.from
                await client.get_panel_status(
                    control_panel_id=self._reauth_panelid, pin=panel_pin)

                # If it is, proceed with configuration update.
                self.hass.config_entries.async_update_entry(
                    entry,
                    data={
                        CONF_ELMAX_PANEL_ID: self._reauth_panelid,
                        CONF_ELMAX_PANEL_PIN: panel_pin,
                        CONF_ELMAX_USERNAME: self._reauth_username,
                        CONF_ELMAX_PASSWORD: password,
                    },
                )
                await self.hass.config_entries.async_reload(entry.entry_id)
                self._reauth_username = None
                self._reauth_panelid = None
                return self.async_abort(reason="reauth_successful")

            except ElmaxBadLoginError:
                _LOGGER.error(
                    "Wrong credentials or failed login while re-authenticating"
                )
                errors["base"] = "bad_auth"
            except NoOnlinePanelsError:
                _LOGGER.warning(
                    "Panel ID %s is no longer associated to this user",
                    self._reauth_panelid,
                )
                errors["base"] = "reauth_panel_disappeared"
            except ElmaxBadPinError:
                errors["base"] = "invalid_pin"

        # We want the user to re-authenticate only for the given panel id using the same login.
        # We pin them to the UI, so the user realizes she must log in with the appropriate credentials
        # for the that specific panel.
        schema = vol.Schema({
            vol.Required(CONF_ELMAX_USERNAME): self._reauth_username,
            vol.Required(CONF_ELMAX_PASSWORD): str,
            vol.Required(CONF_ELMAX_PANEL_ID): self._reauth_panelid,
            vol.Required(CONF_ELMAX_PANEL_PIN): str,
        })
        return self.async_show_form(step_id="reauth_confirm",
                                    data_schema=schema,
                                    errors=errors)