こんにちは。Raspberry Pi(ラズパイ)を使って温度、湿度、CO2濃度をモニタに表示する方法を紹介します。
各種センサの値をモニタに表示して、感覚的な暑い/寒いを数値化します。また、不快指数を算出することで、冷房/暖房をつける目安にもなります。
完成イメージ
各種センサを表示した様子です。ラズパイやセンサーを固定するブレッドボードの作り方は以下の記事を参考にしてください。
こちらがLCDモニタに表示しているデータです。室内の温度、湿度、不快指数(DI)、CO2濃度を確認することができます。
温度と湿度はDHT22から値を取得しています。
不快指数(Discomfort Index=DI)は蒸し暑さを数量的に表した指数で、温度と湿度から計算することができます。不快指数と体感の関係について、Wikipediaから引用した表を以下に示します。
不快指数 | 体感 |
---|---|
〜50 | 寒くてたまらない |
50〜55 | 寒い |
55〜60 | 肌寒い |
60〜65 | 何も感じない |
65〜70 | 快適 |
70〜75 | 不快感を持つ人が出始める |
75〜80 | 半数以上が不快に感じる |
80〜85 | 全員が不快に感じる |
85〜 | 暑くてたまらない |
LCDモニタには英数値のみを表示できるため、体感を英語で置き換えて表示しています。
CO2濃度はMH-Z19Cから値を取得しています。外気の標準が410ppm程度です。室内の濃度は1000ppm以下が望ましいとされていますが、狭いワンルームに設置しているため室内で軽い運動をすると1100ppmになることがあります。1000ppmを超えるとLINEに通知するような仕組みも有用そうです。
準備
接続するセンサとディスプレイは以下です。
- DHT22(温湿度計)
- MH-Z19C(CO2濃度計)
- I2C 1602 LCD(ディスプレイ)
DHT22は約1000円、MH-Z19Cは約2000~3000円で購入できます。
I2C 1602 LCDはOSOYOO社から発売されているスターターキットに同封されていたものを使用しました。
今回の構成について、ラズパイ3B+とRaspberry Pi Zero WHで動作を確認済みです。
回路図
各センサーとGPIOを接続した回路図をfritzingを用いて作成しました。初めてブレッドボードビューを作成したため、かなり見づらいとは思いますがご了承ください。
今回の回路について、本来であれば抵抗および5V, 3V電源を考慮する必要がありますが、今回は動けばいいや精神で組んでいます。(よくない)
ラズパイのGPIOについては公式サイトを参照してください。
シリアル通信
それでは手順を解説します。まずは設定画面を開き、シリアル通信を有効にします。
sudo raspi-config
Interface Options > P6 Serial Port
を選択します。
Would you like a login shell to be accessible over serial?
と訊かれるので、「いいえ」を選択します。
Would you like the serial port hardware to be enabled?
と訊かれるので、「はい」を選択して「了解」を選択します。
以下のコマンドで再起動して設定を適用します。
sudo shutdown -r now
ライブラリの準備
Pythonとpipのインストール
Pythonがインストールされていない場合は以下のコマンドからインストールしてください。
sudo apt-get update
sudo apt-get install build-essential python-dev pip
DHTライブラリのインストール
適当なディレクトリに移動したら、AdafruitのDHTライブラリをインストールします。今回はホームディレクトリ下でインストールします。
cd ~
sudo git clone https://github.com/adafruit/Adafruit_Python_DHT.git
cd Adafruit_Python_DHT
sudo python setup.py install
ライブラリのインストールが完了したら、DHT22が動作していることを確認します。
上記でクローンしたAdafruitディレクトリ内で実行するとImportError: cannot import name 'Raspberry_Pi_2_Driver' from 'Adafruit_DHT'
というエラーが発生するため注意してください。以下の手順のように、ライブラリをインストールしたディレクトリとは別の階層にディレクトリを作成して、テストプログラムを作成および実行してください。
テストプログラムは以下のライブラリから参考にしました。
mkdir sensorScript
cd sensorScript
vim testDHT22.py
以下のPythonプログラムを作成してください。
#!/usr/bin/python
import Adafruit_DHT
# センサー
sensor = Adafruit_DHT.DHT22
# ピン番号
pin = 4
# 温湿度取得
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
# 標準出力
if humidity is not None and temperature is not None:
print('Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(temperature, humidity))
else:
print('Failed to get reading. Try again!')
python testDHT22.py
実行して以下のように測定された気温と湿度が表示されればOKです。
MH-Z19ライブラリのインストール
以下のコマンドでライブラリをインストールします。
sudo pip3 install mh-z19
動作確認をします。
sudo python3 -m mh_z19
CO2濃度の値が表示されればOKです。
温湿度とCO2濃度をLCDに表示するプログラム
スクリプトの準備が完了したら、メインのLCDに表示するプログラムを作成します。
DHTライブラリをインストールしたAdafruit_Python_DHTディレクトリに移動して先程作成したディレクトリに移動します。以下のパスは環境に応じて変更してください。
cd ~/Adafruit_Python_DHT/sensorScript
vim displaySensor.py
以下のPythonプログラムを作成してください。
#!/usr/bin/python
import smbus
import time
import datetime
import Adafruit_DHT
import sys
import mh_z19
I2C_ADDR = 0x27 # I2C device address, if any error, change this address to 0x27
LCD_WIDTH = 16 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
#Open I2C interface
#bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33,LCD_CMD) # 110011 Initialise
lcd_byte(0x32,LCD_CMD) # 110010 Initialise
lcd_byte(0x06,LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C,LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28,LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01,LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
LCD_BACKLIGHT = 0x08 # On
now_dt = datetime.datetime.now()
# Turn off backlight between 0:00 ~ 6:00
if 0 <= now_dt.hour <= 5:
LCD_BACKLIGHT = 0x00 # Off
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR,(bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message,line):
# Send string to display
message = message.ljust(LCD_WIDTH," ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]),LCD_CHR)
def getDI(h, t):
DI_value = 0.81 * t + 0.01 * h *(0.99 * t - 14.3) + 46.3
if DI_value < 55:
taikan = "COLD"
elif 55 <= DI_value < 60:
taikan = "CHILLY"
elif 60 <= DI_value < 65:
taikan = "NORMAL"
elif 65 <= DI_value < 70:
taikan = "COMFORT"
elif 70 <= DI_value < 75:
taikan = "NOT HOT"
elif 75 <= DI_value < 80:
taikan = "BIT HOT"
elif 80 <= DI_value < 85:
taikan = "HOT"
elif 85 <= DI_value:
taikan = "VERY HOT"
return taikan
def main():
# Main program block
# Parse command line parameters.
sensor_args = { '11': Adafruit_DHT.DHT11,
'22': Adafruit_DHT.DHT22,
'2302': Adafruit_DHT.AM2302 }
if len(sys.argv) == 3 and sys.argv[1] in sensor_args:
sensor = sensor_args[sys.argv[1]]
pin = sys.argv[2]
else:
print('Usage: sudo ./Adafruit_DHT.py [11|22|2302] <GPIO pin number>')
print('Example: sudo ./Adafruit_DHT.py 2302 4 - Read from an AM2302 connected to GPIO pin #4')
sys.exit(1)
h, t = Adafruit_DHT.read_retry(sensor, pin)
lcd_init()
lcd_string("{0:0.1f}\'C {1:0.1f}%".format(t, h), LCD_LINE_1)
lcd_string(getDI(h, t) + " " + str(mh_z19.read()) + 'ppm', LCD_LINE_2)
if h is not None and t is not None:
print ("{0:0.1f}".format(t))
else:
print('Failed to get reading. Try again!')
sys.exit(1)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
pass
#lcd_byte(0x01, LCD_CMD)
ポイント
- 午前0時~午前5時まではLCDのライトが眩しいため、次の部分で消灯しています。
# Turn off backlight between 0:00 ~ 6:00 if 0 <= now_dt.hour <= 5: LCD_BACKLIGHT = 0x00 # Off
この部分の0と5を変更することで、消灯時刻を変更できます。 - 不快指数(DI)は
getDI(h, t)
で算出しています。 - LCDの1行目は、
lcd_string("{0:0.1f}\'C {1:0.1f}%".format(t, h), LCD_LINE_1)
で表示しています。tに温度、hに湿度が代入されています。 - LCDの2行目は、
lcd_string(getDI(h, t) + " " + str(mh_z19.read()) + 'ppm', LCD_LINE_2)
で表示しています。不快指数とCO2濃度ライブラリから取得した値を表示しています。
以下のコマンドで動作確認してください。(CO2濃度のライブラリを呼び出すため、管理者権限で実行します)
sudo python ~/Adafruit_Python_DHT/sensorScript/temp.py 22 4
ディスプレイに各種センサが表示されれば成功です。
cronで定期実行する
作成したスクリプトをcronに登録して定期実行しましょう。
crontab -e
vimの編集画面が開いたら、以下のコマンドを文末に追加します。[ユーザー名]は置き換えてください。以下の例は2分おきにスクリプトが実行されます。
*/2 * * * * sudo python3 /home/[ユーザー名]/Adafruit_Python_DHT/sensorScript/temp.py 22 4
保存したら、以下のコマンドで確認します。
crontab -l
追加したコマンドが表示されればOKです。
おわりに
ラズパイに温湿度計とCO2濃度計を接続してLCDに表示する方法を解説しました。センサーで取得した値をmuninを用いてグラフ化したり、グラフ化した画像をPythonのライブラリを用いてDiscordやLineに送るなど様々な活用方法があります。
CO2濃度計は約2000~3000円と少し高いですが、温湿度計は安価で手に入るため、まずは温湿度計を接続して表示するのもいいかもしれません。また、ディスプレイに日経平均やSP500、暗号通貨のレートや明日の天気情報などを常時表示させるのも楽しいですね。
ちなみに、今回はこれまでの記事で最も時間がかかったかもしれません…配線が抜けたりMicroSDカードが故障したりしたときに復旧できるように、記録として残しました。少しでも参考になれば幸いです。
Be First to Comment