Add Homee diagnostics platform (#146340)

* Initial dignostics implementation

* Add diagnostics tests

* change data-set for device diagnostics

* adapt for upcoming pyHomee release

* other solution

* fix review and more
This commit is contained in:
Markus Adrario 2025-06-09 05:24:07 -06:00 committed by GitHub
parent 5d58cdd98e
commit b1a2af9fd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 1230 additions and 0 deletions

View File

@ -0,0 +1,43 @@
"""Diagnostics for homee integration."""
from typing import Any
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntry
from . import DOMAIN, HomeeConfigEntry
TO_REDACT = [CONF_PASSWORD, CONF_USERNAME, "latitude", "longitude", "wlan_ssid"]
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: HomeeConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
return {
"entry_data": async_redact_data(entry.data, TO_REDACT),
"settings": async_redact_data(entry.runtime_data.settings.raw_data, TO_REDACT),
"devices": [{"node": node.raw_data} for node in entry.runtime_data.nodes],
}
async def async_get_device_diagnostics(
hass: HomeAssistant, entry: HomeeConfigEntry, device: DeviceEntry
) -> dict[str, Any]:
"""Return diagnostics for a device."""
# Extract node_id from the device identifiers
split_uid = next(
identifier[1] for identifier in device.identifiers if identifier[0] == DOMAIN
).split("-")
# Homee hub itself only has MAC as identifier and a node_id of -1
node_id = -1 if len(split_uid) < 2 else split_uid[1]
node = entry.runtime_data.get_node_by_id(int(node_id))
assert node is not None
return {
"homee node": node.raw_data,
}

View File

@ -46,6 +46,7 @@ def build_mock_node(file: str) -> AsyncMock:
def attribute_by_type(type, instance=0) -> HomeeAttribute | None:
return {attr.type: attr for attr in mock_node.attributes}.get(type)
mock_node.raw_data = json_node
mock_node.get_attribute_by_type = attribute_by_type
return mock_node

View File

@ -39,6 +39,7 @@ def mock_config_entry() -> MockConfigEntry:
CONF_PASSWORD: TESTPASS,
},
unique_id=HOMEE_ID,
entry_id="test_entry_id",
)
@ -68,5 +69,15 @@ def mock_homee() -> Generator[AsyncMock]:
homee.connected = True
homee.get_access_token.return_value = "test_token"
# Mock the Homee settings raw_data for diagnostics
homee.settings.raw_data = {
"uid": HOMEE_ID,
"homee_name": HOMEE_NAME,
"version": "1.2.3",
"mac_address": "00:05:55:11:ee:cc",
"wlan_ssid": "TestSSID",
"latitude": 52.5200,
"longitude": 13.4050,
}
yield homee

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
"""Test homee diagnostics."""
from unittest.mock import MagicMock
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.homee.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from . import build_mock_node, setup_integration
from .conftest import HOMEE_ID
from tests.common import MockConfigEntry
from tests.components.diagnostics import (
get_diagnostics_for_config_entry,
get_diagnostics_for_device,
)
from tests.typing import ClientSessionGenerator
async def setup_mock_homee(
hass: HomeAssistant, mock_homee: MagicMock, mock_config_entry: MockConfigEntry
) -> None:
"""Set up the number platform."""
mock_homee.nodes = [
build_mock_node("numbers.json"),
build_mock_node("thermostat_with_currenttemp.json"),
build_mock_node("cover_with_position_slats.json"),
]
mock_homee.get_node_by_id = lambda node_id: mock_homee.nodes[node_id - 1]
await setup_integration(hass, mock_config_entry)
async def test_diagnostics_config_entry(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_homee: MagicMock,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics for config entry."""
await setup_mock_homee(hass, mock_homee, mock_config_entry)
result = await get_diagnostics_for_config_entry(
hass, hass_client, mock_config_entry
)
assert result == snapshot
async def test_diagnostics_device(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_homee: MagicMock,
mock_config_entry: MockConfigEntry,
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics for a device."""
await setup_mock_homee(hass, mock_homee, mock_config_entry)
device_entry = device_registry.async_get_device(
identifiers={(DOMAIN, f"{HOMEE_ID}-1")}
)
assert device_entry is not None
result = await get_diagnostics_for_device(
hass, hass_client, mock_config_entry, device_entry
)
assert result == snapshot
async def test_diagnostics_homee_device(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_homee: MagicMock,
mock_config_entry: MockConfigEntry,
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics for the homee hub device."""
mock_homee.nodes = [
build_mock_node("homee.json"),
]
mock_homee.get_node_by_id.return_value = mock_homee.nodes[0]
await setup_integration(hass, mock_config_entry)
device_entry = device_registry.async_get_device(
identifiers={(DOMAIN, f"{HOMEE_ID}")}
)
assert device_entry is not None
result = await get_diagnostics_for_device(
hass, hass_client, mock_config_entry, device_entry
)
assert result == snapshot