@vitormnm/node-red-simple-opcua 1.6.3 → 1.8.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.
Files changed (45) hide show
  1. package/README.md +104 -136
  2. package/client/lib/opcua-client-browser.js +254 -11
  3. package/client/lib/opcua-client-method-service.js +1 -1
  4. package/client/lib/opcua-client-subscription-service.js +0 -2
  5. package/client/lib/opcua-client-write-service.js +14 -4
  6. package/client/opcua-client-config.html +118 -1
  7. package/client/opcua-client-config.js +112 -9
  8. package/client/opcua-client-help.html +6 -0
  9. package/client/opcua-client-utils.js +158 -10
  10. package/client/opcua-client.html +8 -0
  11. package/client/opcua-client.js +97 -1
  12. package/client/view/opcua-client.js +106 -14
  13. package/examples/flows_simple_opc.json +1 -1
  14. package/package.json +2 -2
  15. package/server/lib/opcua-address-space-alarm.js +95 -32
  16. package/server/lib/opcua-address-space-builder.js +717 -59
  17. package/server/lib/opcua-config.js +110 -35
  18. package/server/lib/opcua-server-events-child.js +31 -5
  19. package/server/lib/opcua-server-runtime-child.js +424 -27
  20. package/server/lib/opcua-server-runtime.js +52 -5
  21. package/server/lib/opcua-server-status-child.js +46 -15
  22. package/server/nodered/simple_opcua/server/certificates/mutex +0 -0
  23. package/server/nodered/simple_opcua/server/certificates/own/certs/server_selfsigned_cert_2048.pem +25 -0
  24. package/server/nodered/simple_opcua/server/certificates/own/certs/server_selfsigned_cert_2048.pem.mutex +0 -0
  25. package/server/nodered/simple_opcua/server/certificates/own/openssl.cnf +72 -0
  26. package/server/nodered/simple_opcua/server/certificates/own/private/private_key.pem +28 -0
  27. package/server/nodered/simple_opcua/server/certificates/trusted/certs/NodeOPCUA-Client@tuf[c5a9e20a8b680cdff76aaf0165bb3c9318da37a5].pem +25 -0
  28. package/server/nodered/simple_opcua/server/myServer1/mutex +0 -0
  29. package/server/nodered/simple_opcua/server/myServer1/own/certs/server_selfsigned_cert_2048.pem +25 -0
  30. package/server/nodered/simple_opcua/server/myServer1/own/certs/server_selfsigned_cert_2048.pem.mutex +0 -0
  31. package/server/nodered/simple_opcua/server/myServer1/own/openssl.cnf +72 -0
  32. package/server/nodered/simple_opcua/server/myServer1/own/private/private_key.pem +28 -0
  33. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[91e520c64ff891c67168f08a46dd194071e15dae].pem +25 -0
  34. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[98ae95da627cea4c500753c319161a3554ee38d7].pem +25 -0
  35. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[aef8d7a1cfba13d84189a0bcf1694208fc51a7f9].pem +25 -0
  36. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[c5a9e20a8b680cdff76aaf0165bb3c9318da37a5].pem +25 -0
  37. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[ebdf9acf1d02e347917a14108d3144799c638ea3].pem +25 -0
  38. package/server/opcua-server-io.html +93 -1
  39. package/server/opcua-server-io.js +153 -29
  40. package/server/opcua-server-registry.js +8 -2
  41. package/server/opcua-server.css +64 -0
  42. package/server/opcua-server.html +168 -44
  43. package/server/opcua-server.js +115 -5
  44. package/server/view/opcua-server.css +100 -6
  45. package/server/view/opcua-server.js +746 -48
@@ -15,18 +15,14 @@ class OpcUaAddressSpaceAlarm {
15
15
  }
16
16
 
17
17
  emitTagAccess(operation, details) {
18
- this.registry.emitTagAccess({
18
+ this.registry.emitTagAccess(Object.assign({
19
19
  operation,
20
20
  serverId: this.node.id,
21
21
  serverNodeName: this.node.name || "",
22
22
  serverName: this.serverName,
23
23
  timestamp: new Date().toISOString(),
24
- path: details.path,
25
- nodeID: details.nodeID,
26
- browseName: details.browseName,
27
- dataType: details.dataType,
28
- value: details.value
29
- });
24
+ users: []
25
+ }, details));
30
26
  }
31
27
 
32
28
  createAlarm(namespace, browseName, parentNode, inputNode, conditionName, nodeId, sourceName, alarmConfig) {
@@ -94,6 +90,7 @@ class OpcUaAddressSpaceAlarm {
94
90
  value: sourceName
95
91
  });
96
92
 
93
+ alarmNode.alarmConfig = alarmConfig;
97
94
  return alarmNode;
98
95
  } catch (error) {
99
96
  console.error("createAlarm");
@@ -101,21 +98,21 @@ class OpcUaAddressSpaceAlarm {
101
98
  }
102
99
  }
103
100
 
