python-roborock 4.0.2__tar.gz → 4.1.1__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 (89) hide show
  1. {python_roborock-4.0.2 → python_roborock-4.1.1}/PKG-INFO +1 -1
  2. {python_roborock-4.0.2 → python_roborock-4.1.1}/pyproject.toml +1 -1
  3. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/cli.py +32 -31
  4. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/code_mappings.py +5 -4
  5. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/README.md +0 -2
  6. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/device_manager.py +3 -1
  7. {python_roborock-4.0.2 → python_roborock-4.1.1}/.gitignore +0 -0
  8. {python_roborock-4.0.2 → python_roborock-4.1.1}/LICENSE +0 -0
  9. {python_roborock-4.0.2 → python_roborock-4.1.1}/README.md +0 -0
  10. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/__init__.py +0 -0
  11. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/broadcast_protocol.py +0 -0
  12. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/callbacks.py +0 -0
  13. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/const.py +0 -0
  14. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/__init__.py +0 -0
  15. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/b01_q10/__init__.py +0 -0
  16. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  17. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  18. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/b01_q7/__init__.py +0 -0
  19. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  20. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  21. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/containers.py +0 -0
  22. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/dyad/__init__.py +0 -0
  23. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  24. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/dyad/dyad_containers.py +0 -0
  25. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/v1/__init__.py +0 -0
  26. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/v1/v1_clean_modes.py +0 -0
  27. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/v1/v1_code_mappings.py +0 -0
  28. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/v1/v1_containers.py +0 -0
  29. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/zeo/__init__.py +0 -0
  30. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  31. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/data/zeo/zeo_containers.py +0 -0
  32. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/device_features.py +0 -0
  33. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/__init__.py +0 -0
  34. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/a01_channel.py +0 -0
  35. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/b01_q7_channel.py +0 -0
  36. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/cache.py +0 -0
  37. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/channel.py +0 -0
  38. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/device.py +0 -0
  39. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/file_cache.py +0 -0
  40. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/local_channel.py +0 -0
  41. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/mqtt_channel.py +0 -0
  42. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/__init__.py +0 -0
  43. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/a01/__init__.py +0 -0
  44. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/b01/__init__.py +0 -0
  45. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/b01/q10/__init__.py +0 -0
  46. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/b01/q7/__init__.py +0 -0
  47. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/traits_mixin.py +0 -0
  48. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/__init__.py +0 -0
  49. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/child_lock.py +0 -0
  50. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/clean_summary.py +0 -0
  51. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/command.py +0 -0
  52. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/common.py +0 -0
  53. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/consumeable.py +0 -0
  54. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/device_features.py +0 -0
  55. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  56. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  57. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  58. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/home.py +0 -0
  59. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/led_status.py +0 -0
  60. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/map_content.py +0 -0
  61. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/maps.py +0 -0
  62. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/network_info.py +0 -0
  63. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/rooms.py +0 -0
  64. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/routines.py +0 -0
  65. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  66. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/status.py +0 -0
  67. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  68. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/volume.py +0 -0
  69. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  70. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/devices/v1_channel.py +0 -0
  71. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/diagnostics.py +0 -0
  72. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/exceptions.py +0 -0
  73. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/map/__init__.py +0 -0
  74. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/map/map_parser.py +0 -0
  75. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/mqtt/__init__.py +0 -0
  76. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/mqtt/health_manager.py +0 -0
  77. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/mqtt/roborock_session.py +0 -0
  78. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/mqtt/session.py +0 -0
  79. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/protocol.py +0 -0
  80. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/protocols/__init__.py +0 -0
  81. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/protocols/a01_protocol.py +0 -0
  82. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/protocols/b01_q10_protocol.py +0 -0
  83. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/protocols/b01_q7_protocol.py +0 -0
  84. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/protocols/v1_protocol.py +0 -0
  85. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/py.typed +0 -0
  86. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/roborock_message.py +0 -0
  87. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/roborock_typing.py +0 -0
  88. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/util.py +0 -0
  89. {python_roborock-4.0.2 → python_roborock-4.1.1}/roborock/web_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-roborock
3
- Version: 4.0.2
3
+ Version: 4.1.1
4
4
  Summary: A package to control Roborock vacuums.
