44import math
55import struct
66import time
7- from abc import ABC
7+ from abc import ABC , abstractmethod
88from collections .abc import Callable , Coroutine
99from typing import Any , TypeVar , final
1010
7878EVICT_TIME = 60
7979
8080
81+ _SendCommandT = Callable [[RoborockCommand | str , list | dict | int | None ], Any ]
82+
83+
8184class AttributeCache :
82- def __init__ (self , attribute : RoborockAttribute , api : RoborockClient ):
85+ def __init__ (self , attribute : RoborockAttribute , loop : asyncio . AbstractEventLoop , send_command : _SendCommandT ):
8386 self .attribute = attribute
84- self .api = api
87+ self ._send_command = send_command
8588 self .attribute = attribute
86- self .task = RepeatableTask (self . api . event_loop , self ._async_value , EVICT_TIME )
89+ self .task = RepeatableTask (loop , self ._async_value , EVICT_TIME )
8790 self ._value : Any = None
8891 self ._mutex = asyncio .Lock ()
8992 self .unsupported : bool = False
@@ -96,7 +99,7 @@ async def _async_value(self):
9699 if self .unsupported :
97100 return None
98101 try :
99- self ._value = await self .api . _send_command (self .attribute .get_command )
102+ self ._value = await self ._send_command (self .attribute .get_command , None )
100103 except UnknownMethodError as err :
101104 # Limit the amount of times we call unsupported methods
102105 self .unsupported = True
@@ -115,21 +118,21 @@ def stop(self):
115118 async def update_value (self , params ) -> None :
116119 if self .attribute .set_command is None :
117120 raise RoborockException (f"{ self .attribute .attribute } have no set command" )
118- response = await self .api . _send_command (self .attribute .set_command , params )
121+ response = await self ._send_command (self .attribute .set_command , params )
119122 await self ._async_value ()
120123 return response
121124
122125 async def add_value (self , params ):
123126 if self .attribute .add_command is None :
124127 raise RoborockException (f"{ self .attribute .attribute } have no add command" )
125- response = await self .api . _send_command (self .attribute .add_command , params )
128+ response = await self ._send_command (self .attribute .add_command , params )
126129 await self ._async_value ()
127130 return response
128131
129132 async def close_value (self , params = None ) -> None :
130133 if self .attribute .close_command is None :
131134 raise RoborockException (f"{ self .attribute .attribute } have no close command" )
132- response = await self .api . _send_command (self .attribute .close_command , params )
135+ response = await self ._send_command (self .attribute .close_command , params )
133136 await self ._async_value ()
134137 return response
135138
@@ -153,7 +156,8 @@ def __init__(self, device_info: DeviceData, endpoint: str):
153156 super ().__init__ (device_info )
154157 self ._status_type : type [Status ] = ModelStatus .get (device_info .model , S7MaxVStatus )
155158 self .cache : dict [CacheableAttribute , AttributeCache ] = {
156- cacheable_attribute : AttributeCache (attr , self ) for cacheable_attribute , attr in get_cache_map ().items ()
159+ cacheable_attribute : AttributeCache (attr , self .event_loop , self ._send_command )
160+ for cacheable_attribute , attr in get_cache_map ().items ()
157161 }
158162 if device_info .device .duid not in self ._listeners :
159163 self ._listeners [device_info .device .duid ] = ListenerModel ({}, self .cache )
@@ -364,6 +368,14 @@ def _get_payload(
364368 )
365369 return request_id , timestamp , payload
366370
371+ @abstractmethod
372+ async def _send_command (
373+ self ,
374+ method : RoborockCommand | str ,
375+ params : list | dict | int | None = None ,
376+ ) -> Any :
377+ """Send a command to the Roborock device."""
378+
367379 def on_message_received (self , messages : list [RoborockMessage ]) -> None :
368380 try :
369381 self ._last_device_msg_in = time .monotonic ()
0 commit comments