@vitormnm/node-red-simple-opcua 1.4.0 → 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 CHANGED
@@ -1,4 +1,3 @@
1
- # @vitormnm/node-red-simple-opcua
2
1
  OPC UA client and server with a simple graphical interface for Node-RED.
3
2
  Fully parameterized in JSON.
4
3
 
@@ -0,0 +1,132 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
3
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
4
+ <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
5
+ width="354.000000pt" height="229.000000pt" viewBox="0 0 354.000000 229.000000"
6
+ preserveAspectRatio="xMidYMid meet">
7
+
8
+ <g transform="translate(0.000000,229.000000) scale(0.100000,-0.100000)"
9
+ fill="#000000" stroke="none">
10
+ <path d="M262 2257 l-22 -23 23 -22 23 -22 22 23 22 23 -23 22 -23 22 -22 -23z"/>
11
+ <path d="M195 2170 c-14 -16 -31 -20 -82 -20 -35 0 -63 -4 -63 -10 0 -6 26
12
+ -10 59 -10 44 0 65 -5 85 -21 l27 -21 23 21 c18 17 34 21 87 20 35 0 58 -3 52
13
+ -6 -17 -6 -16 -23 0 -23 8 0 22 -9 32 -20 l18 -20 24 22 c13 12 23 27 23 35 0
14
+ 10 37 13 180 13 155 0 179 -2 174 -15 -4 -10 0 -15 11 -15 11 0 15 5 11 15 -4
15
+ 11 2 15 21 15 l27 0 -37 -38 c-40 -41 -45 -52 -22 -52 8 0 15 5 15 12 0 7 16
16
+ -3 35 -22 l35 -34 35 34 c41 40 42 46 13 77 l-21 23 253 0 254 0 -71 -34 c-40
17
+ -19 -92 -53 -116 -75 -30 -28 -53 -41 -72 -41 -27 0 -28 1 -10 19 16 19 16 21
18
+ -3 49 -39 54 -45 55 -87 12 -38 -39 -38 -40 -20 -60 16 -18 16 -20 2 -20 -10
19
+ 0 -17 7 -17 16 0 9 -6 14 -13 11 -6 -2 -11 -10 -10 -16 4 -14 -30 -14 -44 0
20
+ -8 8 -13 8 -17 0 -4 -6 -32 -11 -63 -11 -44 0 -62 5 -80 22 l-23 21 -22 -20
21
+ c-21 -19 -37 -21 -182 -22 -122 -2 -161 1 -167 11 -7 10 -9 10 -9 1 0 -19 -40
22
+ -16 -62 4 -17 15 -19 15 -36 0 -15 -14 -42 -17 -155 -17 -85 0 -137 -4 -137
23
+ -10 0 -6 49 -10 127 -10 124 0 128 -1 155 -27 l28 -27 28 27 28 27 169 0 c92
24
+ 0 165 -3 161 -7 -3 -4 10 -24 30 -44 l37 -38 38 32 c21 18 39 38 39 45 0 7 13
25
+ 12 32 12 l33 0 -33 -32 -32 -32 42 -43 42 -43 -40 0 c-22 0 -45 5 -52 12 -9 9
26
+ -15 9 -24 0 -7 -7 -30 -12 -52 -12 -34 0 -47 7 -83 42 l-43 42 -43 -42 c-41
27
+ -41 -70 -54 -65 -31 2 6 -3 14 -9 16 -7 3 -13 -2 -13 -11 0 -13 -13 -16 -72
28
+ -16 -64 0 -75 3 -100 27 l-28 27 -28 -27 c-27 -26 -32 -27 -153 -29 l-124 -2
29
+ 103 -3 c81 -3 102 -7 102 -18 0 -8 7 -15 15 -15 8 0 15 7 15 15 0 21 24 19 45
30
+ -5 17 -19 18 -19 43 0 18 14 40 20 78 20 58 0 65 -7 34 -35 -27 -25 -25 -36
31
+ 13 -73 l33 -32 37 38 38 38 -26 28 c-28 31 -30 36 -12 36 7 0 35 -22 62 -50
32
+ 27 -27 54 -50 60 -50 6 0 33 23 60 50 27 28 55 50 62 50 20 0 16 -11 -14 -42
33
+ l-27 -28 37 -38 c20 -21 37 -41 37 -45 0 -4 -30 -7 -67 -7 -55 0 -71 4 -90 22
34
+ l-23 21 -23 -21 c-23 -21 -31 -22 -308 -24 l-284 -3 280 -2 279 -3 28 -27 28
35
+ -27 28 27 c22 21 38 27 72 27 l44 0 -49 -50 c-34 -34 -51 -46 -57 -37 -5 9
36
+ -10 9 -19 0 -10 -10 -7 -14 12 -22 14 -5 31 -16 39 -26 12 -15 10 -16 -21 -14
37
+ -101 7 -659 -2 -659 -11 0 -6 127 -10 362 -10 322 0 363 -2 380 -17 17 -15 19
38
+ -15 36 0 14 13 41 16 138 16 l121 0 28 -29 c35 -37 42 -37 76 -4 l28 27 51
39
+ -46 c28 -25 74 -57 103 -71 l52 -25 -687 -1 c-452 0 -688 -3 -688 -10 0 -7
40
+ 248 -10 725 -10 399 0 725 3 725 7 0 3 -8 15 -17 25 -16 18 -14 21 37 73 30
41
+ 30 59 55 65 55 6 0 35 -25 65 -55 51 -52 53 -55 37 -73 -9 -10 -17 -22 -17
42
+ -25 0 -4 156 -6 348 -5 l347 3 3 128 3 127 97 0 c117 0 188 19 237 61 25 22
43
+ 36 27 39 17 3 -7 12 -36 21 -65 35 -112 143 -216 267 -260 63 -21 224 -22 303
44
+ -1 l50 13 3 153 3 152 -57 -31 c-101 -58 -210 -38 -259 46 -46 78 -27 163 48
45
+ 219 22 16 43 21 95 21 59 0 74 -4 118 -32 28 -18 53 -33 55 -33 2 0 3 70 1
46
+ 155 l-3 154 -42 13 c-24 7 -95 13 -162 13 -114 0 -123 -2 -186 -31 -72 -34
47
+ -136 -87 -180 -147 l-27 -38 -11 34 c-29 87 -133 160 -252 177 -36 5 -558 10
48
+ -1169 10 -1087 1 -1105 1 -1125 20 -22 20 -22 20 -40 0z m1875 -115 l0 -75
49
+ -41 0 c-35 0 -49 7 -86 41 -24 22 -76 56 -116 75 l-71 34 157 0 157 0 0 -75z
50
+ m-881 -150 c-15 -30 -29 -60 -32 -67 -3 -10 -11 -7 -29 9 l-24 23 -29 -30
51
+ c-32 -34 -49 -37 -72 -14 -20 20 -2 44 20 26 11 -9 20 -5 42 18 l29 30 -29 30
52
+ -28 29 90 0 89 -1 -27 -53z m881 -17 l0 -73 -24 58 c-13 32 -29 64 -36 72 -11
53
+ 13 -7 15 24 15 l36 0 0 -72z m-1044 21 c10 -17 -13 -36 -27 -22 -12 12 -4 33
54
+ 11 33 5 0 12 -5 16 -11z m1462 -19 c44 -42 17 -104 -53 -120 -66 -16 -65 -17
55
+ -65 65 l0 75 48 0 c35 0 54 -6 70 -20z m-628 -45 l54 -55 -59 -60 c-41 -41
56
+ -62 -56 -70 -50 -8 7 -15 2 -23 -15 -12 -25 -12 -25 -156 -25 l-145 0 -7 37
57
+ c-4 20 -3 52 2 72 l9 36 105 3 c140 4 158 22 21 22 -95 0 -102 1 -90 17 36 43
58
+ 122 55 181 24 l37 -18 32 33 c18 19 38 34 44 34 6 0 35 -25 65 -55z m-400 29
59
+ c0 -9 -5 -14 -12 -12 -18 6 -21 28 -4 28 9 0 16 -7 16 -16z m-775 -43 c7 -12
60
+ -12 -24 -25 -16 -11 7 -4 25 10 25 5 0 11 -4 15 -9z m773 -12 c-2 -6 -8 -10
61
+ -13 -10 -5 0 -11 4 -13 10 -2 6 4 11 13 11 9 0 15 -5 13 -11z m-419 -35 l23
62
+ -16 -43 -44 c-34 -34 -40 -47 -31 -56 20 -20 14 -24 -43 -26 -30 -1 -55 2 -55
63
+ 5 0 4 18 26 40 48 l40 41 -25 24 c-14 13 -25 27 -25 32 0 15 95 9 119 -8z
64
+ m286 -34 l50 -50 -53 -53 -52 -52 -52 52 -53 53 50 50 c27 27 52 50 55 50 3 0
65
+ 28 -23 55 -50z m-460 10 c-5 -8 -11 -8 -17 -2 -6 6 -7 16 -3 22 5 8 11 8 17 2
66
+ 6 -6 7 -16 3 -22z m-184 5 c-1 -15 -24 -12 -29 3 -3 9 2 13 12 10 10 -1 17 -7
67
+ 17 -13z m439 -4 c0 -14 -18 -23 -30 -16 -6 4 -8 11 -5 16 8 12 35 12 35 0z
68
+ m-252 -49 c2 -7 -3 -12 -12 -12 -9 0 -16 7 -16 16 0 17 22 14 28 -4z m247 -12
69
+ c0 -7 -6 -15 -12 -17 -8 -3 -13 4 -13 17 0 13 5 20 13 18 6 -3 12 -11 12 -18z
70
+ m305 -1 c0 -5 -7 -9 -15 -9 -15 0 -20 12 -9 23 8 8 24 -1 24 -14z m-8 -54 c0
71
+ -5 -5 -11 -11 -13 -6 -2 -11 4 -11 13 0 9 5 15 11 13 6 -2 11 -8 11 -13z
72
+ m-482 -22 c0 -12 -43 -53 -55 -53 -6 0 -24 14 -40 30 l-29 30 62 0 c34 0 62
73
+ -3 62 -7z m122 -20 l28 -27 28 27 c33 32 42 34 42 9 0 -10 -20 -38 -45 -62
74
+ -25 -24 -45 -50 -45 -57 0 -8 -13 -13 -32 -13 l-32 0 34 35 34 35 -39 40 c-31
75
+ 32 -35 40 -20 40 10 0 32 -12 47 -27z m692 16 c-3 -6 14 -32 40 -58 l46 -47
76
+ -50 -49 -50 -50 -52 52 c-44 44 -50 54 -39 67 12 14 8 16 -35 16 -53 0 -105
77
+ 25 -124 59 -11 21 -9 21 130 21 100 0 139 -3 134 -11z m-414 -20 c0 -5 -7 -9
78
+ -15 -9 -15 0 -20 12 -9 23 8 8 24 -1 24 -14z m-362 0 c-2 -6 -8 -10 -13 -10
79
+ -5 0 -11 4 -13 10 -2 6 4 11 13 11 9 0 15 -5 13 -11z m1102 -59 c0 -58 -1 -60
80
+ -26 -60 -14 0 -24 3 -22 8 2 4 12 31 23 60 11 28 21 52 22 52 2 0 3 -27 3 -60z
81
+ m-580 -25 l54 -55 -59 -60 -59 -60 -58 57 -58 57 57 58 c32 32 60 58 63 58 3
82
+ 0 30 -25 60 -55z m-525 15 c-5 -8 -11 -8 -17 -2 -6 6 -7 16 -3 22 5 8 11 8 17
83
+ 2 6 -6 7 -16 3 -22z m365 15 c0 -8 -7 -15 -15 -15 -16 0 -20 12 -8 23 11 12
84
+ 23 8 23 -8z m-410 -50 c11 -13 8 -15 -20 -15 -28 0 -31 2 -20 15 7 8 16 15 20
85
+ 15 4 0 13 -7 20 -15z m1150 -110 l0 -75 -137 0 -137 0 53 26 c29 15 76 48 104
86
+ 75 40 37 60 48 85 49 l32 0 0 -75z"/>
87
+ <path d="M1750 1825 c0 -9 5 -15 11 -13 6 2 11 8 11 13 0 5 -5 11 -11 13 -6 2
88
+ -11 -4 -11 -13z"/>
89
+ <path d="M1750 1765 c0 -9 5 -15 11 -13 6 2 11 8 11 13 0 5 -5 11 -11 13 -6 2
90
+ -11 -4 -11 -13z"/>
91
+ <path d="M1240 1735 c0 -9 5 -15 11 -13 6 2 11 8 11 13 0 5 -5 11 -11 13 -6 2
92
+ -11 -4 -11 -13z"/>
93
+ <path d="M1240 1675 c0 -9 5 -15 11 -13 6 2 11 8 11 13 0 5 -5 11 -11 13 -6 2
94
+ -11 -4 -11 -13z"/>
95
+ <path d="M1697 1574 c-8 -8 1 -24 14 -24 5 0 9 7 9 15 0 15 -12 20 -23 9z"/>
96
+ <path d="M1692 1508 c6 -18 28 -21 28 -4 0 9 -7 16 -16 16 -9 0 -14 -5 -12
97
+ -12z"/>
98
+ <path d="M1380 1480 c0 -5 7 -10 16 -10 8 0 12 5 9 10 -3 6 -10 10 -16 10 -5
99
+ 0 -9 -4 -9 -10z"/>
100
+ <path d="M1380 1425 c0 -9 5 -15 11 -13 6 2 11 8 11 13 0 5 -5 11 -11 13 -6 2
101
+ -11 -4 -11 -13z"/>
102
+ <path d="M610 2075 l-24 -26 27 -27 27 -27 27 27 27 27 -24 26 c-13 14 -26 25
103
+ -30 25 -4 0 -17 -11 -30 -25z"/>
104
+ <path d="M547 2074 c-8 -8 1 -24 14 -24 5 0 9 7 9 15 0 15 -12 20 -23 9z"/>
105
+ <path d="M1047 2064 c-8 -8 1 -24 14 -24 5 0 9 7 9 15 0 15 -12 20 -23 9z"/>
106
+ <path d="M547 2014 c-8 -8 1 -24 14 -24 5 0 9 7 9 15 0 15 -12 20 -23 9z"/>
107
+ <path d="M443 1939 c3 -9 1 -21 -4 -26 -6 -6 2 -20 19 -36 l28 -27 23 24 c22
108
+ 23 22 25 6 50 -18 27 -39 34 -51 15 -4 -8 -9 -7 -16 2 -8 11 -9 10 -5 -2z"/>
109
+ <path d="M712 1918 c6 -18 28 -21 28 -4 0 9 -7 16 -16 16 -9 0 -14 -5 -12 -12z"/>
110
+ <path d="M857 1884 c-8 -8 1 -24 14 -24 5 0 9 7 9 15 0 15 -12 20 -23 9z"/>
111
+ <path d="M250 1840 c0 -5 7 -10 15 -10 8 0 15 5 15 10 0 6 -7 10 -15 10 -8 0
112
+ -15 -4 -15 -10z"/>
113
+ <path d="M422 1749 c2 -6 8 -10 13 -10 5 0 11 4 13 10 2 6 -4 11 -13 11 -9 0
114
+ -15 -5 -13 -11z"/>
115
+ <path d="M422 1689 c2 -6 8 -10 13 -10 5 0 11 4 13 10 2 6 -4 11 -13 11 -9 0
116
+ -15 -5 -13 -11z"/>
117
+ <path d="M1114 995 c-11 -28 3 -579 15 -620 45 -143 162 -222 346 -232 196
118
+ -11 334 56 397 192 22 48 23 61 26 363 l3 313 -153 -3 -153 -3 -5 -283 c-6
119
+ -321 -3 -312 -87 -312 -75 0 -77 9 -81 327 l-3 273 -150 0 c-122 0 -151 -3
120
+ -155 -15z"/>
121
+ <path d="M2151 992 c-11 -20 -291 -825 -291 -835 0 -4 72 -7 160 -7 120 0 162
122
+ 3 165 13 2 6 9 31 15 55 l11 43 116 -3 116 -3 16 -50 16 -50 164 -3 c130 -2
123
+ 162 0 158 10 -2 7 -66 186 -142 398 -75 212 -143 400 -151 418 l-13 32 -165 0
124
+ c-150 0 -166 -2 -175 -18z m208 -392 c12 -58 25 -113 27 -122 5 -16 -2 -18
125
+ -55 -18 -45 0 -61 4 -61 13 0 8 11 65 25 127 14 62 25 115 25 119 0 3 4 1 8
126
+ -4 5 -6 19 -57 31 -115z"/>
127
+ <path d="M2590 1001 c11 -8 11 -11 2 -11 -7 0 -17 -10 -23 -22 -9 -22 -9 -21
128
+ -6 4 2 15 0 25 -4 22 -26 -15 6 -72 33 -61 8 3 5 6 -6 6 -15 1 -17 4 -8 13 8
129
+ 8 15 8 28 -3 16 -12 17 -12 9 1 -6 8 -10 24 -10 34 0 11 -7 21 -15 23 -13 4
130
+ -13 3 0 -6z"/>
131
+ </g>
132
+ </svg>
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ const { dataValueToItemResult, ensureArrayPayload, resolveNodeId, resolveMethodObjectId, buildVariantFromItem, callResultToItemResult } = require("../opcua-client-utils");
4
+
5
+ class OpcUaClientMethodService {
6
+ async execute(node, msg, session, itemsResolver) {
7
+
8
+ // const items = ensureArrayPayload(msg, "OPC UA method call");
9
+ const items = itemsResolver.ensureMethodItems(node, msg, "OPC UA method");
10
+ const payload = [];
11
+
12
+
13
+
14
+ for (const item of items) {
15
+ const methodNodeId = this.resolveMethodId(item);
16
+
17
+ try {
18
+ const objectId = this.resolveMethodObjectIdFromItem(item) || await resolveMethodObjectId(
19
+ session,
20
+ methodNodeId,
21
+ node.connection.methodObjectIdCache
22
+ );
23
+ const argumentDefinition = await this.safeGetMethodArgumentDefinition(
24
+ session,
25
+ methodNodeId,
26
+ node.connection.methodDefinitionCache
27
+ );
28
+ const callRequest = {
29
+ objectId,
30
+ methodId: methodNodeId
31
+ };
32
+
33
+ if (Array.isArray(item.inputs) && item.inputs.length > 0) {
34
+ callRequest.inputArguments = item.inputs.map((input) => buildVariantFromItem(input, input.type));
35
+ }
36
+
37
+ const callResult = await session.call(callRequest);
38
+ payload.push(callResultToItemResult(item, callResult, argumentDefinition));
39
+ } catch (itemError) {
40
+ payload.push({
41
+ name: item.name || methodNodeId,
42
+ nodeID: methodNodeId,
43
+ status: itemError.message,
44
+ outputs: []
45
+ });
46
+ }
47
+ }
48
+
49
+ return payload;
50
+ }
51
+
52
+
53
+
54
+ resolveMethodId(item) {
55
+ const methodId = item && (item.methodID || item.methodId || item.nodeID || item.nodeId);
56
+ if (!methodId || !String(methodId).trim()) {
57
+ throw new Error("Each method item must contain methodId or nodeID");
58
+ }
59
+
60
+ return String(methodId).trim();
61
+ }
62
+
63
+
64
+ resolveMethodObjectIdFromItem(item) {
65
+ const objectId = item && (item.objectID || item.objectId);
66
+ if (!objectId || !String(objectId).trim()) {
67
+ return "";
68
+ }
69
+
70
+ return String(objectId).trim();
71
+ }
72
+
73
+ async safeGetMethodArgumentDefinition(session, methodNodeId, cache) {
74
+ try {
75
+ return await getMethodArgumentDefinition(session, methodNodeId, cache);
76
+ } catch (error) {
77
+ return {
78
+ inputArguments: [],
79
+ outputArguments: []
80
+ };
81
+ }
82
+ }
83
+
84
+ }
85
+
86
+ module.exports = {
87
+ OpcUaClientMethodService
88
+ };
@@ -20,7 +20,7 @@ const YIELD_EVERY = 50;
20
20
  class OpcUaClientWriteService {
21
21
  async execute(node, msg, session, itemsResolver) {
22
22
  const items = itemsResolver.ensureWriteItems(node, msg);
23
-
23
+
24
24
  // 1. Resolve variantes (tipo + valor) — consulta servidor só para quem não tem tipo explícito
25
25
  const variants = await resolveVariants(session, items);
26
26
 
@@ -13,11 +13,15 @@ const {
13
13
  ROOT_NODE_ID
14
14
  } = require("./lib/opcua-client-browser");
15
15
 
16
+
17
+
16
18
  module.exports = function (RED) {
17
19
  function OpcUaClientConfigNode(config) {
18
20
  RED.nodes.createNode(this, config);
19
21
  const node = this;
20
22
 
23
+
24
+
21
25
  node.name = (config.name || "").trim();
22
26
  node.endpoint = (config.endpoint || "").trim();
23
27
  node.securityPolicy = config.securityPolicy || "None";
@@ -74,6 +78,7 @@ module.exports = function (RED) {
74
78
 
75
79
  this.client = client;
76
80
  this.session = session;
81
+
77
82
  return session;
78
83
  } catch (error) {
79
84
  try {
@@ -0,0 +1,61 @@
1
+ <script type="text/html" data-help-name="opcua-client">
2
+ <p>Unified OPC UA client node for read, write, browse and subscription using a shared client configuration node.</p>
3
+
4
+ <h3>Modes</h3>
5
+ <p><b>Read</b>: reads one or more variable values.</p>
6
+ <p><b>Write</b>: writes one or more variable values.</p>
7
+ <p><b>Browse</b>: browses one or more OPC UA nodes and returns their children.</p>
8
+ <p><b>Method</b>: calls one or more OPC UA methods.</p>
9
+ <p><b>Subscription</b>: subscribes to one or more variable values and emits one message per change.</p>
10
+
11
+ <h3>Read</h3>
12
+ <p><b>Input</b> <code>msg.payload</code>:</p>
13
+ <pre><code>[
14
+ {
15
+ "name": "status",
16
+ "nodeID": "ns=2;s=Factory.Line1.Motor1.status"
17
+ }
18
+ ]</code></pre>
19
+ <p>If <code>msg.payload</code> is not an array and <code>NodeId</code> is configured, the node reads that configured node.</p>
20
+
21
+ <h3>Write</h3>
22
+ <p><b>Input</b> <code>msg.payload</code>:</p>
23
+ <pre><code>[
24
+ {
25
+ "name": "speed",
26
+ "nodeID": "ns=2;s=Factory.Line1.Motor1.speed",
27
+ "value": 25.5,
28
+ "type": "Float"
29
+ }
30
+ ]</code></pre>
31
+
32
+ <h3>Browse</h3>
33
+ <p>If <code>msg.payload</code> is not an array and <code>NodeId</code> is configured, the node browses that configured node.</p>
34
+ <p>If <code>msg.payload = []</code>, the node browses the OPC UA <code>RootFolder</code>.</p>
35
+
36
+ <h3>Method</h3>
37
+ <p><code>nodeID</code> and <code>objectId</code> are accepted explicitly. For backward compatibility, <code>nodeID</code> is also accepted as the method id.</p>
38
+ <p><b>Input</b> <code>msg.payload</code>:</p>
39
+ <pre><code>[
40
+ {
41
+ "name": "method1",
42
+ "nodeID": "ns=2;s=motor.method1",
43
+ "inputs": [
44
+ {
45
+ "name": "input1",
46
+ "type": "Int32",
47
+ "value": 1
48
+ },
49
+ {
50
+ "name": "input2",
51
+ "type": "Int32",
52
+ "value": 1
53
+ }
54
+ ]
55
+ },
56
+
57
+
58
+ ]</code></pre>
59
+ <h3>Subscription</h3>
60
+ <p>In subscription mode the node emits one message per value change.</p>
61
+ </script>
@@ -4,6 +4,7 @@ const {
4
4
  AttributeIds,
5
5
  BrowseDirection,
6
6
  coerceNodeId,
7
+ VariantArrayType,
7
8
  DataType,
8
9
  MessageSecurityMode,
9
10
  NodeClass,
@@ -13,6 +14,18 @@ const {
13
14
  Variant
14
15
  } = require("node-opcua");
15
16
 
17
+ // Mapa DataType → TypedArray nativo para escrita eficiente no servidor OPC UA
18
+ const TYPED_ARRAY_MAP = {
19
+ [DataType.SByte]: Int8Array,
20
+ [DataType.Byte]: Uint8Array,
21
+ [DataType.Int16]: Int16Array,
22
+ [DataType.UInt16]: Uint16Array,
23
+ [DataType.Int32]: Int32Array,
24
+ [DataType.UInt32]: Uint32Array,
25
+ [DataType.Float]: Float32Array,
26
+ [DataType.Double]: Float64Array,
27
+ };
28
+
16
29
  function resolveSecurityPolicy(name) {
17
30
  return SecurityPolicy[name] || SecurityPolicy.None;
18
31
  }
@@ -61,19 +74,26 @@ function inferTypeName(value) {
61
74
  if (value instanceof Date) {
62
75
  return "DateTime";
63
76
  }
64
- if (Buffer.isBuffer(value)) {
77
+ if (Buffer.isBuffer(value) || (value && typeof value === 'object' && value.type === 'Buffer' && Array.isArray(value.data))) {
65
78
  return "ByteString";
66
79
  }
67
80
  return "String";
68
81
  }
69
82
 
70
83
  function coerceValue(value, typeName) {
84
+
85
+ if (Array.isArray(value)) {
86
+ return value.map(element => coerceValue(element, typeName));
87
+ }
88
+
89
+
71
90
  switch (typeName) {
72
91
  case "Boolean":
73
92
  if (typeof value === "string") {
74
93
  return value.trim().toLowerCase() === "true";
75
94
  }
76
95
  return Boolean(value);
96
+
77
97
  case "Byte":
78
98
  case "SByte":
79
99
  case "Int16":
@@ -81,16 +101,44 @@ function coerceValue(value, typeName) {
81
101
  case "UInt16":
82
102
  case "UInt32":
83
103
  return Number.parseInt(value, 10);
104
+
84
105
  case "Int64":
85
106
  case "UInt64":
86
107
  return BigInt(value);
108
+
87
109
  case "Float":
88
110
  case "Double":
89
111
  return Number.parseFloat(value);
112
+
113
+ case "ByteString":
114
+ if (value && typeof value === "object" && value.type === "Buffer" && Array.isArray(value.data)) {
115
+ return Buffer.from(value.data);
116
+ }
117
+
118
+ if (Buffer.isBuffer(value)) {
119
+ return value;
120
+ }
121
+
122
+ if (value instanceof Uint8Array) {
123
+ return Buffer.from(value);
124
+ }
125
+
126
+ if (Array.isArray(value)) {
127
+ return Buffer.from(value);
128
+ }
129
+
130
+ if (typeof value === "string") {
131
+ return Buffer.from(value, "base64");
132
+ }
133
+
134
+ return Buffer.alloc(0);
135
+
90
136
  case "DateTime":
91
137
  return value instanceof Date ? value : new Date(value);
138
+
92
139
  case "String":
93
140
  return value === undefined || value === null ? "" : String(value);
141
+
94
142
  default:
95
143
  return value;
96
144
  }
@@ -104,8 +152,26 @@ function buildVariantFromItem(item, fallbackTypeName) {
104
152
  throw new Error("Unsupported OPC UA data type: " + typeName);
105
153
  }
106
154
 
155
+ const isArray = Array.isArray(item.value);
156
+
157
+ if (isArray) {
158
+ // Coerce cada elemento e converte para TypedArray se disponível
159
+ const coercedArray = coerceValue(item.value, typeName); // retorna JS Array
160
+ const TypedArrayCtor = TYPED_ARRAY_MAP[dataType];
161
+
162
+ return new Variant({
163
+ dataType,
164
+ arrayType: VariantArrayType.Array,
165
+ value: TypedArrayCtor
166
+ ? TypedArrayCtor.from(coercedArray) // Int32Array, Float32Array, etc.
167
+ : coercedArray // String[], Boolean[], DateTime[]
168
+ });
169
+ }
170
+
171
+ // Escalar — comportamento original preservado
107
172
  return new Variant({
108
173
  dataType,
174
+ arrayType: VariantArrayType.Scalar,
109
175
  value: coerceValue(item.value, typeName)
110
176
  });
111
177
  }
@@ -317,4 +383,4 @@ module.exports = {
317
383
  resolveSecurityMode,
318
384
  resolveSecurityPolicy,
319
385
  statusCodeToString
320
- };
386
+ };