@vitormnm/node-red-simple-opcua 1.5.0 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitormnm/node-red-simple-opcua",
3
- "version": "1.5.0",
3
+ "version": "1.6.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -22,7 +22,8 @@ class OpcUaAddressSpaceBuilder {
22
22
  this.registry = options.registry;
23
23
  this.node = options.node;
24
24
  this.serverName = options.serverName;
25
- this.authorizationDisabled = !!options.allowAnonymous;
25
+ const hasUsers = Array.isArray(options.users) && options.users.length > 0;
26
+ this.authorizationDisabled = !hasUsers;
26
27
  this.nodeEntries = new Map();
27
28
  this.variableStore = new Map();
28
29
  this.variableNodeIdStore = new Map();
@@ -82,6 +83,7 @@ class OpcUaAddressSpaceBuilder {
82
83
  this.variableStore.clear();
83
84
  this.variableNodeIdStore.clear();
84
85
  this.objectTypeStore.clear();
86
+ if (this.enumerationStore) this.enumerationStore.clear();
85
87
  this.alarmStore.clear(); // Adicione esta linha
86
88
  this.pendingAlarms = [];
87
89
  }
@@ -134,7 +136,20 @@ class OpcUaAddressSpaceBuilder {
134
136
  }
135
137
 
136
138
  readValue(identifierType, identifier) {
137
- return this.getVariableRecord(identifierType, identifier).getValue();
139
+ const record = this.getVariableRecord(identifierType, identifier);
140
+ let val = record.getValue();
141
+ if (record.type === "Int64" || record.type === "UInt64") {
142
+ const convertToNumber = (v) => {
143
+ const num = Number(v);
144
+ return Number.isFinite(num) ? num : v;
145
+ };
146
+ if (record.isArray) {
147
+ val = Array.isArray(val) ? val.map(convertToNumber) : convertToNumber(val);
148
+ } else {
149
+ val = convertToNumber(val);
150
+ }
151
+ }
152
+ return val;
138
153
  }
139
154
 
140
155
  writeValue(identifierType, identifier, value) {
@@ -149,6 +164,10 @@ class OpcUaAddressSpaceBuilder {
149
164
  this.collectObjectTypeDefinition(desiredEntries, objectTypeConfig, objectTypeConfigs);
150
165
  });
151
166
 
167
+ (Array.isArray(treeConfig.enumerations) ? treeConfig.enumerations : []).forEach((enumerationConfig) => {
168
+ this.collectEnumerationDefinition(desiredEntries, enumerationConfig);
169
+ });
170
+
152
171
  (Array.isArray(treeConfig.folders) ? treeConfig.folders : []).forEach((folderConfig) => {
153
172
  this.collectBranch(desiredEntries, "folder", folderConfig, "", "organizedBy", objectTypeConfigs);
154
173
  });
@@ -183,6 +202,11 @@ class OpcUaAddressSpaceBuilder {
183
202
  });
184
203
  }
185
204
 
