9.16. 時刻とNTP

電源を入れたばかりのカメラは、今が何時なのかを把握していません。オンボードのクロックは何らかの任意の瞬間(ほとんどのボードでは 1970-01-01)から開始し、何かが別の値を教えるまでそこから先へカウントを進めます。NTP(Network Time Protocol、ネットワークタイムプロトコル)は、カメラがネットワークに対して実世界の時刻を問い合わせ、その応答から自身のクロックを設定するための仕組みです。

9.16.1. カメラが時刻を知る必要がある理由

多くのスクリプトでは、カメラのクロックは問題になりません。フレーム取得ループは今日が何日かを気にしません。しかし、いくつかのよくある用途では大いに重要になります:

  • ログやアップロードしたデータ内のタイムスタンプ。 すべてのエントリが 1970-01-01 と表示されると、後から内容を把握するのが困難です。

  • スケジュールされたタスク。 「03:00に実行」するには、カメラが03:00が何時なのかを知っている必要があります。

9.16.2. NTPが行うこと

NTPは小さな公開サービスです。「今は何時ですか?」という問いに単一のUDP交換で応答するサーバーのネットワークです。カメラは既知のNTPサーバーに短いリクエストを送信し、サーバーは正確なタイムスタンプ(一般的な公開サーバーであれば数ミリ秒の精度)で応答します。カメラはそれを使って自身のクロックを設定します。カメラが既定で使用するサーバーは pool.ntp.org で、まさにこの種のクライアント向けに設計された、世界規模でロードバランシングされたプールです。

9.16.3. Python API: ntptime

MicroPythonはこのプロトコルを1回の呼び出しにまとめています。一般的なパターンは、まずリンクを確立してから、NTPに時刻を問い合わせることです:

import network
import ntptime
import time

wlan = network.WLAN(network.WLAN.IF_STA)
wlan.active(True)
wlan.connect("my-network", "my-password")

while not wlan.isconnected():
    time.sleep_ms(100)

ntptime.settime()                 # cam's clock is now UTC
print(time.localtime())

ntptime.settime() が返ると、オンボードのリアルタイムクロックと time.localtime() は現在のUTC時刻を反映します。既定値を調整するつまみが2つあります:

  • ntptime.host は問い合わせ先のサーバー名です。別のサーバーを指定するには、settime() を呼び出す前にこれを上書きします(ntptime.host = "time.google.com")。

  • ntptime.timeout は、応答を諦めるまで待機する秒数です。既定値は短く設定されています。

9.16.4. いつ呼び出すか

  • ネットワークリンクが確立した後。 NTPはUDP上で動作し、UDPは確立されたIP設定の上で動作します。まず isconnected()True を返すまで待ちます。

  • 長時間動作するカメラでは定期的に。 オンボードのクロックは時間や日が経つにつれてずれていきます。1日に1回または1週間に1回 settime() を実行すると正確さが保たれます。

9.16.5. タイムゾーン

NTPはUTCを返します。MicroPythonはタイムゾーンデータベースを同梱していないため、UTCをローカル時刻に変換するのはスクリプトの役目です。導入先のゾーンに合わせた固定オフセットを使うのが一般的な方法です:

import time

offset = -5 * 3600                  # hours -> seconds, US Eastern
local = time.localtime(time.time() + offset)
print(local)

夏時間、うるう秒、過去のゾーン変更は、この方法では扱われません。ほとんどのカメラ導入では固定オフセットで十分です。スクリプトが本当に夏時間を含む民用時刻を必要とする場合は、変換をサーバー側で行ってください。

9.16.6. 起こりうる問題

  • まだネットワークがない。 ntptime.settime() はサーバーに到達できない場合に OSError を送出します。リンクが確立していない、名前解決に失敗した、サーバーに到達できない、または ntptime.timeout 以内に応答が届かなかった、のいずれかです。リンクが安定したら再試行してください。

  • キャプティブポータル。 DNSを傍受するWi-FiネットワークはNTPサーバー名に対してポータル自身のIPで応答することがあり、そのIPへのNTPリクエストは意味のない結果を返します。カメラはネットワークが確立していると認識しますが、時刻設定は失敗するか、まったく見当違いの値になります。クリーンなネットワークに移るか、IPをハードコードしてください。

  • 公開プールへの過度なアクセス。 公開NTPプールは乱用するクライアントにレート制限をかけます。1時間に1回で十分です。1分に1回ではカメラがアクセス禁止になります。

ntptime の完全なリファレンスについては、ntptime --- シンプルな NTP クライアント を参照してください。