Skip to content

Commit fbf859b

Browse files
committed
chore: change a bit of how traits work
1 parent b214d5b commit fbf859b

File tree

5 files changed

+93
-56
lines changed

5 files changed

+93
-56
lines changed

roborock/containers.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,3 +1184,12 @@ class DyadSndState(RoborockBase):
11841184
@dataclass
11851185
class DyadOtaNfo(RoborockBase):
11861186
mqttOtaData: dict
1187+
1188+
1189+
@dataclass
1190+
class DndActions(RoborockBase):
1191+
dry: int | None = None
1192+
dust: int | None = None
1193+
led: int | None = None
1194+
resume: int | None = None
1195+
vol: int | None = None

roborock/device_trait.py

Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import datetime
21
from abc import ABC, abstractmethod
32
from collections.abc import Awaitable, Callable
43
from dataclasses import dataclass
54

65
from . import RoborockCommand
7-
from .containers import Consumable, DeviceFeatures, DnDTimer, RoborockBase
6+
from .containers import DeviceFeatures, RoborockBase
87

98

109
@dataclass
1110
class DeviceTrait(ABC):
1211
handle_command: RoborockCommand
13-
_status_type: type[RoborockBase] = RoborockBase
1412

1513
def __init__(self, send_command: Callable[..., Awaitable[None]]):
1614
self.send_command = send_command
@@ -22,8 +20,12 @@ def __init__(self, send_command: Callable[..., Awaitable[None]]):
2220
def supported(cls, features: DeviceFeatures) -> bool:
2321
raise NotImplementedError
2422

23+
@abstractmethod
24+
def from_dict(cls, data: dict) -> bool:
25+
raise NotImplementedError
26+
2527
def on_message(self, data: dict) -> None:
26-
self.status = self._status_type.from_dict(data)
28+
self.status = self.from_dict(data)
2729
for callback in self.subscriptions:
2830
callback(self.status)
2931

@@ -36,44 +38,20 @@ def get(self):
3638
raise NotImplementedError
3739

3840

39-
class DndTrait(DeviceTrait):
40-
handle_command: RoborockCommand = RoborockCommand.GET_DND_TIMER
41-
_status_type: type[DnDTimer] = DnDTimer
42-
status: DnDTimer
43-
44-
def __init__(self, send_command: Callable[..., Awaitable[None]]):
45-
super().__init__(send_command)
46-
47-
@classmethod
48-
def supported(cls, features: DeviceFeatures) -> bool:
49-
return features.is_support_custom_dnd
50-
51-
async def update_dnd(self, enabled: bool, start_time: datetime.time, end_time: datetime.time) -> None:
52-
if self.status.enabled and not enabled:
53-
await self.send_command(RoborockCommand.CLOSE_DND_TIMER)
54-
else:
55-
start = start_time if start_time is not None else self.status.start_time
56-
end = end_time if end_time is not None else self.status.end_time
57-
await self.send_command(RoborockCommand.SET_DND_TIMER, [start.hour, start.minute, end.hour, end.minute])
58-
59-
async def get(self) -> None:
60-
await self.send_command(RoborockCommand.GET_DND_TIMER)
61-
62-
63-
class ConsumableTrait(DeviceTrait):
64-
handle_command = RoborockCommand.GET_CONSUMABLE
65-
_status_type: type[Consumable] = DnDTimer
66-
status: Consumable
67-
68-
def __init__(self, send_command: Callable[..., Awaitable[None]]):
69-
super().__init__(send_command)
70-
71-
@classmethod
72-
def supported(cls, features: DeviceFeatures) -> bool:
73-
return True
74-
75-
async def reset_consumable(self, consumable: str) -> None:
76-
await self.send_command(RoborockCommand.RESET_CONSUMABLE, [consumable])
77-
78-
async def get(self) -> None:
79-
await self.send_command(RoborockCommand.GET_CONSUMABLE)
41+
# class ConsumableTrait(DeviceTrait):
42+
# handle_command = RoborockCommand.GET_CONSUMABLE
43+
# _status_type: type[Consumable] = DnDTimer
44+
# status: Consumable
45+
#
46+
# def __init__(self, send_command: Callable[..., Awaitable[None]]):
47+
# super().__init__(send_command)
48+
#
49+
# @classmethod
50+
# def supported(cls, features: DeviceFeatures) -> bool:
51+
# return True
52+
#
53+
# async def reset_consumable(self, consumable: str) -> None:
54+
# await self.send_command(RoborockCommand.RESET_CONSUMABLE, [consumable])
55+
#
56+
# async def get(self) -> None:
57+
# await self.send_command(RoborockCommand.GET_CONSUMABLE)

