mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Handle homekit accessories where the pairing flag is wrong (#53385)
This commit is contained in:
parent
bf3a16eed4
commit
0db160e372
@ -3,6 +3,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
import aiohomekit
|
import aiohomekit
|
||||||
|
from aiohomekit.exceptions import AuthenticationError
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
@ -270,7 +271,29 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
# invalid. Remove it automatically.
|
# invalid. Remove it automatically.
|
||||||
existing = find_existing_host(self.hass, hkid)
|
existing = find_existing_host(self.hass, hkid)
|
||||||
if not paired and existing:
|
if not paired and existing:
|
||||||
await self.hass.config_entries.async_remove(existing.entry_id)
|
if self.controller is None:
|
||||||
|
await self._async_setup_controller()
|
||||||
|
|
||||||
|
pairing = self.controller.load_pairing(
|
||||||
|
existing.data["AccessoryPairingID"], dict(existing.data)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
await pairing.list_accessories_and_characteristics()
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s (%s - %s) claims to be unpaired but isn't. It's implementation of HomeKit is defective or a zeroconf relay is broadcasting stale data",
|
||||||
|
name,
|
||||||
|
model,
|
||||||
|
hkid,
|
||||||
|
)
|
||||||
|
return self.async_abort(reason="already_paired")
|
||||||
|
except AuthenticationError:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s (%s - %s) is unpaired. Removing invalid pairing for this device",
|
||||||
|
name,
|
||||||
|
model,
|
||||||
|
hkid,
|
||||||
|
)
|
||||||
|
await self.hass.config_entries.async_remove(existing.entry_id)
|
||||||
|
|
||||||
# Set unique-id and error out if it's already configured
|
# Set unique-id and error out if it's already configured
|
||||||
self._abort_if_unique_id_configured(updates=updated_ip_port)
|
self._abort_if_unique_id_configured(updates=updated_ip_port)
|
||||||
|
@ -4,6 +4,7 @@ import unittest.mock
|
|||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
import aiohomekit
|
import aiohomekit
|
||||||
|
from aiohomekit.exceptions import AuthenticationError
|
||||||
from aiohomekit.model import Accessories, Accessory
|
from aiohomekit.model import Accessories, Accessory
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
from aiohomekit.model.services import ServicesTypes
|
from aiohomekit.model.services import ServicesTypes
|
||||||
@ -351,8 +352,48 @@ async def test_discovery_does_not_ignore_non_homekit(hass, controller):
|
|||||||
assert result["type"] == "form"
|
assert result["type"] == "form"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_discovery_broken_pairing_flag(hass, controller):
|
||||||
|
"""
|
||||||
|
There is already a config entry for the pairing and its pairing flag is wrong in zeroconf.
|
||||||
|
|
||||||
|
We have seen this particular implementation error in 2 different devices.
|
||||||
|
"""
|
||||||
|
await controller.add_paired_device(Accessories(), "00:00:00:00:00:00")
|
||||||
|
|
||||||
|
MockConfigEntry(
|
||||||
|
domain="homekit_controller",
|
||||||
|
data={"AccessoryPairingID": "00:00:00:00:00:00"},
|
||||||
|
unique_id="00:00:00:00:00:00",
|
||||||
|
).add_to_hass(hass)
|
||||||
|
|
||||||
|
# We just added a mock config entry so it must be visible in hass
|
||||||
|
assert len(hass.config_entries.async_entries()) == 1
|
||||||
|
|
||||||
|
device = setup_mock_accessory(controller)
|
||||||
|
discovery_info = get_device_discovery_info(device)
|
||||||
|
|
||||||
|
# Make sure that we are pairable
|
||||||
|
assert discovery_info["properties"]["sf"] != 0x0
|
||||||
|
|
||||||
|
# Device is discovered
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
"homekit_controller",
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=discovery_info,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should still be paired.
|
||||||
|
config_entry_count = len(hass.config_entries.async_entries())
|
||||||
|
assert config_entry_count == 1
|
||||||
|
|
||||||
|
# Even though discovered as pairable, we bail out as already paired.
|
||||||
|
assert result["reason"] == "already_paired"
|
||||||
|
|
||||||
|
|
||||||
async def test_discovery_invalid_config_entry(hass, controller):
|
async def test_discovery_invalid_config_entry(hass, controller):
|
||||||
"""There is already a config entry for the pairing id but it's invalid."""
|
"""There is already a config entry for the pairing id but it's invalid."""
|
||||||
|
pairing = await controller.add_paired_device(Accessories(), "00:00:00:00:00:00")
|
||||||
|
|
||||||
MockConfigEntry(
|
MockConfigEntry(
|
||||||
domain="homekit_controller",
|
domain="homekit_controller",
|
||||||
data={"AccessoryPairingID": "00:00:00:00:00:00"},
|
data={"AccessoryPairingID": "00:00:00:00:00:00"},
|
||||||
@ -366,11 +407,16 @@ async def test_discovery_invalid_config_entry(hass, controller):
|
|||||||
discovery_info = get_device_discovery_info(device)
|
discovery_info = get_device_discovery_info(device)
|
||||||
|
|
||||||
# Device is discovered
|
# Device is discovered
|
||||||
result = await hass.config_entries.flow.async_init(
|
with patch.object(
|
||||||
"homekit_controller",
|
pairing,
|
||||||
context={"source": config_entries.SOURCE_ZEROCONF},
|
"list_accessories_and_characteristics",
|
||||||
data=discovery_info,
|
side_effect=AuthenticationError("Invalid pairing keys"),
|
||||||
)
|
):
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
"homekit_controller",
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=discovery_info,
|
||||||
|
)
|
||||||
|
|
||||||
# Discovery of a HKID that is in a pairable state but for which there is
|
# Discovery of a HKID that is in a pairable state but for which there is
|
||||||
# already a config entry - in that case the stale config entry is
|
# already a config entry - in that case the stale config entry is
|
||||||
|
Loading…
x
Reference in New Issue
Block a user