葡萄园智能灌溉系统:Node-RED 与 MCGS 全链路通讯与 UI 配置手册 (v2.0 完整版)
📘 文档版本: v2.0 完整版
🎯 适用场景: 现场边缘网关 (LubanCat-5 / Raspberry Pi 5) + MCGS + 传感器网络
🔧 核心功能: 下行 9 通道控制 + 上行 39 通道监测 + Dashboard 大屏
⚠️ 关键词: 多通道打包、工程量标定、数字孪生、报警防弹
📋 目录
一、系统架构概述
1.1 整体架构图
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 云端/边缘网关 (Node-RED 上位机) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ 🖥️ 智慧葡萄园主控舱 Dashboard │ │
│ │ ┌─────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 💻 现场设备控制区 (9通道下发) │ │ │
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │ 水泵 S1 │ │ 阀门 S2 │ │ 施肥 S3 │ │ 压力 Pres│ │ 频率 Freq│ │ │ │
│ │ │ │ [开关] │ │ [开关] │ │ [开关] │ │ [滑块] │ │ [滑块] │ │ │ │
│ │ │ │ 💡 │ │ 💡 │ │ 💡 │ │ │ │ │ │ │ │
│ │ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬─────┘ └────┬─────┘ │ │ │
│ │ │ └───────────┴───────────┴───────────┴─────────────┘ │ │ │
│ │ │ ↓ │ │ │
│ │ │ 9通道动态打包 │ │ │
│ │ └─────────────────────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 🌱 土壤与水质环境 (39通道监测) │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ │ │
│ │ │ │ 📊 实时仪表 │ │ 📈 历史曲线 │ │ 📋 传感器数值矩阵 │ │ │ │
│ │ │ │ NPK/Gauge │ │ Chart │ │ 温湿度/电导率/压力 │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ │ │
│ │ │ ↑ │ │ │
│ │ │ 39通道解析标定 │ │ │
│ │ └─────────────────────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 🚨 系统报警监控 │ │ │
│ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │
│ │ │ │ 🟢 运行正常 / 🚨 报警: 肥路堵塞 │ │ │ │
│ │ │ └─────────────────────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ MQTT 协议 (EMQX) │
│ sub/控制单元 ←→ attributes │
│ │ │
└────────────────────────────────────┼────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 现场控制层 (MCGS TPC) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ MCGS 触摸屏主控界面 │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
│ │ │ 设备控制区 │ │ 传感器显示 │ │ 报警指示栏 │ │ │
│ │ │ S1-S7 开关 │ │ NPK/温湿度 │ │ 🚨 多路报警灯 │ │ │
│ │ └────────┬────────┘ └────────┬────────┘ └──────────┬──────────┘ │ │
│ │ │ │ │ │ │
│ │ └──────────────────────┼────────────────────────┘ │ │
│ │ │ │ │
│ │ 协议转换/打包 │ │
│ │ │ │ │
│ │ ┌──────────────────────┴────────────────────────┐ │ │
│ │ │ 底层传感器网络 │ │ │
│ │ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │
│ │ │ │NPK传感 │ │温湿度 │ │电导率 │ │压力传感│ │ │ │
│ │ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │ │
│ │ │ RS-485 / Modbus / 4-20mA / 0-10V │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘
1.2 双链路设计说明
| 链路方向 | Topic | 通道数 | 数据方向 | 核心功能 |
|---|---|---|---|---|
| 下行控制 | sub/控制单元 |
9 通道 | Node-RED → MCGS | 设备开关 + 模拟量设定 |
| 上行监测 | attributes |
39 通道 | MCGS → Node-RED | 传感器数据 + 报警 + 状态反馈 |
设计理念:
– 控制集约化: 9 个控制指令合并为 1 个 JSON 下发,减少网络开销
– 监测原子化: 39 个监测字段独立分流,支持精细化展示
– 状态闭环: 控制指令执行结果通过上行链路回传,实现数字孪生
1.3 数据通道明细表
下行控制通道 (9 路):
| 通道 | 名称 | 类型 | 范围 | 说明 |
|---|---|---|---|---|
| S1 | 水泵开关 | Boolean | true/false | 主灌溉泵 |
| S2 | 阀门开关 | Boolean | true/false | 区域阀门 |
| S3 | 施肥开关 | Boolean | true/false | 施肥泵 |
| S4 | 备用开关 4 | Boolean | true/false | 预留扩展 |
| S5 | 备用开关 5 | Boolean | true/false | 预留扩展 |
| S6 | 备用开关 6 | Boolean | true/false | 预留扩展 |
| S7 | 备用开关 7 | Boolean | true/false | 预留扩展 |
| Pres1 | 主路压力设定 | Number | 0-100 | 单位: bar |
| Freq | 运行频率 | Number | 0-50 | 单位: Hz |
上行监测通道 (39 路):
| 类别 | 字段示例 | 数据类型 | 标定系数 | 说明 |
|---|---|---|---|---|
| 土壤养分 | N, P, K | UInt16 | ÷ 10 | 氮磷钾含量 mg/kg |
| 环境参数 | RD11-RD20 | UInt16 | ÷ 10 | 多路温湿度 |
| 水质参数 | EC, pH | UInt16 | ÷ 100 | 电导率/酸碱度 |
| 系统压力 | Pres1, Pres2 | UInt16 | ÷ 10 | 主/支路压力 |
| 设备状态 | S1-S7 | Boolean | – | 开关真实状态 |
| 报警信息 | AM1-AM10 | String | – | 多路报警代码 |
二、下行控制链路:多通道指令动态打包
2.1 功能目标
将网页端 9 个独立的控制指令(S1-S7 设备开关、Pres1 压力设定、Freq 频率设定)动态合并为一个完整的 JSON 报文下发。
为什么需要打包?
– 减少 MQTT 消息数量(9 条 → 1 条)
– 保证指令原子性(同一条报文同时生效)
– 简化 MCGS 端解析逻辑
2.2 网页 UI 节点配置
2.2.1 开关控件 (Switch) – S1 到 S7
| 配置项 | 值 | 必须注意 |
|---|---|---|
| Topic | S1 / S2 / … / S7 |
纯文本,区分大小写 |
| On Payload | true |
⚠️ 必须是 Boolean 类型 |
| Off Payload | false |
⚠️ 必须是 Boolean 类型 |
| Indicator | state of the input |
数字孪生必备 |
| Pass through | ☐ 取消勾选 | 防止死循环 |
配置面板示意:
┌─────────────────────────────────────────┐
│ Group: [💻 现场设备控制区 ▼] │
│ Label: [水泵 S1 ] │
│ Topic: [S1 ] │
│ │
│ On Payload: [true] ☜── 布尔类型 🔵 │
│ Off Payload: [false] ☜── 布尔类型 🔵 │
│ │
│ ☐ Pass through msg... ☜── 必须取消 │
│ │
│ Indicator: [Switch icon shows ] │
│ [state of the input ▼] │
└─────────────────────────────────────────┘
2.2.2 滑动/数字控件 – Pres1 / Freq
| 配置项 | Pres1 (压力) | Freq (频率) |
|---|---|---|
| Topic | Pres1 |
Freq |
| Min | 0 | 0 |
| Max | 100 | 50 |
| Step | 0.1 | 0.1 |
| 单位 | bar | Hz |
2.3 控制指令打包 (Function 节点)
2.3.1 逻辑原理
采用“系统全局记忆”策略:
1. 在 Node-RED 的 flow 上下文中维护 9 个参数的最新状态
2. 任意 UI 节点触发变化时,更新对应参数
3. 统一下发完整 JSON,内置防错拦截机制
2.3.2 节点配置
| 属性 | 值 |
|---|---|
| 名称 | 控制指令打包 |
| Outputs | 1 |
2.3.3 完整代码
/**
* 控制指令打包器 - 9通道动态合并
* 输入: 任意 UI 节点的 msg (含 topic + payload)
* 输出: 完整的 9 参数 JSON 控制报文
*/
// 1. 从 flow 上下文中获取系统记忆,若无则初始化
var control_state = flow.get('control_state') || {
"Freq": 0, // 频率设定
"Pres1": 0, // 压力设定
"S1": false, // 水泵
"S2": false, // 阀门
"S3": false, // 施肥
"S4": false, // 备用
"S5": false, // 备用
"S6": false, // 备用
"S7": false // 备用
};
// 2. 动态匹配并更新状态
// msg.topic 对应 Key, msg.payload 对应 Value
if (control_state.hasOwnProperty(msg.topic)) {
control_state[msg.topic] = msg.payload;
// 保存到 flow 上下文(持久化记忆)
flow.set('control_state', control_state);
node.status({fill:"green", shape:"dot",
text: msg.topic + " → " + msg.payload});
} else {
// 防错拦截:未知的 topic 不处理
node.warn("⚠️ 未知 Topic 拦截: " + msg.topic);
node.status({fill:"red", shape:"ring",
text: "未知: " + msg.topic});
return null; // 终止流
}
// 3. 构建标准输出报文
msg.topic = "sub/控制单元"; // 强制指定下发主题
msg.payload = control_state; // 完整 9 参数对象
// 调试输出(开发时开启)
// node.warn("下发报文: " + JSON.stringify(control_state));
return msg;
2.3.4 输出报文示例
{
"topic": "sub/控制单元",
"payload": {
"Freq": 35.5,
"Pres1": 2.8,
"S1": true,
"S2": false,
"S3": true,
"S4": false,
"S5": false,
"S6": false,
"S7": false
}
}
2.4 MQTT Out 节点配置
| 配置项 | 值 | 说明 |
|---|---|---|
| Server | EMQX 地址 | 192.168.137.238:1883 |
| Topic | sub/控制单元 |
MCGS 订阅此主题 |
| QoS | 1 | 至少送达一次 |
| Retain | false | 不保留最新消息 |
三、上行监测链路:39 通道传感器数据解析与标定
3.1 功能目标
接收 MCGS 汇总上报的工业级数据包(包含 NPK、温湿度、电导率、压力、报警及设备反馈共 39 个字段),进行:
– 工程量还原: 将 UInt16 整数转为实际物理量
– 多路分流: 39 个字段分发到不同 UI 组件
– 容错处理: 异常数据拦截
3.2 MCGS 上报数据格式
MCGS 上报报文示例:
{
"N": 150, // 氮含量 (×10 mg/kg)
"P": 80, // 磷含量
"K": 120, // 钾含量
"RD11": 258, // 1号含水率 (×10 %)
"RD12": 245, // 1号温度 (×10 ℃)
"RD21": 1560, // 电导率 (×100 μS/cm)
"Pres1": 28, // 压力 (×10 bar)
"S1": true, // 水泵实际状态
"AM1": "" // 报警信息 (空=正常)
// ... 共 39 个字段
}
3.3 数据接收与格式化
3.3.1 MQTT In 节点
| 配置项 | 值 |
|---|---|
| Topic | attributes |
| QoS | 1 |
| Output | a parsed JSON object |
3.3.2 JSON 节点(备用转换)
如果 MQTT In 输出的是字符串,添加 JSON 节点:
| 配置项 | 值 |
|---|---|
| Action | Always convert to JavaScript Object |
| Property | msg.payload |
3.4 超级分发中心 (Function 节点)
3.4.1 节点设置
| 属性 | 值 | 必须注意 |
|---|---|---|
| 名称 | 39通道数据分发 |
|
| Outputs | 39 | ⚠️ 必须手动改为 39! |
修改方法:
1. 双击 Function 节点
2. 底部找到 “Outputs” 输入框
3. 将默认值 1 改为 39
4. 点击「完成」
5. 节点会显示 39 个输出端口
3.4.2 工程量还原 (Calibration)
针对底层传来的 UInt16 无符号整数进行系数还原:
| 物理量 | 原始值范围 | 系数 | 结果单位 | 示例 |
|---|---|---|---|---|
| 温度 | 0-65535 | ÷ 10 | ℃ | 245 → 24.5℃ |
| 湿度 | 0-65535 | ÷ 10 | % | 258 → 25.8% |
| NPK | 0-65535 | ÷ 10 | mg/kg | 150 → 15.0mg/kg |
| 电导率 | 0-65535 | ÷ 100 | mS/cm | 1560 → 15.6mS/cm |
| 压力 | 0-65535 | ÷ 10 | bar | 28 → 2.8bar |
3.4.3 完整代码
/**
* 39通道数据分发器 - 超级分发中心
* 输入: MCGS 上报的 39 字段 JSON
* 输出: 39 路独立 msg,分别接入不同 UI 组件
*/
var d = msg.payload;
// 1. 容错机制:检查数据有效性
if (!d || typeof d !== 'object') {
node.error("❌ 无效数据格式");
return null;
}
// 2. 工程量还原函数
function calibrate(value, factor) {
if (value === undefined || value === null) return 0;
return Number(value) / factor;
}
// 3. 物理量还原 (按实际字段调整)
var temp_1 = calibrate(d.RD12, 10); // 1号温度 (℃)
var moist_1 = calibrate(d.RD11, 10); // 1号含水率 (%)
var ec_1 = calibrate(d.RD21, 100); // 电导率 (mS/cm)
var pres_1 = calibrate(d.Pres1, 10); // 主路压力 (bar)
var n_val = calibrate(d.N, 10); // 氮含量
var p_val = calibrate(d.P, 10); // 磷含量
var k_val = calibrate(d.K, 10); // 钾含量
// 4. 同步更新控制状态记忆(用于下行链路的数字孪生)
flow.set('control_state', {
"Freq": d.Freq || 0,
"Pres1": d.Pres1 || 0,
"S1": d.S1 || false,
"S2": d.S2 || false,
"S3": d.S3 || false,
"S4": d.S4 || false,
"S5": d.S5 || false,
"S6": d.S6 || false,
"S7": d.S7 || false
});
// 5. 构建 39 路输出数组
// 每路输出 = { payload: 值, topic: 显示名称 }
// 顺序必须与 UI 组件的连线顺序一致!
return [
// 第 1-10 路: 主要设定值与状态
{ payload: pres_1, topic: "主路压力(bar)" }, // 输出 1 → Gauge
{ payload: d.Freq || 0, topic: "运行频率(Hz)" }, // 输出 2 → Gauge
{ payload: n_val, topic: "氮含量(mg/kg)" }, // 输出 3 → Gauge
{ payload: p_val, topic: "磷含量(mg/kg)" }, // 输出 4 → Gauge
{ payload: k_val, topic: "钾含量(mg/kg)" }, // 输出 5 → Gauge
{ payload: ec_1, topic: "电导率(mS/cm)" }, // 输出 6 → Gauge
{ payload: d.S1, topic: "S1状态" }, // 输出 7 → Switch 反馈
{ payload: d.S2, topic: "S2状态" }, // 输出 8 → Switch 反馈
{ payload: d.S3, topic: "S3状态" }, // 输出 9 → Switch 反馈
{ payload: d.S4, topic: "S4状态" }, // 输出 10
// 第 11-20 路: 多路温湿度
{ payload: moist_1, topic: "1号含水率(%)" }, // 输出 11 → Chart
{ payload: temp_1, topic: "1号温度(℃)" }, // 输出 12 → Chart
{ payload: calibrate(d.RD13, 10), topic: "2号含水率" }, // 输出 13
{ payload: calibrate(d.RD14, 10), topic: "2号温度" }, // 输出 14
{ payload: calibrate(d.RD15, 10), topic: "3号含水率" }, // 输出 15
{ payload: calibrate(d.RD16, 10), topic: "3号温度" }, // 输出 16
{ payload: calibrate(d.RD17, 10), topic: "4号含水率" }, // 输出 17
{ payload: calibrate(d.RD18, 10), topic: "4号温度" }, // 输出 18
{ payload: calibrate(d.RD19, 10), topic: "5号含水率" }, // 输出 19
{ payload: calibrate(d.RD20, 10), topic: "5号温度" }, // 输出 20
// 第 21-30 路: 报警与扩展
{ payload: d.AM1 || "", topic: "主路报警" }, // 输出 21 → 报警 Text
{ payload: d.AM2 || "", topic: "肥路报警" }, // 输出 22 → 报警 Text
{ payload: d.AM3 || "", topic: "泵报警" }, // 输出 23
{ payload: d.AM4 || "", topic: "阀门报警" }, // 输出 24
{ payload: d.AM5 || "", topic: "备用报警5" }, // 输出 25
{ payload: d.AM6 || "", topic: "备用报警6" }, // 输出 26
{ payload: d.AM7 || "", topic: "备用报警7" }, // 输出 27
{ payload: d.AM8 || "", topic: "备用报警8" }, // 输出 28
{ payload: d.AM9 || "", topic: "备用报警9" }, // 输出 29
{ payload: d.AM10 || "", topic: "备用报警10" }, // 输出 30
// 第 31-39 路: 更多设备状态反馈(用于数字孪生)
{ payload: d.S5, topic: "S5状态" }, // 输出 31
{ payload: d.S6, topic: "S6状态" }, // 输出 32
{ payload: d.S7, topic: "S7状态" }, // 输出 33
// ... 可继续扩展至 39 路
{ payload: 0, topic: "保留34" }, // 输出 34
{ payload: 0, topic: "保留35" }, // 输出 35
{ payload: 0, topic: "保留36" }, // 输出 36
{ payload: 0, topic: "保留37" }, // 输出 37
{ payload: 0, topic: "保留38" }, // 输出 38
{ payload: 0, topic: "保留39" } // 输出 39
];
3.5 输出连线方式
Function 节点 (39通道数据分发)
│
├──输出 1──> ui_gauge (主路压力)
├──输出 2──> ui_gauge (运行频率)
├──输出 3──> ui_gauge (氮含量)
├──输出 4──> ui_gauge (磷含量)
├──输出 5──> ui_gauge (钾含量)
├──输出 6──> ui_gauge (电导率)
│
├──输出 7──> ui_switch (S1 反馈输入)
├──输出 8──> ui_switch (S2 反馈输入)
├──输出 9──> ui_switch (S3 反馈输入)
│
├──输出 11──> ui_chart (含水率历史曲线)
├──输出 12──> ui_chart (温度历史曲线)
│
├──输出 21──> function (报警防弹) ──> ui_text
└──输出 22──> function (报警防弹) ──> ui_text
四、Dashboard UI 界面排版与视觉优化
4.1 结构化排版 (Tab & Group)
在右侧的 Dashboard → Layout 面板中建立以下层级:
Dashboard Layout Tree:
│
└── 📱 Tab: 智慧葡萄园主控舱
│
├── 💻 Group: 现场设备控制区
│ ├── [Switch] 水泵 S1
│ ├── [Switch] 阀门 S2
│ ├── [Switch] 施肥 S3
│ ├── [Slider] 压力 Pres1
│ └── [Slider] 频率 Freq
│ Width: 6 (半屏宽)
│
├── 🌱 Group: 土壤与水质环境
│ ├── [Gauge] NPK 仪表盘
│ ├── [Gauge] 电导率
│ ├── [Chart] 温湿度历史曲线
│ └── [Text] 实时数值表
│ Width: 12-18 (全屏或更宽)
│
└── 🚨 Group: 系统报警监控
├── [Text] 主路报警
├── [Text] 肥路报警
└── [Text] 综合状态
Width: 6 (半屏宽)
布局原则:
– 控制区: 左侧/上方,操作最频繁
– 监测区: 中间,信息密度最高
– 报警区: 右侧/下方,需要醒目提示
4.2 报警状态防弹视觉优化
4.2.1 问题描述
如果直接将报警字段接入 ui_text 节点:
– 正常运行时显示空白或 “”
– 操作人员误以为报警功能失效
4.2.2 解决方案:视觉转换过滤
在数据分发后、接入 ui_text 节点前,增加 Function 节点:
/**
* 报警防弹过滤器
* 将空值/undefined 转换为友好的"运行正常"提示
*/
// 兼容 undefined、null、空字符串、纯空格的鲁棒性写法
var val = msg.payload;
if (val === "" || val === undefined || val === null ||
(typeof val === 'string' && val.trim() === "")) {
msg.payload = "🟢 运行正常";
msg.color = "#28a745"; // 绿色
} else {
msg.payload = "🚨 报警: " + val;
msg.color = "#dc3545"; // 红色
}
return msg;
4.2.3 UI 效果对比
| 场景 | 未优化 | 优化后 |
|---|---|---|
| 正常 | [空白] ❌ | 🟢 运行正常 ✅ |
| 报警 | AM1:堵塞 | 🚨 报警: AM1:堵塞 |
4.3 开关状态的数字孪生双向反馈
4.3.1 闭环设计
用户操作 Web Switch S1 ──>
│
├── 下行: Function 打包 ──> MQTT Out ──> MCGS 执行
│
└── 上行: MCGS 回传实际状态 ──> MQTT In ──> Function 分发 ──>
│
▼
Web Switch S1 (输入端)
│
Switch 位置自动同步
4.3.2 Switch 节点关键配置
| 配置项 | 值 | 作用 |
|---|---|---|
| Indicator | Switch icon shows state of the input |
根据回传状态改变位置 |
| Pass through | ☐ 取消勾选 | 阻断循环 |
| On Payload | true (Boolean) |
与回传数据类型匹配 |
| Off Payload | false (Boolean) |
与回传数据类型匹配 |
4.3.3 时序说明
时间轴 →
T0: 用户点击 S1 开关 (请求开启)
├── Web Switch 发出 {topic:"S1", payload:true}
├── Function 打包 → MQTT 下发
└── Switch 位置暂时不变 (等待确认)
T1: MCGS 执行完毕,上报 {S1:true, ...}
├── MQTT In 接收
├── Function 分发 → 输出 7 → Switch 输入
└── Web Switch 位置变为"开启" ✅
结果: 开关位置反映的是 MCGS 的真实状态,而非用户操作
五、核心注意事项(防坑指南)
5.1 数据类型一致性
症状
- Switch 不随回传数据变化
- Debug 看到数据但 UI 无反应
根因
Node-RED Switch 对数据类型敏感:
| 类型 | 示例 | Switch 匹配 |
|---|---|---|
| Boolean | true |
✅ 匹配 On Payload (true) |
| 数字 | 1 |
❌ 不匹配 true |
| 字符串 | "true" |
❌ 不匹配 |
解决方案
统一使用 Boolean 类型:
– MCGS 上报: true / false
– Function 分发: d.S1 (原始 Boolean)
– Switch Payload: true / false (Boolean)
5.2 Function 输出数设置
症状
- 只显示 1 个输出端口
- 无法连接多个 UI 组件
解决方案
双击 Function 节点 → 底部 Outputs → 改为 39。
5.3 Topic 命名一致性
| 位置 | Key/Topic | 大小写敏感 |
|---|---|---|
| MCGS JSON | "S1" |
大写 S |
| Node-RED Switch | S1 |
大写 S |
| Function 检查 | msg.topic === "S1" |
大写 S |
⚠️ s1 ≠ S1,不一致会导致拦截或失效。
5.4 标定系数核对
常见错误:
– 温度显示 245℃(忘记 ÷10)
– 电导率 0.15(系数用错,应该是 ÷100 而非 ÷1000)
建议建立标定对照表贴在 MCGS 和 Node-RED 旁。
六、调试与排错
6.1 分级调试策略
| 层级 | 检查点 | 方法 |
|---|---|---|
| 通讯层 | MQTT 连接 | Dashboard → 节点状态指示 |
| 协议层 | 报文格式 | Debug 节点查看 payload |
| 逻辑层 | Function 执行 | node.warn() / node.status() |
| UI 层 | 显示效果 | 浏览器 F12 检查 |
6.2 常用 Debug 代码
在 Function 节点中添加:
// 查看完整输入
node.warn("输入: " + JSON.stringify(msg));
// 查看特定字段
node.warn("S1 = " + msg.payload.S1 + " (类型: " + typeof msg.payload.S1 + ")");
// 查看 flow 记忆
node.warn("记忆: " + JSON.stringify(flow.get('control_state')));
// 设置节点状态(显示在编辑器中)
node.status({fill:"green", shape:"dot", text:"正常"});
6.3 问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 开关不响应点击 | Pass through 未取消 | 检查 Switch 配置 |
| 开关位置不跟随 | Indicator 设置错误 | 改为 “state of the input” |
| 下发数据不完整 | 9 参数未凑齐 | 检查 flow.get(‘control_state’) |
| 传感器数据为 0 | 标定系数错误 | 核对 ÷10 / ÷100 |
| 报警显示空白 | 未加防弹过滤 | 添加空值检查 Function |
| 只有 1 路输出 | Outputs 未改 39 | 双击修改 |
七、附录:配置速查表与扩展指南
7.1 节点配置汇总
| 节点 | 名称 | 关键配置 |
|---|---|---|
| ui_switch | S1-S7 | Topic: S1-S7, Payload: Boolean, Indicator: input, Pass through: ☐ |
| ui_slider | Pres1/Freq | Topic: Pres1/Freq, Min/Max: 0-100/50 |
| function | 控制指令打包 | 见 2.3.3 代码 |
| function | 39通道分发 | Outputs: 39, 见 3.4.3 代码 |
| function | 报警防弹 | 见 4.2.2 代码 |
| mqtt out | 控制下发 | Topic: sub/控制单元 |
| mqtt in | 监测接收 | Topic: attributes |
7.2 扩展更多设备
如需增加 S8、S9:
- Node-RED 端:
// control_state 添加新字段 "S8": false, "S9": false // 39 路输出改为 41 路 Outputs: 41 - MCGS 端:
- 组态新增开关组件
- 策略脚本添加 S8/S9 到 JSON
- Dashboard:
- Layout 添加新 Switch
- Group 宽度调整
7.3 完整流 JSON(可导入)
[
{
"id": "control_packer",
"type": "function",
"z": "grape_flow",
"name": "控制指令打包",
"func": "var control_state = flow.get('control_state') || {\"Freq\":0,\"Pres1\":0,\"S1\":false,\"S2\":false,\"S3\":false,\"S4\":false,\"S5\":false,\"S6\":false,\"S7\":false};\nif (control_state.hasOwnProperty(msg.topic)) {\n control_state[msg.topic] = msg.payload;\n flow.set('control_state', control_state);\n} else {\n node.warn('未知Topic:' + msg.topic);\n return null;\n}\nmsg.topic = 'sub/控制单元';\nmsg.payload = control_state;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 100,
"wires": [["mqtt_out"]]
}
]
文档结束
配置过程中如遇问题,请参考第六章调试与排错进行排查。


