@vitormnm/node-red-simple-opcua 1.3.2 → 1.4.1
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/README.md +7 -4
- package/client/icons/opcua.svg +132 -0
- package/client/lib/opcua-client-browser.js +46 -7
- package/client/lib/opcua-client-method-service.js +88 -0
- package/client/lib/opcua-client-write-service.js +127 -33
- package/client/opcua-client-config.js +5 -0
- package/client/opcua-client-help.html +61 -0
- package/client/opcua-client-utils.js +68 -2
- package/client/opcua-client.html +14 -1098
- package/client/opcua-client.js +108 -53
- package/client/testClient.json +18 -0
- package/client/view/opcua-client.css +411 -0
- package/client/view/opcua-client.js +1141 -0
- package/icons/opcua.svg +132 -0
- package/icons/opcua2.svg +132 -0
- package/package.json +3 -3
- package/server/icons/opcua.svg +132 -0
- package/server/lib/opcua-address-space-builder.js +24 -2
- package/server/lib/opcua-server-runtime-child.js +117 -26
- package/server/opcua-server-io.html +1 -1
- package/server/opcua-server-io.js +31 -2
- package/server/opcua-server.html +154 -58
- package/server/opcua-server.js +7 -3
- package/object.json +0 -65
|
@@ -214,6 +214,8 @@ class OpcUaServerProcess {
|
|
|
214
214
|
msg.payload = result.payload;
|
|
215
215
|
this.assignReadMetadata(msg, identifierType, result.identifiers);
|
|
216
216
|
|
|
217
|
+
|
|
218
|
+
|
|
217
219
|
if (result.identifiers.length === 1) {
|
|
218
220
|
msg.topic = result.identifiers[0];
|
|
219
221
|
}
|
|
@@ -306,49 +308,137 @@ class OpcUaServerProcess {
|
|
|
306
308
|
}
|
|
307
309
|
|
|
308
310
|
|
|
309
|
-
|
|
310
311
|
writeFromPayload(msg, nodeId) {
|
|
311
312
|
try {
|
|
312
|
-
|
|
313
|
-
|
|
313
|
+
let writtenPaths = null;
|
|
314
|
+
let payload = msg ? msg.payload : undefined;
|
|
315
|
+
|
|
314
316
|
const target = msg && msg.opcuaServerIo ? msg.opcuaServerIo : {};
|
|
315
317
|
const identifierType = this.resolveIdentifierType(target);
|
|
316
318
|
|
|
319
|
+
// Buffer serializado pelo IPC
|
|
320
|
+
if (
|
|
321
|
+
payload &&
|
|
322
|
+
typeof payload === "object" &&
|
|
323
|
+
payload.type === "Buffer" &&
|
|
324
|
+
Array.isArray(payload.data)
|
|
325
|
+
) {
|
|
326
|
+
payload = Buffer.from(payload.data);
|
|
327
|
+
}
|
|
317
328
|
|
|
329
|
+
const dataType =
|
|
330
|
+
target.dataType ||
|
|
331
|
+
target.type ||
|
|
332
|
+
target.builtInType ||
|
|
333
|
+
"";
|
|
334
|
+
|
|
335
|
+
const isByteString =
|
|
336
|
+
typeof dataType === "string" &&
|
|
337
|
+
dataType.toLowerCase() === "bytestring";
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
// Buffer ou Uint8Array
|
|
342
|
+
if (Buffer.isBuffer(payload) || payload instanceof Uint8Array) {
|
|
343
|
+
|
|
344
|
+
const identifier = this.resolveIdentifier(target);
|
|
345
|
+
|
|
346
|
+
this.node.writeValue(
|
|
347
|
+
identifierType,
|
|
348
|
+
identifier,
|
|
349
|
+
Buffer.isBuffer(payload)
|
|
350
|
+
? payload
|
|
351
|
+
: Buffer.from(payload)
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
writtenPaths = [identifier];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Array de números
|
|
358
|
+
else if (
|
|
359
|
+
Array.isArray(payload) &&
|
|
360
|
+
payload.every(item => typeof item === "number")
|
|
361
|
+
) {
|
|
362
|
+
|
|
363
|
+
const identifier = this.resolveIdentifier(target);
|
|
364
|
+
|
|
365
|
+
this.node.writeValue(
|
|
366
|
+
identifierType,
|
|
367
|
+
identifier,
|
|
368
|
+
isByteString
|
|
369
|
+
? Buffer.from(payload)
|
|
370
|
+
: payload
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
writtenPaths = [identifier];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Array de objetos
|
|
377
|
+
else if (Array.isArray(payload)) {
|
|
318
378
|
|
|
319
|
-
if (Array.isArray(payload)) {
|
|
320
379
|
if (!payload.length) {
|
|
321
380
|
throw new Error("msg.payload array does not contain any items");
|
|
322
381
|
}
|
|
323
382
|
|
|
324
|
-
payload.forEach(
|
|
383
|
+
payload.forEach(item => {
|
|
325
384
|
this.writePayloadItem(identifierType, item);
|
|
326
385
|
});
|
|
327
386
|
|
|
328
|
-
writtenPaths = payload.map(
|
|
329
|
-
|
|
387
|
+
writtenPaths = payload.map(item =>
|
|
388
|
+
this.resolvePayloadItemIdentifier(item)
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Objeto { path: value }
|
|
393
|
+
else if (
|
|
394
|
+
payload &&
|
|
395
|
+
typeof payload === "object" &&
|
|
396
|
+
!Array.isArray(payload)
|
|
397
|
+
) {
|
|
330
398
|
|
|
331
399
|
const identifiers = Object.keys(payload);
|
|
400
|
+
|
|
332
401
|
if (!identifiers.length) {
|
|
333
|
-
throw new Error(
|
|
402
|
+
throw new Error(
|
|
403
|
+
"msg.payload object does not contain any " +
|
|
404
|
+
this.getIdentifierLabel(identifierType)
|
|
405
|
+
);
|
|
334
406
|
}
|
|
335
407
|
|
|
336
|
-
identifiers.forEach(
|
|
337
|
-
this.node.writeValue(
|
|
408
|
+
identifiers.forEach(identifier => {
|
|
409
|
+
this.node.writeValue(
|
|
410
|
+
identifierType,
|
|
411
|
+
identifier,
|
|
412
|
+
payload[identifier]
|
|
413
|
+
);
|
|
338
414
|
});
|
|
339
415
|
|
|
340
416
|
writtenPaths = identifiers;
|
|
341
|
-
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Valor simples
|
|
420
|
+
else {
|
|
342
421
|
|
|
343
422
|
const identifier = this.resolveIdentifier(target);
|
|
344
|
-
this.node.writeValue(identifierType, identifier, payload);
|
|
345
423
|
|
|
424
|
+
this.node.writeValue(
|
|
425
|
+
identifierType,
|
|
426
|
+
identifier,
|
|
427
|
+
payload
|
|
428
|
+
);
|
|
346
429
|
|
|
347
|
-
writtenPaths = [identifier]
|
|
430
|
+
writtenPaths = [identifier];
|
|
348
431
|
}
|
|
349
432
|
|
|
350
433
|
msg.opcua = msg.opcua || {};
|
|
351
|
-
|
|
434
|
+
|
|
435
|
+
this.assignWriteMetadata(
|
|
436
|
+
msg,
|
|
437
|
+
identifierType,
|
|
438
|
+
writtenPaths
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
|
|
352
442
|
if (writtenPaths.length === 1) {
|
|
353
443
|
msg.topic = writtenPaths[0];
|
|
354
444
|
}
|
|
@@ -356,7 +446,7 @@ class OpcUaServerProcess {
|
|
|
356
446
|
process.send({
|
|
357
447
|
type: "send",
|
|
358
448
|
data: msg,
|
|
359
|
-
nodeId
|
|
449
|
+
nodeId
|
|
360
450
|
});
|
|
361
451
|
|
|
362
452
|
process.send({
|
|
@@ -364,28 +454,29 @@ class OpcUaServerProcess {
|
|
|
364
454
|
data: {
|
|
365
455
|
fill: "green",
|
|
366
456
|
shape: "dot",
|
|
367
|
-
text:
|
|
457
|
+
text:
|
|
458
|
+
writtenPaths.length > 1
|
|
459
|
+
? `write ${writtenPaths.length} tags`
|
|
460
|
+
: `write ${writtenPaths[0]}`
|
|
368
461
|
},
|
|
369
|
-
nodeId
|
|
462
|
+
nodeId
|
|
370
463
|
});
|
|
371
464
|
|
|
372
|
-
|
|
373
465
|
} catch (error) {
|
|
374
466
|
|
|
375
467
|
process.send({
|
|
376
468
|
type: "error",
|
|
377
|
-
data: {
|
|
469
|
+
data: {
|
|
470
|
+
fill: "red",
|
|
471
|
+
shape: "ring",
|
|
472
|
+
text: "failed write"
|
|
473
|
+
},
|
|
378
474
|
error: error.message,
|
|
379
|
-
nodeId
|
|
475
|
+
nodeId
|
|
380
476
|
});
|
|
381
477
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
//return [path];
|
|
386
478
|
}
|
|
387
479
|
|
|
388
|
-
|
|
389
480
|
resolveIdentifierType(target) {
|
|
390
481
|
return target && target.identifierType === "nodeId" ? "nodeId" : "path";
|
|
391
482
|
}
|
|
@@ -726,4 +817,4 @@ process.on("unhandledRejection", (reason) => {
|
|
|
726
817
|
data: "Unhandled Rejection: " + (reason?.message || reason),
|
|
727
818
|
nodeId: nodeId
|
|
728
819
|
});
|
|
729
|
-
});
|
|
820
|
+
});
|
|
@@ -12,10 +12,19 @@ module.exports = function (RED) {
|
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
+
|
|
16
|
+
const path = require("path");
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
15
23
|
function OpcUaServerIoNode(config) {
|
|
16
24
|
RED.nodes.createNode(this, config);
|
|
17
25
|
const node = this;
|
|
18
26
|
|
|
27
|
+
|
|
19
28
|
node.name = (config.name || "").trim();
|
|
20
29
|
node.serverRef = (config.serverRef || "").trim();
|
|
21
30
|
node.mode = config.mode || "read";
|
|
@@ -106,6 +115,20 @@ module.exports = function (RED) {
|
|
|
106
115
|
});
|
|
107
116
|
}
|
|
108
117
|
|
|
118
|
+
function restoreBuffers(value) {
|
|
119
|
+
// Formato exato que o Node.js IPC gera ao serializar um Buffer
|
|
120
|
+
if (
|
|
121
|
+
value !== null &&
|
|
122
|
+
typeof value === "object" &&
|
|
123
|
+
value.type === "Buffer" &&
|
|
124
|
+
Array.isArray(value.data)
|
|
125
|
+
) {
|
|
126
|
+
return Buffer.from(value.data);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return value;
|
|
130
|
+
}
|
|
131
|
+
|
|
109
132
|
function onMessage(msg, node) {
|
|
110
133
|
if (msg.nodeId == node.id) {
|
|
111
134
|
|
|
@@ -115,7 +138,13 @@ module.exports = function (RED) {
|
|
|
115
138
|
}
|
|
116
139
|
|
|
117
140
|
if (msg.type === "send") {
|
|
118
|
-
|
|
141
|
+
const data = msg.data;
|
|
142
|
+
|
|
143
|
+
if (data && data.payload !== undefined) {
|
|
144
|
+
data.payload = restoreBuffers(data.payload);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
node.send(data);
|
|
119
148
|
}
|
|
120
149
|
|
|
121
150
|
if (msg.type === "error") {
|
|
@@ -132,7 +161,7 @@ module.exports = function (RED) {
|
|
|
132
161
|
});
|
|
133
162
|
|
|
134
163
|
node.send({
|
|
135
|
-
topic
|
|
164
|
+
topic: msg.data.nodeId,
|
|
136
165
|
payload: msg.data.inputArguments,
|
|
137
166
|
opcua: {
|
|
138
167
|
server: msg.data.serverName,
|