104
- checkAlarm(alarm, variableValue) {
101
+ checkAlarm(alarm, variableValue, context = null) {
105
102
  if (alarm) {
106
103
  const alarmConfig = alarm.alarmConfig;
107
104
  const type = alarmConfig.type;
108
105
 
109
106
  if (type === "levelAlarm") {
110
- this.levelAlarm(alarm, variableValue);
107
+ this.levelAlarm(alarm, variableValue, context);
111
108
  }
112
109
  if (type === "digitalAlarm") {
113
- this.digitalAlarm(alarm, variableValue);
110
+ this.digitalAlarm(alarm, variableValue, context);
114
111
  }
115
112
  }
116
113
  }
117
114
 
118
- levelAlarm(alarm, variableValue) {
115
+ levelAlarm(alarm, variableValue, context = null) {
119
116
  const alarmNode = alarm.node;
120
117
  const alarmConfig = alarm.alarmConfig;
121
118
 
@@ -128,38 +125,41 @@ class OpcUaAddressSpaceAlarm {
128
125
  let lastMessage = null;
129
126
  let message = null;
130
127
 
128
+ const sendValue = alarmConfig.sendValue !== false;
129
+
131
130
  if (variableValue >= highHighSp && enabled) {
132
- message = alarmConfig.highHighMessage + ": " + variableValue;
133
- this.raiseAlarm(alarmNode, message, alarmConfig.severity);
131
+ message = sendValue ? (alarmConfig.highHighMessage + ": " + variableValue) : alarmConfig.highHighMessage;
132
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity, true, context);
134
133
  lastMessage = message;
135
134
  } else if (variableValue >= highSp && enabled) {
136
- message = alarmConfig.highMessage + ": " + variableValue;
137
- this.raiseAlarm(alarmNode, message, alarmConfig.severity);
135
+ message = sendValue ? (alarmConfig.highMessage + ": " + variableValue) : alarmConfig.highMessage;
136
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity, true, context);
138
137
  lastMessage = message;
139
138
  } else if (variableValue <= lowLowSp && enabled) {
140
- message = alarmConfig.lowLowMessage + ": " + variableValue;
141
- this.raiseAlarm(alarmNode, message, alarmConfig.severity);
139
+ message = sendValue ? (alarmConfig.lowLowMessage + ": " + variableValue) : alarmConfig.lowLowMessage;
140
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity, true, context);
142
141
  lastMessage = message;
143
142
  } else if (variableValue <= lowSp && enabled) {
144
- message = alarmConfig.lowMessage + ": " + variableValue;
145
- this.raiseAlarm(alarmNode, message, alarmConfig.severity);
143
+ message = sendValue ? (alarmConfig.lowMessage + ": " + variableValue) : alarmConfig.lowMessage;
144
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity, true, context);
146
145
  lastMessage = message;
147
146
  } else if (isActive) {
148
- this.clearAlarm(alarmNode, lastMessage, alarmConfig.severity);
147
+ message = sendValue ? (alarmConfig.normalMessage + ": " + variableValue) : alarmConfig.normalMessage;
148
+ this.clearAlarm(alarmNode, lastMessage || message, alarmConfig.severity, context);
149
149
  }
150
150
 
151
151
  this.alarmMethods(alarmNode);
152
152
  }
153
153
 
154
- digitalAlarm(alarm, variableValue) {
154
+ digitalAlarm(alarm, variableValue, context = null) {
155
155
  const alarmNode = alarm.node;
156
156
  const alarmConfig = alarm.alarmConfig;
157
157
  const enabled = alarmNode.getPropertyByName("enabled").readValue().value.value;
158
158
 
159
159
  if (variableValue && enabled) {
160
- this.raiseAlarm(alarmNode, alarmConfig.digitalMessage, alarmConfig.severity);
160
+ this.raiseAlarm(alarmNode, alarmConfig.digitalMessage, alarmConfig.severity, true, context);
161
161
  } else {
162
- this.clearAlarm(alarmNode, alarmConfig.digitalMessage, alarmConfig.severity);
162
+ this.clearAlarm(alarmNode, alarmConfig.digitalMessage, alarmConfig.severity, context);
163
163
  }
164
164
 
165
165
  this.alarmMethods(alarmNode);
@@ -181,9 +181,9 @@ class OpcUaAddressSpaceAlarm {
181
181
  retain: false
182
182
  });
183
183
 
184
- this.raiseNewConditionAlarm(alarm, message, severity, false);
184
+ this.raiseNewConditionAlarm(alarm, message, severity, false, context);
185
185
  } else {
186
- this.raiseNewConditionAlarm(alarm, message, severity, true);
186
+ this.raiseNewConditionAlarm(alarm, message, severity, true, context);
187
187
  }
188
188
 
