valetudo-map-parser 0.1.9b41__py3-none-any.whl → 0.1.9b43__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.
- valetudo_map_parser/__init__.py +6 -3
- valetudo_map_parser/config/drawable.py +22 -2
- valetudo_map_parser/config/drawable_elements.py +312 -0
- valetudo_map_parser/config/enhanced_drawable.py +447 -0
- valetudo_map_parser/config/shared.py +27 -0
- valetudo_map_parser/config/types.py +2 -1
- valetudo_map_parser/config/utils.py +410 -1
- valetudo_map_parser/hypfer_draw.py +194 -60
- valetudo_map_parser/hypfer_handler.py +344 -40
- valetudo_map_parser/map_data.py +1 -1
- valetudo_map_parser/rand25_handler.py +224 -39
- valetudo_map_parser/reimg_draw.py +1 -1
- valetudo_map_parser-0.1.9b43.dist-info/METADATA +92 -0
- valetudo_map_parser-0.1.9b43.dist-info/RECORD +23 -0
- {valetudo_map_parser-0.1.9b41.dist-info → valetudo_map_parser-0.1.9b43.dist-info}/WHEEL +1 -1
- valetudo_map_parser-0.1.9b41.dist-info/METADATA +0 -47
- valetudo_map_parser-0.1.9b41.dist-info/RECORD +0 -21
- {valetudo_map_parser-0.1.9b41.dist-info → valetudo_map_parser-0.1.9b43.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.9b41.dist-info → valetudo_map_parser-0.1.9b43.dist-info}/NOTICE.txt +0 -0
valetudo_map_parser/__init__.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
"""Valetudo map parser.
|
2
|
-
Version: 0.1.
|
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
|
-
|
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
|
-
]
|
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
|
+
)
|