node-opcua-address-space 2.70.3 → 2.72.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.
Files changed (72) hide show
  1. package/dist/source/loader/load_nodeset2.js +18 -14
  2. package/dist/source/loader/load_nodeset2.js.map +1 -1
  3. package/dist/source/loader/make_semver_compatible.d.ts +6 -0
  4. package/dist/source/loader/make_semver_compatible.js +26 -0
  5. package/dist/source/loader/make_semver_compatible.js.map +1 -0
  6. package/dist/source/loader/make_xml_extension_object_parser.js +12 -2
  7. package/dist/source/loader/make_xml_extension_object_parser.js.map +1 -1
  8. package/dist/src/alarms_and_conditions/ua_acknowledgeable_condition_impl.d.ts +3 -1
  9. package/dist/src/alarms_and_conditions/ua_acknowledgeable_condition_impl.js.map +1 -1
  10. package/dist/src/alarms_and_conditions/ua_alarm_condition_impl.d.ts +12 -6
  11. package/dist/src/alarms_and_conditions/ua_alarm_condition_impl.js +2 -2
  12. package/dist/src/alarms_and_conditions/ua_alarm_condition_impl.js.map +1 -1
  13. package/dist/src/alarms_and_conditions/ua_certificate_expiration_alarm_impl.d.ts +18 -3
  14. package/dist/src/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js +95 -5
  15. package/dist/src/alarms_and_conditions/ua_certificate_expiration_alarm_impl.js.map +1 -1
  16. package/dist/src/alarms_and_conditions/ua_condition_impl.d.ts +7 -2
  17. package/dist/src/alarms_and_conditions/ua_condition_impl.js +6 -4
  18. package/dist/src/alarms_and_conditions/ua_condition_impl.js.map +1 -1
  19. package/dist/src/alarms_and_conditions/ua_discrete_alarm_impl.d.ts +4 -3
  20. package/dist/src/alarms_and_conditions/ua_discrete_alarm_impl.js.map +1 -1
  21. package/dist/src/alarms_and_conditions/ua_exclusive_deviation_alarm_impl.d.ts +6 -3
  22. package/dist/src/alarms_and_conditions/ua_exclusive_deviation_alarm_impl.js.map +1 -1
  23. package/dist/src/alarms_and_conditions/ua_exclusive_level_alarm_impl.d.ts +3 -1
  24. package/dist/src/alarms_and_conditions/ua_exclusive_level_alarm_impl.js +2 -2
  25. package/dist/src/alarms_and_conditions/ua_exclusive_level_alarm_impl.js.map +1 -1
  26. package/dist/src/alarms_and_conditions/ua_exclusive_limit_alarm_impl.d.ts +5 -3
  27. package/dist/src/alarms_and_conditions/ua_exclusive_limit_alarm_impl.js.map +1 -1
  28. package/dist/src/alarms_and_conditions/ua_limit_alarm_impl.d.ts +12 -4
  29. package/dist/src/alarms_and_conditions/ua_limit_alarm_impl.js +3 -3
  30. package/dist/src/alarms_and_conditions/ua_limit_alarm_impl.js.map +1 -1
  31. package/dist/src/alarms_and_conditions/ua_non_exclusive_deviation_alarm_impl.d.ts +4 -3
  32. package/dist/src/alarms_and_conditions/ua_non_exclusive_deviation_alarm_impl.js.map +1 -1
  33. package/dist/src/alarms_and_conditions/ua_non_exclusive_limit_alarm_impl.d.ts +4 -3
  34. package/dist/src/alarms_and_conditions/ua_non_exclusive_limit_alarm_impl.js.map +1 -1
  35. package/dist/src/alarms_and_conditions/ua_off_normal_alarm_impl.d.ts +17 -8
  36. package/dist/src/alarms_and_conditions/ua_off_normal_alarm_impl.js +45 -19
  37. package/dist/src/alarms_and_conditions/ua_off_normal_alarm_impl.js.map +1 -1
  38. package/dist/src/alarms_and_conditions/ua_system_off_normal_alarm_impl.d.ts +4 -3
  39. package/dist/src/alarms_and_conditions/ua_system_off_normal_alarm_impl.js.map +1 -1
  40. package/dist/src/ua_object_impl.d.ts +4 -2
  41. package/dist/src/ua_object_impl.js +7 -1
  42. package/dist/src/ua_object_impl.js.map +1 -1
  43. package/dist/src/ua_variable_type_impl.js +8 -2
  44. package/dist/src/ua_variable_type_impl.js.map +1 -1
  45. package/dist/src/ua_view_impl.d.ts +6 -2
  46. package/dist/src/ua_view_impl.js +8 -1
  47. package/dist/src/ua_view_impl.js.map +1 -1
  48. package/package.json +38 -38
  49. package/source/loader/load_nodeset2.ts +21 -17
  50. package/source/loader/make_semver_compatible.ts +23 -0
  51. package/source/loader/make_xml_extension_object_parser.ts +16 -6
  52. package/src/alarms_and_conditions/ua_acknowledgeable_condition_impl.ts +13 -6
  53. package/src/alarms_and_conditions/ua_alarm_condition_impl.ts +15 -10
  54. package/src/alarms_and_conditions/ua_certificate_expiration_alarm_impl.ts +126 -10
  55. package/src/alarms_and_conditions/ua_condition_impl.ts +26 -13
  56. package/src/alarms_and_conditions/ua_discrete_alarm_impl.ts +10 -4
  57. package/src/alarms_and_conditions/ua_exclusive_deviation_alarm_impl.ts +7 -6
  58. package/src/alarms_and_conditions/ua_exclusive_level_alarm_impl.ts +5 -3
  59. package/src/alarms_and_conditions/ua_exclusive_limit_alarm_impl.ts +7 -6
  60. package/src/alarms_and_conditions/ua_exclusive_rate_of_change_alarm_impl.ts +1 -1
  61. package/src/alarms_and_conditions/ua_limit_alarm_impl.ts +23 -13
  62. package/src/alarms_and_conditions/ua_non_exclusive_deviation_alarm_impl.ts +6 -7
  63. package/src/alarms_and_conditions/ua_non_exclusive_limit_alarm_impl.ts +6 -7
  64. package/src/alarms_and_conditions/ua_off_normal_alarm_impl.ts +62 -30
  65. package/src/alarms_and_conditions/ua_system_off_normal_alarm_impl.ts +5 -5
  66. package/src/ua_object_impl.ts +11 -3
  67. package/src/ua_variable_type_impl.ts +11 -4
  68. package/src/ua_view_impl.ts +6 -4
  69. package/test_helpers/test_fixtures/dataType_issue.xml +9 -9
  70. package/test_helpers/test_fixtures/eurange_issue.xml +73 -0
  71. package/test_helpers/test_fixtures/nodeset_with_guid.xml +1442 -0
  72. package/test_helpers/test_fixtures/nodeset_with_int64_values.xml +31 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-opcua-address-space",
3
- "version": "2.70.3",
3
+ "version": "2.72.1",
4
4
  "description": "pure nodejs OPCUA SDK - module -address-space",
5
5
  "main": "./dist/src/index_current.js",
6
6
  "types": "./dist/source/index.d.ts",
@@ -17,54 +17,54 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@types/lodash": "4.14.182",
20
- "async": "^3.2.3",
20
+ "async": "^3.2.4",
21
21
  "chalk": "4.1.2",
22
22
  "dequeue": "^1.0.5",
23
23
  "lodash": "4.17.21",
24
- "node-opcua-address-space-base": "2.70.3",
24
+ "node-opcua-address-space-base": "2.72.1",
25
25
  "node-opcua-assert": "2.66.0",
26
- "node-opcua-basic-types": "2.70.0",
27
- "node-opcua-client-dynamic-extension-object": "2.70.3",
26
+ "node-opcua-basic-types": "2.72.1",
27
+ "node-opcua-client-dynamic-extension-object": "2.72.1",
28
28
  "node-opcua-constants": "2.70.0",
29
- "node-opcua-data-access": "2.70.3",
30
- "node-opcua-data-model": "2.70.0",
31
- "node-opcua-data-value": "2.70.0",
32
- "node-opcua-date-time": "2.69.0",
33
- "node-opcua-debug": "2.69.0",
34
- "node-opcua-enum": "2.69.0",
35
- "node-opcua-factory": "2.70.0",
36
- "node-opcua-nodeid": "2.70.0",
37
- "node-opcua-nodeset-ua": "2.70.3",
38
- "node-opcua-numeric-range": "2.70.0",
39
- "node-opcua-object-registry": "2.69.0",
40
- "node-opcua-pseudo-session": "2.70.3",
41
- "node-opcua-schemas": "2.70.3",
42
- "node-opcua-service-browse": "2.70.3",
43
- "node-opcua-service-call": "2.70.3",
44
- "node-opcua-service-filter": "2.70.3",
45
- "node-opcua-service-history": "2.70.3",
46
- "node-opcua-service-translate-browse-path": "2.70.3",
47
- "node-opcua-service-write": "2.70.3",
48
- "node-opcua-status-code": "2.70.0",
49
- "node-opcua-types": "2.70.3",
50
- "node-opcua-utils": "2.69.0",
51
- "node-opcua-variant": "2.70.0",
52
- "node-opcua-xml2json": "2.70.3",
29
+ "node-opcua-data-access": "2.72.1",
30
+ "node-opcua-data-model": "2.72.1",
31
+ "node-opcua-data-value": "2.72.1",
32
+ "node-opcua-date-time": "2.71.0",
33
+ "node-opcua-debug": "2.71.0",
34
+ "node-opcua-enum": "2.71.0",
35
+ "node-opcua-factory": "2.72.1",
36
+ "node-opcua-nodeid": "2.71.0",
37
+ "node-opcua-nodeset-ua": "2.72.1",
38
+ "node-opcua-numeric-range": "2.72.1",
39
+ "node-opcua-object-registry": "2.71.0",
40
+ "node-opcua-pseudo-session": "2.72.1",
41
+ "node-opcua-schemas": "2.72.1",
42
+ "node-opcua-service-browse": "2.72.1",
43
+ "node-opcua-service-call": "2.72.1",
44
+ "node-opcua-service-filter": "2.72.1",
45
+ "node-opcua-service-history": "2.72.1",
46
+ "node-opcua-service-translate-browse-path": "2.72.1",
47
+ "node-opcua-service-write": "2.72.1",
48
+ "node-opcua-status-code": "2.71.0",
49
+ "node-opcua-types": "2.72.1",
50
+ "node-opcua-utils": "2.71.0",
51
+ "node-opcua-variant": "2.72.1",
52
+ "node-opcua-xml2json": "2.71.0",
53
53
  "semver": "^7.3.7",
54
54
  "set-prototype-of": "^1.0.0",
55
55
  "thenify": "^3.3.1",
56
56
  "xml-writer": "^1.7.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@types/semver": "7.3.9",
59
+ "@types/semver": "7.3.10",
60
60
  "humanize": "0.0.9",
61
- "node-opcua-benchmarker": "2.69.0",
62
- "node-opcua-binary-stream": "2.69.0",
63
- "node-opcua-extension-object": "2.70.0",
64
- "node-opcua-leak-detector": "2.69.0",
65
- "node-opcua-nodesets": "2.70.3",
66
- "node-opcua-packet-analyzer": "2.70.0",
67
- "node-opcua-test-fixtures": "2.69.0",
61
+ "node-opcua-benchmarker": "2.71.0",
62
+ "node-opcua-binary-stream": "2.71.0",
63
+ "node-opcua-extension-object": "2.72.1",
64
+ "node-opcua-leak-detector": "2.71.0",
65
+ "node-opcua-nodesets": "2.71.0",
66
+ "node-opcua-packet-analyzer": "2.72.1",
67
+ "node-opcua-test-fixtures": "2.71.0",
68
68
  "should": "^13.2.3",
69
69
  "sinon": "^14.0.0",
70
70
  "source-map-support": "^0.5.21"
@@ -84,5 +84,5 @@
84
84
  "internet of things"
85
85
  ],
86
86
  "homepage": "http://node-opcua.github.io/",
87
- "gitHead": "08b5465af631fd010bc48843c951b2e556270de4"
87
+ "gitHead": "ba98dd91a9eada9815268c66c98ca5391bc884e7"
88
88
  }
@@ -17,7 +17,7 @@ import {
17
17
  UAVariableType
18
18
  } from "node-opcua-address-space-base";
19
19
  import { assert, renderError } from "node-opcua-assert";
20
- import { isValidGuid, StatusCodes } from "node-opcua-basic-types";
20
+ import { coerceInt64, coerceUInt64, Int64, isValidGuid, StatusCodes, UInt64 } from "node-opcua-basic-types";
21
21
  import { EUInformation } from "node-opcua-data-access";
22
22
  import {
23
23
  AccessLevelFlag,
@@ -55,6 +55,7 @@ import { NamespacePrivate } from "../../src/namespace_private";
55
55
  import { promoteObjectsAndVariables } from "./namespace_post_step";
56
56
  import { ensureDatatypeExtracted } from "./ensure_datatype_extracted";
57
57
  import { decodeXmlExtensionObject } from "./decode_xml_extension_object";
58
+ import { makeSemverCompatible } from "./make_semver_compatible";
58
59
 
59
60
  const doDebug = checkDebugFlag(__filename);
60
61
  const debugLog = make_debugLog(__filename);
@@ -248,20 +249,6 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
248
249
  return namespace;
249
250
  }
250
251
 
251
- /**
252
- * take a OPCUA version string and make it compliant with the semver specification
253
- * @param version
254
- * @returns
255
- */
256
- function makeSemverCompatible(version?: string): string {
257
- version = version || "0.0.0";
258
- const version_array = version.split(".").map((a) => parseInt(a, 10));
259
-
260
- if (version_array.length === 2) {
261
- version_array.push(0);
262
- }
263
- return version_array.map((a) => a.toString()).join(".");
264
- }
265
252
  function _add_namespace(model: Model) {
266
253
  if (model.requiredModels.length > 0) {
267
254
  // check that required models exist already in the address space
@@ -276,8 +263,18 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
276
263
  );
277
264
  throw new Error("LoadNodeSet : Cannot find namespace for " + requiredModel.modelUri);
278
265
  }
279
-
280
- if (semver.lt(makeSemverCompatible(existingNamespace.version), makeSemverCompatible(requiredModel.version))) {
266
+ /**
267
+ * from https://reference.opcfoundation.org/Core/docs/Part6/F.2/
268
+ * The version of the model defined in the UANodeSet.
269
+ * This is a human readable string and not intended for programmatic comparisons.
270
+ *
271
+ */
272
+ const isLowerVersion = (existingVersion: string, requiredVersion: string): boolean => {
273
+ const existingSemver = makeSemverCompatible(existingVersion);
274
+ const requiredSemver = makeSemverCompatible(requiredVersion);
275
+ return semver.lt(existingSemver, requiredSemver);
276
+ };
277
+ if (isLowerVersion(existingNamespace.version, requiredModel.version)) {
281
278
  errorLog(
282
279
  "Expecting ",
283
280
  requiredModel.modelUri,
@@ -969,6 +966,7 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
969
966
  return {
970
967
  finish(this: any) {
971
968
  this.parent.parent.obj.value = {
969
+ arrayType: VariantArrayType.Scalar,
972
970
  dataType: (DataType as any)[type],
973
971
  value: p(this.text)
974
972
  };
@@ -1027,6 +1025,9 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1027
1025
  };
1028
1026
  }
1029
1027
 
1028
+ const parseUInt64 = (str: string): UInt64 => coerceUInt64(str);
1029
+ const parseInt64 = (str: string): Int64 => coerceInt64(str);
1030
+
1030
1031
  const state_Variant = {
1031
1032
  init: () => {
1032
1033
  /* empty */
@@ -1110,6 +1111,9 @@ export function makeNodeSetParserEngine(addressSpace: IAddressSpace): NodeSet2Pa
1110
1111
  UInt32: parser2("UInt32", parseInt),
1111
1112
  UInt8: parser2("UInt8", parseInt),
1112
1113
 
1114
+ UInt64: parser2("UInt64", parseUInt64),
1115
+ Int64: parser2("Int64", parseInt64),
1116
+
1113
1117
  ByteString: {
1114
1118
  init(this: any) {
1115
1119
  this.value = null;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * take a OPCUA version string and make it compliant with the semver specification
3
+ * @param version
4
+ * @returns
5
+ */
6
+ export function makeSemverCompatible(version?: string): string {
7
+ version = version || "0.0.0";
8
+
9
+ const matches = version.match(/[0-9]+(\.[0-9]+(\.[0-9]+)?)?/);
10
+ if (!matches) {
11
+ return "0.0.0";
12
+ }
13
+ version = matches[0];
14
+ const version_array = version.split(".").map((a) => parseInt(a, 10));
15
+
16
+ if (version_array.length === 1) {
17
+ version_array.push(0);
18
+ }
19
+ if (version_array.length === 2) {
20
+ version_array.push(0);
21
+ }
22
+ return version_array.map((a) => a.toString()).join(".");
23
+ }
@@ -1,4 +1,4 @@
1
- import { Byte, Int16, Int32, Int64, SByte, UAString, UInt16, UInt32 } from "node-opcua-basic-types";
1
+ import { Byte, coerceInt64, coerceUInt64, Int16, Int32, Int64, SByte, UAString, UInt16, UInt32, UInt64 } from "node-opcua-basic-types";
2
2
  import { LocalizedTextLike, LocalizedTextOptions } from "node-opcua-data-model";
3
3
  import { make_debugLog, make_warningLog } from "node-opcua-debug";
4
4
  import { coerceNodeId, NodeId, NodeIdType, resolveNodeId } from "node-opcua-nodeid";
@@ -82,7 +82,7 @@ const localizedTextReader: ReaderStateParserLike = {
82
82
  };
83
83
 
84
84
  function clamp(value: number, minValue: number, maxValue: number) {
85
- if (value < minValue) {
85
+ if (value< minValue) {
86
86
  warningLog(`invalid value range : ${value} < ${minValue} but should be [${minValue} , ${maxValue}]`);
87
87
  return minValue;
88
88
  }
@@ -95,6 +95,7 @@ function clamp(value: number, minValue: number, maxValue: number) {
95
95
 
96
96
  interface Parser<T> {
97
97
  value: T | null;
98
+ parent: any;
98
99
  text: string;
99
100
  }
100
101
  const partials: { [key: string]: ReaderStateParserLike } = {
@@ -105,6 +106,15 @@ const partials: { [key: string]: ReaderStateParserLike } = {
105
106
  this.value = this.text;
106
107
  }
107
108
  },
109
+ Guid: {
110
+ parser: {
111
+ String: {
112
+ finish(this: Parser<string>) {
113
+ this.parent.value = this.text;
114
+ }
115
+ }
116
+ }
117
+ },
108
118
 
109
119
  Boolean: {
110
120
  finish(this: Parser<boolean>) {
@@ -161,8 +171,8 @@ const partials: { [key: string]: ReaderStateParserLike } = {
161
171
  }
162
172
  },
163
173
  Int64: {
164
- finish(this: Parser<Int32>) {
165
- this.value = parseInt(this.text, 10);
174
+ finish(this: Parser<Int64>) {
175
+ this.value = coerceInt64(parseInt(this.text, 10));
166
176
  }
167
177
  },
168
178
 
@@ -185,8 +195,8 @@ const partials: { [key: string]: ReaderStateParserLike } = {
185
195
  },
186
196
 
187
197
  UInt64: {
188
- finish(this: Parser<UInt32>) {
189
- this.value = parseInt(this.text, 10);
198
+ finish(this: Parser<UInt64>) {
199
+ this.value = coerceUInt64(parseInt(this.text, 10));
190
200
  }
191
201
  },
192
202
 
@@ -6,7 +6,7 @@ import { assert } from "node-opcua-assert";
6
6
  import { LocalizedText, LocalizedTextLike } from "node-opcua-data-model";
7
7
  import { NodeId } from "node-opcua-nodeid";
8
8
  import { CallbackT, StatusCode, StatusCodes } from "node-opcua-status-code";
9
- import { DataType, VariantLike } from "node-opcua-variant";
9
+ import { DataType, VariantLike, VariantOptions } from "node-opcua-variant";
10
10
  import { INamespace, RaiseEventData, ISessionContext, UAEventType, UAMethod } from "node-opcua-address-space-base";
11
11
  import { CallMethodResultOptions } from "node-opcua-service-call";
12
12
 
@@ -16,6 +16,7 @@ import { _install_TwoStateVariable_machinery } from "../state_machine/ua_two_sta
16
16
  import { _setAckedState } from "./condition";
17
17
  import { ConditionSnapshot } from "./condition_snapshot";
18
18
  import { UAConditionHelper, UAConditionImpl, UAConditionEx } from "./ua_condition_impl";
19
+ import { InstantiateAlarmConditionOptions } from "./ua_alarm_condition_impl";
19
20
 
20
21
  export interface UAAcknowledgeableConditionHelper extends UAConditionHelper {
21
22
  ///
@@ -53,8 +54,8 @@ export class UAAcknowledgeableConditionImpl extends UAConditionImpl implements U
53
54
  public static instantiate(
54
55
  namespace: INamespace,
55
56
  conditionTypeId: UAEventType | NodeId | string,
56
- options: any,
57
- data: any
57
+ options: InstantiateAlarmConditionOptions,
58
+ data?: Record<string, VariantOptions>
58
59
  ): UAAcknowledgeableConditionImpl {
59
60
  const conditionNode = UAConditionImpl.instantiate(
60
61
  namespace,
@@ -107,7 +108,9 @@ export class UAAcknowledgeableConditionImpl extends UAConditionImpl implements U
107
108
  }
108
109
 
109
110
  public static install_method_handle_on_type(addressSpace: AddressSpacePrivate): void {
110
- const acknowledgeableConditionType = addressSpace.findEventType("AcknowledgeableConditionType") as unknown as UAAcknowledgeableCondition_Base;
111
+ const acknowledgeableConditionType = addressSpace.findEventType(
112
+ "AcknowledgeableConditionType"
113
+ ) as unknown as UAAcknowledgeableCondition_Base;
111
114
  assert(acknowledgeableConditionType !== null);
112
115
  acknowledgeableConditionType.acknowledge.bindMethod(_acknowledge_method);
113
116
  acknowledgeableConditionType.confirm?.bindMethod(_confirm_method);
@@ -297,7 +300,11 @@ export class UAAcknowledgeableConditionImpl extends UAConditionImpl implements U
297
300
  }
298
301
  }
299
302
 
300
- function _acknowledge_method(inputArguments: VariantLike[], context: ISessionContext, callback: CallbackT<CallMethodResultOptions>) {
303
+ function _acknowledge_method(
304
+ inputArguments: VariantLike[],
305
+ context: ISessionContext,
306
+ callback: CallbackT<CallMethodResultOptions>
307
+ ) {
301
308
  UAConditionImpl.with_condition_method(
302
309
  inputArguments,
303
310
  context,
@@ -322,7 +329,7 @@ function _acknowledge_method(inputArguments: VariantLike[], context: ISessionCon
322
329
  *
323
330
  * @private
324
331
  */
325
- function _confirm_method(inputArguments: VariantLike[], context: ISessionContext, callback: CallbackT<CallMethodResultOptions>) {
332
+ function _confirm_method(inputArguments: VariantLike[], context: ISessionContext, callback: CallbackT<CallMethodResultOptions>) {
326
333
  UAConditionImpl.with_condition_method(
327
334
  inputArguments,
328
335
  context,
@@ -8,10 +8,10 @@ import { NodeClass } from "node-opcua-data-model";
8
8
  import { DataValue } from "node-opcua-data-value";
9
9
  import { NodeId, sameNodeId } from "node-opcua-nodeid";
10
10
  import { StatusCodes } from "node-opcua-status-code";
11
- import { DataType } from "node-opcua-variant";
11
+ import { DataType, VariantOptions } from "node-opcua-variant";
12
12
  import { UAAlarmCondition_Base } from "node-opcua-nodeset-ua";
13
+ import { BaseNode, INamespace, UAEventType, UAVariable } from "node-opcua-address-space-base";
13
14
 
14
- import { BaseNode, INamespace, UAEventType, UAVariable } from "../../source";
15
15
  import { _install_TwoStateVariable_machinery } from "../state_machine/ua_two_state_variable";
16
16
  import { UAShelvedStateMachineEx, _clear_timer_if_any } from "../state_machine/ua_shelving_state_machine_ex";
17
17
  import { UATwoStateVariableEx } from "../../source/ua_two_state_variable_ex";
@@ -23,6 +23,7 @@ import {
23
23
  UAAcknowledgeableConditionHelper,
24
24
  UAAcknowledgeableConditionImpl
25
25
  } from "./ua_acknowledgeable_condition_impl";
26
+ import { InstantiateConditionOptions } from "./ua_condition_impl";
26
27
 
27
28
  function _update_suppressedOrShelved(alarmNode: UAAlarmConditionImpl) {
28
29
  alarmNode.suppressedOrShelved.setValueFromSource({
@@ -32,7 +33,7 @@ function _update_suppressedOrShelved(alarmNode: UAAlarmConditionImpl) {
32
33
  }
33
34
  export interface UAAlarmConditionHelper extends UAAcknowledgeableConditionHelper {
34
35
  activateAlarm(): void;
35
- deactivateAlarm(): void;
36
+ deactivateAlarm(retain?: boolean): void;
36
37
  isSuppressedOrShelved(): boolean;
37
38
  getSuppressedOrShelved(): boolean;
38
39
  setMaxTimeShelved(duration: number): void;
@@ -65,14 +66,18 @@ export declare interface UAAlarmConditionImpl extends UAAlarmConditionEx, UAAckn
65
66
  on(eventName: string, eventHandler: any): this;
66
67
  }
67
68
 
69
+ export interface InstantiateAlarmConditionOptions extends InstantiateConditionOptions {
70
+ maxTimeShelved?: number;
71
+ inputNode: BaseNode | NodeId;
72
+ }
68
73
  export class UAAlarmConditionImpl extends UAAcknowledgeableConditionImpl implements UAAlarmConditionEx {
69
74
  public static MaxDuration = Math.pow(2, 31);
70
75
 
71
76
  public static instantiate(
72
77
  namespace: INamespace,
73
78
  alarmConditionTypeId: UAEventType | string | NodeId,
74
- options: any,
75
- data: any
79
+ options: InstantiateAlarmConditionOptions,
80
+ data?: Record<string, VariantOptions>
76
81
  ): UAAlarmConditionImpl {
77
82
  const addressSpace = namespace.addressSpace;
78
83
  // xx assert(Object.prototype.hasOwnProperty.call(options,"conditionOf")); // must provide a conditionOf
@@ -93,7 +98,7 @@ export class UAAlarmConditionImpl extends UAAcknowledgeableConditionImpl impleme
93
98
  options.optionals = options.optionals || [];
94
99
  if (Object.prototype.hasOwnProperty.call(options, "maxTimeShelved")) {
95
100
  options.optionals.push("MaxTimeShelved");
96
- assert(isFinite(options.maxTimeShelved));
101
+ assert(isFinite(options.maxTimeShelved!));
97
102
  }
98
103
 
99
104
  assert(alarmConditionTypeBase === alarmConditionType || alarmConditionType.isSupertypeOf(alarmConditionTypeBase));
@@ -229,16 +234,16 @@ export class UAAlarmConditionImpl extends UAAcknowledgeableConditionImpl impleme
229
234
  branch.setAckedState(false);
230
235
  }
231
236
 
232
- public deactivateAlarm(): void {
237
+ public deactivateAlarm(retain?: boolean): void {
233
238
  const branch = this.currentBranch();
234
- branch.setRetain(true);
239
+ branch.setRetain(retain === undefined ? true : retain);
235
240
  branch.setActiveState(false);
236
241
  }
237
242
 
238
243
  /**
239
244
  * @deprecated use deactivateAlarm instead (with no s after de-activate)
240
245
  */
241
- public desactivateAlarm(): void {
246
+ protected desactivateAlarm(): void {
242
247
  this.deactivateAlarm();
243
248
  }
244
249
 
@@ -325,7 +330,7 @@ export class UAAlarmConditionImpl extends UAAcknowledgeableConditionImpl impleme
325
330
  this._onInputDataValueChange(dataValue);
326
331
  }
327
332
 
328
- public _onInputDataValueChange(newValue: DataValue): void {
333
+ protected _onInputDataValueChange(newValue: DataValue): void {
329
334
  // xx console.log("class=",this.constructor.name,this.browseName.toString());
330
335
  // xx throw new Error("_onInputDataValueChange must be overridden");
331
336
  }
@@ -1,12 +1,20 @@
1
1
  /**
2
2
  * @module node-opcua-address-space.AlarmsAndConditions
3
3
  */
4
- import { DateTime } from "node-opcua-basic-types";
5
- import { DataType } from "node-opcua-variant";
6
- import { UACertificateExpirationAlarm, UACertificateExpirationAlarm_Base } from "node-opcua-nodeset-ua";
7
- import { INamespace } from "node-opcua-address-space-base";
4
+ import { Certificate, exploreCertificate, makeSHA1Thumbprint } from "node-opcua-crypto";
5
+ import { DateTime, minOPCUADate } from "node-opcua-basic-types";
6
+ import { make_warningLog } from "node-opcua-debug";
7
+ import { DataType, VariantOptions } from "node-opcua-variant";
8
+ import { UACertificateExpirationAlarm_Base } from "node-opcua-nodeset-ua";
9
+ import { INamespace, UAObject } from "node-opcua-address-space-base";
10
+ import { ObjectTypeIds } from "node-opcua-constants";
11
+ import { AccessRestrictionsFlag, makeAccessLevelExFlag } from "node-opcua-data-model";
12
+ import { registerNodePromoter } from "../../source/loader/register_node_promoter";
13
+ import { InstantiateOffNormalAlarmOptions, UAOffNormalAlarmImpl } from "./ua_off_normal_alarm_impl";
8
14
  import { UASystemOffNormalAlarmImpl } from "./ua_system_off_normal_alarm_impl";
9
15
 
16
+ const warningLog = make_warningLog("AlarmsAndConditions");
17
+
10
18
  export interface UACertificateExpirationAlarmEx
11
19
  extends Omit<
12
20
  UACertificateExpirationAlarm_Base,
@@ -20,7 +28,15 @@ export interface UACertificateExpirationAlarmEx
20
28
  | "shelvingState"
21
29
  | "silenceState"
22
30
  | "suppressedState"
23
- > {}
31
+ > {
32
+ getExpirationDate(): DateTime;
33
+ setExpirationDate(value: Date): void;
34
+ getExpirationLimit(): number;
35
+ setExpirationLimit(value: number): void;
36
+ setCertificate(certificate: Certificate | null): void;
37
+ getCertificate(): Certificate | null;
38
+ }
39
+
24
40
  export declare interface UACertificateExpirationAlarmImpl extends UACertificateExpirationAlarmEx, UASystemOffNormalAlarmImpl {}
25
41
  /**
26
42
  * This UACertificateExpirationAlarm (SystemOffNormalAlarmType) is raised by the Server when the Server’s
@@ -28,23 +44,123 @@ export declare interface UACertificateExpirationAlarmImpl extends UACertificateE
28
44
  * of expiration. This alarm automatically returns to normal when the certificate is updated.
29
45
  */
30
46
  export class UACertificateExpirationAlarmImpl extends UASystemOffNormalAlarmImpl implements UACertificateExpirationAlarmEx {
31
- public static instantiate(namespace: INamespace, options: any, data: any): UACertificateExpirationAlarmImpl {
32
- return UASystemOffNormalAlarmImpl.instantiate(
47
+ public static instantiate(
48
+ namespace: INamespace,
49
+ alarmType: "CertificateExpirationAlarmType",
50
+ options: InstantiateOffNormalAlarmOptions,
51
+ data?: Record<string, VariantOptions>
52
+ ): UACertificateExpirationAlarmImpl {
53
+ const alarm = UASystemOffNormalAlarmImpl.instantiate(
33
54
  namespace,
34
- "CertificateExpirationAlarmType",
55
+ alarmType || "CertificateExpirationAlarmType",
35
56
  options,
36
57
  data
37
58
  ) as UACertificateExpirationAlarmImpl;
59
+ Object.setPrototypeOf(alarm, UACertificateExpirationAlarmImpl.prototype);
60
+ alarm._post_initialize();
61
+ return alarm;
38
62
  }
39
63
 
40
64
  public getExpirationDate(): DateTime {
41
65
  return this.expirationDate.readValue().value.value;
42
66
  }
43
67
 
44
- public setExpirationDate(value: Date): void {
45
- return this.expirationDate.setValueFromSource({
68
+ public setExpirationDate(expirationDate: Date): void {
69
+ this.expirationDate.setValueFromSource({
46
70
  dataType: DataType.DateTime,
71
+ value: expirationDate
72
+ });
73
+ const now = new Date();
74
+ const expirationLimit = this.getExpirationLimit();
75
+
76
+ const checkDate = new Date(now.getTime() + +expirationLimit);
77
+
78
+ const thumbprint = makeSHA1Thumbprint(this.getCertificate() || Buffer.alloc(0)).toString("hex");
79
+
80
+ if (expirationDate.getTime() <= checkDate.getTime()) {
81
+ if (!this.currentBranch().getActiveState()) {
82
+ warningLog(
83
+ `CertificateExpirationAlarm: becomes active, certificate ${thumbprint} endDate ${expirationDate.toUTCString()} checkDate=${checkDate.toUTCString()} expirationLimit=${expirationLimit}`
84
+ );
85
+ }
86
+ // also raise the event
87
+ if (expirationDate.getTime() <= now.getTime()) {
88
+ this.updateAlarmState(
89
+ true,
90
+ `certificate ${thumbprint} has expired : end date is ${expirationDate.toUTCString()} checkDate=${checkDate.toUTCString()} expirationLimit=${expirationLimit}`
91
+ );
92
+ } else {
93
+ this.updateAlarmState(
94
+ true,
95
+ `certificate ${thumbprint} is about to expire : end date is ${expirationDate.toString()} checkDate=${checkDate.toUTCString()} expirationLimit=${expirationLimit}`
96
+ );
97
+ }
98
+ } else {
99
+ if (this.currentBranch().getActiveState()) {
100
+ warningLog(
101
+ `CertificateExpirationAlarm: becomes desactivated, certificate ${thumbprint} endDate ${expirationDate.toUTCString()} expirationLimit=${expirationLimit}`
102
+ );
103
+ }
104
+ // also raise the event
105
+ this.updateAlarmState(
106
+ false,
107
+ `certificate ${thumbprint} end date is OK: ${expirationDate.toString()} , expirationLimit=${expirationLimit}`
108
+ );
109
+ }
110
+ }
111
+
112
+ public getExpirationLimit(): number {
113
+ return (this.expirationLimit?.readValue().value.value as number) || 0;
114
+ }
115
+
116
+ public setExpirationLimit(value: number): void {
117
+ this.expirationLimit?.setValueFromSource({
118
+ dataType: DataType.Double,
47
119
  value
48
120
  });
49
121
  }
122
+
123
+ public getCertificate(): Certificate | null {
124
+ return (this.certificate.readValue().value.value as Certificate | null) || null;
125
+ }
126
+
127
+ public setCertificate(certificate: Certificate | null): void {
128
+ if (certificate && certificate.length > 0) {
129
+ const info = exploreCertificate(certificate);
130
+ if (info.tbsCertificate.validity.notAfter instanceof Date) {
131
+ this.setExpirationDate(info.tbsCertificate.validity.notAfter);
132
+ } else {
133
+ this.setExpirationDate(minOPCUADate);
134
+ }
135
+ } else {
136
+ this.setExpirationDate(minOPCUADate);
137
+ }
138
+ this.certificate.setValueFromSource({
139
+ dataType: DataType.ByteString,
140
+ value: certificate
141
+ });
142
+ }
143
+
144
+ _post_initialize() {
145
+ if (this.expirationLimit) {
146
+ this.expirationLimit.accessLevel = makeAccessLevelExFlag("CurrentRead | CurrentWrite");
147
+ this.expirationLimit.userAccessLevel = makeAccessLevelExFlag("CurrentRead | CurrentWrite");
148
+ this.expirationLimit.on("value_changed", (dataValue) => {
149
+ // make sure we re-evaluate the certificfate
150
+ const certificate = this.getCertificate();
151
+ this.setCertificate(certificate);
152
+ });
153
+ }
154
+ }
155
+ }
156
+
157
+ export function promoteToCertificateExpirationAlarm(node: UAObject): UACertificateExpirationAlarmImpl {
158
+ if (node instanceof UACertificateExpirationAlarmImpl) {
159
+ return node; // already promoted
160
+ }
161
+ Object.setPrototypeOf(node, UACertificateExpirationAlarmImpl.prototype);
162
+ const _node = node as unknown as UACertificateExpirationAlarmImpl;
163
+ _node._post_initialize();
164
+ return _node;
50
165
  }
166
+ registerNodePromoter(ObjectTypeIds.CertificateExpirationAlarmType, promoteToCertificateExpirationAlarm);