Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions adafruit_ntp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that's a good default but I'd rather not change behavior. Instead, I'd default to None to indicate following the server.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll default it to zero- min(int, None) is an error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, pushed the 'zero', and then changed all of the examples to use the 3600 value, since most people just copy/paste example code anyhow. Did it in a standalone commit in case you disagree and want me to revert.

(default 3600).
"""
self._pool = socketpool
self._server = server
Expand All @@ -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.
Expand All @@ -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)[
Expand All @@ -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."
)

Comment thread
tedder marked this conversation as resolved.
Outdated
self._monotonic_start = (
seconds
+ self._tz_offset
Expand Down