Add diagnostics to Comelit SimpleHome (#128794)

* Add diagnostics to Comelit SimpleHome

* add test

* add missing tests

* introduce SnapshotAssertion

* cleanup

* exclude date based props
This commit is contained in:
Simone Chemelli 2024-10-21 19:33:32 +02:00 committed by GitHub
parent 3e8f3cfb49
commit e08e8641cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 396 additions and 1 deletions

View file

@ -0,0 +1,93 @@
"""Diagnostics support for Comelit integration."""
from __future__ import annotations
from typing import Any
from aiocomelit import (
ComelitSerialBridgeObject,
ComelitVedoAreaObject,
ComelitVedoZoneObject,
)
from aiocomelit.const import BRIDGE
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PIN, CONF_TYPE
from homeassistant.core import HomeAssistant
from .const import DOMAIN
from .coordinator import ComelitBaseCoordinator
TO_REDACT = {CONF_PIN}
async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: ConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
coordinator: ComelitBaseCoordinator = hass.data[DOMAIN][entry.entry_id]
dev_list: list[dict[str, Any]] = []
dev_type_list: list[dict[int, Any]] = []
for dev_type in coordinator.data:
dev_type_list = []
for sensor_data in coordinator.data[dev_type].values():
if isinstance(sensor_data, ComelitSerialBridgeObject):
dev_type_list.append(
{
sensor_data.index: {
"name": sensor_data.name,
"status": sensor_data.status,
"human_status": sensor_data.human_status,
"protected": sensor_data.protected,
"val": sensor_data.val,
"zone": sensor_data.zone,
"power": sensor_data.power,
"power_unit": sensor_data.power_unit,
}
}
)
if isinstance(sensor_data, ComelitVedoAreaObject):
dev_type_list.append(
{
sensor_data.index: {
"name": sensor_data.name,
"human_status": sensor_data.human_status.value,
"p1": sensor_data.p1,
"p2": sensor_data.p2,
"ready": sensor_data.ready,
"armed": sensor_data.armed,
"alarm": sensor_data.alarm,
"alarm_memory": sensor_data.alarm_memory,
"sabotage": sensor_data.sabotage,
"anomaly": sensor_data.anomaly,
"in_time": sensor_data.in_time,
"out_time": sensor_data.out_time,
}
}
)
if isinstance(sensor_data, ComelitVedoZoneObject):
dev_type_list.append(
{
sensor_data.index: {
"name": sensor_data.name,
"human_status": sensor_data.human_status.value,
"status": sensor_data.status,
"status_api": sensor_data.status_api,
}
}
)
dev_list.append({dev_type: dev_type_list})
return {
"entry": async_redact_data(entry.as_dict(), TO_REDACT),
"type": entry.data.get(CONF_TYPE, BRIDGE),
"device_info": {
"last_update success": coordinator.last_update_success,
"last_exception": repr(coordinator.last_exception),
"devices": dev_list,
},
}

View file

@ -1,6 +1,19 @@
"""Common stuff for Comelit SimpleHome tests.""" """Common stuff for Comelit SimpleHome tests."""
from aiocomelit.const import VEDO from aiocomelit import ComelitVedoAreaObject, ComelitVedoZoneObject
from aiocomelit.api import ComelitSerialBridgeObject
from aiocomelit.const import (
CLIMATE,
COVER,
IRRIGATION,
LIGHT,
OTHER,
SCENARIO,
VEDO,
WATT,
AlarmAreaState,
AlarmZoneState,
)
from homeassistant.components.comelit.const import DOMAIN from homeassistant.components.comelit.const import DOMAIN
from homeassistant.const import CONF_DEVICES, CONF_HOST, CONF_PIN, CONF_PORT, CONF_TYPE from homeassistant.const import CONF_DEVICES, CONF_HOST, CONF_PIN, CONF_PORT, CONF_TYPE
@ -27,3 +40,67 @@ MOCK_USER_BRIDGE_DATA = MOCK_CONFIG[DOMAIN][CONF_DEVICES][0]
MOCK_USER_VEDO_DATA = MOCK_CONFIG[DOMAIN][CONF_DEVICES][1] MOCK_USER_VEDO_DATA = MOCK_CONFIG[DOMAIN][CONF_DEVICES][1]
FAKE_PIN = 5678 FAKE_PIN = 5678
BRIDGE_DEVICE_QUERY = {
CLIMATE: {},
COVER: {
0: ComelitSerialBridgeObject(
index=0,
name="Cover0",
status=0,
human_status="closed",
type="cover",
val=0,
protected=0,
zone="Open space",
power=0.0,
power_unit=WATT,
)
},
LIGHT: {
0: ComelitSerialBridgeObject(
index=0,
name="Light0",
status=0,
human_status="off",
type="light",
val=0,
protected=0,
zone="Bathroom",
power=0.0,
power_unit=WATT,
)
},
OTHER: {},
IRRIGATION: {},
SCENARIO: {},
}
VEDO_DEVICE_QUERY = {
"aree": {
0: ComelitVedoAreaObject(
index=0,
name="Area0",
p1=True,
p2=False,
ready=False,
armed=False,
alarm=False,
alarm_memory=False,
sabotage=False,
anomaly=False,
in_time=False,
out_time=False,
human_status=AlarmAreaState.UNKNOWN,
)
},
"zone": {
0: ComelitVedoZoneObject(
index=0,
name="Zone0",
status_api="0x000",
status=0,
human_status=AlarmZoneState.REST,
)
},
}

View file

@ -0,0 +1,144 @@
# serializer version: 1
# name: test_entry_diagnostics_bridge
dict({
'device_info': dict({
'devices': list([
dict({
'clima': list([
]),
}),
dict({
'shutter': list([
dict({
'0': dict({
'human_status': 'closed',
'name': 'Cover0',
'power': 0.0,
'power_unit': 'W',
'protected': 0,
'status': 0,
'val': 0,
'zone': 'Open space',
}),
}),
]),
}),
dict({
'light': list([
dict({
'0': dict({
'human_status': 'off',
'name': 'Light0',
'power': 0.0,
'power_unit': 'W',
'protected': 0,
'status': 0,
'val': 0,
'zone': 'Bathroom',
}),
}),
]),
}),
dict({
'other': list([
]),
}),
dict({
'irrigation': list([
]),
}),
dict({
'scenario': list([
]),
}),
]),
'last_exception': 'None',
'last_update success': True,
}),
'entry': dict({
'data': dict({
'host': 'fake_host',
'pin': '**REDACTED**',
'port': 80,
}),
'disabled_by': None,
'discovery_keys': dict({
}),
'domain': 'comelit',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
'pref_disable_polling': False,
'source': 'user',
'title': 'Mock Title',
'unique_id': None,
'version': 1,
}),
'type': 'Serial bridge',
})
# ---
# name: test_entry_diagnostics_vedo
dict({
'device_info': dict({
'devices': list([
dict({
'aree': list([
dict({
'0': dict({
'alarm': False,
'alarm_memory': False,
'anomaly': False,
'armed': False,
'human_status': 'unknown',
'in_time': False,
'name': 'Area0',
'out_time': False,
'p1': True,
'p2': False,
'ready': False,
'sabotage': False,
}),
}),
]),
}),
dict({
'zone': list([
dict({
'0': dict({
'human_status': 'rest',
'name': 'Zone0',
'status': 0,
'status_api': '0x000',
}),
}),
]),
}),
]),
'last_exception': 'None',
'last_update success': True,
}),
'entry': dict({
'data': dict({
'host': 'fake_vedo_host',
'pin': '**REDACTED**',
'port': 8080,
'type': 'Vedo system',
}),
'disabled_by': None,
'discovery_keys': dict({
}),
'domain': 'comelit',
'minor_version': 1,
'options': dict({
}),
'pref_disable_new_entities': False,
'pref_disable_polling': False,
'source': 'user',
'title': 'Mock Title',
'unique_id': None,
'version': 1,
}),
'type': 'Vedo system',
})
# ---

View file

@ -0,0 +1,81 @@
"""Tests for Comelit Simplehome diagnostics platform."""
from __future__ import annotations
from unittest.mock import patch
from syrupy import SnapshotAssertion
from syrupy.filters import props
from homeassistant.components.comelit.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from .const import (
BRIDGE_DEVICE_QUERY,
MOCK_USER_BRIDGE_DATA,
MOCK_USER_VEDO_DATA,
VEDO_DEVICE_QUERY,
)
from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator
async def test_entry_diagnostics_bridge(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
snapshot: SnapshotAssertion,
) -> None:
"""Test Bridge config entry diagnostics."""
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_BRIDGE_DATA)
entry.add_to_hass(hass)
with (
patch("aiocomelit.api.ComeliteSerialBridgeApi.login"),
patch(
"aiocomelit.api.ComeliteSerialBridgeApi.get_all_devices",
return_value=BRIDGE_DEVICE_QUERY,
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state == ConfigEntryState.LOADED
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot(
exclude=props(
"entry_id",
"created_at",
"modified_at",
)
)
async def test_entry_diagnostics_vedo(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
snapshot: SnapshotAssertion,
) -> None:
"""Test Vedo System config entry diagnostics."""
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_VEDO_DATA)
entry.add_to_hass(hass)
with (
patch("aiocomelit.api.ComelitVedoApi.login"),
patch(
"aiocomelit.api.ComelitVedoApi.get_all_areas_and_zones",
return_value=VEDO_DEVICE_QUERY,
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state == ConfigEntryState.LOADED
assert await get_diagnostics_for_config_entry(hass, hass_client, entry) == snapshot(
exclude=props(
"entry_id",
"created_at",
"modified_at",
)
)