Use ConfigFlow.has_matching_flow to deduplicate homekit_controller flows (#126894)

This commit is contained in:
Erik Montnemery 2024-09-27 13:41:55 +02:00 committed by GitHub
parent 6f70a52880
commit 59a690f214
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 21 additions and 18 deletions

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import logging
import re
from typing import TYPE_CHECKING, Any, cast
from typing import TYPE_CHECKING, Any, Self, cast
import aiohomekit
from aiohomekit import Controller, const as aiohomekit_const
@ -111,6 +111,8 @@ class HomekitControllerFlowHandler(ConfigFlow, domain=DOMAIN):
self.devices: dict[str, AbstractDiscovery] = {}
self.controller: Controller | None = None
self.finish_pairing: FinishPairing | None = None
self.pairing = False
self._device_paired = False
async def _async_setup_controller(self) -> None:
"""Create the controller."""
@ -300,18 +302,10 @@ class HomekitControllerFlowHandler(ConfigFlow, domain=DOMAIN):
# Set unique-id and error out if it's already configured
self._abort_if_unique_id_configured(updates=updated_ip_port)
for progress in self._async_in_progress(include_uninitialized=True):
context = progress["context"]
if context.get("unique_id") == normalized_hkid and not context.get(
"pairing"
):
if paired:
# If the device gets paired, we want to dismiss
# an existing discovery since we can no longer
# pair with it
self.hass.config_entries.flow.async_abort(progress["flow_id"])
else:
raise AbortFlow("already_in_progress")
self.hkid = normalized_hkid
self._device_paired = paired
if self.hass.config_entries.flow.async_has_matching_flow(self):
raise AbortFlow("already_in_progress")
if paired:
# Device is paired but not to us - ignore it
@ -332,13 +326,24 @@ class HomekitControllerFlowHandler(ConfigFlow, domain=DOMAIN):
self.name = name
self.model = model
self.category = Categories(int(properties.get("ci", 0)))
self.hkid = normalized_hkid
# We want to show the pairing form - but don't call async_step_pair
# directly as it has side effects (will ask the device to show a
# pairing code)
return self._async_step_pair_show_form()
def is_matching(self, other_flow: Self) -> bool:
"""Return True if other_flow is matching this flow."""
if other_flow.context.get("unique_id") == self.hkid and not other_flow.pairing:
if self._device_paired:
# If the device gets paired, we want to dismiss
# an existing discovery since we can no longer
# pair with it
self.hass.config_entries.flow.async_abort(other_flow.flow_id)
else:
return True
return False
async def async_step_bluetooth(
self, discovery_info: bluetooth.BluetoothServiceInfoBleak
) -> ConfigFlowResult:
@ -419,7 +424,7 @@ class HomekitControllerFlowHandler(ConfigFlow, domain=DOMAIN):
assert self.controller
if pair_info and self.finish_pairing:
self.context["pairing"] = True
self.pairing = True
code = pair_info["pairing_code"]
try:
code = ensure_pin_format(

View File

@ -1568,7 +1568,7 @@ class ConfigEntriesFlowManager(data_entry_flow.FlowManager[ConfigFlowResult]):
"""Check if an existing matching flow is in progress."""
if not (flows := self._handler_progress_index.get(flow.handler)):
return False
for other_flow in flows:
for other_flow in set(flows):
if other_flow is not flow and flow.is_matching(other_flow): # type: ignore[arg-type]
return True
return False

View File

@ -799,7 +799,6 @@ async def test_pair_form_errors_on_finish(
"title_placeholders": {"name": "TestDevice", "category": "Outlet"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
"pairing": True,
}
@ -850,7 +849,6 @@ async def test_pair_unknown_errors(hass: HomeAssistant, controller) -> None:
"title_placeholders": {"name": "TestDevice", "category": "Outlet"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
"pairing": True,
}