Use ConfigFlow.has_matching_flow to deduplicate yalexs_ble flows (#126899)

This commit is contained in:
Erik Montnemery 2024-09-27 19:07:23 +02:00 committed by GitHub
parent 616c0ebaa4
commit 46812777e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 44 deletions

View File

@ -4,7 +4,7 @@ from __future__ import annotations
from collections.abc import Mapping
import logging
from typing import Any
from typing import Any, Self
from bleak_retry_connector import BleakError, BLEDevice
import voluptuous as vol
@ -68,6 +68,11 @@ class YalexsConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1
_address: str | None = None
_local_name_is_unique = False
active = False
local_name: str | None = None
def __init__(self) -> None:
"""Initialize the config flow."""
self._discovery_info: BluetoothServiceInfoBleak | None = None
@ -81,7 +86,7 @@ class YalexsConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle the bluetooth discovery step."""
await self.async_set_unique_id(discovery_info.address)
self._abort_if_unique_id_configured()
self.context["local_name"] = discovery_info.name
self.local_name = discovery_info.name
self._discovery_info = discovery_info
self.context["title_placeholders"] = {
"name": human_readable_name(
@ -103,8 +108,8 @@ class YalexsConfigFlow(ConfigFlow, domain=DOMAIN):
)
address = lock_cfg.address
local_name = lock_cfg.local_name
hass = self.hass
self.local_name = lock_cfg.local_name
self._local_name_is_unique = local_name_is_unique(self.local_name)
# We do not want to raise on progress as integration_discovery takes
# precedence over other discovery flows since we already have the keys.
@ -116,7 +121,7 @@ class YalexsConfigFlow(ConfigFlow, domain=DOMAIN):
self._abort_if_unique_id_configured(updates=new_data)
for entry in self._async_current_entries():
if (
local_name_is_unique(lock_cfg.local_name)
self._local_name_is_unique
and entry.data.get(CONF_LOCAL_NAME) == lock_cfg.local_name
):
return self.async_update_reload_and_abort(
@ -124,27 +129,14 @@ class YalexsConfigFlow(ConfigFlow, domain=DOMAIN):
)
self._discovery_info = async_find_existing_service_info(
hass, local_name, address
self.hass, self.local_name, address
)
if not self._discovery_info:
return self.async_abort(reason="no_devices_found")
# Integration discovery should abort other flows unless they
# are already in the process of being set up since this discovery
# will already have all the keys and the user can simply confirm.
for progress in self._async_in_progress(include_uninitialized=True):
context = progress["context"]
if (
local_name_is_unique(local_name)
and context.get("local_name") == local_name
) or context.get("unique_id") == address:
if context.get("active"):
# The user has already started interacting with this flow
# and entered the keys. We abort the discovery flow since
# we assume they do not want to use the discovered keys for
# some reason.
raise AbortFlow("already_in_progress")
hass.config_entries.flow.async_abort(progress["flow_id"])
self._address = address
if self.hass.config_entries.flow.async_has_matching_flow(self):
raise AbortFlow("already_in_progress")
self._lock_cfg = lock_cfg
self.context["title_placeholders"] = {
@ -154,6 +146,24 @@ class YalexsConfigFlow(ConfigFlow, domain=DOMAIN):
}
return await self.async_step_integration_discovery_confirm()
def is_matching(self, other_flow: Self) -> bool:
"""Return True if other_flow is matching this flow."""
# Integration discovery should abort other flows unless they
# are already in the process of being set up since this discovery
# will already have all the keys and the user can simply confirm.
if (
self._local_name_is_unique and other_flow.local_name == self.local_name
) or other_flow.unique_id == self._address:
if other_flow.active:
# The user has already started interacting with this flow
# and entered the keys. We abort the discovery flow since
# we assume they do not want to use the discovered keys for
# some reason.
return True
self.hass.config_entries.flow.async_abort(other_flow.flow_id)
return False
async def async_step_integration_discovery_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
@ -234,7 +244,7 @@ class YalexsConfigFlow(ConfigFlow, domain=DOMAIN):
errors: dict[str, str] = {}
if user_input is not None:
self.context["active"] = True
self.active = True
address = user_input[CONF_ADDRESS]
discovery_info = self._discovered_devices[address]
local_name = discovery_info.name

View File

@ -513,14 +513,10 @@ async def test_integration_discovery_takes_precedence_over_bluetooth(
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
flows = [
flow
for flow in hass.config_entries.flow.async_progress()
if flow["handler"] == DOMAIN
]
flows = list(hass.config_entries.flow._handler_progress_index[DOMAIN])
assert len(flows) == 1
assert flows[0]["context"]["unique_id"] == YALE_ACCESS_LOCK_DISCOVERY_INFO.address
assert flows[0]["context"]["local_name"] == YALE_ACCESS_LOCK_DISCOVERY_INFO.name
assert flows[0].unique_id == YALE_ACCESS_LOCK_DISCOVERY_INFO.address
assert flows[0].local_name == YALE_ACCESS_LOCK_DISCOVERY_INFO.name
with patch(
"homeassistant.components.yalexs_ble.util.async_discovered_service_info",
@ -728,14 +724,10 @@ async def test_integration_discovery_takes_precedence_over_bluetooth_uuid_addres
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
flows = [
flow
for flow in hass.config_entries.flow.async_progress()
if flow["handler"] == DOMAIN
]
flows = list(hass.config_entries.flow._handler_progress_index[DOMAIN])
assert len(flows) == 1
assert flows[0]["context"]["unique_id"] == LOCK_DISCOVERY_INFO_UUID_ADDRESS.address
assert flows[0]["context"]["local_name"] == LOCK_DISCOVERY_INFO_UUID_ADDRESS.name
assert flows[0].unique_id == LOCK_DISCOVERY_INFO_UUID_ADDRESS.address
assert flows[0].local_name == LOCK_DISCOVERY_INFO_UUID_ADDRESS.name
with patch(
"homeassistant.components.yalexs_ble.util.async_discovered_service_info",
@ -808,14 +800,10 @@ async def test_integration_discovery_takes_precedence_over_bluetooth_non_unique_
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
flows = [
flow
for flow in hass.config_entries.flow.async_progress()
if flow["handler"] == DOMAIN
]
flows = list(hass.config_entries.flow._handler_progress_index[DOMAIN])
assert len(flows) == 1
assert flows[0]["context"]["unique_id"] == OLD_FIRMWARE_LOCK_DISCOVERY_INFO.address
assert flows[0]["context"]["local_name"] == OLD_FIRMWARE_LOCK_DISCOVERY_INFO.name
assert flows[0].unique_id == OLD_FIRMWARE_LOCK_DISCOVERY_INFO.address
assert flows[0].local_name == OLD_FIRMWARE_LOCK_DISCOVERY_INFO.name
with patch(
"homeassistant.components.yalexs_ble.util.async_discovered_service_info",