@vitormnm/node-red-simple-opcua 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/client/icons/opcua.svg +132 -132
- package/client/lib/opcua-client-browser.js +330 -330
- package/client/lib/opcua-client-method-service.js +88 -88
- package/client/lib/opcua-client-read-service.js +15 -15
- package/client/lib/opcua-client-subscription-id-service.js +24 -24
- package/client/lib/opcua-client-subscription-service.js +170 -170
- package/client/lib/opcua-client-write-service.js +146 -146
- package/client/opcua-client-config.html +80 -80
- package/client/opcua-client.html +140 -140
- package/client/opcua-client.js +1 -7
- package/client/view/opcua-client.js +1140 -1140
- package/icons/opcua.svg +132 -132
- package/icons/opcua2.svg +132 -132
- package/package.json +42 -42
- package/resources/bmc-button.svg +22 -0
- package/server/icons/opcua.svg +132 -132
- package/server/lib/opcua-address-space-alarm.js +341 -341
- package/server/lib/opcua-address-space-builder.js +1484 -1484
- package/server/lib/opcua-config.js +546 -546
- package/server/lib/opcua-constants.js +109 -109
- package/server/lib/opcua-server-events-child.js +139 -139
- package/server/lib/opcua-server-runtime-child.js +819 -819
- package/server/lib/opcua-server-runtime.js +311 -311
- package/server/lib/opcua-server-status-child.js +187 -187
- package/server/lib/server-node-utils.js +16 -16
- package/server/opcua-server-io.html +346 -346
- package/server/opcua-server-io.js +496 -496
- package/server/opcua-server-registry.js +270 -270
- package/server/opcua-server.css +265 -265
- package/server/opcua-server.html +1643 -1643
- package/client/testClient.json +0 -18
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const { AttributeIds, DataType, coerceNodeId } = require("node-opcua");
|
|
4
|
-
const {
|
|
5
|
-
buildVariantFromItem,
|
|
6
|
-
normalizeTypeName,
|
|
7
|
-
resolveNodeId,
|
|
8
|
-
statusCodeToString
|
|
9
|
-
} = require("../opcua-client-utils");
|
|
10
|
-
|
|
11
|
-
// Máximo de tags por chamada session.write (ajuste conforme limite do servidor)
|
|
12
|
-
const WRITE_BATCH_SIZE = 100;
|
|
13
|
-
|
|
14
|
-
// Batches em paralelo simultâneos
|
|
15
|
-
const CONCURRENCY = 5;
|
|
16
|
-
|
|
17
|
-
// Cede o event loop a cada N itens para não travar o Node-RED
|
|
18
|
-
const YIELD_EVERY = 50;
|
|
19
|
-
|
|
20
|
-
class OpcUaClientWriteService {
|
|
21
|
-
async execute(node, msg, session, itemsResolver) {
|
|
22
|
-
const items = itemsResolver.ensureWriteItems(node, msg);
|
|
23
|
-
|
|
24
|
-
// 1. Resolve variantes (tipo + valor) — consulta servidor só para quem não tem tipo explícito
|
|
25
|
-
const variants = await resolveVariants(session, items);
|
|
26
|
-
|
|
27
|
-
// 2. Escreve todos os nós em batches paralelos
|
|
28
|
-
const statusCodes = await writeBatches(session, items, variants);
|
|
29
|
-
|
|
30
|
-
// 3. Monta resultados — statusCode Good já confirma a escrita, sem round-trip extra
|
|
31
|
-
return buildResults(items, variants, statusCodes);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// ─── Resolução de tipos ──────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
async function resolveVariants(session, items) {
|
|
38
|
-
// Separa quais itens precisam consultar o tipo no servidor
|
|
39
|
-
const needsLookup = items
|
|
40
|
-
.map((item, index) => ({ item, index }))
|
|
41
|
-
.filter(({ item }) => !normalizeTypeName(item.type));
|
|
42
|
-
|
|
43
|
-
// Busca tipos desconhecidos em paralelo
|
|
44
|
-
const resolvedTypes = new Map();
|
|
45
|
-
|
|
46
|
-
await mapConcurrent(needsLookup, CONCURRENCY * 2, async ({ item, index }) => {
|
|
47
|
-
try {
|
|
48
|
-
const builtInType = await session.getBuiltInDataType(coerceNodeId(resolveNodeId(item)));
|
|
49
|
-
resolvedTypes.set(index, DataType[builtInType]);
|
|
50
|
-
} catch {
|
|
51
|
-
resolvedTypes.set(index, "String");
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return items.map((item, index) => {
|
|
56
|
-
const typeName = normalizeTypeName(item.type) || resolvedTypes.get(index) || "String";
|
|
57
|
-
return buildVariantFromItem(item, typeName);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ─── Escrita em batches paralelos ────────────────────────────────────────────
|
|
62
|
-
|
|
63
|
-
async function writeBatches(session, items, variants) {
|
|
64
|
-
const allStatusCodes = new Array(items.length);
|
|
65
|
-
|
|
66
|
-
// Divide em batches de WRITE_BATCH_SIZE
|
|
67
|
-
const batches = [];
|
|
68
|
-
for (let i = 0; i < items.length; i += WRITE_BATCH_SIZE) {
|
|
69
|
-
batches.push({ start: i, end: Math.min(i + WRITE_BATCH_SIZE, items.length) });
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let processed = 0;
|
|
73
|
-
|
|
74
|
-
await mapConcurrent(batches, CONCURRENCY, async ({ start, end }) => {
|
|
75
|
-
const nodesToWrite = items.slice(start, end).map((item, i) => ({
|
|
76
|
-
nodeId: coerceNodeId(resolveNodeId(item)),
|
|
77
|
-
attributeId: AttributeIds.Value,
|
|
78
|
-
value: { value: variants[start + i] }
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const statusCodes = await session.write(nodesToWrite);
|
|
83
|
-
statusCodes.forEach((sc, i) => {
|
|
84
|
-
allStatusCodes[start + i] = sc;
|
|
85
|
-
});
|
|
86
|
-
} catch (batchError) {
|
|
87
|
-
// Se o batch falhar por completo, marca todos com erro
|
|
88
|
-
for (let i = start; i < end; i++) {
|
|
89
|
-
allStatusCodes[i] = { name: batchError.message, value: -1 };
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Cede o event loop a cada YIELD_EVERY itens para não travar o Node-RED
|
|
94
|
-
processed += end - start;
|
|
95
|
-
if (processed % YIELD_EVERY === 0) {
|
|
96
|
-
await yieldEventLoop();
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
return allStatusCodes;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ─── Montagem dos resultados ─────────────────────────────────────────────────
|
|
104
|
-
|
|
105
|
-
function buildResults(items, variants, statusCodes) {
|
|
106
|
-
return items.map((item, index) => {
|
|
107
|
-
const nodeId = resolveNodeId(item);
|
|
108
|
-
const sc = statusCodes[index];
|
|
109
|
-
const scName = sc && sc.name ? sc.name : "Good";
|
|
110
|
-
const typeName = DataType[variants[index].dataType] || null;
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
name: item.name || nodeId,
|
|
114
|
-
nodeID: nodeId,
|
|
115
|
-
value: variants[index].value,
|
|
116
|
-
type: typeName,
|
|
117
|
-
status: scName,
|
|
118
|
-
sourceTimestamp: null,
|
|
119
|
-
serverTimestamp: null
|
|
120
|
-
};
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// ─── Utilitários ─────────────────────────────────────────────────────────────
|
|
125
|
-
|
|
126
|
-
async function mapConcurrent(items, concurrency, fn) {
|
|
127
|
-
let index = 0;
|
|
128
|
-
|
|
129
|
-
async function worker() {
|
|
130
|
-
while (index < items.length) {
|
|
131
|
-
const i = index++;
|
|
132
|
-
await fn(items[i], i);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
await Promise.all(
|
|
137
|
-
Array.from({ length: Math.min(concurrency, items.length) }, worker)
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function yieldEventLoop() {
|
|
142
|
-
return new Promise(resolve => setImmediate(resolve));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
module.exports = {
|
|
146
|
-
OpcUaClientWriteService
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { AttributeIds, DataType, coerceNodeId } = require("node-opcua");
|
|
4
|
+
const {
|
|
5
|
+
buildVariantFromItem,
|
|
6
|
+
normalizeTypeName,
|
|
7
|
+
resolveNodeId,
|
|
8
|
+
statusCodeToString
|
|
9
|
+
} = require("../opcua-client-utils");
|
|
10
|
+
|
|
11
|
+
// Máximo de tags por chamada session.write (ajuste conforme limite do servidor)
|
|
12
|
+
const WRITE_BATCH_SIZE = 100;
|
|
13
|
+
|
|
14
|
+
// Batches em paralelo simultâneos
|
|
15
|
+
const CONCURRENCY = 5;
|
|
16
|
+
|
|
17
|
+
// Cede o event loop a cada N itens para não travar o Node-RED
|
|
18
|
+
const YIELD_EVERY = 50;
|
|
19
|
+
|
|
20
|
+
class OpcUaClientWriteService {
|
|
21
|
+
async execute(node, msg, session, itemsResolver) {
|
|
22
|
+
const items = itemsResolver.ensureWriteItems(node, msg);
|
|
23
|
+
|
|
24
|
+
// 1. Resolve variantes (tipo + valor) — consulta servidor só para quem não tem tipo explícito
|
|
25
|
+
const variants = await resolveVariants(session, items);
|
|
26
|
+
|
|
27
|
+
// 2. Escreve todos os nós em batches paralelos
|
|
28
|
+
const statusCodes = await writeBatches(session, items, variants);
|
|
29
|
+
|
|
30
|
+
// 3. Monta resultados — statusCode Good já confirma a escrita, sem round-trip extra
|
|
31
|
+
return buildResults(items, variants, statusCodes);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ─── Resolução de tipos ──────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
async function resolveVariants(session, items) {
|
|
38
|
+
// Separa quais itens precisam consultar o tipo no servidor
|
|
39
|
+
const needsLookup = items
|
|
40
|
+
.map((item, index) => ({ item, index }))
|
|
41
|
+
.filter(({ item }) => !normalizeTypeName(item.type));
|
|
42
|
+
|
|
43
|
+
// Busca tipos desconhecidos em paralelo
|
|
44
|
+
const resolvedTypes = new Map();
|
|
45
|
+
|
|
46
|
+
await mapConcurrent(needsLookup, CONCURRENCY * 2, async ({ item, index }) => {
|
|
47
|
+
try {
|
|
48
|
+
const builtInType = await session.getBuiltInDataType(coerceNodeId(resolveNodeId(item)));
|
|
49
|
+
resolvedTypes.set(index, DataType[builtInType]);
|
|
50
|
+
} catch {
|
|
51
|
+
resolvedTypes.set(index, "String");
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return items.map((item, index) => {
|
|
56
|
+
const typeName = normalizeTypeName(item.type) || resolvedTypes.get(index) || "String";
|
|
57
|
+
return buildVariantFromItem(item, typeName);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ─── Escrita em batches paralelos ────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
async function writeBatches(session, items, variants) {
|
|
64
|
+
const allStatusCodes = new Array(items.length);
|
|
65
|
+
|
|
66
|
+
// Divide em batches de WRITE_BATCH_SIZE
|
|
67
|
+
const batches = [];
|
|
68
|
+
for (let i = 0; i < items.length; i += WRITE_BATCH_SIZE) {
|
|
69
|
+
batches.push({ start: i, end: Math.min(i + WRITE_BATCH_SIZE, items.length) });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let processed = 0;
|
|
73
|
+
|
|
74
|
+
await mapConcurrent(batches, CONCURRENCY, async ({ start, end }) => {
|
|
75
|
+
const nodesToWrite = items.slice(start, end).map((item, i) => ({
|
|
76
|
+
nodeId: coerceNodeId(resolveNodeId(item)),
|
|
77
|
+
attributeId: AttributeIds.Value,
|
|
78
|
+
value: { value: variants[start + i] }
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const statusCodes = await session.write(nodesToWrite);
|
|
83
|
+
statusCodes.forEach((sc, i) => {
|
|
84
|
+
allStatusCodes[start + i] = sc;
|
|
85
|
+
});
|
|
86
|
+
} catch (batchError) {
|
|
87
|
+
// Se o batch falhar por completo, marca todos com erro
|
|
88
|
+
for (let i = start; i < end; i++) {
|
|
89
|
+
allStatusCodes[i] = { name: batchError.message, value: -1 };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Cede o event loop a cada YIELD_EVERY itens para não travar o Node-RED
|
|
94
|
+
processed += end - start;
|
|
95
|
+
if (processed % YIELD_EVERY === 0) {
|
|
96
|
+
await yieldEventLoop();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return allStatusCodes;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ─── Montagem dos resultados ─────────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
function buildResults(items, variants, statusCodes) {
|
|
106
|
+
return items.map((item, index) => {
|
|
107
|
+
const nodeId = resolveNodeId(item);
|
|
108
|
+
const sc = statusCodes[index];
|
|
109
|
+
const scName = sc && sc.name ? sc.name : "Good";
|
|
110
|
+
const typeName = DataType[variants[index].dataType] || null;
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
name: item.name || nodeId,
|
|
114
|
+
nodeID: nodeId,
|
|
115
|
+
value: variants[index].value,
|
|
116
|
+
type: typeName,
|
|
117
|
+
status: scName,
|
|
118
|
+
sourceTimestamp: null,
|
|
119
|
+
serverTimestamp: null
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ─── Utilitários ─────────────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
async function mapConcurrent(items, concurrency, fn) {
|
|
127
|
+
let index = 0;
|
|
128
|
+
|
|
129
|
+
async function worker() {
|
|
130
|
+
while (index < items.length) {
|
|
131
|
+
const i = index++;
|
|
132
|
+
await fn(items[i], i);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
await Promise.all(
|
|
137
|
+
Array.from({ length: Math.min(concurrency, items.length) }, worker)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function yieldEventLoop() {
|
|
142
|
+
return new Promise(resolve => setImmediate(resolve));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
module.exports = {
|
|
146
|
+
OpcUaClientWriteService
|
|
147
147
|
};
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
(function () {
|
|
3
|
-
function toggleCredentials() {
|
|
4
|
-
var authType = $("#node-config-input-authType").val();
|
|
5
|
-
$(".opcua-client-auth-row").toggle(authType === "username");
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
RED.nodes.registerType("opcua-client-config", {
|
|
9
|
-
category: "config",
|
|
10
|
-
defaults: {
|
|
11
|
-
name: { value: "" },
|
|
12
|
-
endpoint: { value: "opc.tcp://localhost:4840", required: true },
|
|
13
|
-
securityPolicy: { value: "None", required: true },
|
|
14
|
-
securityMode: { value: "None", required: true },
|
|
15
|
-
authType: { value: "anonymous", required: true }
|
|
16
|
-
},
|
|
17
|
-
credentials: {
|
|
18
|
-
username: { type: "text" },
|
|
19
|
-
password: { type: "password" }
|
|
20
|
-
},
|
|
21
|
-
label: function () {
|
|
22
|
-
return this.name || this.endpoint || "opcua-client-config";
|
|
23
|
-
},
|
|
24
|
-
oneditprepare: function () {
|
|
25
|
-
$("#node-config-input-authType").on("change", toggleCredentials);
|
|
26
|
-
toggleCredentials();
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
})();
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<script type="text/html" data-template-name="opcua-client-config">
|
|
33
|
-
<div class="form-row">
|
|
34
|
-
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
35
|
-
<input type="text" id="node-config-input-name" placeholder="OPC UA Client">
|
|
36
|
-
</div>
|
|
37
|
-
<div class="form-row">
|
|
38
|
-
<label for="node-config-input-endpoint"><i class="fa fa-plug"></i> Endpoint</label>
|
|
39
|
-
<input type="text" id="node-config-input-endpoint" placeholder="opc.tcp://localhost:4840">
|
|
40
|
-
</div>
|
|
41
|
-
<div class="form-row">
|
|
42
|
-
<label for="node-config-input-securityPolicy"><i class="fa fa-lock"></i> Security Policy</label>
|
|
43
|
-
<select id="node-config-input-securityPolicy">
|
|
44
|
-
<option value="None">None</option>
|
|
45
|
-
<option value="Basic128Rsa15">Basic128Rsa15</option>
|
|
46
|
-
<option value="Basic256">Basic256</option>
|
|
47
|
-
<option value="Basic256Sha256">Basic256Sha256</option>
|
|
48
|
-
<option value="Aes128_Sha256_RsaOaep">Aes128_Sha256_RsaOaep</option>
|
|
49
|
-
<option value="Aes256_Sha256_RsaPss">Aes256_Sha256_RsaPss</option>
|
|
50
|
-
</select>
|
|
51
|
-
</div>
|
|
52
|
-
<div class="form-row">
|
|
53
|
-
<label for="node-config-input-securityMode"><i class="fa fa-shield"></i> Security Mode</label>
|
|
54
|
-
<select id="node-config-input-securityMode">
|
|
55
|
-
<option value="None">None</option>
|
|
56
|
-
<option value="Sign">Sign</option>
|
|
57
|
-
<option value="SignAndEncrypt">SignAndEncrypt</option>
|
|
58
|
-
</select>
|
|
59
|
-
</div>
|
|
60
|
-
<div class="form-row">
|
|
61
|
-
<label for="node-config-input-authType"><i class="fa fa-user"></i> Auth</label>
|
|
62
|
-
<select id="node-config-input-authType">
|
|
63
|
-
<option value="anonymous">Anonymous</option>
|
|
64
|
-
<option value="username">Username/Password</option>
|
|
65
|
-
</select>
|
|
66
|
-
</div>
|
|
67
|
-
<div class="form-row opcua-client-auth-row">
|
|
68
|
-
<label for="node-config-input-username"><i class="fa fa-user-circle"></i> Username</label>
|
|
69
|
-
<input type="text" id="node-config-input-username">
|
|
70
|
-
</div>
|
|
71
|
-
<div class="form-row opcua-client-auth-row">
|
|
72
|
-
<label for="node-config-input-password"><i class="fa fa-key"></i> Password</label>
|
|
73
|
-
<input type="password" id="node-config-input-password">
|
|
74
|
-
</div>
|
|
75
|
-
</script>
|
|
76
|
-
|
|
77
|
-
<script type="text/html" data-help-name="opcua-client-config">
|
|
78
|
-
<p>Shared OPC UA client connection for read, write and method nodes.</p>
|
|
79
|
-
<p>This is a Node-RED configuration node, using <code>category: "config"</code> and the <code>node-config-input-*</code> field pattern described in the official docs.</p>
|
|
80
|
-
</script>
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
(function () {
|
|
3
|
+
function toggleCredentials() {
|
|
4
|
+
var authType = $("#node-config-input-authType").val();
|
|
5
|
+
$(".opcua-client-auth-row").toggle(authType === "username");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
RED.nodes.registerType("opcua-client-config", {
|
|
9
|
+
category: "config",
|
|
10
|
+
defaults: {
|
|
11
|
+
name: { value: "" },
|
|
12
|
+
endpoint: { value: "opc.tcp://localhost:4840", required: true },
|
|
13
|
+
securityPolicy: { value: "None", required: true },
|
|
14
|
+
securityMode: { value: "None", required: true },
|
|
15
|
+
authType: { value: "anonymous", required: true }
|
|
16
|
+
},
|
|
17
|
+
credentials: {
|
|
18
|
+
username: { type: "text" },
|
|
19
|
+
password: { type: "password" }
|
|
20
|
+
},
|
|
21
|
+
label: function () {
|
|
22
|
+
return this.name || this.endpoint || "opcua-client-config";
|
|
23
|
+
},
|
|
24
|
+
oneditprepare: function () {
|
|
25
|
+
$("#node-config-input-authType").on("change", toggleCredentials);
|
|
26
|
+
toggleCredentials();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
})();
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script type="text/html" data-template-name="opcua-client-config">
|
|
33
|
+
<div class="form-row">
|
|
34
|
+
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
35
|
+
<input type="text" id="node-config-input-name" placeholder="OPC UA Client">
|
|
36
|
+
</div>
|
|
37
|
+
<div class="form-row">
|
|
38
|
+
<label for="node-config-input-endpoint"><i class="fa fa-plug"></i> Endpoint</label>
|
|
39
|
+
<input type="text" id="node-config-input-endpoint" placeholder="opc.tcp://localhost:4840">
|
|
40
|
+
</div>
|
|
41
|
+
<div class="form-row">
|
|
42
|
+
<label for="node-config-input-securityPolicy"><i class="fa fa-lock"></i> Security Policy</label>
|
|
43
|
+
<select id="node-config-input-securityPolicy">
|
|
44
|
+
<option value="None">None</option>
|
|
45
|
+
<option value="Basic128Rsa15">Basic128Rsa15</option>
|
|
46
|
+
<option value="Basic256">Basic256</option>
|
|
47
|
+
<option value="Basic256Sha256">Basic256Sha256</option>
|
|
48
|
+
<option value="Aes128_Sha256_RsaOaep">Aes128_Sha256_RsaOaep</option>
|
|
49
|
+
<option value="Aes256_Sha256_RsaPss">Aes256_Sha256_RsaPss</option>
|
|
50
|
+
</select>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="form-row">
|
|
53
|
+
<label for="node-config-input-securityMode"><i class="fa fa-shield"></i> Security Mode</label>
|
|
54
|
+
<select id="node-config-input-securityMode">
|
|
55
|
+
<option value="None">None</option>
|
|
56
|
+
<option value="Sign">Sign</option>
|
|
57
|
+
<option value="SignAndEncrypt">SignAndEncrypt</option>
|
|
58
|
+
</select>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-row">
|
|
61
|
+
<label for="node-config-input-authType"><i class="fa fa-user"></i> Auth</label>
|
|
62
|
+
<select id="node-config-input-authType">
|
|
63
|
+
<option value="anonymous">Anonymous</option>
|
|
64
|
+
<option value="username">Username/Password</option>
|
|
65
|
+
</select>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="form-row opcua-client-auth-row">
|
|
68
|
+
<label for="node-config-input-username"><i class="fa fa-user-circle"></i> Username</label>
|
|
69
|
+
<input type="text" id="node-config-input-username">
|
|
70
|
+
</div>
|
|
71
|
+
<div class="form-row opcua-client-auth-row">
|
|
72
|
+
<label for="node-config-input-password"><i class="fa fa-key"></i> Password</label>
|
|
73
|
+
<input type="password" id="node-config-input-password">
|
|
74
|
+
</div>
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<script type="text/html" data-help-name="opcua-client-config">
|
|
78
|
+
<p>Shared OPC UA client connection for read, write and method nodes.</p>
|
|
79
|
+
<p>This is a Node-RED configuration node, using <code>category: "config"</code> and the <code>node-config-input-*</code> field pattern described in the official docs.</p>
|
|
80
|
+
</script>
|