valetudo-map-parser 0.1.10rc5__tar.gz → 0.1.10rc6__tar.gz

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.
Files changed (36) hide show
  1. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/PKG-INFO +1 -1
  2. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/shared.py +80 -89
  3. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/types.py +18 -1
  4. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/utils.py +51 -7
  5. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/hypfer_handler.py +1 -2
  6. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/map_data.py +1 -1
  7. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/pyproject.toml +1 -1
  8. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/LICENSE +0 -0
  9. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/NOTICE.txt +0 -0
  10. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/README.md +0 -0
  11. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/__init__.py +0 -0
  12. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/__init__.py +0 -0
  13. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/async_utils.py +0 -0
  14. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/auto_crop.py +0 -0
  15. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/color_utils.py +0 -0
  16. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/colors.py +0 -0
  17. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/drawable.py +0 -0
  18. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/drawable_elements.py +0 -0
  19. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/enhanced_drawable.py +0 -0
  20. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/fonts/FiraSans.ttf +0 -0
  21. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/fonts/Inter-VF.ttf +0 -0
  22. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/fonts/Lato-Regular.ttf +0 -0
  23. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/fonts/MPLUSRegular.ttf +0 -0
  24. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/fonts/NotoKufiArabic-VF.ttf +0 -0
  25. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/fonts/NotoSansCJKhk-VF.ttf +0 -0
  26. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/fonts/NotoSansKhojki.ttf +0 -0
  27. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/optimized_element_map.py +0 -0
  28. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/rand256_parser.py +0 -0
  29. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/status_text/status_text.py +0 -0
  30. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/config/status_text/translations.py +0 -0
  31. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/hypfer_draw.py +0 -0
  32. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/hypfer_rooms_handler.py +0 -0
  33. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/py.typed +0 -0
  34. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/rand256_handler.py +0 -0
  35. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/reimg_draw.py +0 -0
  36. {valetudo_map_parser-0.1.10rc5 → valetudo_map_parser-0.1.10rc6}/SCR/valetudo_map_parser/rooms_handler.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: valetudo-map-parser
3
- Version: 0.1.10rc5
3
+ Version: 0.1.10rc6
4
4
  Summary: A Python library to parse Valetudo map data returning a PIL Image object.
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Class Camera Shared.
3
3
  Keep the data between the modules.
4
- Version: v0.1.10
4
+ Version: v0.1.12
5
5
  """
6
6
 
7
7
  import asyncio
@@ -54,71 +54,68 @@ class CameraShared:
54
54
  """
55
55
 
56
56
  def __init__(self, file_name):
