valetudo-map-parser 0.1.9b43__py3-none-any.whl → 0.1.9b44__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.
@@ -2,18 +2,16 @@
2
2
 
3
3
  import hashlib
4
4
  import json
5
- import logging
6
- import numpy as np
7
5
  from dataclasses import dataclass
8
- from logging import getLogger
9
- from typing import Callable, Dict, List, Optional, Tuple, Union
6
+ from typing import Callable, List, Optional
10
7
 
8
+ import numpy as np
11
9
  from PIL import ImageOps
12
10
 
13
- from .types import ChargerPosition, ImageSize, NumpyArray, PilPNG, RobotPosition
14
-
15
-
16
- _LOGGER = getLogger(__name__)
11
+ from .drawable import Drawable
12
+ from .drawable_elements import DrawableElement, DrawingConfig
13
+ from .enhanced_drawable import EnhancedDrawable
14
+ from .types import LOGGER, ChargerPosition, ImageSize, NumpyArray, PilPNG, RobotPosition
17
15
 
18
16
 
19
17
  @dataclass
@@ -114,7 +112,7 @@ class BaseHandler:
114
112
  elif rotation in [90, 270]:
115
113
  self.offset_y = (self.crop_img_size[0] - width) // 2
116
114
  self.offset_x = self.crop_img_size[1] - height
