Dismiss existing discoveries when a HomeKit device is paired (#62632)

This commit is contained in:
J. Nick Koston 2021-12-22 19:40:36 -10:00 committed by GitHub
parent 79627526c7
commit ef5e5c3f96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 12 deletions

View file

@ -9,7 +9,7 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.components import zeroconf
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.data_entry_flow import AbortFlow, FlowResult
from homeassistant.helpers.device_registry import (
CONNECTION_NETWORK_MAC,
async_get_registry as async_get_device_registry,
@ -223,6 +223,8 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
# The hkid is a unique random number that looks like a pairing code.
# It changes if a device is factory reset.
hkid = properties[zeroconf.ATTR_PROPERTIES_ID]
normalized_hkid = normalize_hkid(hkid)
model = properties["md"]
name = discovery_info.name.replace("._hap._tcp.local.", "")
status_flags = int(properties["sf"])
@ -240,7 +242,9 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
config_num = None
# Set unique-id and error out if it's already configured
existing_entry = await self.async_set_unique_id(normalize_hkid(hkid))
existing_entry = await self.async_set_unique_id(
normalized_hkid, raise_on_progress=False
)
updated_ip_port = {
"AccessoryIP": discovery_info.host,
"AccessoryPort": discovery_info.port,
@ -303,7 +307,15 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
# Set unique-id and error out if it's already configured
self._abort_if_unique_id_configured(updates=updated_ip_port)
self.context["hkid"] = hkid
for progress in self._async_in_progress(include_uninitialized=True):
if progress["context"].get("unique_id") == normalized_hkid:
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")
if paired:
# Device is paired but not to us - ignore it

View file

@ -206,7 +206,6 @@ async def test_discovery_works(hass, controller, upper_case_props, missing_cshar
assert result["type"] == "form"
assert result["step_id"] == "pair"
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
@ -577,7 +576,6 @@ async def test_pair_form_errors_on_start(hass, controller, exception, expected):
)
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
@ -593,7 +591,6 @@ async def test_pair_form_errors_on_start(hass, controller, exception, expected):
assert result["errors"]["pairing_code"] == expected
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
@ -627,7 +624,6 @@ async def test_pair_abort_errors_on_finish(hass, controller, exception, expected
)
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
@ -641,7 +637,6 @@ async def test_pair_abort_errors_on_finish(hass, controller, exception, expected
assert result["type"] == "form"
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
@ -669,7 +664,6 @@ async def test_pair_form_errors_on_finish(hass, controller, exception, expected)
)
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
@ -683,7 +677,6 @@ async def test_pair_form_errors_on_finish(hass, controller, exception, expected)
assert result["type"] == "form"
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
@ -697,7 +690,6 @@ async def test_pair_form_errors_on_finish(hass, controller, exception, expected)
assert result["errors"]["pairing_code"] == expected
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_ZEROCONF,
@ -820,7 +812,6 @@ async def test_unignore_works(hass, controller):
assert result["type"] == "form"
assert result["step_id"] == "pair"
assert get_flow_context(hass, result) == {
"hkid": "00:00:00:00:00:00",
"title_placeholders": {"name": "TestDevice"},
"unique_id": "00:00:00:00:00:00",
"source": config_entries.SOURCE_UNIGNORE,
@ -852,3 +843,44 @@ async def test_unignore_ignores_missing_devices(hass, controller):
assert result["type"] == "abort"
assert result["reason"] == "no_devices"
async def test_discovery_dismiss_existing_flow_on_paired(hass, controller):
"""Test that existing flows get dismissed once paired to something else."""
device = setup_mock_accessory(controller)
discovery_info = get_device_discovery_info(device)
# Set device as already not paired
discovery_info.properties["sf"] = 0x01
discovery_info.properties["c#"] = 99999
discovery_info.properties[zeroconf.ATTR_PROPERTIES_ID] = "AA:BB:CC:DD:EE:FF"
# Device is discovered
result = await hass.config_entries.flow.async_init(
"homekit_controller",
context={"source": config_entries.SOURCE_ZEROCONF},
data=discovery_info,
)
assert result["type"] == "form"
assert result["step_id"] == "pair"
await hass.async_block_till_done()
assert (
len(hass.config_entries.flow.async_progress_by_handler("homekit_controller"))
== 1
)
# Set device as already paired
discovery_info.properties["sf"] = 0x00
# Device is discovered again after pairing to someone else
result2 = await hass.config_entries.flow.async_init(
"homekit_controller",
context={"source": config_entries.SOURCE_ZEROCONF},
data=discovery_info,
)
assert result2["type"] == "abort"
assert result2["reason"] == "already_paired"
await hass.async_block_till_done()
assert (
len(hass.config_entries.flow.async_progress_by_handler("homekit_controller"))
== 0
)