Fix iotstrip child device time handling (#1584)
Some checks failed
CI / Perform linting checks (3.13) (push) Has been cancelled
CodeQL checks / Analyze (python) (push) Has been cancelled
CI / Python 3.11 on macos-latest (push) Has been cancelled
CI / Python 3.12 on macos-latest (push) Has been cancelled
CI / Python 3.13 on macos-latest (push) Has been cancelled
CI / Python 3.11 on ubuntu-latest (push) Has been cancelled
CI / Python 3.12 on ubuntu-latest (push) Has been cancelled
CI / Python 3.13 on ubuntu-latest (push) Has been cancelled
CI / Python 3.11 on windows-latest (push) Has been cancelled
CI / Python 3.12 on windows-latest (push) Has been cancelled
CI / Python 3.13 on windows-latest (push) Has been cancelled
Stale / stale (push) Has been cancelled

This fixes the time handling of the child devices for iotstrip to
pull from the parent device time module instead of having each child
with its own time module.
This commit is contained in:
ZeliardM
2025-10-31 16:32:13 -04:00
committed by GitHub
parent adc291b62e
commit 29007e1079
3 changed files with 66 additions and 0 deletions

View File

@@ -7,6 +7,9 @@ from collections import defaultdict
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from datetime import tzinfo
from ..device_type import DeviceType
from ..deviceconfig import DeviceConfig
from ..emeterstatus import EmeterStatus
@@ -349,6 +352,8 @@ class IotStripPlug(IotPlug):
self.add_module(Module.IotAntitheft, Antitheft(self, "anti_theft"))
self.add_module(Module.IotSchedule, Schedule(self, "schedule"))
self.add_module(Module.IotCountdown, Countdown(self, "countdown"))
# Note: do not add a Time module to the child; time is device-level.
# Child exposes time/timezone by delegating to the parent.
async def _initialize_features(self) -> None:
"""Initialize common features."""
@@ -441,6 +446,18 @@ class IotStripPlug(IotPlug):
"""
return False
@property # type: ignore
@requires_update
def time(self) -> datetime:
"""Return current time, delegated from the parent strip."""
return self._parent.time
@property # type: ignore
@requires_update
def timezone(self) -> tzinfo:
"""Return timezone, delegated from the parent strip."""
return self._parent.timezone
@property # type: ignore
@requires_update
def device_id(self) -> str:

View File

@@ -310,6 +310,11 @@ bulb = parametrize_combine([bulb_smart, bulb_iot])
strip_iot = parametrize(
"strip devices iot", model_filter=STRIPS_IOT, protocol_filter={"IOT"}
)
strip_emeter_iot = parametrize(
"strip devices iot with emeter",
model_filter=STRIPS_IOT & WITH_EMETER_IOT,
protocol_filter={"IOT"},
)
strip_smart = parametrize(
"strip devices smart", model_filter=STRIPS_SMART, protocol_filter={"SMART"}
)

View File

@@ -0,0 +1,44 @@
from unittest.mock import AsyncMock
from kasa import Module
from tests.conftest import strip_emeter_iot, strip_iot
@strip_iot
async def test_strip_update_and_child_update_behaviors(dev):
await dev.update()
await dev.update(update_children=False)
assert dev.children, "Expected strip device to have children"
child = dev.children[0]
await child.update(update_children=False)
assert getattr(child, "_features", None)
@strip_iot
async def test_strip_child_delegated_properties(dev):
await dev.update()
child = dev.children[0]
assert child.led is False
assert child.time == dev.time
assert child.timezone == dev.timezone
na = child.next_action
assert isinstance(na, dict)
assert "type" in na
@strip_emeter_iot
async def test_strip_emeter_erase_stats(dev, mocker):
await dev.update()
for child in dev.children:
energy = child.modules.get(Module.Energy)
if energy:
mocker.patch.object(energy, "erase_stats", AsyncMock(return_value={}))
res = await dev.modules[Module.Energy].erase_stats()
assert res == {}