Merge remote-tracking branch 'upstream/master' into feat/light_module_feats

This commit is contained in:
Steven B
2024-12-23 09:46:11 +00:00
216 changed files with 11945 additions and 2156 deletions

View File

@@ -1,7 +1,14 @@
import copy
import logging
from contextlib import nullcontext as does_not_raise
from unittest.mock import patch
import pytest
from kasa import Module, SmartDevice
from kasa import DeviceError, Module
from kasa.exceptions import SmartErrorCode
from kasa.interfaces.energy import Energy
from kasa.smart import SmartDevice
from kasa.smart.modules import Energy as SmartEnergyModule
from tests.conftest import has_emeter_smart
@@ -19,3 +26,84 @@ async def test_supported(dev: SmartDevice):
assert energy_module.supports(Energy.ModuleFeature.VOLTAGE_CURRENT) is False
else:
assert energy_module.supports(Energy.ModuleFeature.VOLTAGE_CURRENT) is True
@has_emeter_smart
async def test_get_energy_usage_error(
dev: SmartDevice, caplog: pytest.LogCaptureFixture
):
"""Test errors on get_energy_usage."""
caplog.set_level(logging.DEBUG)
energy_module = dev.modules.get(Module.Energy)
if not energy_module:
pytest.skip(f"Energy module not supported for {dev}.")
version = dev._components["energy_monitoring"]
expected_raise = does_not_raise() if version > 1 else pytest.raises(DeviceError)
if version > 1:
expected = "get_energy_usage"
expected_current_consumption = 2.002
else:
expected = "current_power"
expected_current_consumption = None
assert expected in energy_module.data
assert energy_module.current_consumption is not None
assert energy_module.consumption_today is not None
assert energy_module.consumption_this_month is not None
last_update = copy.deepcopy(dev._last_update)
resp = copy.deepcopy(last_update)
if ed := resp.get("get_emeter_data"):
ed["power_mw"] = 2002
if cp := resp.get("get_current_power"):
cp["current_power"] = 2.002
resp["get_energy_usage"] = SmartErrorCode.JSON_DECODE_FAIL_ERROR
# version 1 only has get_energy_usage so module should raise an error if
# version 1 and get_energy_usage is in error
with patch.object(dev.protocol, "query", return_value=resp):
await dev.update()
with expected_raise:
assert "get_energy_usage" not in energy_module.data
assert energy_module.current_consumption == expected_current_consumption
assert energy_module.consumption_today is None
assert energy_module.consumption_this_month is None
msg = (
f"Removed key get_energy_usage from response for device {dev.host}"
" as it returned error: JSON_DECODE_FAIL_ERROR"
)
if version > 1:
assert msg in caplog.text
# Now test with no get_emeter_data
# This may not be valid scenario but we have a fallback to get_current_power
# just in case that should be tested.
caplog.clear()
resp = copy.deepcopy(last_update)
if cp := resp.get("get_current_power"):
cp["current_power"] = 2.002
resp["get_energy_usage"] = SmartErrorCode.JSON_DECODE_FAIL_ERROR
# Remove get_emeter_data from the response and from the device which will
# remember it otherwise.
resp.pop("get_emeter_data", None)
dev._last_update.pop("get_emeter_data", None)
with patch.object(dev.protocol, "query", return_value=resp):
await dev.update()
with expected_raise:
assert "get_energy_usage" not in energy_module.data
assert energy_module.current_consumption == expected_current_consumption
# message should only be logged once
assert msg not in caplog.text

View File

@@ -0,0 +1,16 @@
from kasa import Module
from kasa.smart import SmartDevice
from ...device_fixtures import parametrize
homekit = parametrize(
"has homekit", component_filter="homekit", protocol_filter={"SMART"}
)
@homekit
async def test_info(dev: SmartDevice):
"""Test homekit info."""
homekit = dev.modules.get(Module.HomeKit)
assert homekit
assert homekit.info

View File

@@ -0,0 +1,20 @@
from kasa import Module
from kasa.smart import SmartDevice
from ...device_fixtures import parametrize
matter = parametrize(
"has matter", component_filter="matter", protocol_filter={"SMART", "SMARTCAM"}
)
@matter
async def test_info(dev: SmartDevice):
"""Test matter info."""
matter = dev.modules.get(Module.Matter)
assert matter
assert matter.info
setup_code = dev.features.get("matter_setup_code")
assert setup_code
setup_payload = dev.features.get("matter_setup_payload")
assert setup_payload