mirror of
https://github.com/python-kasa/python-kasa.git
synced 2026-07-11 09:52:04 +00:00
Fix SMARTCAM Time module and update tests (#1659)
Update SmartCam time handling to apply timezone-only changes with explicit warnings, while keeping common time and CLI tests focused on devices that support setting clock time and adding SmartCam-specific coverage for the special behavior.
This commit is contained in:
@@ -2,16 +2,20 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime, tzinfo
|
||||
import logging
|
||||
from datetime import UTC, datetime, timedelta, tzinfo
|
||||
from typing import cast
|
||||
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||
|
||||
from ...cachedzoneinfo import CachedZoneInfo
|
||||
from ...exceptions import KasaException
|
||||
from ...feature import Feature
|
||||
from ...interfaces import Time as TimeInterface
|
||||
from ...smart.smartmodule import allow_update_after
|
||||
from ..smartcammodule import SmartCamModule
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Time(SmartCamModule, TimeInterface):
|
||||
"""Implementation of device_local_time."""
|
||||
@@ -76,17 +80,35 @@ class Time(SmartCamModule, TimeInterface):
|
||||
|
||||
@allow_update_after
|
||||
async def set_time(self, dt: datetime) -> dict:
|
||||
"""Set device time."""
|
||||
if not dt.tzinfo:
|
||||
timestamp = dt.replace(tzinfo=self.timezone).timestamp()
|
||||
else:
|
||||
timestamp = dt.timestamp()
|
||||
"""Set device timezone derived from the datetime."""
|
||||
_LOGGER.warning(
|
||||
"SmartCam devices do not support setting clock time directly; "
|
||||
"only timezone settings will be updated."
|
||||
)
|
||||
timezone = dt.tzinfo or self.timezone
|
||||
if not isinstance(timezone, ZoneInfo):
|
||||
raise KasaException(
|
||||
"SmartCam devices can only update timezone using zoneinfo "
|
||||
"timezones; setting clock time is not supported."
|
||||
)
|
||||
|
||||
lt = datetime.fromtimestamp(timestamp).isoformat().replace("T", " ")
|
||||
params = {"seconds_from_1970": int(timestamp), "local_time": lt}
|
||||
# Doesn't seem to update the time, perhaps because timing_mode is ntp
|
||||
res = await self.call("setTimezone", {"system": {"clock_status": params}})
|
||||
if (zinfo := dt.tzinfo) and isinstance(zinfo, ZoneInfo):
|
||||
tz_params = {"zone_id": zinfo.key}
|
||||
res = await self.call("setTimezone", {"system": {"basic": tz_params}})
|
||||
return res
|
||||
utc_offset = cast(timedelta | None, timezone.utcoffset(dt))
|
||||
params: dict[str, str] = {
|
||||
"timezone": self._format_utc_offset(utc_offset),
|
||||
"zone_id": timezone.key,
|
||||
}
|
||||
|
||||
return await self.call("setTimezone", {"system": {"basic": params}})
|
||||
|
||||
@staticmethod
|
||||
def _format_utc_offset(offset: timedelta | None) -> str:
|
||||
"""Format a timedelta offset as UTC+HH:MM/UTC-HH:MM."""
|
||||
if offset is None:
|
||||
offset = timedelta(0)
|
||||
|
||||
total_seconds = int(offset.total_seconds())
|
||||
sign = "+" if total_seconds >= 0 else "-"
|
||||
total_seconds = abs(total_seconds)
|
||||
hours, remainder = divmod(total_seconds, 3600)
|
||||
minutes = remainder // 60
|
||||
return f"UTC{sign}{hours:02d}:{minutes:02d}"
|
||||
|
||||
Reference in New Issue
Block a user