1515
1616from roborock .data import HomeDataDevice , HomeDataProduct
1717from roborock .data .v1 import RoborockStateCode
18- from roborock .data .v1 .v1_code_mappings import RoborockCleanType , RoborockFinishReason , RoborockStartType
19- from roborock .data .v1 .v1_containers import CleanRecord , CleanSummary , Consumable , DnDTimer
18+ from roborock .data .v1 .v1_code_mappings import (
19+ RoborockChargeStatus ,
20+ RoborockCleanType ,
21+ RoborockDockErrorCode ,
22+ RoborockDockTypeCode ,
23+ RoborockErrorCode ,
24+ RoborockFinishReason ,
25+ RoborockInCleaning ,
26+ RoborockStartType ,
27+ )
28+ from roborock .data .v1 .v1_containers import (
29+ AppInitStatus ,
30+ AppInitStatusLocalInfo ,
31+ CleanRecord ,
32+ CleanSummary ,
33+ Consumable ,
34+ DnDTimer ,
35+ NetworkInfo ,
36+ StatusV2 ,
37+ )
2038from roborock .devices .cache import DeviceCache , InMemoryCache
2139from roborock .devices .rpc .v1_channel import V1Channel
2240from roborock .protocols .v1_protocol import SecurityData
@@ -32,53 +50,6 @@ def _serialize_dataclass(obj: Any) -> dict[str, Any]:
3250 return {k : (v .value if isinstance (v , Enum ) else v ) for k , v in asdict (obj ).items () if v is not None }
3351
3452
35- # Simulated network details
36- DEFAULT_NETWORK_INFO = {
37- "ip" : "1.1.1.1" ,
38- "ssid" : "test_wifi" ,
39- "mac" : "aa:bb:cc:dd:ee:ff" ,
40- "bssid" : "aa:bb:cc:dd:ee:ff" ,
41- "rssi" : - 50 ,
42- }
43-
44- # Simulated application init parameters
45- DEFAULT_APP_GET_INIT_STATUS = {
46- "local_info" : {
47- "name" : "custom_A.03.0069_FCC" ,
48- "bom" : "A.03.0069" ,
49- "location" : "us" ,
50- "language" : "en" ,
51- "wifiplan" : "0x39" ,
52- "timezone" : "US/Pacific" ,
53- "logserver" : "awsusor0.fds.api.xiaomi.com" ,
54- "featureset" : 1 ,
55- },
56- "feature_info" : [111 , 112 , 113 , 114 , 115 , 116 , 117 , 118 , 119 , 120 , 122 , 123 , 124 , 125 ],
57- "new_feature_info" : 633887780925447 ,
58- "new_feature_info2" : 8192 ,
59- "new_feature_info_str" : "0000000000002000" ,
60- "status_info" : {
61- "state" : RoborockStateCode .charging ,
62- "battery" : 100 ,
63- "clean_time" : 5610 ,
64- "clean_area" : 96490000 ,
65- "error_code" : 0 ,
66- "in_cleaning" : 0 ,
67- "in_returning" : 0 ,
68- "in_fresh_state" : 1 ,
69- "lab_status" : 1 ,
70- "water_box_status" : 0 ,
71- "map_status" : 3 ,
72- "is_locating" : 0 ,
73- "lock_status" : 0 ,
74- "water_box_mode" : 204 ,
75- "distance_off" : 0 ,
76- "water_box_carriage_status" : 0 ,
77- "mop_forbidden_enable" : 0 ,
78- },
79- }
80-
81-
8253class V1VacuumSimulator (RoborockDeviceSimulator ):
8354 """Firmware simulator for a V1/L01 vacuum device.
8455
@@ -117,6 +88,14 @@ def __init__(
11788 self .dss = dss
11889 self .dock_type = dock_type
11990
91+ self .network_info = NetworkInfo (
92+ ip = "1.1.1.1" ,
93+ ssid = "test_wifi" ,
94+ mac = "aa:bb:cc:dd:ee:ff" ,
95+ bssid = "aa:bb:cc:dd:ee:ff" ,
96+ rssi = - 50 ,
97+ )
98+
12099 self .consumables = Consumable (
121100 main_brush_work_time = 74382 ,
122101 side_brush_work_time = 74383 ,
@@ -196,69 +175,76 @@ def v1_channel(self) -> V1Channel:
196175 return self ._v1_channel
197176
198177 @property
199- def in_cleaning (self ) -> int :
200- """Return 1 if cleaning, else 0."""
201- return 1 if self .state == RoborockStateCode .cleaning else 0
178+ def in_cleaning (self ) -> RoborockInCleaning :
179+ """Return global_clean_not_complete if cleaning, else complete."""
180+ return (
181+ RoborockInCleaning .global_clean_not_complete
182+ if self .state == RoborockStateCode .cleaning
183+ else RoborockInCleaning .complete
184+ )
202185
203186 @property
204187 def in_returning (self ) -> int :
205188 """Return 1 if returning, else 0."""
206189 return 1 if self .state == RoborockStateCode .returning_home else 0
207190
208191 @property
209- def charge_status (self ) -> int :
210- """Return 1 if charging, else 0."""
211- return 1 if self .state == RoborockStateCode .charging else 0
192+ def charge_status (self ) -> RoborockChargeStatus :
193+ """Return charging if charging, else charge_waiting."""
194+ return (
195+ RoborockChargeStatus .charging
196+ if self .state == RoborockStateCode .charging
197+ else RoborockChargeStatus .charge_waiting
198+ )
212199
213200 def get_status_dict (self ) -> dict [str , Any ]:
214201 """Generate status dict using the current simulated state."""
215- return {
216- "msg_ver" : 2 ,
217- "msg_seq" : 458 ,
218- "state" : self .state ,
219- "battery" : self .battery ,
220- "clean_time" : 1176 ,
221- "clean_area" : 20965000 ,
222- "error_code" : 0 ,
223- "map_present" : 1 ,
224- "in_cleaning" : self .in_cleaning ,
225- "in_returning" : self .in_returning ,
226- "in_fresh_state" : 1 ,
227- "lab_status" : 1 ,
228- "water_box_status" : 1 ,
229- "back_type" : - 1 ,
230- "wash_phase" : 0 ,
231- "wash_ready" : 0 ,
232- "fan_power" : self .fan_power ,
233- "dnd_enabled" : self .dnd_enabled ,
234- "map_status" : 3 ,
235- "is_locating" : 0 ,
236- "lock_status" : 0 ,
237- "water_box_mode" : self .water_box_mode ,
238- "water_box_carriage_status" : 1 ,
239- "mop_forbidden_enable" : 1 ,
240- "camera_status" : 3457 ,
241- "is_exploring" : 0 ,
242- "home_sec_status" : 0 ,
243- "home_sec_enable_password" : 0 ,
244- "adbumper_status" : [0 , 0 , 0 ],
245- "water_shortage_status" : 0 ,
246- "grey_water_box_status" : 0 ,
247- "dirty_water_box_status" : 0 ,
248- "dock_type" : self .dock_type ,
249- "dust_collection_status" : 0 ,
250- "auto_dust_collection" : 1 ,
251- "avoid_count" : 19 ,
252- "mop_mode" : self .mop_mode ,
253- "debug_mode" : 0 ,
254- "collision_avoid_status" : 1 ,
255- "switch_map_mode" : 0 ,
256- "dock_error_status" : 0 ,
257- "charge_status" : self .charge_status ,
258- "unsave_map_reason" : 0 ,
259- "unsave_map_flag" : 0 ,
260- "dss" : self .dss ,
261- }
202+ status = StatusV2 (
203+ msg_ver = 2 ,
204+ msg_seq = 458 ,
205+ state = RoborockStateCode (self .state ),
206+ battery = self .battery ,
207+ clean_time = 1176 ,
208+ clean_area = 20965000 ,
209+ error_code = RoborockErrorCode (0 ),
210+ map_present = 1 ,
211+ in_cleaning = self .in_cleaning ,
212+ in_returning = self .in_returning ,
213+ in_fresh_state = 1 ,
214+ lab_status = 1 ,
215+ water_box_status = 1 ,
216+ back_type = - 1 ,
217+ wash_phase = 0 ,
218+ wash_ready = 0 ,
219+ fan_power = self .fan_power ,
220+ dnd_enabled = self .dnd_enabled ,
221+ map_status = 3 ,
222+ is_locating = 0 ,
223+ lock_status = 0 ,
224+ water_box_mode = self .water_box_mode ,
225+ water_box_carriage_status = 1 ,
226+ mop_forbidden_enable = 1 ,
227+ camera_status = 3457 ,
228+ is_exploring = 0 ,
229+ home_sec_status = 0 ,
230+ home_sec_enable_password = 0 ,
231+ adbumper_status = [0 , 0 , 0 ],
232+ water_shortage_status = 0 ,
233+ dock_type = RoborockDockTypeCode (self .dock_type ),
234+ dust_collection_status = 0 ,
235+ auto_dust_collection = 1 ,
236+ avoid_count = 19 ,
237+ mop_mode = self .mop_mode ,
238+ debug_mode = 0 ,
239+ collision_avoid_status = 1 ,
240+ switch_map_mode = 0 ,
241+ dock_error_status = RoborockDockErrorCode (0 ),
242+ charge_status = self .charge_status ,
243+ unsave_map_reason = 0 ,
244+ unsave_map_flag = 0 ,
245+ dss = self .dss ,
246+ )
247+ return _serialize_dataclass (status )
262248
263249 def _handle_app_start (self , params : Any ) -> str :
264250 self .state = RoborockStateCode .cleaning
@@ -297,10 +283,50 @@ def _handle_reset_consumable(self, params: Any) -> str:
297283 return "ok"
298284
299285 def _handle_app_get_init_status (self , params : Any ) -> list [dict [str , Any ]]:
300- return [DEFAULT_APP_GET_INIT_STATUS ]
286+ local_info = AppInitStatusLocalInfo (
287+ location = "us" ,
288+ bom = "A.03.0069" ,
289+ featureset = 1 ,
290+ language = "en" ,
291+ logserver = "awsusor0.fds.api.xiaomi.com" ,
292+ wifiplan = "0x39" ,
293+ timezone = "US/Pacific" ,
294+ name = "custom_A.03.0069_FCC" ,
295+ )
296+ app_init = AppInitStatus (
297+ local_info = local_info ,
298+ feature_info = [111 , 112 , 113 , 114 , 115 , 116 , 117 , 118 , 119 , 120 , 122 , 123 , 124 , 125 ],
299+ new_feature_info = 633887780925447 ,
300+ new_feature_info_str = "0000000000002000" ,
301+ new_feature_info_2 = 8192 ,
302+ )
303+ payload = _serialize_dataclass (app_init )
304+ if "new_feature_info_2" in payload :
305+ payload ["new_feature_info2" ] = payload .pop ("new_feature_info_2" )
306+
307+ payload ["status_info" ] = {
308+ "state" : self .state ,
309+ "battery" : self .battery ,
310+ "clean_time" : 5610 ,
311+ "clean_area" : 96490000 ,
312+ "error_code" : 0 ,
313+ "in_cleaning" : self .in_cleaning .value ,
314+ "in_returning" : self .in_returning ,
315+ "in_fresh_state" : 1 ,
316+ "lab_status" : 1 ,
317+ "water_box_status" : 0 ,
318+ "map_status" : 3 ,
319+ "is_locating" : 0 ,
320+ "lock_status" : 0 ,
321+ "water_box_mode" : self .water_box_mode ,
322+ "distance_off" : 0 ,
323+ "water_box_carriage_status" : 0 ,
324+ "mop_forbidden_enable" : 0 ,
325+ }
326+ return [payload ]
301327
302328 def _handle_get_network_info (self , params : Any ) -> dict [str , Any ]:
303- return DEFAULT_NETWORK_INFO
329+ return _serialize_dataclass ( self . network_info )
304330
305331 async def _handle_publish (self , message : RoborockMessage , channel : FakeChannel ) -> None :
306332 if not message .payload :
0 commit comments