Skip to content

Raspberry Piで温湿度とCO2濃度をモニタリングする(DHT22, MH-Z19C)

こんにちは。Raspberry Pi(ラズパイ)を使って温度、湿度、CO2濃度をモニタに表示する方法を紹介します。

各種センサの値をモニタに表示して、感覚的な暑い/寒いを数値化します。また、不快指数を算出することで、冷房/暖房をつける目安にもなります。

完成イメージ

7596f81c pxl 20230819 010122237 2

各種センサを表示した様子です。ラズパイやセンサーを固定するブレッドボードの作り方は以下の記事を参考にしてください。

889e3330

こちらがLCDモニタに表示しているデータです。室内の温度、湿度、不快指数(DI)、CO2濃度を確認することができます。

温度と湿度はDHT22から値を取得しています。

不快指数(Discomfort Index=DI)は蒸し暑さを数量的に表した指数で、温度と湿度から計算することができます。不快指数と体感の関係について、Wikipediaから引用した表を以下に示します。

不快指数体感
〜50寒くてたまらない
50〜55寒い
55〜60肌寒い
60〜65何も感じない
65〜70快適
70〜75不快感を持つ人が出始める
75〜80半数以上が不快に感じる
80〜85全員が不快に感じる
85〜暑くてたまらない
引用 https://ja.wikipedia.org/wiki/%E4%B8%8D%E5%BF%AB%E6%8C%87%E6%95%B0

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で動作を確認済みです。

回路図

00794f33 温湿度co2濃度計 回路図

各センサーとGPIOを接続した回路図をfritzingを用いて作成しました。初めてブレッドボードビューを作成したため、かなり見づらいとは思いますがご了承ください。

今回の回路について、本来であれば抵抗および5V, 3V電源を考慮する必要がありますが、今回は動けばいいや精神で組んでいます。(よくない)

ラズパイのGPIOについては公式サイトを参照してください。

fa1eedb9 image

シリアル通信

それでは手順を解説します。まずは設定画面を開き、シリアル通信を有効にします。

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です。

13e2cbe0 image

MH-Z19ライブラリのインストール

以下のコマンドでライブラリをインストールします。

sudo pip3 install mh-z19

動作確認をします。

sudo python3 -m mh_z19
7bff9a2d image

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カードが故障したりしたときに復旧できるように、記録として残しました。少しでも参考になれば幸いです。

カテゴリRaspberry Piプログラミング

Be First to Comment

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

コメントは日本語で入力してください。(スパム対策)

CAPTCHA