Add diagnostics to fibaro integration (#143003)

* Add diagnostics to fibaro

* Enhance diagnostic test

---------

Co-authored-by: Josef Zweck <josef@zweck.dev>
This commit is contained in:
rappenze 2025-04-16 13:52:42 +02:00 committed by GitHub
parent 8de23b9559
commit 9bff88ad3e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 219 additions and 0 deletions

View File

@ -211,6 +211,10 @@ class FibaroController:
"""Return list of scenes."""
return self._scenes
def get_all_devices(self) -> list[DeviceModel]:
"""Return list of all fibaro devices."""
return self._fibaro_device_manager.get_devices()
def read_fibaro_info(self) -> InfoModel:
"""Return the general info about the hub."""
return self._fibaro_info

View File

@ -0,0 +1,56 @@
"""Diagnostics support for fibaro integration."""
from __future__ import annotations
from collections.abc import Mapping
from typing import Any
from pyfibaro.fibaro_device import DeviceModel
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntry
from . import CONF_IMPORT_PLUGINS, FibaroConfigEntry
TO_REDACT = {"password"}
def _create_diagnostics_data(
config_entry: FibaroConfigEntry, devices: list[DeviceModel]
) -> dict[str, Any]:
"""Combine diagnostics information and redact sensitive information."""
return {
"config": {CONF_IMPORT_PLUGINS: config_entry.data.get(CONF_IMPORT_PLUGINS)},
"fibaro_devices": async_redact_data([d.raw_data for d in devices], TO_REDACT),
}
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: FibaroConfigEntry
) -> Mapping[str, Any]:
"""Return diagnostics for a config entry."""
controller = config_entry.runtime_data
devices = controller.get_all_devices()
return _create_diagnostics_data(config_entry, devices)
async def async_get_device_diagnostics(
hass: HomeAssistant, config_entry: FibaroConfigEntry, device: DeviceEntry
) -> Mapping[str, Any]:
"""Return diagnostics for a device."""
controller = config_entry.runtime_data
devices = controller.get_all_devices()
ha_device_id = next(iter(device.identifiers))[1]
if ha_device_id == controller.hub_serial:
# special case where the device is representing the fibaro hub
return _create_diagnostics_data(config_entry, devices)
# normal devices are represented by a parent / child structure
filtered_devices = [
device
for device in devices
if ha_device_id in (device.fibaro_id, device.parent_fibaro_id)
]
return _create_diagnostics_data(config_entry, filtered_devices)

View File

@ -70,6 +70,11 @@ def mock_power_sensor() -> Mock:
}
sensor.actions = {}
sensor.has_central_scene_event = False
sensor.raw_data = {
"fibaro_id": 1,
"name": "Test sensor",
"properties": {"power": 6.6, "password": "mysecret"},
}
value_mock = Mock()
value_mock.has_value = False
value_mock.is_bool_value = False
@ -123,6 +128,7 @@ def mock_light() -> Mock:
light.properties = {"manufacturer": ""}
light.actions = {"setValue": 1, "on": 0, "off": 0}
light.supported_features = {}
light.raw_data = {"fibaro_id": 3, "name": "Test light", "properties": {"value": 20}}
value_mock = Mock()
value_mock.has_value = True
value_mock.int_value.return_value = 20

View File

@ -0,0 +1,57 @@
# serializer version: 1
# name: test_config_entry_diagnostics
dict({
'config': dict({
'import_plugins': True,
}),
'fibaro_devices': list([
dict({
'fibaro_id': 3,
'name': 'Test light',
'properties': dict({
'value': 20,
}),
}),
]),
})
# ---
# name: test_device_diagnostics
dict({
'config': dict({
'import_plugins': True,
}),
'fibaro_devices': list([
dict({
'fibaro_id': 3,
'name': 'Test light',
'properties': dict({
'value': 20,
}),
}),
]),
})
# ---
# name: test_device_diagnostics_for_hub
dict({
'config': dict({
'import_plugins': True,
}),
'fibaro_devices': list([
dict({
'fibaro_id': 3,
'name': 'Test light',
'properties': dict({
'value': 20,
}),
}),
dict({
'fibaro_id': 1,
'name': 'Test sensor',
'properties': dict({
'password': '**REDACTED**',
'power': 6.6,
}),
}),
]),
})
# ---

View File

@ -0,0 +1,96 @@
"""Tests for the diagnostics data provided by the fibaro integration."""
from unittest.mock import Mock
from syrupy import SnapshotAssertion
from homeassistant.components.fibaro import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from .conftest import TEST_SERIALNUMBER, init_integration
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 test_config_entry_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_fibaro_client: Mock,
mock_config_entry: MockConfigEntry,
mock_light: Mock,
mock_room: Mock,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics."""
# Arrange
mock_fibaro_client.read_rooms.return_value = [mock_room]
mock_fibaro_client.read_devices.return_value = [mock_light]
# Act
await init_integration(hass, mock_config_entry)
# Assert
assert (
await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry)
== snapshot
)
async def test_device_diagnostics(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_fibaro_client: Mock,
mock_config_entry: MockConfigEntry,
mock_light: Mock,
mock_room: Mock,
entity_registry: er.EntityRegistry,
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics."""
# Arrange
mock_fibaro_client.read_rooms.return_value = [mock_room]
mock_fibaro_client.read_devices.return_value = [mock_light]
# Act
await init_integration(hass, mock_config_entry)
entry = entity_registry.async_get("light.room_1_test_light_3")
device = device_registry.async_get(entry.device_id)
# Assert
assert device
assert (
await get_diagnostics_for_device(hass, hass_client, mock_config_entry, device)
== snapshot
)
async def test_device_diagnostics_for_hub(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
mock_fibaro_client: Mock,
mock_config_entry: MockConfigEntry,
mock_light: Mock,
mock_power_sensor: Mock,
mock_room: Mock,
device_registry: dr.DeviceRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics for the hub."""
# Arrange
mock_fibaro_client.read_rooms.return_value = [mock_room]
mock_fibaro_client.read_devices.return_value = [mock_light, mock_power_sensor]
# Act
await init_integration(hass, mock_config_entry)
device = device_registry.async_get_device({(DOMAIN, TEST_SERIALNUMBER)})
# Assert
assert device
assert (
await get_diagnostics_for_device(hass, hass_client, mock_config_entry, device)
== snapshot
)