Skip to content

Commit f6a944a

Browse files
committed
chore: add comment about rpc channel hacks and separate property files
1 parent 137f17b commit f6a944a

File tree

9 files changed

+110
-102
lines changed

9 files changed

+110
-102
lines changed

roborock/devices/traits/traits_mixin.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ def __init__(self, trait: Trait) -> None:
4040
This will populate the appropriate trait attributes based on the types
4141
of the traits provided.
4242
"""
43-
# trait_map: dict[type[Trait], Trait] = {type(item): item for item in traits}
4443
for item in fields(self):
4544
trait_type = _get_trait_type(item)
4645
if trait_type == type(trait):

roborock/devices/traits/v1/__init__.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,19 @@
66
from roborock.devices.traits import Trait
77
from roborock.devices.v1_rpc_channel import V1RpcChannel
88

9+
from .clean_summary import CleanSummaryTrait
910
from .common import V1TraitMixin
10-
from .properties import CleanSummaryTrait, DoNotDisturbTrait, SoundVolumeTrait, StatusTrait
11+
from .do_not_disturb import DoNotDisturbTrait
12+
from .status import StatusTrait
13+
from .volume import SoundVolumeTrait
1114

1215
__all__ = [
1316
"create",
1417
"PropertiesApi",
15-
"properties",
16-
"V1TraitMixin",
18+
"StatusTrait",
19+
"DoNotDisturbTrait",
20+
"CleanSummaryTrait",
21+
"SoundVolumeTrait",
1722
]
1823

1924

@@ -36,7 +41,10 @@ def __init__(self, product: HomeDataProduct, rpc_channel: V1RpcChannel) -> None:
3641
"""Initialize the V1TraitProps with None values."""
3742
self.status = StatusTrait(product)
3843

39-
# Create traits and set the RPC channel
44+
# This is a hack to allow setting the rpc_channel on all traits. This is
45+
# used so we can preserve the dataclass behavior when the values in the
46+
# traits are updated, but still want to allow them to have a reference
47+
# to the rpc channel for sending commands.
4048
for item in fields(self):
4149
if (trait := getattr(self, item.name, None)) is None:
4250
trait = item.type()
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from typing import Self
2+
3+
from roborock.containers import CleanSummary
4+
from roborock.devices.traits.v1 import common
5+
from roborock.roborock_typing import RoborockCommand
6+
from roborock.util import unpack_list
7+
8+
9+
class CleanSummaryTrait(CleanSummary, common.V1TraitMixin):
10+
"""Trait for managing the clean summary of Roborock devices."""
11+
12+
command = RoborockCommand.GET_CLEAN_SUMMARY
13+
14+
@classmethod
15+
def _parse_type_response(cls, response: common.V1ResponseData) -> Self:
16+
"""Parse the response from the device into a CleanSummary."""
17+
if isinstance(response, dict):
18+
return CleanSummaryTrait.from_dict(response) # type: ignore[return-value]
19+
elif isinstance(response, list):
20+
clean_time, clean_area, clean_count, records = unpack_list(response, 4)
21+
return CleanSummaryTrait( # type: ignore[return-value]
22+
clean_time=clean_time,
23+
clean_area=clean_area,
24+
clean_count=clean_count,
25+
records=records,
26+
)
27+
elif isinstance(response, int):
28+
return CleanSummaryTrait(clean_time=response) # type: ignore[return-value]
29+
raise ValueError(f"Unexpected clean summary format: {response!r}")
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from roborock.containers import DnDTimer
2+
from roborock.devices.traits.v1 import common
3+
from roborock.roborock_typing import RoborockCommand
4+
5+
6+
class DoNotDisturbTrait(DnDTimer, common.V1TraitMixin):
7+
"""Trait for managing Do Not Disturb (DND) settings on Roborock devices."""
8+
9+
command = RoborockCommand.GET_DND_TIMER
10+
11+
async def set_dnd_timer(self, dnd_timer: DnDTimer) -> None:
12+
"""Set the Do Not Disturb (DND) timer settings of the device."""
13+
await self.rpc_channel.send_command(RoborockCommand.SET_DND_TIMER, params=dnd_timer.as_dict())
14+
15+
async def clear_dnd_timer(self) -> None:
16+
"""Clear the Do Not Disturb (DND) timer settings of the device."""
17+
await self.rpc_channel.send_command(RoborockCommand.CLOSE_DND_TIMER)

roborock/devices/traits/v1/properties.py

Lines changed: 0 additions & 95 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing import Self
2+
3+
from roborock.containers import HomeDataProduct, ModelStatus, S7MaxVStatus, Status
4+
from roborock.devices.traits.v1 import common
5+
from roborock.roborock_typing import RoborockCommand
6+
7+
8+
class StatusTrait(Status, common.V1TraitMixin):
9+
"""Trait for managing the status of Roborock devices."""
10+
11+
command = RoborockCommand.GET_STATUS
12+
13+
def __init__(self, product_info: HomeDataProduct) -> None:
14+
"""Initialize the StatusTrait."""
15+
self._product_info = product_info
16+
17+
def _parse_response(self, response: common.V1ResponseData) -> Self:
18+
"""Parse the response from the device into a CleanSummary."""
19+
status_type: type[Status] = ModelStatus.get(self._product_info.model, S7MaxVStatus)
20+
if isinstance(response, list):
21+
response = response[0]
22+
if isinstance(response, dict):
23+
return status_type.from_dict(response)
24+
raise ValueError(f"Unexpected status format: {response!r}")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from dataclasses import dataclass, field
2+
3+
from roborock.devices.traits.v1 import common
4+
from roborock.roborock_typing import RoborockCommand
5+
6+
# TODO: This is currently the pattern for holding all the commands that hold a
7+
# single value, but it still seems too verbose. Maybe we can generate these
8+
# dynamically or somehow make them less code.
9+
10+
11+
@dataclass
12+
class SoundVolume(common.RoborockValueBase):
13+
"""Dataclass for sound volume."""
14+
15+
volume: int | None = field(default=None, metadata={"roborock_value": True})
16+
"""Sound volume level (0-100)."""
17+
18+
19+
class SoundVolumeTrait(SoundVolume, common.V1TraitMixin):
20+
"""Trait for controlling the sound volume of a Roborock device."""
21+
22+
command = RoborockCommand.GET_SOUND_VOLUME
23+
24+
async def set_volume(self, volume: int) -> None:
25+
"""Set the sound volume of the device."""
26+
await self.rpc_channel.send_command(RoborockCommand.CHANGE_SOUND_VOLUME, params=[volume])

tests/devices/traits/v1/test_clean_summary.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from roborock.containers import CleanSummary
88
from roborock.devices.device import RoborockDevice
9-
from roborock.devices.traits.v1.properties import CleanSummaryTrait
9+
from roborock.devices.traits.v1.clean_summary import CleanSummaryTrait
1010
from roborock.exceptions import RoborockException
1111
from roborock.roborock_typing import RoborockCommand
1212

tests/devices/traits/v1/test_dnd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from roborock.containers import DnDTimer
88
from roborock.devices.device import RoborockDevice
9-
from roborock.devices.traits.v1.properties import DoNotDisturbTrait
9+
from roborock.devices.traits.v1.do_not_disturb import DoNotDisturbTrait
1010
from roborock.roborock_typing import RoborockCommand
1111

1212

0 commit comments

Comments
 (0)