mirror of
https://github.com/home-assistant/core.git
synced 2026-09-08 06:31:35 +01:00
Co-authored-by: Paulus Schoutsen <balloob@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
121 lines
4.4 KiB
Python
121 lines
4.4 KiB
Python
"""Tonewinner configuration flow."""
|
|
|
|
import logging
|
|
from typing import Any, override
|
|
|
|
from tonewinner_rs232 import ReceiverInfo, TonewinnerReceiver
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.config_entries import (
|
|
ConfigEntryState,
|
|
ConfigFlow as ConfigEntryFlow,
|
|
ConfigFlowResult,
|
|
)
|
|
from homeassistant.const import CONF_MODEL
|
|
from homeassistant.helpers.selector import SerialPortSelector
|
|
|
|
from .const import CONF_SERIAL_PORT, DOMAIN
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
STEP_USER_DATA_SCHEMA = vol.Schema(
|
|
{
|
|
vol.Required(CONF_SERIAL_PORT): SerialPortSelector(),
|
|
}
|
|
)
|
|
|
|
|
|
class TonewinnerConfigFlow(ConfigEntryFlow, domain=DOMAIN):
|
|
"""Handle the Tonewinner config flow."""
|
|
|
|
async def _async_probe_receiver(self, port: str) -> str | None:
|
|
"""Verify a receiver answers on the port and return its model."""
|
|
receiver = TonewinnerReceiver(port)
|
|
try:
|
|
await receiver.connect()
|
|
info: ReceiverInfo | None = await receiver.query_info()
|
|
finally:
|
|
await receiver.disconnect()
|
|
return info.model if info else None
|
|
|
|
@override
|
|
async def async_step_user(
|
|
self, user_input: dict[str, Any] | None = None
|
|
) -> ConfigFlowResult:
|
|
"""Handle initial step of configuration flow."""
|
|
errors = {}
|
|
if user_input is not None:
|
|
port = user_input[CONF_SERIAL_PORT]
|
|
# Check before probing: an entry already holding the port would
|
|
# make the probe fail even though the receiver is reachable.
|
|
self._async_abort_entries_match({CONF_SERIAL_PORT: port})
|
|
try:
|
|
model = await self._async_probe_receiver(port)
|
|
except OSError as err:
|
|
_LOGGER.warning("Failed to probe receiver on %s: %s", port, err)
|
|
errors["base"] = "cannot_connect"
|
|
else:
|
|
data: dict[str, Any] = {CONF_SERIAL_PORT: port}
|
|
title = "Tonewinner"
|
|
if model:
|
|
data[CONF_MODEL] = model
|
|
title = model
|
|
return self.async_create_entry(title=title, data=data)
|
|
|
|
return self.async_show_form(
|
|
step_id="user",
|
|
data_schema=STEP_USER_DATA_SCHEMA,
|
|
errors=errors,
|
|
)
|
|
|
|
async def async_step_reconfigure(
|
|
self, user_input: dict[str, Any] | None = None
|
|
) -> ConfigFlowResult:
|
|
"""Handle reconfiguration of the serial port connection."""
|
|
errors = {}
|
|
entry = self._get_reconfigure_entry()
|
|
|
|
if user_input is not None:
|
|
port = user_input[CONF_SERIAL_PORT]
|
|
self._async_abort_entries_match({CONF_SERIAL_PORT: port})
|
|
|
|
# Free the port before probing: a held port would race the probe,
|
|
# and an unchanged port deserves a fresh model check (device swap).
|
|
if entry.state is ConfigEntryState.LOADED:
|
|
if not await self.hass.config_entries.async_unload(entry.entry_id):
|
|
# The receiver is still connected; probing would race it.
|
|
_LOGGER.warning(
|
|
"Failed to unload %s before reconfiguring", entry.title
|
|
)
|
|
return self.async_abort(reason="reconfigure_unload_failed")
|
|
else:
|
|
entry.async_cancel_retry_setup()
|
|
|
|
try:
|
|
model = await self._async_probe_receiver(port)
|
|
except OSError as err:
|
|
_LOGGER.warning("Failed to probe receiver on %s: %s", port, err)
|
|
errors["base"] = "cannot_connect"
|
|
# Bring the previous configuration back up so the receiver
|
|
# keeps working while the user retries.
|
|
await self.hass.config_entries.async_setup(entry.entry_id)
|
|
else:
|
|
data: dict[str, Any] = {CONF_SERIAL_PORT: port}
|
|
title = "Tonewinner"
|
|
if model:
|
|
data[CONF_MODEL] = model
|
|
title = model
|
|
return self.async_update_reload_and_abort(
|
|
entry,
|
|
data=data,
|
|
title=title,
|
|
)
|
|
|
|
return self.async_show_form(
|
|
step_id="reconfigure",
|
|
data_schema=self.add_suggested_values_to_schema(
|
|
STEP_USER_DATA_SCHEMA, entry.data
|
|
),
|
|
errors=errors,
|
|
)
|