这里写自定义目录标题
- 前言
- 示例简单介绍
- 变量产生
- opcuaServe配置
- 地址空间的配置
- 创建opcua服务器
- 获取命名空间
- 初始化变量
- 定义文件夹
- 定义文件夹中的变量
- view文件夹增加
- view文件夹中查阅信息定义
- 最终效果
- 加密设置
- opcuaServe组件配置
- 客户端配置
- 参考官网博文
前言
上期博文【Node-RED】node-red-contrib-opcua-server模块使用(1)中,我们主要介绍了,模块安装过程中遇到的相关问题。本期博文,我们介绍node-red-contrib-opcua-server模块的使用,并以官方示例中server-with-context.json流程为例展开介绍,主要涉及地址空间的配置和加密设置。
博文所提示例已经上传资源中,期间设置的所有相关设置都保留在流程中,可以下载使用。
示例简单介绍
示例主要由变量产生和opcuaServe配置 两部分组成。
变量产生
变量产生用到了注入中定时器,周期性的实现变量的生成和变化,变量主要有2部分,isoInput2-isoInput8,isoOutput2-isoOutput8,这个可以自定义,通过函数组件将变量保存到流程的上下文数据中,方便后续的使用。
通过点击注入,在上下文数据中可以进行数据查看,点击右上角的圆圈进行刷新,可以实时更新数据。
opcuaServe配置
node-red-contrib-opcua-server模块中实现opcuaServe配置,主要采用opcua-compact-server组件,在前期测试中,主要以匿名形式设置,加密可以直接跳转到后面加密设置。
- 需要勾选Setting 中的 Show Errors,方便错误信息的查看。
- Discovery中Endpoint Url需配置上地址,端口可以在Setting 中查看。如果Resource Path没有配置,又是本地,Endpoint Url设置为
opc.tcp://localhost:54840
,54840为默认端口,可以自定义更改;如果Resource Path配置了,Endpoint Url设置为opc.tcp://localhost:54840/UA/NodeRED/Compact
,UA/NodeRED/Compact为默认的资源地址。
然后点击部署,当显示active 即表示成功。
地址空间的配置
创建opcua服务器
const opcua = coreServer.choreCompact.opcua;
- 注意:爆红不影响使用
获取命名空间
const namespace = addressSpace.getOwnNamespace();
初始化变量
const Variant = opcua.Variant;const DataType = opcua.DataType;const DataValue = opcua.DataValue;var flexServerInternals = this;this.sandboxFlowContext.set("isoInput1", 0);this.setInterval(() => {flexServerInternals.sandboxFlowContext.set("isoInput1",Math.random() + 50.0);}, 500);this.sandboxFlowContext.set("isoInput2", 0);this.sandboxFlowContext.set("isoInput3", 0);...
定义文件夹
coreServer.debugLog("init dynamic address space");const rootFolder = addressSpace.findNode("RootFolder");node.warn("construct new address space for OPC UA");const myDevice = namespace.addFolder(rootFolder.objects, {"browseName": "RaspberryPI-Zero-WLAN"});const gpioFolder = namespace.addFolder(myDevice, { "browseName": "GPIO" });const isoInputs = namespace.addFolder(gpioFolder, {"browseName": "Inputs"});const isoOutputs = namespace.addFolder(gpioFolder, {"browseName": "Outputs"});
定义文件夹中的变量
const gpioDI1 = namespace.addVariable({"organizedBy": isoInputs,"browseName": "I1","nodeId": "ns=1;s=Isolated_Input1","dataType": "Double","value": {"get": function() {return new Variant({"dataType": DataType.Double,"value": flexServerInternals.sandboxFlowContext.get("isoInput1")});},"set": function(variant) {flexServerInternals.sandboxFlowContext.set("isoInput1",parseFloat(variant.value));return opcua.StatusCodes.Good;}}});const gpioDI2 = namespace.addVariable({"organizedBy": isoInputs,"browseName": "I2","nodeId": "ns=1;s=Isolated_Input2","dataType": "Double","value": {"get": function() {return new Variant({"dataType": DataType.Double,"value": flexServerInternals.sandboxFlowContext.get("isoInput2")});},"set": function(variant) {flexServerInternals.sandboxFlowContext.set("isoInput2",parseFloat(variant.value));return opcua.StatusCodes.Good;}}});...
view文件夹增加
const viewDI = namespace.addView({"organizedBy": rootFolder.views,"browseName": "RPIW0-Digital-Ins"});const viewDO = namespace.addView({"organizedBy": rootFolder.views,"browseName": "RPIW0-Digital-Outs"});
view文件夹中查阅信息定义
viewDI.addReference({"referenceType": "Organizes","nodeId": gpioDI1.nodeId});viewDI.addReference({"referenceType": "Organizes","nodeId": gpioDI2.nodeId});
最终效果
加密设置
opcuaServe组件配置
- 在Security中取消Allow Anonymous勾选
- 勾选Use individual Certificate Files
- Public填上公钥地址,Private填上私钥地址,可以直接用绝对地址,这里用了默认的相对地址
..\certificates
,不太对,依旧报没有路径下没有文件。
C:\Users\11003189\.node-red\node_modules\node-red-contrib-opcua-server\opcua-certificate-2048\server_selfsigned_cert_2048.pem
C:\Users\11003189\.node-red\node_modules\node-red-contrib-opcua-server\opcua-certificate-2048\server_key_2048.pem
客户端配置
- 将公钥的pem文件转der文件,私钥不用。
openssl x509 -in server_selfsigned_cert_2048.pem -out server_selfsigned_cert_2048.der -outform DER
- 在客户端里面直接导入公钥和私钥文件即可。
这里有一个问题,官网博文中说加密模式选Aes128Sha256RsaOaep,但是opcuaServe组件并不支持这个算法模式,所以最后也就没有连接成功,但是官网博文中一样的配置居然连接成功了,很迷。
参考官网博文
How to Deploy a Basic OPC-UA Server in Node-RED - Part 1
How to Build a Secure OPC-UA Server for PLCs in Node-RED
对node-red-contrib-opcua-server模块的研究就先到这里了,原以为该模块的函数部分编辑可以实现二次开发,结果只能是地址空间的配置,而且该模块也没有输出。
又测试了node-red-contrib-opcua,它主要是输出连接状态、收到的写入信息,不能在服务器中对输出信息进行二次处理。
基于以上的情况,需求依旧无法实现,上周的喜悦戛然而止,不过热情依旧,继续探索Opcua 的魅力,目前也看了c++中实现Opcua的底层函数,严重怀疑估计得改底层代码,庆幸NodeRed是开源的,因此继续研究。