1
mirror of https://github.com/home-assistant/core synced 2024-10-04 07:58:43 +02:00
ha-core/homeassistant/components/baf/config_flow.py

123 lines
4.0 KiB
Python

"""Config flow for baf."""
from __future__ import annotations
from asyncio import timeout
import logging
from typing import Any
from aiobafi6 import Device, Service
from aiobafi6.discovery import PORT
import voluptuous as vol
from homeassistant.components import zeroconf
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_IP_ADDRESS
from .const import DOMAIN, RUN_TIMEOUT
from .models import BAFDiscovery
_LOGGER = logging.getLogger(__name__)
async def async_try_connect(ip_address: str) -> Device:
"""Validate we can connect to a device."""
device = Device(Service(ip_addresses=[ip_address], port=PORT))
run_future = device.async_run()
try:
async with timeout(RUN_TIMEOUT):
await device.async_wait_available()
except TimeoutError as ex:
raise CannotConnect from ex
finally:
run_future.cancel()
return device
class BAFFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle BAF discovery config flow."""
VERSION = 1
def __init__(self) -> None:
"""Initialize the BAF config flow."""
self.discovery: BAFDiscovery | None = None
async def async_step_zeroconf(
self, discovery_info: zeroconf.ZeroconfServiceInfo
) -> ConfigFlowResult:
"""Handle zeroconf discovery."""
if discovery_info.ip_address.version == 6:
return self.async_abort(reason="ipv6_not_supported")
properties = discovery_info.properties
ip_address = discovery_info.host
uuid = properties["uuid"]
model = properties["model"]
name = properties["name"]
await self.async_set_unique_id(uuid)
self._abort_if_unique_id_configured(updates={CONF_IP_ADDRESS: ip_address})
self.discovery = BAFDiscovery(ip_address, name, uuid, model)
return await self.async_step_discovery_confirm()
async def async_step_discovery_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Confirm discovery."""
assert self.discovery is not None
discovery = self.discovery
if user_input is not None:
return self.async_create_entry(
title=discovery.name,
data={CONF_IP_ADDRESS: discovery.ip_address},
)
placeholders = {
"name": discovery.name,
"model": discovery.model,
"ip_address": discovery.ip_address,
}
self.context["title_placeholders"] = placeholders
self._set_confirm_only()
return self.async_show_form(
step_id="discovery_confirm", description_placeholders=placeholders
)
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""
errors = {}
ip_address = (user_input or {}).get(CONF_IP_ADDRESS, "")
if user_input is not None:
try:
device = await async_try_connect(ip_address)
except CannotConnect:
errors[CONF_IP_ADDRESS] = "cannot_connect"
except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Unknown exception during connection test to %s", ip_address
)
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
device.dns_sd_uuid, raise_on_progress=False
)
self._abort_if_unique_id_configured(
updates={CONF_IP_ADDRESS: ip_address}
)
return self.async_create_entry(
title=device.name,
data={CONF_IP_ADDRESS: ip_address},
)
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{vol.Required(CONF_IP_ADDRESS, default=ip_address): str}
),
errors=errors,
)
class CannotConnect(Exception):
"""Exception to raise when we cannot connect."""