Add support for matching the zeroconf model property ()

pull/59316/head
J. Nick Koston 2021-11-07 07:44:15 -08:00 committed by GitHub
parent ddf0941275
commit b75476e844
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 0 deletions
homeassistant/components/zeroconf
script/hassfest
tests/components/zeroconf

View File

@ -397,6 +397,11 @@ class ZeroconfDiscovery:
else:
lowercase_manufacturer = None
if "model" in info[ATTR_PROPERTIES]:
lowercase_model: str | None = info[ATTR_PROPERTIES]["model"].lower()
else:
lowercase_model = None
# 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, []):
@ -418,6 +423,11 @@ class ZeroconfDiscovery:
)
):
continue
if "model" in matcher and (
lowercase_model is None
or not fnmatch.fnmatch(lowercase_model, matcher["model"])
):
continue
discovery_flow.async_create_flow(
self.hass,

View File

@ -187,6 +187,7 @@ MANIFEST_SCHEMA = vol.Schema(
str, verify_uppercase, verify_wildcard
),
vol.Optional("manufacturer"): vol.All(str, verify_lowercase),
vol.Optional("model"): vol.All(str, verify_lowercase),
vol.Optional("name"): vol.All(str, verify_lowercase),
}
),

View File

@ -126,6 +126,24 @@ def get_zeroconf_info_mock_manufacturer(manufacturer):
return mock_zc_info
def get_zeroconf_info_mock_model(model):
"""Return info for get_service_info for an zeroconf device."""
def mock_zc_info(service_type, name):
return AsyncServiceInfo(
service_type,
name,
addresses=[b"\n\x00\x00\x14"],
port=80,
weight=0,
priority=0,
server="name.local.",
properties={b"model": model.encode()},
)
return mock_zc_info
async def test_setup(hass, mock_async_zeroconf):
"""Test configured options for a device are loaded via config entry."""
with patch.object(
@ -330,6 +348,39 @@ async def test_zeroconf_match_manufacturer(hass, mock_async_zeroconf):
assert mock_config_flow.mock_calls[0][1][0] == "samsungtv"
async def test_zeroconf_match_model(hass, mock_async_zeroconf):
"""Test matching a specific model in zeroconf."""
def http_only_service_update_mock(ipv6, zeroconf, services, handlers):
"""Call service update handler."""
handlers[0](
zeroconf,
"_airplay._tcp.local.",
"s1000._airplay._tcp.local.",
ServiceStateChange.Added,
)
with patch.dict(
zc_gen.ZEROCONF,
{"_airplay._tcp.local.": [{"domain": "appletv", "model": "appletv*"}]},
clear=True,
), patch.object(
hass.config_entries.flow, "async_init"
) as mock_config_flow, patch.object(
zeroconf, "HaAsyncServiceBrowser", side_effect=http_only_service_update_mock
) as mock_service_browser, patch(
"homeassistant.components.zeroconf.AsyncServiceInfo",
side_effect=get_zeroconf_info_mock_model("appletv"),
):
assert await async_setup_component(hass, zeroconf.DOMAIN, {zeroconf.DOMAIN: {}})
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
await hass.async_block_till_done()
assert len(mock_service_browser.mock_calls) == 1
assert len(mock_config_flow.mock_calls) == 1
assert mock_config_flow.mock_calls[0][1][0] == "appletv"
async def test_zeroconf_match_manufacturer_not_present(hass, mock_async_zeroconf):
"""Test matchers reject when a property is missing."""