python-roborock 7.12.3__tar.gz → 7.13.0__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 (134) hide show
  1. {python_roborock-7.12.3 → python_roborock-7.13.0}/PKG-INFO +1 -1
  2. {python_roborock-7.12.3 → python_roborock-7.13.0}/pyproject.toml +1 -1
  3. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/const.py +2 -0
  4. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/v1/v1_clean_modes.py +21 -3
  5. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/v1/v1_code_mappings.py +1 -0
  6. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/b01_q10_map_parser.py +13 -7
  7. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/b01_q10_render.py +5 -4
  8. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/room_colors.py +17 -9
  9. {python_roborock-7.12.3 → python_roborock-7.13.0}/.gitignore +0 -0
  10. {python_roborock-7.12.3 → python_roborock-7.13.0}/LICENSE +0 -0
  11. {python_roborock-7.12.3 → python_roborock-7.13.0}/README.md +0 -0
  12. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/__init__.py +0 -0
  13. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/broadcast_protocol.py +0 -0
  14. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/callbacks.py +0 -0
  15. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/cli.py +0 -0
  16. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/__init__.py +0 -0
  17. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/b01_q10/__init__.py +0 -0
  18. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  19. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  20. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/b01_q7/__init__.py +0 -0
  21. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  22. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  23. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/code_mappings.py +0 -0
  24. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/containers.py +0 -0
  25. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/dyad/__init__.py +0 -0
  26. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  27. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/dyad/dyad_containers.py +0 -0
  28. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/mower/__init__.py +0 -0
  29. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/mower/mower_code_mappings.py +0 -0
  30. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/mower/mower_containers.py +0 -0
  31. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/v1/__init__.py +0 -0
  32. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/v1/v1_containers.py +0 -0
  33. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/zeo/__init__.py +0 -0
  34. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  35. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/data/zeo/zeo_containers.py +0 -0
  36. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/device_features.py +0 -0
  37. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/README.md +0 -0
  38. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/__init__.py +0 -0
  39. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/cache.py +0 -0
  40. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/device.py +0 -0
  41. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/device_manager.py +0 -0
  42. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/file_cache.py +0 -0
  43. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/rpc/__init__.py +0 -0
  44. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/rpc/a01_channel.py +0 -0
  45. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/rpc/b01_q10_channel.py +0 -0
  46. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/rpc/b01_q7_channel.py +0 -0
  47. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/rpc/v1_channel.py +0 -0
  48. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/__init__.py +0 -0
  49. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/a01/__init__.py +0 -0
  50. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/a01/device_feature.py +0 -0
  51. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/__init__.py +0 -0
  52. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  53. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/button_light.py +0 -0
  54. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/child_lock.py +0 -0
  55. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/clean_history.py +0 -0
  56. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/command.py +0 -0
  57. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/common.py +0 -0
  58. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/consumable.py +0 -0
  59. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/do_not_disturb.py +0 -0
  60. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/dust_collection.py +0 -0
  61. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/goto.py +0 -0
  62. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/map.py +0 -0
  63. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/maps.py +0 -0
  64. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/network_info.py +0 -0
  65. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/remote.py +0 -0
  66. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/status.py +0 -0
  67. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/vacuum.py +0 -0
  68. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q10/volume.py +0 -0
  69. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  70. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q7/clean_summary.py +0 -0
  71. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q7/map.py +0 -0
  72. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/b01/q7/map_content.py +0 -0
  73. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/common.py +0 -0
  74. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/traits_mixin.py +0 -0
  75. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/__init__.py +0 -0
  76. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/child_lock.py +0 -0
  77. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/clean_summary.py +0 -0
  78. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/command.py +0 -0
  79. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/common.py +0 -0
  80. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/consumeable.py +0 -0
  81. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/device_features.py +0 -0
  82. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  83. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  84. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  85. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/home.py +0 -0
  86. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/led_status.py +0 -0
  87. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/map_content.py +0 -0
  88. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/maps.py +0 -0
  89. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/mop_dryer.py +0 -0
  90. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/network_info.py +0 -0
  91. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/obstacle_photos.py +0 -0
  92. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/rooms.py +0 -0
  93. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/routines.py +0 -0
  94. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  95. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/status.py +0 -0
  96. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  97. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/volume.py +0 -0
  98. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  99. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/transport/__init__.py +0 -0
  100. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/transport/channel.py +0 -0
  101. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/transport/local_channel.py +0 -0
  102. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/devices/transport/mqtt_channel.py +0 -0
  103. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/diagnostics.py +0 -0
  104. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/exceptions.py +0 -0
  105. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/__init__.py +0 -0
  106. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/b01_grid_layers.py +0 -0
  107. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/b01_map_parser.py +0 -0
  108. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/b01_q10_overlays.py +0 -0
  109. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/map_parser.py +0 -0
  110. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/proto/__init__.py +0 -0
  111. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/proto/b01_scmap.proto +0 -0
  112. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/map/proto/b01_scmap_pb2.py +0 -0
  113. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/mqtt/__init__.py +0 -0
  114. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/mqtt/health_manager.py +0 -0
  115. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/mqtt/roborock_session.py +0 -0
  116. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/mqtt/session.py +0 -0
  117. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/protocol.py +0 -0
  118. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/protocols/__init__.py +0 -0
  119. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/protocols/a01_protocol.py +0 -0
  120. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/protocols/b01_q10_protocol.py +0 -0
  121. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/protocols/b01_q7_protocol.py +0 -0
  122. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/protocols/v1_protocol.py +0 -0
  123. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/py.typed +0 -0
  124. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/roborock_message.py +0 -0
  125. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/roborock_typing.py +0 -0
  126. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/testing/__init__.py +0 -0
  127. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/testing/a01_simulator.py +0 -0
  128. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/testing/b01_q10_simulator.py +0 -0
  129. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/testing/channel.py +0 -0
  130. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/testing/cloud.py +0 -0
  131. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/testing/simulator.py +0 -0
  132. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/testing/v1_simulator.py +0 -0
  133. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/util.py +0 -0
  134. {python_roborock-7.12.3 → python_roborock-7.13.0}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: python-roborock
