From d246d02ab8d028439ab56681657a6127c1589da5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Simon=20H=C3=B6rrle?=
 <7945681+CM000n@users.noreply.github.com>
Date: Mon, 5 Aug 2024 11:08:27 +0200
Subject: [PATCH] Add apsystems diagnostic binary sensors (#123045)

* add diagnostic sensors

* select output_data from data

* split sensor and binary_sensor configurations

* adjust module description

* convert values to bool

* add strings

* add tests

* add tests

* update translations

* remove already available _attr_has_entity_name

* use dataclass instead of TypedDict

* Update tests/components/apsystems/test_binary_sensor.py

---------

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
---
 .../components/apsystems/__init__.py          |   7 +-
 .../components/apsystems/binary_sensor.py     | 102 +++++
 .../components/apsystems/coordinator.py       |  19 +-
 homeassistant/components/apsystems/sensor.py  |   2 +-
 .../components/apsystems/strings.json         |  14 +
 tests/components/apsystems/conftest.py        |   8 +-
 .../snapshots/test_binary_sensor.ambr         | 377 ++++++++++++++++++
 .../apsystems/test_binary_sensor.py           |  31 ++
 8 files changed, 553 insertions(+), 7 deletions(-)
 create mode 100644 homeassistant/components/apsystems/binary_sensor.py
 create mode 100644 tests/components/apsystems/snapshots/test_binary_sensor.ambr
 create mode 100644 tests/components/apsystems/test_binary_sensor.py

diff --git a/homeassistant/components/apsystems/__init__.py b/homeassistant/components/apsystems/__init__.py
index 91650201a87..372ce52e049 100644
--- a/homeassistant/components/apsystems/__init__.py
+++ b/homeassistant/components/apsystems/__init__.py
@@ -13,7 +13,12 @@ from homeassistant.core import HomeAssistant
 from .const import DEFAULT_PORT
 from .coordinator import ApSystemsDataCoordinator
 
-PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR, Platform.SWITCH]
+PLATFORMS: list[Platform] = [
+    Platform.BINARY_SENSOR,
+    Platform.NUMBER,
+    Platform.SENSOR,
+    Platform.SWITCH,
+]
 
 
 @dataclass
