roborock.data.code_mappings

  1import logging
  2from collections import namedtuple
  3from enum import Enum, IntEnum, StrEnum
  4from typing import Any, Self
  5
  6_LOGGER = logging.getLogger(__name__)
  7completed_warnings = set()
  8
  9
 10class RoborockEnum(IntEnum):
 11    """Roborock Enum for codes with int values"""
 12
 13    _display_name_: str | None
 14
 15    def __new__(cls, value: int, display_name: str | None = None) -> Self:
 16        member = int.__new__(cls, value)
 17        member._value_ = value
 18        member._display_name_ = display_name
 19        return member
 20
 21    @property
 22    def name(self) -> str:
 23        return super().name.lower()
 24
 25    @property
 26    def display_name(self) -> str:
 27        return self._display_name_ or self.name
 28
 29    @classmethod
 30    def _missing_(cls: type[Self], key) -> Self:
 31        if hasattr(cls, "unknown"):
 32            warning = f"Missing {cls.__name__} code: {key} - defaulting to 'unknown'"
 33            if warning not in completed_warnings:
 34                completed_warnings.add(warning)
 35                _LOGGER.warning(warning)
 36            return cls.unknown  # type: ignore
 37        default_value = next(item for item in cls)
 38        warning = f"Missing {cls.__name__} code: {key} - defaulting to {default_value}"
 39        if warning not in completed_warnings:
 40            completed_warnings.add(warning)
 41            _LOGGER.warning(warning)
 42        return default_value
 43
 44    @classmethod
 45    def as_dict(cls: type[Self]) -> dict[str, int]:
 46        result: dict[str, int] = {}
 47        for item in cls:
 48            if item.name == "missing":
 49                continue
 50            result.setdefault(item.display_name, item.value)
 51        return result
 52
 53    @classmethod
 54    def as_enum_dict(cls: type[Self]):
 55        return {i.value: i for i in cls if i.name != "missing"}
 56
 57    @classmethod
 58    def values(cls: type[Self]) -> list[int]:
 59        return list(cls.as_dict().values())
 60
 61    @classmethod
 62    def keys(cls: type[Self]) -> list[str]:
 63        return list(cls.as_dict().keys())
 64
 65    @classmethod
 66    def items(cls: type[Self]):
 67        return cls.as_dict().items()
 68
 69
 70class RoborockModeEnum(StrEnum):
 71    """A custom StrEnum that also stores an integer code for each member."""
 72
 73    code: int
 74    """The integer code associated with the enum member."""
 75
 76    def __new__(cls, value: str, code: int) -> Self:
 77        """Creates a new enum member."""
 78        member = str.__new__(cls, value)
 79        member._value_ = value
 80        member.code = code
 81        return member
 82
 83    @classmethod
 84    def from_code(cls, code: int) -> Self:
 85        for member in cls:
 86            if member.code == code:
 87                return member
 88        message = f"{code} is not a valid code for {cls.__name__}"
 89        if message not in completed_warnings:
 90            completed_warnings.add(message)
 91            _LOGGER.warning(message)
 92        raise ValueError(message)
 93
 94    @classmethod
 95    def from_code_optional(cls, code: int) -> Self | None:
 96        """Gracefully return None if the code does not exist.
 97
 98        This is the silent counterpart to :meth:`from_code`: callers use it when
 99        an unknown code is expected and tolerable (e.g. decoding a device push
100        that may include data points this library does not model yet), so it must
101        not emit the "not a valid code" warning that ``from_code`` logs.
102        """
103        for member in cls:
104            if member.code == code:
105                return member
106        return None
107
108    @classmethod
109    def from_value(cls, value: str) -> Self:
110        """Find enum member by string value (case-insensitive)."""
111        for member in cls:
112            if member.value.lower() == value.lower():
113                return member
114        raise ValueError(f"{value} is not a valid value for {cls.__name__}")
115
116    @classmethod
117    def from_name(cls, name: str) -> Self:
118        """Find enum member by name (case-insensitive)."""
119        for member in cls:
120            if member.name.lower() == name.lower():
121                return member
122        raise ValueError(f"{name} is not a valid name for {cls.__name__}")
123
124    @classmethod
125    def from_any_optional(cls, value: str | int) -> Self | None:
126        """Resolve a string or int to an enum member.
127
128        Tries to look up by enum name, string value, or integer code
129        and returns None if no match is found.
130        """
131        # Try enum name lookup (e.g. "SEEK")
132        try:
133            return cls.from_name(str(value))
134        except ValueError:
135            pass
136        # Try DP string value lookup (e.g. "dpSeek")
137        try:
138            return cls.from_value(str(value))
139        except ValueError:
140            pass
141        # Try integer code lookup (e.g. "11"). Use the silent optional variant so
142        # a value that is neither a name, a DP string, nor a known code resolves
143        # to None without logging a spurious "not a valid code" warning.
144        try:
145            int_code = int(value)
146        except (ValueError, TypeError):
147            return None
148        return cls.from_code_optional(int_code)
149
150    @classmethod
151    def keys(cls) -> list[str]:
152        """Returns a list of all member values."""
153        return [member.value for member in cls]
154
155    def __eq__(self, other: Any) -> bool:
156        if isinstance(other, str):
157            return self.value == other or self.name == other
158        if isinstance(other, int):
159            return self.code == other
160        return super().__eq__(other)
161
162    def __hash__(self) -> int:
163        """Hash a RoborockModeEnum.
164
165        It is critical that you do not mix RoborockModeEnums with raw strings or ints in hashed situations
166        (i.e. sets or keys in dictionaries)
167        """
168        return hash((self.code, self._value_))
169
170
171ProductInfo = namedtuple("ProductInfo", ["nickname", "short_models"])
172
173
174class RoborockProductNickname(Enum):
175    # Coral Series
176    CORAL = ProductInfo(nickname="Coral", short_models=("a20", "a21"))
177    CORALPRO = ProductInfo(nickname="CoralPro", short_models=("a143", "a144"))
178
179    # Pearl Series
180    PEARL = ProductInfo(nickname="Pearl", short_models=("a74", "a75"))
181    PEARLC = ProductInfo(nickname="PearlC", short_models=("a103", "a104"))
182    PEARLE = ProductInfo(nickname="PearlE", short_models=("a167", "a168"))
183    PEARLELITE = ProductInfo(nickname="PearlELite", short_models=("a169", "a170"))
184    PEARLPLUS = ProductInfo(nickname="PearlPlus", short_models=("a86", "a87"))
185    PEARLPLUSS = ProductInfo(nickname="PearlPlusS", short_models=("a116", "a117", "a136"))
186    PEARLS = ProductInfo(nickname="PearlS", short_models=("a100", "a101"))
187    PEARLSLITE = ProductInfo(nickname="PearlSLite", short_models=("a122", "a123"))
188
189    # Ruby Series
190    RUBYPLUS = ProductInfo(nickname="RubyPlus", short_models=("t4", "s4"))
191    RUBYSC = ProductInfo(nickname="RubySC", short_models=("p5", "a08"))
192    RUBYSE = ProductInfo(nickname="RubySE", short_models=("a19",))
193    RUBYSLITE = ProductInfo(nickname="RubySLite", short_models=("p6", "s5e", "a05"))
194
195    # Tanos Series
196    TANOS = ProductInfo(nickname="Tanos", short_models=("t6", "s6"))
197    TANOSE = ProductInfo(nickname="TanosE", short_models=("t7", "a11"))
198    TANOSS = ProductInfo(nickname="TanosS", short_models=("a14", "a15"))
199    TANOSSC = ProductInfo(nickname="TanosSC", short_models=("a39", "a40"))
200    TANOSSE = ProductInfo(nickname="TanosSE", short_models=("a33", "a34"))
201    TANOSSMAX = ProductInfo(nickname="TanosSMax", short_models=("a52",))
202    TANOSSLITE = ProductInfo(nickname="TanosSLite", short_models=("a37", "a38"))
203    TANOSSPLUS = ProductInfo(nickname="TanosSPlus", short_models=("a23", "a24"))
204    TANOSV = ProductInfo(nickname="TanosV", short_models=("t7p", "a09", "a10"))
205
206    # Topaz Series
207    TOPAZS = ProductInfo(nickname="TopazS", short_models=("a29", "a30", "a76"))
208    TOPAZSC = ProductInfo(nickname="TopazSC", short_models=("a64", "a65"))
209    TOPAZSPLUS = ProductInfo(nickname="TopazSPlus", short_models=("a46", "a47", "a66"))
210    TOPAZSPOWER = ProductInfo(nickname="TopazSPower", short_models=("a62",))
211    TOPAZSV = ProductInfo(nickname="TopazSV", short_models=("a26", "a27"))
212
213    # Ultron Series
214    ULTRON = ProductInfo(nickname="Ultron", short_models=("a50", "a51"))
215    ULTRONE = ProductInfo(nickname="UltronE", short_models=("a72", "a84"))
216    ULTRONLITE = ProductInfo(nickname="UltronLite", short_models=("a73", "a85"))
217    ULTRONSC = ProductInfo(nickname="UltronSC", short_models=("a94", "a95"))
218    ULTRONSE = ProductInfo(nickname="UltronSE", short_models=("a124", "a125", "a139", "a140"))
219    ULTRONSPLUS = ProductInfo(nickname="UltronSPlus", short_models=("a68", "a69", "a70"))
220    ULTRONSV = ProductInfo(nickname="UltronSV", short_models=("a96", "a97"))
221
222    # Verdelite Series
223    VERDELITE = ProductInfo(nickname="Verdelite", short_models=("a146", "a147"))
224
225    # Vivian Series
226    VIVIAN = ProductInfo(nickname="Vivian", short_models=("a134", "a135", "a155", "a156"))
227    VIVIANC = ProductInfo(nickname="VivianC", short_models=("a158", "a159"))
228
229
230SHORT_MODEL_TO_ENUM = {model: product for product in RoborockProductNickname for model in product.value.short_models}
231
232
233class RoborockCategory(Enum):
234    """Describes the category of the device."""
235
236    WET_DRY_VAC = "roborock.wetdryvac"
237    VACUUM = "robot.vacuum.cleaner"
238    WASHING_MACHINE = "roborock.wm"
239    MOWER = "roborock.mower"
240    UNKNOWN = "UNKNOWN"
241
242    @classmethod
243    def _missing_(cls, value):
244        _LOGGER.warning("Missing code %s from category", value)
245        return RoborockCategory.UNKNOWN
completed_warnings = set()
class RoborockEnum(enum.IntEnum):
11class RoborockEnum(IntEnum):
12    """Roborock Enum for codes with int values"""
13
14    _display_name_: str | None
15
16    def __new__(cls, value: int, display_name: str | None = None) -> Self:
17        member = int.__new__(cls, value)
18        member._value_ = value
19        member._display_name_ = display_name
20        return member
21
22    @property
23    def name(self) -> str:
24        return super().name.lower()
25
26    @property
27    def display_name(self) -> str:
28        return self._display_name_ or self.name
29
30    @classmethod
31    def _missing_(cls: type[Self], key) -> Self:
32        if hasattr(cls, "unknown"):
33            warning = f"Missing {cls.__name__} code: {key} - defaulting to 'unknown'"
34            if warning not in completed_warnings:
35                completed_warnings.add(warning)
36                _LOGGER.warning(warning)
37            return cls.unknown  # type: ignore
38        default_value = next(item for item in cls)
39        warning = f"Missing {cls.__name__} code: {key} - defaulting to {default_value}"
40        if warning not in completed_warnings:
41            completed_warnings.add(warning)
42            _LOGGER.warning(warning)
43        return default_value
44
45    @classmethod
46    def as_dict(cls: type[Self]) -> dict[str, int]:
47        result: dict[str, int] = {}
48        for item in cls:
49            if item.name == "missing":
50                continue
51            result.setdefault(item.display_name, item.value)
52        return result
53
54    @classmethod
55    def as_enum_dict(cls: type[Self]):
56        return {i.value: i for i in cls if i.name != "missing"}
57
58    @classmethod
59    def values(cls: type[Self]) -> list[int]:
60        return list(cls.as_dict().values())
61
62    @classmethod
63    def keys(cls: type[Self]) -> list[str]:
64        return list(cls.as_dict().keys())
65
66    @classmethod
67    def items(cls: type[Self]):
68        return cls.as_dict().items()

