Add battery module to smartcam devices (#1452)
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

This commit is contained in:
Steven B.
2025-01-14 21:57:35 +00:00
committed by GitHub
parent 2542516009
commit 4e7e18cef1
10 changed files with 200 additions and 25 deletions

View File

@@ -435,6 +435,15 @@ async def get_device_for_fixture(
d = device_for_fixture_name(fixture_data.name, fixture_data.protocol)(
host="127.0.0.123"
)
# smart child devices sometimes check _is_hub_child which needs a parent
# of DeviceType.Hub
class DummyParent:
device_type = DeviceType.Hub
if fixture_data.protocol in {"SMARTCAM.CHILD"}:
d._parent = DummyParent()
if fixture_data.protocol in {"SMART", "SMART.CHILD"}:
d.protocol = FakeSmartProtocol(
fixture_data.data, fixture_data.name, verbatim=verbatim

View File

@@ -262,7 +262,10 @@ class FakeSmartTransport(BaseTransport):
child_fixture["get_device_info"]["device_id"] = device_id
found_child_fixture_infos.append(child_fixture["get_device_info"])
child_protocols[device_id] = FakeSmartProtocol(
child_fixture, fixture_info_tuple.name, is_child=True
child_fixture,
fixture_info_tuple.name,
is_child=True,
verbatim=verbatim,
)
# Look for fixture inline
elif (child_fixtures := parent_fixture_info.get("child_devices")) and (
@@ -273,6 +276,7 @@ class FakeSmartTransport(BaseTransport):
child_fixture,
f"{parent_fixture_name}-{device_id}",
is_child=True,
verbatim=verbatim,
)
else:
pytest.fixtures_missing_methods.setdefault( # type: ignore[attr-defined]
@@ -299,7 +303,10 @@ class FakeSmartTransport(BaseTransport):
# list for smartcam children in order for updates to work.
found_child_fixture_infos.append(child_fixture[CHILD_INFO_FROM_PARENT])
child_protocols[device_id] = FakeSmartCamProtocol(
child_fixture, fixture_info_tuple.name, is_child=True
child_fixture,
fixture_info_tuple.name,
is_child=True,
verbatim=verbatim,
)
else:
warn(

View File

@@ -6,7 +6,7 @@ from typing import Any
from kasa import Credentials, DeviceConfig, SmartProtocol
from kasa.protocols.smartcamprotocol import SmartCamProtocol
from kasa.smartcam.smartcamchild import CHILD_INFO_FROM_PARENT
from kasa.smartcam.smartcamchild import CHILD_INFO_FROM_PARENT, SmartCamChild
from kasa.transports.basetransport import BaseTransport
from .fakeprotocol_smart import FakeSmartTransport
@@ -243,6 +243,20 @@ class FakeSmartCamTransport(BaseTransport):
else:
return {"error_code": -1}
# smartcam child devices do not make requests for getDeviceInfo as they
# get updated from the parent's query. If this is being called from a
# child it must be because the fixture has been created directly on the
# child device with a dummy parent. In this case return the child info
# from parent that's inside the fixture.
if (
not self.verbatim
and method == "getDeviceInfo"
and (cifp := info.get(CHILD_INFO_FROM_PARENT))
):
mapped = SmartCamChild._map_child_info_from_parent(cifp)
result = {"device_info": {"basic_info": mapped}}
return {"result": result, "error_code": 0}
if method in info:
params = request_dict.get("params")
result = copy.deepcopy(info[method])

View File

@@ -269,7 +269,7 @@ async def test_hub_children_update_delays(
for modname, module in child._modules.items():
if (
not (q := module.query())
and modname not in {"DeviceModule", "Light"}
and modname not in {"DeviceModule", "Light", "Battery", "Camera"}
and not module.SYSINFO_LOOKUP_KEYS
):
q = {f"get_dummy_{modname}": {}}

View File

@@ -0,0 +1,33 @@
"""Tests for smartcam battery module."""
from __future__ import annotations
from kasa import Device
from kasa.smartcam.smartcammodule import SmartCamModule
from ...device_fixtures import parametrize
battery_smartcam = parametrize(
"has battery",
component_filter="battery",
protocol_filter={"SMARTCAM", "SMARTCAM.CHILD"},
)
@battery_smartcam
async def test_battery(dev: Device):
"""Test device battery."""
battery = dev.modules.get(SmartCamModule.SmartCamBattery)
assert battery
feat_ids = {
"battery_level",
"battery_low",
"battery_temperature",
"battery_voltage",
"battery_charging",
}
for feat_id in feat_ids:
feat = dev.features.get(feat_id)
assert feat
assert feat.value is not None