valetudo-map-parser 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,510 @@
1
+ """
2
+ Collections of Json and List routines
3
+ ImageData is part of the Image_Handler
4
+ used functions to search data in the json
5
+ provided for the creation of the new camera frame
6
+ Version: v2024.08.0
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any
12
+ import numpy as np
13
+
14
+ from .config.types import (
15
+ Colors,
16
+ ImageSize,
17
+ JsonType,
18
+ NumpyArray,
19
+ )
20
+
21
+
22
+ class ImageData:
23
+ """Class to handle the image data."""
24
+
25
+ @staticmethod
26
+ async def async_extract_color_coordinates(
27
+ source_array: NumpyArray, search_for_colours_list: Colors
28
+ ) -> list:
29
+ """Search for specific colors in an image array and return their coordinates."""
30
+ # Initialize an empty list to store color and coordinates tuples
31
+ color_coordinates_list = []
32
+
33
+ # Iterate over the search_for_colours_list
34
+ for color_to_search in search_for_colours_list:
35
+ # Initialize an empty list to store coordinates for the current color
36
+ color_coordinates = []
37
+
38
+ # Iterate over the image array
39
+ for y in range(source_array.shape[0]):
40
+ for x in range(source_array.shape[1]):
41
+ # Extract the pixel color at the current coordinates
42
+ pixel_color = source_array[y, x]
43
+
44
+ # Check if the current pixel color matches the color_to_search
45
+ if np.all(pixel_color == color_to_search):
46
+ # Record the coordinates for the current color
47
+ color_coordinates.append((x, y))
48
+
49
+ # Append the color and its coordinates to the final list
50
+ color_coordinates_list.append((color_to_search, color_coordinates))
51
+
52
+ # Return the final list of color and coordinates tuples
53
+ return color_coordinates_list
54
+
55
+ @staticmethod
56
+ def sublist(lst, n):
57
+ """Sub lists of specific n number of elements"""
58
+ return [lst[i : i + n] for i in range(0, len(lst), n)]
59
+
60
+ @staticmethod
61
+ def sublist_join(lst, n):
62
+ """Join the lists in a unique list of n elements"""
63
+ arr = np.array(lst)
64
+ num_windows = len(lst) - n + 1
65
+ result = [arr[i : i + n].tolist() for i in range(num_windows)]
66
+ return result
67
+
68
+ # The below functions are basically the same ech one
69
+ # of them is allowing filtering and putting together in a
70
+ # list the specific Layers, Paths, Zones and Pints in the
71
+ # Vacuums Json in parallel.
72
+
73
+ @staticmethod
74
+ def find_layers(
75
+ json_obj: JsonType, layer_dict: dict, active_list: list
76
+ ) -> tuple[dict, list]:
77
+ """Find the layers in the json object."""
78
+ layer_dict = {} if layer_dict is None else layer_dict
79
+ active_list = [] if active_list is None else active_list
80
+ if isinstance(json_obj, dict):
81
+ if "__class" in json_obj and json_obj["__class"] == "MapLayer":
82
+ layer_type = json_obj.get("type")
83
+ active_type = json_obj.get("metaData")
84
+ if layer_type:
85
+ if layer_type not in layer_dict:
86
+ layer_dict[layer_type] = []
87
+ layer_dict[layer_type].append(json_obj.get("compressedPixels", []))
88
+ if layer_type == "segment":
89
+ active_list.append(int(active_type["active"]))
90
+
91
+ for value in json_obj.items():
92
+ ImageData.find_layers(value, layer_dict, active_list)
93
+ elif isinstance(json_obj, list):
94
+ for item in json_obj:
95
+ ImageData.find_layers(item, layer_dict, active_list)
96
+ return layer_dict, active_list
97
+
98
+ @staticmethod
99
+ def find_points_entities(json_obj: JsonType, entity_dict: dict = None) -> dict:
100
+ """Find the points entities in the json object."""
101
+ if entity_dict is None:
102
+ entity_dict = {}
103
+ if isinstance(json_obj, dict):
104
+ if json_obj.get("__class") == "PointMapEntity":
105
+ entity_type = json_obj.get("type")
106
+ if entity_type:
107
+ entity_dict.setdefault(entity_type, []).append(json_obj)
108
+ for value in json_obj.values():
109
+ ImageData.find_points_entities(value, entity_dict)
110
+ elif isinstance(json_obj, list):
111
+ for item in json_obj:
112
+ ImageData.find_points_entities(item, entity_dict)
113
+ return entity_dict
114
+
115
+ @staticmethod
116
+ def find_paths_entities(json_obj: JsonType, entity_dict: dict = None) -> dict:
117
+ """Find the paths entities in the json object."""
118
+
119
+ if entity_dict is None:
120
+ entity_dict = {}
121
+ if isinstance(json_obj, dict):
122
+ if json_obj.get("__class") == "PathMapEntity":
123
+ entity_type = json_obj.get("type")
124
+ if entity_type:
125
+ entity_dict.setdefault(entity_type, []).append(json_obj)
126
+ for value in json_obj.values():
127
+ ImageData.find_paths_entities(value, entity_dict)
128
+ elif isinstance(json_obj, list):
129
+ for item in json_obj:
130
+ ImageData.find_paths_entities(item, entity_dict)
131
+ return entity_dict
132
+
133
+ @staticmethod
134
+ def find_zone_entities(json_obj: JsonType, entity_dict: dict = None) -> dict:
135
+ """Find the zone entities in the json object."""
136
+ if entity_dict is None:
137
+ entity_dict = {}
138
+ if isinstance(json_obj, dict):
139
+ if json_obj.get("__class") == "PolygonMapEntity":
140
+ entity_type = json_obj.get("type")
141
+ if entity_type:
142
+ entity_dict.setdefault(entity_type, []).append(json_obj)
143
+ for value in json_obj.values():
144
+ ImageData.find_zone_entities(value, entity_dict)
145
+ elif isinstance(json_obj, list):
146
+ for item in json_obj:
147
+ ImageData.find_zone_entities(item, entity_dict)
148
+ return entity_dict
149
+
150
+ @staticmethod
151
+ def find_virtual_walls(json_obj: JsonType) -> list:
152
+ """Find the virtual walls in the json object."""
153
+ virtual_walls = []
154
+
155
+ def find_virtual_walls_recursive(obj):
156
+ """Find the virtual walls in the json object recursively."""
157
+ if isinstance(obj, dict):
158
+ if obj.get("__class") == "LineMapEntity":
159
+ entity_type = obj.get("type")
160
+ if entity_type == "virtual_wall":
161
+ virtual_walls.append(obj["points"])
162
+ for value in obj.values():
163
+ find_virtual_walls_recursive(value)
164
+ elif isinstance(obj, list):
165
+ for item in obj:
166
+ find_virtual_walls_recursive(item)
167
+
168
+ find_virtual_walls_recursive(json_obj)
169
+ return virtual_walls
170
+
171
+ @staticmethod
172
+ async def async_get_rooms_coordinates(
173
+ pixels: list, pixel_size: int = 5, rand: bool = False
174
+ ) -> tuple:
175
+ """
176
+ Extract the room coordinates from the vacuum pixels data.
177
+ piexels: dict: The pixels data format [[x,y,z], [x1,y1,z1], [xn,yn,zn]].
178
+ pixel_size: int: The size of the pixel in mm (optional).
179
+ rand: bool: Return the coordinates in a rand256 format (optional).
180
+ """
181
+ # Initialize variables to store max and min coordinates
182
+ max_x, max_y = pixels[0][0], pixels[0][1]
183
+ min_x, min_y = pixels[0][0], pixels[0][1]
184
+ # Iterate through the data list to find max and min coordinates
185
+ for entry in pixels:
186
+ if rand:
187
+ x, y, _ = entry # Extract x and y coordinates
188
+ max_x = max(max_x, x) # Update max x coordinate
189
+ max_y = max(max_y, y) # Update max y coordinate
190
+ min_x = min(min_x, x) # Update min x coordinate
191
+ min_y = min(min_y, y) # Update min y coordinate
192
+ else:
193
+ x, y, z = entry # Extract x and y coordinates
194
+ max_x = max(max_x, x + z) # Update max x coordinate
195
+ max_y = max(max_y, y + pixel_size) # Update max y coordinate
196
+ min_x = min(min_x, x) # Update min x coordinate
197
+ min_y = min(min_y, y) # Update min y coordinate
198
+ if rand:
199
+ return (
200
+ (((max_x * pixel_size) * 10), ((max_y * pixel_size) * 10)),
201
+ (
202
+ ((min_x * pixel_size) * 10),
203
+ ((min_y * pixel_size) * 10),
204
+ ),
205
+ )
206
+ return (
207
+ min_x * pixel_size,
208
+ min_y * pixel_size,
209
+ max_x * pixel_size,
210
+ max_y * pixel_size,
211
+ )
212
+
213
+ # Added below in order to support Valetudo Re.
214
+ # This functions read directly the data from the json created
215
+ # from the parser for Valetudo Re. They allow to use the
216
+ # functions to draw the image without changes on the drawing class.
217
+
218
+ @staticmethod
219
+ def from_rrm_to_compressed_pixels(
220
+ pixel_data: list,
221
+ image_width: int = 0,
222
+ image_height: int = 0,
223
+ image_top: int = 0,
224
+ image_left: int = 0,
225
+ ) -> list:
226
+ """Convert the pixel data to compressed pixels."""
227
+ compressed_pixels = []
228
+
229
+ tot_pixels = 0
230
+ current_x, current_y, count = None, None, 0 # pylint: disable=unused-variable
231
+ for index in pixel_data:
232
+ x = (index % image_width) + image_left
233
+ y = ((image_height - 1) - (index // image_width)) + image_top
234
+
235
+ if current_x == x and current_y == y:
236
+ count += 1
237
+ else:
238
+ if current_x is not None:
239
+ compressed_pixels.append([current_x, current_y, count])
240
+ current_x, current_y, count = x, y, 1
241
+ tot_pixels += 1
242
+ if current_x is not None:
243
+ compressed_pixels.append([current_x, current_y, count])
244
+ return compressed_pixels
245
+
246
+ @staticmethod
247
+ def calculate_max_x_y(coord_array):
248
+ """Calculate the max and min x and y coordinates."""
249
+ max_x = -float("inf")
250
+ max_y = -float("inf")
251
+
252
+ for x, y, _ in coord_array:
253
+ max_x = max(max_x, x)
254
+ max_y = max(max_y, y)
255
+
256
+ return (max_x * 6), (max_y * 6)
257
+
258
+ @staticmethod
259
+ def rrm_coordinates_to_valetudo(points):
260
+ """Transform the coordinates from RRM to Valetudo."""
261
+ transformed_points = []
262
+ dimension_mm = 50 * 1024
263
+ for i, p in enumerate(points):
264
+ if i % 2 == 0:
265
+ transformed_points.append(round(p / 10))
266
+ else:
267
+ transformed_points.append(round((dimension_mm - p) / 10))
268
+ return transformed_points
269
+
270
+ @staticmethod
271
+ def rrm_valetudo_path_array(points):
272
+ """Transform the path coordinates from RRM to Valetudo."""
273
+ transformed_points = []
274
+ for point in points:
275
+ transformed_x = round(point[0] / 10)
276
+ transformed_y = round(point[1] / 10)
277
+ transformed_points.extend([[transformed_x, transformed_y]])
278
+ return transformed_points
279
+
280
+ @staticmethod
281
+ def get_rrm_image(json_data: JsonType) -> JsonType:
282
+ """Get the image data from the json."""
283
+ if isinstance(json_data, tuple):
284
+ return {}
285
+ return json_data.get("image", {})
286
+
287
+ @staticmethod
288
+ def get_rrm_path(json_data: JsonType) -> JsonType:
289
+ """Get the path data from the json."""
290
+ return json_data.get("path", {})
291
+
292
+ @staticmethod
293
+ def get_rrm_goto_predicted_path(json_data: JsonType) -> list or None:
294
+ """Get the predicted path data from the json."""
295
+ try:
296
+ predicted_path = json_data.get("goto_predicted_path", {})
297
+ points = predicted_path["points"]
298
+ except KeyError:
299
+ return None
300
+ predicted_path = ImageData.sublist_join(
301
+ ImageData.rrm_valetudo_path_array(points), 2
302
+ )
303
+ return predicted_path
304
+
305
+ @staticmethod
306
+ def get_rrm_charger_position(json_data: JsonType) -> JsonType:
307
+ """Get the charger position from the json."""
308
+ return json_data.get("charger", {})
309
+
310
+ @staticmethod
311
+ def get_rrm_robot_position(json_data: JsonType) -> JsonType:
312
+ """Get the robot position from the json."""
313
+ return json_data.get("robot", {})
314
+
315
+ @staticmethod
316
+ def get_rrm_robot_angle(json_data: JsonType) -> tuple:
317
+ """
318
+ Get the robot angle from the json.
319
+ Return the calculated angle and original angle.
320
+ """
321
+ angle_c = round(json_data.get("robot_angle", 0))
322
+ angle = (360 - angle_c + 80) if angle_c < 0 else (180 - angle_c - 80)
323
+ return angle % 360, json_data.get("robot_angle", 0)
324
+
325
+ @staticmethod
326
+ def get_rrm_goto_target(json_data: JsonType) -> list or None:
327
+ """Get the goto target from the json."""
328
+ try:
329
+ path_data = json_data.get("goto_target", {})
330
+ except KeyError:
331
+ return None
332
+
333
+ if path_data and path_data != []:
334
+ path_data = ImageData.rrm_coordinates_to_valetudo(path_data)
335
+ return path_data
336
+ return None
337
+
338
+ @staticmethod
339
+ def get_rrm_currently_cleaned_zones(json_data: JsonType) -> dict:
340
+ """Get the currently cleaned zones from the json."""
341
+ re_zones = json_data.get("currently_cleaned_zones", [])
342
+ formatted_zones = ImageData.rrm_valetudo_format_zone(re_zones)
343
+ return formatted_zones
344
+
345
+ @staticmethod
346
+ def get_rrm_forbidden_zones(json_data: JsonType) -> dict:
347
+ """Get the forbidden zones from the json."""
348
+ re_zones = json_data.get("forbidden_zones", [])
349
+ formatted_zones = ImageData.rrm_valetudo_format_zone(re_zones)
350
+ return formatted_zones
351
+
352
+ @staticmethod
353
+ def rrm_valetudo_format_zone(coordinates: list) -> any:
354
+ """Format the zones from RRM to Valetudo."""
355
+ formatted_zones = []
356
+ for zone_data in coordinates:
357
+ if len(zone_data) == 4: # This is a zone_clean (4 coordinates)
358
+ formatted_zone = {
359
+ "__class": "PolygonMapEntity",
360
+ "metaData": {},
361
+ "points": [
362
+ zone_data[0] // 10,
363
+ zone_data[1] // 10,
364
+ zone_data[2] // 10,
365
+ zone_data[1] // 10,
366
+ zone_data[2] // 10,
367
+ zone_data[3] // 10,
368
+ zone_data[0] // 10,
369
+ zone_data[3] // 10,
370
+ ],
371
+ "type": "zone_clean",
372
+ }
373
+ formatted_zones.append(formatted_zone)
374
+ elif len(zone_data) == 8: # This is a no_go_area (8 coordinates)
375
+ formatted_zone = {
376
+ "__class": "PolygonMapEntity",
377
+ "metaData": {},
378
+ "points": [
379
+ zone_data[0] // 10,
380
+ zone_data[1] // 10,
381
+ zone_data[2] // 10,
382
+ zone_data[3] // 10,
383
+ zone_data[4] // 10,
384
+ zone_data[5] // 10,
385
+ zone_data[6] // 10,
386
+ zone_data[7] // 10,
387
+ ],
388
+ "type": "no_go_area",
389
+ }
390
+ formatted_zones.append(formatted_zone)
391
+
392
+ return formatted_zones
393
+
394
+ @staticmethod
395
+ def rrm_valetudo_lines(coordinates: list) -> list:
396
+ """Format the lines from RRM to Valetudo."""
397
+ formatted_lines = []
398
+ for lines in coordinates:
399
+ line = [lines[0] // 10, lines[1] // 10, lines[2] // 10, lines[3] // 10]
400
+ formatted_lines.append(line)
401
+ return formatted_lines
402
+
403
+ @staticmethod
404
+ def get_rrm_virtual_walls(json_data: JsonType) -> list or None:
405
+ """Get the virtual walls from the json."""
406
+ try:
407
+ tmp_data = json_data.get("virtual_walls", [])
408
+ except KeyError:
409
+ return None
410
+ virtual_walls = ImageData.rrm_valetudo_lines(tmp_data)
411
+ return virtual_walls
412
+
413
+ @staticmethod
414
+ def get_rrm_currently_cleaned_blocks(json_data: JsonType) -> list:
415
+ """Get the currently cleaned blocks from the json."""
416
+ return json_data.get("currently_cleaned_blocks", [])
417
+
418
+ @staticmethod
419
+ def get_rrm_forbidden_mop_zones(json_data: JsonType) -> list:
420
+ """Get the forbidden mop zones from the json."""
421
+ return json_data.get("forbidden_mop_zones", [])
422
+
423
+ @staticmethod
424
+ def get_rrm_image_size(json_data: JsonType) -> ImageSize:
425
+ """Get the image size from the json."""
426
+ if isinstance(json_data, tuple):
427
+ return 0, 0
428
+ image = ImageData.get_rrm_image(json_data)
429
+ if image == {}:
430
+ return 0, 0
431
+ dimensions = image.get("dimensions", {})
432
+ return dimensions.get("width", 0), dimensions.get("height", 0)
433
+
434
+ @staticmethod
435
+ def get_rrm_image_position(json_data: JsonType) -> tuple:
436
+ """Get the image position from the json."""
437
+ image = ImageData.get_rrm_image(json_data)
438
+ position = image.get("position", {})
439
+ return position.get("top", 0), position.get("left", 0)
440
+
441
+ @staticmethod
442
+ def get_rrm_floor(json_data: JsonType) -> list:
443
+ """Get the floor data from the json."""
444
+ img = ImageData.get_rrm_image(json_data)
445
+ return img.get("pixels", {}).get("floor", [])
446
+
447
+ @staticmethod
448
+ def get_rrm_walls(json_data: JsonType) -> list:
449
+ """Get the walls data from the json."""
450
+ img = ImageData.get_rrm_image(json_data)
451
+ return img.get("pixels", {}).get("walls", [])
452
+
453
+ @staticmethod
454
+ async def async_get_rrm_segments(
455
+ json_data: JsonType,
456
+ size_x: int,
457
+ size_y: int,
458
+ pos_top: int,
459
+ pos_left: int,
460
+ out_lines: bool = False,
461
+ ) -> tuple or list:
462
+ """Get the segments data from the json."""
463
+
464
+ img = ImageData.get_rrm_image(json_data)
465
+ seg_data = img.get("segments", {})
466
+ seg_ids = seg_data.get("id")
467
+ segments = []
468
+ outlines = []
469
+ count_seg = 0
470
+ for id_seg in seg_ids:
471
+ tmp_data = seg_data.get("pixels_seg_" + str(id_seg))
472
+ segments.append(
473
+ ImageData.from_rrm_to_compressed_pixels(
474
+ tmp_data,
475
+ image_width=size_x,
476
+ image_height=size_y,
477
+ image_top=pos_top,
478
+ image_left=pos_left,
479
+ )
480
+ )
481
+ if out_lines:
482
+ room_coords = await ImageData.async_get_rooms_coordinates(
483
+ pixels=segments[count_seg], rand=True
484
+ )
485
+ outlines.append(room_coords)
486
+ count_seg += 1
487
+ if count_seg > 0:
488
+ if out_lines:
489
+ return segments, outlines
490
+ return segments
491
+ return []
492
+
493
+ @staticmethod
494
+ def get_rrm_segments_ids(json_data: JsonType) -> list or None:
495
+ """Get the segments ids from the json."""
496
+ try:
497
+ img = ImageData.get_rrm_image(json_data)
498
+ seg_ids = img.get("segments", {}).get("id", [])
499
+ except KeyError:
500
+ return None
501
+ return seg_ids
502
+
503
+ @staticmethod
504
+ def convert_negative_angle(angle: int) -> int:
505
+ """Convert negative angle to positive."""
506
+ angle_c = angle % 360 # Ensure angle is within 0-359
507
+ if angle_c < 0:
508
+ angle_c += 360 # Convert negative angle to positive
509
+ angle = angle_c + 180 # add offset
510
+ return angle
File without changes
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: valetudo-map-parser
3
- Version: 0.1.2
4
- Summary: A Python library to parse Valetudo map data returning a PIL Image object
3
+ Version: 0.1.4
4
+ Summary: A Python library to parse Valetudo map data returning a PIL Image object.
5
5
  License: Apache-2.0
6
6
  Author: Sandro Cantarella
7
7
  Author-email: gsca075@gmail.com
@@ -0,0 +1,17 @@
1
+ valetudo_map_parser/__init__.py,sha256=SYv1w4Zf6ADLJ6yC6W8vhzQ96DicDRSP3yuf6ijmlxc,683
2
+ valetudo_map_parser/config/__init__.py,sha256=DQ9plV3ZF_K25Dp5ZQHPDoG-40dQoJNdNi-dfNeR3Zc,48
3
+ valetudo_map_parser/config/auto_crop.py,sha256=eTzMVhaeP7SP2-65jefE4toAigkZM6XUoARsSB5JwH8,10927
4
+ valetudo_map_parser/config/colors.py,sha256=HlgROKagpV7FP9LTU1IvhTKTYjnlBw1ZDMKHVJSct8M,6514
5
+ valetudo_map_parser/config/drawable.py,sha256=8Fp4yqyFbsGvNyCEynYCTpiohRZk_plUSSOyHpECvj8,20356
6
+ valetudo_map_parser/config/shared.py,sha256=8xYBUfKY-tiPhXaT5ttIasnCWL3_RLawIZeTValQC64,9462
7
+ valetudo_map_parser/config/types.py,sha256=bVSEDE0ihrc01jG4fZ1_hUVtoj6hdkbqShytZ6wJwJY,16163
8
+ valetudo_map_parser/hypfer_draw.py,sha256=R8JVrqPPavhj8exCDJKk1QsXgsB12cjy4AIgFffyQec,15773
9
+ valetudo_map_parser/hypfer_handler.py,sha256=PCdfzLpGZD0zXvVufFWadPc-xDqbtsnArfPW0PWViU4,18469
10
+ valetudo_map_parser/images_utils.py,sha256=Ls5OnXXcojBTuUagj3_N4tY3nOe9aot7gl5hrPCXKss,15262
11
+ valetudo_map_parser/map_data.py,sha256=-6etLFZXZikFEUeR2YhPLgXu7dv3YRY2e-u5Mx9ogqw,19498
12
+ valetudo_map_parser/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ valetudo_map_parser-0.1.4.dist-info/LICENSE,sha256=Lh-qBbuRV0-jiCIBhfV7NgdwFxQFOXH3BKOzK865hRs,10480
14
+ valetudo_map_parser-0.1.4.dist-info/METADATA,sha256=qsrU3YyxUwjsKvqo6IReZAneO_6KIAVHVvdVDLYlTMA,1026
15
+ valetudo_map_parser-0.1.4.dist-info/NOTICE.txt,sha256=5lTOuWiU9aiEnJ2go8sc7lTJ7ntMBx0g0GFnNrswCY4,2533
16
+ valetudo_map_parser-0.1.4.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
17
+ valetudo_map_parser-0.1.4.dist-info/RECORD,,
__init__.py DELETED
@@ -1,18 +0,0 @@
1
- """Valetudo Map Parser."""
2
- from SCR.valetudo_map_parser.hypfer_handler import HypferMapImageHandler
3
- from SCR.valetudo_map_parser.config.shared import CameraShared, CameraSharedManager
4
-
5
- __all__ = [
6
- "HypferMapImageHandler",
7
- "CameraShared",
8
- "CameraSharedManager",
9
- "ColorsManagment",
10
- "SnapshotStore",
11
- "UserLanguageStore",
12
- "UserLanguageStore",
13
- "SnapshotStore",
14
- "RoomStore",
15
- "RoomsProperties",
16
- "TrimCropData",
17
- "CameraModes",
18
- ]
@@ -1,6 +0,0 @@
1
- __init__.py,sha256=a9BnpCeG7Ewj34CgO6wjM0RfEyCDURSCHO0gvWbPK_0,469
2
- valetudo_map_parser-0.1.2.dist-info/LICENSE,sha256=Lh-qBbuRV0-jiCIBhfV7NgdwFxQFOXH3BKOzK865hRs,10480
3
- valetudo_map_parser-0.1.2.dist-info/METADATA,sha256=zs5So0xm53-aW0zVrv9a9mg10ii3esC6O6tU4_CHoqQ,1025
4
- valetudo_map_parser-0.1.2.dist-info/NOTICE.txt,sha256=5lTOuWiU9aiEnJ2go8sc7lTJ7ntMBx0g0GFnNrswCY4,2533
5
- valetudo_map_parser-0.1.2.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
6
- valetudo_map_parser-0.1.2.dist-info/RECORD,,