前回の記事ではハードウェアの組み立てやOSの初期設定、必要なライブラリのインストールを行いました。今回は各種センサーや表示器、天気を取得するAPIテストを紹介します。さらに開発中に遭遇したCO2センサーが800ppmから動かないトラブルや権限エラーの解決法を解説します。
Contents
DHT22温湿度センサーの単体テスト
まずは室内温湿度を測定するDHT22の動作確認を行います。PythonスクリプトからAdafruit CircuitPython DHTライブラリを使用してデータを読み取ります。
以下のテストスクリプトを適当なディレクトリに作成して実行します。今回はホームディレクトリに作業フォルダを作成して進めていきます。
cd ~ && mkdir monitor
フォルダを作成したら以下のスクリプトを作成します。
vimは、iキーで編集モード、入力後はEscを押して:wqで保存終了します
vim test_dht22.py
import time
import board
import adafruit_dht
dht_device = adafruit_dht.DHT22(board.D4)
for i in range(5):
try:
temp = dht_device.temperature
humidity = dht_device.humidity
print(f"温度: {temp:.1f} ℃ / 湿度: {humidity:.1f} %")
except RuntimeError as e:
print(f"読み取りスキップ: {e.args[0]}")
time.sleep(2.0)
dht_device.exit()
以下のコマンドでテストスクリプトを実行します。
python3 test_dht22.py
5回連続で温湿度のデータが取得できればDHT22の動作確認は完了です。
e-PaperHATの動作確認と180度回転表示
次に画面表示を担う4.26インチe-PaperHATの描画テストを行います。
以下のスクリプトを作成します。
vim test_epaper.py
import sys
from PIL import Image, ImageDraw
sys.path.append('lib')
from waveshare_epd import epd4in26
epd = epd4in26.EPD()
epd.init()
epd.Clear()
image = Image.new('1', (epd.width, epd.height), 255)
draw = ImageDraw.Draw(image)
draw.rectangle((20, 20, 780, 460), outline=0, width=5)
draw.text((100, 200), "TEST SUCCESS", fill=0)
rotated_image = image.rotate(180)
epd.display(epd.getbuffer(rotated_image))
epd.sleep()
今回は、配置の関係上、ディスプレイ表示を180度反転させて描画する処理を組み込んでいます。通常通り表示する場合は、epd.display(epd.getbuffer(rotated_image))の部分をimageを直接渡す形に書き換えてください。
epd.display(epd.getbuffer(image))
テストスクリプトを実行して、画面が表示されれば成功です。
python3 test_epaper.py

MH-Z19C CO2センサーの接続と単体テスト
続いて室内CO2濃度を測定するMH-Z19Cの動作テストを実施します。UART通信を利用してデータを取り込みます。
まずは通信用ライブラリをインストールします。
pip3 install mh-z19 pyserial --break-system-packages
シリアル通信を安定させるため/boot/firmware/config.txtの設定を確認します。
sudo vim /boot/firmware/config.txt
以下の記述を末尾に追加します。
enable_uart=1
dtoverlay=disable-bt
Bluetoothを無効化することでシリアル通信の安定性が向上します。Bluetoothを利用する場合は、enable_uart=1のみを追加してください。
テスト用のPythonスクリプトを作成して実行します。
vim test_co2.py
import time
import mh_z19
print("CO2テスト開始")
for i in range(5):
try:
data = mh_z19.read_all()
if data and 'co2' in data:
co2 = data['co2']
print(f"CO2濃度: {co2} ppm")
else:
print("データの取得に失敗しました")
except Exception as e:
print(f"エラー発生: {e}")
time.sleep(2.0)
print("テスト終了")
以下を実行して正常にCO2濃度が取得できれば動作確認は完了です。
python3 test_co2.py
ハマりどころ解決:CO2濃度が800ppmから動かない原因と対策
MH-Z19Cを使用する際、数値がずっと初期値である800ppmのまま変化しない現象が発生することがあります。原因と解決策を紹介します。
シリアルポートの権限エラーとLoginShell設定
RaspberryPiのraspi-config設定でシリアルコンソール(LoginShell)が有効になっていると、シリアルポート(/dev/ttyAMA0など)の権限がroot専用(crw——-)になり、一般ユーザーでプログラムを実行した際にPermissionErrorが発生します。
対処手順は以下の通りです。
- sudo raspi-configを実行します
- Interface Optionsを選択します
- Serial Portを選択します
- Would you like a login shell to be accessible over serial?でNoを選択します
- Would you like the serial port hardware to be enabled?でYesを選択します
- 実行ユーザーをdialoutグループに追加してOSを再起動します
sudo usermod -aG dialout $USER
sudo reboot
原因2:例外処理によるエラーの隠蔽
プログラム内でセンサー読み取り時にエラーが発生した際、例外処理(try-except)でエラー内容を出力せずに無視(passなど)していると、通信失敗時の初期値である800ppmが出力され続けてしまいます。
エラー発生時にはしっかりと例外内容を表示させることで原因を特定できます。
except Exception as e:
print(f"CO2エラー発生: {e}")
OpenWeatherMap APIの取得手順
屋外の天気予報データを取得するために利用するOpenWeatherMapのAPIキー取得手順を説明します。アカウント登録からキーの発行まではすべて無料で行えます。

