From b220beb8118660387b539db0c432d0fc6f514197 Mon Sep 17 00:00:00 2001 From: "Steven B." <51370195+sdb9696@users.noreply.github.com> Date: Tue, 16 Jul 2024 13:25:32 +0100 Subject: [PATCH] Use monotonic time for query timing (#1070) To fix intermittent issues with [windows CI](https://github.com/python-kasa/python-kasa/actions/runs/9952477932/job/27493918272?pr=1068). Probably better to use monotonic here anyway. ``` FAILED kasa/tests/test_smartdevice.py::test_update_module_update_delays[L530E(EU)_3.0_1.1.6.json-SMART] - ValueError: Clock moved backwards. Refusing to generate ID. ``` --- kasa/httpclient.py | 6 +++--- kasa/klaptransport.py | 6 ++++-- kasa/smart/smartdevice.py | 2 +- kasa/smartprotocol.py | 2 +- kasa/tests/test_smartdevice.py | 4 ++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/kasa/httpclient.py b/kasa/httpclient.py index 1c8c46e2..ec80ad61 100644 --- a/kasa/httpclient.py +++ b/kasa/httpclient.py @@ -72,7 +72,7 @@ class HttpClient: # Once we know a device needs a wait between sequential queries always wait # first rather than keep erroring then waiting. if self._wait_between_requests: - now = time.time() + now = time.monotonic() gap = now - self._last_request_time if gap < self._wait_between_requests: sleep = self._wait_between_requests - gap @@ -123,7 +123,7 @@ class HttpClient: ex, ) self._wait_between_requests = self.WAIT_BETWEEN_REQUESTS_ON_OSERROR - self._last_request_time = time.time() + self._last_request_time = time.monotonic() raise _ConnectionError( f"Device connection error: {self._config.host}: {ex}", ex ) from ex @@ -140,7 +140,7 @@ class HttpClient: # For performance only request system time if waiting is enabled if self._wait_between_requests: - self._last_request_time = time.time() + self._last_request_time = time.monotonic() return resp.status, response_data diff --git a/kasa/klaptransport.py b/kasa/klaptransport.py index dd90ffd2..c138ba38 100644 --- a/kasa/klaptransport.py +++ b/kasa/klaptransport.py @@ -300,7 +300,9 @@ class KlapTransport(BaseTransport): # There is a 24 hour timeout on the session cookie # but the clock on the device is not always accurate # so we set the expiry to 24 hours from now minus a buffer - self._session_expire_at = time.time() + timeout - SESSION_EXPIRE_BUFFER_SECONDS + self._session_expire_at = ( + time.monotonic() + timeout - SESSION_EXPIRE_BUFFER_SECONDS + ) self._encryption_session = await self.perform_handshake2( local_seed, remote_seed, auth_hash ) @@ -312,7 +314,7 @@ class KlapTransport(BaseTransport): """Return true if session has expired.""" return ( self._session_expire_at is None - or self._session_expire_at - time.time() <= 0 + or self._session_expire_at - time.monotonic() <= 0 ) async def send(self, request: str): diff --git a/kasa/smart/smartdevice.py b/kasa/smart/smartdevice.py index 8cdd2013..21e46cc3 100644 --- a/kasa/smart/smartdevice.py +++ b/kasa/smart/smartdevice.py @@ -159,7 +159,7 @@ class SmartDevice(Device): raise AuthenticationError("Tapo plug requires authentication.") first_update = self._last_update_time is None - now = time.time() + now = time.monotonic() self._last_update_time = now if first_update: diff --git a/kasa/smartprotocol.py b/kasa/smartprotocol.py index 0c95325a..c0dfb31e 100644 --- a/kasa/smartprotocol.py +++ b/kasa/smartprotocol.py @@ -392,7 +392,7 @@ class SnowflakeId: ) def _current_millis(self): - return round(time.time() * 1000) + return round(time.monotonic() * 1000) def _wait_next_millis(self, last_timestamp): timestamp = self._current_millis() diff --git a/kasa/tests/test_smartdevice.py b/kasa/tests/test_smartdevice.py index 99e2ddb9..4e670644 100644 --- a/kasa/tests/test_smartdevice.py +++ b/kasa/tests/test_smartdevice.py @@ -224,7 +224,7 @@ async def test_update_module_update_delays( new_dev = SmartDevice("127.0.0.1", protocol=dev.protocol) await new_dev.update() - first_update_time = time.time() + first_update_time = time.monotonic() assert new_dev._last_update_time == first_update_time for module in new_dev.modules.values(): if module.query(): @@ -236,7 +236,7 @@ async def test_update_module_update_delays( seconds += tick freezer.tick(tick) - now = time.time() + now = time.monotonic() await new_dev.update() for module in new_dev.modules.values(): mod_delay = module.MINIMUM_UPDATE_INTERVAL_SECS