Raspberry Pi 3 + CentOS 7 + DHT22 で部屋の温度と湿度をグラフ化する

この記事は約11分で読めます。
スポンサーリンク

はじめに

 以前から Raspberry Pi をもう少し “らしく” 使いたいなと思っていた。
 GPIO のヘッダピンが出ているからとセンサー系の何かを使った物…… で “温度と湿度のセンサー” が思いついた。
 自室の温度と湿度を一定間隔で取得し続けて可視化すると言う事が面白そうだし。

温湿度センサーを探す

 温湿度センサーに関して Raspberry Pi で使えるような物で尚かつ精度が良さそうな物を探した結果、次の物を購入する事に。

 温湿度センサー単体では無く、動作に必要なプルアップ抵抗など込みで基板上に必要な物がすべて実装された製品。且つ安い。
 採用しているセンサーは DHT22/AM2302 となる。

 DHT22 のスペックとしては非常に簡素に書くと

  • 動作電圧 : 3.3~6 [V]
  • 測定レンジ : 湿度 0~100%RH (誤差 ±2%), 温度 -40~80℃ (誤差 ±0.5℃)
  • 測定間隔 : 2 秒

 となる。

Raspberry Pi 3 に繋ぐ

 注文したセンサーには メス-メス のジャンパワイヤーが付属しているものの、短いので別途長めの製品も一緒に購入しておいた。

 30cm が 6 本なので、裂いて 3-3 に分けて繋げれば 60cm の長さが確保出来るから丁度良い物が買えた。
 このケーブル同士を接続する加工は適当にピンを抜いてきてメス同士を接続。テスターで導通確認後に百均の熱収縮チューブで固定し、口をアルミテープで更に固定しておいた。
 ケーブルにアルミテープを巻いておくとフレキシブルケーブルの様に曲げても形状を維持しやすくなるので、必要な部分に巻いておくと取り回しやすくなるからオススメ。

 Raspberry Pi 3 への接続は次の様にしておいた。

 1 番 PIN から 3.3V を取って 9 番 PIN の GND を使用。データは 7 番 PIN の GPIO 4 を使う事とした。
 センサー側の PIN にも入れ間違えないように基板上のシルクを見ながら確実に繋ぐこと。

 使用しているケースは金属筐体でケーブルを逃がすスリットが入っていたので次の様にペロっとケーブルが出る状態となった。

センサーを設置する

 Raspberry Pi 3 周囲はルーターやら色々あって熱源になっているからセンサーは少しでも離れた位置に設置したい。
 その為、この様に壁へ固定する事で熱源を避けるような形にした。

 センサー部分は基板背面のショートを防ぎたいので導電性が無い事を確認したスポンジをポリウレタン製輪ゴムで止めておき、マスキングテープで壁に貼り付けた。
 問題となるような重量でもないのでこれで十分。

センサーからデータを取得する

 Raspberry Pi 3 には CentOS 7 を入れているが今回はシェルスクリプトと Python 3 でアレコレするのでセンサーへのアクセスでは特にこれと言ったディストリ依存は少ないかなと思われる。

 細かい所は省くが Python 3 関連パッケージは次の様にしている。

rpm -qa | grep python3
python36-3.6.6-5.el7.armv7hl
python36-libs-3.6.6-5.el7.armv7hl
python3-rpm-macros-3-24.el7.noarch
python36-pip-8.1.2-8.el7.noarch
python36-devel-3.6.6-5.el7.armv7hl
python36-setuptools-39.2.0-3.el7.noarch

 DHT22 用のライブラリは探すと多数あったが Adafruit_Python_DHT が一番使いやすそうだったので採用。
 次の様にしてインストールを行う。

git clone https://github.com/adafruit/Adafruit_Python_DHT.git
cd Adafruit_Python_DHT
sudo python3 setup.py install

 取得したソースに example というディレクトリがあり、この中に温度と湿度を取得して表示するサンプルスクリプトが同梱されていた。
 実行してみるとこうなる。

sudo ./AdafruitDHT.py 2302 4
Temp=27.7*  Humidity=41.4%

 このスクリプトは引数にセンサーの型番を入れ、次に使用する GPIO の番号を与えるとデータを取得してくれる。
 もうこのスクリプトそのままで十分なので下手に弄らず使わせて頂くことにした。

 なので

