Arduino環境でESP32を使いntp接続した時にちょっとはまった部分について。
ESP32の初期時刻の設定をWiFi経由のntpで行うことにした。
ググったところ、いろいろなサイトでその実装例が出されていたので、それらを参考にして見た。
また、時刻の設定は起動時のみでよかったので、時刻を取得(すると思うコード)を呼び出したのち、WiFiの接続を解除するようにしてみた。
void setup()
{
// Wifiの設定と時刻の取得
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (WiFi.begin(ssid, password) != WL_DISCONNECTED) {
ESP.restart();
}
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
}
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
void loop()
{
char buffer[256];
struct tm timeInfo;
getLocalTime(&timeInfo);
}
configTimeまでの実装はどこにでもあるようなものだが、その後にWiFiの接続を解除しているような実装はなかった。
上のコードを実行すると、loop内で得られる時刻は1970年のまま、つまり0クリアされたものだった。電源投入直後なので0クリアはわかるのだがconfigTime内でntpに接続し、時刻更新をしていると思ったのだが、どうやらそうではないらしい。
当初原因はわからなかったが、getLocalTimeの実装を見たところwhile文で時刻を取得するようなものになっていた。
もしやと思い、以下の様にconfigTimeの後に時刻を取得するコードを入れてみたところWiFiの接続を解除したのちもgetLocalTimeで正しい時刻が取得できるようになった。
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
struct tm timeInfo;
getLocalTime(&timeInfo);
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
詳細は追えていないのだが、たぶんtime関数の中でntpを使った時刻同期を行うんだろうなとは思ってる。
esp-idf側のAPIとそのサンプルを見るとsntp_get_sync_statusで更新されているかを判断しているようだけど、Arduinoベースだとsntp_get_sync_statusをうまく呼び出すことができず(たぶんarduino-esp32がesp-idfのv4.0.xベースだからコンパイルエラーになる?)、上のような実装が一番簡単だった。
ntpでの時刻調整はデフォルト1時間間隔でntpサーバーに接続するようなのだが、WiFiを切ってしまった後はもちろんntpを使った時刻調整はできない。
WiFi再接続後もArduinoベースでは強制更新のAPIがないので、adjtimeで0クリアした後、getLocalTimeで時刻更新といった方法しかないかもしれない。
コメント