diff --git a/homeassistant/components/kiosker/__init__.py b/homeassistant/components/kiosker/__init__.py index c95dd0d358e2..21ba2bc5f2ef 100644 --- a/homeassistant/components/kiosker/__init__.py +++ b/homeassistant/components/kiosker/__init__.py @@ -7,7 +7,7 @@ from homeassistant.core import HomeAssistant from .coordinator import KioskerConfigEntry, KioskerDataUpdateCoordinator -_PLATFORMS: list[Platform] = [Platform.SENSOR] +_PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: KioskerConfigEntry) -> bool: diff --git a/homeassistant/components/kiosker/binary_sensor.py b/homeassistant/components/kiosker/binary_sensor.py new file mode 100644 index 000000000000..1d03a140e505 --- /dev/null +++ b/homeassistant/components/kiosker/binary_sensor.py @@ -0,0 +1,73 @@ +"""Support for Kiosker 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.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from . import KioskerConfigEntry +from .coordinator import KioskerData +from .entity import KioskerEntity + +# These entities rely on the shared data coordinator instead of per-entity polling. +PARALLEL_UPDATES = 0 + + +@dataclass(frozen=True, kw_only=True) +class KioskerBinarySensorEntityDescription(BinarySensorEntityDescription): + """Describes Kiosker binary sensor entity.""" + + value_fn: Callable[[KioskerData], bool] + + +BINARY_SENSORS: tuple[KioskerBinarySensorEntityDescription, ...] = ( + KioskerBinarySensorEntityDescription( + key="blackoutState", + translation_key="blackout_state", + value_fn=lambda x: x.blackout.visible if x.blackout else False, + ), + KioskerBinarySensorEntityDescription( + key="screensaverState", + translation_key="screensaver_state", + value_fn=lambda x: x.screensaver.visible if x.screensaver else False, + ), + KioskerBinarySensorEntityDescription( + key="charging", + device_class=BinarySensorDeviceClass.BATTERY_CHARGING, + value_fn=lambda x: ( + (x.status.battery_state or "").casefold() in ("charging", "fully charged") + ), + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: KioskerConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up Kiosker binary sensors based on a config entry.""" + coordinator = entry.runtime_data + + async_add_entities( + KioskerBinarySensor(coordinator, description) for description in BINARY_SENSORS + ) + + +class KioskerBinarySensor(KioskerEntity, BinarySensorEntity): + """Representation of a Kiosker binary sensor.""" + + entity_description: KioskerBinarySensorEntityDescription + + @property + def is_on(self) -> bool | None: + """Return the state of the binary sensor.""" + return self.entity_description.value_fn(self.coordinator.data) diff --git a/homeassistant/components/kiosker/icons.json b/homeassistant/components/kiosker/icons.json index b40f689e28ec..749a8d7d02e5 100644 --- a/homeassistant/components/kiosker/icons.json +++ b/homeassistant/components/kiosker/icons.json @@ -1,5 +1,19 @@ { "entity": { + "binary_sensor": { + "blackout_state": { + "default": "mdi:monitor", + "state": { + "on": "mdi:monitor-off" + } + }, + "screensaver_state": { + "default": "mdi:power-sleep", + "state": { + "off": "mdi:monitor-shimmer" + } + } + }, "sensor": { "ambient_light": { "default": "mdi:brightness-6" diff --git a/homeassistant/components/kiosker/strings.json b/homeassistant/components/kiosker/strings.json index 4bee2a50045f..5cd897381e76 100644 --- a/homeassistant/components/kiosker/strings.json +++ b/homeassistant/components/kiosker/strings.json @@ -48,6 +48,14 @@ } }, "entity": { + "binary_sensor": { + "blackout_state": { + "name": "Blackout" + }, + "screensaver_state": { + "name": "Screensaver" + } + }, "sensor": { "ambient_light": { "name": "Ambient light" diff --git a/tests/components/kiosker/snapshots/test_binary_sensor.ambr b/tests/components/kiosker/snapshots/test_binary_sensor.ambr new file mode 100644 index 000000000000..5281a09e6371 --- /dev/null +++ b/tests/components/kiosker/snapshots/test_binary_sensor.ambr @@ -0,0 +1,152 @@ +# serializer version: 1 +# name: test_all_entities[binary_sensor.kiosker_a98be1ce_blackout-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.kiosker_a98be1ce_blackout', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Blackout', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Blackout', + 'platform': 'kiosker', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'blackout_state', + 'unique_id': 'A98BE1CE-5FE7-4A8D-B2C3-123456789ABC_blackoutState', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.kiosker_a98be1ce_blackout-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Kiosker A98BE1CE Blackout', + }), + 'context': , + 'entity_id': 'binary_sensor.kiosker_a98be1ce_blackout', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_all_entities[binary_sensor.kiosker_a98be1ce_charging-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.kiosker_a98be1ce_charging', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Charging', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Charging', + 'platform': 'kiosker', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'A98BE1CE-5FE7-4A8D-B2C3-123456789ABC_charging', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.kiosker_a98be1ce_charging-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery_charging', + 'friendly_name': 'Kiosker A98BE1CE Charging', + }), + 'context': , + 'entity_id': 'binary_sensor.kiosker_a98be1ce_charging', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_all_entities[binary_sensor.kiosker_a98be1ce_screensaver-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.kiosker_a98be1ce_screensaver', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Screensaver', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Screensaver', + 'platform': 'kiosker', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'screensaver_state', + 'unique_id': 'A98BE1CE-5FE7-4A8D-B2C3-123456789ABC_screensaverState', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.kiosker_a98be1ce_screensaver-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Kiosker A98BE1CE Screensaver', + }), + 'context': , + 'entity_id': 'binary_sensor.kiosker_a98be1ce_screensaver', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/kiosker/test_binary_sensor.py b/tests/components/kiosker/test_binary_sensor.py new file mode 100644 index 000000000000..a1b5e0f8ef65 --- /dev/null +++ b/tests/components/kiosker/test_binary_sensor.py @@ -0,0 +1,33 @@ +"""Test the Kiosker binary sensors.""" + +from __future__ import annotations + +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +from syrupy.assertion 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_kiosker_api: MagicMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test all entities.""" + mock_kiosker_api.blackout_get.return_value = SimpleNamespace(visible=True) + mock_kiosker_api.screensaver_get_state.return_value = SimpleNamespace(visible=False) + + with patch("homeassistant.components.kiosker._PLATFORMS", [Platform.BINARY_SENSOR]): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)