mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-08-09 20:24:02 +00:00
Add powerprotection module (#1337)
Some checks are pending
CI / Perform linting checks (3.13) (push) Waiting to run
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.13) (push) Blocked by required conditions
CodeQL checks / Analyze (python) (push) Waiting to run
Some checks are pending
CI / Perform linting checks (3.13) (push) Waiting to run
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, macos-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, ubuntu-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (false, windows-latest, 3.13) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.11) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.12) (push) Blocked by required conditions
CI / Python ${{ matrix.python-version}} on ${{ matrix.os }}${{ fromJSON('[" (extras)", ""]')[matrix.extras == ''] }} (true, ubuntu-latest, 3.13) (push) Blocked by required conditions
CodeQL checks / Analyze (python) (push) Waiting to run
Implements power protection on supported devices. If the power usage is above the given threshold and the feature is enabled, the device will be turned off. Adds the following features: * `overloaded` binary sensor * `power_protection_threshold` number, setting this to `0` turns the feature off. --------- Co-authored-by: Steven B <51370195+sdb9696@users.noreply.github.com>
This commit is contained in:
98
tests/smart/modules/test_powerprotection.py
Normal file
98
tests/smart/modules/test_powerprotection.py
Normal file
@@ -0,0 +1,98 @@
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from kasa import Module, SmartDevice
|
||||
|
||||
from ...device_fixtures import get_parent_and_child_modules, parametrize
|
||||
|
||||
powerprotection = parametrize(
|
||||
"has powerprotection",
|
||||
component_filter="power_protection",
|
||||
protocol_filter={"SMART"},
|
||||
)
|
||||
|
||||
|
||||
@powerprotection
|
||||
@pytest.mark.parametrize(
|
||||
("feature", "prop_name", "type"),
|
||||
[
|
||||
("overloaded", "overloaded", bool),
|
||||
("power_protection_threshold", "protection_threshold", int),
|
||||
],
|
||||
)
|
||||
async def test_features(dev, feature, prop_name, type):
|
||||
"""Test that features are registered and work as expected."""
|
||||
powerprot = next(get_parent_and_child_modules(dev, Module.PowerProtection))
|
||||
assert powerprot
|
||||
device = powerprot._device
|
||||
|
||||
prop = getattr(powerprot, prop_name)
|
||||
assert isinstance(prop, type)
|
||||
|
||||
feat = device.features[feature]
|
||||
assert feat.value == prop
|
||||
assert isinstance(feat.value, type)
|
||||
|
||||
|
||||
@powerprotection
|
||||
async def test_set_enable(dev: SmartDevice, mocker: MockerFixture):
|
||||
"""Test enable."""
|
||||
powerprot = next(get_parent_and_child_modules(dev, Module.PowerProtection))
|
||||
assert powerprot
|
||||
device = powerprot._device
|
||||
|
||||
original_enabled = powerprot.enabled
|
||||
original_threshold = powerprot.protection_threshold
|
||||
|
||||
try:
|
||||
# Simple enable with an existing threshold
|
||||
call_spy = mocker.spy(powerprot, "call")
|
||||
await powerprot.set_enabled(True)
|
||||
params = {
|
||||
"enabled": True,
|
||||
"protection_power": mocker.ANY,
|
||||
}
|
||||
call_spy.assert_called_with("set_protection_power", params)
|
||||
|
||||
# Enable with no threshold param when 0
|
||||
call_spy.reset_mock()
|
||||
await powerprot.set_protection_threshold(0)
|
||||
await device.update()
|
||||
await powerprot.set_enabled(True)
|
||||
params = {
|
||||
"enabled": True,
|
||||
"protection_power": int(powerprot._max_power / 2),
|
||||
}
|
||||
call_spy.assert_called_with("set_protection_power", params)
|
||||
|
||||
# Enable false should not update the threshold
|
||||
call_spy.reset_mock()
|
||||
await powerprot.set_protection_threshold(0)
|
||||
await device.update()
|
||||
await powerprot.set_enabled(False)
|
||||
params = {
|
||||
"enabled": False,
|
||||
"protection_power": 0,
|
||||
}
|
||||
call_spy.assert_called_with("set_protection_power", params)
|
||||
|
||||
finally:
|
||||
await powerprot.set_enabled(original_enabled, threshold=original_threshold)
|
||||
|
||||
|
||||
@powerprotection
|
||||
async def test_set_threshold(dev: SmartDevice, mocker: MockerFixture):
|
||||
"""Test enable."""
|
||||
powerprot = next(get_parent_and_child_modules(dev, Module.PowerProtection))
|
||||
assert powerprot
|
||||
|
||||
call_spy = mocker.spy(powerprot, "call")
|
||||
await powerprot.set_protection_threshold(123)
|
||||
params = {
|
||||
"enabled": mocker.ANY,
|
||||
"protection_power": 123,
|
||||
}
|
||||
call_spy.assert_called_with("set_protection_power", params)
|
||||
|
||||
with pytest.raises(ValueError, match="Threshold out of range"):
|
||||
await powerprot.set_protection_threshold(-10)
|
Reference in New Issue
Block a user