1
0
mirror of https://github.com/natekspencer/hacs-oasis_mini.git synced 2025-12-06 18:44:14 -05:00

Switch to using mqtt

This commit is contained in:
Nathan Spencer
2025-11-22 04:40:58 +00:00
parent 171a608314
commit 886d7598f3
34 changed files with 2036 additions and 1057 deletions

View File

@@ -1,87 +1,52 @@
"""Config flow for Oasis Mini integration."""
"""Config flow for Oasis device integration."""
from __future__ import annotations
import asyncio
import logging
from typing import Any
from typing import Any, Mapping
from aiohttp import ClientConnectorError
from httpx import ConnectError, HTTPStatusError
import voluptuous as vol
from homeassistant.components import dhcp
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_EMAIL, CONF_HOST, CONF_PASSWORD
from homeassistant.core import callback
from homeassistant.helpers.schema_config_entry_flow import (
SchemaCommonFlowHandler,
SchemaFlowError,
SchemaFlowFormStep,
SchemaOptionsFlowHandler,
)
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_EMAIL, CONF_PASSWORD
from . import OasisMiniConfigEntry
from .const import DOMAIN
from .coordinator import OasisMiniCoordinator
from .helpers import create_client
from .pyoasiscontrol import UnauthenticatedError
_LOGGER = logging.getLogger(__name__)
STEP_USER_DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str})
OPTIONS_SCHEMA = vol.Schema(
STEP_USER_DATA_SCHEMA = vol.Schema(
{vol.Required(CONF_EMAIL): str, vol.Required(CONF_PASSWORD): str}
)
async def cloud_login(
handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
) -> dict[str, Any]:
"""Cloud login."""
coordinator: OasisMiniCoordinator = handler.parent_handler.config_entry.runtime_data
try:
await coordinator.device.async_cloud_login(
email=user_input[CONF_EMAIL], password=user_input[CONF_PASSWORD]
)
user_input[CONF_ACCESS_TOKEN] = coordinator.device.access_token
except Exception as ex:
raise SchemaFlowError("invalid_auth") from ex
del user_input[CONF_PASSWORD]
return user_input
OPTIONS_FLOW = {
"init": SchemaFlowFormStep(OPTIONS_SCHEMA, validate_user_input=cloud_login)
}
class OasisMiniConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Oasis Mini."""
class OasisDeviceConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Oasis devices."""
VERSION = 1
MINOR_VERSION = 2
MINOR_VERSION = 3
@staticmethod
@callback
def async_get_options_flow(
config_entry: OasisMiniConfigEntry,
) -> SchemaOptionsFlowHandler:
"""Get the options flow for this handler."""
return SchemaOptionsFlowHandler(config_entry, OPTIONS_FLOW)
async def async_step_dhcp(
self, discovery_info: dhcp.DhcpServiceInfo
async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle DHCP discovery."""
host = {CONF_HOST: discovery_info.ip}
await self.validate_client(host)
self._abort_if_unique_id_configured(updates=host)
# This should never happen since we only listen to DHCP requests
# for configured devices.
return self.async_abort(reason="already_configured")
"""Perform reauth upon an API authentication error."""
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Dialog that informs the user that reauth is required."""
entry = self.hass.config_entries.async_get_entry(self.context["entry_id"])
assert entry
suggested_values = user_input or entry.data
return await self._async_step(
"reauth_confirm", STEP_USER_DATA_SCHEMA, user_input, suggested_values
)
async def async_step_user(
self, user_input: dict[str, Any] | None = None
@@ -115,20 +80,22 @@ class OasisMiniConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input is not None:
if not (errors := await self.validate_client(user_input)):
if step_id != "reconfigure":
self._abort_if_unique_id_configured(updates=user_input)
if existing_entry := self.hass.config_entries.async_get_entry(
self.context.get("entry_id")
):
self.hass.config_entries.async_update_entry(
existing_entry, data=user_input
entry_id = self.context.get("entry_id")
existing_entry = self.hass.config_entries.async_get_entry(entry_id)
if existing_entry and existing_entry.unique_id:
self._abort_if_unique_id_mismatch(reason="wrong_account")
if existing_entry:
return self.async_update_reload_and_abort(
existing_entry,
unique_id=self.unique_id,
title=user_input[CONF_EMAIL],
data=user_input,
reload_even_if_entry_is_unchanged=False,
)
await self.hass.config_entries.async_reload(existing_entry.entry_id)
return self.async_abort(reason="reconfigure_successful")
self._abort_if_unique_id_configured(updates=user_input)
return self.async_create_entry(
title=f"Oasis Mini {self.unique_id}",
data=user_input,
title=user_input[CONF_EMAIL], data=user_input
)
return self.async_show_form(
@@ -142,21 +109,29 @@ class OasisMiniConfigFlow(ConfigFlow, domain=DOMAIN):
errors = {}
try:
async with asyncio.timeout(10):
client = create_client(user_input)
await self.async_set_unique_id(await client.async_get_serial_number())
client = create_client(self.hass, user_input)
await client.async_login(
email=user_input[CONF_EMAIL], password=user_input[CONF_PASSWORD]
)
user_input[CONF_ACCESS_TOKEN] = client.access_token
user = await client.async_get_user()
await self.async_set_unique_id(str(user["id"]))
del user_input[CONF_PASSWORD]
if not self.unique_id:
errors["base"] = "invalid_host"
errors["base"] = "invalid_auth"
except UnauthenticatedError:
errors["base"] = "invalid_auth"
except asyncio.TimeoutError:
errors["base"] = "timeout_connect"
except ConnectError:
errors["base"] = "invalid_host"
errors["base"] = "invalid_auth"
except ClientConnectorError:
errors["base"] = "invalid_host"
errors["base"] = "invalid_auth"
except HTTPStatusError as err:
errors["base"] = str(err)
except Exception as ex: # pylint: disable=broad-except
_LOGGER.error(ex)
errors["base"] = "unknown"
finally:
await client.session.close()
await client.async_close()
return errors