node-red-opcua-otmr 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/opcua-otmr.html +76 -0
- package/opcua-otmr.js +81 -0
- package/package.json +22 -0
package/opcua-otmr.html
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
<script type="text/javascript">
|
2
|
+
RED.nodes.registerType('opcua-otmr', {
|
3
|
+
category: 'function',
|
4
|
+
color: '#77BFC7',
|
5
|
+
defaults: {
|
6
|
+
name: { value: "" },
|
7
|
+
endpoint: { value: "", required: true },
|
8
|
+
port: { value: 4840, validate: RED.validators.number(), required: true },
|
9
|
+
nodeIds: { value: "", required: true },
|
10
|
+
dataType: { value: "" }
|
11
|
+
},
|
12
|
+
inputs: 1,
|
13
|
+
outputs: 1,
|
14
|
+
icon: "node-red/parser-xml.svg",
|
15
|
+
label: function() {
|
16
|
+
return this.name || "opcua-otmr";
|
17
|
+
},
|
18
|
+
oneditprepare: function() {
|
19
|
+
$('#node-input-name').val(this.name);
|
20
|
+
$('#node-input-endpoint').val(this.endpoint);
|
21
|
+
$('#node-input-port').val(this.port);
|
22
|
+
$('#node-input-nodeIds').val(this.nodeIds);
|
23
|
+
$('#node-input-dataType').val(this.dataType);
|
24
|
+
|
25
|
+
$('#node-help').html("<p>This node communicates with an OPC UA server and reads values from various Node IDs.</p>");
|
26
|
+
|
27
|
+
},
|
28
|
+
oneditsave: function() {
|
29
|
+
this.name = $('#node-input-name').val();
|
30
|
+
this.endpoint = $('#node-input-endpoint').val();
|
31
|
+
this.port = $('#node-input-port').val();
|
32
|
+
this.nodeIds = $('#node-input-nodeIds').val();
|
33
|
+
this.dataType = $('#node-input-dataType').val();
|
34
|
+
|
35
|
+
if (!this.endpoint || !this.port || !this.nodeIds) {
|
36
|
+
RED.notify("Endpoint URL, Port, and Node IDs are required fields.", "error");
|
37
|
+
return false; // Prevents the node from being saved
|
38
|
+
}
|
39
|
+
}
|
40
|
+
});
|
41
|
+
</script>
|
42
|
+
|
43
|
+
<script type="text/html" data-template-name="opcua-otmr">
|
44
|
+
<div class="form-row">
|
45
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
46
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
47
|
+
</div>
|
48
|
+
<div class="form-row">
|
49
|
+
<label for="node-input-endpoint"><i class="fa fa-wifi"></i> Endpoint</label>
|
50
|
+
<input type="text" id="node-input-endpoint" placeholder="opc.tcp://hostname">
|
51
|
+
</div>
|
52
|
+
<div class="form-row">
|
53
|
+
<label for="node-input-port"><i class="fa fa-hashtag"></i> Port</label>
|
54
|
+
<input type="text" id="node-input-port" placeholder="4840">
|
55
|
+
</div>
|
56
|
+
<div class="form-row">
|
57
|
+
<label for="node-input-nodeIds"><i class="fa fa-list"></i> Node IDs</label>
|
58
|
+
<input type="text" id="node-input-nodeIds" placeholder="NodeID 1, NodeID 2, ...">
|
59
|
+
</div>
|
60
|
+
<!--
|
61
|
+
<div class="form-row">
|
62
|
+
<label for="node-input-dataType"><i class="fa fa-database"></i> Data Type</label>
|
63
|
+
<input type="text" id="node-input-dataType" placeholder="Data type 1, Data type 2, ...">
|
64
|
+
</div>
|
65
|
+
-->
|
66
|
+
|
67
|
+
<script type="text/html" data-help-name="opcua-otmr">
|
68
|
+
<p>This node communicates with an OPC UA server and reads values from various Node IDs. Data type of each NodeID will be captured automatically</p>
|
69
|
+
</script>
|
70
|
+
|
71
|
+
|
72
|
+
</script>
|
73
|
+
|
74
|
+
<script type="text/html" data-help-name="opcua-otmr">
|
75
|
+
<p>This node communicates with an OPC UA server and reads values from specified Node IDs.</p>
|
76
|
+
</script>
|
package/opcua-otmr.js
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
module.exports = function(RED) {
|
2
|
+
function OpcuaOtmrNode(config) {
|
3
|
+
RED.nodes.createNode(this, config);
|
4
|
+
var node = this;
|
5
|
+
node.endpoint = config.endpoint;
|
6
|
+
node.port = parseInt(config.port); // Parse port as an integer
|
7
|
+
node.nodeIds = config.nodeIds ? config.nodeIds.split(",").map(id => id.trim()) : []; // Split Node IDs by comma and trim whitespace, default to empty array
|
8
|
+
node.dataType = config.dataType;
|
9
|
+
|
10
|
+
const opcua = require("node-opcua");
|
11
|
+
let client = opcua.OPCUAClient.create();
|
12
|
+
let session = null;
|
13
|
+
|
14
|
+
async function connectToServer() {
|
15
|
+
try {
|
16
|
+
const endpointUrl = `${node.endpoint}:${node.port}`;
|
17
|
+
await client.connect(endpointUrl);
|
18
|
+
node.log("Connected to OPC UA server");
|
19
|
+
session = await client.createSession();
|
20
|
+
node.log("Session created");
|
21
|
+
} catch (err) {
|
22
|
+
node.error("Failed to connect to OPC UA server: " + err.message);
|
23
|
+
node.status({ fill: "red", shape: "ring", text: "connection failed" });
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
async function disconnectFromServer() {
|
28
|
+
if (session) {
|
29
|
+
try {
|
30
|
+
await session.close();
|
31
|
+
node.log("Session closed");
|
32
|
+
} catch (closeError) {
|
33
|
+
node.error("Failed to close session: " + closeError.message);
|
34
|
+
}
|
35
|
+
session = null;
|
36
|
+
}
|
37
|
+
await client.disconnect();
|
38
|
+
node.log("Disconnected from OPC UA server");
|
39
|
+
}
|
40
|
+
|
41
|
+
node.on('input', async function(msg) {
|
42
|
+
const nodeIds = node.nodeIds || msg.nodeIds || [];
|
43
|
+
const dataType = node.dataType || msg.dataType;
|
44
|
+
|
45
|
+
if (!node.endpoint || isNaN(node.port) || node.port < 0 || node.port > 65535 || nodeIds.length === 0) {
|
46
|
+
node.error("Endpoint URL, port, and Node IDs must be provided.");
|
47
|
+
node.status({ fill: "red", shape: "ring", text: "missing required fields" });
|
48
|
+
return;
|
49
|
+
}
|
50
|
+
|
51
|
+
if (!client || !session) {
|
52
|
+
await connectToServer();
|
53
|
+
}
|
54
|
+
|
55
|
+
try {
|
56
|
+
const dataValues = await Promise.all(nodeIds.map(async (nodeId) => {
|
57
|
+
const dataValue = await session.readVariableValue(nodeId);
|
58
|
+
return { nodeId, value: dataValue.value.value };
|
59
|
+
}));
|
60
|
+
node.log(`Read values from Node IDs: ${JSON.stringify(dataValues)}`);
|
61
|
+
msg.payload = dataValues;
|
62
|
+
node.send(msg);
|
63
|
+
node.status({ fill: "green", shape: "dot", text: "data read successfully" });
|
64
|
+
} catch (err) {
|
65
|
+
node.error("Failed to read values from OPC UA server: " + err.message);
|
66
|
+
node.status({ fill: "red", shape: "ring", text: "read error" });
|
67
|
+
}
|
68
|
+
});
|
69
|
+
|
70
|
+
node.on('close', async function() {
|
71
|
+
await disconnectFromServer();
|
72
|
+
});
|
73
|
+
|
74
|
+
process.on('SIGINT', async function() {
|
75
|
+
await disconnectFromServer();
|
76
|
+
process.exit();
|
77
|
+
});
|
78
|
+
}
|
79
|
+
|
80
|
+
RED.nodes.registerType("opcua-otmr", OpcuaOtmrNode);
|
81
|
+
};
|
package/package.json
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"name": "node-red-opcua-otmr",
|
3
|
+
"version": "2.0.0",
|
4
|
+
"description": "OPCUA communication",
|
5
|
+
"main": "opcua-otmr.js",
|
6
|
+
"scripts": {
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
8
|
+
},
|
9
|
+
"keywords": [
|
10
|
+
"OPCUA"
|
11
|
+
],
|
12
|
+
"author": "Omid Teimoori",
|
13
|
+
"license": "ISC",
|
14
|
+
"node-red": {
|
15
|
+
"nodes": {
|
16
|
+
"opcua-otmr": "opcua-otmr.js"
|
17
|
+
}
|
18
|
+
},
|
19
|
+
"dependencies": {
|
20
|
+
"node-opcua": "^2.126.0"
|
21
|
+
}
|
22
|
+
}
|