sudo cp AdafruitDHT.py /usr/local/bin

 としてパスの通った場所にコピーしておいた。

 一般ユーザから sudo して /usr/local/bin 以下のコマンドを叩くには visudo して secure_path に /usr/local/bin を追加しておく必要があるので注意。

Munin で定期的にデータを取ってグラフ化する

Web サーバーは Nginx

 Web サーバーとしては Nginx を既に使用しているので別途サブドメインを定義し、server ブロックを記述した設定ファイルを追加する事で Munin にアクセス出来る様に設定を行った。
 Web サーバーを入れておらず、これから Nginx をインストールするという場合は epel リポジトリに nginx.armv7hl があるのでそれでインストールしておくと良い。

Munin インストール

 Munin に関しては Raspberry Pi 3 の CentOS 7 にパッケージが存在しなかったハズなんだけど、数日前に確認したら epel に追加されていたようなのでさっくりインストール出来た。
 次の様にコマンドを打てば依存関係も含め、Munin の動作必要なパッケージが揃う。

sudo yum install munin-nginx

Munin の設定

 /etc/munin 以下に各設定ファイルが存在するので各々を編集していく。

 /etc/munin/munin.conf

dbdir     /var/lib/munin
htmldir   /var/www/html/munin
logdir    /var/log/munin
rundir    /var/run/munin

 の部分がコメントになっているので外す。
 それと設定ファイルの末尾あたりにホスト名を定義しておくのも良い。

#
# A simple host tree
#
[munin.example.com]
    address 127.0.0.1
    use_node_name yes

 /etc/munin/munin-node.conf は特に弄らなくても良いかも知れないが、念のために次の様に 2 箇所だけ弄っておいた。

cidr_allow 192.168.1.0/24

# Which address to bind to;
#host *
host 127.0.0.1

 不要な設定ファイルがあるので 1 つ削除するか若しくは内容をすべてコメントアウトしておく。

sudo rm /etc/munin/conf.d/local.conf

 そして最後に大事なのは /etc/munin/plugins 以下のシンボリックリンクで、デフォルトだと監視対象が多い為に 5 分毎に処理が入ると負荷が結構キツい事になる。
 その為、不要な項目はバンバン削除してしまった方がいい。
 自分はこれを次の様に絞っておいた。temp というファイル名は後述のシェルスクリプトで書いた DHT22 のデータ取得用プラグインとなる。

ls /etc/munin/plugins
acpi   cpu       df         forks    load    netstat   processes  temp     uptime  vmstat
bind9  cpuspeed  diskstats  if_eth0  memory  proc_pri  swap       threads  users

Nginx の設定

 Munin の生成したページへアクセス出来る様にするための Nginx の設定は次の様になる。
 筆者は Nginx をソースからビルドしているので、一部 /usr/local/nginx/html などとなっているが、これは各自環境のパスに書き換える必要があるかもしれない。

server {
    # Example configuration! Change this to suit your needs.
    # Access munin at http://localhost/munin/
    # NOTE - Do not remove this file, otherwise munin package upgrade
    # recreates this.

    listen 80;
    server_name munin.example.com;
    root /var/www/html/munin;
    index index.html;

    location / {
        allow 192.168.1.0/24;
        allow 127.0.0.1;
        deny all;
    }

    # redirect server error pages to the static page /40x.html
    #
    error_page  404              /404.html;
    location = /40x.html {
        root   /usr/local/nginx/html;
    }

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/local/nginx/html;
    }

    location ^~ /munin-cgi/munin-cgi-graph/ {
        access_log off;
        fastcgi_split_path_info ^(/munin-cgi/munin-cgi-graph)(.*);
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_pass unix:/var/run/munin/munin-cgi-graph.sock;
        include fastcgi_params;
    }

    location /munin/static/ {
        alias /etc/munin/static/;
    }

    location /munin/ {
        fastcgi_split_path_info ^(/munin)(.*);
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_pass unix:/var/run/munin/munin-cgi-html.sock;
        include fastcgi_params;
    }
}

 この設定により server_name で定義したホスト名にアクセスすれば Munin のページが表示されるようになる。勿論このあたりは DNS なり hosts でホストを名前解決出来る様に何とかする作業が必要だが、基本的な事なので割愛する。

