node-red - 节点实战总结
二、功能
2.1 循环(for\while)
安装节点node-red-contrib-loop-processing
,该节点支持三种方式的循环:
- array-loop:数组循环,功能类似于数组的forEach或for循环,但此节点无法处理关联的数组,使用示例如下
- counter-loop:使用计数器循环。相当于for(int i=s;i<length;i+n)循环,支持设置指定下标、指定递增值、指定循环结束点。
- while-loop:使用条件循环。相当于while循环。
回到目录
三、网络
3.1 mqtt in\out
安装节点node-red
,将提供与mqtt互联的节点mqtt in 和 ,mqtt out详细使用参考链接:
3.2 httpin/http response/http request
安装节点node-red
,将提供用于Web服务交互的HTTP端点操作。包含http in、http response、http request,详细使用参考链接:
- 【Node-red:httpin/http response/http request节点的使用】
- 【设置http get请求和设置response响应】
- 【Node-red:使用http-request实现post 请求,带请求头和传参】
- 【Node-red:http websoket】
六、存储
6.1 write/read/watch file
安装节点node-red
,将提供用于文件的读\写\删除\增加操作。详细使用参考链接:
【file控件介绍】
6.2 MySQL存/取
安装节点node-red-contrib-stackhero-mysql
,用于读取和写入MySQL或MariaDB数据库。
它使用TLS(SSL)加密,并且与“缓存SHA2密码”身份验证方法兼容(MySQL> = 8)。
使用时,先创建或选择一个数据库实例,并设置名称。
创建数据库实例操作如下:
通过function中的topic和payload对数据库进行增\删\改\查操作,详细如下实例:
- select:查询操作
- insert:插入操作
- 单条插入:
(1)不使用payload传入,直接使用topic中sql表示语句
(2)使用payload传入,在使用topic的sql语句中创建变量,注意变量与payload的object的key要保持一致。
- 批量插入:
- update:更新操作
- delete:删除操作
回到目录
6.3 redis存/取
安装节点node-red-contrib-redis
,用于与redis数据库的交互。使用参考链接:
【Node-RED 读写操作redis】
6.4 TDEngine存/取
安装节点node-red-contrib-tdengine
,用于与TDEngine数据库的交互。
- 数据查询
- 多表插入语句
- 删除语句
七、协议
7.1 modbus
安装节点node-red-contrib-modbus
,用于向ModbusTCP设备写数据或读取ModbusTCP设备数据。使用参考链接:
【Node-RED采集modbus数据】
注意:node-red通过modbus协议采集时,端口不能在0-100以内,node-red会出问题
7.2 opcua - (abplc)
安装节点node-red-contrib-opcua
,基于OPC UA与西门子PLC进行通讯。比如对于AB协议的PLC,node-red暂时不支持直接进行通讯,需要先通过OPC UA服务器与客户端进行通信,然后node-red与OPC UA的进行通讯,从而达到数据管理的目的。使用参考链接:
【Node-RED opc-ua节点操作】
7.3 s7
安装节点node-red-contrib-s7
,基于 Node-red S7 通信,实现 SIMATIC IOT2040 读写 Siemens S7-300/400/1200/1500 或 S7-200 Smart PLC 中的数据。S7 节点是一个允许使用西门子 S7 以太网协议 RFC1006 与 S7-300/400/1200/1500 PLC通信的库。同时,它也适用于 S7-200 Smart PLC。
使用参考链接:
7.4 amqp
安装节点@meowwolf/node-red-contrib-amqp@2.4.1
,基于AMQP协议,实现客户端与消息中间件数据的传递。
AMQP,即 Advanced Message Queuing Protocol(高级消息队列协议),是一个网络协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
一般搭配RabitMQ进行使用,RabbitMQ是一个开源的,在AMQP基础上完整的,可复用的企业消息系统。
节点使用参考链接:node-red:使用node-red-contrib-amqp节点,实现与RabbitMQ服务器(AMQP)的消息传递
八、formats
8.1 时间格式化与时区转换
【node-red-contrib-moment 中文文档教程】
【node-red时区问题解决方案对比】
安装节点node-red-contrib-moment
,使用 Moment.JS 生成格式良好的日期/时间字符串和进行时区/DST/区域设置。
- 对时间字符串进行格式化输出:
选用Date/Time Formatter
节点,配置输入、输出、时区及格式:
- Input(输入):时间(Date)格式的数据
- Format(格式):支持两种格式输入:
(1)如果format为ISO8601
,则输出采用 ISO 8601格式,等同于date.toISOString(),例如“2015-01-28T16:24:48.123Z”。请注意,ISO8601 格式的输出始终采用 UTC(“Z”,祖鲁时间),而不是本地时间,无论您指定哪个输出时区。
(2)手动指定格式字符串,如YYYY-MM-DD HH:mm:ss
更多示例:
- “DD.MM.YYYY HH:mm”给出20.09.2020 08:30
- “dddd, MMMM Do YYYY, h:mm:ss a”给出Sunday, February 14th 2010, 3:25:50 pm
- “[Today is] dddd”给出 Today is Sunday
- “[Date: ]YYYY-MM-DD [Time:]HH:mm:ss”给出 < em>日期:2020-09-20 时间:08:31:45
- locale(时区设置):时区表链接:https://lh.2xlibre.net/locales/
回到目录
8.2 输入(定时器)
安装节点node-red-contrib-cron-plus
,一个灵活的定时器/调度器(cron、solar events、simple dates)节点,具有完全的动态控制和时区支持。
详细使用参考官网案例:https://flows.nodered.org/node/node-red-contrib-cron-plus
九、解析
9.1 buffer-parser
安装节点node-red-contrib-buffer-parser
,用于在缓冲区/数组之间转换值。支持大/小端序、BCD、字节交换等。
- 一、将十六进制数组字节流转换为十进制数字:
- 更多示例:
源码:
[
{
"id": "1523dd03.6332f3",
"type": "buffer-parser",
"z": "ba42f58dd77dba8a",
"name": "",
"data": "payload",
"dataType": "msg",
"specification": "{\"options\":{\"byteSwap\":[\"swap16\"],\"resultType\":\"object\",\"singleResult\":true,\"msgProperty\":\"data\"},\"items\":[{\"name\":\"alphabet\",\"type\":\"string\",\"offset\":0,\"length\":26},{\"name\":\"single byte pos 4\",\"type\":\"int\",\"offset\":4},{\"name\":\"bcd equiv\",\"type\":\"bcd\",\"offset\":4,\"length\":5},{\"name\":\"Array[6] of int16le\",\"type\":\"int16le\",\"offset\":26,\"length\":6},{\"name\":\"Array[6] of int16be\",\"type\":\"int16be\",\"offset\":26,\"length\":6},{\"name\":\"32 bools\",\"type\":\"bool\",\"offset\":0,\"length\":32},{\"name\":\"Array[4] of 16bits\",\"type\":\"16bit\",\"offset\":0,\"length\":4}]}",
"specificationType": "ui",
"items": [
{
"type": "string",
"name": "alphabet",
"offset": 0,
"length": 26,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "int8",
"name": "single byte pos 4",
"offset": 4,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "bcd",
"name": "bcd equiv",
"offset": 4,
"length": 5,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "int16le",
"name": "Array[6] of int16le",
"offset": 26,
"length": 6,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "int16be",
"name": "Array[6] of int16be",
"offset": 26,
"length": 6,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "bool",
"name": "32 bools",
"offset": 0,
"length": 32,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "16bitbe",
"name": "Array[4] of 16bits",
"offset": 0,
"length": 4,
"offsetbit": 0,
"scale": "1",
"mask": ""
}
],
"swap1": "swap16",
"swap2": "",
"swap3": "",
"swap1Type": "swap",
"swap2Type": "swap",
"swap3Type": "swap",
"msgProperty": "data",
"msgPropertyType": "",
"resultType": "object",
"resultTypeType": "",
"multipleResult": false,
"fanOutMultipleResult": false,
"setTopic": true,
"outputs": 1,
"x": 410,
"y": 300,
"wires": [
[
"a3051c67.b82ad"
]
]
},
{
"id": "a3051c67.b82ad",
"type": "debug",
"z": "ba42f58dd77dba8a",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "data",
"targetType": "msg",
"x": 640,
"y": 300,
"wires": []
},
{
"id": "9b72f1f5.1aacc",
"type": "inject",
"z": "ba42f58dd77dba8a",
"name": "Fake PLC data 16bit Array",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[25185,25699,26213,26727,27241,27755,28013,28783,29297,29811,30325,30839,31353,256,512,768,1024,1280,1536,1792,2048,2304,2560,2816,3072,3597]",
"payloadType": "json",
"x": 190,
"y": 300,
"wires": [
[
"1523dd03.6332f3",
"41581ab6f61cec9a"
]
]
},
{
"id": "a9a2dd4c.118f9",
"type": "comment",
"z": "ba42f58dd77dba8a",
"name": "取一个16位值的数组,进行字节反转,拆分出几个值,并在msg.data中传输一个包含命名对象的消息",
"info": "",
"x": 400,
"y": 260,
"wires": []
},
{
"id": "1194a28a.49d0ad",
"type": "buffer-parser",
"z": "ba42f58dd77dba8a",
"name": "",
"data": "payload",
"dataType": "msg",
"specification": "{\"options\":{\"byteSwap\":[\"swap16\"],\"resultType\":\"value\",\"singleResult\":false,\"msgProperty\":\"payload\"},\"items\":[{\"name\":\"plc1/production/alphabet\",\"type\":\"string\",\"offset\":0,\"length\":26},{\"name\":\"plc1/production/status/count\",\"type\":\"int\",\"offset\":25},{\"name\":\"plc1/production/status/sequence\",\"type\":\"bcd\",\"offset\":4},{\"name\":\"plc1/machine/status/runner/temperature\",\"type\":\"int16le\",\"offset\":26},{\"name\":\"plc1/machine/status/runner/speed\",\"type\":\"int16be\",\"offset\":26},{\"name\":\"plc1/machine/status/running\",\"type\":\"bool\",\"offset\":0,\"offsetbit\":0},{\"name\":\"plc1/machine/status/warning\",\"type\":\"bool\",\"offset\":0,\"offsetbit\":1},{\"name\":\"plc1/machine/status/fault\",\"type\":\"bool\",\"offset\":0,\"offsetbit\":2}]}",
"specificationType": "ui",
"items": [
{
"type": "string",
"name": "plc1/production/alphabet",
"offset": 0,
"length": 26,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "int8",
"name": "plc1/production/status/count",
"offset": 25,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "bcd",
"name": "plc1/production/status/sequence",
"offset": 4,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "int16le",
"name": "plc1/machine/status/runner/temperature",
"offset": 26,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "int16be",
"name": "plc1/machine/status/runner/speed",
"offset": 26,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "bool",
"name": "plc1/machine/status/running",
"offset": 0,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
},
{
"type": "bool",
"name": "plc1/machine/status/warning",
"offset": 0,
"length": 1,
"offsetbit": 1,
"scale": "1",
"mask": ""
},
{
"type": "bool",
"name": "plc1/machine/status/fault",
"offset": 0,
"length": 1,
"offsetbit": 2,
"scale": "1",
"mask": ""
}
],
"swap1": "swap16",
"swap2": "",
"swap3": "",
"swap1Type": "swap",
"swap2Type": "swap",
"swap3Type": "swap",
"msgProperty": "payload",
"msgPropertyType": "",
"resultType": "value",
"resultTypeType": "",
"multipleResult": true,
"fanOutMultipleResult": false,
"setTopic": true,
"outputs": 1,
"x": 410,
"y": 460,
"wires": [
[
"858b1ecf.77b58"
]
]
},
{
"id": "858b1ecf.77b58",
"type": "debug",
"z": "ba42f58dd77dba8a",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"x": 650,
"y": 460,
"wires": []
},
{
"id": "c22cd2e8.52649",
"type": "inject",
"z": "ba42f58dd77dba8a",
"name": "Fake PLC data 16bit Array",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "[25185,25699,26213,26727,27241,27755,28013,28783,29297,29811,30325,30839,31353,256,512,768,1024,1280,1536,1792,2048,2304,2560,2816,3072,3597]",
"payloadType": "json",
"x": 190,
"y": 460,
"wires": [
[
"1194a28a.49d0ad",
"b55c0bab245908d7"
]
]
},
{
"id": "970db39d.106a6",
"type": "comment",
"z": "ba42f58dd77dba8a",
"name": "取一个16位值的数组,进行字节反转,拆分出几个值,并使用主题+有效载荷传输单个消息",
"info": "",
"x": 370,
"y": 420,
"wires": []
},
{
"id": "41581ab6f61cec9a",
"type": "debug",
"z": "ba42f58dd77dba8a",
"name": "debug 26",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 400,
"y": 360,
"wires": []
},
{
"id": "b55c0bab245908d7",
"type": "debug",
"z": "ba42f58dd77dba8a",
"name": "debug 27",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 400,
"y": 520,
"wires": []
}
]