diff --git a/homeassistant/components/apsystems/binary_sensor.py b/homeassistant/components/apsystems/binary_sensor.py
new file mode 100644
index 00000000000..528203dc2d9
--- /dev/null
+++ b/homeassistant/components/apsystems/binary_sensor.py
@@ -0,0 +1,102 @@
+"""The read-only binary sensors for APsystems local API integration."""
+
+from __future__ import annotations
+
+from collections.abc import Callable
+from dataclasses import dataclass
+
+from APsystemsEZ1 import ReturnAlarmInfo
+
+from homeassistant.components.binary_sensor import (
+    BinarySensorDeviceClass,
+    BinarySensorEntity,
+    BinarySensorEntityDescription,
+)
+from homeassistant.const import EntityCategory
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers.entity_platform import AddEntitiesCallback
+from homeassistant.helpers.update_coordinator import CoordinatorEntity
+
+from . import ApSystemsConfigEntry, ApSystemsData
+from .coordinator import ApSystemsDataCoordinator
+from .entity import ApSystemsEntity
+
+
+@dataclass(frozen=True, kw_only=True)
+class ApsystemsLocalApiBinarySensorDescription(BinarySensorEntityDescription):
+    """Describes Apsystens Inverter binary sensor entity."""
+
+    is_on: Callable[[ReturnAlarmInfo], bool | None]
+
+
+BINARY_SENSORS: tuple[ApsystemsLocalApiBinarySensorDescription, ...] = (
+    ApsystemsLocalApiBinarySensorDescription(
+        key="off_grid_status",
+        translation_key="off_grid_status",
+        device_class=BinarySensorDeviceClass.PROBLEM,
+        entity_category=EntityCategory.DIAGNOSTIC,
+        is_on=lambda c: bool(c.og),
+    ),
+    ApsystemsLocalApiBinarySensorDescription(
+        key="dc_1_short_circuit_error_status",
+        translation_key="dc_1_short_circuit_error_status",
+        device_class=BinarySensorDeviceClass.PROBLEM,
+        entity_category=EntityCategory.DIAGNOSTIC,
+        is_on=lambda c: bool(c.isce1),
+    ),
+    ApsystemsLocalApiBinarySensorDescription(
+        key="dc_2_short_circuit_error_status",
+        translation_key="dc_2_short_circuit_error_status",
+        device_class=BinarySensorDeviceClass.PROBLEM,
+        entity_category=EntityCategory.DIAGNOSTIC,
+        is_on=lambda c: bool(c.isce2),
+    ),
+    ApsystemsLocalApiBinarySensorDescription(
+        key="output_fault_status",
+        translation_key="output_fault_status",
+        device_class=BinarySensorDeviceClass.PROBLEM,
+        entity_category=EntityCategory.DIAGNOSTIC,
+        is_on=lambda c: bool(c.oe),
+    ),
+)
+
+
+async def async_setup_entry(
+    hass: HomeAssistant,
+    config_entry: ApSystemsConfigEntry,
+    add_entities: AddEntitiesCallback,
+) -> None:
+    """Set up the binary sensor platform."""
+    config = config_entry.runtime_data
+
+    add_entities(
+        ApSystemsBinarySensorWithDescription(
+            data=config,
+            entity_description=desc,
+        )
+        for desc in BINARY_SENSORS
+    )
+
+
+class ApSystemsBinarySensorWithDescription(
+    CoordinatorEntity[ApSystemsDataCoordinator], ApSystemsEntity, BinarySensorEntity
+):
+    """Base binary sensor to be used with description."""
+
+    entity_description: ApsystemsLocalApiBinarySensorDescription
+
+    def __init__(
+        self,
+        data: ApSystemsData,
+        entity_description: ApsystemsLocalApiBinarySensorDescription,
+    ) -> None:
+        """Initialize the sensor."""
+        super().__init__(data.coordinator)
+        ApSystemsEntity.__init__(self, data)
+        self.entity_description = entity_description
+        self._attr_unique_id = f"{data.device_id}_{entity_description.key}"
+
+    @property
+    def is_on(self) -> bool | None:
+        """Return value of sensor."""
+        return self.entity_description.is_on(self.coordinator.data.alarm_info)
diff --git a/homeassistant/components/apsystems/coordinator.py b/homeassistant/components/apsystems/coordinator.py
index f2d076ce3fd..96956bafc3e 100644
--- a/homeassistant/components/apsystems/coordinator.py
+++ b/homeassistant/components/apsystems/coordinator.py
@@ -2,9 +2,10 @@
 
 from __future__ import annotations
 
+from dataclasses import dataclass
 from datetime import timedelta
 
-from APsystemsEZ1 import APsystemsEZ1M, ReturnOutputData
+from APsystemsEZ1 import APsystemsEZ1M, ReturnAlarmInfo, ReturnOutputData
 
 from homeassistant.core import HomeAssistant
 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
@@ -12,7 +13,15 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
 from .const import LOGGER
 
 
-class ApSystemsDataCoordinator(DataUpdateCoordinator[ReturnOutputData]):
+@dataclass
+class ApSystemsSensorData:
+    """Representing different Apsystems sensor data."""
+
+    output_data: ReturnOutputData
+    alarm_info: ReturnAlarmInfo
+
+
+class ApSystemsDataCoordinator(DataUpdateCoordinator[ApSystemsSensorData]):
     """Coordinator used for all sensors."""
 
     def __init__(self, hass: HomeAssistant, api: APsystemsEZ1M) -> None:
@@ -25,5 +34,7 @@ class ApSystemsDataCoordinator(DataUpdateCoordinator[ReturnOutputData]):
         )
         self.api = api
 
