44
55import asyncio
66import base64
7+ import dataclasses
78import hashlib
89import hmac
910import json
@@ -169,7 +170,15 @@ async def refresh_value(self):
169170 await self ._async_value ()
170171
171172
173+ @dataclasses .dataclass
174+ class ListenerModel :
175+ protocol_handlers : dict [RoborockDataProtocol , list [Callable [[Status | Consumable ], None ]]]
176+ cache : dict [CacheableAttribute , AttributeCache ]
177+
178+
172179class RoborockClient :
180+ _listeners : dict [str , ListenerModel ] = {}
181+
173182 def __init__ (self , endpoint : str , device_info : DeviceData , queue_timeout : int = 4 ) -> None :
174183 self .event_loop = get_running_loop_or_create_one ()
175184 self .device_info = device_info
@@ -184,10 +193,12 @@ def __init__(self, endpoint: str, device_info: DeviceData, queue_timeout: int =
184193 self .cache : dict [CacheableAttribute , AttributeCache ] = {
185194 cacheable_attribute : AttributeCache (attr , self ) for cacheable_attribute , attr in get_cache_map ().items ()
186195 }
187- self ._listeners : list [Callable [[str , CacheableAttribute , RoborockBase ], None ]] = []
188196 self .is_available : bool = True
189197 self .queue_timeout = queue_timeout
190198 self ._status_type : type [Status ] = ModelStatus .get (self .device_info .model , S7MaxVStatus )
199+ if device_info .device .duid not in self ._listeners :
200+ self ._listeners [device_info .device .duid ] = ListenerModel ({}, self .cache )
201+ self .listener_model = self ._listeners [device_info .device .duid ]
191202
192203 def __del__ (self ) -> None :
193204 self .release ()
@@ -260,32 +271,36 @@ def on_message_received(self, messages: list[RoborockMessage]) -> None:
260271 data_protocol = RoborockDataProtocol (int (data_point_number ))
261272 self ._logger .debug (f"Got device update for { data_protocol .name } : { data_point } " )
262273 if data_protocol in ROBOROCK_DATA_STATUS_PROTOCOL :
263- if self .cache [ CacheableAttribute . status ]. value is None :
274+ if data_protocol not in self .listener_model . protocol_handlers :
264275 self ._logger .debug (
265276 f"Got status update({ data_protocol .name } ) before get_status was called."
266277 )
267278 return
268- value = self .cache [CacheableAttribute .status ].value
279+ value = self .listener_model . cache [CacheableAttribute .status ].value
269280 value [data_protocol .name ] = data_point
270281 status = self ._status_type .from_dict (value )
271- for listener in self ._listeners :
272- listener (self . device_info . device . duid , CacheableAttribute . status , status )
282+ for listener in self .listener_model . protocol_handlers . get ( data_protocol , []) :
283+ listener (status )
273284 elif data_protocol in ROBOROCK_DATA_CONSUMABLE_PROTOCOL :
274- if self .cache [ CacheableAttribute . consumable ]. value is None :
285+ if data_protocol not in self .listener_model . protocol_handlers :
275286 self ._logger .debug (
276287 f"Got consumable update({ data_protocol .name } )"
277288 + "before get_consumable was called."
278289 )
279290 return
280- value = self .cache [CacheableAttribute .consumable ].value
291+ value = self .listener_model . cache [CacheableAttribute .consumable ].value
281292 value [data_protocol .name ] = data_point
282293 consumable = Consumable .from_dict (value )
283- for listener in self ._listeners :
284- listener (
285- self .device_info .device .duid , CacheableAttribute .consumable , consumable
286- )
294+ for listener in self .listener_model .protocol_handlers .get (data_protocol , []):
295+ listener (consumable )
287296 return
288297 except ValueError :
298+ self ._logger .warning (
299+ f"Got listener data for { data_point_number } , data: { data_point } . "
300+ f"This lets us update data quicker, please open an issue "
301+ f"at https://github.com/humbertogontijo/python-roborock/issues"
302+ )
303+
289304 pass
290305 dps = {data_point_number : data_point }
291306 self ._logger .debug (f"Got unknown data point { dps } " )
@@ -552,8 +567,13 @@ async def get_server_timer(self) -> list[ServerTimer]:
552567 return [ServerTimer (* server_timers )]
553568 return []
554569
555- def add_listener (self , listener : Callable ):
556- self ._listeners .append (listener )
570+ def add_listener (
571+ self , protocol : RoborockDataProtocol , listener : Callable , cache : dict [CacheableAttribute , AttributeCache ]
572+ ):
573+ self .listener_model .cache = cache
574+ if protocol not in self .listener_model .protocol_handlers :
575+ self .listener_model .protocol_handlers [protocol ] = []
576+ self .listener_model .protocol_handlers [protocol ].append (listener )
557577
558578 async def get_from_cache (self , key : CacheableAttribute ) -> AttributeCache | None :
559579 val = self .cache .get (key )
0 commit comments