8000 Add setting to change carpet clean mode (#1458) · ryenitcher/python-kasa@773801c · GitHub
[go: up one dir, main page]

Skip to content

Commit 773801c

Browse files
authored
Add setting to change carpet clean mode (python-kasa#1458)
Add new setting to control carpet clean mode: ``` == Configuration == Carpet clean mode (carpet_clean_mode): Normal *Boost* ```
1 parent d27697c commit 773801c

File tree

4 files changed

+94
-2
lines changed

4 files changed

+94
-2
lines changed

devtools/helpers/smartrequests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ def get_component_requests(component_id, ver_code):
437437
"overheat_protection": [],
438438
# Vacuum components
439439
"clean": [
440+
SmartRequest.get_raw_request("getCarpetClean"),
440441
SmartRequest.get_raw_request("getCleanRecords"),
441442
SmartRequest.get_raw_request("getVacStatus"),
442443
SmartRequest.get_raw_request("getAreaUnit"),

kasa/smart/modules/clean.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import logging
66
from datetime import timedelta
7-
from enum import IntEnum
7+
from enum import IntEnum, StrEnum
88
from typing import Annotated, Literal
99

1010
from ...feature import Feature
@@ -56,6 +56,13 @@ class FanSpeed(IntEnum):
5656
Ultra = 5
5757

5858

59+
class CarpetCleanMode(StrEnum):
60+
"""Carpet clean mode."""
61+
62+
Normal = "normal"
63+
Boost = "boost"
64+
65+
5966
class AreaUnit(IntEnum):
6067
"""Area unit."""
6168

@@ -143,7 +150,6 @@ def _initialize_features(self) -> None:
143150
type=Feature.Type.Sensor,
144151
)
145152
)
146-
147153
self._add_feature(
148154
Feature(
149155
self._device,
@@ -171,6 +177,20 @@ def _initialize_features(self) -> None:
171177
type=Feature.Type.Number,
172178
)
173179
)
180+
self._add_feature(
181+
Feature(
182+
self._device,
183+
id="carpet_clean_mode",
184+
name="Carpet clean mode",
185+
container=self,
186+
attribute_getter="carpet_clean_mode",
187+
attribute_setter="set_carpet_clean_mode",
188+
icon="mdi:rug",
189+
choices_getter=lambda: list(CarpetCleanMode.__members__),
190+
category=Feature.Category.Config,
191+
type=Feature.Type.Choice,
192+
)
193+
)
174194
self._add_feature(
175195
Feature(
176196
self._device,
@@ -234,6 +254,7 @@ def query(self) -> dict:
234254
return {
235255
"getVacStatus": {},
236256
"getCleanInfo": {},
257+
"getCarpetClean": {},
237258
"getAreaUnit": {},
238259
"getBatteryInfo": {},
239260
"getCleanStatus": {},
@@ -342,6 +363,24 @@ def status(self) -> Status:
342363
_LOGGER.warning("Got unknown status code: %s (%s)", status_code, self.data)
343364
return Status.UnknownInternal
344365

366+
@property
367+
def carpet_clean_mode(self) -> Annotated[str, FeatureAttribute()]:
368+
"""Return carpet clean mode."""
369+
return CarpetCleanMode(self.data["getCarpetClean"]["carpet_clean_prefer"]).name
370+
371+
async def set_carpet_clean_mode(
372+
self, mode: str
373+
) -> Annotated[dict, FeatureAttribute()]:
374+
"""Set carpet clean mode."""
375+
name_to_value = {x.name: x.value for x in CarpetCleanMode}
376+
if mode not in name_to_value:
377+
raise ValueError(
378+
"Invalid carpet clean mode %s, available %s", mode, name_to_value
379+
)
380+
return await self.call(
381+
"setCarpetClean", {"carpet_clean_prefer": name_to_value[mode]}
382+
)
383+
345384
@property
346385
def area_unit(self) -> AreaUnit:
347386
"""Return area unit."""

tests/fixtures/smart/RV20 Max Plus(EU)_1.0_1.0.7.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@
162162
"getBatteryInfo": {
163163
"battery_percentage": 75
164164
},
165+
"getCarpetClean": {
166+
"carpet_clean_prefer": "boost"
167+
},
165168
"getCleanAttr": {
166169
"cistern": 2,
167170
"clean_number": 1,

tests/smart/modules/test_clean.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
("vacuum_status", "status", Status),
2222
("vacuum_error", "error", ErrorCode),
2323
("vacuum_fan_speed", "fan_speed_preset", str),
24+
("carpet_clean_mode", "carpet_clean_mode", str),
2425
("battery_level", "battery", int),
2526
],
2627
)
@@ -69,6 +70,13 @@ async def test_features(dev: SmartDevice, feature: str, prop_name: str, type: ty
6970
{"suction": 1, "type": "global"},
7071
id="vacuum_fan_speed",
7172
),
73+
pytest.param(
74+
"carpet_clean_mode",
75+
"Boost",
76+
"setCarpetClean",
77+
{"carpet_clean_prefer": "boost"},
78+
id="carpet_clean_mode",
79+
),
7280
pytest.param(
7381
"clean_count",
7482
2,
@@ -151,3 +159,44 @@ async def test_unknown_status(
151159

152160
assert clean.status is Status.UnknownInternal
153161
assert "Got unknown status code: 123" in caplog.text
162+
163+
164+
@clean
165+
@pytest.mark.parametrize(
166+
("setting", "value", "exc", "exc_message"),
167+
[
168+
pytest.param(
169+
"vacuum_fan_speed",
170+
"invalid speed",
171+
ValueError,
172+
"Invalid fan speed",
173+
id="vacuum_fan_speed",
174+
),
175+
pytest.param(
176+
"carpet_clean_mode",
177+
"invalid mode",
178+
ValueError,
179+
"Invalid carpet clean mode",
180+
id="carpet_clean_mode",
181+
),
182+
],
183+
)
184+
async def test_invalid_settings(
185+
dev: SmartDevice,
186+
mocker: MockerFixture,
187+
setting: str,
188+
value: str,
189+
exc: type[Exception],
190+
exc_message: str,
191+
):
192+
"""Test invalid settings."""
193+
clean = next(get_parent_and_child_modules(dev, Module.Clean))
194+
195+
# Not using feature.set_value() as it checks for valid values
196+
setter_name = dev.features[setting].attribute_setter
197+
assert isinstance(setter_name, str)
198+
199+
setter = getattr(clean, setter_name)
200+
201+
with pytest.raises(exc, match=exc_message):
202+
await setter(value)

0 commit comments

Comments
 (0)
0