1818import io
1919import zlib
2020from dataclasses import dataclass , field
21- from typing import Any
21+ from typing import Protocol , cast
2222
2323from Crypto .Cipher import AES
2424from Crypto .Util .Padding import pad , unpad
25- from google .protobuf .message import DecodeError
25+ from google .protobuf .message import DecodeError , Message
2626from PIL import Image
2727from vacuum_map_parser_base .config .image_config import ImageConfig
2828from vacuum_map_parser_base .map_data import ImageData , MapData
3636_MAP_FILE_FORMAT = "PNG"
3737
3838
39+ class _ProtoMessage (Protocol ):
40+ def HasField (self , field_name : str ) -> bool : ...
41+
42+
43+ class _ScPointMessage (_ProtoMessage , Protocol ):
44+ x : float
45+ y : float
46+
47+
48+ class _ScMapBoundaryInfoMessage (_ProtoMessage , Protocol ):
49+ mapMd5 : str
50+ vMinX : int
51+ vMaxX : int
52+ vMinY : int
53+ vMaxY : int
54+
55+
56+ class _ScMapExtInfoMessage (_ProtoMessage , Protocol ):
57+ taskBeginDate : int
58+ mapUploadDate : int
59+ mapValid : int
60+ radian : int
61+ force : int
62+ cleanPath : int
63+ boudaryInfo : _ScMapBoundaryInfoMessage
64+ mapVersion : int
65+ mapValueType : int
66+
67+
68+ class _ScMapHeadMessage (_ProtoMessage , Protocol ):
69+ mapHeadId : int
70+ sizeX : int
71+ sizeY : int
72+ minX : float
73+ minY : float
74+ maxX : float
75+ maxY : float
76+ resolution : float
77+
78+
79+ class _ScRoomDataMessage (_ProtoMessage , Protocol ):
80+ roomId : int
81+ roomName : str
82+ roomTypeId : int
83+ meterialId : int
84+ cleanState : int
85+ roomClean : int
86+ roomCleanIndex : int
87+ roomNamePost : _ScPointMessage
88+ colorId : int
89+ floor_direction : int
90+ global_seq : int
91+
92+
93+ class _ScMapDataContainerMessage (_ProtoMessage , Protocol ):
94+ mapData : bytes
95+
96+
97+ class _ScMapMessage (_ProtoMessage , Protocol ):
98+ mapType : int
99+ mapExtInfo : _ScMapExtInfoMessage
100+ mapHead : _ScMapHeadMessage
101+ mapData : _ScMapDataContainerMessage
102+ roomDataInfo : list [_ScRoomDataMessage ]
103+
104+
39105@dataclass (frozen = True )
40106class _ScPoint :
41107 x : float | None = None
@@ -185,7 +251,7 @@ def _decode_b01_map_payload(raw_payload: bytes, *, serial: str, model: str) -> b
185251 raise RoborockException ("Failed to decode B01 map payload" ) from err
186252
187253
188- def _parse_proto (blob : bytes , message : Any , * , context : str ) -> None :
254+ def _parse_proto (blob : bytes , message : Message , * , context : str ) -> None :
189255 try :
190256 message .ParseFromString (blob )
191257 except DecodeError as err :
@@ -199,14 +265,14 @@ def _decode_map_data_bytes(value: bytes) -> bytes:
199265 return value
200266
201267
202- def _parse_sc_point (parsed : Any ) -> _ScPoint :
268+ def _parse_sc_point (parsed : _ScPointMessage ) -> _ScPoint :
203269 return _ScPoint (
204270 x = parsed .x if parsed .HasField ("x" ) else None ,
205271 y = parsed .y if parsed .HasField ("y" ) else None ,
206272 )
207273
208274
209- def _parse_sc_map_boundary_info (parsed : Any ) -> _ScMapBoundaryInfo :
275+ def _parse_sc_map_boundary_info (parsed : _ScMapBoundaryInfoMessage ) -> _ScMapBoundaryInfo :
210276 return _ScMapBoundaryInfo (
211277 map_md5 = parsed .mapMd5 if parsed .HasField ("mapMd5" ) else None ,
212278 v_min_x = parsed .vMinX if parsed .HasField ("vMinX" ) else None ,
@@ -216,7 +282,7 @@ def _parse_sc_map_boundary_info(parsed: Any) -> _ScMapBoundaryInfo:
216282 )
217283
218284
219- def _parse_sc_map_ext_info (parsed : Any ) -> _ScMapExtInfo :
285+ def _parse_sc_map_ext_info (parsed : _ScMapExtInfoMessage ) -> _ScMapExtInfo :
220286 return _ScMapExtInfo (
221287 task_begin_date = parsed .taskBeginDate if parsed .HasField ("taskBeginDate" ) else None ,
222288 map_upload_date = parsed .mapUploadDate if parsed .HasField ("mapUploadDate" ) else None ,
@@ -230,7 +296,7 @@ def _parse_sc_map_ext_info(parsed: Any) -> _ScMapExtInfo:
230296 )
231297
232298
233- def _parse_sc_map_head (parsed : Any ) -> _ScMapHead :
299+ def _parse_sc_map_head (parsed : _ScMapHeadMessage ) -> _ScMapHead :
234300 return _ScMapHead (
235301 map_head_id = parsed .mapHeadId if parsed .HasField ("mapHeadId" ) else None ,
236302 size_x = parsed .sizeX if parsed .HasField ("sizeX" ) else None ,
@@ -243,7 +309,7 @@ def _parse_sc_map_head(parsed: Any) -> _ScMapHead:
243309 )
244310
245311
246- def _parse_sc_room_data (parsed : Any ) -> _ScRoomData :
312+ def _parse_sc_room_data (parsed : _ScRoomDataMessage ) -> _ScRoomData :
247313 return _ScRoomData (
248314 room_id = parsed .roomId if parsed .HasField ("roomId" ) else None ,
249315 room_name = parsed .roomName if parsed .HasField ("roomName" ) else None ,
@@ -261,8 +327,8 @@ def _parse_sc_room_data(parsed: Any) -> _ScRoomData:
261327
262328def _parse_scmap_payload (payload : bytes ) -> _ScMapPayload :
263329 """Parse inflated SCMap bytes into typed map metadata."""
264- parsed : Any = getattr (b01_scmap_pb2 , "RobotMap" )()
265- _parse_proto (payload , parsed , context = "B01 SCMap" )
330+ parsed = cast ( _ScMapMessage , getattr (b01_scmap_pb2 , "RobotMap" )() )
331+ _parse_proto (payload , cast ( Message , parsed ) , context = "B01 SCMap" )
266332
267333 map_data = None
268334 if parsed .HasField ("mapData" ):
0 commit comments