Node-RED触发流程
Node-RED触发流程
本节介绍接收和处理 IoT 按钮按键消息的 Node-RED 流程。学习完本节后,您将能够:
- 创建 MQTT In 节点以接收按钮消息
- 实现用于开/关操作的切换开关逻辑
- 集成 Shelly 继电器或其他智能设备
- 部署并测试完整的按钮到操作流程
开始本节前,请确保:
- Node-RED 已安装并运行(参见第 09 章)
- MQTT Broker 已配置(Mosquitto)
- 已完成 04-08. MQTT消息传输
- 基本熟悉 Node-RED 流程
按钮触发流程遵循一个简单的链条:
[MQTT In] → [函数:解析] → [切换节点] → [MQTT Out:Shelly] │ │ └─────────────┴──→ [调试](监控)| 节点 | 类型 | 用途 |
|---|---|---|
| MQTT In | mqtt in | 订阅按钮主题 |
| 解析 JSON | function | 从 JSON 负载中提取按钮数据 |
| Toggle | node-red-contrib-toggle | 切换开/关状态 |
| MQTT Out | mqtt out | 发送命令到 Shelly/设备 |
| Debug | debug | 监控传入消息 |
步骤 1:安装所需节点
Section titled “步骤 1:安装所需节点”# 在 Node-RED 容器或安装目录中cd ~/.node-rednpm install node-red-contrib-togglenpm install node-red-contrib-shelly # 可选,用于 Shelly 集成然后重启 Node-RED。
步骤 2:创建 MQTT In 节点
Section titled “步骤 2:创建 MQTT In 节点”配置:
- 节点:MQTT In
- 主题:
factory/button/# - 输出:
一个解析后的 JSON 对象 - 名称:
按键按下 - 服务器:您的 Mosquitto Broker(选择或添加 MQTT Broker 配置)
╔══════════════════════════════════════════════════╗║ [MQTT In] ║║ ║║ 服务器: Mosquitto(localhost:1883) ║║ 主题: factory/button/# ║║ QoS: 1 ║║ 输出: 自动检测(JSON 字符串) ║║ ║║ 名称: 按键按下 ║╚══════════════════════════════════════════════════╝# 通配符订阅所有按钮主题,允许多个按钮使用同一流程。
步骤 3:解析函数节点
Section titled “步骤 3:解析函数节点”// 解析传入的按钮消息// 输入:msg.payload = JSON 字符串// 输出:msg.payload = 解析后的对象
// 按钮发送:{"button_id":"BTN-001","action":"toggle","battery_voltage":3.85}
try { // 解析 JSON 负载(如果还不是对象) let data = typeof msg.payload === 'string' ? JSON.parse(msg.payload) : msg.payload;
// 提取按钮信息 msg.buttonId = data.button_id; msg.batteryVoltage = data.battery_voltage; msg.batteryPercent = data.battery_percent;
// 记录电池状态 if (data.battery_percent < 20) { node.warn(`低电量:${data.button_id} 剩余 ${data.battery_percent}%`); }
// 设置负载以触发切换 msg.payload = { action: data.action || "toggle", source: data.button_id };
return msg;
} catch (error) { node.error("解析错误:" + error.message, msg); return null;}节点配置:
- 节点:Function
- 名称:
解析按钮数据 - 输出:1
步骤 4:配置切换节点
Section titled “步骤 4:配置切换节点”node-red-contrib-toggle 维护一个状态,并在每次收到消息时切换该状态。
配置:
- 节点:Toggle
- 主题:
toggle(或留空) - 输出值:
- 开值:
{"state": "ON", "source": "button"} - 关值:
{"state": "OFF", "source": "button"}
- 开值:
- 初始状态:
off - 随机:false
- 名称:
切换继电器
╔══════════════════════════════════════════════════╗║ [Toggle] ║║ ║║ 起始状态: off ║║ 开负载: {"state":"ON"} ║║ 关负载: {"state":"OFF"} ║║ ║║ 名称: 切换继电器 ║╚══════════════════════════════════════════════════╝步骤 5:创建用于 Shelly 的 MQTT Out 节点
Section titled “步骤 5:创建用于 Shelly 的 MQTT Out 节点”配置:
- 节点:MQTT Out
- 主题:
shellies/shelly1-ABC123/relay/0/command - QoS:1
- 保留:false
- 名称:
Shelly 命令 - 服务器:同一 Mosquitto Broker
注意:将 Shelly 主题替换为您实际的 Shelly 设备主题。
步骤 6:完整流程 JSON
Section titled “步骤 6:完整流程 JSON”为方便导入,以下是完整的流程:
[ { "id": "btn_mqtt_in", "type": "mqtt in", "topic": "factory/button/#", "qos": "1", "datatype": "auto", "broker": "your_broker_id", "name": "按键按下", "x": 100, "y": 100, "wires": [["btn_parse"]] }, { "id": "btn_parse", "type": "function", "func": "try {\n let data = typeof msg.payload === 'string' ? JSON.parse(msg.payload) : msg.payload;\n msg.buttonId = data.button_id;\n msg.batteryVoltage = data.battery_voltage;\n if (data.battery_percent < 20) {\n node.warn(`低电量:${data.button_id} 剩余 ${data.battery_percent}%`);\n }\n msg.payload = {action: data.action || 'toggle', source: data.button_id};\n return msg;\n} catch (error) {\n node.error('解析错误:' + error.message, msg);\n return null;\n}", "outputs": 1, "name": "解析按钮数据", "x": 300, "y": 100, "wires": [["btn_toggle"]] }, { "id": "btn_toggle", "type": "toggle", "name": "切换继电器", "topic": "", "onvalue": "{\"state\":\"ON\"}", "onvalueType": "json", "offvalue": "{\"state\":\"OFF\"}", "offvalueType": "json", "onstartup": false, "startstate": "off", "random": false, "x": 500, "y": 100, "wires": [["btn_mqtt_out"]] }, { "id": "btn_mqtt_out", "type": "mqtt out", "topic": "shellies/shelly1-ABC123/relay/0/command", "qos": "1", "retain": "false", "broker": "your_broker_id", "name": "Shelly 命令", "x": 700, "y": 100, "wires": [] }, { "id": "btn_debug", "type": "debug", "name": "按钮监控", "active": true, "tosidebar": true, "console": false, "x": 500, "y": 200, "wires": [] }]使用 导入 菜单(汉堡菜单 → 导入 → 剪贴板)将此 JSON 导入 Node-RED。
步骤 7:测试流程
Section titled “步骤 7:测试流程”- 部署 Node-RED 中的流程
- 按下 IoT 按钮(或使用 MQTT Explorer 模拟)
- 观察调试面板中的传入消息
- 验证Shelly 设备是否随每次按压切换开/关
使用 MQTT CLI 手动测试:
# 模拟按钮按下mosquitto_pub -h localhost -t "factory/button/01/press" \ -m '{"button_id":"BTN-001","action":"toggle","battery_voltage":3.85,"battery_percent":85}'扩展:用于演示的注入节点
Section titled “扩展:用于演示的注入节点”为演示目的,添加一个模拟按钮按下的注入节点:
[注入节点]按钮:点击模拟按压负载:{"button_id":"BTN-DEMO","action":"toggle","battery_voltage":3.85,"battery_percent":85}重复:无名称:模拟按钮要支持多个按钮,添加一个带通配符主题的 MQTT In 节点,并通过按钮 ID 进行路由:
// 函数节点:按按钮路由let buttonId = msg.buttonId || "unknown";
switch(buttonId) { case "BTN-001": msg.topic = "shellies/shelly1-ABC123/relay/0/command"; break; case "BTN-002": msg.topic = "shellies/shelly1-DEF456/relay/0/command"; break; default: node.warn("未知按钮:" + buttonId); return null;}
return msg;- MQTT In 节点接收按钮消息
- 切换节点在每次按压时切换状态
- Shelly(或目标设备)正确响应
- 调试面板显示解析后的数据
- 多次按压一致地交替开/关
问题 1:未收到消息
Section titled “问题 1:未收到消息”症状:按下按钮时调试面板不显示任何内容
可能原因:
- MQTT Broker 连接问题
- 主题不匹配
- MQTT In 节点未连接到正确的 Broker
解决方案:
# 直接用 mosquitto_sub 测试mosquitto_sub -h localhost -t "factory/button/#" -v
# 如果这里没有输出,说明按钮没有发布消息# 检查 ESP32 上的 WiFi 凭据和 MQTT Broker问题 2:切换不工作
Section titled “问题 2:切换不工作”症状:消息到达但 Shelly 不切换
可能原因:
- 切换输出值与 Shelly 期望值不匹配
- MQTT Out 节点主题错误
- Shelly 未连接到 MQTT
解决方案:绕过切换节点直接发送命令进行验证:
# 直接测试 Shellymosquitto_pub -h localhost -t "shellies/shelly1-ABC123/relay/0/command" -m "on"mosquitto_pub -h localhost -t "shellies/shelly1-ABC123/relay/0/command" -m "off"- ✅ 对多按钮安装使用通配符主题(
#) - ✅ 在流程中包含电池监测以发送低电量告警
- ✅ 添加通知节点(邮件、短信)用于重要的按钮事件
- ✅ 在流程上下文中存储切换状态以在 Node-RED 重启后持久保持
- ❌ 不要为按钮事件使用保留消息
- ❌ 避免在流程中放置复杂逻辑——保持简单可靠
- Node-RED 通过带通配符主题的 MQTT In 节点接收按钮按下消息
- 切换节点提供开/关状态切换,每次按压切换一次
- MQTT Out 节点发送命令到 Shelly 或其他智能设备
- 电池监测可集成用于主动维护
- 多按钮支持通过在函数节点中进行主题路由轻松实现