@vitormnm/node-red-simple-opcua 1.0.2 → 1.0.3
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/client/lib/opcua-client-browser.js +291 -0
- package/client/lib/opcua-client-read-service.js +16 -0
- package/client/lib/opcua-client-subscription-id-service.js +25 -0
- package/client/lib/opcua-client-subscription-service.js +171 -0
- package/client/lib/opcua-client-write-service.js +53 -0
- package/client/opcua-client-config.html +80 -0
- package/client/opcua-client-config.js +159 -0
- package/client/opcua-client-utils.js +320 -0
- package/client/opcua-client.html +1225 -0
- package/client/opcua-client.js +380 -0
- package/object.json +65 -0
- package/package.json +1 -5
- package/server/lib/opcua-address-space-alarm.js +341 -0
- package/server/lib/opcua-address-space-builder.js +1456 -0
- package/server/lib/opcua-config.js +546 -0
- package/server/lib/opcua-constants.js +109 -0
- package/server/lib/opcua-server-events-child.js +140 -0
- package/server/lib/opcua-server-methods.js +198 -0
- package/server/lib/opcua-server-runtime-child.js +729 -0
- package/server/lib/opcua-server-runtime.js +311 -0
- package/server/lib/opcua-server-status-child.js +188 -0
- package/server/lib/server-node-utils.js +16 -0
- package/server/opcua-server-io.html +347 -0
- package/server/opcua-server-io.js +463 -0
- package/server/opcua-server-registry.js +270 -0
- package/server/opcua-server.css +265 -0
- package/server/opcua-server.html +1548 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
(function () {
|
|
3
|
+
function updateModeUi(node) {
|
|
4
|
+
var mode = $("#node-input-mode").val() || "read";
|
|
5
|
+
var identifierType = $("#node-input-identifierType").val() || "path";
|
|
6
|
+
var isTagMode = mode === "read" || mode === "write" || mode === "event" || mode === "activeAlarms";
|
|
7
|
+
var isMethodMode = mode === "method-input" || mode === "method-output";
|
|
8
|
+
var isEventsMode = mode === "events";
|
|
9
|
+
|
|
10
|
+
$(".opcua-server-io-tag-row").toggle(isTagMode);
|
|
11
|
+
$(".opcua-server-io-tag-path-row").toggle(isTagMode && identifierType === "path");
|
|
12
|
+
$(".opcua-server-io-tag-nodeid-row").toggle(isTagMode && identifierType === "nodeId");
|
|
13
|
+
$(".opcua-server-io-method-row").toggle(isMethodMode);
|
|
14
|
+
$(".opcua-server-io-events-row").toggle(isEventsMode);
|
|
15
|
+
|
|
16
|
+
node.mode = mode;
|
|
17
|
+
node.identifierType = identifierType;
|
|
18
|
+
if (mode === "method-input") {
|
|
19
|
+
node.inputs = 0;
|
|
20
|
+
node.outputs = 1;
|
|
21
|
+
} else if (mode === "events") {
|
|
22
|
+
node.inputs = 0;
|
|
23
|
+
node.outputs = 1;
|
|
24
|
+
} else if (mode === "method-output") {
|
|
25
|
+
node.inputs = 1;
|
|
26
|
+
node.outputs = 0;
|
|
27
|
+
} else {
|
|
28
|
+
node.inputs = 1;
|
|
29
|
+
node.outputs = 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
node._def.inputs = node.inputs;
|
|
33
|
+
node._def.outputs = node.outputs;
|
|
34
|
+
RED.nodes.dirty(true);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function loadServerRefOptions(node) {
|
|
38
|
+
|
|
39
|
+
var currentValue = $("#node-input-serverRef").typedInput("value") || node.serverRef || "";
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
return $.getJSON("opcua-server-io/servers").done(function (servers) {
|
|
43
|
+
var options = (servers || []).map(function (server) {
|
|
44
|
+
// return {
|
|
45
|
+
// value: server.value || server.serverName || server.name || server.id,
|
|
46
|
+
// label: server.label || server.serverName || server.name || server.id
|
|
47
|
+
// };
|
|
48
|
+
return {
|
|
49
|
+
value: server,
|
|
50
|
+
label: server
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (currentValue && !options.some(function (option) { return option.value === currentValue; })) {
|
|
55
|
+
options.unshift({
|
|
56
|
+
value: currentValue,
|
|
57
|
+
label: currentValue
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
$("#node-input-serverRef").typedInput("types", [{
|
|
62
|
+
value: "server",
|
|
63
|
+
options: options
|
|
64
|
+
}]);
|
|
65
|
+
|
|
66
|
+
if (currentValue) {
|
|
67
|
+
$("#node-input-serverRef").typedInput("value", currentValue);
|
|
68
|
+
}
|
|
69
|
+
}).fail(function () {
|
|
70
|
+
$("#node-input-serverRef").typedInput("types", [{
|
|
71
|
+
value: "server",
|
|
72
|
+
options: currentValue ? [{ value: currentValue, label: currentValue }] : []
|
|
73
|
+
}]);
|
|
74
|
+
if (currentValue) {
|
|
75
|
+
$("#node-input-serverRef").typedInput("value", currentValue);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
RED.nodes.registerType("opcua-server-io", {
|
|
81
|
+
category: "network",
|
|
82
|
+
color: "#d9edf7",
|
|
83
|
+
defaults: {
|
|
84
|
+
name: { value: "" },
|
|
85
|
+
serverRef: { value: "" },
|
|
86
|
+
mode: { value: "read", required: true },
|
|
87
|
+
identifierType: { value: "path" },
|
|
88
|
+
tagPath: { value: "" },
|
|
89
|
+
tagNodeId: { value: "" },
|
|
90
|
+
methodName: { value: "" },
|
|
91
|
+
intervalMs: {
|
|
92
|
+
value: 500,
|
|
93
|
+
required: true,
|
|
94
|
+
validate: RED.validators.number()
|
|
95
|
+
},
|
|
96
|
+
inputs: { value: 1 },
|
|
97
|
+
outputs: { value: 1 }
|
|
98
|
+
},
|
|
99
|
+
inputs: 1,
|
|
100
|
+
outputs: 1,
|
|
101
|
+
icon: "bridge.svg",
|
|
102
|
+
label: function () {
|
|
103
|
+
return this.name || this.methodName || this.tagPath || this.tagNodeId || "opcua-server-io";
|
|
104
|
+
},
|
|
105
|
+
oneditprepare: function () {
|
|
106
|
+
var node = this;
|
|
107
|
+
var modeField = $("#node-input-mode");
|
|
108
|
+
var identifierField = $("#node-input-identifierType");
|
|
109
|
+
var serverRefField = $("#node-input-serverRef");
|
|
110
|
+
|
|
111
|
+
modeField.val(node.mode || "read");
|
|
112
|
+
identifierField.val(node.identifierType || "path");
|
|
113
|
+
serverRefField.typedInput({
|
|
114
|
+
type: "server",
|
|
115
|
+
types: [{
|
|
116
|
+
value: "server",
|
|
117
|
+
options: []
|
|
118
|
+
}]
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
loadServerRefOptions(node);
|
|
122
|
+
modeField.on("change", function () {
|
|
123
|
+
updateModeUi(node);
|
|
124
|
+
});
|
|
125
|
+
identifierField.on("change", function () {
|
|
126
|
+
updateModeUi(node);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
updateModeUi(node);
|
|
130
|
+
},
|
|
131
|
+
oneditsave: function () {
|
|
132
|
+
var mode = $("#node-input-mode").val() || "read";
|
|
133
|
+
this.mode = mode;
|
|
134
|
+
this.serverRef = $("#node-input-serverRef").typedInput("value") || "";
|
|
135
|
+
this.identifierType = $("#node-input-identifierType").val() || "path";
|
|
136
|
+
|
|
137
|
+
if (mode === "method-input") {
|
|
138
|
+
this.inputs = 0;
|
|
139
|
+
this.outputs = 1;
|
|
140
|
+
} else if (mode === "events") {
|
|
141
|
+
this.inputs = 0;
|
|
142
|
+
this.outputs = 1;
|
|
143
|
+
} else if (mode === "method-output") {
|
|
144
|
+
this.inputs = 1;
|
|
145
|
+
this.outputs = 0;
|
|
146
|
+
} else {
|
|
147
|
+
this.inputs = 1;
|
|
148
|
+
this.outputs = 1;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
})();
|
|
153
|
+
</script>
|
|
154
|
+
|
|
155
|
+
<script type="text/html" data-template-name="opcua-server-io">
|
|
156
|
+
<div class="form-row">
|
|
157
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
158
|
+
<input type="text" id="node-input-name" placeholder="opcua-server-io">
|
|
159
|
+
</div>
|
|
160
|
+
<div class="form-row">
|
|
161
|
+
<label for="node-input-serverRef"><i class="fa fa-server"></i> Server</label>
|
|
162
|
+
<input type="text" id="node-input-serverRef" placeholder="Optional: server name or serverName">
|
|
163
|
+
</div>
|
|
164
|
+
<div class="form-row">
|
|
165
|
+
<label for="node-input-mode"><i class="fa fa-exchange"></i> Mode</label>
|
|
166
|
+
<select id="node-input-mode">
|
|
167
|
+
<option value="read">Read</option>
|
|
168
|
+
<option value="write">Write</option>
|
|
169
|
+
<option value="event">Event</option>
|
|
170
|
+
<option value="events">Events Server</option>
|
|
171
|
+
<option value="status">Status Server</option>
|
|
172
|
+
<option value="activeAlarms">Active Alarms</option>
|
|
173
|
+
<option value="method-input">Method Input</option>
|
|
174
|
+
<option value="method-output">Method Output</option>
|
|
175
|
+
</select>
|
|
176
|
+
</div>
|
|
177
|
+
<div class="form-row opcua-server-io-events-row">
|
|
178
|
+
<label for="node-input-intervalMs"><i class="fa fa-clock-o"></i> Interval (ms)</label>
|
|
179
|
+
<input type="text" id="node-input-intervalMs" placeholder="500">
|
|
180
|
+
</div>
|
|
181
|
+
<div class="form-row opcua-server-io-tag-row">
|
|
182
|
+
<label for="node-input-identifierType"><i class="fa fa-crosshairs"></i> Identifier</label>
|
|
183
|
+
<select id="node-input-identifierType">
|
|
184
|
+
<option value="path">Path</option>
|
|
185
|
+
<option value="nodeId">NodeId</option>
|
|
186
|
+
</select>
|
|
187
|
+
</div>
|
|
188
|
+
<div class="form-row opcua-server-io-tag-row opcua-server-io-tag-path-row">
|
|
189
|
+
<label for="node-input-tagPath"><i class="fa fa-sitemap"></i> Tag path</label>
|
|
190
|
+
<input type="text" id="node-input-tagPath" placeholder="Maquina1.Sensores.MotorA.Ligado">
|
|
191
|
+
</div>
|
|
192
|
+
<div class="form-row opcua-server-io-tag-row opcua-server-io-tag-nodeid-row">
|
|
193
|
+
<label for="node-input-tagNodeId"><i class="fa fa-hashtag"></i> Tag nodeId</label>
|
|
194
|
+
<input type="text" id="node-input-tagNodeId" placeholder="ns=1;s=Maquina1.Sensores.MotorA.Ligado">
|
|
195
|
+
</div>
|
|
196
|
+
<div class="form-row opcua-server-io-method-row">
|
|
197
|
+
<label for="node-input-methodName"><i class="fa fa-cogs"></i> Method</label>
|
|
198
|
+
<input type="text" id="node-input-methodName" placeholder="cmd_on">
|
|
199
|
+
</div>
|
|
200
|
+
</script>
|
|
201
|
+
|
|
202
|
+
<script type="text/html" data-help-name="opcua-server-io">
|
|
203
|
+
<p>Unified server-side node for read, write and OPC UA method flow integration.</p>
|
|
204
|
+
|
|
205
|
+
<h3>Modes</h3>
|
|
206
|
+
<p><b>Read</b>: reads tags from an active <code>opc-ua-server</code> node.</p>
|
|
207
|
+
<p><b>Write</b>: writes values to tags in an active <code>opc-ua-server</code> node.</p>
|
|
208
|
+
<p><b>Method Input</b>: receives method calls coming from OPC UA clients.</p>
|
|
209
|
+
<p><b>Method Output</b>: sends the method response back to the waiting OPC UA call.</p>
|
|
210
|
+
|
|
211
|
+
<h3>Read</h3>
|
|
212
|
+
<p><b>Input</b>:</p>
|
|
213
|
+
<p>Use <code>msg.payload</code> as an array of items. The field <code>path</code> is the identifier to read, following the selected <code>Identifier</code> mode.</p>
|
|
214
|
+
<pre><code>{
|
|
215
|
+
"payload": [
|
|
216
|
+
{
|
|
217
|
+
"name": "status",
|
|
218
|
+
"path": "ns=2;s=Factory.Line1.Motor1.status"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"name": "speed",
|
|
222
|
+
"path": "ns=2;s=Factory.Line1.Motor1.speed"
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
}</code></pre>
|
|
226
|
+
<p><b>Output</b>:</p>
|
|
227
|
+
<pre><code>{
|
|
228
|
+
"topic": "ns=2;s=Factory.Line1.Motor1.status",
|
|
229
|
+
"payload": [
|
|
230
|
+
{
|
|
231
|
+
"name": "status",
|
|
232
|
+
"path": "ns=2;s=Factory.Line1.Motor1.status",
|
|
233
|
+
"value": true
|
|
234
|
+
}
|
|
235
|
+
],
|
|
236
|
+
"opcua": {
|
|
237
|
+
"identifierType": "nodeId",
|
|
238
|
+
"server": "MeuServidor",
|
|
239
|
+
"readNodeIds": ["ns=2;s=Factory.Line1.Motor1.status"],
|
|
240
|
+
"tagNodeId": "ns=2;s=Factory.Line1.Motor1.status"
|
|
241
|
+
}
|
|
242
|
+
}</code></pre>
|
|
243
|
+
|
|
244
|
+
<h3>Write</h3>
|
|
245
|
+
<p><b>Input</b>:</p>
|
|
246
|
+
<p>Use the same array format, adding <code>value</code> in each item.</p>
|
|
247
|
+
<pre><code>{
|
|
248
|
+
"payload": [
|
|
249
|
+
{
|
|
250
|
+
"name": "status",
|
|
251
|
+
"path": "ns=2;s=Factory.Line1.Motor1.status",
|
|
252
|
+
"value": 10
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
}</code></pre>
|
|
256
|
+
<p><b>Output</b>:</p>
|
|
257
|
+
<pre><code>{
|
|
258
|
+
"topic": "ns=2;s=Factory.Line1.Motor1.status",
|
|
259
|
+
"payload": [
|
|
260
|
+
{
|
|
261
|
+
"name": "status",
|
|
262
|
+
"path": "ns=2;s=Factory.Line1.Motor1.status",
|
|
263
|
+
"value": 10
|
|
264
|
+
}
|
|
265
|
+
],
|
|
266
|
+
"opcua": {
|
|
267
|
+
"identifierType": "nodeId",
|
|
268
|
+
"server": "MeuServidor",
|
|
269
|
+
"writtenNodeIds": ["ns=2;s=Factory.Line1.Motor1.status"],
|
|
270
|
+
"tagNodeId": "ns=2;s=Factory.Line1.Motor1.status"
|
|
271
|
+
}
|
|
272
|
+
}</code></pre>
|
|
273
|
+
|
|
274
|
+
<h3>Method Input</h3>
|
|
275
|
+
<p><b>Output</b>:</p>
|
|
276
|
+
<p>Emits one message when an OPC UA client calls the configured method.</p>
|
|
277
|
+
<pre><code>{
|
|
278
|
+
"payload": [
|
|
279
|
+
{
|
|
280
|
+
"dataType": "Float",
|
|
281
|
+
"value": 25.5
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"dataType": "Boolean",
|
|
285
|
+
"value": true
|
|
286
|
+
}
|
|
287
|
+
],
|
|
288
|
+
"opcua": {
|
|
289
|
+
"server": "MeuServidor",
|
|
290
|
+
"method": "cmd_on"
|
|
291
|
+
},
|
|
292
|
+
"_callId": "1713700000000_0.1234"
|
|
293
|
+
}</code></pre>
|
|
294
|
+
|
|
295
|
+
<h3>Method Output</h3>
|
|
296
|
+
<p><b>Input</b>:</p>
|
|
297
|
+
<p>Send the same <code>_callId</code> back with <code>msg.payload</code> as an array of OPC UA output variants.</p>
|
|
298
|
+
<pre><code>{
|
|
299
|
+
"_callId": "1713700000000_0.1234",
|
|
300
|
+
"payload": [
|
|
301
|
+
{
|
|
302
|
+
"dataType": 10,
|
|
303
|
+
"value": 25.5
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"dataType": 1,
|
|
307
|
+
"value": true
|
|
308
|
+
}
|
|
309
|
+
]
|
|
310
|
+
}</code></pre>
|
|
311
|
+
<p><b>Output</b>:</p>
|
|
312
|
+
<pre><code>{
|
|
313
|
+
"_callId": "1713700000000_0.1234",
|
|
314
|
+
"payload": [
|
|
315
|
+
{
|
|
316
|
+
"dataType": 10,
|
|
317
|
+
"value": 25.5
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"dataType": 1,
|
|
321
|
+
"value": true
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
}</code></pre>
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
<h3>Events</h3>
|
|
328
|
+
<p>Send the same back with <code>msg.payload</code> as an array of OPC UA output variants.</p>
|
|
329
|
+
<pre><code>
|
|
330
|
+
msg.payload = [
|
|
331
|
+
{
|
|
332
|
+
"nodePath": "server1.motor1",
|
|
333
|
+
"severity": 500,
|
|
334
|
+
"message": "motor1 fault"
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"nodePath": "server1",
|
|
338
|
+
"severity": 1000,
|
|
339
|
+
"message": "new order 1"
|
|
340
|
+
},
|
|
341
|
+
]
|
|
342
|
+
</code></pre>
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
</script>
|