Suppress homekit bridge discovery by homekit controller (#39990)
parent
11d74124cd
commit
84578f515d
|
@ -8,12 +8,19 @@ import voluptuous as vol
|
|||
from homeassistant import config_entries
|
||||
from homeassistant.components import zeroconf
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.device_registry import (
|
||||
CONNECTION_NETWORK_MAC,
|
||||
async_get_registry as async_get_device_registry,
|
||||
)
|
||||
|
||||
from .connection import get_accessory_name, get_bridge_information
|
||||
from .const import DOMAIN, KNOWN_DEVICES
|
||||
|
||||
HOMEKIT_IGNORE = ["Home Assistant Bridge"]
|
||||
HOMEKIT_DIR = ".homekit"
|
||||
HOMEKIT_BRIDGE_DOMAIN = "homekit"
|
||||
HOMEKIT_BRIDGE_SERIAL_NUMBER = "homekit.bridge"
|
||||
HOMEKIT_BRIDGE_MODEL = "Home Assistant HomeKit Bridge"
|
||||
|
||||
PAIRING_FILE = "pairing.json"
|
||||
|
||||
PIN_FORMAT = re.compile(r"^(\d{3})-{0,1}(\d{2})-{0,1}(\d{3})$")
|
||||
|
@ -141,6 +148,17 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow):
|
|||
|
||||
return self.async_abort(reason="no_devices")
|
||||
|
||||
async def _hkid_is_homekit_bridge(self, hkid):
|
||||
"""Determine if the device is a homekit bridge."""
|
||||
dev_reg = await async_get_device_registry(self.hass)
|
||||
device = dev_reg.async_get_device(
|
||||
identifiers=set(), connections={(CONNECTION_NETWORK_MAC, hkid)}
|
||||
)
|
||||
|
||||
if device is None:
|
||||
return False
|
||||
return device.model == HOMEKIT_BRIDGE_MODEL
|
||||
|
||||
async def async_step_zeroconf(self, discovery_info):
|
||||
"""Handle a discovered HomeKit accessory.
|
||||
|
||||
|
@ -153,6 +171,12 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow):
|
|||
key.lower(): value for (key, value) in discovery_info["properties"].items()
|
||||
}
|
||||
|
||||
if "id" not in properties:
|
||||
_LOGGER.warning(
|
||||
"HomeKit device %s: id not exposed, in violation of spec", properties
|
||||
)
|
||||
return self.async_abort(reason="invalid_properties")
|
||||
|
||||
# The hkid is a unique random number that looks like a pairing code.
|
||||
# It changes if a device is factory reset.
|
||||
hkid = properties["id"]
|
||||
|
@ -208,7 +232,7 @@ class HomekitControllerFlowHandler(config_entries.ConfigFlow):
|
|||
# Devices in HOMEKIT_IGNORE have native local integrations - users
|
||||
# should be encouraged to use native integration and not confused
|
||||
# by alternative HK API.
|
||||
if model in HOMEKIT_IGNORE:
|
||||
if await self._hkid_is_homekit_bridge(hkid):
|
||||
return self.async_abort(reason="ignored_model")
|
||||
|
||||
self.model = model
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"already_configured": "Accessory is already configured with this controller.",
|
||||
"invalid_config_entry": "This device is showing as ready to pair but there is already a conflicting configuration entry for it in Home Assistant that must first be removed.",
|
||||
"accessory_not_found_error": "Cannot add pairing as device can no longer be found.",
|
||||
"invalid_properties": "Invalid properties announced by device.",
|
||||
"already_in_progress": "Config flow for device is already in progress."
|
||||
}
|
||||
},
|
||||
|
|
|
@ -8,10 +8,11 @@ from aiohomekit.model.services import ServicesTypes
|
|||
import pytest
|
||||
|
||||
from homeassistant.components.homekit_controller import config_flow
|
||||
from homeassistant.helpers import device_registry
|
||||
|
||||
import tests.async_mock
|
||||
from tests.async_mock import patch
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.common import MockConfigEntry, mock_device_registry
|
||||
|
||||
PAIRING_START_FORM_ERRORS = [
|
||||
(KeyError, "pairing_failed"),
|
||||
|
@ -233,11 +234,45 @@ async def test_pair_already_paired_1(hass, controller):
|
|||
assert result["reason"] == "already_paired"
|
||||
|
||||
|
||||
async def test_id_missing(hass, controller):
|
||||
"""Test id is missing."""
|
||||
device = setup_mock_accessory(controller)
|
||||
discovery_info = get_device_discovery_info(device)
|
||||
|
||||
# Remove id from device
|
||||
del discovery_info["properties"]["id"]
|
||||
|
||||
# Device is discovered
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
"homekit_controller", context={"source": "zeroconf"}, data=discovery_info
|
||||
)
|
||||
assert result["type"] == "abort"
|
||||
assert result["reason"] == "invalid_properties"
|
||||
|
||||
|
||||
async def test_discovery_ignored_model(hass, controller):
|
||||
"""Already paired."""
|
||||
device = setup_mock_accessory(controller)
|
||||
discovery_info = get_device_discovery_info(device)
|
||||
discovery_info["properties"]["md"] = config_flow.HOMEKIT_IGNORE[0]
|
||||
|
||||
config_entry = MockConfigEntry(domain=config_flow.HOMEKIT_BRIDGE_DOMAIN, data={})
|
||||
formatted_mac = device_registry.format_mac("AA:BB:CC:DD:EE:FF")
|
||||
|
||||
dev_reg = mock_device_registry(hass)
|
||||
dev_reg.async_get_or_create(
|
||||
config_entry_id=config_entry.entry_id,
|
||||
identifiers={
|
||||
(
|
||||
config_flow.HOMEKIT_BRIDGE_DOMAIN,
|
||||
config_entry.entry_id,
|
||||
config_flow.HOMEKIT_BRIDGE_SERIAL_NUMBER,
|
||||
)
|
||||
},
|
||||
connections={(device_registry.CONNECTION_NETWORK_MAC, formatted_mac)},
|
||||
model=config_flow.HOMEKIT_BRIDGE_MODEL,
|
||||
)
|
||||
|
||||
discovery_info["properties"]["id"] = "AA:BB:CC:DD:EE:FF"
|
||||
|
||||
# Device is discovered
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
|
Loading…
Reference in New Issue