Skip to content

Commit e0afcbc

Browse files
abmantisfrenck
authored andcommitted
Debounce updates in Idasen Desk (home-assistant#153503)
1 parent cd56a6a commit e0afcbc

File tree

4 files changed

+58
-9
lines changed

4 files changed

+58
-9
lines changed

homeassistant/components/idasen_desk/coordinator.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88

99
from homeassistant.components import bluetooth
1010
from homeassistant.config_entries import ConfigEntry
11-
from homeassistant.core import HomeAssistant
11+
from homeassistant.core import HomeAssistant, callback
12+
from homeassistant.helpers.debounce import Debouncer
1213
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
1314

1415
_LOGGER = logging.getLogger(__name__)
1516

1617
type IdasenDeskConfigEntry = ConfigEntry[IdasenDeskCoordinator]
1718

19+
UPDATE_DEBOUNCE_TIME = 0.2
20+
1821

1922
class IdasenDeskCoordinator(DataUpdateCoordinator[int | None]):
2023
"""Class to manage updates for the Idasen Desk."""
@@ -33,9 +36,22 @@ def __init__(
3336
hass, _LOGGER, config_entry=config_entry, name=config_entry.title
3437
)
3538
self.address = address
39+
self.desk = Desk(self._async_handle_update)
40+
3641
self._expected_connected = False
42+
self._height: int | None = None
3743

38-
self.desk = Desk(self.async_set_updated_data)
44+
@callback
45+
def async_update_data() -> None:
46+
self.async_set_updated_data(self._height)
47+
48+
self._debouncer = Debouncer(
49+
hass=self.hass,
50+
logger=_LOGGER,
51+
cooldown=UPDATE_DEBOUNCE_TIME,
52+
immediate=True,
53+
function=async_update_data,
54+
)
3955

4056
async def async_connect(self) -> bool:
4157
"""Connect to desk."""
@@ -60,3 +76,9 @@ async def async_connect_if_expected(self) -> None:
6076
"""Ensure that the desk is connected if that is the expected state."""
6177
if self._expected_connected:
6278
await self.async_connect()
79+
80+
@callback
81+
def _async_handle_update(self, height: int | None) -> None:
82+
"""Handle an update from the desk."""
83+
self._height = height
84+
self._debouncer.async_schedule_call()

tests/components/idasen_desk/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
tx_power=-127,
3939
)
4040

41+
UPDATE_DEBOUNCE_TIME = 0.2
42+
4143

4244
async def init_integration(hass: HomeAssistant) -> MockConfigEntry:
4345
"""Set up the IKEA Idasen Desk integration in Home Assistant."""

tests/components/idasen_desk/test_cover.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from unittest.mock import AsyncMock, MagicMock
55

66
from bleak.exc import BleakError
7+
from freezegun.api import FrozenDateTimeFactory
78
import pytest
89

910
from homeassistant.components.cover import (
@@ -22,12 +23,13 @@
2223
from homeassistant.core import HomeAssistant
2324
from homeassistant.exceptions import HomeAssistantError
2425

25-
from . import init_integration
26+
from . import UPDATE_DEBOUNCE_TIME, init_integration
27+
28+
from tests.common import async_fire_time_changed
2629

2730

2831
async def test_cover_available(
29-
hass: HomeAssistant,
30-
mock_desk_api: MagicMock,
32+
hass: HomeAssistant, mock_desk_api: MagicMock, freezer: FrozenDateTimeFactory
3133
) -> None:
3234
"""Test cover available property."""
3335
entity_id = "cover.test"
@@ -42,6 +44,9 @@ async def test_cover_available(
4244
mock_desk_api.is_connected = False
4345
mock_desk_api.trigger_update_callback(None)
4446

47+
freezer.tick(UPDATE_DEBOUNCE_TIME)
48+
async_fire_time_changed(hass)
49+
4550
state = hass.states.get(entity_id)
4651
assert state
4752
assert state.state == STATE_UNAVAILABLE
@@ -64,6 +69,7 @@ async def test_cover_services(
6469
service_data: dict[str, Any],
6570
expected_state: str,
6671
expected_position: int,
72+
freezer: FrozenDateTimeFactory,
6773
) -> None:
6874
"""Test cover services."""
6975
entity_id = "cover.test"
@@ -78,7 +84,9 @@ async def test_cover_services(
7884
{"entity_id": entity_id, **service_data},
7985
blocking=True,
8086
)
81-
await hass.async_block_till_done()
87+
freezer.tick(UPDATE_DEBOUNCE_TIME)
88+
async_fire_time_changed(hass)
89+
8290
state = hass.states.get(entity_id)
8391
assert state
8492
assert state.state == expected_state
@@ -113,4 +121,3 @@ async def test_cover_services_exception(
113121
{"entity_id": entity_id, **service_data},
114122
blocking=True,
115123
)
116-
await hass.async_block_till_done()

tests/components/idasen_desk/test_sensor.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,23 @@
22

33
from unittest.mock import MagicMock
44

5+
from freezegun.api import FrozenDateTimeFactory
56
import pytest
67

78
from homeassistant.const import STATE_UNAVAILABLE
89
from homeassistant.core import HomeAssistant
910

10-
from . import init_integration
11+
from . import UPDATE_DEBOUNCE_TIME, init_integration
12+
13+
from tests.common import async_fire_time_changed
1114

1215
EXPECTED_INITIAL_HEIGHT = "1"
1316

1417

1518
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
16-
async def test_height_sensor(hass: HomeAssistant, mock_desk_api: MagicMock) -> None:
19+
async def test_height_sensor(
20+
hass: HomeAssistant, mock_desk_api: MagicMock, freezer: FrozenDateTimeFactory
21+
) -> None:
1722
"""Test height sensor."""
1823
await init_integration(hass)
1924

@@ -24,6 +29,15 @@ async def test_height_sensor(hass: HomeAssistant, mock_desk_api: MagicMock) -> N
2429

2530
mock_desk_api.height = 1.2
2631
mock_desk_api.trigger_update_callback(None)
32+
await hass.async_block_till_done()
33+
34+
# State should still be the same due to the debouncer
35+
state = hass.states.get(entity_id)
36+
assert state
37+
assert state.state == EXPECTED_INITIAL_HEIGHT
38+
39+
freezer.tick(UPDATE_DEBOUNCE_TIME)
40+
async_fire_time_changed(hass)
2741

2842
state = hass.states.get(entity_id)
2943
assert state
@@ -34,6 +48,7 @@ async def test_height_sensor(hass: HomeAssistant, mock_desk_api: MagicMock) -> N
3448
async def test_sensor_available(
3549
hass: HomeAssistant,
3650
mock_desk_api: MagicMock,
51+
freezer: FrozenDateTimeFactory,
3752
) -> None:
3853
"""Test sensor available property."""
3954
await init_integration(hass)
@@ -46,6 +61,9 @@ async def test_sensor_available(
4661
mock_desk_api.is_connected = False
4762
mock_desk_api.trigger_update_callback(None)
4863

64+
freezer.tick(UPDATE_DEBOUNCE_TIME)
65+
async_fire_time_changed(hass)
66+
4967
state = hass.states.get(entity_id)
5068
assert state
5169
assert state.state == STATE_UNAVAILABLE

0 commit comments

Comments
 (0)