From 80dbce14ec31f30c74f094aff486ac8f8baa8cb3 Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Sat, 28 Dec 2024 16:49:14 +0100 Subject: [PATCH] Add binary sensor to Tile (#134153) --- homeassistant/components/tile/__init__.py | 2 +- .../components/tile/binary_sensor.py | 69 +++++++++++++++++++ homeassistant/components/tile/icons.json | 5 ++ homeassistant/components/tile/strings.json | 7 ++ .../tile/snapshots/test_binary_sensor.ambr | 47 +++++++++++++ tests/components/tile/test_binary_sensor.py | 27 ++++++++ 6 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/tile/binary_sensor.py create mode 100644 tests/components/tile/snapshots/test_binary_sensor.ambr create mode 100644 tests/components/tile/test_binary_sensor.py diff --git a/homeassistant/components/tile/__init__.py b/homeassistant/components/tile/__init__.py index 5c0bbbb42ff..4b7dc9ca3b5 100644 --- a/homeassistant/components/tile/__init__.py +++ b/homeassistant/components/tile/__init__.py @@ -13,7 +13,7 @@ from homeassistant.util.async_ import gather_with_limited_concurrency from .coordinator import TileConfigEntry, TileCoordinator -PLATFORMS = [Platform.DEVICE_TRACKER] +PLATFORMS = [Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER] DEVICE_TYPES = ["PHONE", "TILE"] DEFAULT_INIT_TASK_LIMIT = 2 diff --git a/homeassistant/components/tile/binary_sensor.py b/homeassistant/components/tile/binary_sensor.py new file mode 100644 index 00000000000..1719c793c0e --- /dev/null +++ b/homeassistant/components/tile/binary_sensor.py @@ -0,0 +1,69 @@ +"""Support for Tile binary sensors.""" + +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass + +from pytile.tile import Tile + +from homeassistant.components.binary_sensor import ( + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from .coordinator import TileConfigEntry, TileCoordinator +from .entity import TileEntity + + +@dataclass(frozen=True, kw_only=True) +class TileBinarySensorEntityDescription(BinarySensorEntityDescription): + """Describes Tile binary sensor entity.""" + + is_on_fn: Callable[[Tile], bool] + + +ENTITIES: tuple[TileBinarySensorEntityDescription, ...] = ( + TileBinarySensorEntityDescription( + key="lost", + translation_key="lost", + is_on_fn=lambda tile: tile.lost, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, entry: TileConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up Tile binary sensors.""" + + async_add_entities( + TileBinarySensor(coordinator, entity_description) + for entity_description in ENTITIES + for coordinator in entry.runtime_data.values() + ) + + +class TileBinarySensor(TileEntity, BinarySensorEntity): + """Representation of a Tile binary sensor.""" + + entity_description: TileBinarySensorEntityDescription + + def __init__( + self, + coordinator: TileCoordinator, + description: TileBinarySensorEntityDescription, + ) -> None: + """Initialize.""" + super().__init__(coordinator) + self.entity_description = description + self._attr_unique_id = ( + f"{coordinator.username}_{self._tile.uuid}_{description.key}" + ) + + @property + def is_on(self) -> bool: + """Return True if the binary sensor is on.""" + return self.entity_description.is_on_fn(self._tile) diff --git a/homeassistant/components/tile/icons.json b/homeassistant/components/tile/icons.json index f6f38fe8cef..bac7cfcdcb0 100644 --- a/homeassistant/components/tile/icons.json +++ b/homeassistant/components/tile/icons.json @@ -1,5 +1,10 @@ { "entity": { + "binary_sensor": { + "lost": { + "default": "mdi:map-marker-remove" + } + }, "device_tracker": { "tile": { "default": "mdi:view-grid" diff --git a/homeassistant/components/tile/strings.json b/homeassistant/components/tile/strings.json index 2d34d13c436..5146a5e9aff 100644 --- a/homeassistant/components/tile/strings.json +++ b/homeassistant/components/tile/strings.json @@ -33,5 +33,12 @@ } } } + }, + "entity": { + "binary_sensor": { + "lost": { + "name": "Lost" + } + } } } diff --git a/tests/components/tile/snapshots/test_binary_sensor.ambr b/tests/components/tile/snapshots/test_binary_sensor.ambr new file mode 100644 index 00000000000..5f72f53fa1e --- /dev/null +++ b/tests/components/tile/snapshots/test_binary_sensor.ambr @@ -0,0 +1,47 @@ +# serializer version: 1 +# name: test_all_entities[binary_sensor.wallet_lost-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': None, + 'entity_id': 'binary_sensor.wallet_lost', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Lost', + 'platform': 'tile', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'lost', + 'unique_id': 'user@host.com_19264d2dffdbca32_lost', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.wallet_lost-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Wallet Lost', + }), + 'context': , + 'entity_id': 'binary_sensor.wallet_lost', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/tile/test_binary_sensor.py b/tests/components/tile/test_binary_sensor.py new file mode 100644 index 00000000000..c8b4b9b8376 --- /dev/null +++ b/tests/components/tile/test_binary_sensor.py @@ -0,0 +1,27 @@ +"""Tests for the Tile Binary sensor platform.""" + +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_pytile: AsyncMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, +) -> None: + """Test all entities.""" + with patch("homeassistant.components.tile.PLATFORMS", [Platform.BINARY_SENSOR]): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)