wifi + NTP (ESP-IDF)
プログラムの書き方
wi-fi については, ESP-IDF Programming Guide の API Reference の Wi-Fi を参照してプログラムを作成する. 動作モードには Station mode と AP mode の 2 つがあるが, "ESP32 connects to an access point." である Station mode を使えば良い.
また, NTP での時刻合わせについては, ESP-IDF Programming Guide の API Reference の System Time の "SNTP Time Synchronization" を参照すれば良い.
サンプルプログラムの実行
wifi 接続
$ cd ~/esp $ cp -r esp-idf/examples/wifi/getting_started/station wifi-station $ cd wifi-station
コンパイル
$ make
最初に make をすると menuconfig の画面が表示される. "Example Configuration" を選択し, 接続先の AP (アクセスポイント) の SSID とパスワードを入力する.
実行する. wifi への接続と取得したネットワークパラメタが確認できる.
$ make flash monitor ...(中略)... I (3067) esp_netif_handlers: sta ip: 192.168.0.29, mask: 255.255.255.0, gw: 192.168.0.1 I (3067) wifi station: got ip:192.168.0.29 ...(後略)...
プロジェクトの作成とサンプルプログラムの実行
$ cd ~/esp $ cp -r esp-idf/examples/protocols/sntp wifi-sntp $ cd wifi-sntp
コンパイル
$ make
最初に make をすると menuconfig の画面が表示される. ここで SSID とパスワードを入力する.
実行する. ログに現在の New York や上海の現在時刻が表示されているのがわかる.
$ make flash monitor ...(中略)... I (3057) esp_netif_handlers: sta ip: 192.168.0.29, mask: 255.255.255.0, gw: 192.168.0.1 I (3057) example_connect: Got IP event! I (3057) example_connect: Connected to <YOUR_SSID> I (3067) example_connect: IPv4 address: 192.168.0.29 I (3067) example_connect: IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fe02:23f8 I (3077) example: Initializing SNTP I (3077) example: Waiting for system time to be set... (1/10) I (5027) example: Notification of a time synchronization event I (5087) wifi:state: run -> init (0) I (5087) wifi:pm stop, total sleep time: 2802519 us / 4182121 us ...(中略)... I (5187) example: The current date/time in New York is: Tue May 5 22:40:08 2020 I (5187) example: The current date/time in Shanghai is: Wed May 6 11:40:08 2020 I (5197) example: Entering deep sleep for 10 seconds ...(後略)...
サンプルプログラムの修正
前述の esp-idf/examples/wifi/getting_started/station に NTP 関連のソースコードを追加することを考える. esp-idf/examples/protocols/sntp でもネットワークに接続可能であるが, そのメインプログラム中に書いてある通り, 接続を担っている example_connect() は機能が非常に単純なようであり, そのまま使うのは推奨されていないからである.
esp-idf/examples/protocols/README.md より抜粋 Protocols examples use a simple helper function, `example_connect()`, to establish Wi-Fi or Ethernet connection. This function is implemented in [examples/common_components/protocol_examples/common/connect.c](../common_components/protocol_examples_common/connect.c), and has a very simple behavior: block until connection is established and IP address is obtained, then return. This function is used to reduce the amount of boilerplate and to keep the example code focused on the protocol or library being demonstrated. The simple `example_connect()` function does not handle timeouts, does not gracefully handle various error conditions, and is only suited for use in examples. When developing real applications, this helper function needs to be replaced with full Wi-Fi / Ethernet connection handling code. Such code can be found in [examples/wifi/getting_started/](../wifi/getting_started) and [examples/ethernet/basic/](../ethernet/basic) examples.
以下では, メインプログラムの修正箇所のみ述べる.
ヘッダファイルの追加
18 19 #include "lwip/err.h" 20 #include "lwip/sys.h" 21 22 #include "esp_sntp.h" 23 static void sntp_obtain_time(void); 24
- 22 行目: include ファイルの追加. NTP のヘッダファイル.
- 23 行目: 後述する関数の定義
メイン関数の修正
125 void app_main(void) 126 { 127 //Initialize NVS 128 esp_err_t ret = nvs_flash_init(); 129 if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { 130 ESP_ERROR_CHECK(nvs_flash_erase()); 131 ret = nvs_flash_init(); 132 } 133 ESP_ERROR_CHECK(ret); 134 135 ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); 136 wifi_init_sta(); 137 138 //NTPでの時間合わせ 139 sntp_obtain_time(); 140 }
- 138-139 行目: 追加
関数の追加
142 static void sntp_obtain_time(void) 143 { 144 char strftime_buf[64]; 145 146 // STNP 初期化 147 ESP_LOGI(TAG, "Initializing SNTP"); 148 sntp_setoperatingmode(SNTP_OPMODE_POLL); 149 sntp_setservername(0, "ntp.nict.jp"); 150 sntp_init(); 151 152 // wait for time to be set 153 time_t now = 0; 154 struct tm timeinfo = { 0 }; 155 int retry = 0; 156 const int retry_count = 10; 157 while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) { 158 ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); 159 vTaskDelay(2000 / portTICK_PERIOD_MS); 160 } 161 162 time(&now); 163 setenv("TZ", "JST-9", 1); 164 tzset(); 165 localtime_r(&now, &timeinfo); 166 strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); 167 ESP_LOGI(TAG, "The current date/time in Tokyo is: %s", strftime_buf); 168 169 printf("%04d/", timeinfo.tm_year + 1900); 170 printf("%02d/", timeinfo.tm_mon + 1); 171 printf("%02d", timeinfo.tm_mday); 172 printf(" "); 173 printf("%d", timeinfo.tm_wday); 174 printf(" "); 175 printf("%02d:", timeinfo.tm_hour); 176 printf("%02d:", timeinfo.tm_min); 177 printf("%02d\n", timeinfo.tm_sec); 178 }
プログラムの実行
実行すると, 現在の日本時間がログに表示される.
$ make flash monitor I (3067) esp_netif_handlers: sta ip: 192.168.0.29, mask: 255.255.255.0, gw: 192.168.0.1 I (3067) wifi station: got ip:192.168.0.29 I (3067) wifi station: connected to ap SSID:XXXXXXXX password:XXXXXXXX I (3077) wifi station: Initializing SNTP I (3077) wifi station: Waiting for system time to be set... (1/10) I (5087) wifi station: Waiting for system time to be set... (2/10) I (7087) wifi station: The current date/time in Tokyo is: Wed May 6 22:30:24 2020 2020/05/06 3 22:30:24