From e6226b092442c9a0d30ce0b166054b495131394b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=ADlio=20Costa?= Date: Mon, 20 Nov 2023 07:07:29 +0000 Subject: [PATCH] Add height sensor to Idasen Desk integration (#103324) --- .../components/idasen_desk/__init__.py | 2 +- .../components/idasen_desk/manifest.json | 2 +- .../components/idasen_desk/sensor.py | 100 ++++++++++++++++++ .../components/idasen_desk/strings.json | 7 ++ requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/idasen_desk/conftest.py | 1 + tests/components/idasen_desk/test_sensors.py | 27 +++++ 8 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 homeassistant/components/idasen_desk/sensor.py create mode 100644 tests/components/idasen_desk/test_sensors.py diff --git a/homeassistant/components/idasen_desk/__init__.py b/homeassistant/components/idasen_desk/__init__.py index 564406d423e..5e112aa39f7 100644 --- a/homeassistant/components/idasen_desk/__init__.py +++ b/homeassistant/components/idasen_desk/__init__.py @@ -24,7 +24,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN -PLATFORMS: list[Platform] = [Platform.BUTTON, Platform.COVER] +PLATFORMS: list[Platform] = [Platform.BUTTON, Platform.COVER, Platform.SENSOR] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/idasen_desk/manifest.json b/homeassistant/components/idasen_desk/manifest.json index 9681b2136e1..0a96a976bb3 100644 --- a/homeassistant/components/idasen_desk/manifest.json +++ b/homeassistant/components/idasen_desk/manifest.json @@ -12,5 +12,5 @@ "documentation": "https://www.home-assistant.io/integrations/idasen_desk", "iot_class": "local_push", "quality_scale": "silver", - "requirements": ["idasen-ha==2.3"] + "requirements": ["idasen-ha==2.4"] } diff --git a/homeassistant/components/idasen_desk/sensor.py b/homeassistant/components/idasen_desk/sensor.py new file mode 100644 index 00000000000..cb9668dc8f7 --- /dev/null +++ b/homeassistant/components/idasen_desk/sensor.py @@ -0,0 +1,100 @@ +"""Representation of Idasen Desk sensors.""" +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +from typing import Any + +from homeassistant import config_entries +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) +from homeassistant.const import UnitOfLength +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from . import DeskData, IdasenDeskCoordinator +from .const import DOMAIN + + +@dataclass +class IdasenDeskSensorDescriptionMixin: + """Required values for IdasenDesk sensors.""" + + value_fn: Callable[[IdasenDeskCoordinator], float | None] + + +@dataclass +class IdasenDeskSensorDescription( + SensorEntityDescription, + IdasenDeskSensorDescriptionMixin, +): + """Class describing IdasenDesk sensor entities.""" + + +SENSORS = ( + IdasenDeskSensorDescription( + key="height", + translation_key="height", + icon="mdi:arrow-up-down", + native_unit_of_measurement=UnitOfLength.METERS, + device_class=SensorDeviceClass.DISTANCE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + suggested_display_precision=3, + value_fn=lambda coordinator: coordinator.desk.height, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: config_entries.ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up Idasen Desk sensors.""" + data: DeskData = hass.data[DOMAIN][entry.entry_id] + async_add_entities( + IdasenDeskSensor( + data.address, data.device_info, data.coordinator, sensor_description + ) + for sensor_description in SENSORS + ) + + +class IdasenDeskSensor(CoordinatorEntity, SensorEntity): + """IdasenDesk sensor.""" + + entity_description: IdasenDeskSensorDescription + _attr_has_entity_name = True + + def __init__( + self, + address: str, + device_info: DeviceInfo, + coordinator: IdasenDeskCoordinator, + description: IdasenDeskSensorDescription, + ) -> None: + """Initialize the IdasenDesk sensor entity.""" + super().__init__(coordinator) + self.entity_description = description + + self._attr_unique_id = f"{description.key}-{address}" + self._attr_device_info = device_info + self._address = address + + async def async_added_to_hass(self) -> None: + """When entity is added to hass.""" + await super().async_added_to_hass() + self._handle_coordinator_update() + + @callback + def _handle_coordinator_update(self, *args: Any) -> None: + """Handle data update.""" + self._attr_native_value = self.entity_description.value_fn(self.coordinator) + super()._handle_coordinator_update() diff --git a/homeassistant/components/idasen_desk/strings.json b/homeassistant/components/idasen_desk/strings.json index 6b9bf80edfc..446ef93e542 100644 --- a/homeassistant/components/idasen_desk/strings.json +++ b/homeassistant/components/idasen_desk/strings.json @@ -19,5 +19,12 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", "no_devices_found": "No unconfigured devices found. Make sure that the desk is in Bluetooth pairing mode. Enter pairing mode by pressing the small button with the Bluetooth logo on the controller for about 3 seconds, until it starts blinking." } + }, + "entity": { + "sensor": { + "height": { + "name": "Height" + } + } } } diff --git a/requirements_all.txt b/requirements_all.txt index 3f28c8b18f1..780d2264f9c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1061,7 +1061,7 @@ ical==6.1.0 icmplib==3.0 # homeassistant.components.idasen_desk -idasen-ha==2.3 +idasen-ha==2.4 # homeassistant.components.network ifaddr==0.2.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d09c4dfa292..9ac9060abab 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -836,7 +836,7 @@ ical==6.1.0 icmplib==3.0 # homeassistant.components.idasen_desk -idasen-ha==2.3 +idasen-ha==2.4 # homeassistant.components.network ifaddr==0.2.0 diff --git a/tests/components/idasen_desk/conftest.py b/tests/components/idasen_desk/conftest.py index d6c2ba5ad6b..8159039aff4 100644 --- a/tests/components/idasen_desk/conftest.py +++ b/tests/components/idasen_desk/conftest.py @@ -55,6 +55,7 @@ def mock_desk_api(): mock_desk.move_up = AsyncMock(side_effect=mock_move_up) mock_desk.move_down = AsyncMock(side_effect=mock_move_down) mock_desk.stop = AsyncMock() + mock_desk.height = 1 mock_desk.height_percent = 60 mock_desk.is_moving = False mock_desk.address = "AA:BB:CC:DD:EE:FF" diff --git a/tests/components/idasen_desk/test_sensors.py b/tests/components/idasen_desk/test_sensors.py new file mode 100644 index 00000000000..23d7ac2447b --- /dev/null +++ b/tests/components/idasen_desk/test_sensors.py @@ -0,0 +1,27 @@ +"""Test the IKEA Idasen Desk sensors.""" +from unittest.mock import MagicMock + +from homeassistant.core import HomeAssistant + +from . import init_integration + + +async def test_height_sensor( + hass: HomeAssistant, + mock_desk_api: MagicMock, + entity_registry_enabled_by_default: None, +) -> None: + """Test height sensor.""" + await init_integration(hass) + + entity_id = "sensor.test_height" + state = hass.states.get(entity_id) + assert state + assert state.state == "1" + + mock_desk_api.height = 1.2 + mock_desk_api.trigger_update_callback(None) + + state = hass.states.get(entity_id) + assert state + assert state.state == "1.2"