roborock.devices.cache

This module provides caching functionality for the Roborock device management system.

This module defines a cache interface that you may use to cache device information to avoid unnecessary API calls. Callers may implement this interface to provide their own caching mechanism.

  1"""This module provides caching functionality for the Roborock device management system.
  2
  3This module defines a cache interface that you may use to cache device
  4information to avoid unnecessary API calls. Callers may implement
  5this interface to provide their own caching mechanism.
  6"""
  7
  8from dataclasses import dataclass, field
  9from typing import Any, Protocol
 10
 11from roborock.data import CombinedMapInfo, HomeData, NetworkInfo, RoborockBase
 12from roborock.device_features import DeviceFeatures
 13
 14
 15@dataclass
 16class DeviceCacheData(RoborockBase):
 17    """Data structure for caching device information."""
 18
 19    network_info: NetworkInfo | None = None
 20    """Network information for the device"""
 21
 22    home_map_info: dict[int, CombinedMapInfo] | None = None
 23    """Home map information for the device by map_flag."""
 24
 25    home_map_content_base64: dict[int, str] | None = None
 26    """Home cache content for the device (encoded base64) by map_flag."""
 27
 28    device_features: DeviceFeatures | None = None
 29    """Device features information."""
 30
 31    trait_data: dict[str, Any] | None = None
 32    """Trait-specific cached data used internally for caching device features."""
 33
 34
 35@dataclass
 36class CacheData(RoborockBase):
 37    """Data structure for caching device information."""
 38
 39    home_data: HomeData | None = None
 40    """Home data containing device and product information."""
 41
 42    device_info: dict[str, DeviceCacheData] = field(default_factory=dict)
 43    """Per-device cached information indexed by device DUID."""
 44
 45    network_info: dict[str, NetworkInfo] = field(default_factory=dict)
 46    """Network information indexed by device DUID.
 47
 48    This is deprecated. Use the per-device `network_info` field instead.
 49    """
 50
 51    home_map_info: dict[int, CombinedMapInfo] = field(default_factory=dict)
 52    """Home map information indexed by map_flag.
 53
 54    This is deprecated. Use the per-device `home_map_info` field instead.
 55    """
 56
 57    home_map_content: dict[int, bytes] = field(default_factory=dict)
 58    """Home cache content for each map data indexed by map_flag.
 59
 60    This is deprecated. Use the per-device `home_map_content_base64` field instead.
 61    """
 62
 63    home_map_content_base64: dict[int, str] = field(default_factory=dict)
 64    """Home cache content for each map data (encoded base64) indexed by map_flag.
 65
 66    This is deprecated. Use the per-device `home_map_content_base64` field instead.
 67    """
 68
 69    device_features: DeviceFeatures | None = None
 70    """Device features information.
 71
 72    This is deprecated. Use the per-device `device_features` field instead.
 73    """
 74
 75    trait_data: dict[str, Any] | None = None
 76    """Trait-specific cached data used internally for caching device features.
 77
 78    This is deprecated. Use the per-device `trait_data` field instead.
 79    """
 80
 81
 82class Cache(Protocol):
 83    """Protocol for a cache that can store and retrieve values."""
 84
 85    async def get(self) -> CacheData:
 86        """Get cached value."""
 87        ...
 88
 89    async def set(self, value: CacheData) -> None:
 90        """Set value in the cache."""
 91        ...
 92
 93
 94@dataclass
 95class DeviceCache(RoborockBase):
 96    """Provides a cache interface for a specific device.
 97
 98    This is a convenience wrapper around a general Cache implementation to
 99    provide device-specific caching functionality.
100    """
101
102    def __init__(self, duid: str, cache: Cache) -> None:
103        """Initialize the device cache with the given cache implementation."""
104        self._duid = duid
105        self._cache = cache
106
107    async def get(self) -> DeviceCacheData:
108        """Get cached device-specific information."""
109        cache_data = await self._cache.get()
110        if self._duid not in cache_data.device_info:
111            cache_data.device_info[self._duid] = DeviceCacheData()
112            await self._cache.set(cache_data)
113        return cache_data.device_info[self._duid]
114
115    async def set(self, device_cache_data: DeviceCacheData) -> None:
116        """Set cached device-specific information."""
117        cache_data = await self._cache.get()
118        cache_data.device_info[self._duid] = device_cache_data
119        await self._cache.set(cache_data)
120
121
122class InMemoryCache(Cache):
123    """In-memory cache implementation."""
124
125    def __init__(self) -> None:
126        """Initialize the in-memory cache."""
127        self._data = CacheData()
128
129    async def get(self) -> CacheData:
130        return self._data
131
132    async def set(self, value: CacheData) -> None:
133        self._data = value
134
135
136class NoCache(Cache):
137    """No-op cache implementation."""
138
139    async def get(self) -> CacheData:
140        return CacheData()
141
142    async def set(self, value: CacheData) -> None:
143        pass
@dataclass
class DeviceCacheData(roborock.data.containers.RoborockBase):
16@dataclass
17class DeviceCacheData(RoborockBase):
18    """Data structure for caching device information."""
19
20    network_info: NetworkInfo | None = None
21    """Network information for the device"""
22
23    home_map_info: dict[int, CombinedMapInfo] | None = None
24    """Home map information for the device by map_flag."""
25
26    home_map_content_base64: dict[int, str] | None = None
27    """Home cache content for the device (encoded base64) by map_flag."""
28
29    device_features: DeviceFeatures | None = None
30    """Device features information."""
31
32    trait_data: dict[str, Any] | None = None
33    """Trait-specific cached data used internally for caching device features."""

