本文就来手把手教大家搭建一个 自动化智能灌溉系统。土干了,水泵自动开启;水够湿润,自动关停。而且,还带Web管理后台——手机打开浏览器就能看土壤湿度、光照状态、水泵运行日志。

完整代码及配套网页均已开源,文末会贴出所有代码,可直接复制使用。

一、项目预览

先来看一下最终效果(手机、电脑都能打开(统一局域网下)):

  • 🌿 土壤湿度卡片:显示“湿润”或“干燥”,附带对应的表情符号

  • ☀️ 光照状态卡片:显示“明亮”或“较暗”

  • 💧 水泵状态卡片:显示“运行中”或“已关闭”

  • 一个开关:可在 自动模式与 手动模式之间自由切换

  • 两个手动按钮:手动开启/关闭水泵

  • 系统日志区:自动记录每一次操作(开/关水泵、切换模式、储水报警等)

二、准备工作:硬件清单

硬件 型号/规格 参考价格
树莓派 3B / 4B 均可 ¥300~600
土壤湿度传感器 YL-69 或 FC-28 ¥15~25
光敏传感器模块 数字型 DO 输出 ¥8~15
继电器模块 一路 5V ¥10~20
微型水泵 5V/12V直流 ¥25~40
杜邦线 母对母 ×若干 ¥5~10
面包板(可选) 便于接线 ¥8~15

 

                                         还需要一个这个(里面可以放3个1.5V的干电池)

 

三、环境搭建:库的安装

 

3.1 安装 Python 库

首先是 RPi.GPIO,这个库是树莓派 GPIO 控制的核心模块。Raspberry Pi OS 通常已预装 RPi.GPIO。如未安装,可以使用以下命令:

bash

sudo apt update

sudo apt install python3-rpi.gpio

或使用 pip3:(这个第一个方法不行的的时候你们自己试一下,一般情况下都能下载好)

bash

sudo pip3 install RPi.GPIO

验证是否安装成功:

bash

python3 -c "import RPi.GPIO as GPIO; print(GPIO.VERSION)"

如果输出类似 0.7.1 的版本号,说明安装成功。

然后是 Flask(Python Web 框架):

bash

sudo apt install python3-flask

⚠️ 注意:RPi.GPIO 只能在树莓派上运行,在普通电脑(Windows/Mac)上无法安装。如果你在电脑上调试代码,需要先把所有 GPIO 相关的部分注释掉,只在树莓派上真正运行。

(运行代码必须在树莓派上运行)

四、硬件接线

4.1 传感器引脚说明

土壤湿度传感器(YL-69 或 FC-28)有 4 个引脚:

引脚 含义
AO 模拟信号输出(本项目未使用)
DO 数字信号输出(本项目使用)
GND 电源负极
VCC 电源正极

🌱 什么是 DO 引脚? DO 是数字量输出。传感器模块内部有一个比较器,它会将测量的湿度值与一个可调的“阈值”进行比较——湿度高于阈值输出低电平(表示湿润),低于阈值输出高电平(表示干燥)。传感器上的那个蓝色十字旋钮,就是用来调节这个阈值(灵敏度)的。

光敏传感器引脚类似。光照充足时输出低电平,光照不足(变暗)时输出高电平。

💡 传感器原理小科普:电阻式土壤湿度传感器通过两个金属探针检测土壤导电能力。土壤越湿→导电性越好→探针间电阻越小→输出电平发生变化。

继电器模块引脚一般标注为:VCC、GND、IN(信号输入)。

4.2 接线表

本项目中使用的 GPIO 引脚(BCM 编号方式):

硬件 硬件上的引脚 连接到树莓派的 BCM 编号 说明
继电器模块 VCC 5V(物理 2 号) 给继电器内部电路供电
  GND GND(任选) 共地
  IN GPIO27 控制信号(树莓派发指令)
独立电源(给水泵供电) 正极(+) → 继电器的 COM 端子 不直接接树莓派
  负极(-) → 水泵的黑线(负极) 独立回路,不与树莓派共地
水泵 红线(正极) → 继电器的 NO 端子 继电器吸合时水泵得电
  黑线(负极) → 独立电源的负极(-) 形成回路
