valetudo-map-parser 0.1.9b41__py3-none-any.whl → 0.1.9b42__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.
@@ -1,8 +1,10 @@
1
1
  """Valetudo map parser.
2
- Version: 0.1.8"""
2
+ Version: 0.1.9"""
3
3
 
4
4
  from .config.colors import ColorsManagment
5
5
  from .config.drawable import Drawable
6
+ from .config.drawable_elements import DrawableElement, DrawingConfig
7
+ from .config.enhanced_drawable import EnhancedDrawable
6
8
  from .config.rand25_parser import RRMapParser
7
9
  from .config.shared import CameraShared, CameraSharedManager
8
10
  from .config.types import (
@@ -25,10 +27,11 @@ __all__ = [
25
27
  "CameraSharedManager",
26
28
  "ColorsManagment",
27
29
  "Drawable",
30
+ "DrawableElement",
31
+ "DrawingConfig",
32
+ "EnhancedDrawable",
28
33
  "SnapshotStore",
29
34
  "UserLanguageStore",
30
- "UserLanguageStore",
31
- "SnapshotStore",
32
35
  "RoomStore",
33
36
  "RoomsProperties",
34
37
  "TrimCropData",
@@ -10,14 +10,20 @@ Refactored for clarity, consistency, and optimized parameter usage.
10
10
  from __future__ import annotations
11
11
 
12
12
  import asyncio
13
+ import logging
13
14
  import math
14
15
 
16
+ # cv2 is imported but not used directly in this file
17
+ # It's needed for other modules that import from here
15
18
  import numpy as np
16
19
  from PIL import ImageDraw, ImageFont
17
20
 
18
21
  from .types import Color, NumpyArray, PilPNG, Point, Tuple, Union
19
22
 
20
23
 
24
+ _LOGGER = logging.getLogger(__name__)
25
+
26
+
21
27
  class Drawable:
22
28
  """
23
29
  Collection of drawing utility functions for the image handlers.
@@ -47,16 +53,30 @@ class Drawable:
47
53
  ) -> NumpyArray:
48
54
  """Draw the layers (rooms) from the vacuum JSON data onto the image array."""
49
55
  image_array = layer
56
+ # Extract alpha from color
57
+ alpha = color[3] if len(color) == 4 else 255
58
+
59
+ # For debugging
60
+ _LOGGER.debug("Drawing with color %s and alpha %s", color, alpha)
61
+
62
+ # Create the full color with alpha
63
+ full_color = color if len(color) == 4 else (*color, 255)
64
+
50
65
  # Loop through pixels to find min and max coordinates
51
66
  for x, y, z in pixels:
52
67
  col = x * pixel_size
53
68
  row = y * pixel_size
54
69
  # Draw pixels as blocks
55
70
  for i in range(z):
56
- image_array[
71
+ # Get the region to update
72
+ region = image_array[
57
73
  row : row + pixel_size,
58
74
  col + i * pixel_size : col + (i + 1) * pixel_size,
59
- ] = color
75
+ ]
76
+
77
+ # Simple direct assignment - ignore alpha for now to ensure visibility
78
+ region[:] = full_color
79
+
60
80
  return image_array
61
81
 
62
82
  @staticmethod
