Initial commit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
"""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,
|
||||
)
|
||||
Reference in New Issue
Block a user