This commit is contained in:
J. Nick Koston
2023-02-15 15:58:46 -06:00
parent e6d1f30b4d
commit 19e6b61837
4 changed files with 76 additions and 260 deletions

View File

@@ -4,242 +4,65 @@ To update, run python3 -m script.hassfest
""" """
HOMEKIT = { HOMEKIT = {
"3810X": { "3810X": "roku",
"domain": "roku", "3820X": "roku",
"iot_class": "local_polling", "4660X": "roku",
}, "7820X": "roku",
"3820X": { "819LMB": "myq",
"domain": "roku", "AC02": "tado",
"iot_class": "local_polling", "Abode": "abode",
}, "BSB002": "hue",
"4660X": { "C105X": "roku",
"domain": "roku", "C135X": "roku",
"iot_class": "local_polling", "EB-*": "ecobee",
}, "Escea": "escea",
"7820X": { "HHKBridge*": "hive",
"domain": "roku", "Healty Home Coach": "netatmo",
"iot_class": "local_polling", "Iota": "abode",
}, "LIFX A19": "lifx",
"819LMB": { "LIFX BR30": "lifx",
"domain": "myq", "LIFX Beam": "lifx",
"iot_class": "cloud_polling", "LIFX Candle": "lifx",
}, "LIFX Clean": "lifx",
"AC02": { "LIFX Color": "lifx",
"domain": "tado", "LIFX DLCOL": "lifx",
"iot_class": "cloud_polling", "LIFX DLWW": "lifx",
}, "LIFX Dlight": "lifx",
"Abode": { "LIFX Downlight": "lifx",
"domain": "abode", "LIFX Filament": "lifx",
"iot_class": "cloud_push", "LIFX GU10": "lifx",
}, "LIFX Lightstrip": "lifx",
"BSB002": { "LIFX Mini": "lifx",
"domain": "hue", "LIFX Nightvision": "lifx",
"iot_class": "local_push", "LIFX Pls": "lifx",
}, "LIFX Plus": "lifx",
"C105X": { "LIFX Tile": "lifx",
"domain": "roku", "LIFX White": "lifx",
"iot_class": "local_polling", "LIFX Z": "lifx",
}, "MYQ": "myq",
"C135X": { "NL29": "nanoleaf",
"domain": "roku", "NL42": "nanoleaf",
"iot_class": "local_polling", "NL47": "nanoleaf",
}, "NL48": "nanoleaf",
"EB-*": { "NL52": "nanoleaf",
"domain": "ecobee", "NL59": "nanoleaf",
"iot_class": "cloud_polling", "Netatmo Relay": "netatmo",
}, "PowerView": "hunterdouglas_powerview",
"Escea": { "Presence": "netatmo",
"domain": "escea", "Rachio": "rachio",
"iot_class": "local_push", "SPK5": "rainmachine",
}, "Sensibo": "sensibo",
"HHKBridge*": { "Smart Bridge": "lutron_caseta",
"domain": "hive", "Socket": "wemo",
"iot_class": "cloud_polling", "TRADFRI": "tradfri",
}, "Touch HD": "rainmachine",
"Healty Home Coach": { "Welcome": "netatmo",
"domain": "netatmo", "Wemo": "wemo",
"iot_class": "cloud_polling", "YL*": "yeelight",
}, "ecobee*": "ecobee",
"Iota": { "iSmartGate": "gogogate2",
"domain": "abode", "iZone": "izone",
"iot_class": "cloud_push", "tado": "tado",
},
"LIFX A19": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX BR30": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Beam": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Candle": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Clean": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Color": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX DLCOL": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX DLWW": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Dlight": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Downlight": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Filament": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX GU10": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Lightstrip": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Mini": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Nightvision": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Pls": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Plus": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Tile": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX White": {
"domain": "lifx",
"iot_class": "local_polling",
},
"LIFX Z": {
"domain": "lifx",
"iot_class": "local_polling",
},
"MYQ": {
"domain": "myq",
"iot_class": "cloud_polling",
},
"NL29": {
"domain": "nanoleaf",
"iot_class": "local_push",
},
"NL42": {
"domain": "nanoleaf",
"iot_class": "local_push",
},
"NL47": {
"domain": "nanoleaf",
"iot_class": "local_push",
},
"NL48": {
"domain": "nanoleaf",
"iot_class": "local_push",
},
"NL52": {
"domain": "nanoleaf",
"iot_class": "local_push",
},
"NL59": {
"domain": "nanoleaf",
"iot_class": "local_push",
},
"Netatmo Relay": {
"domain": "netatmo",
"iot_class": "cloud_polling",
},
"PowerView": {
"domain": "hunterdouglas_powerview",
"iot_class": "local_polling",
},
"Presence": {
"domain": "netatmo",
"iot_class": "cloud_polling",
},
"Rachio": {
"domain": "rachio",
"iot_class": "cloud_push",
},
"SPK5": {
"domain": "rainmachine",
"iot_class": "local_polling",
},
"Sensibo": {
"domain": "sensibo",
"iot_class": "cloud_polling",
},
"Smart Bridge": {
"domain": "lutron_caseta",
"iot_class": "local_push",
},
"Socket": {
"domain": "wemo",
"iot_class": "local_push",
},
"TRADFRI": {
"domain": "tradfri",
"iot_class": "local_polling",
},
"Touch HD": {
"domain": "rainmachine",
"iot_class": "local_polling",
},
"Welcome": {
"domain": "netatmo",
"iot_class": "cloud_polling",
},
"Wemo": {
"domain": "wemo",
"iot_class": "local_push",
},
"YL*": {
"domain": "yeelight",
"iot_class": "local_push",
},
"ecobee*": {
"domain": "ecobee",
"iot_class": "cloud_polling",
},
"iSmartGate": {
"domain": "gogogate2",
"iot_class": "local_polling",
},
"iZone": {
"domain": "izone",
"iot_class": "local_polling",
},
"tado": {
"domain": "tado",
"iot_class": "cloud_polling",
},
} }
ZEROCONF = { ZEROCONF = {

View File

@@ -423,11 +423,14 @@ async def async_get_homekit(
hass: HomeAssistant, hass: HomeAssistant,
) -> dict[str, HomeKitDiscoveredIntegration]: ) -> dict[str, HomeKitDiscoveredIntegration]:
"""Return cached list of homekit models.""" """Return cached list of homekit models."""
all_domains = set(HOMEKIT.values())
integrations_by_domain = await async_get_integrations(hass, all_domains)
homekit: dict[str, HomeKitDiscoveredIntegration] = { homekit: dict[str, HomeKitDiscoveredIntegration] = {
model: HomeKitDiscoveredIntegration(details["domain"], details["iot_class"]) model: HomeKitDiscoveredIntegration(domain, integration_or_exception.iot_class)
for model, details in HOMEKIT.items() for model, domain in HOMEKIT.items()
if (integration_or_exception := integrations_by_domain.get(domain))
and isinstance(integration_or_exception, Integration)
} }
integrations = await async_get_custom_components(hass) integrations = await async_get_custom_components(hass)
for integration in integrations.values(): for integration in integrations.values():
if ( if (

View File

@@ -12,7 +12,7 @@ from .serializer import format_python_namespace
def generate_and_validate(integrations: dict[str, Integration]) -> str: def generate_and_validate(integrations: dict[str, Integration]) -> str:
"""Validate and generate zeroconf data.""" """Validate and generate zeroconf data."""
service_type_dict = defaultdict(list) service_type_dict = defaultdict(list)
homekit_dict: dict[str, dict[str, str]] = {} homekit_dict: dict[str, str] = {}
for domain in sorted(integrations): for domain in sorted(integrations):
integration = integrations[domain] integration = integrations[domain]
@@ -42,10 +42,7 @@ def generate_and_validate(integrations: dict[str, Integration]) -> str:
) )
break break
homekit_dict[model] = { homekit_dict[model] = domain
"domain": domain,
"iot_class": integration.manifest["iot_class"],
}
# HomeKit models are matched on starting string, make sure none overlap. # HomeKit models are matched on starting string, make sure none overlap.
warned = set() warned = set()

View File

@@ -542,7 +542,7 @@ async def test_homekit_match_partial_space(hass, mock_async_zeroconf):
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{"LIFX": {"domain": "lifx", "iot_class": "local_polling"}}, {"LIFX": "lifx"},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
@@ -578,7 +578,7 @@ async def test_device_with_invalid_name(hass, mock_async_zeroconf, caplog):
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{"LIFX": {"domain": "lifx", "iot_class": "local_polling"}}, {"LIFX": "lifx"},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
@@ -609,7 +609,7 @@ async def test_homekit_match_partial_dash(hass, mock_async_zeroconf):
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{"Smart Bridge": {"domain": "lutron_caseta", "iot_class": "local_push"}}, {"Smart Bridge": "lutron_caseta"},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
@@ -638,11 +638,7 @@ async def test_homekit_match_partial_fnmatch(hass, mock_async_zeroconf):
zc_gen.ZEROCONF, zc_gen.ZEROCONF,
{"_hap._tcp.local.": [{"domain": "homekit_controller"}]}, {"_hap._tcp.local.": [{"domain": "homekit_controller"}]},
clear=True, clear=True,
), patch.dict( ), patch.dict(zc_gen.HOMEKIT, {"YLDP*": "yeelight"}, clear=True), patch.object(
zc_gen.HOMEKIT,
{"YLDP*": {"domain": "yeelight", "iot_class": "local_push"}},
clear=True,
), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
) as mock_config_flow, patch.object( ) as mock_config_flow, patch.object(
zeroconf, zeroconf,
@@ -671,7 +667,7 @@ async def test_homekit_match_full(hass, mock_async_zeroconf):
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{"BSB002": {"domain": "hue", "iot_class": "local_push"}}, {"BSB002": "hue"},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
@@ -702,10 +698,7 @@ async def test_homekit_already_paired(hass, mock_async_zeroconf):
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{ {"AC02": "tado", "tado": "tado"},
"AC02": {"domain": "tado", "iot_class": "cloud_polling"},
"tado": {"domain": "tado", "iot_class": "cloud_polling"},
},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
@@ -737,7 +730,7 @@ async def test_homekit_invalid_paring_status(hass, mock_async_zeroconf):
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{"Smart Bridge": {"domain": "lutron_caseta", "iot_class": "local_push"}}, {"Smart Bridge": "lutron_caseta"},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
@@ -801,7 +794,7 @@ async def test_homekit_controller_still_discovered_unpaired_for_cloud(
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{"Rachio": {"domain": "rachio", "iot_class": "cloud_push"}}, {"Rachio": "rachio"},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"
@@ -841,7 +834,7 @@ async def test_homekit_controller_still_discovered_unpaired_for_polling(
clear=True, clear=True,
), patch.dict( ), patch.dict(
zc_gen.HOMEKIT, zc_gen.HOMEKIT,
{"iSmartGate": {"domain": "gogogate2", "iot_class": "local_polling"}}, {"iSmartGate": "gogogate2"},
clear=True, clear=True,
), patch.object( ), patch.object(
hass.config_entries.flow, "async_init" hass.config_entries.flow, "async_init"