@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.
@@ -0,0 +1,341 @@
1
+ const {
2
+ StatusCodes,
3
+ Variant,
4
+ DataType
5
+ } = require("./opcua-constants");
6
+
7
+ class OpcUaAddressSpaceAlarm {
8
+
9
+ constructor(options) {
10
+ this.namespace = options.namespace;
11
+ this.node = options.node;
12
+ this.serverName = options.registry;
13
+ this.registry = options.registry;
14
+ this.alarmTypesByNamespace = new Map();
15
+ }
16
+
17
+ emitTagAccess(operation, details) {
18
+ this.registry.emitTagAccess({
19
+ operation,
20
+ serverId: this.node.id,
21
+ serverNodeName: this.node.name || "",
22
+ serverName: this.serverName,
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
+ });
30
+ }
31
+
32
+ createAlarm(namespace, browseName, parentNode, inputNode, conditionName, nodeId, sourceName, alarmConfig) {
33
+ try {
34
+ const type = alarmConfig.type;
35
+ let alarmNode = null;
36
+ const alarmTypes = this.ensureNamespaceTypes(namespace);
37
+
38
+ const config = {
39
+ browseName: browseName,
40
+ componentOf: parentNode,
41
+ inputNode: inputNode,
42
+ conditionSource: parentNode,
43
+ conditionName: conditionName,
44
+ normalState: false,
45
+ nodeId: nodeId,
46
+ description: alarmConfig.description || "",
47
+ namespace: namespace,
48
+ optionals: [
49
+ "ConfirmedState",
50
+ "Confirm"
51
+ ]
52
+ };
53
+
54
+ if (type === "digitalAlarm") {
55
+ alarmNode = namespace.instantiateAlarmCondition(alarmTypes.digitalAlarmType, config);
56
+ }
57
+
58
+ if (type === "levelAlarm") {
59
+ alarmNode = namespace.instantiateAlarmCondition(alarmTypes.levelAlarmType, config);
60
+
61
+ alarmNode.getPropertyByName("lowLowLimit")
62
+ .setValueFromSource({
63
+ dataType: DataType.Int32,
64
+ value: alarmConfig.lowLowLimit
65
+ });
66
+
67
+ alarmNode.getPropertyByName("lowLimit")
68
+ .setValueFromSource({
69
+ dataType: DataType.Int32,
70
+ value: alarmConfig.lowLimit
71
+ });
72
+
73
+ alarmNode.getPropertyByName("highHighLimit")
74
+ .setValueFromSource({
75
+ dataType: DataType.Int32,
76
+ value: alarmConfig.highHighLimit
77
+ });
78
+
79
+ alarmNode.getPropertyByName("highLimit")
80
+ .setValueFromSource({
81
+ dataType: DataType.Int32,
82
+ value: alarmConfig.highLimit
83
+ });
84
+ }
85
+
86
+ alarmNode.getPropertyByName("enabled")
87
+ .setValueFromSource({
88
+ dataType: DataType.Boolean,
89
+ value: alarmConfig.enabled
90
+ });
91
+
92
+ alarmNode.sourceName.setValueFromSource({
93
+ dataType: DataType.String,
94
+ value: sourceName
95
+ });
96
+
97
+ return alarmNode;
98
+ } catch (error) {
99
+ console.error("createAlarm");
100
+ console.error(error);
101
+ }
102
+ }
103
+
104
+ checkAlarm(alarm, variableValue) {
105
+ if (alarm) {
106
+ const alarmConfig = alarm.alarmConfig;
107
+ const type = alarmConfig.type;
108
+
109
+ if (type === "levelAlarm") {
110
+ this.levelAlarm(alarm, variableValue);
111
+ }
112
+ if (type === "digitalAlarm") {
113
+ this.digitalAlarm(alarm, variableValue);
114
+ }
115
+ }
116
+ }
117
+
118
+ levelAlarm(alarm, variableValue) {
119
+ const alarmNode = alarm.node;
120
+ const alarmConfig = alarm.alarmConfig;
121
+
122
+ const isActive = alarmNode.activeState.id.readValue().value.value;
123
+ const highHighSp = alarmNode.getPropertyByName("highHighLimit").readValue().value.value;
124
+ const highSp = alarmNode.getPropertyByName("highLimit").readValue().value.value;
125
+ const lowSp = alarmNode.getPropertyByName("lowLimit").readValue().value.value;
126
+ const lowLowSp = alarmNode.getPropertyByName("lowLowLimit").readValue().value.value;
127
+ const enabled = alarmNode.getPropertyByName("enabled").readValue().value.value;
128
+ let lastMessage = null;
129
+ let message = null;
130
+
131
+ if (variableValue >= highHighSp && enabled) {
132
+ message = alarmConfig.highHighMessage + ": " + variableValue;
133
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity);
134
+ lastMessage = message;
135
+ } else if (variableValue >= highSp && enabled) {
136
+ message = alarmConfig.highMessage + ": " + variableValue;
137
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity);
138
+ lastMessage = message;
139
+ } else if (variableValue <= lowLowSp && enabled) {
140
+ message = alarmConfig.lowLowMessage + ": " + variableValue;
141
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity);
142
+ lastMessage = message;
143
+ } else if (variableValue <= lowSp && enabled) {
144
+ message = alarmConfig.lowMessage + ": " + variableValue;
145
+ this.raiseAlarm(alarmNode, message, alarmConfig.severity);
146
+ lastMessage = message;
147
+ } else if (isActive) {
148
+ this.clearAlarm(alarmNode, lastMessage, alarmConfig.severity);
149
+ }
150
+
151
+ this.alarmMethods(alarmNode);
152
+ }
153
+
154
+ digitalAlarm(alarm, variableValue) {
155
+ const alarmNode = alarm.node;
156
+ const alarmConfig = alarm.alarmConfig;
157
+ const enabled = alarmNode.getPropertyByName("enabled").readValue().value.value;
158
+
159
+ if (variableValue && enabled) {
160
+ this.raiseAlarm(alarmNode, alarmConfig.digitalMessage, alarmConfig.severity);
161
+ } else {
162
+ this.clearAlarm(alarmNode, alarmConfig.digitalMessage, alarmConfig.severity);
163
+ }
164
+
165
+ this.alarmMethods(alarmNode);
166
+ }
167
+
168
+ alarmMethods(alarmNode) {
169
+ alarmNode.confirm.bindMethod((inputArguments, context, callback) => {
170
+ const alarm = context.object;
171
+ const severity = alarm.severity.readValue().value.value;
172
+ const message = alarm.message.readValue().value.value.text;
173
+ alarm.confirmedState.setValue(true);
174
+
175
+ const isAcked = alarm.ackedState.id.readValue().value.value;
176
+
177
+ if (isAcked) {
178
+ alarm.raiseNewCondition({
179
+ message: message,
180
+ severity: severity,
181
+ retain: false
182
+ });
183
+
184
+ this.raiseNewConditionAlarm(alarm, message, severity, false);
185
+ } else {
186
+ this.raiseNewConditionAlarm(alarm, message, severity, true);
187
+ }
188
+
189
+ callback(null, {
190
+ statusCode: StatusCodes.Good,
191
+ outputArguments: []
192
+ });
193
+ });
194
+
195
+ alarmNode.acknowledge.bindMethod((inputArguments, context, callback) => {
196
+ const alarm = context.object;
197
+ const severity = alarm.severity.readValue().value.value;
198
+ const message = alarm.message.readValue().value.value.text;
199
+ alarm.ackedState.setValue(true);
200
+ alarm.confirmedState.setValue(false);
201
+
202
+ this.raiseNewConditionAlarm(alarm, message, severity, true);
203
+
204
+ callback(null, {
205
+ statusCode: StatusCodes.Good,
206
+ outputArguments: []
207
+ });
208
+ });
209
+
210
+ alarmNode.addComment.bindMethod((inputArguments, context, callback) => {
211
+ const comment = inputArguments[1].value;
212
+ const alarm = context.object;
213
+
214
+ alarm.comment.setValueFromSource({
215
+ value: comment,
216
+ dataType: DataType.LocalizedText
217
+ });
218
+ callback(null, {
219
+ statusCode: StatusCodes.Good,
220
+ outputArguments: []
221
+ });
222
+ });
223
+ }
224
+
225
+ clearAlarm(alarmNode, message, severity) {
226
+ const isAcked = !alarmNode.ackedState.id.readValue().value.value;
227
+
228
+ alarmNode.activeState.setValue(false);
229
+ alarmNode.raiseNewCondition({ message, severity: severity, isAcked });
230
+
231
+ this.raiseNewConditionAlarm(alarmNode, message, severity, isAcked);
232
+ }
233
+
234
+ raiseAlarm(alarmNode, message, severity, retain = true) {
235
+ const isActive = alarmNode.activeState.id.readValue().value.value;
236
+ const isAcked = alarmNode.ackedState.id.readValue().value.value;
237
+ if (isActive && isAcked) {
238
+ alarmNode.activeState.setValue(false);
239
+ alarmNode.ackedState.setValue(true);
240
+ alarmNode.confirmedState.setValue(true);
241
+ } else {
242
+ alarmNode.ackedState.setValue(false);
243
+ alarmNode.confirmedState.setValue(true);
244
+ }
245
+
246
+ alarmNode.activeState.setValue(true);
247
+ this.raiseNewConditionAlarm(alarmNode, message, severity, retain);
248
+ }
249
+
250
+ raiseNewConditionAlarm(alarmNode, message, severity, retain) {
251
+ alarmNode.raiseNewCondition({ message, severity, retain });
252
+
253
+ this.registry.registerActiveAlarms(alarmNode, message, severity, retain, this.node);
254
+
255
+ this.emitTagAccess("alarm", {
256
+ message: message,
257
+ severity: severity,
258
+ retain: retain,
259
+ dataType: "alarm",
260
+ value: "highHighSp"
261
+ });
262
+ }
263
+
264
+ ensureNamespaceTypes(namespace) {
265
+ const namespaceKey = namespace.index;
266
+ if (this.alarmTypesByNamespace.has(namespaceKey)) {
267
+ return this.alarmTypesByNamespace.get(namespaceKey);
268
+ }
269
+
270
+ const types = this.createObjectType(namespace);
271
+ this.alarmTypesByNamespace.set(namespaceKey, types);
272
+ return types;
273
+ }
274
+
275
+ createObjectType(namespace) {
276
+ const digitalAlarm = namespace.addObjectType({
277
+ browseName: "digitalAlarm",
278
+ subtypeOf: "OffNormalAlarmType"
279
+ });
280
+
281
+ const levelAlarm = namespace.addObjectType({
282
+ browseName: "levelAlarm",
283
+ subtypeOf: "OffNormalAlarmType"
284
+ });
285
+
286
+ namespace.addVariable({
287
+ propertyOf: digitalAlarm,
288
+ browseName: "enabled",
289
+ dataType: "Boolean",
290
+ modellingRule: "Mandatory",
291
+ value: new Variant({ dataType: DataType.Boolean, value: true })
292
+ });
293
+
294
+ namespace.addVariable({
295
+ propertyOf: levelAlarm,
296
+ browseName: "enabled",
297
+ dataType: "Boolean",
298
+ modellingRule: "Mandatory",
299
+ value: new Variant({ dataType: DataType.Boolean, value: true })
300
+ });
301
+
302
+ namespace.addVariable({
303
+ propertyOf: levelAlarm,
304
+ browseName: "highHighLimit",
305
+ dataType: "Int32",
306
+ modellingRule: "Mandatory",
307
+ value: new Variant({ dataType: DataType.Int32, value: 0 })
308
+ });
309
+
310
+ namespace.addVariable({
311
+ propertyOf: levelAlarm,
312
+ browseName: "highLimit",
313
+ dataType: "Int32",
314
+ modellingRule: "Mandatory",
315
+ value: new Variant({ dataType: DataType.Int32, value: 0 })
316
+ });
317
+
318
+ namespace.addVariable({
319
+ propertyOf: levelAlarm,
320
+ browseName: "lowLimit",
321
+ dataType: "Int32",
322
+ modellingRule: "Mandatory",
323
+ value: new Variant({ dataType: DataType.Int32, value: 0 })
324
+ });
325
+
326
+ namespace.addVariable({
327
+ propertyOf: levelAlarm,
328
+ browseName: "lowLowLimit",
329
+ dataType: "Int32",
330
+ modellingRule: "Mandatory",
331
+ value: new Variant({ dataType: DataType.Int32, value: 0 })
332
+ });
333
+
334
+ return {
335
+ digitalAlarmType: digitalAlarm,
336
+ levelAlarmType: levelAlarm
337
+ };
338
+ }
339
+ }
340
+
341
+ module.exports = { OpcUaAddressSpaceAlarm };