57
- self.camera_mode: str = CameraModes.MAP_VIEW # Camera mode
58
- self.frame_number: int = 0 # camera Frame number
59
- self.destinations: list = [] # MQTT rand destinations
60
- self.rand256_active_zone: list = [] # Active zone for rand256
61
- self.rand256_zone_coordinates: list = [] # Active zone coordinates for rand256
62
- self.is_rand: bool = False # MQTT rand data
63
- self._new_mqtt_message = False # New MQTT message
64
- # Initialize last_image with default gray image (250x150 minimum)
65
- self.last_image = Image.new(
66
- "RGBA", (250, 150), (128, 128, 128, 255)
67
- ) # Gray default image
68
- self.new_image: PilPNG | None = None # New image received
69
- self.binary_image: bytes | None = None # Current image in binary format
70
- self.image_last_updated: float = 0.0 # Last image update time
71
- self.image_format = "image/pil" # Image format
72
- self.image_size = None # Image size
73
- self.robot_size = None # Robot size
74
- self.image_auto_zoom: bool = False # Auto zoom image
75
- self.image_zoom_lock_ratio: bool = True # Zoom lock ratio
76
- self.image_ref_height: int = 0 # Image reference height
77
- self.image_ref_width: int = 0 # Image reference width
78
- self.image_aspect_ratio: str = "None" # Change Image aspect ratio
79
- self.image_grab = True # Grab image from MQTT
80
- self.image_rotate: int = 0 # Rotate image
81
- self.drawing_limit: float = 0.0 # Drawing CPU limit
82
- self.current_room = None # Current room of rhe vacuum
83
- self.user_colors = Colors # User base colors
84
- self.rooms_colors = Colors # Rooms colors
85
- self.vacuum_battery = 0 # Vacuum battery state
86
- self.vacuum_connection = False # Vacuum connection state
87
- self.vacuum_state = None # Vacuum state
88
- self.charger_position = None # Vacuum Charger position
89
- self.show_vacuum_state = None # Show vacuum state on the map
57
+ self.camera_mode: str = CameraModes.MAP_VIEW
58
+ self.frame_number: int = 0
59
+ self.destinations: list = []
60
+ self.rand256_active_zone: list = []
61
+ self.rand256_zone_coordinates: list = []
62
+ self.is_rand: bool = False
63
+ self._new_mqtt_message = False
64
+ self.last_image = Image.new("RGBA", (250, 150), (128, 128, 128, 255))
65
+ self.new_image: PilPNG | None = None
66
+ self.binary_image: bytes | None = None
67
+ self.image_last_updated: float = 0.0
68
+ self.image_format = "image/pil"
69
+ self.image_size = None
70
+ self.robot_size = None
71
+ self.image_auto_zoom: bool = False
72
+ self.image_zoom_lock_ratio: bool = True
73
+ self.image_ref_height: int = 0
74
+ self.image_ref_width: int = 0
75
+ self.image_aspect_ratio: str = "None"
76
+ self.image_grab = True
77
+ self.image_rotate: int = 0
78
+ self.drawing_limit: float = 0.0
79
+ self.current_room = None
80
+ self.user_colors = Colors
81
+ self.rooms_colors = Colors
82
+ self.vacuum_battery = 0
83
+ self.vacuum_connection = False
84
+ self.vacuum_state = None
85
+ self.charger_position = None
86
+ self.show_vacuum_state = None
90
87
  self.vacuum_status_font: str = (
91
- "custom_components/mqtt_vacuum_camera/utils/fonts/FiraSans.ttf" # Font
88
+ "custom_components/mqtt_vacuum_camera/utils/fonts/FiraSans.ttf"
92
89
  )
93
- self.vacuum_status_size: int = 50 # Vacuum status size
94
- self.vacuum_status_position: bool = True # Vacuum status text image top
95
- self.snapshot_take = False # Take snapshot
96
- self.vacuum_error = None # Vacuum error
97
- self.vacuum_api = None # Vacuum API
98
- self.vacuum_ips = None # Vacuum IPs
99
- self.vac_json_id = None # Vacuum json id
100
- self.margins = "100" # Image margins
101
- self.obstacles_data = None # Obstacles data
102
- self.obstacles_pos = None # Obstacles position
103
- self.offset_top = 0 # Image offset top
104
- self.offset_down = 0 # Image offset down
105
- self.offset_left = 0 # Image offset left
106
- self.offset_right = 0 # Image offset right
107
- self.export_svg = False # Export SVG
108
- self.svg_path = None # SVG Export path
109
- self.enable_snapshots = False # Enable snapshots
110
- self.file_name = file_name # vacuum friendly name as File name
111
- self.attr_calibration_points = None # Calibration points of the image
112
- self.map_rooms = None # Rooms data from the vacuum
113
- self.map_pred_zones = None # Predefined zones data
114
- self.map_pred_points = None # Predefined points data
115
- self.map_new_path = None # New path data
116
- self.map_old_path = None # Old path data
117
- self.user_language = None # User language
90
+ self.vacuum_status_size: int = 50
91
+ self.vacuum_status_position: bool = True
92
+ self.snapshot_take = False
93
+ self.vacuum_error = None
94
+ self.vacuum_api = None
95
+ self.vacuum_ips = None
96
+ self.vac_json_id = None
97
+ self.margins = "100"
98
+ self.obstacles_data = None
99
+ self.obstacles_pos = None
100
+ self.offset_top = 0
101
+ self.offset_down = 0
102
+ self.offset_left = 0
103
+ self.offset_right = 0
104
+ self.export_svg = False
105
+ self.svg_path = None
106
+ self.enable_snapshots = False
107
+ self.file_name = file_name
108
+ self.attr_calibration_points = None
109
+ self.map_rooms = None
110
+ self.map_pred_zones = None
111
+ self.map_pred_points = None
112
+ self.map_new_path = None
113
+ self.map_old_path = None
114
+ self.user_language = None
118
115
  self.trim_crop_data = None
119
- self.trims = TrimsData.from_dict(DEFAULT_VALUES["trims_data"]) # Trims data
116
+ self.trims = TrimsData.from_dict(DEFAULT_VALUES["trims_data"])
120
117
  self.skip_room_ids: List[str] = []
121
- self.device_info = None # Store the device_info
118
+ self.device_info = None
122
119
 
123
120
  def vacuum_bat_charged(self) -> bool:
124
121
  """Check if the vacuum is charging."""
@@ -126,49 +123,35 @@ class CameraShared:
126
123
 
127
124
  @staticmethod
128
125
  def _compose_obstacle_links(vacuum_host_ip: str, obstacles: list) -> list | None:
129
- """
130
- Compose JSON with obstacle details including the image link.
131
- """
126
+ """Compose JSON with obstacle details including the image link."""
132
127
  obstacle_links = []
133
128
  if not obstacles or not vacuum_host_ip:
134
129
  return None
135
130
 
136
131
  for obstacle in obstacles:
137
- # Extract obstacle details
138
132
  label = obstacle.get("label", "")
139
133
  points = obstacle.get("points", {})
140
134
  image_id = obstacle.get("id", "None")
141
135
 
142
136
  if label and points and image_id and vacuum_host_ip:
143
- # Append formatted obstacle data
144
137
  if image_id != "None":
145
- # Compose the link
146
138
  image_link = (
147
139
  f"http://{vacuum_host_ip}"
148
140
  f"/api/v2/robot/capabilities/ObstacleImagesCapability/img/{image_id}"
149
141
  )
150
142
  obstacle_links.append(
151
- {
152
- "point": points,
153
- "label": label,
154
- "link": image_link,
155
- }
143
+ {"point": points, "label": label, "link": image_link}
156
144
  )
157
145
  else:
158
- obstacle_links.append(
159
- {
160
- "point": points,
161
- "label": label,
162
- }
163
- )
146
+ obstacle_links.append({"point": points, "label": label})
164
147
  return obstacle_links
165
148
 
166
149
  def update_user_colors(self, user_colors):
167
- """Update the user colors."""
150
+ """Update user colors palette"""
168
151
  self.user_colors = user_colors
169
152
 
170
153
  def get_user_colors(self):
171
- """Get the user colors."""
154
+ """Return user colors"""
172
155
  return self.user_colors
173
156
 
174
157
  def update_rooms_colors(self, user_colors):
@@ -176,7 +159,7 @@ class CameraShared:
176
159
  self.rooms_colors = user_colors
177
160
 
178
161
  def get_rooms_colors(self):
179
- """Get the rooms colors."""
162
+ """Return rooms colors"""
180
163
  return self.rooms_colors
181
164
 
182
165
  def reset_trims(self) -> dict:
@@ -185,7 +168,7 @@ class CameraShared:
185
168
  return self.trims
186
169
 
187
170
  async def batch_update(self, **kwargs):
188
- """Batch update multiple attributes."""
171
+ """Update the data of Shared in Batch"""
189
172
  for key, value in kwargs.items():
190
173
  setattr(self, key, value)
191
174
 
@@ -210,24 +193,32 @@ class CameraShared:
210
193
  )
211
194
  attrs[ATTR_OBSTACLES] = self.obstacles_data
212
195
 
213
- if self.enable_snapshots:
214
- attrs[ATTR_SNAPSHOT] = self.snapshot_take
215
- else:
216
- attrs[ATTR_SNAPSHOT] = False
196
+ attrs[ATTR_SNAPSHOT] = self.snapshot_take if self.enable_snapshots else False
217
197
 
218
- # Add dynamic shared attributes if they are available
219
198
  shared_attrs = {
220
199
  ATTR_ROOMS: self.map_rooms,
221
200
  ATTR_ZONES: self.map_pred_zones,
222
201
  ATTR_POINTS: self.map_pred_points,
223
202
  }
224
-
225
203
  for key, value in shared_attrs.items():
226
204
  if value is not None:
227
205
  attrs[key] = value
228
206
 
229
207
  return attrs
230
208
 
209
+ def to_dict(self) -> dict:
210
+ """Return a dictionary with image and attributes data."""
211
+ return {
212
+ "image": {
213
+ "binary": self.binary_image,
214
+ "pil_image_size": self.new_image.size,
215
+ "size": self.new_image.size if self.new_image else None,
216
+ "format": self.image_format,
217
+ "updated": self.image_last_updated,
218
+ },
219
+ "attributes": self.generate_attributes(),
220
+ }
221
+
231
222
 
