89 lines
1.8 KiB
Python
89 lines
1.8 KiB
Python
|
"""Functions to sync the hardware clock to internet network time servers
|
||
|
|
||
|
Derived from the 2016 implementation.
|
||
|
"""
|
||
|
|
||
|
___license___ = "MIT"
|
||
|
|
||
|
import database
|
||
|
import socket
|
||
|
|
||
|
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
|
||
|
NTP_DELTA = 3155673600
|
||
|
# With Mk3 Firmware an IP address string works 5%, hangs at socket.socket(..) 95%, could be a bug in 2016 upython?
|
||
|
NTP_HOSTS = ["0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org"]
|
||
|
NTP_PORT = 123
|
||
|
|
||
|
|
||
|
def get_NTP_time():
|
||
|
for NTP_HOST in NTP_HOSTS:
|
||
|
res = query_NTP_host(NTP_HOST)
|
||
|
if res is not None:
|
||
|
return res
|
||
|
return None
|
||
|
|
||
|
|
||
|
def query_NTP_host(_NTP_HOST):
|
||
|
NTP_QUERY = bytearray(48)
|
||
|
NTP_QUERY[0] = 0x1b
|
||
|
# Catch exception when run on a network without working DNS
|
||
|
try:
|
||
|
addr = socket.getaddrinfo(_NTP_HOST, NTP_PORT)[0][-1]
|
||
|
except OSError:
|
||
|
return None
|
||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||
|
s.sendto(NTP_QUERY, addr)
|
||
|
|
||
|
# Setting timeout for receiving data. Because we're using UDP,
|
||
|
# there's no need for a timeout on send.
|
||
|
s.settimeout(2)
|
||
|
msg = None
|
||
|
try:
|
||
|
msg = s.recv(48)
|
||
|
except OSError:
|
||
|
pass
|
||
|
finally:
|
||
|
s.close()
|
||
|
|
||
|
if msg is None:
|
||
|
return None
|
||
|
|
||
|
import struct
|
||
|
|
||
|
stratum = int(msg[1])
|
||
|
if stratum == 0:
|
||
|
# KoD, reason doesn't matter, failover to next host
|
||
|
return None
|
||
|
|
||
|
val = struct.unpack("!I", msg[40:44])[0]
|
||
|
|
||
|
print("Using NTP Host: %s, Stratum: %d" % (_NTP_HOST, stratum))
|
||
|
return val - NTP_DELTA
|
||
|
|
||
|
|
||
|
def set_NTP_time():
|
||
|
import time
|
||
|
from pyb import RTC
|
||
|
print("Setting time from NTP")
|
||
|
|
||
|
t = get_NTP_time()
|
||
|
if t is None:
|
||
|
print("Could not set time from NTP")
|
||
|
return False
|
||
|
|
||
|
tz = 0
|
||
|
with database.Database() as db:
|
||
|
tz = db.get("timezone", 0)
|
||
|
|
||
|
tz_minutes = int(abs(tz) % 100) * (1 if tz >= 0 else -1)
|
||
|
tz_hours = int(tz / 100)
|
||
|
t += (tz_hours * 3600) + (tz_minutes * 60)
|
||
|
|
||
|
tm = time.localtime(t)
|
||
|
tm = tm[0:3] + (0,) + tm[3:6] + (0,)
|
||
|
|
||
|
rtc = RTC()
|
||
|
rtc.init()
|
||
|
rtc.datetime(tm)
|
||
|
|
||
|
return True
|