Refactor zeroconf matching to be more DRY (#60293)
parent
86cd46a0dd
commit
fd116fc408
|
@ -48,6 +48,18 @@ HOMEKIT_TYPES = [
|
|||
"_hap._udp.local.",
|
||||
]
|
||||
|
||||
# Keys we support matching against in properties that are always matched in
|
||||
# upper case. ex: ZeroconfServiceInfo.properties["macaddress"]
|
||||
UPPER_MATCH_PROPS = {"macaddress"}
|
||||
# Keys we support matching against in properties that are always matched in
|
||||
# lower case. ex: ZeroconfServiceInfo.properties["model"]
|
||||
LOWER_MATCH_PROPS = {"manufacturer", "model"}
|
||||
# Top level keys we support matching against in properties that are always matched in
|
||||
# lower case. ex: ZeroconfServiceInfo.name
|
||||
LOWER_MATCH_ATTRS = {"name"}
|
||||
# Everything we support matching
|
||||
ALL_MATCHERS = UPPER_MATCH_PROPS | LOWER_MATCH_PROPS | LOWER_MATCH_ATTRS
|
||||
|
||||
CONF_DEFAULT_INTERFACE = "default_interface"
|
||||
CONF_IPV6 = "ipv6"
|
||||
DEFAULT_DEFAULT_INTERFACE = True
|
||||
|
@ -306,6 +318,18 @@ async def _async_register_hass_zc_service(
|
|||
await aio_zc.async_register_service(info, allow_name_change=True)
|
||||
|
||||
|
||||
def _match_against_data(matcher: dict[str, str], match_data: dict[str, str]) -> bool:
|
||||
"""Check a matcher to ensure all values in match_data match."""
|
||||
return not any(
|
||||
key
|
||||
for key in ALL_MATCHERS
|
||||
if key in matcher
|
||||
and (
|
||||
key not in match_data or not fnmatch.fnmatch(match_data[key], matcher[key])
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class ZeroconfDiscovery:
|
||||
"""Discovery via zeroconf."""
|
||||
|
||||
|
@ -380,10 +404,10 @@ class ZeroconfDiscovery:
|
|||
return
|
||||
|
||||
_LOGGER.debug("Discovered new device %s %s", name, info)
|
||||
props: dict[str, str] = info.properties
|
||||
|
||||
# If we can handle it as a HomeKit discovery, we do that here.
|
||||
if service_type in HOMEKIT_TYPES:
|
||||
props = info.properties
|
||||
if domain := async_get_homekit_discovery_domain(self.homekit_models, props):
|
||||
discovery_flow.async_create_flow(
|
||||
self.hass, domain, {"source": config_entries.SOURCE_HOMEKIT}, info
|
||||
|
@ -405,52 +429,22 @@ class ZeroconfDiscovery:
|
|||
# likely bad homekit data
|
||||
return
|
||||
|
||||
if info.name:
|
||||
lowercase_name: str | None = info.name.lower()
|
||||
else:
|
||||
lowercase_name = None
|
||||
|
||||
if "macaddress" in info.properties:
|
||||
uppercase_mac: str | None = info.properties["macaddress"].upper()
|
||||
else:
|
||||
uppercase_mac = None
|
||||
|
||||
if "manufacturer" in info.properties:
|
||||
lowercase_manufacturer: str | None = info.properties["manufacturer"].lower()
|
||||
else:
|
||||
lowercase_manufacturer = None
|
||||
|
||||
if "model" in info.properties:
|
||||
lowercase_model: str | None = info.properties["model"].lower()
|
||||
else:
|
||||
lowercase_model = None
|
||||
match_data: dict[str, str] = {}
|
||||
for key in LOWER_MATCH_ATTRS:
|
||||
attr_value: str = getattr(info, key)
|
||||
match_data[key] = attr_value.lower()
|
||||
for key in UPPER_MATCH_PROPS:
|
||||
if key in props:
|
||||
match_data[key] = props[key].upper()
|
||||
for key in LOWER_MATCH_PROPS:
|
||||
if key in props:
|
||||
match_data[key] = props[key].lower()
|
||||
|
||||
# Not all homekit types are currently used for discovery
|
||||
# so not all service type exist in zeroconf_types
|
||||
for matcher in self.zeroconf_types.get(service_type, []):
|
||||
if len(matcher) > 1:
|
||||
if "macaddress" in matcher and (
|
||||
uppercase_mac is None
|
||||
or not fnmatch.fnmatch(uppercase_mac, matcher["macaddress"])
|
||||
):
|
||||
continue
|
||||
if "name" in matcher and (
|
||||
lowercase_name is None
|
||||
or not fnmatch.fnmatch(lowercase_name, matcher["name"])
|
||||
):
|
||||
continue
|
||||
if "manufacturer" in matcher and (
|
||||
lowercase_manufacturer is None
|
||||
or not fnmatch.fnmatch(
|
||||
lowercase_manufacturer, matcher["manufacturer"]
|
||||
)
|
||||
):
|
||||
continue
|
||||
if "model" in matcher and (
|
||||
lowercase_model is None
|
||||
or not fnmatch.fnmatch(lowercase_model, matcher["model"])
|
||||
):
|
||||
continue
|
||||
if len(matcher) > 1 and not _match_against_data(matcher, match_data):
|
||||
continue
|
||||
|
||||
discovery_flow.async_create_flow(
|
||||
self.hass,
|
||||
|
|
Loading…
Reference in New Issue