Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add configurable time between NTP calls #37

Merged
merged 5 commits into from
Jul 18, 2024
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
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
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
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."
)

tedder marked this conversation as resolved.
Show resolved Hide resolved
self._monotonic_start = (
seconds
+ self._tz_offset
Expand Down
Loading