valetudo-map-parser 0.1.11b1__tar.gz → 0.1.12b0__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 (38) hide show
  1. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/PKG-INFO +1 -1
  2. valetudo_map_parser-0.1.12b0/SCR/valetudo_map_parser/__init__.py +175 -0
  3. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/async_utils.py +1 -1
  4. valetudo_map_parser-0.1.12b0/SCR/valetudo_map_parser/config/colors.py +410 -0
  5. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/drawable.py +10 -73
  6. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/rand256_parser.py +129 -111
  7. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/shared.py +27 -8
  8. valetudo_map_parser-0.1.12b0/SCR/valetudo_map_parser/config/status_text/__init__.py +6 -0
  9. valetudo_map_parser-0.1.12b0/SCR/valetudo_map_parser/config/status_text/status_text.py +121 -0
  10. valetudo_map_parser-0.1.12b0/SCR/valetudo_map_parser/config/types.py +337 -0
  11. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/utils.py +99 -75
  12. valetudo_map_parser-0.1.12b0/SCR/valetudo_map_parser/const.py +288 -0
  13. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/hypfer_draw.py +121 -150
  14. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/hypfer_handler.py +210 -183
  15. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/map_data.py +31 -0
  16. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/rand256_handler.py +207 -218
  17. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/rooms_handler.py +4 -5
  18. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/pyproject.toml +1 -1
  19. valetudo_map_parser-0.1.11b1/SCR/valetudo_map_parser/__init__.py +0 -66
  20. valetudo_map_parser-0.1.11b1/SCR/valetudo_map_parser/config/colors.py +0 -827
  21. valetudo_map_parser-0.1.11b1/SCR/valetudo_map_parser/config/status_text/status_text.py +0 -96
  22. valetudo_map_parser-0.1.11b1/SCR/valetudo_map_parser/config/types.py +0 -671
  23. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/LICENSE +0 -0
  24. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/NOTICE.txt +0 -0
  25. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/README.md +0 -0
  26. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/__init__.py +0 -0
  27. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/drawable_elements.py +0 -0
  28. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/fonts/FiraSans.ttf +0 -0
  29. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/fonts/Inter-VF.ttf +0 -0
  30. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/fonts/Lato-Regular.ttf +0 -0
  31. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/fonts/MPLUSRegular.ttf +0 -0
  32. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/fonts/NotoKufiArabic-VF.ttf +0 -0
  33. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/fonts/NotoSansCJKhk-VF.ttf +0 -0
  34. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/fonts/NotoSansKhojki.ttf +0 -0
  35. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/optimized_element_map.py +0 -0
  36. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/config/status_text/translations.py +0 -0
  37. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/py.typed +0 -0
  38. {valetudo_map_parser-0.1.11b1 → valetudo_map_parser-0.1.12b0}/SCR/valetudo_map_parser/reimg_draw.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: valetudo-map-parser
