IoT for Beginners:基于继电器与 MQTT 的自动植物浇水系统——含传感器/执行器时序控制实现
IoT for Beginners基于继电器与 MQTT 的自动植物浇水系统——含传感器/执行器时序控制实现【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本文基于 IoT for Beginners 仓库中 Farm 项目第 3 课Automated Plant Watering展开系统讲解如何用 3.3V/5V 的 IoT 开发板通过继电器驱动水阀与水泵、如何用 MQTT 将控制逻辑从设备端集中到服务端以及最重要的工程问题——传感器与执行器之间的响应延迟如何建模并用 Python 线程在服务端实现泵水 5 秒 → 等待 20 秒 → 复测的完整浇水循环。读完本文你可以从零搭建一套可复测、可校准、节水可靠的自动灌溉原型。课程定位与学习路线本课是 Farm 项目数字农业系列的第三课承接上一课土壤湿度监测的soil-moisture-sensor项目在此基础上构建一个自动浇水系统的核心部件。课程覆盖五个知识点从低电流 IoT 设备控制高电流设备继电器原理在 Wio Terminal / Raspberry Pi / 虚拟设备三种硬件上驱动继电器通过 MQTT 集中化控制植物浇水遥测上行 命令下行传感器与执行器的时序timing问题建模在服务端代码中实现带时序的浇水循环。本课各阶段的可运行参考代码分别位于 code-relay、code-mqtt、code-timing 三个目录中。从低电流 IoT 设备控制高电流设备IoT 设备通常只能输出 3.3V 或 5V、且电流不超过 1A。这足以驱动传感器和 LED 这类低电流执行器但对于浇花用的水泵来说远远不够——即使是最小的家用盆栽泵电流也会超出开发板能力直接供电会烧毁主板的供电电路。解决方案与家用电灯开关完全同构把高功率负载接在外部电源上用执行器而非开发板本身去接通外部电源。手指按动开关只需极少的能量却能让 230V 电网中的灯亮起。IoT 设备扮演的正是手指的角色。两者量级对比供电来源典型电压可驱动电流IoT 开发板GPIO3.3V / 5V 1A家用电网230V北美 120V、日本 100V数十安培单条支路常见 30A在多种可用的手指替代品中最流行的是继电器relay——一种把电信号转换为机械动作、从而接通/断开外部电路的执行器。继电器的工作原理继电器的核心是一个电磁铁电流通过导线线圈时线圈被磁化断电后磁性消失。工作过程分为两个状态吸合on控制电路给电磁铁通电磁场拉动衔铁arm触点闭合外部负载电路如水泵回路导通释放off控制电路断电磁场消失衔铁弹回触点断开负载电路断开。继电器是典型的数字执行器输入高电平即吸合低电平即释放。控制电路只需很少的电流就能驱动电磁铁因此可以直接由 IoT 开发板的 3.3V/5V GPIO 控制而负载电路output circuit能承载多大的电流完全取决于继电器本身的规格。图继电器吸合后指示灯点亮水泵启动并给草莓植株供水图源课程演示动画。实际接线时需要注意负载回路的走向。课程使用 Grove 继电器模块其负载回路有两个端子一个可以是电源、一个是地可承载 250V / 10A的输出——足够驱动多种市电设备。以课程中的 5V 水泵为例一根红线从 USB 电源的 5V 接到负载回路的一个端子另一根红线从负载回路的另一个端子接到水泵黑线从水泵接回电源地。继电器吸合时回路导通水泵即获得 5V 供电启动。图水泵经继电器接在外部 5V 电源上IoT 开发板只控制继电器的控制电路。两个工程细节值得记住继电器动作时会伴随清晰的咔哒声触点与衔铁的低频机械接触这是判断继电器是否正常工作的最直观信号继电器也可做成**换向changeover**形态衔铁动作时不是简单的通/断而是把公共端从一路输出切换到另一路输出。课程使用的 Grove 继电器是常开normally-open型即无信号时输出回路断开。实操在三类硬件上驱动继电器课程的第一个任务是把上一课的soil-moisture-sensor项目扩展为土壤湿度 450 时打开继电器。注意电容式土壤湿度传感器的读数特性读数越低表示土壤越湿润越高表示越干燥因此大于 450对应太干、需要浇水。Wio TerminalArduino 平台Grove 继电器为数字执行器插入 Wio Terminal 左侧的 Grove 口该口是 I2C/数字复用口口线编号为PIN_WIRE_SCL右侧 Grove 口留给土壤湿度传感器模拟口。参考 Wio Terminal 继电器操作指南核心代码只有三步// setup() 中把 I2C/数字复用口配置为输出 pinMode(PIN_WIRE_SCL, OUTPUT); // loop() 中根据湿度控制继电器 if (soil_moisture 450) { Serial.println(Soil Moisture is too low, turning relay on.); digitalWrite(PIN_WIRE_SCL, HIGH); // 高电平 吸合 } else { Serial.println(Soil Moisture is ok, turning relay off.); digitalWrite(PIN_WIRE_SCL, LOW); // 低电平 释放 }完整工程见 code-relay/wio-terminal 源码其中loop()每 10 秒读取一次analogRead(A0)并做出开关判断。首次上电可用digitalWrite(..., HIGH); delay(500); digitalWrite(..., LOW);验证继电器每 10 秒咔哒一次。Raspberry PiPython 平台Pi 上通过 Grove Base Hat 的D5数字口接继电器土壤湿度传感器仍在 A0 口使用 Grove Python 库。参考 Raspberry Pi 继电器操作指南from grove.grove_relay import GroveRelay relay GroveRelay(5) # 绑定 D5 口 if soil_moisture 450: print(Soil Moisture is too low, turning relay on.) relay.on() else: print(Soil Moisture is ok, turning relay off.) relay.off()虚拟设备CounterFit没有硬件时可以用 CounterFit 虚拟设备完成同样的实验在 Actuators 面板中选择 Relay、Pin 设为 5 添加代码上把库换成 shim 版本即可与真实 Pi 代码几乎一致from counterfit_shims_grove.grove_relay import GroveRelay relay GroveRelay(5)参考 虚拟设备继电器操作指南。三类硬件的完整代码分别在 code-relay/pi、code-relay/virtual-device 目录下。通过 MQTT 集中控制浇水逻辑直接由设备判断湿度 450 就开泵只适合单点实验。在真实的商业灌溉系统中控制逻辑必须集中化它要综合多个传感器的数据做决策而且配置变更只需在一个地方完成。本课通过 MQTT 模拟这一架构设备端client接入 MQTT broker客户端 ID 命名为你的IDsoilmoisturesensor_clientMQTT 接入细节可回看 项目 1 第 4 课发布遥测消息属性名固定为soil_moisture主题id/telemetry每 10 秒一次。设备端参考实现code-mqtt/pi 版本id ID client_telemetry_topic id /telemetry server_command_topic id /commands client_name id soilmoisturesensor_client mqtt_client mqtt.Client(client_name) mqtt_client.connect(test.mosquitto.org) mqtt_client.loop_start() def handle_command(client, userdata, message): payload json.loads(message.payload.decode()) if payload[relay_on]: relay.on() else: relay.off() mqtt_client.subscribe(server_command_topic) mqtt_client.on_message handle_command while True: soil_moisture adc.read(0) mqtt_client.publish(client_telemetry_topic, json.dumps({soil_moisture: soil_moisture})) time.sleep(10)服务端server新建soil-moisture-sensor-server项目订阅遥测主题并下行命令客户端 ID 为你的IDsoilmoisturesensor_server命令消息的属性名固定为relay_on布尔值主题id/commands判定逻辑与之前一致soil_moisture 450则relay_on true否则false。服务端参考实现code-mqtt/server/app.pydef handle_telemetry(client, userdata, message): payload json.loads(message.payload.decode()) command { relay_on : payload[soil_moisture] 450 } client.publish(server_command_topic, json.dumps(command)) mqtt_client.subscribe(client_telemetry_topic) mqtt_client.on_message handle_telemetry测试方法运行设备与服务端两个程序改变湿度虚拟设备直接改传感器数值真实设备加水或把传感器拔出土壤观察继电器随命令动作。完整的 MQTT 版代码含 Wio Terminal / 虚拟设备版本在 code-mqtt 目录。传感器与执行器时序浇水系统最容易被忽略的工程问题这是本课的技术核心。回顾第一课的夜灯光照传感器对光照变化即时响应反馈回路几乎无延迟。但土壤湿度完全不同——上一课中如果你真实浇过水会注意到湿度读数是过几秒后才开始下降的。这并非传感器慢而是水渗过土壤本身需要时间。课程给出的典型观测某次测量值为 658 时开始浇水读数并不立即变化因为水还没有到达传感器浇水结束时水仍在途中之后读数才下跌到 320反映新的湿度水平。如果把传感器正对着浇水点还可能看到读数先快速下跌又回升——水先润湿传感器周边、再向整盆土壤扩散稀释。这意味着如果照搬夜灯式的简单逻辑——读数 450 就开泵回到 450 就关泵——传感器在 450 处关泵时已经在途的水还会继续下渗最终土壤被过湿既浪费水资源又可能造成烂根对植物而言水多和水少同样致命。正确的建模方式是承认存在一个执行器动作到被测属性变化之间的延迟因此控制循环必须包含两段等待图一次完整的浇水循环——第 1 步测量、第 2 步加水、第 3 步等待水渗透、第 4 步复测。由此得到基础浇水策略打开水泵 5 秒等待 20 秒让水渗透、读数稳定——课程作者实测自己的草莓植株约需 20 秒复测土壤湿度若仍高于目标值重复上述步骤。其中 5 秒是保守值宁可少浇一点再补浇也不能让水留在土里收不回来。更进一步最佳时序泵 5 秒、等 20 秒并非理论推导而是实测校准的产物——先跑起来拿到传感器数据后用持续反馈回路不断调整甚至可以做比例控制例如每高出目标值 100 就多泵 1 秒。课程还提出了两个延伸思考一天中是否存在适合/不适合浇水的时段室外种植是否应接入天气预报在下雨前暂停自动浇水——这些正是把能跑的原型推向生产系统时需要回答的问题。实操在服务端实现带时序的浇水循环服务端控制逻辑新的服务端逻辑变为收到遥测消息检查土壤湿度若正常则什么都不做若过高土壤过干执行下发命令打开继电器等待 5 秒water_time下发命令关闭继电器再等待 20 秒wait_time让湿度稳定。重叠问题10 秒遥测 vs 25 秒浇水周期一个完整的浇水周期耗时约 25 秒而设备每 10 秒发布一条遥测——服务器在等待稳定期间仍会收到新的遥测可能触发第二次浇水周期。课程给出两种规避方案让设备改为每分钟才发一次遥测使下一周期必然发生在下一消息之前浇水周期内取消遥测订阅周期结束后重新订阅。第一种方案在大规模农场中未必合适农民可能正希望记录浇水过程中的湿度变化用于事后分析不同区域的流速以指导精准灌溉。第二种方案更优服务端只是在用不上的时候忽略遥测而遥测本身依然存在于 broker 上其他订阅者不受影响——这正是 MQTT 发布/订阅架构的价值一条遥测可以被多个消费者同时消费例如一个服务负责入库供分析另一个服务负责控制浇水。完整代码解析参考实现位于 code-timing/server/app.py相对 MQTT 版本code-mqtt/server/app.py的增量如下第 1 步导入线程库使 Python 可以在等待期间继续处理其他消息回调import threading第 2 步定义时序参数app.py L18-L19。water_time是继电器运行时长wait_time是复测前的稳定等待water_time 5 wait_time 20第 3 步封装命令下发函数app.py L21-L24。命令构造成 JSON 字典后经 MQTT 发布到server_command_topicstate决定开/关def send_relay_command(client, state): command { relay_on : state } print(Sending message:, command) client.publish(server_command_topic, json.dumps(command))第 4 步浇水周期核心函数app.py L26-L37严格对应上文时序——先退订遥测防止周期内重复触发开泵 → 等待water_time→ 关泵 → 等待wait_time→ 重新订阅def control_relay(client): print(Unsubscribing from telemetry) mqtt_client.unsubscribe(client_telemetry_topic) send_relay_command(client, True) time.sleep(water_time) send_relay_command(client, False) time.sleep(wait_time) print(Subscribing to telemetry) mqtt_client.subscribe(client_telemetry_topic)第 5 步遥测回调只做判断与派发app.py L39-L44。注意control_relay运行在独立线程中——如果直接在 MQTT 回调线程里sleep(25)主消息循环会被阻塞退订期间的消息虽然不会触发新周期但线程模型会变得脆弱且无法并发处理其他事件def handle_telemetry(client, userdata, message): payload json.loads(message.payload.decode()) print(Message received:, payload) if payload[soil_moisture] 450: threading.Thread(targetcontrol_relay, args(client,)).start()验证运行确保 IoT 端程序运行后执行python app.py需先激活虚拟环境改变湿度观察输出。典型一次完整浇水周期的日志如下(.venv) ➜ soil-moisture-sensor-server ✗ python app.py Message received: {soil_moisture: 457} Unsubscribing from telemetry Sending message: {relay_on: True} Sending message: {relay_on: False} Subscribing to telemetry Message received: {soil_moisture: 302}继电器应打开约 5 秒、关闭后至少 20 秒内不再动作只有复测仍高于 450 才会再次启动。课程给出的一个巧妙测试法使用干土在继电器打开期间手动往土里倒水模拟水泵继电器关闭时停止倒水——虚拟环境下同理。硬件提示若要搭建真实系统课程建议 6V 微型水泵配 USB 终端电源且泵的供电必须经过继电器绝不能直接接开发板 GPIO。进阶任务构建更高效的浇水循环课后任务assignment.md要求把固定 5 秒升级为按缺口比例泵水核心是校准实验从干土开始记录初始湿度读数每次固定增加水量泵运行 1 秒或倒入固定体积的水泵需保持恒速保证每秒供水量恒定等待读数稳定后记录新值重复多次建立累计泵水时长—湿度读数—下降量对照表。课程给出的示例数据累计泵水时长湿度读数下降量干土64301s621222s601203s579224s560195s539216s52118由此算出平均每秒泵水使读数下降约 20.3。把该系数写回服务端即可缺口多少就泵多久泵水时长 ≈当前读数 − 目标读数/ 20.3再配合wait_time复测修正实现接近目标值的精准浇水。虚拟硬件学习者可以手动按每秒 20.3 递增读数来模拟整个流程。小结这一课把能亮的原型升级为能控的系统沉淀出三条可复用的 IoT 工程经验功率隔离GPIO 只碰执行器的控制端大功率负载永远走外部电源——继电器是这种架构的标准件从单株盆栽泵到工业灌溉系统都适用同一原理控制集中化通过 MQTT 把决策从设备端上移到服务端id/telemetry上行、id/commands下行获得多传感器决策与统一配置的能力且遥测的发布/订阅模型允许多个消费者并存时序建模凡是被测属性变化滞后于执行器动作的系统浇水、室温、湿度等简单阈值开关都会过冲正确做法是短动作 稳定等待 复测 数据校准的闭环且时序参数必须以实测数据为准。课程的延伸挑战值得动手验证找出你家中同样存在执行器动作 → 传感器读数滞后特性的设备空调、加湿器、暖气片分析它测量什么属性、响应需要多久、过冲是否可接受、以及如何把属性拉回目标区间——这套分析框架适用于几乎所有闭环控制型 IoT 系统。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考