问题:多个状态同时存在显示哪个
设备可能“有报警但还在运行”,也可能“故障且通讯中断”。如果直接显示最后收到的状态,界面会乱跳。正确做法是定义状态优先级,永远显示当前最严重/最该关注的状态。
定义优先级(数字越大越优先)
离线/通讯中断 = 5(最高,数据已不可信)
故障 = 4
报警 = 3
待机 = 2
运行 = 1
离线优先级最高,是因为通讯断了之后其他状态都是过期数据,必须先提示“数据不可信”。
Node-RED 实现思路
- 各状态位通过不同 MQTT 主题/消息进入
- 用 function 节点维护每台设备的上下文(context)状态对象
- 每来一个状态,更新对应位,再按优先级规则计算“最终显示状态”
- 输出统一的汇总状态给看板/数据库
function 节点核心逻辑:
const s = context.get('state') || {};
Object.assign(s, msg.payload); // 更新对应状态位
let final = 'run';
if (s.offline) final = 'offline';
else if (s.fault) final = 'fault';
else if (s.alarm) final = 'alarm';
else if (s.standby) final = 'standby';
context.set('state', s);
return { payload: { device: s.device, state: final } };
通讯中断怎么自动判定
不能只靠设备主动发“我离线了”——真断了它根本发不出来。要靠超时判定:
- 每收到一次数据,记录最后通讯时间戳
- 用定时节点(每 5~10 秒)检查:当前时间 - 最后时间 > 阈值(如 15 秒),则置 offline=true
- 收到新数据时自动清除 offline
这就是“心跳超时”机制,是判断设备在线与否的可靠方法。
状态防抖
报警位可能在临界点快速跳变,建议:
- 连续 N 次为真才确认报警
- 连续 M 次为假才解除
- 避免状态灯频繁闪烁和误报
输出与落地
计算出的最终状态一路写时序库(便于统计故障时长),一路推看板实时显示,一路在故障/离线时触发告警。把这套逻辑做成可复用的子流程(subflow),多台设备直接复制改设备号即可。