レタスのかわをぜんぶむく

ぜんぶむきます

1万円台で作れるIoTセンサでCO2と気圧をグラフ化する

温度や湿度の変化は変化を自覚してから不調が来るものの、気圧やCO2濃度の変化は不調が来てから(能動的に調べて)変化を知ることが多い。
去年2月から丸1年とちょっとフルリモートで働いているのだけど、やることは明確なものの何故か手が動かない時は内因として水分補給や血行の問題、外因では低気圧や部屋の換気が原因となっているケースが多かった。

一度気づいてからは定期的に対策するようにするのだけど、障害対応とか不具合調査で下手にフローに入ってしまうとそれも難しい。
なのでまずは検知しづらい生産性低下の外的要因を確認できるようにしたい!というモチベーションで気圧計やCO2濃度計を調達しようと思って1月頃から調べ始めたのだけど、業務用のCO2濃度計がとにかく高い。
わざわざ業務用で調べたのはAmazonで調べると怪しげな海外メーカーのCO2濃度計が投げ売りされていたりして不安になったのと、下記の記事を読んだから。

どうせ買うならちゃんと動作するものがほしいし、もちろんできれば安くで欲しい。
ということで無ければ作るの精神で自作することを決めた。

必要なもの

Raspberry Pi 4b 4GB ¥6,490
後々設定を変更したりしやすくするためにWifiがついてたらなんでも良いと思う。(長いので以下RPiと呼称する)
他の用途で遊ぶかもしれないなと思って少しスペックが高めのRPi4b 4GBモデルを買ったけど、今回の用途だけで利用するならスペック的にはRPi Zero WHくらいで良さそう。
入出力インターフェースは減るものの、Rpi Zero WHだと¥2,500くらいで入手できる。
https://www.amazon.co.jp/gp/product/B087TM3VRX

RPi用電源 ¥1,139
本体購入のときと一緒にAmazonでまとめて購入。多分もっと安く入手できそう。
https://www.amazon.co.jp/gp/product/B07DN5V3VN

microSD 32GB ¥851
本体購入のときと一緒にAmazonでまとめて購入。容量とかこだわりたい人はお好みで。
https://www.amazon.co.jp/gp/product/B06XSV23T1

ジャンパワイヤ(メス-メス) ¥380
半田付け無しで電子部品とRPiを接続するのに使う。
電子部品側もピンが用意されているものを買う必要があるので注意。
https://www.amazon.co.jp/gp/product/B01A4DDUTA

MH-Z19C (CO2センサ) ¥2,480
今回の重要部品その1。
値段がRPi Zero WHと同じくらいする。
https://akizukidenshi.com/catalog/g/gM-16142

SSCI-023238 (BME280 温湿度気圧センサ) ¥2,178
今回の重要部品その2。
この電子部品であれば温湿度も同時に取れるので採用。ピンを自分で半田付けする前提なら半額くらいで買える。
BME280で調べればSSCI-023238でなくとも同様のデータが取れる電子部品が大量に出てくるのでそちらでも代用可。
https://www.amazon.co.jp/gp/product/B07XYZZB5Q

必要に応じて

HDMI-microHDMIケーブル
RPiの初期セットアップに画面をつないで操作するために利用。
持ってたので今回の費用計上からは除外。初期セットアップを画面接続無しでやるなら不要かも。
https://www.amazon.co.jp/gp/product/B00HQY7XIU

microSDリーダー
RPiの起動イメージを書き込むために必要。
持ってたので今回の費用計上からは除外。
https://www.amazon.co.jp/gp/product/B0829KGK2F

この構成だとここまでで¥13,500前後。
RPi 4bをRPi Zero WHに変えたり、センサ系の部品をピン無しのものを買って自分で半田付けすれば¥8,000くらいにおさまるはず。
(その場合一番高い部品はCO2センサになる)

半田ごてとか道具が揃っていて、その辺の作業に抵抗ない(楽しめる)人はコスト的にそっちの方がよさそう。

セットアップ

RPi上で動作させるOSのセットアップ

Raspberry Pi Imagerという公式のツールがあるのでそれを利用する。
OSには色々種類があるものの、定番ぽいRaspbian Fullを選んで書き込み。

下記がとても参考になった。
dev.classmethod.jp

初期設定

