Skip to content

Commit cceaff7

Browse files
authored
Fix roborock off peak electricity timer (home-assistant#158292)
1 parent 079c6da commit cceaff7

File tree

4 files changed

+85
-21
lines changed

4 files changed

+85
-21
lines changed

homeassistant/components/roborock/time.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import logging
88
from typing import Any
99

10-
from roborock.data import DnDTimer
10+
from roborock.data import DnDTimer, ValleyElectricityTimer
1111
from roborock.exceptions import RoborockException
1212

1313
from homeassistant.components.time import TimeEntity, TimeEntityDescription
@@ -80,13 +80,14 @@ class RoborockTimeDescription(TimeEntityDescription):
8080
key="off_peak_start",
8181
translation_key="off_peak_start",
8282
trait=lambda api: api.valley_electricity_timer,
83-
update_value=lambda trait, desired_time: trait.update_value(
84-
[
85-
desired_time.hour,
86-
desired_time.minute,
87-
trait.end_hour,
88-
trait.end_minute,
89-
]
83+
update_value=lambda trait, desired_time: trait.set_timer(
84+
ValleyElectricityTimer(
85+
enabled=trait.enabled,
86+
start_hour=desired_time.hour,
87+
start_minute=desired_time.minute,
88+
end_hour=trait.end_hour,
89+
end_minute=trait.end_minute,
90+
)
9091
),
9192
get_value=lambda trait: datetime.time(
9293
hour=trait.start_hour, minute=trait.start_minute
@@ -98,13 +99,14 @@ class RoborockTimeDescription(TimeEntityDescription):
9899
key="off_peak_end",
99100
translation_key="off_peak_end",
100101
trait=lambda api: api.valley_electricity_timer,
101-
update_value=lambda trait, desired_time: trait.update_value(
102-
[
103-
trait.start_hour,
104-
trait.start_minute,
105-
desired_time.hour,
106-
desired_time.minute,
107-
]
102+
update_value=lambda trait, desired_time: trait.set_timer(
103+
ValleyElectricityTimer(
104+
enabled=trait.enabled,
105+
start_hour=trait.start_hour,
106+
start_minute=trait.start_minute,
107+
end_hour=desired_time.hour,
108+
end_minute=desired_time.minute,
109+
)
108110
),
109111
get_value=lambda trait: datetime.time(
110112
hour=trait.end_hour, minute=trait.end_minute

tests/components/roborock/conftest.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
NetworkInfo,
2222
RoborockBase,
2323
RoborockDyadStateCode,
24+
ValleyElectricityTimer,
2425
ZeoError,
2526
ZeoState,
2627
)
@@ -40,6 +41,9 @@
4041
from roborock.devices.traits.v1.routines import RoutinesTrait
4142
from roborock.devices.traits.v1.smart_wash_params import SmartWashParamsTrait
4243
from roborock.devices.traits.v1.status import StatusTrait
44+
from roborock.devices.traits.v1.valley_electricity_timer import (
45+
ValleyElectricityTimerTrait,
46+
)
4347
from roborock.devices.traits.v1.volume import SoundVolumeTrait
4448
from roborock.devices.traits.v1.wash_towel_mode import WashTowelModeTrait
4549
from roborock.roborock_message import RoborockDyadDataProtocol, RoborockZeoProtocol
@@ -68,6 +72,7 @@
6872
STATUS,
6973
USER_DATA,
7074
USER_EMAIL,
75+
VALLEY_ELECTRICITY_TIMER,
7176
)
7277

7378
from tests.common import MockConfigEntry
@@ -188,6 +193,25 @@ async def set_dnd_timer(timer: DnDTimer) -> None:
188193
return dnd_trait
189194

190195

196+
def make_valley_electric_timer(dataclass_template: RoborockBase) -> AsyncMock:
197+
"""Make a function for the fake timer trait that emulates the real behavior."""
198+
valley_electric_timer_trait = make_mock_switch(
199+
trait_spec=ValleyElectricityTimerTrait,
200+
dataclass_template=dataclass_template,
201+
)
202+
203+
async def set_timer(timer: ValleyElectricityTimer) -> None:
204+
setattr(valley_electric_timer_trait, "start_hour", timer.start_hour)
205+
setattr(valley_electric_timer_trait, "start_minute", timer.start_minute)
206+
setattr(valley_electric_timer_trait, "end_hour", timer.end_hour)
207+
setattr(valley_electric_timer_trait, "end_minute", timer.end_minute)
208+
setattr(valley_electric_timer_trait, "enabled", timer.enabled)
209+
210+
valley_electric_timer_trait.set_timer = AsyncMock()
211+
valley_electric_timer_trait.set_timer.side_effect = set_timer
212+
return valley_electric_timer_trait
213+
214+
191215
def make_home_trait(
192216
map_info: list[MultiMapsListMapInfo],
193217
current_map: int | None,
@@ -257,7 +281,9 @@ def create_v1_properties(network_info: NetworkInfo) -> AsyncMock:
257281
v1_properties.child_lock = make_mock_switch()
258282
v1_properties.led_status = make_mock_switch()
259283
v1_properties.flow_led_status = make_mock_switch()
260-
v1_properties.valley_electricity_timer = make_mock_switch()
284+
v1_properties.valley_electricity_timer = make_valley_electric_timer(
285+
dataclass_template=VALLEY_ELECTRICITY_TIMER,
286+
)
261287
v1_properties.dust_collection_mode = make_mock_trait(
262288
trait_spec=DustCollectionModeTrait
263289
)

tests/components/roborock/mock_data.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
NetworkInfo,
1515
S7Status,
1616
UserData,
17+
ValleyElectricityTimer,
1718
)
1819
from vacuum_map_parser_base.config.image_config import ImageConfig
1920
from vacuum_map_parser_base.map_data import ImageData
@@ -1072,6 +1073,16 @@
10721073
}
10731074
)
10741075

1076+
VALLEY_ELECTRICITY_TIMER = ValleyElectricityTimer.from_dict(
1077+
{
1078+
"start_hour": 23,
1079+
"start_minute": 0,
1080+
"end_hour": 7,
1081+
"end_minute": 0,
1082+
"enabled": 1,
1083+
}
1084+
)
1085+
10751086
STATUS = S7Status.from_dict(
10761087
{
10771088
"msg_ver": 2,

tests/components/roborock/test_time.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
"""Test Roborock Time platform."""
22

3+
from collections.abc import Callable
34
from datetime import time
5+
from typing import Any
46

57
import pytest
68
import roborock
7-
from roborock.data import DnDTimer
9+
from roborock.data import DnDTimer, RoborockBaseTimer, ValleyElectricityTimer
810

911
from homeassistant.components.time import SERVICE_SET_VALUE
1012
from homeassistant.const import Platform
@@ -22,23 +24,44 @@ def platforms() -> list[Platform]:
2224
return [Platform.TIME]
2325

2426

27+
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
2528
@pytest.mark.parametrize(
26-
("entity_id", "start_state", "expected_args", "end_state"),
29+
("entity_id", "start_state", "expected_call", "expected_args", "end_state"),
2730
[
2831
(
2932
"time.roborock_s7_maxv_do_not_disturb_begin",
3033
"22:00:00",
34+
lambda x: x.v1_properties.dnd.set_dnd_timer,
3135
DnDTimer(start_hour=1, start_minute=1, end_hour=7, end_minute=0, enabled=1),
3236
"01:01:00",
3337
),
3438
(
3539
"time.roborock_s7_maxv_do_not_disturb_end",
3640
"07:00:00",
41+
lambda x: x.v1_properties.dnd.set_dnd_timer,
3742
DnDTimer(
3843
start_hour=22, start_minute=0, end_hour=1, end_minute=1, enabled=1
3944
),
4045
"01:01:00",
4146
),
47+
(
48+
"time.roborock_s7_maxv_off_peak_start",
49+
"23:00:00",
50+
lambda x: x.v1_properties.valley_electricity_timer.set_timer,
51+
ValleyElectricityTimer(
52+
start_hour=1, start_minute=1, end_hour=7, end_minute=0, enabled=1
53+
),
54+
"01:01:00",
55+
),
56+
(
57+
"time.roborock_s7_maxv_off_peak_end",
58+
"07:00:00",
59+
lambda x: x.v1_properties.valley_electricity_timer.set_timer,
60+
ValleyElectricityTimer(
61+
start_hour=23, start_minute=0, end_hour=1, end_minute=1, enabled=1
62+
),
63+
"01:01:00",
64+
),
4265
],
4366
)
4467
async def test_update_success(
@@ -48,7 +71,8 @@ async def test_update_success(
4871
entity_id: str,
4972
start_state: str,
5073
end_state: str,
51-
expected_args: DnDTimer,
74+
expected_call: Callable[[FakeDevice], Any],
75+
expected_args: RoborockBaseTimer,
5276
) -> None:
5377
"""Test turning switch entities on and off."""
5478
# Ensure that the entity exist, as these test can pass even if there is no entity.
@@ -64,10 +88,11 @@ async def test_update_success(
6488
target={"entity_id": entity_id},
6589
)
6690

67-
assert fake_vacuum.v1_properties.dnd.set_dnd_timer.call_count == 1
91+
call = expected_call(fake_vacuum)
92+
assert call.call_count == 1
6893
# Since we update the begin or end time separately: Verify that the args are built properly
6994
# by reading the existing value and only updating the relevant fields.
70-
assert fake_vacuum.v1_properties.dnd.set_dnd_timer.call_args == ((expected_args,),)
95+
assert call.call_args == ((expected_args,),)
7196

7297
state = hass.states.get(entity_id)
7398
assert state is not None

0 commit comments

Comments
 (0)