5
5
  Project-URL: Repository, https://github.com/humbertogontijo/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 = "4.0.2"
3
+ version = "4.1.1"
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"
@@ -41,8 +41,8 @@ from pyshark import FileCapture # type: ignore
41
41
  from pyshark.capture.live_capture import LiveCapture, UnknownInterfaceException # type: ignore
42
42
  from pyshark.packet.packet import Packet # type: ignore
43
43
 
44
- from roborock import SHORT_MODEL_TO_ENUM, RoborockCommand
45
- from roborock.data import DeviceData, RoborockBase, UserData
44
+ from roborock import RoborockCommand
45
+ from roborock.data import RoborockBase, UserData
46
46
  from roborock.device_features import DeviceFeatures
47
47
  from roborock.devices.cache import Cache, CacheData
48
48
  from roborock.devices.device import RoborockDevice
@@ -53,7 +53,6 @@ from roborock.devices.traits.v1.consumeable import ConsumableAttribute
53
53
  from roborock.devices.traits.v1.map_content import MapContentTrait
54
54
  from roborock.exceptions import RoborockException, RoborockUnsupportedFeature
55
55
  from roborock.protocol import MessageParser
56
- from roborock.version_1_apis.roborock_mqtt_client_v1 import RoborockMqttClientV1
57
56
  from roborock.web_api import RoborockApiClient
58
57
 
59
58
  _LOGGER = logging.getLogger(__name__)