Data structure for caching device information.

DeviceCacheData( network_info: roborock.data.v1.v1_containers.NetworkInfo | None = None, home_map_info: dict[int, roborock.data.containers.CombinedMapInfo] | None = None, home_map_content_base64: dict[int, str] | None = None, device_features: roborock.device_features.DeviceFeatures | None = None, trait_data: dict[str, typing.Any] | None = None)
network_info: roborock.data.v1.v1_containers.NetworkInfo | None = None

Network information for the device

home_map_info: dict[int, roborock.data.containers.CombinedMapInfo] | None = None

Home map information for the device by map_flag.

home_map_content_base64: dict[int, str] | None = None

Home cache content for the device (encoded base64) by map_flag.

device_features: roborock.device_features.DeviceFeatures | None = None

Device features information.

trait_data: dict[str, typing.Any] | None = None

Trait-specific cached data used internally for caching device features.

@dataclass
class CacheData(roborock.data.containers.RoborockBase):
36@dataclass
37class CacheData(RoborockBase):
38    """Data structure for caching device information."""
39
40    home_data: HomeData | None = None
41    """Home data containing device and product information."""
42
43    device_info: dict[str, DeviceCacheData] = field(default_factory=dict)
44    """Per-device cached information indexed by device DUID."""
45
46    network_info: dict[str, NetworkInfo] = field(default_factory=dict)
47    """Network information indexed by device DUID.
48
49    This is deprecated. Use the per-device `network_info` field instead.
50    """
51
52    home_map_info: dict[int, CombinedMapInfo] = field(default_factory=dict)
53    """Home map information indexed by map_flag.
54
55    This is deprecated. Use the per-device `home_map_info` field instead.
56    """
57
58    home_map_content: dict[int, bytes] = field(default_factory=dict)
59    """Home cache content for each map data indexed by map_flag.
60
61    This is deprecated. Use the per-device `home_map_content_base64` field instead.
62    """
63
64    home_map_content_base64: dict[int, str] = field(default_factory=dict)
65    """Home cache content for each map data (encoded base64) indexed by map_flag.
66
67    This is deprecated. Use the per-device `home_map_content_base64` field instead.
68    """
69
70    device_features: DeviceFeatures | None = None
71    """Device features information.
72
73    This is deprecated. Use the per-device `device_features` field instead.
74    """
75
76    trait_data: dict[str, Any] | None = None
77    """Trait-specific cached data used internally for caching device features.
78
79    This is deprecated. Use the per-device `trait_data` field instead.
80    """

Data structure for caching device information.

CacheData( home_data: roborock.data.containers.HomeData | None = None, device_info: dict[str, DeviceCacheData] = <factory>, network_info: dict[str, roborock.data.v1.v1_containers.NetworkInfo] = <factory>, home_map_info: dict[int, roborock.data.containers.CombinedMapInfo] = <factory>, home_map_content: dict[int, bytes] = <factory>, home_map_content_base64: dict[int, str] = <factory>, device_features: roborock.device_features.DeviceFeatures | None = None, trait_data: dict[str, typing.Any] | None = None)
home_data: roborock.data.containers.HomeData | None = None

Home data containing device and product information.

device_info: dict[str, DeviceCacheData]

Per-device cached information indexed by device DUID.

Network information indexed by device DUID.

This is deprecated. Use the per-device network_info field instead.

home_map_info: dict[int, roborock.data.containers.CombinedMapInfo]

Home map information indexed by map_flag.

This is deprecated. Use the per-device home_map_info field instead.

home_map_content: dict[int, bytes]

Home cache content for each map data indexed by map_flag.

This is deprecated. Use the per-device home_map_content_base64 field instead.

home_map_content_base64: dict[int, str]

Home cache content for each map data (encoded base64) indexed by map_flag.

This is deprecated. Use the per-device home_map_content_base64 field instead.

device_features: roborock.device_features.DeviceFeatures | None = None

Device features information.

This is deprecated. Use the per-device device_features field instead.

trait_data: dict[str, typing.Any] | None = None

Trait-specific cached data used internally for caching device features.

This is deprecated. Use the per-device trait_data field instead.

class Cache(typing.Protocol):
83class Cache(Protocol):
84    """Protocol for a cache that can store and retrieve values."""
85
86    async def get(self) -> CacheData:
87        """Get cached value."""
88        ...
89
90    async def set(self, value: CacheData) -> None:
91        """Set value in the cache."""
92        ...

