Skip to content

Commit 8245d18

Browse files
committed
refactor: inject logger into dps_listeners, improve callback exception handling.
This also renames discover_features to start in v1 properties.
1 parent f3839fb commit 8245d18

5 files changed

Lines changed: 37 additions & 8 deletions

File tree

roborock/callbacks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def wrapper(value: V) -> None:
2626
try:
2727
callback(value)
2828
except Exception as ex: # noqa: BLE001
29-
logger.error("Uncaught error in callback '%s': %s", callback.__name__, ex)
29+
logger.error("Uncaught error in callback '%s': %s", getattr(callback, "__name__", "Unknown"), ex)
3030

3131
return wrapper
3232

roborock/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ async def _v1_trait(context: RoborockContext, device_id: str, display_func: Call
419419
device = await device_manager.get_device(device_id)
420420
if device.v1_properties is None:
421421
raise RoborockUnsupportedFeature(f"Device {device.name} does not support V1 protocol")
422-
await device.v1_properties.discover_features()
422+
await device.v1_properties.start()
423423
trait = display_func(device.v1_properties)
424424
if trait is None:
425425
raise RoborockUnsupportedFeature("Trait not supported by device")

roborock/devices/rpc/v1_channel.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def __init__(
190190
self._device_cache = device_cache
191191
self._reconnect_task: asyncio.Task[None] | None = None
192192
self._last_network_info_refresh: datetime.datetime | None = None
193-
self._dps_listeners = CallbackList[dict[RoborockDataProtocol, Any]]()
193+
self._dps_listeners = CallbackList[dict[RoborockDataProtocol, Any]](self._logger)
194194

195195
@property
196196
def is_connected(self) -> bool:
@@ -452,10 +452,7 @@ def _on_mqtt_message(self, message: RoborockMessage) -> None:
452452
return
453453

454454
if datapoints:
455-
try:
456-
self._dps_listeners(datapoints)
457-
except Exception:
458-
self._logger.exception("Error in DPS listener callback")
455+
self._dps_listeners(datapoints)
459456

460457
def _on_local_message(self, message: RoborockMessage) -> None:
461458
"""Handle incoming local messages."""

roborock/devices/traits/v1/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,9 @@ def close(self) -> None:
248248
def _on_dps_update(self, dps: dict[RoborockDataProtocol, Any]) -> None:
249249
"""Handle incoming messages from the device.
250250
251-
This will notify all traits of the new values.
251+
This will notify all traits of the new values. This can be improved in
252+
the future to be dynamic when we have more traits that support dynamic
253+
updates but for now we just invoke them manually.
252254
"""
253255
_LOGGER.debug("Received message from device: %s", dps)
254256
self.status.update_from_dps(dps)

tests/devices/rpc/test_v1_channel.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,3 +612,33 @@ async def test_v1_channel_add_dps_listener(
612612
dps_listener.reset_mock()
613613
v1_channel._on_mqtt_message(push_message)
614614
dps_listener.assert_not_called()
615+
616+
617+
async def test_v1_channel_dps_listener_raises_exception(
618+
v1_channel: V1Channel,
619+
mock_mqtt_channel: FakeChannel,
620+
) -> None:
621+
"""Test that DPS listener that raises exceptions is ignored."""
622+
mock_mqtt_channel.response_queue.append(TEST_NETWORK_INFO_RESPONSE)
623+
await v1_channel.subscribe(Mock())
624+
625+
# Create a mock listener for DPS updates
626+
dps_listener1 = Mock()
627+
dps_listener1.side_effect = Exception("DPS listener failed")
628+
dps_listener2 = Mock()
629+
unsub_dps1 = v1_channel.add_dps_listener(dps_listener1)
630+
unsub_dps2 = v1_channel.add_dps_listener(dps_listener2)
631+
632+
# Simulate an incoming MQTT message with data protocol payload.
633+
dps_payload = json.dumps({"dps": {"121": 5}}).encode()
634+
push_message = RoborockMessage(
635+
protocol=RoborockMessageProtocol.GENERAL_REQUEST,
636+
payload=dps_payload,
637+
)
638+
mock_mqtt_channel.notify_subscribers(push_message)
639+
640+
dps_listener1.assert_called_once()
641+
dps_listener2.assert_called_once()
642+
643+
unsub_dps1()
644+
unsub_dps2()

0 commit comments

Comments
 (0)