Roborock Enum for codes with int values

name: str
22    @property
23    def name(self) -> str:
24        return super().name.lower()

The name of the Enum member.

display_name: str
26    @property
27    def display_name(self) -> str:
28        return self._display_name_ or self.name
@classmethod
def as_dict(cls: type[typing.Self]) -> dict[str, int]:
45    @classmethod
46    def as_dict(cls: type[Self]) -> dict[str, int]:
47        result: dict[str, int] = {}
48        for item in cls:
49            if item.name == "missing":
50                continue
51            result.setdefault(item.display_name, item.value)
52        return result
@classmethod
def as_enum_dict(cls: type[typing.Self]):
54    @classmethod
55    def as_enum_dict(cls: type[Self]):
56        return {i.value: i for i in cls if i.name != "missing"}
@classmethod
def values(cls: type[typing.Self]) -> list[int]:
58    @classmethod
59    def values(cls: type[Self]) -> list[int]:
60        return list(cls.as_dict().values())
@classmethod
def keys(cls: type[typing.Self]) -> list[str]:
62    @classmethod
63    def keys(cls: type[Self]) -> list[str]:
64        return list(cls.as_dict().keys())
@classmethod
def items(cls: type[typing.Self]):
66    @classmethod
67    def items(cls: type[Self]):
68        return cls.as_dict().items()
class RoborockModeEnum(enum.StrEnum):
 71class RoborockModeEnum(StrEnum):
 72    """A custom StrEnum that also stores an integer code for each member."""
 73
 74    code: int
 75    """The integer code associated with the enum member."""
 76
 77    def __new__(cls, value: str, code: int) -> Self:
 78        """Creates a new enum member."""
 79        member = str.__new__(cls, value)
 80        member._value_ = value
 81        member.code = code
 82        return member
 83
 84    @classmethod
 85    def from_code(cls, code: int) -> Self:
 86        for member in cls:
 87            if member.code == code:
 88                return member
 89        message = f"{code} is not a valid code for {cls.__name__}"
 90        if message not in completed_warnings:
 91            completed_warnings.add(message)
 92            _LOGGER.warning(message)
 93        raise ValueError(message)
 94
 95    @classmethod
 96    def from_code_optional(cls, code: int) -> Self | None:
 97        """Gracefully return None if the code does not exist.
 98
 99        This is the silent counterpart to :meth:`from_code`: callers use it when
100        an unknown code is expected and tolerable (e.g. decoding a device push
101        that may include data points this library does not model yet), so it must
102        not emit the "not a valid code" warning that ``from_code`` logs.
103        """
104        for member in cls:
105            if member.code == code:
106                return member
107        return None
108
109    @classmethod
110    def from_value(cls, value: str) -> Self:
111        """Find enum member by string value (case-insensitive)."""
112        for member in cls:
113            if member.value.lower() == value.lower():
114                return member
115        raise ValueError(f"{value} is not a valid value for {cls.__name__}")
116
117    @classmethod
118    def from_name(cls, name: str) -> Self:
119        """Find enum member by name (case-insensitive)."""
120        for member in cls:
121            if member.name.lower() == name.lower():
122                return member
123        raise ValueError(f"{name} is not a valid name for {cls.__name__}")
124
125    @classmethod
126    def from_any_optional(cls, value: str | int) -> Self | None:
127        """Resolve a string or int to an enum member.
128
129        Tries to look up by enum name, string value, or integer code
130        and returns None if no match is found.
131        """
132        # Try enum name lookup (e.g. "SEEK")
133        try:
134            return cls.from_name(str(value))
135        except ValueError:
136            pass
137        # Try DP string value lookup (e.g. "dpSeek")
138        try:
139            return cls.from_value(str(value))
140        except ValueError:
141            pass
142        # Try integer code lookup (e.g. "11"). Use the silent optional variant so
143        # a value that is neither a name, a DP string, nor a known code resolves
144        # to None without logging a spurious "not a valid code" warning.
145        try:
146            int_code = int(value)
147        except (ValueError, TypeError):
148            return None
149        return cls.from_code_optional(int_code)
150
151    @classmethod
152    def keys(cls) -> list[str]:
153        """Returns a list of all member values."""
154        return [member.value for member in cls]
155
156    def __eq__(self, other: Any) -> bool:
157        if isinstance(other, str):
158            return self.value == other or self.name == other
159        if isinstance(other, int):
160            return self.code == other
161        return super().__eq__(other)
162
163    def __hash__(self) -> int:
164        """Hash a RoborockModeEnum.
165
166        It is critical that you do not mix RoborockModeEnums with raw strings or ints in hashed situations
167        (i.e. sets or keys in dictionaries)
168        """
169        return hash((self.code, self._value_))

