mirror of
https://github.com/home-assistant/core.git
synced 2026-08-28 02:24:46 -05:00
sandbox: trim the compat lane to one runner
The one-shot full cross-sweep that produced the original backlog (run_compat_full.py + categorize_failures.py + generate_backlog.py) and its machine-generated outputs (COMPAT_FULL.md/.csv, COMPAT_LATEST.md, COMPAT.csv, BACKLOG_FAILURES.json) were Phase-16 measurement scaffolding; the gate is long cleared. Keep the single ongoing runner (run_compat.py) and the two curated summaries (COMPAT.md, BACKLOG.md). Git-ignore the per-run machine output so it stops being checked in. Living docs updated; recover the full-sweep tooling from git history if a fresh tree-wide sweep is ever needed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
63ead8828c
commit
5433c8a558
@@ -0,0 +1,4 @@
|
||||
# Generated compat-lane output (run_compat.py). The curated COMPAT.md
|
||||
# baseline is committed; the per-run machine output is not.
|
||||
/COMPAT.csv
|
||||
/COMPAT_LATEST.md
|
||||
@@ -1,646 +0,0 @@
|
||||
{
|
||||
"test-only": {
|
||||
"aemet": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n }),",
|
||||
"node_id": "tests.components.aemet.test_diagnostics::test_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"airly": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.airly.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"airnow": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.airnow.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"airq": [
|
||||
{
|
||||
"excerpt": " 'config_entry': dict({\n - 'created_at': '2025-01-01T00:00:00+00:00',\n + 'created_at': '2026-05-24T04:51:45.904605+00:00',\n 'data': dict({\n ...\n 'minor_version': 1,...",
|
||||
"node_id": "tests.components.airq.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"airvisual": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.airvisual.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"airvisual_pro": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.airvisual_pro.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"airzone": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 'wifi-channel': 6,",
|
||||
"node_id": "tests.components.airzone.test_diagnostics::test_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"airzone_cloud": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 'temperature-setpoint-max-auto-air': 30.0,",
|
||||
"node_id": "tests.components.airzone_cloud.test_diagnostics::test_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"aladdin_connect": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.aladdin_connect.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"alexa_devices": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.alexa_devices.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"ambient_station": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.ambient_station.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"bang_olufsen": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.bang_olufsen.test_diagnostics::test_async_get_config_entry_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.bang_olufsen.test_diagnostics::test_async_get_config_entry_diagnostics_with_battery"
|
||||
}
|
||||
],
|
||||
"braviatv": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.braviatv.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"co2signal": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.co2signal.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"coinbase": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.coinbase.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"comelit": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.comelit.test_diagnostics::test_entry_diagnostics_bridge"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.comelit.test_diagnostics::test_entry_diagnostics_vedo"
|
||||
}
|
||||
],
|
||||
"data_grand_lyon": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.data_grand_lyon.test_diagnostics::test_config_entry_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.data_grand_lyon.test_diagnostics::test_config_entry_diagnostics_with_velov"
|
||||
}
|
||||
],
|
||||
"deconz": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.deconz.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"devolo_home_control": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.devolo_home_control.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"devolo_home_network": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.devolo_home_network.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"dsmr_reader": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.dsmr_reader.test_diagnostics::test_get_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"ecovacs": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.ecovacs.test_diagnostics::test_diagnostics[username@cloud]"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.ecovacs.test_diagnostics::test_diagnostics[username@self-hosted]"
|
||||
}
|
||||
],
|
||||
"eheimdigital": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.eheimdigital.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"enphase_envoy": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n dict({",
|
||||
"node_id": "tests.components.enphase_envoy.test_diagnostics::test_entry_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n dict({",
|
||||
"node_id": "tests.components.enphase_envoy.test_diagnostics::test_entry_diagnostics_with_fixtures"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n dict({",
|
||||
"node_id": "tests.components.enphase_envoy.test_diagnostics::test_entry_diagnostics_with_fixtures_with_error"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 0,",
|
||||
"node_id": "tests.components.enphase_envoy.test_diagnostics::test_entry_diagnostics_with_interface_information[envoy]"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 0,",
|
||||
"node_id": "tests.components.enphase_envoy.test_diagnostics::test_entry_diagnostics_with_interface_information[envoy_metered_batt_relay]"
|
||||
}
|
||||
],
|
||||
"firefly_iii": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.firefly_iii.test_diagnostics::test_get_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"freshr": [
|
||||
{
|
||||
"excerpt": " ...\n 'entry': dict({\n - 'created_at': '2026-01-01T00:00:00+00:00',\n + 'created_at': '2026-05-24T04:53:55.668547+00:00',\n 'data': dict({\n ......",
|
||||
"node_id": "tests.components.freshr.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"fritz": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.fritz.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"fronius": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n }),",
|
||||
"node_id": "tests.components.fronius.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"fyta": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 'scientific_name': 'Theobroma cacao',",
|
||||
"node_id": "tests.components.fyta.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"gios": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.gios.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"goodwe": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.goodwe.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"google_weather": [
|
||||
{
|
||||
"excerpt": " 'entry': dict({\n - 'created_at': '2026-03-20T21:22:23+00:00',\n + 'created_at': '2026-05-24T04:54:19.938808+00:00',\n 'data': dict({\n ...\n 'minor_version': 1,...",
|
||||
"node_id": "tests.components.google_weather.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"growatt_server": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.growatt_server.test_diagnostics::test_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.growatt_server.test_diagnostics::test_diagnostics_classic_api"
|
||||
}
|
||||
],
|
||||
"guardian": [
|
||||
{
|
||||
"excerpt": " Omitting 1 identical items, use -vv to show\n Differing items:\n {'entry': {'created_at': '2026-05-24T04:54:25.511997+00:00', 'data': {'ip_address': '192.168.1.100', 'port': 7777, 'uid': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}} != {'entry': {'created_at': <ANY>, 'data': {'ip_address': '192.168.1.100', 'port': 7777, 'uid': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}}\n Use -v to get more diff\n\ntests/components/guardian/test_diagnostics.py:24: in test_entry_diagnostics",
|
||||
"node_id": "tests.components.guardian.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"heos": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n dict({",
|
||||
"node_id": "tests.components.heos.test_diagnostics::test_config_entry_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.heos.test_diagnostics::test_config_entry_diagnostics_error_getting_system"
|
||||
}
|
||||
],
|
||||
"homeassistant_connect_zbt2": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.homeassistant_connect_zbt2.test_diagnostics::test_diagnostics_for_config_entry"
|
||||
}
|
||||
],
|
||||
"husqvarna_automower": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.husqvarna_automower.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"imgw_pib": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.imgw_pib.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"immich": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.immich.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"iqvia": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.iqvia.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"kostal_plenticore": [
|
||||
{
|
||||
"excerpt": " Omitting 3 identical items, use -vv to show\n Differing items:\n {'config_entry': {'created_at': '2026-05-24T04:55:51.181434+00:00', 'data': {'host': '192.168.1.2', 'password': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}} != {'config_entry': {'created_at': <ANY>, 'data': {'host': '192.168.1.2', 'password': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}}\n Use -v to get more diff\n\ntests/components/kostal_plenticore/test_diagnostics.py:26: in test_entry_diagnostics",
|
||||
"node_id": "tests.components.kostal_plenticore.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"lacrosse_view": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.lacrosse_view.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"madvr": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.madvr.test_diagnostics::test_entry_diagnostics[positive_payload0]"
|
||||
}
|
||||
],
|
||||
"melcloud": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.melcloud.test_diagnostics::test_get_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"modern_forms": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.modern_forms.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"motionblinds_ble": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.motionblinds_ble.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"nextdns": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 'cache_boost': True,",
|
||||
"node_id": "tests.components.nextdns.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"nice_go": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.nice_go.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"notion": [
|
||||
{
|
||||
"excerpt": " Omitting 1 identical items, use -vv to show\n Differing items:\n {'entry': {'created_at': '2026-05-24T04:57:19.794228+00:00', 'data': {'refresh_token': '**REDACTED**', 'user_uuid': '**REDACTED**', 'username': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}} != {'entry': {'created_at': <ANY>, 'data': {'refresh_token': '**REDACTED**', 'user_uuid': '**REDACTED**', 'username': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}}\n Use -v to get more diff\n\ntests/components/notion/test_diagnostics.py:19: in test_entry_diagnostics",
|
||||
"node_id": "tests.components.notion.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"novy_cooker_hood": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.novy_cooker_hood.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"openuv": [
|
||||
{
|
||||
"excerpt": " Omitting 1 identical items, use -vv to show\n Differing items:\n {'entry': {'created_at': '2026-05-24T04:57:39.013753+00:00', 'data': {'api_key': '**REDACTED**', 'elevation': 0, 'latitude': '**REDACTED**', 'longitude': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}} != {'entry': {'created_at': <ANY>, 'data': {'api_key': '**REDACTED**', 'elevation': 0, 'latitude': '**REDACTED**', 'longitude': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}}\n Use -v to get more diff\n\ntests/components/openuv/test_diagnostics.py:20: in test_entry_diagnostics",
|
||||
"node_id": "tests.components.openuv.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"opower": [
|
||||
{
|
||||
"excerpt": " ...\n 'entry': dict({\n - 'created_at': '2026-03-07T23:00:00+00:00',\n + 'created_at': '2026-05-24T04:57:42.183600+00:00',\n 'data': dict({\n ......",
|
||||
"node_id": "tests.components.opower.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"p1_monitor": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.p1_monitor.test_init::test_migration"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.p1_monitor.test_init::test_port_migration"
|
||||
}
|
||||
],
|
||||
"pegel_online": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.pegel_online.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"philips_js": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.philips_js.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"pi_hole": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.pi_hole.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"portainer": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.portainer.test_diagnostics::test_get_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"proximity": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.proximity.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"proxmoxve": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 'disk': 1234567890,",
|
||||
"node_id": "tests.components.proxmoxve.test_diagnostics::test_get_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"purpleair": [
|
||||
{
|
||||
"excerpt": " Omitting 1 identical items, use -vv to show\n Differing items:\n {'entry': {'created_at': '2026-05-24T04:58:14.127275+00:00', 'data': {'api_key': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}} != {'entry': {'created_at': <ANY>, 'data': {'api_key': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}}\n Use -v to get more diff\n\ntests/components/purpleair/test_diagnostics.py:18: in test_entry_diagnostics",
|
||||
"node_id": "tests.components.purpleair.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"rainforest_raven": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.rainforest_raven.test_diagnostics::test_entry_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.rainforest_raven.test_diagnostics::test_entry_diagnostics_no_meters"
|
||||
}
|
||||
],
|
||||
"rainmachine": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.rainmachine.test_diagnostics::test_entry_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.rainmachine.test_diagnostics::test_entry_diagnostics_failed_controller_diagnostics"
|
||||
}
|
||||
],
|
||||
"recollect_waste": [
|
||||
{
|
||||
"excerpt": " Omitting 1 identical items, use -vv to show\n Differing items:\n {'entry': {'created_at': '2026-05-24T04:58:25.488020+00:00', 'data': {'place_id': '**REDACTED**', 'service_id': '67890'}, 'disabled_by': None, 'discovery_keys': {}, ...}} != {'entry': {'created_at': <ANY>, 'data': {'place_id': '**REDACTED**', 'service_id': '67890'}, 'disabled_by': None, 'discovery_keys': {}, ...}}\n Use -v to get more diff\n\ntests/components/recollect_waste/test_diagnostics.py:20: in test_entry_diagnostics",
|
||||
"node_id": "tests.components.recollect_waste.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"ridwell": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.ridwell.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"samsungtv": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.samsungtv.test_diagnostics::test_entry_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.samsungtv.test_diagnostics::test_entry_diagnostics_encrypte_offline"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.samsungtv.test_diagnostics::test_entry_diagnostics_encrypted"
|
||||
}
|
||||
],
|
||||
"scrape": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.scrape.test_init::test_migrate_from_version_1_to_2"
|
||||
}
|
||||
],
|
||||
"screenlogic": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n ]),",
|
||||
"node_id": "tests.components.screenlogic.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"simplisafe": [
|
||||
{
|
||||
"excerpt": " Omitting 2 identical items, use -vv to show\n Differing items:\n {'entry': {'created_at': '2026-05-24T04:59:00.139992+00:00', 'data': {'token': '**REDACTED**', 'username': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}} != {'entry': {'created_at': <ANY>, 'data': {'token': '**REDACTED**', 'username': '**REDACTED**'}, 'disabled_by': None, 'discovery_keys': {}, ...}}\n Use -v to get more diff\n\ntests/components/simplisafe/test_diagnostics.py:18: in test_entry_diagnostics",
|
||||
"node_id": "tests.components.simplisafe.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"slide_local": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.slide_local.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"sma": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.sma.test_diagnostics::test_get_config_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"solarlog": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.solarlog.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"switchbot": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.switchbot.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"switcher_kis": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.switcher_kis.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"systemmonitor": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.systemmonitor.test_diagnostics::test_diagnostics"
|
||||
},
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.systemmonitor.test_diagnostics::test_diagnostics_missing_items"
|
||||
}
|
||||
],
|
||||
"tankerkoenig": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.tankerkoenig.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"tplink_omada": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 'memUtil': 20,",
|
||||
"node_id": "tests.components.tplink_omada.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"tractive": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.tractive.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"twinkly": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.twinkly.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"unifi": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n 'dtim_ng': 1,",
|
||||
"node_id": "tests.components.unifi.test_diagnostics::test_entry_diagnostics[wlan_payload0-dpi_group_payload0-dpi_app_payload0-device_payload0-client_payload0-config_entry_options0]"
|
||||
}
|
||||
],
|
||||
"utility_meter": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.utility_meter.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"v2c": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.v2c.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"velbus": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.velbus.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"vicare": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.vicare.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"vodafone_station": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.vodafone_station.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"watts": [
|
||||
{
|
||||
"excerpt": " ...\n 'entry': dict({\n - 'created_at': '2026-01-01T12:00:00+00:00',\n + 'created_at': '2026-05-24T05:01:22.558366+00:00',\n 'data': dict({\n ......",
|
||||
"node_id": "tests.components.watts.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"watttime": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.watttime.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"webmin": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.webmin.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"webostv": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.webostv.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"whirlpool": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.whirlpool.test_diagnostics::test_entry_diagnostics"
|
||||
}
|
||||
],
|
||||
"workday": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.workday.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"zha": [
|
||||
{
|
||||
"excerpt": " ...\n 'pref_disable_polling': False,\n + 'sandbox': 'built-in',\n 'source': 'user',\n ...\n })",
|
||||
"node_id": "tests.components.zha.test_diagnostics::test_diagnostics_for_config_entry"
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
"bluetooth": [
|
||||
{
|
||||
"excerpt": "tests/components/bluetooth/test_models.py:126: in test_wrapped_bleak_client_local_adapter_only\n await client.connect()\n.venv/lib/python3.14/site-packages/habluetooth/wrappers.py:437: in connect\n self._backend = wrapped_backend.client(\nE TypeError: BleakClientBlueZDBus.__init__() missing 1 required keyword-only argument: 'bluez'",
|
||||
"node_id": "tests.components.bluetooth.test_models::test_wrapped_bleak_client_local_adapter_only"
|
||||
}
|
||||
],
|
||||
"chess_com": [
|
||||
{
|
||||
"excerpt": " ...\n 'is_streamer': False,\n - 'joined': '2026-02-20T10:48:14',\n + 'joined': '2026-02-20T05:48:14',\n - 'last_online': '2026-03-06T12:32:59',\n + 'last_online': '2026-03-06T07:32:59',...",
|
||||
"node_id": "tests.components.chess_com.test_diagnostics::test_diagnostics"
|
||||
}
|
||||
],
|
||||
"google": [
|
||||
{
|
||||
"excerpt": " - some-updated-token\n + ACCESS_TOKEN\n\ntests/components/google/test_init.py:729: in test_invalid_token_expiry_in_config_entry\n assert entries[0].data[\"token\"][\"access_token\"] == \"some-updated-token\"\nE AssertionError: assert 'ACCESS_TOKEN' == 'some-updated-token'",
|
||||
"node_id": "tests.components.google.test_init::test_invalid_token_expiry_in_config_entry[timestamp_naive]"
|
||||
}
|
||||
],
|
||||
"html5": [
|
||||
{
|
||||
"excerpt": " Omitting 3 identical items, use -vv to show\n Differing items:\n {'timestamp': 18000000} != {'timestamp': 0}\n Use -v to get more diff\n\ntests/components/html5/test_notify.py:1165: in test_html5_send_message",
|
||||
"node_id": "tests.components.html5.test_notify::test_html5_send_message[service_data11-expected_payload11-86400-None]"
|
||||
}
|
||||
],
|
||||
"mastodon": [
|
||||
{
|
||||
"excerpt": " ...\n 'locked': False,\n - 'created_at': datetime.datetime(2016, 11, 24, 0, 0, tzinfo=tzlocal()),\n + 'created_at': datetime.datetime(2016, 11, 24, 0, 0, tzinfo=tzutc()),\n 'following_count': 328,\n ...",
|
||||
"node_id": "tests.components.mastodon.test_services::test_get_account_success"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -56,8 +56,9 @@ second condition), as a deliberate call relying on git history for rollback.
|
||||
**Docker test image** (`hass_client/Dockerfile` + `docker-compose.test.yml`)
|
||||
— see [`hass_client/docs/docker.md`](hass_client/docs/docker.md).
|
||||
- `docs/` — per-phase decision write-ups.
|
||||
- `run_compat.py` + `COMPAT.md` + `COMPAT.csv` — compat-lane runner
|
||||
and report (Phase 10).
|
||||
- `run_compat.py` + curated `COMPAT.md` / `BACKLOG.md` — compat-lane
|
||||
runner and reports. Per-run machine output (`COMPAT.csv` /
|
||||
`COMPAT_LATEST.md`) is git-ignored.
|
||||
|
||||
The HA Core side of the integration lives at
|
||||
`../homeassistant/components/sandbox/`.
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
integration,status,passed,failed,errors,skipped
|
||||
input_boolean,pass,18,0,0,0
|
||||
input_button,pass,15,0,0,0
|
||||
input_datetime,pass,28,0,0,0
|
||||
input_number,pass,24,0,0,0
|
||||
input_select,pass,26,0,0,0
|
||||
input_text,pass,23,0,0,0
|
||||
counter,pass,751,0,0,0
|
||||
timer,pass,877,0,0,0
|
||||
schedule,pass,387,0,0,0
|
||||
zone,pass,32,0,0,0
|
||||
tag,pass,12,0,0,0
|
||||
group,pass,392,0,0,0
|
||||
person,pass,34,0,0,0
|
||||
scene,pass,41,0,0,0
|
||||
todo,pass,281,0,0,0
|
||||
automation,pass,117,0,0,0
|
||||
script,pass,64,0,0,0
|
||||
alert,pass,18,0,0,0
|
||||
template,pass,2470,0,0,0
|
||||
plant,pass,11,0,0,0
|
||||
proximity,issues,27,1,0,0
|
||||
min_max,pass,20,0,0,0
|
||||
statistics,pass,56,0,0,0
|
||||
utility_meter,issues,94,1,0,0
|
||||
derivative,pass,76,0,0,0
|
||||
integration,pass,61,0,0,0
|
||||
generic_thermostat,pass,114,0,0,0
|
||||
generic_hygrostat,pass,76,0,0,0
|
||||
history_stats,pass,55,0,0,0
|
||||
threshold,pass,114,0,0,0
|
||||
filter,pass,32,0,0,0
|
||||
mqtt_statestream,pass,17,0,0,0
|
||||
recorder,pass,932,0,0,17
|
||||
rest,pass,128,0,0,0
|
||||
logbook,pass,106,0,0,0
|
||||
command_line,pass,78,0,0,0
|
||||
trend,pass,39,0,0,0
|
||||
|
@@ -1,808 +0,0 @@
|
||||
integration,status,passed,failed,errors,skipped,duration_s,dominant_bucket
|
||||
acaia,pass,24,0,0,0,3.52,
|
||||
accuweather,pass,38,0,0,0,5.08,
|
||||
acmeda,pass,8,0,0,0,2.59,
|
||||
actron_air,pass,49,0,0,0,5.25,
|
||||
adax,pass,20,0,0,0,2.86,
|
||||
adguard,pass,36,0,0,0,3.42,
|
||||
advantage_air,pass,20,0,0,0,4.91,
|
||||
aemet,issues,16,1,0,0,3.26,
|
||||
aftership,pass,2,0,0,0,2.29,
|
||||
aidot,pass,16,0,0,0,2.90,
|
||||
airgradient,pass,47,0,0,0,4.70,
|
||||
airly,issues,21,1,0,0,2.99,
|
||||
airnow,issues,9,1,0,0,2.55,
|
||||
airobot,pass,60,0,0,0,4.85,
|
||||
airos,pass,62,0,0,0,4.89,
|
||||
airpatrol,pass,25,0,0,0,3.19,
|
||||
airq,issues,22,1,0,0,3.30,
|
||||
airthings,pass,12,0,0,0,2.56,
|
||||
airthings_ble,pass,38,0,0,0,4.13,
|
||||
airtouch4,pass,5,0,0,0,2.39,
|
||||
airtouch5,pass,5,0,0,0,2.45,
|
||||
airvisual,issues,15,1,0,0,2.95,
|
||||
airvisual_pro,issues,10,1,0,0,2.68,
|
||||
airzone,issues,37,1,0,0,5.58,
|
||||
airzone_cloud,issues,26,1,0,0,4.95,
|
||||
aladdin_connect,issues,32,1,0,0,3.78,
|
||||
alarmdecoder,pass,8,0,0,0,2.40,
|
||||
alexa_devices,issues,72,1,0,0,7.34,
|
||||
altruist,pass,11,0,0,0,2.61,
|
||||
amberelectric,pass,39,0,0,0,3.62,
|
||||
ambient_network,pass,7,0,0,0,2.76,
|
||||
ambient_station,issues,3,1,0,0,2.59,
|
||||
analytics_insights,pass,20,0,0,0,3.11,
|
||||
androidtv,pass,79,0,0,0,5.23,
|
||||
androidtv_remote,pass,40,0,0,0,4.60,
|
||||
anglian_water,pass,14,0,0,0,3.52,
|
||||
anova,pass,11,0,0,0,2.65,
|
||||
anthemav,pass,11,0,0,0,2.59,
|
||||
aosmith,pass,33,0,0,0,3.64,
|
||||
apcupsd,pass,44,0,0,0,4.29,
|
||||
apple_tv,pass,51,0,0,0,4.60,
|
||||
aprilaire,pass,3,0,0,0,2.51,
|
||||
apsystems,pass,13,0,0,0,3.03,
|
||||
aquacell,pass,13,0,0,0,2.89,
|
||||
aranet,pass,19,0,0,0,3.42,
|
||||
arcam_fmj,pass,85,0,0,0,5.84,
|
||||
arve,pass,5,0,0,0,2.70,
|
||||
aseko_pool_live,pass,13,0,0,0,2.80,
|
||||
asuswrt,pass,60,0,0,0,4.68,
|
||||
atag,pass,14,0,0,0,2.94,
|
||||
aurora,pass,4,0,0,0,2.48,
|
||||
aurora_abb_powerone,pass,7,0,0,0,6.85,
|
||||
aussie_broadband,pass,14,0,0,0,2.68,
|
||||
autarco,pass,13,0,0,0,2.73,
|
||||
autoskope,pass,22,0,0,0,2.91,
|
||||
avea,pass,20,0,0,0,3.12,
|
||||
awair,pass,24,0,0,0,2.73,
|
||||
aws_s3,pass,51,0,0,0,4.96,
|
||||
azure_data_explorer,pass,18,0,0,0,2.75,
|
||||
azure_devops,pass,20,0,0,0,2.82,
|
||||
azure_event_hub,pass,21,0,0,0,2.65,
|
||||
azure_storage,pass,25,0,0,0,3.70,
|
||||
backblaze_b2,pass,77,0,0,0,5.64,
|
||||
baf,pass,8,0,0,0,2.46,
|
||||
balboa,pass,42,0,0,0,5.47,
|
||||
bang_olufsen,issues,100,2,0,0,35.95,
|
||||
bayesian,pass,48,0,0,0,3.16,
|
||||
blebox,pass,117,0,0,0,8.95,
|
||||
blue_current,pass,28,0,0,0,3.03,
|
||||
bluemaestro,pass,11,0,0,0,2.77,
|
||||
bluesound,pass,39,0,0,0,4.73,
|
||||
bluetooth,issues,234,1,0,1,9.76,
|
||||
bond,pass,141,0,0,0,6.29,
|
||||
bosch_alarm,pass,121,0,0,0,11.87,
|
||||
bosch_shc,pass,16,0,0,0,2.66,
|
||||
braviatv,issues,19,1,0,0,2.74,
|
||||
bring,pass,72,0,0,0,6.03,
|
||||
broadlink,pass,104,0,0,0,4.81,
|
||||
brother,pass,33,0,0,0,7.24,
|
||||
brottsplatskartan,pass,4,0,0,0,2.30,
|
||||
brunt,pass,8,0,0,0,2.39,
|
||||
bryant_evolution,pass,24,0,0,0,3.09,
|
||||
bsblan,pass,127,0,0,0,11.91,
|
||||
bthome,pass,107,0,0,0,6.98,
|
||||
caldav,pass,109,0,0,0,6.70,
|
||||
cambridge_audio,pass,52,0,0,0,7.84,
|
||||
casper_glow,pass,67,0,0,0,6.44,
|
||||
cast,pass,86,0,0,0,6.63,
|
||||
ccm15,pass,8,0,0,0,2.52,
|
||||
centriconnect,pass,10,0,0,0,2.49,
|
||||
cert_expiry,pass,18,0,0,0,2.82,
|
||||
chacon_dio,pass,16,0,0,0,2.83,
|
||||
chess_com,issues,8,1,0,0,2.82,
|
||||
cielo_home,pass,7,0,0,0,18.27,
|
||||
cloudflare,pass,14,0,0,0,2.53,
|
||||
cloudflare_r2,pass,59,0,0,0,4.67,
|
||||
co2signal,issues,15,1,0,0,2.87,
|
||||
coinbase,issues,15,1,0,0,2.59,
|
||||
color_extractor,pass,9,0,0,0,4.47,
|
||||
comelit,issues,93,2,0,0,8.99,
|
||||
compit,pass,65,0,0,0,6.46,
|
||||
control4,pass,54,0,0,0,4.60,
|
||||
cookidoo,pass,52,0,0,0,5.41,
|
||||
coolmaster,pass,37,0,0,0,3.46,
|
||||
cpuspeed,pass,8,0,0,0,2.38,
|
||||
crownstone,pass,11,0,0,0,2.68,
|
||||
cync,pass,19,0,0,0,2.65,
|
||||
daikin,pass,31,0,0,0,3.09,
|
||||
data_grand_lyon,issues,40,2,0,0,3.29,
|
||||
datadog,pass,12,0,0,0,2.41,
|
||||
deako,pass,13,0,0,0,2.86,
|
||||
deconz,issues,172,1,0,1,12.86,
|
||||
decora_wifi,pass,13,0,0,0,3.01,
|
||||
deluge,pass,7,0,0,0,2.30,
|
||||
denon_rs232,pass,23,0,0,0,3.07,
|
||||
denonavr,pass,16,0,0,0,2.87,
|
||||
derivative,pass,76,0,0,0,4.62,
|
||||
devialet,pass,13,0,0,0,2.63,
|
||||
devolo_home_control,issues,41,1,0,0,4.24,
|
||||
devolo_home_network,issues,51,1,0,0,6.02,
|
||||
dexcom,pass,10,0,0,0,2.45,
|
||||
dialogflow,pass,17,0,0,0,3.17,
|
||||
directv,pass,24,0,0,0,3.07,
|
||||
discord,pass,11,0,0,0,2.51,
|
||||
discovergy,pass,25,0,0,0,3.19,
|
||||
dlink,pass,15,0,0,0,2.57,
|
||||
dlna_dmr,pass,72,0,0,0,13.95,
|
||||
dlna_dms,pass,55,0,0,0,7.98,
|
||||
dnsip,pass,21,0,0,0,2.72,
|
||||
dormakaba_dkey,pass,14,0,0,0,2.86,
|
||||
downloader,pass,21,0,0,0,2.63,
|
||||
drop_connect,pass,30,0,0,0,3.78,
|
||||
dropbox,pass,29,0,0,0,3.63,
|
||||
droplet,pass,16,0,0,0,3.18,
|
||||
dsmr,pass,75,0,0,0,4.57,
|
||||
dsmr_reader,issues,8,1,0,0,2.77,
|
||||
duckdns,pass,18,0,0,0,2.68,
|
||||
duco,pass,61,0,0,0,7.51,
|
||||
dunehd,pass,6,0,0,0,2.38,
|
||||
duotecno,pass,5,0,0,0,2.35,
|
||||
dwd_weather_warnings,pass,11,0,0,0,2.47,
|
||||
dynalite,pass,33,0,0,0,3.44,
|
||||
eafm,pass,18,0,0,0,2.64,
|
||||
earn_e_p1,pass,25,0,0,0,2.87,
|
||||
easyenergy,pass,70,0,0,0,5.17,
|
||||
ecobee,pass,60,0,0,0,3.53,
|
||||
ecoforest,pass,4,0,0,0,2.35,
|
||||
econet,pass,4,0,0,0,2.33,
|
||||
ecovacs,issues,74,2,0,0,6.74,
|
||||
ecowitt,pass,1,0,0,0,2.32,
|
||||
edl21,pass,2,0,0,0,2.29,
|
||||
efergy,pass,12,0,0,0,2.54,
|
||||
egauge,pass,16,0,0,0,2.81,
|
||||
eheimdigital,issues,79,1,0,0,8.30,
|
||||
ekeybionyx,pass,13,0,0,0,7.73,
|
||||
electrasmart,pass,6,0,0,0,2.33,
|
||||
electric_kiwi,pass,18,0,0,0,3.04,
|
||||
elgato,pass,36,0,0,0,3.88,
|
||||
elkm1,pass,45,0,0,0,3.43,
|
||||
elmax,pass,29,0,0,0,2.85,
|
||||
elvia,pass,9,0,0,0,2.72,
|
||||
emoncms,pass,16,0,0,0,2.71,
|
||||
emonitor,pass,7,0,0,0,2.38,
|
||||
emulated_roku,pass,7,0,0,0,2.39,
|
||||
energenie_power_sockets,pass,13,0,0,0,2.61,
|
||||
energyid,pass,81,0,0,0,3.92,
|
||||
energyzero,pass,41,0,0,0,3.82,
|
||||
enigma2,pass,26,0,0,0,3.30,
|
||||
enocean,pass,14,0,0,0,2.77,
|
||||
enphase_envoy,issues,231,5,0,0,24.65,
|
||||
epic_games_store,pass,20,0,0,0,2.68,
|
||||
epion,pass,4,0,0,0,2.33,
|
||||
epson,pass,5,0,0,0,2.46,
|
||||
eq3btsmart,pass,4,0,0,0,2.56,
|
||||
escea,pass,3,0,0,0,2.32,
|
||||
essent,pass,14,0,0,0,2.69,
|
||||
eufylife_ble,pass,10,0,0,0,2.79,
|
||||
eurotronic_cometblue,pass,39,0,0,0,4.04,
|
||||
evil_genius_labs,pass,10,0,0,0,2.53,
|
||||
faa_delays,pass,4,0,0,0,2.33,
|
||||
fastdotcom,pass,8,0,0,0,2.50,
|
||||
feedreader,pass,30,0,0,0,3.02,
|
||||
fibaro,pass,45,0,0,0,3.93,
|
||||
file,pass,26,0,0,0,2.84,
|
||||
filesize,pass,13,0,0,0,2.58,
|
||||
filter,pass,32,0,0,0,4.13,
|
||||
fing,pass,17,0,0,0,2.88,
|
||||
firefly_iii,issues,25,1,0,0,3.30,
|
||||
fireservicerota,pass,5,0,0,0,2.35,
|
||||
fitbit,pass,60,0,0,0,6.46,
|
||||
fivem,pass,5,0,0,0,2.36,
|
||||
fjaraskupan,pass,11,0,0,0,2.87,
|
||||
flexit_bacnet,pass,19,0,0,0,2.75,
|
||||
flipr,pass,18,0,0,0,2.79,
|
||||
flo,pass,10,0,0,0,2.73,
|
||||
flume,pass,11,0,0,0,2.50,
|
||||
fluss,pass,16,0,0,0,2.71,
|
||||
flux_led,pass,82,0,0,0,6.59,
|
||||
folder_watcher,pass,10,0,0,0,2.63,
|
||||
forecast_solar,pass,28,0,0,0,2.97,
|
||||
forked_daapd,pass,36,0,0,0,4.60,
|
||||
freedompro,pass,38,0,0,0,4.48,
|
||||
freshr,issues,28,1,0,0,3.42,
|
||||
fressnapf_tracker,pass,45,0,0,0,4.49,
|
||||
fritz,issues,138,1,0,0,10.15,
|
||||
fritzbox,pass,132,0,0,0,8.57,
|
||||
fritzbox_callmonitor,pass,12,0,0,0,2.45,
|
||||
fronius,issues,35,1,0,0,3.89,
|
||||
frontier_silicon,pass,22,0,0,0,2.64,
|
||||
fujitsu_fglair,pass,25,0,0,0,3.56,
|
||||
fumis,pass,72,0,0,0,5.55,
|
||||
fyta,issues,33,1,0,0,3.71,
|
||||
garages_amsterdam,pass,6,0,0,0,2.45,
|
||||
gardena_bluetooth,pass,40,0,0,0,5.17,
|
||||
gdacs,pass,8,0,0,0,2.70,
|
||||
generic_hygrostat,pass,76,0,0,0,4.01,
|
||||
generic_thermostat,pass,114,0,0,0,5.61,
|
||||
geniushub,pass,23,0,0,0,2.89,
|
||||
gentex_homelink,pass,13,0,0,0,2.75,
|
||||
geo_json_events,pass,5,0,0,0,2.55,
|
||||
geocaching,pass,5,0,0,0,2.81,
|
||||
geofency,pass,5,0,0,0,3.00,
|
||||
geonetnz_quakes,pass,9,0,0,0,2.78,
|
||||
geonetnz_volcano,pass,7,0,0,0,2.64,
|
||||
ghost,pass,27,0,0,0,3.44,
|
||||
gios,issues,17,1,0,0,3.07,
|
||||
github,pass,17,0,0,0,2.90,
|
||||
glances,pass,16,0,0,0,2.77,
|
||||
goalzero,pass,15,0,0,0,2.75,
|
||||
gogogate2,pass,15,0,0,0,2.67,
|
||||
goodwe,issues,5,1,0,0,2.59,
|
||||
google,issues,136,1,0,0,8.22,
|
||||
google_air_quality,pass,19,0,0,0,2.77,
|
||||
google_assistant_sdk,pass,41,0,0,0,3.71,
|
||||
google_drive,pass,40,0,0,0,4.21,
|
||||
google_mail,pass,28,0,0,0,3.57,
|
||||
google_photos,pass,35,0,0,0,3.52,
|
||||
google_sheets,pass,24,0,0,0,3.06,
|
||||
google_tasks,pass,42,0,0,0,4.20,
|
||||
google_travel_time,pass,44,0,0,0,3.65,
|
||||
google_weather,issues,44,1,0,0,3.85,
|
||||
govee_ble,pass,20,0,0,0,3.21,
|
||||
govee_light_local,pass,23,0,0,0,3.02,
|
||||
gpsd,pass,2,0,0,0,2.37,
|
||||
gpslogger,pass,3,0,0,1,2.91,
|
||||
gree,pass,123,0,0,0,7.31,
|
||||
green_planet_energy,pass,11,0,0,0,2.75,
|
||||
group,pass,392,0,0,0,24.47,
|
||||
growatt_server,issues,140,2,0,0,14.23,
|
||||
guardian,issues,11,1,0,0,2.54,
|
||||
guntamatic,pass,15,0,0,0,2.61,
|
||||
habitica,pass,382,0,0,0,38.88,
|
||||
hanna,pass,5,0,0,0,2.41,
|
||||
harmony,pass,22,0,0,0,2.79,
|
||||
hdfury,pass,50,0,0,0,6.49,
|
||||
hegel,pass,12,0,0,0,2.51,
|
||||
heos,issues,147,2,0,0,8.10,
|
||||
here_travel_time,pass,39,0,0,0,3.12,
|
||||
hisense_aehw4a1,pass,4,0,0,0,2.32,
|
||||
history_stats,pass,55,0,0,0,7.60,
|
||||
hive,pass,19,0,0,0,2.85,
|
||||
hko,pass,4,0,0,0,2.38,
|
||||
hlk_sw16,pass,4,0,0,0,2.29,
|
||||
holiday,pass,34,0,0,0,3.70,
|
||||
home_connect,pass,311,0,0,0,15.93,
|
||||
homeassistant_connect_zbt2,issues,24,1,0,0,4.13,
|
||||
homeassistant_sky_connect,pass,36,0,0,0,4.29,
|
||||
homee,pass,199,0,0,0,16.24,
|
||||
homekit,pass,372,0,0,0,13.61,
|
||||
homematicip_cloud,pass,182,0,0,0,23.98,
|
||||
homevolt,pass,33,0,0,0,3.29,
|
||||
homewizard,pass,149,0,0,0,10.98,
|
||||
homeworks,pass,38,0,0,0,4.28,
|
||||
honeywell,pass,44,0,0,0,4.33,
|
||||
honeywell_string_lights,pass,7,0,0,0,2.39,
|
||||
hr_energy_qube,pass,28,0,0,0,4.07,
|
||||
html5,issues,64,1,0,0,5.72,
|
||||
huawei_lte,pass,36,0,0,0,3.65,
|
||||
hue,pass,113,0,0,0,20.05,
|
||||
hue_ble,pass,19,0,0,0,3.05,
|
||||
huisbaasje,pass,13,0,0,0,2.47,
|
||||
hunterdouglas_powerview,pass,39,0,0,0,3.29,
|
||||
husqvarna_automower,issues,93,1,0,0,14.73,
|
||||
husqvarna_automower_ble,pass,42,0,0,0,5.09,
|
||||
huum,pass,34,0,0,0,3.35,
|
||||
hvv_departures,pass,9,0,0,0,2.32,
|
||||
hydrawise,pass,35,0,0,0,4.25,
|
||||
hypontech,pass,17,0,0,0,2.66,
|
||||
ialarm,pass,7,0,0,0,2.30,
|
||||
iaqualink,pass,28,0,0,0,2.86,
|
||||
ibeacon,pass,24,0,0,0,3.53,
|
||||
icloud,pass,17,0,0,0,2.47,
|
||||
idasen_desk,pass,30,0,0,0,3.75,
|
||||
idrive_e2,pass,65,0,0,0,4.66,
|
||||
ifttt,pass,1,0,0,0,2.47,
|
||||
igloohome,pass,8,0,0,0,2.37,
|
||||
imap,pass,159,0,0,0,12.42,
|
||||
imeon_inverter,pass,17,0,0,0,2.94,
|
||||
imgw_pib,issues,15,1,0,0,2.79,
|
||||
immich,issues,54,1,0,0,3.82,
|
||||
improv_ble,pass,38,0,0,0,3.69,
|
||||
incomfort,pass,50,0,0,0,4.05,
|
||||
indevolt,pass,83,0,0,0,6.18,
|
||||
inels,pass,28,0,0,0,3.04,
|
||||
influxdb,pass,145,0,0,0,6.03,
|
||||
inkbird,pass,16,0,0,0,2.99,
|
||||
insteon,pass,79,0,0,0,18.55,
|
||||
integration,pass,61,0,0,0,4.02,
|
||||
intelliclima,pass,28,0,0,0,3.21,
|
||||
intellifire,pass,29,0,0,0,4.24,
|
||||
iometer,pass,17,0,0,0,2.77,
|
||||
ios,pass,3,0,0,0,2.32,
|
||||
iotawatt,pass,9,0,0,0,2.45,
|
||||
iotty,pass,24,0,0,0,3.17,
|
||||
ipma,pass,15,0,0,0,2.73,
|
||||
ipp,pass,29,0,0,0,3.05,
|
||||
iqvia,issues,4,1,0,0,2.40,
|
||||
irm_kmi,pass,13,0,0,0,2.69,
|
||||
iron_os,pass,95,0,0,0,8.95,
|
||||
iskra,pass,13,0,0,0,2.45,
|
||||
islamic_prayer_times,pass,45,0,0,0,3.82,
|
||||
israel_rail,pass,9,0,0,0,2.56,
|
||||
iss,pass,17,0,0,0,2.56,
|
||||
ista_ecotrend,pass,49,0,0,0,4.07,
|
||||
isy994,pass,31,0,0,0,3.06,
|
||||
ituran,pass,19,0,0,0,2.96,
|
||||
izone,pass,10,0,0,0,2.55,
|
||||
jellyfin,pass,44,0,0,0,8.58,
|
||||
jewish_calendar,pass,123,0,0,0,11.89,
|
||||
justnimbus,pass,7,0,0,0,2.37,
|
||||
jvc_projector,pass,31,0,0,0,5.73,
|
||||
kaleidescape,pass,19,0,0,0,4.00,
|
||||
keenetic_ndms2,pass,14,0,0,0,2.38,
|
||||
kegtron,pass,12,0,0,0,2.73,
|
||||
keymitt_ble,pass,7,0,0,0,2.58,
|
||||
kiosker,pass,43,0,0,0,3.31,
|
||||
kmtronic,pass,11,0,0,0,2.48,
|
||||
knocki,pass,17,0,0,0,2.77,
|
||||
knx,pass,387,0,0,0,28.04,
|
||||
kodi,pass,21,0,0,0,2.77,
|
||||
kostal_plenticore,issues,38,1,0,0,4.10,
|
||||
kraken,pass,11,0,0,0,2.85,
|
||||
kulersky,pass,17,0,0,0,2.94,
|
||||
lacrosse_view,issues,28,1,0,0,3.09,
|
||||
lamarzocco,pass,94,0,0,0,14.30,
|
||||
lametric,pass,55,0,0,0,5.57,
|
||||
landisgyr_heat_meter,pass,10,0,0,0,2.77,
|
||||
lastfm,pass,15,0,0,0,2.52,
|
||||
launch_library,pass,2,0,0,0,2.28,
|
||||
laundrify,pass,18,0,0,0,2.79,
|
||||
lcn,pass,149,0,0,0,13.39,
|
||||
ld2410_ble,pass,6,0,0,0,2.56,
|
||||
leaone,pass,6,0,0,0,2.56,
|
||||
led_ble,pass,9,0,0,0,2.65,
|
||||
lektrico,pass,13,0,0,0,2.78,
|
||||
letpot,pass,40,0,0,0,4.13,
|
||||
lg_infrared,pass,61,0,0,0,4.33,
|
||||
lg_netcast,pass,22,0,0,0,3.46,
|
||||
lg_soundbar,pass,11,0,0,0,2.73,
|
||||
lg_thinq,pass,29,0,0,0,4.08,
|
||||
libre_hardware_monitor,pass,26,0,0,0,3.19,
|
||||
lichess,pass,8,0,0,0,2.48,
|
||||
lidarr,pass,12,0,0,0,2.60,
|
||||
liebherr,pass,76,0,0,0,5.72,
|
||||
lifx,pass,72,0,0,0,5.42,
|
||||
linkplay,pass,9,0,0,0,2.49,
|
||||
litejet,pass,32,0,0,0,3.77,
|
||||
litterrobot,pass,63,0,0,0,5.89,
|
||||
livisi,pass,4,0,0,0,2.36,
|
||||
local_calendar,pass,50,0,0,0,5.05,
|
||||
local_ip,pass,3,0,0,0,2.34,
|
||||
local_todo,pass,55,0,0,0,5.56,
|
||||
locative,pass,5,0,0,1,2.99,
|
||||
lojack,pass,16,0,0,0,2.92,
|
||||
london_underground,pass,12,0,0,0,2.55,
|
||||
lookin,pass,7,0,0,0,2.37,
|
||||
loqed,pass,17,0,0,0,2.98,
|
||||
luftdaten,pass,11,0,0,0,2.59,
|
||||
lunatone,pass,40,0,0,0,3.78,
|
||||
lupusec,pass,5,0,0,0,2.38,
|
||||
lutron,pass,42,0,0,0,3.76,
|
||||
lutron_caseta,pass,52,0,0,0,4.93,
|
||||
lyric,pass,4,0,0,0,2.40,
|
||||
madvr,issues,16,1,0,0,3.19,
|
||||
mailgun,pass,5,0,0,0,2.69,
|
||||
marantz_infrared,pass,36,0,0,0,3.44,
|
||||
mastodon,issues,82,1,0,0,26.20,
|
||||
matter,pass,372,0,0,1,68.76,
|
||||
mcp,pass,45,0,0,0,4.15,
|
||||
mcp_server,pass,47,0,0,0,5.93,
|
||||
mealie,pass,94,0,0,0,7.84,
|
||||
meater,pass,10,0,0,0,2.54,
|
||||
medcom_ble,pass,9,0,0,0,2.62,
|
||||
media_extractor,pass,20,0,0,0,7.61,
|
||||
melcloud,issues,23,1,0,0,2.79,
|
||||
melnor,pass,17,0,0,0,3.53,
|
||||
met,pass,18,0,0,0,2.57,
|
||||
met_eireann,pass,10,0,0,0,2.53,
|
||||
meteo_france,pass,6,0,0,0,2.45,
|
||||
meteo_lt,pass,7,0,0,0,2.47,
|
||||
meteoclimatic,pass,3,0,0,0,2.36,
|
||||
metoffice,pass,18,0,0,0,3.12,
|
||||
microbees,pass,9,0,0,0,2.54,
|
||||
miele,pass,115,0,0,0,10.16,
|
||||
mikrotik,pass,21,0,0,0,2.75,
|
||||
mill,pass,31,0,0,0,4.49,
|
||||
min_max,pass,20,0,0,0,2.58,
|
||||
minecraft_server,pass,40,0,0,0,3.49,
|
||||
mitsubishi_comfort,pass,66,0,0,0,5.31,
|
||||
moat,pass,11,0,0,0,2.79,
|
||||
mobile_app,pass,135,0,0,0,13.24,
|
||||
modem_callerid,pass,9,0,0,0,2.56,
|
||||
modern_forms,issues,29,1,0,0,3.44,
|
||||
moehlenhoff_alpha2,pass,8,0,0,0,2.41,
|
||||
mold_indicator,pass,37,0,0,0,3.05,
|
||||
monarch_money,pass,5,0,0,0,2.60,
|
||||
monoprice,pass,23,0,0,0,3.24,
|
||||
monzo,pass,11,0,0,0,2.72,
|
||||
moon,pass,11,0,0,0,2.46,
|
||||
mopeka,pass,14,0,0,0,2.90,
|
||||
motion_blinds,pass,12,0,0,0,2.53,
|
||||
motionblinds_ble,issues,42,1,0,0,6.28,
|
||||
motionmount,pass,38,0,0,0,3.53,
|
||||
mpd,pass,7,0,0,0,2.90,
|
||||
mta,pass,27,0,0,0,2.96,
|
||||
mullvad,pass,4,0,0,0,2.30,
|
||||
music_assistant,pass,127,0,0,0,9.42,
|
||||
mutesync,pass,5,0,0,0,2.32,
|
||||
myneomitis,pass,43,0,0,0,4.11,
|
||||
mysensors,pass,61,0,0,0,5.08,
|
||||
mystrom,pass,23,0,0,0,2.76,
|
||||
myuplink,pass,38,0,0,0,4.83,
|
||||
nam,pass,39,0,0,0,3.38,
|
||||
namecheapdns,pass,20,0,0,0,2.66,
|
||||
nanoleaf,pass,30,0,0,0,2.86,
|
||||
nasweb,pass,8,0,0,0,2.44,
|
||||
nederlandse_spoorwegen,pass,29,0,0,0,3.38,
|
||||
ness_alarm,pass,39,0,0,0,3.04,
|
||||
netgear,pass,10,0,0,0,2.41,
|
||||
netgear_lte,pass,11,0,0,0,2.63,
|
||||
nexia,pass,21,0,0,0,3.55,
|
||||
nextbus,pass,28,0,0,0,2.73,
|
||||
nextcloud,pass,17,0,0,0,2.93,
|
||||
nextdns,issues,52,1,0,0,5.83,
|
||||
nfandroidtv,pass,8,0,0,0,2.39,
|
||||
nibe_heatpump,pass,64,0,0,0,4.34,
|
||||
nice_go,issues,43,1,0,0,4.51,
|
||||
nightscout,pass,11,0,0,0,2.52,
|
||||
niko_home_control,pass,32,0,0,0,3.78,
|
||||
nina,pass,21,0,0,0,3.17,
|
||||
nintendo_parental_controls,pass,30,0,0,0,3.33,
|
||||
nmap_tracker,pass,13,0,0,0,2.57,
|
||||
nmbs,pass,5,0,0,0,2.50,
|
||||
nobo_hub,pass,59,0,0,0,4.63,
|
||||
nordpool,pass,37,0,0,0,4.93,
|
||||
notion,issues,7,1,0,0,2.55,
|
||||
novy_cooker_hood,issues,28,1,0,0,3.15,
|
||||
nrgkick,pass,87,0,0,0,5.68,
|
||||
ntfy,pass,85,0,0,0,6.82,
|
||||
nuheat,pass,9,0,0,0,2.46,
|
||||
nuki,pass,14,0,0,0,2.61,
|
||||
nut,pass,78,0,0,0,4.64,
|
||||
nws,pass,30,0,0,0,3.25,
|
||||
nyt_games,pass,10,0,0,0,2.60,
|
||||
nzbget,pass,10,0,0,0,2.46,
|
||||
obihai,pass,5,0,0,0,2.35,
|
||||
ohme,pass,34,0,0,0,4.42,
|
||||
omie,pass,19,0,0,0,2.86,
|
||||
omnilogic,pass,8,0,0,0,2.39,
|
||||
ondilo_ico,pass,17,0,0,0,2.98,
|
||||
onedrive,pass,79,0,0,0,6.52,
|
||||
onedrive_for_business,pass,38,0,0,0,4.62,
|
||||
onewire,pass,33,0,0,0,3.51,
|
||||
onkyo,pass,48,0,0,0,4.18,
|
||||
open_meteo,pass,5,0,0,0,2.70,
|
||||
opendisplay,pass,67,0,0,0,6.63,
|
||||
openevse,pass,40,0,0,0,4.50,
|
||||
openexchangerates,pass,9,0,0,0,2.38,
|
||||
opengarage,pass,6,0,0,0,2.37,
|
||||
openhome,pass,11,0,0,0,2.58,
|
||||
openrgb,pass,69,0,0,0,4.65,
|
||||
opensky,pass,12,0,0,0,2.64,
|
||||
opentherm_gw,pass,29,0,0,0,5.67,
|
||||
openuv,issues,10,1,0,0,2.69,
|
||||
openweathermap,pass,15,0,0,0,2.65,
|
||||
opower,issues,35,1,0,0,5.84,
|
||||
oralb,pass,14,0,0,0,2.89,
|
||||
orvibo,pass,15,0,0,0,2.60,
|
||||
osoenergy,pass,17,0,0,0,2.95,
|
||||
otbr,pass,103,0,0,0,7.85,
|
||||
otp,pass,7,0,0,0,2.44,
|
||||
ouman_eh_800,pass,20,0,0,0,3.07,
|
||||
ourgroceries,pass,21,0,0,0,2.81,
|
||||
overkiz,pass,181,0,0,0,9.91,
|
||||
overseerr,pass,45,0,0,0,4.83,
|
||||
ovo_energy,pass,7,0,0,0,2.39,
|
||||
owntracks,pass,71,0,0,0,5.75,
|
||||
p1_monitor,issues,11,2,0,0,2.73,
|
||||
paj_gps,pass,19,0,0,0,3.06,
|
||||
palazzetti,pass,17,0,0,0,2.99,
|
||||
panasonic_viera,pass,32,0,0,0,2.99,
|
||||
paperless_ngx,pass,41,0,0,0,3.57,
|
||||
peblar,pass,62,0,0,0,5.20,
|
||||
peco,pass,33,0,0,0,2.98,
|
||||
pegel_online,issues,9,1,0,0,2.60,
|
||||
permobil,pass,9,0,0,0,2.48,
|
||||
pglab,pass,21,0,0,0,3.50,
|
||||
philips_js,issues,15,1,0,0,3.73,
|
||||
pi_hole,issues,25,1,0,0,3.38,
|
||||
picnic,pass,40,0,0,0,3.35,
|
||||
ping,pass,21,0,0,0,2.92,
|
||||
pjlink,pass,29,0,0,0,3.31,
|
||||
plaato,pass,13,0,0,0,2.95,
|
||||
playstation_network,pass,68,0,0,0,6.66,
|
||||
plex,pass,53,0,0,0,6.67,
|
||||
plugwise,pass,86,0,0,0,8.26,
|
||||
point,pass,5,0,0,0,2.47,
|
||||
pooldose,pass,75,0,0,0,5.31,
|
||||
poolsense,pass,5,0,0,0,2.36,
|
||||
portainer,issues,86,1,0,0,12.95,
|
||||
powerfox,pass,22,0,0,0,3.04,
|
||||
powerfox_local,pass,21,0,0,0,2.87,
|
||||
powerwall,pass,37,0,0,0,3.57,
|
||||
prana,pass,37,0,0,0,3.77,
|
||||
private_ble_device,pass,21,0,0,0,3.29,
|
||||
probe_plus,pass,6,0,0,0,2.58,
|
||||
profiler,pass,13,0,0,0,2.57,
|
||||
progettihwsw,pass,4,0,0,0,2.35,
|
||||
prowl,pass,24,0,0,0,2.80,
|
||||
proximity,issues,27,1,0,0,3.03,
|
||||
proxmoxve,issues,103,1,0,0,9.21,
|
||||
ps4,pass,41,0,0,0,3.33,
|
||||
ptdevices,pass,7,0,0,0,2.41,
|
||||
pterodactyl,pass,14,0,0,0,2.66,
|
||||
pure_energie,pass,8,0,0,0,2.46,
|
||||
purpleair,issues,19,1,0,0,3.03,
|
||||
pushbullet,pass,17,0,0,0,2.62,
|
||||
pushover,pass,16,0,0,0,2.47,
|
||||
pvoutput,pass,17,0,0,0,2.75,
|
||||
pvpc_hourly_pricing,pass,2,0,0,0,2.38,
|
||||
pyload,pass,67,0,0,0,4.55,
|
||||
qbittorrent,pass,8,0,0,0,2.54,
|
||||
qbus,pass,25,0,0,0,4.01,
|
||||
qingping,pass,15,0,0,0,2.99,
|
||||
qnap,pass,6,0,0,0,2.39,
|
||||
qnap_qsw,pass,18,0,0,0,3.07,
|
||||
rabbitair,pass,7,0,0,0,2.40,
|
||||
rachio,pass,6,0,0,0,2.52,
|
||||
radarr,pass,32,0,0,0,3.90,
|
||||
radio_browser,pass,10,0,0,0,2.58,
|
||||
radiotherm,pass,7,0,0,0,2.36,
|
||||
rainbird,pass,70,0,0,0,4.30,
|
||||
rainforest_eagle,pass,12,0,0,0,2.46,
|
||||
rainforest_raven,issues,19,2,0,0,3.17,
|
||||
rainmachine,issues,19,2,0,0,2.88,
|
||||
random,pass,9,0,0,0,2.41,
|
||||
rapt_ble,pass,11,0,0,0,2.75,
|
||||
rdw,pass,10,0,0,0,2.58,
|
||||
recollect_waste,issues,3,1,0,0,2.50,
|
||||
redgtech,pass,18,0,0,0,2.77,
|
||||
refoss,pass,2,0,0,0,2.29,
|
||||
rehlko,pass,16,0,0,0,2.90,
|
||||
remote_calendar,pass,44,0,0,0,3.94,
|
||||
renault,pass,104,0,0,0,5.68,
|
||||
renson,pass,3,0,0,0,2.29,
|
||||
rfxtrx,pass,89,0,0,0,7.52,
|
||||
rhasspy,pass,3,0,0,0,2.28,
|
||||
ridwell,issues,13,1,0,0,2.69,
|
||||
risco,pass,69,0,0,0,4.26,
|
||||
rituals_perfume_genie,pass,25,0,0,0,3.10,
|
||||
roborock,pass,183,0,0,0,18.48,
|
||||
roku,pass,67,0,0,0,6.53,
|
||||
romy,pass,6,0,0,0,2.38,
|
||||
roomba,pass,26,0,0,0,2.69,
|
||||
roon,pass,5,0,0,0,2.34,
|
||||
route_b_smart_meter,pass,7,0,0,0,2.61,
|
||||
rova,pass,11,0,0,0,2.44,
|
||||
rpi_power,pass,6,0,0,0,2.33,
|
||||
ruckus_unleashed,pass,29,0,0,0,2.80,
|
||||
russound_rio,pass,50,0,0,0,6.05,
|
||||
ruuvi_gateway,pass,5,0,0,0,2.46,
|
||||
ruuvitag_ble,pass,13,0,0,0,2.75,
|
||||
rympro,pass,7,0,0,0,2.28,
|
||||
sabnzbd,pass,19,0,0,0,2.93,
|
||||
samsung_infrared,pass,18,0,0,0,2.74,
|
||||
samsungtv,issues,166,3,0,0,13.46,
|
||||
sanix,pass,6,0,0,0,2.35,
|
||||
satel_integra,pass,89,0,0,0,7.63,
|
||||
saunum,pass,68,0,0,0,4.99,
|
||||
schlage,pass,49,0,0,0,4.78,
|
||||
scrape,issues,37,1,0,0,3.12,
|
||||
screenlogic,issues,33,1,0,0,3.84,
|
||||
season,pass,21,0,0,0,2.91,
|
||||
sense,pass,19,0,0,0,3.20,
|
||||
sensibo,pass,69,0,0,0,8.44,
|
||||
sensirion_ble,pass,11,0,0,0,2.74,
|
||||
sensorpro,pass,11,0,0,0,2.74,
|
||||
sensorpush,pass,11,0,0,0,2.75,
|
||||
sensorpush_cloud,pass,5,0,0,0,2.45,
|
||||
sensoterra,pass,5,0,0,0,2.38,
|
||||
sentry,pass,24,0,0,0,2.52,
|
||||
senz,pass,21,0,0,0,3.05,
|
||||
seventeentrack,pass,16,0,0,0,2.61,
|
||||
sfr_box,pass,26,0,0,0,2.85,
|
||||
sftp_storage,pass,34,0,0,0,8.68,
|
||||
sharkiq,pass,42,0,0,0,3.25,
|
||||
shelly,pass,636,0,0,0,45.69,
|
||||
shopping_list,pass,60,0,0,0,4.74,
|
||||
sia,pass,21,0,0,0,2.65,
|
||||
simplefin,pass,12,0,0,0,2.68,
|
||||
simplepush,pass,5,0,0,0,2.32,
|
||||
simplisafe,issues,15,1,0,0,2.98,
|
||||
sky_remote,pass,9,0,0,0,2.40,
|
||||
slack,pass,13,0,0,0,2.44,
|
||||
sleep_as_android,pass,44,0,0,0,4.54,
|
||||
sleepiq,pass,33,0,0,0,4.94,
|
||||
slide_local,issues,48,1,0,0,4.02,
|
||||
slimproto,pass,2,0,0,0,2.34,
|
||||
sma,issues,33,1,0,0,3.82,
|
||||
smappee,pass,20,0,0,0,2.72,
|
||||
smarla,pass,37,0,0,0,4.23,
|
||||
smart_meter_texas,pass,16,0,0,0,2.58,
|
||||
smartthings,pass,340,0,0,0,70.72,
|
||||
smarttub,pass,40,0,0,0,4.88,
|
||||
smarty,pass,12,0,0,0,2.78,
|
||||
smhi,pass,20,0,0,0,3.39,
|
||||
smlight,pass,98,0,0,0,7.10,
|
||||
snapcast,pass,18,0,0,0,3.34,
|
||||
snoo,pass,21,0,0,0,3.43,
|
||||
snooz,pass,35,0,0,0,4.87,
|
||||
solaredge,pass,62,0,0,0,11.00,
|
||||
solarlog,issues,25,1,0,0,3.29,
|
||||
solarman,pass,17,0,0,0,2.79,
|
||||
solax,pass,3,0,0,0,2.33,
|
||||
soma,pass,7,0,0,0,2.30,
|
||||
somfy_mylink,pass,11,0,0,0,2.41,
|
||||
sonarr,pass,56,0,0,0,9.69,
|
||||
songpal,pass,26,0,0,0,3.03,
|
||||
sonos,pass,174,0,0,0,18.92,
|
||||
soundtouch,pass,31,0,0,0,3.29,
|
||||
speedtestdotnet,pass,8,0,0,0,2.37,
|
||||
splunk,pass,36,0,0,0,2.94,
|
||||
spotify,pass,70,0,0,0,8.97,
|
||||
sql,pass,80,0,0,0,6.49,
|
||||
squeezebox,pass,129,0,0,0,12.83,
|
||||
srp_energy,pass,15,0,0,0,2.70,
|
||||
starline,pass,4,0,0,0,2.27,
|
||||
starlink,pass,8,0,0,0,2.69,
|
||||
statistics,pass,56,0,0,0,4.17,
|
||||
steam_online,pass,14,0,0,0,2.48,
|
||||
steamist,pass,23,0,0,0,2.93,
|
||||
stiebel_eltron,pass,9,0,0,0,2.75,
|
||||
stookwijzer,pass,12,0,0,0,2.61,
|
||||
streamlabswater,pass,6,0,0,0,2.38,
|
||||
subaru,pass,59,0,0,0,4.58,
|
||||
suez_water,pass,19,0,0,0,4.18,
|
||||
sun,pass,27,0,0,1,4.86,
|
||||
sunricher_dali,pass,50,0,0,0,5.83,
|
||||
sunweg,pass,1,0,0,0,2.23,
|
||||
surepetcare,pass,15,0,0,0,2.74,
|
||||
swiss_public_transport,pass,36,0,0,0,3.10,
|
||||
switch_as_x,pass,176,0,0,0,10.02,
|
||||
switchbee,pass,6,0,0,0,2.34,
|
||||
switchbot,issues,352,1,0,0,19.66,
|
||||
switchbot_cloud,pass,134,0,0,0,10.81,
|
||||
switcher_kis,issues,76,1,0,0,7.69,
|
||||
syncthing,pass,5,0,0,0,2.30,
|
||||
syncthru,pass,9,0,0,0,2.59,
|
||||
system_bridge,pass,39,0,0,0,4.46,
|
||||
systemmonitor,issues,34,2,0,0,4.87,
|
||||
systemnexa2,pass,34,0,0,0,3.57,
|
||||
tado,pass,40,0,0,0,4.67,
|
||||
tailscale,pass,14,0,0,0,2.75,
|
||||
tailwind,pass,36,0,0,0,3.30,
|
||||
tami4,pass,14,0,0,0,2.56,
|
||||
tankerkoenig,issues,20,1,0,0,2.84,
|
||||
tautulli,pass,8,0,0,0,2.35,
|
||||
technove,pass,40,0,0,0,3.71,
|
||||
tedee,pass,41,0,0,0,4.48,
|
||||
telegram_bot,pass,123,0,0,0,13.16,
|
||||
teleinfo,pass,24,0,0,0,3.22,
|
||||
tellduslive,pass,15,0,0,0,2.41,
|
||||
teltonika,pass,50,0,0,0,3.79,
|
||||
template,pass,2470,0,0,0,60.07,
|
||||
tesla_fleet,pass,153,0,0,0,12.29,
|
||||
tesla_wall_connector,pass,12,0,0,0,2.47,
|
||||
teslemetry,pass,158,0,0,0,16.84,
|
||||
tessie,pass,67,0,0,0,4.46,
|
||||
thermobeacon,pass,11,0,0,0,2.72,
|
||||
thermopro,pass,18,0,0,0,3.01,
|
||||
thethingsnetwork,pass,8,0,0,0,2.40,
|
||||
thread,pass,65,0,0,0,4.17,
|
||||
threshold,pass,114,0,0,0,4.14,
|
||||
tibber,pass,92,0,0,0,13.32,
|
||||
tile,pass,11,0,0,0,2.50,
|
||||
tilt_ble,pass,11,0,0,0,2.79,
|
||||
tilt_pi,pass,6,0,0,0,2.43,
|
||||
time_date,pass,18,0,0,0,2.78,
|
||||
tod,pass,32,0,0,0,3.25,
|
||||
todoist,pass,50,0,0,0,4.23,
|
||||
togrill,pass,62,0,0,0,5.73,
|
||||
tolo,pass,7,0,0,0,2.35,
|
||||
tomorrowio,pass,21,0,0,0,3.08,
|
||||
toon,pass,10,0,0,0,2.71,
|
||||
totalconnect,pass,66,0,0,0,11.65,
|
||||
touchline,pass,8,0,0,0,2.52,
|
||||
touchline_sl,pass,15,0,0,0,2.71,
|
||||
tplink_omada,issues,52,1,0,0,4.67,
|
||||
traccar,pass,5,0,0,1,2.90,
|
||||
traccar_server,pass,12,0,0,0,2.88,
|
||||
tractive,issues,48,1,0,0,4.03,
|
||||
tradfri,pass,91,0,0,0,6.36,
|
||||
trafikverket_ferry,pass,13,0,0,0,2.52,
|
||||
trafikverket_train,pass,41,0,0,0,3.14,
|
||||
trafikverket_weatherstation,pass,16,0,0,0,2.53,
|
||||
trane,pass,39,0,0,0,3.98,
|
||||
transmission,pass,75,0,0,0,4.60,
|
||||
trend,pass,39,0,0,0,3.25,
|
||||
triggercmd,pass,5,0,0,0,2.37,
|
||||
trmnl,pass,36,0,0,0,3.72,
|
||||
twentemilieu,pass,17,0,0,0,2.87,
|
||||
twilio,pass,1,0,0,0,2.57,
|
||||
twinkly,issues,25,1,0,0,4.12,
|
||||
twitch,pass,16,0,0,0,4.22,
|
||||
uhoo,pass,24,0,0,0,2.99,
|
||||
ukraine_alarm,pass,11,0,0,0,2.43,
|
||||
unifi,issues,158,1,0,0,12.39,
|
||||
unifi_access,pass,155,0,0,0,10.85,
|
||||
upb,pass,6,0,0,0,2.42,
|
||||
upcloud,pass,6,0,0,0,2.35,
|
||||
upnp,pass,23,0,0,0,3.83,
|
||||
uptime,pass,4,0,0,0,2.36,
|
||||
uptime_kuma,pass,38,0,0,0,3.58,
|
||||
uptimerobot,pass,35,0,0,0,3.18,
|
||||
utility_meter,issues,94,1,0,0,6.00,
|
||||
v2c,issues,12,1,0,0,2.86,
|
||||
vallox,pass,76,0,0,0,5.65,
|
||||
vegehub,pass,18,0,0,0,2.92,
|
||||
velbus,issues,57,1,0,0,8.99,
|
||||
velux,pass,80,0,0,0,4.86,
|
||||
venstar,pass,12,0,0,0,2.56,
|
||||
vera,pass,29,0,0,0,3.08,
|
||||
version,pass,10,0,0,0,2.55,
|
||||
vesync,pass,175,0,0,0,12.54,
|
||||
vicare,issues,54,1,0,0,4.48,
|
||||
victron_ble,pass,34,0,0,0,3.61,
|
||||
victron_gx,pass,62,0,0,0,14.13,
|
||||
victron_remote_monitoring,pass,22,0,0,0,3.03,
|
||||
vilfo,pass,9,0,0,0,2.46,
|
||||
vizio,pass,73,0,0,0,4.50,
|
||||
vlc_telnet,pass,39,0,0,0,3.40,
|
||||
vodafone_station,issues,53,1,0,0,4.60,
|
||||
volumio,pass,9,0,0,0,2.29,
|
||||
volvo,pass,110,0,0,0,8.64,
|
||||
volvooncall,pass,4,0,0,0,2.20,
|
||||
wake_on_lan,pass,15,0,0,0,2.50,
|
||||
wallbox,pass,38,0,0,0,3.67,
|
||||
waqi,pass,20,0,0,0,2.63,
|
||||
waterfurnace,pass,77,0,0,0,11.93,
|
||||
watergate,pass,16,0,0,0,3.04,
|
||||
watts,issues,51,1,0,0,5.17,
|
||||
watttime,issues,11,1,0,0,2.56,
|
||||
waze_travel_time,pass,23,0,0,0,14.84,
|
||||
weatherflow,pass,5,0,0,0,2.95,
|
||||
weatherflow_cloud,pass,17,0,0,0,3.12,
|
||||
weatherkit,pass,35,0,0,0,2.92,
|
||||
webdav,pass,25,0,0,0,3.90,
|
||||
webmin,issues,11,1,0,0,2.52,
|
||||
webostv,issues,82,1,0,0,12.04,
|
||||
weheat,pass,16,0,0,0,2.85,
|
||||
wemo,pass,93,0,0,0,6.71,
|
||||
whirlpool,issues,239,1,0,0,12.16,
|
||||
whois,pass,41,0,0,0,3.40,
|
||||
wiffi,pass,4,0,0,0,2.19,
|
||||
wiim,pass,29,0,0,0,3.02,
|
||||
wilight,pass,22,0,0,0,2.82,
|
||||
withings,pass,62,0,0,0,8.01,
|
||||
wiz,pass,56,0,0,0,4.34,
|
||||
wled,pass,100,0,0,0,7.60,
|
||||
wmspro,pass,39,0,0,0,4.04,
|
||||
wolflink,pass,10,0,0,0,2.49,
|
||||
workday,issues,70,1,0,0,6.14,
|
||||
worldclock,pass,6,0,0,0,2.42,
|
||||
ws66i,pass,24,0,0,0,3.12,
|
||||
wsdot,pass,16,0,0,0,2.66,
|
||||
xbox,pass,203,0,0,0,14.92,
|
||||
xiaomi_aqara,pass,12,0,0,0,2.46,
|
||||
xiaomi_ble,pass,92,0,0,0,6.22,
|
||||
xiaomi_miio,pass,51,0,0,0,4.11,
|
||||
xthings_cloud,pass,30,0,0,0,3.72,
|
||||
yale_smart_alarm,pass,37,0,0,0,3.71,
|
||||
yalexs_ble,pass,26,0,0,0,3.32,
|
||||
yamaha_musiccast,pass,9,0,0,0,2.52,
|
||||
yardian,pass,16,0,0,0,2.79,
|
||||
yeelight,pass,62,0,0,0,4.73,
|
||||
yolink,pass,10,0,0,0,3.10,
|
||||
youless,pass,4,0,0,0,2.41,
|
||||
youtube,pass,24,0,0,0,3.38,
|
||||
zamg,pass,9,0,0,0,2.52,
|
||||
zerproc,pass,10,0,0,0,2.49,
|
||||
zeversolar,pass,10,0,0,0,2.46,
|
||||
zha,issues,339,1,0,4,70.49,
|
||||
zimi,pass,16,0,0,0,2.65,
|
||||
zinvolt,pass,12,0,0,0,2.77,
|
||||
zodiac,pass,5,0,0,0,2.31,
|
||||
zwave_js,pass,611,0,0,0,60.17,
|
||||
zwave_me,pass,8,0,0,0,2.24,
|
||||
|
@@ -1,857 +0,0 @@
|
||||
# Sandbox — full compat sweep (Phase 16)
|
||||
|
||||
**This file is auto-generated by `run_compat_full.py`** — re-run the
|
||||
script to refresh it. Companion machine-readable CSV is `COMPAT_FULL.csv`,
|
||||
categorised remediation backlog is `BACKLOG.md`.
|
||||
|
||||
## Sweep parameters
|
||||
|
||||
- Started: `2026-05-24T00:51:34`
|
||||
- Finished: `2026-05-24T01:03:01`
|
||||
- Wall time: **687s**
|
||||
- Outer concurrency: **6**
|
||||
- Per-integration pytest-xdist: **off**
|
||||
- Plugin: `hass_client.testing.pytest_plugin` (in-process)
|
||||
|
||||
## Discovery
|
||||
|
||||
Walked `homeassistant/components/`, applied the Phase 16 filters:
|
||||
|
||||
| Filter | Skipped |
|
||||
| --- | ---: |
|
||||
| No / invalid manifest | 1 |
|
||||
| `integration_type` in (`virtual`, `system`) | 206 |
|
||||
| Domain in `ALWAYS_MAIN` | 3 |
|
||||
| Ships a platform in `SANDBOX_INCOMPATIBLE_PLATFORMS` | 73 |
|
||||
| No `config_flow` in manifest | 380 |
|
||||
| No `test_*.py` files | 0 |
|
||||
| **Eligible (this sweep)** | **807** |
|
||||
|
||||
## Summary
|
||||
|
||||
- Integrations exercised: **807**
|
||||
- Fully passing: **711** (88.10%)
|
||||
- With failures: **96**
|
||||
- Timeouts: **0**
|
||||
- Spawn errors: **0**
|
||||
- No tests collected: **0**
|
||||
|
||||
- Tests passed: **34266**
|
||||
- Tests failed: **112**
|
||||
- Test errors: **0**
|
||||
- Tests skipped: **11**
|
||||
- **Test-level pass rate: 99.67%**
|
||||
|
||||
## Per-integration results
|
||||
|
||||
| integration | status | passed | failed | errors | skipped | dur (s) | bucket |
|
||||
| --- | --- | ---: | ---: | ---: | ---: | ---: | --- |
|
||||
| acaia | pass | 24 | 0 | 0 | 0 | 3.5 | |
|
||||
| accuweather | pass | 38 | 0 | 0 | 0 | 5.1 | |
|
||||
| acmeda | pass | 8 | 0 | 0 | 0 | 2.6 | |
|
||||
| actron_air | pass | 49 | 0 | 0 | 0 | 5.2 | |
|
||||
| adax | pass | 20 | 0 | 0 | 0 | 2.9 | |
|
||||
| adguard | pass | 36 | 0 | 0 | 0 | 3.4 | |
|
||||
| advantage_air | pass | 20 | 0 | 0 | 0 | 4.9 | |
|
||||
| aemet | issues | 16 | 1 | 0 | 0 | 3.3 | |
|
||||
| aftership | pass | 2 | 0 | 0 | 0 | 2.3 | |
|
||||
| aidot | pass | 16 | 0 | 0 | 0 | 2.9 | |
|
||||
| airgradient | pass | 47 | 0 | 0 | 0 | 4.7 | |
|
||||
| airly | issues | 21 | 1 | 0 | 0 | 3.0 | |
|
||||
| airnow | issues | 9 | 1 | 0 | 0 | 2.5 | |
|
||||
| airobot | pass | 60 | 0 | 0 | 0 | 4.8 | |
|
||||
| airos | pass | 62 | 0 | 0 | 0 | 4.9 | |
|
||||
| airpatrol | pass | 25 | 0 | 0 | 0 | 3.2 | |
|
||||
| airq | issues | 22 | 1 | 0 | 0 | 3.3 | |
|
||||
| airthings | pass | 12 | 0 | 0 | 0 | 2.6 | |
|
||||
| airthings_ble | pass | 38 | 0 | 0 | 0 | 4.1 | |
|
||||
| airtouch4 | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| airtouch5 | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| airvisual | issues | 15 | 1 | 0 | 0 | 2.9 | |
|
||||
| airvisual_pro | issues | 10 | 1 | 0 | 0 | 2.7 | |
|
||||
| airzone | issues | 37 | 1 | 0 | 0 | 5.6 | |
|
||||
| airzone_cloud | issues | 26 | 1 | 0 | 0 | 4.9 | |
|
||||
| aladdin_connect | issues | 32 | 1 | 0 | 0 | 3.8 | |
|
||||
| alarmdecoder | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| alexa_devices | issues | 72 | 1 | 0 | 0 | 7.3 | |
|
||||
| altruist | pass | 11 | 0 | 0 | 0 | 2.6 | |
|
||||
| amberelectric | pass | 39 | 0 | 0 | 0 | 3.6 | |
|
||||
| ambient_network | pass | 7 | 0 | 0 | 0 | 2.8 | |
|
||||
| ambient_station | issues | 3 | 1 | 0 | 0 | 2.6 | |
|
||||
| analytics_insights | pass | 20 | 0 | 0 | 0 | 3.1 | |
|
||||
| androidtv | pass | 79 | 0 | 0 | 0 | 5.2 | |
|
||||
| androidtv_remote | pass | 40 | 0 | 0 | 0 | 4.6 | |
|
||||
| anglian_water | pass | 14 | 0 | 0 | 0 | 3.5 | |
|
||||
| anova | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| anthemav | pass | 11 | 0 | 0 | 0 | 2.6 | |
|
||||
| aosmith | pass | 33 | 0 | 0 | 0 | 3.6 | |
|
||||
| apcupsd | pass | 44 | 0 | 0 | 0 | 4.3 | |
|
||||
| apple_tv | pass | 51 | 0 | 0 | 0 | 4.6 | |
|
||||
| aprilaire | pass | 3 | 0 | 0 | 0 | 2.5 | |
|
||||
| apsystems | pass | 13 | 0 | 0 | 0 | 3.0 | |
|
||||
| aquacell | pass | 13 | 0 | 0 | 0 | 2.9 | |
|
||||
| aranet | pass | 19 | 0 | 0 | 0 | 3.4 | |
|
||||
| arcam_fmj | pass | 85 | 0 | 0 | 0 | 5.8 | |
|
||||
| arve | pass | 5 | 0 | 0 | 0 | 2.7 | |
|
||||
| aseko_pool_live | pass | 13 | 0 | 0 | 0 | 2.8 | |
|
||||
| asuswrt | pass | 60 | 0 | 0 | 0 | 4.7 | |
|
||||
| atag | pass | 14 | 0 | 0 | 0 | 2.9 | |
|
||||
| aurora | pass | 4 | 0 | 0 | 0 | 2.5 | |
|
||||
| aurora_abb_powerone | pass | 7 | 0 | 0 | 0 | 6.8 | |
|
||||
| aussie_broadband | pass | 14 | 0 | 0 | 0 | 2.7 | |
|
||||
| autarco | pass | 13 | 0 | 0 | 0 | 2.7 | |
|
||||
| autoskope | pass | 22 | 0 | 0 | 0 | 2.9 | |
|
||||
| avea | pass | 20 | 0 | 0 | 0 | 3.1 | |
|
||||
| awair | pass | 24 | 0 | 0 | 0 | 2.7 | |
|
||||
| aws_s3 | pass | 51 | 0 | 0 | 0 | 5.0 | |
|
||||
| azure_data_explorer | pass | 18 | 0 | 0 | 0 | 2.8 | |
|
||||
| azure_devops | pass | 20 | 0 | 0 | 0 | 2.8 | |
|
||||
| azure_event_hub | pass | 21 | 0 | 0 | 0 | 2.6 | |
|
||||
| azure_storage | pass | 25 | 0 | 0 | 0 | 3.7 | |
|
||||
| backblaze_b2 | pass | 77 | 0 | 0 | 0 | 5.6 | |
|
||||
| baf | pass | 8 | 0 | 0 | 0 | 2.5 | |
|
||||
| balboa | pass | 42 | 0 | 0 | 0 | 5.5 | |
|
||||
| bang_olufsen | issues | 100 | 2 | 0 | 0 | 35.9 | |
|
||||
| bayesian | pass | 48 | 0 | 0 | 0 | 3.2 | |
|
||||
| blebox | pass | 117 | 0 | 0 | 0 | 9.0 | |
|
||||
| blue_current | pass | 28 | 0 | 0 | 0 | 3.0 | |
|
||||
| bluemaestro | pass | 11 | 0 | 0 | 0 | 2.8 | |
|
||||
| bluesound | pass | 39 | 0 | 0 | 0 | 4.7 | |
|
||||
| bluetooth | issues | 234 | 1 | 0 | 1 | 9.8 | |
|
||||
| bond | pass | 141 | 0 | 0 | 0 | 6.3 | |
|
||||
| bosch_alarm | pass | 121 | 0 | 0 | 0 | 11.9 | |
|
||||
| bosch_shc | pass | 16 | 0 | 0 | 0 | 2.7 | |
|
||||
| braviatv | issues | 19 | 1 | 0 | 0 | 2.7 | |
|
||||
| bring | pass | 72 | 0 | 0 | 0 | 6.0 | |
|
||||
| broadlink | pass | 104 | 0 | 0 | 0 | 4.8 | |
|
||||
| brother | pass | 33 | 0 | 0 | 0 | 7.2 | |
|
||||
| brottsplatskartan | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| brunt | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| bryant_evolution | pass | 24 | 0 | 0 | 0 | 3.1 | |
|
||||
| bsblan | pass | 127 | 0 | 0 | 0 | 11.9 | |
|
||||
| bthome | pass | 107 | 0 | 0 | 0 | 7.0 | |
|
||||
| caldav | pass | 109 | 0 | 0 | 0 | 6.7 | |
|
||||
| cambridge_audio | pass | 52 | 0 | 0 | 0 | 7.8 | |
|
||||
| casper_glow | pass | 67 | 0 | 0 | 0 | 6.4 | |
|
||||
| cast | pass | 86 | 0 | 0 | 0 | 6.6 | |
|
||||
| ccm15 | pass | 8 | 0 | 0 | 0 | 2.5 | |
|
||||
| centriconnect | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| cert_expiry | pass | 18 | 0 | 0 | 0 | 2.8 | |
|
||||
| chacon_dio | pass | 16 | 0 | 0 | 0 | 2.8 | |
|
||||
| chess_com | issues | 8 | 1 | 0 | 0 | 2.8 | |
|
||||
| cielo_home | pass | 7 | 0 | 0 | 0 | 18.3 | |
|
||||
| cloudflare | pass | 14 | 0 | 0 | 0 | 2.5 | |
|
||||
| cloudflare_r2 | pass | 59 | 0 | 0 | 0 | 4.7 | |
|
||||
| co2signal | issues | 15 | 1 | 0 | 0 | 2.9 | |
|
||||
| coinbase | issues | 15 | 1 | 0 | 0 | 2.6 | |
|
||||
| color_extractor | pass | 9 | 0 | 0 | 0 | 4.5 | |
|
||||
| comelit | issues | 93 | 2 | 0 | 0 | 9.0 | |
|
||||
| compit | pass | 65 | 0 | 0 | 0 | 6.5 | |
|
||||
| control4 | pass | 54 | 0 | 0 | 0 | 4.6 | |
|
||||
| cookidoo | pass | 52 | 0 | 0 | 0 | 5.4 | |
|
||||
| coolmaster | pass | 37 | 0 | 0 | 0 | 3.5 | |
|
||||
| cpuspeed | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| crownstone | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| cync | pass | 19 | 0 | 0 | 0 | 2.6 | |
|
||||
| daikin | pass | 31 | 0 | 0 | 0 | 3.1 | |
|
||||
| data_grand_lyon | issues | 40 | 2 | 0 | 0 | 3.3 | |
|
||||
| datadog | pass | 12 | 0 | 0 | 0 | 2.4 | |
|
||||
| deako | pass | 13 | 0 | 0 | 0 | 2.9 | |
|
||||
| deconz | issues | 172 | 1 | 0 | 1 | 12.9 | |
|
||||
| decora_wifi | pass | 13 | 0 | 0 | 0 | 3.0 | |
|
||||
| deluge | pass | 7 | 0 | 0 | 0 | 2.3 | |
|
||||
| denon_rs232 | pass | 23 | 0 | 0 | 0 | 3.1 | |
|
||||
| denonavr | pass | 16 | 0 | 0 | 0 | 2.9 | |
|
||||
| derivative | pass | 76 | 0 | 0 | 0 | 4.6 | |
|
||||
| devialet | pass | 13 | 0 | 0 | 0 | 2.6 | |
|
||||
| devolo_home_control | issues | 41 | 1 | 0 | 0 | 4.2 | |
|
||||
| devolo_home_network | issues | 51 | 1 | 0 | 0 | 6.0 | |
|
||||
| dexcom | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| dialogflow | pass | 17 | 0 | 0 | 0 | 3.2 | |
|
||||
| directv | pass | 24 | 0 | 0 | 0 | 3.1 | |
|
||||
| discord | pass | 11 | 0 | 0 | 0 | 2.5 | |
|
||||
| discovergy | pass | 25 | 0 | 0 | 0 | 3.2 | |
|
||||
| dlink | pass | 15 | 0 | 0 | 0 | 2.6 | |
|
||||
| dlna_dmr | pass | 72 | 0 | 0 | 0 | 13.9 | |
|
||||
| dlna_dms | pass | 55 | 0 | 0 | 0 | 8.0 | |
|
||||
| dnsip | pass | 21 | 0 | 0 | 0 | 2.7 | |
|
||||
| dormakaba_dkey | pass | 14 | 0 | 0 | 0 | 2.9 | |
|
||||
| downloader | pass | 21 | 0 | 0 | 0 | 2.6 | |
|
||||
| drop_connect | pass | 30 | 0 | 0 | 0 | 3.8 | |
|
||||
| dropbox | pass | 29 | 0 | 0 | 0 | 3.6 | |
|
||||
| droplet | pass | 16 | 0 | 0 | 0 | 3.2 | |
|
||||
| dsmr | pass | 75 | 0 | 0 | 0 | 4.6 | |
|
||||
| dsmr_reader | issues | 8 | 1 | 0 | 0 | 2.8 | |
|
||||
| duckdns | pass | 18 | 0 | 0 | 0 | 2.7 | |
|
||||
| duco | pass | 61 | 0 | 0 | 0 | 7.5 | |
|
||||
| dunehd | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| duotecno | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| dwd_weather_warnings | pass | 11 | 0 | 0 | 0 | 2.5 | |
|
||||
| dynalite | pass | 33 | 0 | 0 | 0 | 3.4 | |
|
||||
| eafm | pass | 18 | 0 | 0 | 0 | 2.6 | |
|
||||
| earn_e_p1 | pass | 25 | 0 | 0 | 0 | 2.9 | |
|
||||
| easyenergy | pass | 70 | 0 | 0 | 0 | 5.2 | |
|
||||
| ecobee | pass | 60 | 0 | 0 | 0 | 3.5 | |
|
||||
| ecoforest | pass | 4 | 0 | 0 | 0 | 2.4 | |
|
||||
| econet | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| ecovacs | issues | 74 | 2 | 0 | 0 | 6.7 | |
|
||||
| ecowitt | pass | 1 | 0 | 0 | 0 | 2.3 | |
|
||||
| edl21 | pass | 2 | 0 | 0 | 0 | 2.3 | |
|
||||
| efergy | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| egauge | pass | 16 | 0 | 0 | 0 | 2.8 | |
|
||||
| eheimdigital | issues | 79 | 1 | 0 | 0 | 8.3 | |
|
||||
| ekeybionyx | pass | 13 | 0 | 0 | 0 | 7.7 | |
|
||||
| electrasmart | pass | 6 | 0 | 0 | 0 | 2.3 | |
|
||||
| electric_kiwi | pass | 18 | 0 | 0 | 0 | 3.0 | |
|
||||
| elgato | pass | 36 | 0 | 0 | 0 | 3.9 | |
|
||||
| elkm1 | pass | 45 | 0 | 0 | 0 | 3.4 | |
|
||||
| elmax | pass | 29 | 0 | 0 | 0 | 2.8 | |
|
||||
| elvia | pass | 9 | 0 | 0 | 0 | 2.7 | |
|
||||
| emoncms | pass | 16 | 0 | 0 | 0 | 2.7 | |
|
||||
| emonitor | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| emulated_roku | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| energenie_power_sockets | pass | 13 | 0 | 0 | 0 | 2.6 | |
|
||||
| energyid | pass | 81 | 0 | 0 | 0 | 3.9 | |
|
||||
| energyzero | pass | 41 | 0 | 0 | 0 | 3.8 | |
|
||||
| enigma2 | pass | 26 | 0 | 0 | 0 | 3.3 | |
|
||||
| enocean | pass | 14 | 0 | 0 | 0 | 2.8 | |
|
||||
| enphase_envoy | issues | 231 | 5 | 0 | 0 | 24.6 | |
|
||||
| epic_games_store | pass | 20 | 0 | 0 | 0 | 2.7 | |
|
||||
| epion | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| epson | pass | 5 | 0 | 0 | 0 | 2.5 | |
|
||||
| eq3btsmart | pass | 4 | 0 | 0 | 0 | 2.6 | |
|
||||
| escea | pass | 3 | 0 | 0 | 0 | 2.3 | |
|
||||
| essent | pass | 14 | 0 | 0 | 0 | 2.7 | |
|
||||
| eufylife_ble | pass | 10 | 0 | 0 | 0 | 2.8 | |
|
||||
| eurotronic_cometblue | pass | 39 | 0 | 0 | 0 | 4.0 | |
|
||||
| evil_genius_labs | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| faa_delays | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| fastdotcom | pass | 8 | 0 | 0 | 0 | 2.5 | |
|
||||
| feedreader | pass | 30 | 0 | 0 | 0 | 3.0 | |
|
||||
| fibaro | pass | 45 | 0 | 0 | 0 | 3.9 | |
|
||||
| file | pass | 26 | 0 | 0 | 0 | 2.8 | |
|
||||
| filesize | pass | 13 | 0 | 0 | 0 | 2.6 | |
|
||||
| filter | pass | 32 | 0 | 0 | 0 | 4.1 | |
|
||||
| fing | pass | 17 | 0 | 0 | 0 | 2.9 | |
|
||||
| firefly_iii | issues | 25 | 1 | 0 | 0 | 3.3 | |
|
||||
| fireservicerota | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| fitbit | pass | 60 | 0 | 0 | 0 | 6.5 | |
|
||||
| fivem | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| fjaraskupan | pass | 11 | 0 | 0 | 0 | 2.9 | |
|
||||
| flexit_bacnet | pass | 19 | 0 | 0 | 0 | 2.8 | |
|
||||
| flipr | pass | 18 | 0 | 0 | 0 | 2.8 | |
|
||||
| flo | pass | 10 | 0 | 0 | 0 | 2.7 | |
|
||||
| flume | pass | 11 | 0 | 0 | 0 | 2.5 | |
|
||||
| fluss | pass | 16 | 0 | 0 | 0 | 2.7 | |
|
||||
| flux_led | pass | 82 | 0 | 0 | 0 | 6.6 | |
|
||||
| folder_watcher | pass | 10 | 0 | 0 | 0 | 2.6 | |
|
||||
| forecast_solar | pass | 28 | 0 | 0 | 0 | 3.0 | |
|
||||
| forked_daapd | pass | 36 | 0 | 0 | 0 | 4.6 | |
|
||||
| freedompro | pass | 38 | 0 | 0 | 0 | 4.5 | |
|
||||
| freshr | issues | 28 | 1 | 0 | 0 | 3.4 | |
|
||||
| fressnapf_tracker | pass | 45 | 0 | 0 | 0 | 4.5 | |
|
||||
| fritz | issues | 138 | 1 | 0 | 0 | 10.2 | |
|
||||
| fritzbox | pass | 132 | 0 | 0 | 0 | 8.6 | |
|
||||
| fritzbox_callmonitor | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| fronius | issues | 35 | 1 | 0 | 0 | 3.9 | |
|
||||
| frontier_silicon | pass | 22 | 0 | 0 | 0 | 2.6 | |
|
||||
| fujitsu_fglair | pass | 25 | 0 | 0 | 0 | 3.6 | |
|
||||
| fumis | pass | 72 | 0 | 0 | 0 | 5.6 | |
|
||||
| fyta | issues | 33 | 1 | 0 | 0 | 3.7 | |
|
||||
| garages_amsterdam | pass | 6 | 0 | 0 | 0 | 2.5 | |
|
||||
| gardena_bluetooth | pass | 40 | 0 | 0 | 0 | 5.2 | |
|
||||
| gdacs | pass | 8 | 0 | 0 | 0 | 2.7 | |
|
||||
| generic_hygrostat | pass | 76 | 0 | 0 | 0 | 4.0 | |
|
||||
| generic_thermostat | pass | 114 | 0 | 0 | 0 | 5.6 | |
|
||||
| geniushub | pass | 23 | 0 | 0 | 0 | 2.9 | |
|
||||
| gentex_homelink | pass | 13 | 0 | 0 | 0 | 2.8 | |
|
||||
| geo_json_events | pass | 5 | 0 | 0 | 0 | 2.5 | |
|
||||
| geocaching | pass | 5 | 0 | 0 | 0 | 2.8 | |
|
||||
| geofency | pass | 5 | 0 | 0 | 0 | 3.0 | |
|
||||
| geonetnz_quakes | pass | 9 | 0 | 0 | 0 | 2.8 | |
|
||||
| geonetnz_volcano | pass | 7 | 0 | 0 | 0 | 2.6 | |
|
||||
| ghost | pass | 27 | 0 | 0 | 0 | 3.4 | |
|
||||
| gios | issues | 17 | 1 | 0 | 0 | 3.1 | |
|
||||
| github | pass | 17 | 0 | 0 | 0 | 2.9 | |
|
||||
| glances | pass | 16 | 0 | 0 | 0 | 2.8 | |
|
||||
| goalzero | pass | 15 | 0 | 0 | 0 | 2.7 | |
|
||||
| gogogate2 | pass | 15 | 0 | 0 | 0 | 2.7 | |
|
||||
| goodwe | issues | 5 | 1 | 0 | 0 | 2.6 | |
|
||||
| google | issues | 136 | 1 | 0 | 0 | 8.2 | |
|
||||
| google_air_quality | pass | 19 | 0 | 0 | 0 | 2.8 | |
|
||||
| google_assistant_sdk | pass | 41 | 0 | 0 | 0 | 3.7 | |
|
||||
| google_drive | pass | 40 | 0 | 0 | 0 | 4.2 | |
|
||||
| google_mail | pass | 28 | 0 | 0 | 0 | 3.6 | |
|
||||
| google_photos | pass | 35 | 0 | 0 | 0 | 3.5 | |
|
||||
| google_sheets | pass | 24 | 0 | 0 | 0 | 3.1 | |
|
||||
| google_tasks | pass | 42 | 0 | 0 | 0 | 4.2 | |
|
||||
| google_travel_time | pass | 44 | 0 | 0 | 0 | 3.7 | |
|
||||
| google_weather | issues | 44 | 1 | 0 | 0 | 3.9 | |
|
||||
| govee_ble | pass | 20 | 0 | 0 | 0 | 3.2 | |
|
||||
| govee_light_local | pass | 23 | 0 | 0 | 0 | 3.0 | |
|
||||
| gpsd | pass | 2 | 0 | 0 | 0 | 2.4 | |
|
||||
| gpslogger | pass | 3 | 0 | 0 | 1 | 2.9 | |
|
||||
| gree | pass | 123 | 0 | 0 | 0 | 7.3 | |
|
||||
| green_planet_energy | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| group | pass | 392 | 0 | 0 | 0 | 24.5 | |
|
||||
| growatt_server | issues | 140 | 2 | 0 | 0 | 14.2 | |
|
||||
| guardian | issues | 11 | 1 | 0 | 0 | 2.5 | |
|
||||
| guntamatic | pass | 15 | 0 | 0 | 0 | 2.6 | |
|
||||
| habitica | pass | 382 | 0 | 0 | 0 | 38.9 | |
|
||||
| hanna | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| harmony | pass | 22 | 0 | 0 | 0 | 2.8 | |
|
||||
| hdfury | pass | 50 | 0 | 0 | 0 | 6.5 | |
|
||||
| hegel | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| heos | issues | 147 | 2 | 0 | 0 | 8.1 | |
|
||||
| here_travel_time | pass | 39 | 0 | 0 | 0 | 3.1 | |
|
||||
| hisense_aehw4a1 | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| history_stats | pass | 55 | 0 | 0 | 0 | 7.6 | |
|
||||
| hive | pass | 19 | 0 | 0 | 0 | 2.8 | |
|
||||
| hko | pass | 4 | 0 | 0 | 0 | 2.4 | |
|
||||
| hlk_sw16 | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| holiday | pass | 34 | 0 | 0 | 0 | 3.7 | |
|
||||
| home_connect | pass | 311 | 0 | 0 | 0 | 15.9 | |
|
||||
| homeassistant_connect_zbt2 | issues | 24 | 1 | 0 | 0 | 4.1 | |
|
||||
| homeassistant_sky_connect | pass | 36 | 0 | 0 | 0 | 4.3 | |
|
||||
| homee | pass | 199 | 0 | 0 | 0 | 16.2 | |
|
||||
| homekit | pass | 372 | 0 | 0 | 0 | 13.6 | |
|
||||
| homematicip_cloud | pass | 182 | 0 | 0 | 0 | 24.0 | |
|
||||
| homevolt | pass | 33 | 0 | 0 | 0 | 3.3 | |
|
||||
| homewizard | pass | 149 | 0 | 0 | 0 | 11.0 | |
|
||||
| homeworks | pass | 38 | 0 | 0 | 0 | 4.3 | |
|
||||
| honeywell | pass | 44 | 0 | 0 | 0 | 4.3 | |
|
||||
| honeywell_string_lights | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| hr_energy_qube | pass | 28 | 0 | 0 | 0 | 4.1 | |
|
||||
| html5 | issues | 64 | 1 | 0 | 0 | 5.7 | |
|
||||
| huawei_lte | pass | 36 | 0 | 0 | 0 | 3.7 | |
|
||||
| hue | pass | 113 | 0 | 0 | 0 | 20.1 | |
|
||||
| hue_ble | pass | 19 | 0 | 0 | 0 | 3.0 | |
|
||||
| huisbaasje | pass | 13 | 0 | 0 | 0 | 2.5 | |
|
||||
| hunterdouglas_powerview | pass | 39 | 0 | 0 | 0 | 3.3 | |
|
||||
| husqvarna_automower | issues | 93 | 1 | 0 | 0 | 14.7 | |
|
||||
| husqvarna_automower_ble | pass | 42 | 0 | 0 | 0 | 5.1 | |
|
||||
| huum | pass | 34 | 0 | 0 | 0 | 3.3 | |
|
||||
| hvv_departures | pass | 9 | 0 | 0 | 0 | 2.3 | |
|
||||
| hydrawise | pass | 35 | 0 | 0 | 0 | 4.3 | |
|
||||
| hypontech | pass | 17 | 0 | 0 | 0 | 2.7 | |
|
||||
| ialarm | pass | 7 | 0 | 0 | 0 | 2.3 | |
|
||||
| iaqualink | pass | 28 | 0 | 0 | 0 | 2.9 | |
|
||||
| ibeacon | pass | 24 | 0 | 0 | 0 | 3.5 | |
|
||||
| icloud | pass | 17 | 0 | 0 | 0 | 2.5 | |
|
||||
| idasen_desk | pass | 30 | 0 | 0 | 0 | 3.8 | |
|
||||
| idrive_e2 | pass | 65 | 0 | 0 | 0 | 4.7 | |
|
||||
| ifttt | pass | 1 | 0 | 0 | 0 | 2.5 | |
|
||||
| igloohome | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| imap | pass | 159 | 0 | 0 | 0 | 12.4 | |
|
||||
| imeon_inverter | pass | 17 | 0 | 0 | 0 | 2.9 | |
|
||||
| imgw_pib | issues | 15 | 1 | 0 | 0 | 2.8 | |
|
||||
| immich | issues | 54 | 1 | 0 | 0 | 3.8 | |
|
||||
| improv_ble | pass | 38 | 0 | 0 | 0 | 3.7 | |
|
||||
| incomfort | pass | 50 | 0 | 0 | 0 | 4.0 | |
|
||||
| indevolt | pass | 83 | 0 | 0 | 0 | 6.2 | |
|
||||
| inels | pass | 28 | 0 | 0 | 0 | 3.0 | |
|
||||
| influxdb | pass | 145 | 0 | 0 | 0 | 6.0 | |
|
||||
| inkbird | pass | 16 | 0 | 0 | 0 | 3.0 | |
|
||||
| insteon | pass | 79 | 0 | 0 | 0 | 18.5 | |
|
||||
| integration | pass | 61 | 0 | 0 | 0 | 4.0 | |
|
||||
| intelliclima | pass | 28 | 0 | 0 | 0 | 3.2 | |
|
||||
| intellifire | pass | 29 | 0 | 0 | 0 | 4.2 | |
|
||||
| iometer | pass | 17 | 0 | 0 | 0 | 2.8 | |
|
||||
| ios | pass | 3 | 0 | 0 | 0 | 2.3 | |
|
||||
| iotawatt | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| iotty | pass | 24 | 0 | 0 | 0 | 3.2 | |
|
||||
| ipma | pass | 15 | 0 | 0 | 0 | 2.7 | |
|
||||
| ipp | pass | 29 | 0 | 0 | 0 | 3.0 | |
|
||||
| iqvia | issues | 4 | 1 | 0 | 0 | 2.4 | |
|
||||
| irm_kmi | pass | 13 | 0 | 0 | 0 | 2.7 | |
|
||||
| iron_os | pass | 95 | 0 | 0 | 0 | 8.9 | |
|
||||
| iskra | pass | 13 | 0 | 0 | 0 | 2.4 | |
|
||||
| islamic_prayer_times | pass | 45 | 0 | 0 | 0 | 3.8 | |
|
||||
| israel_rail | pass | 9 | 0 | 0 | 0 | 2.6 | |
|
||||
| iss | pass | 17 | 0 | 0 | 0 | 2.6 | |
|
||||
| ista_ecotrend | pass | 49 | 0 | 0 | 0 | 4.1 | |
|
||||
| isy994 | pass | 31 | 0 | 0 | 0 | 3.1 | |
|
||||
| ituran | pass | 19 | 0 | 0 | 0 | 3.0 | |
|
||||
| izone | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| jellyfin | pass | 44 | 0 | 0 | 0 | 8.6 | |
|
||||
| jewish_calendar | pass | 123 | 0 | 0 | 0 | 11.9 | |
|
||||
| justnimbus | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| jvc_projector | pass | 31 | 0 | 0 | 0 | 5.7 | |
|
||||
| kaleidescape | pass | 19 | 0 | 0 | 0 | 4.0 | |
|
||||
| keenetic_ndms2 | pass | 14 | 0 | 0 | 0 | 2.4 | |
|
||||
| kegtron | pass | 12 | 0 | 0 | 0 | 2.7 | |
|
||||
| keymitt_ble | pass | 7 | 0 | 0 | 0 | 2.6 | |
|
||||
| kiosker | pass | 43 | 0 | 0 | 0 | 3.3 | |
|
||||
| kmtronic | pass | 11 | 0 | 0 | 0 | 2.5 | |
|
||||
| knocki | pass | 17 | 0 | 0 | 0 | 2.8 | |
|
||||
| knx | pass | 387 | 0 | 0 | 0 | 28.0 | |
|
||||
| kodi | pass | 21 | 0 | 0 | 0 | 2.8 | |
|
||||
| kostal_plenticore | issues | 38 | 1 | 0 | 0 | 4.1 | |
|
||||
| kraken | pass | 11 | 0 | 0 | 0 | 2.9 | |
|
||||
| kulersky | pass | 17 | 0 | 0 | 0 | 2.9 | |
|
||||
| lacrosse_view | issues | 28 | 1 | 0 | 0 | 3.1 | |
|
||||
| lamarzocco | pass | 94 | 0 | 0 | 0 | 14.3 | |
|
||||
| lametric | pass | 55 | 0 | 0 | 0 | 5.6 | |
|
||||
| landisgyr_heat_meter | pass | 10 | 0 | 0 | 0 | 2.8 | |
|
||||
| lastfm | pass | 15 | 0 | 0 | 0 | 2.5 | |
|
||||
| launch_library | pass | 2 | 0 | 0 | 0 | 2.3 | |
|
||||
| laundrify | pass | 18 | 0 | 0 | 0 | 2.8 | |
|
||||
| lcn | pass | 149 | 0 | 0 | 0 | 13.4 | |
|
||||
| ld2410_ble | pass | 6 | 0 | 0 | 0 | 2.6 | |
|
||||
| leaone | pass | 6 | 0 | 0 | 0 | 2.6 | |
|
||||
| led_ble | pass | 9 | 0 | 0 | 0 | 2.7 | |
|
||||
| lektrico | pass | 13 | 0 | 0 | 0 | 2.8 | |
|
||||
| letpot | pass | 40 | 0 | 0 | 0 | 4.1 | |
|
||||
| lg_infrared | pass | 61 | 0 | 0 | 0 | 4.3 | |
|
||||
| lg_netcast | pass | 22 | 0 | 0 | 0 | 3.5 | |
|
||||
| lg_soundbar | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| lg_thinq | pass | 29 | 0 | 0 | 0 | 4.1 | |
|
||||
| libre_hardware_monitor | pass | 26 | 0 | 0 | 0 | 3.2 | |
|
||||
| lichess | pass | 8 | 0 | 0 | 0 | 2.5 | |
|
||||
| lidarr | pass | 12 | 0 | 0 | 0 | 2.6 | |
|
||||
| liebherr | pass | 76 | 0 | 0 | 0 | 5.7 | |
|
||||
| lifx | pass | 72 | 0 | 0 | 0 | 5.4 | |
|
||||
| linkplay | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| litejet | pass | 32 | 0 | 0 | 0 | 3.8 | |
|
||||
| litterrobot | pass | 63 | 0 | 0 | 0 | 5.9 | |
|
||||
| livisi | pass | 4 | 0 | 0 | 0 | 2.4 | |
|
||||
| local_calendar | pass | 50 | 0 | 0 | 0 | 5.1 | |
|
||||
| local_ip | pass | 3 | 0 | 0 | 0 | 2.3 | |
|
||||
| local_todo | pass | 55 | 0 | 0 | 0 | 5.6 | |
|
||||
| locative | pass | 5 | 0 | 0 | 1 | 3.0 | |
|
||||
| lojack | pass | 16 | 0 | 0 | 0 | 2.9 | |
|
||||
| london_underground | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| lookin | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| loqed | pass | 17 | 0 | 0 | 0 | 3.0 | |
|
||||
| luftdaten | pass | 11 | 0 | 0 | 0 | 2.6 | |
|
||||
| lunatone | pass | 40 | 0 | 0 | 0 | 3.8 | |
|
||||
| lupusec | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| lutron | pass | 42 | 0 | 0 | 0 | 3.8 | |
|
||||
| lutron_caseta | pass | 52 | 0 | 0 | 0 | 4.9 | |
|
||||
| lyric | pass | 4 | 0 | 0 | 0 | 2.4 | |
|
||||
| madvr | issues | 16 | 1 | 0 | 0 | 3.2 | |
|
||||
| mailgun | pass | 5 | 0 | 0 | 0 | 2.7 | |
|
||||
| marantz_infrared | pass | 36 | 0 | 0 | 0 | 3.4 | |
|
||||
| mastodon | issues | 82 | 1 | 0 | 0 | 26.2 | |
|
||||
| matter | pass | 372 | 0 | 0 | 1 | 68.8 | |
|
||||
| mcp | pass | 45 | 0 | 0 | 0 | 4.1 | |
|
||||
| mcp_server | pass | 47 | 0 | 0 | 0 | 5.9 | |
|
||||
| mealie | pass | 94 | 0 | 0 | 0 | 7.8 | |
|
||||
| meater | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| medcom_ble | pass | 9 | 0 | 0 | 0 | 2.6 | |
|
||||
| media_extractor | pass | 20 | 0 | 0 | 0 | 7.6 | |
|
||||
| melcloud | issues | 23 | 1 | 0 | 0 | 2.8 | |
|
||||
| melnor | pass | 17 | 0 | 0 | 0 | 3.5 | |
|
||||
| met | pass | 18 | 0 | 0 | 0 | 2.6 | |
|
||||
| met_eireann | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| meteo_france | pass | 6 | 0 | 0 | 0 | 2.5 | |
|
||||
| meteo_lt | pass | 7 | 0 | 0 | 0 | 2.5 | |
|
||||
| meteoclimatic | pass | 3 | 0 | 0 | 0 | 2.4 | |
|
||||
| metoffice | pass | 18 | 0 | 0 | 0 | 3.1 | |
|
||||
| microbees | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| miele | pass | 115 | 0 | 0 | 0 | 10.2 | |
|
||||
| mikrotik | pass | 21 | 0 | 0 | 0 | 2.8 | |
|
||||
| mill | pass | 31 | 0 | 0 | 0 | 4.5 | |
|
||||
| min_max | pass | 20 | 0 | 0 | 0 | 2.6 | |
|
||||
| minecraft_server | pass | 40 | 0 | 0 | 0 | 3.5 | |
|
||||
| mitsubishi_comfort | pass | 66 | 0 | 0 | 0 | 5.3 | |
|
||||
| moat | pass | 11 | 0 | 0 | 0 | 2.8 | |
|
||||
| mobile_app | pass | 135 | 0 | 0 | 0 | 13.2 | |
|
||||
| modem_callerid | pass | 9 | 0 | 0 | 0 | 2.6 | |
|
||||
| modern_forms | issues | 29 | 1 | 0 | 0 | 3.4 | |
|
||||
| moehlenhoff_alpha2 | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| mold_indicator | pass | 37 | 0 | 0 | 0 | 3.0 | |
|
||||
| monarch_money | pass | 5 | 0 | 0 | 0 | 2.6 | |
|
||||
| monoprice | pass | 23 | 0 | 0 | 0 | 3.2 | |
|
||||
| monzo | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| moon | pass | 11 | 0 | 0 | 0 | 2.5 | |
|
||||
| mopeka | pass | 14 | 0 | 0 | 0 | 2.9 | |
|
||||
| motion_blinds | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| motionblinds_ble | issues | 42 | 1 | 0 | 0 | 6.3 | |
|
||||
| motionmount | pass | 38 | 0 | 0 | 0 | 3.5 | |
|
||||
| mpd | pass | 7 | 0 | 0 | 0 | 2.9 | |
|
||||
| mta | pass | 27 | 0 | 0 | 0 | 3.0 | |
|
||||
| mullvad | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| music_assistant | pass | 127 | 0 | 0 | 0 | 9.4 | |
|
||||
| mutesync | pass | 5 | 0 | 0 | 0 | 2.3 | |
|
||||
| myneomitis | pass | 43 | 0 | 0 | 0 | 4.1 | |
|
||||
| mysensors | pass | 61 | 0 | 0 | 0 | 5.1 | |
|
||||
| mystrom | pass | 23 | 0 | 0 | 0 | 2.8 | |
|
||||
| myuplink | pass | 38 | 0 | 0 | 0 | 4.8 | |
|
||||
| nam | pass | 39 | 0 | 0 | 0 | 3.4 | |
|
||||
| namecheapdns | pass | 20 | 0 | 0 | 0 | 2.7 | |
|
||||
| nanoleaf | pass | 30 | 0 | 0 | 0 | 2.9 | |
|
||||
| nasweb | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| nederlandse_spoorwegen | pass | 29 | 0 | 0 | 0 | 3.4 | |
|
||||
| ness_alarm | pass | 39 | 0 | 0 | 0 | 3.0 | |
|
||||
| netgear | pass | 10 | 0 | 0 | 0 | 2.4 | |
|
||||
| netgear_lte | pass | 11 | 0 | 0 | 0 | 2.6 | |
|
||||
| nexia | pass | 21 | 0 | 0 | 0 | 3.6 | |
|
||||
| nextbus | pass | 28 | 0 | 0 | 0 | 2.7 | |
|
||||
| nextcloud | pass | 17 | 0 | 0 | 0 | 2.9 | |
|
||||
| nextdns | issues | 52 | 1 | 0 | 0 | 5.8 | |
|
||||
| nfandroidtv | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| nibe_heatpump | pass | 64 | 0 | 0 | 0 | 4.3 | |
|
||||
| nice_go | issues | 43 | 1 | 0 | 0 | 4.5 | |
|
||||
| nightscout | pass | 11 | 0 | 0 | 0 | 2.5 | |
|
||||
| niko_home_control | pass | 32 | 0 | 0 | 0 | 3.8 | |
|
||||
| nina | pass | 21 | 0 | 0 | 0 | 3.2 | |
|
||||
| nintendo_parental_controls | pass | 30 | 0 | 0 | 0 | 3.3 | |
|
||||
| nmap_tracker | pass | 13 | 0 | 0 | 0 | 2.6 | |
|
||||
| nmbs | pass | 5 | 0 | 0 | 0 | 2.5 | |
|
||||
| nobo_hub | pass | 59 | 0 | 0 | 0 | 4.6 | |
|
||||
| nordpool | pass | 37 | 0 | 0 | 0 | 4.9 | |
|
||||
| notion | issues | 7 | 1 | 0 | 0 | 2.5 | |
|
||||
| novy_cooker_hood | issues | 28 | 1 | 0 | 0 | 3.1 | |
|
||||
| nrgkick | pass | 87 | 0 | 0 | 0 | 5.7 | |
|
||||
| ntfy | pass | 85 | 0 | 0 | 0 | 6.8 | |
|
||||
| nuheat | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| nuki | pass | 14 | 0 | 0 | 0 | 2.6 | |
|
||||
| nut | pass | 78 | 0 | 0 | 0 | 4.6 | |
|
||||
| nws | pass | 30 | 0 | 0 | 0 | 3.3 | |
|
||||
| nyt_games | pass | 10 | 0 | 0 | 0 | 2.6 | |
|
||||
| nzbget | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| obihai | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| ohme | pass | 34 | 0 | 0 | 0 | 4.4 | |
|
||||
| omie | pass | 19 | 0 | 0 | 0 | 2.9 | |
|
||||
| omnilogic | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| ondilo_ico | pass | 17 | 0 | 0 | 0 | 3.0 | |
|
||||
| onedrive | pass | 79 | 0 | 0 | 0 | 6.5 | |
|
||||
| onedrive_for_business | pass | 38 | 0 | 0 | 0 | 4.6 | |
|
||||
| onewire | pass | 33 | 0 | 0 | 0 | 3.5 | |
|
||||
| onkyo | pass | 48 | 0 | 0 | 0 | 4.2 | |
|
||||
| open_meteo | pass | 5 | 0 | 0 | 0 | 2.7 | |
|
||||
| opendisplay | pass | 67 | 0 | 0 | 0 | 6.6 | |
|
||||
| openevse | pass | 40 | 0 | 0 | 0 | 4.5 | |
|
||||
| openexchangerates | pass | 9 | 0 | 0 | 0 | 2.4 | |
|
||||
| opengarage | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| openhome | pass | 11 | 0 | 0 | 0 | 2.6 | |
|
||||
| openrgb | pass | 69 | 0 | 0 | 0 | 4.6 | |
|
||||
| opensky | pass | 12 | 0 | 0 | 0 | 2.6 | |
|
||||
| opentherm_gw | pass | 29 | 0 | 0 | 0 | 5.7 | |
|
||||
| openuv | issues | 10 | 1 | 0 | 0 | 2.7 | |
|
||||
| openweathermap | pass | 15 | 0 | 0 | 0 | 2.6 | |
|
||||
| opower | issues | 35 | 1 | 0 | 0 | 5.8 | |
|
||||
| oralb | pass | 14 | 0 | 0 | 0 | 2.9 | |
|
||||
| orvibo | pass | 15 | 0 | 0 | 0 | 2.6 | |
|
||||
| osoenergy | pass | 17 | 0 | 0 | 0 | 3.0 | |
|
||||
| otbr | pass | 103 | 0 | 0 | 0 | 7.9 | |
|
||||
| otp | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| ouman_eh_800 | pass | 20 | 0 | 0 | 0 | 3.1 | |
|
||||
| ourgroceries | pass | 21 | 0 | 0 | 0 | 2.8 | |
|
||||
| overkiz | pass | 181 | 0 | 0 | 0 | 9.9 | |
|
||||
| overseerr | pass | 45 | 0 | 0 | 0 | 4.8 | |
|
||||
| ovo_energy | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| owntracks | pass | 71 | 0 | 0 | 0 | 5.8 | |
|
||||
| p1_monitor | issues | 11 | 2 | 0 | 0 | 2.7 | |
|
||||
| paj_gps | pass | 19 | 0 | 0 | 0 | 3.1 | |
|
||||
| palazzetti | pass | 17 | 0 | 0 | 0 | 3.0 | |
|
||||
| panasonic_viera | pass | 32 | 0 | 0 | 0 | 3.0 | |
|
||||
| paperless_ngx | pass | 41 | 0 | 0 | 0 | 3.6 | |
|
||||
| peblar | pass | 62 | 0 | 0 | 0 | 5.2 | |
|
||||
| peco | pass | 33 | 0 | 0 | 0 | 3.0 | |
|
||||
| pegel_online | issues | 9 | 1 | 0 | 0 | 2.6 | |
|
||||
| permobil | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| pglab | pass | 21 | 0 | 0 | 0 | 3.5 | |
|
||||
| philips_js | issues | 15 | 1 | 0 | 0 | 3.7 | |
|
||||
| pi_hole | issues | 25 | 1 | 0 | 0 | 3.4 | |
|
||||
| picnic | pass | 40 | 0 | 0 | 0 | 3.4 | |
|
||||
| ping | pass | 21 | 0 | 0 | 0 | 2.9 | |
|
||||
| pjlink | pass | 29 | 0 | 0 | 0 | 3.3 | |
|
||||
| plaato | pass | 13 | 0 | 0 | 0 | 2.9 | |
|
||||
| playstation_network | pass | 68 | 0 | 0 | 0 | 6.7 | |
|
||||
| plex | pass | 53 | 0 | 0 | 0 | 6.7 | |
|
||||
| plugwise | pass | 86 | 0 | 0 | 0 | 8.3 | |
|
||||
| point | pass | 5 | 0 | 0 | 0 | 2.5 | |
|
||||
| pooldose | pass | 75 | 0 | 0 | 0 | 5.3 | |
|
||||
| poolsense | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| portainer | issues | 86 | 1 | 0 | 0 | 12.9 | |
|
||||
| powerfox | pass | 22 | 0 | 0 | 0 | 3.0 | |
|
||||
| powerfox_local | pass | 21 | 0 | 0 | 0 | 2.9 | |
|
||||
| powerwall | pass | 37 | 0 | 0 | 0 | 3.6 | |
|
||||
| prana | pass | 37 | 0 | 0 | 0 | 3.8 | |
|
||||
| private_ble_device | pass | 21 | 0 | 0 | 0 | 3.3 | |
|
||||
| probe_plus | pass | 6 | 0 | 0 | 0 | 2.6 | |
|
||||
| profiler | pass | 13 | 0 | 0 | 0 | 2.6 | |
|
||||
| progettihwsw | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| prowl | pass | 24 | 0 | 0 | 0 | 2.8 | |
|
||||
| proximity | issues | 27 | 1 | 0 | 0 | 3.0 | |
|
||||
| proxmoxve | issues | 103 | 1 | 0 | 0 | 9.2 | |
|
||||
| ps4 | pass | 41 | 0 | 0 | 0 | 3.3 | |
|
||||
| ptdevices | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| pterodactyl | pass | 14 | 0 | 0 | 0 | 2.7 | |
|
||||
| pure_energie | pass | 8 | 0 | 0 | 0 | 2.5 | |
|
||||
| purpleair | issues | 19 | 1 | 0 | 0 | 3.0 | |
|
||||
| pushbullet | pass | 17 | 0 | 0 | 0 | 2.6 | |
|
||||
| pushover | pass | 16 | 0 | 0 | 0 | 2.5 | |
|
||||
| pvoutput | pass | 17 | 0 | 0 | 0 | 2.7 | |
|
||||
| pvpc_hourly_pricing | pass | 2 | 0 | 0 | 0 | 2.4 | |
|
||||
| pyload | pass | 67 | 0 | 0 | 0 | 4.6 | |
|
||||
| qbittorrent | pass | 8 | 0 | 0 | 0 | 2.5 | |
|
||||
| qbus | pass | 25 | 0 | 0 | 0 | 4.0 | |
|
||||
| qingping | pass | 15 | 0 | 0 | 0 | 3.0 | |
|
||||
| qnap | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| qnap_qsw | pass | 18 | 0 | 0 | 0 | 3.1 | |
|
||||
| rabbitair | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| rachio | pass | 6 | 0 | 0 | 0 | 2.5 | |
|
||||
| radarr | pass | 32 | 0 | 0 | 0 | 3.9 | |
|
||||
| radio_browser | pass | 10 | 0 | 0 | 0 | 2.6 | |
|
||||
| radiotherm | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| rainbird | pass | 70 | 0 | 0 | 0 | 4.3 | |
|
||||
| rainforest_eagle | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| rainforest_raven | issues | 19 | 2 | 0 | 0 | 3.2 | |
|
||||
| rainmachine | issues | 19 | 2 | 0 | 0 | 2.9 | |
|
||||
| random | pass | 9 | 0 | 0 | 0 | 2.4 | |
|
||||
| rapt_ble | pass | 11 | 0 | 0 | 0 | 2.8 | |
|
||||
| rdw | pass | 10 | 0 | 0 | 0 | 2.6 | |
|
||||
| recollect_waste | issues | 3 | 1 | 0 | 0 | 2.5 | |
|
||||
| redgtech | pass | 18 | 0 | 0 | 0 | 2.8 | |
|
||||
| refoss | pass | 2 | 0 | 0 | 0 | 2.3 | |
|
||||
| rehlko | pass | 16 | 0 | 0 | 0 | 2.9 | |
|
||||
| remote_calendar | pass | 44 | 0 | 0 | 0 | 3.9 | |
|
||||
| renault | pass | 104 | 0 | 0 | 0 | 5.7 | |
|
||||
| renson | pass | 3 | 0 | 0 | 0 | 2.3 | |
|
||||
| rfxtrx | pass | 89 | 0 | 0 | 0 | 7.5 | |
|
||||
| rhasspy | pass | 3 | 0 | 0 | 0 | 2.3 | |
|
||||
| ridwell | issues | 13 | 1 | 0 | 0 | 2.7 | |
|
||||
| risco | pass | 69 | 0 | 0 | 0 | 4.3 | |
|
||||
| rituals_perfume_genie | pass | 25 | 0 | 0 | 0 | 3.1 | |
|
||||
| roborock | pass | 183 | 0 | 0 | 0 | 18.5 | |
|
||||
| roku | pass | 67 | 0 | 0 | 0 | 6.5 | |
|
||||
| romy | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| roomba | pass | 26 | 0 | 0 | 0 | 2.7 | |
|
||||
| roon | pass | 5 | 0 | 0 | 0 | 2.3 | |
|
||||
| route_b_smart_meter | pass | 7 | 0 | 0 | 0 | 2.6 | |
|
||||
| rova | pass | 11 | 0 | 0 | 0 | 2.4 | |
|
||||
| rpi_power | pass | 6 | 0 | 0 | 0 | 2.3 | |
|
||||
| ruckus_unleashed | pass | 29 | 0 | 0 | 0 | 2.8 | |
|
||||
| russound_rio | pass | 50 | 0 | 0 | 0 | 6.0 | |
|
||||
| ruuvi_gateway | pass | 5 | 0 | 0 | 0 | 2.5 | |
|
||||
| ruuvitag_ble | pass | 13 | 0 | 0 | 0 | 2.8 | |
|
||||
| rympro | pass | 7 | 0 | 0 | 0 | 2.3 | |
|
||||
| sabnzbd | pass | 19 | 0 | 0 | 0 | 2.9 | |
|
||||
| samsung_infrared | pass | 18 | 0 | 0 | 0 | 2.7 | |
|
||||
| samsungtv | issues | 166 | 3 | 0 | 0 | 13.5 | |
|
||||
| sanix | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| satel_integra | pass | 89 | 0 | 0 | 0 | 7.6 | |
|
||||
| saunum | pass | 68 | 0 | 0 | 0 | 5.0 | |
|
||||
| schlage | pass | 49 | 0 | 0 | 0 | 4.8 | |
|
||||
| scrape | issues | 37 | 1 | 0 | 0 | 3.1 | |
|
||||
| screenlogic | issues | 33 | 1 | 0 | 0 | 3.8 | |
|
||||
| season | pass | 21 | 0 | 0 | 0 | 2.9 | |
|
||||
| sense | pass | 19 | 0 | 0 | 0 | 3.2 | |
|
||||
| sensibo | pass | 69 | 0 | 0 | 0 | 8.4 | |
|
||||
| sensirion_ble | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| sensorpro | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| sensorpush | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| sensorpush_cloud | pass | 5 | 0 | 0 | 0 | 2.5 | |
|
||||
| sensoterra | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| sentry | pass | 24 | 0 | 0 | 0 | 2.5 | |
|
||||
| senz | pass | 21 | 0 | 0 | 0 | 3.0 | |
|
||||
| seventeentrack | pass | 16 | 0 | 0 | 0 | 2.6 | |
|
||||
| sfr_box | pass | 26 | 0 | 0 | 0 | 2.8 | |
|
||||
| sftp_storage | pass | 34 | 0 | 0 | 0 | 8.7 | |
|
||||
| sharkiq | pass | 42 | 0 | 0 | 0 | 3.3 | |
|
||||
| shelly | pass | 636 | 0 | 0 | 0 | 45.7 | |
|
||||
| shopping_list | pass | 60 | 0 | 0 | 0 | 4.7 | |
|
||||
| sia | pass | 21 | 0 | 0 | 0 | 2.6 | |
|
||||
| simplefin | pass | 12 | 0 | 0 | 0 | 2.7 | |
|
||||
| simplepush | pass | 5 | 0 | 0 | 0 | 2.3 | |
|
||||
| simplisafe | issues | 15 | 1 | 0 | 0 | 3.0 | |
|
||||
| sky_remote | pass | 9 | 0 | 0 | 0 | 2.4 | |
|
||||
| slack | pass | 13 | 0 | 0 | 0 | 2.4 | |
|
||||
| sleep_as_android | pass | 44 | 0 | 0 | 0 | 4.5 | |
|
||||
| sleepiq | pass | 33 | 0 | 0 | 0 | 4.9 | |
|
||||
| slide_local | issues | 48 | 1 | 0 | 0 | 4.0 | |
|
||||
| slimproto | pass | 2 | 0 | 0 | 0 | 2.3 | |
|
||||
| sma | issues | 33 | 1 | 0 | 0 | 3.8 | |
|
||||
| smappee | pass | 20 | 0 | 0 | 0 | 2.7 | |
|
||||
| smarla | pass | 37 | 0 | 0 | 0 | 4.2 | |
|
||||
| smart_meter_texas | pass | 16 | 0 | 0 | 0 | 2.6 | |
|
||||
| smartthings | pass | 340 | 0 | 0 | 0 | 70.7 | |
|
||||
| smarttub | pass | 40 | 0 | 0 | 0 | 4.9 | |
|
||||
| smarty | pass | 12 | 0 | 0 | 0 | 2.8 | |
|
||||
| smhi | pass | 20 | 0 | 0 | 0 | 3.4 | |
|
||||
| smlight | pass | 98 | 0 | 0 | 0 | 7.1 | |
|
||||
| snapcast | pass | 18 | 0 | 0 | 0 | 3.3 | |
|
||||
| snoo | pass | 21 | 0 | 0 | 0 | 3.4 | |
|
||||
| snooz | pass | 35 | 0 | 0 | 0 | 4.9 | |
|
||||
| solaredge | pass | 62 | 0 | 0 | 0 | 11.0 | |
|
||||
| solarlog | issues | 25 | 1 | 0 | 0 | 3.3 | |
|
||||
| solarman | pass | 17 | 0 | 0 | 0 | 2.8 | |
|
||||
| solax | pass | 3 | 0 | 0 | 0 | 2.3 | |
|
||||
| soma | pass | 7 | 0 | 0 | 0 | 2.3 | |
|
||||
| somfy_mylink | pass | 11 | 0 | 0 | 0 | 2.4 | |
|
||||
| sonarr | pass | 56 | 0 | 0 | 0 | 9.7 | |
|
||||
| songpal | pass | 26 | 0 | 0 | 0 | 3.0 | |
|
||||
| sonos | pass | 174 | 0 | 0 | 0 | 18.9 | |
|
||||
| soundtouch | pass | 31 | 0 | 0 | 0 | 3.3 | |
|
||||
| speedtestdotnet | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| splunk | pass | 36 | 0 | 0 | 0 | 2.9 | |
|
||||
| spotify | pass | 70 | 0 | 0 | 0 | 9.0 | |
|
||||
| sql | pass | 80 | 0 | 0 | 0 | 6.5 | |
|
||||
| squeezebox | pass | 129 | 0 | 0 | 0 | 12.8 | |
|
||||
| srp_energy | pass | 15 | 0 | 0 | 0 | 2.7 | |
|
||||
| starline | pass | 4 | 0 | 0 | 0 | 2.3 | |
|
||||
| starlink | pass | 8 | 0 | 0 | 0 | 2.7 | |
|
||||
| statistics | pass | 56 | 0 | 0 | 0 | 4.2 | |
|
||||
| steam_online | pass | 14 | 0 | 0 | 0 | 2.5 | |
|
||||
| steamist | pass | 23 | 0 | 0 | 0 | 2.9 | |
|
||||
| stiebel_eltron | pass | 9 | 0 | 0 | 0 | 2.8 | |
|
||||
| stookwijzer | pass | 12 | 0 | 0 | 0 | 2.6 | |
|
||||
| streamlabswater | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| subaru | pass | 59 | 0 | 0 | 0 | 4.6 | |
|
||||
| suez_water | pass | 19 | 0 | 0 | 0 | 4.2 | |
|
||||
| sun | pass | 27 | 0 | 0 | 1 | 4.9 | |
|
||||
| sunricher_dali | pass | 50 | 0 | 0 | 0 | 5.8 | |
|
||||
| sunweg | pass | 1 | 0 | 0 | 0 | 2.2 | |
|
||||
| surepetcare | pass | 15 | 0 | 0 | 0 | 2.7 | |
|
||||
| swiss_public_transport | pass | 36 | 0 | 0 | 0 | 3.1 | |
|
||||
| switch_as_x | pass | 176 | 0 | 0 | 0 | 10.0 | |
|
||||
| switchbee | pass | 6 | 0 | 0 | 0 | 2.3 | |
|
||||
| switchbot | issues | 352 | 1 | 0 | 0 | 19.7 | |
|
||||
| switchbot_cloud | pass | 134 | 0 | 0 | 0 | 10.8 | |
|
||||
| switcher_kis | issues | 76 | 1 | 0 | 0 | 7.7 | |
|
||||
| syncthing | pass | 5 | 0 | 0 | 0 | 2.3 | |
|
||||
| syncthru | pass | 9 | 0 | 0 | 0 | 2.6 | |
|
||||
| system_bridge | pass | 39 | 0 | 0 | 0 | 4.5 | |
|
||||
| systemmonitor | issues | 34 | 2 | 0 | 0 | 4.9 | |
|
||||
| systemnexa2 | pass | 34 | 0 | 0 | 0 | 3.6 | |
|
||||
| tado | pass | 40 | 0 | 0 | 0 | 4.7 | |
|
||||
| tailscale | pass | 14 | 0 | 0 | 0 | 2.8 | |
|
||||
| tailwind | pass | 36 | 0 | 0 | 0 | 3.3 | |
|
||||
| tami4 | pass | 14 | 0 | 0 | 0 | 2.6 | |
|
||||
| tankerkoenig | issues | 20 | 1 | 0 | 0 | 2.8 | |
|
||||
| tautulli | pass | 8 | 0 | 0 | 0 | 2.3 | |
|
||||
| technove | pass | 40 | 0 | 0 | 0 | 3.7 | |
|
||||
| tedee | pass | 41 | 0 | 0 | 0 | 4.5 | |
|
||||
| telegram_bot | pass | 123 | 0 | 0 | 0 | 13.2 | |
|
||||
| teleinfo | pass | 24 | 0 | 0 | 0 | 3.2 | |
|
||||
| tellduslive | pass | 15 | 0 | 0 | 0 | 2.4 | |
|
||||
| teltonika | pass | 50 | 0 | 0 | 0 | 3.8 | |
|
||||
| template | pass | 2470 | 0 | 0 | 0 | 60.1 | |
|
||||
| tesla_fleet | pass | 153 | 0 | 0 | 0 | 12.3 | |
|
||||
| tesla_wall_connector | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| teslemetry | pass | 158 | 0 | 0 | 0 | 16.8 | |
|
||||
| tessie | pass | 67 | 0 | 0 | 0 | 4.5 | |
|
||||
| thermobeacon | pass | 11 | 0 | 0 | 0 | 2.7 | |
|
||||
| thermopro | pass | 18 | 0 | 0 | 0 | 3.0 | |
|
||||
| thethingsnetwork | pass | 8 | 0 | 0 | 0 | 2.4 | |
|
||||
| thread | pass | 65 | 0 | 0 | 0 | 4.2 | |
|
||||
| threshold | pass | 114 | 0 | 0 | 0 | 4.1 | |
|
||||
| tibber | pass | 92 | 0 | 0 | 0 | 13.3 | |
|
||||
| tile | pass | 11 | 0 | 0 | 0 | 2.5 | |
|
||||
| tilt_ble | pass | 11 | 0 | 0 | 0 | 2.8 | |
|
||||
| tilt_pi | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| time_date | pass | 18 | 0 | 0 | 0 | 2.8 | |
|
||||
| tod | pass | 32 | 0 | 0 | 0 | 3.3 | |
|
||||
| todoist | pass | 50 | 0 | 0 | 0 | 4.2 | |
|
||||
| togrill | pass | 62 | 0 | 0 | 0 | 5.7 | |
|
||||
| tolo | pass | 7 | 0 | 0 | 0 | 2.4 | |
|
||||
| tomorrowio | pass | 21 | 0 | 0 | 0 | 3.1 | |
|
||||
| toon | pass | 10 | 0 | 0 | 0 | 2.7 | |
|
||||
| totalconnect | pass | 66 | 0 | 0 | 0 | 11.7 | |
|
||||
| touchline | pass | 8 | 0 | 0 | 0 | 2.5 | |
|
||||
| touchline_sl | pass | 15 | 0 | 0 | 0 | 2.7 | |
|
||||
| tplink_omada | issues | 52 | 1 | 0 | 0 | 4.7 | |
|
||||
| traccar | pass | 5 | 0 | 0 | 1 | 2.9 | |
|
||||
| traccar_server | pass | 12 | 0 | 0 | 0 | 2.9 | |
|
||||
| tractive | issues | 48 | 1 | 0 | 0 | 4.0 | |
|
||||
| tradfri | pass | 91 | 0 | 0 | 0 | 6.4 | |
|
||||
| trafikverket_ferry | pass | 13 | 0 | 0 | 0 | 2.5 | |
|
||||
| trafikverket_train | pass | 41 | 0 | 0 | 0 | 3.1 | |
|
||||
| trafikverket_weatherstation | pass | 16 | 0 | 0 | 0 | 2.5 | |
|
||||
| trane | pass | 39 | 0 | 0 | 0 | 4.0 | |
|
||||
| transmission | pass | 75 | 0 | 0 | 0 | 4.6 | |
|
||||
| trend | pass | 39 | 0 | 0 | 0 | 3.2 | |
|
||||
| triggercmd | pass | 5 | 0 | 0 | 0 | 2.4 | |
|
||||
| trmnl | pass | 36 | 0 | 0 | 0 | 3.7 | |
|
||||
| twentemilieu | pass | 17 | 0 | 0 | 0 | 2.9 | |
|
||||
| twilio | pass | 1 | 0 | 0 | 0 | 2.6 | |
|
||||
| twinkly | issues | 25 | 1 | 0 | 0 | 4.1 | |
|
||||
| twitch | pass | 16 | 0 | 0 | 0 | 4.2 | |
|
||||
| uhoo | pass | 24 | 0 | 0 | 0 | 3.0 | |
|
||||
| ukraine_alarm | pass | 11 | 0 | 0 | 0 | 2.4 | |
|
||||
| unifi | issues | 158 | 1 | 0 | 0 | 12.4 | |
|
||||
| unifi_access | pass | 155 | 0 | 0 | 0 | 10.9 | |
|
||||
| upb | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| upcloud | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| upnp | pass | 23 | 0 | 0 | 0 | 3.8 | |
|
||||
| uptime | pass | 4 | 0 | 0 | 0 | 2.4 | |
|
||||
| uptime_kuma | pass | 38 | 0 | 0 | 0 | 3.6 | |
|
||||
| uptimerobot | pass | 35 | 0 | 0 | 0 | 3.2 | |
|
||||
| utility_meter | issues | 94 | 1 | 0 | 0 | 6.0 | |
|
||||
| v2c | issues | 12 | 1 | 0 | 0 | 2.9 | |
|
||||
| vallox | pass | 76 | 0 | 0 | 0 | 5.6 | |
|
||||
| vegehub | pass | 18 | 0 | 0 | 0 | 2.9 | |
|
||||
| velbus | issues | 57 | 1 | 0 | 0 | 9.0 | |
|
||||
| velux | pass | 80 | 0 | 0 | 0 | 4.9 | |
|
||||
| venstar | pass | 12 | 0 | 0 | 0 | 2.6 | |
|
||||
| vera | pass | 29 | 0 | 0 | 0 | 3.1 | |
|
||||
| version | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| vesync | pass | 175 | 0 | 0 | 0 | 12.5 | |
|
||||
| vicare | issues | 54 | 1 | 0 | 0 | 4.5 | |
|
||||
| victron_ble | pass | 34 | 0 | 0 | 0 | 3.6 | |
|
||||
| victron_gx | pass | 62 | 0 | 0 | 0 | 14.1 | |
|
||||
| victron_remote_monitoring | pass | 22 | 0 | 0 | 0 | 3.0 | |
|
||||
| vilfo | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| vizio | pass | 73 | 0 | 0 | 0 | 4.5 | |
|
||||
| vlc_telnet | pass | 39 | 0 | 0 | 0 | 3.4 | |
|
||||
| vodafone_station | issues | 53 | 1 | 0 | 0 | 4.6 | |
|
||||
| volumio | pass | 9 | 0 | 0 | 0 | 2.3 | |
|
||||
| volvo | pass | 110 | 0 | 0 | 0 | 8.6 | |
|
||||
| volvooncall | pass | 4 | 0 | 0 | 0 | 2.2 | |
|
||||
| wake_on_lan | pass | 15 | 0 | 0 | 0 | 2.5 | |
|
||||
| wallbox | pass | 38 | 0 | 0 | 0 | 3.7 | |
|
||||
| waqi | pass | 20 | 0 | 0 | 0 | 2.6 | |
|
||||
| waterfurnace | pass | 77 | 0 | 0 | 0 | 11.9 | |
|
||||
| watergate | pass | 16 | 0 | 0 | 0 | 3.0 | |
|
||||
| watts | issues | 51 | 1 | 0 | 0 | 5.2 | |
|
||||
| watttime | issues | 11 | 1 | 0 | 0 | 2.6 | |
|
||||
| waze_travel_time | pass | 23 | 0 | 0 | 0 | 14.8 | |
|
||||
| weatherflow | pass | 5 | 0 | 0 | 0 | 3.0 | |
|
||||
| weatherflow_cloud | pass | 17 | 0 | 0 | 0 | 3.1 | |
|
||||
| weatherkit | pass | 35 | 0 | 0 | 0 | 2.9 | |
|
||||
| webdav | pass | 25 | 0 | 0 | 0 | 3.9 | |
|
||||
| webmin | issues | 11 | 1 | 0 | 0 | 2.5 | |
|
||||
| webostv | issues | 82 | 1 | 0 | 0 | 12.0 | |
|
||||
| weheat | pass | 16 | 0 | 0 | 0 | 2.8 | |
|
||||
| wemo | pass | 93 | 0 | 0 | 0 | 6.7 | |
|
||||
| whirlpool | issues | 239 | 1 | 0 | 0 | 12.2 | |
|
||||
| whois | pass | 41 | 0 | 0 | 0 | 3.4 | |
|
||||
| wiffi | pass | 4 | 0 | 0 | 0 | 2.2 | |
|
||||
| wiim | pass | 29 | 0 | 0 | 0 | 3.0 | |
|
||||
| wilight | pass | 22 | 0 | 0 | 0 | 2.8 | |
|
||||
| withings | pass | 62 | 0 | 0 | 0 | 8.0 | |
|
||||
| wiz | pass | 56 | 0 | 0 | 0 | 4.3 | |
|
||||
| wled | pass | 100 | 0 | 0 | 0 | 7.6 | |
|
||||
| wmspro | pass | 39 | 0 | 0 | 0 | 4.0 | |
|
||||
| wolflink | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| workday | issues | 70 | 1 | 0 | 0 | 6.1 | |
|
||||
| worldclock | pass | 6 | 0 | 0 | 0 | 2.4 | |
|
||||
| ws66i | pass | 24 | 0 | 0 | 0 | 3.1 | |
|
||||
| wsdot | pass | 16 | 0 | 0 | 0 | 2.7 | |
|
||||
| xbox | pass | 203 | 0 | 0 | 0 | 14.9 | |
|
||||
| xiaomi_aqara | pass | 12 | 0 | 0 | 0 | 2.5 | |
|
||||
| xiaomi_ble | pass | 92 | 0 | 0 | 0 | 6.2 | |
|
||||
| xiaomi_miio | pass | 51 | 0 | 0 | 0 | 4.1 | |
|
||||
| xthings_cloud | pass | 30 | 0 | 0 | 0 | 3.7 | |
|
||||
| yale_smart_alarm | pass | 37 | 0 | 0 | 0 | 3.7 | |
|
||||
| yalexs_ble | pass | 26 | 0 | 0 | 0 | 3.3 | |
|
||||
| yamaha_musiccast | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| yardian | pass | 16 | 0 | 0 | 0 | 2.8 | |
|
||||
| yeelight | pass | 62 | 0 | 0 | 0 | 4.7 | |
|
||||
| yolink | pass | 10 | 0 | 0 | 0 | 3.1 | |
|
||||
| youless | pass | 4 | 0 | 0 | 0 | 2.4 | |
|
||||
| youtube | pass | 24 | 0 | 0 | 0 | 3.4 | |
|
||||
| zamg | pass | 9 | 0 | 0 | 0 | 2.5 | |
|
||||
| zerproc | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| zeversolar | pass | 10 | 0 | 0 | 0 | 2.5 | |
|
||||
| zha | issues | 339 | 1 | 0 | 4 | 70.5 | |
|
||||
| zimi | pass | 16 | 0 | 0 | 0 | 2.7 | |
|
||||
| zinvolt | pass | 12 | 0 | 0 | 0 | 2.8 | |
|
||||
| zodiac | pass | 5 | 0 | 0 | 0 | 2.3 | |
|
||||
| zwave_js | pass | 611 | 0 | 0 | 0 | 60.2 | |
|
||||
| zwave_me | pass | 8 | 0 | 0 | 0 | 2.2 | |
|
||||
|
||||
Per-failure tracebacks are dumped under `${SANDBOX_ERRORS_DIR:-/tmp/sandbox_errors}/<integration>/`.
|
||||
@@ -1,57 +0,0 @@
|
||||
# Sandbox compat report
|
||||
|
||||
Plugin: `hass_client.testing.pytest_plugin`
|
||||
|
||||
## Summary
|
||||
|
||||
- Integrations passing: **35**
|
||||
- Integrations with issues: **2**
|
||||
- Timeouts: **0**
|
||||
- No tests collected: **0**
|
||||
|
||||
- Tests passed: **7646**
|
||||
- Tests failed: **2**
|
||||
- Test errors: **0**
|
||||
- Tests skipped: **17**
|
||||
|
||||
## Per-integration results
|
||||
|
||||
| integration | status | passed | failed | errors | skipped |
|
||||
| --- | --- | ---: | ---: | ---: | ---: |
|
||||
| input_boolean | pass | 18 | 0 | 0 | 0 |
|
||||
| input_button | pass | 15 | 0 | 0 | 0 |
|
||||
| input_datetime | pass | 28 | 0 | 0 | 0 |
|
||||
| input_number | pass | 24 | 0 | 0 | 0 |
|
||||
| input_select | pass | 26 | 0 | 0 | 0 |
|
||||
| input_text | pass | 23 | 0 | 0 | 0 |
|
||||
| counter | pass | 751 | 0 | 0 | 0 |
|
||||
| timer | pass | 877 | 0 | 0 | 0 |
|
||||
| schedule | pass | 387 | 0 | 0 | 0 |
|
||||
| zone | pass | 32 | 0 | 0 | 0 |
|
||||
| tag | pass | 12 | 0 | 0 | 0 |
|
||||
| group | pass | 392 | 0 | 0 | 0 |
|
||||
| person | pass | 34 | 0 | 0 | 0 |
|
||||
| scene | pass | 41 | 0 | 0 | 0 |
|
||||
| todo | pass | 281 | 0 | 0 | 0 |
|
||||
| automation | pass | 117 | 0 | 0 | 0 |
|
||||
| script | pass | 64 | 0 | 0 | 0 |
|
||||
| alert | pass | 18 | 0 | 0 | 0 |
|
||||
| template | pass | 2470 | 0 | 0 | 0 |
|
||||
| plant | pass | 11 | 0 | 0 | 0 |
|
||||
| proximity | issues | 27 | 1 | 0 | 0 |
|
||||
| min_max | pass | 20 | 0 | 0 | 0 |
|
||||
| statistics | pass | 56 | 0 | 0 | 0 |
|
||||
| utility_meter | issues | 94 | 1 | 0 | 0 |
|
||||
| derivative | pass | 76 | 0 | 0 | 0 |
|
||||
| integration | pass | 61 | 0 | 0 | 0 |
|
||||
| generic_thermostat | pass | 114 | 0 | 0 | 0 |
|
||||
| generic_hygrostat | pass | 76 | 0 | 0 | 0 |
|
||||
| history_stats | pass | 55 | 0 | 0 | 0 |
|
||||
| threshold | pass | 114 | 0 | 0 | 0 |
|
||||
| filter | pass | 32 | 0 | 0 | 0 |
|
||||
| mqtt_statestream | pass | 17 | 0 | 0 | 0 |
|
||||
| recorder | pass | 932 | 0 | 0 | 17 |
|
||||
| rest | pass | 128 | 0 | 0 | 0 |
|
||||
| logbook | pass | 106 | 0 | 0 | 0 |
|
||||
| command_line | pass | 78 | 0 | 0 | 0 |
|
||||
| trend | pass | 39 | 0 | 0 | 0 |
|
||||
+9
-11
@@ -515,18 +515,16 @@ only thing that differs is how the channel pair is materialised.
|
||||
|
||||
The compat lane runner
|
||||
[`run_compat.py`](run_compat.py) drives either plugin against a list of
|
||||
integration test directories, parses pytest's summary line, and writes
|
||||
[`COMPAT.csv`](COMPAT.csv) + [`COMPAT_LATEST.md`](COMPAT_LATEST.md)
|
||||
(the curated baseline lives in [`COMPAT.md`](COMPAT.md)). Per-failure
|
||||
output lands in `${SANDBOX_ERRORS_DIR:-/tmp/sandbox_errors}`.
|
||||
integration test directories, parses pytest's summary line, and writes a
|
||||
machine CSV plus a `COMPAT_LATEST.md` per-run report (both git-ignored). The
|
||||
curated baseline lives in [`COMPAT.md`](COMPAT.md) and the curated residual
|
||||
backlog in [`BACKLOG.md`](BACKLOG.md). Per-failure output lands in
|
||||
`${SANDBOX_ERRORS_DIR:-/tmp/sandbox_errors}`.
|
||||
|
||||
[`run_compat_full.py`](run_compat_full.py) is the wider cross-sweep
|
||||
runner Phase 16 landed: asyncio + JUnit XML + outer concurrency,
|
||||
exercises every classifier-routable integration in the tree and writes
|
||||
[`COMPAT_FULL.md`](COMPAT_FULL.md) + [`COMPAT_FULL.csv`](COMPAT_FULL.csv).
|
||||
[`categorize_failures.py`](categorize_failures.py) buckets the
|
||||
JUnit failures into [`BACKLOG.md`](BACKLOG.md) +
|
||||
[`BACKLOG_FAILURES.json`](BACKLOG_FAILURES.json).
|
||||
The one-shot full cross-sweep tooling that produced the original backlog
|
||||
(`run_compat_full.py` + `categorize_failures.py` + `generate_backlog.py`) was
|
||||
removed once the measurement was done; recover it from git history if a fresh
|
||||
tree-wide sweep is ever needed.
|
||||
|
||||
**Baseline numbers (Phase 17):** 35/37 integrations pass on the
|
||||
v1-baseline 37-integration set (99.97 % test-level); 711/807
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
"""Bucket sandbox compat-sweep failures into named categories.
|
||||
|
||||
Pairs with ``run_compat_full.py``. The runner dumps a per-test traceback
|
||||
into ``$SANDBOX_ERRORS_DIR/<integration>/<path>__<name>.txt``; this
|
||||
script walks that tree, runs each file through an ordered list of
|
||||
signature matchers, and writes:
|
||||
|
||||
- ``BACKLOG_FAILURES.json`` — machine-readable rollup
|
||||
(``{bucket → {integration → [test_node, …]}}``) for downstream tooling.
|
||||
- A short stdout summary suitable for `tee`-ing onto an issue.
|
||||
|
||||
Categories are
|
||||
ordered most-specific → most-generic; the first match wins, so unknown
|
||||
genuinely means "no rule fired". A "≥95% of failures buckets out of
|
||||
``unknown``" smoke gate lives at the bottom of the run; if that fails,
|
||||
add more rules and re-run.
|
||||
|
||||
Usage::
|
||||
|
||||
cd sandbox
|
||||
# After run_compat_full.py finishes:
|
||||
uv run python categorize_failures.py
|
||||
|
||||
# Or against a custom errors dir:
|
||||
uv run python categorize_failures.py --errors-dir /tmp/sandbox_errors
|
||||
|
||||
The rules are intentionally regex-based on the per-test traceback excerpt
|
||||
(JUnit's ``<failure>`` text + the ``--tb=short`` body). They're meant to
|
||||
be cheap to extend — every rule is "if regex matches, bucket name" — so
|
||||
adding a new category as failure shapes appear is one tuple entry.
|
||||
"""
|
||||
|
||||
# Standalone CLI driver. Same Ruff carve-out as ``run_compat_full.py``.
|
||||
# ruff: noqa: INP001, T201, S108
|
||||
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
_HERE = Path(__file__).resolve().parent
|
||||
DEFAULT_ERRORS_DIR = Path(
|
||||
os.environ.get("SANDBOX_ERRORS_DIR", "/tmp/sandbox_errors")
|
||||
)
|
||||
DEFAULT_BACKLOG_JSON = _HERE / "BACKLOG_FAILURES.json"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Rule:
|
||||
"""One signature rule: name + compiled regex pattern."""
|
||||
|
||||
bucket: str
|
||||
pattern: re.Pattern[str]
|
||||
|
||||
|
||||
# Order matters — first hit wins. Specific signatures (test-only autotag
|
||||
# noise, named protocol gaps) sit above generic catch-alls. Patterns are
|
||||
# compiled with ``re.IGNORECASE | re.DOTALL`` for resilience.
|
||||
def _compile(pattern: str) -> re.Pattern[str]:
|
||||
return re.compile(pattern, re.IGNORECASE | re.DOTALL)
|
||||
|
||||
|
||||
RULES: tuple[Rule, ...] = (
|
||||
# ---- test-only -------------------------------------------------------
|
||||
# The autotag patch mutates entry.data; tests that assert
|
||||
# ``entry.data == <anything>`` or snapshot it see the new
|
||||
# ``__sandbox_group`` key. Same root cause whether it surfaces in an
|
||||
# `assert`, a `mappingproxy(...)` repr (pytest truncates the diff into
|
||||
# the JUnit `message` attribute and the visible slice often omits the
|
||||
# tag itself), or a Syrupy snapshot diff.
|
||||
Rule("test-only", _compile(r"__sandbox_group")),
|
||||
Rule("test-only", _compile(r"mappingproxy\(.+?'built-in'")),
|
||||
Rule("test-only", _compile(r"mappingproxy\(.+?'custom'")),
|
||||
# The autotag is the only thing that injects the literal value
|
||||
# ``'built-in'`` into a config-entry data assertion's diff.
|
||||
Rule("test-only", _compile(r"'built-in'.*?(==|expected|snapshot)")),
|
||||
# A `+ '__sandbox_group'` in a Syrupy diff is unambiguously the
|
||||
# autotag.
|
||||
Rule("test-only", _compile(r"\+\s+'__sandbox_group'")),
|
||||
# Catch-all for the `assert <something>.data == <literal>` shape.
|
||||
# `entry.data` is always a `MappingProxyType`; the only time the
|
||||
# assertion fails is when an extra key was added — and the only
|
||||
# extra-key source the compat lane adds is the autotag.
|
||||
Rule(
|
||||
"test-only",
|
||||
_compile(r"assert\s+mappingproxy\(.+?\)\s*==\s*[\{\[]"),
|
||||
),
|
||||
# Diagnostic snapshots that include the entry's
|
||||
# full ``as_dict()`` now see a top-level ``+ 'sandbox': '<group>'``
|
||||
# line in the diff. Same root cause as ``__sandbox_group`` — the
|
||||
# autotag synthesises the field for compat coverage, the snapshot
|
||||
# was captured pre-autotag. Fix: refresh the snapshot in the
|
||||
# integration's test tree (out of sandbox scope).
|
||||
Rule("test-only", _compile(r"\+\s+'sandbox'\s*:\s*'(?:built-in|custom|main)'")),
|
||||
# Snapshot drift on ``'created_at'`` / ``'modified_at'``: tests that
|
||||
# didn't pin the wall clock with freezegun, so the snapshot's
|
||||
# baked-in timestamp doesn't match the new run's. Environmental,
|
||||
# not a sandbox bridge issue; fix is for the integration's test to use
|
||||
# ``@pytest.mark.freeze_time``. Matches both Syrupy diff form
|
||||
# (``+ 'created_at': ...``) and pytest dict-diff form
|
||||
# (``'created_at': '<iso>', 'data': ...``).
|
||||
Rule(
|
||||
"test-only",
|
||||
_compile(r"'(?:created_at|modified_at)'\s*:\s*'?\d{4}-\d{2}-\d{2}T"),
|
||||
),
|
||||
|
||||
# ---- proxy-missing ---------------------------------------------------
|
||||
Rule("proxy-missing", _compile(r"KeyError.*?_DOMAIN_PROXIES")),
|
||||
Rule("proxy-missing", _compile(r"no proxy (class )?for domain")),
|
||||
Rule("proxy-missing", _compile(r"unknown sandbox entity domain")),
|
||||
# Bridge gap: integration registers an entity in the sandbox but it
|
||||
# never shows up in main's entity registry. `proxy-missing` reuses
|
||||
# this bucket since the fix story is the same — make the bridge
|
||||
# surface the entity to main.
|
||||
Rule(
|
||||
"proxy-missing",
|
||||
_compile(r"async_is_registered.+?\n.*?AssertionError.*?False"),
|
||||
),
|
||||
# Same root cause as the registry case: an integration that runs in
|
||||
# the sandbox registers an entity, but main's state machine never
|
||||
# sees it — `hass.states.get(...)` returns None.
|
||||
Rule(
|
||||
"proxy-missing",
|
||||
_compile(
|
||||
r"hass\.states\.get\(.+?\)\.state.+?\n.*?AttributeError.+?NoneType"
|
||||
),
|
||||
),
|
||||
|
||||
# ---- protocol gaps ---------------------------------------------------
|
||||
# data_schema serialisation drift. The bridge does voluptuous-serialize
|
||||
# round-tripping; a regression would surface as None / wrong type.
|
||||
Rule(
|
||||
"data-schema-stripped",
|
||||
_compile(r"data_schema.*?(is None|None type|stripped|missing)"),
|
||||
),
|
||||
Rule(
|
||||
"data-schema-stripped",
|
||||
_compile(r"FlowResult.*?data_schema.*?None"),
|
||||
),
|
||||
Rule(
|
||||
"service-schema-missing",
|
||||
_compile(r"hass\.services\.async_register.*?schema"),
|
||||
),
|
||||
Rule(
|
||||
"service-schema-missing",
|
||||
_compile(r"ServiceValidationError.*?bridge"),
|
||||
),
|
||||
# Be conservative — `unique_id=None` shows up incidentally in many
|
||||
# `ConfigEntry` reprs, so only match assertions where the line in
|
||||
# question is *about* unique_id, not where it merely mentions one.
|
||||
Rule(
|
||||
"unique-id-not-propagated",
|
||||
_compile(r"assert\s+[^=]+unique_id[^=]*?(==|is)"),
|
||||
),
|
||||
Rule(
|
||||
"unique-id-not-propagated",
|
||||
_compile(r"AssertionError.+?unique_id\s+(does not match|mismatch)"),
|
||||
),
|
||||
|
||||
# ---- restore_state ---------------------------------------------------
|
||||
Rule(
|
||||
"restore-state-not-applied",
|
||||
_compile(r"async_get_last_state.*?(None|missing|not restored)"),
|
||||
),
|
||||
Rule(
|
||||
"restore-state-not-applied",
|
||||
_compile(r"restore.*?state.*?did not survive"),
|
||||
),
|
||||
|
||||
# ---- context propagation --------------------------------------------
|
||||
Rule("context-not-propagated", _compile(r"context\.user_id\b")),
|
||||
Rule("context-not-propagated", _compile(r"context\.parent_id\b")),
|
||||
Rule("context-not-propagated", _compile(r"Context\(.*?user_id=.+?\).*?==")),
|
||||
|
||||
# ---- channel / re-entrancy ------------------------------------------
|
||||
Rule(
|
||||
"re-entrant-channel",
|
||||
_compile(r"sandbox.*?channel\.call.*?(deadlock|timeout|never returned)"),
|
||||
),
|
||||
Rule(
|
||||
"re-entrant-channel",
|
||||
_compile(r"TimeoutError.*?sandbox.*?call"),
|
||||
),
|
||||
|
||||
# ---- store ----------------------------------------------------------
|
||||
Rule("store-key-rejected", _compile(r"_require_key.*?invalid")),
|
||||
Rule("store-key-rejected", _compile(r"sandbox.*?store.*?(rejected|invalid key)")),
|
||||
|
||||
# ---- flow / async ---------------------------------------------------
|
||||
Rule(
|
||||
"flow-step-not-async",
|
||||
_compile(r"RuntimeWarning.*?coroutine.*?async_step_"),
|
||||
),
|
||||
Rule("flow-step-not-async", _compile(r"async_step_.*?never awaited")),
|
||||
|
||||
# ---- platform deny-list ---------------------------------------------
|
||||
Rule(
|
||||
"integration-uses-deny-listed-platform",
|
||||
_compile(r"sandbox.*?incompatible platform|deny-list.*?platform"),
|
||||
),
|
||||
|
||||
# ---- non-idempotent service handlers --------------------------------
|
||||
Rule(
|
||||
"non-idempotent-service-handler",
|
||||
_compile(r"_resolve_attachments|service handler.*?pre-?dispatch"),
|
||||
),
|
||||
|
||||
# ---- dependencies-not-shared ----------------------------------------
|
||||
Rule(
|
||||
"dependencies-not-shared",
|
||||
_compile(r"state for .+? not found.*?sandbox"),
|
||||
),
|
||||
Rule(
|
||||
"dependencies-not-shared",
|
||||
_compile(r"main-side .+? not available to sandbox"),
|
||||
),
|
||||
# An integration test mocks a dependency (HTTP client, websocket, …)
|
||||
# in the main process, but the sandbox runs in a separate process and
|
||||
# never sees the mock — setup fails with SETUP_ERROR / SETUP_RETRY.
|
||||
# Same root cause as the explicit "share state" patterns above.
|
||||
Rule(
|
||||
"dependencies-not-shared",
|
||||
_compile(
|
||||
r"ConfigEntryState\.SETUP_ERROR.+?is\s+"
|
||||
r"<?ConfigEntryState\.LOADED",
|
||||
),
|
||||
),
|
||||
Rule(
|
||||
"dependencies-not-shared",
|
||||
_compile(
|
||||
r"ConfigEntryState\.SETUP_ERROR.+?is\s+"
|
||||
r"<?ConfigEntryState\.SETUP_RETRY",
|
||||
),
|
||||
),
|
||||
Rule(
|
||||
"dependencies-not-shared",
|
||||
_compile(r"failed on setup with .+?ConfigEntryState\.SETUP_ERROR"),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _load_traceback(path: Path) -> str:
|
||||
"""Return the contents of a per-test error dump (utf-8, lossy)."""
|
||||
try:
|
||||
return path.read_text(encoding="utf-8", errors="replace")
|
||||
except OSError:
|
||||
return ""
|
||||
|
||||
|
||||
def categorise(traceback: str) -> str:
|
||||
"""Match ``traceback`` against the rule list and return the bucket name."""
|
||||
for rule in RULES:
|
||||
if rule.pattern.search(traceback):
|
||||
return rule.bucket
|
||||
return "unknown"
|
||||
|
||||
|
||||
def walk_errors(errors_dir: Path) -> dict[str, dict[str, list[tuple[str, str]]]]:
|
||||
"""Walk per-integration error dumps; return ``{bucket → {domain → [(node, excerpt)]}}``."""
|
||||
out: dict[str, dict[str, list[tuple[str, str]]]] = defaultdict(
|
||||
lambda: defaultdict(list)
|
||||
)
|
||||
if not errors_dir.is_dir():
|
||||
return out
|
||||
for integration_dir in sorted(errors_dir.iterdir()):
|
||||
# The per-integration log lives at ``<errors_dir>/<integration>.log``
|
||||
# alongside its sibling directory. JUnit XML lives in ``_junit/``;
|
||||
# skip both — they aren't per-test failure dumps.
|
||||
if not integration_dir.is_dir():
|
||||
continue
|
||||
if integration_dir.name.startswith("_"):
|
||||
continue
|
||||
for traceback_file in sorted(integration_dir.rglob("*.txt")):
|
||||
text = _load_traceback(traceback_file)
|
||||
if not text:
|
||||
continue
|
||||
node_id = _extract_node_id(text, traceback_file)
|
||||
excerpt = _short_excerpt(text)
|
||||
bucket = categorise(text)
|
||||
out[bucket][integration_dir.name].append((node_id, excerpt))
|
||||
return out
|
||||
|
||||
|
||||
_NODE_LINE = re.compile(r"^node_id:\s*(.+)$", re.MULTILINE)
|
||||
|
||||
|
||||
def _extract_node_id(text: str, path: Path) -> str:
|
||||
"""Pull the ``node_id`` header from a dump; fall back to the file stem."""
|
||||
if (match := _NODE_LINE.search(text)) is not None:
|
||||
return match.group(1).strip()
|
||||
return path.stem
|
||||
|
||||
|
||||
def _short_excerpt(text: str, *, lines: int = 6) -> str:
|
||||
"""Return the first ``lines`` lines after the header so backlog entries stay terse."""
|
||||
body = text.split("\n", maxsplit=4)[-1] if "\n" in text else text
|
||||
return "\n".join(body.splitlines()[:lines])
|
||||
|
||||
|
||||
def render_summary(
|
||||
buckets: dict[str, dict[str, list[tuple[str, str]]]],
|
||||
) -> list[str]:
|
||||
"""Render a stdout-friendly summary block."""
|
||||
total_failures = sum(
|
||||
len(node_list)
|
||||
for integrations in buckets.values()
|
||||
for node_list in integrations.values()
|
||||
)
|
||||
lines = [
|
||||
"Failure categorisation",
|
||||
"-" * 32,
|
||||
f"Total failures bucketed: {total_failures}",
|
||||
"",
|
||||
"Per-bucket counts (most → least):",
|
||||
]
|
||||
per_bucket = sorted(
|
||||
(
|
||||
(
|
||||
bucket,
|
||||
sum(len(nodes) for nodes in integrations.values()),
|
||||
len(integrations),
|
||||
)
|
||||
for bucket, integrations in buckets.items()
|
||||
),
|
||||
key=lambda r: (-r[1], r[0]),
|
||||
)
|
||||
for bucket, count, integration_count in per_bucket:
|
||||
lines.append(
|
||||
f" {bucket:<40} {count:>5} failures across {integration_count:>3} integrations"
|
||||
)
|
||||
unknown_count = next(
|
||||
(count for bucket, count, _ in per_bucket if bucket == "unknown"),
|
||||
0,
|
||||
)
|
||||
if total_failures:
|
||||
ratio = (total_failures - unknown_count) / total_failures
|
||||
lines.append("")
|
||||
lines.append(
|
||||
f"Categorisation hit rate: {ratio:.1%}"
|
||||
f" (target ≥95%; unknown bucket = {unknown_count})"
|
||||
)
|
||||
return lines
|
||||
|
||||
|
||||
def serialise_buckets(
|
||||
buckets: dict[str, dict[str, list[tuple[str, str]]]],
|
||||
) -> dict[str, dict[str, list[dict[str, str]]]]:
|
||||
"""Convert tuples to plain dicts for JSON output."""
|
||||
return {
|
||||
bucket: {
|
||||
integration: [
|
||||
{"node_id": node, "excerpt": excerpt}
|
||||
for node, excerpt in items
|
||||
]
|
||||
for integration, items in integrations.items()
|
||||
}
|
||||
for bucket, integrations in buckets.items()
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
"""CLI entry point."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--errors-dir", type=Path, default=DEFAULT_ERRORS_DIR,
|
||||
help=("Per-test error dump root "
|
||||
"(default: $SANDBOX_ERRORS_DIR or /tmp/sandbox_errors)."),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out", type=Path, default=DEFAULT_BACKLOG_JSON,
|
||||
help="Where to write the bucket → integration → nodes JSON rollup.",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
buckets = walk_errors(args.errors_dir)
|
||||
args.out.write_text(json.dumps(serialise_buckets(buckets), indent=2, sort_keys=True))
|
||||
print("\n".join(render_summary(buckets)))
|
||||
print(f"\nWrote {args.out}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,264 +0,0 @@
|
||||
"""Render a draft ``BACKLOG.md`` from the categorizer's JSON rollup.
|
||||
|
||||
Pairs with ``categorize_failures.py``. Reads ``BACKLOG_FAILURES.json``
|
||||
(``{bucket → {integration → [{node_id, excerpt}]}}``) and writes the
|
||||
section-per-bucket Markdown backlog.
|
||||
|
||||
The "Proposed fix" stub is intentionally left as a TODO marker per
|
||||
section — that field needs human judgement (file paths, rough size,
|
||||
complexity), and the sweep should produce the draft skeleton so the
|
||||
backlog landing is reviewable without a 600-line Markdown blob in the
|
||||
commit diff.
|
||||
|
||||
Usage::
|
||||
|
||||
cd sandbox
|
||||
uv run python generate_backlog.py # writes BACKLOG.md
|
||||
uv run python generate_backlog.py --out FOO.md # custom output path
|
||||
"""
|
||||
|
||||
# ruff: noqa: INP001, T201
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
_HERE = Path(__file__).resolve().parent
|
||||
DEFAULT_BACKLOG_JSON = _HERE / "BACKLOG_FAILURES.json"
|
||||
DEFAULT_BACKLOG_MD = _HERE / "BACKLOG.md"
|
||||
|
||||
# Per-bucket prose. Keeps the generator output reviewable by anchoring
|
||||
# each section to a one-liner from the plan; the proposed-fix block is a
|
||||
# TODO marker the human fills in after looking at the actual rows.
|
||||
BUCKET_BLURB: dict[str, str] = {
|
||||
"test-only": (
|
||||
"Test scaffolding noise — the compat-lane autotag patch mutates"
|
||||
" `entry.data` to add `__sandbox_group`, and some helper-integration"
|
||||
" tests or Syrupy snapshots assert the entry data is empty / matches"
|
||||
" a snapshot that pre-dates the tag. Not a sandbox bridge bug."
|
||||
),
|
||||
"proxy-missing": (
|
||||
"The bridge ships proxies for all 32 entity domains. Any hit here"
|
||||
" means the integration registers an entity in a domain the bridge"
|
||||
" doesn't recognise — either a new domain landed in HA Core or the"
|
||||
" dispatch map missed one."
|
||||
),
|
||||
"data-schema-stripped": (
|
||||
"The bridge does a `voluptuous_serialize`-based round-trip so flow"
|
||||
" schemas survive the bridge. Any hit here means a `vol.Schema`"
|
||||
" shape the serializer can't represent (custom validators, untagged"
|
||||
" `vol.Any`, etc.)."
|
||||
),
|
||||
"service-schema-missing": (
|
||||
"Mirror of `data-schema-stripped` for `hass.services.async_register`."
|
||||
" The same bridge serialises service schemas; gaps here are"
|
||||
" edge cases (custom validators, schema-on-the-fly registrations)."
|
||||
),
|
||||
"unique-id-not-propagated": (
|
||||
"The bridge marshals `flow.context['unique_id']` into the proxy. Hits"
|
||||
" here are flow shapes that set unique_id outside the standard"
|
||||
" `async_set_unique_id` path (e.g. discovery flows that abort"
|
||||
" inside `async_step_user`)."
|
||||
),
|
||||
"restore-state-not-applied": (
|
||||
"The runtime warm-loads `RestoreStateData` from"
|
||||
" `<config>/.storage/sandbox/<group>/core.restore_state`. Hits"
|
||||
" here mean an integration's restore-state assertion fires before"
|
||||
" the warm-load completes, or expects state the previous run never"
|
||||
" persisted."
|
||||
),
|
||||
"context-not-propagated": (
|
||||
"The event mirror forwards events with the sandbox-side `context_id`"
|
||||
" but does NOT honour it for main's user/origin resolution. Integration"
|
||||
" tests"
|
||||
" that assert on `context.user_id` or `context.parent_id` fail here."
|
||||
" Carrying a richer Context shape is post-v2 work."
|
||||
),
|
||||
"re-entrant-channel": (
|
||||
"The channel dispatcher is concurrent so a handler can"
|
||||
" issue `channel.call(...)`. Hits here mean a re-entrant shape we"
|
||||
" haven't seen — the semaphore cap might be too aggressive, or a"
|
||||
" handler chain exceeds the in-flight ceiling."
|
||||
),
|
||||
"store-key-rejected": (
|
||||
"The `RemoteStore` validator rejects keys containing `/`, `\\`,"
|
||||
" NUL, `.`, or `..`. An integration using one of those characters"
|
||||
" trips this. Probably wants a translation step on the sandbox side"
|
||||
" rather than relaxing the validator."
|
||||
),
|
||||
"flow-step-not-async": (
|
||||
"The flow proxy expects every step on the integration's"
|
||||
" `ConfigFlow` to be an async coroutine. A sync step would emit a"
|
||||
" `coroutine 'async_step_*' was never awaited` warning that this"
|
||||
" bucket catches."
|
||||
),
|
||||
"integration-uses-deny-listed-platform": (
|
||||
"Classifier let an integration through that ships a"
|
||||
" `SANDBOX_INCOMPATIBLE_PLATFORMS` platform. Either the classifier"
|
||||
" has a bug or the platform-set should grow."
|
||||
),
|
||||
"non-idempotent-service-handler": (
|
||||
"The `ai_task`/`image` shape — the service handler"
|
||||
" does material work before calling the entity method. Today's"
|
||||
" resolution is `ALWAYS_MAIN`; integrations that hit this should"
|
||||
" join that set or sandbox-handler interception needs designing"
|
||||
" (post-v2 work)."
|
||||
),
|
||||
"dependencies-not-shared": (
|
||||
"Integration depends on a main-side service or piece of state that"
|
||||
" opt-in sharing doesn't expose. Tracked alongside the unfinished"
|
||||
" state-sharing consumer (see"
|
||||
" `sandbox/docs/design-share-states.md`)."
|
||||
),
|
||||
"unknown": (
|
||||
"Catch-all bucket of last resort. Every entry here means the"
|
||||
" categorizer's regex set didn't fire — add a more-specific rule"
|
||||
" in `categorize_failures.py::RULES`."
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def _bucket_priority(name: str) -> int:
|
||||
"""Stable sort key — most-actionable buckets first when counts tie."""
|
||||
order = [
|
||||
"proxy-missing",
|
||||
"context-not-propagated",
|
||||
"data-schema-stripped",
|
||||
"service-schema-missing",
|
||||
"unique-id-not-propagated",
|
||||
"restore-state-not-applied",
|
||||
"re-entrant-channel",
|
||||
"non-idempotent-service-handler",
|
||||
"integration-uses-deny-listed-platform",
|
||||
"store-key-rejected",
|
||||
"flow-step-not-async",
|
||||
"dependencies-not-shared",
|
||||
"test-only",
|
||||
"unknown",
|
||||
]
|
||||
try:
|
||||
return order.index(name)
|
||||
except ValueError:
|
||||
return len(order)
|
||||
|
||||
|
||||
def render_backlog(payload: dict[str, dict[str, list[dict[str, str]]]]) -> str:
|
||||
"""Render the BACKLOG.md draft."""
|
||||
lines: list[str] = [
|
||||
"# Sandbox — compat sweep backlog",
|
||||
"",
|
||||
"**Auto-generated draft** from `BACKLOG_FAILURES.json`."
|
||||
" `generate_backlog.py` writes the skeleton; the *Proposed fix* and"
|
||||
" *Estimated size* lines need human curation before this lands as the"
|
||||
" final deliverable.",
|
||||
"",
|
||||
"Sections are ordered by integration count (largest first). Within"
|
||||
" each section the affected-integration roll-up is capped at 10 — the"
|
||||
" rest live in `BACKLOG_FAILURES.json` if a reviewer wants the full"
|
||||
" set.",
|
||||
"",
|
||||
]
|
||||
|
||||
bucket_rows = []
|
||||
for bucket, integrations in payload.items():
|
||||
if not integrations:
|
||||
continue
|
||||
failure_count = sum(len(nodes) for nodes in integrations.values())
|
||||
bucket_rows.append((bucket, failure_count, len(integrations)))
|
||||
|
||||
bucket_rows.sort(key=lambda row: (-row[2], _bucket_priority(row[0]), row[0]))
|
||||
|
||||
lines.append("## Bucket overview")
|
||||
lines.append("")
|
||||
lines.append("| Bucket | Failures | Integrations |")
|
||||
lines.append("| --- | ---: | ---: |")
|
||||
for bucket, failures, integrations_count in bucket_rows:
|
||||
lines.append(f"| `{bucket}` | {failures} | {integrations_count} |")
|
||||
lines.append("")
|
||||
|
||||
for bucket, failures, integrations_count in bucket_rows:
|
||||
lines.append(f"## {bucket}")
|
||||
lines.append("")
|
||||
lines.append(BUCKET_BLURB.get(bucket, "_No description on file._"))
|
||||
lines.append("")
|
||||
lines.append(f"- **Failures:** {failures}")
|
||||
lines.append(f"- **Integrations affected:** {integrations_count}")
|
||||
lines.append("")
|
||||
integrations = payload[bucket]
|
||||
sorted_ints = sorted(
|
||||
integrations.items(), key=lambda pair: (-len(pair[1]), pair[0])
|
||||
)
|
||||
top = sorted_ints[:10]
|
||||
if top:
|
||||
lines.append("### Top integrations")
|
||||
lines.append("")
|
||||
lines.append("| Integration | Failure count |")
|
||||
lines.append("| --- | ---: |")
|
||||
for integration, nodes in top:
|
||||
lines.append(f"| `{integration}` | {len(nodes)} |")
|
||||
if len(sorted_ints) > 10:
|
||||
lines.append(
|
||||
f"| _… +{len(sorted_ints) - 10} more in"
|
||||
" `BACKLOG_FAILURES.json`_ | |"
|
||||
)
|
||||
lines.append("")
|
||||
sample_int, sample_nodes = top[0]
|
||||
sample = sample_nodes[0]
|
||||
lines.append("### Representative failure")
|
||||
lines.append("")
|
||||
lines.append(f"`{sample_int}::{sample['node_id'].split('::')[-1]}`")
|
||||
lines.append("")
|
||||
lines.append("```")
|
||||
lines.append((sample["excerpt"] or "").strip())
|
||||
lines.append("```")
|
||||
lines.append("")
|
||||
lines.append("### Proposed fix")
|
||||
lines.append("")
|
||||
lines.append("_TODO: write before landing._")
|
||||
lines.append("")
|
||||
lines.append("### Estimated size")
|
||||
lines.append("")
|
||||
lines.append("_TODO: file/lines/complexity rough estimate._")
|
||||
lines.append("")
|
||||
|
||||
lines.append("## `ALWAYS_MAIN` additions recommended")
|
||||
lines.append("")
|
||||
lines.append(
|
||||
"_TODO: list integrations whose dominant bucket is"
|
||||
" `non-idempotent-service-handler` or `dependencies-not-shared` and"
|
||||
" whose fix story is \"keep them on main\"._"
|
||||
)
|
||||
lines.append("")
|
||||
lines.append("## Classifier rule changes recommended")
|
||||
lines.append("")
|
||||
lines.append(
|
||||
"_TODO: list classifier deltas suggested by the sweep — e.g.,"
|
||||
" a new platform name to add to `SANDBOX_INCOMPATIBLE_PLATFORMS`,"
|
||||
" or an integration-type rule the classifier should tighten._"
|
||||
)
|
||||
lines.append("")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
"""CLI entry point."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--input", type=Path, default=DEFAULT_BACKLOG_JSON,
|
||||
help="Input JSON produced by `categorize_failures.py`.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out", type=Path, default=DEFAULT_BACKLOG_MD,
|
||||
help="Where to write BACKLOG.md draft.",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
payload = json.loads(args.input.read_text())
|
||||
args.out.write_text(render_backlog(payload))
|
||||
print(f"Wrote {args.out}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,572 +0,0 @@
|
||||
"""Run the full sandbox compat sweep across every routable integration.
|
||||
|
||||
This sweep broadens the 37-integration baseline to cover
|
||||
**every config-entry-based integration** that the sandbox classifier would
|
||||
route to a sandbox. The goal of this run is not to fix anything — it is
|
||||
to *measure* and *categorize* so the resulting backlog is grounded in real
|
||||
data.
|
||||
|
||||
Discovery rules (see ``discover_integrations``):
|
||||
|
||||
- Walk ``homeassistant/components/``.
|
||||
- Skip ``integration_type`` ``virtual`` or ``system`` (no runtime to
|
||||
sandbox).
|
||||
- Skip the ``ALWAYS_MAIN`` set (decided by the classifier already).
|
||||
- Skip integrations whose ``manifest.json`` has ``config_flow: false``
|
||||
(YAML-only integrations are out of scope).
|
||||
- Skip integrations whose ``tests/components/<domain>/`` directory has no
|
||||
``test_*.py`` files (no signal either way).
|
||||
- Skip integrations whose source ships a platform file in
|
||||
``SANDBOX_INCOMPATIBLE_PLATFORMS`` (classifier would route them to main,
|
||||
so the sweep wouldn't be measuring the bridge).
|
||||
|
||||
For every surviving integration the runner spawns a pytest subprocess with
|
||||
``-p hass_client.testing.pytest_plugin`` (the in-process plugin used by
|
||||
the baseline), captures the JUnit XML output, and dumps the full
|
||||
text output + per-test failure tracebacks into the per-integration error
|
||||
directory so the categorizer (``categorize_failures.py``) can bucket
|
||||
every failure.
|
||||
|
||||
Outer concurrency comes from asyncio + a semaphore: by default four
|
||||
integrations run in parallel. Per-integration parallelism via
|
||||
``pytest-xdist`` ``-n auto`` is opt-in (``--xdist``) because the
|
||||
``xdist`` worker spin-up cost dominates for small integrations and the
|
||||
outer concurrency already keeps the box busy.
|
||||
|
||||
Usage::
|
||||
|
||||
cd sandbox
|
||||
# Full sweep (every classifier-routable integration)
|
||||
uv run python run_compat_full.py
|
||||
|
||||
# Restrict to a list (handy for iterating on the categorizer)
|
||||
uv run python run_compat_full.py input_boolean light switch
|
||||
|
||||
# Validation: re-run the 37-integration baseline
|
||||
uv run python run_compat_full.py --baseline-37
|
||||
|
||||
The two committed deliverables are written at the end:
|
||||
|
||||
- ``COMPAT_FULL.md`` — per-integration results table + sweep header.
|
||||
- ``COMPAT_FULL.csv`` — machine-readable version of the same table.
|
||||
"""
|
||||
|
||||
# Standalone CLI driver, not a package module — Ruff's package-naming /
|
||||
# print-for-status / /tmp-fallback rules don't apply here, same as
|
||||
# ``run_compat.py``.
|
||||
# ruff: noqa: INP001, T201, S108, PERF401
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import csv as csv_module
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from xml.etree.ElementTree import ParseError, parse as et_parse
|
||||
|
||||
# Paths are relative to this script (sandbox/run_compat_full.py).
|
||||
_HERE = Path(__file__).resolve().parent
|
||||
CORE_ROOT = _HERE.parent
|
||||
COMPONENTS_DIR = CORE_ROOT / "homeassistant" / "components"
|
||||
CORE_TESTS_DIR = CORE_ROOT / "tests" / "components"
|
||||
DEFAULT_CSV = _HERE / "COMPAT_FULL.csv"
|
||||
DEFAULT_REPORT_MD = _HERE / "COMPAT_FULL.md"
|
||||
ERRORS_DIR = Path(os.environ.get("SANDBOX_ERRORS_DIR", "/tmp/sandbox_errors"))
|
||||
|
||||
# Mirrors homeassistant/components/sandbox/const.py. Duplicated here
|
||||
# because importing the live module would require booting the core test
|
||||
# env from this stand-alone driver. The unit tests guard against
|
||||
# behavioural drift; the per-integration sweep is allowed to lag by an
|
||||
# entry — if either set changes, update both copies and re-run.
|
||||
ALWAYS_MAIN: frozenset[str] = frozenset(
|
||||
{"script", "automation", "scene", "cloud", "ai_task", "image"}
|
||||
)
|
||||
SANDBOX_INCOMPATIBLE_PLATFORMS: frozenset[str] = frozenset(
|
||||
{"stt", "tts", "conversation", "assist_satellite", "wake_word", "camera"}
|
||||
)
|
||||
|
||||
# The 37-integration baseline list, for the ``--baseline-37`` shortcut. The
|
||||
# list lives both here and in ``COMPAT.md``; keep them in sync.
|
||||
BASELINE_37: tuple[str, ...] = (
|
||||
"input_boolean", "input_button", "input_datetime", "input_number",
|
||||
"input_select", "input_text", "counter", "timer", "schedule", "zone",
|
||||
"tag", "group", "person", "scene", "todo", "automation", "script",
|
||||
"alert", "template", "plant", "proximity", "min_max", "statistics",
|
||||
"utility_meter", "derivative", "integration", "generic_thermostat",
|
||||
"generic_hygrostat", "history_stats", "threshold", "filter",
|
||||
"mqtt_statestream", "recorder", "rest", "logbook", "command_line",
|
||||
"trend",
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Result:
|
||||
"""Single-integration pytest-run summary."""
|
||||
|
||||
integration: str
|
||||
passed: int = 0
|
||||
failed: int = 0
|
||||
errors: int = 0
|
||||
skipped: int = 0
|
||||
duration: float = 0.0
|
||||
status: str = "no_tests"
|
||||
failure_signatures: list[str] = field(default_factory=list)
|
||||
dominant_bucket: str | None = None
|
||||
|
||||
@property
|
||||
def total(self) -> int:
|
||||
"""Total tests collected and run for this integration."""
|
||||
return self.passed + self.failed + self.errors + self.skipped
|
||||
|
||||
|
||||
def _has_test_files(test_dir: Path) -> bool:
|
||||
"""Return True if ``test_dir`` ships at least one ``test_*.py``."""
|
||||
if not test_dir.is_dir():
|
||||
return False
|
||||
return any(
|
||||
p.name.startswith("test_") and p.suffix == ".py"
|
||||
for p in test_dir.iterdir()
|
||||
)
|
||||
|
||||
|
||||
def _ships_incompatible_platform(component_dir: Path) -> bool:
|
||||
"""Return True if ``component_dir`` has a platform in the deny-list."""
|
||||
return any(
|
||||
(component_dir / f"{plat}.py").exists()
|
||||
for plat in SANDBOX_INCOMPATIBLE_PLATFORMS
|
||||
)
|
||||
|
||||
|
||||
def discover_integrations() -> tuple[list[str], dict[str, int]]:
|
||||
"""Return the (sorted) eligible integration names and filter stats."""
|
||||
stats: dict[str, int] = {
|
||||
"no_manifest": 0,
|
||||
"virtual_or_system": 0,
|
||||
"always_main": 0,
|
||||
"incompatible_platform": 0,
|
||||
"no_config_flow": 0,
|
||||
"no_tests": 0,
|
||||
"eligible": 0,
|
||||
}
|
||||
eligible: list[str] = []
|
||||
for component in sorted(COMPONENTS_DIR.iterdir()):
|
||||
if not component.is_dir():
|
||||
continue
|
||||
manifest_path = component / "manifest.json"
|
||||
if not manifest_path.exists():
|
||||
stats["no_manifest"] += 1
|
||||
continue
|
||||
try:
|
||||
manifest = json.loads(manifest_path.read_text())
|
||||
except (json.JSONDecodeError, OSError):
|
||||
stats["no_manifest"] += 1
|
||||
continue
|
||||
itype = manifest.get("integration_type", "hub")
|
||||
if itype in ("virtual", "system"):
|
||||
stats["virtual_or_system"] += 1
|
||||
continue
|
||||
if component.name in ALWAYS_MAIN:
|
||||
stats["always_main"] += 1
|
||||
continue
|
||||
if _ships_incompatible_platform(component):
|
||||
stats["incompatible_platform"] += 1
|
||||
continue
|
||||
if not manifest.get("config_flow", False):
|
||||
stats["no_config_flow"] += 1
|
||||
continue
|
||||
if not _has_test_files(CORE_TESTS_DIR / component.name):
|
||||
stats["no_tests"] += 1
|
||||
continue
|
||||
eligible.append(component.name)
|
||||
stats["eligible"] += 1
|
||||
return eligible, stats
|
||||
|
||||
|
||||
def _parse_junit(xml_path: Path, *, errors_dir: Path, integration: str) -> Result:
|
||||
"""Parse a JUnit XML report into a ``Result`` + per-test traceback dump."""
|
||||
result = Result(integration=integration)
|
||||
try:
|
||||
# XML is produced by pytest's own --junit-xml in the same
|
||||
# subprocess we control — not untrusted input. S314 carve-out.
|
||||
tree = et_parse(xml_path) # noqa: S314
|
||||
except (ParseError, FileNotFoundError):
|
||||
result.status = "no_tests"
|
||||
return result
|
||||
root = tree.getroot()
|
||||
# JUnit format: <testsuites><testsuite ...><testcase .../></testsuite></testsuites>
|
||||
suite = root[0] if len(root) > 0 else None
|
||||
if suite is None or suite.tag != "testsuite":
|
||||
return result
|
||||
|
||||
result.passed = int(suite.attrib.get("tests", 0))
|
||||
result.failed = int(suite.attrib.get("failures", 0))
|
||||
result.errors = int(suite.attrib.get("errors", 0))
|
||||
result.skipped = int(suite.attrib.get("skipped", 0))
|
||||
result.duration = float(suite.attrib.get("time", 0.0))
|
||||
# JUnit's ``tests`` counts every test including failures/errors/skipped.
|
||||
# Re-derive ``passed`` so the dataclass meaning matches the baseline CSV.
|
||||
result.passed = max(0, result.passed - result.failed - result.errors - result.skipped)
|
||||
|
||||
integration_errors_dir = errors_dir / integration
|
||||
if integration_errors_dir.exists():
|
||||
shutil.rmtree(integration_errors_dir)
|
||||
|
||||
for testcase in suite:
|
||||
if testcase.tag != "testcase":
|
||||
continue
|
||||
failure_node = None
|
||||
for child in testcase:
|
||||
if child.tag in ("failure", "error"):
|
||||
failure_node = child
|
||||
break
|
||||
if failure_node is None:
|
||||
continue
|
||||
integration_errors_dir.mkdir(parents=True, exist_ok=True)
|
||||
classname = testcase.attrib.get("classname", "unknown").replace(".", "/")
|
||||
# Best-effort filename: ``<classname>::<name>`` with characters that
|
||||
# are awkward in a filename replaced by underscores. The dot→slash
|
||||
# swap on classname keeps the path layout close to the on-disk test
|
||||
# tree so reviewers can find the originating file quickly.
|
||||
name = testcase.attrib.get("name", "unknown")
|
||||
safe_name = "".join(
|
||||
c if c.isalnum() or c in "_.-[]" else "_" for c in name
|
||||
)
|
||||
node_path = integration_errors_dir / f"{classname}__{safe_name}.txt"
|
||||
node_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
body = [
|
||||
f"node_id: {testcase.attrib.get('classname', '')}::{name}",
|
||||
f"kind: {failure_node.tag}",
|
||||
f"message: {failure_node.attrib.get('message', '')}",
|
||||
"",
|
||||
failure_node.text or "",
|
||||
]
|
||||
node_path.write_text("\n".join(body))
|
||||
# Cheap dominant-bucket hint: store the failure message so the
|
||||
# caller (and categorize_failures.py) can guess without re-reading.
|
||||
result.failure_signatures.append(failure_node.attrib.get("message", ""))
|
||||
|
||||
if result.total == 0:
|
||||
result.status = "no_tests"
|
||||
elif result.failed == 0 and result.errors == 0:
|
||||
result.status = "pass"
|
||||
else:
|
||||
result.status = "issues"
|
||||
return result
|
||||
|
||||
|
||||
async def run_one(
|
||||
integration: str,
|
||||
*,
|
||||
semaphore: asyncio.Semaphore,
|
||||
timeout: float,
|
||||
use_xdist: bool,
|
||||
errors_dir: Path,
|
||||
junit_dir: Path,
|
||||
) -> Result:
|
||||
"""Spawn pytest for one integration, parse JUnit, return a ``Result``."""
|
||||
test_dir = CORE_TESTS_DIR / integration
|
||||
junit_path = junit_dir / f"{integration}.xml"
|
||||
log_path = errors_dir / f"{integration}.log"
|
||||
cmd = [
|
||||
"uv", "run", "python", "-m", "pytest",
|
||||
"-p", "hass_client.testing.pytest_plugin",
|
||||
str(test_dir),
|
||||
"--tb=short", "-q", "--no-header", "--no-cov",
|
||||
f"--junit-xml={junit_path}",
|
||||
]
|
||||
if use_xdist:
|
||||
cmd.extend(["-n", "auto"])
|
||||
|
||||
async with semaphore:
|
||||
start = time.monotonic()
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
cwd=CORE_ROOT,
|
||||
)
|
||||
try:
|
||||
stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=timeout)
|
||||
except TimeoutError:
|
||||
proc.kill()
|
||||
await proc.wait()
|
||||
duration = time.monotonic() - start
|
||||
errors_dir.mkdir(parents=True, exist_ok=True)
|
||||
log_path.write_text(
|
||||
f"timed out after {timeout:.0f}s\n"
|
||||
)
|
||||
return Result(
|
||||
integration=integration, status="timeout", duration=duration
|
||||
)
|
||||
except (FileNotFoundError, PermissionError) as exc:
|
||||
errors_dir.mkdir(parents=True, exist_ok=True)
|
||||
log_path.write_text(f"failed to spawn pytest: {exc}\n")
|
||||
return Result(integration=integration, status="error", duration=0.0)
|
||||
|
||||
duration = time.monotonic() - start
|
||||
output = stdout.decode("utf-8", errors="replace") if stdout else ""
|
||||
|
||||
result = _parse_junit(junit_path, errors_dir=errors_dir, integration=integration)
|
||||
result.duration = duration
|
||||
|
||||
if result.status in ("issues", "timeout") or result.total == 0:
|
||||
# Keep the full pytest output around for awkward-failure debugging
|
||||
# (e.g. collection errors that the JUnit report can't represent).
|
||||
errors_dir.mkdir(parents=True, exist_ok=True)
|
||||
log_path.write_text(output)
|
||||
return result
|
||||
|
||||
|
||||
def write_csv(results: list[Result], path: Path) -> None:
|
||||
"""Persist per-integration results in the same column order as COMPAT.csv."""
|
||||
with path.open("w", newline="") as fh:
|
||||
writer = csv_module.writer(fh)
|
||||
writer.writerow([
|
||||
"integration", "status", "passed", "failed", "errors", "skipped",
|
||||
"duration_s", "dominant_bucket",
|
||||
])
|
||||
for result in results:
|
||||
writer.writerow([
|
||||
result.integration, result.status, result.passed, result.failed,
|
||||
result.errors, result.skipped, f"{result.duration:.2f}",
|
||||
result.dominant_bucket or "",
|
||||
])
|
||||
|
||||
|
||||
def write_report(
|
||||
results: list[Result],
|
||||
*,
|
||||
path: Path,
|
||||
discovery_stats: dict[str, int],
|
||||
started_at: datetime,
|
||||
finished_at: datetime,
|
||||
concurrency: int,
|
||||
use_xdist: bool,
|
||||
) -> None:
|
||||
"""Render the COMPAT_FULL.md report. See module docstring for shape."""
|
||||
counts: dict[str, int] = {"pass": 0, "issues": 0, "timeout": 0, "no_tests": 0, "error": 0}
|
||||
totals = {"passed": 0, "failed": 0, "errors": 0, "skipped": 0}
|
||||
for result in results:
|
||||
counts[result.status] = counts.get(result.status, 0) + 1
|
||||
totals["passed"] += result.passed
|
||||
totals["failed"] += result.failed
|
||||
totals["errors"] += result.errors
|
||||
totals["skipped"] += result.skipped
|
||||
|
||||
test_total = totals["passed"] + totals["failed"] + totals["errors"]
|
||||
pass_rate = (totals["passed"] / test_total * 100.0) if test_total else 0.0
|
||||
integration_total = len(results)
|
||||
integration_pass_rate = (
|
||||
counts.get("pass", 0) / integration_total * 100.0
|
||||
if integration_total else 0.0
|
||||
)
|
||||
|
||||
lines: list[str] = [
|
||||
"# Sandbox — full compat sweep",
|
||||
"",
|
||||
"**This file is auto-generated by `run_compat_full.py`** — re-run the",
|
||||
"script to refresh it. Companion machine-readable CSV is `COMPAT_FULL.csv`,",
|
||||
"categorised remediation backlog is `BACKLOG.md`.",
|
||||
"",
|
||||
"## Sweep parameters",
|
||||
"",
|
||||
f"- Started: `{started_at.isoformat(timespec='seconds')}`",
|
||||
f"- Finished: `{finished_at.isoformat(timespec='seconds')}`",
|
||||
f"- Wall time: **{(finished_at - started_at).total_seconds():.0f}s**",
|
||||
f"- Outer concurrency: **{concurrency}**",
|
||||
f"- Per-integration pytest-xdist: **{'on' if use_xdist else 'off'}**",
|
||||
"- Plugin: `hass_client.testing.pytest_plugin` (in-process)",
|
||||
"",
|
||||
"## Discovery",
|
||||
"",
|
||||
"Walked `homeassistant/components/`, applied the discovery filters:",
|
||||
"",
|
||||
"| Filter | Skipped |",
|
||||
"| --- | ---: |",
|
||||
f"| No / invalid manifest | {discovery_stats.get('no_manifest', 0)} |",
|
||||
f"| `integration_type` in (`virtual`, `system`) | {discovery_stats.get('virtual_or_system', 0)} |",
|
||||
f"| Domain in `ALWAYS_MAIN` | {discovery_stats.get('always_main', 0)} |",
|
||||
f"| Ships a platform in `SANDBOX_INCOMPATIBLE_PLATFORMS` | {discovery_stats.get('incompatible_platform', 0)} |",
|
||||
f"| No `config_flow` in manifest | {discovery_stats.get('no_config_flow', 0)} |",
|
||||
f"| No `test_*.py` files | {discovery_stats.get('no_tests', 0)} |",
|
||||
f"| **Eligible (this sweep)** | **{discovery_stats.get('eligible', 0)}** |",
|
||||
"",
|
||||
"## Summary",
|
||||
"",
|
||||
f"- Integrations exercised: **{integration_total}**",
|
||||
f"- Fully passing: **{counts.get('pass', 0)}** ({integration_pass_rate:.2f}%)",
|
||||
f"- With failures: **{counts.get('issues', 0)}**",
|
||||
f"- Timeouts: **{counts.get('timeout', 0)}**",
|
||||
f"- Spawn errors: **{counts.get('error', 0)}**",
|
||||
f"- No tests collected: **{counts.get('no_tests', 0)}**",
|
||||
"",
|
||||
f"- Tests passed: **{totals['passed']}**",
|
||||
f"- Tests failed: **{totals['failed']}**",
|
||||
f"- Test errors: **{totals['errors']}**",
|
||||
f"- Tests skipped: **{totals['skipped']}**",
|
||||
f"- **Test-level pass rate: {pass_rate:.2f}%**",
|
||||
"",
|
||||
"## Per-integration results",
|
||||
"",
|
||||
"| integration | status | passed | failed | errors | skipped | dur (s) | bucket |",
|
||||
"| --- | --- | ---: | ---: | ---: | ---: | ---: | --- |",
|
||||
]
|
||||
for result in sorted(results, key=lambda r: r.integration):
|
||||
lines.append(
|
||||
f"| {result.integration} | {result.status} | {result.passed} | "
|
||||
f"{result.failed} | {result.errors} | {result.skipped} | "
|
||||
f"{result.duration:.1f} | {result.dominant_bucket or ''} |"
|
||||
)
|
||||
lines.append("")
|
||||
lines.append("Per-failure tracebacks are dumped under "
|
||||
"`${SANDBOX_ERRORS_DIR:-/tmp/sandbox_errors}/<integration>/`.")
|
||||
path.write_text("\n".join(lines) + "\n")
|
||||
|
||||
|
||||
async def _gather(
|
||||
integrations: list[str],
|
||||
*,
|
||||
concurrency: int,
|
||||
timeout: float,
|
||||
use_xdist: bool,
|
||||
errors_dir: Path,
|
||||
junit_dir: Path,
|
||||
) -> list[Result]:
|
||||
"""Run the per-integration pytest invocations with outer concurrency."""
|
||||
semaphore = asyncio.Semaphore(concurrency)
|
||||
results: list[Result] = []
|
||||
completed = 0
|
||||
total = len(integrations)
|
||||
start = time.monotonic()
|
||||
|
||||
async def _run_and_log(integration: str) -> Result:
|
||||
nonlocal completed
|
||||
result = await run_one(
|
||||
integration,
|
||||
semaphore=semaphore,
|
||||
timeout=timeout,
|
||||
use_xdist=use_xdist,
|
||||
errors_dir=errors_dir,
|
||||
junit_dir=junit_dir,
|
||||
)
|
||||
completed += 1
|
||||
elapsed = time.monotonic() - start
|
||||
rate = completed / elapsed if elapsed > 0 else 0.0
|
||||
eta_min = (total - completed) / rate / 60 if rate else 0.0
|
||||
print(
|
||||
f"[{completed}/{total}] {integration} -> {result.status} "
|
||||
f"({result.passed}p/{result.failed}f/{result.errors}e/{result.skipped}s) "
|
||||
f"in {result.duration:.1f}s | ETA: {eta_min:.0f}m",
|
||||
flush=True,
|
||||
)
|
||||
return result
|
||||
|
||||
tasks = [asyncio.create_task(_run_and_log(d)) for d in integrations]
|
||||
for task in asyncio.as_completed(tasks):
|
||||
results.append(await task)
|
||||
return results
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
"""Drive the full sweep."""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"integrations",
|
||||
nargs="*",
|
||||
help=(
|
||||
"Specific integration names. Defaults to every classifier-routable"
|
||||
" integration discovered in `homeassistant/components/`."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--baseline-37", action="store_true",
|
||||
help="Restrict to the 37-integration baseline list.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--concurrency", type=int, default=4,
|
||||
help="How many integrations to run in parallel (default: 4).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--timeout", type=float, default=300.0,
|
||||
help="Per-integration timeout in seconds (default: 300).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--xdist", action="store_true",
|
||||
help="Pass `-n auto` to per-integration pytest (default: off).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--csv", type=Path, default=DEFAULT_CSV,
|
||||
help="Where to write the per-integration CSV.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--report", type=Path, default=DEFAULT_REPORT_MD,
|
||||
help="Where to write the Markdown report.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--errors-dir", type=Path, default=ERRORS_DIR,
|
||||
help="Per-test error dump root (default: $SANDBOX_ERRORS_DIR or /tmp/sandbox_errors).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--junit-dir", type=Path, default=ERRORS_DIR / "_junit",
|
||||
help="Where to keep per-integration JUnit XML files.",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
args.errors_dir.mkdir(parents=True, exist_ok=True)
|
||||
args.junit_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if args.baseline_37 and args.integrations:
|
||||
print("--baseline-37 conflicts with explicit integrations.", file=sys.stderr)
|
||||
return 1
|
||||
if args.baseline_37:
|
||||
integrations = list(BASELINE_37)
|
||||
discovery_stats: dict[str, int] = {"eligible": len(integrations)}
|
||||
elif args.integrations:
|
||||
integrations = list(args.integrations)
|
||||
discovery_stats = {"eligible": len(integrations)}
|
||||
else:
|
||||
integrations, discovery_stats = discover_integrations()
|
||||
|
||||
if not integrations:
|
||||
print("No integrations to run.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(f"Running {len(integrations)} integrations "
|
||||
f"(concurrency={args.concurrency}, timeout={args.timeout:.0f}s, "
|
||||
f"xdist={'on' if args.xdist else 'off'})")
|
||||
|
||||
started_at = datetime.now()
|
||||
results = asyncio.run(_gather(
|
||||
integrations,
|
||||
concurrency=args.concurrency,
|
||||
timeout=args.timeout,
|
||||
use_xdist=args.xdist,
|
||||
errors_dir=args.errors_dir,
|
||||
junit_dir=args.junit_dir,
|
||||
))
|
||||
finished_at = datetime.now()
|
||||
results.sort(key=lambda r: r.integration)
|
||||
|
||||
write_csv(results, args.csv)
|
||||
write_report(
|
||||
results,
|
||||
path=args.report,
|
||||
discovery_stats=discovery_stats,
|
||||
started_at=started_at,
|
||||
finished_at=finished_at,
|
||||
concurrency=args.concurrency,
|
||||
use_xdist=args.xdist,
|
||||
)
|
||||
print(f"\nWrote {args.csv}")
|
||||
print(f"Wrote {args.report}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user