
Node-RED:自定义节点开发:打造专属工具箱
文章目录
- Node-RED:自定义节点开发:打造专属工具箱
-
- 摘要
- 一、为什么需要自定义节点?------超越子流程的边界
- 二、项目结构:一个标准自定义节点长什么样?
-
- [🔑 关键命名规则:](#🔑 关键命名规则:)
- [三、第一步:创建 package.json](#三、第一步:创建 package.json)
- 四、定义配置界面:my-node.html
-
- 基础模板:
- [💡 高级技巧:](#💡 高级技巧:)
- 五、实现核心逻辑:my-node.js
-
- 基础框架:
- [🔑 关键概念:](#🔑 关键概念:)
- 六、本地开发与调试:高效迭代的秘诀
-
- [步骤 1:链接到本地 Node-RED](#步骤 1:链接到本地 Node-RED)
- [步骤 2:启用自动重载(开发模式)](#步骤 2:启用自动重载(开发模式))
- [步骤 3:调试技巧](#步骤 3:调试技巧)
- 七、图标与国际化:提升专业感
- [八、发布到 npm:让全世界都能用](#八、发布到 npm:让全世界都能用)
-
- 步骤:
- [📌 发布前检查清单:](#📌 发布前检查清单:)
- 九、最佳实践:写出高质量节点
- [十、实战案例:封装阿里云 IoT 上报节点](#十、实战案例:封装阿里云 IoT 上报节点)
- 写在最后:从使用者到创造者
关键字: Node-RED、 自定义节点、 节点开发、 npm包、 HTML模板 封装、 调试
摘要
去年我们做了一个智慧楼宇项目,有 20 多种设备需要接入 Modbus。
每次都要写一堆 Function 节点:解析寄存器、转浮点、处理字节序......
不仅流程图臃肿,还容易出错。
后来,我花了一天时间,封装了一个 modbus-parser 自定义节点:
- 左侧调色板拖出来就能用
- 可视化配置寄存器地址和数据类型
- 输出标准化 JSON
从此,新增设备只需填参数,不再写一行 JS。
今天这篇文章,就带你从零开始,开发属于你自己的 Node-RED 节点 。
你将学会:
- 自定义节点的完整目录结构
- 如何用 HTML 定义配置界面
- 如何用 JavaScript 实现核心逻辑
- 如何本地测试与调试
- 如何发布到 npm 供团队或社区使用
这不是 API 文档复读,而是一份 "从想法到可复用积木"的实战开发手册。
一、为什么需要自定义节点?------超越子流程的边界
子流程(Subflow)虽好,但有局限:
- ❌ 无法发布到 npm 共享
- ❌ 配置界面简陋(只有文本框)
- ❌ 不能包含 Dashboard 控件
- ❌ 无法实现复杂状态管理
而自定义节点:
- ✅ 拥有专业级配置面板
- ✅ 支持图标、下拉菜单、校验提示
- ✅ 可打包成 npm 包,一键安装
- ✅ 性能更高(原生节点调度)
💡 适用场景:
- 封装通用协议(如 Modbus、BACnet)
- 集成特定 SDK(如阿里云 IoT、微信 API)
- 构建团队内部标准组件库
二、项目结构:一个标准自定义节点长什么样?
Node-RED 对自定义节点有约定目录结构:
text
node-red-contrib-my-node/
├── package.json # npm 包信息
├── README.md # 使用说明
├── icon.png (可选) # 节点图标
├── nodes/
│ ├── my-node.html # 配置界面(前端)
│ └── my-node.js # 运行逻辑(后端)
└── test/ (可选)
└── my-node_spec.js # 单元测试
🔑 关键命名规则:
- 文件名必须一致:
my-node.html+my-node.js - npm 包名建议以
node-red-contrib-开头(社区惯例)
三、第一步:创建 package.json
json
{
"name": "node-red-contrib-modbus-parser",
"version": "1.0.0",
"description": "Parse Modbus register data into structured JSON",
"keywords": ["node-red", "modbus", "parser"],
"node-red": {
"nodes": {
"modbus-parser": "nodes/modbus-parser.js"
}
},
"dependencies": {
"buffer": "^6.0.3"
}
}
⚠️ 注意:
node-red.nodes字段告诉 Node-RED 哪个 JS 文件对应哪个节点名。
四、定义配置界面:my-node.html
这是用户双击节点时看到的弹窗。
基础模板:
html
<script type="text/html" data-template-name="modbus-parser">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="My Parser">
</div>
<div class="form-row">
<label><i class="fa fa-cog"></i> Register Address</label>
<input type="number" id="node-input-register" min="0" value="0">
</div>
<div class="form-row">
<label>Data Type</label>
<select id="node-input-type">
<option value="uint16">Unsigned 16-bit</option>
<option value="float32">Float 32-bit</option>
<option value="string">String</option>
</select>
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('modbus-parser', {
category: 'function', // 分类:function, input, output 等
color: '#a6bbcf', // 节点颜色
defaults: {
name: {value: ""},
register: {value: 0, required: true},
type: {value: "uint16"}
},
inputs: 1,
outputs: 1,
icon: "arrow-in.png", // 内置图标或自定义 icon.png
label: function() {
return this.name || "Modbus Parser";
}
});
</script>
💡 高级技巧:
- 表单校验 :
required: true自动提示 - 动态选项 :用 JavaScript 动态填充
<select> - 帮助链接 :在底部加
<p>See <a href="...">docs</a></p>
五、实现核心逻辑:my-node.js
这是节点运行时的后端代码。
基础框架:
javascript
module.exports = function(RED) {
function ModbusParserNode(config) {
RED.nodes.createNode(this, config);
const node = this;
// 保存配置
node.register = config.register;
node.type = config.type;
// 监听输入消息
node.on('input', function(msg, send, done) {
try {
// 核心解析逻辑
let value = parseModbusData(
msg.payload,
node.register,
node.type
);
// 修改 msg 并发送
msg.parsed = value;
send(msg);
done(); // 标记完成(用于异步)
} catch (e) {
node.error("解析失败: " + e.message, msg);
done(e); // 报错并终止
}
});
}
RED.nodes.registerType("modbus-parser", ModbusParserNode);
};
function parseModbusData(buffer, reg, type) {
// 实现具体解析...
if (type === "float32") {
return buffer.readFloatBE(reg * 2);
}
// ...
}
🔑 关键概念:
send():发送输出消息(支持多输出:send([msg1, null]))done():标记异步操作完成(Node-RED 1.0+ 必须调用)node.error():触发 Catch 节点捕获
六、本地开发与调试:高效迭代的秘诀
步骤 1:链接到本地 Node-RED
bash
# 在自定义节点目录下
npm link
# 进入 Node-RED 用户目录(如 ~/.node-red)
npm link node-red-contrib-modbus-parser
步骤 2:启用自动重载(开发模式)
编辑 settings.js:
javascript
export NODE_RED_ENABLE_SAFE_MODE=false
// 或启动时加 --safe-mode=false
💡 修改
.js或.html后,刷新浏览器即可生效,无需重启!
步骤 3:调试技巧
- 在
.js中加node.warn("Debug: " + JSON.stringify(msg)) - 用浏览器开发者工具查看 HTML 表单绑定
- 用
console.log输出到 Node-RED 终端(慎用)
七、图标与国际化:提升专业感
自定义图标:
- 在节点目录放
icon.png(推荐 20x20 或 30x30) - 在
.html的registerType中指定:icon: "icon.png"
多语言支持(可选):
html
<script type="text/html" data-help-name="modbus-parser">
<p>解析 Modbus 寄存器数据。</p>
</script>
帮助文档会显示在节点右键 → "Help" 中。
八、发布到 npm:让全世界都能用
步骤:
-
注册 npm 账号(
npm adduser) -
确保
package.json版本号正确 -
执行发布:
bashnpm publish -
安装验证:
bashnpm install node-red-contrib-modbus-parser
📌 发布前检查清单:
- README.md 包含使用示例
- 关键配置有默认值
- 错误处理完善
- 无硬编码敏感信息
- 测试通过
💡 社区贡献:发布后可在 Node-RED Flow 提交,让更多人发现。
九、最佳实践:写出高质量节点
| 原则 | 说明 |
|---|---|
| 单一职责 | 一个节点只做一件事(如"解析",不包含"连接") |
| 配置最小化 | 默认值合理,高级选项可折叠 |
| 错误明确 | 报错信息包含上下文(如"寄存器 100 超出范围") |
| 性能注意 | 避免在 input 中做 heavy 计算,考虑缓存 |
| 向后兼容 | 升级时保留旧配置字段 |
十、实战案例:封装阿里云 IoT 上报节点
需求:
- 输入
msg.payload = { temp: 25 } - 自动加上设备证书、时间戳
- 调用阿里云 MQTT 上报
节点配置界面:
- ProductKey(文本)
- DeviceName(文本)
- DeviceSecret(密码框)
- Topic(文本,默认
/user/update)
核心逻辑(简化):
javascript
const aliyun = require('aliyun-iot-device-sdk');
node.device = aliyun({
productKey: config.productKey,
deviceName: config.deviceName,
deviceSecret: config.deviceSecret
});
node.on('input', (msg) => {
node.device.publish(config.topic, JSON.stringify(msg.payload));
});
✅ 效果:团队所有设备上报,统一用此节点,安全又规范。
写在最后:从使用者到创造者
Node-RED 的强大,不仅在于它提供的 4000+ 节点,
更在于每个人都能成为生态的建设者。
当你把重复的 50 行 Function 代码,
封装成一个带图标、有校验、可共享的自定义节点时,
你就完成了从"自动化使用者"到"工具创造者"的跃迁。
在此之前,不妨动手做一个小节点:
比如 "timestamp-adder" ------ 自动给 msg 加上 ISO 时间戳 。
当你在调色板看到自己写的节点亮起绿灯时,你会明白------
真正的自由,是能按自己的方式扩展世界。