A custom StrEnum that also stores an integer code for each member.

code: int

The integer code associated with the enum member.

@classmethod
def from_code(cls, code: int) -> Self:
84    @classmethod
85    def from_code(cls, code: int) -> Self:
86        for member in cls:
87            if member.code == code:
88                return member
89        message = f"{code} is not a valid code for {cls.__name__}"
90        if message not in completed_warnings:
91            completed_warnings.add(message)
92            _LOGGER.warning(message)
93        raise ValueError(message)
@classmethod
def from_code_optional(cls, code: int) -> Optional[Self]:
 95    @classmethod
 96    def from_code_optional(cls, code: int) -> Self | None:
 97        """Gracefully return None if the code does not exist.
 98
 99        This is the silent counterpart to :meth:`from_code`: callers use it when
100        an unknown code is expected and tolerable (e.g. decoding a device push
101        that may include data points this library does not model yet), so it must
102        not emit the "not a valid code" warning that ``from_code`` logs.
103        """
104        for member in cls:
105            if member.code == code:
106                return member
107        return None

Gracefully return None if the code does not exist.

This is the silent counterpart to from_code(): callers use it when an unknown code is expected and tolerable (e.g. decoding a device push that may include data points this library does not model yet), so it must not emit the "not a valid code" warning that from_code logs.

