Daily Hack
🌡

Raspberry Pi 5で室内の温度・湿度を自動記録してみた

デジタル
#Raspberry Pi#自動化#IoT#プログラミング#スマートホーム

「部屋が暑いと思ったけど、実際何度だったんだろう?」「冬場の乾燥、どのくらいひどい?」——感覚に頼っていた室内環境を、データで「見える化」してみませんか。

この記事では、Raspberry Pi 5 と BME280 センサーを使って、温度・湿度・気圧を自動で記録し、グラフで確認できるシステムを一から作る方法を解説します。

室内環境モニタリング システム構成図

完成イメージ

  • 5分ごとに温度・湿度・気圧を自動計測
  • データは CSV ファイルに蓄積
  • ブラウザから簡易ダッシュボードでグラフ確認
  • 異常値(高温・高湿度)を検知したらターミナルに警告表示

必要なもの

| パーツ | 目安価格 | |--------|----------| | Raspberry Pi 5(4GB 以上) | 約10,000円 | | microSD カード(32GB 以上) | 約1,000円 | | USB-C 電源アダプター(5V/5A) | 約2,000円 | | BME280 センサーモジュール | 約500〜800円 | | ジャンパーワイヤー(メス-メス)4本 | 約200円 | | ブレッドボード(任意) | 約300円 |

BME280 は Amazon や秋月電子、スイッチサイエンスなどで購入できます。「BMP280」という似た名前のセンサーもありますが、こちらは湿度が計測できないので注意してください。

STEP 1: Raspberry Pi OS のセットアップ

すでに OS が入っている方は STEP 2 に進んでください。

1-1. OS を microSD に書き込む

PC で Raspberry Pi Imager をダウンロードし、microSD カードに OS を書き込みます。

# 公式サイトからダウンロード
# https://www.raspberrypi.com/software/

OS は Raspberry Pi OS (64-bit) を選択してください。書き込み時の設定で以下を有効にしておくと便利です。

  • SSH を有効にする
  • Wi-Fi の SSID とパスワードを設定する
  • ユーザー名とパスワードを設定する

1-2. 起動と初期設定

microSD を挿して電源を入れたら、SSH で接続します。

ssh pi@raspberrypi.local

接続できたら、まずシステムを最新に更新します。

sudo apt update && sudo apt upgrade -y

STEP 2: I2C を有効にする

BME280 は I2C(アイ・スクエアド・シー)という通信方式でデータをやり取りします。Raspberry Pi では初期状態で無効になっているため、有効化が必要です。

sudo raspi-config

以下の順で選択します。

  1. Interface Options を選択
  2. I2C を選択
  3. Yes で有効化
  4. Finish で終了

設定後、再起動します。

sudo reboot

STEP 3: BME280 を配線する

再起動後、BME280 センサーを Raspberry Pi に接続します。

ピン接続表

| BME280 | Raspberry Pi GPIO | |--------|-------------------| | VIN (電源) | Pin 1(3.3V) | | GND (グランド) | Pin 6(GND) | | SCL (クロック) | Pin 5(GPIO 3 / SCL) | | SDA (データ) | Pin 3(GPIO 2 / SDA) |

接続の確認

配線が終わったら、センサーが認識されているか確認します。

sudo apt install -y i2c-tools
i2cdetect -y 1

以下のように 76 または 77 が表示されれば成功です。

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
...
70: -- -- -- -- -- -- 76 --

76 が表示されない場合は、配線を再確認してください。VIN と GND が逆になっていないか、ジャンパーワイヤーがしっかり刺さっているかを確認しましょう。

STEP 4: Python 環境を構築する

4-1. 必要なライブラリをインストール

# 仮想環境を作成(推奨)
python3 -m venv ~/env-monitor
source ~/env-monitor/bin/activate

# ライブラリをインストール
pip install smbus2 RPi.bme280 flask matplotlib

4-2. センサーの動作確認

まず、センサーが正しく値を返すかテストします。

# test_sensor.py
import smbus2
import bme280

port = 1
address = 0x76  # i2cdetect で確認したアドレス
bus = smbus2.SMBus(port)

calibration_params = bme280.load_calibration_params(bus, address)
data = bme280.sample(bus, address, calibration_params)

print(f"温度: {data.temperature:.1f} °C")
print(f"湿度: {data.humidity:.1f} %")
print(f"気圧: {data.pressure:.1f} hPa")
python test_sensor.py

以下のような出力が表示されれば成功です。

温度: 24.3 °C
湿度: 48.2 %
気圧: 1013.5 hPa

STEP 5: データ記録スクリプトを作る

5分ごとにセンサーデータを CSV に記録するスクリプトを作成します。

# monitor.py
import smbus2
import bme280
import csv
import os
import time
from datetime import datetime

# === 設定 ===
INTERVAL = 300           # 計測間隔(秒): 300秒 = 5分
CSV_FILE = "environment_log.csv"
TEMP_WARN = 30.0         # 警告: 温度がこの値を超えたら通知
HUMIDITY_WARN = 70.0     # 警告: 湿度がこの値を超えたら通知

# === I2C 初期化 ===
port = 1
address = 0x76
bus = smbus2.SMBus(port)
calibration_params = bme280.load_calibration_params(bus, address)

def read_sensor():
    """センサーからデータを読み取る"""
    data = bme280.sample(bus, address, calibration_params)
    return {
        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "temperature": round(data.temperature, 1),
        "humidity": round(data.humidity, 1),
        "pressure": round(data.pressure, 1),
    }

def write_csv(reading):
    """CSV ファイルにデータを追記する"""
    file_exists = os.path.exists(CSV_FILE)
    with open(CSV_FILE, "a", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=reading.keys())
        if not file_exists:
            writer.writeheader()
        writer.writerow(reading)