モニタとUSBマウス/キーボードを繋いで、初期パスワードの設定。
後から調べたら最初からsshで起動できるように設定を編集することもできるらしい。

起動後、インターフェイスからSSH(VNC), I2C, シリアルポートを有効にする。
SSH(VNC)はRPiに画面を接続せずとも外部PCからアクセス出来るようにするため。I2C、シリアルポートは電子部品とのやりとりのため。
SSHで接続するには接続するPCとRPiが同じWifiに接続していれば ssh pi@raspberrypi.local で接続できる。

より具体的には下記の記事が参考になった。
パブリックなネットワークだと危険な気がするものの、家庭内LANなので一旦問題なしとしてすすめる。

dev.classmethod.jp

配線

f:id:uskey:20210314212708p:plain:w300

RPi [番号] と書かれたものはRPi上のGPIOピン上でのマッピング(参考)。
配線失敗すると基盤が死ぬこともあるらしいので注意する。
各ピンと電子部品間でどのような通信が動いてるか把握するのは後回し。
ネットを調べると先人達の知恵があるのでそれを元に配線を行う。

二酸化炭素センサ (MH-Z19)

取れる情報 : CO2, 気温(低精度)

RPi - MH-Z19間の接続
RPi 04(5V)  <-> Vin
RPi 06(GND) <-> GND
RPi 08(TXD) <-> RXD 
RPi 10(RXD) <-> TXD

Pythonから利用するためのスクリプトが存在していてpipからインストールできる。
(ソースは下記)

github.com

GithubのREADMEを眺めているとドキュメントされていない機能として気温が取れる、とのことなのでどうせなのでその値も取得してみる。

GPIOを利用するにはroot権限が必要になるためsudoをつけて実行する。
下記のように実行して値が返ってきたらok。

$ sudo pip install mh-z19
$ sudo python -m mh_z19 --all
{"SS": 0, "UhUl": 7936, "TT": 73, "co2": 688, "temperature": 33} 

室温がだいぶ上振れしていて精度が悪いように見えるものの気にせず進める。  

温湿度/気圧センサ (SSCI-023238 BME280)

取れる情報 : 気温, 湿度, 気圧

RPi - SSCI-023238間の接続
RPi01(3.3V) <-> Vio
------       <-> VCore
RPi 03(SDA)  <-> SDI
RPi 05(SCL)  <-> SCK
RPi 09(GND)  <-> GND
RPi 17(3.3V) <-> CSB
RPi 20(GND)  <-> SDO

メーカーのスイッチサイエンス社からPythonでデータを取得するサンプルプログラムが提供されているのでそちらを利用する

github.com

同様に下記のようにして動作確認をして値が返ってきたらok

$ wget https://raw.githubusercontent.com/SWITCHSCIENCE/BME280/master/Python27/bme280_sample.py
$ sudo python bme280_sample.py
temp : 22.23  ℃
pressure : 1009.89 hPa
hum :  35.11

サンプルプログラムのままだと入力待ちを続けたり、出力が扱いづらいのでjsonで返すようにするなどよしなに整形する。
センサからデータを取得するスクリプトをPython2系で進めてしまっていることに気づいたが、後から差し替えもできるので一旦作りきってから改修することにして前に進める。

グラフ化

ここもスクリプト同様に外部のサービスを利用する。
IoT系のデータをいい感じに表示するサービスは複数あるものの、今回は無料で利用できて簡単なAmbientを利用する。

ambidata.io

ユーザー登録後、チャネルを作成してID, ライトキーを保存しておく。
また、Python用のモジュールが用意されているので導入しておく。

$ sudo pip install git+https://github.com/AmbientDataInc/ambient-python-lib.git

Ambientに保存するデータ量・更新頻度の制限については公式のspecに記載があり

- 1ユーザーあたり8個までチャネルを生成できます。
- 1チャネルあたり8種類のデーターを送信できます。
- 送信から次の送信まではチャネルごとに最低5秒空ける必要があります。それより短い間隔で送信したものは無視されます。
- 1チャネルあたり1日3,000件までデーターを登録できます。平均すると28.8秒に1回のペースです。
  - bulk_send()やnode.js、Pythonで複数件のデーターを一括登録する場合、APIのコール回数は1回ですが、データー登録は複数件とカウントされます。
  - 件数のカウントは0時に0クリアされます。
  - チャネルデーターを削除しても1日の登録件数のカウントは0クリアされません。
