| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent b2a15af commit 9030179
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -35,7 +35,7 @@ async def _post_update_hook(self) -> None: | |||
| 35 | 35 | If the configured zone is not available on this host, compute the device's | |
| 36 | 36 | current UTC offset and choose a best-match available zone, preferring DST- | |
| 37 | 37 | observing candidates when the original index implies DST. As a last resort, | |
| 38 | - use a fixed-offset timezone. | ||
| 38 | + use a fixed-offset timezone. If the device clock is not set, use UTC. | ||
| 39 | 39 | """ | |
| 40 | 40 | if res := self.data.get("get_timezone"): | |
| 41 | 41 | idx = res.get("index") | |
@@ -58,6 +58,11 @@ async def _post_update_hook(self) -> None: | |||
| 58 | 58 | now_utc = datetime.now(UTC) | |
| 59 | 59 | delta = device_local - now_utc.replace(tzinfo=None) | |
| 60 | 60 | rounded = timedelta(seconds=60 * round(delta.total_seconds() / 60)) | |
| 61 | + # UTC offsets range from -12h to +14h, anything beyond that means the | ||
| 62 | + # device clock is not set (e.g. before provisioning). | ||
| 63 | + if abs(rounded) > timedelta(hours=14): | ||
| 64 | + self._timezone = UTC | ||
| 65 | + return | ||
| 61 | 66 | ||
| 62 | 67 | dst_expected = None | |
| 63 | 68 | if res := self.data.get("get_timezone"): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -513,6 +513,40 @@ async def test_time_post_update_uses_offset_when_index_missing_unit( | |||
| 513 | 513 | assert inst.timezone.utcoffset(now) == timedelta(0) | |
| 514 | 514 | ||
| 515 | 515 | ||
| 516 | + @device_iot | ||
| 517 | + async def test_time_post_update_unsynced_clock_uses_utc( | ||
| 518 | + dev: Device, mocker: MockerFixture | ||
| 519 | + ): | ||
| 520 | + """Fall back to UTC when the device clock is not set. | ||
| 521 | + | ||
| 522 | + An unprovisioned device can report e.g. year 2000, which is no valid UTC offset | ||
| 523 | + away from the host time, so the offset-based guess must not be attempted. | ||
| 524 | + """ | ||
| 525 | + from zoneinfo import ZoneInfoNotFoundError | ||
| 526 | + | ||
| 527 | + proto = dev.protocol._transport.proto # type: ignore[attr-defined] | ||
| 528 | + for target in ("time", "smartlife.iot.common.timesetting"): | ||
| 529 | + if target in proto: | ||
| 530 | + proto[target]["get_time"] = { | ||
| 531 | + "year": 2000, | ||
| 532 | + "month": 1, | ||
| 533 | + "mday": 1, | ||
| 534 | + "hour": 2, | ||
| 535 | + "min": 45, | ||
| 536 | + "sec": 0, | ||
| 537 | + } | ||
| 538 | + # Force the offset-based path, as when the zone is not available on the host | ||
| 539 | + mocker.patch( | ||
| 540 | + "kasa.iot.modules.time.get_timezone", | ||
| 541 | + new=AsyncMock(side_effect=ZoneInfoNotFoundError("missing on host")), | ||
| 542 | + ) | ||
| 543 | + | ||
| 544 | + await dev.update() | ||
| 545 | + time_mod = dev.modules[Module.Time] | ||
| 546 | + assert time_mod.timezone is UTC | ||
| 547 | + assert time_mod.time.year == 2000 | ||
| 548 | + | ||
| 549 | + | ||
| 516 | 550 | async def test_time_get_time_exception_returns_none_unit(mocker: MockerFixture): | |
| 517 | 551 | """Cover Time.get_time exception path (unit test of iot Time).""" | |
| 518 | 552 | from kasa.iot.modules.time import Time as TimeModule | |
| Back | FazBrowse Home | New Git URL |
0 commit comments