前書き
皆さんは部屋でコーディングしているときや作業しているときに「気だるいな」や「なんか頭痛がする」と感じたことはありませんか?
そういうときはだいたい換気をすると解決するので二酸化炭素めぇ...と思っていたんです
最近RaspberryPi+CO2センサーで二酸化炭素濃度を可視化している記事1を見つけました
真似するしかない、ということでセンサー買って作って視覚化までしてみました
この記事に書いてある内容で起こった出来事には責任を取れません
自己責任で行ってください
使ったものもろもろ
使用機材
- RaspberryPi 3B+
- MH-Z19C2
- Amazonで手に入れた野生のジャンパ線(メス-メス)
なぜこの時期に3B+かというとそこに使っていない3B+が埃被っていたからです
新しく買うならZero 2 Wとかを使うべきでしょう
それとMH-Z19Cは私が買ったときは2,500円程度だったんですが倍近く値上げしていました....
世知辛い
使用ソフト
- RaspberryPi OS Lite
- InfluxDB
- Grafana
ラズパイは基本SSHで操作するのでGUIは不要
Raspberry Pi Imagerで焼き込むときにWiFiの設定(有線の場合は不要)、ユーザーの設定とSSH公開鍵を焼き込んでおくと、最初からSSH接続できるので楽
InfluxDBはラズパイからネットワーク経由でアクセスできる場所に
GrafanaはInfluxDBにアクセスできる場所にデプロイしましょう
我が家では外出中でもアクセスできるようにKubernetesにデプロイしてCloudFlare Tunnel経由で公開しています
InfluxDBとGrafanaをデプロイ
InfluxDB
まずはInfluxDBをデプロイします
公式から出ているhelmチャートがあるみたいなのでそれを使います
私はingressを使用するのでvalueFileをちょっとだけ書きます
また使用しているIngressClassとStorageClassはデフォルトに設定しているので割愛します
ingress:
enabled: true
hostname: influxdb.example.com
デプロイできたことを確認したら公式ドキュメントに従って初期設定を行います
WebUIにアクセスできてバケットやapiトークンの作成ができればOKです
Grafana
こちらも同じように公式ドキュメントにしたがってデプロイしていきます
必要に応じてリソース制限やStorageClassやサービスを変更します
私はドキュメントとは別にIngressを設定しました
セットアップを済ませWebUIが使えたらOKです
組み立て
GNDと5VはGNDと5Vに接続するだけです
RXはGPIO14に、TXはGPIO15に接続します
ラズパイのGPIOヘッダーは順番にGPIO番号が振られているわけではないのでpinout
コマンドを使用して目的の番号を探してください
GNDと5Vの場所もpinout
でわかります
ラズパイの設定
ここに手こずりました
Bluetoothを無効化しないと使えないみたいでこれにたどり着くまでとても時間がかかりました
/boot/firmware/config.txtに以下の設定があることを確認します
なければ[all]のところに追記してください
[all]
enable_uart=1
dtoverlay=pi3-disable-bt
この状態で再起動します
起動して/dev/ttyAMA0
が存在していればOKです
簡単にコーディング
偉大な先人がデータを読み出すpythonのライブラリを作っていただいていたのでそれを使います
pythonはなんかvenvとか言うものを使わないと使えなくなたみたいなので先に設定しておいてください
このあとはvenv環境で動かしてる前提で書いていきます
pythom -m pip install mh_z19
pythonコマンド経由でpipを呼び出すのは多分venvのpipを使うためだと思います
pipでグローバルにパッケージをインストールできないようになってるようなので
sudo python -m mh_z19
を実行して{co2: 450}
とかが表示されればokです
ちなみにシリアル通信を使用するのでsudoが必要です
私の環境だとvenvを有効化したうえでvenv/bin/python3 -m mh_z19
としないと呼び出せませんでした
なにか間違えたかも知れません
実際にデータをinfluxDBにpushするコードはこちらです
import influxdb_client, time
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS
import mh_z19
#influxdb client init
token = ""
org = "influxdata"
url = "https://influxdb.example.com"
bucket="ExampleBucket"
write_client = influxdb_client.InfluxDBClient(url=url, token=token, org=org)
write_api = write_client.write_api(write_options=SYNCHRONOUS)
ExpectExecCycle = 5 #s
def getCo2():
co2DataValue = mh_z19.read()
return co2DataValue
def getPushData():
Data = getCo2()
record = (
Point(bucket)
.tag("functionality", "Sensor")
.field("co2_level", Data["co2"])
)
write_api.write(bucket=bucket, org=org, record=record)
while True:
biginTime = time.time()
getPushData()
endTime = time.time()
execTime = endTime - biginTime
diffTime = ExpectExecCycle - execTime
time.sleep(diffTime)
ほとんどinfluxDBのチュートリアルそのままのコードを使っていますがapiキーだけ目的のバケットへのwrite権限だけのものにしています
最小権限の原則ってやつです
環境に合わせてうまく調整してください
コード最後の方はCO2データの読み出しに結構時間がかかっていたので厳密に5秒感覚でデータを取るようにちょっとした細工しています
あとはsystemdデーモンにするなりして完成です
Grafanaで可視化
まずinfluxDBのwebUIを開きます
Data Explorer > CO2のデータがあるバケット > タグ等
で目的のCO2のデータだけが見えるようにしてください
目的のデータだけが見えるようになったらSCRIPT EDITER
を押してfluxクエリを表示します
それをすべてコピーしてGrafanaに移動します
先にGrafanaでinfluxDBの情報が見えるようにデータソースとして登録します
ここはおそらく案内があるのでその通りに作成してください
ここでもapiキーはすべてのバケットにread権限だけにしています
最小権限の原則ってやつです(二回目)
データソースとして登録できたらダッシュボードとパネルを作成します
パネルの設定画面でデータソースをinfluxDBにして、queryの欄に先ほどコピーしたものを貼り付けます
あとは細かい見え方や表示の仕方などを調整して完成です
後書き
特に理由はないですが自室のデータを公開しているのでどんなものか気になった人は見てみてください
部屋を閉じきって2~3時間もすれば平気で1000ppm3は超えるので定期的な換気は重要と再認識しました
数分窓を開けておくだけできれいにCO2濃度が落ちていくのを見えるのは面白かったです
自分のいる環境がどんな状態か可視化されるのは新鮮でしたし、換気のタイミングもはっきりわかるのでおすすめです
個人的にはいい感じに可視化出来ていて、デスクトップのあいてる端の方においておくと幸せになれるので満足しています
それとドアを開ける、窓を開ける等の動作にかなり敏感に反応していて驚きました
今後もセンサー類は追加していこうと思っています
-
CO2濃度は400ppm前後が外気、500~700ppmが正常に換気された室内、1000ppmを超える眠気などが起き始め換気推奨と言われている ↩