手順は以下の通りです。
- OpenWeatherMap公式サイトへアクセスしSign inからCreate an Accountを選択します
- ユーザー名、メールアドレス、パスワードを入力して利用規約に同意しアカウントを作成します
- 登録したメールアドレスに確認メールが届くためVerify your emailをクリックして認証を完了させます
- マイページにログインしAPI keysタブを開きます
- 初期状態で生成されているKeyの値をコピーするか新規で名前をつけてGenerateボタンを押しAPIキーを作成します
注意点として、アカウント作成直後はAPIキーが有効化されておらず通信エラーが発生する場合があります。有効化完了までに数分から数時間程度かかることがあるため、プログラム実行時にエラーが出る場合は少し時間をおいてから試してください。
OpenWeatherMap APIからの天気予報データ取得
続いて屋外の天気情報や気温、降水確率を取得するためにOpenWeatherMapAPIを利用します。APIアクセス用にrequestsライブラリをインストールします。
pip3 install requests --break-system-packages
現在地の外気温湿度および予報データを取得するPythonスクリプトを作成します。
YOUR_API_KEY_HEREに先ほど取得したAPIを入れてください。CITYには市を入れてください。
vim test_weather.py
import requests
API_KEY = "YOUR_API_KEY_HERE"
CITY = "Tokyo,JP"
CURRENT_URL = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric&lang=ja"
FORECAST_URL = f"http://api.openweathermap.org/data/2.5/forecast?q={CITY}&appid={API_KEY}&units=metric&lang=ja"
try:
res_current = requests.get(CURRENT_URL).json()
if res_current.get("cod") == 200:
cur_temp = res_current["main"]["temp"]
cur_humidity = res_current["main"]["humidity"]
cur_weather = res_current["weather"][0]["description"]
print(f"天気: {cur_weather} | 気温: {cur_temp:.1f}℃ | 湿度: {cur_humidity}%")
res_forecast = requests.get(FORECAST_URL).json()
if res_forecast.get("cod") == "200":
daily_data = {}
for item in res_forecast["list"]:
date_str = item["dt_txt"].split(" ")[0]
temp = item["main"]["temp"]
weather = item["weather"][0]["description"]
pop = int(item.get("pop", 0) * 100)
if date_str not in daily_data:
daily_data[date_str] = {"temps": [], "weathers": [], "pops": []}
daily_data[date_str]["temps"].append(temp)
daily_data[date_str]["weathers"].append(weather)
daily_data[date_str]["pops"].append(pop)
for date in list(daily_data.keys())[:3]:
temps = daily_data[date]["temps"]
max_temp = max(temps)
min_temp = min(temps)
max_pop = max(daily_data[date]["pops"])
main_weather = max(set(daily_data[date]["weathers"]), key=daily_data[date]["weathers"].count)
print(f"{date} 天気: {main_weather} | 最高: {max_temp:.1f}℃ / 最低: {min_temp:.1f}℃ | 降水確率: {max_pop}%")
except Exception as e:
print(f"通信エラー発生: {e}")
テストスクリプトを実行して現在の天気や今後の最高気温・最低気温、降水確率が正しく取得できればテスト完了です。
python3 test_weather.py
まとめと次回予告
今回はDHT22、e-PaperHAT、MH-Z19C、OpenWeatherMapAPIの単体テスト手順と、MH-Z19Cのハマりどころである800ppm固定化現象の解決法を解説しました。
次回はPILライブラリを使ったアイコン描画や日本語フォント設定、全データをまとめたメインプログラムの実装について解説します。










