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

Roborock Enum for codes with int values

name: str
14    @property
15    def name(self) -> str:
16        return super().name.lower()

The name of the Enum member.

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