def check_warnings(reading):
    """異常値を検知して警告を出す"""
    warnings = []
    if reading["temperature"] > TEMP_WARN:
        warnings.append(f"[警告] 温度が {reading['temperature']}°C に達しました")
    if reading["humidity"] > HUMIDITY_WARN:
        warnings.append(f"[警告] 湿度が {reading['humidity']}% に達しました")
    for w in warnings:
        print(w)

# === メインループ ===
print("室内環境モニタリングを開始します")
print(f"計測間隔: {INTERVAL}秒 / 保存先: {CSV_FILE}")
print("-" * 50)

while True:
    reading = read_sensor()
    write_csv(reading)
    check_warnings(reading)
    print(f"[{reading['timestamp']}] "
          f"{reading['temperature']}°C / "
          f"{reading['humidity']}% / "
          f"{reading['pressure']}hPa")
    time.sleep(INTERVAL)

実行

python monitor.py

ターミナルに計測値が表示され、environment_log.csv にデータが蓄積されていきます。

STEP 6: Web ダッシュボードを作る

記録したデータをブラウザからグラフで確認できるようにします。

# dashboard.py
from flask import Flask, render_template_string
import csv
import os

app = Flask(__name__)
CSV_FILE = "environment_log.csv"

HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>室内環境ダッシュボード</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  <style>
    body { font-family: sans-serif; max-width: 900px; margin: 0 auto; padding: 20px; background: #f5f5f5; }
    h1 { color: #1b4332; }
    .card { background: #fff; border-radius: 12px; padding: 20px; margin: 16px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
    .latest { display: flex; gap: 20px; justify-content: center; text-align: center; }
    .latest div { flex: 1; }
    .latest .value { font-size: 2em; font-weight: bold; color: #2d6a4f; }
    .latest .label { color: #666; font-size: 0.9em; }
  </style>
</head>
<body>
  <h1>室内環境ダッシュボード</h1>
  <div class="card">
    <h2>最新の計測値</h2>
    <div class="latest">
      <div><div class="value">{{ latest.temperature }}°C</div><div class="label">温度</div></div>
      <div><div class="value">{{ latest.humidity }}%</div><div class="label">湿度</div></div>
      <div><div class="value">{{ latest.pressure }} hPa</div><div class="label">気圧</div></div>
    </div>
    <p style="text-align:center; color:#999; font-size:0.85em;">最終更新: {{ latest.timestamp }}</p>
  </div>
  <div class="card">
    <canvas id="tempChart"></canvas>
  </div>
  <div class="card">
    <canvas id="humChart"></canvas>
  </div>
  <script>
    const labels = {{ timestamps | tojson }};
    const temps = {{ temperatures | tojson }};
    const hums = {{ humidities | tojson }};

    new Chart(document.getElementById("tempChart"), {
      type: "line",
      data: { labels, datasets: [{ label: "温度 (°C)", data: temps, borderColor: "#c1121f", tension: 0.3, fill: false }] },
      options: { responsive: true }
    });
    new Chart(document.getElementById("humChart"), {
      type: "line",
      data: { labels, datasets: [{ label: "湿度 (%)", data: hums, borderColor: "#2d6a4f", tension: 0.3, fill: false }] },
      options: { responsive: true }
    });
  </script>
</body>
</html>
"""

@app.route("/")
def dashboard():
    rows = []
    if os.path.exists(CSV_FILE):
        with open(CSV_FILE) as f:
            rows = list(csv.DictReader(f))

    # 直近 288 件(= 24時間分 @ 5分間隔)を取得
    rows = rows[-288:]

    latest = rows[-1] if rows else {"timestamp": "-", "temperature": "-", "humidity": "-", "pressure": "-"}
    timestamps = [r["timestamp"][-8:] for r in rows]  # HH:MM:SS のみ
    temperatures = [float(r["temperature"]) for r in rows]
    humidities = [float(r["humidity"]) for r in rows]

    return render_template_string(
        HTML_TEMPLATE,
        latest=latest,
        timestamps=timestamps,
        temperatures=temperatures,
        humidities=humidities,
    )

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

実行

# monitor.py と並行して、別のターミナルで実行
python dashboard.py

ブラウザで http://raspberrypi.local:8080 にアクセスすると、リアルタイムでグラフが確認できます。

STEP 7: 自動起動を設定する

Raspberry Pi を再起動しても自動で計測が始まるようにします。

systemd サービスを作成

sudo nano /etc/systemd/system/env-monitor.service

以下を記入します。

[Unit]
Description=Environment Monitor
After=network.target

[Service]
ExecStart=/home/pi/env-monitor/bin/python /home/pi/monitor.py
WorkingDirectory=/home/pi
Restart=always
User=pi

[Install]
WantedBy=multi-user.target

サービスを有効化・起動

sudo systemctl enable env-monitor
sudo systemctl start env-monitor

# 動作確認
sudo systemctl status env-monitor

Active: active (running) と表示されれば成功です。

トラブルシューティング

| 症状 | 原因と対処 | |------|-----------| | i2cdetect で何も表示されない | 配線を確認。SCL/SDA が逆になっていないか、3.3V に接続しているか確認 | | アドレスが 77 になる | address = 0x77 に変更する。モジュールによってアドレスが異なる | | 湿度が常に 0% | BMP280(湿度非対応)を使っている可能性あり。BME280 か確認 | | Permission denied エラー | sudo usermod -aG i2c pi を実行して再ログイン |


約1,500円のセンサーを追加するだけで、自宅が「データで見える」ようになります。エアコン稼働の判断、カビ対策、睡眠環境の改善など、データがあるだけで暮らしの判断がぐっとラクになるはずです。