各サービスの起動

 Munin や Nginx を自動起動するように設定し、サービスを起動させる。

sudo systemctl enable munin-node munin-cgi-graph.socket
sudo systemctl start munin-node munin-cgi-graph.socket
# Nginx を今回インストールしたのであれば次行も
sudo systemctl enable nginx
sudo systemctl start nginx

 これで設定したホスト名にアクセスし、Munin のページが表示されることを確認する。

Munin で DHT22 のデータを取得するプラグインを書く

 Munin でプラグインを書くことはしたことが無かったので、オフィシャルドキュメントやら色々読みあさったら「動作するだけ」の非常に最低限なシェルスクリプトが出来た。

 (2019/06/10) スクリプトに機能追加や Munin Plugin としての記述を追加したバージョンが出来たので以下再掲

 動作に際しては AdafruitDHT.py が必要になる。Adafruit_Python_DHT に同梱のスクリプトを /usr/local/bin に放り込んでおくと良い。

#!/bin/bash
# -*- sh -*-

: << =cut

=head1 NAME
Munin Plugin for Adafruit_Python_DHT.

=head1 APPLICABLE SYSTEMS

Raspberry Pi with DHT11/22, AM2302 connected.

=head1 CONFIGURATION

 [dht]
  user root
  env.script             - Location of Adafruit_Python_DHT example script.
                           It default filename is "AdafruitDHT.py"
  env.sensor             - Kind of sensor. 11 or 22 or 2302
  env.gpio               - GPIO Number connected.
  env.tempcorrection     - Temperature Correction Value.
  env.humiditycorrection - Humidity Correction Value.
  env.retry              - Number of retries at error.

=head2 DEFAULT CONFIGURATION

 Default configurations are...

 [dht]
  user root
  env.script /usr/local/bin/AdafruitDHT.py
  env.sensor 2302
  env.gpio 4
  env.tempcorrection 0
  env.humiditycorrection 0
  env.retry 2

=head1 AUTHOR

BuCCi

=head1 LICENSE

GPLv2

=head1 MAGIC MARKERS

  #%# family=auto
  #%# capabilities=autoconf

=cut

LANG=C

if [ "$1" = "autoconf" ]; then
    echo yes
    exit 0
fi

# set script file
SCRIPT=${script:-/usr/local/bin/AdafruitDHT.py}

# set device info.
SENSOR=${sensor:-2302}
GPIO=${gpio:-4}

# Value Correction.
TempCorrection=${tempcorrection:-0}
HumidityCorrection=${humiditycorrection:-0}

# Configuration.
if [ "$1" = "config" ]; then
    echo 'graph_title Room Temperature/Humidity'
    # echo 'graph_args --base 1000'
    # echo 'graph_args --base 1000 --upper-limit 50 --lower-limit 0'
    echo 'graph_category Room'
    echo 'temp.label Temperature (C)'
    echo 'temp.type GAUGE'
    echo 'temp.min -40'
    echo 'temp.max 80'
    echo 'temp.draw LINE2'
    echo 'humidity.label Humidity (%)'
    echo 'humidity.type GAUGE'
    echo 'humidity.min 0'
    echo 'humidity.max 100'
    echo 'humidity.draw LINE2'
    exit 0
fi

# Set Variables.
STAT=1
RCNT=1
MAX_RETRY=${retry:-2}

# It is adjusted to return 0 in the case of an error after a certain number of retries.
while [ $STAT -ne 0 ]
do
    DHT=`$SCRIPT $SENSOR $GPIO`
    STAT=$?
    if [ $RCNT -eq $MAX_RETRY ]; then
        A=`echo "-1 * $TempCorrection" | bc`
        B=`echo "-1 * $HumidityCorrection" | bc`
        DHT="Temp=$A*  Humidity=$B%"
        STAT=0
    fi
    RCNT=$((++RCNT))
done

# Parse
Temperature=`echo $DHT | sed -e 's/Temp\=\(.*\)\*.*$/\1/;'`
Humidity=`echo $DHT | sed -e 's/^.*Humidity\=\(.*\)\%.*$/\1/;'`

# Value set & Correction
echo temp.value `echo "$Temperature + $TempCorrection" | bc`
echo humidity.value `echo "$Humidity + $HumidityCorrection" | bc`