232
223
  class CameraSharedManager:
233
224
  """Camera Shared Manager class."""
@@ -8,7 +8,7 @@ import json
8
8
  import logging
9
9
  import threading
10
10
  from dataclasses import asdict, dataclass
11
- from typing import Any, Dict, Optional, Tuple, TypedDict, Union
11
+ from typing import Any, Dict, Optional, Tuple, TypedDict, Union, List, NotRequired
12
12
 
13
13
  import numpy as np
14
14
  from PIL import Image
@@ -18,6 +18,23 @@ DEFAULT_ROOMS = 1
18
18
 
19
19
  LOGGER = logging.getLogger(__package__)
20
20
 
21
+ class Spot(TypedDict):
22
+ name: str
23
+ coordinates: List[int] # [x, y]
24
+
25
+ class Zone(TypedDict):
26
+ name: str
27
+ coordinates: List[List[int]] # [[x1, y1, x2, y2, repeats], ...]
28
+
29
+ class Room(TypedDict):
30
+ name: str
31
+ id: int
32
+
33
+ class Destinations(TypedDict, total=False):
34
+ spots: NotRequired[Optional[List[Spot]]]
35
+ zones: NotRequired[Optional[List[Zone]]]
36
+ rooms: NotRequired[Optional[List[Room]]]
37
+ updated: NotRequired[Optional[int]]
21
38
 
22
39
  class RoomProperty(TypedDict):
23
40
  number: int
@@ -5,7 +5,7 @@ from time import time
5
5
  import hashlib
6
6
  import json
7
7
  from dataclasses import dataclass
8
- from typing import Callable, List, Optional
8
+ from typing import Callable, List, Optional, Tuple
9
9
  import io
10
10
 
11
11
  import numpy as np
@@ -23,6 +23,7 @@ from .types import (
23
23
  NumpyArray,
24
24
  PilPNG,
25
25
  RobotPosition,
26
+ Destinations
26
27
  )
27
28
  from ..map_data import HyperMapData
28
29
  from .async_utils import AsyncNumPy
@@ -91,9 +92,9 @@ class BaseHandler:
91
92
  async def async_get_image(
92
93
  self,
93
94
  m_json: dict | None,
94
- destinations: list | None = None,
95
+ destinations: Destinations | None = None,
95
96
  bytes_format: bool = False,
96
- ) -> PilPNG | bytes:
97
+ ) -> Tuple[PilPNG | bytes, dict]:
97
98
  """
98
99
  Unified async function to get PIL image from JSON data for both Hypfer and Rand256 handlers.
99
100
 
@@ -108,7 +109,7 @@ class BaseHandler:
108
109
  @param bytes_format: If True, also convert to PNG bytes and store in shared.binary_image
109
110
  @param text_enabled: If True, draw text on the image
110
111
  @param vacuum_status: Vacuum status to display on the image
111
- @return: PIL Image or None
112
+ @return: PIL Image or None and data dictionary
112
113
  """
113
114
  try:
114
115
  # Backup current image to last_image before processing new one
@@ -122,6 +123,7 @@ class BaseHandler:
122
123
  m_json=m_json,
123
124
  destinations=destinations,
124
125
  )
126
+
125
127
  elif hasattr(self, "async_get_image_from_json"):
126
128
  # This is a Hypfer handler
127
129
  self.json_data = await HyperMapData.async_from_valetudo_json(m_json)
@@ -141,7 +143,10 @@ class BaseHandler:
141
143
 
142
144
  # Store the new image in shared data
143
145
  if new_image is not None:
146
+ # Update shared data
147
+ await self._async_update_shared_data(destinations)
144
148
  self.shared.new_image = new_image
149
+ # Add text to the image
145
150
  if self.shared.show_vacuum_state:
146
151
  text_editor = StatusText(self.shared)
147
152
  img_text = await text_editor.get_status_text(new_image)
@@ -160,18 +165,22 @@ class BaseHandler:
160
165
  self.shared.binary_image = pil_to_png_bytes(self.shared.last_image)
161
166
  # Update the timestamp with current datetime
