From cda7883485a3d34af0403ef1f966315ab8d17285 Mon Sep 17 00:00:00 2001 From: ted Date: Tue, 16 Jul 2024 14:15:14 -0700 Subject: [PATCH 1/5] add cache_seconds --- adafruit_ntp.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/adafruit_ntp.py b/adafruit_ntp.py index a41f598..d43c5b4 100644 --- a/adafruit_ntp.py +++ b/adafruit_ntp.py @@ -46,6 +46,7 @@ def __init__( port: int = 123, tz_offset: float = 0, socket_timeout: int = 10, + cache_seconds: int = 3600, ) -> None: """ :param object socketpool: A socket provider such as CPython's `socket` module. @@ -55,6 +56,8 @@ def __init__( CircuitPython. CPython will determine timezone automatically and adjust (so don't use this.) For example, Pacific daylight savings time is -7. :param int socket_timeout: UDP socket timeout, in seconds. + :param int cache_seconds: how many seconds to use a cached result from NTP server + (default 3600). """ self._pool = socketpool self._server = server @@ -63,6 +66,7 @@ def __init__( self._packet = bytearray(PACKET_SIZE) self._tz_offset = int(tz_offset * 60 * 60) self._socket_timeout = socket_timeout + self._cache_seconds = cache_seconds # This is our estimated start time for the monotonic clock. We adjust it based on the ntp # responses. @@ -74,7 +78,8 @@ def __init__( def datetime(self) -> time.struct_time: """Current time from NTP server. Accessing this property causes the NTP time request, unless there has already been a recent request. Raises OSError exception if no response - is received within socket_timeout seconds""" + is received within socket_timeout seconds, ArithmeticError for substantially incorrect + NTP results.""" if time.monotonic_ns() > self.next_sync: if self._socket_address is None: self._socket_address = self._pool.getaddrinfo(self._server, self._port)[ @@ -92,8 +97,20 @@ def datetime(self) -> time.struct_time: # the packet. destination = time.monotonic_ns() poll = struct.unpack_from("!B", self._packet, offset=2)[0] - self.next_sync = destination + (2**poll) * 1_000_000_000 + + cache_offset = max(2**poll, self._cache_seconds) + self.next_sync = destination + cache_offset * 1_000_000_000 seconds = struct.unpack_from("!I", self._packet, offset=PACKET_SIZE - 8)[0] + + # value should always be larger; giving a small buffer to handle jitter. + if (seconds + 5) < self._monotonic_start: + failed_offset = (self._monotonic_start - seconds) / 1_000_000_000 + raise ArithmeticError( + "need a time machine, ntp time is " + + str(failed_offset) + + "seconds in the past." + ) + self._monotonic_start = ( seconds + self._tz_offset From d32525334389e50166f87f8efde4f1b8f86149cc Mon Sep 17 00:00:00 2001 From: ted Date: Wed, 17 Jul 2024 10:02:15 -0700 Subject: [PATCH 2/5] rm stray code from other PR --- adafruit_ntp.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/adafruit_ntp.py b/adafruit_ntp.py index d43c5b4..4a695ec 100644 --- a/adafruit_ntp.py +++ b/adafruit_ntp.py @@ -102,15 +102,6 @@ def datetime(self) -> time.struct_time: self.next_sync = destination + cache_offset * 1_000_000_000 seconds = struct.unpack_from("!I", self._packet, offset=PACKET_SIZE - 8)[0] - # value should always be larger; giving a small buffer to handle jitter. - if (seconds + 5) < self._monotonic_start: - failed_offset = (self._monotonic_start - seconds) / 1_000_000_000 - raise ArithmeticError( - "need a time machine, ntp time is " - + str(failed_offset) - + "seconds in the past." - ) - self._monotonic_start = ( seconds + self._tz_offset From d12142866ea061a11ae397dfcea9ff5e402c9c61 Mon Sep 17 00:00:00 2001 From: ted Date: Wed, 17 Jul 2024 10:05:42 -0700 Subject: [PATCH 3/5] default to no-change for cache_offset --- adafruit_ntp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_ntp.py b/adafruit_ntp.py index 4a695ec..bc6db0d 100644 --- a/adafruit_ntp.py +++ b/adafruit_ntp.py @@ -46,7 +46,7 @@ def __init__( port: int = 123, tz_offset: float = 0, socket_timeout: int = 10, - cache_seconds: int = 3600, + cache_seconds: int = 0, ) -> None: """ :param object socketpool: A socket provider such as CPython's `socket` module. @@ -57,7 +57,7 @@ def __init__( this.) For example, Pacific daylight savings time is -7. :param int socket_timeout: UDP socket timeout, in seconds. :param int cache_seconds: how many seconds to use a cached result from NTP server - (default 3600). + (default 0, which respects NTP server's minimum). """ self._pool = socketpool self._server = server From 8ca6173115a6c6fef859d0b0d56402bf717e4785 Mon Sep 17 00:00:00 2001 From: ted Date: Wed, 17 Jul 2024 10:05:58 -0700 Subject: [PATCH 4/5] add a reasonable default for cache_offset to all examples --- README.rst | 2 +- examples/ntp_connection_manager.py | 4 ++-- examples/ntp_cpython.py | 2 +- examples/ntp_set_rtc.py | 2 +- examples/ntp_simpletest.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index d1d7bbd..6fdaba1 100644 --- a/README.rst +++ b/README.rst @@ -70,7 +70,7 @@ Usage Example wifi.radio.connect(wifi_ssid, wifi_password) pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio) - ntp = adafruit_ntp.NTP(pool, tz_offset=0) + ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_offset=3600) while True: print(ntp.datetime) diff --git a/examples/ntp_connection_manager.py b/examples/ntp_connection_manager.py index b3cd28b..db3e4e9 100644 --- a/examples/ntp_connection_manager.py +++ b/examples/ntp_connection_manager.py @@ -33,7 +33,7 @@ # get the socket pool from connection manager socket = adafruit_connection_manager.get_radio_socketpool(radio) -# adjust tz_offset for locale... -ntp = adafruit_ntp.NTP(socket, tz_offset=-5) +# adjust tz_offset for locale, only ping NTP server every hour +ntp = adafruit_ntp.NTP(socket, tz_offset=-5, cache_seconds=3600) print(ntp.datetime) diff --git a/examples/ntp_cpython.py b/examples/ntp_cpython.py index 76d5735..e01a3b6 100644 --- a/examples/ntp_cpython.py +++ b/examples/ntp_cpython.py @@ -9,7 +9,7 @@ import adafruit_ntp # Don't use tz_offset kwarg with CPython because it will adjust automatically. -ntp = adafruit_ntp.NTP(socket) +ntp = adafruit_ntp.NTP(socket, cache_seconds=3600) while True: print(ntp.datetime) diff --git a/examples/ntp_set_rtc.py b/examples/ntp_set_rtc.py index 363c8b4..e4f331b 100644 --- a/examples/ntp_set_rtc.py +++ b/examples/ntp_set_rtc.py @@ -21,7 +21,7 @@ wifi.radio.connect(secrets["ssid"], secrets["password"]) pool = socketpool.SocketPool(wifi.radio) -ntp = adafruit_ntp.NTP(pool, tz_offset=0) +ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_seconds=3600) # NOTE: This changes the system time so make sure you aren't assuming that time # doesn't jump. diff --git a/examples/ntp_simpletest.py b/examples/ntp_simpletest.py index 0258e16..ef256c6 100644 --- a/examples/ntp_simpletest.py +++ b/examples/ntp_simpletest.py @@ -20,7 +20,7 @@ wifi.radio.connect(secrets["ssid"], secrets["password"]) pool = socketpool.SocketPool(wifi.radio) -ntp = adafruit_ntp.NTP(pool, tz_offset=0) +ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_offset=3600) while True: print(ntp.datetime) From 9a4dbe723cbe4c6d21699bd8b5b77eaf75383a51 Mon Sep 17 00:00:00 2001 From: ted Date: Wed, 17 Jul 2024 10:07:39 -0700 Subject: [PATCH 5/5] fix invalid param name --- README.rst | 2 +- examples/ntp_simpletest.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 6fdaba1..67a62ea 100644 --- a/README.rst +++ b/README.rst @@ -70,7 +70,7 @@ Usage Example wifi.radio.connect(wifi_ssid, wifi_password) pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio) - ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_offset=3600) + ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_seconds=3600) while True: print(ntp.datetime) diff --git a/examples/ntp_simpletest.py b/examples/ntp_simpletest.py index ef256c6..a3f1b70 100644 --- a/examples/ntp_simpletest.py +++ b/examples/ntp_simpletest.py @@ -20,7 +20,7 @@ wifi.radio.connect(secrets["ssid"], secrets["password"]) pool = socketpool.SocketPool(wifi.radio) -ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_offset=3600) +ntp = adafruit_ntp.NTP(pool, tz_offset=0, cache_seconds=3600) while True: print(ntp.datetime)