exit 0

 このシェルスクリプトを dht というファイル名で保存し、chmod 755 した上で /etc/munin/plugins 以下にコピー。
 更に /etc/munin/plugin-conf.d/00-default に以下の様に自環境にあった値をセットしたエントリを追加する。

[dht]
  user root
  env.script /usr/local/bin/AdafruitDHT.py
  env.sensor 2302
  env.gpio 4
  env.tempcorrection 0
  env.humiditycorrection 0
  env.retry 2

 設定ファイルを保存したら systemctl restart munin-node とするとデフォルトの場合 5 分おきに温度と湿度を取得してグラフ化してくれるようになる。

 今回、GitHub を初体験したので気になる方はそちらからスクリプトをダウンロードする事も可。

buccimoni/MuninDHT
Munin Plugin for Adafruit_Python_DHT. Contribute to buccimoni/MuninDHT development by creating an account on GitHub.

 筆者の様に飽和塩法を用いて湿度の精度がバッチリ確認出来ている温湿度計基準で補正する場合、変数 TempCorrection で温度、HumidityCorrection で湿度をプラスマイナスさせることが出来る様に工夫しておいた。
 基準となる温湿度計を近い位置に置いて表示されている数値と同じになる様、補正値を調整することに。

 この個体の補正値は温度 0、湿度 -2.5 とすることで基準に合わせることが出来た。わりと精度の良いセンサーの様だった。
 筐体内にセンサーがある温湿度計と比較するとセンサー剥き出しの DHT22 は湿度が変動しやすく、補正後でも基準とした温湿度計より高く出る事が有る。

 このプラグインによって作成されるグラフは次の様になる。
 (グラフの画像データを毎時更新に切り替えたが、サーバー側のキャッシュ次第で常に最新とは限らない)

 1 つのグラフで温度と湿度の両方を一発で見られるようにと書いてみた。
 縦軸のスケールが 0~100 なので湿度は良いにしても温度には大きすぎて変化が分かりづらいという欠点もあったりなかったり。
 温度と湿度はグラフを分けるように書き直すのも手だけど、そうなると 2 つのグラフになって見づらいし…… などと悩みも出てくる。

 2019/05/23 追記
 縦軸のスケール設定 --upper-limit の値を 50 やそれ以下に設定すると温度か湿度何れかが設定値を超えたときに自動でスケールが変わるのでグラフが多少見やすくなると分かった。

 もう少し手段を変えて AdafruitDHT.py から定期的にログファイルを吐かせ、それを読みに行くようなプラグインにすれば「温度と湿度混合のグラフ」と「温度と湿度を分離した 2 つのグラフ」という感じに複数一気に行けるハズ。
 取り敢えずそこは追々と言うことで。

おわりに

 Raspberry Pi 3 を使い始めてから結構経つけど、今まで宅内用 DNS サーバーと ぶっちろぐ クローンとしてのみ使っていた物がやっと Raspberry Pi らしくセンサー搭載と相成った。
 もうすぐやってくる憂鬱な梅雨。こうして湿度をグラフで可視化して眺めるのもまた気を紛らわせるには多少良いかなと。
 今後は年間の温度や湿度の推移も見ることが出来そうで非常に楽しみ。

 わりと難しく考えては居た物の、実際に作業をしてみるとそう難しい物でも無くて簡単だったからセンサー系入門には最適な物だったかなと思う。

その後

 室内の温度/湿度をグラフ化して数日が経過した。
 DHT22 は湿度の変化に対する反応速度が非常に速く、手元の一般的な市販の温湿度計では追従出来ないような変化でも的確に拾ってくれる。
 その為、湿度の変化が激しい状態だと市販の湿度計とのズレが出てしまう。これは単に市販の温湿度計が変化に追いつけないだけなので、湿度が安定した状態が続くと市販品と DHT22 はおおよそ同一の湿度を示すようになる。
 湿度センサーの精度を気にするのであればやはり飽和塩法で一定の湿度環境をつくり出した上でソフトウェア側で補正していく使い方をした方が良いだろうかと思った。

  • 2019/05/23 20:00 -- その後の項を追記した。
  • 2019/06/10 13:30 -- 機能追加したスクリプトを掲載。GitHub にあるリポジトリへのリンクも追加。
スポンサーリンク

コメント

タイトルとURLをコピーしました