【Qiita電子工作部】ニトリLEDデジタル時計（改）からThingSpeakへ温度、湿度、気圧データをおくってみた

![title](https://github.com/riraosan/riraosan.github.io/blob/master/2021-04-30/titlepic2.png?raw=true)

# 目次

- [はじめに](#はじめに)
- [開発環境について](#開発環境について)
- [BME280の温度・湿度・気圧をクラウドサービスに送ってみる。(ThingSpeak)](#bme280の温度湿度気圧をクラウドサービスに送ってみるthingspeak)
    - [ThingSpeakって何](#thingspeakって何)
    - [ThingSpeakへ気温、湿度、気圧データを送るにはREST APIを叩く](#thingspeakへ気温湿度気圧データを送るにはrest-apiを叩く)
    - [ESP32(ATOM Lite）からThingSpeak APIを叩いてみる](#esp32atom-liteからthingspeak-apiを叩いてみる)
- [おわりに](#おわりに)

# はじめに

今日は2021年GW初日。自宅に引きこもっています。ちょくちょく現場に出勤しているものの、ほぼ毎日在宅勤務です。

そんな毎日を過ごしていると、２月ぐらいにしょうもないアイデアが出てきました。

- ホームセンター「ニトリ」で買ったLEDデジタル時計（ホルツM）をESP32-WiFi-NTP時計に改造できるんじゃない？

で、とりあえず[できちゃいました。目標達成です](https://github.com/riraosan/ESP32_ntp_clock)。[作成済みの記事](https://qiita.com/riraosan/items/b38e11ea974d6900a515)はちょくちょく改修していく予定です。

余力があったので、引き続きこのネタを少しだけ深堀りしようと思います。

目標は次のとおり。

- [x] BME280の温度・湿度・気圧をクラウドサービスに送ってみる。(IFTTT, ThingSpeakとかとか)
- [ ] DAISOで買ってきた人感センサーライト(税込330円）を再利用して、じいじ、ばあばの動きを検出したら、孫に通知を出す仕組みを作ってみる。

# 開発環境について

[VSCode](https://code.visualstudio.com/)+[PlatformIO](https://platformio.org/)+[arduino-esp32](https://github.com/espressif/arduino-esp32)+[m5Stack ATOM Lite](https://shop.m5stack.com/products/atom-lite-esp32-development-kit?variant=32259605200986)でサンプルコードを作成しています。

ライブラリのインポート方法は[platformio.iniファイル](https://github.com/riraosan/ESP32ClockDetectingMovement/blob/main/platformio.ini)か[PlatformIOドキュメント](https://docs.platformio.org/en/latest/projectconf/index.html)などを参照してください。

# BME280の温度・湿度・気圧をクラウドサービスに送ってみる。(ThingSpeak)

## [ThingSpeak](https://thingspeak.com/)って何？

[The MathWorks, Inc](https://jp.mathworks.com/)が運営している、IoT機器が記録したデータを分析するプラットフォームサービスです。Facebookで海外の方が紹介していたので使ってみました。

>About ThingSpeak
ThingSpeak is an IoT analytics platform service that allows you to aggregate, visualize, and analyze live data streams in the cloud. You can send data to ThingSpeak from your devices, create instant visualization of live data, and send alerts.
ThingSpeakは、ライブデータストリームをクラウド上で集約、可視化、分析することができるIoT分析プラットフォームサービスです。デバイスからThingSpeakにデータを送信し、ライブデータを瞬時に可視化したり、アラートを送信することができます。

＃DeepLで翻訳したら、かなり自然な日本語文が出てきた。:open_mouth:

ThingSpeakにアカウントを作って「チャンネル」を作成しました。さらに、[`ニトリNTP時計`](https://github.com/riraosan/ESP32_ntp_clock#-ntp-clock-example-for-esp32-m5stack-atom-lite)から送ったデータをグラフで表示させてみました。

https://thingspeak.com/channels/1361249

### チャンネルキャプチャ画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103572/e9b9f523-2934-37ac-78b3-bdfb7c59f0da.png)

グラフはiframeでブログやWikiのWebページに埋め込めるようです。QiitaやGitHubはiframeを許可してないので、埋め込めません。キャプチャ画像を貼っておきます。

## ThingSpeakへ気温、湿度、気圧データを送るにはREST APIを叩く

ThingSpeakのチャンネルにはREST APIキーが与えられていて、そのキーを含むURIへリクエストを送ると`Channel Feed`へデータを書き込めます。APIキーは`Write API Key`と`Read API Keys`があります。`Read API Keys`は公開しても問題ないと思います。

![2021-04-29_1619667584.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103572/85b65918-d33d-db99-b717-2e4e1f02d8c3.png)

REST APIはこのような感じ。[^1]

```html:Write&#x20;a&#x20;Channel&#x20;field
GET https://api.thingspeak.com/update?api_key=XXXXXXXXXX&field1=0
```
```html:Read&#x20;a&#x20;Channel&#x20;field
GET https://api.thingspeak.com/channels/1361249/fields/1.json?results=2
```
[^1]: 書き込んでいるのにGETリクエストですね。PUTじゃないの？新規にフィールドを作成しているわけではないので、POSTではないよね。
チャンネルにはfieldが8個用意されています(field1~field8)。`...&field1=24.999` `...&field8=1021.22`のようにしてデータを送信します。

## ESP32(ATOM Lite）からThingSpeak APIを叩いてみる

ThingSpeakがAPIを叩く為のarduino-esp32ライブラリをすでに提供してくれていました。WiFiClientSecureライブラリと[thingspeak-arduinoライブラリ](https://github.com/mathworks/thingspeak-arduino)を使いました。[わたしが作成したサンプルはGitHub](https://github.com/riraosan/ESP32ClockDetectingMovement/blob/main/src/main.cpp)にあります。

`WiFiClientSecure.h`ライブラリと`ThingSpeak.h`ライブラリを読み込みます。`#define TS_ENABLE_SSL`を忘れないように。

```c++:main.cpp
#define TS_ENABLE_SSL //Don't forget it for ThingSpeak.h!!
#include <SerialTelnetBridge.h>
#include <Ticker.h>
#include <ESPUI.h>
#include <TM1637Display.h>
#include <BME280Class.h>
#include <Button2.h>
#include <WiFiClientSecure.h>
#include <ThingSpeak.h>
#include "secrets.h"
```

`secrets.h`を読み込みます。このファイルに`SECRET_CH_ID`, `SECRET_WRITE_APIKEY`と`SECRET_TS_ROOT_CA`を定義します。
下に示した`SECRET_TS_ROOT_CA`はサンプルからコピーしたものです。
`SECRET_TS_ROOT_CA`の作成方法は[Arduino – ESP32 WiFiClientSecure ライブラリで、安定して https ( SSL )記事をGETする方法](https://www.mgo-tec.com/blog-entry-arduino-esp32-ssl-stable-root-ca.html/2)を参照してください。ルート証明書はしばらく更新されないと思われます。更新されると、ThingSpeak APIにリクエストを送ってもレスポンスが返ってきませんので注意してください。

>有効期限(Expiration Date)
Expiration Date: November 9, 2031 at 7:00:00 PM EST

```c++:secrets.h
#define SECRET_CH_ID 0000000      // replace 0000000 with your channel number
#define SECRET_WRITE_APIKEY "XYZ" // replace XYZ with your channel write API Key

// ThingSpeak Root Certificate, Expiration Date: November 9, 2031 at 7:00:00 PM EST
#define SECRET_TS_ROOT_CA "-----BEGIN CERTIFICATE-----\n"                                      \
                          "MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" \
                          "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
                          "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" \
                          "ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" \
                          "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" \
                          "LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" \
                          "RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" \
                          "+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" \
                          "PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" \
                          "xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" \
                          "Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" \
                          "hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" \
                          "EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" \
                          "MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" \
                          "FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" \
                          "nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" \
                          "eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" \
                          "hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" \
                          "Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" \
                          "vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" \
                          "+OkuE6N36B9K\n"                                                     \
                          "-----END CERTIFICATE-----\n"
```

つぎのようにThingSpeakライブラリを初期化します。

```c++:main.cpp
WiFiClientSecure _client;
...
void initThingSpeak(void)
{
    _client.setCACert(certificate);
    ThingSpeak.begin(_client);
}
```
setup()で初期化実行します。WiFiアクセスポイントにつながってから実行します。

```c++:main.cpp
void setup(void)
{
...
    initThingSpeak();
...
}
```
つぎのような感じで、ThingSpeakへデータを送ります。

```c++:main.cpp
void sendThingSpeakChannel(float temperature, float humidity, float pressure)
{
    ThingSpeak.setField(1, temperature);
    ThingSpeak.setField(2, humidity);
    ThingSpeak.setField(3, pressure);

    // write to the ThingSpeak channel
    int code = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
    if (code == 200)
        log_d("Channel update successful.");
    else
        log_d("Problem updating channel. HTTP error code %d", code);
}
```

わたしの作成したコードでは、Tickerライブラリを使って1分毎にチャンネルへデータを送信しています。無料アカウントの場合、あるリクエストから次のリクエストまでの間隔が15秒以上必要という制限があります。データの送信に失敗する場合は適切なウェイトを入れてください。

# おわりに

次は、このニトリLEDデジタルWiFi-NTP時計にPIRセンサー（人感センサー）を取り付けた場合について記事を書きたいと思います。
このPIRセンサーは[DAISOで購入した人感センサーライト（税込み330円）](https://note.com/tomorrow56/n/n145b9c184f36)をばらして制御基板をそのままニトリLEDデジタル時計に組み込んでみました。
この人感センサーをつかって、「じいじ、ばあばの動きを検出したら、孫に通知を出す仕組みを作ってみる。」を実現してみたいと思います。

（了）