Protocol for a cache that can store and retrieve values.

Cache(*args, **kwargs)
1739def _no_init_or_replace_init(self, *args, **kwargs):
1740    cls = type(self)
1741
1742    if cls._is_protocol:
1743        raise TypeError('Protocols cannot be instantiated')
1744
1745    # Already using a custom `__init__`. No need to calculate correct
1746    # `__init__` to call. This can lead to RecursionError. See bpo-45121.
1747    if cls.__init__ is not _no_init_or_replace_init:
1748        return
1749
1750    # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
1751    # The first instantiation of the subclass will call `_no_init_or_replace_init` which
1752    # searches for a proper new `__init__` in the MRO. The new `__init__`
1753    # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent
1754    # instantiation of the protocol subclass will thus use the new
1755    # `__init__` and no longer call `_no_init_or_replace_init`.
1756    for base in cls.__mro__:
1757        init = base.__dict__.get('__init__', _no_init_or_replace_init)
1758        if init is not _no_init_or_replace_init:
1759            cls.__init__ = init
1760            break
1761    else:
1762        # should not happen
1763        cls.__init__ = object.__init__
1764
1765    cls.__init__(self, *args, **kwargs)
async def get(self) -> CacheData:
86    async def get(self) -> CacheData:
87        """Get cached value."""
88        ...

Get cached value.

async def set(self, value: CacheData) -> None:
90    async def set(self, value: CacheData) -> None:
91        """Set value in the cache."""
92        ...

Set value in the cache.

@dataclass
class DeviceCache(roborock.data.containers.RoborockBase):
 95@dataclass
 96class DeviceCache(RoborockBase):
 97    """Provides a cache interface for a specific device.
 98
 99    This is a convenience wrapper around a general Cache implementation to
100    provide device-specific caching functionality.
101    """
102
103    def __init__(self, duid: str, cache: Cache) -> None:
104        """Initialize the device cache with the given cache implementation."""
105        self._duid = duid
106        self._cache = cache
107
108    async def get(self) -> DeviceCacheData:
109        """Get cached device-specific information."""
110        cache_data = await self._cache.get()
111        if self._duid not in cache_data.device_info:
112            cache_data.device_info[self._duid] = DeviceCacheData()
113            await self._cache.set(cache_data)
114        return cache_data.device_info[self._duid]
115
116    async def set(self, device_cache_data: DeviceCacheData) -> None:
117        """Set cached device-specific information."""
118        cache_data = await self._cache.get()
119        cache_data.device_info[self._duid] = device_cache_data
120        await self._cache.set(cache_data)

Provides a cache interface for a specific device.

This is a convenience wrapper around a general Cache implementation to provide device-specific caching functionality.

DeviceCache(duid: str, cache: Cache)
103    def __init__(self, duid: str, cache: Cache) -> None:
104        """Initialize the device cache with the given cache implementation."""
105        self._duid = duid
106        self._cache = cache

Initialize the device cache with the given cache implementation.

async def get(self) -> DeviceCacheData:
108    async def get(self) -> DeviceCacheData:
109        """Get cached device-specific information."""
110        cache_data = await self._cache.get()
111        if self._duid not in cache_data.device_info:
112            cache_data.device_info[self._duid] = DeviceCacheData()
113            await self._cache.set(cache_data)
114        return cache_data.device_info[self._duid]

Get cached device-specific information.

async def set(self, device_cache_data: DeviceCacheData) -> None:
116    async def set(self, device_cache_data: DeviceCacheData) -> None:
117        """Set cached device-specific information."""
118        cache_data = await self._cache.get()
119        cache_data.device_info[self._duid] = device_cache_data
120        await self._cache.set(cache_data)

Set cached device-specific information.

class InMemoryCache(Cache):
123class InMemoryCache(Cache):
124    """In-memory cache implementation."""
125
126    def __init__(self) -> None:
127        """Initialize the in-memory cache."""
128        self._data = CacheData()
129
130    async def get(self) -> CacheData:
131        return self._data
132
133    async def set(self, value: CacheData) -> None:
134        self._data = value

In-memory cache implementation.

InMemoryCache()
126    def __init__(self) -> None:
127        """Initialize the in-memory cache."""
128        self._data = CacheData()

Initialize the in-memory cache.

async def get(self) -> CacheData:
130    async def get(self) -> CacheData:
131        return self._data

Get cached value.

async def set(self, value: CacheData) -> None:
133    async def set(self, value: CacheData) -> None:
134        self._data = value

Set value in the cache.

class NoCache(Cache):
137class NoCache(Cache):
138    """No-op cache implementation."""
139
140    async def get(self) -> CacheData:
141        return CacheData()
142
143    async def set(self, value: CacheData) -> None:
144        pass

No-op cache implementation.

async def get(self) -> CacheData:
140    async def get(self) -> CacheData:
141        return CacheData()

Get cached value.

async def set(self, value: CacheData) -> None:
143    async def set(self, value: CacheData) -> None:
144        pass

Set value in the cache.

Inherited Members
Cache
Cache