3
- Version: 0.1.11b1
3
+ Version: 0.1.12b0
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
@@ -0,0 +1,175 @@
1
+ """Valetudo map parser.
2
+ Version: 0.1.12"""
3
+
4
+ from pathlib import Path
5
+
6
+ from .config.colors import ColorsManagement
7
+ from .config.drawable import Drawable
8
+ from .config.drawable_elements import DrawableElement, DrawingConfig
9
+ from .config.rand256_parser import RRMapParser
10
+ from .config.shared import CameraShared, CameraSharedManager
11
+ from .config.status_text.status_text import StatusText
12
+ from .config.status_text.translations import translations as STATUS_TEXT_TRANSLATIONS
13
+ from .config.types import (
14
+ CameraModes,
15
+ ImageSize,
16
+ JsonType,
17
+ NumpyArray,
18
+ PilPNG,
19
+ RoomsProperties,
20
+ RoomStore,
21
+ SnapshotStore,
22
+ TrimCropData,
23
+ UserLanguageStore,
24
+ )
25
+ from .config.utils import ResizeParams, async_resize_image
26
+ from .const import (
27
+ ATTR_CALIBRATION_POINTS,
28
+ ATTR_CAMERA_MODE,
29
+ ATTR_CONTENT_TYPE,
30
+ ATTR_FRIENDLY_NAME,
31
+ ATTR_IMAGE_LAST_UPDATED,
32
+ ATTR_JSON_DATA,
33
+ ATTR_OBSTACLES,
34
+ ATTR_POINTS,
35
+ ATTR_ROOMS,
36
+ ATTR_ROTATE,
37
+ ATTR_SNAPSHOT,
38
+ ATTR_SNAPSHOT_PATH,
39
+ ATTR_VACUUM_BATTERY,
40
+ ATTR_VACUUM_CHARGING,
41
+ ATTR_VACUUM_JSON_ID,
42
+ ATTR_VACUUM_POSITION,
43
+ ATTR_VACUUM_STATUS,
44
+ ATTR_VACUUM_TOPIC,
45
+ ATTR_ZONES,
46
+ CAMERA_STORAGE,
47
+ COLORS,
48
+ CONF_ASPECT_RATIO,
49
+ CONF_AUTO_ZOOM,
50
+ CONF_EXPORT_SVG,
51
+ CONF_OFFSET_BOTTOM,
52
+ CONF_OFFSET_LEFT,
53
+ CONF_OFFSET_RIGHT,
54
+ CONF_OFFSET_TOP,
55
+ CONF_SNAPSHOTS_ENABLE,
56
+ CONF_TRIMS_SAVE,
57
+ CONF_VACUUM_CONFIG_ENTRY_ID,
58
+ CONF_VACUUM_CONNECTION_STRING,
59
+ CONF_VACUUM_ENTITY_ID,
60
+ CONF_VACUUM_IDENTIFIERS,
61
+ CONF_VAC_STAT,
62
+ CONF_VAC_STAT_FONT,
63
+ CONF_VAC_STAT_POS,
64
+ CONF_VAC_STAT_SIZE,
65
+ CONF_ZOOM_LOCK_RATIO,
66
+ DECODED_TOPICS,
67
+ DEFAULT_IMAGE_SIZE,
68
+ DEFAULT_PIXEL_SIZE,
69
+ DEFAULT_VALUES,
70
+ FONTS_AVAILABLE,
71
+ ICON,
72
+ NAME,
73
+ NON_DECODED_TOPICS,
74
+ NOT_STREAMING_STATES,
75
+ SENSOR_NO_DATA,
76
+ )
77
+ from .hypfer_handler import HypferMapImageHandler
78
+ from .map_data import HyperMapData
79
+ from .rand256_handler import ReImageHandler
80
+ from .rooms_handler import RandRoomsHandler, RoomsHandler
81
+
82
+
83
+ def get_default_font_path() -> str:
84
+ """Return the absolute path to the bundled default font directory.
85
+
86
+ This returns the path to the fonts folder; the caller can join a specific font file
87
+ to avoid hard-coding a particular font here.
88
+ """
89
+ return str((Path(__file__).resolve().parent / "config" / "fonts").resolve())
90
+
91
+
92
+ __all__ = [
93
+ # Attribute Constants
94
+ "ATTR_CALIBRATION_POINTS",
95
+ "ATTR_CAMERA_MODE",
96
+ "ATTR_CONTENT_TYPE",
97
+ "ATTR_FRIENDLY_NAME",
98
+ "ATTR_IMAGE_LAST_UPDATED",
99
+ "ATTR_JSON_DATA",
100
+ "ATTR_OBSTACLES",
101
+ "ATTR_POINTS",
102
+ "ATTR_ROOMS",
103
+ "ATTR_ROTATE",
104
+ "ATTR_SNAPSHOT",
105
+ "ATTR_SNAPSHOT_PATH",
106
+ "ATTR_VACUUM_BATTERY",
107
+ "ATTR_VACUUM_CHARGING",
108
+ "ATTR_VACUUM_JSON_ID",
109
+ "ATTR_VACUUM_POSITION",
110
+ "ATTR_VACUUM_STATUS",
111
+ "ATTR_VACUUM_TOPIC",
112
+ "ATTR_ZONES",
113
+ # Configuration Constants
114
+ "CAMERA_STORAGE",
115
+ "COLORS",
116
+ "CONF_ASPECT_RATIO",
117
+ "CONF_AUTO_ZOOM",
118
+ "CONF_EXPORT_SVG",
119
+ "CONF_OFFSET_BOTTOM",
120
+ "CONF_OFFSET_LEFT",
121
+ "CONF_OFFSET_RIGHT",
122
+ "CONF_OFFSET_TOP",
123
+ "CONF_SNAPSHOTS_ENABLE",
124
+ "CONF_TRIMS_SAVE",
125
+ "CONF_VACUUM_CONFIG_ENTRY_ID",
126
+ "CONF_VACUUM_CONNECTION_STRING",
127
+ "CONF_VACUUM_ENTITY_ID",
128
+ "CONF_VACUUM_IDENTIFIERS",
129
+ "CONF_VAC_STAT",
130
+ "CONF_VAC_STAT_FONT",
131
+ "CONF_VAC_STAT_POS",
132
+ "CONF_VAC_STAT_SIZE",
133
+ "CONF_ZOOM_LOCK_RATIO",
134
+ # Default Values
135
+ "DECODED_TOPICS",
136
+ "DEFAULT_IMAGE_SIZE",
137
+ "DEFAULT_PIXEL_SIZE",
138
+ "DEFAULT_VALUES",
139
+ "FONTS_AVAILABLE",
140
+ "ICON",
141
+ "NAME",
142
+ "NON_DECODED_TOPICS",
143
+ "NOT_STREAMING_STATES",
144
+ "SENSOR_NO_DATA",
145
+ # Classes and Handlers
146
+ "CameraShared",
147
+ "CameraSharedManager",
148
+ "ColorsManagement",
149
+ "Drawable",
150
+ "DrawableElement",
151
+ "DrawingConfig",
152
+ "HyperMapData",
153
+ "HypferMapImageHandler",
154
+ "RRMapParser",
155
+ "RandRoomsHandler",
156
+ "ReImageHandler",
157
+ "RoomsHandler",
158
+ "StatusText",
159
+ # Types
160
+ "CameraModes",
161
+ "ImageSize",
162
+ "JsonType",
163
+ "NumpyArray",
164
+ "PilPNG",
165
+ "RoomsProperties",
166
+ "RoomStore",
167
+ "SnapshotStore",
168
+ "TrimCropData",
169
+ "UserLanguageStore",
170
+ # Utilities
171
+ "ResizeParams",
172
+ "STATUS_TEXT_TRANSLATIONS",
173
+ "async_resize_image",
174
+ "get_default_font_path",
175
+ ]
@@ -49,7 +49,7 @@ class AsyncPIL:
49
49
  ) -> Image.Image:
