python-kasa/kasa/smartcam/modules/time.py
2024-11-23 09:07:47 +01:00

91 lines
3.0 KiB
Python

"""Implementation of time module."""
from __future__ import annotations
from datetime import UTC, datetime, tzinfo
from typing import cast
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
from ...cachedzoneinfo import CachedZoneInfo
from ...feature import Feature
from ...interfaces import Time as TimeInterface
from ..smartcammodule import SmartCamModule
class Time(SmartCamModule, TimeInterface):
"""Implementation of device_local_time."""
QUERY_GETTER_NAME = "getTimezone"
QUERY_MODULE_NAME = "system"
QUERY_SECTION_NAMES = "basic"
_timezone: tzinfo = UTC
_time: datetime
def _initialize_features(self) -> None:
"""Initialize features after the initial update."""
self._add_feature(
Feature(
device=self._device,
id="device_time",
name="Device time",
attribute_getter="time",
container=self,
category=Feature.Category.Debug,
type=Feature.Type.Sensor,
)
)
def query(self) -> dict:
"""Query to execute during the update cycle."""
q = super().query()
q["getClockStatus"] = {self.QUERY_MODULE_NAME: {"name": "clock_status"}}
return q
async def _post_update_hook(self) -> None:
"""Perform actions after a device update."""
time_data = self.data["getClockStatus"]["system"]["clock_status"]
timezone_data = self.data["getTimezone"]["system"]["basic"]
zone_id = timezone_data["zone_id"]
timestamp = time_data["seconds_from_1970"]
try:
# Zoneinfo will return a DST aware object
tz: tzinfo = await CachedZoneInfo.get_cached_zone_info(zone_id)
except ZoneInfoNotFoundError:
# timezone string like: UTC+10:00
timezone_str = timezone_data["timezone"]
tz = cast(tzinfo, datetime.strptime(timezone_str[-6:], "%z").tzinfo)
self._timezone = tz
self._time = datetime.fromtimestamp(
cast(float, timestamp),
tz=tz,
)
@property
def timezone(self) -> tzinfo:
"""Return current timezone."""
return self._timezone
@property
def time(self) -> datetime:
"""Return device's current datetime."""
return self._time
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()
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