土壤湿度传感器 VCC 3.3V(物理 1 号) 给传感器供电
  GND GND(任选,与继电器不同孔亦可) 共地
  DO GPIO22 检测湿度(干燥=高电平)
  AO 不接 本项目中不用
光敏传感器 VCC 3.3V(物理 17 号) 给传感器供电
  GND GND(任选) 共地
  DO GPIO26 检测亮度(暗=高电平)

📋 分步详细说明(附文字图示)

1️⃣ 继电器 + 独立电源 + 水泵

text

独立电源(例如12V适配器):
  (+) 正极 ──────→ 继电器 COM 端子
  (-) 负极 ──────→ 水泵 黑线

继电器:
  NO 端子 ──────→ 水泵 红线
  VCC ──────→ 树莓派 物理2号(5V)
  GND ──────→ 树莓派 物理6号(GND)
  IN  ──────→ 树莓派 物理13号(GPIO27)

水泵:
  红线 → 继电器 NO
  黑线 → 独立电源 负极

⚠️ 重要:水泵和树莓派之间没有直接的电连接,树莓派只控制继电器。水泵的电源来自独立电源,不是树莓派的5V。


2️⃣ 土壤湿度传感器

text

土壤传感器模块(通常有4个引脚:VCC、GND、DO、AO):
  VCC → 树莓派 物理1号(3.3V)
  GND → 树莓派 物理9号(GND)
  DO  → 树莓派 物理15号(GPIO22)
  AO  → 不接

💡 传感器上的蓝色电位器可以调节灵敏度:逆时针转到底(最灵敏),然后慢慢顺时针调,直到插入湿土时DO指示灯灭、插入干土时指示灯亮。


3️⃣ 光敏传感器

text

光敏传感器模块(通常3个引脚:VCC、GND、DO):
  VCC → 树莓派 物理17号(3.3V)
  GND → 树莓派 物理14号(GND)
  DO  → 树莓派 物理37号(GPIO26)

💡 光敏模块也有蓝色电位器,调节光线阈值:用手遮住时DO指示灯亮(表示较暗),对着光时指示灯灭(表示明亮)。

五、代码详解(完整版)

5.1 主程序 app.py

 

python

"""
树莓派智慧灌溉系统 - Smart Irrigation System
Flask Web + RPi.GPIO 水泵控制 + 数字传感器
"""

import time
import smtplib
import threading
import logging
from datetime import datetime
from email.mime.text import MIMEText

from flask import Flask, render_template, jsonify, request
import RPi.GPIO as GPIO

# --------------- GPIO 初始化 ---------------
PUMP_PIN = 27          # 水泵控制引脚
MOISTURE_DO_PIN = 22   # 土壤湿度传感器 DO 引脚
LIGHT_DO_PIN = 26      # 光敏传感器 DO 引脚

GPIO.setmode(GPIO.BCM)        # 使用 BCM 引脚编号
GPIO.setwarnings(False)
GPIO.setup(PUMP_PIN, GPIO.OUT)
GPIO.output(PUMP_PIN, GPIO.HIGH)  # 默认关闭(HIGH=关)
GPIO.setup(MOISTURE_DO_PIN, GPIO.IN)
GPIO.setup(LIGHT_DO_PIN, GPIO.IN)

