8000 Cache zoneinfo for smart devices (#1156) · msz-coder/python-kasa@7c1686d · GitHub
[go: up one dir, main page]

Skip to content

Commit 7c1686d

Browse files
authored
Cache zoneinfo for smart devices (python-kasa#1156)
1 parent 9641edc commit 7c1686d

File tree

3 files changed

+45
-32
lines changed

3 files changed

+45
-32
lines changed

kasa/cachedzoneinfo.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Module for caching ZoneInfos."""
2+
3+
from __future__ import annotations
4+
5+
import asyncio
6+
7+
from zoneinfo import ZoneInfo
8+
9+
10+
class CachedZoneInfo(ZoneInfo):
11+
"""Cache ZoneInfo objects."""
12+
13+
_cache: dict[str, ZoneInfo] = {}
14+
15+
@classmethod
16+
async def get_cached_zone_info(cls, time_zone_str: str) -> ZoneInfo:
17+
"""Get a cached zone info object."""
18+
if cached := cls._cache.get(time_zone_str):
19+
return cached
20+
loop = asyncio.get_running_loop()
21+
zinfo = await loop.run_in_executor(None, _get_zone_info, time_zone_str)
22+
cls._cache[time_zone_str] = zinfo
23+
return zinfo
24+
25+
26+
def _get_zone_info(time_zone_str: str) -> ZoneInfo:
27+
"""Get a time zone object for the given time zone string."""
28+
return ZoneInfo(time_zone_str)

kasa/iot/iottimezone.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
from __future__ import annotations
44

5-
import asyncio
65
import logging
76
from datetime import datetime, tzinfo
87

9-
from zoneinfo import ZoneInfo
8+
from ..cachedzoneinfo import CachedZoneInfo
109

1110
_LOGGER = logging.getLogger(__name__)
1211

@@ -17,10 +16,10 @@ async def get_timezone(index: int) -> tzinfo:
1716
_LOGGER.error(
1817
"Unexpected index %s not configured as a timezone, defaulting to UTC", index
1918
)
20-
return await _CachedZoneInfo.get_cached_zone_info("Etc/UTC")
19+
return await CachedZoneInfo.get_cached_zone_info("Etc/UTC")
2120

2221
name = TIMEZONE_INDEX[index]
23-
return await _CachedZoneInfo.get_cached_zone_info(name)
22+
return await CachedZoneInfo.get_cached_zone_info(name)
2423

2524

2625
async def get_timezone_index(name: str) -> int:
@@ -30,7 +29,7 @@ async def get_timezone_index(name: str) -> int:
3029
return rev[name]
3130

3231
# Try to find a supported timezone matching dst true/false
33-
zone = await _CachedZoneInfo.get_cached_zone_info(name)
32+
zone = await CachedZoneInfo.get_cached_zone_info(name)
3433
now = datetime.now()
3534
winter = datetime(now.year, 1, 1, 12)
3635
summer = datetime(now.year, 7, 1, 12)
@@ -43,27 +42,6 @@ async def get_timezone_index(name: str) -> int:
4342
raise ValueError("Device does not support timezone %s", name)
4443

4544

46-
class _CachedZoneInfo(ZoneInfo):
47-
"""Cache zone info objects."""
48-
49-
_cache: dict[str, ZoneInfo] = {}
50-
51-
@classmethod
52-
async def get_cached_zone_info(cls, time_zone_str: str) -> ZoneInfo:
53-
"""Get a cached zone info object."""
54-
if cached := cls._cache.get(time_zone_str):
55-
return cached
56-
loop = asyncio.get_running_loop()
57-
zinfo = await loop.run_in_executor(None, _get_zone_info, time_zone_str)
58-
cls._cache[time_zone_str] = zinfo
59-
return zinfo
60-
61-
< 6D40 /div>
62-
def _get_zone_info(time_zone_str: str) -> ZoneInfo:
63-
"""Get a time zone object for the given time zone string."""
64-
return ZoneInfo(time_zone_str)
65-
66-
6745
TIMEZONE_INDEX = {
6846
0: "Etc/GMT+12",
6947
1: "Pacific/Samoa",

kasa/smart/modules/time.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
from time import mktime
77
from typing import cast
88

9-
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
9+
from zoneinfo import ZoneInfoNotFoundError
1010

11+
from ...cachedzoneinfo import CachedZoneInfo
1112
from ...feature import Feature
1213
from ..smartmodule import SmartModule
1314

@@ -18,6 +19,8 @@ class Time(SmartModule):
1819
REQUIRED_COMPONENT = "time"
1920
QUERY_GETTER_NAME = "get_device_time"
2021

22+
_timezone: tzinfo = timezone.utc
23+
2124
def _initialize_features(self):
2225
"""Initialize features after the initial update."""
2326
self._add_feature(
@@ -32,21 +35,25 @@ def _initialize_features(self):
3235
)
3336
)
3437

35-
@property
36-
def timezone(self) -> tzinfo:
37-
"""Return current timezone."""
38+
async def _post_update_hook(self):
39+
"""Perform actions after a device update."""
3840
td = timedelta(minutes=cast(float, self.data.get("time_diff")))
3941
if region := self.data.get("region"):
4042
try:
4143
# Zoneinfo will return a DST aware object
42-
tz: tzinfo = ZoneInfo(region)
44+
tz: tzinfo = await CachedZoneInfo.get_cached_zone_info(region)
4345
except ZoneInfoNotFoundError:
4446
tz = timezone(td, region)
4547
else:
4648
# in case the device returns a blank region this will result in the
4749
# tzname being a UTC offset
4850
tz = timezone(td)
49-
return tz
51+
self._timezone = tz
52+
53+
@property
54+
def timezone(self) -> tzinfo:
55+
"""Return current timezone."""
56+
return self._timezone
5057

5158
@property
5259
def time(self) -> datetime:

0 commit comments

Comments
 (0)
0