[Code] NTPで取得した時刻をRTCへセットする
NTPで取得した時刻をRTCへセットする(ESP32)
2021/6/28
投稿者:管理人
ESP-WROOM-32でやってみました。調査結果により書き直したので、記事タイトルと内容に
ズレがあります。
調べてわかったこと
起動時のNTP時刻取得後は、1時間毎のgetLocalTime()時に
NTP時刻同期していました。よって、提供される時刻の精度は問題ないと思われます。つまり、NTP又はネットワーク内タイムサーバに接続できる環境なら、RTCモジュール追加の必要はない?かもしれません。タイムサーバ接続不可能な環境で使うならRTCは有ったほうが良いと思います。
getLocalTime()
ローカル時刻を取得する。
失敗時10ms毎に取得繰返し5000mS(デフォルト)でタイムアウト
取得成功でtrue返す。失敗でfalse返す。
例 getLocalTime(&timeinfo, 5000)
getLocalTime()後のsntp_get_sync_statusをシリアルモニタ表示してみた。
前半 10分間隔 後半 11分間隔でgetLocalTime()してます。
約60分毎に sntp_get_sync_status = COMPLETED とあります。
スケッチ例 「SimpleTime」で実験中
(ESP32 Dev Module用のスケッチ例 ESP32→TIME→SimpleTime)
コメントとテストを追記したスケッチ(手直し中)
WiFi.disconnect(true);とWiFi.mode(WIFI_OFF);の2行は
接続を継続するため無効にしました。
include行は < から < へ修正して下さい。
hiro yamamoto works
https://sky.ap.teacup.com/melondaikonhou/252.html
#include <WiFi.h>
#include "time.h"
const char* ssid = "my-ssid";
const char* password = "my-password";
const char* ntpServer = "pool.ntp.org"; // NTPサーバ,IP Address指定できるか?
const long gmtOffset_sec = 9 * 3600; // 時差を秒で設定・・・9時間
const int daylightOffset_sec = 0; // サマータイム設定・・・0
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo, 5000)) {
// コメント追記 タイムアウトデフォルト5000mS
Serial.println("Failed to obtain time");
return;
}
//追記 NTP同期確認のため ・・・COMPLETEDで同期完了と思う
if (sntp_get_sync_status() == SNTP_SYNC_STATUS_COMPLETED) {
Serial.println("sntp_get_sync_status = COMPLETED");
Serial.println(&timeinfo, "%A, %B %m %d %Y %H:%M:%S");
// コメント追記 A 曜日英語表記,B 月英語表記,m 月の数字,d 日,Y 年,H時:M分:S秒
}
}
void setup() {
Serial.begin(115200);
//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime();
//disconnect WiFi as it's no longer needed
//WiFi.disconnect(true); //無効にしました
//WiFi.mode(WIFI_OFF); // 無効にしました
}
void loop() {
//delay(1000); // 無効にしました
printLocalTime();
delay(660000); // 追記しました
}
(スケッチ例を公開している方々に感謝します。)
RTC時刻合わせするスケッチもよかったらどうぞ
#include <WiFi.h>
#include "time.h"
#include <Wire.h>
#include <RTClib.h>
const char* ssid = "my-ssid";
const char* password = "my-password";
const char* ntpServer = "pool.ntp.org"; // pool.ntp.org
const long gmtOffset_sec = 9 * 3600; // 時差を秒で設定・・・9時間
const int daylightOffset_sec = 0; // サマータイム設定・・・0
unsigned long interval_t = 60000 * 61 * 1; // 60000(mS)*60*1=1h 60000(1min)
unsigned long previousMillis_t = 0;
unsigned long previous_t = 0;
char date_ymdhms[21]; // yyyy/mm/dd,hh:mm:ssn0
RTC_DS3231 rtc;//select use RTC DS3231
void printLocalTime() {
//sntp_get_sync_status()は時間同期のステータスを取得します。
//更新が完了すると、ステータスはSNTP_SYNC_STATUS_COMPLETEDとして返されます。
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
if (sntp_get_sync_status() == SNTP_SYNC_STATUS_COMPLETED) {
Serial.println("sntp_get_sync_status = COMPLETED");
Serial.println(&timeinfo, "%A, %B %m %d %Y %H:%M:%S");
}
}
void setup() {
Serial.begin(115200);
Wire.begin();
//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
printLocalTime(); // NTP時刻取得、同期ステータス表示、システム時刻表示
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
}
// RTCが電源を失った時(電池切れ)getLocalTime()して取得成功の場合取得時刻をRTCにセットし、
// 失敗の場合コンパイル時刻をRTCにセットする。
if (rtc.lostPower()) {
Serial.println("RTC lost power, let's set the time!");
struct tm timeInfo;
if (!getLocalTime(&timeInfo)) {
/* 失敗でメッセージを表示しコンパイル時刻をRTCへセット 取得成功で取得時刻をRTCへセット */
Serial.println("Failed to obtain time Set to compile time"); // 時間の取得に失敗しましたコンパイル時刻をセットします
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // コンパイル日時を仮設定
DateTime now = rtc.now();
sprintf(date_ymdhms, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
Serial.println(date_ymdhms);
} else {
rtc.adjust(DateTime(timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec));
//tm_year:1900年からの年数 tm_mon:1月からの月数
Serial.println("adjust RTC !!");
DateTime now = rtc.now();
sprintf(date_ymdhms, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
Serial.println(date_ymdhms);
}
}
//disconnect WiFi as it's no longer needed
//WiFi.disconnect(true);
//WiFi.mode(WIFI_OFF);
}
void loop() {
// 定期的にgetLocalTime()して同期できたらRTCをセットする
unsigned long currentMillis_t = millis();
if (currentMillis_t - previousMillis_t >= interval_t) { //interval_t 61分はOK60分はNG
previousMillis_t = currentMillis_t;
struct tm timeInfo;
if (getLocalTime(&timeInfo)) {
if (sntp_get_sync_status() == SNTP_SYNC_STATUS_COMPLETED) {
rtc.adjust(DateTime(timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec));
//tm_year:1900年からの年数 tm_mon:1月からの月数
Serial.println("adjust RTC !!");
} // else { Serial.println("NOT COMPLET"); }
} else {
Serial.println("Failed to obtain time");
}
}
//delay(1000);
// 10分毎にRTC時刻を取得して表示する。
unsigned long interval = 60000 * 10 *1; // 60000(1min)
unsigned long current_t = millis();
if (current_t - previous_t >= interval) {
previous_t = current_t;
//printLocalTime(); // このスケッチオリジナルの関数
DateTime now = rtc.now();
sprintf(date_ymdhms, "%04d/%02d/%02d,%02d:%02d:%02d", now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
Serial.println(date_ymdhms);
}
}