From d6458bc574c32e498905486d43ad54a4bb900e81 Mon Sep 17 00:00:00 2001 From: Raphael Hehl <7577984+RaHehl@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:39:38 +0200 Subject: [PATCH] Add diagnostics support to UniFi Access integration (#166819) Co-authored-by: RaHehl Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../components/unifi_access/diagnostics.py | 41 ++++++++++++ .../unifi_access/quality_scale.yaml | 2 +- .../snapshots/test_diagnostics.ambr | 64 +++++++++++++++++++ .../unifi_access/test_diagnostics.py | 29 +++++++++ 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/unifi_access/diagnostics.py create mode 100644 tests/components/unifi_access/snapshots/test_diagnostics.ambr create mode 100644 tests/components/unifi_access/test_diagnostics.py diff --git a/homeassistant/components/unifi_access/diagnostics.py b/homeassistant/components/unifi_access/diagnostics.py new file mode 100644 index 00000000000..903838dd6c6 --- /dev/null +++ b/homeassistant/components/unifi_access/diagnostics.py @@ -0,0 +1,41 @@ +"""Diagnostics support for UniFi Access.""" + +from __future__ import annotations + +from typing import Any + +from homeassistant.components.diagnostics import async_redact_data +from homeassistant.const import CONF_API_TOKEN +from homeassistant.core import HomeAssistant + +from .coordinator import UnifiAccessConfigEntry + +TO_REDACT = {CONF_API_TOKEN} + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, entry: UnifiAccessConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + data = entry.runtime_data.data + return { + "entry_data": async_redact_data(dict(entry.data), TO_REDACT), + "coordinator_data": { + "doors": { + door_id: door.model_dump(mode="json") + for door_id, door in data.doors.items() + }, + "emergency": data.emergency.model_dump(mode="json"), + "door_lock_rules": { + door_id: rule.model_dump(mode="json") + for door_id, rule in data.door_lock_rules.items() + }, + "unconfirmed_lock_rule_doors": sorted(data.unconfirmed_lock_rule_doors), + "supports_lock_rules": data.supports_lock_rules, + "lock_rule_support_complete": data.lock_rule_support_complete, + "door_thumbnails": { + door_id: thumb.model_dump(mode="json") + for door_id, thumb in data.door_thumbnails.items() + }, + }, + } diff --git a/homeassistant/components/unifi_access/quality_scale.yaml b/homeassistant/components/unifi_access/quality_scale.yaml index d86686eb816..01de812a0bb 100644 --- a/homeassistant/components/unifi_access/quality_scale.yaml +++ b/homeassistant/components/unifi_access/quality_scale.yaml @@ -41,7 +41,7 @@ rules: # Gold devices: done - diagnostics: todo + diagnostics: done discovery-update-info: todo discovery: todo docs-data-update: todo diff --git a/tests/components/unifi_access/snapshots/test_diagnostics.ambr b/tests/components/unifi_access/snapshots/test_diagnostics.ambr new file mode 100644 index 00000000000..f5125b71357 --- /dev/null +++ b/tests/components/unifi_access/snapshots/test_diagnostics.ambr @@ -0,0 +1,64 @@ +# serializer version: 1 +# name: test_diagnostics + dict({ + 'coordinator_data': dict({ + 'door_lock_rules': dict({ + 'door-001': dict({ + 'ended_time': 0, + 'type': '', + }), + 'door-002': dict({ + 'ended_time': 0, + 'type': '', + }), + }), + 'door_thumbnails': dict({ + 'door-001': dict({ + 'door_thumbnail_last_update': 1700000000, + 'url': '/preview/front_door.png', + }), + }), + 'doors': dict({ + 'door-001': dict({ + 'door_lock_relay_status': 'lock', + 'door_position_status': 'close', + 'door_thumbnail': '/preview/front_door.png', + 'door_thumbnail_last_update': 1700000000, + 'floor_id': '', + 'full_name': '', + 'id': 'door-001', + 'is_bind_hub': False, + 'lock_rule_status': None, + 'name': 'Front Door', + 'type': 'door', + }), + 'door-002': dict({ + 'door_lock_relay_status': 'unlock', + 'door_position_status': 'open', + 'door_thumbnail': None, + 'door_thumbnail_last_update': None, + 'floor_id': '', + 'full_name': '', + 'id': 'door-002', + 'is_bind_hub': False, + 'lock_rule_status': None, + 'name': 'Back Door', + 'type': 'door', + }), + }), + 'emergency': dict({ + 'evacuation': False, + 'lockdown': False, + }), + 'lock_rule_support_complete': True, + 'supports_lock_rules': True, + 'unconfirmed_lock_rule_doors': list([ + ]), + }), + 'entry_data': dict({ + 'api_token': '**REDACTED**', + 'host': '192.168.1.1', + 'verify_ssl': False, + }), + }) +# --- diff --git a/tests/components/unifi_access/test_diagnostics.py b/tests/components/unifi_access/test_diagnostics.py new file mode 100644 index 00000000000..e0ccf58ea31 --- /dev/null +++ b/tests/components/unifi_access/test_diagnostics.py @@ -0,0 +1,29 @@ +"""Tests for the diagnostics data provided by the UniFi Access integration.""" + +from unittest.mock import MagicMock + +from syrupy.assertion import SnapshotAssertion + +from homeassistant.core import HomeAssistant + +from . import setup_integration + +from tests.common import MockConfigEntry +from tests.components.diagnostics import get_diagnostics_for_config_entry +from tests.typing import ClientSessionGenerator + + +async def test_diagnostics( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + mock_client: MagicMock, + mock_config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, +) -> None: + """Test diagnostics.""" + await setup_integration(hass, mock_config_entry) + + assert ( + await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry) + == snapshot + )