@@ -0,0 +1,312 @@
1
+ """
2
+ Drawable Elements Configuration.
3
+ Defines the elements that can be drawn on the map and their properties.
4
+ Version: 0.1.9
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from enum import IntEnum
11
+ from typing import Dict, List, Tuple, Union
12
+
13
+ from .colors import DefaultColors, SupportedColor
14
+
15
+
16
+ # numpy is not used in this file
17
+
18
+
19
+ _LOGGER = logging.getLogger(__name__)
20
+
21
+ # Type aliases
22
+ Color = Tuple[int, int, int, int] # RGBA color
23
+ PropertyDict = Dict[str, Union[Color, float, int]]
24
+
25
+
26
+ class DrawableElement(IntEnum):
27
+ """Enumeration of drawable map elements with unique integer codes."""
28
+
29
+ # Base elements
30
+ FLOOR = 1
31
+ WALL = 2
32
+ ROBOT = 3
33
+ CHARGER = 4
34
+ VIRTUAL_WALL = 5
35
+ RESTRICTED_AREA = 6
36
+ NO_MOP_AREA = 7
37
+ OBSTACLE = 8
38
+ PATH = 9
39
+ PREDICTED_PATH = 10
40
+ GO_TO_TARGET = 11
41
+
42
+ # Rooms (101-115 for up to 15 rooms)
43
+ ROOM_1 = 101
44
+ ROOM_2 = 102
45
+ ROOM_3 = 103
46
+ ROOM_4 = 104
47
+ ROOM_5 = 105
48
+ ROOM_6 = 106
49
+ ROOM_7 = 107
50
+ ROOM_8 = 108
51
+ ROOM_9 = 109
52
+ ROOM_10 = 110
53
+ ROOM_11 = 111
54
+ ROOM_12 = 112
55
+ ROOM_13 = 113
56
+ ROOM_14 = 114
57
+ ROOM_15 = 115
58
+
59
+
60
+ class DrawingConfig:
61
+ """Configuration for which elements to draw and their properties."""
62
+
63
+ def __init__(self):
64
+ """Initialize with all elements enabled by default."""
65
+ # Dictionary of element_code -> enabled status
66
+ self._enabled_elements = {element: True for element in DrawableElement}
67
+
68
+ # Dictionary of element_code -> drawing properties (color, opacity, etc.)
69
+ self._element_properties: Dict[DrawableElement, PropertyDict] = {}
70
+
71
+ # Initialize default properties
72
+ self._set_default_properties()
73
+
74
+ def _set_default_properties(self):
75
+ """Set default drawing properties for each element."""
76
+ # Set properties for rooms using DefaultColors
77
+ for room_id in range(1, 16):
78
+ room_element = getattr(DrawableElement, f"ROOM_{room_id}")
79
+ room_key = SupportedColor.room_key(room_id - 1)
80
+ rgb = DefaultColors.DEFAULT_ROOM_COLORS.get(room_key, (135, 206, 250))
81
+ alpha = DefaultColors.DEFAULT_ALPHA.get(f"alpha_room_{room_id - 1}", 255.0)
82
+
83
+ self._element_properties[room_element] = {
84
+ "color": (*rgb, int(alpha)),
85
+ "opacity": alpha / 255.0,
86
+ "z_index": 10, # Drawing order
87
+ }
88
+
89
+ # Map DrawableElement to SupportedColor
90
+ element_color_mapping = {
91
+ DrawableElement.FLOOR: SupportedColor.MAP_BACKGROUND,
92
+ DrawableElement.WALL: SupportedColor.WALLS,
93
+ DrawableElement.ROBOT: SupportedColor.ROBOT,
94
+ DrawableElement.CHARGER: SupportedColor.CHARGER,
95
+ DrawableElement.VIRTUAL_WALL: SupportedColor.NO_GO,
96
+ DrawableElement.RESTRICTED_AREA: SupportedColor.NO_GO,
97
+ DrawableElement.PATH: SupportedColor.PATH,
98
+ DrawableElement.PREDICTED_PATH: SupportedColor.PREDICTED_PATH,
99
+ DrawableElement.GO_TO_TARGET: SupportedColor.GO_TO,
100
+ DrawableElement.NO_MOP_AREA: SupportedColor.NO_GO, # Using NO_GO for no-mop areas
101
+ DrawableElement.OBSTACLE: SupportedColor.NO_GO, # Using NO_GO for obstacles
102
+ }
103
+
104
+ # Set z-index for each element type
105
+ z_indices = {
106
+ DrawableElement.FLOOR: 0,
107
+ DrawableElement.WALL: 20,
108
+ DrawableElement.ROBOT: 50,
109
+ DrawableElement.CHARGER: 40,
110
+ DrawableElement.VIRTUAL_WALL: 30,
111
+ DrawableElement.RESTRICTED_AREA: 25,
112
+ DrawableElement.NO_MOP_AREA: 25,
113
+ DrawableElement.OBSTACLE: 15,
114
+ DrawableElement.PATH: 35,
115
+ DrawableElement.PREDICTED_PATH: 34,
116
+ DrawableElement.GO_TO_TARGET: 45,
117
+ }
118
+
119
+ # Set properties for other elements using DefaultColors
120
+ for element, color_key in element_color_mapping.items():
121
+ rgb = DefaultColors.COLORS_RGB.get(color_key, (0, 0, 0))
122
+ alpha_key = f"alpha_{color_key}"
123
+ alpha = DefaultColors.DEFAULT_ALPHA.get(alpha_key, 255.0)
124
+
125
+ # Special case for semi-transparent elements
126
+ if element in [
127
+ DrawableElement.RESTRICTED_AREA,
128
+ DrawableElement.NO_MOP_AREA,
129
+ DrawableElement.PREDICTED_PATH,
130
+ ]:
131
+ alpha = 125.0 # Semi-transparent by default
132
+
133
+ self._element_properties[element] = {
134
+ "color": (*rgb, int(alpha)),
135
+ "opacity": alpha / 255.0,
136
+ "z_index": z_indices.get(element, 0),
137
+ }
138
+
139
+ def enable_element(self, element_code: DrawableElement) -> None:
140
+ """Enable drawing of a specific element."""
141
+ if element_code in self._enabled_elements:
142
+ self._enabled_elements[element_code] = True
143
+ _LOGGER.info(
144
+ "Enabled element %s (%s)", element_code.name, element_code.value
145
+ )
146
+ _LOGGER.info(
147
+ "Element %s is now enabled: %s",
148
+ element_code.name,
149
+ self._enabled_elements[element_code],
150
+ )
151
+
152
+ def disable_element(self, element_code: DrawableElement) -> None:
153
+ """Disable drawing of a specific element."""
154
+ if element_code in self._enabled_elements:
155
+ self._enabled_elements[element_code] = False
156
+ _LOGGER.info(
157
+ "Disabled element %s (%s)", element_code.name, element_code.value
158
+ )
159
+ _LOGGER.info(
160
+ "Element %s is now enabled: %s",
161
+ element_code.name,
162
+ self._enabled_elements[element_code],
163
+ )
164
+
165
+ def set_elements(self, element_codes: List[DrawableElement]) -> None:
166
+ """Enable only the specified elements, disable all others."""
167
+ # First disable all
168
+ for element in self._enabled_elements:
169
+ self._enabled_elements[element] = False
170
+
171
+ # Then enable specified ones
172
+ for element in element_codes:
173
+ if element in self._enabled_elements:
174
+ self._enabled_elements[element] = True
175
+
176
+ def is_enabled(self, element_code: DrawableElement) -> bool:
177
+ """Check if an element is enabled for drawing."""
178
+ enabled = self._enabled_elements.get(element_code, False)
179
+ _LOGGER.debug(
180
+ "Checking if element %s is enabled: %s",
181
+ element_code.name if hasattr(element_code, "name") else element_code,
182
+ enabled,
183
+ )
184
+ return enabled
185
+
186
+ def set_property(
187
+ self, element_code: DrawableElement, property_name: str, value
188
+ ) -> None:
189
+ """Set a drawing property for an element."""
190
+ if element_code in self._element_properties:
191
+ self._element_properties[element_code][property_name] = value
192
+
193
+ def get_property(
194
+ self, element_code: DrawableElement, property_name: str, default=None
195
+ ):
196
+ """Get a drawing property for an element."""
197
+ if element_code in self._element_properties:
198
+ return self._element_properties[element_code].get(property_name, default)
199
+ return default
200
+
201
+ def get_enabled_elements(self) -> List[DrawableElement]:
202
+ """Get list of enabled element codes."""
203
+ return [
204
+ element for element, enabled in self._enabled_elements.items() if enabled
205
+ ]
206
+
207
+ def get_drawing_order(self) -> List[DrawableElement]:
208
+ """Get list of enabled elements in drawing order (by z_index)."""
209
+ enabled = self.get_enabled_elements()
210
+ return sorted(enabled, key=lambda e: self.get_property(e, "z_index", 0))
211
+
212
+ def update_from_device_info(self, device_info: dict) -> None:
213
+ """Update configuration based on device info dictionary."""
214
+ # Map DrawableElement to SupportedColor
215
+ element_color_mapping = {
216
+ DrawableElement.FLOOR: SupportedColor.MAP_BACKGROUND,
217
+ DrawableElement.WALL: SupportedColor.WALLS,
218
+ DrawableElement.ROBOT: SupportedColor.ROBOT,
219
+ DrawableElement.CHARGER: SupportedColor.CHARGER,
220
+ DrawableElement.VIRTUAL_WALL: SupportedColor.NO_GO,
221
+ DrawableElement.RESTRICTED_AREA: SupportedColor.NO_GO,
222
+ DrawableElement.PATH: SupportedColor.PATH,
223
+ DrawableElement.PREDICTED_PATH: SupportedColor.PREDICTED_PATH,
224
+ DrawableElement.GO_TO_TARGET: SupportedColor.GO_TO,
225
+ DrawableElement.NO_MOP_AREA: SupportedColor.NO_GO,
226
+ DrawableElement.OBSTACLE: SupportedColor.NO_GO,
227
+ }
228
+
229
+ # Update room colors from device info
230
+ for room_id in range(1, 16):
231
+ room_element = getattr(DrawableElement, f"ROOM_{room_id}")
232
+ color_key = SupportedColor.room_key(room_id - 1)
233
+ alpha_key = f"alpha_room_{room_id - 1}"
234
+
235
+ if color_key in device_info:
236
+ rgb = device_info[color_key]
237
+ alpha = device_info.get(alpha_key, 255.0)
238
+
239
+ # Create RGBA color
240
+ rgba = (*rgb, int(alpha))
241
+
242
+ # Update color and opacity
243
+ self.set_property(room_element, "color", rgba)
244
+ self.set_property(room_element, "opacity", alpha / 255.0)
245
+
246
+ _LOGGER.debug(
247
+ "Updated room %d color to %s with alpha %s", room_id, rgb, alpha
248
+ )
249
+
250
+ # Update other element colors
251
+ for element, color_key in element_color_mapping.items():
252
+ if color_key in device_info:
253
+ rgb = device_info[color_key]
254
+ alpha_key = f"alpha_{color_key}"
255
+ alpha = device_info.get(alpha_key, 255.0)
256
+
257
+ # Special case for semi-transparent elements
258
+ if element in [
259
+ DrawableElement.RESTRICTED_AREA,
260
+ DrawableElement.NO_MOP_AREA,
261
+ DrawableElement.PREDICTED_PATH,
262
+ ]:
263
+ if alpha > 200: # If alpha is too high for these elements
264
+ alpha = 125.0 # Use a more appropriate default
265
+
266
+ # Create RGBA color
267
+ rgba = (*rgb, int(alpha))
268
+
269
+ # Update color and opacity
270
+ self.set_property(element, "color", rgba)
271
+ self.set_property(element, "opacity", alpha / 255.0)
272
+
273
+ _LOGGER.debug(
274
+ "Updated element %s color to %s with alpha %s",
275
+ element.name,
276
+ rgb,
277
+ alpha,
278
+ )
279
+
280
+ # Check for disabled elements using specific boolean flags
281
+ # Map element disable flags to DrawableElement enum values
282
+ element_disable_mapping = {
283
+ "disable_floor": DrawableElement.FLOOR,
284
+ "disable_wall": DrawableElement.WALL,
285
+ "disable_robot": DrawableElement.ROBOT,
286
+ "disable_charger": DrawableElement.CHARGER,
287
+ "disable_virtual_walls": DrawableElement.VIRTUAL_WALL,
288
+ "disable_restricted_areas": DrawableElement.RESTRICTED_AREA,
289
+ "disable_no_mop_areas": DrawableElement.NO_MOP_AREA,
290
+ "disable_obstacles": DrawableElement.OBSTACLE,
291
+ "disable_path": DrawableElement.PATH,
292
+ "disable_predicted_path": DrawableElement.PREDICTED_PATH,
293
+ "disable_go_to_target": DrawableElement.GO_TO_TARGET,
294
+ }
295
+
296
+ # Process base element disable flags
297
+ for disable_key, element in element_disable_mapping.items():
298
+ if device_info.get(disable_key, False):
299
+ self.disable_element(element)
300
+ _LOGGER.info(
301
+ "Disabled %s element from device_info setting", element.name
302
+ )
303
+
304
+ # Process room disable flags (1-15)
305
+ for room_id in range(1, 16):
306
+ disable_key = f"disable_room_{room_id}"
307
+ if device_info.get(disable_key, False):
308
+ room_element = getattr(DrawableElement, f"ROOM_{room_id}")
309
+ self.disable_element(room_element)
310
+ _LOGGER.info(
311
+ "Disabled ROOM_%d element from device_info setting", room_id
312
+ )