@vitormnm/node-red-simple-opcua 1.4.3 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/client/icons/opcua.svg +132 -132
  2. package/client/lib/opcua-client-browser.js +368 -330
  3. package/client/lib/opcua-client-method-service.js +88 -88
  4. package/client/lib/opcua-client-read-service.js +27 -15
  5. package/client/lib/opcua-client-subscription-id-service.js +24 -24
  6. package/client/lib/opcua-client-subscription-service.js +175 -170
  7. package/client/lib/opcua-client-write-service.js +146 -146
  8. package/client/opcua-client-config.html +80 -80
  9. package/client/opcua-client-utils.js +217 -22
  10. package/client/opcua-client.html +140 -140
  11. package/client/view/opcua-client.js +1144 -1140
  12. package/examples/flows_simple_opc.json +1 -2851
  13. package/icons/opcua.svg +132 -132
  14. package/icons/opcua2.svg +132 -132
  15. package/package.json +3 -3
  16. package/server/icons/opcua.svg +132 -132
  17. package/server/lib/opcua-address-space-alarm.js +341 -341
  18. package/server/lib/opcua-address-space-builder.js +1797 -1485
  19. package/server/lib/opcua-config.js +800 -546
  20. package/server/lib/opcua-constants.js +120 -109
  21. package/server/lib/opcua-server-events-child.js +139 -139
  22. package/server/lib/opcua-server-methods.js +2 -0
  23. package/server/lib/opcua-server-runtime-child.js +874 -819
  24. package/server/lib/opcua-server-runtime.js +385 -311
  25. package/server/lib/opcua-server-status-child.js +187 -187
  26. package/server/lib/server-node-utils.js +16 -16
  27. package/server/opcua-server-io.html +346 -346
  28. package/server/opcua-server-io.js +497 -496
  29. package/server/opcua-server-registry.js +270 -270
  30. package/server/opcua-server.css +265 -265
  31. package/server/opcua-server.html +158 -1643
  32. package/server/opcua-server.js +24 -13
  33. package/server/view/opcua-server.css +496 -0
  34. package/server/view/opcua-server.js +1585 -0
