温湿度・気圧のロガーを作る #5

**[1話 センサー1つ+Ambient編](https://qiita.com/after-a-rain/items/20d337702f93cd589044)** / **[2話 センサー2つ+Ambient編](https://qiita.com/after-a-rain/items/80fe94cb3b2870ea9f0c)** / **[3話 センサー4つ編](https://qiita.com/after-a-rain/items/f64626f3f72e62b783c0)**
**[4話 SDカード記録編](https://qiita.com/after-a-rain/items/d736854791fa27aea543)** / **[5話 システム時刻・NTP編](https://qiita.com/after-a-rain/items/ec9e772df0c6ea029e84)**

あらすじ: BME280、SDカードモジュールのSPI接続と、SDカードモジュールのテストができました。

# 5話

NTPサーバーからの時刻取得のしくみを勉強しました。

## 用意したもの

- Arduino的なもの ESP-WROOM-02開発ボード (Switch Science)  **×1**  
  https://www.switch-science.com/catalog/2500/



## やったこと

いつもどおり、HPを見ながら...と思ったところ、ググっているとこんな記事に出会いました。

​	ESP8266のntpの設定は1行で - Qiita
​	https://qiita.com/h_nari/items/d0374d1e1e36b9d988c0

こんなに楽なのだと感動しました。
なので、こちらを試しながら、前回の参考HPのNTP関連のスケッチを書き換える方針で考えます。

サンプルスケッチをそのまま書き込んで動作確認。うまくいきました。
しかし、このあと書き換えるにあたり、時刻データの格納のしくみを考えなければいけません。
なお、調べていくにつれ、C言語の基本っぽいのかなとわかりました。

スケッチを詳しく解釈していきます。

まず``void setup()``内の

```c#
configTzTime("JST-9", "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
```

 で、NICTから日本標準時を取得しシステム時刻を変更しています。(標準時を日本時間として取得 のが適切?)

次に、``void loop()``内での動きを理解します。

```c#
void loop() {
  time_t t;
  struct tm *tm;
  static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};

  t = time(NULL);
  tm = localtime(&t);
  Serial.printf("ESP8266/Arduino ver%s :  %04d/%02d/%02d(%s) %02d:%02d:%02d\n",
        __STR(ARDUINO_ESP8266_GIT_DESC),
        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
        wd[tm->tm_wday],
        tm->tm_hour, tm->tm_min, tm->tm_sec);
  delay(1000);
}
```

2行目`` time_t t;``でtime_t型の変数としてtを定義しています。time_t型はシステム時刻を扱うデータ型。time_t型は、1970/1/1 0:00:00 からの秒数を保存。
6行目``  t = time(NULL);``でtに現在のシステム時刻を格納します。``time(NULL)``はtime関数における現在時刻を戻り値として教えてくれる。
ここまでで、``t``に日本標準時が格納されたことがわかります。

3行目``struct tm *tm;``では tm構造体 としての tmという名称のポインタ変数を定義しています。
tm構造体は、tm_secに秒、tm_minに分を格納する感じで、現在時刻を全部バラバラにして格納する枠組み。
ポインタ変数は、エクセルでB1に=A1と入れるとA1の値を表示するみたいな感じです。凄いのは、B1を編集すればA1も変わるというところ。化けの皮か。

7行目`` tm = localtime(&t);``で ポインタ変数 tm に t のポインタをlocaltime関数で1970/1/1からの秒を年月日時分秒にバラバラにして格納。バラバラにしてもポインタのままなのね、しゅごい。
localtime関数は19701/1 からの秒を、年月日時分秒にバラバラにして返してくれる関数。tm構造体専用技。

なので今tmには、tに入っている取得した日本標準時が1970からの秒になっているやつに、リンクするためのアドレスが年月日などに分けて入っている感じなのかな。



```C#
 Serial.printf("ESP8266/Arduino ver%s :  %04d/%02d/%02d(%s) %02d:%02d:%02d\n",
        __STR(ARDUINO_ESP8266_GIT_DESC),
        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
        wd[tm->tm_wday],
        tm->tm_hour, tm->tm_min, tm->tm_sec);
```

ここでは、シリアルモニタへの表示をさせるわけですが、printf()を学びます。

printf("hogehoge① hige②", ①の情報元, ②の情報元)という感じで書いてあって、" "内の①,②のポジションには%~~の形で①, ②の情報の表示ルールを書くわけです。

今回で言えば、最初に現れるのが``%S``で情報元は``__STR(ARDUINO_ESP8266_GIT_DESC)``なので、日本語になおすと、 <u>バージョン情報</u>を<u>文字列</u>として表示してねという感じ。
次は、``%04d``で情報元は`` tm->tm_year+1900``なので、<u>0埋め4桁の符号付き整数</u>で<u>ポインタ変数tm中のtm_yearに1900を足して</u>表示してねという感じ。

ここで、一つ気になったのはprintf中で演算したものはそのprintfを終えても残るのか否か。ググるよりやるほうが速そうなので今度やってみます。**(課題)**

これで、一通りシステム時刻関連のあれこれと、printf関連のルールを学びました。
あと、ポインタと構造体を理解したのも美味しい。
今後、スケッチを最適化したり、書き起こしたいときに役に立ちそうです。

次回は、全部くっつけて、時刻取得SDカード温湿度気圧ロガーをそれっぽくします。

**[6話に続きます]**()

## 参考文献

勝手にソースコードを拝借しています。すみません。ありがとうございます。
何かあればお申し付けください。

+ ESP8266 with two BME280 Sensors over SPI – Robot Zero OneRobot Zero One  
  https://robotzero.one/esp8266-two-bme280-sensors-spi/
+ 温度、湿度、気圧を測定し、記録する - AmbientでIoTをはじめよう  
  https://pages.switch-science.com/letsiot/temphumidpress/
+ ESP8266のntpの設定は1行で - Qiita  
  https://qiita.com/h_nari/items/d0374d1e1e36b9d988c0
+ 読本C/9.9 時間関数 - WisdomSoft  
  http://www.wisdomsoft.jp/412.html
+ C言語入門 - とほほのWWW入門  
  http://www.tohoho-web.com/ex/c-lang.html