mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-22 19:23:34 +00:00
Stabilise on_since value for smart devices (#1144)
Caches the `on_since` value to prevent jitter caused by the device calculations.
This commit is contained in:
parent
81e2685605
commit
1fcf3e44c2
@ -435,7 +435,11 @@ class Device(ABC):
|
|||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def on_since(self) -> datetime | None:
|
def on_since(self) -> datetime | None:
|
||||||
"""Return the time that the device was turned on or None if turned off."""
|
"""Return the time that the device was turned on or None if turned off.
|
||||||
|
|
||||||
|
This returns a cached value if the device reported value difference is under
|
||||||
|
five seconds to avoid device-caused jitter.
|
||||||
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def wifi_scan(self) -> list[WifiNetwork]:
|
async def wifi_scan(self) -> list[WifiNetwork]:
|
||||||
|
@ -181,6 +181,7 @@ class IotDevice(Device):
|
|||||||
self._legacy_features: set[str] = set()
|
self._legacy_features: set[str] = set()
|
||||||
self._children: Mapping[str, IotDevice] = {}
|
self._children: Mapping[str, IotDevice] = {}
|
||||||
self._modules: dict[str | ModuleName[Module], IotModule] = {}
|
self._modules: dict[str | ModuleName[Module], IotModule] = {}
|
||||||
|
self._on_since: datetime | None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self) -> Sequence[IotDevice]:
|
def children(self) -> Sequence[IotDevice]:
|
||||||
@ -594,18 +595,25 @@ class IotDevice(Device):
|
|||||||
@property # type: ignore
|
@property # type: ignore
|
||||||
@requires_update
|
@requires_update
|
||||||
def on_since(self) -> datetime | None:
|
def on_since(self) -> datetime | None:
|
||||||
"""Return pretty-printed on-time, or None if not available."""
|
"""Return the time that the device was turned on or None if turned off.
|
||||||
if "on_time" not in self._sys_info:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if self.is_off:
|
This returns a cached value if the device reported value difference is under
|
||||||
|
five seconds to avoid device-caused jitter.
|
||||||
|
"""
|
||||||
|
if self.is_off or "on_time" not in self._sys_info:
|
||||||
|
self._on_since = None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
on_time = self._sys_info["on_time"]
|
on_time = self._sys_info["on_time"]
|
||||||
|
|
||||||
return datetime.now(timezone.utc).astimezone().replace(
|
time = datetime.now(timezone.utc).astimezone().replace(microsecond=0)
|
||||||
microsecond=0
|
|
||||||
) - timedelta(seconds=on_time)
|
on_since = time - timedelta(seconds=on_time)
|
||||||
|
if not self._on_since or timedelta(
|
||||||
|
seconds=0
|
||||||
|
) < on_since - self._on_since > timedelta(seconds=5):
|
||||||
|
self._on_since = on_since
|
||||||
|
return self._on_since
|
||||||
|
|
||||||
@property # type: ignore
|
@property # type: ignore
|
||||||
@requires_update
|
@requires_update
|
||||||
|
@ -318,6 +318,7 @@ class IotStripPlug(IotPlug):
|
|||||||
self._set_sys_info(parent.sys_info)
|
self._set_sys_info(parent.sys_info)
|
||||||
self._device_type = DeviceType.StripSocket
|
self._device_type = DeviceType.StripSocket
|
||||||
self.protocol = parent.protocol # Must use the same connection as the parent
|
self.protocol = parent.protocol # Must use the same connection as the parent
|
||||||
|
self._on_since: datetime | None = None
|
||||||
|
|
||||||
async def _initialize_modules(self):
|
async def _initialize_modules(self):
|
||||||
"""Initialize modules not added in init."""
|
"""Initialize modules not added in init."""
|
||||||
@ -438,14 +439,20 @@ class IotStripPlug(IotPlug):
|
|||||||
def on_since(self) -> datetime | None:
|
def on_since(self) -> datetime | None:
|
||||||
"""Return on-time, if available."""
|
"""Return on-time, if available."""
|
||||||
if self.is_off:
|
if self.is_off:
|
||||||
|
self._on_since = None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
info = self._get_child_info()
|
info = self._get_child_info()
|
||||||
on_time = info["on_time"]
|
on_time = info["on_time"]
|
||||||
|
|
||||||
return datetime.now(timezone.utc).astimezone().replace(
|
time = datetime.now(timezone.utc).astimezone().replace(microsecond=0)
|
||||||
microsecond=0
|
|
||||||
) - timedelta(seconds=on_time)
|
on_since = time - timedelta(seconds=on_time)
|
||||||
|
if not self._on_since or timedelta(
|
||||||
|
seconds=0
|
||||||
|
) < on_since - self._on_since > timedelta(seconds=5):
|
||||||
|
self._on_since = on_since
|
||||||
|
return self._on_since
|
||||||
|
|
||||||
@property # type: ignore
|
@property # type: ignore
|
||||||
@requires_update
|
@requires_update
|
||||||
|
@ -66,6 +66,7 @@ class SmartDevice(Device):
|
|||||||
self._children: Mapping[str, SmartDevice] = {}
|
self._children: Mapping[str, SmartDevice] = {}
|
||||||
self._last_update = {}
|
self._last_update = {}
|
||||||
self._last_update_time: float | None = None
|
self._last_update_time: float | None = None
|
||||||
|
self._on_since: datetime | None = None
|
||||||
|
|
||||||
async def _initialize_children(self):
|
async def _initialize_children(self):
|
||||||
"""Initialize children for power strips."""
|
"""Initialize children for power strips."""
|
||||||
@ -494,15 +495,25 @@ class SmartDevice(Device):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def on_since(self) -> datetime | None:
|
def on_since(self) -> datetime | None:
|
||||||
"""Return the time that the device was turned on or None if turned off."""
|
"""Return the time that the device was turned on or None if turned off.
|
||||||
|
|
||||||
|
This returns a cached value if the device reported value difference is under
|
||||||
|
five seconds to avoid device-caused jitter.
|
||||||
|
"""
|
||||||
if (
|
if (
|
||||||
not self._info.get("device_on")
|
not self._info.get("device_on")
|
||||||
or (on_time := self._info.get("on_time")) is None
|
or (on_time := self._info.get("on_time")) is None
|
||||||
):
|
):
|
||||||
|
self._on_since = None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
on_time = cast(float, on_time)
|
on_time = cast(float, on_time)
|
||||||
return self.time - timedelta(seconds=on_time)
|
on_since = self.time - timedelta(seconds=on_time)
|
||||||
|
if not self._on_since or timedelta(
|
||||||
|
seconds=0
|
||||||
|
) < on_since - self._on_since > timedelta(seconds=5):
|
||||||
|
self._on_since = on_since
|
||||||
|
return self._on_since
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def timezone(self) -> dict:
|
def timezone(self) -> dict:
|
||||||
|
Loading…
Reference in New Issue
Block a user