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

Espruino on ESP32 起動時に時刻合わせを行う

ESP32のRTCはバッテリバックアップされていないようなので、電源OFFで時刻を忘れてしまうようです。
あ、以前(Espruino on ESP32 でぽちっとな - いっぺーちゃんの いろいろやってみよ~) gettimeofday使わないようにしたので、RTCがバッテリバックアップされていてもダメか。

時刻合わせを行うには、SNTPでタイムサーバから時刻を取得するのが一般的ですが、EspruinoはUDP通信をサポートしていない(!!!?)ので、SNTP処理をJavascriptで記述できません。

次の記事では、時刻合わせをしておく必要があるので、とりあえず、起動時にSNTPを実行して時刻合わせを行うような処理を追加しておきます。

 

targets/esp32/main.c に以下の修正を加えます。

diff --git a/targets/esp32/main.c b/targets/esp32/main.c
index 00a9dcf..024ad6b 100644
--- a/targets/esp32/main.c
+++ b/targets/esp32/main.c
@@ -41,6 +41,47 @@ static void timerTask(void *data) {
   }
 }
 
+// ADD start [IPPEI]
+#include "apps/sntp/sntp.h"
+static void sntpTask(void *data) {
+    int t_flag = 0;
+    time_t now = 0;
+    int retry = 0;
+    const int retry_count = 10;
+
+    jsiConsolePrintf("SNTP_task: Initializing SNTP\n");
+    sntp_setoperatingmode(SNTP_OPMODE_POLL);
+    sntp_setservername(0, "pool.ntp.org");
+    sntp_init();
+    // wait for time to be set
+    retry = 0;
+    while(++retry < retry_count) {
+        // jsiConsolePrintf("SNTP_task: Waiting for system time to be set... (%d/%d)\n", retry, retry_count);
+        vTaskDelay(2000 / portTICK_PERIOD_MS);
+        time(&now);
+        //printf("SNTP_task: time :%ld\n", now);
+        if (now >= 946684800) {
+            // 2000/1/1 00:00:00 ~
+            t_flag = 1;
+            // set system time
+            JsSysTime stime = (JsSysTime)now * (JsSysTime)(1000*1000);
+            jsiLastIdleTime = stime;
+            jshSetSystemTime(stime);
+            break;
+        }
+    }
+    if (!t_flag) {
+        jsiConsolePrintf("SNTP_task: **** system time is NOT set ****\n>");
+    }
+    else {
+        jsiConsolePrintf("SNTP_task: system time is set\n>");
+    }
+    // jsiConsolePrintf("SNTP_task: stop SNTP\n");
+    sntp_stop();
+    vTaskDelete(NULL);
+}
+// ADD end [IPPEI]
+
 
 static void espruinoTask(void *data) {
   PWMInit();
@@ -91,10 +132,12 @@ int app_main(void)
   task_init(espruinoTask,"EspruinoTask",20000,5,0);
   task_init(uartTask,"ConsoleTask",2000,20,0);
   task_init(timerTask,"TimerTask",2048,19,0);
+  task_init(sntpTask,"sntpTask",2048,19,0);
 #else
   xTaskCreatePinnedToCore(&espruinoTask, "espruinoTask", 20000, NULL, 5, NULL, 0);
   xTaskCreatePinnedToCore(&uartTask,"uartTask",2000,NULL,20,NULL,0);
   xTaskCreatePinnedToCore(&timerTask,"timerTask",2048,NULL,19,NULL,0);
+  xTaskCreatePinnedToCore(&sntpTask,"sntpTask",2048,NULL,19,NULL,0);
 #endif
   return 0;
 }

 

処理としては、起動時に sntpTask を起動し、その中でSNTP処理を起動、時刻が設定されるのを待ちます。
時刻が設定されたら(2000年1月1日 00:00:00 以降の時刻を取得できたら設定済みとみなす)、システム時刻を設定し、SNTP処理を終了してタスクを終了します。
時刻が設定されていなければ、2秒待ってリトライ。retry_count回(あ、retry_count-1回か?サンプルプログラムから拾ってきたままだ(^^ゞ。。。その辺はあまり重要ではないので。)行ってもダメなら設定を諦めます。
使用するタイムサーバを変更したいときは、sntp_setservernameの第2パラメータを変更してください。
メインタスクで処理を行わず専用のタスクを起動しているのは、時刻設定待ちでシステム起動を中断しないためです。

無事時刻が設定されれば、コンソールに「SNTP_task: system time is set」と表示されます。

時刻を取得するには、

var date=new Date()

と実行すれば現在の時刻が取得できます。

時刻を年月日時分秒で確認するには以下のように実行します。

console.log(date.toString())
Sun Jul 23 2017 03:45:00 GMT+0000

。。。時刻が違うって?
デフォルトではグリニッジ標準時(GMT)です。
(UTCの方が正しいと思うけど、気にしない)

日本時間を表示するには、以下のようにtimezoneを設定します。

E.setTimeZone(9);

再度表示してみます。

console.log(date.toString())
Sun Jul 23 2017 12:45:00 GMT+0900

はい、できました。