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.
- valetudo_map_parser/__init__.py +32 -0
- valetudo_map_parser/config/__init__.py +1 -0
- valetudo_map_parser/config/auto_crop.py +288 -0
- valetudo_map_parser/config/colors.py +178 -0
- valetudo_map_parser/config/drawable.py +561 -0
- valetudo_map_parser/config/shared.py +249 -0
- valetudo_map_parser/config/types.py +590 -0
- valetudo_map_parser/hypfer_draw.py +422 -0
- valetudo_map_parser/hypfer_handler.py +418 -0
- valetudo_map_parser/images_utils.py +398 -0
- valetudo_map_parser/map_data.py +510 -0
- valetudo_map_parser/py.typed +0 -0
- {valetudo_map_parser-0.1.2.dist-info → valetudo_map_parser-0.1.4.dist-info}/METADATA +2 -2
- valetudo_map_parser-0.1.4.dist-info/RECORD +17 -0
- __init__.py +0 -18
- valetudo_map_parser-0.1.2.dist-info/RECORD +0 -6
- {valetudo_map_parser-0.1.2.dist-info → valetudo_map_parser-0.1.4.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.2.dist-info → valetudo_map_parser-0.1.4.dist-info}/NOTICE.txt +0 -0
- {valetudo_map_parser-0.1.2.dist-info → valetudo_map_parser-0.1.4.dist-info}/WHEEL +0 -0
@@ -0,0 +1,249 @@
|
|
1
|
+
"""
|
2
|
+
Class Camera Shared.
|
3
|
+
Keep the data between the modules.
|
4
|
+
Version: v2024.12.0
|
5
|
+
"""
|
6
|
+
|
7
|
+
import asyncio
|
8
|
+
import logging
|
9
|
+
|
10
|
+
from .types import (
|
11
|
+
ATTR_CALIBRATION_POINTS,
|
12
|
+
ATTR_MARGINS,
|
13
|
+
ATTR_POINTS,
|
14
|
+
ATTR_ROOMS,
|
15
|
+
ATTR_ROTATE,
|
16
|
+
ATTR_SNAPSHOT,
|
17
|
+
ATTR_VACUUM_BATTERY,
|
18
|
+
ATTR_VACUUM_JSON_ID,
|
19
|
+
ATTR_VACUUM_POSITION,
|
20
|
+
ATTR_VACUUM_STATUS,
|
21
|
+
ATTR_ZONES,
|
22
|
+
ATTR_CAMERA_MODE,
|
23
|
+
ATTR_OBSTACLES,
|
24
|
+
CONF_ASPECT_RATIO,
|
25
|
+
CONF_AUTO_ZOOM,
|
26
|
+
CONF_OFFSET_BOTTOM,
|
27
|
+
CONF_OFFSET_LEFT,
|
28
|
+
CONF_OFFSET_RIGHT,
|
29
|
+
CONF_OFFSET_TOP,
|
30
|
+
CONF_SNAPSHOTS_ENABLE,
|
31
|
+
CONF_VAC_STAT,
|
32
|
+
CONF_VAC_STAT_FONT,
|
33
|
+
CONF_VAC_STAT_POS,
|
34
|
+
CONF_VAC_STAT_SIZE,
|
35
|
+
CONF_ZOOM_LOCK_RATIO,
|
36
|
+
DEFAULT_VALUES,
|
37
|
+
CameraModes,
|
38
|
+
)
|
39
|
+
from .types import Colors
|
40
|
+
|
41
|
+
_LOGGER = logging.getLogger(__name__)
|
42
|
+
|
43
|
+
|
44
|
+
class CameraShared:
|
45
|
+
"""
|
46
|
+
CameraShared class to keep the data between the classes.
|
47
|
+
Implements a kind of Thread Safe data shared area.
|
48
|
+
"""
|
49
|
+
|
50
|
+
def __init__(self, file_name):
|
51
|
+
self.camera_mode: str = CameraModes.MAP_VIEW # Camera mode
|
52
|
+
self.frame_number: int = 0 # camera Frame number
|
53
|
+
self.destinations: list = [] # MQTT rand destinations
|
54
|
+
self.rand256_active_zone: list = [] # Active zone for rand256
|
55
|
+
self.is_rand: bool = False # MQTT rand data
|
56
|
+
self._new_mqtt_message = False # New MQTT message
|
57
|
+
self.last_image = None # Last image received
|
58
|
+
self.image_size = None # Image size
|
59
|
+
self.image_auto_zoom: bool = False # Auto zoom image
|
60
|
+
self.image_zoom_lock_ratio: bool = True # Zoom lock ratio
|
61
|
+
self.image_ref_height: int = 0 # Image reference height
|
62
|
+
self.image_ref_width: int = 0 # Image reference width
|
63
|
+
self.image_aspect_ratio: str = "None" # Change Image aspect ratio
|
64
|
+
self.image_grab = True # Grab image from MQTT
|
65
|
+
self.image_rotate: int = 0 # Rotate image
|
66
|
+
self.drawing_limit: float = 0.0 # Drawing CPU limit
|
67
|
+
self.current_room = None # Current room of rhe vacuum
|
68
|
+
self.user_colors = Colors # User base colors
|
69
|
+
self.rooms_colors = Colors # Rooms colors
|
70
|
+
self.vacuum_battery = None # Vacuum battery state
|
71
|
+
self.vacuum_bat_charged: bool = True # Vacuum charged and ready
|
72
|
+
self.vacuum_connection = None # Vacuum connection state
|
73
|
+
self.vacuum_state = None # Vacuum state
|
74
|
+
self.charger_position = None # Vacuum Charger position
|
75
|
+
self.show_vacuum_state = None # Show vacuum state on the map
|
76
|
+
self.vacuum_status_font: str = (
|
77
|
+
"custom_components/mqtt_vacuum_camera/utils/fonts/FiraSans.ttf" # Font
|
78
|
+
)
|
79
|
+
self.vacuum_status_size: int = 50 # Vacuum status size
|
80
|
+
self.vacuum_status_position: bool = True # Vacuum status text image top
|
81
|
+
self.snapshot_take = False # Take snapshot
|
82
|
+
self.vacuum_error = None # Vacuum error
|
83
|
+
self.vacuum_api = None # Vacuum API
|
84
|
+
self.vacuum_ips = None # Vacuum IPs
|
85
|
+
self.vac_json_id = None # Vacuum json id
|
86
|
+
self.margins = "100" # Image margins
|
87
|
+
self.obstacles_data = None # Obstacles data
|
88
|
+
self.offset_top = 0 # Image offset top
|
89
|
+
self.offset_down = 0 # Image offset down
|
90
|
+
self.offset_left = 0 # Image offset left
|
91
|
+
self.offset_right = 0 # Image offset right
|
92
|
+
self.export_svg = False # Export SVG
|
93
|
+
self.svg_path = None # SVG Export path
|
94
|
+
self.enable_snapshots = False # Enable snapshots
|
95
|
+
self.file_name = file_name # vacuum friendly name as File name
|
96
|
+
self.attr_calibration_points = None # Calibration points of the image
|
97
|
+
self.map_rooms = None # Rooms data from the vacuum
|
98
|
+
self.map_pred_zones = None # Predefined zones data
|
99
|
+
self.map_pred_points = None # Predefined points data
|
100
|
+
self.map_new_path = None # New path data
|
101
|
+
self.map_old_path = None # Old path data
|
102
|
+
self.trim_crop_data = None
|
103
|
+
self.user_language = None # User language
|
104
|
+
|
105
|
+
def update_user_colors(self, user_colors):
|
106
|
+
"""Update the user colors."""
|
107
|
+
self.user_colors = user_colors
|
108
|
+
|
109
|
+
def get_user_colors(self):
|
110
|
+
"""Get the user colors."""
|
111
|
+
return self.user_colors
|
112
|
+
|
113
|
+
def update_rooms_colors(self, user_colors):
|
114
|
+
"""Update the rooms colors."""
|
115
|
+
self.rooms_colors = user_colors
|
116
|
+
|
117
|
+
def get_rooms_colors(self):
|
118
|
+
"""Get the rooms colors."""
|
119
|
+
return self.rooms_colors
|
120
|
+
|
121
|
+
async def batch_update(self, **kwargs):
|
122
|
+
"""Batch update multiple attributes."""
|
123
|
+
for key, value in kwargs.items():
|
124
|
+
setattr(self, key, value)
|
125
|
+
|
126
|
+
async def batch_get(self, *args):
|
127
|
+
"""Batch get multiple attributes."""
|
128
|
+
return {key: getattr(self, key) for key in args}
|
129
|
+
|
130
|
+
def generate_attributes(self) -> dict:
|
131
|
+
"""Generate and return the shared attribute's dictionary."""
|
132
|
+
attrs = {
|
133
|
+
ATTR_CAMERA_MODE: self.camera_mode,
|
134
|
+
ATTR_VACUUM_BATTERY: f"{self.vacuum_battery}%",
|
135
|
+
ATTR_VACUUM_POSITION: self.current_room,
|
136
|
+
ATTR_VACUUM_STATUS: self.vacuum_state,
|
137
|
+
ATTR_VACUUM_JSON_ID: self.vac_json_id,
|
138
|
+
ATTR_CALIBRATION_POINTS: self.attr_calibration_points,
|
139
|
+
}
|
140
|
+
if self.obstacles_data:
|
141
|
+
attrs[ATTR_OBSTACLES] = self.obstacles_data
|
142
|
+
|
143
|
+
if self.enable_snapshots:
|
144
|
+
attrs[ATTR_SNAPSHOT] = self.snapshot_take
|
145
|
+
else:
|
146
|
+
attrs[ATTR_SNAPSHOT] = False
|
147
|
+
|
148
|
+
# Add dynamic shared attributes if they are available
|
149
|
+
shared_attrs = {
|
150
|
+
ATTR_ROOMS: self.map_rooms,
|
151
|
+
ATTR_ZONES: self.map_pred_zones,
|
152
|
+
ATTR_POINTS: self.map_pred_points,
|
153
|
+
}
|
154
|
+
|
155
|
+
for key, value in shared_attrs.items():
|
156
|
+
if value is not None:
|
157
|
+
attrs[key] = value
|
158
|
+
|
159
|
+
return attrs
|
160
|
+
|
161
|
+
|
162
|
+
class CameraSharedManager:
|
163
|
+
"""Camera Shared Manager class."""
|
164
|
+
|
165
|
+
def __init__(self, file_name, device_info):
|
166
|
+
self._instances = {}
|
167
|
+
self._lock = asyncio.Lock()
|
168
|
+
self.file_name = file_name
|
169
|
+
self.device_info = device_info
|
170
|
+
|
171
|
+
# Automatically initialize shared data for the instance
|
172
|
+
# self._init_shared_data(device_info)
|
173
|
+
|
174
|
+
def update_shared_data(self, device_info):
|
175
|
+
"""Initialize the shared data with device_info."""
|
176
|
+
instance = self.get_instance() # Retrieve the correct instance
|
177
|
+
|
178
|
+
try:
|
179
|
+
instance.attr_calibration_points = None
|
180
|
+
|
181
|
+
# Initialize shared data with defaults from DEFAULT_VALUES
|
182
|
+
instance.offset_top = device_info.get(
|
183
|
+
CONF_OFFSET_TOP, DEFAULT_VALUES["offset_top"]
|
184
|
+
)
|
185
|
+
instance.offset_down = device_info.get(
|
186
|
+
CONF_OFFSET_BOTTOM, DEFAULT_VALUES["offset_bottom"]
|
187
|
+
)
|
188
|
+
instance.offset_left = device_info.get(
|
189
|
+
CONF_OFFSET_LEFT, DEFAULT_VALUES["offset_left"]
|
190
|
+
)
|
191
|
+
instance.offset_right = device_info.get(
|
192
|
+
CONF_OFFSET_RIGHT, DEFAULT_VALUES["offset_right"]
|
193
|
+
)
|
194
|
+
instance.image_auto_zoom = device_info.get(
|
195
|
+
CONF_AUTO_ZOOM, DEFAULT_VALUES["auto_zoom"]
|
196
|
+
)
|
197
|
+
instance.image_zoom_lock_ratio = device_info.get(
|
198
|
+
CONF_ZOOM_LOCK_RATIO, DEFAULT_VALUES["zoom_lock_ratio"]
|
199
|
+
)
|
200
|
+
instance.image_aspect_ratio = device_info.get(
|
201
|
+
CONF_ASPECT_RATIO, DEFAULT_VALUES["aspect_ratio"]
|
202
|
+
)
|
203
|
+
instance.image_rotate = int(
|
204
|
+
device_info.get(ATTR_ROTATE, DEFAULT_VALUES["rotate_image"])
|
205
|
+
)
|
206
|
+
instance.margins = int(
|
207
|
+
device_info.get(ATTR_MARGINS, DEFAULT_VALUES["margins"])
|
208
|
+
)
|
209
|
+
instance.show_vacuum_state = device_info.get(
|
210
|
+
CONF_VAC_STAT, DEFAULT_VALUES["show_vac_status"]
|
211
|
+
)
|
212
|
+
instance.vacuum_status_font = device_info.get(
|
213
|
+
CONF_VAC_STAT_FONT, DEFAULT_VALUES["vac_status_font"]
|
214
|
+
)
|
215
|
+
instance.vacuum_status_size = device_info.get(
|
216
|
+
CONF_VAC_STAT_SIZE, DEFAULT_VALUES["vac_status_size"]
|
217
|
+
)
|
218
|
+
instance.vacuum_status_position = device_info.get(
|
219
|
+
CONF_VAC_STAT_POS, DEFAULT_VALUES["vac_status_position"]
|
220
|
+
)
|
221
|
+
|
222
|
+
# If enable_snapshots, check for png in www.
|
223
|
+
instance.enable_snapshots = device_info.get(
|
224
|
+
CONF_SNAPSHOTS_ENABLE, DEFAULT_VALUES["enable_www_snapshots"]
|
225
|
+
)
|
226
|
+
|
227
|
+
except TypeError as ex:
|
228
|
+
_LOGGER.error("Shared data can't be initialized due to a TypeError! %s", ex)
|
229
|
+
except AttributeError as ex:
|
230
|
+
_LOGGER.error(
|
231
|
+
"Shared data can't be initialized due to an AttributeError! %s", ex
|
232
|
+
)
|
233
|
+
except RuntimeError as ex:
|
234
|
+
_LOGGER.error(
|
235
|
+
"An unexpected error occurred while initializing shared data %s:", ex
|
236
|
+
)
|
237
|
+
|
238
|
+
def get_instance(self):
|
239
|
+
"""Get the shared instance."""
|
240
|
+
if self.file_name not in self._instances:
|
241
|
+
self._instances[self.file_name] = CameraShared(self.file_name)
|
242
|
+
self._instances[self.file_name].file_name = self.file_name
|
243
|
+
return self._instances[self.file_name]
|
244
|
+
|
245
|
+
async def update_instance(self, **kwargs):
|
246
|
+
"""Update the shared instance."""
|
247
|
+
async with self._lock:
|
248
|
+
instance = self.get_instance()
|
249
|
+
await instance.batch_update(**kwargs)
|