1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-30 12:14:20 +01:00
Files
core/homeassistant/components/peblar/config_flow.py
2026-04-30 21:14:48 +02:00

245 lines
8.8 KiB
Python

"""Config flow to configure the Peblar integration."""
from collections.abc import Mapping
from typing import Any
from aiohttp import CookieJar
from peblar import Peblar, PeblarAuthenticationError, PeblarConnectionError
import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_HOST, CONF_PASSWORD
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from homeassistant.helpers.selector import (
TextSelector,
TextSelectorConfig,
TextSelectorType,
)
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
from .const import DOMAIN, LOGGER
class PeblarFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle a Peblar config flow."""
VERSION = 1
_discovery_info: ZeroconfServiceInfo
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle a flow initiated by the user."""
errors = {}
if user_input is not None:
peblar = Peblar(
host=user_input[CONF_HOST],
session=async_create_clientsession(
self.hass, cookie_jar=CookieJar(unsafe=True)
),
)
try:
await peblar.login(password=user_input[CONF_PASSWORD])
info = await peblar.system_information()
except PeblarAuthenticationError:
errors[CONF_PASSWORD] = "invalid_auth"
except PeblarConnectionError:
errors[CONF_HOST] = "cannot_connect"
except Exception: # noqa: BLE001
LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
info.product_serial_number, raise_on_progress=False
)
self._abort_if_unique_id_configured()
return self.async_create_entry(title="Peblar", data=user_input)
else:
user_input = {}
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(
CONF_HOST, default=user_input.get(CONF_HOST)
): TextSelector(TextSelectorConfig(autocomplete="off")),
vol.Required(CONF_PASSWORD): TextSelector(
TextSelectorConfig(type=TextSelectorType.PASSWORD)
),
}
),
errors=errors,
)
async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of a Peblar device."""
errors = {}
reconfigure_entry = self._get_reconfigure_entry()
if user_input is not None:
peblar = Peblar(
host=user_input[CONF_HOST],
session=async_create_clientsession(
self.hass, cookie_jar=CookieJar(unsafe=True)
),
)
try:
await peblar.login(password=user_input[CONF_PASSWORD])
info = await peblar.system_information()
except PeblarAuthenticationError:
errors[CONF_PASSWORD] = "invalid_auth"
except PeblarConnectionError:
errors[CONF_HOST] = "cannot_connect"
except Exception: # noqa: BLE001
LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(info.product_serial_number)
self._abort_if_unique_id_mismatch(reason="different_device")
return self.async_update_reload_and_abort(
reconfigure_entry,
data_updates=user_input,
)
host = reconfigure_entry.data[CONF_HOST]
if user_input is not None:
host = user_input[CONF_HOST]
return self.async_show_form(
step_id="reconfigure",
data_schema=vol.Schema(
{
vol.Required(CONF_HOST, default=host): TextSelector(
TextSelectorConfig(autocomplete="off")
),
vol.Required(CONF_PASSWORD): TextSelector(
TextSelectorConfig(type=TextSelectorType.PASSWORD)
),
}
),
errors=errors,
)
async def async_step_zeroconf(
self, discovery_info: ZeroconfServiceInfo
) -> ConfigFlowResult:
"""Handle zeroconf discovery of a Peblar device."""
if not (sn := discovery_info.properties.get("sn")):
return self.async_abort(reason="no_serial_number")
await self.async_set_unique_id(sn)
self._abort_if_unique_id_configured(updates={CONF_HOST: discovery_info.host})
self._discovery_info = discovery_info
self.context.update(
{
"title_placeholders": {
"name": discovery_info.name.replace("._http._tcp.local.", "")
},
"configuration_url": f"http://{discovery_info.host}",
},
)
return await self.async_step_zeroconf_confirm()
async def async_step_zeroconf_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle a flow initiated by zeroconf."""
errors = {}
if user_input is not None:
peblar = Peblar(
host=self._discovery_info.host,
session=async_create_clientsession(
self.hass, cookie_jar=CookieJar(unsafe=True)
),
)
try:
await peblar.login(password=user_input[CONF_PASSWORD])
except PeblarAuthenticationError:
errors[CONF_PASSWORD] = "invalid_auth"
except PeblarConnectionError:
errors["base"] = "cannot_connect"
except Exception: # noqa: BLE001
LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
return self.async_create_entry(
title="Peblar",
data={
CONF_HOST: self._discovery_info.host,
CONF_PASSWORD: user_input[CONF_PASSWORD],
},
)
return self.async_show_form(
step_id="zeroconf_confirm",
data_schema=vol.Schema(
{
vol.Required(CONF_PASSWORD): TextSelector(
TextSelectorConfig(type=TextSelectorType.PASSWORD)
),
}
),
description_placeholders={
"hostname": self._discovery_info.name.replace("._http._tcp.local.", ""),
"host": self._discovery_info.host,
},
errors=errors,
)
async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle initiation of re-authentication with a Peblar device."""
return await self.async_step_reauth_confirm()
async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle re-authentication with a Peblar device."""
errors = {}
if user_input is not None:
reauth_entry = self._get_reauth_entry()
peblar = Peblar(
host=reauth_entry.data[CONF_HOST],
session=async_create_clientsession(
self.hass, cookie_jar=CookieJar(unsafe=True)
),
)
try:
await peblar.login(password=user_input[CONF_PASSWORD])
except PeblarAuthenticationError:
errors[CONF_PASSWORD] = "invalid_auth"
except PeblarConnectionError:
errors["base"] = "cannot_connect"
except Exception: # noqa: BLE001
LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
return self.async_update_reload_and_abort(
reauth_entry,
data={
CONF_HOST: reauth_entry.data[CONF_HOST],
CONF_PASSWORD: user_input[CONF_PASSWORD],
},
)
return self.async_show_form(
step_id="reauth_confirm",
data_schema=vol.Schema(
{
vol.Required(CONF_PASSWORD): TextSelector(
TextSelectorConfig(type=TextSelectorType.PASSWORD)
),
}
),
errors=errors,
)