205
+ collectEnumerationDefinition(desiredEntries, config) {
206
+ const path = this.buildEnumerationPath(config.name);
207
+ desiredEntries.set(path, this.buildEntryDefinition("enumeration", config, path, "", "typeDefinition"));
208
+ }
209
+
186
210
  collectBranch(desiredEntries, kind, config, parentPath, relationship, objectTypeConfigs, options) {
187
211
  const settings = options || {};
188
212
  const path = settings.preserveCollectionNames
@@ -635,6 +659,11 @@ class OpcUaAddressSpaceBuilder {
635
659
  return;
636
660
  }
637
661
 
662
+ if (definition.kind === "enumeration") {
663
+ this.addEnumerationTypeDefinition(definition.config);
664
+ return;
665
+ }
666
+
638
667
  if (definition.kind === "object") {
639
668
  this.addObject(parentNode, definition.config, definition.parentPath, definition.relationship, definition.path);
640
669
  return;
@@ -702,6 +731,10 @@ class OpcUaAddressSpaceBuilder {
702
731
  this.objectTypeStore.delete(entry.config.name);
703
732
  }
704
733
 
734
+ if (entry.kind === "enumeration" && this.enumerationStore) {
735
+ this.enumerationStore.delete(entry.config.name);
736
+ }
737
+
705
738
  try {
706
739
  entry.namespace.deleteNode(entry.node);
707
740
 
@@ -774,6 +807,28 @@ class OpcUaAddressSpaceBuilder {
774
807
  });
775
808
  }
776
809
 
810
+ addEnumerationTypeDefinition(config) {
811
+ const namespace = this.getNamespaceForConfig(config);
812
+ const enumTypeNode = namespace.addEnumerationType({
813
+ browseName: config.displayName || config.name,
814
+ displayName: config.displayName || config.name,
815
+ description: config.description || "",
816
+ nodeId: this.resolveNodeId(config, this.buildEnumerationPath(config.name), namespace),
817
+ enumeration: config.enumeration
818
+ });
819
+
820
+ const path = this.buildEnumerationPath(config.name);
821
+
822
+ this.registerNodeEntry("enumeration", path, "", "typeDefinition", config, enumTypeNode, namespace);
823
+ if (!this.enumerationStore) this.enumerationStore = new Map();
824
+ this.enumerationStore.set(config.name, {
825
+ node: enumTypeNode,
826
+ config: config,
827
+ path: path,
828
+ namespace: namespace
829
+ });
830
+ }
831
+
777
832
  addObjectTypeInstance(parentNode, instanceConfig, parentPath, relationship, pathOverride) {
778
833
  const objectTypeEntry = this.objectTypeStore.get(instanceConfig.objectsType);
779
834
  if (!objectTypeEntry || !objectTypeEntry.node) {
@@ -1032,6 +1087,14 @@ class OpcUaAddressSpaceBuilder {
1032
1087
  this.registerNodeEntry("folder", nextPath, parentPath, relationship, folderConfig, folderNode, namespace);
1033
1088
  }
1034
1089
 
1090
+ resolveDataType(type) {
1091
+ if (DATA_TYPE_MAP[type]) return DATA_TYPE_MAP[type];
1092
+ if (this.enumerationStore && this.enumerationStore.has(type)) {
1093
+ return this.enumerationStore.get(type).node.nodeId;
1094
+ }
1095
+ return type;
1096
+ }
1097
+
1035
1098
  addVariable(parentNode, variableConfig, parentPath, pathOverride) {
1036
1099
  const namespace = this.getNamespaceForConfig(variableConfig);
1037
1100
  const name = variableConfig.name;
@@ -1044,7 +1107,7 @@ class OpcUaAddressSpaceBuilder {
1044
1107
  type,
1045
1108
  access,
1046
1109
  isArray: this.isArrayValue(variableConfig.value),
1047
- currentValue: variableConfig.value
1110
+ currentValue: this.coerceValue(variableConfig.value, type, this.isArrayValue(variableConfig.value))
1048
1111
  };
1049
1112
 
1050
1113
  const variableNode = namespace.addVariable({
@@ -1054,7 +1117,7 @@ class OpcUaAddressSpaceBuilder {
1054
1117
  description: variableConfig.description || "",
1055
1118
  nodeId,
1056
1119
  rolePermissions: this.buildRolePermissions("variable", variableConfig),
1057
- dataType: type,
1120
+ dataType: this.resolveDataType(type),
1058
1121
  modellingRule: this.isObjectTypePath(parentPath) ? "Mandatory" : undefined,
1059
1122
  valueRank: state.isArray ? 1 : -1,
1060
1123
  accessLevel: access === "readwrite" ? "CurrentRead | CurrentWrite" : "CurrentRead",
@@ -1070,14 +1133,40 @@ class OpcUaAddressSpaceBuilder {
1070
1133
  value: state.currentValue
1071
1134
  });
1072
1135
 
1136
+ let val = state.currentValue;
1137
+ if (state.type === "Int64" || state.type === "UInt64") {
1138
+ const bigIntToInt64Array = (v) => {
1139
+ let bigintVal;
1140
+ try {
1141
+ bigintVal = BigInt(v);
1142
+ } catch (e) {
1143
+ bigintVal = 0n;
1144
+ }
1145
+ const mask = 0xFFFFFFFFFFFFFFFFn;
1146
+ bigintVal = bigintVal & mask;
1147
+
1148
+ const high = Number(bigintVal >> 32n);
1149
+ const low = Number(bigintVal & 0xFFFFFFFFn);
1150
+ return [high, low];
1151
+ };
1152
+
1153
+ if (state.isArray) {
1154
+ val = Array.isArray(val) ? val.map(bigIntToInt64Array) : [bigIntToInt64Array(val)];
1155
+ } else {
1156
+ val = bigIntToInt64Array(val);
1157
+ }
1158
+ }
1159
+
1073
1160
  const variantOptions = {
1074
- dataType: DATA_TYPE_MAP[state.type],
1075
- value: state.currentValue
1161
+ dataType: DATA_TYPE_MAP[state.type] || DataType.Int32,
1162
+ value: val
1076
1163
  };
1077
1164
 
1078
1165
  // ByteString nunca e array - Buffer nao deve ser VariantArrayType.Array
1079
1166
  if (state.type !== "ByteString" && this.isArrayValue(state.currentValue)) {
1080
1167
  variantOptions.arrayType = VariantArrayType.Array;
1168
+ } else if (state.type === "Int64" || state.type === "UInt64") {
1169
+ variantOptions.arrayType = VariantArrayType.Scalar;
1081
1170
  }
1082
1171
 
1083
1172
  return new Variant(variantOptions);
@@ -1119,6 +1208,8 @@ class OpcUaAddressSpaceBuilder {
1119
1208
  path: path,
1120
1209
  nodeId: nodeId,
1121
1210
  nodeIdKey: this.normalizeNodeIdKey(nodeId),
1211
+ type: state.type,
1212
+ isArray: state.isArray,
1122
1213
  getValue: () => state.currentValue,
1123
1214
  setRuntimeValue: (nextValue) => {
1124
1215
  state.currentValue = this.coerceValue(nextValue, state.type, state.isArray);
@@ -1228,6 +1319,10 @@ class OpcUaAddressSpaceBuilder {
1228
1319
  return "__objectTypes." + name;
1229
1320
  }
1230
1321
 
1322
+ buildEnumerationPath(name) {
1323
+ return "__enumerations." + name;
1324
+ }
1325
+
1231
1326
  buildCollectionPath(parentPath, collectionName, name) {
1232
1327
 
1233
1328
  // return parentPath ? parentPath + "." + collectionName + "." + name : collectionName + "." + name;
@@ -1264,6 +1359,21 @@ class OpcUaAddressSpaceBuilder {
1264
1359
  }
1265
1360
 
1266
1361
  emitTagAccess(operation, details) {
1362
+ let val = details.value;
1363
+ if (details.dataType === "Int64" || details.dataType === "UInt64") {
1364
+ const convertToNumber = (v) => {
1365
+ const num = Number(v);
1366
+ return Number.isFinite(num) ? num : v;
1367
+ };
1368
+ const isArray = this.isArrayValue(val);
1369
+ if (isArray) {
1370
+ const items = this.extractArrayItems(val);
1371
+ val = Array.isArray(items) ? items.map(convertToNumber) : convertToNumber(val);
1372
+ } else {
1373
+ val = convertToNumber(val);
1374
+ }
1375
+ }
1376
+
1267
1377
  this.registry.emitTagAccess({
1268
1378
  operation,
1269
1379
  serverId: this.node.id,
@@ -1274,7 +1384,7 @@ class OpcUaAddressSpaceBuilder {
1274
1384
  nodeID: details.nodeID,
1275
1385
  browseName: details.browseName,
1276
1386
  dataType: details.dataType,
1277
- value: details.value
1387
+ value: val
1278
1388
  });
1279
1389
  }
1280
1390
 
@@ -1443,7 +1553,11 @@ class OpcUaAddressSpaceBuilder {
1443
1553
  }
1444
1554
 
1445
1555
  if (this.extractArrayItems(value)) {
1446
- throw new Error("Expected scalar value for type " + type + " but received array");
1556
+ if ((type === "Int64" || type === "UInt64") && Array.isArray(value) && value.length === 2 && typeof value[0] === "number" && typeof value[1] === "number") {
1557
+ // Do not throw, this is a standard scalar Int64/UInt64 represented as [high, low]
1558
+ } else {
1559
+ throw new Error("Expected scalar value for type " + type + " but received array");
1560
+ }
1447
1561
  }
1448
1562
 
1449
1563
  return this.coerceScalarValue(value, type);
@@ -1468,6 +1582,86 @@ class OpcUaAddressSpaceBuilder {
1468
1582
  return Math.trunc(parsed);
1469
1583
  }
1470
1584
 
1585
+ if (type === "Int64") {
1586
+ const minVal = -9223372036854775808n;
1587
+ const maxVal = 9223372036854775807n;
1588
+ if (Array.isArray(value) && value.length === 2) {
1589
+ try {
1590
+ const h = BigInt(value[0]);
1591
+ const l = BigInt(value[1]);
1592
+ const signMask = 1n << 31n;
1593
+ const shiftHigh = 1n << 32n;
1594
+ let bigintVal;
1595
+ if ((h & signMask) === signMask) {
1596
+ bigintVal = (h & ~signMask) * shiftHigh + l - 0x8000000000000000n;
1597
+ } else {
1598
+ bigintVal = h * shiftHigh + l;
1599
+ }
1600
+ if (bigintVal < minVal) bigintVal = minVal;
1601
+ else if (bigintVal > maxVal) bigintVal = maxVal;
1602
+ return String(bigintVal);
1603
+ } catch (error) {
1604
+ return "0";
1605
+ }
1606
+ }
1607
+ try {
1608
+ let bigintVal = BigInt(value);
1609
+ if (bigintVal < minVal) bigintVal = minVal;
1610
+ else if (bigintVal > maxVal) bigintVal = maxVal;
1611
+ return String(bigintVal);
1612
+ } catch (error) {
1613
+ const parsed = Number(value);
1614
+ if (Number.isFinite(parsed)) {
1615
+ try {
1616
+ let bigintVal = BigInt(Math.trunc(parsed));
1617
+ if (bigintVal < minVal) bigintVal = minVal;
1618
+ else if (bigintVal > maxVal) bigintVal = maxVal;
1619
+ return String(bigintVal);
1620
+ } catch (e2) {
1621
+ return "0";
1622
+ }
1623
+ }
1624
+ return "0";
1625
+ }
1626
+ }
1627
+
1628
+ if (type === "UInt64") {
1629
+ const minVal = 0n;
1630
+ const maxVal = 18446744073709551615n;
1631
+ if (Array.isArray(value) && value.length === 2) {
1632
+ try {
1633
+ const h = BigInt(value[0]);
1634
+ const l = BigInt(value[1]);
1635
+ const shiftHigh = 1n << 32n;
1636
+ let bigintVal = h * shiftHigh + l;
1637
+ if (bigintVal < minVal) bigintVal = minVal;
1638
+ else if (bigintVal > maxVal) bigintVal = maxVal;
1639
+ return String(bigintVal);
1640
+ } catch (error) {
1641
+ return "0";
1642
+ }
1643
+ }
1644
+ try {
1645
+ let bigintVal = BigInt(value);
1646
+ if (bigintVal < minVal) bigintVal = minVal;
1647
+ else if (bigintVal > maxVal) bigintVal = maxVal;
1648
+ return String(bigintVal);
1649
+ } catch (error) {
1650
+ const parsed = Number(value);
1651
+ if (Number.isFinite(parsed)) {
1652
+ try {
1653
+ let bigintVal = BigInt(Math.trunc(parsed));
1654
+ if (bigintVal < minVal) bigintVal = minVal;
1655
+ else if (bigintVal > maxVal) bigintVal = maxVal;
1656
+ return String(bigintVal);
1657
+ } catch (e2) {
1658
+ return "0";
1659
+ }
1660
+ }
1661
+ return "0";
1662
+ }
1663
+ }
1664
+
1471
1665
  if (type === "Float") {
1472
1666
  const parsed = Number(value);
1473
1667
  if (!Number.isFinite(parsed)) {
@@ -1574,7 +1768,7 @@ function compareEntryCreationOrder(left, right) {
1574
1768
  }
1575
1769
 
1576
1770
  function kindRank(kind) {
1577
- if (kind === "objectTypeDefinition") {
1771
+ if (kind === "objectTypeDefinition" || kind === "enumeration") {
1578
1772
  return -1;
1579
1773
  }
1580
1774
  if (kind === "folder") {
@@ -92,7 +92,17 @@ class OpcUaServerConfigParser {
92
92
  };
93
93
 
94
94
  (Array.isArray(groups) ? groups : []).forEach(addGroup);
95
- (Array.isArray(users) ? users : []).forEach((user) => addGroup(user && user.group));
95
+ (Array.isArray(users) ? users : []).forEach((user) => {
96
+ if (user && user.group) {
97
+ if (typeof user.group === "string") {
98
+ user.group.split(",").forEach(addGroup);
99
+ } else if (Array.isArray(user.group)) {
100
+ user.group.forEach(addGroup);
101
+ } else {
102
+ addGroup(user.group);
103
+ }
104
+ }
105
+ });
96
106
 
97
107
  return resolved;
98
108
  }
@@ -121,10 +131,17 @@ class OpcUaServerConfigParser {
121
131
  this._objectsTypesMap[typeDef.name] = typeDef;
122
132
  }
123
133
 
134
+ const enumerations = this.normalizeEnumerations(parsed.enumerations || parsed.enumeration || []);
135
+ this._enumerationsMap = {};
136
+ for (const enumDef of enumerations) {
137
+ this._enumerationsMap[enumDef.name] = enumDef;
138
+ }
139
+
124
140
  return {
125
141
  objects: this.normalizeObjects(parsed.objects || []),
126
142
  folders: this.normalizeFolders(parsed.folders || []),
127
143
  objectsTypes,
144
+ enumerations,
128
145
  nameSpaces: this.normalizeNamespaces(parsed.nameSpaces || parsed.namespaces || [])
129
146
  };
130
147
  }
@@ -366,6 +383,41 @@ class OpcUaServerConfigParser {
366
383
  return normalizedBranch;
367
384
  }
368
385
 
386
+ normalizeEnumerations(enumerations) {
387
+ if (!Array.isArray(enumerations)) {
388
+ throw new Error("'enumerations' must be an array");
389
+ }
390
+ return enumerations.map((config) => this.normalizeEnumeration(config));
391
+ }
392
+
393
+ normalizeEnumeration(enumerationConfig) {
394
+ if (!enumerationConfig || typeof enumerationConfig !== "object" || Array.isArray(enumerationConfig)) {
395
+ throw new Error("Each enumeration must be an object");
396
+ }
397
+
398
+ const name = this.requiredName(enumerationConfig, "enumeration");
399
+
400
+ let enumerationStates = [];
401
+ if (Array.isArray(enumerationConfig.enumeration)) {
402
+ enumerationStates = enumerationConfig.enumeration.map(state => {
403
+ return {
404
+ value: Number.isFinite(Number(state.value)) ? Number(state.value) : 0,
405
+ displayName: typeof state.displayName === "string" ? state.displayName : ""
406
+ };
407
+ });
408
+ }
409
+
410
+ return {
411
+ name,
412
+ displayName: enumerationConfig.displayName || name,
413
+ description: enumerationConfig.description || "",
414
+ nodeId: this.normalizeOptionalNodeId(enumerationConfig.nodeId),
415
+ namespaceId: this.normalizeNamespaceId(enumerationConfig.namespaceId),
416
+ accessPermission: this.normalizeAccessPermissions(enumerationConfig.accessPermission || enumerationConfig.accessPermissions),
417
+ enumeration: enumerationStates
418
+ };
419
+ }
420
+
369
421
  // Returns the string value after "s=" in a nodeId like "ns=2;s=Motor_type2"
370
422
  _extractNodeIdValue(nodeId) {
371
423
  if (!nodeId) return "";
@@ -485,11 +537,21 @@ class OpcUaServerConfigParser {
485
537
  const username = typeof userConfig.username === "string" ? userConfig.username.trim() : "";
486
538
  const passwordHash = typeof userConfig.passwordHash === "string" ? userConfig.passwordHash : "";
487
539
  const password = typeof userConfig.password === "string" ? userConfig.password : "";
488
- const group = typeof userConfig.group === "string"
489
- ? userConfig.group.trim()
490
- : typeof userConfig.role === "string"
491
- ? userConfig.role.trim()
492
- : "";
540
+
541
+ let group = "";
542
+ if (userConfig.group !== undefined) {
543
+ if (Array.isArray(userConfig.group)) {
544
+ group = userConfig.group.map(g => typeof g === "string" ? g.trim() : "").filter(Boolean).join(",");
545
+ } else if (typeof userConfig.group === "string") {
546
+ group = userConfig.group.trim();
547
+ }
548
+ } else if (userConfig.role !== undefined) {
549
+ if (Array.isArray(userConfig.role)) {
550
+ group = userConfig.role.map(r => typeof r === "string" ? r.trim() : "").filter(Boolean).join(",");
551
+ } else if (typeof userConfig.role === "string") {
552
+ group = userConfig.role.trim();
553
+ }
554
+ }
493
555
 
494
556
  if (!username) {
495
557
  throw new Error("Each user requires a non-empty username");
@@ -543,6 +605,7 @@ class OpcUaServerConfigParser {
543
605
  uint16: "UInt16",
544
606
  int32: "Int32",
545
607
  uint32: "UInt32",
608
+ int64: "Int64",
546
609
  float: "Float",
547
610
  boolean: "Boolean",
548
611
  string: "String",
@@ -550,7 +613,7 @@ class OpcUaServerConfigParser {
550
613
  localizedText: "LocalizedText",
551
614
  };
552
615
  const canonical = aliases[normalized.toLowerCase()] || normalized;
553
- if (!DATA_TYPE_MAP[canonical]) {
616
+ if (!DATA_TYPE_MAP[canonical] && (!this._enumerationsMap || !this._enumerationsMap[canonical])) {
554
617
  throw new Error("Unsupported variable type: " + type);
555
618
  }
556
619
 
@@ -638,7 +701,7 @@ class OpcUaServerConfigParser {
638
701
  }
639
702
 
640
703
  coerceScalarValue(value, type) {
641
- if (type === "Int32") {
704
+ if (type === "Int32" || (this._enumerationsMap && this._enumerationsMap[type])) {
642
705
  const parsed = Number(value);
643
706
  if (!Number.isFinite(parsed)) {
644
707
  return 0;
@@ -646,6 +709,66 @@ class OpcUaServerConfigParser {
646
709
  return Math.trunc(parsed);
647
710
  }
648
711
 
712
+ if (type === "Int64") {
713
+ const minVal = -9223372036854775808n;
714
+ const maxVal = 9223372036854775807n;
715
+ try {
716
+ let bigintVal = BigInt(value);
717
+ if (bigintVal < minVal) bigintVal = minVal;
718
+ else if (bigintVal > maxVal) bigintVal = maxVal;
719
+ return String(bigintVal);
720
+ } catch (error) {
721
+ const parsed = Number(value);
722
+ if (Number.isFinite(parsed)) {
723
+ if (parsed >= 9223372036854775807) {
724
+ return String(maxVal);
725
+ }
726
+ if (parsed <= -9223372036854775808) {
727
+ return String(minVal);
728
+ }
729
+ try {
730
+ let bigintVal = BigInt(Math.trunc(parsed));
731
+ if (bigintVal < minVal) bigintVal = minVal;
732
+ else if (bigintVal > maxVal) bigintVal = maxVal;
733
+ return String(bigintVal);
734
+ } catch (e2) {
735
+ return "0";
736
+ }
737
+ }
738
+ return "0";
739
+ }
740
+ }
741
+
742
+ if (type === "UInt64") {
743
+ const minVal = 0n;
744
+ const maxVal = 18446744073709551615n;
745
+ try {
746
+ let bigintVal = BigInt(value);
747
+ if (bigintVal < minVal) bigintVal = minVal;
748
+ else if (bigintVal > maxVal) bigintVal = maxVal;
749
+ return String(bigintVal);
750
+ } catch (error) {
751
+ const parsed = Number(value);
752
+ if (Number.isFinite(parsed)) {
753
+ if (parsed >= 18446744073709551615) {
754
+ return String(maxVal);
755
+ }
756
+ if (parsed <= 0) {
757
+ return String(minVal);
758
+ }
759
+ try {
760
+ let bigintVal = BigInt(Math.trunc(parsed));
761
+ if (bigintVal < minVal) bigintVal = minVal;
762
+ else if (bigintVal > maxVal) bigintVal = maxVal;
763
+ return String(bigintVal);
764
+ } catch (e2) {
765
+ return "0";
766
+ }
767
+ }
768
+ return "0";
769
+ }
770
+ }
771
+
649
772
  if (type === "Float") {
650
773
  const parsed = Number(value);
651
774
  if (!Number.isFinite(parsed)) {
@@ -45,6 +45,7 @@ const DATA_TYPE_MAP = {
45
45
  UInt16: DataType.UInt16,
46
46
  Int32: DataType.Int32,
47
47
  UInt32: DataType.UInt32,
48
+ Int64: DataType.Int64,
48
49
  Float: DataType.Float,
49
50
  Boolean: DataType.Boolean,
50
51
  String: DataType.String,
@@ -113,6 +113,8 @@ class OpcUaServerMethods {
113
113
  const eventId = inputArguments[0].value;
114
114
  const comment = inputArguments[1].value;
115
115
 
116
+
117
+
116
118
  const alarm = context.object;
117
119
  // severity atual
118
120
  const severity = alarm.severity.readValue().value.value;