189
189
  callback(null, {
@@ -199,7 +199,7 @@ class OpcUaAddressSpaceAlarm {
199
199
  alarm.ackedState.setValue(true);
200
200
  alarm.confirmedState.setValue(false);
201
201
 
202
- this.raiseNewConditionAlarm(alarm, message, severity, true);
202
+ this.raiseNewConditionAlarm(alarm, message, severity, true, context);
203
203
 
204
204
  callback(null, {
205
205
  statusCode: StatusCodes.Good,
@@ -222,16 +222,16 @@ class OpcUaAddressSpaceAlarm {
222
222
  });
223
223
  }
224
224
 
225
- clearAlarm(alarmNode, message, severity) {
225
+ clearAlarm(alarmNode, message, severity, context = null) {
226
226
  const isAcked = !alarmNode.ackedState.id.readValue().value.value;
227
227
 
228
228
  alarmNode.activeState.setValue(false);
229
229
  alarmNode.raiseNewCondition({ message, severity: severity, isAcked });
230
230
 
231
- this.raiseNewConditionAlarm(alarmNode, message, severity, isAcked);
231
+ this.raiseNewConditionAlarm(alarmNode, message, severity, isAcked, context);
232
232
  }
233
233
 
234
- raiseAlarm(alarmNode, message, severity, retain = true) {
234
+ raiseAlarm(alarmNode, message, severity, retain = true, context = null) {
235
235
  const isActive = alarmNode.activeState.id.readValue().value.value;
236
236
  const isAcked = alarmNode.ackedState.id.readValue().value.value;
237
237
  if (isActive && isAcked) {
@@ -244,20 +244,83 @@ class OpcUaAddressSpaceAlarm {
244
244
  }
245
245
 
246
246
  alarmNode.activeState.setValue(true);
247
- this.raiseNewConditionAlarm(alarmNode, message, severity, retain);
247
+ this.raiseNewConditionAlarm(alarmNode, message, severity, retain, context);
248
+ }
249
+
250
+ getUserGroups(username) {
251
+ const normalized = String(username || "").trim();
252
+ if (!normalized || normalized.toLowerCase() === "anonymous") {
253
+ return [];
254
+ }
255
+ const users = (this.node && this.node.runtime && this.node.runtime.users) || [];
256
+ const user = users.find(u => u && u.username === normalized);
257
+ if (!user) {
258
+ return [];
259
+ }
260
+ return typeof user.group === "string"
261
+ ? user.group.split(",").map(g => g.trim()).filter(Boolean)
262
+ : Array.isArray(user.group)
263
+ ? user.group
264
+ : [];
248
265
  }
249
266
 
250
- raiseNewConditionAlarm(alarmNode, message, severity, retain) {
267
+ raiseNewConditionAlarm(alarmNode, message, severity, retain, context = null) {
251
268
  alarmNode.raiseNewCondition({ message, severity, retain });
252
269
 
253
270
  this.registry.registerActiveAlarms(alarmNode, message, severity, retain, this.node);
254
271
 
272
+ const alarmConfig = alarmNode.alarmConfig || {};
273
+ const sendValue = alarmConfig.sendValue !== false;
274
+
275
+ const ConditionName = alarmNode.getPropertyByName("ConditionName").readValue().value.value;
276
+ const SourceName = alarmNode.getPropertyByName("SourceName").readValue().value.value;
277
+ const isActive = alarmNode.activeState.id.readValue().value.value;
278
+ const isAcked = alarmNode.ackedState.id.readValue().value.value;
279
+ const ConfirmedState = alarmNode.confirmedState.id.readValue().value.value;
280
+
281
+ const activeContext = context || this.registry.activeWriteContext;
282
+
283
+ const users = [];
284
+ if (activeContext && activeContext.session) {
285
+ const session = activeContext.session;
286
+ const username = (session.userIdentityToken && session.userIdentityToken.userName)
287
+ ? session.userIdentityToken.userName
288
+ : "anonymous";
289
+ const groups = this.getUserGroups(username);
290
+ users.push({
291
+ name: username,
292
+ groups: groups
293
+ });
294
+ } else {
295
+ users.push({
296
+ name: "anonymous",
297
+ groups: []
298
+ });
299
+ }
300
+
255
301
  this.emitTagAccess("alarm", {
302
+ path: alarmNode.path || alarmNode.browseName.name,
303
+ nodeID: alarmNode.nodeId.toString(),
304
+ browseName: alarmNode.browseName.name,
256
305
  message: message,
257
306
  severity: severity,
258
307
  retain: retain,
259
308
  dataType: "alarm",
260
- value: "highHighSp"
309
+ value: sendValue ? "highHighSp" : null,
310
+ activeState: isActive,
311
+ sourceName: SourceName,
312
+ conditionName: ConditionName,
313
+ ConfirmedState: ConfirmedState,
314
+ ackedState: isAcked,
315
+ users: users,
316
+ alarmNode: {
317
+ nodeId: alarmNode.nodeId,
318
+ browseName: alarmNode.browseName,
319
+ displayName: alarmNode.displayName,
320
+ description: alarmNode.description,
321
+ nodeClass: alarmNode.nodeClass,
322
+ typeDefinition: alarmNode.typeDefinition
323
+ }
261
324
  });
262
325
  }
263
326