3
- Version: 7.12.3
3
+ Version: 7.13.0
4
4
  Summary: A package to control Roborock vacuums.
5
5
  Project-URL: Repository, https://github.com/python-roborock/python-roborock
6
6
  Project-URL: Documentation, https://python-roborock.readthedocs.io/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-roborock"
3
- version = "7.12.3"
3
+ version = "7.13.0"
4
4
  description = "A package to control Roborock vacuums."
5
5
  authors = [{ name = "humbertogontijo", email = "humbertogontijo@users.noreply.github.com" }, {name="Lash-L"}, {name="allenporter"}]
6
6
  requires-python = ">=3.11, <4"
@@ -47,6 +47,7 @@ ROBOROCK_C1 = "roborock.vacuum.c1"
47
47
  ROBOROCK_S8_PRO_ULTRA = "roborock.vacuum.a70"
48
48
  ROBOROCK_S8 = "roborock.vacuum.a51"
49
49
  ROBOROCK_P10 = "roborock.vacuum.a75" # also known as q_revo
50
+ ROBOROCK_P30_PRO = "roborock.vacuum.a306"
50
51
  ROBOROCK_S8_MAXV_ULTRA = "roborock.vacuum.a97"
51
52
  ROBOROCK_QREVO_S = "roborock.vacuum.a104"
52
53
  ROBOROCK_QREVO_PRO = "roborock.vacuum.a101"
@@ -77,6 +78,7 @@ SUPPORTED_VACUUMS = [
77
78
  ROBOROCK_S4_MAX,
78
79
  ROBOROCK_S7,
79
80
  ROBOROCK_P10,
81
+ ROBOROCK_P30_PRO,
80
82
  ROBOROCK_Q10,
81
83
  ROCKROBO_G10_SG,
82
84
  ]
@@ -55,6 +55,7 @@ class WaterModes(RoborockModeEnum):
55
55
  CUSTOM = ("custom_water_flow", 207)
56
56
  EXTREME = ("extreme", 208)
57
57
  SMART_MODE = ("smart_mode", 209)
58
+ SMART_WATER = ("smart_water", 210)
58
59
  PURE_WATER_FLOW_START = ("slight", 221)
59
60
  PURE_WATER_FLOW_SMALL = ("low", 225)
60
61
  PURE_WATER_FLOW_GENTLE = ("gentle", 230)
@@ -199,14 +200,22 @@ def get_water_modes(features: DeviceFeatures) -> list[WaterModes]:
199
200
 
