Raspberry Pi 3 で CO2濃度を測る (Raspbian OS)

## はじめに

以前書いた[こちらの記事](https://qiita.com/revsystem/items/5a362e749ef80358e801) は多くの"いいね"(LGTM)や記事のストックがされていてページビューが伸びているものの、Raspberry Pi 3 model B に CentOS7がインストールされていることを前提にしていてあまり一般的な環境ではないのでRaspbian OSを前提として新たに記事を書きました。

元記事でも参考にしている [窓を開けて新鮮な空気をいれよう！Raspberry Pi でCO2 濃度を測ろう](https://qiita.com/UedaTakeyuki/items/c5226960a7328155635f#mh-z19%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC) の MH-Z19 センサー用ライブラリ を使用しました。
これを使うことでCO2濃度の計測やキャリブレーションがノンプログラミングでできるようになりました。より手軽にRaspberry Piとセンサーの組み合わせを試せると思います。

本記事では、MH-Z19 から得たCO2濃度と気温を [Mackarel](https://mackerel.io/ja/) でグラフ化します。

## 参考情報

- <http://qiita.com/UedaTakeyuki/items/c5226960a7328155635f>
- <https://qiita.com/yukataoka/items/a3b4065e8210b8f372ff>
- <https://qiita.com/ww24/items/5409aefd87f14beff504>
- <https://pypi.org/project/mh-z19/>
- <https://mackerel.io/ja/docs/entry/advanced/custom-metrics>
- <https://raspida.com/release-raspberry-pi-imager>
- <https://github.com/mackerelio/mackerel-agent/releases>

## 準備する物

- [アイ・オー・データ機器 UD-RP3BP Raspberry Pi メインボード（Bluetooth、Wi-Fi対応モデル） Raspberry Pi 3 Model B+](https://www.amazon.co.jp/dp/B07SDFCDYQ/)
- [MH-Z19 0-5000PPM CO2室内空気質モニタ用赤外線CO2センサUART / PWM](https://www.amazon.co.jp/dp/B07JF4YTTB/)
- [ELEGOO 120pcs多色デュポンワイヤー、arduino用ワイヤ—ゲ—ジ28AWG オス-メス オス-オス メス –メス ブレッドボードジャンパーワイヤー](https://www.amazon.co.jp/dp/B06Y48V9DL/)
- [HiLetgo® 20個セット 40Pin 2.54mm 単一列端子ピン ヘッダー ストリップ PBC 1*40 P ピッチ Ardunioに対応 DIYセット [並行輸入品]](https://www.amazon.co.jp/dp/B012HY288S/)
- その他、Raspberry Piをセットアップするための周辺機器(microSDカード 4GB以上, HDMI接続のディスプレイ,キーボード,マウス)

## Raspbian OSの準備

Raspberry Pi Imagerを使用してRaspbianOSをSDカードに書き込みます。
[Raspberry Pi Imager](https://www.raspberrypi.org/downloads/)ダウンロードページから、使用しているPCのOS用のものをダウンロードします。
(以下はmacOS版の画面です。)
<img width="748" alt="スクリーンショット 2020-03-30 1.47.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/891d1c11-4c2f-9bb0-1a01-13f0f8c67571.png">

Operating System を選択し、OS選択画面を開きます。
一番上の Raspbian を選択します。

<img width="792" alt="スクリーンショット 2020-03-29 4.03.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/dc5ad865-d9ce-d8f6-6a18-eec80e5ace77.png">

次に SD Card を選択します。(SDカードリーダー等にセットされているものが表示されます。)
ダウンロードするOSイメージのサイズが約1.1GB、microSDカードへの書き込まれるサイズが約3GBなので4GB以上のmicroSDカードが必要です。
<img width="792" alt="スクリーンショット 2020-03-29 4.04.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/87f8fc8a-51fa-2645-d4bc-21353b1d4e80.png">

OS, microSDカードの選択が完了すると WRITE がクリックできるようになります。
<img width="792" alt="スクリーンショット 2020-03-29 4.04.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/e90dd0f6-5e9f-f10e-b8bc-29f38ba53c68.png">

WRITEをクリックすると書き込みが始まります。OS書き込み終了までおよそ10分~15分ほどかかります。ダウンロード速度など環境によって時間は異なります。
<img width="792" alt="スクリーンショット 2020-03-29 4.05.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/291e6a17-ce26-d81b-b6c1-79b2f68deb22.png">

書き込みが完了するとメッセージが表示されるのでmicroSDカードを抜き、Raspberry PiでOSを起動します。
<img width="748" alt="スクリーンショット 2020-03-29 4.15.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/2ad0dd82-804e-b254-3220-feaa31157de6.png">

## RaspbianOSのアップデート

作業を進める前に、OSを最新の状態にします。

```shell-session
sudo apt-get update
sudo apt-get upgrade
sudo apt clean
sudo reboot
```

## UARTシリアル通信の設定

UARTシリアル通信の設定を変更します。Raspberry PiにVNCで接続している場合や直接ディスプレイを接続している場合はRaspberry Pi Configuration、SSH接続している場合はraspi-configで設定できます。

### Raspberry Pi Configurationから設定する場合

メニューから `Preferences` →　`Raspberry Pi Configuration`を選択します。次に `Interfaces` のタブを選択します。
Serial Port とSerial Console を以下の状態に変更します。(デフォルトはどちらもdisable)

| 項目名| 値 |
|:---|:---|
| Serial Port | Enable |
| Serial Console | disable |

<img width="552" alt="スクリーンショット 2020-03-29 5.11.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/989eccf2-0e32-27c3-eaa4-ddff39d73dcd.png">

設定後、OSを再起動します。
<img width="552" alt="スクリーンショット 2020-03-29 5.07.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/4fe6fce7-bfee-b0d6-8d17-3ddd4d6b3117.png">

### Terminalから設定する場合

```shell-session
sudo raspi-config
```

`5 Interfacing Option` -> `P6 Serial`
> Would you like a login shell to be accessible over serial?
No を選択。

<img width="1035" alt="スクリーンショット 2020-03-29 5.13.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/df80c824-8f83-f61b-6bb3-2fb79738362d.png">
<img width="1039" alt="スクリーンショット 2020-03-29 5.13.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/fd1c2162-53d6-c8cf-57ed-495c0224f562.png">
<img width="782" alt="スクリーンショット 2020-03-29 5.14.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/f47d0d67-9401-4a03-7b1f-14aaf71ada0d.png">

> Would you like the serial port hardware to be enabled?
Yes を選択。

<img width="782" alt="スクリーンショット 2020-03-29 5.14.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/41358d0e-1360-58bc-d292-3daff3bf064c.png">

## MH-Z19の配線

以下のように、MH-Z19とRaspberry Piを接続します。
ピンヘッダーをMH-Z19の下から挿し、メス-メスのジャンパーワイヤーで接続しました。
メス-オスのジャンパーワイヤーとブレッドボードで接続することもできます。
![DSC_0654.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/9cfa2d67-0d09-7f87-0888-1cb3d9ab1025.jpeg)

Raspberry PiとMH-Z19の接続は以下のとおりです。画像は Raspberry Pi 2ものもになっていますが、Raspberry Pi 3でも同じ配線です。
配線する際は、Raspberry Piの電源を落としてから行います。電源を入れたまま配線した場合はMH-Z19が認識されない場合があります。

![Raspberry Pi](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/ba0fec0d-7cd1-d052-4d8d-0ea5739da647.png)
(Drown with [Cacoo](https://cacoo.com/))

## センサーライブラリのインストール

```shell
sudo pip3 install mh-z19
```

### CO2濃度と気温の取得

以下のコマンドを実行することで、CO2濃度が得られます、

```shell-session
sudo python3 -m mh_z19
{"co2": 398}
```

```shell-session
sudo python3 -m mh_z19  --all
{"co2": 383, "temperature": 26, "TT": 66, "SS": 0, "UhUl": 0}
```

上記のコマンドで `null`や`9`が返る場合は配線が誤っているかMH-Z19とジャンパーワイヤーの接触が悪いことが原因と考えられます。Raspberry Piの電源を落として正しく配線したのちRaspberry Piを起動すると正常に認識します。

--allオプションを指定すると、気温など他の値も取得できますがこれらの値はMH-Z19の公式ドキュメントには掲載されていない値のようです。
TTは気温とは関連せずNDIR (非分散赤外線) 法によるCO2濃度の測定に必要な値のようです。この値は常に気温(摂氏)+40の値が出力されておりかつ気温も実際と比較して誤差が大きいため精度は低そうです。

#### 参考

- [mh-z19 CO2 concentration sensor library for All models of Raspberry Pi](https://pypi.org/project/mh-z19/) : `Undocumented response values of 0x86 command.`
- [Is the undocumented TT value on the responses of command 0x86 really related to the ambient temperature?](https://github.com/UedaTakeyuki/mh-z19/wiki/Is-the-undocumented-TT-value-on-the-responses-of-command-0x86-really-related-to-the-ambient-temperature%3F) : `The random mismatch between TT value and other thermal sensor value.`

## Mackerelの設定

サーバの管理や監視が行えるmackerelを使い取得したCO2濃度をグラフ化します。
[サインアップ](https://mackerel.io/signup)すると14日間の試用期間ののちFreeプランに移行します。
Freeプランではグラフの保持期間が1日に限られます。

### mackerelにサインアップ

[サインアップ](https://mackerel.io/signup) ページから手続きができます。詳細は[ヘルプ](https://mackerel.io/ja/docs/)を参照してください。

サインアップ後、APIキーを取得します。

### mackerel-agentのインストール

記事執筆時点の最新版 v0.67.0をインストールします。

ARMプロセッサ用のバイナリをダウンロードします。

```shell-session
cd ~/
mkdir src && cd src
curl -sL https://github.com/mackerelio/mackerel-agent/releases/download/v0.67.0/mackerel-agent_linux_arm.tar.gz | tar xz
```

実行ファイルを /usr/local/bin/へ、mackerel-agent.conf を/etc/mackerel-agent/へ配置します。

```shell-session
sudo mkdir -p /usr/local/bin/ /etc/mackerel-agent
sudo cp -dpR mackerel-agent_linux_arm/mackerel-agent /usr/local/bin/
sudo cp mackerel-agent_linux_arm/mackerel-agent.conf /etc/mackerel-agent/
```

設定ファイルにAPIキーを登録します。
APIキーはmackerelにサインイン後、[オーガニゼーションのページ](https://mackerel.io/my)に記載されています。

```shell-session
sudo mackerel-agent init -apikey="YOUR API KEY"
```

mackerelをsystemdのserviceとして登録します。

```shell-session
sudo vi /lib/systemd/system/mackerel-agent.service
```

```:/lib/systemd/system/mackerel-agent.service
[Unit]
Description=mackerel-agent
After=network.target network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/mackerel-agent
ExecReload=/bin/kill -HUP $MAINPID
KillMode=control-group
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=mackerel-agent.service
```

```shell-session:サービス自動起動の有効化とサービス起動
sudo systemctl enable mackerel-agent
sudo systemctl start mackerel-agent
```

### カスタムメトリックの追加

#### jqのインストール

CO2濃度の計測結果は以下のようにJSON形式で返されるので、mackerel-agentに値のみを渡せるように jq コマンドをインストールします。

```shell-session
sudo python3 -m mh_z19
{"co2": 398}
```

jq コマンドをインストールします。

```shell-session
sudo apt-get install jq
```

#### rubyのインストール

カスタムメトリックにCO2濃度の値を渡すスクリプトを ruby で書いたため ruby をインストールします。

```shell-session
sudo apt-get install ruby
```

#### CO2濃度を取得するスクリプト

```shell-session
mkdir -p /home/pi/mackerel
```

```:/home/pi/mackerel/mh_z19_monitoring.rb
#!/usr/bin/env ruby
#encoding:UTF-8


arg = ENV.fetch("MONITOR") { "co2" }

if ENV['MACKEREL_AGENT_PLUGIN_META'] == '1'
    require 'json'

    meta = {
        :graphs => {
            'mh_z19.'+arg => {
                :label   => arg,
                :unit    => 'integer',
                :metrics => [
                    {
                        :name  => 'monitoring',
                        :label => arg
                    }
                ]
            }
        }
    }


puts '# mackerel-agent-plugin'
puts meta.to_json
exit 0
end

res = `/usr/bin/python3 -m mh_z19  --all | jq .#{arg}`
res.chomp!

puts [ 'mh_z19.'+arg+'.monitoring', res , Time.now.to_i ].join("\t")
```

#### mackerel-confに追記

mackerel-agent.confに上記のスクリプトを呼び出す設定を追記します。

```shell-session
sudo vi /etc/mackerel-agent/mackerel-agent.conf
```

```:/etc/mackerel-agent/mackerel-agent.conf
[plugin.metrics.co2]
command = "ruby /home/pi/mackerel/mh_z19_monitoring.rb"
env = { MONITOR = "co2" }

[plugin.metrics.temp]
command = "ruby /home/pi/mackerel/mh_z19_monitoring.rb"
env = { MONITOR = "temperature" }
```

#### CO2濃度を取得するスクリプト (Shell Script)

ruby スクリプトではなく Shell Scriptを使う例。

```home/pi/mackerel/mh_z19_monitoring.sh
#!/bin/bash

SECONDS=`date '+%s'`

LABEL='CO2 monitor'
VALUE=`python3 -m mh_z19  --all | jq .co2`

echo -e "${LABEL}\t${VALUE}\t${SECONDS}"
```

```:/etc/mackerel-agent/mackerel-agent.conf
[plugin.metrics.co2]
command = "ruby /home/pi/mackerel/mh_z19_monitoring.sh"
```

### mackerelグラフ

![スクリーンショット 2020-03-30 2.00.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/0bdf6100-651f-48a7-256c-47fb6dc6719c.png)
![スクリーンショット 2020-03-30 2.27.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61809/d58ee29e-3ffb-081e-7680-778e565347e5.png)

CO2濃度の値が突然異常な値を示したりグラフが途切れてしまうことがあり、手元の環境では安定した値が取得出来ていません。

## MH-Z19のキャリブレーション

以前書いた記事では手動で[補正(キャリブレーション)](https://qiita.com/revsystem/items/5a362e749ef80358e801#%E8%A3%9C%E6%AD%A3%E3%82%AD%E3%83%A3%E3%83%AA%E3%83%96%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)を実施していましたが、今回利用するライブラリではキャリブレーション用のコマンドラインオプションが用意されています。
[CALIBRATION & detection range](https://github.com/UedaTakeyuki/mh-z19/wiki/CALIBRATION-&-detection-range)

外気のCO2濃度は400ppmで、MH-Z19のマニュアルによるとこのセンサーの測定誤差は±(50ppm + 5%)あるそうなので測定値はおよそ350ppm ~ 450ppmが基準値となりそうです。

キャリブレーションの仕様は、[マニュアル](https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf)に記載されています。

### ZERO Point Calibration

換気をしている室内で350ppm ~ 450ppの範囲を著しく逸脱する場合は、ゼロポイントキャリブレーションを行います。

```shell-session
sudo /usr/bin/python3 -m mh_z19  --zero_point_calibration
```

マニュアルによると`20分以上400ppm未満で動作したことを確認すること`と書かれているので20分間は換気された状態で放置したほうが良さそうです。
> NOTE：ZERO POINT is 400PPM, PLS MAKE SURE THE SENSOR HAD BEEN WORKED UNDER 400PPM FOR OVER 20MINUTES

### Automatic Baseline Correction (ABC logic function)

電源ONのあと24時間毎に自動的にZERO Point Calibrationを実行するオプション。常時CO2濃度を計測している場合は、MH-Z19に通電したあとに一度このオプションを実行したほうが良いでしょう。
> intelligently after a continuous operation period. The automatic calibration cycle is every 24 hours after powered on. The zero point of automatic calibration is 400ppm.

ただし、このオプションはオフィスや学校、家などの屋内に適しておりビニールハウスや農場、冷蔵施設には適さないそうです。その様な環境では、このオプションをOFFにし都度 ZERO Point Calibration を手動実行したほうがよいと書かれています。

> This function is usually suitable for indoor air quality monitor such as offices, schools and homes, not suitable for greenhouse, farm and refrigeratory where this function should be off. Please do zero calibration timely, such as
manual or commend calibration.

ONにする場合。

```shell-session
sudo /usr/bin/python3 -m mh_z19  --abc_on
```

OFFにする場合。

```shell-session
sudo /usr/bin/python3 -m mh_z19  --abc_off
```