Daily Hack

Raspberry Pi 5で植物の水やりを自動化してみた

ラズベリーパイ
#Raspberry Pi#自動化#IoT#プログラミング#ガーデニング

旅行中に植物を枯らしてしまった経験はありませんか? 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
  1. Interface OptionsSPIYes で有効化
  2. 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
PRスポンサーリンク
お家でできるヨガ・フィットネス(オンライン講座)

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鉢から試して、うまくいったら複数の鉢に拡張してみてください。

PRスポンサーリンク
骨盤矯正メディフェクト