ESP32でNetatmo Weather Stationもどきを作る

# はじめに

[Netatmo ウェザーステーション](https://www.amazon.co.jp/dp/B00FFS73GG) という製品がございまして、室内と室外の温度湿度を測ることができます。
が、この製品は長らく使っていると壊れます。
私が買ったNetatmoも最近クラウドにレポートを送るのが途切れ途切れになってきました。
周囲でも「壊れた」という声はきくのですが、そうやって買い直させてクラウド維持費を稼ぐビジネスモデルなのかもしれません（そんな馬鹿な！）。

というわけで自分で似たようなものを作りました。

室内モジュール

![室内.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204320/a36b8f04-69e6-f638-fcce-a8bd203d9b6c.jpeg)

室外モジュール

![室外.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204320/3b9b6ec0-ef5d-4618-8eb3-7ab8e9d201df.jpeg)


# 目標

以下を計測しWiFi経由でMQTTにてスマートホーム制御プロセスに報告します。

* 室内
    * 温度
    * 湿度
    * 大気圧
    * ガス
    * 二酸化炭素濃度
    * 騒音
    * 臭い
* 室外
    * 温度
    * 湿度
    * 大気圧
    * ガス
    * 煙
    * 植木鉢の水分

Netatmoとは異なる要求としては以下を設定しました。

* 家庭内LANで完結させ、外部にデータを出さない
* Netatmoの最小計測間隔は5分だが、より高頻度に計測し、「二酸化炭素濃度が高くなったら換気扇を回す」が料理をはじめたらすぐに発生することを目指す
* タバコの煙・臭いを検出し、室外がタバコ臭い時は換気扇を動作させないようにする (たまに近所でタバコを吐く人がいるため。吸ってもいいが吐くな！)
* RGB LEDで状態が常にみえるようにする

# レシピ

以下に記載していない配線材料、抵抗、コンデンサ、ケース類を含めて全部で1万円くらいです。
もちろん秋月で買わなければならない義理はございませんので、amazonやaliexpressで安く仕上げましょう。

## 室内・室外共通部品 (各1台、合計2組)

| 製品名    | 秋月売り場 | お値段(約) |
| -------- | -------- | --------: |
| ESP32    | [ＥＳＰ３２－ＤｅｖＫｉｔＣ－３２Ｅ ＥＳＰ３２－ＷＲＯＯＭ－３２Ｅ開発ボード ４ＭＢ: 無線、高周波関連商品 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gM-15673/) | 1200円 |
| 5V ACアダプタ | [超小型スイッチングＡＣアダプター５Ｖ１Ａ ＡＤ－Ｄ５０Ｐ１００: 電源一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gM-06096/) | 600円 |
| AM2320 | [温湿度センサ モジュール ＡＭ２３２０: センサ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gM-08663/) | 600円 |
| BME680 | [ＢＭＥ６８０使用 温湿度・気圧・ガスセンサモジュールキット: 組立キット(モジュール) 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gK-14469/) | 1300円 |

## 室内

| 製品名    | 秋月売り場 | お値段(約) |
| -------- | -------- | --------: |
| MH-Z19C | [ＣＯ２センサーモジュール ＭＨ－Ｚ１９Ｃ: センサ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gM-16142/) | 2500円 |
| コンデンサマイク | [エレクトレットコンデンサーマイクロホン（ＥＣＭ） ＷＭ－６１Ａ相当品 リードピン付: パーツ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gP-08182/) | 50円 |
| LM386 | [オーディオアンプＩＣ ＮＪＭ３８６ＢＤ: 半導体(モジュール) 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gI-00022/) | 50円 |
| TGS2450 | [においセンサ ＴＧＳ２４５０: センサ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gP-00989/) | 300円 |
| TTA008B | [トランジスタ ＴＴＡ００８Ｂ ８０Ｖ２Ａ: 半導体(モジュール) 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gI-09938/) | 25円 |
| RGB LED | [ＲＧＢフルカラーＬＥＤ ５ｍｍ ＯＳＴＡ５１３１Ａ カソードコモン （１０個入）: LED(発光ダイオード) 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gI-03037/) | 500円(10個) |
| LED拡散∩ | [ＬＥＤ光拡散キャップ（５ｍｍ） 白 （５０個入）: LED(発光ダイオード) 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gI-01120/) | 200円(50個) |

## 室外

| 製品名    | 秋月売り場 | お値段(約) |
| -------- | -------- | --------: |
| MQ-2 | [ガスセンサー（煙センサー） ＭＱ－２: センサ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gP-16141/) | 300円 |
| MQピッチ変換 | [ＭＱガスセンサ用ピッチ変換キット: センサ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gK-16296/) | 60円 |
| SEN0193 | [静電容量式土壌水分センサー: センサ一般 秋月電子通商-電子部品・ネット通販](https://akizukidenshi.com/catalog/g/gM-13550/) | 1000円 |

# ハードウェア

## 室内・室外共通

### ESP32

買ってきて技適マークがあれば手続きなしでWiFiを出せます。

### AM2320, BME680 (温度、湿度、大気圧、ガス）

ともにi2cなので適当にプルアップしてi2cに繋げばOK.
秋月のBME680モジュールはジャンパ設定でプルアップしてくれます。

BME680があればAM2320は不要といえば不要ですが、今回は本体からすこし離して本体の発熱の影響をうけない計測も試してみるために追加しました。
内外ともにBME680にする必要もないといえばそうなのですが、比較をするには同じものが2つあったほうが正確ですね（部品の個体差はあるでしょうが）。

BME680のガスセンサーは、IAQという空気質の指標の計算ができます。
が、計算式が記載されているdatasheetには誤記らしきものがたくさんあり、公式のライブラリはクローズソースになっています。
以下のソースが参考になります。

[G6EJD/BME680-Example: Using the BME680 to measure temperature, pressure, humdity and air quality](https://github.com/G6EJD/BME680-Example)
[thstielow/raspi-bme680-iaq: Basic IAQ calculator for the Bosch bme680 sensor, compensating the humidity dependency and long-term drifts. Outputs a gas quality score on a range of 0-100%.](https://github.com/thstielow/raspi-bme680-iaq)


## 室内

### MH-Z19C (二酸化炭素濃度)

幅がユニバーサル基盤と微妙にずれていましたがソケットをつけたら無事つきました。
発熱しますので近くに温度湿度センサーをつけてはいけません。

PWMとシリアル接続で二酸化炭素濃度が読めます。
オートキャリブレーション機能を設定するにはシリアル接続が必須です。
他方、シリアル接続のみではマニュアルキャリブレーションができません。
従って、

* シリアル接続
* マニュアルキャリブレーション

の双方(信号線としては3本)をESP32と接続します。

### コンデンサマイク、LM386 (騒音)

以下と同じです。

[Arduino Sound Level Meter - Measure Sound/Noise Level in dB with Microphone and Arduino](https://circuitdigest.com/microcontroller-projects/arduino-sound-level-measurement)

### TGS2450 (臭い)

秋月の販売ページの接続例をそのまま実装すればできます。 
センサーのピン番号に注意。

### RGB LED (表示用)

Netatmoは上部タッチセンサーを押すと二酸化炭素濃度に応じて光ります。
平常レベルだと緑、ちょっと高くなると黄色、濃くなると赤になります。

今回は押さなくても常に連続的に光るようにしました。
ついでにキャンドル風にゆらゆら光らせました。

RGBそれぞれに220Ωを繋げてPWMで光らせます。
RGB LEDは拡散キャップをつけないと色が混ざらないのでつけておきます。

## 室外

電池稼働は諦めて電源を窓の隙間から通します。
そして雨のかからなそうなところに本体を設置し、そこから信号線を伸ばして簡易百葉箱的な覆いの下にAM2320を設置しました。

室外機にのみつくセンサーは以下です。

### MQ-2 (煙)

秋月でピッチ変換ソケットを売っていますのでそれを使います。
負荷抵抗は10kにしました。

### SEN0193 (土壌水分)

近くに小さな植木鉢が置いてあるため、その土壌水分を検出して水切れを教えてもらいます。

# ソフトウェア

今回はArduino IDEから書き込んでいます。
Arduino IDEの設定は以下の通りですね。

[ESP32を買ってしまった - Qiita](https://qiita.com/zuggokuman/items/f16be131f3fd2ea1d478)

5秒ごとに計測し1σ以上の変化があるか1分経過するごとにmqttで報告させています。

Arduino IDEは`.ino`という拡張子ですがその中身はc++です。
内外で共通のクラスを作って継承して共通化しています。
STLが使えるのでリングバッファで時系列情報を蓄積して平均や分散をとったりログを貯めるといったことも簡単にできます。

センサーがエラーを出している時に内蔵LEDを点滅させるようなコードをいれておくと、設置したあとソケットの緩み等による動作不良にすぐに気づくので便利です。

## 使用ライブラリ

以下のライブラリを使用させていただきました。 感謝です。

* [PubSubClient - Arduino Reference](https://www.arduino.cc/reference/en/libraries/pubsubclient/)
* [NTPClient - Arduino Reference](https://www.arduino.cc/reference/en/libraries/ntpclient/)
* [ArduinoJson: Efficient JSON serialization for embedded C++](https://arduinojson.org/)
* [arcao/Syslog: An Arduino library for logging to Syslog server in IETF format (RFC 5424) and BSD format (RFC 3164)](https://github.com/arcao/Syslog)
* AM2320
  [asukiaaa/AM2320_asukiaaa](https://github.com/asukiaaa/AM2320_asukiaaa)
* BME680
  [adafruit/Adafruit_BME680](https://github.com/adafruit/Adafruit_BME680)
* MH-Z19C
  [crisap94/MHZ19: MH-Z19 CO2 sensor library for ESP8266 or Arduino](https://github.com/crisap94/MHZ19)

# ポイント

## ESP32

使ってみて気づいた注意点は...

* WiFi使用時はADC1のみ使用可能 (ADC2は使えない)
* アナログ、デジタルともに入力は3.3Vまで
* デジタル出力も3.3V。5Vの半分は超えるので出すだけなら*大体*動きます（規格が3.0Vではなく3.3Vになっているのはそのためです）
* アナログで計測する電圧の範囲は可変で設定可能(後述)
* i2cを含めてプルアップは自分でいれたほうが安定する
* gpio12を使うとフラッシュがうまく書けないことがある
* 書き込めない時は`...___...___`の時にボタン（下記1つめの記事参照）を長めに押す
* OS起動時のシリアルは74880bps
* OTAは便利

[Arduino IDEでESP32/ESP8266を使う時のメモ - Qiita](https://qiita.com/jerrywdlee/items/586c59e7806c97043cd6)
[ESP32-WROOM-32](https://ht-deko.com/arduino/esp-wroom-32.html)

## mqtt, json

接続がきれたら再接続するコードや、長時間`loop()`が止まる時は`mqtt.loop()`を自分で呼ぶといったおまじないが必要です。

callback関数の中で`publish()`すると引数が破壊されます。
ちゃんとコピーしておくか、callbackの中で`publish()`はしないでどこか別の場所に積んでおいて外のloopで処理します。

今回はmqttではjsonを飛ばしていますが、PCで使うような立派なjsonクラスとは違いメッセージサイズに気を付ける必要があります。

debugのon/offや設置したあとに調整する必要がある値（センサーの閾値、サーボの回転角度など）はmqttで可変にしておくと、ちょっとした調整で焼き直す必要がなくて楽です。

## MH-Z19C

こちらに記載がある通りなのですが、

[ESP32(M5Stack)で作る、安価なCO2モニタ【秋月でCO2センサ取扱開始 記念】 - Qiita](https://qiita.com/nara256/items/a3cecc5fbf043b2d042c)

ESP32はUARTを複数持っていて、それぞれのピンを自由に設定できます。
0番を使うと開発時コンソール出力ができなくなってしまうので別のものを使います。

ブートしたら手動キャリブレーションのピンをHIGHにしてUARTを初期化したのち、オートキャリブレーションを無効化するコマンドを出します。
オートキャリブレーションが有効だと過去24時間の間での最低値を400ppmとして設定してしまうため、室内に設置しているときは誤動作の原因となります。

手動キャリブレーションのためのピンも接続しておき、mqttでリクエストを受け取ったら手動キャリブレーション操作(7秒以上LOWを出力)をするようにします。
風通しの良い室外に30分程度放置してから遠隔でリクエストを飛ばします。
スイッチをつけて人間が近くで押してもいいのですが呼気の影響がでるかもしれません。
というか寒いor暑い季節に外まで押しにいくのは単純に面倒ですね。

オートキャリブレーション無効化コマンドを起動時にだしているのに、なぜか数日後にオートキャリブレーションが走ってしまうことがありました。
数時間ごとにオートキャリブレーション無効化コマンドを発行することで安定してオートキャリブレーションしなくなりました。
コマンド転送を失敗している訳でもなさそうなのですが...

ライブラリの`writeCommnad()`の冒頭に

```c:
  while(hserial->available()){
    hserial->read();
  }
```
を追加しておくと、受信バッファにゴミがあった時でも正しく動くようになります。

## 騒音

適当に`analogRead()`してもなんとなくな数値がとれますが、ちゃんとやるにはFFTして定常ノイズを潰してからA特性で比較したほうがよさそうです。

## ガス・臭い・水分

ちゃんと校正して計算式を立てればいいのですが、リファレンスとなる機材がないので`analogRead()`した値でなんとなく（ひどい）。
しばらく使っていると、「だいたいこの値が閾値かな」というのがわかります。

`analogRead()`について詳細は以下が参考になります。dbの設定が味噌。

[ESP32のADCについて - Qiita](https://qiita.com/koichaman/items/8c98ee5b6028e8d80703)

## RGB LED キャンドル風演出

RGB LEDは青以外のレベルを半分にします。

ESP32 RTOSのマルチスレッド機能を使いLEDをゆらゆら揺らすスレッドを作ります。
測定中でもゆらゆらします。

`loop()`とは別スレッドですので`delay(1000)`とかしてもそのスレッドだけがsleepしてくれます。

[FreeRTOSでマルチタスク (on ESP32) - Qiita](https://qiita.com/hideakitai/items/bd95d0db63097b8808f9)
[\[M5Stack\] マルチスレッドで並列処理を行う - Qiita](https://qiita.com/kotai2003/items/6a4d620a51ca0f1535dc)

夜中にゆらゆら光っても困るので、mqttから遠隔でnightmodeに設定すると消えるようにしました。

今回はRGBでGPIOを3本消費していますが、ピンの節約とデジタル化のためにマイコン付きのLEDにする方法もあります。
[明日の天気を予知してくれる魔法のランタンをつくる - Qiita](https://qiita.com/mtakatou/items/74173c5697f9d1ecfff7)


# 完成!

あとは適当にグラフを書かせたり、観測値に基づいてエアコンを制御したりすれば完成。

# 謝辞

製品やライブラリの作者の皆様、参考にしたサイトの筆者の皆様、ありがとうございました。

# 過去記事紹介と次回予告

過去にQiitaでネタにしたオモチャたち。
実は自宅にあるものは投稿当時から更新しているのですが、そのうち気が向いたらupdate記事を書くかも...

* [おうちハックした自宅に2年すんでみたおはなし - Qiita](https://qiita.com/mtakatou/items/0fc7dc141f49fd1a48a4) (2019年7月)

こちらにある壁から吊っているセンサーもESP32にしてE-INKで状態表示をするようにしました。
基本はMQTTですが、赤外線の信号とE-INK (ePaper)に表示する内容はhttpでPOSTしています。

* [普通の加湿器をラズパイでスマートにしてHomeKitにつなげる - Qiita](https://qiita.com/mtakatou/items/8b9384e529532fc7da4d) (2020年12月)

こちらもESP32にするとともに、歪み計で加湿器全体の重さを計って水の量を推測するようにしました。

* [浴室乾燥機制御盤をNodeMCUとサーボで自動制御する - Qiita](https://qiita.com/mtakatou/items/29dff79dd5500c5de28d) (2019年11月)

こちらもOLEDが焼けてきたのでE-INKに変更してESP32にしました。
いろいろ付けたらピンの数がギリギリでした。

# トンガ火山噴火の気圧変化が計測できましたよ (追記 2022/01/16)

このBME680でも天変地異が起きたことを検出できました。

![bme680.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204320/53fcc0d9-f992-2b96-8438-1eb7213280ce.png)

他の皆さんの観測結果

*  [トンガでの火山噴火による衝撃波の検出に成功? - Qiita](https://qiita.com/tlab/items/5f3df5d2aa84f1d59176)

* [トンガでの火山噴火による衝撃波の検出に成功? in 大阪 - Qiita](https://qiita.com/c60evaporator/items/46b915137d2dbfd24aec)

* [Takahito KAZAMA on Twitter: &quot;京大理学部1号館地下・重力測定室に設置している気圧計（BME280というセンサーを使用）で、どうやらトンガの噴火の空振が観測されているようだ。 普段気圧は日周・半日周的に変化しているけど、昨日20時台だけで約2 hPaの急激な気圧変化が観測されている。 https://t.co/UBhNFWq7r8&quot; / Twitter](https://twitter.com/KazamaTakahito/status/1482511486690140160)

* [Sandy Macdonald on Twitter: &quot;The Tonga volcanic eruption pressure shockwave measured on a hastily set up @pimoroni BME280 sensor and @Raspberry_Pi in York, UK. That's 16,270 km away, and taking 14h 20m to get here gives a speed of 1,135 km/h or 315 m/s! #Tonga #TongaVolcano https://t.co/b4JzUtdih9&quot; / Twitter](https://twitter.com/sandyjmacdonald/status/1482446483655962626)

# センサー地獄！ (追記: 2022秋)

その後、調子に乗って多数のセンサーを載せ、「ぼくのかんがえたさいきょうのセンサー用基底クラス」を継承してシングルトンにするようにし、観測値もinfluxdb/victoria metricsにesp32から直接書き込むようにしました。

* 紫外線

日傘をもってお出かけ。

[Qwiic - VEML6075搭載 UV光センサモジュール — スイッチサイエンス](https://www.switch-science.com/products/7303)

* 土壌水分検出と自動水やり

植木鉢に自動で水やりをします。

[Unit Watering(水分測定センサー付き給水ポンプユニット) M5STACK-U101 M5Stack製｜電子部品・半導体通販のマルツ](https://www.marutsu.co.jp/pc/i/2225598/)

* 雨の検出

濡れると静電容量が変化するので555の周波数が変わります。

* 風速計

風車が回転するとフォトインタラプタからパルスが出ます。

[ESP32 パルスカウンタの使い方 - Qiita](https://qiita.com/bleach31/items/256229d006e0b3134341)

[Amazon.co.jp: Nitrip 風向センサー 風速計 風力計 風量計 カップ式 風速風量湿度測定用 気象観測システム 風速風速計 風速送信機 信号風センサー 風力事業などに : 産業・研究開発用品](https://www.amazon.co.jp/Nitrip-%E9%A2%A8%E9%80%9F%E9%A2%A8%E9%87%8F%E6%B9%BF%E5%BA%A6%E6%B8%AC%E5%AE%9A%E7%94%A8-%E6%B0%97%E8%B1%A1%E8%A6%B3%E6%B8%AC%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-%E4%BF%A1%E5%8F%B7%E9%A2%A8%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC-%E9%A2%A8%E5%8A%9B%E4%BA%8B%E6%A5%AD%E3%81%AA%E3%81%A9%E3%81%AB/dp/B08CMLB4BZ)
(aliexpressでもっと安く買えます)