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:
Paulus Schoutsen
2026-07-07 15:12:23 -04:00
co-authored by Claude Opus 4.8
parent 63ead8828c
commit 5433c8a558
11 changed files with 16 additions and 3641 deletions
+4
View File
@@ -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
-646
View File
@@ -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
View File
@@ -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/`.
-38
View File
@@ -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 integration status passed failed errors skipped
2 input_boolean pass 18 0 0 0
3 input_button pass 15 0 0 0
4 input_datetime pass 28 0 0 0
5 input_number pass 24 0 0 0
6 input_select pass 26 0 0 0
7 input_text pass 23 0 0 0
8 counter pass 751 0 0 0
9 timer pass 877 0 0 0
10 schedule pass 387 0 0 0
11 zone pass 32 0 0 0
12 tag pass 12 0 0 0
13 group pass 392 0 0 0
14 person pass 34 0 0 0
15 scene pass 41 0 0 0
16 todo pass 281 0 0 0
17 automation pass 117 0 0 0
18 script pass 64 0 0 0
19 alert pass 18 0 0 0
20 template pass 2470 0 0 0
21 plant pass 11 0 0 0
22 proximity issues 27 1 0 0
23 min_max pass 20 0 0 0
24 statistics pass 56 0 0 0
25 utility_meter issues 94 1 0 0
26 derivative pass 76 0 0 0
27 integration pass 61 0 0 0
28 generic_thermostat pass 114 0 0 0
29 generic_hygrostat pass 76 0 0 0
30 history_stats pass 55 0 0 0
31 threshold pass 114 0 0 0
32 filter pass 32 0 0 0
33 mqtt_statestream pass 17 0 0 0
34 recorder pass 932 0 0 17
35 rest pass 128 0 0 0
36 logbook pass 106 0 0 0
37 command_line pass 78 0 0 0
38 trend pass 39 0 0 0
-808
View File
@@ -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 integration status passed failed errors skipped duration_s dominant_bucket
2 acaia pass 24 0 0 0 3.52
3 accuweather pass 38 0 0 0 5.08
4 acmeda pass 8 0 0 0 2.59
5 actron_air pass 49 0 0 0 5.25
6 adax pass 20 0 0 0 2.86
7 adguard pass 36 0 0 0 3.42
8 advantage_air pass 20 0 0 0 4.91
9 aemet issues 16 1 0 0 3.26
10 aftership pass 2 0 0 0 2.29
11 aidot pass 16 0 0 0 2.90
12 airgradient pass 47 0 0 0 4.70
13 airly issues 21 1 0 0 2.99
14 airnow issues 9 1 0 0 2.55
15 airobot pass 60 0 0 0 4.85
16 airos pass 62 0 0 0 4.89
17 airpatrol pass 25 0 0 0 3.19
18 airq issues 22 1 0 0 3.30
19 airthings pass 12 0 0 0 2.56
20 airthings_ble pass 38 0 0 0 4.13
21 airtouch4 pass 5 0 0 0 2.39
22 airtouch5 pass 5 0 0 0 2.45
23 airvisual issues 15 1 0 0 2.95
24 airvisual_pro issues 10 1 0 0 2.68
25 airzone issues 37 1 0 0 5.58
26 airzone_cloud issues 26 1 0 0 4.95
27 aladdin_connect issues 32 1 0 0 3.78
28 alarmdecoder pass 8 0 0 0 2.40
29 alexa_devices issues 72 1 0 0 7.34
30 altruist pass 11 0 0 0 2.61
31 amberelectric pass 39 0 0 0 3.62
32 ambient_network pass 7 0 0 0 2.76
33 ambient_station issues 3 1 0 0 2.59
34 analytics_insights pass 20 0 0 0 3.11
35 androidtv pass 79 0 0 0 5.23
36 androidtv_remote pass 40 0 0 0 4.60
37 anglian_water pass 14 0 0 0 3.52
38 anova pass 11 0 0 0 2.65
39 anthemav pass 11 0 0 0 2.59
40 aosmith pass 33 0 0 0 3.64
41 apcupsd pass 44 0 0 0 4.29
42 apple_tv pass 51 0 0 0 4.60
43 aprilaire pass 3 0 0 0 2.51
44 apsystems pass 13 0 0 0 3.03
45 aquacell pass 13 0 0 0 2.89
46 aranet pass 19 0 0 0 3.42
47 arcam_fmj pass 85 0 0 0 5.84
48 arve pass 5 0 0 0 2.70
49 aseko_pool_live pass 13 0 0 0 2.80
50 asuswrt pass 60 0 0 0 4.68
51 atag pass 14 0 0 0 2.94
52 aurora pass 4 0 0 0 2.48
53 aurora_abb_powerone pass 7 0 0 0 6.85
54 aussie_broadband pass 14 0 0 0 2.68
55 autarco pass 13 0 0 0 2.73
56 autoskope pass 22 0 0 0 2.91
57 avea pass 20 0 0 0 3.12
58 awair pass 24 0 0 0 2.73
59 aws_s3 pass 51 0 0 0 4.96
60 azure_data_explorer pass 18 0 0 0 2.75
61 azure_devops pass 20 0 0 0 2.82
62 azure_event_hub pass 21 0 0 0 2.65
63 azure_storage pass 25 0 0 0 3.70
64 backblaze_b2 pass 77 0 0 0 5.64
65 baf pass 8 0 0 0 2.46
66 balboa pass 42 0 0 0 5.47
67 bang_olufsen issues 100 2 0 0 35.95
68 bayesian pass 48 0 0 0 3.16
69 blebox pass 117 0 0 0 8.95
70 blue_current pass 28 0 0 0 3.03
71 bluemaestro pass 11 0 0 0 2.77
72 bluesound pass 39 0 0 0 4.73
73 bluetooth issues 234 1 0 1 9.76
74 bond pass 141 0 0 0 6.29
75 bosch_alarm pass 121 0 0 0 11.87
76 bosch_shc pass 16 0 0 0 2.66
77 braviatv issues 19 1 0 0 2.74
78 bring pass 72 0 0 0 6.03
79 broadlink pass 104 0 0 0 4.81
80 brother pass 33 0 0 0 7.24
81 brottsplatskartan pass 4 0 0 0 2.30
82 brunt pass 8 0 0 0 2.39
83 bryant_evolution pass 24 0 0 0 3.09
84 bsblan pass 127 0 0 0 11.91
85 bthome pass 107 0 0 0 6.98
86 caldav pass 109 0 0 0 6.70
87 cambridge_audio pass 52 0 0 0 7.84
88 casper_glow pass 67 0 0 0 6.44
89 cast pass 86 0 0 0 6.63
90 ccm15 pass 8 0 0 0 2.52
91 centriconnect pass 10 0 0 0 2.49
92 cert_expiry pass 18 0 0 0 2.82
93 chacon_dio pass 16 0 0 0 2.83
94 chess_com issues 8 1 0 0 2.82
95 cielo_home pass 7 0 0 0 18.27
96 cloudflare pass 14 0 0 0 2.53
97 cloudflare_r2 pass 59 0 0 0 4.67
98 co2signal issues 15 1 0 0 2.87
99 coinbase issues 15 1 0 0 2.59
100 color_extractor pass 9 0 0 0 4.47
101 comelit issues 93 2 0 0 8.99
102 compit pass 65 0 0 0 6.46
103 control4 pass 54 0 0 0 4.60
104 cookidoo pass 52 0 0 0 5.41
105 coolmaster pass 37 0 0 0 3.46
106 cpuspeed pass 8 0 0 0 2.38
107 crownstone pass 11 0 0 0 2.68
108 cync pass 19 0 0 0 2.65
109 daikin pass 31 0 0 0 3.09
110 data_grand_lyon issues 40 2 0 0 3.29
111 datadog pass 12 0 0 0 2.41
112 deako pass 13 0 0 0 2.86
113 deconz issues 172 1 0 1 12.86
114 decora_wifi pass 13 0 0 0 3.01
115 deluge pass 7 0 0 0 2.30
116 denon_rs232 pass 23 0 0 0 3.07
117 denonavr pass 16 0 0 0 2.87
118 derivative pass 76 0 0 0 4.62
119 devialet pass 13 0 0 0 2.63
120 devolo_home_control issues 41 1 0 0 4.24
121 devolo_home_network issues 51 1 0 0 6.02
122 dexcom pass 10 0 0 0 2.45
123 dialogflow pass 17 0 0 0 3.17
124 directv pass 24 0 0 0 3.07
125 discord pass 11 0 0 0 2.51
126 discovergy pass 25 0 0 0 3.19
127 dlink pass 15 0 0 0 2.57
128 dlna_dmr pass 72 0 0 0 13.95
129 dlna_dms pass 55 0 0 0 7.98
130 dnsip pass 21 0 0 0 2.72
131 dormakaba_dkey pass 14 0 0 0 2.86
132 downloader pass 21 0 0 0 2.63
133 drop_connect pass 30 0 0 0 3.78
134 dropbox pass 29 0 0 0 3.63
135 droplet pass 16 0 0 0 3.18
136 dsmr pass 75 0 0 0 4.57
137 dsmr_reader issues 8 1 0 0 2.77
138 duckdns pass 18 0 0 0 2.68
139 duco pass 61 0 0 0 7.51
140 dunehd pass 6 0 0 0 2.38
141 duotecno pass 5 0 0 0 2.35
142 dwd_weather_warnings pass 11 0 0 0 2.47
143 dynalite pass 33 0 0 0 3.44
144 eafm pass 18 0 0 0 2.64
145 earn_e_p1 pass 25 0 0 0 2.87
146 easyenergy pass 70 0 0 0 5.17
147 ecobee pass 60 0 0 0 3.53
148 ecoforest pass 4 0 0 0 2.35
149 econet pass 4 0 0 0 2.33
150 ecovacs issues 74 2 0 0 6.74
151 ecowitt pass 1 0 0 0 2.32
152 edl21 pass 2 0 0 0 2.29
153 efergy pass 12 0 0 0 2.54
154 egauge pass 16 0 0 0 2.81
155 eheimdigital issues 79 1 0 0 8.30
156 ekeybionyx pass 13 0 0 0 7.73
157 electrasmart pass 6 0 0 0 2.33
158 electric_kiwi pass 18 0 0 0 3.04
159 elgato pass 36 0 0 0 3.88
160 elkm1 pass 45 0 0 0 3.43
161 elmax pass 29 0 0 0 2.85
162 elvia pass 9 0 0 0 2.72
163 emoncms pass 16 0 0 0 2.71
164 emonitor pass 7 0 0 0 2.38
165 emulated_roku pass 7 0 0 0 2.39
166 energenie_power_sockets pass 13 0 0 0 2.61
167 energyid pass 81 0 0 0 3.92
168 energyzero pass 41 0 0 0 3.82
169 enigma2 pass 26 0 0 0 3.30
170 enocean pass 14 0 0 0 2.77
171 enphase_envoy issues 231 5 0 0 24.65
172 epic_games_store pass 20 0 0 0 2.68
173 epion pass 4 0 0 0 2.33
174 epson pass 5 0 0 0 2.46
175 eq3btsmart pass 4 0 0 0 2.56
176 escea pass 3 0 0 0 2.32
177 essent pass 14 0 0 0 2.69
178 eufylife_ble pass 10 0 0 0 2.79
179 eurotronic_cometblue pass 39 0 0 0 4.04
180 evil_genius_labs pass 10 0 0 0 2.53
181 faa_delays pass 4 0 0 0 2.33
182 fastdotcom pass 8 0 0 0 2.50
183 feedreader pass 30 0 0 0 3.02
184 fibaro pass 45 0 0 0 3.93
185 file pass 26 0 0 0 2.84
186 filesize pass 13 0 0 0 2.58
187 filter pass 32 0 0 0 4.13
188 fing pass 17 0 0 0 2.88
189 firefly_iii issues 25 1 0 0 3.30
190 fireservicerota pass 5 0 0 0 2.35
191 fitbit pass 60 0 0 0 6.46
192 fivem pass 5 0 0 0 2.36
193 fjaraskupan pass 11 0 0 0 2.87
194 flexit_bacnet pass 19 0 0 0 2.75
195 flipr pass 18 0 0 0 2.79
196 flo pass 10 0 0 0 2.73
197 flume pass 11 0 0 0 2.50
198 fluss pass 16 0 0 0 2.71
199 flux_led pass 82 0 0 0 6.59
200 folder_watcher pass 10 0 0 0 2.63
201 forecast_solar pass 28 0 0 0 2.97
202 forked_daapd pass 36 0 0 0 4.60
203 freedompro pass 38 0 0 0 4.48
204 freshr issues 28 1 0 0 3.42
205 fressnapf_tracker pass 45 0 0 0 4.49
206 fritz issues 138 1 0 0 10.15
207 fritzbox pass 132 0 0 0 8.57
208 fritzbox_callmonitor pass 12 0 0 0 2.45
209 fronius issues 35 1 0 0 3.89
210 frontier_silicon pass 22 0 0 0 2.64
211 fujitsu_fglair pass 25 0 0 0 3.56
212 fumis pass 72 0 0 0 5.55
213 fyta issues 33 1 0 0 3.71
214 garages_amsterdam pass 6 0 0 0 2.45
215 gardena_bluetooth pass 40 0 0 0 5.17
216 gdacs pass 8 0 0 0 2.70
217 generic_hygrostat pass 76 0 0 0 4.01
218 generic_thermostat pass 114 0 0 0 5.61
219 geniushub pass 23 0 0 0 2.89
220 gentex_homelink pass 13 0 0 0 2.75
221 geo_json_events pass 5 0 0 0 2.55
222 geocaching pass 5 0 0 0 2.81
223 geofency pass 5 0 0 0 3.00
224 geonetnz_quakes pass 9 0 0 0 2.78
225 geonetnz_volcano pass 7 0 0 0 2.64
226 ghost pass 27 0 0 0 3.44
227 gios issues 17 1 0 0 3.07
228 github pass 17 0 0 0 2.90
229 glances pass 16 0 0 0 2.77
230 goalzero pass 15 0 0 0 2.75
231 gogogate2 pass 15 0 0 0 2.67
232 goodwe issues 5 1 0 0 2.59
233 google issues 136 1 0 0 8.22
234 google_air_quality pass 19 0 0 0 2.77
235 google_assistant_sdk pass 41 0 0 0 3.71
236 google_drive pass 40 0 0 0 4.21
237 google_mail pass 28 0 0 0 3.57
238 google_photos pass 35 0 0 0 3.52
239 google_sheets pass 24 0 0 0 3.06
240 google_tasks pass 42 0 0 0 4.20
241 google_travel_time pass 44 0 0 0 3.65
242 google_weather issues 44 1 0 0 3.85
243 govee_ble pass 20 0 0 0 3.21
244 govee_light_local pass 23 0 0 0 3.02
245 gpsd pass 2 0 0 0 2.37
246 gpslogger pass 3 0 0 1 2.91
247 gree pass 123 0 0 0 7.31
248 green_planet_energy pass 11 0 0 0 2.75
249 group pass 392 0 0 0 24.47
250 growatt_server issues 140 2 0 0 14.23
251 guardian issues 11 1 0 0 2.54
252 guntamatic pass 15 0 0 0 2.61
253 habitica pass 382 0 0 0 38.88
254 hanna pass 5 0 0 0 2.41
255 harmony pass 22 0 0 0 2.79
256 hdfury pass 50 0 0 0 6.49
257 hegel pass 12 0 0 0 2.51
258 heos issues 147 2 0 0 8.10
259 here_travel_time pass 39 0 0 0 3.12
260 hisense_aehw4a1 pass 4 0 0 0 2.32
261 history_stats pass 55 0 0 0 7.60
262 hive pass 19 0 0 0 2.85
263 hko pass 4 0 0 0 2.38
264 hlk_sw16 pass 4 0 0 0 2.29
265 holiday pass 34 0 0 0 3.70
266 home_connect pass 311 0 0 0 15.93
267 homeassistant_connect_zbt2 issues 24 1 0 0 4.13
268 homeassistant_sky_connect pass 36 0 0 0 4.29
269 homee pass 199 0 0 0 16.24
270 homekit pass 372 0 0 0 13.61
271 homematicip_cloud pass 182 0 0 0 23.98
272 homevolt pass 33 0 0 0 3.29
273 homewizard pass 149 0 0 0 10.98
274 homeworks pass 38 0 0 0 4.28
275 honeywell pass 44 0 0 0 4.33
276 honeywell_string_lights pass 7 0 0 0 2.39
277 hr_energy_qube pass 28 0 0 0 4.07
278 html5 issues 64 1 0 0 5.72
279 huawei_lte pass 36 0 0 0 3.65
280 hue pass 113 0 0 0 20.05
281 hue_ble pass 19 0 0 0 3.05
282 huisbaasje pass 13 0 0 0 2.47
283 hunterdouglas_powerview pass 39 0 0 0 3.29
284 husqvarna_automower issues 93 1 0 0 14.73
285 husqvarna_automower_ble pass 42 0 0 0 5.09
286 huum pass 34 0 0 0 3.35
287 hvv_departures pass 9 0 0 0 2.32
288 hydrawise pass 35 0 0 0 4.25
289 hypontech pass 17 0 0 0 2.66
290 ialarm pass 7 0 0 0 2.30
291 iaqualink pass 28 0 0 0 2.86
292 ibeacon pass 24 0 0 0 3.53
293 icloud pass 17 0 0 0 2.47
294 idasen_desk pass 30 0 0 0 3.75
295 idrive_e2 pass 65 0 0 0 4.66
296 ifttt pass 1 0 0 0 2.47
297 igloohome pass 8 0 0 0 2.37
298 imap pass 159 0 0 0 12.42
299 imeon_inverter pass 17 0 0 0 2.94
300 imgw_pib issues 15 1 0 0 2.79
301 immich issues 54 1 0 0 3.82
302 improv_ble pass 38 0 0 0 3.69
303 incomfort pass 50 0 0 0 4.05
304 indevolt pass 83 0 0 0 6.18
305 inels pass 28 0 0 0 3.04
306 influxdb pass 145 0 0 0 6.03
307 inkbird pass 16 0 0 0 2.99
308 insteon pass 79 0 0 0 18.55
309 integration pass 61 0 0 0 4.02
310 intelliclima pass 28 0 0 0 3.21
311 intellifire pass 29 0 0 0 4.24
312 iometer pass 17 0 0 0 2.77
313 ios pass 3 0 0 0 2.32
314 iotawatt pass 9 0 0 0 2.45
315 iotty pass 24 0 0 0 3.17
316 ipma pass 15 0 0 0 2.73
317 ipp pass 29 0 0 0 3.05
318 iqvia issues 4 1 0 0 2.40
319 irm_kmi pass 13 0 0 0 2.69
320 iron_os pass 95 0 0 0 8.95
321 iskra pass 13 0 0 0 2.45
322 islamic_prayer_times pass 45 0 0 0 3.82
323 israel_rail pass 9 0 0 0 2.56
324 iss pass 17 0 0 0 2.56
325 ista_ecotrend pass 49 0 0 0 4.07
326 isy994 pass 31 0 0 0 3.06
327 ituran pass 19 0 0 0 2.96
328 izone pass 10 0 0 0 2.55
329 jellyfin pass 44 0 0 0 8.58
330 jewish_calendar pass 123 0 0 0 11.89
331 justnimbus pass 7 0 0 0 2.37
332 jvc_projector pass 31 0 0 0 5.73
333 kaleidescape pass 19 0 0 0 4.00
334 keenetic_ndms2 pass 14 0 0 0 2.38
335 kegtron pass 12 0 0 0 2.73
336 keymitt_ble pass 7 0 0 0 2.58
337 kiosker pass 43 0 0 0 3.31
338 kmtronic pass 11 0 0 0 2.48
339 knocki pass 17 0 0 0 2.77
340 knx pass 387 0 0 0 28.04
341 kodi pass 21 0 0 0 2.77
342 kostal_plenticore issues 38 1 0 0 4.10
343 kraken pass 11 0 0 0 2.85
344 kulersky pass 17 0 0 0 2.94
345 lacrosse_view issues 28 1 0 0 3.09
346 lamarzocco pass 94 0 0 0 14.30
347 lametric pass 55 0 0 0 5.57
348 landisgyr_heat_meter pass 10 0 0 0 2.77
349 lastfm pass 15 0 0 0 2.52
350 launch_library pass 2 0 0 0 2.28
351 laundrify pass 18 0 0 0 2.79
352 lcn pass 149 0 0 0 13.39
353 ld2410_ble pass 6 0 0 0 2.56
354 leaone pass 6 0 0 0 2.56
355 led_ble pass 9 0 0 0 2.65
356 lektrico pass 13 0 0 0 2.78
357 letpot pass 40 0 0 0 4.13
358 lg_infrared pass 61 0 0 0 4.33
359 lg_netcast pass 22 0 0 0 3.46
360 lg_soundbar pass 11 0 0 0 2.73
361 lg_thinq pass 29 0 0 0 4.08
362 libre_hardware_monitor pass 26 0 0 0 3.19
363 lichess pass 8 0 0 0 2.48
364 lidarr pass 12 0 0 0 2.60
365 liebherr pass 76 0 0 0 5.72
366 lifx pass 72 0 0 0 5.42
367 linkplay pass 9 0 0 0 2.49
368 litejet pass 32 0 0 0 3.77
369 litterrobot pass 63 0 0 0 5.89
370 livisi pass 4 0 0 0 2.36
371 local_calendar pass 50 0 0 0 5.05
372 local_ip pass 3 0 0 0 2.34
373 local_todo pass 55 0 0 0 5.56
374 locative pass 5 0 0 1 2.99
375 lojack pass 16 0 0 0 2.92
376 london_underground pass 12 0 0 0 2.55
377 lookin pass 7 0 0 0 2.37
378 loqed pass 17 0 0 0 2.98
379 luftdaten pass 11 0 0 0 2.59
380 lunatone pass 40 0 0 0 3.78
381 lupusec pass 5 0 0 0 2.38
382 lutron pass 42 0 0 0 3.76
383 lutron_caseta pass 52 0 0 0 4.93
384 lyric pass 4 0 0 0 2.40
385 madvr issues 16 1 0 0 3.19
386 mailgun pass 5 0 0 0 2.69
387 marantz_infrared pass 36 0 0 0 3.44
388 mastodon issues 82 1 0 0 26.20
389 matter pass 372 0 0 1 68.76
390 mcp pass 45 0 0 0 4.15
391 mcp_server pass 47 0 0 0 5.93
392 mealie pass 94 0 0 0 7.84
393 meater pass 10 0 0 0 2.54
394 medcom_ble pass 9 0 0 0 2.62
395 media_extractor pass 20 0 0 0 7.61
396 melcloud issues 23 1 0 0 2.79
397 melnor pass 17 0 0 0 3.53
398 met pass 18 0 0 0 2.57
399 met_eireann pass 10 0 0 0 2.53
400 meteo_france pass 6 0 0 0 2.45
401 meteo_lt pass 7 0 0 0 2.47
402 meteoclimatic pass 3 0 0 0 2.36
403 metoffice pass 18 0 0 0 3.12
404 microbees pass 9 0 0 0 2.54
405 miele pass 115 0 0 0 10.16
406 mikrotik pass 21 0 0 0 2.75
407 mill pass 31 0 0 0 4.49
408 min_max pass 20 0 0 0 2.58
409 minecraft_server pass 40 0 0 0 3.49
410 mitsubishi_comfort pass 66 0 0 0 5.31
411 moat pass 11 0 0 0 2.79
412 mobile_app pass 135 0 0 0 13.24
413 modem_callerid pass 9 0 0 0 2.56
414 modern_forms issues 29 1 0 0 3.44
415 moehlenhoff_alpha2 pass 8 0 0 0 2.41
416 mold_indicator pass 37 0 0 0 3.05
417 monarch_money pass 5 0 0 0 2.60
418 monoprice pass 23 0 0 0 3.24
419 monzo pass 11 0 0 0 2.72
420 moon pass 11 0 0 0 2.46
421 mopeka pass 14 0 0 0 2.90
422 motion_blinds pass 12 0 0 0 2.53
423 motionblinds_ble issues 42 1 0 0 6.28
424 motionmount pass 38 0 0 0 3.53
425 mpd pass 7 0 0 0 2.90
426 mta pass 27 0 0 0 2.96
427 mullvad pass 4 0 0 0 2.30
428 music_assistant pass 127 0 0 0 9.42
429 mutesync pass 5 0 0 0 2.32
430 myneomitis pass 43 0 0 0 4.11
431 mysensors pass 61 0 0 0 5.08
432 mystrom pass 23 0 0 0 2.76
433 myuplink pass 38 0 0 0 4.83
434 nam pass 39 0 0 0 3.38
435 namecheapdns pass 20 0 0 0 2.66
436 nanoleaf pass 30 0 0 0 2.86
437 nasweb pass 8 0 0 0 2.44
438 nederlandse_spoorwegen pass 29 0 0 0 3.38
439 ness_alarm pass 39 0 0 0 3.04
440 netgear pass 10 0 0 0 2.41
441 netgear_lte pass 11 0 0 0 2.63
442 nexia pass 21 0 0 0 3.55
443 nextbus pass 28 0 0 0 2.73
444 nextcloud pass 17 0 0 0 2.93
445 nextdns issues 52 1 0 0 5.83
446 nfandroidtv pass 8 0 0 0 2.39
447 nibe_heatpump pass 64 0 0 0 4.34
448 nice_go issues 43 1 0 0 4.51
449 nightscout pass 11 0 0 0 2.52
450 niko_home_control pass 32 0 0 0 3.78
451 nina pass 21 0 0 0 3.17
452 nintendo_parental_controls pass 30 0 0 0 3.33
453 nmap_tracker pass 13 0 0 0 2.57
454 nmbs pass 5 0 0 0 2.50
455 nobo_hub pass 59 0 0 0 4.63
456 nordpool pass 37 0 0 0 4.93
457 notion issues 7 1 0 0 2.55
458 novy_cooker_hood issues 28 1 0 0 3.15
459 nrgkick pass 87 0 0 0 5.68
460 ntfy pass 85 0 0 0 6.82
461 nuheat pass 9 0 0 0 2.46
462 nuki pass 14 0 0 0 2.61
463 nut pass 78 0 0 0 4.64
464 nws pass 30 0 0 0 3.25
465 nyt_games pass 10 0 0 0 2.60
466 nzbget pass 10 0 0 0 2.46
467 obihai pass 5 0 0 0 2.35
468 ohme pass 34 0 0 0 4.42
469 omie pass 19 0 0 0 2.86
470 omnilogic pass 8 0 0 0 2.39
471 ondilo_ico pass 17 0 0 0 2.98
472 onedrive pass 79 0 0 0 6.52
473 onedrive_for_business pass 38 0 0 0 4.62
474 onewire pass 33 0 0 0 3.51
475 onkyo pass 48 0 0 0 4.18
476 open_meteo pass 5 0 0 0 2.70
477 opendisplay pass 67 0 0 0 6.63
478 openevse pass 40 0 0 0 4.50
479 openexchangerates pass 9 0 0 0 2.38
480 opengarage pass 6 0 0 0 2.37
481 openhome pass 11 0 0 0 2.58
482 openrgb pass 69 0 0 0 4.65
483 opensky pass 12 0 0 0 2.64
484 opentherm_gw pass 29 0 0 0 5.67
485 openuv issues 10 1 0 0 2.69
486 openweathermap pass 15 0 0 0 2.65
487 opower issues 35 1 0 0 5.84
488 oralb pass 14 0 0 0 2.89
489 orvibo pass 15 0 0 0 2.60
490 osoenergy pass 17 0 0 0 2.95
491 otbr pass 103 0 0 0 7.85
492 otp pass 7 0 0 0 2.44
493 ouman_eh_800 pass 20 0 0 0 3.07
494 ourgroceries pass 21 0 0 0 2.81
495 overkiz pass 181 0 0 0 9.91
496 overseerr pass 45 0 0 0 4.83
497 ovo_energy pass 7 0 0 0 2.39
498 owntracks pass 71 0 0 0 5.75
499 p1_monitor issues 11 2 0 0 2.73
500 paj_gps pass 19 0 0 0 3.06
501 palazzetti pass 17 0 0 0 2.99
502 panasonic_viera pass 32 0 0 0 2.99
503 paperless_ngx pass 41 0 0 0 3.57
504 peblar pass 62 0 0 0 5.20
505 peco pass 33 0 0 0 2.98
506 pegel_online issues 9 1 0 0 2.60
507 permobil pass 9 0 0 0 2.48
508 pglab pass 21 0 0 0 3.50
509 philips_js issues 15 1 0 0 3.73
510 pi_hole issues 25 1 0 0 3.38
511 picnic pass 40 0 0 0 3.35
512 ping pass 21 0 0 0 2.92
513 pjlink pass 29 0 0 0 3.31
514 plaato pass 13 0 0 0 2.95
515 playstation_network pass 68 0 0 0 6.66
516 plex pass 53 0 0 0 6.67
517 plugwise pass 86 0 0 0 8.26
518 point pass 5 0 0 0 2.47
519 pooldose pass 75 0 0 0 5.31
520 poolsense pass 5 0 0 0 2.36
521 portainer issues 86 1 0 0 12.95
522 powerfox pass 22 0 0 0 3.04
523 powerfox_local pass 21 0 0 0 2.87
524 powerwall pass 37 0 0 0 3.57
525 prana pass 37 0 0 0 3.77
526 private_ble_device pass 21 0 0 0 3.29
527 probe_plus pass 6 0 0 0 2.58
528 profiler pass 13 0 0 0 2.57
529 progettihwsw pass 4 0 0 0 2.35
530 prowl pass 24 0 0 0 2.80
531 proximity issues 27 1 0 0 3.03
532 proxmoxve issues 103 1 0 0 9.21
533 ps4 pass 41 0 0 0 3.33
534 ptdevices pass 7 0 0 0 2.41
535 pterodactyl pass 14 0 0 0 2.66
536 pure_energie pass 8 0 0 0 2.46
537 purpleair issues 19 1 0 0 3.03
538 pushbullet pass 17 0 0 0 2.62
539 pushover pass 16 0 0 0 2.47
540 pvoutput pass 17 0 0 0 2.75
541 pvpc_hourly_pricing pass 2 0 0 0 2.38
542 pyload pass 67 0 0 0 4.55
543 qbittorrent pass 8 0 0 0 2.54
544 qbus pass 25 0 0 0 4.01
545 qingping pass 15 0 0 0 2.99
546 qnap pass 6 0 0 0 2.39
547 qnap_qsw pass 18 0 0 0 3.07
548 rabbitair pass 7 0 0 0 2.40
549 rachio pass 6 0 0 0 2.52
550 radarr pass 32 0 0 0 3.90
551 radio_browser pass 10 0 0 0 2.58
552 radiotherm pass 7 0 0 0 2.36
553 rainbird pass 70 0 0 0 4.30
554 rainforest_eagle pass 12 0 0 0 2.46
555 rainforest_raven issues 19 2 0 0 3.17
556 rainmachine issues 19 2 0 0 2.88
557 random pass 9 0 0 0 2.41
558 rapt_ble pass 11 0 0 0 2.75
559 rdw pass 10 0 0 0 2.58
560 recollect_waste issues 3 1 0 0 2.50
561 redgtech pass 18 0 0 0 2.77
562 refoss pass 2 0 0 0 2.29
563 rehlko pass 16 0 0 0 2.90
564 remote_calendar pass 44 0 0 0 3.94
565 renault pass 104 0 0 0 5.68
566 renson pass 3 0 0 0 2.29
567 rfxtrx pass 89 0 0 0 7.52
568 rhasspy pass 3 0 0 0 2.28
569 ridwell issues 13 1 0 0 2.69
570 risco pass 69 0 0 0 4.26
571 rituals_perfume_genie pass 25 0 0 0 3.10
572 roborock pass 183 0 0 0 18.48
573 roku pass 67 0 0 0 6.53
574 romy pass 6 0 0 0 2.38
575 roomba pass 26 0 0 0 2.69
576 roon pass 5 0 0 0 2.34
577 route_b_smart_meter pass 7 0 0 0 2.61
578 rova pass 11 0 0 0 2.44
579 rpi_power pass 6 0 0 0 2.33
580 ruckus_unleashed pass 29 0 0 0 2.80
581 russound_rio pass 50 0 0 0 6.05
582 ruuvi_gateway pass 5 0 0 0 2.46
583 ruuvitag_ble pass 13 0 0 0 2.75
584 rympro pass 7 0 0 0 2.28
585 sabnzbd pass 19 0 0 0 2.93
586 samsung_infrared pass 18 0 0 0 2.74
587 samsungtv issues 166 3 0 0 13.46
588 sanix pass 6 0 0 0 2.35
589 satel_integra pass 89 0 0 0 7.63
590 saunum pass 68 0 0 0 4.99
591 schlage pass 49 0 0 0 4.78
592 scrape issues 37 1 0 0 3.12
593 screenlogic issues 33 1 0 0 3.84
594 season pass 21 0 0 0 2.91
595 sense pass 19 0 0 0 3.20
596 sensibo pass 69 0 0 0 8.44
597 sensirion_ble pass 11 0 0 0 2.74
598 sensorpro pass 11 0 0 0 2.74
599 sensorpush pass 11 0 0 0 2.75
600 sensorpush_cloud pass 5 0 0 0 2.45
601 sensoterra pass 5 0 0 0 2.38
602 sentry pass 24 0 0 0 2.52
603 senz pass 21 0 0 0 3.05
604 seventeentrack pass 16 0 0 0 2.61
605 sfr_box pass 26 0 0 0 2.85
606 sftp_storage pass 34 0 0 0 8.68
607 sharkiq pass 42 0 0 0 3.25
608 shelly pass 636 0 0 0 45.69
609 shopping_list pass 60 0 0 0 4.74
610 sia pass 21 0 0 0 2.65
611 simplefin pass 12 0 0 0 2.68
612 simplepush pass 5 0 0 0 2.32
613 simplisafe issues 15 1 0 0 2.98
614 sky_remote pass 9 0 0 0 2.40
615 slack pass 13 0 0 0 2.44
616 sleep_as_android pass 44 0 0 0 4.54
617 sleepiq pass 33 0 0 0 4.94
618 slide_local issues 48 1 0 0 4.02
619 slimproto pass 2 0 0 0 2.34
620 sma issues 33 1 0 0 3.82
621 smappee pass 20 0 0 0 2.72
622 smarla pass 37 0 0 0 4.23
623 smart_meter_texas pass 16 0 0 0 2.58
624 smartthings pass 340 0 0 0 70.72
625 smarttub pass 40 0 0 0 4.88
626 smarty pass 12 0 0 0 2.78
627 smhi pass 20 0 0 0 3.39
628 smlight pass 98 0 0 0 7.10
629 snapcast pass 18 0 0 0 3.34
630 snoo pass 21 0 0 0 3.43
631 snooz pass 35 0 0 0 4.87
632 solaredge pass 62 0 0 0 11.00
633 solarlog issues 25 1 0 0 3.29
634 solarman pass 17 0 0 0 2.79
635 solax pass 3 0 0 0 2.33
636 soma pass 7 0 0 0 2.30
637 somfy_mylink pass 11 0 0 0 2.41
638 sonarr pass 56 0 0 0 9.69
639 songpal pass 26 0 0 0 3.03
640 sonos pass 174 0 0 0 18.92
641 soundtouch pass 31 0 0 0 3.29
642 speedtestdotnet pass 8 0 0 0 2.37
643 splunk pass 36 0 0 0 2.94
644 spotify pass 70 0 0 0 8.97
645 sql pass 80 0 0 0 6.49
646 squeezebox pass 129 0 0 0 12.83
647 srp_energy pass 15 0 0 0 2.70
648 starline pass 4 0 0 0 2.27
649 starlink pass 8 0 0 0 2.69
650 statistics pass 56 0 0 0 4.17
651 steam_online pass 14 0 0 0 2.48
652 steamist pass 23 0 0 0 2.93
653 stiebel_eltron pass 9 0 0 0 2.75
654 stookwijzer pass 12 0 0 0 2.61
655 streamlabswater pass 6 0 0 0 2.38
656 subaru pass 59 0 0 0 4.58
657 suez_water pass 19 0 0 0 4.18
658 sun pass 27 0 0 1 4.86
659 sunricher_dali pass 50 0 0 0 5.83
660 sunweg pass 1 0 0 0 2.23
661 surepetcare pass 15 0 0 0 2.74
662 swiss_public_transport pass 36 0 0 0 3.10
663 switch_as_x pass 176 0 0 0 10.02
664 switchbee pass 6 0 0 0 2.34
665 switchbot issues 352 1 0 0 19.66
666 switchbot_cloud pass 134 0 0 0 10.81
667 switcher_kis issues 76 1 0 0 7.69
668 syncthing pass 5 0 0 0 2.30
669 syncthru pass 9 0 0 0 2.59
670 system_bridge pass 39 0 0 0 4.46
671 systemmonitor issues 34 2 0 0 4.87
672 systemnexa2 pass 34 0 0 0 3.57
673 tado pass 40 0 0 0 4.67
674 tailscale pass 14 0 0 0 2.75
675 tailwind pass 36 0 0 0 3.30
676 tami4 pass 14 0 0 0 2.56
677 tankerkoenig issues 20 1 0 0 2.84
678 tautulli pass 8 0 0 0 2.35
679 technove pass 40 0 0 0 3.71
680 tedee pass 41 0 0 0 4.48
681 telegram_bot pass 123 0 0 0 13.16
682 teleinfo pass 24 0 0 0 3.22
683 tellduslive pass 15 0 0 0 2.41
684 teltonika pass 50 0 0 0 3.79
685 template pass 2470 0 0 0 60.07
686 tesla_fleet pass 153 0 0 0 12.29
687 tesla_wall_connector pass 12 0 0 0 2.47
688 teslemetry pass 158 0 0 0 16.84
689 tessie pass 67 0 0 0 4.46
690 thermobeacon pass 11 0 0 0 2.72
691 thermopro pass 18 0 0 0 3.01
692 thethingsnetwork pass 8 0 0 0 2.40
693 thread pass 65 0 0 0 4.17
694 threshold pass 114 0 0 0 4.14
695 tibber pass 92 0 0 0 13.32
696 tile pass 11 0 0 0 2.50
697 tilt_ble pass 11 0 0 0 2.79
698 tilt_pi pass 6 0 0 0 2.43
699 time_date pass 18 0 0 0 2.78
700 tod pass 32 0 0 0 3.25
701 todoist pass 50 0 0 0 4.23
702 togrill pass 62 0 0 0 5.73
703 tolo pass 7 0 0 0 2.35
704 tomorrowio pass 21 0 0 0 3.08
705 toon pass 10 0 0 0 2.71
706 totalconnect pass 66 0 0 0 11.65
707 touchline pass 8 0 0 0 2.52
708 touchline_sl pass 15 0 0 0 2.71
709 tplink_omada issues 52 1 0 0 4.67
710 traccar pass 5 0 0 1 2.90
711 traccar_server pass 12 0 0 0 2.88
712 tractive issues 48 1 0 0 4.03
713 tradfri pass 91 0 0 0 6.36
714 trafikverket_ferry pass 13 0 0 0 2.52
715 trafikverket_train pass 41 0 0 0 3.14
716 trafikverket_weatherstation pass 16 0 0 0 2.53
717 trane pass 39 0 0 0 3.98
718 transmission pass 75 0 0 0 4.60
719 trend pass 39 0 0 0 3.25
720 triggercmd pass 5 0 0 0 2.37
721 trmnl pass 36 0 0 0 3.72
722 twentemilieu pass 17 0 0 0 2.87
723 twilio pass 1 0 0 0 2.57
724 twinkly issues 25 1 0 0 4.12
725 twitch pass 16 0 0 0 4.22
726 uhoo pass 24 0 0 0 2.99
727 ukraine_alarm pass 11 0 0 0 2.43
728 unifi issues 158 1 0 0 12.39
729 unifi_access pass 155 0 0 0 10.85
730 upb pass 6 0 0 0 2.42
731 upcloud pass 6 0 0 0 2.35
732 upnp pass 23 0 0 0 3.83
733 uptime pass 4 0 0 0 2.36
734 uptime_kuma pass 38 0 0 0 3.58
735 uptimerobot pass 35 0 0 0 3.18
736 utility_meter issues 94 1 0 0 6.00
737 v2c issues 12 1 0 0 2.86
738 vallox pass 76 0 0 0 5.65
739 vegehub pass 18 0 0 0 2.92
740 velbus issues 57 1 0 0 8.99
741 velux pass 80 0 0 0 4.86
742 venstar pass 12 0 0 0 2.56
743 vera pass 29 0 0 0 3.08
744 version pass 10 0 0 0 2.55
745 vesync pass 175 0 0 0 12.54
746 vicare issues 54 1 0 0 4.48
747 victron_ble pass 34 0 0 0 3.61
748 victron_gx pass 62 0 0 0 14.13
749 victron_remote_monitoring pass 22 0 0 0 3.03
750 vilfo pass 9 0 0 0 2.46
751 vizio pass 73 0 0 0 4.50
752 vlc_telnet pass 39 0 0 0 3.40
753 vodafone_station issues 53 1 0 0 4.60
754 volumio pass 9 0 0 0 2.29
755 volvo pass 110 0 0 0 8.64
756 volvooncall pass 4 0 0 0 2.20
757 wake_on_lan pass 15 0 0 0 2.50
758 wallbox pass 38 0 0 0 3.67
759 waqi pass 20 0 0 0 2.63
760 waterfurnace pass 77 0 0 0 11.93
761 watergate pass 16 0 0 0 3.04
762 watts issues 51 1 0 0 5.17
763 watttime issues 11 1 0 0 2.56
764 waze_travel_time pass 23 0 0 0 14.84
765 weatherflow pass 5 0 0 0 2.95
766 weatherflow_cloud pass 17 0 0 0 3.12
767 weatherkit pass 35 0 0 0 2.92
768 webdav pass 25 0 0 0 3.90
769 webmin issues 11 1 0 0 2.52
770 webostv issues 82 1 0 0 12.04
771 weheat pass 16 0 0 0 2.85
772 wemo pass 93 0 0 0 6.71
773 whirlpool issues 239 1 0 0 12.16
774 whois pass 41 0 0 0 3.40
775 wiffi pass 4 0 0 0 2.19
776 wiim pass 29 0 0 0 3.02
777 wilight pass 22 0 0 0 2.82
778 withings pass 62 0 0 0 8.01
779 wiz pass 56 0 0 0 4.34
780 wled pass 100 0 0 0 7.60
781 wmspro pass 39 0 0 0 4.04
782 wolflink pass 10 0 0 0 2.49
783 workday issues 70 1 0 0 6.14
784 worldclock pass 6 0 0 0 2.42
785 ws66i pass 24 0 0 0 3.12
786 wsdot pass 16 0 0 0 2.66
787 xbox pass 203 0 0 0 14.92
788 xiaomi_aqara pass 12 0 0 0 2.46
789 xiaomi_ble pass 92 0 0 0 6.22
790 xiaomi_miio pass 51 0 0 0 4.11
791 xthings_cloud pass 30 0 0 0 3.72
792 yale_smart_alarm pass 37 0 0 0 3.71
793 yalexs_ble pass 26 0 0 0 3.32
794 yamaha_musiccast pass 9 0 0 0 2.52
795 yardian pass 16 0 0 0 2.79
796 yeelight pass 62 0 0 0 4.73
797 yolink pass 10 0 0 0 3.10
798 youless pass 4 0 0 0 2.41
799 youtube pass 24 0 0 0 3.38
800 zamg pass 9 0 0 0 2.52
801 zerproc pass 10 0 0 0 2.49
802 zeversolar pass 10 0 0 0 2.46
803 zha issues 339 1 0 4 70.49
804 zimi pass 16 0 0 0 2.65
805 zinvolt pass 12 0 0 0 2.77
806 zodiac pass 5 0 0 0 2.31
807 zwave_js pass 611 0 0 0 60.17
808 zwave_me pass 8 0 0 0 2.24
-857
View File
@@ -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>/`.
-57
View File
@@ -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
View File
@@ -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
-386
View File
@@ -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())
-264
View File
@@ -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())
-572
View File
@@ -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())