HEX
Server: Apache/2.4.63 (Unix)
System: Linux Synopilou92 4.4.302+ #72806 SMP Mon Jul 21 23:16:00 CST 2025 x86_64
User: pilou92 (1026)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /volume1/docker/homeassistant2025/custom_components/landroid_cloud/config_flow.py
"""Adds support for Landroid Cloud compatible devices."""

from __future__ import annotations

from homeassistant import config_entries, core, exceptions
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, CONF_TYPE
from pyworxcloud import WorxCloud
from pyworxcloud.exceptions import AuthorizationError, TooManyRequestsError

from .const import DOMAIN, LOGLEVEL
from .scheme import DATA_SCHEMA
from .utils.logger import LandroidLogger, LoggerType, LogLevel

LOGGER = LandroidLogger(name=__name__, log_level=LOGLEVEL)


async def validate_input(hass: core.HomeAssistant, data):
    """Validate the user input allows us to connect.

    Data has the keys from DATA_SCHEMA with values provided by the user.
    """

    LOGGER.log(LoggerType.CONFIG, "data: %s", data)

    worx = WorxCloud(
        data.get(CONF_EMAIL), data.get(CONF_PASSWORD), data.get(CONF_TYPE).lower()
    )
    try:
        auth = await hass.async_add_executor_job(worx.authenticate)
    except TooManyRequestsError:
        raise TooManyRequests from None
    except AuthorizationError:
        raise InvalidAuth from None

    if not auth:
        raise InvalidAuth

    return {"title": f"{data[CONF_TYPE]} - {data[CONF_EMAIL]}"}


class InvalidAuth(exceptions.HomeAssistantError):
    """Error to indicate there is invalid auth."""


class CannotConnect(exceptions.HomeAssistantError):
    """Error to indicate we cannot connect."""


class TooManyRequests(exceptions.HomeAssistantError):
    """Error to indicate we made too many requests."""


class LandroidCloudConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
    """Handle a config flow for Landroid Cloud."""

    VERSION = 1
    CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH

    def check_for_existing(self, data):
        """Check whether an existing entry is using the same URLs."""
        return any(
            entry.data.get(CONF_EMAIL) == data.get(CONF_EMAIL)
            and entry.data.get(CONF_TYPE).lower()
            == (
                data.get(CONF_TYPE).lower()
                if not isinstance(data.get(CONF_TYPE), type(None))
                else "worx"
            )
            for entry in self._async_current_entries()
        )

    def __init__(self):
        """Initialize the config flow."""
        self._errors = {}

    async def async_step_user(self, user_input=None):
        """Handle the initial Landroid Cloud step."""
        self._errors = {}
        if user_input is not None:
            if self.check_for_existing(user_input):
                return self.async_abort(reason="already_exists")

            try:
                validated = await validate_input(self.hass, user_input)
            except CannotConnect:
                self._errors["base"] = "cannot_connect"
            except InvalidAuth:
                self._errors["base"] = "invalid_auth"
            except TooManyRequests:
                self._errors["base"] = "too_many_requests"
            except Exception as ex:  # pylint: disable=broad-except
                LOGGER.log(
                    LoggerType.CONFIG,
                    "Unexpected exception: %s",
                    ex,
                    log_level=LogLevel.ERROR,
                )
                self._errors["base"] = "unknown"

            if "base" not in self._errors:
                await self.async_set_unique_id(
                    f"{user_input[CONF_EMAIL]}_{user_input[CONF_TYPE]}"
                )

                return self.async_create_entry(
                    title=validated["title"],
                    data=user_input,
                    description=f"API connector for {validated['title']} cloud",
                )

        return self.async_show_form(
            step_id="user", data_schema=DATA_SCHEMA, errors=self._errors
        )

    async def async_step_import(self, import_config):
        """Import a config entry."""
        if import_config is not None:
            if self.check_for_existing(import_config):
                LOGGER.log(
                    LoggerType.CONFIG_IMPORT,
                    "Landroid_cloud configuration for %s already imported, you can "
                    "safely remove the entry from your configuration.yaml as this "
                    "is no longer used",
                    import_config.get(CONF_EMAIL),
                    log_level=LogLevel.WARNING,
                )
                return self.async_abort(reason="already_exists")

            try:
                await validate_input(self.hass, import_config)
            except CannotConnect:
                self._errors["base"] = "cannot_connect"
            except InvalidAuth:
                self._errors["base"] = "invalid_auth"
            except Exception:  # pylint: disable=broad-except
                LOGGER.log(
                    LoggerType.CONFIG_IMPORT,
                    "Unexpected exception",
                    log_level=LogLevel.ERROR,
                )
                self._errors["base"] = "unknown"

            if "base" not in self._errors:
                return self.async_create_entry(
                    title=f"Import - {import_config.get(CONF_EMAIL)}",
                    data=import_config,
                )