跳转至

Node-RED实现OPC UA数据采集与MQTT上报华为云

一、内容简介

在工业现场中,网关作为边缘数据处理节点,通过 OPC UA 协议连接 PLC 、工业控制设备或其他支持 OPC UA 的数据源,实现现场设备数据的标准化采集;随后利用 MQTT 协议将采集后的数据经过格式转换后安全、高效地上传至华为云 IoT 平台,实现设备数据的远程监控与管理。

本教程基于钡铼技术 BL118 边缘计算网关搭建一个完整的边缘数据采集与上云流程:使用网关内置 Node-RED 平台,通过 OPC UA 协议采集工业设备数据(使用本地模拟 OPC UA服务器),再通过 MQTT 协议将数据上报到华为云 IoT 平台。

二、前置准备

2.1 OPC UA 插件安装

打开 Node-RED 右上角菜单 - 管理面板 - 安装,搜索插件: node-red-contrib-opcua ,点击安装;

安装完成后左侧节点栏出现 opcua-server 、 opcua-client 、 opcua 工具类节点,用于搭建本地OPC UA 服务与采集客户端。

2.2 华为云IoT 平台准备

  1. 登录华为云 IoTDA ,创建产品、注册设备,获取设备 ID 、产品 ID ;
  2. 使用华为云 MQTT 客户端生成工具(地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/ )生成 MQTT 连接客户端 ID 、用户名、密码;
  3. 记录 IoTDA 接入域名、 MQTT 端口(标准 1883 非加密 /8883 TLS 加密)。

三、OPC UA 完整配置流程

3.1 创建本地模拟OPC UA Server

  1. 拖拽 opcua-server 节点至画布,双击打开配置面板:

宣传图

2.部署流程后可以看到OPC UA服务器正常运行。

宣传图

OPC UA server

running

3.2 OPC UA Client客户端配置

从 Node-Red左侧面板中拖一个OpeUa-Client节点到工作区, 双击OpcUa-Client节点, 配置如下:

宣传图

点击 Endpoint后的"笔型"按钮,打开 Endpoint编辑页面, IP地址为OPC UA Server所在设备地址,配置如下:

宣传图

3.3 创建OPC UA测试变量

  1. 拖拽 inject 注入节点,命名 add value ,配置如下:

宣传图

  1. 连接 debug 调试节点到 server 节点后面,部署流程;
  2. 手动点击 inject 节点触发,调试窗口输出变量创建成功日志

宣传图

3.4 订阅OPC UA 变量实时数据

  1. 复制 add value 节点,重命名为 Subscribe ,修改消息配置:

宣传图

  1. 将 Subscribe 节点输出连接至 opcua-client 输入端;
  2. 部署流程后,服务端会重启,需先执行 add value 重建变量,再触发 Subscribe 订阅;

宣传图

3.5 取消订阅

  1. 复制 Subscribe节点, 命名 Unsubscribe, 修改 payload:

宣传图

2.触发节点后日志提示 unsubscribing,停止接收该变量推送。

四、MQTT节点对接华为云IoTDA配置

4.1m qtt节点配置

拖入一个 mqtt out节点,双击配置如下:

宣传图

上报主题: 华为云标准属性上报主题$ oc/ devices/{device _ id}/ sys/ properties/ report.(device _ id}替换为真实设备ID;

点击服务端后的"笔型"按钮,配置接入信息

宣传图

宣传图

4.2 Function数据格式转换节点

OPC UA采集到的原始数据不能直接上报,需要转换为华为云IoTDA要求的JSON格式。在OpeUa-Client和 mqtt out节点之间拖入一个 Function节点, 双击打开编辑, 填入以下代码:

//转换OPC UA采集数据为华为云标准属性上报报文

let data= msg. payload. value;

