Skip to content

Commit 0e214cd

Browse files
fix: adding fallback cache (to be tested)
1 parent 0ba4fef commit 0e214cd

File tree

2 files changed

+102
-99
lines changed

2 files changed

+102
-99
lines changed

roborock/api.py

Lines changed: 79 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
from .roborock_future import RoborockFuture
5252
from .roborock_message import RoborockMessage
5353
from .roborock_typing import DeviceProp, DockSummary, RoborockCommand
54-
from .util import unpack_list
54+
from .util import fallback_cache, unpack_list
5555

5656
_LOGGER = logging.getLogger(__name__)
5757
KEEPALIVE = 60
@@ -77,11 +77,11 @@ async def request(self, method: str, url: str, params=None, data=None, headers=N
7777
_headers = {**self.base_headers, **(headers or {})}
7878
async with aiohttp.ClientSession() as session:
7979
async with session.request(
80-
method,
81-
_url,
82-
params=params,
83-
data=data,
84-
headers=_headers,
80+
method,
81+
_url,
82+
params=params,
83+
data=data,
84+
headers=_headers,
8585
) as resp:
8686
return await resp.json()
8787

@@ -173,7 +173,7 @@ def on_connection_lost(self, exc: Optional[Exception]) -> None:
173173
def should_keepalive(self) -> bool:
174174
now = self.time_func()
175175
# noinspection PyUnresolvedReferences
176-
if now - self._last_disconnection > self.keep_alive**2 and now - self._last_device_msg_in > self.keep_alive:
176+
if now - self._last_disconnection > self.keep_alive ** 2 and now - self._last_device_msg_in > self.keep_alive:
177177
return False
178178
return True
179179

@@ -194,10 +194,10 @@ async def _async_response(self, request_id: int, protocol_id: int = 0) -> tuple[
194194
del self._waiting_queue[request_id]
195195

196196
def _get_payload(
197-
self,
198-
method: RoborockCommand,
199-
params: Optional[list | dict] = None,
200-
secured=False,
197+
self,
198+
method: RoborockCommand,
199+
params: Optional[list | dict] = None,
200+
secured=False,
201201
):
202202
timestamp = math.floor(time.time())
203203
request_id = randint(10000, 99999)
@@ -225,115 +225,98 @@ def _get_payload(
225225
async def send_command(self, method: RoborockCommand, params: Optional[list | dict] = None):
226226
raise NotImplementedError
227227

228+
@fallback_cache()
228229
async def get_status(self) -> Status | None:
229230
status = await self.send_command(RoborockCommand.GET_STATUS)
230231
if isinstance(status, dict):
231232
_cls: Type[Status] = ModelStatus.get(
232233
self.device_info.model, S7MaxVStatus
233234
) # Default to S7 MAXV if we don't have the data
234235
return _cls.from_dict(status)
235-
236236
return None
237237

238+
@fallback_cache()
238239
async def get_dnd_timer(self) -> DnDTimer | None:
239-
try:
240-
dnd_timer = await self.send_command(RoborockCommand.GET_DND_TIMER)
241-
if isinstance(dnd_timer, dict):
242-
return DnDTimer.from_dict(dnd_timer)
243-
except RoborockTimeout as e:
244-
_LOGGER.error(e)
240+
dnd_timer = await self.send_command(RoborockCommand.GET_DND_TIMER)
241+
if isinstance(dnd_timer, dict):
242+
return DnDTimer.from_dict(dnd_timer)
245243
return None
246244

245+
@fallback_cache()
247246
async def get_clean_summary(self) -> CleanSummary | None:
248-
try:
249-
clean_summary = await self.send_command(RoborockCommand.GET_CLEAN_SUMMARY)
250-
if isinstance(clean_summary, dict):
251-
return CleanSummary.from_dict(clean_summary)
252-
elif isinstance(clean_summary, list):
253-
clean_time, clean_area, clean_count, records = unpack_list(clean_summary, 4)
254-
return CleanSummary(
255-
clean_time=clean_time,
256-
clean_area=clean_area,
257-
clean_count=clean_count,
258-
records=records,
259-
)
260-
elif isinstance(clean_summary, int):
261-
return CleanSummary(clean_time=clean_summary)
262-
except RoborockTimeout as e:
263-
_LOGGER.error(e)
247+
clean_summary = await self.send_command(RoborockCommand.GET_CLEAN_SUMMARY)
248+
if isinstance(clean_summary, dict):
249+
return CleanSummary.from_dict(clean_summary)
250+
elif isinstance(clean_summary, list):
251+
clean_time, clean_area, clean_count, records = unpack_list(clean_summary, 4)
252+
return CleanSummary(
253+
clean_time=clean_time,
254+
clean_area=clean_area,
255+
clean_count=clean_count,
256+
records=records,
257+
)
258+
elif isinstance(clean_summary, int):
259+
return CleanSummary(clean_time=clean_summary)
264260
return None
265261

262+
@fallback_cache()
266263
async def get_clean_record(self, record_id: int) -> CleanRecord | None:
267-
try:
268-
clean_record = await self.send_command(RoborockCommand.GET_CLEAN_RECORD, [record_id])
269-
if isinstance(clean_record, dict):
270-
return CleanRecord.from_dict(clean_record)
271-
except RoborockTimeout as e:
272-
_LOGGER.error(e)
264+
clean_record = await self.send_command(RoborockCommand.GET_CLEAN_RECORD, [record_id])
265+
if isinstance(clean_record, dict):
266+
return CleanRecord.from_dict(clean_record)
273267
return None
274268

269+
@fallback_cache()
275270
async def get_consumable(self) -> Consumable | None:
276-
try:
277-
consumable = await self.send_command(RoborockCommand.GET_CONSUMABLE)
278-
if isinstance(consumable, dict):
279-
return Consumable.from_dict(consumable)
280-
except RoborockTimeout as e:
281-
_LOGGER.error(e)
271+
consumable = await self.send_command(RoborockCommand.GET_CONSUMABLE)
272+
if isinstance(consumable, dict):
273+
return Consumable.from_dict(consumable)
282274
return None
283275

276+
@fallback_cache()
284277
async def get_wash_towel_mode(self) -> WashTowelMode | None:
285-
try:
286-
washing_mode = await self.send_command(RoborockCommand.GET_WASH_TOWEL_MODE)
287-
if isinstance(washing_mode, dict):
288-
return WashTowelMode.from_dict(washing_mode)
289-
except RoborockTimeout as e:
290-
_LOGGER.error(e)
278+
washing_mode = await self.send_command(RoborockCommand.GET_WASH_TOWEL_MODE)
279+
if isinstance(washing_mode, dict):
280+
return WashTowelMode.from_dict(washing_mode)
291281
return None
292282

283+
@fallback_cache()
293284
async def get_dust_collection_mode(self) -> DustCollectionMode | None:
294-
try:
295-
dust_collection = await self.send_command(RoborockCommand.GET_DUST_COLLECTION_MODE)
296-
if isinstance(dust_collection, dict):
297-
return DustCollectionMode.from_dict(dust_collection)
298-
except RoborockTimeout as e:
299-
_LOGGER.error(e)
285+
dust_collection = await self.send_command(RoborockCommand.GET_DUST_COLLECTION_MODE)
286+
if isinstance(dust_collection, dict):
287+
return DustCollectionMode.from_dict(dust_collection)
300288
return None
301289

290+
@fallback_cache()
302291
async def get_smart_wash_params(self) -> SmartWashParams | None:
303-
try:
304-
mop_wash_mode = await self.send_command(RoborockCommand.GET_SMART_WASH_PARAMS)
305-
if isinstance(mop_wash_mode, dict):
306-
return SmartWashParams.from_dict(mop_wash_mode)
307-
except RoborockTimeout as e:
308-
_LOGGER.error(e)
292+
mop_wash_mode = await self.send_command(RoborockCommand.GET_SMART_WASH_PARAMS)
293+
if isinstance(mop_wash_mode, dict):
294+
return SmartWashParams.from_dict(mop_wash_mode)
309295
return None
310296

297+
@fallback_cache()
311298
async def get_dock_summary(self, dock_type: RoborockDockTypeCode) -> DockSummary | None:
312299
"""Gets the status summary from the dock with the methods available for a given dock.
313300
314301
:param dock_type: RoborockDockTypeCode"""
315-
try:
316-
commands: list[
317-
Coroutine[
318-
Any,
319-
Any,
320-
DustCollectionMode | WashTowelMode | SmartWashParams | None,
321-
]
322-
] = [self.get_dust_collection_mode()]
323-
if dock_type == RoborockDockTypeCode.empty_wash_fill_dock or dock_type == RoborockDockTypeCode.s8_dock:
324-
commands += [
325-
self.get_wash_towel_mode(),
326-
self.get_smart_wash_params(),
327-
]
328-
[dust_collection_mode, wash_towel_mode, smart_wash_params] = unpack_list(
329-
list(await asyncio.gather(*commands)), 3
330-
)
331-
332-
return DockSummary(dust_collection_mode, wash_towel_mode, smart_wash_params)
333-
except RoborockTimeout as e:
334-
_LOGGER.error(e)
335-
return None
302+
commands: list[
303+
Coroutine[
304+
Any,
305+
Any,
306+
DustCollectionMode | WashTowelMode | SmartWashParams | None,
307+
]
308+
] = [self.get_dust_collection_mode()]
309+
if dock_type == RoborockDockTypeCode.empty_wash_fill_dock or dock_type == RoborockDockTypeCode.s8_dock:
310+
commands += [
311+
self.get_wash_towel_mode(),
312+
self.get_smart_wash_params(),
313+
]
314+
[dust_collection_mode, wash_towel_mode, smart_wash_params] = unpack_list(
315+
list(await asyncio.gather(*commands)), 3
316+
)
317+
return DockSummary(dust_collection_mode, wash_towel_mode, smart_wash_params)
336318

319+
@fallback_cache()
337320
async def get_prop(self) -> DeviceProp | None:
338321
[status, dnd_timer, clean_summary, consumable] = await asyncio.gather(
339322
*[
@@ -360,33 +343,30 @@ async def get_prop(self) -> DeviceProp | None:
360343
)
361344
return None
362345

346+
@fallback_cache()
363347
async def get_multi_maps_list(self) -> MultiMapsList | None:
364-
try:
365-
multi_maps_list = await self.send_command(RoborockCommand.GET_MULTI_MAPS_LIST)
366-
if isinstance(multi_maps_list, dict):
367-
return MultiMapsList.from_dict(multi_maps_list)
368-
except RoborockTimeout as e:
369-
_LOGGER.error(e)
348+
multi_maps_list = await self.send_command(RoborockCommand.GET_MULTI_MAPS_LIST)
349+
if isinstance(multi_maps_list, dict):
350+
return MultiMapsList.from_dict(multi_maps_list)
370351
return None
371352

353+
@fallback_cache()
372354
async def get_networking(self) -> NetworkInfo | None:
373-
try:
374-
networking_info = await self.send_command(RoborockCommand.GET_NETWORK_INFO)
375-
if isinstance(networking_info, dict):
376-
return NetworkInfo.from_dict(networking_info)
377-
except RoborockTimeout as e:
378-
_LOGGER.error(e)
355+
networking_info = await self.send_command(RoborockCommand.GET_NETWORK_INFO)
356+
if isinstance(networking_info, dict):
357+
return NetworkInfo.from_dict(networking_info)
379358
return None
380359

381-
async def get_room_mapping(self) -> list[RoomMapping]:
360+
@fallback_cache()
361+
async def get_room_mapping(self) -> list[RoomMapping] | None:
382362
"""Gets the mapping from segment id -> iot id. Only works on local api."""
383363
mapping = await self.send_command(RoborockCommand.GET_ROOM_MAPPING)
384364
if isinstance(mapping, list):
385365
return [
386366
RoomMapping(segment_id=segment_id, iot_id=iot_id) # type: ignore
387367
for segment_id, iot_id in [unpack_list(room, 2) for room in mapping]
388368
]
389-
return []
369+
return None
390370

391371

392372
class RoborockApiClient:

roborock/util.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,26 @@ def wrapped(*args, **kwargs):
3232
return wrapped
3333

3434
return decorator
35+
36+
37+
class CacheableResult:
38+
last_run_result = None
39+
40+
41+
def fallback_cache():
42+
_run_sync = run_sync()
43+
cache = CacheableResult()
44+
45+
def decorator(func):
46+
@functools.wraps(func)
47+
def wrapped(*args, **kwargs):
48+
try:
49+
cache.last_run_result = _run_sync(func(*args, **kwargs))
50+
except Exception as e:
51+
if cache.last_run_result is None:
52+
raise e
53+
return cache.last_run_result
54+
55+
return wrapped
56+
57+
return decorator

0 commit comments

Comments
 (0)