Skip to content

Commit c0a313b

Browse files
authored
feat(q10): add status update listener callback API (#770)
* feat(q10): add status update listener API * style(q10): apply ruff-format to status trait * fix(q10): correct typo in docstring for StatusTrait
1 parent 26b4b8d commit c0a313b

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

roborock/devices/traits/b01/q10/status.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
"""Status trait for Q10 B01 devices."""
22

33
import logging
4+
from collections.abc import Callable
5+
from typing import Any
46

7+
from roborock.callbacks import CallbackList
8+
from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
59
from roborock.data.b01_q10.b01_q10_containers import Q10Status
610

711
from .common import DpsDataConverter
@@ -16,11 +20,22 @@ class StatusTrait(Q10Status):
1620
1721
This is a thin wrapper around Q10Status that provides the Trait interface.
1822
The current values reflect the most recently received data from the device.
19-
New values can be requited through the `Q10PropertiesApi`'s `refresh` method.
23+
New values can be requested through the `Q10PropertiesApi`'s `refresh` method.
2024
"""
2125

22-
def update_from_dps(self, decoded_dps: dict) -> None:
26+
def __init__(self) -> None:
27+
"""Initialize the status trait."""
28+
super().__init__()
29+
self._update_callbacks: CallbackList[dict[B01_Q10_DP, Any]] = CallbackList(logger=_LOGGER)
30+
31+
def add_update_listener(self, callback: Callable[[dict[B01_Q10_DP, Any]], None]) -> Callable[[], None]:
32+
"""Register a callback for decoded DPS updates.
33+
34+
Returns a callable to remove the listener.
35+
"""
36+
return self._update_callbacks.add_callback(callback)
37+
38+
def update_from_dps(self, decoded_dps: dict[B01_Q10_DP, Any]) -> None:
2339
"""Update the trait from raw DPS data."""
2440
_CONVERTER.update_from_dps(self, decoded_dps)
25-
# In the future we can register listeners and notify them here on update
26-
# if `update_from_dps` performed any updates.
41+
self._update_callbacks(decoded_dps)

tests/devices/traits/b01/q10/test_status.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import pytest
1111

1212
from roborock.data.b01_q10.b01_q10_code_mappings import (
13+
B01_Q10_DP,
1314
YXDeviceCleanTask,
1415
YXDeviceState,
1516
YXFanLevel,
@@ -139,3 +140,22 @@ async def test_status_trait_refresh(
139140
assert q10_api.status.battery == 100
140141
assert q10_api.status.status == YXDeviceState.CHARGING_STATE
141142
assert q10_api.status.fan_level == YXFanLevel.NORMAL
143+
144+
145+
def test_status_trait_update_listener(q10_api: Q10PropertiesApi) -> None:
146+
"""Test that status listeners receive updates and can unsubscribe."""
147+
updates: list[dict[B01_Q10_DP, Any]] = []
148+
149+
unsubscribe = q10_api.status.add_update_listener(updates.append)
150+
151+
first_update = {B01_Q10_DP.BATTERY: 88}
152+
q10_api.status.update_from_dps(first_update)
153+
154+
assert updates == [first_update]
155+
156+
unsubscribe()
157+
158+
second_update = {B01_Q10_DP.BATTERY: 87}
159+
q10_api.status.update_from_dps(second_update)
160+
161+
assert updates == [first_update]

0 commit comments

Comments
 (0)