-    async def _async_update_data(self) -> ReturnOutputData:
-        return await self.api.get_output_data()
+    async def _async_update_data(self) -> ApSystemsSensorData:
+        output_data = await self.api.get_output_data()
+        alarm_info = await self.api.get_alarm_info()
+        return ApSystemsSensorData(output_data=output_data, alarm_info=alarm_info)
diff --git a/homeassistant/components/apsystems/sensor.py b/homeassistant/components/apsystems/sensor.py
index 637def4e418..afeb9d071ab 100644
--- a/homeassistant/components/apsystems/sensor.py
+++ b/homeassistant/components/apsystems/sensor.py
@@ -148,4 +148,4 @@ class ApSystemsSensorWithDescription(
     @property
     def native_value(self) -> StateType:
         """Return value of sensor."""
-        return self.entity_description.value_fn(self.coordinator.data)
+        return self.entity_description.value_fn(self.coordinator.data.output_data)
diff --git a/homeassistant/components/apsystems/strings.json b/homeassistant/components/apsystems/strings.json
index 18200f7b49d..e02f86c2730 100644
--- a/homeassistant/components/apsystems/strings.json
+++ b/homeassistant/components/apsystems/strings.json
@@ -19,6 +19,20 @@
     }
   },
   "entity": {
+    "binary_sensor": {
+      "off_grid_status": {
+        "name": "Off grid status"
+      },
+      "dc_1_short_circuit_error_status": {
+        "name": "DC 1 short circuit error status"
+      },
+      "dc_2_short_circuit_error_status": {
+        "name": "DC 2 short circuit error status"
+      },
+      "output_fault_status": {
+        "name": "Output fault status"
+      }
+    },
     "sensor": {
       "total_power": {
         "name": "Total power"
diff --git a/tests/components/apsystems/conftest.py b/tests/components/apsystems/conftest.py
index c191c7ca2dc..7e6140e8279 100644
--- a/tests/components/apsystems/conftest.py
+++ b/tests/components/apsystems/conftest.py
@@ -3,7 +3,7 @@
 from collections.abc import Generator
 from unittest.mock import AsyncMock, MagicMock, patch
 
-from APsystemsEZ1 import ReturnDeviceInfo, ReturnOutputData, Status
+from APsystemsEZ1 import ReturnAlarmInfo, ReturnDeviceInfo, ReturnOutputData, Status
 import pytest
 
 from homeassistant.components.apsystems.const import DOMAIN
@@ -52,6 +52,12 @@ def mock_apsystems() -> Generator[MagicMock]:
             e2=6.0,
             te2=7.0,
         )
+        mock_api.get_alarm_info.return_value = ReturnAlarmInfo(
+            og=Status.normal,
+            isce1=Status.alarm,
+            isce2=Status.normal,
+            oe=Status.alarm,
+        )
         mock_api.get_device_power_status.return_value = Status.normal
         yield mock_api
 
diff --git a/tests/components/apsystems/snapshots/test_binary_sensor.ambr b/tests/components/apsystems/snapshots/test_binary_sensor.ambr
new file mode 100644
index 00000000000..bb06b019f31
--- /dev/null
+++ b/tests/components/apsystems/snapshots/test_binary_sensor.ambr
@@ -0,0 +1,377 @@
+# serializer version: 1
+# name: test_all_entities[binary_sensor.mock_title_dc_1_short_circuit_error_status-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_dc_1_short_circuit_error_status',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'DC 1 short circuit error status',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'dc_1_short_circuit_error_status',
+    'unique_id': 'MY_SERIAL_NUMBER_dc_1_short_circuit_error_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_dc_1_short_circuit_error_status-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title DC 1 short circuit error status',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_dc_1_short_circuit_error_status',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'on',
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_dc_2_short_circuit_error_status-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_dc_2_short_circuit_error_status',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'DC 2 short circuit error status',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'dc_2_short_circuit_error_status',
+    'unique_id': 'MY_SERIAL_NUMBER_dc_2_short_circuit_error_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_dc_2_short_circuit_error_status-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title DC 2 short circuit error status',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_dc_2_short_circuit_error_status',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'off',
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_off_grid_status-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_off_grid_status',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'Off grid status',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'off_grid_status',
+    'unique_id': 'MY_SERIAL_NUMBER_off_grid_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_off_grid_status-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title Off grid status',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_off_grid_status',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'off',
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_output_fault_status-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_output_fault_status',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'Output fault status',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'output_fault_status',
+    'unique_id': 'MY_SERIAL_NUMBER_output_fault_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_output_fault_status-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title Output fault status',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_output_fault_status',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'on',
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_problem',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'Problem',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'off_grid_status',
+    'unique_id': 'MY_SERIAL_NUMBER_off_grid_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title Problem',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_problem',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'off',
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem_2-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_problem_2',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'Problem',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'dc_1_short_circuit_error_status',
+    'unique_id': 'MY_SERIAL_NUMBER_dc_1_short_circuit_error_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem_2-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title Problem',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_problem_2',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'on',
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem_3-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_problem_3',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'Problem',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'dc_2_short_circuit_error_status',
+    'unique_id': 'MY_SERIAL_NUMBER_dc_2_short_circuit_error_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem_3-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title Problem',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_problem_3',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'off',
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem_4-entry]
+  EntityRegistryEntrySnapshot({
+    'aliases': set({
+    }),
+    'area_id': None,
+    'capabilities': None,
+    'config_entry_id': <ANY>,
+    'device_class': None,
+    'device_id': <ANY>,
+    'disabled_by': None,
+    'domain': 'binary_sensor',
+    'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
+    'entity_id': 'binary_sensor.mock_title_problem_4',
+    'has_entity_name': True,
+    'hidden_by': None,
+    'icon': None,
+    'id': <ANY>,
+    'labels': set({
+    }),
+    'name': None,
+    'options': dict({
+    }),
+    'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
+    'original_icon': None,
+    'original_name': 'Problem',
+    'platform': 'apsystems',
+    'previous_unique_id': None,
+    'supported_features': 0,
+    'translation_key': 'output_fault_status',
+    'unique_id': 'MY_SERIAL_NUMBER_output_fault_status',
+    'unit_of_measurement': None,
+  })
+# ---
+# name: test_all_entities[binary_sensor.mock_title_problem_4-state]
+  StateSnapshot({
+    'attributes': ReadOnlyDict({
+      'device_class': 'problem',
+      'friendly_name': 'Mock Title Problem',
+    }),
+    'context': <ANY>,
+    'entity_id': 'binary_sensor.mock_title_problem_4',
+    'last_changed': <ANY>,
+    'last_reported': <ANY>,
+    'last_updated': <ANY>,
+    'state': 'on',
+  })
+# ---
diff --git a/tests/components/apsystems/test_binary_sensor.py b/tests/components/apsystems/test_binary_sensor.py
new file mode 100644
index 00000000000..0c6fbffc93c
--- /dev/null
+++ b/tests/components/apsystems/test_binary_sensor.py
@@ -0,0 +1,31 @@
+"""Test the APSystem binary sensor module."""
+
+from unittest.mock import AsyncMock, patch
+
+from syrupy import SnapshotAssertion
+
+from homeassistant.const import Platform
+from homeassistant.core import HomeAssistant
+from homeassistant.helpers import entity_registry as er
+
+from . import setup_integration
+
+from tests.common import MockConfigEntry, snapshot_platform
+
+
+async def test_all_entities(
+    hass: HomeAssistant,
+    snapshot: SnapshotAssertion,
+    mock_apsystems: AsyncMock,
+    mock_config_entry: MockConfigEntry,
+    entity_registry: er.EntityRegistry,
+) -> None:
+    """Test all entities."""
+    with patch(
+        "homeassistant.components.apsystems.PLATFORMS",
+        [Platform.BINARY_SENSOR],
+    ):
+        await setup_integration(hass, mock_config_entry)
+        await snapshot_platform(
+            hass, entity_registry, snapshot, mock_config_entry.entry_id
+        )
-- 
GitLab