如何在Node-RED中实现适配Puck.js按钮的可取消触发状态机
基于Node-RED实现Puck.js按键触发延迟告警的状态机方案
方案1:原生节点实现零额外代码状态机(推荐)
完全使用Node-RED自带节点实现,无需编写自定义函数,维护成本最低:
- 先定义2个流上下文变量:
is_counting(布尔值,标记当前是否处于30秒倒计时等待取消状态) - 流结构按以下顺序搭建:
- 入口为
mqtt in节点,对接Puck.js发送的按键事件topic - 接
switch节点,判断flow.is_counting的状态:- 分支1:
flow.is_counting为false(空闲状态)- 第一步:接LED控制节点,触发闪烁
- 第二步:接
change节点,将flow.is_counting设为true - 第三步:接trigger节点,配置规则为「收到消息后等待30秒发送消息,期间收到新消息则取消待发任务」
- trigger节点后续接两个动作:先触发LED停止闪烁,再调用SMS发送节点
- 最后接
change节点,将flow.is_counting重置为false
- 分支2:
flow.is_counting为true(倒计时状态)- 第一步:接LED控制节点,停止闪烁
- 第二步:接
change节点,将flow.is_counting重置为false,无后续动作直接回到空闲状态
- 分支1:
- 入口为
方案2:轻量自定义函数实现可扩展状态机
如果后续需要扩展更多状态(比如区分长短按、多按键逻辑),可以用单个function节点实现,核心代码不到20行:
// 读取流上下文存储的状态,默认空闲 const currentState = flow.get("puck_state") || "idle"; switch (currentState) { case "idle": // 空闲状态收到按键进入倒计时 node.send([{ payload: "blink" }, null]); flow.set("puck_state", "counting"); // 存储定时器ID用于后续取消 const timer = setTimeout(() => { node.send([{ payload: "stop_blink" }, { payload: "send_sms" }]); flow.set("puck_state", "idle"); }, 30000); flow.set("current_timer", timer); break; case "counting": // 倒计时状态收到按键直接取消请求 clearTimeout(flow.get("current_timer")); node.send([{ payload: "stop_blink" }, null]); flow.set("puck_state", "idle"); break; } return null;
function节点设置2个出口,第一个出口对接LED控制节点,第二个出口对接SMS发送节点即可,后续新增状态直接在switch语句中加分支即可。
注意事项
- 状态变量优先用流上下文存储,不要用全局上下文,避免和其他流的变量冲突
- 调试时可以在状态变更节点后加debug节点,打印当前状态值快速排查问题
内容的提问来源于stack exchange,提问作者HeneryH
相关产品推荐
相关产品推荐

