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.
```
This commit is contained in:
Steven B. 2024-07-16 13:25:32 +01:00 committed by GitHub
parent 7e9b1687d0
commit b220beb811
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 11 additions and 9 deletions

View File

@ -72,7 +72,7 @@ class HttpClient:
# Once we know a device needs a wait between sequential queries always wait # Once we know a device needs a wait between sequential queries always wait
# first rather than keep erroring then waiting. # first rather than keep erroring then waiting.
if self._wait_between_requests: if self._wait_between_requests:
now = time.time() now = time.monotonic()
gap = now - self._last_request_time gap = now - self._last_request_time
if gap < self._wait_between_requests: if gap < self._wait_between_requests:
sleep = self._wait_between_requests - gap sleep = self._wait_between_requests - gap
@ -123,7 +123,7 @@ class HttpClient:
ex, ex,
) )
self._wait_between_requests = self.WAIT_BETWEEN_REQUESTS_ON_OSERROR self._wait_between_requests = self.WAIT_BETWEEN_REQUESTS_ON_OSERROR
self._last_request_time = time.time() self._last_request_time = time.monotonic()
raise _ConnectionError( raise _ConnectionError(
f"Device connection error: {self._config.host}: {ex}", ex f"Device connection error: {self._config.host}: {ex}", ex
) from ex ) from ex
@ -140,7 +140,7 @@ class HttpClient:
# For performance only request system time if waiting is enabled # For performance only request system time if waiting is enabled
if self._wait_between_requests: if self._wait_between_requests:
self._last_request_time = time.time() self._last_request_time = time.monotonic()
return resp.status, response_data return resp.status, response_data

View File

@ -300,7 +300,9 @@ class KlapTransport(BaseTransport):
# There is a 24 hour timeout on the session cookie # There is a 24 hour timeout on the session cookie
# but the clock on the device is not always accurate # but the clock on the device is not always accurate
# so we set the expiry to 24 hours from now minus a buffer # 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( self._encryption_session = await self.perform_handshake2(
local_seed, remote_seed, auth_hash local_seed, remote_seed, auth_hash
) )
@ -312,7 +314,7 @@ class KlapTransport(BaseTransport):
"""Return true if session has expired.""" """Return true if session has expired."""
return ( return (
self._session_expire_at is None 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): async def send(self, request: str):

View File

@ -159,7 +159,7 @@ class SmartDevice(Device):
raise AuthenticationError("Tapo plug requires authentication.") raise AuthenticationError("Tapo plug requires authentication.")
first_update = self._last_update_time is None first_update = self._last_update_time is None
now = time.time() now = time.monotonic()
self._last_update_time = now self._last_update_time = now
if first_update: if first_update:

View File

@ -392,7 +392,7 @@ class SnowflakeId:
) )
def _current_millis(self): def _current_millis(self):
return round(time.time() * 1000) return round(time.monotonic() * 1000)
def _wait_next_millis(self, last_timestamp): def _wait_next_millis(self, last_timestamp):
timestamp = self._current_millis() timestamp = self._current_millis()

View File

@ -224,7 +224,7 @@ async def test_update_module_update_delays(
new_dev = SmartDevice("127.0.0.1", protocol=dev.protocol) new_dev = SmartDevice("127.0.0.1", protocol=dev.protocol)
await new_dev.update() await new_dev.update()
first_update_time = time.time() first_update_time = time.monotonic()
assert new_dev._last_update_time == first_update_time assert new_dev._last_update_time == first_update_time
for module in new_dev.modules.values(): for module in new_dev.modules.values():
if module.query(): if module.query():
@ -236,7 +236,7 @@ async def test_update_module_update_delays(
seconds += tick seconds += tick
freezer.tick(tick) freezer.tick(tick)
now = time.time() now = time.monotonic()
await new_dev.update() await new_dev.update()
for module in new_dev.modules.values(): for module in new_dev.modules.values():
mod_delay = module.MINIMUM_UPDATE_INTERVAL_SECS mod_delay = module.MINIMUM_UPDATE_INTERVAL_SECS