いっぺーちゃんの いろいろやってみよ~

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