Raspberry Pi 5で植物の水やりを自動化してみた
旅行中に植物を枯らしてしまった経験はありませんか? Raspberry Pi 5 を使えば、土の乾燥を自動で検知して水をやるシステムがわずか数千円で作れます。
この記事では、部品の選び方から配線、プログラムの作成、自動起動の設定まで、すべての手順を解説します。
完成イメージ
- 土壌の水分量を定期的にチェック
- 乾いていたらポンプが自動で水をやる
- やりすぎ防止の安全機構付き
- ログを記録して水やり履歴を確認可能
必要なもの
| パーツ | 目安価格 | |--------|----------| | Raspberry Pi 5(4GB 以上) | 約10,000円 | | microSD カード(32GB 以上) | 約1,000円 | | USB-C 電源アダプター | 約2,000円 | | 静電容量式土壌水分センサー | 約400円 | | MCP3008(AD コンバーター) | 約500円 | | 5V リレーモジュール | 約300円 | | 小型水中ポンプ(DC 3-5V) | 約500円 | | シリコンチューブ(内径 6mm) | 約300円 | | ブレッドボード+ジャンパーワイヤー | 約500円 | | 水タンク(ペットボトルでも可) | 0円〜 |
重要: 土壌水分センサーは「静電容量式」を選んでください。「抵抗式」は電極が腐食しやすく、長期利用には向きません。
STEP 1: 基本セットアップ
Raspberry Pi OS のインストールと初期設定が済んでいない場合は、以下を実行します。
# システム更新
sudo apt update && sudo apt upgrade -y
SPI を有効にする
MCP3008 は SPI 通信を使うため、有効化が必要です。
sudo raspi-config
- Interface Options → SPI → Yes で有効化
- Finish → 再起動
sudo reboot
STEP 2: 配線する
全体の構成
[土壌水分センサー] → [MCP3008] → [Raspberry Pi] → [リレー] → [ポンプ]
(AD変換) (判断・制御) (スイッチ) (水やり)
MCP3008 の配線
MCP3008 は、アナログ信号(土壌水分センサーの出力)をデジタル信号に変換する IC です。
| MCP3008 ピン | 接続先 | |-------------|--------| | VDD (Pin 16) | 3.3V (Pin 1) | | VREF (Pin 15) | 3.3V (Pin 1) | | AGND (Pin 14) | GND (Pin 6) | | CLK (Pin 13) | SCLK / GPIO 11 (Pin 23) | | DOUT (Pin 12) | MISO / GPIO 9 (Pin 21) | | DIN (Pin 11) | MOSI / GPIO 10 (Pin 19) | | CS (Pin 10) | CE0 / GPIO 8 (Pin 24) | | DGND (Pin 9) | GND (Pin 6) | | CH0 (Pin 1) | 土壌水分センサーの出力 |
土壌水分センサーの配線
| センサー | 接続先 | |---------|--------| | VCC | 3.3V (Pin 1) | | GND | GND (Pin 6) | | AOUT | MCP3008 の CH0 (Pin 1) |
リレーモジュールの配線
| リレー | 接続先 | |-------|--------| | VCC | 5V (Pin 2) | | GND | GND (Pin 9) | | IN | GPIO 27 (Pin 13) | | COM | ポンプの+線 | | NO | 電源(5V)の+線 |
ポンプの−線は電源の GND に直結します。
STEP 3: Python 環境を構築する
python3 -m venv ~/auto-water
source ~/auto-water/bin/activate
pip install spidev RPi.GPIO
STEP 4: センサーの値を確認する
まず、土壌水分センサーの値がどの範囲になるか確認しましょう。
# test_soil.py
import spidev
import time
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1350000
def read_soil_moisture(channel=0):
"""MCP3008 からアナログ値を読み取る(0〜1023)"""
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 3) << 8) + adc[2]
return value
print("土壌水分センサーの値を5秒ごとに表示します")
print("空気中 → 高い値(乾燥)/ 水中 → 低い値(湿潤)")
print("-" * 40)
while True:
value = read_soil_moisture()
print(f"センサー値: {value} / 1023")
time.sleep(5)
python test_soil.py
以下のように値が変化するはずです。
| 状態 | センサー値の目安 | |------|----------------| | 空気中(超乾燥) | 800〜1023 | | 乾いた土 | 500〜800 | | 適度に湿った土 | 300〜500 | | 水中(びしょびしょ) | 0〜300 |
この値は環境やセンサーによって異なります。実際に使う土に挿して、「乾燥」と「適湿」の境目の値を確認しておきましょう。
STEP 5: 自動水やりスクリプトを作る
# auto_water.py
import spidev
import RPi.GPIO as GPIO
import time
import os
from datetime import datetime
# === 設定 ===
PUMP_PIN = 27 # リレー制御ピン
CHECK_INTERVAL = 1800 # チェック間隔(秒): 30分
DRY_THRESHOLD = 600 # この値以上で「乾燥」と判定
PUMP_DURATION = 5 # ポンプ稼働時間(秒)
MAX_WATER_PER_DAY = 4 # 1日の最大水やり回数
LOG_FILE = "watering_log.csv"
# === 初期化 ===
GPIO.setmode(GPIO.BCM)
GPIO.setup(PUMP_PIN, GPIO.OUT)
GPIO.output(PUMP_PIN, GPIO.LOW) # 初期状態: OFF
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1350000
water_count_today = 0
last_reset_date = datetime.now().date()
def read_soil_moisture(channel=0):
"""土壌水分を読み取る"""
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 3) << 8) + adc[2]
return value
def activate_pump(duration):
"""ポンプを指定秒数だけ動かす"""
print(f" ポンプ ON({duration}秒間)")
GPIO.output(PUMP_PIN, GPIO.HIGH)
time.sleep(duration)
GPIO.output(PUMP_PIN, GPIO.LOW)
print(" ポンプ OFF")
def log_event(moisture, action):
"""イベントをログに記録する"""
file_exists = os.path.exists(LOG_FILE)
with open(LOG_FILE, "a") as f:
if not file_exists:
f.write("timestamp,moisture,action\n")
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(f"{timestamp},{moisture},{action}\n")
# === メインループ ===
print("自動水やりシステムを開始します")
print(f"乾燥しきい値: {DRY_THRESHOLD} / チェック間隔: {CHECK_INTERVAL}秒")
print(f"1日の最大水やり回数: {MAX_WATER_PER_DAY}")
print("-" * 50)
try:
while True:
# 日付が変わったらカウントリセット
today = datetime.now().date()
if today != last_reset_date:
water_count_today = 0
last_reset_date = today
moisture = read_soil_moisture()
now = datetime.now().strftime("%H:%M:%S")
if moisture >= DRY_THRESHOLD:
if water_count_today < MAX_WATER_PER_DAY:
print(f"[{now}] 水分: {moisture}(乾燥)→ 水やりを実行します")
activate_pump(PUMP_DURATION)
water_count_today += 1
log_event(moisture, f"watered ({water_count_today}/{MAX_WATER_PER_DAY})")
# 水やり後、水が浸透するまで少し待つ
print(" 水の浸透を待っています(60秒)...")
time.sleep(60)
else:
print(f"[{now}] 水分: {moisture}(乾燥)→ 本日の上限に達したためスキップ")
log_event(moisture, "skipped (daily limit)")
else:
print(f"[{now}] 水分: {moisture}(適湿)→ 水やり不要")
log_event(moisture, "ok")
time.sleep(CHECK_INTERVAL)
except KeyboardInterrupt:
print("\n終了します")
finally:
GPIO.output(PUMP_PIN, GPIO.LOW)
GPIO.cleanup()
spi.close()
実行
python auto_water.py
STEP 6: 自動起動を設定する
sudo nano /etc/systemd/system/auto-water.service
[Unit]
Description=Auto Watering System
After=network.target
[Service]
ExecStart=/home/pi/auto-water/bin/python /home/pi/auto_water.py
WorkingDirectory=/home/pi
Restart=always
User=pi
[Install]
WantedBy=multi-user.target
sudo systemctl enable auto-water
sudo systemctl start auto-water
sudo systemctl status auto-water
安全上の注意
- 水漏れ対策: ポンプとチューブの接続部は結束バンドでしっかり固定してください
- 電源の防水: Raspberry Pi や電源アダプターに水がかからない場所に設置してください
- ポンプの空回り防止: タンクの水がなくなるとポンプが壊れます。定期的にタンクの残量を確認してください
- テスト: 本番稼働の前に、水やり回数の上限やポンプの稼働時間を短めに設定して、数日間テスト運用しましょう
トラブルシューティング
| 症状 | 原因と対処 | |------|-----------| | センサー値が常に 0 | SPI が有効か確認。配線の VCC/GND が正しいか確認 | | センサー値が変化しない | センサーを土に十分深く挿しているか確認 | | ポンプが動かない | リレーの IN ピンの接続を確認。COM/NO の配線を確認 | | 水が出ない | チューブの詰まり、ポンプの向き(吸水口・排水口)を確認 |
一度セットアップすれば、旅行中でも安心して家を空けられます。最初は1鉢から試して、うまくいったら複数の鉢に拡張してみてください。