ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ESP32+Flask实现智能农业自动灌溉系统实战

ESP32+Flask实现智能农业自动灌溉系统实战 分享一个很有意思的农业智能化场景当园区里的大部分机械设备和自动化装置“不需要天天有人操作”这套系统依然能通过环境数据感知、自动灌溉和远程告警让作物“不靠人工照看也能正常生长”。这种思路不只是停留在概念阶段而是可以用常见的嵌入式硬件加 Web 服务完整落地。本文会从原理、硬件选型到代码逐步展开属于物联网与农业自动化结合的入门级实战教程。适合正在学习物联网开发、Python Web 开发或者对智能农业感兴趣的同学。读完这篇文章后你能独立搭建一套带自动灌溉、环境监测和远程告警的水培种植系统也能理解设备端与服务端之间是如何协作的。1. 背景与核心概念1.1 什么是“机械人不上班照样能吃饱饭”这句话可以从两个层面理解。第一层是字面意思农业机械设备本身不需要像人一样“打卡上班”电力充足、程序跑起来之后它就能持续工作只要控制系统稳定设备就可以在夜间、节假日、无人值守时自动调节灌溉、补光、通风。第二层是引申含义系统具备“自主决策”能力。这里的“自主决策”不一定是多复杂的 AI 算法更多是指基于阈值判断和传感数据闭环让设备在没有人到场的情况下也能完成浇水、施肥、温湿度调节这些基础农事操作。因此这类系统的核心价值不是完全替代人而是把重复性、规律性的操作交给自动化装置让人从“守在大棚里盯着”变成“有异常才介入”。这样一来即使园区的常规劳动力减少作物也依然能被照顾得很好。1.2 自动化种植解决了什么问题传统种植中浇水、施肥、光照管理依赖人的经验对新手来说容易出现几个问题浇水量不好控制水多了容易沤根水少了叶片萎蔫。临时出差或外出植物无人照看。凭感觉施肥容易造成肥害或者营养不良。环境变化不能及时感知等发现异常时作物已经受害。自动水培监测系统通过传感器采集土壤湿度、空气温湿度、光照强度等数据用继电器控制水泵、补光灯、风扇再结合后端 Web 平台记录历史数据让种植过程变成果断执行的控制逻辑。1.3 常见应用场景这类系统的应用范围很广不只是“阳台种菜”这么简单小型植物工厂多层水培架自动循环营养液。家庭阳台种植自动补水和补光出差也能远程查看状态。农业大棚控制卷帘、风机、水帘等设备。科研实验记录不同环境下作物生长差异。教育演示适合物联网课程教学和课程设计。1.4 系统整体架构下面的 ASCII 图展示了系统各部分的连接关系[传感器] DHT11 土壤湿度 光敏传感器 | v [ESP32 开发板] -- 运行 MicroPython / Arduino 固件 | | Wi-Fi v [后端服务] Python Flask/Django MySQL/SQLite | | Web 页面 v [浏览器 / 手机] 查看数据、手动控制、接收告警逻辑上分成三层感知层传感器负责采集环境数据。控制层ESP32 负责读取数据并根据阈值控制继电器。应用层后端服务负责记录数据、展示图表、发送告警。2. 环境准备与版本说明2.1 硬件准备在开始之前我们需要准备好以下硬件名称型号数量说明主控板ESP32 DevKitC 或 NodeMCU-32S1自带 Wi-Fi适合物联网温湿度传感器DHT11 或 DHT221测量空气温度与湿度土壤湿度传感器电容式土壤湿度模块1测量基质或土壤含水量光敏传感器光敏电阻模块或 BH17501检测光照强度继电器模块单路或双路继电器2控制水泵和补光灯小型水泵直流 3.3V 或 5V 潜水泵1用于自动灌溉LED 补光灯植物补光灯或任意 LED 灯带1模拟补光电源5V/2A USB 电源1给开发板供电杜邦线公对公、公对母若干连接线路面包板面包板1搭建电路原型DHT11 精度较低但便宜适合学习验证DHT22 精度更高适合实际种植环境。土壤湿度传感器建议选电容式这类传感器不容易被电解腐蚀使用寿命更长。2.2 软件准备软件方面我建议按下面的组合来安装Python 3.8 或以上版本用于编写后端服务。Flask 或 Django本文示例使用 Flask轻量易上手。MicroPython 固件刷入 ESP32 开发板。一个串口终端工具比如 Putty 或 VS Code 里的 Serial Monitor。数据库使用 SQLite零配置适合教学演示。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.3 开发板刷写 MicroPython新买的 ESP32 通常不带 MicroPython 固件。我们可以先用esptool.py擦除与烧录。安装 esptoolpip install esptool先按着开发板上的 BOOT 键再插入 USB然后运行esptool.py --port COM3 erase_flash注意Windows 端口名可能是COM3或COM4macOS 和 Linux 下通常是/dev/ttyUSB0或/dev/tty.usbserial-xxxx。烧录固件esptool.py --chip esp32 --port COM3 write_flash -z 0x1000 esp32-20220117-v1.18.bin这里的固件文件名需要改成你实际下载的版本。烧录完成后打开串口终端设置波特率 115200就能看到 MicroPython 的交互提示符。2.4 后端运行环境为了快速验证我们可以在项目根目录创建一个虚拟环境python -m venv venv激活虚拟环境Windowsvenv\Scripts\activateLinux/macOSsource venv/bin/activate然后安装依赖pip install flask flask-cors pymysql requests如果你不想用 MySQL可以先用 SQLite后面再迁移。3. 核心语法、配置或原理拆解3.1 传感器数据读取原理传感器本质上把物理量转换成电信号。例如 DHT11 通过单总线协议输出数字信号ESP32 通过 GPIO 读取时序波形来解析温湿度数据。在用 MicroPython 时我们可以直接编写一个简单的 DHT 读取方法from machine import Pin import dht dht_sensor dht.DHT11(Pin(4)) def read_dht(): try: dht_sensor.measure() temp dht_sensor.temperature() humi dht_sensor.humidity() return temp, humi except OSError as e: print(读取失败, e) return None, None需要注意的是DHT11 的采样间隔建议大于 1 秒频繁读取容易造成传感器无响应。3.2 阈值控制逻辑自动控制不需要复杂的 PID 算法对大多数家庭种植场景来说阈值控制就够了。所谓的阈值控制就是设置上限和下限当超过或低于目标值时执行对应动作。一个简单的逻辑如下SOIL_DRY 40 PUMP_GPIO 15 if soil_value SOIL_DRY: relay_pin.value(1) # 开启水泵 time.sleep(5) # 持续浇水 5 秒 relay_pin.value(0) # 关闭水泵这种策略的核心是“死区控制”简单可靠但不太适合精确调节营养液浓度。如果需要更平滑的控制后续可以引入 PID 或模糊控制不过对入门项目来说阈值控制已经能解决 80% 的问题。3.3 Wi-Fi 连接与数据上报ESP32 连接 Wi-Fi 后可以使用urequests库向后端发送 HTTP 请求。示例代码如下import network import urequests def connect_wifi(ssid, password): station network.WLAN(network.STA_IF) station.active(True) if not station.isconnected(): station.connect(ssid, password) while not station.isconnected(): time.sleep(1) return station def report_data(data): url http://你的服务器IP:5000/api/upload headers {Content-Type: application/json} response urequests.post(url, jsondata, headersheaders) response.close()这里不推荐在程序里频繁使用同步urequests因为网络阻塞会影响控制响应。但作为入门示例这种写法最容易理解。3.4 后端接口设计后端服务提供两个核心接口/api/upload接收设备上报的环境数据。/api/statusWeb 前端查询最新数据和设备状态。我们可以再用一个/api/control接口实现手动控制让用户在页面上点击“开泵”和“关泵”。3.5 数据库表设计建表不需要太复杂一张环境数据表加一张控制记录表即可。以 MySQL 或 SQLite 为例CREATE TABLE sensor_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, temp REAL NOT NULL, humi REAL NOT NULL, soil INTEGER NOT NULL, light INTEGER NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP );这样的表结构已经可以支撑日常查询、画趋势图、生成日报等功能。4. 完整实战案例下面我们完整搭建一个“ESP32 Flask”自动水培监测系统。4.1 创建项目结构建议先创建如下目录结构auto-plant/ ├── device/ │ └── main.py # ESP32 设备端程序 ├── server/ │ ├── app.py # Flask 后端服务 │ ├── requirements.txt │ └── plant.db # SQLite 数据库自动生成 └── web/ └── index.html # 前端展示页面可选这里的device/main.py是写入 ESP32 的 MicroPython 代码server/app.py是运行在电脑或云服务器上的 Flask 服务。4.2 编写 ESP32 设备端代码将下面的代码保存为main.py上传到 ESP32 开发板。# 文件路径device/main.py import time import network import urequests from machine import Pin, ADC import dht # 配置区 WIFI_SSID 你的WiFi名称 WIFI_PASSWORD 你的WiFi密码 SERVER_URL http://你的服务器IP:5000/api/upload # 引脚定义 DHT_PIN Pin(4) SOIL_PIN ADC(Pin(34)) LIGHT_PIN ADC(Pin(35)) RELAY_PUMP Pin(15, Pin.OUT) RELAY_LIGHT Pin(16, Pin.OUT) # 初始化 dht_sensor dht.DHT11(DHT_PIN) SOIL_PIN.atten(ADC.ATTN_11DB) LIGHT_PIN.atten(ADC.ATTN_11DB) RELAY_PUMP.value(0) RELAY_LIGHT.value(0) # 连续读取次数用于滤波 SAMPLES 5 def connect_wifi(): station network.WLAN(network.STA_IF) station.active(True) if not station.isconnected(): print(正在连接Wi-Fi...) station.connect(WIFI_SSID, WIFI_PASSWORD) while not station.isconnected(): time.sleep(1) print(连接成功IP地址:, station.ifconfig()[0]) def read_soil(): values [] for _ in range(SAMPLES): values.append(SOIL_PIN.read()) time.sleep(0.1) return sum(values) // len(values) def read_light(): values [] for _ in range(SAMPLES): values.append(LIGHT_PIN.read()) time.sleep(0.1) return sum(values) // len(values) def auto_control(soil, temp): # 土壤湿度阈值数值越小代表越干需要根据不同传感器校准 if soil 800: print(土壤偏干开启水泵5秒) RELAY_PUMP.value(1) time.sleep(5) RELAY_PUMP.value(0) if temp 35: print(温度偏高打开风扇或降低光照强度) RELAY_LIGHT.value(1) else: RELAY_LIGHT.value(0) def report(temp, humi, soil, light): try: payload { temp: temp, humi: humi, soil: soil, light: light } headers {Content-Type: application/json} response urequests.post(SERVER_URL, jsonpayload, headersheaders) print(上报结果:, response.status_code) response.close() except Exception as e: print(上报失败:, e) def main(): connect_wifi() while True: try: dht_sensor.measure() temp dht_sensor.temperature() humi dht_sensor.humidity() except OSError as e: print(DHT读取失败跳过本轮) temp 0 humi 0 soil read_soil() light read_light() print(温度: {}°C, 湿度: {}%, 土壤: {}, 光照: {}.format( temp, humi, soil, light )) auto_control(soil, temp) report(temp, humi, soil, light) time.sleep(30) if __name__ __main__: main()代码说明土壤湿度读取采用多次采样取平均值减少传感器波动。自动控制逻辑写在auto_control函数中方便修改策略。数据每 30 秒上报一次避免频繁请求给服务器造成压力。DHT11 读取失败时跳过本轮以免程序崩溃。4.3 编写 Flask 后端服务在server/app.py中编写后端服务。# 文件路径server/app.py from flask import Flask, request, jsonify, render_template_string import sqlite3 import time app Flask(__name__) DB_PATH plant.db def init_db(): conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( CREATE TABLE IF NOT EXISTS sensor_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, temp REAL NOT NULL, humi REAL NOT NULL, soil INTEGER NOT NULL, light INTEGER NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ) conn.commit() conn.close() app.route(/api/upload, methods[POST]) def upload(): data request.get_json() temp data.get(temp) humi data.get(humi) soil data.get(soil) light data.get(light) if temp is None or humi is None or soil is None or light is None: return jsonify({code: 1, msg: 参数不完整}), 400 conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( INSERT INTO sensor_data (temp, humi, soil, light) VALUES (?, ?, ?, ?), (temp, humi, soil, light) ) conn.commit() conn.close() return jsonify({code: 0, msg: ok}) app.route(/api/status, methods[GET]) def status(): conn sqlite3.connect(DB_PATH) cursor conn.cursor() cursor.execute( SELECT temp, humi, soil, light, create_time FROM sensor_data ORDER BY id DESC LIMIT 10 ) rows cursor.fetchall() conn.close() if not rows: return jsonify({code: 0, data: []}) result [] for row in rows: result.append({ temp: row[0], humi: row[1], soil: row[2], light: row[3], create_time: row[4] }) return jsonify({code: 0, data: result}) app.route(/, methods[GET]) def index(): return render_template_string( !DOCTYPE html html head title自动水培监控系统/title meta charsetutf-8 /head body h2自动水培监控系统/h2 p设备上报数据后这里会展示最近10条记录。/p pre iddata/pre script fetch(/api/status) .then(res res.json()) .then(data { document.getElementById(data).innerText JSON.stringify(data, null, 2); }); /script /body /html ) if __name__ __main__: init_db() app.run(host0.0.0.0, port5000, debugTrue)Flask 默认监听 127.0.0.1这里设置host0.0.0.0是为了让局域网内的 ESP32 或手机都能访问。4.4 运行与验证启动后端服务cd server python app.py启动成功后控制台会显示* Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:5000把device/main.py中 WiFi 和服务器地址改成实际值上传到 ESP32。打开浏览器访问http://127.0.0.1:5000可以看到最新的设备上报数据。观察 ESP32 串口输出应该能看到类似内容温度: 26°C, 湿度: 58%, 土壤: 620, 光照: 2100 上报结果: 2004.5 结果说明到这里整套系统已经跑通ESP32 每隔 30 秒采集一次环境数据。数据通过 Wi-Fi 上报到 Flask 服务。服务端把数据存入 SQLite 数据库。用户可以通过浏览器查看最近的状态记录。控制逻辑会在土壤偏干时自动打开水泵补水 5 秒后关闭。这套流程的核心价值在于即使没有人在现场“确定性的控制策略”让设备独立完成了一次灌溉决策。5. 常见问题与排查思路在实际部署过程中最容易遇到下面几个问题。5.1 ESP32 无法连接 Wi-Fi问题现象常见原因解决思路串口打印反复出现“正在连接Wi-Fi”密码错误、Wi-Fi 频段不兼容、信号弱检查 SSID 和密码确认路由器是否为 2.4GHz靠近路由器重试连接后不久掉线电源供电不足换成 5V/2A 稳定电源避免使用劣质 USB 线ESP32 部分开发板只支持 2.4GHz Wi-Fi如果路由器开了 5GHz 和 2.4GHz 双频合一建议在开发测试阶段单独开启一个 2.4GHz 热点。5.2 传感器读数一直不变问题现象常见原因解决思路土壤湿度读数始终是最大值或最小值引脚配置错误、传感器接线松动检查 ADC 引脚是否可读换一个引脚重试温湿度读到 0 或异常值DHT11 供电电压不稳、数据线过长给传感器独立供电缩短接线距离检查上拉电阻ADC 引脚在读取模拟传感器时需要配置atten(ADC.ATTN_11DB)否则输入电压范围默认很小读数结果会异常。5.3 继电器不动作问题现象常见原因解决思路代码执行了value(1)但继电器不响继电器高电平触发/低电平触发搞反先查模块规格书将value(1)改为value(0)测试开发板复位后继电器误动作GPIO 默认电平不确定初始化阶段显式把继电器引脚设为 0继电器模块建议使用光耦隔离版本板载信号指示灯的型号更方便排查。5.4 后端接口 404 或 500问题现象常见原因解决思路访问/api/upload返回 404路由写错或服务未重启检查 URL 是否拼写正确重启 Flask 服务返回 500数据库表未创建手动执行init_db()或检查数据库路径权限5.5 设备端上报失败问题现象常见原因解决思路打印“上报失败”服务器地址不可达ESP32 与电脑连同一个局域网检查防火墙是否允许 5000 端口上报很慢DNS 解析或网络延迟直接用 IP 地址代替域名减少 DNS 查询如果服务器部署在云主机需要到云控制台的安全组放行 5000 端口并确认服务监听了0.0.0.0。6. 最佳实践与工程建议6.1 硬件层面传感器供电和继电器供电尽量独立避免电机启动瞬间拉低电压导致开发板复位。水泵必须放在低处且保证进水口浸没在水中防止空转烧毁。接线使用不同颜色区分正负极并在关键节点做标记。长期使用场景中定期校准土壤湿度传感器因为湿润环境会让电极状态漂移。6.2 软件层面控制逻辑要设置“手动模式”和“自动模式”的切换开关方便调试。水泵每次开启时间不要太长建议在程序里加上最大运行时长限制防止传感器故障时一直浇水。上报数据增加设备 ID 字段方便未来接入多个设备。传感器读取失败要重试而不是直接跳过否则容易造成控制策略误判。不要在生产环境使用 Flask 自带服务器稳定性不够建议改用 Gunicorn 或 uWSGI。6.3 数据层面记录数据时应该一并记录设备状态、控制动作和操作人方便追溯。定期清理旧数据避免 SQLite 表无限膨胀。如果数据需要长期分析建议从 SQLite 迁移到 MySQL 或 TimescaleDB。6.4 安全与可靠性设备端上报接口不需要暴露到公网时尽量只在局域网内部访问。如果必须远程访问不要直接开放数据库端口建议通过后端 API 加简单 Token 鉴权。涉及自动灌溉的代码要谨慎处理液位传感器没有液位数据时不要盲目启动水泵。任何涉及实际生产环境的变更都应该先在测试设备上验证再上真实种植场景。6.5 控制策略升级阈值控制是第一步。如果希望系统更智能可以逐步引入分段式灌溉根据一天中的不同时段调整干湿阈值。模糊控制把温湿度、土壤湿度组合成模糊规则表。PID 控制用在营养液 EC 值调节等需要稳定控制的场景。简单预测结合未来几小时的天气预报决定是否提前补水。这些升级方向都不需要推翻现有架构只需要调整服务端策略模块。7. 总结与学习路线通过这套实战案例你已经掌握了一条完整的物联网应用链路从传感器采集数据、ESP32 上报数据到 Flask 后端接收存储再到浏览器展示数据。同时你也理解了阈值控制在自动化种植中的应用价值。下一步可以往这几个方向继续深入学习 MQTT 协议用 EMQX 或 Mosquitto 取代 HTTP 上报降低设备功耗提升实时性。学习 Vue 或 React做一个更美观的数据大屏。学习 Docker 部署把后端打包成容器镜像方便迁移到云服务器。学习 PID 控制算法应用到营养液循环系统中。接入摄像头利用图像识别判断作物生长状态真正做到“不用人看也能知道长得好不好”。自动化种植的难点往往不在硬件本身而在于对环境变化的准确感知和可靠控制。建议你在真实环境中多跑几天收集数据再根据数据调整灌溉阈值。每一次控制记录的积累都是后续优化策略的基础。如果这篇文章对你有帮助欢迎收藏备用。实际搭建过程中遇到其他报错也可以顺着接口、数据库、网络三个方向逐层排查。设备没反应就先看串口接口不对就先看日志数据没进来就先看数据库大多数问题都能用这套思路快速定位。
返回列表