diff --git a/homeassistant/components/peblar/__init__.py b/homeassistant/components/peblar/__init__.py index 854565081e8..43c48e28bd0 100644 --- a/homeassistant/components/peblar/__init__.py +++ b/homeassistant/components/peblar/__init__.py @@ -29,6 +29,7 @@ from .coordinator import ( ) PLATFORMS = [ + Platform.BINARY_SENSOR, Platform.NUMBER, Platform.SELECT, Platform.SENSOR, diff --git a/homeassistant/components/peblar/binary_sensor.py b/homeassistant/components/peblar/binary_sensor.py new file mode 100644 index 00000000000..f28a02422a9 --- /dev/null +++ b/homeassistant/components/peblar/binary_sensor.py @@ -0,0 +1,89 @@ +"""Support for Peblar binary sensors.""" + +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass + +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DOMAIN +from .coordinator import PeblarConfigEntry, PeblarData, PeblarDataUpdateCoordinator + + +@dataclass(frozen=True, kw_only=True) +class PeblarBinarySensorEntityDescription(BinarySensorEntityDescription): + """Class describing Peblar binary sensor entities.""" + + is_on_fn: Callable[[PeblarData], bool] + + +DESCRIPTIONS = [ + PeblarBinarySensorEntityDescription( + key="active_error_codes", + translation_key="active_error_codes", + device_class=BinarySensorDeviceClass.PROBLEM, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + is_on_fn=lambda x: bool(x.system.active_error_codes), + ), + PeblarBinarySensorEntityDescription( + key="active_warning_codes", + translation_key="active_warning_codes", + device_class=BinarySensorDeviceClass.PROBLEM, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + is_on_fn=lambda x: bool(x.system.active_warning_codes), + ), +] + + +async def async_setup_entry( + hass: HomeAssistant, + entry: PeblarConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up Peblar binary sensor based on a config entry.""" + async_add_entities( + PeblarBinarySensorEntity(entry=entry, description=description) + for description in DESCRIPTIONS + ) + + +class PeblarBinarySensorEntity( + CoordinatorEntity[PeblarDataUpdateCoordinator], BinarySensorEntity +): + """Defines a Peblar binary sensor entity.""" + + entity_description: PeblarBinarySensorEntityDescription + + _attr_has_entity_name = True + + def __init__( + self, + entry: PeblarConfigEntry, + description: PeblarBinarySensorEntityDescription, + ) -> None: + """Initialize the binary sensor entity.""" + super().__init__(entry.runtime_data.data_coordinator) + self.entity_description = description + self._attr_unique_id = f"{entry.unique_id}-{description.key}" + self._attr_device_info = DeviceInfo( + identifiers={ + (DOMAIN, entry.runtime_data.system_information.product_serial_number) + }, + ) + + @property + def is_on(self) -> bool: + """Return state of the binary sensor.""" + return self.entity_description.is_on_fn(self.coordinator.data) diff --git a/homeassistant/components/peblar/icons.json b/homeassistant/components/peblar/icons.json index 2da03b00519..2b24bf71ebc 100644 --- a/homeassistant/components/peblar/icons.json +++ b/homeassistant/components/peblar/icons.json @@ -1,5 +1,13 @@ { "entity": { + "binary_sensor": { + "active_error_codes": { + "default": "mdi:alert" + }, + "active_warning_codes": { + "default": "mdi:alert" + } + }, "number": { "charge_current_limit": { "default": "mdi:speedometer" diff --git a/homeassistant/components/peblar/strings.json b/homeassistant/components/peblar/strings.json index e7e531f3bf7..0632fa31dd0 100644 --- a/homeassistant/components/peblar/strings.json +++ b/homeassistant/components/peblar/strings.json @@ -33,6 +33,14 @@ } }, "entity": { + "binary_sensor": { + "active_error_codes": { + "name": "Active errors" + }, + "active_warning_codes": { + "name": "Active warnings" + } + }, "number": { "charge_current_limit": { "name": "Charge limit" diff --git a/tests/components/peblar/snapshots/test_binary_sensor.ambr b/tests/components/peblar/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..5dd008dd320 --- /dev/null +++ b/tests/components/peblar/snapshots/test_binary_sensor.ambr @@ -0,0 +1,95 @@ +# serializer version: 1 +# name: test_entities[binary_sensor][binary_sensor.peblar_ev_charger_active_errors-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.peblar_ev_charger_active_errors', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Active errors', + 'platform': 'peblar', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'active_error_codes', + 'unique_id': '23-45-A4O-MOF-active_error_codes', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[binary_sensor][binary_sensor.peblar_ev_charger_active_errors-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'problem', + 'friendly_name': 'Peblar EV Charger Active errors', + }), + 'context': , + 'entity_id': 'binary_sensor.peblar_ev_charger_active_errors', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_entities[binary_sensor][binary_sensor.peblar_ev_charger_active_warnings-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.peblar_ev_charger_active_warnings', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Active warnings', + 'platform': 'peblar', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'active_warning_codes', + 'unique_id': '23-45-A4O-MOF-active_warning_codes', + 'unit_of_measurement': None, + }) +# --- +# name: test_entities[binary_sensor][binary_sensor.peblar_ev_charger_active_warnings-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'problem', + 'friendly_name': 'Peblar EV Charger Active warnings', + }), + 'context': , + 'entity_id': 'binary_sensor.peblar_ev_charger_active_warnings', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/peblar/test_binary_sensor.py b/tests/components/peblar/test_binary_sensor.py new file mode 100644 index 00000000000..670b5b67145 --- /dev/null +++ b/tests/components/peblar/test_binary_sensor.py @@ -0,0 +1,35 @@ +"""Tests for the Peblar binary sensor platform.""" + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.peblar.const import DOMAIN +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr, entity_registry as er + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.mark.parametrize("init_integration", [Platform.BINARY_SENSOR], indirect=True) +@pytest.mark.usefixtures("entity_registry_enabled_by_default", "init_integration") +async def test_entities( + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + device_registry: dr.DeviceRegistry, + mock_config_entry: MockConfigEntry, +) -> None: + """Test the binary sensors entities.""" + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + # Ensure all entities are correctly assigned to the Peblar device + device_entry = device_registry.async_get_device( + identifiers={(DOMAIN, "23-45-A4O-MOF")} + ) + assert device_entry + entity_entries = er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + for entity_entry in entity_entries: + assert entity_entry.device_id == device_entry.id