node-opcua-address-space-for-conformance-testing 2.167.0 → 2.169.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/address_space_for_conformance_testing.d.ts +6 -2
- package/dist/address_space_for_conformance_testing.js +27 -1306
- package/dist/address_space_for_conformance_testing.js.map +1 -1
- package/dist/conformance_testing/access_right_variables.d.ts +5 -0
- package/dist/conformance_testing/access_right_variables.js +45 -0
- package/dist/conformance_testing/access_right_variables.js.map +1 -0
- package/dist/conformance_testing/analog_data_items.d.ts +5 -0
- package/dist/conformance_testing/analog_data_items.js +117 -0
- package/dist/conformance_testing/analog_data_items.js.map +1 -0
- package/dist/conformance_testing/discrete_variables.d.ts +4 -0
- package/dist/conformance_testing/discrete_variables.js +111 -0
- package/dist/conformance_testing/discrete_variables.js.map +1 -0
- package/dist/conformance_testing/enumeration_variable.d.ts +5 -0
- package/dist/conformance_testing/enumeration_variable.js +24 -0
- package/dist/conformance_testing/enumeration_variable.js.map +1 -0
- package/dist/conformance_testing/helpers.d.ts +13 -0
- package/dist/conformance_testing/helpers.js +204 -0
- package/dist/conformance_testing/helpers.js.map +1 -0
- package/dist/conformance_testing/mass_variables.d.ts +5 -0
- package/dist/conformance_testing/mass_variables.js +31 -0
- package/dist/conformance_testing/mass_variables.js.map +1 -0
- package/dist/conformance_testing/node_with_references.d.ts +5 -0
- package/dist/conformance_testing/node_with_references.js +119 -0
- package/dist/conformance_testing/node_with_references.js.map +1 -0
- package/dist/conformance_testing/object_with_methods.d.ts +5 -0
- package/dist/conformance_testing/object_with_methods.js +85 -0
- package/dist/conformance_testing/object_with_methods.js.map +1 -0
- package/dist/conformance_testing/path_and_large_arrays.d.ts +6 -0
- package/dist/conformance_testing/path_and_large_arrays.js +33 -0
- package/dist/conformance_testing/path_and_large_arrays.js.map +1 -0
- package/dist/conformance_testing/sample_view.d.ts +5 -0
- package/dist/conformance_testing/sample_view.js +25 -0
- package/dist/conformance_testing/sample_view.js.map +1 -0
- package/dist/conformance_testing/simulation_variables.d.ts +5 -0
- package/dist/conformance_testing/simulation_variables.js +113 -0
- package/dist/conformance_testing/simulation_variables.js.map +1 -0
- package/dist/conformance_testing/static_variables.d.ts +2 -0
- package/dist/conformance_testing/static_variables.js +70 -0
- package/dist/conformance_testing/static_variables.js.map +1 -0
- package/dist/conformance_testing/trigger_nodes.d.ts +5 -0
- package/dist/conformance_testing/trigger_nodes.js +41 -0
- package/dist/conformance_testing/trigger_nodes.js.map +1 -0
- package/dist/conformance_testing/type_defaults.d.ts +54 -0
- package/dist/conformance_testing/type_defaults.js +96 -0
- package/dist/conformance_testing/type_defaults.js.map +1 -0
- package/package.json +12 -12
- package/src/address_space_for_conformance_testing.ts +34 -1494
- package/src/conformance_testing/access_right_variables.ts +55 -0
- package/src/conformance_testing/analog_data_items.ts +136 -0
- package/src/conformance_testing/discrete_variables.ts +131 -0
- package/src/conformance_testing/enumeration_variable.ts +27 -0
- package/src/conformance_testing/helpers.ts +226 -0
- package/src/conformance_testing/mass_variables.ts +42 -0
- package/src/conformance_testing/node_with_references.ts +130 -0
- package/src/conformance_testing/object_with_methods.ts +93 -0
- package/src/conformance_testing/path_and_large_arrays.ts +35 -0
- package/src/conformance_testing/sample_view.ts +28 -0
- package/src/conformance_testing/simulation_variables.ts +129 -0
- package/src/conformance_testing/static_variables.ts +71 -0
- package/src/conformance_testing/trigger_nodes.ts +49 -0
- package/src/conformance_testing/type_defaults.ts +60 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access-right test variables for conformance testing.
|
|
3
|
+
*/
|
|
4
|
+
import type { Namespace, UAObject } from "node-opcua-address-space";
|
|
5
|
+
import { makeAccessLevelFlag } from "node-opcua-data-model";
|
|
6
|
+
import { DataType, Variant, VariantArrayType } from "node-opcua-variant";
|
|
7
|
+
|
|
8
|
+
const defaultInt32Value = new Variant({
|
|
9
|
+
dataType: DataType.Int32,
|
|
10
|
+
arrayType: VariantArrayType.Scalar,
|
|
11
|
+
value: 36
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const accessRightConfigs: {
|
|
15
|
+
name: string;
|
|
16
|
+
accessLevel: string;
|
|
17
|
+
userAccessLevel: string;
|
|
18
|
+
value?: Record<string, unknown>;
|
|
19
|
+
}[] = [
|
|
20
|
+
{ name: "AccessLevel_CurrentRead", accessLevel: "CurrentRead", userAccessLevel: "CurrentRead" },
|
|
21
|
+
{ name: "AccessLevel_CurrentWrite", accessLevel: "CurrentWrite", userAccessLevel: "CurrentWrite", value: {} },
|
|
22
|
+
{ name: "AccessLevel_CurrentRead_NotUser", accessLevel: "CurrentRead", userAccessLevel: "" },
|
|
23
|
+
{ name: "AccessLevel_CurrentWrite_NotUser", accessLevel: "CurrentWrite | CurrentRead", userAccessLevel: "CurrentRead" },
|
|
24
|
+
{ name: "AccessLevel_CurrentRead_NotCurrentWrite", accessLevel: "CurrentRead", userAccessLevel: "CurrentRead" },
|
|
25
|
+
{ name: "AccessLevel_CurrentWrite_NotCurrentRead", accessLevel: "CurrentWrite", userAccessLevel: "CurrentWrite" },
|
|
26
|
+
{ name: "AccessLevel_DeniedAll", accessLevel: "", userAccessLevel: "" }
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export function addAccessRightVariables(namespace: Namespace, parentFolder: UAObject): void {
|
|
30
|
+
const accessRight_Folder = namespace.addFolder(parentFolder, {
|
|
31
|
+
browseName: "AccessRight",
|
|
32
|
+
description: "Folder containing various nodes with different access right behavior",
|
|
33
|
+
nodeId: "s=AccessRight"
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const accessLevel_All_Folder = namespace.addFolder(accessRight_Folder, {
|
|
37
|
+
browseName: "AccessLevel",
|
|
38
|
+
description: "Various node with different access right behavior",
|
|
39
|
+
nodeId: "s=AccessLevel"
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
for (const config of accessRightConfigs) {
|
|
43
|
+
namespace.addVariable({
|
|
44
|
+
componentOf: accessLevel_All_Folder,
|
|
45
|
+
browseName: config.name,
|
|
46
|
+
description: { locale: "en", text: config.name },
|
|
47
|
+
nodeId: `s=${config.name}`,
|
|
48
|
+
dataType: "Int32",
|
|
49
|
+
valueRank: -1,
|
|
50
|
+
accessLevel: makeAccessLevelFlag(config.accessLevel),
|
|
51
|
+
userAccessLevel: makeAccessLevelFlag(config.userAccessLevel),
|
|
52
|
+
value: config.value ?? defaultInt32Value
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analog data items, data items, and array analog data items for conformance testing.
|
|
3
|
+
*/
|
|
4
|
+
import type { Namespace, UAObject } from "node-opcua-address-space";
|
|
5
|
+
import { assert } from "node-opcua-assert";
|
|
6
|
+
import { standardUnits } from "node-opcua-data-access";
|
|
7
|
+
import { DataType, VariantArrayType } from "node-opcua-variant";
|
|
8
|
+
|
|
9
|
+
interface RangeOptions {
|
|
10
|
+
low: number;
|
|
11
|
+
high: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function makeRange(dataType: DataType): { engineeringUnitsRange: RangeOptions; instrumentRange: RangeOptions } {
|
|
15
|
+
let engineeringUnitsRange = { low: -200, high: 200 };
|
|
16
|
+
let instrumentRange = { low: -200, high: 200 };
|
|
17
|
+
if (DataType[dataType][0] === "U" || dataType === DataType.Byte) {
|
|
18
|
+
engineeringUnitsRange = { low: 10, high: 250 };
|
|
19
|
+
instrumentRange = { low: 10, high: 250 };
|
|
20
|
+
}
|
|
21
|
+
return { engineeringUnitsRange, instrumentRange };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function addAnalogDataItems(namespace: Namespace, parentFolder: UAObject): void {
|
|
25
|
+
function _addDataItem(localParentFolder: UAObject, dataType: DataType, initialValue: unknown): void {
|
|
26
|
+
const name = `${DataType[dataType]}DataItem`;
|
|
27
|
+
const nodeId = `s=${name}`;
|
|
28
|
+
|
|
29
|
+
const v = namespace.addDataItem({
|
|
30
|
+
componentOf: localParentFolder,
|
|
31
|
+
nodeId,
|
|
32
|
+
browseName: name,
|
|
33
|
+
definition: "(tempA -25) + tempB",
|
|
34
|
+
dataType,
|
|
35
|
+
value: {
|
|
36
|
+
arrayType: VariantArrayType.Scalar,
|
|
37
|
+
dataType,
|
|
38
|
+
value: initialValue
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
assert(v.nodeId.toString() === `ns=${namespace.index};${nodeId}`, `ns=${namespace.index};${nodeId} ${v.nodeId.toString()}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function _addAnalogDataItem(localParentFolder: UAObject, dataType: DataType, initialValue: unknown): void {
|
|
45
|
+
const { engineeringUnitsRange, instrumentRange } = makeRange(dataType);
|
|
46
|
+
assert(
|
|
47
|
+
Array.isArray(initialValue) ||
|
|
48
|
+
((initialValue as number) >= engineeringUnitsRange.low && (initialValue as number) <= engineeringUnitsRange.high)
|
|
49
|
+
);
|
|
50
|
+
const name = `${DataType[dataType]}AnalogDataItem`;
|
|
51
|
+
const nodeId = `s=${name}`;
|
|
52
|
+
|
|
53
|
+
namespace.addAnalogDataItem({
|
|
54
|
+
componentOf: localParentFolder,
|
|
55
|
+
nodeId,
|
|
56
|
+
browseName: name,
|
|
57
|
+
definition: "...",
|
|
58
|
+
valuePrecision: 0.5,
|
|
59
|
+
engineeringUnitsRange,
|
|
60
|
+
instrumentRange,
|
|
61
|
+
engineeringUnits: standardUnits.degree_celsius,
|
|
62
|
+
dataType,
|
|
63
|
+
value: { arrayType: VariantArrayType.Scalar, dataType, value: initialValue }
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function _addArrayAnalogDataItem(localParentFolder: UAObject, dataType: DataType, initialValue: unknown) {
|
|
68
|
+
const name = `${DataType[dataType]}ArrayAnalogDataItem`;
|
|
69
|
+
const nodeId = `s=${name}`;
|
|
70
|
+
const { engineeringUnitsRange, instrumentRange } = makeRange(dataType);
|
|
71
|
+
|
|
72
|
+
namespace.addAnalogDataItem({
|
|
73
|
+
componentOf: localParentFolder,
|
|
74
|
+
nodeId,
|
|
75
|
+
browseName: name,
|
|
76
|
+
definition: "(tempA -25) + tempB",
|
|
77
|
+
valuePrecision: 0.5,
|
|
78
|
+
engineeringUnitsRange,
|
|
79
|
+
instrumentRange,
|
|
80
|
+
engineeringUnits: standardUnits.degree_celsius,
|
|
81
|
+
dataType,
|
|
82
|
+
value: {
|
|
83
|
+
arrayType: VariantArrayType.Array,
|
|
84
|
+
dataType,
|
|
85
|
+
value: [initialValue, initialValue, initialValue, initialValue, initialValue]
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const analogItemFolder = namespace.addObject({
|
|
91
|
+
organizedBy: parentFolder,
|
|
92
|
+
browseName: "Simulation_AnalogDataItem",
|
|
93
|
+
typeDefinition: "FolderType",
|
|
94
|
+
nodeId: "s=Simulation_AnalogDataItem"
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const { engineeringUnitsRange, instrumentRange } = makeRange(DataType.Double);
|
|
98
|
+
namespace.addAnalogDataItem({
|
|
99
|
+
componentOf: analogItemFolder,
|
|
100
|
+
nodeId: "s=DoubleAnalogDataItemWithEU",
|
|
101
|
+
browseName: "DoubleAnalogDataItemWithEU",
|
|
102
|
+
definition: "(tempA -25) + tempB",
|
|
103
|
+
valuePrecision: 0.5,
|
|
104
|
+
engineeringUnitsRange,
|
|
105
|
+
instrumentRange,
|
|
106
|
+
engineeringUnits: standardUnits.degree_celsius,
|
|
107
|
+
dataType: DataType.Double,
|
|
108
|
+
value: { dataType: DataType.Double, value: 19.5 }
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const data = [
|
|
112
|
+
{ dataType: DataType.Double, value: 3.14 },
|
|
113
|
+
{ dataType: DataType.Float, value: 3.14 },
|
|
114
|
+
{ dataType: DataType.Int16, value: -10 },
|
|
115
|
+
{ dataType: DataType.UInt16, value: 10 },
|
|
116
|
+
{ dataType: DataType.Int32, value: -100 },
|
|
117
|
+
{ dataType: DataType.UInt32, value: 100 },
|
|
118
|
+
{ dataType: DataType.Int64, value: [0, 0] },
|
|
119
|
+
{ dataType: DataType.UInt64, value: [0, 0] },
|
|
120
|
+
{ dataType: DataType.Byte, value: 65 },
|
|
121
|
+
{ dataType: DataType.SByte, value: -23 }
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
for (const e of data) {
|
|
125
|
+
_addAnalogDataItem(analogItemFolder, e.dataType, e.value);
|
|
126
|
+
}
|
|
127
|
+
for (const e of data) {
|
|
128
|
+
_addDataItem(analogItemFolder, e.dataType, e.value);
|
|
129
|
+
}
|
|
130
|
+
_addDataItem(analogItemFolder, DataType.String, "some string");
|
|
131
|
+
_addDataItem(analogItemFolder, DataType.DateTime, new Date());
|
|
132
|
+
|
|
133
|
+
for (const e of data) {
|
|
134
|
+
_addArrayAnalogDataItem(analogItemFolder, e.dataType, e.value);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discrete variable types: TwoStateDiscrete, MultiStateDiscrete, MultiStateValueDiscrete.
|
|
3
|
+
*/
|
|
4
|
+
import type { Int64, UInt64 } from "node-opcua-basic-types";
|
|
5
|
+
import type { Namespace, UAObject } from "node-opcua-address-space";
|
|
6
|
+
|
|
7
|
+
function getDADiscreteTypeFolder(namespace: Namespace, parentFolder: UAObject): UAObject {
|
|
8
|
+
const name = "Simulation_DA_DiscreteType";
|
|
9
|
+
const nodeId = "s=Simulation_DA_DiscreteType";
|
|
10
|
+
|
|
11
|
+
let node = parentFolder.getFolderElementByName(name);
|
|
12
|
+
if (!node) {
|
|
13
|
+
node = namespace.addObject({
|
|
14
|
+
organizedBy: parentFolder,
|
|
15
|
+
typeDefinition: "FolderType",
|
|
16
|
+
browseName: name,
|
|
17
|
+
nodeId
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return node as UAObject;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function addTwoStateDiscreteVariables(namespace: Namespace, parentFolder: UAObject): void {
|
|
24
|
+
const DADiscreteTypeFolder = getDADiscreteTypeFolder(namespace, parentFolder);
|
|
25
|
+
|
|
26
|
+
const twoStateDiscrete001 = namespace.addTwoStateDiscrete({
|
|
27
|
+
organizedBy: DADiscreteTypeFolder,
|
|
28
|
+
nodeId: "s=TwoStateDiscrete001",
|
|
29
|
+
browseName: "TwoStateDiscrete001",
|
|
30
|
+
trueState: "Enabled",
|
|
31
|
+
falseState: "Disabled"
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const twoStateDiscrete002 = namespace.addTwoStateDiscrete({
|
|
35
|
+
organizedBy: DADiscreteTypeFolder,
|
|
36
|
+
nodeId: "s=TwoStateDiscrete002",
|
|
37
|
+
browseName: "TwoStateDiscrete002",
|
|
38
|
+
trueState: "On",
|
|
39
|
+
falseState: "Off",
|
|
40
|
+
optionals: ["TransitionTime", "EffectiveDisplayName"]
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const twoStateDiscrete003 = namespace.addTwoStateDiscrete({
|
|
44
|
+
browseName: "twoStateDiscrete003",
|
|
45
|
+
nodeId: "s=TwoStateDiscrete003",
|
|
46
|
+
optionals: ["TransitionTime"],
|
|
47
|
+
isTrueSubStateOf: twoStateDiscrete002
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const twoStateDiscrete004 = namespace.addTwoStateDiscrete({
|
|
51
|
+
organizedBy: DADiscreteTypeFolder,
|
|
52
|
+
nodeId: "s=TwoStateDiscrete004",
|
|
53
|
+
browseName: "TwoStateDiscrete004",
|
|
54
|
+
trueState: "InProgress",
|
|
55
|
+
falseState: "Stopped"
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const twoStateDiscrete005 = namespace.addTwoStateDiscrete({
|
|
59
|
+
organizedBy: DADiscreteTypeFolder,
|
|
60
|
+
nodeId: "s=TwoStateDiscrete005",
|
|
61
|
+
browseName: "TwoStateDiscrete005",
|
|
62
|
+
trueState: "InProgress",
|
|
63
|
+
falseState: "Stopped"
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
twoStateDiscrete001.setValueFromSource({ dataType: "Boolean", value: false });
|
|
67
|
+
twoStateDiscrete002.setValueFromSource({ dataType: "Boolean", value: false });
|
|
68
|
+
twoStateDiscrete003.setValueFromSource({ dataType: "Boolean", value: false });
|
|
69
|
+
twoStateDiscrete004.setValueFromSource({ dataType: "Boolean", value: false });
|
|
70
|
+
twoStateDiscrete005.setValueFromSource({ dataType: "Boolean", value: false });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function addMultiStateDiscreteVariable(namespace: Namespace, parentFolder: UAObject): void {
|
|
74
|
+
const DADiscreteTypeFolder = getDADiscreteTypeFolder(namespace, parentFolder);
|
|
75
|
+
|
|
76
|
+
for (let i = 1; i <= 5; i++) {
|
|
77
|
+
const name = `MultiStateDiscrete${i.toString().padStart(3, "0")}`;
|
|
78
|
+
namespace.addMultiStateDiscrete({
|
|
79
|
+
organizedBy: DADiscreteTypeFolder,
|
|
80
|
+
nodeId: `s=${name}`,
|
|
81
|
+
browseName: name,
|
|
82
|
+
enumStrings: ["Red", "Orange", "Green"],
|
|
83
|
+
value: 1 // Orange
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function addMultiStateValueDiscreteVariables(namespaceDemo: Namespace, parentFolder: UAObject): void {
|
|
89
|
+
const multistateValueDiscreteTypeFolder = namespaceDemo.addObject({
|
|
90
|
+
organizedBy: parentFolder,
|
|
91
|
+
typeDefinition: "FolderType",
|
|
92
|
+
browseName: "Simulation_DA_MultiStateValueDiscreteType",
|
|
93
|
+
nodeId: "s=Simulation_DA_MultiStateValueDiscreteType"
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
function _add_multi_state_variable(
|
|
97
|
+
folder: UAObject,
|
|
98
|
+
dataType: string,
|
|
99
|
+
_value: number | UInt64 | Int64,
|
|
100
|
+
enumValues: Record<string, number>
|
|
101
|
+
) {
|
|
102
|
+
const name = `${dataType}MultiStateValueDiscrete`;
|
|
103
|
+
const nodeId = `s=${name}`;
|
|
104
|
+
|
|
105
|
+
namespaceDemo.addMultiStateValueDiscrete({
|
|
106
|
+
organizedBy: folder,
|
|
107
|
+
browseName: name,
|
|
108
|
+
nodeId,
|
|
109
|
+
dataType,
|
|
110
|
+
enumValues,
|
|
111
|
+
value: 0x0000 // Zero
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const enumValueUnsigned = { Zero: 0x00, One: 0x01, Two: 0x02, Three: 0x03, Four: 0x04, Five: 0x05, Six: 0x06, Seven: 0x07 };
|
|
116
|
+
const enumValueSigned = { MinusOne: -1, MinusTwo: -2, MinusThree: -3, ...enumValueUnsigned };
|
|
117
|
+
|
|
118
|
+
const data = [
|
|
119
|
+
{ dataType: "Int16", value: -1, enumValue: enumValueSigned },
|
|
120
|
+
{ dataType: "UInt16", value: 10, enumValue: enumValueUnsigned },
|
|
121
|
+
{ dataType: "Int32", value: -1, enumValue: enumValueSigned },
|
|
122
|
+
{ dataType: "UInt32", value: 100, enumValue: enumValueUnsigned },
|
|
123
|
+
{ dataType: "Int64", value: [0, 0], enumValue: enumValueUnsigned },
|
|
124
|
+
{ dataType: "UInt64", value: [0, 0], enumValue: enumValueSigned },
|
|
125
|
+
{ dataType: "Byte", value: 1, enumValue: enumValueUnsigned },
|
|
126
|
+
{ dataType: "SByte", value: -1, enumValue: enumValueSigned }
|
|
127
|
+
];
|
|
128
|
+
for (const e of data) {
|
|
129
|
+
_add_multi_state_variable(multistateValueDiscreteTypeFolder, e.dataType, e.value, e.enumValue);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enumeration type and variable for conformance testing.
|
|
3
|
+
*/
|
|
4
|
+
import type { Namespace, UAObject } from "node-opcua-address-space";
|
|
5
|
+
|
|
6
|
+
export function addEnumerationVariable(namespaceDemo: Namespace, parentFolder: UAObject): void {
|
|
7
|
+
const addressSpace = namespaceDemo.addressSpace;
|
|
8
|
+
|
|
9
|
+
const myEnumType = namespaceDemo.addEnumerationType({
|
|
10
|
+
browseName: "SimulationEnumerationType",
|
|
11
|
+
enumeration: [
|
|
12
|
+
{ value: 1, displayName: "RUNNING" },
|
|
13
|
+
{ value: 2, displayName: "BLOCKED" },
|
|
14
|
+
{ value: 3, displayName: "IDLE" },
|
|
15
|
+
{ value: 4, displayName: "UNDER MAINTENANCE" }
|
|
16
|
+
]
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const e = namespaceDemo.addVariable({
|
|
20
|
+
organizedBy: parentFolder,
|
|
21
|
+
propertyOf: (addressSpace.rootFolder.objects.server as unknown as Record<string, unknown>)
|
|
22
|
+
.vendorServerInfos as unknown as UAObject,
|
|
23
|
+
dataType: myEnumType,
|
|
24
|
+
browseName: "RunningState"
|
|
25
|
+
});
|
|
26
|
+
e.writeEnumValue("RUNNING");
|
|
27
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper utilities for conformance testing address space construction.
|
|
3
|
+
*/
|
|
4
|
+
import type { Namespace, UAObject, UAVariable } from "node-opcua-address-space";
|
|
5
|
+
import { assert } from "node-opcua-assert";
|
|
6
|
+
import * as ec from "node-opcua-basic-types";
|
|
7
|
+
import { randomString } from "node-opcua-basic-types";
|
|
8
|
+
import { AccessLevelFlag, LocalizedText, makeAccessLevelFlag, QualifiedName } from "node-opcua-data-model";
|
|
9
|
+
import { make_debugLog, make_warningLog } from "node-opcua-debug";
|
|
10
|
+
import { findBuiltInType } from "node-opcua-factory";
|
|
11
|
+
import { buildVariantArray, DataType, Variant, VariantArrayType } from "node-opcua-variant";
|
|
12
|
+
|
|
13
|
+
const debugLog = make_debugLog(__filename);
|
|
14
|
+
const warningLog = make_warningLog(__filename);
|
|
15
|
+
|
|
16
|
+
// ─── Validators & Random Generators ─────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
function defaultValidator(/*value*/) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getValidatorFuncForType(dataType: DataType): (value: unknown) => boolean {
|
|
23
|
+
const f = (ec as Record<string, unknown>)[`isValid${dataType}`];
|
|
24
|
+
return (f as (value: unknown) => boolean) || defaultValidator;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getRandomFuncForType(dataType: DataType): () => unknown {
|
|
28
|
+
const dataTypeName = DataType[dataType];
|
|
29
|
+
const f = (ec as Record<string, unknown>)[`random${dataTypeName}`];
|
|
30
|
+
|
|
31
|
+
if (f) {
|
|
32
|
+
return f as () => unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
switch (dataTypeName) {
|
|
36
|
+
case "Variant":
|
|
37
|
+
return () => {
|
|
38
|
+
return new Variant();
|
|
39
|
+
};
|
|
40
|
+
case "QualifiedName":
|
|
41
|
+
return () => {
|
|
42
|
+
return new QualifiedName({ name: randomString() });
|
|
43
|
+
};
|
|
44
|
+
case "LocalizedText":
|
|
45
|
+
return () => {
|
|
46
|
+
return new LocalizedText({ text: randomString() });
|
|
47
|
+
};
|
|
48
|
+
case "XmlElement":
|
|
49
|
+
return () => {
|
|
50
|
+
const element = randomString();
|
|
51
|
+
const content = randomString();
|
|
52
|
+
return `<${element}>${content}</${element}>`;
|
|
53
|
+
};
|
|
54
|
+
default:
|
|
55
|
+
// c8 ignore next
|
|
56
|
+
throw new Error(`Cannot find random${dataTypeName}() func anywhere`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─── DataType Lookup ────────────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
export function findDataType(dataTypeName: string): DataType {
|
|
63
|
+
const builtInDataTypeName = findBuiltInType(dataTypeName);
|
|
64
|
+
const dataType = DataType[builtInDataTypeName.name as keyof typeof DataType];
|
|
65
|
+
// c8 ignore next
|
|
66
|
+
if (!dataType) {
|
|
67
|
+
throw new Error(` dataType ${dataTypeName} must exists`);
|
|
68
|
+
}
|
|
69
|
+
return dataType;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ─── Validation ─────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
function validate_value_or_array(isArray: boolean, variantValue: unknown, validatorFunc: (v: unknown) => boolean) {
|
|
75
|
+
assert(typeof validatorFunc === "function");
|
|
76
|
+
if (isArray) {
|
|
77
|
+
const arr = variantValue as ArrayLike<unknown>;
|
|
78
|
+
const n = Math.min(10, arr.length);
|
|
79
|
+
for (let i = 0; i < n; i++) {
|
|
80
|
+
// c8 ignore next
|
|
81
|
+
if (!validatorFunc(arr[i])) {
|
|
82
|
+
throw new Error(`default value must be valid for dataType ${variantValue} at index ${i} got ${arr[i]}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// c8 ignore next
|
|
87
|
+
if (!validatorFunc(variantValue)) {
|
|
88
|
+
throw new Error(`default value must be valid for dataType ${variantValue}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ─── Variant Construction ───────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
export function makeVariant(dataTypeName: string, arrayType: VariantArrayType, dimensions: number[] | null, current_value: unknown) {
|
|
96
|
+
const dataType = findDataType(dataTypeName);
|
|
97
|
+
const validatorFunc = getValidatorFuncForType(dataType);
|
|
98
|
+
const isArray = arrayType === VariantArrayType.Array || arrayType === VariantArrayType.Matrix;
|
|
99
|
+
validate_value_or_array(isArray, current_value, validatorFunc);
|
|
100
|
+
|
|
101
|
+
return new Variant({
|
|
102
|
+
dataType,
|
|
103
|
+
arrayType,
|
|
104
|
+
dimensions,
|
|
105
|
+
value: current_value
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ─── Generic Variable Helpers ───────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
export function addVariable(
|
|
112
|
+
namespace: Namespace,
|
|
113
|
+
parent: UAObject,
|
|
114
|
+
varName: string,
|
|
115
|
+
dataTypeName: string,
|
|
116
|
+
current_value: unknown,
|
|
117
|
+
valueRank: number,
|
|
118
|
+
arrayDimensions: number[] | null,
|
|
119
|
+
extra_name: string
|
|
120
|
+
): UAVariable {
|
|
121
|
+
assert(typeof extra_name === "string");
|
|
122
|
+
|
|
123
|
+
const arrayType = valueRank <= 0 ? VariantArrayType.Scalar : valueRank === 1 ? VariantArrayType.Array : VariantArrayType.Matrix;
|
|
124
|
+
const variant = makeVariant(dataTypeName, arrayType, arrayDimensions, current_value);
|
|
125
|
+
const name = varName + extra_name;
|
|
126
|
+
const nodeId = `${parent.nodeId.toString()}_${varName}${extra_name}`;
|
|
127
|
+
const placeholder = { variant };
|
|
128
|
+
|
|
129
|
+
const variable = namespace.addVariable({
|
|
130
|
+
browseName: name,
|
|
131
|
+
componentOf: parent,
|
|
132
|
+
dataType: varName,
|
|
133
|
+
description: { locale: "en", text: name },
|
|
134
|
+
nodeId,
|
|
135
|
+
valueRank,
|
|
136
|
+
arrayDimensions,
|
|
137
|
+
accessLevel: makeAccessLevelFlag("CurrentRead | CurrentWrite"),
|
|
138
|
+
userAccessLevel: makeAccessLevelFlag("CurrentRead | CurrentWrite"),
|
|
139
|
+
value: variant
|
|
140
|
+
});
|
|
141
|
+
(variable as unknown as Record<string, unknown>)._backdoor_placeholder = placeholder;
|
|
142
|
+
return variable;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function addScalarVariable(
|
|
146
|
+
namespace: Namespace,
|
|
147
|
+
parent: UAObject,
|
|
148
|
+
name: string,
|
|
149
|
+
realType: string,
|
|
150
|
+
default_value: unknown,
|
|
151
|
+
extra_name: string
|
|
152
|
+
) {
|
|
153
|
+
assert(typeof extra_name === "string");
|
|
154
|
+
const initialValue = typeof default_value === "function" ? default_value() : default_value;
|
|
155
|
+
const variable = addVariable(namespace, parent, name, realType, initialValue, -1, null, extra_name);
|
|
156
|
+
assert(variable.valueRank === -1);
|
|
157
|
+
assert(variable.accessLevel === AccessLevelFlag.CurrentRead + AccessLevelFlag.CurrentWrite);
|
|
158
|
+
assert(variable.userAccessLevel === AccessLevelFlag.CurrentRead + AccessLevelFlag.CurrentWrite);
|
|
159
|
+
assert(variable.historizing === false);
|
|
160
|
+
return variable;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function addArrayVariable(
|
|
164
|
+
namespace: Namespace,
|
|
165
|
+
parent: UAObject,
|
|
166
|
+
dataTypeName: string,
|
|
167
|
+
default_value: unknown,
|
|
168
|
+
realTypeName: string,
|
|
169
|
+
arrayLength: number,
|
|
170
|
+
extra_name: string
|
|
171
|
+
): void {
|
|
172
|
+
assert(typeof dataTypeName === "string");
|
|
173
|
+
assert(typeof realTypeName === "string");
|
|
174
|
+
|
|
175
|
+
// c8 ignore next
|
|
176
|
+
if (!DataType[realTypeName as keyof typeof DataType]) {
|
|
177
|
+
warningLog("dataTypeName", dataTypeName);
|
|
178
|
+
warningLog("realTypeName", realTypeName);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
assert(DataType[realTypeName as keyof typeof DataType], " expecting a valid real type");
|
|
182
|
+
arrayLength = arrayLength || 10;
|
|
183
|
+
|
|
184
|
+
const local_defaultValue = typeof default_value === "function" ? default_value() : default_value;
|
|
185
|
+
const current_value = buildVariantArray(DataType[realTypeName as keyof typeof DataType], arrayLength, local_defaultValue);
|
|
186
|
+
const variable = addVariable(namespace, parent, dataTypeName, realTypeName, current_value, 1, null, extra_name);
|
|
187
|
+
|
|
188
|
+
assert(variable.valueRank === 1);
|
|
189
|
+
assert(variable.accessLevel === AccessLevelFlag.CurrentRead + AccessLevelFlag.CurrentWrite);
|
|
190
|
+
assert(variable.userAccessLevel === AccessLevelFlag.CurrentRead + AccessLevelFlag.CurrentWrite);
|
|
191
|
+
assert(variable.historizing === false);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function addMultiDimensionalArrayVariable(
|
|
195
|
+
namespace: Namespace,
|
|
196
|
+
parent: UAObject,
|
|
197
|
+
dataTypeName: string,
|
|
198
|
+
default_value: unknown,
|
|
199
|
+
realTypeName: string,
|
|
200
|
+
nbRows: number,
|
|
201
|
+
nbCols: number,
|
|
202
|
+
extra_name: string
|
|
203
|
+
): void {
|
|
204
|
+
assert(typeof dataTypeName === "string");
|
|
205
|
+
assert(typeof realTypeName === "string");
|
|
206
|
+
|
|
207
|
+
// c8 ignore next
|
|
208
|
+
if (!DataType[realTypeName as keyof typeof DataType]) {
|
|
209
|
+
debugLog("dataTypeName", dataTypeName);
|
|
210
|
+
debugLog("realTypeName", realTypeName);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
assert(DataType[realTypeName as keyof typeof DataType], " expecting a valid real type");
|
|
214
|
+
|
|
215
|
+
nbRows = nbRows || 6;
|
|
216
|
+
nbCols = nbCols || 2;
|
|
217
|
+
|
|
218
|
+
const local_defaultValue = typeof default_value === "function" ? default_value() : default_value;
|
|
219
|
+
const current_value = buildVariantArray(DataType[realTypeName as keyof typeof DataType], nbRows * nbCols, local_defaultValue);
|
|
220
|
+
const variable = addVariable(namespace, parent, dataTypeName, realTypeName, current_value, 2, [nbRows, nbCols], extra_name);
|
|
221
|
+
|
|
222
|
+
assert(variable.valueRank === 2);
|
|
223
|
+
assert(variable.accessLevel === AccessLevelFlag.CurrentRead + AccessLevelFlag.CurrentWrite);
|
|
224
|
+
assert(variable.userAccessLevel === AccessLevelFlag.CurrentRead + AccessLevelFlag.CurrentWrite);
|
|
225
|
+
assert(variable.historizing === false);
|
|
226
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mass variables: 100 items per supported data-type.
|
|
3
|
+
*/
|
|
4
|
+
import type { Namespace, UAObject } from "node-opcua-address-space";
|
|
5
|
+
|
|
6
|
+
import { addVariable } from "./helpers";
|
|
7
|
+
import { typeAndDefaultValue } from "./type_defaults";
|
|
8
|
+
|
|
9
|
+
function addMassVariablesOfType(
|
|
10
|
+
namespace: Namespace,
|
|
11
|
+
parent: UAObject,
|
|
12
|
+
dataTypeName: string,
|
|
13
|
+
default_value: unknown,
|
|
14
|
+
realType: string
|
|
15
|
+
): void {
|
|
16
|
+
const nodeName = `Scalar_Mass_${dataTypeName}`;
|
|
17
|
+
|
|
18
|
+
const scalarMass_Type = namespace.addObject({
|
|
19
|
+
browseName: nodeName,
|
|
20
|
+
description: "This folder will contain 100 items per supported data-type.",
|
|
21
|
+
nodeId: `s=${nodeName}`,
|
|
22
|
+
organizedBy: parent
|
|
23
|
+
});
|
|
24
|
+
for (let i = 0; i <= 99; i++) {
|
|
25
|
+
const extra_name = `_${i.toString().padStart(2, "0")}`;
|
|
26
|
+
const local_defaultValue = typeof default_value === "function" ? default_value() : default_value;
|
|
27
|
+
addVariable(namespace, scalarMass_Type, dataTypeName, realType, local_defaultValue, -1, null, extra_name);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function addMassVariables(namespace: Namespace, scalarFolder: UAObject): void {
|
|
32
|
+
const scalarMass = namespace.addFolder(scalarFolder, {
|
|
33
|
+
browseName: "Scalar_Mass",
|
|
34
|
+
description: "This folder will contain 100 items per supported data-type.",
|
|
35
|
+
nodeId: "s=Scalar_Mass"
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
for (const e of typeAndDefaultValue) {
|
|
39
|
+
const realType = e.realType || e.type;
|
|
40
|
+
addMassVariablesOfType(namespace, scalarMass, e.type, e.defaultValue, realType);
|
|
41
|
+
}
|
|
42
|
+
}
|