penguin/homekey-relay

homekey-relay

custom_components/homekey_reader/config_flow.py

raw ยท 3472 bytes

"""Config flow for HomeKey Reader."""

from __future__ import annotations

from typing import Any

import voluptuous as vol

from homeassistant.components import bluetooth
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_ADDRESS

from .const import DOMAIN, SERVICE_UUID


class HomeKeyReaderConfigFlow(ConfigFlow, domain=DOMAIN):
    """Handle a config flow for HomeKey Reader."""

    VERSION = 1

    def __init__(self) -> None:
        self._discovery_info: BluetoothServiceInfoBleak | None = None
        self._discovered: dict[str, BluetoothServiceInfoBleak] = {}

    async def async_step_bluetooth(
        self, discovery_info: BluetoothServiceInfoBleak
    ) -> ConfigFlowResult:
        """Handle Bluetooth discovery."""
        await self.async_set_unique_id(discovery_info.address)
        self._abort_if_unique_id_configured()

        self._discovery_info = discovery_info
        name = discovery_info.name or discovery_info.address
        self.context["title_placeholders"] = {"name": name}
        return await self.async_step_bluetooth_confirm()

    async def async_step_bluetooth_confirm(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Confirm a Bluetooth-discovered reader."""
        assert self._discovery_info is not None

        if user_input is not None:
            return self.async_create_entry(
                title=self._discovery_info.name or "HomeKey Reader",
                data={CONF_ADDRESS: self._discovery_info.address},
            )

        self._set_confirm_only()
        return self.async_show_form(
            step_id="bluetooth_confirm",
            description_placeholders={
                "name": self._discovery_info.name or self._discovery_info.address,
                "address": self._discovery_info.address,
            },
        )

    async def async_step_user(
        self, user_input: dict[str, Any] | None = None
    ) -> ConfigFlowResult:
        """Let the user choose a currently visible reader."""
        if user_input is not None:
            address = user_input[CONF_ADDRESS]
            info = self._discovered[address]

            await self.async_set_unique_id(address, raise_on_progress=False)
            self._abort_if_unique_id_configured()

            return self.async_create_entry(
                title=info.name or "HomeKey Reader",
                data={CONF_ADDRESS: address},
            )

        configured = self._async_current_ids(include_ignore=False)
        wanted_uuid = SERVICE_UUID.lower()

        for info in bluetooth.async_discovered_service_info(
            self.hass, connectable=False
        ):
            service_data_uuids = {uuid.lower() for uuid in info.service_data}
            if wanted_uuid not in service_data_uuids:
                continue
            if info.address in configured:
                continue
            self._discovered[info.address] = info

        if not self._discovered:
            return self.async_abort(reason="no_devices_found")

        choices = {
            address: f"{info.name or 'HomeKey Reader'} ({address})"
            for address, info in self._discovered.items()
        }

        return self.async_show_form(
            step_id="user",
            data_schema=vol.Schema({vol.Required(CONF_ADDRESS): vol.In(choices)}),
        )