@classmethod
def from_value(cls, value: str) -> Self:
109    @classmethod
110    def from_value(cls, value: str) -> Self:
111        """Find enum member by string value (case-insensitive)."""
112        for member in cls:
113            if member.value.lower() == value.lower():
114                return member
115        raise ValueError(f"{value} is not a valid value for {cls.__name__}")

Find enum member by string value (case-insensitive).

@classmethod
def from_name(cls, name: str) -> Self:
117    @classmethod
118    def from_name(cls, name: str) -> Self:
119        """Find enum member by name (case-insensitive)."""
120        for member in cls:
121            if member.name.lower() == name.lower():
122                return member
123        raise ValueError(f"{name} is not a valid name for {cls.__name__}")

Find enum member by name (case-insensitive).

@classmethod
def from_any_optional(cls, value: str | int) -> Optional[Self]:
125    @classmethod
126    def from_any_optional(cls, value: str | int) -> Self | None:
127        """Resolve a string or int to an enum member.
128
129        Tries to look up by enum name, string value, or integer code
130        and returns None if no match is found.
131        """
132        # Try enum name lookup (e.g. "SEEK")
133        try:
134            return cls.from_name(str(value))
135        except ValueError:
136            pass
137        # Try DP string value lookup (e.g. "dpSeek")
138        try:
139            return cls.from_value(str(value))
140        except ValueError:
141            pass
142        # Try integer code lookup (e.g. "11"). Use the silent optional variant so
143        # a value that is neither a name, a DP string, nor a known code resolves
144        # to None without logging a spurious "not a valid code" warning.
145        try:
146            int_code = int(value)
147        except (ValueError, TypeError):
148            return None
149        return cls.from_code_optional(int_code)

Resolve a string or int to an enum member.

Tries to look up by enum name, string value, or integer code and returns None if no match is found.

@classmethod
def keys(cls) -> list[str]:
151    @classmethod
152    def keys(cls) -> list[str]:
153        """Returns a list of all member values."""
154        return [member.value for member in cls]

Returns a list of all member values.

class ProductInfo(builtins.tuple):

ProductInfo(nickname, short_models)

ProductInfo(nickname, short_models)

Create new instance of ProductInfo(nickname, short_models)

nickname

Alias for field number 0

short_models

Alias for field number 1

