Debounce updates in Idasen Desk (#153503)

This commit is contained in:
Abílio Costa
2025-10-03 17:26:13 +00:00
committed by Franck Nijhof
parent cd56a6a98d
commit e0afcbc02b
4 changed files with 59 additions and 10 deletions
@@ -8,13 +8,16 @@ from idasen_ha import Desk
from homeassistant.components import bluetooth
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.debounce import Debouncer
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
_LOGGER = logging.getLogger(__name__)
type IdasenDeskConfigEntry = ConfigEntry[IdasenDeskCoordinator]
UPDATE_DEBOUNCE_TIME = 0.2
class IdasenDeskCoordinator(DataUpdateCoordinator[int | None]):
"""Class to manage updates for the Idasen Desk."""
@@ -33,9 +36,22 @@ class IdasenDeskCoordinator(DataUpdateCoordinator[int | None]):
hass, _LOGGER, config_entry=config_entry, name=config_entry.title
)
self.address = address
self._expected_connected = False
self.desk = Desk(self._async_handle_update)
self.desk = Desk(self.async_set_updated_data)
self._expected_connected = False
self._height: int | None = None
@callback
def async_update_data() -> None:
self.async_set_updated_data(self._height)
self._debouncer = Debouncer(
hass=self.hass,
logger=_LOGGER,
cooldown=UPDATE_DEBOUNCE_TIME,
immediate=True,
function=async_update_data,
)
async def async_connect(self) -> bool:
"""Connect to desk."""
@@ -60,3 +76,9 @@ class IdasenDeskCoordinator(DataUpdateCoordinator[int | None]):
"""Ensure that the desk is connected if that is the expected state."""
if self._expected_connected:
await self.async_connect()
@callback
def _async_handle_update(self, height: int | None) -> None:
"""Handle an update from the desk."""
self._height = height
self._debouncer.async_schedule_call()
+2
View File
@@ -38,6 +38,8 @@ NOT_IDASEN_DISCOVERY_INFO = BluetoothServiceInfoBleak(
tx_power=-127,
)
UPDATE_DEBOUNCE_TIME = 0.2
async def init_integration(hass: HomeAssistant) -> MockConfigEntry:
"""Set up the IKEA Idasen Desk integration in Home Assistant."""
+12 -5
View File
@@ -4,6 +4,7 @@ from typing import Any
from unittest.mock import AsyncMock, MagicMock
from bleak.exc import BleakError
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components.cover import (
@@ -22,12 +23,13 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from . import init_integration
from . import UPDATE_DEBOUNCE_TIME, init_integration
from tests.common import async_fire_time_changed
async def test_cover_available(
hass: HomeAssistant,
mock_desk_api: MagicMock,
hass: HomeAssistant, mock_desk_api: MagicMock, freezer: FrozenDateTimeFactory
) -> None:
"""Test cover available property."""
entity_id = "cover.test"
@@ -42,6 +44,9 @@ async def test_cover_available(
mock_desk_api.is_connected = False
mock_desk_api.trigger_update_callback(None)
freezer.tick(UPDATE_DEBOUNCE_TIME)
async_fire_time_changed(hass)
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_UNAVAILABLE
@@ -64,6 +69,7 @@ async def test_cover_services(
service_data: dict[str, Any],
expected_state: str,
expected_position: int,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test cover services."""
entity_id = "cover.test"
@@ -78,7 +84,9 @@ async def test_cover_services(
{"entity_id": entity_id, **service_data},
blocking=True,
)
await hass.async_block_till_done()
freezer.tick(UPDATE_DEBOUNCE_TIME)
async_fire_time_changed(hass)
state = hass.states.get(entity_id)
assert state
assert state.state == expected_state
@@ -113,4 +121,3 @@ async def test_cover_services_exception(
{"entity_id": entity_id, **service_data},
blocking=True,
)
await hass.async_block_till_done()
+20 -2
View File
@@ -2,18 +2,23 @@
from unittest.mock import MagicMock
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from . import init_integration
from . import UPDATE_DEBOUNCE_TIME, init_integration
from tests.common import async_fire_time_changed
EXPECTED_INITIAL_HEIGHT = "1"
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_height_sensor(hass: HomeAssistant, mock_desk_api: MagicMock) -> None:
async def test_height_sensor(
hass: HomeAssistant, mock_desk_api: MagicMock, freezer: FrozenDateTimeFactory
) -> None:
"""Test height sensor."""
await init_integration(hass)
@@ -24,6 +29,15 @@ async def test_height_sensor(hass: HomeAssistant, mock_desk_api: MagicMock) -> N
mock_desk_api.height = 1.2
mock_desk_api.trigger_update_callback(None)
await hass.async_block_till_done()
# State should still be the same due to the debouncer
state = hass.states.get(entity_id)
assert state
assert state.state == EXPECTED_INITIAL_HEIGHT
freezer.tick(UPDATE_DEBOUNCE_TIME)
async_fire_time_changed(hass)
state = hass.states.get(entity_id)
assert state
@@ -34,6 +48,7 @@ async def test_height_sensor(hass: HomeAssistant, mock_desk_api: MagicMock) -> N
async def test_sensor_available(
hass: HomeAssistant,
mock_desk_api: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test sensor available property."""
await init_integration(hass)
@@ -46,6 +61,9 @@ async def test_sensor_available(
mock_desk_api.is_connected = False
mock_desk_api.trigger_update_callback(None)
freezer.tick(UPDATE_DEBOUNCE_TIME)
async_fire_time_changed(hass)
state = hass.states.get(entity_id)
assert state
assert state.state == STATE_UNAVAILABLE