@@ -95,12 +95,12 @@ def translate_virtual_wall(self, edit: VirtualWallEdit) -> tuple[str, Any]:
9595 """
9696 # V1 uses the full map update approach
9797 wall_data = [int (edit .x1 ), int (edit .y1 ), int (edit .x2 ), int (edit .y2 )]
98- return "set_virtual_wall" , [wall_data ]
98+ return RoborockCommand . SET_VIRTUAL_WALL , [wall_data ]
9999
100100 def translate_no_go_zone (self , edit : NoGoZoneEdit ) -> tuple [str , Any ]:
101101 """Translate to SET_NO_GO_ZONES command."""
102102 zone_data = [int (edit .x1 ), int (edit .y1 ), int (edit .x2 ), int (edit .y2 )]
103- return "set_no_go_zones" , [zone_data ]
103+ return RoborockCommand . SET_NO_GO_ZONES , [zone_data ]
104104
105105 def translate_split_room (self , edit : SplitRoomEdit ) -> tuple [str , Any ]:
106106 """Translate to SPLIT_SEGMENT command.
@@ -264,12 +264,110 @@ async def execute_edits(
264264 additive_edits = virtual_state .get_additive_edits ()
265265 if additive_edits and topology_success :
266266 _LOGGER .info (f"Stage 3: Executing { len (additive_edits )} additive edits" )
267- for edit in additive_edits :
268- result = await self ._execute_edit (edit , map_flag )
269- results .append (result )
267+
268+ if self ._protocol == "v1" :
269+ # V1 requires batching additive edits as they overwrite the entire state
270+ batch_results = await self ._execute_v1_additive_batch (virtual_state , additive_edits , map_flag )
271+ results .extend (batch_results )
272+ else :
273+ # B01 might support individual updates (verify)
274+ for edit in additive_edits :
275+ result = await self ._execute_edit (edit , map_flag )
276+ results .append (result )
270277
271278 return results
272279
280+ async def _execute_v1_additive_batch (
281+ self ,
282+ virtual_state : VirtualState ,
283+ edits : list [EditObject ],
284+ map_flag : int | None ,
285+ ) -> list [TranslationResult ]:
286+ """Execute additive edits as a batch for V1 protocol.
287+
288+ V1 commands like set_virtual_wall overwrite the entire list,
289+ so we must combine new edits with existing state.
290+ """
291+ results : list [TranslationResult ] = []
292+ pending_walls = [e for e in edits if isinstance (e , VirtualWallEdit ) and e .status == EditStatus .APPLIED ]
293+ pending_zones = [e for e in edits if isinstance (e , NoGoZoneEdit ) and e .status == EditStatus .APPLIED ]
294+ pending_mop_zones = [e for e in edits if e .edit_type == EditType .MOP_FORBIDDEN_ZONE and e .status == EditStatus .APPLIED ]
295+
296+ # 1. Handle Virtual Walls
297+ if pending_walls :
298+ # Combine original walls with new ones
299+ all_walls = list (virtual_state ._original_walls )
300+ for wall in pending_walls :
301+ all_walls .append ((wall .x1 , wall .y1 , wall .x2 , wall .y2 ))
302+
303+ # Format: [map_flag, [[x1, y1, x2, y2], ...]]
304+ params = [list (w ) for w in all_walls ]
305+ if map_flag is not None :
306+ params = [map_flag , params ]
307+
308+ try :
309+ _LOGGER .debug (f"Sending V1 wall batch: { params } " )
310+ await self ._command .send (RoborockCommand .SET_VIRTUAL_WALL , params )
311+ for edit in pending_walls :
312+ edit .status = EditStatus .SYNCED
313+ results .append (TranslationResult (success = True , edit = edit ))
314+ except Exception as e :
315+ _LOGGER .error (f"Failed to sync wall batch: { e } " )
316+ for edit in pending_walls :
317+ edit .status = EditStatus .FAILED
318+ results .append (TranslationResult (success = False , edit = edit , error = str (e )))
319+
320+ # 2. Handle No-Go Zones
321+ if pending_zones :
322+ # Combine original zones with new ones
323+ all_zones = list (virtual_state ._original_no_go_zones )
324+ for zone in pending_zones :
325+ all_zones .append ((zone .x1 , zone .y1 , zone .x2 , zone .y2 ))
326+
327+ # Format: [map_flag, [[x1, y1, x2, y2], ...]]
328+ params = [list (z ) for z in all_zones ]
329+ if map_flag is not None :
330+ params = [map_flag , params ]
331+
332+ try :
333+ _LOGGER .debug (f"Sending V1 zone batch: { params } " )
334+ await self ._command .send (RoborockCommand .SET_NO_GO_ZONES , params )
335+ for edit in pending_zones :
336+ edit .status = EditStatus .SYNCED
337+ results .append (TranslationResult (success = True , edit = edit ))
338+ except Exception as e :
339+ _LOGGER .error (f"Failed to sync zone batch: { e } " )
340+ for edit in pending_zones :
341+ edit .status = EditStatus .FAILED
342+ results .append (TranslationResult (success = False , edit = edit , error = str (e )))
343+
344+ # 3. Handle Mop Forbidden Zones
345+ if pending_mop_zones :
346+ # Combine original mop zones with new ones
347+ all_mop_zones = list (virtual_state ._original_mop_zones )
348+ for zone in pending_mop_zones :
349+ # Mop zones are typically same 4-coord format
350+ if hasattr (zone , 'x1' ):
351+ all_mop_zones .append ((zone .x1 , zone .y1 , zone .x2 , zone .y2 ))
352+
353+ params = [list (z ) for z in all_mop_zones ]
354+ if map_flag is not None :
355+ params = [map_flag , params ]
356+
357+ try :
358+ _LOGGER .debug (f"Sending V1 mop zone batch: { params } " )
359+ await self ._command .send (RoborockCommand .SET_MOP_FORBIDDEN_ZONE , params )
360+ for edit in pending_mop_zones :
361+ edit .status = EditStatus .SYNCED
362+ results .append (TranslationResult (success = True , edit = edit ))
363+ except Exception as e :
364+ _LOGGER .error (f"Failed to sync mop zone batch: { e } " )
365+ for edit in pending_mop_zones :
366+ edit .status = EditStatus .FAILED
367+ results .append (TranslationResult (success = False , edit = edit , error = str (e )))
368+
369+ return results
370+
273371 async def _execute_edit (
274372 self ,
275373 edit : EditObject ,
@@ -500,5 +598,5 @@ async def _repopulate_room_ids(self, virtual_state: VirtualState) -> None:
500598
501599 # 5. Update the base map for the VirtualState so subsequent matches are correct
502600 # This is important if we're doing multiple rounds or just to keep state consistent.
503- # virtual_state._base_map = new_map (Internal access needed or a public setter )
504- # For now, we've updated the pending edits which is the primary goal for execution.
601+ virtual_state .refresh_base_map ( new_map )
602+ _LOGGER . info ( "Refreshed VirtualState base map after remapping" )
0 commit comments