200
201
  def get_water_slide_mode_name(code: int) -> str | None:
201
202
  """Get the app's range name for a water slide code, or None if out of range."""
203
+ mode = _resolve_water_slide_mode(code)
204
+ return mode.value if mode is not None else None
205
+
206
+
207
+ def _resolve_water_slide_mode(code: int) -> WaterModes | None:
208
+ """Resolve a raw slider code to the water mode for its app range."""
202
209
  if code == 200:
203
- return WaterModes.OFF.value
210
+ return WaterModes.OFF
211
+ if code == WaterModes.SMART_WATER.code:
212
+ return WaterModes.SMART_WATER
204
213
  position = code - 220
205
214
  if position < 1:
206
215
  return None
207
216
  for last_position, mode in _WATER_SLIDE_RANGES:
208
217
  if position <= last_position:
209
- return mode.value
218
+ return mode
210
219
  return None
211
220
 
212
221
 
@@ -300,7 +309,14 @@ def get_cleaning_mode_parameters(cleaning_mode: CleaningMode, features: DeviceFe
300
309
  raise RoborockUnsupportedFeature(f"Cleaning mode {cleaning_mode.value!r} is not supported")
301
310
 
302
311
  fan_power, water_box_mode, mop_mode = _get_clean_motor_mode_params(cleaning_mode, features)
303
- params: dict[str, int] = {"fan_power": fan_power.code, "water_box_mode": water_box_mode.code}
312
+ water_code = water_box_mode.code
313
+ if features.is_water_slide_mode_supported:
314
+ # Aliased water enums retain legacy codes; the device mapping preserves
315
+ # slide-specific wire values without changing the user-facing names.
316
+ water_code = next(
317
+ code for code, name in get_water_mode_mapping(features).items() if name == water_box_mode.value
318
+ )
319
+ params: dict[str, int] = {"fan_power": fan_power.code, "water_box_mode": water_code}
304
320
  if features.is_clean_route_setting_supported:
305
321
  params["mop_mode"] = mop_mode.code
306
322
  return [params]
@@ -337,6 +353,8 @@ def get_current_cleaning_mode(
337
353
  return None
338
354
  clean_mode_enum = _resolve_clean_mode(clean_mode, features)
339
355
  water_mode_enum = _resolve_mode_code(water_mode, WaterModes)
356
+ if features.is_water_slide_mode_supported and isinstance(water_mode, int):
357
+ water_mode_enum = _resolve_water_slide_mode(water_mode) or water_mode_enum
340
358
  mop_mode_enum = _resolve_mode_code(mop_mode, CleanRoutes)
341
359
  if clean_mode_enum is None or water_mode_enum is None:
342
360
  return None
@@ -386,6 +386,7 @@ class RoborockDockTypeCode(RoborockEnum):
386
386
  f1s_dock = 44
387
387
  o7h_dock = 45
388
388
  f1c_dock = 46
389
+ type_49_dock = 49
389
390
 
390
391
 
391
392
  class RoborockDockDustCollectionModeCode(RoborockEnum):
@@ -801,8 +801,8 @@ class B01Q10MapParser:
801
801
  """
802
802
  return self.parsed_from_packet(packet)
803
803
 
804
- def parsed_from_packet(self, packet: Q10MapPacket) -> ParsedMapData:
805
- """Render a (possibly erase-modified) packet into a PNG + ``MapData``."""
804
+ def map_data_from_packet(self, packet: Q10MapPacket) -> MapData:
805
+ """Build MapData with a rendered base image, without PNG serialization."""
806
806
  image = self._render(packet)
807
807
 
808
808
  map_data = MapData()
@@ -830,17 +830,23 @@ class B01Q10MapParser:
830
830
  if packet.carpet_mask is not None:
831
831
  map_data.carpet_map = {i for i, value in enumerate(packet.carpet_mask) if value}
832
832
 
833
+ return map_data
834
+
835
+ def parsed_from_packet(self, packet: Q10MapPacket) -> ParsedMapData:
836
+ """Render a (possibly erase-modified) packet into a PNG + ``MapData``."""
837
+ map_data = self.map_data_from_packet(packet)
833
838
  image_bytes = io.BytesIO()
834
- image.save(image_bytes, format=_MAP_FILE_FORMAT)
839
+ if map_data.image is not None:
840
+ map_data.image.data.save(image_bytes, format=_MAP_FILE_FORMAT)
835
841
  return ParsedMapData(image_content=image_bytes.getvalue(), map_data=map_data)
836
842
 
837
843
  def _render(self, packet: Q10MapPacket) -> Image.Image:
838
844
  """Render the Q10 grid with the V1 map palette."""
839
845
  palette = _build_palette(packet.grid, packet.width)
840
- rgba = bytearray()
841
- for value in packet.grid:
842
- rgba.extend(palette[value])
843
- img = Image.frombytes("RGBA", (packet.width, packet.height), bytes(rgba))
846
+ flat_palette = [channel for color in palette for channel in color]
847
+ p_img = Image.frombytes("P", (packet.width, packet.height), packet.grid)
848
+ p_img.putpalette(flat_palette, rawmode="RGBA")
849
+ img = p_img.convert("RGBA")
844
850
  # The ss07 grid is stored top-down (row 0 = top of the home), so it is
845
851
  # rendered as-is -- unlike the V1/Q7 convention, no vertical flip.
846
852
  scale = self._config.map_scale
@@ -109,10 +109,9 @@ def render_q10_map(
109
109
  # areas disappear (as the app shows).
110
110
  render_packet = erased_packet(packet, cells)
111
111
 
112
- parsed = parser.parsed_from_packet(render_packet)
113
- if parsed.image_content is None or parsed.map_data is None:
112
+ map_data = parser.map_data_from_packet(render_packet)
113
+ if map_data.image is None:
114
114
  raise RoborockException("Failed to render Q10 map image")
115
- map_data = parsed.map_data
116
115
 
117
116
  has_drawables = False
118
117
  if trace_calibration is not None and trace is not None:
@@ -128,7 +127,9 @@ def render_q10_map(
128
127
  if has_drawables:
129
128
  return _draw_map_content(map_data, config=config)
130
129
 
131
- return parsed.image_content
130
+ buffer = io.BytesIO()
131
+ map_data.image.data.save(buffer, format="PNG")
132
+ return buffer.getvalue()
132
133
 
133
134
 
134
135
  def solve_q10_calibration(
@@ -23,23 +23,31 @@ def adjacency_aware_room_colors(
23
23
  if width <= 0:
24
24
  return {}
25
25
 
26
+ lut = [room_id_from_cell(i) for i in range(256)]
26
27
  room_ids: set[int] = set()
27
28
  neighbors: dict[int, set[int]] = {}
28
29
  for index, value in enumerate(grid):
29
- room_id = room_id_from_cell(value)
30
+ room_id = lut[value] if 0 <= value < 256 else room_id_from_cell(value)
30
31
  if room_id is None:
31
32
  continue
32
33
  room_ids.add(room_id)
33
34
  neighbors.setdefault(room_id, set())
34
35
 
35
- for neighbor_index in (index - 1 if index % width else -1, index - width):
36
- if neighbor_index < 0:
37
- continue
38
- neighbor_id = room_id_from_cell(grid[neighbor_index])
39
- if neighbor_id is None or neighbor_id == room_id:
40
- continue
41
- neighbors[room_id].add(neighbor_id)
42
- neighbors.setdefault(neighbor_id, set()).add(room_id)
36
+ if index % width:
37
+ left_val = grid[index - 1]
38
+ if left_val != value:
39
+ neighbor_id = lut[left_val] if 0 <= left_val < 256 else room_id_from_cell(left_val)
40
+ if neighbor_id is not None and neighbor_id != room_id:
41
+ neighbors[room_id].add(neighbor_id)
42
+ neighbors.setdefault(neighbor_id, set()).add(room_id)
43
+
44
+ if index >= width:
45
+ up_val = grid[index - width]
46
+ if up_val != value:
47
+ neighbor_id = lut[up_val] if 0 <= up_val < 256 else room_id_from_cell(up_val)
48
+ if neighbor_id is not None and neighbor_id != room_id:
49
+ neighbors[room_id].add(neighbor_id)
50
+ neighbors.setdefault(neighbor_id, set()).add(room_id)
43
51
 
44
52
  candidates: list[Color] = []
45
53
  for palette_id in map(int, ColorsPalette.ROOM_COLORS):