- 1チャネルあたり8個までチャートを生成できます。
- データーの保存期間は1年間です。

とのこと。

一回の書き込みAPIアクセスで1セット8種類のデータを送信することが出来るため、一度に送信するデータの種類を増やすと送信可能な回数が減るかと思ったものの、実際には1日3000データではなく1日3000セットが制限だったため今回のセンサ分(5種類)は問題なし。
無料でこれだけ使えてデータが1年残るのはかなり太っ腹だと思う。

Ambientに登録する処理の実装

MH-Z19, BME280からデータを取得してAmbientに登録する下記のようなスクリプトを作成する。
channel_id, write_keyは先程登録した際に保存しておいたものを利用する。 (import bme280 としているものは先のサンプルプログラムをいい感じに修正したもの)

import datetime
import mh_z19
import ambient
import bme280
  
mhz19res  = mh_z19.read_all();
bme280res = bme280.readData();
  
if 'co2' in mhz19res :
    am = ambient.Ambient(channel_id, write_key)
    status = am.send({'d1' : mhz19res['co2'], 'd2' : mhz19res['temperature'], 'd3' : bme280res['temperature'], 'd4' : bme280res['pressure'], 'd5' : bme280res['hum']}, 60)

データの登録に成功しているとAmbientのチャネルでは下記のように表示される。
f:id:uskey:20210314194208p:plain:w400

それぞれのデータに対してはまだ名前がついていないため、適切な名前をつけたりチャート表示の変更を行う。

定期実行

スクリプトからAmbientへのデータ登録の確認ができれば、いよいよ時系列グラフ描画のために定期実行の設定をしたい。

先程のスペックから''平均すると28.8秒に1回のペースです'' とのことなのでその制限に触れない30秒毎にデータを送信する。
(crontabでは指定できる最小単位が分なので、即実行するものとは別に30秒待ってから実行する設定を行う)

$ crontab -e

* * * * * sudo python ~/monitor.py
* * * * * sleep 30; sudo python ~/monitor.py

正しく動作していればAmbient側で下記のようにグラフ表示が行われる。
(データやチャネルへの名前設定などは別途設定済み)
f:id:uskey:20210314195009p:plain:w400

このボードは設定によって全体公開にすることも可能で、試しに全体公開した家の作業部屋のボードが下記。

https://ambidata.io/bd/board.html?id=23516

人間が部屋にいて作業をしているとCO2がじわじわ上がっていったり、エアコンをつけると気温/湿度が周期的に変化したりなど様々な傾向が見て取れて面白い。
また、RPiの電源が落ちているなどの要因でデータの登録に間隔が空くとその部分は直線になるのでわかりやすい。
(MH-Z19から取れる気温は小数点以下の精度が無く、20℃を超えると誤差がすごい(5℃以上上振れする)のであまり当てにしてはいけない。仕様書に載ってない機能なのでそれはそう。)

まとめ

学生時代は半田付けが苦手だったり、自作したLANケーブルが自分のものだけ疎通しなかったりと散々だった(特別研究の担当職員に「しろめ君はそこそこプログラム書けるのに手先不器用だねえ!」と爆笑された記憶がある)ものの、センサ類からの値の読み出しはに手なりで書けるPythonを使えたり、処理の定期実行にcrontabが使えたりと普段仕事でLinux環境を利用している人ならなんとなくで利用できちゃうので電子工作に抵抗感がある人でもそんなに気合を入れなくても構築出来て満足感が高い。
(セットアップから最初のセンサをつないで値を読み出すまで1時間もかからなかった)

ちょっとお金を出してよく出来た既製品を買ってもデータを簡単に外部連携出来るモデルはあまりないし(しかも業務用だとべらぼうに値段が上がる)、少しでもプログラミングの経験があればとっつきやすいためエンジニアリングが好きな人にはおすすめ出来そう。
一方で、ちゃんとしたケースを作る。電源をバッテリ駆動にする。などを考え始めると沼にハマりそうなので一定の注意が必要。沼を覗いてる時沼もお前を覗いている。

他にも色々できそうなので時々やっていきたいですね。
おわり。