117
- _LOGGER.debug(
115
+ LOGGER.debug(
118
116
  "%s Image Coordinates Offsets (x,y): %s. %s",
119
117
  self.file_name,
120
118
  self.offset_x,
@@ -142,7 +140,7 @@ class BaseHandler:
142
140
  self.offset_x = width - self.crop_img_size[0]
143
141
  self.offset_y = height - self.crop_img_size[1]
144
142
 
145
- _LOGGER.debug(
143
+ LOGGER.debug(
146
144
  "%s Image Coordinates Offsets (x,y): %s. %s",
147
145
  self.file_name,
148
146
  self.offset_x,
@@ -173,7 +171,7 @@ class BaseHandler:
173
171
  self.offset_y = (self.crop_img_size[0] - width) // 2
174
172
  self.offset_x = self.crop_img_size[1] - height
175
173
 
176
- _LOGGER.debug(
174
+ LOGGER.debug(
177
175
  "%s Image Coordinates Offsets (x,y): %s. %s",
178
176
  self.file_name,
179
177
  self.offset_x,
@@ -205,7 +203,7 @@ class BaseHandler:
205
203
  self.offset_y = (self.crop_img_size[0] - width) // 2
206
204
  self.offset_x = self.crop_img_size[1] - height
207
205
 
208
- _LOGGER.debug(
206
+ LOGGER.debug(
209
207
  "%s Image Coordinates Offsets (x,y): %s. %s",
210
208
  self.file_name,
211
209
  self.offset_x,
@@ -233,7 +231,7 @@ class BaseHandler:
233
231
  self.offset_x = width - self.crop_img_size[0]
234
232
  self.offset_y = height - self.crop_img_size[1]
235
233
 
236
- _LOGGER.debug(
234
+ LOGGER.debug(
237
235
  "%s Image Coordinates Offsets (x,y): %s. %s",
238
236
  self.file_name,
239
237
  self.offset_x,
@@ -261,7 +259,7 @@ class BaseHandler:
261
259
  self.offset_x = width - self.crop_img_size[0]
262
260
  self.offset_y = height - self.crop_img_size[1]
263
261
 
264
- _LOGGER.debug(
262
+ LOGGER.debug(
265
263
  "%s Image Coordinates Offsets (x,y): %s. %s",
266
264
  self.file_name,
267
265
  self.offset_x,
@@ -446,7 +444,7 @@ class BaseHandler:
446
444
  }
447
445
  id_count += 1
448
446
  if id_count > 1:
449
- _LOGGER.debug("%s: Zones Properties updated.", self.file_name)
447
+ LOGGER.debug("%s: Zones Properties updated.", self.file_name)
450
448
  return zone_properties
451
449
 
452
450
  async def async_points_propriety(self, points_data) -> dict:
@@ -467,7 +465,7 @@ class BaseHandler:
467
465
  }
468
466
  id_count += 1
469
467
  if id_count > 1:
470
- _LOGGER.debug("%s: Point Properties updated.", self.file_name)
468
+ LOGGER.debug("%s: Point Properties updated.", self.file_name)
471
469
  return point_properties
472
470
 
473
471
  @staticmethod
@@ -489,7 +487,7 @@ async def async_resize_image(params: ResizeParams):
489
487
  wsf, hsf = [int(x) for x in params.aspect_ratio.split(",")]
490
488
 
491
489
  if wsf == 0 or hsf == 0 or params.width <= 0 or params.height <= 0:
492
- _LOGGER.warning(
490
+ LOGGER.warning(
493
491
  "Invalid aspect ratio parameters: width=%s, height=%s, wsf=%s, hsf=%s. Returning original image.",
494
492
  params.width,
495
493
  params.height,
@@ -509,8 +507,8 @@ async def async_resize_image(params: ResizeParams):
509
507
  new_width = params.pil_img.width
510
508
  new_height = int(params.pil_img.width / new_aspect_ratio)
511
509
 
512
- _LOGGER.debug("Resizing image to aspect ratio: %s, %s", wsf, hsf)
513
- _LOGGER.debug("New image size: %s x %s", new_width, new_height)
510
+ LOGGER.debug("Resizing image to aspect ratio: %s, %s", wsf, hsf)
511
+ LOGGER.debug("New image size: %s x %s", new_width, new_height)
514
512
 
515
513
  if (params.crop_size is not None) and (params.offset_func is not None):
516
514
  offset = OffsetParams(wsf, hsf, new_width, new_height, params.is_rand)
@@ -544,50 +542,47 @@ def initialize_drawing_config(handler):
544
542
  Returns:
545
543
  Tuple of (DrawingConfig, Drawable, EnhancedDrawable)
546
544
  """
547
- from .drawable import Drawable
548
- from .drawable_elements import DrawableElement, DrawingConfig
549
- from .enhanced_drawable import EnhancedDrawable
550
545
 
551
546
  # Initialize drawing configuration
552
547
  drawing_config = DrawingConfig()
553
548
 
554
- # Get logger from the handler
555
- _LOGGER = logging.getLogger(handler.__class__.__module__)
556
-
557
- if hasattr(handler.shared, "device_info") and handler.shared.device_info is not None:
558
- _LOGGER.info(
549
+ if (
550
+ hasattr(handler.shared, "device_info")
551
+ and handler.shared.device_info is not None
552
+ ):
553
+ LOGGER.info(
559
554
  "%s: Initializing drawing config from device_info", handler.file_name
560
555
  )
561
- _LOGGER.info(
556
+ LOGGER.info(
562
557
  "%s: device_info contains disable_obstacles: %s",
563
558
  handler.file_name,
564
559
  "disable_obstacles" in handler.shared.device_info,
565
560
  )
566
- _LOGGER.info(
561
+ LOGGER.info(
567
562
  "%s: device_info contains disable_path: %s",
568
563
  handler.file_name,
569
564
  "disable_path" in handler.shared.device_info,
570
565
  )
571
- _LOGGER.info(
566
+ LOGGER.info(
572
567
  "%s: device_info contains disable_elements: %s",
573
568
  handler.file_name,
574
569
  "disable_elements" in handler.shared.device_info,
575
570
  )
576
571
 
577
572
  if "disable_obstacles" in handler.shared.device_info:
578
- _LOGGER.info(
573
+ LOGGER.info(
579
574
  "%s: disable_obstacles value: %s",
580
575
  handler.file_name,
581
576
  handler.shared.device_info["disable_obstacles"],
582
577
  )
583
578
  if "disable_path" in handler.shared.device_info:
584
- _LOGGER.info(
579
+ LOGGER.info(
585
580
  "%s: disable_path value: %s",
586
581
  handler.file_name,
587
582
  handler.shared.device_info["disable_path"],
588
583
  )
589
584
  if "disable_elements" in handler.shared.device_info:
590
- _LOGGER.info(
585
+ LOGGER.info(
591
586
  "%s: disable_elements value: %s",
592
587
  handler.file_name,
593
588
  handler.shared.device_info["disable_elements"],
@@ -596,12 +591,12 @@ def initialize_drawing_config(handler):
596
591
  drawing_config.update_from_device_info(handler.shared.device_info)
597
592
 
598
593
  # Verify elements are disabled
599
- _LOGGER.info(
594
+ LOGGER.info(
600
595
  "%s: After initialization, PATH enabled: %s",
601
596
  handler.file_name,
602
597
  drawing_config.is_enabled(DrawableElement.PATH),
603
598
  )
604
- _LOGGER.info(
599
+ LOGGER.info(
605
600
  "%s: After initialization, OBSTACLE enabled: %s",
606
601
  handler.file_name,
607
602
  drawing_config.is_enabled(DrawableElement.OBSTACLE),
@@ -738,7 +733,9 @@ def get_room_at_position(element_map, x, y, room_base=101):
738
733
  return None
739
734
 
740
735
 
741
- def update_element_map_with_robot(element_map, robot_position, robot_element=3, robot_radius=25):
736
+ def update_element_map_with_robot(
737
+ element_map, robot_position, robot_element=3, robot_radius=25
738
+ ):
742
739
  """
743
740
  Update the element map with the robot position.
744
741
 
@@ -762,14 +759,18 @@ def update_element_map_with_robot(element_map, robot_position, robot_element=3,
762
759
  int(robot_position[0] + dx),
763
760
  int(robot_position[1] + dy),
764
761
  )
765
- if (
766
- 0 <= ry < element_map.shape[0]
767
- and 0 <= rx < element_map.shape[1]
768
- ):
762
+ if 0 <= ry < element_map.shape[0] and 0 <= rx < element_map.shape[1]:
769
763
  element_map[ry, rx] = robot_element
770
764
 
771
765
 
772
- def manage_drawable_elements(handler, action, element_code=None, element_codes=None, property_name=None, value=None):
766
+ def manage_drawable_elements(
767
+ handler,
768
+ action,
769
+ element_code=None,
770
+ element_codes=None,
771
+ property_name=None,
772
+ value=None,
773
+ ):
773
774
  """
774
775
  Manage drawable elements (enable, disable, set elements, set properties).
775
776
 
@@ -793,11 +794,15 @@ def manage_drawable_elements(handler, action, element_code=None, element_codes=N
793
794
  handler.drawing_config.disable_element(element_code)
794
795
  elif action == "set_elements" and element_codes is not None:
795
796
  handler.drawing_config.set_elements(element_codes)
796
- elif action == "set_property" and element_code is not None and property_name is not None:
797
+ elif (
798
+ action == "set_property"
799
+ and element_code is not None
800
+ and property_name is not None
801
+ ):
797
802
  handler.drawing_config.set_property(element_code, property_name, value)
798
803
 
799
804
 
800
- def handle_room_outline_error(file_name, room_id, error, logger=None):
805
+ def handle_room_outline_error(file_name, room_id, error):
801
806
  """
802
807
  Handle errors during room outline extraction.
803
808
 
@@ -805,20 +810,22 @@ def handle_room_outline_error(file_name, room_id, error, logger=None):
805
810
  file_name: Name of the file for logging
806
811
  room_id: Room ID for logging
807
812
  error: The error that occurred
808
- logger: Logger instance (optional)
809
813
 
810
814
  Returns:
811
815
  None
812
816
  """
813
- _LOGGER = logger or logging.getLogger(__name__)
814
817
 
815
- _LOGGER.warning(
818
+ LOGGER.warning(
816
819
  "%s: Failed to trace outline for room %s: %s",
817
- file_name, str(room_id), str(error)
820
+ file_name,
821
+ str(room_id),
822
+ str(error),
818
823
  )
819
824
 
820
825
 
821
- async def async_extract_room_outline(room_mask, min_x, min_y, max_x, max_y, file_name, room_id_int, logger=None):
826
+ async def async_extract_room_outline(
827
+ room_mask, min_x, min_y, max_x, max_y, file_name, room_id_int
828
+ ):
822
829
  """
823
830
  Extract the outline of a room from a binary mask.
824
831
 
@@ -830,13 +837,9 @@ async def async_extract_room_outline(room_mask, min_x, min_y, max_x, max_y, file
830
837
  max_y: Maximum y coordinate of the room
831
838
  file_name: Name of the file for logging
832
839
  room_id_int: Room ID for logging
833
- logger: Logger instance (optional)
834
-
835
840
  Returns:
836
841
  List of (x, y) points forming the room outline
837
842
  """
838
- # Use the provided logger or create a new one
839
- _LOGGER = logger or logging.getLogger(__name__)
840
843
 
841
844
  # Get the dimensions of the mask
842
845
  height, width = room_mask.shape
@@ -874,24 +877,33 @@ async def async_extract_room_outline(room_mask, min_x, min_y, max_x, max_y, file
874
877
  is_boundary = False
875
878
  for dy, dx in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
876
879
  ny, nx = y + dy, x + dx
877
- if (ny < 0 or ny >= height or nx < 0 or nx >= width or
878
- room_mask[ny, nx] == 0):
880
+ if (
881
+ ny < 0
882
+ or ny >= height
883
+ or nx < 0
884
+ or nx >= width
885
+ or room_mask[ny, nx] == 0
886
+ ):
879
887
  is_boundary = True
880
888
  break
881
889
  if is_boundary:
882
890
  boundary_points.append((x, y))
883
891
 
884
892
  # Log the number of boundary points found
885
- _LOGGER.debug(
893
+ LOGGER.debug(
886
894
  "%s: Room %s has %d boundary points",
887
- file_name, str(room_id_int), len(boundary_points)
895
+ file_name,
896
+ str(room_id_int),
897
+ len(boundary_points),
888
898
  )
889
899
 
890
900
  # If we found too few boundary points, use the rectangular outline
891
901
  if len(boundary_points) < 8: # Need at least 8 points for a meaningful shape
892
- _LOGGER.debug(
902
+ LOGGER.debug(
893
903
  "%s: Room %s has too few boundary points (%d), using rectangular outline",
894
- file_name, str(room_id_int), len(boundary_points)
904
+ file_name,
905
+ str(room_id_int),
906
+ len(boundary_points),
895
907
  )
896
908
  return rect_outline
897
909
 
@@ -903,7 +915,7 @@ async def async_extract_room_outline(room_mask, min_x, min_y, max_x, max_y, file
903
915
 
904
916
  # Calculate angles from centroid
905
917
  def calculate_angle(point):
906
- return np.arctan2(point[1] - centroid_y, point[0] - centroid_x)
918
+ return np.arctan2(point[1] - int(centroid_y), point[0] - int(centroid_x))
907
919
 
908
920
  # Sort boundary points by angle
909
921
  boundary_points.sort(key=calculate_angle)
@@ -912,10 +924,12 @@ async def async_extract_room_outline(room_mask, min_x, min_y, max_x, max_y, file
912
924
  if len(boundary_points) > 20:
913
925
  # Take every Nth point to simplify
914
926
  step = len(boundary_points) // 20
915
- simplified_outline = [boundary_points[i] for i in range(0, len(boundary_points), step)]
927
+ simplified_outline = [
928
+ boundary_points[i] for i in range(0, len(boundary_points), step)
929
+ ]
916
930
  # Make sure we have at least 8 points
917
931
  if len(simplified_outline) < 8:
918
- simplified_outline = boundary_points[::len(boundary_points)//8]
932
+ simplified_outline = boundary_points[:: len(boundary_points) // 8]
919
933
  else:
920
934
  simplified_outline = boundary_points
921
935
 
@@ -926,16 +940,19 @@ async def async_extract_room_outline(room_mask, min_x, min_y, max_x, max_y, file
926
940
  # Convert NumPy int64 values to regular Python integers
927
941
  simplified_outline = [(int(x), int(y)) for x, y in simplified_outline]
928
942
 
929
- _LOGGER.debug(
943
+ LOGGER.debug(
930
944
  "%s: Room %s outline has %d points",
931
- file_name, str(room_id_int), len(simplified_outline)
945
+ file_name,
946
+ str(room_id_int),
947
+ len(simplified_outline),
932
948
  )
933
949
 
934
950
  return simplified_outline
935
951
 
936
952
  except (ValueError, IndexError, TypeError, ArithmeticError) as e:
937
- _LOGGER.warning(
953
+ LOGGER.warning(
938
954
  "%s: Error tracing room outline: %s. Using rectangular outline instead.",
939
- file_name, str(e)
955
+ file_name,
956
+ str(e),
940
957
  )
941
958
  return rect_outline
@@ -252,27 +252,26 @@ class ImageDraw:
252
252
  except KeyError:
253
253
  _LOGGER.info("%s No obstacle found.", self.file_name)
254
254
  return np_array
255
- else:
256
- obstacle_positions = []
257
- if obstacle_data:
258
- for obstacle in obstacle_data:
259
- label = obstacle.get("metaData", {}).get("label")
260
- points = obstacle.get("points", [])
261
-
262
- if label and points:
263
- obstacle_pos = {
264
- "label": label,
265
- "points": {"x": points[0], "y": points[1]},
266
- }
267
- obstacle_positions.append(obstacle_pos)
268
-
269
- # List of dictionaries containing label and points for each obstacle
270
- # and draw obstacles on the map
271
- if obstacle_positions:
272
- await self.img_h.draw.async_draw_obstacles(
273
- np_array, obstacle_positions, color_no_go
274
- )
275
- return np_array
255
+ obstacle_positions = []
256
+ if obstacle_data:
257
+ for obstacle in obstacle_data:
258
+ label = obstacle.get("metaData", {}).get("label")
259
+ points = obstacle.get("points", [])
260
+
261
+ if label and points:
262
+ obstacle_pos = {
263
+ "label": label,
264
+ "points": {"x": points[0], "y": points[1]},
265
+ }
266
+ obstacle_positions.append(obstacle_pos)
267
+
268
+ # List of dictionaries containing label and points for each obstacle
269
+ # and draw obstacles on the map
270
+ if obstacle_positions:
271
+ await self.img_h.draw.async_draw_obstacles(
272
+ np_array, obstacle_positions, color_no_go
273
+ )
274
+ return np_array
276
275
 
277
276
  async def async_draw_charger(
278
277
  self,
@@ -286,18 +285,17 @@ class ImageDraw:
286
285
  except KeyError:
287
286
  _LOGGER.warning("%s: No charger position found.", self.file_name)
288
287
  return np_array
289
- else:
290
- if charger_pos:
291
- charger_pos = charger_pos[0]["points"]
292
- self.img_h.charger_pos = {
293
- "x": charger_pos[0],
294
- "y": charger_pos[1],
295
- }
296
- np_array = await self.img_h.draw.battery_charger(
297
- np_array, charger_pos[0], charger_pos[1], color_charger
298
- )
299
- return np_array
288
+ if charger_pos:
289
+ charger_pos = charger_pos[0]["points"]
290
+ self.img_h.charger_pos = {
291
+ "x": charger_pos[0],
292
+ "y": charger_pos[1],
293
+ }
294
+ np_array = await self.img_h.draw.battery_charger(
295
+ np_array, charger_pos[0], charger_pos[1], color_charger
296
+ )
300
297
  return np_array
298
+ return np_array
301
299
 
302
300
  async def async_get_json_id(self, my_json: JsonType) -> str | None:
303
301
  """Return the JSON ID from the image."""