50
50
  """Async image resizing."""
51
51
  if resample is None:
52
- resample = Image.LANCZOS
52
+ resample = Image.Resampling.LANCZOS
53
53
  return await make_async(image.resize, size, resample)
54
54
 
55
55
  @staticmethod
@@ -0,0 +1,410 @@
1
+ """Colors for the maps Elements."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from enum import StrEnum
6
+ from typing import Dict, List, Tuple
7
+
8
+ import numpy as np
9
+
10
+ from ..const import (
11
+ ALPHA_BACKGROUND,
12
+ ALPHA_CHARGER,
13
+ ALPHA_GO_TO,
14
+ ALPHA_MOVE,
15
+ ALPHA_NO_GO,
16
+ ALPHA_ROBOT,
17
+ ALPHA_ROOM_0,
18
+ ALPHA_ROOM_1,
19
+ ALPHA_ROOM_2,
20
+ ALPHA_ROOM_3,
21
+ ALPHA_ROOM_4,
22
+ ALPHA_ROOM_5,
23
+ ALPHA_ROOM_6,
24
+ ALPHA_ROOM_7,
25
+ ALPHA_ROOM_8,
26
+ ALPHA_ROOM_9,
27
+ ALPHA_ROOM_10,
28
+ ALPHA_ROOM_11,
29
+ ALPHA_ROOM_12,
30
+ ALPHA_ROOM_13,
31
+ ALPHA_ROOM_14,
32
+ ALPHA_ROOM_15,
33
+ ALPHA_TEXT,
34
+ ALPHA_WALL,
35
+ ALPHA_ZONE_CLEAN,
36
+ COLOR_BACKGROUND,
37
+ COLOR_CHARGER,
38
+ COLOR_GO_TO,
39
+ COLOR_MOVE,
40
+ COLOR_NO_GO,
41
+ COLOR_ROBOT,
42
+ COLOR_ROOM_0,
43
+ COLOR_ROOM_1,
44
+ COLOR_ROOM_2,
45
+ COLOR_ROOM_3,
46
+ COLOR_ROOM_4,
47
+ COLOR_ROOM_5,
48
+ COLOR_ROOM_6,
49
+ COLOR_ROOM_7,
50
+ COLOR_ROOM_8,
51
+ COLOR_ROOM_9,
52
+ COLOR_ROOM_10,
53
+ COLOR_ROOM_11,
54
+ COLOR_ROOM_12,
55
+ COLOR_ROOM_13,
56
+ COLOR_ROOM_14,
57
+ COLOR_ROOM_15,
58
+ COLOR_TEXT,
59
+ COLOR_WALL,
60
+ COLOR_ZONE_CLEAN,
61
+ )
62
+ from .types import LOGGER, Color
63
+
64
+ color_transparent = (0, 0, 0, 0)
65
+ color_charger = (0, 128, 0, 255)
66
+ color_move = (238, 247, 255, 255)
67
+ color_robot = (255, 255, 204, 255)
68
+ color_no_go = (255, 0, 0, 255)
69
+ color_go_to = (0, 255, 0, 255)
70
+ color_background = (0, 125, 255, 255)
71
+ color_zone_clean = (255, 255, 255, 125)
72
+ color_wall = (255, 255, 0, 255)
73
+ color_text = (255, 255, 255, 255)
74
+ color_grey = (125, 125, 125, 255)
75
+ color_black = (0, 0, 0, 255)
76
+ color_room_0 = (135, 206, 250, 255)
77
+ color_room_1 = (176, 226, 255, 255)
78
+ color_room_2 = (164, 211, 238, 255)
79
+ color_room_3 = (141, 182, 205, 255)
80
+ color_room_4 = (96, 123, 139, 255)
81
+ color_room_5 = (224, 255, 255, 255)
82
+ color_room_6 = (209, 238, 238, 255)
83
+ color_room_7 = (180, 205, 205, 255)
84
+ color_room_8 = (122, 139, 139, 255)
85
+ color_room_9 = (175, 238, 238, 255)
86
+ color_room_10 = (84, 153, 199, 255)
87
+ color_room_11 = (133, 193, 233, 255)
88
+ color_room_12 = (245, 176, 65, 255)
89
+ color_room_13 = (82, 190, 128, 255)
90
+ color_room_14 = (72, 201, 176, 255)
91
+ color_room_15 = (165, 105, 18, 255)
92
+
93
+ rooms_color = [
94
+ color_room_0,
95
+ color_room_1,
96
+ color_room_2,
97
+ color_room_3,
98
+ color_room_4,
99
+ color_room_5,
100
+ color_room_6,
101
+ color_room_7,
102
+ color_room_8,
103
+ color_room_9,
104
+ color_room_10,
105
+ color_room_11,
106
+ color_room_12,
107
+ color_room_13,
108
+ color_room_14,
109
+ color_room_15,
110
+ ]
111
+
112
+ base_colors_array = [
113
+ color_wall,
114
+ color_zone_clean,
115
+ color_robot,
116
+ color_background,
117
+ color_move,
118
+ color_charger,
119
+ color_no_go,
120
+ color_go_to,
121
+ color_text,
122
+ ]
123
+
124
+ color_array = [
125
+ base_colors_array[0], # color_wall
126
+ base_colors_array[6], # color_no_go
127
+ base_colors_array[7], # color_go_to
128
+ color_black,
129
+ base_colors_array[2], # color_robot
130
+ base_colors_array[5], # color_charger
131
+ color_text,
132
+ base_colors_array[4], # color_move
133
+ base_colors_array[3], # color_background
134
+ base_colors_array[1], # color_zone_clean
135
+ color_transparent,
136
+ rooms_color,
137
+ ]
138
+
139
+
140
+ class SupportedColor(StrEnum):
141
+ """Color of a supported map element."""
142
+
143
+ CHARGER = "color_charger"
144
+ PATH = "color_move"
145
+ PREDICTED_PATH = "color_predicted_move"
146
+ WALLS = "color_wall"
147
+ ROBOT = "color_robot"
148
+ GO_TO = "color_go_to"
149
+ NO_GO = "color_no_go"
150
+ ZONE_CLEAN = "color_zone_clean"
151
+ MAP_BACKGROUND = "color_background"
152
+ TEXT = "color_text"
153
+ TRANSPARENT = "color_transparent"
154
+ COLOR_ROOM_PREFIX = "color_room_"
155
+
156
+ @staticmethod
157
+ def room_key(index: int) -> str:
158
+ return f"{SupportedColor.COLOR_ROOM_PREFIX}{index}"
159
+
160
+
161
+ class DefaultColors:
162
+ """Container that simplifies retrieving default RGB and RGBA colors."""
163
+
164
+ COLORS_RGB: Dict[str, Tuple[int, int, int]] = {
165
+ SupportedColor.CHARGER: (255, 128, 0),
166
+ SupportedColor.PATH: (50, 150, 255), # More vibrant blue for better visibility
167
+ SupportedColor.PREDICTED_PATH: (93, 109, 126),
168
+ SupportedColor.WALLS: (255, 255, 0),
169
+ SupportedColor.ROBOT: (255, 255, 204),
170
+ SupportedColor.GO_TO: (0, 255, 0),
171
+ SupportedColor.NO_GO: (255, 0, 0),
172
+ SupportedColor.ZONE_CLEAN: (255, 255, 255),
173
+ SupportedColor.MAP_BACKGROUND: (0, 125, 255),
174
+ SupportedColor.TEXT: (0, 0, 0),
175
+ SupportedColor.TRANSPARENT: (0, 0, 0),
176
+ }
177
+
178
+ DEFAULT_ROOM_COLORS: Dict[str, Tuple[int, int, int]] = {
179
+ SupportedColor.room_key(i): color
180
+ for i, color in enumerate(
181
+ [
182
+ (135, 206, 250),
183
+ (176, 226, 255),
184
+ (165, 105, 18),
185
+ (164, 211, 238),
186
+ (141, 182, 205),
187
+ (96, 123, 139),
188
+ (224, 255, 255),
189
+ (209, 238, 238),
190
+ (180, 205, 205),
191
+ (122, 139, 139),
192
+ (175, 238, 238),
193
+ (84, 153, 199),
194
+ (133, 193, 233),
195
+ (245, 176, 65),
196
+ (82, 190, 128),
197
+ (72, 201, 176),
198
+ ]
199
+ )
200
+ }
201
+
202
+ DEFAULT_ALPHA: Dict[str, float] = {
203
+ f"alpha_{key}": 255.0 for key in COLORS_RGB.keys()
204
+ }
205
+ # Override specific alpha values
206
+ DEFAULT_ALPHA.update(
207
+ {
208
+ "alpha_color_path": 200.0, # Make path slightly transparent but still very visible
209
+ "alpha_color_wall": 150.0, # Keep walls semi-transparent
210
+ }
211
+ )
212
+ DEFAULT_ALPHA.update({f"alpha_room_{i}": 255.0 for i in range(16)})
213
+
214
+ @classmethod
215
+ def get_rgba(cls, key: str, alpha: float) -> Color:
216
+ rgb = cls.COLORS_RGB.get(key, (0, 0, 0))
217
+ r, g, b = rgb # Explicitly unpack the RGB values
218
+ return r, g, b, int(alpha)
219
+
220
+
221
+ class ColorsManagement:
222
+ """Manages user-defined and default colors for map elements."""
223
+
224
+ def __init__(self, shared_var) -> None:
225
+ """
226
+ Initialize ColorsManagement for Home Assistant.
227
+ Uses optimized initialization for better performance.
228
+ """
229
+ self.shared_var = shared_var
230
+ self.color_cache = {} # Cache for frequently used color blends
231
+
232
+ # Initialize colors efficiently
233
+ self.user_colors = self.initialize_user_colors(self.shared_var.device_info)
234
+ self.rooms_colors = self.initialize_rooms_colors(self.shared_var.device_info)
235
+
236
+ @staticmethod
237
+ def add_alpha_to_rgb(alpha_channels, rgb_colors):
238
+ """
239
+ Add alpha channel to RGB colors using corresponding alpha channels.
240
+ Uses NumPy for vectorized operations when possible for better performance.
241
+
242
+ Args:
243
+ alpha_channels (List[Optional[float]]): List of alpha channel values (0.0-255.0).
244
+ rgb_colors (List[Tuple[int, int, int]]): List of RGB colors.
245
+
246
+ Returns:
247
+ List[Tuple[int, int, int, int]]: List of RGBA colors with alpha channel added.
248
+ """
249
+ if len(alpha_channels) != len(rgb_colors):
250
+ LOGGER.warning("Input lists must have the same length.")
251
+ return []
252
+
253
+ # Fast path for empty lists
254
+ if not rgb_colors:
255
+ return []
256
+
257
+ # Try to use NumPy for vectorized operations
258
+ try:
259
+ # Convert inputs to NumPy arrays for vectorized processing
260
+ alphas = np.array(alpha_channels, dtype=np.float32)
261
+
262
+ # Clip alpha values to valid range [0, 255]
263
+ alphas = np.clip(alphas, 0, 255).astype(np.int32)
264
+
265
+ # Process RGB colors
266
+ result = []
267
+ for _, (alpha, rgb) in enumerate(zip(alphas, rgb_colors)):
268
+ if rgb is None:
269
+ result.append((0, 0, 0, int(alpha)))
270
+ else:
271
+ result.append((rgb[0], rgb[1], rgb[2], int(alpha)))
272
+
273
+ return result
274
+
275
+ except (ValueError, TypeError, AttributeError):
276
+ # Fallback to non-vectorized method if NumPy processing fails
277
+ result = []
278
+ for alpha, rgb in zip(alpha_channels, rgb_colors):
279
+ try:
280
+ alpha_int = int(alpha)
281
+ alpha_int = max(0, min(255, alpha_int)) # Clip to valid range
282
+
283
+ if rgb is None:
284
+ result.append((0, 0, 0, alpha_int))
285
+ else:
286
+ result.append((rgb[0], rgb[1], rgb[2], alpha_int))
287
+ except (ValueError, TypeError):
288
+ result.append(None)
289
+
290
+ return result
291
+
292
+ def set_initial_colours(self, device_info: dict) -> None:
293
+ """Set the initial colours for the map using optimized methods."""
294
+ try:
295
+ # Define color keys and default values
296
+ base_color_keys = [
297
+ (COLOR_WALL, color_wall, ALPHA_WALL),
298
+ (COLOR_ZONE_CLEAN, color_zone_clean, ALPHA_ZONE_CLEAN),
299
+ (COLOR_ROBOT, color_robot, ALPHA_ROBOT),
300
+ (COLOR_BACKGROUND, color_background, ALPHA_BACKGROUND),
301
+ (COLOR_MOVE, color_move, ALPHA_MOVE),
302
+ (COLOR_CHARGER, color_charger, ALPHA_CHARGER),
303
+ (COLOR_NO_GO, color_no_go, ALPHA_NO_GO),
304
+ (COLOR_GO_TO, color_go_to, ALPHA_GO_TO),
305
+ (COLOR_TEXT, color_text, ALPHA_TEXT),
306
+ ]
307
+
308
+ room_color_keys = [
309
+ (COLOR_ROOM_0, color_room_0, ALPHA_ROOM_0),
310
+ (COLOR_ROOM_1, color_room_1, ALPHA_ROOM_1),
311
+ (COLOR_ROOM_2, color_room_2, ALPHA_ROOM_2),
312
+ (COLOR_ROOM_3, color_room_3, ALPHA_ROOM_3),
313
+ (COLOR_ROOM_4, color_room_4, ALPHA_ROOM_4),
314
+ (COLOR_ROOM_5, color_room_5, ALPHA_ROOM_5),
315
+ (COLOR_ROOM_6, color_room_6, ALPHA_ROOM_6),
316
+ (COLOR_ROOM_7, color_room_7, ALPHA_ROOM_7),
317
+ (COLOR_ROOM_8, color_room_8, ALPHA_ROOM_8),
318
+ (COLOR_ROOM_9, color_room_9, ALPHA_ROOM_9),
319
+ (COLOR_ROOM_10, color_room_10, ALPHA_ROOM_10),
320
+ (COLOR_ROOM_11, color_room_11, ALPHA_ROOM_11),
321
+ (COLOR_ROOM_12, color_room_12, ALPHA_ROOM_12),
322
+ (COLOR_ROOM_13, color_room_13, ALPHA_ROOM_13),
323
+ (COLOR_ROOM_14, color_room_14, ALPHA_ROOM_14),
324
+ (COLOR_ROOM_15, color_room_15, ALPHA_ROOM_15),
325
+ ]
326
+
327
+ # Extract user colors and alphas efficiently
328
+ user_colors = [
329
+ device_info.get(color_key, default_color)
330
+ for color_key, default_color, _ in base_color_keys
331
+ ]
332
+ user_alpha = [
333
+ device_info.get(alpha_key, 255) for _, _, alpha_key in base_color_keys
334
+ ]
335
+
336
+ # Extract room colors and alphas efficiently
337
+ rooms_colors = [
338
+ device_info.get(color_key, default_color)
339
+ for color_key, default_color, _ in room_color_keys
340
+ ]
341
+ rooms_alpha = [
342
+ device_info.get(alpha_key, 255) for _, _, alpha_key in room_color_keys
343
+ ]
344
+
345
+ # Use our optimized add_alpha_to_rgb method
346
+ self.shared_var.update_user_colors(
347
+ self.add_alpha_to_rgb(user_alpha, user_colors)
348
+ )
349
+ self.shared_var.update_rooms_colors(
350
+ self.add_alpha_to_rgb(rooms_alpha, rooms_colors)
351
+ )
352
+
353
+ # Clear the color cache after initialization
354
+ self.color_cache.clear()
355
+
356
+ except (ValueError, IndexError, UnboundLocalError) as e:
357
+ LOGGER.warning("Error while populating colors: %s", e)
358
+
359
+ def initialize_user_colors(self, device_info: dict) -> List[Color]:
360
+ """
361
+ Initialize user-defined colors with defaults as fallback.
362
+ :param device_info: Dictionary containing user-defined colors.
363
+ :return: List of RGBA colors for map elements.
364
+ """
365
+ colors = []
366
+ for key in SupportedColor:
367
+ if key.startswith(SupportedColor.COLOR_ROOM_PREFIX):
368
+ continue # Skip room colors for user_colors
369
+ rgb = device_info.get(key, DefaultColors.COLORS_RGB.get(key))
370
+ alpha = device_info.get(
371
+ f"alpha_{key}", DefaultColors.DEFAULT_ALPHA.get(f"alpha_{key}")
372
+ )
373
+ colors.append(self.add_alpha_to_color(rgb, alpha))
374
+ return colors
375
+
376
+ def initialize_rooms_colors(self, device_info: dict) -> List[Color]:
377
+ """
378
+ Initialize room colors with defaults as fallback.
379
+ :param device_info: Dictionary containing user-defined room colors.
380
+ :return: List of RGBA colors for rooms.
381
+ """
382
+ colors = []
383
+ for i in range(16):
384
+ rgb = device_info.get(
385
+ SupportedColor.room_key(i),
386
+ DefaultColors.DEFAULT_ROOM_COLORS.get(SupportedColor.room_key(i)),
387
+ )
388
+ alpha = device_info.get(
389
+ f"alpha_room_{i}", DefaultColors.DEFAULT_ALPHA.get(f"alpha_room_{i}")
390
+ )
391
+ colors.append(self.add_alpha_to_color(rgb, alpha))
392
+ return colors
393
+
394
+ @staticmethod
395
+ def add_alpha_to_color(rgb: Tuple[int, int, int], alpha: float) -> Color:
396
+ """
397
+ Convert RGB to RGBA by appending the alpha value.
398
+ :param rgb: RGB values.
399
+ :param alpha: Alpha value (0.0 to 255.0).
400
+ :return: RGBA color.
401
+ """
402
+ return (*rgb, int(alpha)) if rgb else (0, 0, 0, int(alpha))
403
+
404
+ def get_user_colors(self) -> List[Color]:
405
+ """Return the list of RGBA colors for user-defined map elements."""
406
+ return self.user_colors
407
+
408
+ def get_rooms_colors(self) -> List[Color]:
409
+ """Return the list of RGBA colors for rooms."""
410
+ return self.rooms_colors