mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
Add diagnostics for bosch alam integration (#142165)
* add diagnostics to bosch_alarm * use snapshot
This commit is contained in:
parent
934e81db43
commit
7a9a4db8d7
73
homeassistant/components/bosch_alarm/diagnostics.py
Normal file
73
homeassistant/components/bosch_alarm/diagnostics.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
"""Diagnostics for bosch alarm."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.diagnostics import async_redact_data
|
||||||
|
from homeassistant.const import CONF_PASSWORD
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from . import BoschAlarmConfigEntry
|
||||||
|
from .const import CONF_INSTALLER_CODE, CONF_USER_CODE
|
||||||
|
|
||||||
|
TO_REDACT = [CONF_INSTALLER_CODE, CONF_USER_CODE, CONF_PASSWORD]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_config_entry_diagnostics(
|
||||||
|
hass: HomeAssistant, entry: BoschAlarmConfigEntry
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Return diagnostics for a config entry."""
|
||||||
|
|
||||||
|
return {
|
||||||
|
"entry_data": async_redact_data(entry.data, TO_REDACT),
|
||||||
|
"data": {
|
||||||
|
"model": entry.runtime_data.model,
|
||||||
|
"serial_number": entry.runtime_data.serial_number,
|
||||||
|
"protocol_version": entry.runtime_data.protocol_version,
|
||||||
|
"firmware_version": entry.runtime_data.firmware_version,
|
||||||
|
"areas": [
|
||||||
|
{
|
||||||
|
"id": area_id,
|
||||||
|
"name": area.name,
|
||||||
|
"all_ready": area.all_ready,
|
||||||
|
"part_ready": area.part_ready,
|
||||||
|
"faults": area.faults,
|
||||||
|
"alarms": area.alarms,
|
||||||
|
"disarmed": area.is_disarmed(),
|
||||||
|
"arming": area.is_arming(),
|
||||||
|
"pending": area.is_pending(),
|
||||||
|
"part_armed": area.is_part_armed(),
|
||||||
|
"all_armed": area.is_all_armed(),
|
||||||
|
"armed": area.is_armed(),
|
||||||
|
"triggered": area.is_triggered(),
|
||||||
|
}
|
||||||
|
for area_id, area in entry.runtime_data.areas.items()
|
||||||
|
],
|
||||||
|
"points": [
|
||||||
|
{
|
||||||
|
"id": point_id,
|
||||||
|
"name": point.name,
|
||||||
|
"open": point.is_open(),
|
||||||
|
"normal": point.is_normal(),
|
||||||
|
}
|
||||||
|
for point_id, point in entry.runtime_data.points.items()
|
||||||
|
],
|
||||||
|
"doors": [
|
||||||
|
{
|
||||||
|
"id": door_id,
|
||||||
|
"name": door.name,
|
||||||
|
"open": door.is_open(),
|
||||||
|
"locked": door.is_locked(),
|
||||||
|
}
|
||||||
|
for door_id, door in entry.runtime_data.doors.items()
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"id": output_id,
|
||||||
|
"name": output.name,
|
||||||
|
"active": output.is_active(),
|
||||||
|
}
|
||||||
|
for output_id, output in entry.runtime_data.outputs.items()
|
||||||
|
],
|
||||||
|
"history_events": entry.runtime_data.events,
|
||||||
|
},
|
||||||
|
}
|
@ -4,7 +4,7 @@ from collections.abc import Generator
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from bosch_alarm_mode2.panel import Area
|
from bosch_alarm_mode2.panel import Area, Door, Output, Point
|
||||||
from bosch_alarm_mode2.utils import Observable
|
from bosch_alarm_mode2.utils import Observable
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -78,14 +78,65 @@ def mock_setup_entry() -> Generator[AsyncMock]:
|
|||||||
yield mock_setup_entry
|
yield mock_setup_entry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def points() -> Generator[dict[int, Point]]:
|
||||||
|
"""Define a mocked door."""
|
||||||
|
names = [
|
||||||
|
"Window",
|
||||||
|
"Door",
|
||||||
|
"Motion Detector",
|
||||||
|
"CO Detector",
|
||||||
|
"Smoke Detector",
|
||||||
|
"Glassbreak Sensor",
|
||||||
|
"Bedroom",
|
||||||
|
]
|
||||||
|
points = {}
|
||||||
|
for i, name in enumerate(names):
|
||||||
|
mock = AsyncMock(spec=Point)
|
||||||
|
mock.name = name
|
||||||
|
mock.status_observer = AsyncMock(spec=Observable)
|
||||||
|
mock.is_open.return_value = False
|
||||||
|
mock.is_normal.return_value = True
|
||||||
|
points[i] = mock
|
||||||
|
return points
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def output() -> Generator[Output]:
|
||||||
|
"""Define a mocked output."""
|
||||||
|
mock = AsyncMock(spec=Output)
|
||||||
|
mock.name = "Output A"
|
||||||
|
mock.status_observer = AsyncMock(spec=Observable)
|
||||||
|
mock.is_active.return_value = False
|
||||||
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def door() -> Generator[Door]:
|
||||||
|
"""Define a mocked door."""
|
||||||
|
mock = AsyncMock(spec=Door)
|
||||||
|
mock.name = "Main Door"
|
||||||
|
mock.status_observer = AsyncMock(spec=Observable)
|
||||||
|
mock.is_open.return_value = False
|
||||||
|
mock.is_locked.return_value = True
|
||||||
|
return mock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def area() -> Generator[Area]:
|
def area() -> Generator[Area]:
|
||||||
"""Define a mocked area."""
|
"""Define a mocked area."""
|
||||||
mock = AsyncMock(spec=Area)
|
mock = AsyncMock(spec=Area)
|
||||||
mock.name = "Area1"
|
mock.name = "Area1"
|
||||||
mock.status_observer = AsyncMock(spec=Observable)
|
mock.status_observer = AsyncMock(spec=Observable)
|
||||||
|
mock.alarm_observer = AsyncMock(spec=Observable)
|
||||||
|
mock.ready_observer = AsyncMock(spec=Observable)
|
||||||
|
mock.alarms = []
|
||||||
|
mock.faults = []
|
||||||
|
mock.all_ready = True
|
||||||
|
mock.part_ready = True
|
||||||
mock.is_triggered.return_value = False
|
mock.is_triggered.return_value = False
|
||||||
mock.is_disarmed.return_value = True
|
mock.is_disarmed.return_value = True
|
||||||
|
mock.is_armed.return_value = False
|
||||||
mock.is_arming.return_value = False
|
mock.is_arming.return_value = False
|
||||||
mock.is_pending.return_value = False
|
mock.is_pending.return_value = False
|
||||||
mock.is_part_armed.return_value = False
|
mock.is_part_armed.return_value = False
|
||||||
@ -95,7 +146,12 @@ def area() -> Generator[Area]:
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_panel(
|
def mock_panel(
|
||||||
area: AsyncMock, model_name: str, serial_number: str | None
|
area: AsyncMock,
|
||||||
|
door: AsyncMock,
|
||||||
|
output: AsyncMock,
|
||||||
|
points: dict[int, AsyncMock],
|
||||||
|
model_name: str,
|
||||||
|
serial_number: str | None,
|
||||||
) -> Generator[AsyncMock]:
|
) -> Generator[AsyncMock]:
|
||||||
"""Define a fixture to set up Bosch Alarm."""
|
"""Define a fixture to set up Bosch Alarm."""
|
||||||
with (
|
with (
|
||||||
@ -106,10 +162,18 @@ def mock_panel(
|
|||||||
):
|
):
|
||||||
client = mock_panel.return_value
|
client = mock_panel.return_value
|
||||||
client.areas = {1: area}
|
client.areas = {1: area}
|
||||||
|
client.doors = {1: door}
|
||||||
|
client.outputs = {1: output}
|
||||||
|
client.points = points
|
||||||
client.model = model_name
|
client.model = model_name
|
||||||
|
client.faults = []
|
||||||
|
client.events = []
|
||||||
client.firmware_version = "1.0.0"
|
client.firmware_version = "1.0.0"
|
||||||
|
client.protocol_version = "1.0.0"
|
||||||
client.serial_number = serial_number
|
client.serial_number = serial_number
|
||||||
client.connection_status_observer = AsyncMock(spec=Observable)
|
client.connection_status_observer = AsyncMock(spec=Observable)
|
||||||
|
client.faults_observer = AsyncMock(spec=Observable)
|
||||||
|
client.history_observer = AsyncMock(spec=Observable)
|
||||||
yield client
|
yield client
|
||||||
|
|
||||||
|
|
||||||
|
290
tests/components/bosch_alarm/snapshots/test_diagnostics.ambr
Normal file
290
tests/components/bosch_alarm/snapshots/test_diagnostics.ambr
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_diagnostics[amax_3000]
|
||||||
|
dict({
|
||||||
|
'data': dict({
|
||||||
|
'areas': list([
|
||||||
|
dict({
|
||||||
|
'alarms': list([
|
||||||
|
]),
|
||||||
|
'all_armed': False,
|
||||||
|
'all_ready': True,
|
||||||
|
'armed': False,
|
||||||
|
'arming': False,
|
||||||
|
'disarmed': True,
|
||||||
|
'faults': list([
|
||||||
|
]),
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Area1',
|
||||||
|
'part_armed': False,
|
||||||
|
'part_ready': True,
|
||||||
|
'pending': False,
|
||||||
|
'triggered': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'doors': list([
|
||||||
|
dict({
|
||||||
|
'id': 1,
|
||||||
|
'locked': True,
|
||||||
|
'name': 'Main Door',
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'firmware_version': '1.0.0',
|
||||||
|
'history_events': list([
|
||||||
|
]),
|
||||||
|
'model': 'AMAX 3000',
|
||||||
|
'outputs': list([
|
||||||
|
dict({
|
||||||
|
'active': False,
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Output A',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'points': list([
|
||||||
|
dict({
|
||||||
|
'id': 0,
|
||||||
|
'name': 'Window',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Door',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 2,
|
||||||
|
'name': 'Motion Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 3,
|
||||||
|
'name': 'CO Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 4,
|
||||||
|
'name': 'Smoke Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 5,
|
||||||
|
'name': 'Glassbreak Sensor',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 6,
|
||||||
|
'name': 'Bedroom',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'protocol_version': '1.0.0',
|
||||||
|
'serial_number': None,
|
||||||
|
}),
|
||||||
|
'entry_data': dict({
|
||||||
|
'host': '0.0.0.0',
|
||||||
|
'installer_code': '**REDACTED**',
|
||||||
|
'model': 'AMAX 3000',
|
||||||
|
'password': '**REDACTED**',
|
||||||
|
'port': 7700,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_diagnostics[b5512]
|
||||||
|
dict({
|
||||||
|
'data': dict({
|
||||||
|
'areas': list([
|
||||||
|
dict({
|
||||||
|
'alarms': list([
|
||||||
|
]),
|
||||||
|
'all_armed': False,
|
||||||
|
'all_ready': True,
|
||||||
|
'armed': False,
|
||||||
|
'arming': False,
|
||||||
|
'disarmed': True,
|
||||||
|
'faults': list([
|
||||||
|
]),
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Area1',
|
||||||
|
'part_armed': False,
|
||||||
|
'part_ready': True,
|
||||||
|
'pending': False,
|
||||||
|
'triggered': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'doors': list([
|
||||||
|
dict({
|
||||||
|
'id': 1,
|
||||||
|
'locked': True,
|
||||||
|
'name': 'Main Door',
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'firmware_version': '1.0.0',
|
||||||
|
'history_events': list([
|
||||||
|
]),
|
||||||
|
'model': 'B5512 (US1B)',
|
||||||
|
'outputs': list([
|
||||||
|
dict({
|
||||||
|
'active': False,
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Output A',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'points': list([
|
||||||
|
dict({
|
||||||
|
'id': 0,
|
||||||
|
'name': 'Window',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Door',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 2,
|
||||||
|
'name': 'Motion Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 3,
|
||||||
|
'name': 'CO Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 4,
|
||||||
|
'name': 'Smoke Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 5,
|
||||||
|
'name': 'Glassbreak Sensor',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 6,
|
||||||
|
'name': 'Bedroom',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'protocol_version': '1.0.0',
|
||||||
|
'serial_number': None,
|
||||||
|
}),
|
||||||
|
'entry_data': dict({
|
||||||
|
'host': '0.0.0.0',
|
||||||
|
'model': 'B5512 (US1B)',
|
||||||
|
'password': '**REDACTED**',
|
||||||
|
'port': 7700,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_diagnostics[solution_3000]
|
||||||
|
dict({
|
||||||
|
'data': dict({
|
||||||
|
'areas': list([
|
||||||
|
dict({
|
||||||
|
'alarms': list([
|
||||||
|
]),
|
||||||
|
'all_armed': False,
|
||||||
|
'all_ready': True,
|
||||||
|
'armed': False,
|
||||||
|
'arming': False,
|
||||||
|
'disarmed': True,
|
||||||
|
'faults': list([
|
||||||
|
]),
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Area1',
|
||||||
|
'part_armed': False,
|
||||||
|
'part_ready': True,
|
||||||
|
'pending': False,
|
||||||
|
'triggered': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'doors': list([
|
||||||
|
dict({
|
||||||
|
'id': 1,
|
||||||
|
'locked': True,
|
||||||
|
'name': 'Main Door',
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'firmware_version': '1.0.0',
|
||||||
|
'history_events': list([
|
||||||
|
]),
|
||||||
|
'model': 'Solution 3000',
|
||||||
|
'outputs': list([
|
||||||
|
dict({
|
||||||
|
'active': False,
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Output A',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'points': list([
|
||||||
|
dict({
|
||||||
|
'id': 0,
|
||||||
|
'name': 'Window',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 1,
|
||||||
|
'name': 'Door',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 2,
|
||||||
|
'name': 'Motion Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 3,
|
||||||
|
'name': 'CO Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 4,
|
||||||
|
'name': 'Smoke Detector',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 5,
|
||||||
|
'name': 'Glassbreak Sensor',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
dict({
|
||||||
|
'id': 6,
|
||||||
|
'name': 'Bedroom',
|
||||||
|
'normal': True,
|
||||||
|
'open': False,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
'protocol_version': '1.0.0',
|
||||||
|
'serial_number': '1234567890',
|
||||||
|
}),
|
||||||
|
'entry_data': dict({
|
||||||
|
'host': '0.0.0.0',
|
||||||
|
'model': 'Solution 3000',
|
||||||
|
'port': 7700,
|
||||||
|
'user_code': '**REDACTED**',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
# ---
|
32
tests/components/bosch_alarm/test_diagnostics.py
Normal file
32
tests/components/bosch_alarm/test_diagnostics.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
"""Test the Bosch Alarm diagnostics."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
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_panel: AsyncMock,
|
||||||
|
area: AsyncMock,
|
||||||
|
model_name: str,
|
||||||
|
serial_number: str,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
config_flow_data: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
"""Test generating diagnostics for bosch alarm."""
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
diag = await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry)
|
||||||
|
assert diag == snapshot
|
Loading…
x
Reference in New Issue
Block a user