"""Config flow for Denon AVR Bluetooth integration.""" from __future__ import annotations import logging import re from typing import Any import voluptuous as vol from homeassistant import config_entries from homeassistant.data_entry_flow import FlowResult from .const import DOMAIN from .protocol import find_denon_devices _LOGGER = logging.getLogger(__name__) _MAC_RE = re.compile(r"^([0-9A-F]{2}:){5}[0-9A-F]{2}$", re.IGNORECASE) MANUAL_SCHEMA = vol.Schema( { vol.Required("mac"): str, vol.Optional("name", default="Denon AVR-S540BT"): str, } ) class DenonBTConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow for Denon AVR Bluetooth.""" VERSION = 1 def __init__(self) -> None: self._discovered: list[dict[str, Any]] = [] async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Entry point — try D-Bus discovery, fall back to manual.""" self._discovered = await self.hass.async_add_executor_job( find_denon_devices ) if self._discovered: return await self.async_step_select() return await self.async_step_manual() # ── Device selection ───────────────────────────────────────────────────── async def async_step_select( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Let the user pick a discovered device or go manual.""" if user_input is not None: chosen = user_input["device"] if chosen == "_manual": return await self.async_step_manual() for dev in self._discovered: if dev["mac"] == chosen: await self.async_set_unique_id(dev["mac"].upper()) self._abort_if_unique_id_configured() return self.async_create_entry( title=dev["name"], data={"mac": dev["mac"], "name": dev["name"]}, ) options = { dev["mac"]: f"{dev['name']} ({dev['mac']})" for dev in self._discovered } options["_manual"] = "Enter MAC address manually\u2026" return self.async_show_form( step_id="select", data_schema=vol.Schema( {vol.Required("device"): vol.In(options)} ), ) # ── Manual MAC entry ───────────────────────────────────────────────────── async def async_step_manual( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Handle manual MAC address entry.""" errors: dict[str, str] = {} if user_input is not None: mac = user_input["mac"].strip().upper() name = user_input.get("name", "Denon AVR") if not _MAC_RE.match(mac): errors["base"] = "invalid_mac" else: await self.async_set_unique_id(mac) self._abort_if_unique_id_configured() return self.async_create_entry( title=name, data={"mac": mac, "name": name}, ) return self.async_show_form( step_id="manual", data_schema=MANUAL_SCHEMA, errors=errors, )