【ラズパイ】DHT22、Node.js、Chart.jsでつくる温度ロガー
こんなこと、やります。
- ラズパイでDHT22を使う
- 一定時間おきに温度・湿度を測定してCSV保存する
- Node.jsでWebサーバーを立ち上げる
- Chart.jsでデータをグラフ化
最近3DプリンタでABSフィラメントを使い始めたのですが、室内温度が低いためか造形に失敗してしまいます。ひび割れたり、造形物が剥がれたりと、ABSフィラメントで印刷するには温度管理が重要なようです。ようするに、ABSフィラメントを使う場合、室内を暖かくしてやらないといけないんですね。
そこで、本来なら3Dプリンタを箱に入れて断熱対策したいのですが、玄関先に置いてあるためあまり大げさなことはできません。とりあえず、こんな感じでビニールシートを被せ、保温対策してみました。
今回は、このビニールシートがどれほどの効果があるのかフィードバックを得たいと思い、ラズパイで温度ロガーを作ってみることにしました。
つかうもの
はじめに、この記事でつかうものをご紹介します。
ラズパイ
ラズパイは、3Dプリンタをラズパイで動かしてコードレス化するために、OctoPiをOSとしてインストールしています。OctoPiについて詳しくはこちらの記事をご覧ください。
DHT22
こちらのDHT22温度湿度センサモジュールを使用します。DHT22にはAM2302というチップが使われています。
1-Wireという通信方法でデータを受信するのですが、今回はDHTライブラリを使うので通信方法のことは意識せずにデータを受信できますのでご安心ください。
青色の温度・湿度センサDHT11もあります。
次の通りスペックが若干違います。DHT22の方が精度は高いです。
項目 | DHT11 | DHT22 |
---|---|---|
電源 | 3V~5V | 3V~5V |
湿度 | 20~80%(5%) | 0~100%(2.5%) |
温度 | 0~50℃(±2℃) | -40~80℃(±0.5℃) |
測定レート | 毎秒1回 | 毎秒2回 |
DHT22を使うための準備
ここでは、DHT22を使うための準備を行っていきます。
ラズパイを最新状態にする
まずは、ライブラリをインストールする前やる「おまじない」です。パッケージリストやインストールされているパッケージ類を最新状態にしておきます。
$ sudo apt-get update
$ sudo apt-get upgrade
python3とpipを使えるようにする
$ sudo apt-get install python3-dev python3-pip
setuptoolsとwheelとpipを最新状態にしておく
$ sudo python3 -m pip install --upgrade pip setuptools wheel
AdafruitのDHTライブラリをインストール
$ sudo pip3 install Adafruit_DHT
▼ こちらのAdafruitのDHTライブラリを使えば、ラズパイで簡単に温度と湿度が取得できるようになります。
ラズパイとDHT22の配線
ラズパイとDHT22の配線は次のとおりです。
DATAピンは、4.7kΩの抵抗でプルアップする必要があります。また、センサのDATAピンは、ラズパイのGPIO14(物理番号8番)へつなぎました。DHT22の電源電圧は3V3へつなぎます。
▼ こちらの図のように、DHT22センサをステレオミニでラズパイへ配線できるようにしてみました。
Thingiverse
3Dプリンタのアルミニウムプロファイルの溝に設置できるよう、3Dプリンタで土台とM3のT型ナットを作成しました。土台とT型ナットは、ThingiverseからSTLファイルをダウンロードいただけます。
▼ Chassis for DHT22 sensor and Stereo 3.5mm mini phone on A 3D Printer
▼ T-nut M3 drop-in rotating V-Slot
▼ T型ナットのおかげで、温度ロガーを3Dプリンタのプロファイルに固定化できました。
PythonとDHT22で温度・湿度の表示
Vimなどで次のPythonプログラムを新規作成します。ここではdht22_test.pyとして、ホームディレクトリへ保存しました。
5秒おきに温度と湿度を取得します。
import Adafruit_DHT
from time import sleep
DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 14
while True:
humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
if humidity is not None and temperature is not None:
print("Temp: {0:0.1f}C Humidity: {1:0.1f}%".format(temperature, humidity))
sleep(5)
else:
print("Failed.")
次のようにして、Python3でプログラムを実行します。
$ python3 dht22_test.py
Temp: 19.8C Humidity: 46.6%
Temp: 19.5C Humidity: 46.4%
Temp: 19.5C Humidity: 46.5%
このように、5秒おきに温度が出力できれば成功です。プログラムを終了する際は、control + Cを押します。
Vimがおかしい
ところで、ラズパイにデフォルトで入っているVimはVim-tinyのため、キー操作がVimと違い使いづらいです。次のようにして、Vimを再インストールしておきましょう。
$ sudo apt-get --purge remove vim-common vim-tiny
$ sudo apt-get install vim
Vimがつらい?
Vimに慣れていない方ですと操作が難解かもしれませんが、ポイントだけ押さえておけばすぐに慣れると思います。Linuxではよく使うので、Vimを覚えておいて損はないですよ。
温度ロガーの制作
ここからは本題の、「温度ロガーの制作」を行っていきます。
Pythonで温度・湿度データをCSVファイルに保存する
先ほどのプログラムを改良して、Pythonで温度・湿度データをCSVファイルに保存します。
import Adafruit_DHT
from time import sleep
import datetime
DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 14
file_path = "./dat/data.csv"
with open(file_path, mode='a+'):
pass
def put_data(humid, temp):
print("{} / {}".format(humid, temp))
dt_now = datetime.datetime.now()
# dt_today = datetime.date.today()
count = 0
datas = []
with open(file_path, mode='r') as f:
for l in f.readlines():
l = l.replace("\n", "")
datas.append(l)
tmp_str = "{0:0.1f},{1:0.1f}".format(temp, humid)
datas.append("{},{}".format(dt_now, tmp_str))
datas = datas[max(0, len(datas)-3000):]
with open(file_path, mode="w") as f:
contents = ""
for d in datas:
contents += "{}\n".format(d)
# print(contents)
f.write(contents)
while True:
humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
if humidity is not None and temperature is not None:
put_data(humidity, temperature)
sleep(60)
else:
print("Failed.")
仕様は次のとおりです。
- 1分おきにデータを取得し、追記する
- 3000件溜まったら、過去のデータを切り捨てる
ちなみに1分おきにデータを書き加えていくと、1日あたり1440件になります。ですから約2日分のデータを確認できます。
バックグラウンドジョブで実行する
バックグラウンドかつ、SSHをログアウトしてもプログラムを継続させるために、nohupと&を使って次のようにプログラムを実行させます。
$ nohup python3 logger.py &
[1] 18117
プログラムを停止したい場合はpsコマンドでプロセスIDを調べてkillします
$ ps x
PID TTY STAT TIME COMMAND
319 ? Ssl 1:09 /home/pi/oprint/bin/python3 /home/pi/oprint/bin/octoprint serve --h
949 ? Ss 0:00 /lib/systemd/systemd --user
950 ? S 0:00 (sd-pam)
963 ? S 0:03 sshd: pi@pts/0
965 pts/0 Ss 0:03 -bash
18117 pts/0 S 0:01 python3 logger.py
19299 pts/0 R+ 0:00 ps x
$ kill 18117
これでデータファイルの準備はできました。あとは、データを見やすくするために、Node.jsでWebサーバーを立ち上げ、Chart.jsで数値をグラフ化します。
Node.jsのインストール
Node.jsとパッケージ管理ツールのnpmをインストールします。
$ sudo apt-get install -y nodejs npm
$ npm -v
5.8.0
$ node -v
v10.24.0
次に、WebアプリケーションフレームワークのExpressをインストールします。
$ npm install --save express
Node.jsでWebサーバーの起動
次の内容の app.js ファイルを作ります。
var express = require('express');
var app = express();
app.use(express.static('www'));
var port = 8888;
app.listen(port,function(){
console.log("Starting with port:%d mode:%s", port, app.settings.env)
});
www ディレクトリを作成します。ここでHTMLファイルを管理します。
$ mkdir www
www ディレクトリ内にindex.html ファイルをつくりましょう。
<!DOCTYPE html>
<html><head></head><body>
Hello world!
</body></html>
Node.jsでWebサーバーを起動します。
$ node app.js
ブラウザからhttp://<ラズパイのIPアドレス>:8888/へアクセスしてみましょう。「Hello world!」が表示されれば成功です。
SSHログアウト後も継続させるには、$ nohup node app.js &で実行しましょう。
ディレクトリツリー
ここまでで、ディレクトリツリーは次のような構成になっています。
$ tree
.
|-- app.js
|-- dat
| `-- data.csv
|-- logger.py
|-- nohup.out
`-- www
|-- dat -> /home/pi/dht22/dat
`-- index.html
3 directories, 5 files
index.htmlにJavaScriptを実装しますが、JavaScriptからdata.csvへアクセスできるようにするため、シンボリックリンクを作成しています。
$ ln -s "$(pwd)/dat" www/dat
Chart.jsのインストール
あとは、温度・湿度データをWebページに表現すれば良いだけです。XMLHttpRequestを使ってCSVファイルを読み込み、Chart.jsでグラフ化します。
先ほどのindex.htmlを次のように書き換えて、データをグラフ化してみました。
<!DOCTYPE html>
<html>
<head><title>DHT22 Logger</title></head>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script
src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.min.js"
integrity="sha512-VMsZqo0ar06BMtg0tPsdgRADvl0kDHpTbugCBBrL55KmucH6hP9zWdLIWY//OTfMnzz6xWQRxQqsUFefwHuHyg=="
crossorigin="anonymous"></script>
<script
src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@next/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<body>
<div style="width:100%">
<canvas id="tempChart"></canvas>
<canvas id="humidChart"></canvas>
</div>
<script>
var date_datas = [];
var humidity_datas = [];
var temperature_datas = [];
function getCSV(){
var req = new XMLHttpRequest();
req.open("get", "./dat/data.csv", true);
req.send(null);
req.onload = function(){
var lines = req.responseText.split("\n");
// console.log(req.responseText);
for(var i=0; i<lines.length; i++){
// console.log(lines[i]);
var arr = lines[i].split(',');
date_datas.push(arr[0]);
temperature_datas.push(arr[1]);
humidity_datas.push(arr[2]);
}
showChart();
}
}
getCSV();
function showChart() {
// console.log(date_datas);
// console.log(humidity_datas);
// console.log(temperature_datas);
var ctx1 = document.getElementById('tempChart');
var ctx2 = document.getElementById('humidChart');
var tempChart = new Chart(ctx1, {
type: 'line',
data: {
labels: date_datas,
datasets: [{
label: '温度',
data: temperature_datas,
borderColor: '#f88',
}],
},
options: {
scales: {
y: {
min: 0,
max: 50,
},
}
},
});
var humidChart = new Chart(ctx2, {
type: 'line',
data: {
labels: date_datas,
datasets: [{
label: '湿度',
data: humidity_datas,
borderColor: '#48f',
}],
},
options: {
scales: {
y: {
min: 0,
max: 100,
},
}
},
});
}
</script>
</body>
</html>
▼ このような感じで印刷をはじめると、3Dプリンタ周辺の温度が上昇していくのが分かりました。
ビニールシートで囲ったことである程度の温度上昇はできましたが、安定してABSフィラメントを印刷できるほどではありませんでした。残念です。
結局その後、Ender3 V2が丸ごと入るエンクロージャーをAmazonで購入しまして解決です。3Dプリンタ内の温度を高く維持でき、ABSがおどろくほどキレイに印刷できるようになりましたよ!
▼ こちらの記事もご参考ください。