5353"""
5454
5555import logging
56+ from collections .abc import Callable
5657from dataclasses import dataclass , field , fields
5758from typing import Any , get_args
5859
5960from roborock .data .containers import HomeData , HomeDataProduct , RoborockBase
6061from roborock .data .v1 .v1_code_mappings import RoborockDockTypeCode
6162from roborock .devices .cache import DeviceCache
6263from roborock .devices .traits import Trait
64+ from roborock .exceptions import RoborockException
6365from roborock .map .map_parser import MapParserConfig
64- from roborock .protocols .v1_protocol import V1RpcChannel
66+ from roborock .protocols .v1_protocol import V1RpcChannel , decode_data_protocol_message
67+ from roborock .roborock_message import RoborockDataProtocol , RoborockMessage
6568from roborock .web_api import UserWebApiClient
6669
6770from . import (
@@ -176,6 +179,7 @@ def __init__(
176179 rpc_channel : V1RpcChannel ,
177180 mqtt_rpc_channel : V1RpcChannel ,
178181 map_rpc_channel : V1RpcChannel ,
182+ add_dps_listener : Callable [[Callable [[dict [RoborockDataProtocol , Any ]], None ]], Callable [[], None ]],
179183 web_api : UserWebApiClient ,
180184 device_cache : DeviceCache ,
181185 map_parser_config : MapParserConfig | None = None ,
@@ -189,6 +193,8 @@ def __init__(
189193 self ._web_api = web_api
190194 self ._device_cache = device_cache
191195 self ._region = region
196+ self ._unsub : Callable [[], None ] | None = None
197+ self ._add_dps_listener = add_dps_listener
192198
193199 self .device_features = DeviceFeaturesTrait (product , self ._device_cache )
194200 self .status = StatusTrait (self .device_features , region = self ._region )
@@ -227,6 +233,29 @@ def _get_rpc_channel(self, trait: V1TraitMixin) -> V1RpcChannel:
227233 else :
228234 return self ._rpc_channel
229235
236+ async def start (self ) -> None :
237+ """Start the properties API and discover features."""
238+ if self ._unsub :
239+ return
240+ await self .discover_features ()
241+ self ._unsub = self ._add_dps_listener (self ._on_dps_update )
242+
243+ def close (self ) -> None :
244+ if self ._unsub :
245+ self ._unsub ()
246+ self ._unsub = None
247+
248+ def _on_dps_update (self , dps : dict [RoborockDataProtocol , Any ]) -> None :
249+ """Handle incoming messages from the device.
250+
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.
254+ """
255+ _LOGGER .debug ("Received message from device: %s" , dps )
256+ self .status .update_from_dps (dps )
257+ self .consumables .update_from_dps (dps )
258+
230259 async def discover_features (self ) -> None :
231260 """Populate any supported traits that were not initialized in __init__."""
232261 _LOGGER .debug ("Starting optional trait discovery" )
@@ -330,6 +359,7 @@ def create(
330359 rpc_channel : V1RpcChannel ,
331360 mqtt_rpc_channel : V1RpcChannel ,
332361 map_rpc_channel : V1RpcChannel ,
362+ add_dps_listener : Callable [[Callable [[dict [RoborockDataProtocol , Any ]], None ]], Callable [[], None ]],
333363 web_api : UserWebApiClient ,
334364 device_cache : DeviceCache ,
335365 map_parser_config : MapParserConfig | None = None ,
@@ -343,6 +373,7 @@ def create(
343373 rpc_channel ,
344374 mqtt_rpc_channel ,
345375 map_rpc_channel ,
376+ add_dps_listener ,
346377 web_api ,
347378 device_cache ,
348379 map_parser_config ,
0 commit comments