3. 灌溉云平台远程控制架构设计
要把“手机点一下,田间阀门就开”这件事真正跑通,必须先想清楚系统里到底有哪几层、每层负责什么、消息在层与层之间怎么流动。MQTT 灌溉云平台的远程控制并不是一个单体程序,而是一条跨越现场与云端的消息链路。本节围绕设备端、MQTT Broker、云平台服务、用户应用四层架构展开,重点讲清各层的职责边界、主题(Topic)设计以及一次“开阀”指令从用户点击到阀门动作、再到状态回传的完整数据流。
四层架构的职责划分
设备端位于田间现场,通常由灌溉控制器(如基于 ESP32、STM32 或工业 RTU 的主控板)、阀门继电器/电磁阀、土壤湿度传感器、流量计、压力传感器等组成。它的核心职责有三件:采集(周期性上报土壤湿度、流量、阀门状态)、执行(订阅控制主题,收到指令后驱动继电器动作)、保活(维持与 Broker 的长连接并处理断线重连)。设备端是“哑执行者”,不应在本地做复杂的业务决策,否则云端策略与现场行为容易不一致。
MQTT Broker 是消息中枢,负责连接管理、主题路由、QoS 保障和会话保持。它不关心业务语义,只按主题把消息分发给订阅者。工程上常用 EMQX、Mosquitto 或云厂商的托管 MQTT 服务。Broker 的关键配置包括:是否开启持久会话(clean session=false 可让设备离线期间的 QoS1 消息在重连后补发)、最大连接数、主题 ACL 权限(防止设备越权订阅其他设备的控制主题)。
云平台服务是业务大脑,承担设备接入鉴权、指令编排、规则引擎、数据存储与告警。它一方面订阅设备上报的主题,把遥测数据写入时序数据库;另一方面接收用户应用的指令请求,做权限校验和参数合法性检查后,再向设备控制主题发布命令。云平台服务还负责“指令—回执”的关联,避免用户发出指令后无法确认是否执行成功。
用户应用包括手机 App、Web 管理后台或小程序,负责展示设备状态、下发控制意图。它不直接与设备通信,而是通过 HTTPS/REST 或 WebSocket 调用云平台服务,由云平台服务转换为 MQTT 消息。这样做的价值在于:用户应用无需知道设备在线地址,鉴权、审计、限流都集中在云端。
主题(Topic)设计:让数据流有明确的路由
四层之间靠主题解耦,主题设计直接决定系统是否可扩展。推荐采用“产品/设备/功能”三级结构,把上行与下行分开,避免设备误收自己的上报消息。以下是一份可直接参考的主题规划示例(示例参数,非实测):
# 上行:设备 → 云平台
irrigation/{deviceId}/state 设备状态(阀门开/关、在线状态)
irrigation/{deviceId}/telemetry 遥测数据(土壤湿度、流量、压力)
irrigation/{deviceId}/event 事件告警(阀门故障、低电量)
# 下行:云平台 → 设备
irrigation/{deviceId}/cmd 控制指令(开阀/关阀/定时)
irrigation/{deviceId}/cmd/ack 指令回执(执行结果)
# 示例:设备 ID 为 DEV-001
irrigation/DEV-001/cmd
irrigation/DEV-001/state
这里有一个容易被忽略的工程细节:控制指令与状态上报必须使用不同主题。如果设备既发布又订阅同一个主题,会出现自己收到自己消息的回环问题。另外,设备端只应被授权订阅自己的 cmd 主题,云平台服务则订阅通配符 irrigation/+/state 与 irrigation/+/telemetry,通过 ACL 把权限收紧到最小范围。
一次“开阀”指令的完整数据流
以用户在 App 上点击“开启 1 号阀”为例,完整链路如下(示例参数):
- 用户应用向云平台发起
POST /api/devices/DEV-001/command,请求体为{"action":"valve_open","valve":1,"duration":600},携带用户 Token。 - 云平台服务校验 Token 与设备归属关系,检查设备是否在线(查询连接状态缓存),生成唯一
msgId,然后向irrigation/DEV-001/cmd发布 QoS1 消息,载荷包含msgId、动作和时长。 - MQTT Broker 按主题路由,把消息推送给已订阅该主题的 DEV-001 连接。
- 设备端收到指令,解析后驱动继电器吸合,阀门开启,同时启动 600 秒倒计时;随后向
irrigation/DEV-001/cmd/ack发布回执{"msgId":"...","result":"ok"},并向state主题上报valve1=on。 - 云平台服务订阅到 ack 与 state,更新设备影子(Device Shadow),并通过 WebSocket 把最新状态推送给用户应用,App 上的阀门图标变为“开启中”。
这条链路里,QoS 的选择值得说明:控制指令用 QoS1,保证“至少送达一次”,配合 msgId 做幂等去重,避免重复开阀;遥测数据可用 QoS0,允许偶发丢失以换取吞吐;告警事件用 QoS1 并持久化。若设备恰好离线,Broker 开启持久会话后,QoS1 指令会在设备重连后补发——但这带来一个风险:用户十分钟前点的“开阀”可能在设备上线后才执行。因此云平台服务应在指令中带上有效期(如 expireAt),设备端收到过期指令直接丢弃并回执 expired。
架构落地时的三个关键判断
其一,设备影子是否必要。当用户应用频繁刷新页面而设备上报间隔较长时,直接查设备会拖慢体验。云平台维护一份设备影子(最近一次 state 的缓存),用户读影子、写指令,读写分离,能显著降低对设备在线状态的依赖。
其二,指令回执的超时判定。云平台发布指令后启动定时器(示例设为 10 秒),超时未收到 ack 则标记为“执行超时”,并向用户应用返回明确结果,而不是让界面一直转圈。超时阈值应大于设备网络往返加执行时间的合理上限。
其三,离线与弱网的处理。田间 4G/NB-IoT 信号不稳定是常态。设备端应实现指数退避重连(如 1s、2s、4s、8s,上限 60s),并在本地缓存最近状态,重连后立即补报一次 state,让云端影子尽快收敛到真实值。
把四层职责、主题路由和指令回执链路定清楚之后,后续的设备接入鉴权、规则引擎策略配置和前端状态同步才有稳定的地基。远程控制的可靠性,本质上不取决于某一层写得多复杂,而取决于层与层之间的契约是否清晰、异常路径是否被显式处理。