class RoborockProductNickname(enum.Enum):
175class RoborockProductNickname(Enum):
176    # Coral Series
177    CORAL = ProductInfo(nickname="Coral", short_models=("a20", "a21"))
178    CORALPRO = ProductInfo(nickname="CoralPro", short_models=("a143", "a144"))
179
180    # Pearl Series
181    PEARL = ProductInfo(nickname="Pearl", short_models=("a74", "a75"))
182    PEARLC = ProductInfo(nickname="PearlC", short_models=("a103", "a104"))
183    PEARLE = ProductInfo(nickname="PearlE", short_models=("a167", "a168"))
184    PEARLELITE = ProductInfo(nickname="PearlELite", short_models=("a169", "a170"))
185    PEARLPLUS = ProductInfo(nickname="PearlPlus", short_models=("a86", "a87"))
186    PEARLPLUSS = ProductInfo(nickname="PearlPlusS", short_models=("a116", "a117", "a136"))
187    PEARLS = ProductInfo(nickname="PearlS", short_models=("a100", "a101"))
188    PEARLSLITE = ProductInfo(nickname="PearlSLite", short_models=("a122", "a123"))
189
190    # Ruby Series
191    RUBYPLUS = ProductInfo(nickname="RubyPlus", short_models=("t4", "s4"))
192    RUBYSC = ProductInfo(nickname="RubySC", short_models=("p5", "a08"))
193    RUBYSE = ProductInfo(nickname="RubySE", short_models=("a19",))
194    RUBYSLITE = ProductInfo(nickname="RubySLite", short_models=("p6", "s5e", "a05"))
195
196    # Tanos Series
197    TANOS = ProductInfo(nickname="Tanos", short_models=("t6", "s6"))
198    TANOSE = ProductInfo(nickname="TanosE", short_models=("t7", "a11"))
199    TANOSS = ProductInfo(nickname="TanosS", short_models=("a14", "a15"))
200    TANOSSC = ProductInfo(nickname="TanosSC", short_models=("a39", "a40"))
201    TANOSSE = ProductInfo(nickname="TanosSE", short_models=("a33", "a34"))
202    TANOSSMAX = ProductInfo(nickname="TanosSMax", short_models=("a52",))
203    TANOSSLITE = ProductInfo(nickname="TanosSLite", short_models=("a37", "a38"))
204    TANOSSPLUS = ProductInfo(nickname="TanosSPlus", short_models=("a23", "a24"))
205    TANOSV = ProductInfo(nickname="TanosV", short_models=("t7p", "a09", "a10"))
206
207    # Topaz Series
208    TOPAZS = ProductInfo(nickname="TopazS", short_models=("a29", "a30", "a76"))
209    TOPAZSC = ProductInfo(nickname="TopazSC", short_models=("a64", "a65"))
210    TOPAZSPLUS = ProductInfo(nickname="TopazSPlus", short_models=("a46", "a47", "a66"))
211    TOPAZSPOWER = ProductInfo(nickname="TopazSPower", short_models=("a62",))
212    TOPAZSV = ProductInfo(nickname="TopazSV", short_models=("a26", "a27"))
213
214    # Ultron Series
215    ULTRON = ProductInfo(nickname="Ultron", short_models=("a50", "a51"))
216    ULTRONE = ProductInfo(nickname="UltronE", short_models=("a72", "a84"))
217    ULTRONLITE = ProductInfo(nickname="UltronLite", short_models=("a73", "a85"))
218    ULTRONSC = ProductInfo(nickname="UltronSC", short_models=("a94", "a95"))
219    ULTRONSE = ProductInfo(nickname="UltronSE", short_models=("a124", "a125", "a139", "a140"))
220    ULTRONSPLUS = ProductInfo(nickname="UltronSPlus", short_models=("a68", "a69", "a70"))
221    ULTRONSV = ProductInfo(nickname="UltronSV", short_models=("a96", "a97"))
222
223    # Verdelite Series
224    VERDELITE = ProductInfo(nickname="Verdelite", short_models=("a146", "a147"))
225
226    # Vivian Series
227    VIVIAN = ProductInfo(nickname="Vivian", short_models=("a134", "a135", "a155", "a156"))
228    VIVIANC = ProductInfo(nickname="VivianC", short_models=("a158", "a159"))
CORAL = <RoborockProductNickname.CORAL: ProductInfo(nickname='Coral', short_models=('a20', 'a21'))>
CORALPRO = <RoborockProductNickname.CORALPRO: ProductInfo(nickname='CoralPro', short_models=('a143', 'a144'))>
PEARL = <RoborockProductNickname.PEARL: ProductInfo(nickname='Pearl', short_models=('a74', 'a75'))>
PEARLC = <RoborockProductNickname.PEARLC: ProductInfo(nickname='PearlC', short_models=('a103', 'a104'))>
PEARLE = <RoborockProductNickname.PEARLE: ProductInfo(nickname='PearlE', short_models=('a167', 'a168'))>
PEARLELITE = <RoborockProductNickname.PEARLELITE: ProductInfo(nickname='PearlELite', short_models=('a169', 'a170'))>
PEARLPLUS = <RoborockProductNickname.PEARLPLUS: ProductInfo(nickname='PearlPlus', short_models=('a86', 'a87'))>
PEARLPLUSS = <RoborockProductNickname.PEARLPLUSS: ProductInfo(nickname='PearlPlusS', short_models=('a116', 'a117', 'a136'))>
PEARLS = <RoborockProductNickname.PEARLS: ProductInfo(nickname='PearlS', short_models=('a100', 'a101'))>
PEARLSLITE = <RoborockProductNickname.PEARLSLITE: ProductInfo(nickname='PearlSLite', short_models=('a122', 'a123'))>
RUBYPLUS = <RoborockProductNickname.RUBYPLUS: ProductInfo(nickname='RubyPlus', short_models=('t4', 's4'))>
RUBYSC = <RoborockProductNickname.RUBYSC: ProductInfo(nickname='RubySC', short_models=('p5', 'a08'))>
RUBYSE = <RoborockProductNickname.RUBYSE: ProductInfo(nickname='RubySE', short_models=('a19',))>
RUBYSLITE = <RoborockProductNickname.RUBYSLITE: ProductInfo(nickname='RubySLite', short_models=('p6', 's5e', 'a05'))>
TANOS = <RoborockProductNickname.TANOS: ProductInfo(nickname='Tanos', short_models=('t6', 's6'))>
TANOSE = <RoborockProductNickname.TANOSE: ProductInfo(nickname='TanosE', short_models=('t7', 'a11'))>
TANOSS = <RoborockProductNickname.TANOSS: ProductInfo(nickname='TanosS', short_models=('a14', 'a15'))>
TANOSSC = <RoborockProductNickname.TANOSSC: ProductInfo(nickname='TanosSC', short_models=('a39', 'a40'))>
TANOSSE = <RoborockProductNickname.TANOSSE: ProductInfo(nickname='TanosSE', short_models=('a33', 'a34'))>
TANOSSMAX = <RoborockProductNickname.TANOSSMAX: ProductInfo(nickname='TanosSMax', short_models=('a52',))>
TANOSSLITE = <RoborockProductNickname.TANOSSLITE: ProductInfo(nickname='TanosSLite', short_models=('a37', 'a38'))>
TANOSSPLUS = <RoborockProductNickname.TANOSSPLUS: ProductInfo(nickname='TanosSPlus', short_models=('a23', 'a24'))>
TANOSV = <RoborockProductNickname.TANOSV: ProductInfo(nickname='TanosV', short_models=('t7p', 'a09', 'a10'))>
TOPAZS = <RoborockProductNickname.TOPAZS: ProductInfo(nickname='TopazS', short_models=('a29', 'a30', 'a76'))>
TOPAZSC = <RoborockProductNickname.TOPAZSC: ProductInfo(nickname='TopazSC', short_models=('a64', 'a65'))>
TOPAZSPLUS = <RoborockProductNickname.TOPAZSPLUS: ProductInfo(nickname='TopazSPlus', short_models=('a46', 'a47', 'a66'))>
TOPAZSPOWER = <RoborockProductNickname.TOPAZSPOWER: ProductInfo(nickname='TopazSPower', short_models=('a62',))>
TOPAZSV = <RoborockProductNickname.TOPAZSV: ProductInfo(nickname='TopazSV', short_models=('a26', 'a27'))>
ULTRON = <RoborockProductNickname.ULTRON: ProductInfo(nickname='Ultron', short_models=('a50', 'a51'))>
ULTRONE = <RoborockProductNickname.ULTRONE: ProductInfo(nickname='UltronE', short_models=('a72', 'a84'))>
ULTRONLITE = <RoborockProductNickname.ULTRONLITE: ProductInfo(nickname='UltronLite', short_models=('a73', 'a85'))>
ULTRONSC = <RoborockProductNickname.ULTRONSC: ProductInfo(nickname='UltronSC', short_models=('a94', 'a95'))>
ULTRONSE = <RoborockProductNickname.ULTRONSE: ProductInfo(nickname='UltronSE', short_models=('a124', 'a125', 'a139', 'a140'))>
ULTRONSPLUS = <RoborockProductNickname.ULTRONSPLUS: ProductInfo(nickname='UltronSPlus', short_models=('a68', 'a69', 'a70'))>
ULTRONSV = <RoborockProductNickname.ULTRONSV: ProductInfo(nickname='UltronSV', short_models=('a96', 'a97'))>
VERDELITE = <RoborockProductNickname.VERDELITE: ProductInfo(nickname='Verdelite', short_models=('a146', 'a147'))>
VIVIAN = <RoborockProductNickname.VIVIAN: ProductInfo(nickname='Vivian', short_models=('a134', 'a135', 'a155', 'a156'))>
VIVIANC = <RoborockProductNickname.VIVIANC: ProductInfo(nickname='VivianC', short_models=('a158', 'a159'))>
SHORT_MODEL_TO_ENUM = {'a20': <RoborockProductNickname.CORAL: ProductInfo(nickname='Coral', short_models=('a20', 'a21'))>, 'a21': <RoborockProductNickname.CORAL: ProductInfo(nickname='Coral', short_models=('a20', 'a21'))>, 'a143': <RoborockProductNickname.CORALPRO: ProductInfo(nickname='CoralPro', short_models=('a143', 'a144'))>, 'a144': <RoborockProductNickname.CORALPRO: ProductInfo(nickname='CoralPro', short_models=('a143', 'a144'))>, 'a74': <RoborockProductNickname.PEARL: ProductInfo(nickname='Pearl', short_models=('a74', 'a75'))>, 'a75': <RoborockProductNickname.PEARL: ProductInfo(nickname='Pearl', short_models=('a74', 'a75'))>, 'a103': <RoborockProductNickname.PEARLC: ProductInfo(nickname='PearlC', short_models=('a103', 'a104'))>, 'a104': <RoborockProductNickname.PEARLC: ProductInfo(nickname='PearlC', short_models=('a103', 'a104'))>, 'a167': <RoborockProductNickname.PEARLE: ProductInfo(nickname='PearlE', short_models=('a167', 'a168'))>, 'a168': <RoborockProductNickname.PEARLE: ProductInfo(nickname='PearlE', short_models=('a167', 'a168'))>, 'a169': <RoborockProductNickname.PEARLELITE: ProductInfo(nickname='PearlELite', short_models=('a169', 'a170'))>, 'a170': <RoborockProductNickname.PEARLELITE: ProductInfo(nickname='PearlELite', short_models=('a169', 'a170'))>, 'a86': <RoborockProductNickname.PEARLPLUS: ProductInfo(nickname='PearlPlus', short_models=('a86', 'a87'))>, 'a87': <RoborockProductNickname.PEARLPLUS: ProductInfo(nickname='PearlPlus', short_models=('a86', 'a87'))>, 'a116': <RoborockProductNickname.PEARLPLUSS: ProductInfo(nickname='PearlPlusS', short_models=('a116', 'a117', 'a136'))>, 'a117': <RoborockProductNickname.PEARLPLUSS: ProductInfo(nickname='PearlPlusS', short_models=('a116', 'a117', 'a136'))>, 'a136': <RoborockProductNickname.PEARLPLUSS: ProductInfo(nickname='PearlPlusS', short_models=('a116', 'a117', 'a136'))>, 'a100': <RoborockProductNickname.PEARLS: ProductInfo(nickname='PearlS', short_models=('a100', 'a101'))>, 'a101': <RoborockProductNickname.PEARLS: ProductInfo(nickname='PearlS', short_models=('a100', 'a101'))>, 'a122': <RoborockProductNickname.PEARLSLITE: ProductInfo(nickname='PearlSLite', short_models=('a122', 'a123'))>, 'a123': <RoborockProductNickname.PEARLSLITE: ProductInfo(nickname='PearlSLite', short_models=('a122', 'a123'))>, 't4': <RoborockProductNickname.RUBYPLUS: ProductInfo(nickname='RubyPlus', short_models=('t4', 's4'))>, 's4': <RoborockProductNickname.RUBYPLUS: ProductInfo(nickname='RubyPlus', short_models=('t4', 's4'))>, 'p5': <RoborockProductNickname.RUBYSC: ProductInfo(nickname='RubySC', short_models=('p5', 'a08'))>, 'a08': <RoborockProductNickname.RUBYSC: ProductInfo(nickname='RubySC', short_models=('p5', 'a08'))>, 'a19': <RoborockProductNickname.RUBYSE: ProductInfo(nickname='RubySE', short_models=('a19',))>, 'p6': <RoborockProductNickname.RUBYSLITE: ProductInfo(nickname='RubySLite', short_models=('p6', 's5e', 'a05'))>, 's5e': <RoborockProductNickname.RUBYSLITE: ProductInfo(nickname='RubySLite', short_models=('p6', 's5e', 'a05'))>, 'a05': <RoborockProductNickname.RUBYSLITE: ProductInfo(nickname='RubySLite', short_models=('p6', 's5e', 'a05'))>, 't6': <RoborockProductNickname.TANOS: ProductInfo(nickname='Tanos', short_models=('t6', 's6'))>, 's6': <RoborockProductNickname.TANOS: ProductInfo(nickname='Tanos', short_models=('t6', 's6'))>, 't7': <RoborockProductNickname.TANOSE: ProductInfo(nickname='TanosE', short_models=('t7', 'a11'))>, 'a11': <RoborockProductNickname.TANOSE: ProductInfo(nickname='TanosE', short_models=('t7', 'a11'))>, 'a14': <RoborockProductNickname.TANOSS: ProductInfo(nickname='TanosS', short_models=('a14', 'a15'))>, 'a15': <RoborockProductNickname.TANOSS: ProductInfo(nickname='TanosS', short_models=('a14', 'a15'))>, 'a39': <RoborockProductNickname.TANOSSC: ProductInfo(nickname='TanosSC', short_models=('a39', 'a40'))>, 'a40': <RoborockProductNickname.TANOSSC: ProductInfo(nickname='TanosSC', short_models=('a39', 'a40'))>, 'a33': <RoborockProductNickname.TANOSSE: ProductInfo(nickname='TanosSE', short_models=('a33', 'a34'))>, 'a34': <RoborockProductNickname.TANOSSE: ProductInfo(nickname='TanosSE', short_models=('a33', 'a34'))>, 'a52': <RoborockProductNickname.TANOSSMAX: ProductInfo(nickname='TanosSMax', short_models=('a52',))>, 'a37': <RoborockProductNickname.TANOSSLITE: ProductInfo(nickname='TanosSLite', short_models=('a37', 'a38'))>, 'a38': <RoborockProductNickname.TANOSSLITE: ProductInfo(nickname='TanosSLite', short_models=('a37', 'a38'))>, 'a23': <RoborockProductNickname.TANOSSPLUS: ProductInfo(nickname='TanosSPlus', short_models=('a23', 'a24'))>, 'a24': <RoborockProductNickname.TANOSSPLUS: ProductInfo(nickname='TanosSPlus', short_models=('a23', 'a24'))>, 't7p': <RoborockProductNickname.TANOSV: ProductInfo(nickname='TanosV', short_models=('t7p', 'a09', 'a10'))>, 'a09': <RoborockProductNickname.TANOSV: ProductInfo(nickname='TanosV', short_models=('t7p', 'a09', 'a10'))>, 'a10': <RoborockProductNickname.TANOSV: ProductInfo(nickname='TanosV', short_models=('t7p', 'a09', 'a10'))>, 'a29': <RoborockProductNickname.TOPAZS: ProductInfo(nickname='TopazS', short_models=('a29', 'a30', 'a76'))>, 'a30': <RoborockProductNickname.TOPAZS: ProductInfo(nickname='TopazS', short_models=('a29', 'a30', 'a76'))>, 'a76': <RoborockProductNickname.TOPAZS: ProductInfo(nickname='TopazS', short_models=('a29', 'a30', 'a76'))>, 'a64': <RoborockProductNickname.TOPAZSC: ProductInfo(nickname='TopazSC', short_models=('a64', 'a65'))>, 'a65': <RoborockProductNickname.TOPAZSC: ProductInfo(nickname='TopazSC', short_models=('a64', 'a65'))>, 'a46': <RoborockProductNickname.TOPAZSPLUS: ProductInfo(nickname='TopazSPlus', short_models=('a46', 'a47', 'a66'))>, 'a47': <RoborockProductNickname.TOPAZSPLUS: ProductInfo(nickname='TopazSPlus', short_models=('a46', 'a47', 'a66'))>, 'a66': <RoborockProductNickname.TOPAZSPLUS: ProductInfo(nickname='TopazSPlus', short_models=('a46', 'a47', 'a66'))>, 'a62': <RoborockProductNickname.TOPAZSPOWER: ProductInfo(nickname='TopazSPower', short_models=('a62',))>, 'a26': <RoborockProductNickname.TOPAZSV: ProductInfo(nickname='TopazSV', short_models=('a26', 'a27'))>, 'a27': <RoborockProductNickname.TOPAZSV: ProductInfo(nickname='TopazSV', short_models=('a26', 'a27'))>, 'a50': <RoborockProductNickname.ULTRON: ProductInfo(nickname='Ultron', short_models=('a50', 'a51'))>, 'a51': <RoborockProductNickname.ULTRON: ProductInfo(nickname='Ultron', short_models=('a50', 'a51'))>, 'a72': <RoborockProductNickname.ULTRONE: ProductInfo(nickname='UltronE', short_models=('a72', 'a84'))>, 'a84': <RoborockProductNickname.ULTRONE: ProductInfo(nickname='UltronE', short_models=('a72', 'a84'))>, 'a73': <RoborockProductNickname.ULTRONLITE: ProductInfo(nickname='UltronLite', short_models=('a73', 'a85'))>, 'a85': <RoborockProductNickname.ULTRONLITE: ProductInfo(nickname='UltronLite', short_models=('a73', 'a85'))>, 'a94': <RoborockProductNickname.ULTRONSC: ProductInfo(nickname='UltronSC', short_models=('a94', 'a95'))>, 'a95': <RoborockProductNickname.ULTRONSC: ProductInfo(nickname='UltronSC', short_models=('a94', 'a95'))>, 'a124': <RoborockProductNickname.ULTRONSE: ProductInfo(nickname='UltronSE', short_models=('a124', 'a125', 'a139', 'a140'))>, 'a125': <RoborockProductNickname.ULTRONSE: ProductInfo(nickname='UltronSE', short_models=('a124', 'a125', 'a139', 'a140'))>, 'a139': <RoborockProductNickname.ULTRONSE: ProductInfo(nickname='UltronSE', short_models=('a124', 'a125', 'a139', 'a140'))>, 'a140': <RoborockProductNickname.ULTRONSE: ProductInfo(nickname='UltronSE', short_models=('a124', 'a125', 'a139', 'a140'))>, 'a68': <RoborockProductNickname.ULTRONSPLUS: ProductInfo(nickname='UltronSPlus', short_models=('a68', 'a69', 'a70'))>, 'a69': <RoborockProductNickname.ULTRONSPLUS: ProductInfo(nickname='UltronSPlus', short_models=('a68', 'a69', 'a70'))>, 'a70': <RoborockProductNickname.ULTRONSPLUS: ProductInfo(nickname='UltronSPlus', short_models=('a68', 'a69', 'a70'))>, 'a96': <RoborockProductNickname.ULTRONSV: ProductInfo(nickname='UltronSV', short_models=('a96', 'a97'))>, 'a97': <RoborockProductNickname.ULTRONSV: ProductInfo(nickname='UltronSV', short_models=('a96', 'a97'))>, 'a146': <RoborockProductNickname.VERDELITE: ProductInfo(nickname='Verdelite', short_models=('a146', 'a147'))>, 'a147': <RoborockProductNickname.VERDELITE: ProductInfo(nickname='Verdelite', short_models=('a146', 'a147'))>, 'a134': <RoborockProductNickname.VIVIAN: ProductInfo(nickname='Vivian', short_models=('a134', 'a135', 'a155', 'a156'))>, 'a135': <RoborockProductNickname.VIVIAN: ProductInfo(nickname='Vivian', short_models=('a134', 'a135', 'a155', 'a156'))>, 'a155': <RoborockProductNickname.VIVIAN: ProductInfo(nickname='Vivian', short_models=('a134', 'a135', 'a155', 'a156'))>, 'a156': <RoborockProductNickname.VIVIAN: ProductInfo(nickname='Vivian', short_models=('a134', 'a135', 'a155', 'a156'))>, 'a158': <RoborockProductNickname.VIVIANC: ProductInfo(nickname='VivianC', short_models=('a158', 'a159'))>, 'a159': <RoborockProductNickname.VIVIANC: ProductInfo(nickname='VivianC', short_models=('a158', 'a159'))>}
class RoborockCategory(enum.Enum):
234class RoborockCategory(Enum):
235    """Describes the category of the device."""
236
237    WET_DRY_VAC = "roborock.wetdryvac"
238    VACUUM = "robot.vacuum.cleaner"
239    WASHING_MACHINE = "roborock.wm"
240    MOWER = "roborock.mower"
241    UNKNOWN = "UNKNOWN"
242
243    @classmethod
244    def _missing_(cls, value):
245        _LOGGER.warning("Missing code %s from category", value)
246        return RoborockCategory.UNKNOWN

Describes the category of the device.

WET_DRY_VAC = <RoborockCategory.WET_DRY_VAC: 'roborock.wetdryvac'>
VACUUM = <RoborockCategory.VACUUM: 'robot.vacuum.cleaner'>
WASHING_MACHINE = <RoborockCategory.WASHING_MACHINE: 'roborock.wm'>
MOWER = <RoborockCategory.MOWER: 'roborock.mower'>
UNKNOWN = <RoborockCategory.UNKNOWN: 'UNKNOWN'>