From 2631c77bee74fb736384702fff8cd819b1bf2ed4 Mon Sep 17 00:00:00 2001 From: Kevin Stillhammer Date: Tue, 2 Dec 2025 20:05:34 +0100 Subject: [PATCH] add platform binary_sensor to fressnapf_tracker (#157753) --- .../components/fressnapf_tracker/__init__.py | 6 +- .../fressnapf_tracker/binary_sensor.py | 69 +++++++++++++ .../components/fressnapf_tracker/strings.json | 7 ++ .../snapshots/test_binary_sensor.ambr | 99 +++++++++++++++++++ .../fressnapf_tracker/test_binary_sensor.py | 33 +++++++ 5 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/fressnapf_tracker/binary_sensor.py create mode 100644 tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr create mode 100644 tests/components/fressnapf_tracker/test_binary_sensor.py diff --git a/homeassistant/components/fressnapf_tracker/__init__.py b/homeassistant/components/fressnapf_tracker/__init__.py index 930011f366d..6794aa92fe3 100644 --- a/homeassistant/components/fressnapf_tracker/__init__.py +++ b/homeassistant/components/fressnapf_tracker/__init__.py @@ -12,7 +12,11 @@ from .coordinator import ( FressnapfTrackerDataUpdateCoordinator, ) -PLATFORMS: list[Platform] = [Platform.DEVICE_TRACKER, Platform.SENSOR] +PLATFORMS: list[Platform] = [ + Platform.BINARY_SENSOR, + Platform.DEVICE_TRACKER, + Platform.SENSOR, +] async def async_setup_entry( diff --git a/homeassistant/components/fressnapf_tracker/binary_sensor.py b/homeassistant/components/fressnapf_tracker/binary_sensor.py new file mode 100644 index 00000000000..cf0b418afdf --- /dev/null +++ b/homeassistant/components/fressnapf_tracker/binary_sensor.py @@ -0,0 +1,69 @@ +"""Binary Sensor platform for fressnapf_tracker.""" + +from collections.abc import Callable +from dataclasses import dataclass + +from fressnapftracker import Tracker + +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 AddConfigEntryEntitiesCallback + +from . import FressnapfTrackerConfigEntry +from .entity import FressnapfTrackerEntity + + +@dataclass(frozen=True, kw_only=True) +class FressnapfTrackerBinarySensorDescription(BinarySensorEntityDescription): + """Class describing Fressnapf Tracker binary_sensor entities.""" + + value_fn: Callable[[Tracker], bool] + + +BINARY_SENSOR_ENTITY_DESCRIPTIONS: tuple[ + FressnapfTrackerBinarySensorDescription, ... +] = ( + FressnapfTrackerBinarySensorDescription( + key="charging", + device_class=BinarySensorDeviceClass.BATTERY_CHARGING, + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda data: data.charging, + ), + FressnapfTrackerBinarySensorDescription( + translation_key="deep_sleep", + key="deep_sleep_value", + device_class=BinarySensorDeviceClass.POWER, + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda data: bool(data.deep_sleep_value), + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: FressnapfTrackerConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up the Fressnapf Tracker binary_sensors.""" + + async_add_entities( + FressnapfTrackerBinarySensor(coordinator, sensor_description) + for sensor_description in BINARY_SENSOR_ENTITY_DESCRIPTIONS + for coordinator in entry.runtime_data + ) + + +class FressnapfTrackerBinarySensor(FressnapfTrackerEntity, BinarySensorEntity): + """Fressnapf Tracker binary_sensor for general information.""" + + entity_description: FressnapfTrackerBinarySensorDescription + + @property + def is_on(self) -> bool: + """Return True if the binary sensor is on.""" + return self.entity_description.value_fn(self.coordinator.data) diff --git a/homeassistant/components/fressnapf_tracker/strings.json b/homeassistant/components/fressnapf_tracker/strings.json index 666656af114..655183e7e52 100644 --- a/homeassistant/components/fressnapf_tracker/strings.json +++ b/homeassistant/components/fressnapf_tracker/strings.json @@ -45,5 +45,12 @@ } } } + }, + "entity": { + "binary_sensor": { + "deep_sleep": { + "name": "Deep Sleep" + } + } } } diff --git a/tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr b/tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..fac61dcf6b1 --- /dev/null +++ b/tests/components/fressnapf_tracker/snapshots/test_binary_sensor.ambr @@ -0,0 +1,99 @@ +# serializer version: 1 +# name: test_state_entity_device_snapshots[binary_sensor.fluffy_charging-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.fluffy_charging', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Charging', + 'platform': 'fressnapf_tracker', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'ABC123456_charging', + 'unit_of_measurement': None, + }) +# --- +# name: test_state_entity_device_snapshots[binary_sensor.fluffy_charging-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery_charging', + 'friendly_name': 'Fluffy Charging', + }), + 'context': , + 'entity_id': 'binary_sensor.fluffy_charging', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_state_entity_device_snapshots[binary_sensor.fluffy_deep_sleep-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': , + 'entity_id': 'binary_sensor.fluffy_deep_sleep', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Deep Sleep', + 'platform': 'fressnapf_tracker', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'deep_sleep', + 'unique_id': 'ABC123456_deep_sleep_value', + 'unit_of_measurement': None, + }) +# --- +# name: test_state_entity_device_snapshots[binary_sensor.fluffy_deep_sleep-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Fluffy Deep Sleep', + }), + 'context': , + 'entity_id': 'binary_sensor.fluffy_deep_sleep', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/fressnapf_tracker/test_binary_sensor.py b/tests/components/fressnapf_tracker/test_binary_sensor.py new file mode 100644 index 00000000000..c63388fae47 --- /dev/null +++ b/tests/components/fressnapf_tracker/test_binary_sensor.py @@ -0,0 +1,33 @@ +"""Test the Fressnapf Tracker binary_sensor platform.""" + +from collections.abc import AsyncGenerator +from unittest.mock import patch + +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from tests.common import MockConfigEntry, snapshot_platform + + +@pytest.fixture(autouse=True) +async def platforms() -> AsyncGenerator[None]: + """Return the platforms to be loaded for this test.""" + with patch( + "homeassistant.components.fressnapf_tracker.PLATFORMS", [Platform.BINARY_SENSOR] + ): + yield + + +@pytest.mark.usefixtures("init_integration") +async def test_state_entity_device_snapshots( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, +) -> None: + """Test binary_sensor entity is created correctly.""" + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)