python-roborock 2.43.0__tar.gz → 2.44.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.
- {python_roborock-2.43.0 → python_roborock-2.44.0}/PKG-INFO +1 -1
- {python_roborock-2.43.0 → python_roborock-2.44.0}/pyproject.toml +1 -1
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/cli.py +43 -1
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/device_manager.py +2 -0
- python_roborock-2.44.0/roborock/devices/traits/sound_volume.py +31 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/v1_rpc_channel.py +4 -1
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/protocols/v1_protocol.py +28 -12
- {python_roborock-2.43.0 → python_roborock-2.44.0}/LICENSE +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/README.md +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/__init__.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/api.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/b01_containers.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/broadcast_protocol.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/callbacks.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/clean_modes.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/cloud_api.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/code_mappings.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/command_cache.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/const.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/containers.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/device_features.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/README.md +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/__init__.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/a01_channel.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/b01_channel.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/cache.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/channel.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/device.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/local_channel.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/mqtt_channel.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/b01/__init__.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/b01/props.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/clean_summary.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/dnd.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/dyad.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/status.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/trait.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/traits/zeo.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/devices/v1_channel.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/exceptions.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/mqtt/__init__.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/mqtt/roborock_session.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/mqtt/session.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/protocol.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/protocols/a01_protocol.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/protocols/b01_protocol.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/py.typed +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/roborock_future.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/roborock_message.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/roborock_typing.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/util.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_1_apis/__init__.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_1_apis/roborock_client_v1.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_1_apis/roborock_local_client_v1.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_a01_apis/__init__.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_a01_apis/roborock_client_a01.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_a01_apis/roborock_mqtt_client_a01.py +0 -0
- {python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/web_api.py +0 -0
|
@@ -382,7 +382,7 @@ async def execute_scene(ctx, scene_id):
|
|
|
382
382
|
@click.pass_context
|
|
383
383
|
@async_command
|
|
384
384
|
async def status(ctx, device_id: str):
|
|
385
|
-
"""Get device status
|
|
385
|
+
"""Get device status."""
|
|
386
386
|
context: RoborockContext = ctx.obj
|
|
387
387
|
|
|
388
388
|
device_manager = await context.get_device_manager()
|
|
@@ -414,6 +414,46 @@ async def clean_summary(ctx, device_id: str):
|
|
|
414
414
|
click.echo(dump_json(clean_summary_result.as_dict()))
|
|
415
415
|
|
|
416
416
|
|
|
417
|
+
@session.command()
|
|
418
|
+
@click.option("--device_id", required=True)
|
|
419
|
+
@click.pass_context
|
|
420
|
+
@async_command
|
|
421
|
+
async def volume(ctx, device_id: str):
|
|
422
|
+
"""Get device volume."""
|
|
423
|
+
context: RoborockContext = ctx.obj
|
|
424
|
+
|
|
425
|
+
device_manager = await context.get_device_manager()
|
|
426
|
+
device = await device_manager.get_device(device_id)
|
|
427
|
+
|
|
428
|
+
if not (volume_trait := device.traits.get("sound_volume")):
|
|
429
|
+
click.echo(f"Device {device.name} does not have a volume trait")
|
|
430
|
+
return
|
|
431
|
+
|
|
432
|
+
volume_result = await volume_trait.get_volume()
|
|
433
|
+
click.echo(f"Device {device_id} volume:")
|
|
434
|
+
click.echo(volume_result)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
@session.command()
|
|
438
|
+
@click.option("--device_id", required=True)
|
|
439
|
+
@click.option("--volume", required=True, type=int)
|
|
440
|
+
@click.pass_context
|
|
441
|
+
@async_command
|
|
442
|
+
async def set_volume(ctx, device_id: str, volume: int):
|
|
443
|
+
"""Set the devicevolume."""
|
|
444
|
+
context: RoborockContext = ctx.obj
|
|
445
|
+
|
|
446
|
+
device_manager = await context.get_device_manager()
|
|
447
|
+
device = await device_manager.get_device(device_id)
|
|
448
|
+
|
|
449
|
+
if not (volume_trait := device.traits.get("sound_volume")):
|
|
450
|
+
click.echo(f"Device {device.name} does not have a volume trait")
|
|
451
|
+
return
|
|
452
|
+
|
|
453
|
+
await volume_trait.set_volume(volume)
|
|
454
|
+
click.echo(f"Set Device {device_id} volume to {volume}")
|
|
455
|
+
|
|
456
|
+
|
|
417
457
|
@click.command()
|
|
418
458
|
@click.option("--device_id", required=True)
|
|
419
459
|
@click.option("--cmd", required=True)
|
|
@@ -653,6 +693,8 @@ cli.add_command(session)
|
|
|
653
693
|
cli.add_command(get_device_info)
|
|
654
694
|
cli.add_command(update_docs)
|
|
655
695
|
cli.add_command(clean_summary)
|
|
696
|
+
cli.add_command(volume)
|
|
697
|
+
cli.add_command(set_volume)
|
|
656
698
|
|
|
657
699
|
|
|
658
700
|
def main():
|
|
@@ -25,6 +25,7 @@ from .traits.b01.props import B01PropsApi
|
|
|
25
25
|
from .traits.clean_summary import CleanSummaryTrait
|
|
26
26
|
from .traits.dnd import DoNotDisturbTrait
|
|
27
27
|
from .traits.dyad import DyadApi
|
|
28
|
+
from .traits.sound_volume import SoundVolumeTrait
|
|
28
29
|
from .traits.status import StatusTrait
|
|
29
30
|
from .traits.trait import Trait
|
|
30
31
|
from .traits.zeo import ZeoApi
|
|
@@ -156,6 +157,7 @@ async def create_device_manager(
|
|
|
156
157
|
traits.append(StatusTrait(product, channel.rpc_channel))
|
|
157
158
|
traits.append(DoNotDisturbTrait(channel.rpc_channel))
|
|
158
159
|
traits.append(CleanSummaryTrait(channel.rpc_channel))
|
|
160
|
+
traits.append(SoundVolumeTrait(channel.rpc_channel))
|
|
159
161
|
case DeviceVersion.A01:
|
|
160
162
|
mqtt_channel = create_mqtt_channel(user_data, mqtt_params, mqtt_session, device)
|
|
161
163
|
match product.category:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Module for controlling the sound volume of Roborock devices."""
|
|
2
|
+
|
|
3
|
+
from roborock.devices.traits.trait import Trait
|
|
4
|
+
from roborock.devices.v1_rpc_channel import V1RpcChannel
|
|
5
|
+
from roborock.exceptions import RoborockException
|
|
6
|
+
from roborock.roborock_typing import RoborockCommand
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"SoundVolumeTrait",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SoundVolumeTrait(Trait):
|
|
14
|
+
"""Trait for controlling the sound volume of a Roborock device."""
|
|
15
|
+
|
|
16
|
+
name = "sound_volume"
|
|
17
|
+
|
|
18
|
+
def __init__(self, rpc_channel: V1RpcChannel) -> None:
|
|
19
|
+
"""Initialize the SoundVolumeTrait."""
|
|
20
|
+
self._rpc_channel = rpc_channel
|
|
21
|
+
|
|
22
|
+
async def get_volume(self) -> int:
|
|
23
|
+
"""Get the current sound volume of the device."""
|
|
24
|
+
response = await self._rpc_channel.send_command(RoborockCommand.GET_SOUND_VOLUME)
|
|
25
|
+
if not isinstance(response, list) or not response:
|
|
26
|
+
raise RoborockException(f"Unexpected volume format: {response!r}")
|
|
27
|
+
return int(response[0])
|
|
28
|
+
|
|
29
|
+
async def set_volume(self, volume: int) -> None:
|
|
30
|
+
"""Set the sound volume of the device."""
|
|
31
|
+
await self._rpc_channel.send_command(RoborockCommand.CHANGE_SOUND_VOLUME, params=[volume])
|
|
@@ -149,7 +149,10 @@ class PayloadEncodedV1RpcChannel(BaseV1RpcChannel):
|
|
|
149
149
|
return
|
|
150
150
|
_LOGGER.debug("Received response (request_id=%s): %s", self._name, decoded.request_id)
|
|
151
151
|
if decoded.request_id == request_message.request_id:
|
|
152
|
-
|
|
152
|
+
if decoded.api_error:
|
|
153
|
+
future.set_exception(decoded.api_error)
|
|
154
|
+
else:
|
|
155
|
+
future.set_result(decoded.data)
|
|
153
156
|
|
|
154
157
|
unsub = await self._channel.subscribe(find_response)
|
|
155
158
|
try:
|
|
@@ -108,9 +108,18 @@ class ResponseMessage:
|
|
|
108
108
|
data: ResponseData
|
|
109
109
|
"""The data of the response, where the type depends on the command."""
|
|
110
110
|
|
|
111
|
+
api_error: RoborockException | None = None
|
|
112
|
+
"""The API error message of the response if any."""
|
|
113
|
+
|
|
111
114
|
|
|
112
115
|
def decode_rpc_response(message: RoborockMessage) -> ResponseMessage:
|
|
113
|
-
"""Decode a V1 RPC_RESPONSE message.
|
|
116
|
+
"""Decode a V1 RPC_RESPONSE message.
|
|
117
|
+
|
|
118
|
+
This will raise a RoborockException if the message cannot be parsed. A
|
|
119
|
+
response object will be returned even if there is an error in the
|
|
120
|
+
response, as long as we can extract the request ID. This is so we can
|
|
121
|
+
associate an API response with a request even if there was an error.
|
|
122
|
+
"""
|
|
114
123
|
if not message.payload:
|
|
115
124
|
return ResponseMessage(request_id=message.seq, data={})
|
|
116
125
|
try:
|
|
@@ -136,19 +145,26 @@ def decode_rpc_response(message: RoborockMessage) -> ResponseMessage:
|
|
|
136
145
|
) from e
|
|
137
146
|
|
|
138
147
|
request_id: int | None = data_point_response.get("id")
|
|
148
|
+
exc: RoborockException | None = None
|
|
139
149
|
if error := data_point_response.get("error"):
|
|
140
|
-
|
|
141
|
-
|
|
150
|
+
exc = RoborockException(error)
|
|
142
151
|
if not (result := data_point_response.get("result")):
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
result
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
exc = RoborockException(f"Invalid V1 message format: missing 'result' in data point for {message.payload!r}")
|
|
153
|
+
else:
|
|
154
|
+
_LOGGER.debug("Decoded V1 message result: %s", result)
|
|
155
|
+
if isinstance(result, str):
|
|
156
|
+
if result == "unknown_method":
|
|
157
|
+
exc = RoborockException("The method called is not recognized by the device.")
|
|
158
|
+
elif result != "ok":
|
|
159
|
+
exc = RoborockException(f"Unexpected API Result: {result}")
|
|
160
|
+
result = {}
|
|
161
|
+
if not isinstance(result, (dict, list, int)):
|
|
162
|
+
raise RoborockException(
|
|
163
|
+
f"Invalid V1 message format: 'result' was unexpected type {type(result)}. {message.payload!r}"
|
|
164
|
+
)
|
|
165
|
+
if not request_id and exc:
|
|
166
|
+
raise exc
|
|
167
|
+
return ResponseMessage(request_id=request_id, data=result, api_error=exc)
|
|
152
168
|
|
|
153
169
|
|
|
154
170
|
@dataclass
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_1_apis/roborock_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_1_apis/roborock_mqtt_client_v1.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_roborock-2.43.0 → python_roborock-2.44.0}/roborock/version_a01_apis/roborock_client_a01.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|