@@ -1,109 +1,120 @@
1
- "use strict";
2
-
3
- const os = require("os");
4
- const opcua = require("node-opcua");
5
-
6
- const {
7
- OPCUAServer,
8
- Variant,
9
- DataType,
10
- StatusCodes,
11
- SecurityPolicy,
12
- VariantArrayType,
13
- MessageSecurityMode,
14
- UserTokenType,
15
- coerceNodeId ,
16
- } = opcua;
17
-
18
- const DEFAULT_PORT = 4840;
19
- const DEFAULT_SERVER_NAME = "Node-RED OPC UA Server";
20
- const DEFAULT_NAMESPACE_URI = "urn:node-red:opc-ua-server";
21
- const DEFAULT_RESOURCE_PATH = "/";
22
-
23
- const SECURITY_POLICY_MAP = {
24
- None: SecurityPolicy.None,
25
- Basic128Rsa15: SecurityPolicy.Basic128Rsa15,
26
- Basic256: SecurityPolicy.Basic256,
27
- Basic256Sha256: SecurityPolicy.Basic256Sha256,
28
- Aes128_Sha256_RsaOaep: SecurityPolicy.Aes128_Sha256_RsaOaep,
29
- Aes256_Sha256_RsaPss: SecurityPolicy.Aes256_Sha256_RsaPss
30
- };
31
-
32
- const SECURITY_MODE_MAP = {
33
- None: MessageSecurityMode.None,
34
- Sign: MessageSecurityMode.Sign,
35
- SignAndEncrypt: MessageSecurityMode.SignAndEncrypt
36
- };
37
-
38
- const DATA_TYPE_MAP = {
39
- Int16: DataType.Int16,
40
- UInt16: DataType.UInt16,
41
- Int32: DataType.Int32,
42
- UInt32: DataType.UInt32,
43
- Float: DataType.Float,
44
- Boolean: DataType.Boolean,
45
- String: DataType.String,
46
- ByteString : DataType.ByteString,
47
- LocalizedText : DataType.LocalizedText
48
- };
49
-
50
- function normalizePort(port) {
51
- const parsed = Number(port);
52
- if (!Number.isInteger(parsed) || parsed <= 0) {
53
- return DEFAULT_PORT;
54
- }
55
-
56
- return parsed;
57
- }
58
-
59
- function buildApplicationUri(serverName) {
60
- const host = os.hostname() || "localhost";
61
- return "urn:" + host + ":node-red:" + sanitizeUriSegment(serverName);
62
- }
63
-
64
- function sanitizeUriSegment(value) {
65
- return String(value || "opc-ua-server")
66
- .trim()
67
- .replace(/\s+/g, "-")
68
- .replace(/[^a-zA-Z0-9:_-]/g, "")
69
- .toLowerCase();
70
- }
71
-
72
- function sanitizeNodeIdPath(path) {
73
- return String(path || "")
74
- .split(".")
75
- .map((segment) => sanitizeNodeIdSegment(segment))
76
- .filter((segment) => segment !== "")
77
- .join(".");
78
- }
79
-
80
- function sanitizeNodeIdSegment(segment) {
81
- const normalized = String(segment || "")
82
- .trim()
83
- .replace(/\s+/g, "_")
84
- .replace(/[^a-zA-Z0-9._-]/g, "_");
85
-
86
- return normalized || "item";
87
- }
88
-
89
- module.exports = {
90
- OPCUAServer,
91
- Variant,
92
- DataType,
93
- StatusCodes,
94
- VariantArrayType,
95
- SecurityPolicy,
96
- MessageSecurityMode,
97
- UserTokenType,
98
- coerceNodeId,
99
- DEFAULT_PORT,
100
- DEFAULT_SERVER_NAME,
101
- DEFAULT_NAMESPACE_URI,
102
- DEFAULT_RESOURCE_PATH,
103
- SECURITY_POLICY_MAP,
104
- SECURITY_MODE_MAP,
105
- DATA_TYPE_MAP,
106
- normalizePort,
107
- buildApplicationUri,
108
- sanitizeNodeIdPath
109
- };
1
+ "use strict";
2
+
3
+ const os = require("os");
4
+ const opcua = require("node-opcua");
5
+
6
+ const {
7
+ OPCUAServer,
8
+ Variant,
9
+ DataType,
10
+ StatusCodes,
11
+ SecurityPolicy,
12
+ VariantArrayType,
13
+ MessageSecurityMode,
14
+ UserTokenType,
15
+ coerceNodeId ,
16
+ resolveNodeId,
17
+ PermissionType,
18
+ makeRoles,
19
+ WellKnownRoles,
20
+ OPCUACertificateManager,
21
+ } = opcua;
22
+
23
+ const DEFAULT_PORT = 4840;
24
+ const DEFAULT_SERVER_NAME = "Node-RED OPC UA Server";
25
+ const DEFAULT_NAMESPACE_URI = "urn:node-red:opc-ua-server";
26
+ const DEFAULT_RESOURCE_PATH = "/";
27
+
28
+ const SECURITY_POLICY_MAP = {
29
+ None: SecurityPolicy.None,
30
+ Basic128Rsa15: SecurityPolicy.Basic128Rsa15,
31
+ Basic256: SecurityPolicy.Basic256,
32
+ Basic256Sha256: SecurityPolicy.Basic256Sha256,
33
+ Aes128_Sha256_RsaOaep: SecurityPolicy.Aes128_Sha256_RsaOaep,
34
+ Aes256_Sha256_RsaPss: SecurityPolicy.Aes256_Sha256_RsaPss
35
+ };
36
+
37
+ const SECURITY_MODE_MAP = {
38
+ None: MessageSecurityMode.None,
39
+ Sign: MessageSecurityMode.Sign,
40
+ SignAndEncrypt: MessageSecurityMode.SignAndEncrypt
41
+ };
42
+
43
+ const DATA_TYPE_MAP = {
44
+ Int16: DataType.Int16,
45
+ UInt16: DataType.UInt16,
46
+ Int32: DataType.Int32,
47
+ UInt32: DataType.UInt32,
48
+ Int64: DataType.Int64,
49
+ Float: DataType.Float,
50
+ Boolean: DataType.Boolean,
51
+ String: DataType.String,
52
+ ByteString : DataType.ByteString,
53
+ LocalizedText : DataType.LocalizedText
54
+ };
55
+
56
+ function normalizePort(port) {
57
+ const parsed = Number(port);
58
+ if (!Number.isInteger(parsed) || parsed <= 0) {
59
+ return DEFAULT_PORT;
60
+ }
61
+
62
+ return parsed;
63
+ }
64
+
65
+ function buildApplicationUri(serverName) {
66
+ const host = os.hostname() || "localhost";
67
+ return "urn:" + host + ":node-red:" + sanitizeUriSegment(serverName);
68
+ }
69
+
70
+ function sanitizeUriSegment(value) {
71
+ return String(value || "opc-ua-server")
72
+ .trim()
73
+ .replace(/\s+/g, "-")
74
+ .replace(/[^a-zA-Z0-9:_-]/g, "")
75
+ .toLowerCase();
76
+ }
77
+
78
+ function sanitizeNodeIdPath(path) {
79
+ return String(path || "")
80
+ .split(".")
81
+ .map((segment) => sanitizeNodeIdSegment(segment))
82
+ .filter((segment) => segment !== "")
83
+ .join(".");
84
+ }
85
+
86
+ function sanitizeNodeIdSegment(segment) {
87
+ const normalized = String(segment || "")
88
+ .trim()
89
+ .replace(/\s+/g, "_")
90
+ .replace(/[^a-zA-Z0-9._-]/g, "_");
91
+
92
+ return normalized || "item";
93
+ }
94
+
95
+ module.exports = {
96
+ OPCUAServer,
97
+ Variant,
98
+ DataType,
99
+ OPCUACertificateManager,
100
+ StatusCodes,
101
+ VariantArrayType,
102
+ SecurityPolicy,
103
+ MessageSecurityMode,
104
+ UserTokenType,
105
+ coerceNodeId,
106
+ resolveNodeId,
107
+ PermissionType,
108
+ makeRoles,
109
+ WellKnownRoles,
110
+ DEFAULT_PORT,
111
+ DEFAULT_SERVER_NAME,
112
+ DEFAULT_NAMESPACE_URI,
113
+ DEFAULT_RESOURCE_PATH,
114
+ SECURITY_POLICY_MAP,
115
+ SECURITY_MODE_MAP,
116
+ DATA_TYPE_MAP,
117
+ normalizePort,
118
+ buildApplicationUri,
119
+ sanitizeNodeIdPath
120
+ };
@@ -1,140 +1,140 @@
1
- "use strict";
2
-
3
-
4
- const registry = require("../opcua-server-registry");
5
- const { resolveRegisteredServer } = require("./server-node-utils");
6
-
7
-
8
-
9
-
10
- function eventsServer(node, rootNode, nodeId) {
11
-
12
-
13
-
14
- // 🔥 ALTERADO: usar Map para garantir unicidade por nodeID
15
- node.queue = {
16
- read: new Map(),
17
- write: new Map(),
18
- alarm: new Map()
19
- };
20
-
21
- if (node.flushTimer) {
22
- clearInterval(node.flushTimer);
23
- node.flushTimer = null;
24
- }
25
-
26
-
27
- node.flushTimer = setInterval(() => {
28
- flushQueue(node, nodeId);
29
-
30
- }, rootNode.intervalMs);
31
-
32
- ///rootNode.intervalMs
33
- node.enqueueAccessEvent = function (event) {
34
- if (!matchesServer(node.serverRef, event)) {
35
-
36
- }
37
-
38
- if (event.operation === "read") {
39
- upsertEvent(node.queue.read, event);
40
-
41
- }
42
-
43
- if (event.operation === "write") {
44
- upsertEvent(node.queue.write, event);
45
- }
46
-
47
- if (event.operation === "alarm") {
48
- upsertEvent(node.queue.alarm, event);
49
- }
50
- };
51
-
52
- registry.registerAccessListener(node.id, node);
53
- }
54
-
55
-
56
-
57
-
58
-
59
- function flushQueue(node, nodeId) {
60
-
61
-
62
-
63
- // ALTERADO: usar size (Map)
64
- if (!node.queue.read.size && !node.queue.write.size) {
65
-
66
- }
67
-
68
-
69
- const payload = {
70
- serverRef: node.serverRef || "",
71
- intervalMs: node.intervalMs,
72
- timestamp: new Date().toISOString(),
73
-
74
- // 🔥 ALTERADO: converter Map -> Array
75
- read: Array.from(node.queue.read.values()),
76
- write: Array.from(node.queue.write.values()),
77
- alarm: Array.from(node.queue.alarm.values())
78
- };
79
-
80
- // ALTERADO: limpar Maps
81
- node.queue.read.clear();
82
- node.queue.write.clear();
83
- node.queue.alarm.clear();
84
-
85
- process.send({
86
- type: "send",
87
- data: {
88
- payload,
89
- opcua: {
90
- server: payload.serverRef
91
- }
92
- },
93
- nodeId: nodeId
94
- });
95
-
96
- process.send({
97
- type: "status",
98
- data: {
99
- fill: "green",
100
- shape: "dot",
101
- text: "read " + payload.read.length + " write " + payload.write.length
102
- },
103
- nodeId: nodeId
104
- });
105
-
106
-
107
-
108
-
109
- }
110
-
111
-
112
- function upsertEvent(map, event) {
113
- const key = String(event.nodeID || "").trim();
114
- if (!key) return;
115
-
116
- map.set(key, event); // sobrescreve automaticamente
117
- }
118
-
119
- function matchesServer(serverRef, event) {
120
- if (!serverRef) {
121
- return true;
122
- }
123
-
124
- const normalizedRef = String(serverRef).trim();
125
- return normalizedRef === String(event.serverId || "").trim()
126
- || normalizedRef === String(event.serverNodeName || "").trim()
127
- || normalizedRef === String(event.serverName || "").trim();
128
- }
129
-
130
- function normalizeInterval(value) {
131
- const interval = Number(value);
132
- if (!Number.isFinite(interval) || interval <= 0) {
133
- return 500;
134
- }
135
-
136
- return Math.trunc(interval);
137
- }
138
- module.exports = {
139
- "eventsServer": eventsServer
1
+ "use strict";
2
+
3
+
4
+ const registry = require("../opcua-server-registry");
5
+ const { resolveRegisteredServer } = require("./server-node-utils");
6
+
7
+
8
+
9
+
10
+ function eventsServer(node, rootNode, nodeId) {
11
+
12
+
13
+
14
+ // 🔥 ALTERADO: usar Map para garantir unicidade por nodeID
15
+ node.queue = {
16
+ read: new Map(),
17
+ write: new Map(),
18
+ alarm: new Map()
19
+ };
20
+
21
+ if (node.flushTimer) {
22
+ clearInterval(node.flushTimer);
23
+ node.flushTimer = null;
24
+ }
25
+
26
+
27
+ node.flushTimer = setInterval(() => {
28
+ flushQueue(node, nodeId);
29
+
30
+ }, rootNode.intervalMs);
31
+
32
+ ///rootNode.intervalMs
33
+ node.enqueueAccessEvent = function (event) {
34
+ if (!matchesServer(node.serverRef, event)) {
35
+
36
+ }
37
+
38
+ if (event.operation === "read") {
39
+ upsertEvent(node.queue.read, event);
40
+
41
+ }
42
+
43
+ if (event.operation === "write") {
44
+ upsertEvent(node.queue.write, event);
45
+ }
46
+
47
+ if (event.operation === "alarm") {
48
+ upsertEvent(node.queue.alarm, event);
49
+ }
50
+ };
51
+
52
+ registry.registerAccessListener(node.id, node);
53
+ }
54
+
55
+
56
+
57
+
58
+
59
+ function flushQueue(node, nodeId) {
60
+
61
+
62
+
63
+ // ALTERADO: usar size (Map)
64
+ if (!node.queue.read.size && !node.queue.write.size) {
65
+
66
+ }
67
+
68
+
69
+ const payload = {
70
+ serverRef: node.serverRef || "",
71
+ intervalMs: node.intervalMs,
72
+ timestamp: new Date().toISOString(),
73
+
74
+ // 🔥 ALTERADO: converter Map -> Array
75
+ read: Array.from(node.queue.read.values()),
76
+ write: Array.from(node.queue.write.values()),
77
+ alarm: Array.from(node.queue.alarm.values())
78
+ };
79
+
80
+ // ALTERADO: limpar Maps
81
+ node.queue.read.clear();
82
+ node.queue.write.clear();
83
+ node.queue.alarm.clear();
84
+
85
+ process.send({
86
+ type: "send",
87
+ data: {
88
+ payload,
89
+ opcua: {
90
+ server: payload.serverRef
91
+ }
92
+ },
93
+ nodeId: nodeId
94
+ });
95
+
96
+ process.send({
97
+ type: "status",
98
+ data: {
99
+ fill: "green",
100
+ shape: "dot",
101
+ text: "read " + payload.read.length + " write " + payload.write.length
102
+ },
103
+ nodeId: nodeId
104
+ });
105
+
106
+
107
+
108
+
109
+ }
110
+
111
+
112
+ function upsertEvent(map, event) {
113
+ const key = String(event.nodeID || "").trim();
114
+ if (!key) return;
115
+
116
+ map.set(key, event); // sobrescreve automaticamente
117
+ }
118
+
119
+ function matchesServer(serverRef, event) {
120
+ if (!serverRef) {
121
+ return true;
122
+ }
123
+
124
+ const normalizedRef = String(serverRef).trim();
125
+ return normalizedRef === String(event.serverId || "").trim()
126
+ || normalizedRef === String(event.serverNodeName || "").trim()
127
+ || normalizedRef === String(event.serverName || "").trim();
128
+ }
129
+
130
+ function normalizeInterval(value) {
131
+ const interval = Number(value);
132
+ if (!Number.isFinite(interval) || interval <= 0) {
133
+ return 500;
134
+ }
135
+
136
+ return Math.trunc(interval);
137
+ }
138
+ module.exports = {
139
+ "eventsServer": eventsServer
140
140
  }
@@ -113,6 +113,8 @@ class OpcUaServerMethods {
113
113
  const eventId = inputArguments[0].value;
114
114
  const comment = inputArguments[1].value;
115
115
 
116
+
117
+
116
118
  const alarm = context.object;
117
119
  // severity atual
118
120
  const severity = alarm.severity.readValue().value.value;