valetudo-map-parser 0.1.2__py3-none-any.whl → 0.1.3__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.
@@ -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)