mirror of
https://github.com/python-kasa/python-kasa.git
synced 2024-12-22 19:23:34 +00:00
a01247d48f
Python 3.11 ships with latest Debian Bookworm. pypy is not that widely used with this library based on statistics. It could be added back when pypy supports python 3.11.
186 lines
5.0 KiB
Python
186 lines
5.0 KiB
Python
"""Module for io device timezone lookups."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import datetime, timedelta, tzinfo
|
|
from typing import cast
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from ..cachedzoneinfo import CachedZoneInfo
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def get_timezone(index: int) -> tzinfo:
|
|
"""Get the timezone from the index."""
|
|
if index > 109:
|
|
_LOGGER.error(
|
|
"Unexpected index %s not configured as a timezone, defaulting to UTC", index
|
|
)
|
|
return await CachedZoneInfo.get_cached_zone_info("Etc/UTC")
|
|
|
|
name = TIMEZONE_INDEX[index]
|
|
return await CachedZoneInfo.get_cached_zone_info(name)
|
|
|
|
|
|
async def get_timezone_index(tzone: tzinfo) -> int:
|
|
"""Return the iot firmware index for a valid IANA timezone key."""
|
|
if isinstance(tzone, ZoneInfo):
|
|
name = tzone.key
|
|
rev = {val: key for key, val in TIMEZONE_INDEX.items()}
|
|
if name in rev:
|
|
return rev[name]
|
|
|
|
for i in range(110):
|
|
if _is_same_timezone(tzone, await get_timezone(i)):
|
|
return i
|
|
raise ValueError("Device does not support timezone %s", name)
|
|
|
|
|
|
async def get_matching_timezones(tzone: tzinfo) -> list[str]:
|
|
"""Return the iot firmware index for a valid IANA timezone key."""
|
|
matches = []
|
|
if isinstance(tzone, ZoneInfo):
|
|
name = tzone.key
|
|
vals = {val for val in TIMEZONE_INDEX.values()}
|
|
if name in vals:
|
|
matches.append(name)
|
|
|
|
for i in range(110):
|
|
fw_tz = await get_timezone(i)
|
|
if _is_same_timezone(tzone, fw_tz):
|
|
match_key = cast(ZoneInfo, fw_tz).key
|
|
if match_key not in matches:
|
|
matches.append(match_key)
|
|
return matches
|
|
|
|
|
|
def _is_same_timezone(tzone1: tzinfo, tzone2: tzinfo) -> bool:
|
|
"""Return true if the timezones have the same utcffset and dst offset.
|
|
|
|
Iot devices only support a limited static list of IANA timezones; this is used to
|
|
check if a static timezone matches the same utc offset and dst settings.
|
|
"""
|
|
now = datetime.now()
|
|
start_day = datetime(now.year, 1, 1, 12)
|
|
for i in range(365):
|
|
the_day = start_day + timedelta(days=i)
|
|
if tzone1.utcoffset(the_day) != tzone2.utcoffset(the_day):
|
|
return False
|
|
return True
|
|
|
|
|
|
TIMEZONE_INDEX = {
|
|
0: "Etc/GMT+12",
|
|
1: "Pacific/Samoa",
|
|
2: "US/Hawaii",
|
|
3: "US/Alaska",
|
|
4: "Mexico/BajaNorte",
|
|
5: "Etc/GMT+8",
|
|
6: "PST8PDT",
|
|
7: "US/Arizona",
|
|
8: "America/Mazatlan",
|
|
9: "MST",
|
|
10: "MST7MDT",
|
|
11: "Mexico/General",
|
|
12: "Etc/GMT+6",
|
|
13: "CST6CDT",
|
|
14: "America/Monterrey",
|
|
15: "Canada/Saskatchewan",
|
|
16: "America/Bogota",
|
|
17: "Etc/GMT+5",
|
|
18: "EST",
|
|
19: "America/Indiana/Indianapolis",
|
|
20: "America/Caracas",
|
|
21: "America/Asuncion",
|
|
22: "Etc/GMT+4",
|
|
23: "Canada/Atlantic",
|
|
24: "America/Cuiaba",
|
|
25: "Brazil/West",
|
|
26: "America/Santiago",
|
|
27: "Canada/Newfoundland",
|
|
28: "America/Sao_Paulo",
|
|
29: "America/Argentina/Buenos_Aires",
|
|
30: "America/Cayenne",
|
|
31: "America/Miquelon",
|
|
32: "America/Montevideo",
|
|
33: "Chile/Continental",
|
|
34: "Etc/GMT+2",
|
|
35: "Atlantic/Azores",
|
|
36: "Atlantic/Cape_Verde",
|
|
37: "Africa/Casablanca",
|
|
38: "UCT",
|
|
39: "GB",
|
|
40: "Africa/Monrovia",
|
|
41: "Europe/Amsterdam",
|
|
42: "Europe/Belgrade",
|
|
43: "Europe/Brussels",
|
|
44: "Europe/Sarajevo",
|
|
45: "Africa/Lagos",
|
|
46: "Africa/Windhoek",
|
|
47: "Asia/Amman",
|
|
48: "Europe/Athens",
|
|
49: "Asia/Beirut",
|
|
50: "Africa/Cairo",
|
|
51: "Asia/Damascus",
|
|
52: "EET",
|
|
53: "Africa/Harare",
|
|
54: "Europe/Helsinki",
|
|
55: "Asia/Istanbul",
|
|
56: "Asia/Jerusalem",
|
|
57: "Europe/Kaliningrad",
|
|
58: "Africa/Tripoli",
|
|
59: "Asia/Baghdad",
|
|
60: "Asia/Kuwait",
|
|
61: "Europe/Minsk",
|
|
62: "Europe/Moscow",
|
|
63: "Africa/Nairobi",
|
|
64: "Asia/Tehran",
|
|
65: "Asia/Muscat",
|
|
66: "Asia/Baku",
|
|
67: "Europe/Samara",
|
|
68: "Indian/Mauritius",
|
|
69: "Asia/Tbilisi",
|
|
70: "Asia/Yerevan",
|
|
71: "Asia/Kabul",
|
|
72: "Asia/Ashgabat",
|
|
73: "Asia/Yekaterinburg",
|
|
74: "Asia/Karachi",
|
|
75: "Asia/Kolkata",
|
|
76: "Asia/Colombo",
|
|
77: "Asia/Kathmandu",
|
|
78: "Asia/Almaty",
|
|
79: "Asia/Dhaka",
|
|
80: "Asia/Novosibirsk",
|
|
81: "Asia/Rangoon",
|
|
82: "Asia/Bangkok",
|
|
83: "Asia/Krasnoyarsk",
|
|
84: "Asia/Chongqing",
|
|
85: "Asia/Irkutsk",
|
|
86: "Asia/Singapore",
|
|
87: "Australia/Perth",
|
|
88: "Asia/Taipei",
|
|
89: "Asia/Ulaanbaatar",
|
|
90: "Asia/Tokyo",
|
|
91: "Asia/Seoul",
|
|
92: "Asia/Yakutsk",
|
|
93: "Australia/Adelaide",
|
|
94: "Australia/Darwin",
|
|
95: "Australia/Brisbane",
|
|
96: "Australia/Canberra",
|
|
97: "Pacific/Guam",
|
|
98: "Australia/Hobart",
|
|
99: "Antarctica/DumontDUrville",
|
|
100: "Asia/Magadan",
|
|
101: "Asia/Srednekolymsk",
|
|
102: "Etc/GMT-11",
|
|
103: "Asia/Anadyr",
|
|
104: "Pacific/Auckland",
|
|
105: "Etc/GMT-12",
|
|
106: "Pacific/Fiji",
|
|
107: "Etc/GMT-13",
|
|
108: "Pacific/Apia",
|
|
109: "Etc/GMT-14",
|
|
}
|