162
167
  self.shared.image_last_updated = datetime.datetime.fromtimestamp(time())
163
- return new_image
168
+ LOGGER.debug("%s: Frame Completed.", self.file_name)
169
+ data = {}
170
+ if bytes_format:
171
+ data = self.shared.to_dict()
172
+ return new_image, data
164
173
  else:
165
174
  LOGGER.warning(
166
175
  "%s: Failed to generate image from JSON data", self.file_name
167
176
  )
168
177
  if bytes_format and hasattr(self.shared, "last_image"):
169
- return pil_to_png_bytes(self.shared.last_image)
178
+ return pil_to_png_bytes(self.shared.last_image), {}
170
179
  return (
171
180
  self.shared.last_image
172
181
  if hasattr(self.shared, "last_image")
173
182
  else None
174
- )
183
+ ), {}
175
184
 
176
185
  except Exception as e:
177
186
  LOGGER.warning(
@@ -184,6 +193,41 @@ class BaseHandler:
184
193
  self.shared.last_image if hasattr(self.shared, "last_image") else None
185
194
  )
186
195
 
196
+ async def _async_update_shared_data(self, destinations: Destinations | None = None):
197
+ """Update the shared data with the latest information."""
198
+
199
+ if hasattr(self, "get_rooms_attributes") and (
200
+ self.shared.map_rooms is None and destinations is not None
201
+ ):
202
+ (
203
+ self.shared.map_rooms,
204
+ self.shared.map_pred_zones,
205
+ self.shared.map_pred_points,
206
+ ) = await self.get_rooms_attributes(destinations)
207
+ if self.shared.map_rooms:
208
+ LOGGER.debug("%s: Rand256 attributes rooms updated", self.file_name)
209
+
210
+ if hasattr(self, "async_get_rooms_attributes") and (
211
+ self.shared.map_rooms is None
212
+ ):
213
+ if self.shared.map_rooms is None:
214
+ self.shared.map_rooms = await self.async_get_rooms_attributes()
215
+ if self.shared.map_rooms:
216
+ LOGGER.debug("%s: Hyper attributes rooms updated", self.file_name)
217
+
218
+ if hasattr(self, "get_calibration_data") and self.shared.attr_calibration_points is None:
219
+ self.shared.attr_calibration_points = self.get_calibration_data(self.shared.image_rotate)
220
+
221
+ if not self.shared.image_size:
222
+ self.shared.image_size = self.get_img_size()
223
+
224
+ self.shared.vac_json_id = self.get_json_id()
225
+
226
+ if not self.shared.charger_position:
227
+ self.shared.charger_position = self.get_charger_position()
228
+
229
+ self.shared.current_room = self.get_robot_position()
230
+
187
231
  def prepare_resize_params(self, pil_img: PilPNG, rand: bool=False) -> ResizeParams:
188
232
  """Prepare resize parameters for image resizing."""
189
233
  if self.shared.image_rotate in [0, 180]:
@@ -409,11 +409,10 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
409
409
  )
410
410
  return self.room_propriety
411
411
 
412
- def get_calibration_data(self) -> CalibrationPoints:
412
+ def get_calibration_data(self, rotation_angle: int = 0) -> CalibrationPoints:
413
413
  """Get the calibration data from the JSON data.
414
414
  this will create the attribute calibration points."""
415
415
  calibration_data = []
416
- rotation_angle = self.shared.image_rotate
417
416
  LOGGER.info("Getting %s Calibrations points.", self.file_name)
418
417
 
419
418
  # Define the map points (fixed)
@@ -709,7 +709,7 @@ class HyperMapData:
709
709
  """Class to handle the map data snapshots."""
710
710
 
711
711
  json_data: Any = None
712
- json_id: str = "" or None
712
+ json_id: Optional[str] = None
713
713
  obstacles: dict[str, list[Any]] = field(default_factory=dict)
714
714
  paths: dict[str, list[Any]] = field(default_factory=dict)
715
715
  image_size: dict[str, int | list[int]] = field(default_factory=dict)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "valetudo-map-parser"
3
- version = "0.1.10rc5"
3
+ version = "0.1.10rc6"
4
4
  description = "A Python library to parse Valetudo map data returning a PIL Image object."
5
5
  authors = ["Sandro Cantarella <gsca075@gmail.com>"]
6
6
  license = "Apache-2.0"