micropython on ESP32 でNTPサーバから時刻取得
前回、時刻を設定できるようにしたので、今回はNTPサーバから時刻を取得してみます。
これらを組み合わせると、時刻合わせが自動で行えるようになります。
以下のプログラムをntptime.pyという名前で保存し、upipmでインストールします。
import usocket as socket try: import ustruct as struct except: import struct def time(): # (datetime.date(1970, 1, 1) - datetime.date(1900, 1, 1)).days * 24 * 60 * 60 NTP_DELTA = 2208988800 # ntp server ntp_host = "ntp.nict.jp" NTP_QUERY = bytearray(48) NTP_QUERY[0] = 0x1b addr = socket.getaddrinfo(ntp_host, 123)[0][-1] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # s.settimeout(1) res = s.sendto(NTP_QUERY, addr) msg = s.recv(48) s.close() val = struct.unpack("!I", msg[40:44])[0] return val - NTP_DELTA
以下のように使用します。
import ntptime import utime # timeメソッドを呼び出すと経過秒数が取得できます ntptime.time() ==> 1503019707 # その値をそのままutime.set_time()に渡せば時刻を設定できます。 utime.set_time(1503019707) utime.localtime() ==> (2017, 8, 18, 10, 28, 27, 4, 230) # 通常はこんな感じでまとめれば良いでしょう utime.set_time(ntptime.time()) utime.localtime() ==>(2017, 8, 18, 10, 29, 4, 4, 230)
以下解説のようなものです。
必要なモジュールを読み込みます。
import usocket as socket try: import ustruct as struct except: import struct
timeメソッドを定義しています。
def time(): ....
使用する定数です。
NTPサーバからは1900年1月1日00:00:00(UTC)からの経過秒数が送られてきますが、必要なのは1970年1月1日00:00:00(UTC)からの経過秒数なので、それを補正するための定数です。
# (datetime.date(1970, 1, 1) - datetime.date(1900, 1, 1)).days * 24 * 60 * 60 NTP_DELTA = 2208988800
接続するNTPサーバです。別のところに接続したければ変更してください。
# ntp server ntp_host = "ntp.nict.jp"
NTPサーバに送信するqueryパケットを生成しています。
NTP_QUERY = bytearray(48) NTP_QUERY[0] = 0x1b
NTPサーバと接続するためのアドレスとソケットを作成します。
addr = socket.getaddrinfo(ntp_host, 123)[0][-1] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
QUERYパケットを送信します。
res = s.sendto(NTP_QUERY, addr)
サーバからのレスポンスを受信します。
msg = s.recv(48)
ソケットをクローズします
s.close()
受信データの40~44バイト目に経過秒数データ(正確に表現すると「送信タイムスタンプの整数部」)が入っているので、これを整数に変換しています(ネットワークバイトオーダの整数なので、unpackのフォーマットには「!I」が指定されています)。
変換結果を1970年1月1日00:00:00(UTC)からの経過秒数に変換した値を返します。
val = struct.unpack("!I", msg[40:44])[0] return val - NTP_DELTA