async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Meater Temperature Probe from a config entry.""" # Store an API object to access session = async_get_clientsession(hass) meater_api = MeaterApi(session) # Add the credentials try: _LOGGER.debug("Authenticating with the Meater API") await meater_api.authenticate( entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD] ) except (ServiceUnavailableError, TooManyRequestsError) as err: raise ConfigEntryNotReady from err except AuthenticationError as err: raise ConfigEntryAuthFailed( f"Unable to authenticate with the Meater API: {err}" ) from err async def async_update_data() -> dict[str, MeaterProbe]: """Fetch data from API endpoint.""" try: # Note: asyncio.TimeoutError and aiohttp.ClientError are already # handled by the data update coordinator. async with async_timeout.timeout(10): devices: list[MeaterProbe] = await meater_api.get_all_devices() except AuthenticationError as err: raise ConfigEntryAuthFailed("The API call wasn't authenticated") from err except TooManyRequestsError as err: raise UpdateFailed( "Too many requests have been made to the API, rate limiting is in place" ) from err return {device.id: device for device in devices} coordinator = DataUpdateCoordinator( hass, _LOGGER, # Name of the data. For logging purposes. name="meater_api", update_method=async_update_data, # Polling interval. Will only be polled if there are subscribers. update_interval=timedelta(seconds=30), ) await coordinator.async_config_entry_first_refresh() hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN].setdefault("known_probes", set()) hass.data[DOMAIN][entry.entry_id] = { "api": meater_api, "coordinator": coordinator, } await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True
async def async_step_user(self, user_input=None): """Define the login user step.""" if user_input is None: return self.async_show_form( step_id="user", data_schema=FLOW_SCHEMA, ) username: str = user_input[CONF_USERNAME] await self.async_set_unique_id(username.lower()) self._abort_if_unique_id_configured() username = user_input[CONF_USERNAME] password = user_input[CONF_PASSWORD] session = aiohttp_client.async_get_clientsession(self.hass) api = MeaterApi(session) errors = {} try: await api.authenticate(user_input[CONF_USERNAME], user_input[CONF_PASSWORD]) except AuthenticationError: errors["base"] = "invalid_auth" except ServiceUnavailableError: errors["base"] = "service_unavailable_error" except Exception: # pylint: disable=broad-except errors["base"] = "unknown_auth_error" else: return self.async_create_entry( title="Meater", data={ "username": username, "password": password }, ) return self.async_show_form( step_id="user", data_schema=FLOW_SCHEMA, errors=errors, )
async def _try_connect_meater(self, step_id, placeholders: dict[str, str] | None, username: str, password: str) -> FlowResult: session = aiohttp_client.async_get_clientsession(self.hass) api = MeaterApi(session) errors = {} try: await api.authenticate(username, password) except AuthenticationError: errors["base"] = "invalid_auth" except ServiceUnavailableError: errors["base"] = "service_unavailable_error" except Exception: # pylint: disable=broad-except errors["base"] = "unknown_auth_error" else: data = {"username": username, "password": password} existing_entry = await self.async_set_unique_id(username.lower()) if existing_entry: self.hass.config_entries.async_update_entry(existing_entry, data=data) await self.hass.config_entries.async_reload( existing_entry.entry_id) return self.async_abort(reason="reauth_successful") return self.async_create_entry( title="Meater", data=data, ) return self.async_show_form( step_id=step_id, data_schema=self._data_schema, description_placeholders=placeholders, errors=errors, )