let res={
" services":[],
" properties": {
" temperature": data // 对应平台产品模型定义的属性名},
"eventTime": new Date(). getTime(). toString()


};

msg. payload= JSON. stringify(res);

return msg;

五、云端验证

全部节点部署完成,先点击订阅,此时还未赋值,执行 add value 创建变量后,再触发Subscribe 开启实时采集,此时云端变量值变为设定的30;

宣传图

宣传图

六、OPC UA、MQTT优缺点对比

| 对比项 | OPC UA | MQTT | | 主要用途 | 工业设备数据采集 | 工业设备数据采集 | | 通信模型 | 客户端/服务器 | 发布/订阅 | | 实时性 | 高 | 高 | | 安全性 | 支持证书、加密 | 依赖TLS认证 | | 数据模型 | 丰富,支持节点模型 | 简单消息模型 | | 典型场景 | PLC、SCADA、MES | loT平台、云端监控 |

OPC UA和MQTT并不是替代关系,而是上下游协作关系。OPC UA负责工业现场数据标准化采集,MQTT负责数据高效传输到云平台。

七、总结

在工业物联网场景中,OPCUA与MQTT组合是一种常见的数据上云架构。OPCUA负责现场设备数据采集,MQTT 负责边缘侧与云平台的数据传输,两者结合能够兼顾工业兼容性和云端接入效率。

[
    {
        "id": "f3f15bacdde76a69",
        "type": "OpcUa-Server",
        "z": "e65dce2b3df1277b",
        "port": "4840",
        "name": "",
        "endpoint": "",
        "users": "",
        "nodesetDir": "",
        "autoAcceptUnknownCertificate": true,
        "registerToDiscovery": false,
        "constructDefaultAddressSpace": true,
        "allowAnonymous": true,
        "endpointNone": true,
        "endpointSign": true,
        "endpointSignEncrypt": true,
        "endpointBasic128Rsa15": true,
        "endpointBasic256": true,
        "endpointBasic256Sha256": true,
        "maxNodesPerBrowse": 0,
        "maxNodesPerHistoryReadData": 0,
        "maxNodesPerHistoryReadEvents": 0,
        "maxNodesPerHistoryUpdateData": 0,
        "maxNodesPerRead": 0,
        "maxNodesPerWrite": 0,
        "maxNodesPerMethodCall": 0,


        "maxNodesPerRegisterNodes": 0,
        "maxNodesPerNodeManagement": 0,
        "maxMonitoredItemsPerCall": 0,
        "maxNodesPerHistoryUpdateEvents": 0,
        "maxNodesPerTranslateBrowsePathsToNodeIds": 0,
        "maxConnectionsPerEndpoint": 20,
        "maxMessageSize": 4096,
        "maxBufferSize": 4096,
        "maxSessions": 20,
        "x": 420,
        "y": 140,
        "wires": [
            [
                "0beeecb74fd4c7ea"
            ]
        ]
    },
    {
        "id": "2fa06dcd0efae16a",
        "type": "OpcUa-Client",
        "z": "e65dce2b3df1277b",
        "endpoint": "3b672bd8c700a6a4",
        "action": "read",
        "deadbandtype": "a",
        "deadbandvalue": 1,
        "time": 10,
        "timeUnit": "s",


        "certificate": "n",
        "localfile": "",
        "localkeyfile": "",
        "securitymode": "None",
        "securitypolicy": "None",
        "useTransport": false,
        "maxChunkCount": 1,
        "maxMessageSize": 8192,
        "receiveBufferSize": 8192,
        "sendBufferSize": 8192,
        "setstatusandtime": false,
        "keepsessionalive": false,
        "name": "",
        "applicationName": "",
        "applicationUri": "",
        "x": 360,
        "y": 320,
        "wires": [
            [
                "46d1590b12e81355",
                "3f95a8c49fe83119"
            ],
            [],
            []
        ]
    },
    {


        "id": "3f95a8c49fe83119",
        "type": "debug",
        "z": "e65dce2b3df1277b",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 540,
        "y": 260,
        "wires": []
    },
    {
        "id": "0beeecb74fd4c7ea",
        "type": "debug",
        "z": "e65dce2b3df1277b",
        "name": "debug 2",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",




        "y": 140,
        "wires": [
            [
                "f3f15bacdde76a69"
            ]
        ]
    },
    {
        "id": "9307d4d78d376da3",
        "type": "inject",
        "z": "e65dce2b3df1277b",
        "name": "Subscribe",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "ns=1;s=TestAddVariable",
        "payload": "{ \"action\": \"subscribe\"}",


        "payloadType": "json",
        "x": 140,
        "y": 300,
        "wires": [
            [
                "2fa06dcd0efae16a"
            ]
        ]
    },
    {
        "id": "7bc50aa9e07b3450",
        "type": "inject",
        "z": "e65dce2b3df1277b",
        "name": "Unsubscribe",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,


        "topic": "ns=1;s=TestAddVariable",
        "payload": "{ \"action\": \"unsubscribe\"}",
        "payloadType": "json",
        "x": 130,
        "y": 340,
        "wires": [
            [
                "2fa06dcd0efae16a"
            ]
        ]
    },
    {
        "id": "513a0236a53a64b2",
        "type": "mqtt out",
        "z": "e65dce2b3df1277b",
        "name": "",
        "topic": "$oc/devices/6a4df1276b6c4d5f8d6731e1_test/sys/properties/report",
        "qos": "0",
        "retain": "",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "9ff3171cd70e07aa",
        "x": 860,
        "y": 320,


        "wires": []
    },
    {
        "id": "46d1590b12e81355",
        "type": "function",
        "z": "e65dce2b3df1277b",
        "name": "function 7",
        "func": "//  取出  OPC UA  推送的数值 \nvar value = msg.payload;\n\n//  华为云属\n性上报  JSON  格式 \nmsg.payload = {\n    \"services\": [\n        {\n            \"service_id\": \"s1\",          //  改为你实际的服务 ID\n            \"properties\": {\n                \"hum\": value       //  改为你实际的\n属性标识符 \n            }\n        }\n    ]\n};\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 540,
        "y": 320,
        "wires": [
            [
                "513a0236a53a64b2"
            ]
        ]
    },
    {
        "id": "3b672bd8c700a6a4",


        "type": "OpcUa-Endpoint",
        "endpoint": "opc.tcp://127.0.0.1:4840",
        "secpol": "None",
        "secmode": "None",
        "none": true,
        "login": false,
        "usercert": false,
        "usercertificate": "",
        "userprivatekey": ""
    },
    {
        "id": "9ff3171cd70e07aa",
        "type": "mqtt-broker",
        "name": "",
        "broker": "8292c9706d.iotda-device.cn-south-4.myhuaweicloud.com",
        "port": "1883",
        "tls": "",
        "clientid": "6a4df1276b6c4d5f8d6731e1_test_0_1_2026070811",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",


        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]

售后支持: 0755-29451836