# --------------- Flask 应用 ---------------
app = Flask(__name__)
logging.basicConfig(level=logging.INFO,
                    format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

# =============== 全局状态 ===============
pump_status = False          # 水泵当前状态
auto_mode = True             # 自动/手动模式
soil_dry = True              # 土壤是否干燥(True=干燥)
is_dark = False              # 是否天黑(True=暗)
logs: list[str] = []         # 系统日志
MAX_LOGS = 20

# 储水报警相关
pump_on_time: float | None = None
soil_dry_at_pump_on: bool = True
last_alarm_email_time: float = 0
ALARM_EMAIL_COOLDOWN = 300  # 5分钟


def add_log(msg: str):
    ts = datetime.now().strftime("%H:%M")
    entry = f"[{ts}] {msg}"
    logs.insert(0, entry)
    if len(logs) > MAX_LOGS:
        logs.pop()
    logger.info(entry)


# =============== 水泵控制 ===============
PUMP_ON = GPIO.LOW
PUMP_OFF = GPIO.HIGH


def turn_on_pump():
    global pump_status, pump_on_time, soil_dry_at_pump_on
    if not pump_status:
        GPIO.output(PUMP_PIN, PUMP_ON)
        pump_status = True
        pump_on_time = time.time()
        soil_dry_at_pump_on = soil_dry
        add_log("水泵开启")


def turn_off_pump():
    global pump_status, pump_on_time
    if pump_status:
        GPIO.output(PUMP_PIN, PUMP_OFF)
        pump_status = False
        pump_on_time = None
        add_log("水泵关闭")


# =============== 邮件报警 ===============
def send_alarm_email(reason: str):
    smtp_user = "your_email@qq.com"      # ⚠️ 改成你的QQ邮箱
    smtp_pass = "your_authorization_code" # ⚠️ 改成授权码
    receiver = "your_email@qq.com"

    subject = "智慧灌溉系统报警"
    body = f"报警时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n" \
           f"报警原因:{reason}\n\n" \
           f"系统已自动关闭水泵,请检查储水杯。"

    msg = MIMEText(body, "plain", "utf-8")
    msg["Subject"] = subject
    msg["From"] = smtp_user
    msg["To"] = receiver

    try:
        server = smtplib.SMTP_SSL("smtp.qq.com", 465)
        server.login(smtp_user, smtp_pass)
        server.sendmail(smtp_user, [receiver], msg.as_string())
        server.quit()
        add_log(f"报警邮件已发送: {reason}")
    except Exception as e:
        add_log(f"邮件发送失败: {e}")
python

# =============== 传感器读取 ===============
def read_sensors():
    """读取传感器数字引脚"""
    global soil_dry, is_dark

    while True:
        soil_raw = GPIO.input(MOISTURE_DO_PIN)
        light_raw = GPIO.input(LIGHT_DO_PIN)

        # DO=HIGH 表示干燥,DO=LOW 表示湿润
        soil_dry = (soil_raw == GPIO.HIGH)
        # DO=HIGH 表示暗,DO=LOW 表示亮
        is_dark = (light_raw == GPIO.HIGH)

        if int(time.time()) % 10 == 0:
            logger.info(f"传感器: 土壤DO={soil_raw}, 光照DO={light_raw}, soil_dry={soil_dry}, is_dark={is_dark}")

        time.sleep(1)


# =============== 储水报警检测 ===============
def check_water_alarm():
    global last_alarm_email_time, pump_on_time

    if not pump_status or pump_on_time is None:
        return

    elapsed = time.time() - pump_on_time
    if elapsed >= 30 and soil_dry and soil_dry_at_pump_on:
        reason = f"水泵运行{elapsed:.0f}秒,土壤仍干燥,可能储水杯没水"
        add_log(f"储水报警: {reason}")
        if time.time() - last_alarm_email_time >= ALARM_EMAIL_COOLDOWN:
            last_alarm_email_time = time.time()
            threading.Thread(target=send_alarm_email,
                             args=(reason,), daemon=True).start()
        else:
            add_log("距上次报警不足5分钟,跳过邮件发送")
        pump_on_time = time.time()  # 重置计时


# =============== 自动灌溉主循环 ===============
def auto_irrigation_loop():
    while True:
        check_water_alarm()

        if auto_mode:
            now = datetime.now()
            in_noon = 10 <= now.hour < 15
            bright_in_noon = in_noon and not is_dark

            if soil_dry and not bright_in_noon and not pump_status:
                turn_on_pump()
                add_log("自动开启水泵:土壤干燥")
            elif not soil_dry and pump_status:
                turn_off_pump()
                add_log("土壤湿润,自动关闭水泵")

        time.sleep(1)


# =============== Flask 路由 ===============
@app.route("/")
def index():
    return render_template("index.html")


@app.route("/api/status")
def api_status():
    return jsonify({
        "soil_dry": soil_dry,
        "is_dark": is_dark,
        "pump_status": pump_status,
        "auto_mode": auto_mode,
        "logs": logs[:5],
    })


@app.route("/api/pump", methods=["POST"])
def api_pump():
    global auto_mode
    action = request.json.get("action")

    if action == "on":
        auto_mode = False
        turn_on_pump()
    elif action == "off":
        auto_mode = False
        turn_off_pump()

    return jsonify({"ok": True, "pump_status": pump_status, "auto_mode": auto_mode})


@app.route("/api/mode", methods=["POST"])
def api_mode():
    global auto_mode
    mode = request.json.get("mode")
    auto_mode = (mode == "auto")
    add_log(f"切换为{'自动' if auto_mode else '手动'}模式")
    return jsonify({"ok": True, "auto_mode": auto_mode})


# =============== 启动 ===============
if __name__ == "__main__":
    add_log("系统启动")

    threading.Thread(target=read_sensors, daemon=True).start()
    threading.Thread(target=auto_irrigation_loop, daemon=True).start()

    app.run(host="0.0.0.0", port=5000, debug=False, use_reloader=False)
 

📧 如何获取QQ邮箱授权码

  1. 登录 QQ 邮箱 → 设置 → 账户

  1. 向下滚动找到“POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务”

  1. 开启“IMAP/SMTP服务”,按提示发送短信验证

  2. 系统会生成一串授权码(例如 abcdefghijklmnop),保存好,作为代码中 smtp_pass 使用。

5.2 Web 页面 index.html

html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智慧灌溉系统</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    font-family: -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
    min-height: 100vh; color: #e0e0e0;
  }
  .container { max-width: 960px; margin: 0 auto; padding: 20px; }

  h1 {
    text-align: center; font-size: 1.8rem; padding: 18px 0 6px;
    color: #4fc3f7; letter-spacing: 2px;
  }
  .subtitle { text-align: center; color: #90a4ae; font-size: .85rem; margin-bottom: 24px; }

  /* 卡片样式 */
  .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-bottom: 20px; }
  .card {
    background: rgba(255,255,255,.07); border-radius: 14px;
    padding: 20px; backdrop-filter: blur(6px);
    border: 1px solid rgba(255,255,255,.1);
    transition: transform .2s; text-align: center;
  }
  .card:hover { transform: translateY(-2px); }
  .card-title { font-size: .8rem; color: #90a4ae; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px; }
  .card-value { font-size: 1.6rem; font-weight: 700; }
  .card-value.status-ok   { color: #4caf50; }
  .card-value.status-warn { color: #f44336; }
  .card-value.pump-on     { color: #4caf50; }
  .card-value.pump-off    { color: #f44336; }
  .card-value.auto        { color: #4fc3f7; }
  .card-value.manual      { color: #ff9800; }
  .card-icon { font-size: 2.4rem; margin-bottom: 6px; }

  /* 操作区 */
  .controls {
    background: rgba(255,255,255,.07); border-radius: 14px;
    padding: 20px; margin-bottom: 20px;
    border: 1px solid rgba(255,255,255,.1);
    display: flex; flex-wrap: wrap; gap: 16px; align-items: center; justify-content: center;
  }
  .controls label { font-size: .85rem; color: #b0bec5; }

  .switch { position: relative; display: inline-block; width: 56px; height: 28px; }
  .switch input { opacity: 0; width: 0; height: 0; }
  .slider {
    position: absolute; cursor: pointer; inset: 0;
    background: #ff9800; border-radius: 28px; transition: .3s;
  }
  .slider::before {
    content: ""; position: absolute; height: 22px; width: 22px;
    left: 3px; bottom: 3px; background: #fff; border-radius: 50%; transition: .3s;
  }
  .switch input:checked + .slider { background: #4fc3f7; }
  .switch input:checked + .slider::before { transform: translateX(28px); }

  .btn {
    padding: 10px 24px; border: none; border-radius: 8px;
    font-size: .9rem; font-weight: 600; cursor: pointer;
    transition: .2s; color: #fff;
  }
  .btn:active { transform: scale(.96); }
  .btn-on  { background: #4caf50; }
  .btn-on:hover  { background: #388e3c; }
  .btn-off { background: #f44336; }
  .btn-off:hover { background: #c62828; }

  /* 日志区 */
  .log-section {
    background: rgba(255,255,255,.07); border-radius: 14px;
    padding: 20px; border: 1px solid rgba(255,255,255,.1);
  }
  .log-section h3 { font-size: .9rem; color: #90a4ae; margin-bottom: 12px; }
  .log-list { list-style: none; }
  .log-list li {
    padding: 8px 12px; margin-bottom: 6px; border-radius: 8px;
    background: rgba(255,255,255,.04); font-size: .85rem;
    font-family: "Cascadia Code", "Fira Code", monospace;
    border-left: 3px solid #4fc3f7;
  }
  .log-list li:first-child { animation: fadeIn .4s; }
  @keyframes fadeIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
  .no-log { color: #607d8b; font-size: .85rem; }

  @media (max-width: 600px) {
    .cards { grid-template-columns: 1fr 1fr; }
    .controls { flex-direction: column; }
  }
</style>
</head>
<body>
<div class="container">
  <h1>智慧灌溉系统</h1>
  <p class="subtitle">Raspberry Pi Smart Irrigation</p>

  <div class="cards">
    <div class="card">
      <div class="card-title">土壤湿度</div>
      <div class="card-icon" id="soilIcon">--</div>
      <div class="card-value" id="soilVal">--</div>
    </div>
    <div class="card">
      <div class="card-title">光照状态</div>
      <div class="card-icon" id="lightIcon">--</div>
      <div class="card-value" id="lightVal">--</div>
    </div>
    <div class="card">
      <div class="card-title">水泵状态</div>
      <div class="card-icon" id="pumpIcon">--</div>
      <div class="card-value" id="pumpVal">--</div>
    </div>
  </div>

  <div class="controls">
    <label>模式切换</label>
    <span id="modeLabel" style="min-width:36px; font-weight:600;">手动</span>
    <label class="switch">
      <input type="checkbox" id="modeSwitch" checked>
      <span class="slider"></span>
    </label>
    <button class="btn btn-on"  id="btnOn">开启水泵</button>
    <button class="btn btn-off" id="btnOff">关闭水泵</button>
  </div>

  <div class="log-section">
    <h3>系统日志(最近 5 条)</h3>
    <ul class="log-list" id="logList">
      <li class="no-log">暂无日志...</li>
    </ul>
  </div>
</div>

<script>
const $ = id => document.getElementById(id);

async function poll() {
  try {
    const r = await fetch("/api/status");
    const d = await r.json();

    // 土壤
    if (d.soil_dry) {
      $("soilIcon").textContent = "🚨";
      $("soilVal").textContent = "干燥";
      $("soilVal").className = "card-value status-warn";
    } else {
      $("soilIcon").textContent = "🌿";
      $("soilVal").textContent = "湿润";
      $("soilVal").className = "card-value status-ok";
    }

    // 光照
    if (d.is_dark) {
      $("lightIcon").textContent = "🌙";
      $("lightVal").textContent = "较暗";
      $("lightVal").className = "card-value status-warn";
    } else {
      $("lightIcon").textContent = "☀️";
      $("lightVal").textContent = "明亮";
      $("lightVal").className = "card-value status-ok";
    }

    // 水泵
    if (d.pump_status) {
      $("pumpIcon").textContent = "💧";
      $("pumpVal").textContent = "运行中";
      $("pumpVal").className = "card-value pump-on";
    } else {
      $("pumpIcon").textContent = "⛔";
      $("pumpVal").textContent = "已关闭";
      $("pumpVal").className = "card-value pump-off";
    }

    $("modeSwitch").checked = d.auto_mode;
    updateModeLabel(d.auto_mode);

    const logList = $("logList");
    if (d.logs.length === 0) {
      logList.innerHTML = '<li class="no-log">暂无日志...</li>';
    } else {
      logList.innerHTML = d.logs.map(l => `<li>${esc(l)}</li>`).join("");
    }
  } catch (e) {
    console.error("poll error", e);
  }
}

function esc(s) {
  const d = document.createElement("div");
  d.textContent = s;
  return d.innerHTML;
}

function updateModeLabel(auto) {
  $("modeLabel").textContent = auto ? "自动" : "手动";
  $("modeLabel").style.color = auto ? "#4fc3f7" : "#ff9800";
}

$("modeSwitch").addEventListener("change", async function () {
  const mode = this.checked ? "auto" : "manual";
  await fetch("/api/mode", {
    method: "POST",
    headers: {"Content-Type": "application/json"},
    body: JSON.stringify({mode})
  });
  poll();
});

$("btnOn").addEventListener("click", async () => {
  await fetch("/api/pump", {
    method: "POST",
    headers: {"Content-Type": "application/json"},
    body: JSON.stringify({action: "on"})
  });
  poll();
});

$("btnOff").addEventListener("click", async () => {
  await fetch("/api/pump", {
    method: "POST",
    headers: {"Content-Type": "application/json"},
    body: JSON.stringify({action: "off"})
  });
  poll();
});

setInterval(poll, 1000);
poll();
</script>
</body>
</html>

5.3 代码逻辑解读

核心工作流程:

  1. 传感器线程(read_sensors) 每隔 1 秒读取土壤湿度和光照状态,更新全局变量 soil_dry 和 is_dark

  2. 自动灌溉线程(auto_irrigation_loop) 循环判断自动模式下土壤状态和光照条件,决定水泵的开启或关闭

  3. 储水报警检测(check_water_alarm) 水泵持续运行 30 秒后如果土壤仍然干燥,触发邮件报警

  4. Flask Web 服务 提供 /api/status 和 /api/pump/api/mode 三个 API,前端每秒轮询刷新数据

🧠 BCM 与 BOARD 的区别:BCM 编号对应 Broadcom 芯片的 GPIO 通道号(如 GPIO27),而 BOARD 编号对应物理引脚位置(如物理第 13 脚)。本项目使用 GPIO.BCM 模式。

六、项目文件部署

6.1 创建项目文件夹

bash

mkdir ~/smart_irrigation
cd ~/smart_irrigation

6.2 创建文件

bash

 

nano python      # 粘贴上面 Python 代码
粘贴到这个里面,按ctrl o保存这个文件以及给这个文件起名,然后ctrl x退出文件
mkdir templates    (创建名为templates的文件夹)
nano templates/index.html   # 粘贴上面 HTML 代码

复制粘贴需要一个工具(把自己电脑上的文件传输到树莓派本机)

这个是网址:https://filezilla-project.org/download.php?type=client

直接下载安装即可

直接打开的它里面的字体是乱码(就是别的格式),所以我们的要选格式(这个是我之前传输的文件,不是本次项目的)

这样这个文件好了

📁 注意:index.html 务必放在 templates 文件夹中,因为 Flask 默认在这个位置查找模板文件。

6.3 修改邮箱配置

打开 app.py 找到以下两行:

python

smtp_user = "your_email@qq.com"
smtp_pass = "your_authorization_code"

替换成你的 QQ 邮箱和授权码(不是 QQ 密码)。

6.4 运行

bash

python3 app.py

控制台会显示类似 Running on http://0.0.0.0:5000 的信息。

同一局域网下,手机或电脑浏览器打开 http://树莓派IP:5000 即可。

七、开机自启(systemd)[能运行且能看到数据下面不用看,但是不行的话试一下这些]

想要系统一启动就自动运行 Web 程序,通过 systemd 注册为 Linux 服务即可实现。树莓派重启后无需人工干预,灌溉系统自动启动。

7.1 创建工作目录并放置代码

bash

sudo mkdir -p /opt/smart_irrigation
sudo cp ~/smart_irrigation/app.py /opt/smart_irrigation/
sudo cp -r ~/smart_irrigation/templates /opt/smart_irrigation/

7.2 创建服务文件

bash

sudo nano /etc/systemd/system/smart_irrigation.service

写入以下内容:

ini

[Unit]
Description=Smart Irrigation System
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/opt/smart_irrigation
ExecStart=/usr/bin/python3 /opt/smart_irrigation/app.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

7.3 启用服务

bash

sudo systemctl daemon-reload
sudo systemctl enable smart_irrigation
sudo systemctl start smart_irrigation
sudo systemctl status smart_irrigation   # 检查状态

状态显示 active (running) 即成功。

查看实时日志:

bash

sudo journalctl -u smart_irrigation -f

重启树莓派验证:sudo reboot

 

 

如果遇到其他问题,欢迎在评论区留言,我看到都会尽力解答!

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