Raspberry Pi 5で室内の温度・湿度を自動記録してみた
「部屋が暑いと思ったけど、実際何度だったんだろう?」「冬場の乾燥、どのくらいひどい?」——感覚に頼っていた室内環境を、データで「見える化」してみませんか。
この記事では、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
以下の順で選択します。
- Interface Options を選択
- I2C を選択
- Yes で有効化
- 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円のセンサーを追加するだけで、自宅が「データで見える」ようになります。エアコン稼働の判断、カビ対策、睡眠環境の改善など、データがあるだけで暮らしの判断がぐっとラクになるはずです。