async def validate_input(user_input: dict[str, Any]) -> dict[str, str] | None:
    """Login to the brunt api and return errors if any."""
    errors = None
    bapi = BruntClientAsync(
        username=user_input[CONF_USERNAME],
        password=user_input[CONF_PASSWORD],
    )
    try:
        await bapi.async_login()
    except ClientResponseError as exc:
        if exc.status == 403:
            _LOGGER.warning("Brunt Credentials are incorrect")
            errors = {"base": "invalid_auth"}
        else:
            _LOGGER.exception(
                "Unknown error when trying to login to Brunt: %s", exc)
            errors = {"base": "unknown"}
    except ServerDisconnectedError:
        _LOGGER.warning("Cannot connect to Brunt")
        errors = {"base": "cannot_connect"}
    except Exception as exc:  # pylint: disable=broad-except
        _LOGGER.exception("Unknown error when trying to login to Brunt: %s",
                          exc)
        errors = {"base": "unknown"}
    finally:
        await bapi.async_close()
    return errors
예제 #2
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up Brunt using config flow."""
    session = async_get_clientsession(hass)
    bapi = BruntClientAsync(
        username=entry.data[CONF_USERNAME],
        password=entry.data[CONF_PASSWORD],
        session=session,
    )
    try:
        await bapi.async_login()
    except ServerDisconnectedError as exc:
        raise ConfigEntryNotReady("Brunt not ready to connect.") from exc
    except ClientResponseError as exc:
        raise ConfigEntryAuthFailed(
            f"Brunt could not connect with username: {entry.data[CONF_USERNAME]}."
        ) from exc

    async def async_update_data():
        """Fetch data from the Brunt endpoint for all Things.

        Error 403 is the API response for any kind of authentication error (failed password or email)
        Error 401 is the API response for things that are not part of the account, could happen when a device is deleted from the account.
        """
        try:
            async with async_timeout.timeout(10):
                things = await bapi.async_get_things(force=True)
                return {thing.SERIAL: thing for thing in things}
        except ServerDisconnectedError as err:
            raise UpdateFailed(f"Error communicating with API: {err}") from err
        except ClientResponseError as err:
            if err.status == 403:
                raise ConfigEntryAuthFailed() from err
            if err.status == 401:
                _LOGGER.warning(
                    "Device not found, will reload Brunt integration")
                await hass.config_entries.async_reload(entry.entry_id)

    coordinator = DataUpdateCoordinator(
        hass,
        _LOGGER,
        name="brunt",
        update_method=async_update_data,
        update_interval=REGULAR_INTERVAL,
    )
    await coordinator.async_config_entry_first_refresh()

    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.entry_id] = {
        DATA_BAPI: bapi,
        DATA_COOR: coordinator
    }
    hass.config_entries.async_setup_platforms(entry, PLATFORMS)
    return True