python-roborock 4.1.1__tar.gz → 4.2.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 (96) hide show
  1. {python_roborock-4.1.1 → python_roborock-4.2.1}/PKG-INFO +2 -2
  2. {python_roborock-4.1.1 → python_roborock-4.2.1}/pyproject.toml +2 -2
  3. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/cli.py +28 -6
  4. python_roborock-4.2.1/roborock/devices/README.md +41 -0
  5. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/device.py +1 -1
  6. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/device_manager.py +4 -6
  7. python_roborock-4.2.1/roborock/devices/rpc/__init__.py +14 -0
  8. {python_roborock-4.1.1/roborock/devices → python_roborock-4.2.1/roborock/devices/rpc}/a01_channel.py +1 -2
  9. python_roborock-4.2.1/roborock/devices/rpc/b01_q10_channel.py +36 -0
  10. {python_roborock-4.1.1/roborock/devices → python_roborock-4.2.1/roborock/devices/rpc}/b01_q7_channel.py +2 -3
  11. {python_roborock-4.1.1/roborock/devices → python_roborock-4.2.1/roborock/devices/rpc}/v1_channel.py +4 -5
  12. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/a01/__init__.py +2 -2
  13. python_roborock-4.2.1/roborock/devices/traits/b01/__init__.py +12 -0
  14. python_roborock-4.2.1/roborock/devices/traits/b01/q10/__init__.py +29 -0
  15. python_roborock-4.2.1/roborock/devices/traits/b01/q10/command.py +32 -0
  16. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/b01/q7/__init__.py +2 -2
  17. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/traits_mixin.py +3 -0
  18. python_roborock-4.2.1/roborock/devices/transport/__init__.py +8 -0
  19. {python_roborock-4.1.1/roborock/devices → python_roborock-4.2.1/roborock/devices/transport}/local_channel.py +2 -2
  20. python_roborock-4.1.1/roborock/devices/README.md +0 -669
  21. python_roborock-4.1.1/roborock/devices/traits/b01/__init__.py +0 -5
  22. python_roborock-4.1.1/roborock/devices/traits/b01/q10/__init__.py +0 -1
  23. {python_roborock-4.1.1 → python_roborock-4.2.1}/.gitignore +0 -0
  24. {python_roborock-4.1.1 → python_roborock-4.2.1}/LICENSE +0 -0
  25. {python_roborock-4.1.1 → python_roborock-4.2.1}/README.md +0 -0
  26. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/__init__.py +0 -0
  27. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/broadcast_protocol.py +0 -0
  28. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/callbacks.py +0 -0
  29. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/const.py +0 -0
  30. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/__init__.py +0 -0
  31. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/b01_q10/__init__.py +0 -0
  32. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/b01_q10/b01_q10_code_mappings.py +0 -0
  33. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/b01_q10/b01_q10_containers.py +0 -0
  34. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/b01_q7/__init__.py +0 -0
  35. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/b01_q7/b01_q7_code_mappings.py +0 -0
  36. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/b01_q7/b01_q7_containers.py +0 -0
  37. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/code_mappings.py +0 -0
  38. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/containers.py +0 -0
  39. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/dyad/__init__.py +0 -0
  40. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/dyad/dyad_code_mappings.py +0 -0
  41. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/dyad/dyad_containers.py +0 -0
  42. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/v1/__init__.py +0 -0
  43. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/v1/v1_clean_modes.py +0 -0
  44. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/v1/v1_code_mappings.py +0 -0
  45. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/v1/v1_containers.py +0 -0
  46. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/zeo/__init__.py +0 -0
  47. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/zeo/zeo_code_mappings.py +0 -0
  48. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/data/zeo/zeo_containers.py +0 -0
  49. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/device_features.py +0 -0
  50. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/__init__.py +0 -0
  51. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/cache.py +0 -0
  52. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/file_cache.py +0 -0
  53. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/__init__.py +0 -0
  54. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/__init__.py +0 -0
  55. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/child_lock.py +0 -0
  56. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/clean_summary.py +0 -0
  57. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/command.py +0 -0
  58. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/common.py +0 -0
  59. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/consumeable.py +0 -0
  60. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/device_features.py +0 -0
  61. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/do_not_disturb.py +0 -0
  62. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/dust_collection_mode.py +0 -0
  63. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/flow_led_status.py +0 -0
  64. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/home.py +0 -0
  65. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/led_status.py +0 -0
  66. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/map_content.py +0 -0
  67. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/maps.py +0 -0
  68. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/network_info.py +0 -0
  69. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/rooms.py +0 -0
  70. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/routines.py +0 -0
  71. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/smart_wash_params.py +0 -0
  72. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/status.py +0 -0
  73. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/valley_electricity_timer.py +0 -0
  74. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/volume.py +0 -0
  75. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/devices/traits/v1/wash_towel_mode.py +0 -0
  76. {python_roborock-4.1.1/roborock/devices → python_roborock-4.2.1/roborock/devices/transport}/channel.py +0 -0
  77. {python_roborock-4.1.1/roborock/devices → python_roborock-4.2.1/roborock/devices/transport}/mqtt_channel.py +0 -0
  78. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/diagnostics.py +0 -0
  79. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/exceptions.py +0 -0
  80. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/map/__init__.py +0 -0
  81. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/map/map_parser.py +0 -0
  82. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/mqtt/__init__.py +0 -0
  83. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/mqtt/health_manager.py +0 -0
  84. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/mqtt/roborock_session.py +0 -0
  85. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/mqtt/session.py +0 -0
  86. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/protocol.py +0 -0
  87. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/protocols/__init__.py +0 -0
  88. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/protocols/a01_protocol.py +0 -0
  89. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/protocols/b01_q10_protocol.py +0 -0
  90. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/protocols/b01_q7_protocol.py +0 -0
  91. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/protocols/v1_protocol.py +0 -0
  92. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/py.typed +0 -0
  93. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/roborock_message.py +0 -0
  94. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/roborock_typing.py +0 -0
  95. {python_roborock-4.1.1 → python_roborock-4.2.1}/roborock/util.py +0 -0
  96. {python_roborock-4.1.1 → python_roborock-4.2.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.1.1
3
+ Version: 4.2.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/
@@ -16,7 +16,7 @@ Classifier: Operating System :: OS Independent
16
16
  Classifier: Topic :: Software Development :: Libraries
17
17
  Requires-Python: <4,>=3.11
18
18
  Requires-Dist: aiohttp<4,>=3.8.2
19
- Requires-Dist: aiomqtt<3,>=2.3.2
19
+ Requires-Dist: aiomqtt<3,>=2.5.0
20
20
  Requires-Dist: click-shell~=2.1
21
21
  Requires-Dist: click>=8
22
22
  Requires-Dist: construct<3,>=2.10.57
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-roborock"
3
- version = "4.1.1"
3
+ version = "4.2.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"
@@ -27,7 +27,7 @@ dependencies = [
27
27
  "construct>=2.10.57,<3",
28
28
  "vacuum-map-parser-roborock",
29
29
  "pyrate-limiter>=3.7.0,<4",
30
- "aiomqtt>=2.3.2,<3",
30
+ "aiomqtt>=2.5.0,<3",
31
31
  "click-shell~=2.1",
32
32
  ]
33
33
 
@@ -43,6 +43,7 @@ from pyshark.packet.packet import Packet # type: ignore
43
43
 
44
44
  from roborock import RoborockCommand
45
45
  from roborock.data import RoborockBase, UserData
46
+ from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
46
47
  from roborock.device_features import DeviceFeatures
47
48
  from roborock.devices.cache import Cache, CacheData
48
49
  from roborock.devices.device import RoborockDevice
@@ -745,6 +746,21 @@ async def network_info(ctx, device_id: str):
745
746
  await _display_v1_trait(context, device_id, lambda v1: v1.network_info)
746
747
 
747
748
 
749
+ def _parse_b01_q10_command(cmd: str) -> B01_Q10_DP:
750
+ """Parse B01_Q10 command from either enum name or value."""
751
+ try:
752
+ return B01_Q10_DP(int(cmd))
753
+ except ValueError:
754
+ try:
755
+ return B01_Q10_DP.from_name(cmd)
756
+ except ValueError:
757
+ try:
758
+ return B01_Q10_DP.from_value(cmd)
759
+ except ValueError:
760
+ pass
761
+ raise RoborockException(f"Invalid command {cmd} for B01_Q10 device")
762
+
763
+
748
764
  @click.command()
749
765
  @click.option("--device_id", required=True)
750
766
  @click.option("--cmd", required=True)
@@ -755,12 +771,18 @@ async def command(ctx, cmd, device_id, params):
755
771
  context: RoborockContext = ctx.obj
756
772
  device_manager = await context.get_device_manager()
757
773
  device = await device_manager.get_device(device_id)
758
- if device.v1_properties is None:
759
- raise RoborockException(f"Device {device.name} does not support V1 protocol")
760
- command_trait: Trait = device.v1_properties.command
761
- result = await command_trait.send(cmd, json.loads(params) if params is not None else None)
762
- if result:
763
- click.echo(dump_json(result))
774
+ if device.v1_properties is not None:
775
+ command_trait: Trait = device.v1_properties.command
776
+ result = await command_trait.send(cmd, json.loads(params) if params is not None else None)
777
+ if result:
778
+ click.echo(dump_json(result))
779
+ elif device.b01_q10_properties is not None:
780
+ cmd_value = _parse_b01_q10_command(cmd)
781
+ command_trait: Trait = device.b01_q10_properties.command
782
+ await command_trait.send(cmd_value, json.loads(params) if params is not None else None)
783
+ click.echo("Command sent successfully; Enable debug logging (-d) to see responses.")
784
+ # Q10 commands don't have a specific time to respond, so wait a bit and log
785
+ await asyncio.sleep(5)
764
786
 
765
787
 
766
788
  @click.command()
@@ -0,0 +1,41 @@
1
+ # Roborock Device Manager
2
+
3
+ This library provides a high-level interface for discovering and controlling Roborock devices. It abstracts the underlying communication protocols (MQTT, Local TCP) and provides a unified `DeviceManager` for interacting with your devices.
4
+
5
+ For internal architecture details, protocol specifications, and design documentation, please refer to [docs/DEVICES.md](https://github.com/python-roborock/python-roborock/docs/DEVICES.md).
6
+
7
+ ## Getting Started
8
+
9
+ ### Credentials
10
+
11
+ To connect to your devices, you first need to obtain your user data (including the `rriot` token) from the Roborock Cloud. This is handled via the `RoborockApiClient`.
12
+
13
+ ## Usage Guide
14
+
15
+ The core entry point for the library is the `DeviceManager`. It handles:
16
+ 1. **Device Discovery**: Fetching the list of devices associated with your account.
17
+ 2. **Connection Management**: Automatically determining the best connection method (Local vs MQTT) and protocol version (V1 vs A01/B01).
18
+ 3. **Command Execution**: Sending commands and query status.
19
+
20
+ ### Example
21
+
22
+ See [examples/example.py](https://github.com/python-roborock/python-roborock/examples/example.py) for a complete example of how to login, create a device manager, and list the status of your vacuums.
23
+
24
+ ### Device Properties
25
+
26
+ Different devices support different property sets:
27
+
28
+ * **`v1_properties`**: Primarily for Vacuum Robots (S7, S8, Q5, etc.). Supports traits like `status`, `consumables`, `fan_power`, `water_box`.
29
+ * **`a01_properties`**: For Washer/Dryers and handheld Wet/Dry Vacuums (Dyad, Zeo) that use another newer protocol.
30
+ * **`b01_q7_properties`** and **`b01_q10_properties`**: For newer Vacuum/Mop devices using newer protocol instead of v1.
31
+
32
+ You can check if a property set is available by checking if the property on the device object is not `None` (e.g. `if device.v1_properties:`).
33
+
34
+ ### Caching
35
+
36
+ Use `FileCache` or your own `Cache` implementation to persist:
37
+ - `HomeData`: The list of your home's rooms and devices.
38
+ - `NetworkingInfo`: Device IP addresses and tokens.
39
+ - `Device Capabilities`: What features your specific model supports.
40
+
41
+ This speeds up startup time and reduces load on the Roborock cloud APIs.
@@ -18,9 +18,9 @@ from roborock.exceptions import RoborockException
18
18
  from roborock.roborock_message import RoborockMessage
19
19
  from roborock.util import RoborockLoggerAdapter
20
20
 
21
- from .channel import Channel
22
21
  from .traits import Trait
23
22
  from .traits.traits_mixin import TraitsMixin
23
+ from .transport.channel import Channel
24
24
 
25
25
  _LOGGER = logging.getLogger(__name__)
26
26
 
@@ -25,10 +25,10 @@ from roborock.protocol import create_mqtt_params
25
25
  from roborock.web_api import RoborockApiClient, UserWebApiClient
26
26
 
27
27
  from .cache import Cache, DeviceCache, NoCache
28
- from .channel import Channel
29
- from .mqtt_channel import create_mqtt_channel
28
+ from .rpc.v1_channel import create_v1_channel
30
29
  from .traits import Trait, a01, b01, v1
31
- from .v1_channel import create_v1_channel
30
+ from .transport.channel import Channel
31
+ from .transport.mqtt_channel import create_mqtt_channel
32
32
 
33
33
  _LOGGER = logging.getLogger(__name__)
34
34
 
@@ -242,9 +242,7 @@ async def create_device_manager(
242
242
  channel = create_mqtt_channel(user_data, mqtt_params, mqtt_session, device)
243
243
  model_part = product.model.split(".")[-1]
244
244
  if "ss" in model_part:
245
- raise UnsupportedDeviceError(
246
- f"Device {device.name} has unsupported version B01 product model {product.model}"
247
- )
245
+ trait = b01.q10.create(channel)
248
246
  elif "sc" in model_part:
249
247
  # Q7 devices start with 'sc' in their model naming.
250
248
  trait = b01.q7.create(channel)
@@ -0,0 +1,14 @@
1
+ """Module for sending device specific commands to Roborock devices.
2
+
3
+ This module provides a application-level interface for sending commands to Roborock
4
+ devices. These modules can be used by traits (higher level APIs) to send commands.
5
+
6
+ Each module may contain details that are common across all traits, and may depend
7
+ on the transport level modules (e.g. MQTT, Local device) for issuing the
8
+ commands.
9
+
10
+ The lowest level protocol encoding is handled in `roborock.protocols` which
11
+ have no dependencies on the transport level modules.
12
+ """
13
+
14
+ __all__: list[str] = []
@@ -5,6 +5,7 @@ import logging
5
5
  from collections.abc import Callable
6
6
  from typing import Any, overload
7
7
 
8
+ from roborock.devices.transport.mqtt_channel import MqttChannel
8
9
  from roborock.exceptions import RoborockException
9
10
  from roborock.protocols.a01_protocol import (
10
11
  decode_rpc_response,
@@ -16,8 +17,6 @@ from roborock.roborock_message import (
16
17
  RoborockZeoProtocol,
17
18
  )
18
19
 
19
- from .mqtt_channel import MqttChannel
20
-
21
20
  _LOGGER = logging.getLogger(__name__)
22
21
  _TIMEOUT = 10.0
23
22
 
@@ -0,0 +1,36 @@
1
+ """Thin wrapper around the MQTT channel for Roborock B01 Q10 devices."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+
7
+ from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
8
+ from roborock.devices.transport.mqtt_channel import MqttChannel
9
+ from roborock.exceptions import RoborockException
10
+ from roborock.protocols.b01_q10_protocol import (
11
+ ParamsType,
12
+ encode_mqtt_payload,
13
+ )
14
+
15
+ _LOGGER = logging.getLogger(__name__)
16
+
17
+
18
+ async def send_command(
19
+ mqtt_channel: MqttChannel,
20
+ command: B01_Q10_DP,
21
+ params: ParamsType,
22
+ ) -> None:
23
+ """Send a command on the MQTT channel, without waiting for a response"""
24
+ _LOGGER.debug("Sending B01 MQTT command: cmd=%s params=%s", command, params)
25
+ roborock_message = encode_mqtt_payload(command, params)
26
+ _LOGGER.debug("Sending MQTT message: %s", roborock_message)
27
+ try:
28
+ await mqtt_channel.publish(roborock_message)
29
+ except RoborockException as ex:
30
+ _LOGGER.debug(
31
+ "Error sending B01 decoded command (method=%s params=%s): %s",
32
+ command,
33
+ params,
34
+ ex,
35
+ )
36
+ raise
@@ -1,4 +1,4 @@
1
- """Thin wrapper around the MQTT channel for Roborock B01 devices."""
1
+ """Thin wrapper around the MQTT channel for Roborock B01 Q7 devices."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -7,6 +7,7 @@ import json
7
7
  import logging
8
8
  from typing import Any
9
9
 
10
+ from roborock.devices.transport.mqtt_channel import MqttChannel
10
11
  from roborock.exceptions import RoborockException
11
12
  from roborock.protocols.b01_q7_protocol import (
12
13
  Q7RequestMessage,
@@ -15,8 +16,6 @@ from roborock.protocols.b01_q7_protocol import (
15
16
  )
16
17
  from roborock.roborock_message import RoborockMessage
17
18
 
18
- from .mqtt_channel import MqttChannel
19
-
20
19
  _LOGGER = logging.getLogger(__name__)
21
20
  _TIMEOUT = 10.0
22
21
 
@@ -12,6 +12,10 @@ from dataclasses import dataclass
12
12
  from typing import Any, TypeVar
13
13
 
14
14
  from roborock.data import HomeDataDevice, NetworkInfo, RoborockBase, UserData
15
+ from roborock.devices.cache import DeviceCache
16
+ from roborock.devices.transport.channel import Channel
17
+ from roborock.devices.transport.local_channel import LocalChannel, LocalSession, create_local_session
18
+ from roborock.devices.transport.mqtt_channel import MqttChannel
15
19
  from roborock.exceptions import RoborockException
16
20
  from roborock.mqtt.health_manager import HealthManager
17
21
  from roborock.mqtt.session import MqttParams, MqttSession
@@ -32,11 +36,6 @@ from roborock.roborock_message import RoborockMessage, RoborockMessageProtocol
32
36
  from roborock.roborock_typing import RoborockCommand
33
37
  from roborock.util import RoborockLoggerAdapter
34
38
 
35
- from .cache import DeviceCache
36
- from .channel import Channel
37
- from .local_channel import LocalChannel, LocalSession, create_local_session
38
- from .mqtt_channel import MqttChannel
39
-
40
39
  _LOGGER = logging.getLogger(__name__)
41
40
 
42
41
  __all__ = [
@@ -48,9 +48,9 @@ from roborock.data.zeo.zeo_code_mappings import (
48
48
  ZeoState,
49
49
  ZeoTemperature,
50
50
  )
51
- from roborock.devices.a01_channel import send_decoded_command
52
- from roborock.devices.mqtt_channel import MqttChannel
51
+ from roborock.devices.rpc.a01_channel import send_decoded_command
53
52
  from roborock.devices.traits import Trait
53
+ from roborock.devices.transport.mqtt_channel import MqttChannel
54
54
  from roborock.roborock_message import RoborockDyadDataProtocol, RoborockZeoProtocol
55
55
 
56
56
  __init__ = [
@@ -0,0 +1,12 @@
1
+ """Traits for B01 devices."""
2
+
3
+ from . import q7, q10
4
+ from .q7 import Q7PropertiesApi
5
+ from .q10 import Q10PropertiesApi
6
+
7
+ __all__ = [
8
+ "Q7PropertiesApi",
9
+ "Q10PropertiesApi",
10
+ "q7",
11
+ "q10",
12
+ ]
@@ -0,0 +1,29 @@
1
+ """Traits for Q10 B01 devices."""
2
+
3
+ from typing import Any
4
+
5
+ from roborock.devices.rpc.b01_q7_channel import send_decoded_command
6
+ from roborock.devices.traits import Trait
7
+ from roborock.devices.transport.mqtt_channel import MqttChannel
8
+
9
+ from .command import CommandTrait
10
+
11
+ __all__ = [
12
+ "Q10PropertiesApi",
13
+ ]
14
+
15
+
16
+ class Q10PropertiesApi(Trait):
17
+ """API for interacting with B01 devices."""
18
+
19
+ command: CommandTrait
20
+ """Trait for sending commands to Q10 devices."""
21
+
22
+ def __init__(self, channel: MqttChannel) -> None:
23
+ """Initialize the B01Props API."""
24
+ self.command = CommandTrait(channel)
25
+
26
+
27
+ def create(channel: MqttChannel) -> Q10PropertiesApi:
28
+ """Create traits for B01 devices."""
29
+ return Q10PropertiesApi(channel)
@@ -0,0 +1,32 @@
1
+ from typing import Any
2
+
3
+ from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP
4
+ from roborock.devices.rpc.b01_q10_channel import send_command
5
+ from roborock.devices.transport.mqtt_channel import MqttChannel
6
+ from roborock.protocols.b01_q10_protocol import ParamsType
7
+
8
+
9
+ class CommandTrait:
10
+ """Trait for sending commands to Q10 Roborock devices.
11
+
12
+ This trait allows sending raw commands directly to the device. It is particularly
13
+ useful for accessing features that do not have their own traits. Generally
14
+ it is preferred to use specific traits for device functionality when
15
+ available.
16
+ """
17
+
18
+ def __init__(self, channel: MqttChannel) -> None:
19
+ """Initialize the CommandTrait."""
20
+ self._channel = channel
21
+
22
+ async def send(self, command: B01_Q10_DP, params: ParamsType = None) -> Any:
23
+ """Send a command to the device.
24
+
25
+ Sending a raw command to the device using this method does not update
26
+ the internal state of any other traits. It is the responsibility of the
27
+ caller to ensure that any traits affected by the command are refreshed
28
+ as needed.
29
+ """
30
+ if not self._channel:
31
+ raise ValueError("Device trait in invalid state")
32
+ return await send_command(self._channel, command, params=params)
@@ -10,9 +10,9 @@ from roborock.data.b01_q7.b01_q7_code_mappings import (
10
10
  SCWindMapping,
11
11
  WaterLevelMapping,
12
12
  )
13
- from roborock.devices.b01_q7_channel import send_decoded_command
14
- from roborock.devices.mqtt_channel import MqttChannel
13
+ from roborock.devices.rpc.b01_q7_channel import send_decoded_command
15
14
  from roborock.devices.traits import Trait
15
+ from roborock.devices.transport.mqtt_channel import MqttChannel
16
16
  from roborock.protocols.b01_q7_protocol import CommandType, ParamsType, Q7RequestMessage
17
17
  from roborock.roborock_message import RoborockB01Props
18
18
  from roborock.roborock_typing import RoborockB01Q7Methods
@@ -34,6 +34,9 @@ class TraitsMixin:
34
34
  b01_q7_properties: b01.Q7PropertiesApi | None = None
35
35
  """B01 Q7 properties trait, if supported."""
36
36
 
37
+ b01_q10_properties: b01.Q10PropertiesApi | None = None
38
+ """B01 Q10 properties trait, if supported."""
39
+
37
40
  def __init__(self, trait: Trait) -> None:
38
41
  """Initialize the TraitsMixin with the given trait.
39
42
 
@@ -0,0 +1,8 @@
1
+ """Module for handling network connections to Roborock devices.
2
+
3
+ This is used internally by the device manager for creating connections to
4
+ Roborock devices. These modules contain common code, not specific to a
5
+ particular device or application level protocol.
6
+ """
7
+
8
+ __all__: list[str] = []
@@ -8,10 +8,10 @@ from dataclasses import dataclass
8
8
  from roborock.callbacks import CallbackList, decoder_callback
9
9
  from roborock.exceptions import RoborockConnectionException, RoborockException
10
10
  from roborock.protocol import create_local_decoder, create_local_encoder
11
+ from roborock.protocols.v1_protocol import LocalProtocolVersion
11
12
  from roborock.roborock_message import RoborockMessage, RoborockMessageProtocol
13
+ from roborock.util import RoborockLoggerAdapter, get_next_int
12
14
 
13
- from ..protocols.v1_protocol import LocalProtocolVersion
14
- from ..util import RoborockLoggerAdapter, get_next_int
15
15
  from .channel import Channel
16
16
 
17
17
  _LOGGER = logging.getLogger(__name__)