From 04c171ee74d7b9eefc08e9f8126752a1d29918e2 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Tue, 30 Apr 2024 21:49:39 -0700 Subject: [PATCH 1/4] Add ESP32SPI support --- README.rst | 16 ++++++---------- adafruit_ntp.py | 27 ++++++++++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/README.rst b/README.rst index 671ca15..d1d7bbd 100644 --- a/README.rst +++ b/README.rst @@ -59,21 +59,17 @@ Usage Example .. code-block:: python + import adafruit_connection_manager import adafruit_ntp - import socketpool + import os import time import wifi - # Get wifi details and more from a secrets.py file - try: - from secrets import secrets - except ImportError: - print("WiFi secrets are kept in secrets.py, please add them there!") - raise + wifi_ssid = os.getenv("CIRCUITPY_WIFI_SSID") + wifi_password = os.getenv("CIRCUITPY_WIFI_PASSWORD") + wifi.radio.connect(wifi_ssid, wifi_password) - wifi.radio.connect(secrets["ssid"], secrets["password"]) - - pool = socketpool.SocketPool(wifi.radio) + pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio) ntp = adafruit_ntp.NTP(pool, tz_offset=0) while True: diff --git a/adafruit_ntp.py b/adafruit_ntp.py index b405402..db85128 100644 --- a/adafruit_ntp.py +++ b/adafruit_ntp.py @@ -22,10 +22,14 @@ import struct import time +from micropython import const + + __version__ = "0.0.0+auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_NTP.git" NTP_TO_UNIX_EPOCH = 2208988800 # 1970-01-01 00:00:00 +PACKET_SIZE = const(48) class NTP: @@ -53,9 +57,8 @@ def __init__( :param int socket_timeout: UDP socket timeout, in seconds. """ self._pool = socketpool - self._server = server - self._port = port - self._packet = bytearray(48) + self._socket_address = self._pool.getaddrinfo(server, port)[0][4] + self._packet = bytearray(PACKET_SIZE) self._tz_offset = int(tz_offset * 60 * 60) self._socket_timeout = socket_timeout @@ -72,20 +75,26 @@ def datetime(self) -> time.struct_time: is received within socket_timeout seconds""" if time.monotonic_ns() > self.next_sync: self._packet[0] = 0b00100011 # Not leap second, NTP version 4, Client mode - for i in range(1, len(self._packet)): + for i in range(1, PACKET_SIZE): self._packet[i] = 0 with self._pool.socket(self._pool.AF_INET, self._pool.SOCK_DGRAM) as sock: sock.settimeout(self._socket_timeout) - sock.sendto(self._packet, (self._server, self._port)) - sock.recvfrom_into(self._packet) + if hasattr(sock, "sendto"): + sock.sendto(self._packet, self._socket_address) + sock.recvfrom_into(self._packet) + else: + sock.connect( + self._socket_address, + conntype=self._pool._interface.UDP_MODE, # pylint: disable=protected-access + ) + sock.send(self._packet) + self._packet[:PACKET_SIZE] = sock.recv(PACKET_SIZE) # Get the time in the context to minimize the difference between it and receiving # 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 - seconds = struct.unpack_from( - "!I", self._packet, offset=len(self._packet) - 8 - )[0] + seconds = struct.unpack_from("!I", self._packet, offset=PACKET_SIZE - 8)[0] self._monotonic_start = ( seconds + self._tz_offset From 397e56ea73e6c7de2ef1e6c9ad615c36bdb29131 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Wed, 1 May 2024 16:12:24 -0700 Subject: [PATCH 2/4] Allow to create NTP without active connection --- adafruit_ntp.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/adafruit_ntp.py b/adafruit_ntp.py index db85128..5ef1d0e 100644 --- a/adafruit_ntp.py +++ b/adafruit_ntp.py @@ -57,7 +57,9 @@ def __init__( :param int socket_timeout: UDP socket timeout, in seconds. """ self._pool = socketpool - self._socket_address = self._pool.getaddrinfo(server, port)[0][4] + self._server = server + self._port = port + self._socket_address = None self._packet = bytearray(PACKET_SIZE) self._tz_offset = int(tz_offset * 60 * 60) self._socket_timeout = socket_timeout @@ -74,6 +76,11 @@ def datetime(self) -> time.struct_time: unless there has already been a recent request. Raises OSError exception if no response is received within socket_timeout seconds""" if time.monotonic_ns() > self.next_sync: + if self._socket_address is None: + self._socket_address = self._pool.getaddrinfo(self._server, self._port)[ + 0 + ][4] + self._packet[0] = 0b00100011 # Not leap second, NTP version 4, Client mode for i in range(1, PACKET_SIZE): self._packet[i] = 0 From 25634be10035d17209a8af8e8457c13d2b9bcbf1 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Fri, 3 May 2024 06:53:10 -0700 Subject: [PATCH 3/4] Simplify method --- adafruit_ntp.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/adafruit_ntp.py b/adafruit_ntp.py index 5ef1d0e..87d1c4d 100644 --- a/adafruit_ntp.py +++ b/adafruit_ntp.py @@ -63,6 +63,9 @@ def __init__( self._packet = bytearray(PACKET_SIZE) self._tz_offset = int(tz_offset * 60 * 60) self._socket_timeout = socket_timeout + self._connect_mode = hasattr(self._pool, "_interface") and getattr( + self._pool._interface, "UDP_MODE", None + ) # This is our estimated start time for the monotonic clock. We adjust it based on the ntp # responses. @@ -85,17 +88,15 @@ def datetime(self) -> time.struct_time: for i in range(1, PACKET_SIZE): self._packet[i] = 0 with self._pool.socket(self._pool.AF_INET, self._pool.SOCK_DGRAM) as sock: + # Since the ESP32SPI doesn't support sendto, we are using + # connect + send to standardize code sock.settimeout(self._socket_timeout) - if hasattr(sock, "sendto"): - sock.sendto(self._packet, self._socket_address) - sock.recvfrom_into(self._packet) + if self._connect_mode: + sock.connect(self._socket_address, self._connect_mode) else: - sock.connect( - self._socket_address, - conntype=self._pool._interface.UDP_MODE, # pylint: disable=protected-access - ) - sock.send(self._packet) - self._packet[:PACKET_SIZE] = sock.recv(PACKET_SIZE) + sock.connect(self._socket_address) + sock.send(self._packet) + sock.recv_into(self._packet) # Get the time in the context to minimize the difference between it and receiving # the packet. destination = time.monotonic_ns() From 4e58a10e6bf912d686b44f2022a5a0d796d95a33 Mon Sep 17 00:00:00 2001 From: Justin Myers Date: Mon, 6 May 2024 08:59:38 -0700 Subject: [PATCH 4/4] Simplify more --- adafruit_ntp.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/adafruit_ntp.py b/adafruit_ntp.py index 87d1c4d..5e9c790 100644 --- a/adafruit_ntp.py +++ b/adafruit_ntp.py @@ -63,9 +63,6 @@ def __init__( self._packet = bytearray(PACKET_SIZE) self._tz_offset = int(tz_offset * 60 * 60) self._socket_timeout = socket_timeout - self._connect_mode = hasattr(self._pool, "_interface") and getattr( - self._pool._interface, "UDP_MODE", None - ) # This is our estimated start time for the monotonic clock. We adjust it based on the ntp # responses. @@ -91,10 +88,7 @@ def datetime(self) -> time.struct_time: # Since the ESP32SPI doesn't support sendto, we are using # connect + send to standardize code sock.settimeout(self._socket_timeout) - if self._connect_mode: - sock.connect(self._socket_address, self._connect_mode) - else: - sock.connect(self._socket_address) + sock.connect(self._socket_address) sock.send(self._packet) sock.recv_into(self._packet) # Get the time in the context to minimize the difference between it and receiving