diff --git a/README.md b/README.md index 3d3b4ac..99a825c 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ and modules which are documented and supported. 4.11 [Functors and singletons](./README.md#411-functors-and-singletons) Useful decorators. 4.12 [Quaternions](./README.md#412-quaternions) Scale, move and rotate 3D objects with minimal mathematics. 4.13 [A Pyboard power meter](./README.md#413-a-pyboard-power-meter) One of my own projects. + 4.14 [NTP time](./README.md#414-ntp-time) More portable than official driver with other benefits. 5. [Module Index](./README.md#5-module-index) Supported code. Device drivers, GUI's, utilities. 5.1 [uasyncio](./README.md#51-uasyncio) Tutorial and drivers for asynchronous coding. 5.2 [Memory Device Drivers](./README.md#52-memory-device-drivers) Drivers for nonvolatile memory devices. @@ -297,6 +298,20 @@ enabling it to provide information on power factor and to work with devices which generate as well as consume power. It uses the official LCD160CR display as a touch GUI interface. It is documented [here](./power/README.md). +## 4.14 NTP Time + +The official code has a number of drawbacks, mainly a lack of portability. + 1. It does not check the host device's epoch. This version returns the number + of seconds since the host device's epoch. + 2. It uses socket timeouts while the docs recommend select.poll as being more + portable. This version remedies that. + 3. This version has very basic support for local time in the form of an offset + in hours relative to UTC. + 4. In the event of a timeout this version returns 0: the caller should check + for this and re-try after a period. + +Code is [here](./ntptime/ntptime.py). + ##### [Index](./README.md#0-index) # 5. Module index diff --git a/ntptime/ntptime.py b/ntptime/ntptime.py new file mode 100644 index 0000000..55d8ac9 --- /dev/null +++ b/ntptime/ntptime.py @@ -0,0 +1,35 @@ +# Adapted from official ntptime by Peter Hinch July 2022 +# The main aim is portability: +# Detects host device's epoch and returns time relative to that. +# Basic approach to local time: add offset in hours relative to UTC. +# Timeouts return a time of 0. These happen: caller should check for this. +# Replace socket timeout with select.poll as per docs: +# http://docs.micropython.org/en/latest/library/socket.html#socket.socket.settimeout + +import socket +import struct +import select +from time import gmtime + +# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 +# (date(1970, 1, 1) - date(1900, 1, 1)).days * 24*60*60 +NTP_DELTA = 3155673600 if gmtime(0)[0] == 2000 else 2208988800 + +# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org' +host = "pool.ntp.org" + +def time(hrs_offset=0): # Local time offset in hrs relative to UTC + NTP_QUERY = bytearray(48) + NTP_QUERY[0] = 0x1B + addr = socket.getaddrinfo(host, 123)[0][-1] + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + poller = select.poll() + poller.register(s, select.POLLIN) + s.sendto(NTP_QUERY, addr) + if poller.poll(1000): # time in milliseconds + msg = s.recv(48) + s.close() + val = struct.unpack("!I", msg[40:44])[0] + return val - NTP_DELTA + hrs_offset * 3600 + s.close() # Timeout occurred + return 0