roborock/device_traits/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .dnd import Dnd

roborock/device_traits/dnd.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import datetime
2+
from collections.abc import Awaitable, Callable
3+
4+
from roborock import DeviceFeatures, DndActions, RoborockCommand
5+
from roborock.device_trait import DeviceTrait
6+
7+
8+
class Dnd(DeviceTrait):
9+
handle_command: RoborockCommand = RoborockCommand.GET_DND_TIMER
10+
11+
def __init__(self, send_command: Callable[..., Awaitable[None]]):
12+
self.start_hour: int | None = None
13+
self.start_minute: int | None = None
14+
self.end_hour: int | None = None
15+
self.end_minute: int | None = None
16+
self.enabled: bool | None = None
17+
self.start_time: datetime.time | None = None
18+
self.end_time: datetime.time | None = None
19+
self.actions: DndActions | None = None
20+
super().__init__(send_command)
21+
22+
def from_dict(self, dnd_dict: dict):
23+
self.start_hour = dnd_dict.get("start_hour")
24+
self.start_minute = dnd_dict.get("start_minute")
25+
self.end_hour = dnd_dict.get("end_hour")
26+
self.end_minute = dnd_dict.get("end_minute")
27+
self.enabled = bool(dnd_dict.get("enabled"))
28+
self.actions = DndActions.from_dict(dnd_dict.get("actions"))
29+
self.start_time = (
30+
datetime.time(hour=self.start_hour, minute=self.start_minute)
31+
if self.start_hour is not None and self.start_minute is not None
32+
else None
33+
)
34+
self.end_time = (
35+
datetime.time(hour=self.end_hour, minute=self.end_minute)
36+
if self.end_hour is not None and self.end_minute is not None
37+
else None
38+
)
39+
40+
def to_dict(self) -> dict:
41+
return {}
42+
43+
@classmethod
44+
def supported(cls, features: DeviceFeatures) -> bool:
45+
return features.is_support_custom_dnd
46+
47+
async def update_dnd(self, enabled: bool, start_time: datetime.time, end_time: datetime.time) -> None:
48+
if self.enabled and not enabled:
49+
await self.send_command(RoborockCommand.CLOSE_DND_TIMER)
50+
else:
51+
start = start_time if start_time is not None else self.start_time
52+
end = end_time if end_time is not None else self.end_time
53+
await self.send_command(RoborockCommand.SET_DND_TIMER, [start.hour, start.minute, end.hour, end.minute])
54+
55+
async def get(self) -> None:
56+
await self.send_command(RoborockCommand.GET_DND_TIMER)

roborock/roborock_device.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
from . import RoborockCommand
1010
from .containers import DeviceData, ModelStatus, S7MaxVStatus, Status, UserData
11-
from .device_trait import ConsumableTrait, DeviceTrait, DndTrait
11+
from .device_trait import DeviceTrait
12+
from .device_traits import Dnd
1213
from .mqtt.roborock_session import MqttParams, RoborockMqttSession
1314
from .protocol import MessageParser, Utils, md5hex
1415
from .roborock_message import RoborockMessage, RoborockMessageProtocol
@@ -36,8 +37,8 @@ def __init__(self, user_data: UserData, device_info: DeviceData):
3637
self._message_id_types: dict[int, DeviceTrait] = {}
3738
self._command_to_trait = {}
3839
self._all_supported_traits = []
39-
self._dnd_trait: DndTrait | None = self.determine_supported_traits(DndTrait)
40-
self._consumable_trait: ConsumableTrait | None = self.determine_supported_traits(ConsumableTrait)
40+
self._dnd_trait: Dnd | None = self.determine_supported_traits(Dnd)
41+
# self._consumable_trait: ConsumableTrait | None = self.determine_supported_traits(ConsumableTrait)
4142
self._status_type: type[Status] = ModelStatus.get(device_info.model, S7MaxVStatus)
4243
# TODO: One per client EVER
4344
self.session = RoborockMqttSession(
@@ -153,11 +154,3 @@ def on_message(self, message_bytes: bytes):
153154

154155
# This should also probably be split with on_cloud_message and on_local_message.
155156
print(message)
156-
157-
@property
158-
def dnd(self) -> DndTrait | None:
159-
return self._dnd_trait
160-
161-
@property
162-
def consumable(self) -> ConsumableTrait | None:
163-
return self._consumable_trait

0 commit comments

Comments
 (0)