@t0a5tbr0t/node-red-contrib-opcua 0.1.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/CHANGELOG.md +6 -0
- package/LICENSE +20 -0
- package/Readme.md +239 -0
- package/images/PROSYS-OPC-UA-EXAMPLE2.png +0 -0
- package/images/nodeopcua64.png +0 -0
- package/images/opcuanode.png +0 -0
- package/images/opcuanodeLogo64.png +0 -0
- package/opcua/101-opcuaitem.html +106 -0
- package/opcua/101-opcuaitem.js +82 -0
- package/opcua/102-opcuaclient.html +274 -0
- package/opcua/102-opcuaclient.js +2741 -0
- package/opcua/103-opcuabrowser.html +71 -0
- package/opcua/103-opcuabrowser.js +230 -0
- package/opcua/104-opcuaserver.html +261 -0
- package/opcua/104-opcuaserver.js +1844 -0
- package/opcua/105-opcuaendpoint.html +224 -0
- package/opcua/105-opcuaendpoint.js +64 -0
- package/opcua/106-opcuaevent.html +110 -0
- package/opcua/106-opcuaevent.js +50 -0
- package/opcua/107-opcuamethod.html +244 -0
- package/opcua/107-opcuamethod.js +521 -0
- package/opcua/108-opcuarights.html +223 -0
- package/opcua/108-opcuarights.js +156 -0
- package/opcua/109-opcuadiscovery.html +51 -0
- package/opcua/109-opcuadiscovery.js +180 -0
- package/opcua/dump_certificates.js +55 -0
- package/opcua/icons/opcuanode.png +0 -0
- package/opcua/icons/opcuanodeLogo.png +0 -0
- package/opcua/opcua-basics.js +1061 -0
- package/opcua/public/vendor/opc-foundation/binary/OPC.ISA95.Types.bsd.xml +141 -0
- package/opcua/public/vendor/opc-foundation/binary/Opc.Ua.Adi.Types.bsd.xml +76 -0
- package/opcua/public/vendor/opc-foundation/binary/Opc.Ua.Di.Types.bsd.xml +11 -0
- package/opcua/public/vendor/opc-foundation/binary/Opc.Ua.Gds.Types.bsd.xml +25 -0
- package/opcua/public/vendor/opc-foundation/binary/Opc.Ua.Types.bsd.xml +2391 -0
- package/opcua/public/vendor/opc-foundation/csv/AttributeIds.csv +22 -0
- package/opcua/public/vendor/opc-foundation/csv/NodeIds.csv +5746 -0
- package/opcua/public/vendor/opc-foundation/csv/Opc.Ua.StatusCodes.csv +227 -0
- package/opcua/public/vendor/opc-foundation/csv/OpcUaDiModel.csv +1523 -0
- package/opcua/public/vendor/opc-foundation/csv/OpcUaGdsModel.csv +400 -0
- package/opcua/public/vendor/opc-foundation/csv/ServerCapabilities.csv +13 -0
- package/opcua/public/vendor/opc-foundation/csv/ServerCapabilityIdentifiers.csv +13 -0
- package/opcua/public/vendor/opc-foundation/csv/StatusCode.csv +227 -0
- package/opcua/public/vendor/opc-foundation/csv/StatusCodes.csv +227 -0
- package/opcua/public/vendor/opc-foundation/schema/OPC.ISA95.Types.xsd +163 -0
- package/opcua/public/vendor/opc-foundation/schema/OPCBinarySchema.xsd +119 -0
- package/opcua/public/vendor/opc-foundation/schema/Opc.Ua.Types.xsd +3938 -0
- package/opcua/public/vendor/opc-foundation/schema/SecuredApplication.xsd +106 -0
- package/opcua/public/vendor/opc-foundation/schema/UANodeSet.xsd +420 -0
- package/opcua/public/vendor/opc-foundation/xml/OPC.ISA95.NodeSet2.Nov52013.xml +3293 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.ISA95.NodeSet2.xml +3589 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Adi.NodeSet2.xml +8301 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Adi.Types.bsd.xml +76 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Adi.Types.xsd +157 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.AutoID.NodeSet2.xml +6062 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Di.NodeSet2.xml +5066 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Di.PredefinedNodes.xml +11495 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Di.Types.bsd +86 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Di.Types.bsd.xml +11 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Di.Types.xsd +155 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Gds.NodeSet.xml +15226 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Gds.NodeSet2.xml +6214 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Gds.Types.bsd.xml +25 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.Gds.Types.xsd +30 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet-2.xml +134881 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet-3.xml +134881 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet.xml +134881 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part10.xml +832 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part11.xml +793 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part12.xml +3877 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part13.xml +344 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part3.xml +1103 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part4.xml +3091 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part5.xml +17092 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part8.xml +525 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part9.xml +2049 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.Part999.xml +134 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.xml +67169 -0
- package/opcua/public/vendor/opc-foundation/xml/Opc.Ua.PredefinedNodes.xml +64500 -0
- package/opcua/public/vendor/opc-foundation/xml/OpcUaDiModel.xml +1239 -0
- package/opcua/utils.js +55 -0
- package/package.json +68 -0
- package/users.json +22 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
|
|
3
|
+
Copyright 2022 Valmet Automation Inc.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
|
|
17
|
+
-->
|
|
18
|
+
|
|
19
|
+
<script type="text/javascript">
|
|
20
|
+
RED.nodes.registerType('OpcUa-Rights', {
|
|
21
|
+
category: "opcua",
|
|
22
|
+
color:"#3FADB5",
|
|
23
|
+
defaults: {
|
|
24
|
+
accessLevelCurrentRead: {value: true},
|
|
25
|
+
accessLevelCurrentWrite: {value: true},
|
|
26
|
+
accessLevelStatusWrite: {value: true},
|
|
27
|
+
accessLevelHistoryRead: {value: true},
|
|
28
|
+
accessLevelHistoryWrite: {value: true},
|
|
29
|
+
accessLevelSemanticChange: {value: true},
|
|
30
|
+
role: {value: "a"}, // User Role like Anonymous, Operator, Engineer,...
|
|
31
|
+
// Permissions
|
|
32
|
+
permissionBrowse: {value: true},
|
|
33
|
+
permissionRead: {value: true},
|
|
34
|
+
permissionWrite: {value: true},
|
|
35
|
+
permissionWriteAttribute: {value: true},
|
|
36
|
+
permissionReadRole: {value: true},
|
|
37
|
+
permissionWriteRole: {value: true},
|
|
38
|
+
permissionReadHistory: {value: true},
|
|
39
|
+
permissionWriteHistory: {value: true},
|
|
40
|
+
permissionInsertHistory: {value: true},
|
|
41
|
+
permissionModifyHistory: {value: true},
|
|
42
|
+
permissionDeleteHistory: {value: true},
|
|
43
|
+
permissionReceiveEvents: {value: true},
|
|
44
|
+
permissionCall: {value: true},
|
|
45
|
+
permissionAddReference: {value: true},
|
|
46
|
+
permissionRemoveReference: {value: true},
|
|
47
|
+
permissionDeleteNode: {value: true},
|
|
48
|
+
permissionAddNode: {value: true},
|
|
49
|
+
name: {value: ""},
|
|
50
|
+
},
|
|
51
|
+
inputs: 1,
|
|
52
|
+
outputs: 1,
|
|
53
|
+
align: "right",
|
|
54
|
+
icon: "opcuanodeLogo.png",
|
|
55
|
+
label: function () {
|
|
56
|
+
return this.name || "OPC UA Rights";
|
|
57
|
+
},
|
|
58
|
+
labelStyle: function () {
|
|
59
|
+
return this.name ? "node_label_italic" : "";
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<script type="text/x-red" data-template-name="OpcUa-Rights">
|
|
65
|
+
<div class="form-row">
|
|
66
|
+
<label for="node-input-accessLevelCurrentRead" style="width:72%;"><i class="icon-tasks"></i> Access level: read</label>
|
|
67
|
+
<input type="checkbox" id="node-input-accessLevelCurrentRead" style="max-width:20px">
|
|
68
|
+
</div>
|
|
69
|
+
<div class="form-row">
|
|
70
|
+
<label for="node-input-accessLevelCurrentWrite" style="width:72%;"><i class="icon-tasks"></i> Access level: write</label>
|
|
71
|
+
<input type="checkbox" id="node-input-accessLevelCurrentWrite" style="max-width:20px">
|
|
72
|
+
</div>
|
|
73
|
+
<div class="form-row">
|
|
74
|
+
<label for="node-input-accessLevelStatusWrite" style="width:72%;"><i class="icon-tasks"></i> Access level: status write</label>
|
|
75
|
+
<input type="checkbox" id="node-input-accessLevelStatusWrite" style="max-width:20px">
|
|
76
|
+
</div>
|
|
77
|
+
<div class="form-row">
|
|
78
|
+
<label for="node-input-accessLevelHistoryRead" style="width:72%;"><i class="icon-tasks"></i> Access level: history read</label>
|
|
79
|
+
<input type="checkbox" id="node-input-accessLevelHistoryRead" style="max-width:20px">
|
|
80
|
+
</div>
|
|
81
|
+
<div class="form-row">
|
|
82
|
+
<label for="node-input-accessLevelHistoryWrite" style="width:72%;"><i class="icon-tasks"></i> Access level: history write</label>
|
|
83
|
+
<input type="checkbox" id="node-input-accessLevelHistoryWrite" style="max-width:20px">
|
|
84
|
+
</div>
|
|
85
|
+
<div class="form-row">
|
|
86
|
+
<label for="node-input-accessLevelSemanticChange" style="width:72%;"><i class="icon-tasks"></i> Access level: semantic change</label>
|
|
87
|
+
<input type="checkbox" id="node-input-accessLevelSemanticChange" style="max-width:20px">
|
|
88
|
+
</div>
|
|
89
|
+
<hr>
|
|
90
|
+
<div class="form-row">
|
|
91
|
+
<label for="node-input-role"><i class="icon-time"></i> User role</label>
|
|
92
|
+
<select type="text" id="node-input-role" style="max-width:160px">
|
|
93
|
+
<option value="a">Anonymous</option>
|
|
94
|
+
<option value="u">Authenticated user</option>
|
|
95
|
+
<option value="b">Observer</option>
|
|
96
|
+
<option value="e">Engineer</option>
|
|
97
|
+
<option value="o">Operator</option>
|
|
98
|
+
<option value="c">Configure admin</option>
|
|
99
|
+
<option value="s">Security admin</option>
|
|
100
|
+
<option value="v">Supervisor</option>
|
|
101
|
+
</select>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="form-row">
|
|
104
|
+
<label for="node-input-permissionBrowse" style="width:72%;"><i class="icon-tasks"></i> Permission: browse</label>
|
|
105
|
+
<input type="checkbox" id="node-input-permissionBrowse" style="max-width:20px">
|
|
106
|
+
</div>
|
|
107
|
+
<div class="form-row">
|
|
108
|
+
<label for="node-input-permissionRead" style="width:72%;"><i class="icon-tasks"></i> Permission: read</label>
|
|
109
|
+
<input type="checkbox" id="node-input-permissionRead" style="max-width:20px">
|
|
110
|
+
</div>
|
|
111
|
+
<div class="form-row">
|
|
112
|
+
<label for="node-input-permissionWrite" style="width:72%;"><i class="icon-tasks"></i> Permission: write</label>
|
|
113
|
+
<input type="checkbox" id="node-input-permissionWrite" style="max-width:20px">
|
|
114
|
+
</div>
|
|
115
|
+
<div class="form-row">
|
|
116
|
+
<label for="node-input-permissionWriteAttribute" style="width:72%;"><i class="icon-tasks"></i> Permission: write attribute</label>
|
|
117
|
+
<input type="checkbox" id="node-input-permissionWriteAttribute" style="max-width:20px">
|
|
118
|
+
</div>
|
|
119
|
+
<div class="form-row">
|
|
120
|
+
<label for="node-input-permissionReadRole" style="width:72%;"><i class="icon-tasks"></i> Permission: read role</label>
|
|
121
|
+
<input type="checkbox" id="node-input-permissionReadRole" style="max-width:20px">
|
|
122
|
+
</div>
|
|
123
|
+
<div class="form-row">
|
|
124
|
+
<label for="node-input-permissionWriteRole" style="width:72%;"><i class="icon-tasks"></i> Permission: write role</label>
|
|
125
|
+
<input type="checkbox" id="node-input-permissionWriteRole" style="max-width:20px">
|
|
126
|
+
</div>
|
|
127
|
+
<div class="form-row">
|
|
128
|
+
<label for="node-input-permissionReadHistory" style="width:72%;"><i class="icon-tasks"></i> Permission: read history</label>
|
|
129
|
+
<input type="checkbox" id="node-input-permissionReadHistory" style="max-width:20px">
|
|
130
|
+
</div>
|
|
131
|
+
<div class="form-row">
|
|
132
|
+
<label for="node-input-permissionWriteHistory" style="width:72%;"><i class="icon-tasks"></i> Permission: write history</label>
|
|
133
|
+
<input type="checkbox" id="node-input-permissionWriteHistory" style="max-width:20px">
|
|
134
|
+
</div>
|
|
135
|
+
<div class="form-row">
|
|
136
|
+
<label for="node-input-permissionInsertHistory" style="width:72%;"><i class="icon-tasks"></i> Permission: insert history</label>
|
|
137
|
+
<input type="checkbox" id="node-input-permissionInsertHistory" style="max-width:20px">
|
|
138
|
+
</div>
|
|
139
|
+
<div class="form-row">
|
|
140
|
+
<label for="node-input-permissionModifyHistory" style="width:72%;"><i class="icon-tasks"></i> Permission: modify history</label>
|
|
141
|
+
<input type="checkbox" id="node-input-permissionModifyHistory" style="max-width:20px">
|
|
142
|
+
</div>
|
|
143
|
+
<div class="form-row">
|
|
144
|
+
<label for="node-input-permissionDeleteHistory" style="width:72%;"><i class="icon-tasks"></i> Permission: delete history</label>
|
|
145
|
+
<input type="checkbox" id="node-input-permissionDeleteHistory" style="max-width:20px">
|
|
146
|
+
</div>
|
|
147
|
+
<div class="form-row">
|
|
148
|
+
<label for="node-input-permissionReceiveEvents" style="width:72%;"><i class="icon-tasks"></i> Permission: receive events</label>
|
|
149
|
+
<input type="checkbox" id="node-input-permissionReceiveEvents" style="max-width:20px">
|
|
150
|
+
</div>
|
|
151
|
+
<div class="form-row">
|
|
152
|
+
<label for="node-input-permissionCall" style="width:72%;"><i class="icon-tasks"></i> Permission: call methods</label>
|
|
153
|
+
<input type="checkbox" id="node-input-permissionCall" style="max-width:20px">
|
|
154
|
+
</div>
|
|
155
|
+
<div class="form-row">
|
|
156
|
+
<label for="node-input-permissionAddReference" style="width:72%;"><i class="icon-tasks"></i> Permission: add reference</label>
|
|
157
|
+
<input type="checkbox" id="node-input-permissionAddReference" style="max-width:20px">
|
|
158
|
+
</div>
|
|
159
|
+
<div class="form-row">
|
|
160
|
+
<label for="node-input-permissionRemoveReference" style="width:72%;"><i class="icon-tasks"></i> Permission: remove reference</label>
|
|
161
|
+
<input type="checkbox" id="node-input-permissionRemoveReference" style="max-width:20px">
|
|
162
|
+
</div>
|
|
163
|
+
<div class="form-row">
|
|
164
|
+
<label for="node-input-permissionDeleteNode" style="width:72%;"><i class="icon-tasks"></i> Permission: delete node</label>
|
|
165
|
+
<input type="checkbox" id="node-input-permissionDeleteNode" style="max-width:20px">
|
|
166
|
+
</div>
|
|
167
|
+
<div class="form-row">
|
|
168
|
+
<label for="node-input-permissionAddNode" style="width:72%;"><i class="icon-tasks"></i> Permission: add node</label>
|
|
169
|
+
<input type="checkbox" id="node-input-permissionAddNode" style="max-width:20px">
|
|
170
|
+
</div>
|
|
171
|
+
<hr>
|
|
172
|
+
<div class="form-row">
|
|
173
|
+
<label for="node-input-name"><i class="icon-tag"></i>Name</label>
|
|
174
|
+
<input type="text" id="node-input-name" placeholder="">
|
|
175
|
+
</div>
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<script type="text/x-red" data-help-name="OpcUa-Rights">
|
|
179
|
+
<p>Set object / variable access level, user access level and permissions</p>
|
|
180
|
+
<h2>Access rights</h2>
|
|
181
|
+
<h3>Access level parameters inside node</h3>
|
|
182
|
+
<ul>
|
|
183
|
+
<li>CurrentRead
|
|
184
|
+
<li>CurrentWrite
|
|
185
|
+
<li>StatusWrite
|
|
186
|
+
<li>HistoryRead
|
|
187
|
+
<li>HistoryWrite
|
|
188
|
+
<li>SemanticChange
|
|
189
|
+
</ul>
|
|
190
|
+
<h2>User role, only well known roles available</h2>
|
|
191
|
+
<ul>
|
|
192
|
+
<li>Anonymous
|
|
193
|
+
<li>Authenticated user; username & password
|
|
194
|
+
<li>Observer
|
|
195
|
+
<li>Engineer
|
|
196
|
+
<li>Operator
|
|
197
|
+
<li>Configure admin
|
|
198
|
+
<li>Security admin
|
|
199
|
+
<li>Supervisor
|
|
200
|
+
</ul>
|
|
201
|
+
<h3>Permissions</h3>
|
|
202
|
+
<ul>
|
|
203
|
+
<li>Browse
|
|
204
|
+
<li>Read
|
|
205
|
+
<li>Write
|
|
206
|
+
<li>Write attribute
|
|
207
|
+
<li>Read role
|
|
208
|
+
<li>Write role
|
|
209
|
+
<li>Read history
|
|
210
|
+
<li>Write history
|
|
211
|
+
<li>Insert history
|
|
212
|
+
<li>Modify history
|
|
213
|
+
<li>Delete history
|
|
214
|
+
<li>Receive events
|
|
215
|
+
<li>Call methods
|
|
216
|
+
<li>Add reference
|
|
217
|
+
<li>Remove reference
|
|
218
|
+
<li>Delete node
|
|
219
|
+
<li>Add node
|
|
220
|
+
</ul>
|
|
221
|
+
<strong>Name</strong>
|
|
222
|
+
<p>Name in the flow of Node-RED.</p>
|
|
223
|
+
</script>
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
|
|
3
|
+
Copyright 2022 Valmet Automation Inc.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
|
|
17
|
+
**/
|
|
18
|
+
|
|
19
|
+
'use strict'
|
|
20
|
+
|
|
21
|
+
// const { WellKnownRoles } = require("node-opcua");
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* OPC UA rights node representation for Node-RED to add msg object OPC UA access rights, role and permissions
|
|
25
|
+
*
|
|
26
|
+
* @param RED
|
|
27
|
+
*/
|
|
28
|
+
module.exports = function (RED) {
|
|
29
|
+
var opcua = require('node-opcua');
|
|
30
|
+
const chalk = require("chalk");
|
|
31
|
+
function OPCUARightsNode(n) {
|
|
32
|
+
RED.nodes.createNode(this, n)
|
|
33
|
+
this.name = n.name;
|
|
34
|
+
this.accessLevelCurrentRead = n.accessLevelCurrentRead;
|
|
35
|
+
this.accessLevelCurrentWrite = n.accessLevelCurrentWrite;
|
|
36
|
+
this.accessLevelStatusWrite = n.accessLevelStatusWrite;
|
|
37
|
+
this.accessLevelHistoryRead = n.accessLevelHistoryRead;
|
|
38
|
+
this.accessLevelHistoryWrite = n.accessLevelHistoryWrite;
|
|
39
|
+
this.accessLevelSemanticChange = n.accessLevelSemanticChange;
|
|
40
|
+
this.role = n.role;
|
|
41
|
+
// TODO Permissions
|
|
42
|
+
this.permissionBrowse = n.permissionBrowse;
|
|
43
|
+
this.permissionRead = n.permissionRead;
|
|
44
|
+
this.permissionWrite = n.permissionWrite;
|
|
45
|
+
this.permissionWriteAttribute = n.permissionWriteAttribute;
|
|
46
|
+
this.permissionReadRole = n.permissionReadRole;
|
|
47
|
+
this.permissionWriteRole = n.permissionWriteRole;
|
|
48
|
+
this.permissionReadHistory = n.permissionReadHistory;
|
|
49
|
+
this.permissionWriteHistory = n.permissionWriteHistory;
|
|
50
|
+
this.permissionInsertHistory = n.permissionInsertHistory;
|
|
51
|
+
this.permissionModifyHistory = n.permissionModifyHistory;
|
|
52
|
+
this.permissionDeleteHistory = n.permissionDeleteHistory;
|
|
53
|
+
this.permissionReceiveEvents = n.permissionReceiveEvents;
|
|
54
|
+
this.permissionCall = n.permissionCall;
|
|
55
|
+
this.permissionAddReference = n.permissionAddReference;
|
|
56
|
+
this.permissionRemoveReference = n.permissionRemoveReference;
|
|
57
|
+
this.permissionDeleteNode = n.permissionDeleteNode;
|
|
58
|
+
this.permissionAddNode = n.permissionAddNode;
|
|
59
|
+
var node = this;
|
|
60
|
+
|
|
61
|
+
node.debug(chalk.yellow("Node parameters: ") + chalk.cyan(JSON.stringify(node)));
|
|
62
|
+
|
|
63
|
+
node.on("input", function (msg) {
|
|
64
|
+
// This node will extend new field to msg so addVariable can set needed access level and permissions
|
|
65
|
+
// From the selected values
|
|
66
|
+
// TODO
|
|
67
|
+
var levelString = "";
|
|
68
|
+
if (node.accessLevelCurrentRead === true) levelString += "CurrentRead |";
|
|
69
|
+
if (node.accessLevelCurrentWrite === true) levelString += " CurrentWrite |";
|
|
70
|
+
if (node.accessLevelStatusWrite === true) levelString += " StatusWrite |";
|
|
71
|
+
if (node.accessLevelHistoryRead === true) levelString += " HistoryRead |";
|
|
72
|
+
if (node.accessLevelHistoryWrite === true) levelString += " HistoryWrite |";
|
|
73
|
+
if (node.accessLevelSemanticChange === true) levelString += " SemanticChange";
|
|
74
|
+
console.log("Access level string: " + levelString);
|
|
75
|
+
var accessLevel = opcua.makeAccessLevelFlag(levelString);
|
|
76
|
+
var userAccessLevel = opcua.makeAccessLevelFlag(levelString);
|
|
77
|
+
// var accessLevel = opcua.makeAccessLevelFlag("CurrentRead | CurrentWrite | StatusWrite | HistoryRead | HistoryWrite | SemanticChange");
|
|
78
|
+
// var userAccessLevel = opcua.makeAccessLevelFlag("CurrentRead | CurrentWrite | StatusWrite | HistoryRead | HistoryWrite | SemanticChange");
|
|
79
|
+
msg.accessLevel = accessLevel;
|
|
80
|
+
msg.userAccessLevel = userAccessLevel; // Uses same, TODO add option to select which one to use
|
|
81
|
+
msg.accessRestrictions = opcua.AccessRestrictionsFlag.None; // TODO extend when needed
|
|
82
|
+
console.log("Access level: " + msg.accessLevel + " user access level: " + msg.userAccessLevel + " restrictions: " + msg.accessRestrictions);
|
|
83
|
+
|
|
84
|
+
// TODO node.role == "a" Anonymous etc.
|
|
85
|
+
let role;
|
|
86
|
+
if (node.role === "a") {
|
|
87
|
+
role = opcua.WellKnownRoles.Anonymous;
|
|
88
|
+
}
|
|
89
|
+
if (node.role === "u") {
|
|
90
|
+
role = opcua.WellKnownRoles.AuthenticatedUser;
|
|
91
|
+
}
|
|
92
|
+
if (node.role === "e") {
|
|
93
|
+
role = opcua.WellKnownRoles.Engineer;
|
|
94
|
+
}
|
|
95
|
+
if (node.role === "b") {
|
|
96
|
+
role = opcua.WellKnownRoles.Observer;
|
|
97
|
+
}
|
|
98
|
+
if (node.role === "o") {
|
|
99
|
+
role = opcua.WellKnownRoles.Operator;
|
|
100
|
+
}
|
|
101
|
+
if (node.role === "c") {
|
|
102
|
+
role = opcua.WellKnownRoles.ConfigureAdmin;
|
|
103
|
+
}
|
|
104
|
+
if (node.role === "s") {
|
|
105
|
+
role = opcua.WellKnownRoles.SecurityAdmin;
|
|
106
|
+
}
|
|
107
|
+
if (node.role === "v") {
|
|
108
|
+
role = opcua.WellKnownRoles.Supervisor;
|
|
109
|
+
}
|
|
110
|
+
console.log("Role: " + role + " selection was " + node.role);
|
|
111
|
+
|
|
112
|
+
// Collect multiple role permissions together
|
|
113
|
+
let permissionString = "";
|
|
114
|
+
if (node.permissionBrowse === true) permissionString += "Browse |";
|
|
115
|
+
if (node.permissionRead === true) permissionString += " Read |";
|
|
116
|
+
if (node.permissionWrite === true) permissionString += " Write |";
|
|
117
|
+
if (node.permissionWriteAttribute === true) permissionString += " WriteAttribute |";
|
|
118
|
+
if (node.permissionReadRole === true) permissionString += " ReadRolePermissions |";
|
|
119
|
+
if (node.permissionWriteRole === true) permissionString += " WriteRolePermissions |";
|
|
120
|
+
if (node.permissionReadHistory === true) permissionString += " ReadHistory |";
|
|
121
|
+
if (node.permissionWriteHistory === true) permissionString += " WriteHistorizing |";
|
|
122
|
+
if (node.permissionInsertHistory === true) permissionString += " InsertHistory |";
|
|
123
|
+
if (node.permissionModifyHistory === true) permissionString += " ModifyHistory |";
|
|
124
|
+
if (node.permissionDeleteHistory === true) permissionString += " DeleteHistory |";
|
|
125
|
+
if (node.permissionReceiveEvents === true) permissionString += " ReceiveEvents |";
|
|
126
|
+
if (node.permissionCall === true) permissionString += " Call |";
|
|
127
|
+
if (node.permissionAddReference === true) permissionString += " AddReference |";
|
|
128
|
+
if (node.permissionRemoveReference === true) permissionString += " RemoveReference |";
|
|
129
|
+
if (node.permissionDeleteNode === true) permissionString += " DeleteNode |";
|
|
130
|
+
if (node.permissionAddNode === true) permissionString += " AddNode";
|
|
131
|
+
console.log("Permission string: " + permissionString);
|
|
132
|
+
const permissionFlag = opcua. makePermissionFlag(permissionString);
|
|
133
|
+
console.log("Permission flag: " + permissionFlag);
|
|
134
|
+
if (msg.permissions && Array.isArray(msg.permissions)) {
|
|
135
|
+
var merged = msg.permissions.concat([{ roleId: role, permissions: permissionFlag }]);
|
|
136
|
+
console.log("Concatenated permissions: " + JSON.stringify(merged));
|
|
137
|
+
msg.permissions = merged;
|
|
138
|
+
// msg.permissions.concat([{ roleId: opcua.WellKnownRoles.Anonymous, permissions: opcua.allPermissions }]);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Current node
|
|
142
|
+
msg.permissions = [{ roleId: role, permissions: permissionFlag }];
|
|
143
|
+
}
|
|
144
|
+
console.log("Permissions: " + JSON.stringify(msg.permissions));
|
|
145
|
+
|
|
146
|
+
node.send(msg);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
node.on("close", function () {
|
|
150
|
+
console.log("Closed");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
RED.nodes.registerType("OpcUa-Rights", OPCUARightsNode);
|
|
156
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
|
|
3
|
+
Copyright 2023 Valmet Automation Inc.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
|
|
17
|
+
-->
|
|
18
|
+
|
|
19
|
+
<script type="text/javascript">
|
|
20
|
+
RED.nodes.registerType('OpcUa-Discovery',{
|
|
21
|
+
category: 'opcua',
|
|
22
|
+
color:"#3FADB5",
|
|
23
|
+
defaults: {
|
|
24
|
+
name: {value:""}
|
|
25
|
+
},
|
|
26
|
+
inputs:1,
|
|
27
|
+
outputs:1,
|
|
28
|
+
align: "right",
|
|
29
|
+
icon: "opcuanodeLogo.png",
|
|
30
|
+
label: function() {
|
|
31
|
+
return this.name || "OPC UA Discovery";
|
|
32
|
+
},
|
|
33
|
+
labelStyle: function() {
|
|
34
|
+
return this.name?"node_label_italic":"";
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<script type="text/x-red" data-template-name="OpcUa-Discovery">
|
|
40
|
+
<div class="form-row">
|
|
41
|
+
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
42
|
+
<input type="text" id="node-input-name" placeholder="">
|
|
43
|
+
</div>
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<script type="text/x-red" data-help-name="OpcUa-Discovery">
|
|
47
|
+
<p>OPC UA Discovery server for the OPC UA Servers to register themselves.</p>
|
|
48
|
+
<p>UAExpert and other OPC UA Clients can look available servers from the discovery server.</p>
|
|
49
|
+
<p>NOTE: You can check port status on Windows with command: netstat -ano | findstr :4840</p>
|
|
50
|
+
<p> UaExpert can be listening port and then you will get error message: 'port is in use'</p>
|
|
51
|
+
</script>
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
|
|
3
|
+
Copyright 2023 Valmet Automation Inc.
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
|
16
|
+
|
|
17
|
+
**/
|
|
18
|
+
|
|
19
|
+
'use strict'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* OPC UA Discovery server uses default port 4840 for the discovery
|
|
24
|
+
*
|
|
25
|
+
* @param RED
|
|
26
|
+
*/
|
|
27
|
+
module.exports = function (RED) {
|
|
28
|
+
const opcua = require('node-opcua');
|
|
29
|
+
const utils = require("./utils");
|
|
30
|
+
const path = require('path');
|
|
31
|
+
const os = require('os');
|
|
32
|
+
const chalk = require("chalk");
|
|
33
|
+
|
|
34
|
+
function OPCUADiscoveryNode(n) {
|
|
35
|
+
RED.nodes.createNode(this, n)
|
|
36
|
+
this.name = n.name;
|
|
37
|
+
var node = this;
|
|
38
|
+
var xmlFiles = [path.join(__dirname, 'public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.xml')]; // Standard & basic types
|
|
39
|
+
|
|
40
|
+
const certificateManager = new opcua.OPCUACertificateManager({
|
|
41
|
+
rootFolder: path.join(path.dirname(__dirname), "./Discovery"), // Own PKI storage for discovery LDS certificates
|
|
42
|
+
automaticallyAcceptUnknownCertificate: true // TODO implement configuration / argument option to turn this on/off
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const server_options = {
|
|
46
|
+
port: 4840,
|
|
47
|
+
// resourcePath: "UADiscovery", // Do not use this, most of servers / client expect discovery is on port 4840 directly
|
|
48
|
+
nodeset_filename: xmlFiles,
|
|
49
|
+
buildInfo: {
|
|
50
|
+
buildNumber: "",
|
|
51
|
+
buildDate: ""
|
|
52
|
+
},
|
|
53
|
+
serverCapabilities: {
|
|
54
|
+
maxBrowseContinuationPoints: 10,
|
|
55
|
+
maxHistoryContinuationPoints: 10,
|
|
56
|
+
maxSessions: 20
|
|
57
|
+
},
|
|
58
|
+
serverInfo: {
|
|
59
|
+
applicationUri: opcua.makeApplicationUrn(os.hostname(), "Node-Red-OPCUA-Discovery"),
|
|
60
|
+
productUri: "Node-Red-OPCUA-Discovery",
|
|
61
|
+
applicationName: {
|
|
62
|
+
text: "Node-Red-OPCUA-Discovery",
|
|
63
|
+
locale: "en"
|
|
64
|
+
},
|
|
65
|
+
gatewayServerUri: null,
|
|
66
|
+
discoveryProfileUri: null,
|
|
67
|
+
discoveryUrls: []
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
server_options.buildInfo = {
|
|
72
|
+
buildNumber: "0.2.300",
|
|
73
|
+
buildDate: "2023-03-13T16:30:00"
|
|
74
|
+
};
|
|
75
|
+
const server = new opcua.OPCUADiscoveryServer(server_options);
|
|
76
|
+
const hostname = os.hostname();
|
|
77
|
+
node.debug(" server host :" + chalk.cyan(hostname));
|
|
78
|
+
node.debug(" server PID :" + chalk.cyan(process.pid));
|
|
79
|
+
(async () => {
|
|
80
|
+
try {
|
|
81
|
+
await certificateManager.initialize();
|
|
82
|
+
await server.start(function (err) {
|
|
83
|
+
if (err) {
|
|
84
|
+
node.status({
|
|
85
|
+
fill: "red",
|
|
86
|
+
shape: "ring",
|
|
87
|
+
text: "Not running, error: " + err
|
|
88
|
+
});
|
|
89
|
+
node.error("Server failed to start... error: ", err);
|
|
90
|
+
node.error("In Windows you can check port status with command: netstat -ano | findstr :4840");
|
|
91
|
+
node.error("UaExpert can be running and listening port");
|
|
92
|
+
// process.exit(-3);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
node.debug(" server on port :" + chalk.cyan(server.endpoints[0].port.toString()));
|
|
96
|
+
node.debug(" serverInfo :");
|
|
97
|
+
node.debug(chalk.cyan(JSON.stringify(server.serverInfo)));
|
|
98
|
+
node.debug("Discovery server now waiting for server register calls. CTRL+C to stop");
|
|
99
|
+
node.status({
|
|
100
|
+
fill: "green",
|
|
101
|
+
shape: "dot",
|
|
102
|
+
text: "Discovery on port: " + server.endpoints[0].port.toString()
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
server.on("response", (response) => {
|
|
106
|
+
node.debug(
|
|
107
|
+
// "Time: ", response.responseHeader.timestamp, " handle: ", response.responseHeader.requestHandle,
|
|
108
|
+
// Show messages
|
|
109
|
+
" request: " + response.schema.name +
|
|
110
|
+
" status: " + response.responseHeader.serviceResult.toString()
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
server.on(
|
|
115
|
+
"request",
|
|
116
|
+
(request, channel) => {
|
|
117
|
+
node.debug(
|
|
118
|
+
// "Time: ", request.requestHeader.timestamp,
|
|
119
|
+
// " handle: ", request.requestHeader.requestHandle,
|
|
120
|
+
" request: " + request.schema.name,
|
|
121
|
+
// " channel ID: ", channel.channelId.toString()
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
} catch (err) {
|
|
127
|
+
node.error("Cannot start server, error: ", err);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
})();
|
|
131
|
+
|
|
132
|
+
// List servers registered to discovery
|
|
133
|
+
node.on("input", function (msg) {
|
|
134
|
+
const discovery_server_endpointUrl = "opc.tcp://localhost:4840";
|
|
135
|
+
const allservers = [];
|
|
136
|
+
node.debug("Interrogating ", discovery_server_endpointUrl);
|
|
137
|
+
(async () => {
|
|
138
|
+
try {
|
|
139
|
+
const { servers, endpoints } = await opcua.findServers(discovery_server_endpointUrl);
|
|
140
|
+
// Servers on network
|
|
141
|
+
node.debug("--------------------------------------------------------------");
|
|
142
|
+
for (const server of servers) {
|
|
143
|
+
node.debug(" applicationUri:", chalk.cyan.bold(server.applicationUri));
|
|
144
|
+
node.debug(" productUri:", chalk.cyan.bold(server.productUri));
|
|
145
|
+
node.debug(" applicationName:", chalk.cyan.bold(server.applicationName.text));
|
|
146
|
+
// node.debug(" type:", chalk.cyan.bold(ApplicationType[server.applicationType]));
|
|
147
|
+
node.debug(" gatewayServerUri:", server.gatewayServerUri ? chalk.cyan.bold(server.gatewayServerUri) : "");
|
|
148
|
+
node.debug("discoveryProfileUri:", server.discoveryProfileUri ? chalk.cyan.bold(server.discoveryProfileUri) : "");
|
|
149
|
+
node.debug(" discoveryUrls:");
|
|
150
|
+
for (const discoveryUrl of server.discoveryUrls) {
|
|
151
|
+
node.debug(" " + chalk.cyan.bold(discoveryUrl));
|
|
152
|
+
allservers.push(discoveryUrl);
|
|
153
|
+
}
|
|
154
|
+
node.debug("--------------------------------------------------------------");
|
|
155
|
+
}
|
|
156
|
+
// Registered server endpoints
|
|
157
|
+
for (const endpoint of endpoints) {
|
|
158
|
+
node.debug(endpoint.endpointUrl.toString(), endpoint.securityLevel, endpoint.securityPolicyUri, endpoint.securityMode);
|
|
159
|
+
// allservers.push(endpoint);
|
|
160
|
+
}
|
|
161
|
+
// node.debug("Registered servers: " + JSON.stringify(allservers));
|
|
162
|
+
msg.payload = allservers;
|
|
163
|
+
node.send(msg);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
node.debug("err ", err.message);
|
|
166
|
+
// process.exit(-2);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
})();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
node.on("close", function () {
|
|
173
|
+
server.shutdown(() => {
|
|
174
|
+
node.debug(" shutting down completed ");
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
RED.nodes.registerType("OpcUa-Discovery", OPCUADiscoveryNode);
|
|
180
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const { crypto_utils } = require("node-opcua");
|
|
4
|
+
|
|
5
|
+
exports.dumpCertificates = async function dumpCertificates(client) {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
|
|
10
|
+
const endpoints = await client.getEndpoints();
|
|
11
|
+
var i = 0;
|
|
12
|
+
endpoints.forEach(function (endpoint, i) {
|
|
13
|
+
/*
|
|
14
|
+
verbose_log("endpoint " + endpoint.endpointUrl + "");
|
|
15
|
+
verbose_log("Application URI " + endpoint.server.applicationUri);
|
|
16
|
+
verbose_log("Product URI " + endpoint.server.productUri);
|
|
17
|
+
verbose_log("Application Name " + endpoint.server.applicationName.text);
|
|
18
|
+
*/
|
|
19
|
+
var applicationName = endpoint.server.applicationName.text;
|
|
20
|
+
if (!applicationName) {
|
|
21
|
+
applicationName = "OPCUA_Server";
|
|
22
|
+
}
|
|
23
|
+
/*
|
|
24
|
+
verbose_log("Security Mode " + endpoint.securityMode.toString());
|
|
25
|
+
verbose_log("securityPolicyUri " + endpoint.securityPolicyUri);
|
|
26
|
+
verbose_log("Type " + endpoint.server.applicationType);
|
|
27
|
+
*/
|
|
28
|
+
// verbose_log("certificate " + "..." + " endpoint.serverCertificate");
|
|
29
|
+
endpoint.server.discoveryUrls = endpoint.server.discoveryUrls || [];
|
|
30
|
+
// verbose_log("discoveryUrls " + endpoint.server.discoveryUrls.join(" - "));
|
|
31
|
+
serverCertificate = endpoint.serverCertificate;
|
|
32
|
+
// Use applicationName instead of fixed server_certificate
|
|
33
|
+
var certificate_filename = path.join(__dirname, "../../PKI/" + applicationName + i + ".pem");
|
|
34
|
+
if (serverCertificate) {
|
|
35
|
+
fs.writeFileSync(certificate_filename, crypto_utils.toPem(serverCertificate, "CERTIFICATE"));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
endpoints.forEach(function (endpoint) {
|
|
40
|
+
// verbose_log("Identify Token for : Security Mode= " + endpoint.securityMode.toString(), " Policy=", endpoint.securityPolicyUri);
|
|
41
|
+
endpoint.userIdentityTokens.forEach(function (token) {
|
|
42
|
+
/*
|
|
43
|
+
verbose_log("policyId " + token.policyId);
|
|
44
|
+
verbose_log("tokenType " + token.tokenType.toString());
|
|
45
|
+
verbose_log("issuedTokenType " + token.issuedTokenType);
|
|
46
|
+
verbose_log("issuerEndpointUrl " + token.issuerEndpointUrl);
|
|
47
|
+
verbose_log("securityPolicyUri " + token.securityPolicyUri);
|
|
48
|
+
*/
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
} catch(err) {
|
|
52
|
+
console.log(err);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
Binary file
|
|
Binary file
|