python-kasa/tests/smart/modules/test_clean.py
Teemu R. 773801cad5
Some checks failed
CI / Perform linting checks (3.13) (push) Has been cancelled
CodeQL checks / Analyze (python) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.11) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.12) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.13) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.11) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.12) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.13) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.11) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.12) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.13) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.11) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.12) (push) Has been cancelled
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.13) (push) Has been cancelled
Add setting to change carpet clean mode (#1458)
Add new setting to control carpet clean mode:
```
== Configuration ==
Carpet clean mode (carpet_clean_mode): Normal *Boost*
```
2025-01-15 19:35:41 +00:00

203 lines
5.5 KiB
Python

from __future__ import annotations
import logging
import pytest
from pytest_mock import MockerFixture
from kasa import Module
from kasa.smart import SmartDevice
from kasa.smart.modules.clean import ErrorCode, Status
from ...device_fixtures import get_parent_and_child_modules, parametrize
clean = parametrize("clean module", component_filter="clean", protocol_filter={"SMART"})
@clean
@pytest.mark.parametrize(
("feature", "prop_name", "type"),
[
("vacuum_status", "status", Status),
("vacuum_error", "error", ErrorCode),
("vacuum_fan_speed", "fan_speed_preset", str),
("carpet_clean_mode", "carpet_clean_mode", str),
("battery_level", "battery", int),
],
)
async def test_features(dev: SmartDevice, feature: str, prop_name: str, type: type):
"""Test that features are registered and work as expected."""
clean = next(get_parent_and_child_modules(dev, Module.Clean))
assert clean is not None
prop = getattr(clean, prop_name)
assert isinstance(prop, type)
feat = clean._device.features[feature]
assert feat.value == prop
assert isinstance(feat.value, type)
@pytest.mark.parametrize(
("feature", "value", "method", "params"),
[
pytest.param(
"vacuum_start",
1,
"setSwitchClean",
{
"clean_mode": 0,
"clean_on": True,
"clean_order": True,
"force_clean": False,
},
id="vacuum_start",
),
pytest.param(
"vacuum_pause", 1, "setRobotPause", {"pause": True}, id="vacuum_pause"
),
pytest.param(
"vacuum_return_home",
1,
"setSwitchCharge",
{"switch_charge": True},
id="vacuum_return_home",
),
pytest.param(
"vacuum_fan_speed",
"Quiet",
"setCleanAttr",
{"suction": 1, "type": "global"},
id="vacuum_fan_speed",
),
pytest.param(
"carpet_clean_mode",
"Boost",
"setCarpetClean",
{"carpet_clean_prefer": "boost"},
id="carpet_clean_mode",
),
pytest.param(
"clean_count",
2,
"setCleanAttr",
{"clean_number": 2, "type": "global"},
id="clean_count",
),
],
)
@clean
async def test_actions(
dev: SmartDevice,
mocker: MockerFixture,
feature: str,
value: str | int,
method: str,
params: dict,
):
"""Test the clean actions."""
clean = next(get_parent_and_child_modules(dev, Module.Clean))
call = mocker.spy(clean, "call")
await dev.features[feature].set_value(value)
call.assert_called_with(method, params)
@pytest.mark.parametrize(
("err_status", "error"),
[
pytest.param([], ErrorCode.Ok, id="empty error"),
pytest.param([0], ErrorCode.Ok, id="no error"),
pytest.param([3], ErrorCode.MainBrushStuck, id="known error"),
pytest.param([123], ErrorCode.UnknownInternal, id="unknown error"),
pytest.param([3, 4], ErrorCode.MainBrushStuck, id="multi-error"),
],
)
@clean
async def test_post_update_hook(dev: SmartDevice, err_status: list, error: ErrorCode):
"""Test that post update hook sets error states correctly."""
clean = next(get_parent_and_child_modules(dev, Module.Clean))
clean.data["getVacStatus"]["err_status"] = err_status
await clean._post_update_hook()
assert clean._error_code is error
if error is not ErrorCode.Ok:
assert clean.status is Status.Error
@clean
async def test_resume(dev: SmartDevice, mocker: MockerFixture):
"""Test that start calls resume if the state is paused."""
clean = next(get_parent_and_child_modules(dev, Module.Clean))
call = mocker.spy(clean, "call")
resume = mocker.spy(clean, "resume")
mocker.patch.object(
type(clean),
"status",
new_callable=mocker.PropertyMock,
return_value=Status.Paused,
)
await clean.start()
call.assert_called_with("setRobotPause", {"pause": False})
resume.assert_awaited()
@clean
async def test_unknown_status(
dev: SmartDevice, mocker: MockerFixture, caplog: pytest.LogCaptureFixture
):
"""Test that unknown status is logged."""
clean = next(get_parent_and_child_modules(dev, Module.Clean))
caplog.set_level(logging.DEBUG)
clean.data["getVacStatus"]["status"] = 123
assert clean.status is Status.UnknownInternal
assert "Got unknown status code: 123" in caplog.text
@clean
@pytest.mark.parametrize(
("setting", "value", "exc", "exc_message"),
[
pytest.param(
"vacuum_fan_speed",
"invalid speed",
ValueError,
"Invalid fan speed",
id="vacuum_fan_speed",
),
pytest.param(
"carpet_clean_mode",
"invalid mode",
ValueError,
"Invalid carpet clean mode",
id="carpet_clean_mode",
),
],
)
async def test_invalid_settings(
dev: SmartDevice,
mocker: MockerFixture,
setting: str,
value: str,
exc: type[Exception],
exc_message: str,
):
"""Test invalid settings."""
clean = next(get_parent_and_child_modules(dev, Module.Clean))
# Not using feature.set_value() as it checks for valid values
setter_name = dev.features[setting].attribute_setter
assert isinstance(setter_name, str)
setter = getattr(clean, setter_name)
with pytest.raises(exc, match=exc_message):
await setter(value)