Raspberry Pi 3 Model BとMH-Z19でCO2測定

きっかけ

ほぼ自宅勤務になったので部屋の換気が気になり始める

そんな中で CO2 計測してみたいが、市販の計測器高いと感じていたがふとラズパイ (Raspberry Pi 3 Model B) が転がってることを思い出す。
センサーとかないのかなと調べてみたら、MH-Z19 というセンサーで計測できることを知る。

色々購入してみる

アマゾンで注文してみると 2 週間かかった。中国から送ってくるみたいなのでそんなもんなんだろう。 電子工作っぽいものは初めてなのでハンダゴテすら持ってなかったので USB はんだごてを買う。
(はんだの種類すら知らなかったので調べる)

さらにこのセンサーを取り付けるためには、どうやらピンヘッダ、ジャンプワイヤーってのが必要らしい。
→ 買う

届いたMH-Z19にもケーブルが付属していたが、これは使わない。
f:id:flick-flick:20200422224324j:plain

はんだ付けの練習

Youtube で勉強して何度か練習してはんだ付けをしてみる。
ちっちゃくてうまく見えないがうまくいったっぽい

ラズパイのインターフェースを調べてみる

どうやらこの 2 つのピンがキモらしい。

  • VIN = 電力を外部に出力(供給)するピンらしい。(乾電池で言うプラス極)
  • GND = 乾電池で言うマイナス極的なピンらしい

あとこの用語もよく出てきたのメモしておく

UART = Universal Asynchronous Receiver/Transmitter (ユーアートと読むらしい)
シリアル通信上の規格、信号線は TX(送信)を相手の RX(受信)に接続する。
- 各デバイスは対等
- 1 対 1 の通信
- 信号線は送受信の 2 本
- 9600bps と 115200bps が標準(最高 1Mbps 程度)

https://manual.atmark-techno.com/armadillo-guide-std/armadillo-guide-std-hardware-expansion_ja-1.0.1/ch04.html

MH-Z19 をラズパイにはんだ付けする

MH-Z19 でググると出てくる通りにはんだ付けする。
ピンヘッダというのを、MH−Z19 にぶっ刺してはんだ付けした後に、ジャンプワイヤーでラズパイと接続する。
この時点ではうまくいっているのかはわからない。

本体に雑に輪ゴムでくくりつけておくことにする。
f:id:flick-flick:20200509123457j:plain

MH-Z19 にコマンドを送ることができるユーティリティツールをラズパイにインストール

Python 環境整えて、mh_z19 ライブラリをインストール

MH-Z19 の Python 用ライブラリ
github.com

MH-Z19 の仕様書
https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf

動かす

# sudo python3 -m mh_z19
{"co2": 726}

すんなり計測できた(ありがたい
しばらくバックグラウンドプロセスでログを出し続けてみる
楽しい

外の空気が 400ppm らしいので、それがこのセンサーの最低値になるらしい。最低値としてリセットするためにしばらく外に放置して下記コマンドでリセットする。(キャリブレーションというらしい)

# sudo python3 -m mh_z19 --zero_point_calibration

さらになんかいい感じにキャリブレーションを調整してくれるモードがあるらしいので、有効にしておく。

# sudo python3 -m mh_z19 --abc_on

CO2 値がめっちゃ高い部屋で暮らしていたことを知る。

狭い部屋で締め切っているので当たり前っちゃーあたり前だけど、部屋についてる通気口をなんとかしてもうちょっとまともな数値(せめて 1000ppm 以下)をキープできないか?

部屋に換気ファンを付けてみる

PC 用のファンを取り付けてテストしてみる。
ラズパイは 5V 出力までしかできないので、トランジスタというのを使って昇圧すればいけるっぽい。
が、回路図の読み方がわからず挫折。

USB(5V) から電源をとって、12V に昇圧して PC 用ファンの 4 ピンにできるパーツを発見したので購入。
ラズパイの USB ポートからその変換パーツを通じて、PC ファンに電源を供給した状態で通気孔にファンを貼り付けてみる。
排気(部屋から外に空気を逃がす)で設置してみると改善なし。吸気(外から部屋に空気を吸い込む)で設置してみたら改善して常に 500 ~ 800ppm を維持できた

計測をモニタリング、アラート通知をしてみる

ssh でラズパイにログインして CO2 計測ログを見るのが面倒なので、せっかくなので Fluent-Bit でどこかにログ転送してみる。
datadog は無料枠だとアラート通知できないみたいなので、mackerel を使ってみる。

実際は curl を cron なんかでスケジュール実行して、mackerel に送ればいいだけなんだけど Fluent-Bit を使ってみたかった。
無事計測できて、とりあえず 1200ppm を超えたら slack に通知するように設定した。
f:id:flick-flick:20200822143559p:plain
寝てる間も通気孔のファン回しっぱなしだと締め切っていても800ppm維持できてるっぽい

よくわらなかったところ

MH-Z19 にコマンドを送るライブラリめっちゃ便利で楽だったが、Fluent-Bit から python 呼び出すときに外部ライブラリ依存させたくなかったので、MH-Z19へのコマンド送信部分を抜き出してFluent-Bitからの呼び出し用にScriptにしたらなんかよくわからんエラーが出てかなりの時間ハマった。

どうやら、ラズパイからMH-Z19への接続(通信)が多重になると出るエラーっぽい?よくわからんが tty を開け閉めしてたら直った。
この辺シリアル通信の知識がまったくないので調べることが多すぎて挫折した。

調べたことだけメモしておく

tty = 端末(ターミナル)のこと。ssh ログインした状態で `tty` すると現在の端末デバイス ID がわかる。 echo 'Hello' > /dev/pts/2 とかやると/dev/pts/2 の端末にメッセージ送信できる
stty = tty の各種設定を表示・変更できるコマンド

エラー内容

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/dist-packages/serial/serialposix.py", line 501, in read
    'device reports readiness to read but returned no data '
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 6, in f
  File "/usr/local/lib/python3.7/dist-packages/serial/serialposix.py", line 509, in read
    raise SerialException('read failed: {}'.format(e))
serial.serialutil.SerialException: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

どうやら getty というサービスが起動していて、指定の tty (今回は/dev/ttyS0) の接続を監視し続けているらしい。

# systemctl status serial-getty@ttyS0.service
● serial-getty@ttyS0.service - Serial Getty on ttyS0
   Loaded: loaded (/lib/systemd/system/serial-getty@.service; disabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-05-06 18:46:11 JST; 2min 41s ago
     Docs: man:agetty(8)
           man:systemd-getty-generator(8)
           http://0pointer.de/blog/projects/serial-console.html
 Main PID: 15798 (agetty)
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/system-serial\x2dgetty.slice/serial-getty@ttyS0.service
           └─15798 /sbin/agetty --keep-baud 115200,38400,9600 ttyS0 vt220

May 06 18:46:11 raspberrypi systemd[1]: Started Serial Getty on ttyS0.

で確認すると active になっているので

sudo systemctl stop serial-getty@ttyS0.service

で停止させて、再度

sudo systemctl start serial-getty@ttyS0.service

で開始させたらエラー解消した。 よくわからん

[参考]

窓を開けて新鮮な空気をいれよう!Raspberry Pi でCO2 濃度を測ろう - Qiita

ラズパイのGPIOシリアル通信時のエラー:serial.serialutil.SerialException device reports readiness to read but returned no data - suzu6

mh_z19b 仕様書 https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf

github.com