@@ -822,44 +821,46 @@ async def get_device_info(ctx: click.Context):
822
821
  """
823
822
  click.echo("Discovering devices...")
824
823
  context: RoborockContext = ctx.obj
825
- connection_cache = await context.get_devices()
826
-
827
- home_data = connection_cache.cache_data.home_data
828
-
829
- all_devices = home_data.get_all_devices()
830
- if not all_devices:
824
+ device_connection_manager = await context.get_device_manager()
825
+ device_manager = await device_connection_manager.ensure_device_manager()
826
+ devices = await device_manager.get_devices()
827
+ if not devices:
831
828
  click.echo("No devices found.")
832
829
  return
833
830
 
834
- click.echo(f"Found {len(all_devices)} devices. Fetching data...")
831
+ click.echo(f"Found {len(devices)} devices. Fetching data...")
835
832
 
836
833
  all_products_data = {}
837
834
 
838
- for device in all_devices:
835
+ for device in devices:
839
836
  click.echo(f" - Processing {device.name} ({device.duid})")
840
- product_info = home_data.product_map[device.product_id]
841
- device_data = DeviceData(device, product_info.model)
842
- mqtt_client = RoborockMqttClientV1(connection_cache.user_data, device_data)
843
837
 
844
- try:
845
- init_status_result = await mqtt_client.send_command(
846
- RoborockCommand.APP_GET_INIT_STATUS,
847
- )
848
- product_nickname = SHORT_MODEL_TO_ENUM.get(product_info.model.split(".")[-1]).name
849
- current_product_data = {
850
- "Protocol Version": device.pv,
851
- "Product Nickname": product_nickname,
852
- "New Feature Info": init_status_result.get("new_feature_info"),
853
- "New Feature Info Str": init_status_result.get("new_feature_info_str"),
854
- "Feature Info": init_status_result.get("feature_info"),
855
- }
838
+ if device.product.model in all_products_data:
839
+ click.echo(f" - Skipping duplicate model {device.product.model}")
840
+ continue
856
841
 
857
- all_products_data[product_info.model] = current_product_data
842
+ current_product_data = {
843
+ "Protocol Version": device.device_info.pv,
844
+ "Product Nickname": device.product.product_nickname.name,
845
+ }
846
+ if device.v1_properties is not None:
847
+ try:
848
+ result: list[dict[str, Any]] = await device.v1_properties.command.send(
849
+ RoborockCommand.APP_GET_INIT_STATUS
850
+ )
851
+ except Exception as e:
852
+ click.echo(f" - Error processing device {device.name}: {e}", err=True)
853
+ continue
854
+ init_status_result = result[0] if result else {}
855
+ current_product_data.update(
856
+ {
857
+ "New Feature Info": init_status_result.get("new_feature_info"),
858
+ "New Feature Info Str": init_status_result.get("new_feature_info_str"),
859
+ "Feature Info": init_status_result.get("feature_info"),
860
+ }
861
+ )
858
862
 
859
- except Exception as e:
860
- click.echo(f" - Error processing device {device.name}: {e}", err=True)
861
- finally:
862
- await mqtt_client.async_release()
863
+ all_products_data[device.product.model] = current_product_data
863
864
 
864
865
  if all_products_data:
865
866
  click.echo("\n--- Device Information (copy to your YAML file) ---\n")
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import logging
4
4
  from collections import namedtuple
5
5
  from enum import Enum, IntEnum, StrEnum
6
+ from typing import Self
6
7
 
7
8
  _LOGGER = logging.getLogger(__name__)
8
9
  completed_warnings = set()
@@ -57,7 +58,7 @@ class RoborockModeEnum(StrEnum):
57
58
  code: int
58
59
  """The integer code associated with the enum member."""
59
60
 
60
- def __new__(cls, value: str, code: int) -> RoborockModeEnum:
61
+ def __new__(cls, value: str, code: int) -> Self:
61
62
  """Creates a new enum member."""
62
63
  member = str.__new__(cls, value)
63
64
  member._value_ = value
@@ -65,7 +66,7 @@ class RoborockModeEnum(StrEnum):
65
66
  return member
66
67
 
67
68
  @classmethod
68
- def from_code(cls, code: int) -> RoborockModeEnum:
69
+ def from_code(cls, code: int) -> Self:
69
70
  for member in cls:
70
71
  if member.code == code:
71
72
  return member
@@ -83,7 +84,7 @@ class RoborockModeEnum(StrEnum):
83
84
  return None
84
85
 
85
86
  @classmethod
86
- def from_value(cls, value: str) -> RoborockModeEnum:
87
+ def from_value(cls, value: str) -> Self:
87
88
  """Find enum member by string value (case-insensitive)."""
88
89
  for member in cls:
89
90
  if member.value.lower() == value.lower():
@@ -91,7 +92,7 @@ class RoborockModeEnum(StrEnum):
91
92
  raise ValueError(f"{value} is not a valid value for {cls.__name__}")
92
93
 
93
94
  @classmethod
94
- def from_name(cls, name: str) -> RoborockModeEnum:
95
+ def from_name(cls, name: str) -> Self:
95
96
  """Find enum member by name (case-insensitive)."""
96
97
  for member in cls:
97
98
  if member.name.lower() == name.lower():
@@ -556,8 +556,6 @@ The new design:
556
556
  - Clear separation of concerns through layers
557
557
  - Users work with devices, not raw clients
558
558
 
559
- **Note**: Legacy APIs in `version_1_apis/` and `version_a01_apis/` are deprecated and will be removed.
560
-
561
559
 
562
560
  ## Implementation Details
563
561
 
@@ -186,6 +186,7 @@ async def create_device_manager(
186
186
  session: aiohttp.ClientSession | None = None,
187
187
  ready_callback: DeviceReadyCallback | None = None,
188
188
  mqtt_session_unauthorized_hook: SessionUnauthorizedHook | None = None,
189
+ prefer_cache: bool = True,
189
190
  ) -> DeviceManager:
190
191
  """Convenience function to create and initialize a DeviceManager.
191
192
 
@@ -198,6 +199,7 @@ async def create_device_manager(
198
199
  mqtt_session_unauthorized_hook: Optional hook for MQTT session unauthorized
199
200
  events which may indicate rate limiting or revoked credentials. The
200
201
  caller may use this to refresh authentication tokens as needed.
202
+ prefer_cache: Whether to prefer cached device data over always fetching it from the API.
201
203
 
202
204
  Returns:
203
205
  An initialized DeviceManager with discovered devices.
@@ -259,5 +261,5 @@ async def create_device_manager(
259
261
  return dev
260
262
 
261
263
  manager = DeviceManager(web_api, device_creator, mqtt_session=mqtt_session, cache=cache, diagnostics=diagnostics)
262
- await manager.discover_devices()
264
+ await manager.discover_devices(prefer_cache)
263
265
  return manager
File without changes