6262from roborock .device_features import ZeoFeatures
6363from roborock .devices .rpc .a01_channel import send_decoded_command
6464from roborock .devices .traits import Trait
65- from roborock .protocols .a01_protocol import decode_rpc_response
6665from roborock .devices .traits .a01 .device_features import ZeoFeatureTrait
6766from roborock .devices .transport .mqtt_channel import MqttChannel
6867from roborock .exceptions import RoborockException
6968from roborock .mqtt .session import MqttQos
70- from roborock .roborock_message import RoborockDyadDataProtocol , RoborockMessage , RoborockMessageProtocol , RoborockZeoProtocol
69+ from roborock .protocols .a01_protocol import decode_rpc_response
70+ from roborock .roborock_message import (
71+ RoborockDyadDataProtocol ,
72+ RoborockMessage ,
73+ RoborockMessageProtocol ,
74+ RoborockZeoProtocol ,
75+ )
7176
7277_LOGGER = logging .getLogger (__name__ )
7378
@@ -217,8 +222,12 @@ def to_dp_bool(val: Any) -> str:
217222 RoborockZeoProtocol .ION_DEODORIZATION : parse_bool ,
218223 RoborockZeoProtocol .UV_LIGHT : parse_bool ,
219224 RoborockZeoProtocol .SMART_HOSTING : parse_bool ,
220- RoborockZeoProtocol .SOFTENER_EXPANSION_TYPE : lambda val : _decode_expansion_type (val , ZeoSoftenerExpansionType .softener ),
221- RoborockZeoProtocol .DETERGENT_EXPANSION_TYPE : lambda val : _decode_expansion_type (val , ZeoDetergentExpansionType .concentrated_detergent ),
225+ RoborockZeoProtocol .SOFTENER_EXPANSION_TYPE : lambda val : _decode_expansion_type (
226+ val , ZeoSoftenerExpansionType .softener
227+ ),
228+ RoborockZeoProtocol .DETERGENT_EXPANSION_TYPE : lambda val : _decode_expansion_type (
229+ val , ZeoDetergentExpansionType .concentrated_detergent
230+ ),
222231 RoborockZeoProtocol .SMILE_LIGHT_STATUS : parse_bool ,
223232 RoborockZeoProtocol .POWER_LIGHT : parse_bool ,
224233 RoborockZeoProtocol .PANEL_PROGRAM_PARAMS_SET : lambda val : int (val ),
@@ -336,6 +345,7 @@ class ZeoStartParams:
336345# 32-bit integer at DP 222. This mirrors WasherDpsCache.customMode in
337346# module 725 of the React Native plugin bundle.
338347
348+
339349@dataclass
340350class ZeoCustomMode :
341351 """Decoded custom programme parameters from DP 222 (LoadCloudProgram).
@@ -610,9 +620,7 @@ def _start_params(self) -> tuple[RoborockZeoProtocol, ...]:
610620 (RoborockZeoProtocol .ION_DEODORIZATION , "ion_deodorization" ),
611621 )
612622
613- async def _build_feature_gated_dps (
614- self , features : ZeoFeatures | None , dps : dict [RoborockZeoProtocol , Any ]
615- ) -> None :
623+ async def _build_feature_gated_dps (self , features : ZeoFeatures | None , dps : dict [RoborockZeoProtocol , Any ]) -> None :
616624 """Add feature-gated DPs to *dps* in-place, batch-querying uncached ones.
617625
618626 Only includes DPs whose corresponding FeatureBit is set in *features*.
@@ -822,12 +830,8 @@ async def _build_save_payload(self) -> dict[RoborockZeoProtocol, Any]:
822830 """Bundle Mode + Program + cached optionals for a save command."""
823831 await self ._ensure_subscribed ()
824832 payload : dict [RoborockZeoProtocol , Any ] = {
825- RoborockZeoProtocol .MODE : self ._dps_cache .get (
826- int (RoborockZeoProtocol .MODE ), 1
827- ),
828- RoborockZeoProtocol .PROGRAM : self ._dps_cache .get (
829- int (RoborockZeoProtocol .PROGRAM ), 1
830- ),
833+ RoborockZeoProtocol .MODE : self ._dps_cache .get (int (RoborockZeoProtocol .MODE ), 1 ),
834+ RoborockZeoProtocol .PROGRAM : self ._dps_cache .get (int (RoborockZeoProtocol .PROGRAM ), 1 ),
831835 }
832836 for dp in self ._save_params :
833837 val = self ._dps_cache .get (int (dp ))
@@ -994,15 +998,15 @@ async def get_auto_detergent(self) -> bool:
994998 self ._channel ,
995999 {
9961000 RoborockZeoProtocol .ID_QUERY : [
997- RoborockZeoProtocol .DETERGENT_TYPE if self .is_addition_type_control
1001+ RoborockZeoProtocol .DETERGENT_TYPE
1002+ if self .is_addition_type_control
9981003 else RoborockZeoProtocol .DETERGENT_SET ,
9991004 ],
10001005 },
10011006 value_encoder = json .dumps ,
10021007 )
10031008 raw = result .get (
1004- RoborockZeoProtocol .DETERGENT_TYPE if self .is_addition_type_control
1005- else RoborockZeoProtocol .DETERGENT_SET
1009+ RoborockZeoProtocol .DETERGENT_TYPE if self .is_addition_type_control else RoborockZeoProtocol .DETERGENT_SET
10061010 )
10071011 return parse_bool (raw ) if not self .is_addition_type_control else bool (raw and int (raw ) > 0 )
10081012
@@ -1012,15 +1016,15 @@ async def get_auto_softener(self) -> bool:
10121016 self ._channel ,
10131017 {
10141018 RoborockZeoProtocol .ID_QUERY : [
1015- RoborockZeoProtocol .SOFTENER_TYPE if self .is_addition_type_control
1019+ RoborockZeoProtocol .SOFTENER_TYPE
1020+ if self .is_addition_type_control
10161021 else RoborockZeoProtocol .SOFTENER_SET ,
10171022 ],
10181023 },
10191024 value_encoder = json .dumps ,
10201025 )
10211026 raw = result .get (
1022- RoborockZeoProtocol .SOFTENER_TYPE if self .is_addition_type_control
1023- else RoborockZeoProtocol .SOFTENER_SET
1027+ RoborockZeoProtocol .SOFTENER_TYPE if self .is_addition_type_control else RoborockZeoProtocol .SOFTENER_SET
10241028 )
10251029 return parse_bool (raw ) if not self .is_addition_type_control else bool (raw and int (raw ) > 0 )
10261030
@@ -1223,12 +1227,15 @@ async def load_general_info(self) -> dict[RoborockZeoProtocol, Any]:
12231227 async def upload_log (self ) -> dict [RoborockZeoProtocol , Any ]:
12241228 """Request the device to upload diagnostic logs (RPC call)."""
12251229 import random as _random
1230+
12261231 return await send_decoded_command (
12271232 self ._channel ,
1228- {RoborockZeoProtocol .RPC_REQUEST : {
1229- "id" : _random .randint (0 , 999999 ),
1230- "method" : "user_upload_log" ,
1231- }},
1233+ {
1234+ RoborockZeoProtocol .RPC_REQUEST : {
1235+ "id" : _random .randint (0 , 999999 ),
1236+ "method" : "user_upload_log" ,
1237+ }
1238+ },
12321239 value_encoder = lambda x : x ,
12331240 )
12341241
@@ -1355,26 +1362,45 @@ async def set_value(self, protocol: RoborockZeoProtocol, value: Any) -> dict[Rob
13551362# auto‑enable logic and for force‑load DP selection. These frozensets
13561363# mirror the ``isHyperionSeries / isHaliaSeries / isHeraSeries`` and
13571364# ``isM1Series / isMuseSeries / isMetisSeries`` guards.
1358- _HYPERION_HALIA_HERA_PRODUCT_IDS : frozenset [str ] = frozenset ({
1359- # Hyperion series
1360- "roborock.wm.a141" , "roborock.wm.a149" , "roborock.wm.a207" , "roborock.wm.a230" ,
1361- # Halia series
1362- "roborock.wm.a240" , "roborock.wm.a241" ,
1363- # Hera series
1364- "roborock.wm.a227" , "roborock.wm.a261" , "roborock.wm.a273" ,
1365- "roborock.wm.a268" , "roborock.wm.a269" ,
1366- })
1367-
1368- _M1_MUSE_METIS_PRODUCT_IDS : frozenset [str ] = frozenset ({
1369- # M1 series
1370- "roborock.wm.a92" , "roborock.wm.a93" , "roborock.wm.a133" , "roborock.wm.a277" ,
1371- "roborock.wm.a162" , "roborock.wm.a233" , "roborock.wm.a276" , "roborock.wm.a234" ,
1372- "roborock.wm.a218" ,
1373- # Muse series
1374- "roborock.wm.a142" , "roborock.wm.a215" ,
1375- # Metis series
1376- "roborock.wm.a154" , "roborock.wm.a214" ,
1377- })
1365+ _HYPERION_HALIA_HERA_PRODUCT_IDS : frozenset [str ] = frozenset (
1366+ {
1367+ # Hyperion series
1368+ "roborock.wm.a141" ,
1369+ "roborock.wm.a149" ,
1370+ "roborock.wm.a207" ,
1371+ "roborock.wm.a230" ,
1372+ # Halia series
1373+ "roborock.wm.a240" ,
1374+ "roborock.wm.a241" ,
1375+ # Hera series
1376+ "roborock.wm.a227" ,
1377+ "roborock.wm.a261" ,
1378+ "roborock.wm.a273" ,
1379+ "roborock.wm.a268" ,
1380+ "roborock.wm.a269" ,
1381+ }
1382+ )
1383+
1384+ _M1_MUSE_METIS_PRODUCT_IDS : frozenset [str ] = frozenset (
1385+ {
1386+ # M1 series
1387+ "roborock.wm.a92" ,
1388+ "roborock.wm.a93" ,
1389+ "roborock.wm.a133" ,
1390+ "roborock.wm.a277" ,
1391+ "roborock.wm.a162" ,
1392+ "roborock.wm.a233" ,
1393+ "roborock.wm.a276" ,
1394+ "roborock.wm.a234" ,
1395+ "roborock.wm.a218" ,
1396+ # Muse series
1397+ "roborock.wm.a142" ,
1398+ "roborock.wm.a215" ,
1399+ # Metis series
1400+ "roborock.wm.a154" ,
1401+ "roborock.wm.a214" ,
1402+ }
1403+ )
13781404
13791405
13801406def _is_dryer (product : HomeDataProduct ) -> bool :
0 commit comments