Created
November 23, 2019 00:15
-
-
Save Tugzrida/9c36a6ed30639689e73f4f66dfde83d6 to your computer and use it in GitHub Desktop.
Implementation of NTP and Australian DST in MicroPython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time, socket | |
from struct import unpack | |
from machine import RTC | |
standardTimeOffset = 60 * 60 * 10 # The base TZ UTC offset in sec, AEST(UTC+10) | |
summerTimeDifference = 60 * 60 * 1 # The difference between the base TZ and DST TZ in sec, AEDT(UTC+11), 1 hour ahead | |
rtc = RTC() | |
lastSync = 0 | |
def isDST(now): | |
# Returns true or false adhering to the Australian DST standard(begin DST at 2am (base TZ) on the first Sunday | |
# of October, end at 2am(base TZ) on the first Sunday of April.) Provided `now` should always be in base TZ. | |
month = now[1] | |
if (month >= 11 or month <= 3): return True # Nov, Dec, Jan, Feb, Mar are always summer time | |
if (month >= 5 and month <= 9): return False # May, Jun, Jul, Aug, Sep are always standard time | |
date = now[2] | |
hour = now[3] | |
dow = now[6] | |
lastSun = date - (dow + 1) # Representing the previous Sunday, even if today is Sunday | |
if (month == 10): | |
# DST if lastSun was this month or today is changing sunday and after 2am | |
return ((lastSun > 0) or (dow == 6 and hour >= 2)) | |
if (month == 4): | |
# DST if lastSun was last month and today isn't changing sunday after 2am | |
return ((lastSun <= 0) and (dow != 6 or hour < 2)) | |
def ntpSync(): | |
# Sets the RTC to the current time in the base TZ, and sets lastSync to the current ticks. | |
global lastSync | |
NTP_QUERY = bytearray(48) | |
NTP_QUERY[0] = 0x1b | |
addr = socket.getaddrinfo("au.pool.ntp.org", 123)[0][-1] | |
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
try: | |
s.settimeout(1) | |
res = s.sendto(NTP_QUERY, addr) | |
msg = s.recv(48) | |
tm = time.localtime(unpack("!I", msg[40:44])[0] - 3155673600 + standardTimeOffset) | |
rtc.datetime((tm[0], tm[1], tm[2], tm[6] + 1, tm[3], tm[4], tm[5], 0)) | |
lastSync = time.ticks_ms() | |
print("Time synced with NTP") | |
except OSError as e: | |
if e.args[0] == 110: | |
print('NTP timeout!') | |
else: | |
raise e | |
finally: | |
s.close() | |
def getTime(): | |
# The function that should be used to get the time in other code. | |
# Updates the time from NTP if necessary, then returns a tuple of the standard time.localtime() tuple, | |
# and the current DST state bool. | |
if time.ticks_diff(time.ticks_ms(), lastSync) > 1800000: | |
ntpSync() | |
now = time.localtime() | |
dst = isDST(now) | |
if dst: | |
now = time.localtime(time.mktime(now) + summerTimeDifference) | |
return now, dst | |
ntpSync() # Initial sync of the RTC |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment