node-opcua-address-space-for-conformance-testing 2.180.0 → 2.181.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/dist/address_space_for_conformance_testing.d.ts +12 -2
- package/dist/address_space_for_conformance_testing.js +32 -27
- package/dist/address_space_for_conformance_testing.js.map +1 -1
- package/dist/conformance_testing/alarm_input_nodes.d.ts +2 -0
- package/dist/conformance_testing/alarm_input_nodes.js +102 -0
- package/dist/conformance_testing/alarm_input_nodes.js.map +1 -0
- package/dist/conformance_testing/ctt_folder.d.ts +2 -0
- package/dist/conformance_testing/ctt_folder.js +375 -0
- package/dist/conformance_testing/ctt_folder.js.map +1 -0
- package/dist/conformance_testing/ctt_tree.d.ts +35 -0
- package/dist/conformance_testing/ctt_tree.js +85 -0
- package/dist/conformance_testing/ctt_tree.js.map +1 -0
- package/dist/conformance_testing/custom_extension_object.d.ts +63 -0
- package/dist/conformance_testing/custom_extension_object.js +48 -0
- package/dist/conformance_testing/custom_extension_object.js.map +1 -0
- package/dist/conformance_testing/discrete_variables.js +6 -4
- package/dist/conformance_testing/discrete_variables.js.map +1 -1
- package/dist/conformance_testing/helpers.d.ts +2 -1
- package/dist/conformance_testing/helpers.js +23 -5
- package/dist/conformance_testing/helpers.js.map +1 -1
- package/dist/conformance_testing/mass_variables.d.ts +2 -1
- package/dist/conformance_testing/mass_variables.js +7 -6
- package/dist/conformance_testing/mass_variables.js.map +1 -1
- package/dist/conformance_testing/path_and_large_arrays.d.ts +2 -1
- package/dist/conformance_testing/path_and_large_arrays.js +6 -5
- package/dist/conformance_testing/path_and_large_arrays.js.map +1 -1
- package/dist/conformance_testing/simulation_variables.d.ts +2 -1
- package/dist/conformance_testing/simulation_variables.js +9 -9
- package/dist/conformance_testing/simulation_variables.js.map +1 -1
- package/dist/conformance_testing/static_variables.d.ts +2 -1
- package/dist/conformance_testing/static_variables.js +19 -12
- package/dist/conformance_testing/static_variables.js.map +1 -1
- package/dist/conformance_testing/type_defaults.d.ts +15 -1
- package/dist/conformance_testing/type_defaults.js +30 -1
- package/dist/conformance_testing/type_defaults.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +19 -14
- package/src/address_space_for_conformance_testing.ts +37 -18
- package/src/conformance_testing/alarm_input_nodes.ts +151 -0
- package/src/conformance_testing/ctt_folder.ts +440 -0
- package/src/conformance_testing/ctt_tree.ts +105 -0
- package/src/conformance_testing/custom_extension_object.ts +105 -0
- package/src/conformance_testing/discrete_variables.ts +6 -4
- package/src/conformance_testing/helpers.ts +26 -6
- package/src/conformance_testing/mass_variables.ts +5 -4
- package/src/conformance_testing/path_and_large_arrays.ts +5 -4
- package/src/conformance_testing/simulation_variables.ts +6 -6
- package/src/conformance_testing/static_variables.ts +31 -9
- package/src/conformance_testing/type_defaults.ts +31 -2
- package/src/index.ts +1 -1
|
@@ -4,7 +4,17 @@
|
|
|
4
4
|
* Builds the conformance-testing address space by delegating to focused sub-modules.
|
|
5
5
|
*/
|
|
6
6
|
import type { AddressSpace } from "node-opcua-address-space";
|
|
7
|
-
|
|
7
|
+
import { type CustomExtensionObjectOptions } from "./conformance_testing/custom_extension_object.js";
|
|
8
|
+
export type { CustomExtensionObjectOptions } from "./conformance_testing/custom_extension_object.js";
|
|
9
|
+
export interface BuildAddressSpaceForConformanceTestingOptions {
|
|
8
10
|
mass_variable?: boolean;
|
|
9
11
|
mass_variables?: boolean;
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The concrete structure the ExtensionObject variables hold. Namespace zero
|
|
14
|
+
* has none worth exercising, so a caller that has loaded a companion nodeset
|
|
15
|
+
* passes one in; without it those variables keep a null ExtensionObject.
|
|
16
|
+
* See ./conformance_testing/custom_extension_object.ts.
|
|
17
|
+
*/
|
|
18
|
+
extensionObject?: CustomExtensionObjectOptions;
|
|
19
|
+
}
|
|
20
|
+
export declare function build_address_space_for_conformance_testing(addressSpace: AddressSpace, options?: BuildAddressSpaceForConformanceTestingOptions): Promise<void>;
|
|
@@ -2,28 +2,31 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.build_address_space_for_conformance_testing = build_address_space_for_conformance_testing;
|
|
4
4
|
const testHelpers_1 = require("node-opcua-address-space/testHelpers");
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
5
|
+
const access_right_variables_js_1 = require("./conformance_testing/access_right_variables.js");
|
|
6
|
+
const analog_data_items_js_1 = require("./conformance_testing/analog_data_items.js");
|
|
7
|
+
const ctt_folder_js_1 = require("./conformance_testing/ctt_folder.js");
|
|
8
|
+
const custom_extension_object_js_1 = require("./conformance_testing/custom_extension_object.js");
|
|
9
|
+
const discrete_variables_js_1 = require("./conformance_testing/discrete_variables.js");
|
|
10
|
+
const enumeration_variable_js_1 = require("./conformance_testing/enumeration_variable.js");
|
|
11
|
+
const mass_variables_js_1 = require("./conformance_testing/mass_variables.js");
|
|
12
|
+
const node_with_references_js_1 = require("./conformance_testing/node_with_references.js");
|
|
13
|
+
const object_with_methods_js_1 = require("./conformance_testing/object_with_methods.js");
|
|
14
|
+
const path_and_large_arrays_js_1 = require("./conformance_testing/path_and_large_arrays.js");
|
|
15
|
+
const sample_view_js_1 = require("./conformance_testing/sample_view.js");
|
|
16
|
+
const simulation_variables_js_1 = require("./conformance_testing/simulation_variables.js");
|
|
17
|
+
const static_variables_js_1 = require("./conformance_testing/static_variables.js");
|
|
18
|
+
const trigger_nodes_js_1 = require("./conformance_testing/trigger_nodes.js");
|
|
17
19
|
async function build_address_space_for_conformance_testing(addressSpace, options) {
|
|
18
20
|
const namespace = addressSpace.registerNamespace("urn://node-opcua-simulator");
|
|
19
21
|
options = options || {};
|
|
20
22
|
options.mass_variable = options.mass_variable || false;
|
|
23
|
+
const custom = (0, custom_extension_object_js_1.resolveCustomExtensionObject)(addressSpace, options.extensionObject);
|
|
21
24
|
const objectsFolder = addressSpace.findNode("ObjectsFolder");
|
|
22
25
|
const simulationFolder = namespace.addFolder(objectsFolder, {
|
|
23
26
|
browseName: "Simulation",
|
|
24
27
|
nodeId: "s=SimulationFolder"
|
|
25
28
|
});
|
|
26
|
-
(0,
|
|
29
|
+
(0, access_right_variables_js_1.addAccessRightVariables)(namespace, simulationFolder);
|
|
27
30
|
const staticVariablesFolder = namespace.addFolder(simulationFolder, {
|
|
28
31
|
browseName: "Static"
|
|
29
32
|
});
|
|
@@ -31,25 +34,27 @@ async function build_address_space_for_conformance_testing(addressSpace, options
|
|
|
31
34
|
browseName: "All Profiles"
|
|
32
35
|
});
|
|
33
36
|
// Scalars/Array/MultiDim array of all sorts
|
|
34
|
-
await (0,
|
|
37
|
+
await (0, static_variables_js_1.addStaticVariables)(namespace, allProfileFolder, custom);
|
|
35
38
|
if (options.mass_variables) {
|
|
36
|
-
(0,
|
|
39
|
+
(0, mass_variables_js_1.addMassVariables)(namespace, allProfileFolder, custom);
|
|
37
40
|
}
|
|
38
|
-
(0,
|
|
41
|
+
(0, analog_data_items_js_1.addAnalogDataItems)(namespace, allProfileFolder);
|
|
39
42
|
const dynamicVariablesFolder = namespace.addFolder(simulationFolder, {
|
|
40
43
|
browseName: "Dynamic"
|
|
41
44
|
});
|
|
42
|
-
(0,
|
|
43
|
-
(0,
|
|
44
|
-
(0,
|
|
45
|
-
(0,
|
|
46
|
-
(0,
|
|
45
|
+
(0, simulation_variables_js_1.addSimulationVariables)(namespace, dynamicVariablesFolder, custom);
|
|
46
|
+
(0, path_and_large_arrays_js_1.addVeryLargeArrayVariables)(namespace, staticVariablesFolder, custom);
|
|
47
|
+
(0, path_and_large_arrays_js_1.addPath10Deep)(namespace, simulationFolder);
|
|
48
|
+
(0, node_with_references_js_1.addNodeWithReferences)(namespace, simulationFolder);
|
|
49
|
+
(0, object_with_methods_js_1.addObjectWithMethod)(namespace, simulationFolder);
|
|
47
50
|
(0, testHelpers_1.add_eventGeneratorObject)(namespace, simulationFolder);
|
|
48
|
-
(0,
|
|
49
|
-
(0,
|
|
50
|
-
(0,
|
|
51
|
-
(0,
|
|
52
|
-
(0,
|
|
53
|
-
(0,
|
|
51
|
+
(0, sample_view_js_1.addSampleView)(namespace);
|
|
52
|
+
(0, enumeration_variable_js_1.addEnumerationVariable)(namespace, simulationFolder);
|
|
53
|
+
(0, discrete_variables_js_1.addMultiStateValueDiscreteVariables)(namespace, simulationFolder);
|
|
54
|
+
(0, discrete_variables_js_1.addTwoStateDiscreteVariables)(namespace, simulationFolder);
|
|
55
|
+
(0, discrete_variables_js_1.addMultiStateDiscreteVariable)(namespace, simulationFolder);
|
|
56
|
+
(0, trigger_nodes_js_1.addTriggerNodes)(namespace, simulationFolder);
|
|
57
|
+
// nodes named after the CTT settings the folders above do not serve
|
|
58
|
+
(0, ctt_folder_js_1.addCttFolder)(namespace, objectsFolder);
|
|
54
59
|
}
|
|
55
60
|
//# sourceMappingURL=address_space_for_conformance_testing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address_space_for_conformance_testing.js","sourceRoot":"","sources":["../src/address_space_for_conformance_testing.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"address_space_for_conformance_testing.js","sourceRoot":"","sources":["../src/address_space_for_conformance_testing.ts"],"names":[],"mappings":";;AAwCA,kGAgEC;AAlGD,sEAAgF;AAChF,+FAA0F;AAC1F,qFAAgF;AAChF,uEAAmE;AACnE,iGAAmI;AACnI,uFAIqD;AACrD,2FAAuF;AACvF,+EAA2E;AAC3E,2FAAsF;AACtF,yFAAmF;AACnF,6FAA2G;AAC3G,yEAAqE;AACrE,2FAAuF;AACvF,mFAA+E;AAC/E,6EAAyE;AAgBlE,KAAK,UAAU,2CAA2C,CAC7D,YAA0B,EAC1B,OAAuD;IAEvD,MAAM,SAAS,GAAG,YAAY,CAAC,iBAAiB,CAAC,4BAA4B,CAAC,CAAC;IAE/E,OAAO,GAAG,OAAO,IAAI,EAAE,CAAC;IACxB,OAAO,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,KAAK,CAAC;IACvD,MAAM,MAAM,GAAG,IAAA,yDAA4B,EAAC,YAAY,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAEnF,MAAM,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC,eAAe,CAAa,CAAC;IAEzE,MAAM,gBAAgB,GAAG,SAAS,CAAC,SAAS,CAAC,aAAa,EAAE;QACxD,UAAU,EAAE,YAAY;QACxB,MAAM,EAAE,oBAAoB;KAC/B,CAAC,CAAC;IAEH,IAAA,mDAAuB,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAErD,MAAM,qBAAqB,GAAG,SAAS,CAAC,SAAS,CAAC,gBAAgB,EAAE;QAChE,UAAU,EAAE,QAAQ;KACvB,CAAC,CAAC;IAEH,MAAM,gBAAgB,GAAG,SAAS,CAAC,SAAS,CAAC,qBAAqB,EAAE;QAChE,UAAU,EAAE,cAAc;KAC7B,CAAC,CAAC;IAEH,4CAA4C;IAC5C,MAAM,IAAA,wCAAkB,EAAC,SAAS,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAE9D,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QACzB,IAAA,oCAAgB,EAAC,SAAS,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;IACD,IAAA,yCAAkB,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAEhD,MAAM,sBAAsB,GAAG,SAAS,CAAC,SAAS,CAAC,gBAAgB,EAAE;QACjE,UAAU,EAAE,SAAS;KACxB,CAAC,CAAC;IACH,IAAA,gDAAsB,EAAC,SAAS,EAAE,sBAAsB,EAAE,MAAM,CAAC,CAAC;IAElE,IAAA,qDAA0B,EAAC,SAAS,EAAE,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAErE,IAAA,wCAAa,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAE3C,IAAA,+CAAqB,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAEnD,IAAA,4CAAmB,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAEjD,IAAA,sCAAwB,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAEtD,IAAA,8BAAa,EAAC,SAAS,CAAC,CAAC;IAEzB,IAAA,gDAAsB,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAEpD,IAAA,2DAAmC,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAEjE,IAAA,oDAA4B,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAE1D,IAAA,qDAA6B,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAE3D,IAAA,kCAAe,EAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAE7C,oEAAoE;IACpE,IAAA,4BAAY,EAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addAlarmInputNodes = addAlarmInputNodes;
|
|
4
|
+
const node_opcua_variant_1 = require("node-opcua-variant");
|
|
5
|
+
/** where the CTT keeps these settings; outside "Server Test/NodeIds", so the whole path is the key */
|
|
6
|
+
const GROUP = "Server Test/Alarms and Conditions/Supported Condition Types";
|
|
7
|
+
/** the limits every limit-derived alarm here is given, in the units of a 0..100 input */
|
|
8
|
+
const LIMITS = { lowLowLimit: 10, lowLimit: 25, highLimit: 75, highHighLimit: 90 };
|
|
9
|
+
const double = (value) => new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Double, value });
|
|
10
|
+
const boolean = (value) => new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Boolean, value });
|
|
11
|
+
/**
|
|
12
|
+
* The object every alarm is a condition of. It must be an event source of
|
|
13
|
+
* something, or `conditionSource` throws; making it an event source of the
|
|
14
|
+
* Server object is what puts its events on the Server notifier the CTT
|
|
15
|
+
* subscribes to.
|
|
16
|
+
*/
|
|
17
|
+
function addAlarmSource(ctt) {
|
|
18
|
+
const server = ctt.addressSpace.rootFolder.objects.server;
|
|
19
|
+
return ctt.namespace.addObject({
|
|
20
|
+
browseName: "AlarmSource",
|
|
21
|
+
nodeId: ctt.nodeId("Server Test/Alarms and Conditions/AlarmSource"),
|
|
22
|
+
organizedBy: ctt.folder("Server Test/Alarms and Conditions"),
|
|
23
|
+
description: "condition source of the CTT alarm input nodes",
|
|
24
|
+
eventSourceOf: server
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function addAlarmInputNodes(ctt) {
|
|
28
|
+
const namespace = ctt.namespace;
|
|
29
|
+
const conditionSource = addAlarmSource(ctt);
|
|
30
|
+
/** the writable Variable a CTT alarm setting points at; 50 sits inside LIMITS, so alarms start inactive */
|
|
31
|
+
const inputNode = (leaf, kind) => ctt.variable(`${GROUP}/${leaf}`, kind, -1, kind === "Double" ? double(50) : boolean(false), null);
|
|
32
|
+
/** a deviation setpoint, at 0 so the deviation the alarm evaluates is the input value itself */
|
|
33
|
+
const setpointNode = (leaf) => ctt.variable(`${GROUP}/${leaf}`, "Double", -1, double(0), null);
|
|
34
|
+
const alarmOptions = (browseName, input) => ({
|
|
35
|
+
browseName,
|
|
36
|
+
nodeId: ctt.nodeId(`Server Test/Alarms and Conditions/${browseName}`),
|
|
37
|
+
conditionSource,
|
|
38
|
+
inputNode: input
|
|
39
|
+
});
|
|
40
|
+
// ── AlarmConditionType ──────────────────────────────────────────────
|
|
41
|
+
// the base type has no sub-state model: the CTT drives ActiveState itself
|
|
42
|
+
namespace.instantiateAlarmCondition("AlarmConditionType", alarmOptions("AlarmCondition", inputNode("AlarmConditionType Input Nodes", "Double")));
|
|
43
|
+
// ── the limit family ────────────────────────────────────────────────
|
|
44
|
+
namespace.instantiateLimitAlarm("LimitAlarmType", {
|
|
45
|
+
...alarmOptions("LimitAlarm", inputNode("LimitAlarmType Input Nodes", "Double")),
|
|
46
|
+
...LIMITS
|
|
47
|
+
});
|
|
48
|
+
for (const [typeName, leaf] of [
|
|
49
|
+
["ExclusiveLimitAlarmType", "ExclusiveLimitAlarmType Input Nodes"],
|
|
50
|
+
["ExclusiveLevelAlarmType", "ExclusiveLevelAlarmType Input Nodes"],
|
|
51
|
+
["ExclusiveRateOfChangeAlarmType", "ExclusiveRateOfChangeAlarmType Input Nodes"]
|
|
52
|
+
]) {
|
|
53
|
+
namespace.instantiateExclusiveLimitAlarm(typeName, {
|
|
54
|
+
...alarmOptions(typeName.replace(/Type$/, ""), inputNode(leaf, "Double")),
|
|
55
|
+
...LIMITS
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
for (const [typeName, leaf] of [
|
|
59
|
+
["NonExclusiveLimitAlarmType", "NonExclusiveLimitAlarmType Input Nodes"],
|
|
60
|
+
["NonExclusiveLevelAlarmType", "NonExclusiveLevelAlarmType Input Nodes"],
|
|
61
|
+
["NonExclusiveRateOfChangeAlarmType", "NonExclusiveRateOfChangeAlarmType Input Nodes"]
|
|
62
|
+
]) {
|
|
63
|
+
namespace.instantiateNonExclusiveLimitAlarm(typeName, {
|
|
64
|
+
...alarmOptions(typeName.replace(/Type$/, ""), inputNode(leaf, "Double")),
|
|
65
|
+
...LIMITS
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// ── the deviation pairs: the setpoint is a setting of its own ───────
|
|
69
|
+
const exclusiveSetpoint = setpointNode("Exclusive Deviation Setpoint Source");
|
|
70
|
+
namespace.instantiateExclusiveDeviationAlarm({
|
|
71
|
+
...alarmOptions("ExclusiveDeviationAlarm", inputNode("ExclusiveDeviationAlarmType Input Nodes", "Double")),
|
|
72
|
+
...LIMITS,
|
|
73
|
+
setpointNode: exclusiveSetpoint
|
|
74
|
+
});
|
|
75
|
+
const nonExclusiveSetpoint = setpointNode("NonExclusive Deviation Setpoint Source");
|
|
76
|
+
namespace.instantiateNonExclusiveDeviationAlarm({
|
|
77
|
+
...alarmOptions("NonExclusiveDeviationAlarm", inputNode("NonExclusiveDeviationAlarmType Input Nodes", "Double")),
|
|
78
|
+
...LIMITS,
|
|
79
|
+
setpointNode: nonExclusiveSetpoint
|
|
80
|
+
});
|
|
81
|
+
// ── the discrete family ─────────────────────────────────────────────
|
|
82
|
+
namespace.instantiateDiscreteAlarm("DiscreteAlarmType", alarmOptions("DiscreteAlarm", inputNode("DiscreteAlarmType Input Nodes", "Boolean")));
|
|
83
|
+
// OffNormalAlarmType is active while its input differs from NormalState
|
|
84
|
+
const normalState = namespace.addVariable({
|
|
85
|
+
browseName: "OffNormalNormalState",
|
|
86
|
+
nodeId: ctt.nodeId("Server Test/Alarms and Conditions/OffNormalNormalState"),
|
|
87
|
+
componentOf: ctt.folder("Server Test/Alarms and Conditions"),
|
|
88
|
+
description: "the value OffNormalAlarmType considers normal",
|
|
89
|
+
dataType: "Boolean",
|
|
90
|
+
value: boolean(false)
|
|
91
|
+
});
|
|
92
|
+
namespace.instantiateOffNormalAlarm({
|
|
93
|
+
...alarmOptions("OffNormalAlarm", inputNode("OffNormalAlarmType Input Nodes", "Boolean")),
|
|
94
|
+
normalState
|
|
95
|
+
});
|
|
96
|
+
// `instantiateOffNormalAlarm` is hardwired to OffNormalAlarmType and
|
|
97
|
+
// UASystemOffNormalAlarmImpl is not exported, so the derived type is
|
|
98
|
+
// instantiated generically: the node and its mandatory children exist,
|
|
99
|
+
// the NormalState comparison is not wired.
|
|
100
|
+
namespace.instantiateAlarmCondition("SystemOffNormalAlarmType", alarmOptions("SystemOffNormalAlarm", inputNode("SystemOffNormalAlarmType Input Nodes", "Boolean")));
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=alarm_input_nodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alarm_input_nodes.js","sourceRoot":"","sources":["../../src/conformance_testing/alarm_input_nodes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.addCttFolder = addCttFolder;
|
|
7
|
+
/**
|
|
8
|
+
* The `CTT` folder: nodes named after the settings of the OPC Foundation
|
|
9
|
+
* Compliance Test Tool (UACTT) server project.
|
|
10
|
+
*
|
|
11
|
+
* The browse path below Objects/CTT mirrors the setting path below
|
|
12
|
+
* "Server Test/NodeIds", e.g. the setting
|
|
13
|
+
* Server Test/NodeIds/Static/HA Profile/Arrays/Int162D
|
|
14
|
+
* is served by
|
|
15
|
+
* Objects/CTT/Static/HA Profile/Arrays/Int162D (NodeId s=CTT/Static/HA Profile/Arrays/Int162D)
|
|
16
|
+
* so a CTT project generator can fill the setting by browsing, without any
|
|
17
|
+
* hand-maintained map. See ./ctt_tree.ts for how a setting outside that prefix
|
|
18
|
+
* is keyed. Only settings the rest of this address space does not already serve
|
|
19
|
+
* are built here - plus the two Bool settings, see addBooleanScalarAndArray().
|
|
20
|
+
*
|
|
21
|
+
* Not covered, and why:
|
|
22
|
+
* Decimal deprecated in OPC UA 1.05
|
|
23
|
+
* the HA Aggregates nodes need node-opcua-aggregates and a seeded
|
|
24
|
+
* history matching the CTT's StartOfBadData*
|
|
25
|
+
* NodeDoesNotSupportServerTimestamp needs the variable read path to omit it
|
|
26
|
+
* NodeManagement/RootNode the server has no AddNodes service
|
|
27
|
+
* Chattering Alarms needs an alarm that flips state on its own
|
|
28
|
+
* DiscrepancyAlarmType Input Nodes see ./alarm_input_nodes.ts
|
|
29
|
+
*/
|
|
30
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
31
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
32
|
+
const node_opcua_data_access_1 = require("node-opcua-data-access");
|
|
33
|
+
const node_opcua_data_model_1 = require("node-opcua-data-model");
|
|
34
|
+
const node_opcua_variant_1 = require("node-opcua-variant");
|
|
35
|
+
const alarm_input_nodes_js_1 = require("./alarm_input_nodes.js");
|
|
36
|
+
const ctt_tree_js_1 = require("./ctt_tree.js");
|
|
37
|
+
// ─── Static / All Profiles ──────────────────────────────────────────────
|
|
38
|
+
function addVariantVariables(ctt) {
|
|
39
|
+
// "Variant" in CTT terms: a Variable whose DataType attribute is BaseDataType
|
|
40
|
+
const scalar = new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Double, value: 3.14 });
|
|
41
|
+
ctt.variable("Static/All Profiles/Scalar/Variant", "BaseDataType", -1, scalar, null);
|
|
42
|
+
// The array is the one case the CTT actually type-checks: Attribute Read 023.js
|
|
43
|
+
// asserts AssertUaValueOfType(BuiltInType.Variant, ...) against this node, so the
|
|
44
|
+
// *value* has to be Variant-encoded (BuiltInType 24), not merely stored on a
|
|
45
|
+
// BaseDataType-typed Variable. A Float64Array reads back as Double (11) and fails
|
|
46
|
+
// that assertion. Mixed element types are also the point of the type, and exercise
|
|
47
|
+
// the encoder the way the test intends.
|
|
48
|
+
ctt.variable("Static/All Profiles/Arrays/Variant", "BaseDataType", 1, new node_opcua_variant_1.Variant({
|
|
49
|
+
dataType: node_opcua_variant_1.DataType.Variant,
|
|
50
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Array,
|
|
51
|
+
value: [
|
|
52
|
+
new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Double, value: 1 }),
|
|
53
|
+
new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.UInt32, value: 2 }),
|
|
54
|
+
new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.String, value: "three" }),
|
|
55
|
+
new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Boolean, value: true }),
|
|
56
|
+
new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Float, value: 5.5 })
|
|
57
|
+
]
|
|
58
|
+
}), [5]);
|
|
59
|
+
ctt.variable("Static/All Profiles/Multi-Dimensional-Arrays/Variant", "BaseDataType", 2, new node_opcua_variant_1.Variant({
|
|
60
|
+
dataType: node_opcua_variant_1.DataType.Double,
|
|
61
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Matrix,
|
|
62
|
+
dimensions: [2, 3],
|
|
63
|
+
value: new Float64Array([1, 2, 3, 4, 5, 6])
|
|
64
|
+
}), [2, 3]);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* `Static/All Profiles/Scalar/Bool` and `.../Arrays/Bool`, which the Simulation
|
|
68
|
+
* folder would otherwise serve.
|
|
69
|
+
*
|
|
70
|
+
* A generator resolves a setting by overlay, then convention, then the CTT's own
|
|
71
|
+
* default, then by *browse name*, then by rule. The HA Profile nodes below are
|
|
72
|
+
* browse-named after their setting leaf, so `Static/HA Profile/Scalar/Bool` is
|
|
73
|
+
* literally named `Bool` - and the name step matches it against the All Profiles
|
|
74
|
+
* `Bool` settings, for which there is no convention node, while the Simulation
|
|
75
|
+
* node named `Boolean` matches neither. The name step runs before the rule step,
|
|
76
|
+
* so those two settings would silently resolve to a historizing node. Every other
|
|
77
|
+
* type name is safe: `Byte`, `Double` and the rest match both nodes and the rule
|
|
78
|
+
* scoring then prefers the non-historizing one.
|
|
79
|
+
*
|
|
80
|
+
* Building the two nodes here makes the convention step answer first, which is
|
|
81
|
+
* both deterministic and where the CTT-specific extras belong - hence the two
|
|
82
|
+
* Description properties, which View Minimum Continuation Point 01 012 needs
|
|
83
|
+
* (it browses the Scalar/Bool setting node with a NodeClassMask of Variable and
|
|
84
|
+
* wants at least two such references).
|
|
85
|
+
*/
|
|
86
|
+
function addBooleanScalarAndArray(ctt) {
|
|
87
|
+
const scalar = ctt.typedVariable("Static/All Profiles/Scalar/Bool", "Boolean", -1);
|
|
88
|
+
for (const name of ["Description1", "Description2"]) {
|
|
89
|
+
ctt.namespace.addVariable({
|
|
90
|
+
propertyOf: scalar,
|
|
91
|
+
browseName: name,
|
|
92
|
+
nodeId: ctt.nodeId(`Static/All Profiles/Scalar/Bool/${name}`),
|
|
93
|
+
dataType: "String",
|
|
94
|
+
value: new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.String, value: `${name} of the static Boolean` })
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
ctt.typedVariable("Static/All Profiles/Arrays/Bool", "Boolean", 1);
|
|
98
|
+
}
|
|
99
|
+
function addImageVariable(ctt) {
|
|
100
|
+
// the abstract Image data type (the concrete ImagePNG/GIF/JPG/BMP nodes live under Simulation)
|
|
101
|
+
let png;
|
|
102
|
+
try {
|
|
103
|
+
png = node_fs_1.default.readFileSync(node_path_1.default.join(__dirname, "../../data", "tux.png"));
|
|
104
|
+
}
|
|
105
|
+
catch (_err) {
|
|
106
|
+
png = Buffer.from("89504e470d0a1a0a", "hex");
|
|
107
|
+
}
|
|
108
|
+
ctt.variable("Static/All Profiles/Scalar/Image", "Image", -1, new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.ByteString, value: png }), null);
|
|
109
|
+
}
|
|
110
|
+
function addStructureVariables(ctt) {
|
|
111
|
+
const addressSpace = ctt.addressSpace;
|
|
112
|
+
const structures = [
|
|
113
|
+
{ dataType: "Range", fields: { low: -10, high: 10 } },
|
|
114
|
+
{
|
|
115
|
+
dataType: "EUInformation",
|
|
116
|
+
fields: {
|
|
117
|
+
namespaceUri: "http://www.opcfoundation.org/UA/units/un/cefact",
|
|
118
|
+
unitId: 4408652,
|
|
119
|
+
displayName: { text: "°C" },
|
|
120
|
+
description: { text: "degree Celsius" }
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{ dataType: "TimeZoneDataType", fields: { offset: 60, daylightSavingInOffset: false } },
|
|
124
|
+
{
|
|
125
|
+
dataType: "EnumValueType",
|
|
126
|
+
fields: { value: [1, 0], displayName: { text: "One" }, description: { text: "the value one" } }
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
dataType: "Argument",
|
|
130
|
+
fields: {
|
|
131
|
+
name: "arg",
|
|
132
|
+
dataType: "i=6",
|
|
133
|
+
valueRank: -1,
|
|
134
|
+
arrayDimensions: null,
|
|
135
|
+
description: { text: "an Int32 argument" }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
structures.forEach((s, i) => {
|
|
140
|
+
const dataTypeNode = addressSpace.findDataType(s.dataType);
|
|
141
|
+
if (!dataTypeNode)
|
|
142
|
+
throw new Error(`DataType ${s.dataType} not found`);
|
|
143
|
+
const value = addressSpace.constructExtensionObject(dataTypeNode, s.fields);
|
|
144
|
+
ctt.variable(`Static/All Profiles/Structures/Structure${String(i + 1).padStart(3, "0")}`, s.dataType, -1, new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.ExtensionObject, value }), null);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// ─── Static / DA Profile ────────────────────────────────────────────────
|
|
148
|
+
function addAnalogItemArrays(ctt) {
|
|
149
|
+
const folder = ctt.folder("Static/DA Profile/AnalogItemType Arrays");
|
|
150
|
+
for (const dataTypeName of ["Double", "Float", "Int16", "Int32", "UInt16", "UInt32"]) {
|
|
151
|
+
const dataType = node_opcua_variant_1.DataType[dataTypeName];
|
|
152
|
+
ctt.namespace.addAnalogDataItem({
|
|
153
|
+
organizedBy: folder,
|
|
154
|
+
browseName: dataTypeName,
|
|
155
|
+
nodeId: ctt.nodeId(`Static/DA Profile/AnalogItemType Arrays/${dataTypeName}`),
|
|
156
|
+
dataType: dataTypeName,
|
|
157
|
+
valueRank: 1,
|
|
158
|
+
arrayDimensions: [5],
|
|
159
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Array,
|
|
160
|
+
engineeringUnitsRange: { low: -100, high: 100 },
|
|
161
|
+
instrumentRange: { low: -1000, high: 1000 },
|
|
162
|
+
engineeringUnits: node_opcua_data_access_1.standardUnits.degree_celsius,
|
|
163
|
+
value: new node_opcua_variant_1.Variant({ dataType, arrayType: node_opcua_variant_1.VariantArrayType.Array, value: (0, node_opcua_variant_1.buildVariantArray)(dataType, 5, 0) }),
|
|
164
|
+
accessLevel: ctt_tree_js_1.readWrite,
|
|
165
|
+
userAccessLevel: ctt_tree_js_1.readWrite
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function axis(addressSpace, title, low, high) {
|
|
170
|
+
const axisInformation = addressSpace.findDataType("AxisInformation");
|
|
171
|
+
if (!axisInformation)
|
|
172
|
+
throw new Error("AxisInformation not found");
|
|
173
|
+
return addressSpace.constructExtensionObject(axisInformation, {
|
|
174
|
+
engineeringUnits: node_opcua_data_access_1.standardUnits.second,
|
|
175
|
+
euRange: { low, high },
|
|
176
|
+
title: { text: title },
|
|
177
|
+
axisScaleType: 0, // Linear
|
|
178
|
+
axisSteps: null
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The five ArrayItemType subtypes: plain variables of the right VariableType,
|
|
183
|
+
* given the mandatory ArrayItemType properties by hand. instantiate() refuses
|
|
184
|
+
* a ValueRank that differs from the type's (ImageItemType and CubeItemType
|
|
185
|
+
* need 2 and 3) and namespace.addYArrayItem() ignores nodeId and organizedBy.
|
|
186
|
+
*/
|
|
187
|
+
function addArrayItems(ctt) {
|
|
188
|
+
const addressSpace = ctt.addressSpace;
|
|
189
|
+
const namespace = ctt.namespace;
|
|
190
|
+
const group = "Static/DA Profile/ArrayItemType";
|
|
191
|
+
const folder = ctt.folder(group);
|
|
192
|
+
const xAxis = axis(addressSpace, "x", 0, 10);
|
|
193
|
+
const yAxis = axis(addressSpace, "y", 0, 20);
|
|
194
|
+
const zAxis = axis(addressSpace, "z", 0, 30);
|
|
195
|
+
const rangeType = addressSpace.findDataType("Range");
|
|
196
|
+
const xvType = addressSpace.findDataType("XVType");
|
|
197
|
+
if (!rangeType || !xvType)
|
|
198
|
+
throw new Error("Range or XVType not found");
|
|
199
|
+
const extensionObject = (value) => new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.ExtensionObject, value });
|
|
200
|
+
const arrayItem = (typeName, options, axes) => {
|
|
201
|
+
const v = namespace.addVariable({
|
|
202
|
+
organizedBy: folder,
|
|
203
|
+
browseName: typeName,
|
|
204
|
+
nodeId: ctt.nodeId(`${group}/${typeName}`),
|
|
205
|
+
typeDefinition: typeName,
|
|
206
|
+
dataType: options.dataType,
|
|
207
|
+
valueRank: options.valueRank,
|
|
208
|
+
arrayDimensions: options.arrayDimensions,
|
|
209
|
+
accessLevel: ctt_tree_js_1.readWrite,
|
|
210
|
+
userAccessLevel: ctt_tree_js_1.readWrite,
|
|
211
|
+
value: options.value
|
|
212
|
+
});
|
|
213
|
+
const property = (browseName, dataType, value, valueRank = -1) => namespace.addVariable({ propertyOf: v, browseName, dataType, valueRank, value, modellingRule: "Mandatory" });
|
|
214
|
+
property("Title", "LocalizedText", new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.LocalizedText, value: { text: typeName } }));
|
|
215
|
+
property("AxisScaleType", "AxisScaleEnumeration", new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Int32, value: 0 }));
|
|
216
|
+
property("EURange", "Range", extensionObject(addressSpace.constructExtensionObject(rangeType, { low: 0, high: 100 })));
|
|
217
|
+
property("InstrumentRange", "Range", extensionObject(addressSpace.constructExtensionObject(rangeType, { low: 0, high: 1000 })));
|
|
218
|
+
property("EngineeringUnits", "EUInformation", extensionObject(node_opcua_data_access_1.standardUnits.degree_celsius));
|
|
219
|
+
for (const [name, value] of Object.entries(axes)) {
|
|
220
|
+
property(name, "AxisInformation", value, value.arrayType === node_opcua_variant_1.VariantArrayType.Array ? 1 : -1);
|
|
221
|
+
}
|
|
222
|
+
return v;
|
|
223
|
+
};
|
|
224
|
+
arrayItem("YArrayItemType", {
|
|
225
|
+
dataType: "Double",
|
|
226
|
+
valueRank: 1,
|
|
227
|
+
arrayDimensions: [5],
|
|
228
|
+
value: new node_opcua_variant_1.Variant({
|
|
229
|
+
dataType: node_opcua_variant_1.DataType.Double,
|
|
230
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Array,
|
|
231
|
+
value: new Float64Array([1, 2, 3, 4, 5])
|
|
232
|
+
})
|
|
233
|
+
}, { XAxisDefinition: extensionObject(xAxis) });
|
|
234
|
+
arrayItem("XYArrayItemType", {
|
|
235
|
+
dataType: "XVType",
|
|
236
|
+
valueRank: 1,
|
|
237
|
+
arrayDimensions: [3],
|
|
238
|
+
value: new node_opcua_variant_1.Variant({
|
|
239
|
+
dataType: node_opcua_variant_1.DataType.ExtensionObject,
|
|
240
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Array,
|
|
241
|
+
value: [0, 1, 2].map((i) => addressSpace.constructExtensionObject(xvType, { x: i, value: i * 2 }))
|
|
242
|
+
})
|
|
243
|
+
}, { XAxisDefinition: extensionObject(xAxis) });
|
|
244
|
+
arrayItem("ImageItemType", {
|
|
245
|
+
dataType: "UInt16",
|
|
246
|
+
valueRank: 2,
|
|
247
|
+
arrayDimensions: [2, 3],
|
|
248
|
+
value: new node_opcua_variant_1.Variant({
|
|
249
|
+
dataType: node_opcua_variant_1.DataType.UInt16,
|
|
250
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Matrix,
|
|
251
|
+
dimensions: [2, 3],
|
|
252
|
+
value: new Uint16Array([1, 2, 3, 4, 5, 6])
|
|
253
|
+
})
|
|
254
|
+
}, { XAxisDefinition: extensionObject(xAxis), YAxisDefinition: extensionObject(yAxis) });
|
|
255
|
+
arrayItem("CubeItemType", {
|
|
256
|
+
dataType: "Double",
|
|
257
|
+
valueRank: 3,
|
|
258
|
+
arrayDimensions: [2, 2, 2],
|
|
259
|
+
value: new node_opcua_variant_1.Variant({
|
|
260
|
+
dataType: node_opcua_variant_1.DataType.Double,
|
|
261
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Matrix,
|
|
262
|
+
dimensions: [2, 2, 2],
|
|
263
|
+
value: new Float64Array([1, 2, 3, 4, 5, 6, 7, 8])
|
|
264
|
+
})
|
|
265
|
+
}, {
|
|
266
|
+
XAxisDefinition: extensionObject(xAxis),
|
|
267
|
+
YAxisDefinition: extensionObject(yAxis),
|
|
268
|
+
ZAxisDefinition: extensionObject(zAxis)
|
|
269
|
+
});
|
|
270
|
+
arrayItem("NDimensionArrayItemType", {
|
|
271
|
+
dataType: "Double",
|
|
272
|
+
valueRank: 2,
|
|
273
|
+
arrayDimensions: [2, 3],
|
|
274
|
+
value: new node_opcua_variant_1.Variant({
|
|
275
|
+
dataType: node_opcua_variant_1.DataType.Double,
|
|
276
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Matrix,
|
|
277
|
+
dimensions: [2, 3],
|
|
278
|
+
value: new Float64Array([1, 2, 3, 4, 5, 6])
|
|
279
|
+
})
|
|
280
|
+
}, {
|
|
281
|
+
AxisDefinition: new node_opcua_variant_1.Variant({
|
|
282
|
+
dataType: node_opcua_variant_1.DataType.ExtensionObject,
|
|
283
|
+
arrayType: node_opcua_variant_1.VariantArrayType.Array,
|
|
284
|
+
value: [xAxis, yAxis]
|
|
285
|
+
})
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
// ─── Static / HA Profile ────────────────────────────────────────────────
|
|
289
|
+
const HA_TYPES = [
|
|
290
|
+
"Bool",
|
|
291
|
+
"Byte",
|
|
292
|
+
"ByteString",
|
|
293
|
+
"DateTime",
|
|
294
|
+
"Double",
|
|
295
|
+
"Float",
|
|
296
|
+
"Int16",
|
|
297
|
+
"Int32",
|
|
298
|
+
"Int64",
|
|
299
|
+
"SByte",
|
|
300
|
+
"String",
|
|
301
|
+
"UInt16",
|
|
302
|
+
"UInt32",
|
|
303
|
+
"UInt64",
|
|
304
|
+
"XmlElement"
|
|
305
|
+
];
|
|
306
|
+
/** a variable with in-memory history and a first value, so reads are Good with timestamps */
|
|
307
|
+
function historize(ctt, variable) {
|
|
308
|
+
ctt.addressSpace.installHistoricalDataNode(variable);
|
|
309
|
+
const current = variable.readValue().value;
|
|
310
|
+
variable.setValueFromSource(current);
|
|
311
|
+
return variable;
|
|
312
|
+
}
|
|
313
|
+
function addHistorizingVariables(ctt) {
|
|
314
|
+
for (const leaf of HA_TYPES) {
|
|
315
|
+
const dataTypeName = ctt_tree_js_1.TYPE_ALIAS[leaf] ?? leaf;
|
|
316
|
+
historize(ctt, ctt.typedVariable(`Static/HA Profile/Scalar/${leaf}`, dataTypeName, -1));
|
|
317
|
+
historize(ctt, ctt.typedVariable(`Static/HA Profile/Arrays/${leaf}`, dataTypeName, 1));
|
|
318
|
+
historize(ctt, ctt.typedVariable(`Static/HA Profile/Arrays/${leaf}2D`, dataTypeName, 2));
|
|
319
|
+
}
|
|
320
|
+
const range = ctt.addressSpace.findDataType("Range");
|
|
321
|
+
if (!range)
|
|
322
|
+
throw new Error("Range not found");
|
|
323
|
+
historize(ctt, ctt.variable("Static/HA Profile/StructureNodeSupportingHistory", "Range", -1, new node_opcua_variant_1.Variant({
|
|
324
|
+
dataType: node_opcua_variant_1.DataType.ExtensionObject,
|
|
325
|
+
value: ctt.addressSpace.constructExtensionObject(range, { low: 0, high: 1 })
|
|
326
|
+
}), null));
|
|
327
|
+
// AccessLevel_* : the AccessLevel attribute; UserAccessLevel_* : the UserAccessLevel attribute
|
|
328
|
+
const history = node_opcua_data_model_1.AccessLevelFlag.HistoryRead;
|
|
329
|
+
const flags = {
|
|
330
|
+
ReadOnly: node_opcua_data_model_1.AccessLevelFlag.CurrentRead | history,
|
|
331
|
+
WriteOnly: node_opcua_data_model_1.AccessLevelFlag.CurrentWrite | history,
|
|
332
|
+
None: history
|
|
333
|
+
};
|
|
334
|
+
for (const attribute of ["AccessLevel", "UserAccessLevel"]) {
|
|
335
|
+
for (const [kind, flag] of Object.entries(flags)) {
|
|
336
|
+
const relPath = `Static/HA Profile/AccessRights/${attribute}_${kind}`;
|
|
337
|
+
const i = relPath.lastIndexOf("/");
|
|
338
|
+
const full = node_opcua_data_model_1.AccessLevelFlag.CurrentRead | node_opcua_data_model_1.AccessLevelFlag.CurrentWrite | history;
|
|
339
|
+
const v = ctt.namespace.addVariable({
|
|
340
|
+
componentOf: ctt.folder(relPath.slice(0, i)),
|
|
341
|
+
browseName: relPath.slice(i + 1),
|
|
342
|
+
nodeId: ctt.nodeId(relPath),
|
|
343
|
+
description: `CTT setting ${relPath}`,
|
|
344
|
+
dataType: "Int32",
|
|
345
|
+
valueRank: -1,
|
|
346
|
+
accessLevel: full,
|
|
347
|
+
userAccessLevel: full,
|
|
348
|
+
value: new node_opcua_variant_1.Variant({ dataType: node_opcua_variant_1.DataType.Int32, value: 36 })
|
|
349
|
+
});
|
|
350
|
+
historize(ctt, v);
|
|
351
|
+
// installHistoricalDataNode() adds CurrentRead to both attributes: set the flags after it
|
|
352
|
+
v.accessLevel = attribute === "AccessLevel" ? flag : full;
|
|
353
|
+
v.userAccessLevel = attribute === "UserAccessLevel" ? flag : full;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// ─── entry point ────────────────────────────────────────────────────────
|
|
358
|
+
function addCttFolder(namespace, objectsFolder) {
|
|
359
|
+
const root = namespace.addFolder(objectsFolder, {
|
|
360
|
+
browseName: "CTT",
|
|
361
|
+
nodeId: "s=CTT",
|
|
362
|
+
description: "Nodes named after the settings of the OPC Foundation Compliance Test Tool server project"
|
|
363
|
+
});
|
|
364
|
+
const ctt = new ctt_tree_js_1.CttFolder(namespace, root);
|
|
365
|
+
addVariantVariables(ctt);
|
|
366
|
+
addBooleanScalarAndArray(ctt);
|
|
367
|
+
addImageVariable(ctt);
|
|
368
|
+
addStructureVariables(ctt);
|
|
369
|
+
addAnalogItemArrays(ctt);
|
|
370
|
+
addArrayItems(ctt);
|
|
371
|
+
addHistorizingVariables(ctt);
|
|
372
|
+
(0, alarm_input_nodes_js_1.addAlarmInputNodes)(ctt);
|
|
373
|
+
return root;
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=ctt_folder.js.map
|