1+ from collections .abc import Callable
2+ from datetime import time
13from typing import Any
24
3- from roborock .data import HomeDataProduct , RoborockCategory
5+ from roborock .data import DyadProductInfo , DyadSndState , HomeDataProduct , RoborockCategory
6+ from roborock .data .dyad .dyad_code_mappings import (
7+ DyadBrushSpeed ,
8+ DyadCleanMode ,
9+ DyadError ,
10+ DyadSelfCleanLevel ,
11+ DyadSelfCleanMode ,
12+ DyadSuction ,
13+ DyadWarmLevel ,
14+ DyadWaterLevel ,
15+ RoborockDyadStateCode ,
16+ )
17+ from roborock .data .zeo .zeo_code_mappings import (
18+ ZeoDetergentType ,
19+ ZeoDryingMode ,
20+ ZeoError ,
21+ ZeoMode ,
22+ ZeoProgram ,
23+ ZeoRinse ,
24+ ZeoSoftenerType ,
25+ ZeoSpin ,
26+ ZeoState ,
27+ ZeoTemperature ,
28+ )
429from roborock .devices .a01_channel import send_decoded_command
530from roborock .devices .mqtt_channel import MqttChannel
631from roborock .devices .traits import Trait
1237]
1338
1439
40+ DYAD_PROTOCOL_ENTRIES : dict [RoborockDyadDataProtocol , Callable ] = {
41+ RoborockDyadDataProtocol .STATUS : lambda val : RoborockDyadStateCode (val ).name ,
42+ RoborockDyadDataProtocol .SELF_CLEAN_MODE : lambda val : DyadSelfCleanMode (val ).name ,
43+ RoborockDyadDataProtocol .SELF_CLEAN_LEVEL : lambda val : DyadSelfCleanLevel (val ).name ,
44+ RoborockDyadDataProtocol .WARM_LEVEL : lambda val : DyadWarmLevel (val ).name ,
45+ RoborockDyadDataProtocol .CLEAN_MODE : lambda val : DyadCleanMode (val ).name ,
46+ RoborockDyadDataProtocol .SUCTION : lambda val : DyadSuction (val ).name ,
47+ RoborockDyadDataProtocol .WATER_LEVEL : lambda val : DyadWaterLevel (val ).name ,
48+ RoborockDyadDataProtocol .BRUSH_SPEED : lambda val : DyadBrushSpeed (val ).name ,
49+ RoborockDyadDataProtocol .POWER : lambda val : int (val ),
50+ RoborockDyadDataProtocol .AUTO_DRY : lambda val : bool (val ),
51+ RoborockDyadDataProtocol .MESH_LEFT : lambda val : int (360000 - val * 60 ),
52+ RoborockDyadDataProtocol .BRUSH_LEFT : lambda val : int (360000 - val * 60 ),
53+ RoborockDyadDataProtocol .ERROR : lambda val : DyadError (val ).name ,
54+ RoborockDyadDataProtocol .VOLUME_SET : lambda val : int (val ),
55+ RoborockDyadDataProtocol .STAND_LOCK_AUTO_RUN : lambda val : bool (val ),
56+ RoborockDyadDataProtocol .AUTO_DRY_MODE : lambda val : bool (val ),
57+ RoborockDyadDataProtocol .SILENT_DRY_DURATION : lambda val : int (val ), # in minutes
58+ RoborockDyadDataProtocol .SILENT_MODE : lambda val : bool (val ),
59+ RoborockDyadDataProtocol .SILENT_MODE_START_TIME : lambda val : time (
60+ hour = int (val / 60 ), minute = val % 60
61+ ), # in minutes since 00:00
62+ RoborockDyadDataProtocol .SILENT_MODE_END_TIME : lambda val : time (
63+ hour = int (val / 60 ), minute = val % 60
64+ ), # in minutes since 00:00
65+ RoborockDyadDataProtocol .RECENT_RUN_TIME : lambda val : [
66+ int (v ) for v in val .split ("," )
67+ ], # minutes of cleaning in past few days.
68+ RoborockDyadDataProtocol .TOTAL_RUN_TIME : lambda val : int (val ),
69+ RoborockDyadDataProtocol .SND_STATE : lambda val : DyadSndState .from_dict (val ),
70+ RoborockDyadDataProtocol .PRODUCT_INFO : lambda val : DyadProductInfo .from_dict (val ),
71+ }
72+
73+ ZEO_PROTOCOL_ENTRIES : dict [RoborockZeoProtocol , Callable ] = {
74+ # ro
75+ RoborockZeoProtocol .STATE : lambda val : ZeoState (val ).name ,
76+ RoborockZeoProtocol .COUNTDOWN : lambda val : int (val ),
77+ RoborockZeoProtocol .WASHING_LEFT : lambda val : int (val ),
78+ RoborockZeoProtocol .ERROR : lambda val : ZeoError (val ).name ,
79+ RoborockZeoProtocol .TIMES_AFTER_CLEAN : lambda val : int (val ),
80+ RoborockZeoProtocol .DETERGENT_EMPTY : lambda val : bool (val ),
81+ RoborockZeoProtocol .SOFTENER_EMPTY : lambda val : bool (val ),
82+ # rw
83+ RoborockZeoProtocol .MODE : lambda val : ZeoMode (val ).name ,
84+ RoborockZeoProtocol .PROGRAM : lambda val : ZeoProgram (val ).name ,
85+ RoborockZeoProtocol .TEMP : lambda val : ZeoTemperature (val ).name ,
86+ RoborockZeoProtocol .RINSE_TIMES : lambda val : ZeoRinse (val ).name ,
87+ RoborockZeoProtocol .SPIN_LEVEL : lambda val : ZeoSpin (val ).name ,
88+ RoborockZeoProtocol .DRYING_MODE : lambda val : ZeoDryingMode (val ).name ,
89+ RoborockZeoProtocol .DETERGENT_TYPE : lambda val : ZeoDetergentType (val ).name ,
90+ RoborockZeoProtocol .SOFTENER_TYPE : lambda val : ZeoSoftenerType (val ).name ,
91+ RoborockZeoProtocol .SOUND_SET : lambda val : bool (val ),
92+ }
93+
94+
95+ def convert_dyad_value (protocol : int , value : Any ) -> Any :
96+ """Convert a dyad protocol value to its corresponding type."""
97+ protocol_value = RoborockDyadDataProtocol (protocol )
98+ if (converter := DYAD_PROTOCOL_ENTRIES .get (protocol_value )) is not None :
99+ return converter (value )
100+ return None
101+
102+
103+ def convert_zeo_value (protocol : int , value : Any ) -> Any :
104+ """Convert a zeo protocol value to its corresponding type."""
105+ protocol_value = RoborockZeoProtocol (protocol )
106+ if (converter := ZEO_PROTOCOL_ENTRIES .get (protocol_value )) is not None :
107+ return converter (value )
108+ return None
109+
110+
15111class DyadApi (Trait ):
16112 """API for interacting with Dyad devices."""
17113
@@ -22,7 +118,12 @@ def __init__(self, channel: MqttChannel) -> None:
22118 async def query_values (self , protocols : list [RoborockDyadDataProtocol ]) -> dict [RoborockDyadDataProtocol , Any ]:
23119 """Query the device for the values of the given Dyad protocols."""
24120 params = {RoborockDyadDataProtocol .ID_QUERY : [int (p ) for p in protocols ]}
25- return await send_decoded_command (self ._channel , params )
121+ response = await send_decoded_command (self ._channel , params )
122+ return {
123+ RoborockDyadDataProtocol (int (k )): v
124+ for k , val in response .items ()
125+ if (v := convert_dyad_value (int (k ), val )) is not None
126+ }
26127
27128 async def set_value (self , protocol : RoborockDyadDataProtocol , value : Any ) -> dict [RoborockDyadDataProtocol , Any ]:
28129 """Set a value for a specific protocol on the device."""
@@ -42,7 +143,12 @@ def __init__(self, channel: MqttChannel) -> None:
42143 async def query_values (self , protocols : list [RoborockZeoProtocol ]) -> dict [RoborockZeoProtocol , Any ]:
43144 """Query the device for the values of the given protocols."""
44145 params = {RoborockZeoProtocol .ID_QUERY : [int (p ) for p in protocols ]}
45- return await send_decoded_command (self ._channel , params )
146+ response = await send_decoded_command (self ._channel , params )
147+ return {
148+ RoborockZeoProtocol (int (k )): v
149+ for k , val in response .items ()
150+ if (v := convert_zeo_value (int (k ), val )) is not None
151+ }
46152
47153 async def set_value (self , protocol : RoborockZeoProtocol , value : Any ) -> dict [RoborockZeoProtocol , Any ]:
48154 """Set a value for a specific protocol on the device."""
0 commit comments