@jsgorana/node-red-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 ADDED
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 0.1.0 - Unreleased
6
+
7
+ Initial pre-release of `@jsgorana/node-red-opcua`.
8
+
9
+ - Added client nodes: endpoint, read, write, browse, and subscribe.
10
+ - Added bidirectional `opcua-server` node for exposing Node-RED values.
11
+ - Added shared, ref-counted OPC-UA connection management with reconnect handling.
12
+ - Added fail-fast operation timeouts for read/write/browse workflows.
13
+ - Added secure-by-default client certificate validation with persisted PKI storage.
14
+ - Added username/password authentication and Sign/SignAndEncrypt server support.
15
+ - Added batch read/write support.
16
+ - Added shared endpoint subscriptions with per-node monitored items.
17
+ - Added subscribe deadband/data-change filter support.
18
+ - Added polished Node-RED example flows.
19
+ - Added automated tests, linting, and GitHub Actions CI.
@@ -0,0 +1,36 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve `@jsgorana/node-red-opcua`.
4
+
5
+ ## Requirements
6
+
7
+ - Node.js 22.9 or newer
8
+ - npm
9
+
10
+ ## Local Setup
11
+
12
+ ```bash
13
+ npm install
14
+ npm run lint
15
+ npm test
16
+ ```
17
+
18
+ The test suite starts local OPC-UA servers as needed; no external OPC-UA server is required.
19
+
20
+ ## Development Notes
21
+
22
+ - Keep runtime node files under `nodes/`.
23
+ - Keep shared logic in `nodes/lib/` where it can be tested without Node-RED.
24
+ - Add or update tests for behavioral changes.
25
+ - Preserve secure defaults. Development-only security bypasses should be explicit and logged.
26
+ - Do not publish from feature branches or local experiments.
27
+
28
+ ## Before Opening a PR
29
+
30
+ ```bash
31
+ npm run lint
32
+ npm test
33
+ ```
34
+
35
+ Include a short description of the change, the reason for it, and any manual OPC-UA or
36
+ Node-RED validation performed.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jsgorana
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,506 @@
1
+ # @jsgorana/node-red-opcua
2
+
3
+ Modern OPC-UA client and server nodes for Node-RED.
4
+
5
+ Use Node-RED to read, write, browse, and subscribe to industrial OPC-UA servers, or expose
6
+ Node-RED values as an OPC-UA server that PLCs, SCADA systems, historians, and test clients
7
+ can read and write.
8
+
9
+ This package is built for Node-RED 5.x and current `node-opcua`. It is intended as a clean,
10
+ maintained alternative to older OPC-UA Node-RED packages that have become difficult to rely
11
+ on in modern IIOT deployments.
12
+
13
+ ![Server and client demo flow](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/server-client-demo-flow.png)
14
+
15
+ ## What You Get
16
+
17
+ | Node | Use it for |
18
+ | --- | --- |
19
+ | `opcua-endpoint` | Shared OPC-UA client endpoint configuration: URL, security, authentication, timeout, PKI trust behavior |
20
+ | `opcua-read` | Read one or many OPC-UA node values |
21
+ | `opcua-write` | Write one or many OPC-UA node values with explicit data types |
22
+ | `opcua-browse` | Browse an address space from a starting NodeId |
23
+ | `opcua-subscribe` | Subscribe to value changes with sampling, publishing, queue, trigger, and deadband settings |
24
+ | `opcua-server` | Serve Node-RED values as OPC-UA variables and emit messages when OPC-UA clients write |
25
+
26
+ Core behavior:
27
+
28
+ - One shared, ref-counted OPC-UA connection per endpoint config node.
29
+ - Automatic reconnect and subscription re-arm after outages.
30
+ - Fail-fast read/write/browse operation timeout so flows do not hang forever.
31
+ - Secure-by-default certificate validation for encrypted client connections.
32
+ - Username/password authentication for client and server use cases.
33
+ - Server-side `None`, `Sign`, and `SignAndEncrypt` endpoint options.
34
+ - Three bundled example flows that are ready to import from the Node-RED Examples menu.
35
+
36
+ ## Requirements
37
+
38
+ - Node.js `>=22.9.0`
39
+ - Node-RED 5.x recommended
40
+ - Node-RED 4.x is supported by package metadata, but Node-RED 5.x is the primary target
41
+
42
+ ## Installation
43
+
44
+ ### Palette Manager
45
+
46
+ In Node-RED:
47
+
48
+ 1. Open **Menu -> Manage palette**.
49
+ 2. Go to **Install**.
50
+ 3. Search for `@jsgorana/node-red-opcua`.
51
+ 4. Click **Install**.
52
+
53
+ ### npm
54
+
55
+ From your Node-RED user directory:
56
+
57
+ ```bash
58
+ npm install @jsgorana/node-red-opcua
59
+ ```
60
+
61
+ Then restart Node-RED if your runtime does not automatically reload installed nodes.
62
+
63
+ ## Fastest Start: Self-Contained Demo
64
+
65
+ The quickest way to prove the package is working is the bundled **Server + Client Demo**.
66
+ It runs an OPC-UA server and OPC-UA client in the same Node-RED instance, so no PLC,
67
+ simulator, or external server is required.
68
+
69
+ 1. In Node-RED, open **Menu -> Import**.
70
+ 2. Select the **Examples** tab.
71
+ 3. Open `@jsgorana/node-red-opcua`.
72
+ 4. Import **Server + Client Demo**.
73
+ 5. Click **Deploy**.
74
+ 6. Click **Simulate sensor**.
75
+ 7. Watch the read/subscription/debug nodes update.
76
+
77
+ ![Import examples dialog](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/node-red-import-examples-menu.png)
78
+
79
+ The demo exposes:
80
+
81
+ - `ns=1;s=Temperature`
82
+ - `ns=1;s=Setpoint`
83
+
84
+ The client nodes connect to:
85
+
86
+ ```text
87
+ opc.tcp://localhost:4840/UA/NodeRED
88
+ ```
89
+
90
+ Use `localhost` only when the client and server are in the same runtime/container/host.
91
+ For remote systems, use the OPC-UA server host name or IP address that is reachable from
92
+ Node-RED.
93
+
94
+ ## Example Flows
95
+
96
+ Import examples from **Menu -> Import -> Examples -> @jsgorana/node-red-opcua**.
97
+
98
+ ### Server + Client Demo
99
+
100
+ Self-contained flow for first validation. The orange group serves values; the blue group
101
+ reads, writes, and subscribes to the server above it.
102
+
103
+ ![Server and client demo](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/server-client-demo-flow.png)
104
+
105
+ ### Client Quickstart
106
+
107
+ Client-only patterns for connecting to your own OPC-UA server:
108
+
109
+ - Read a value on demand.
110
+ - Write a value.
111
+ - Browse the address space.
112
+ - Subscribe to live value changes.
113
+
114
+ ![Client quickstart flow](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/client-quickstart-flow.png)
115
+
116
+ ### Server Quickstart
117
+
118
+ Server-only pattern for exposing Node-RED data outward:
119
+
120
+ - Feed Node-RED values into served OPC-UA variables.
121
+ - Receive messages when an OPC-UA client writes a variable.
122
+
123
+ ![Server quickstart flow](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/server-quickstart-flow.png)
124
+
125
+ ## Client Endpoint Configuration
126
+
127
+ All client operation nodes use an `opcua-endpoint` config node. Multiple read/write/browse/
128
+ subscribe nodes that point at the same endpoint share one connection and session.
129
+
130
+ ![Endpoint security configuration](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/endpoint-security-config.png)
131
+
132
+ Important fields:
133
+
134
+ | Field | Meaning |
135
+ | --- | --- |
136
+ | Endpoint | OPC-UA endpoint URL, for example `opc.tcp://192.168.1.20:4840/UA/MyServer` |
137
+ | Security Mode | `None`, `Sign`, or `SignAndEncrypt` |
138
+ | Security Policy | `None`, `Basic256Sha256`, `Aes128_Sha256_RsaOaep`, `Aes256_Sha256_RsaPss`, or legacy policies |
139
+ | Authentication | Anonymous or username/password |
140
+ | Op timeout | Maximum time a read/write/browse operation waits before failing |
141
+
142
+ For production systems, prefer:
143
+
144
+ - `Security Mode`: `SignAndEncrypt`
145
+ - `Security Policy`: `Basic256Sha256` or stronger
146
+ - Authentication: username/password if your server supports it
147
+ - Server certificate trusted in the Node-RED PKI store
148
+
149
+ ## Reading Values
150
+
151
+ ### Single Read
152
+
153
+ Configure `Node ID` on the node, or pass it with `msg.nodeId`.
154
+
155
+ Input:
156
+
157
+ ```json
158
+ {
159
+ "nodeId": "ns=1;s=Temperature"
160
+ }
161
+ ```
162
+
163
+ Output:
164
+
165
+ ```json
166
+ {
167
+ "payload": 23.7,
168
+ "nodeId": "ns=1;s=Temperature",
169
+ "statusCode": "Good (0x00000000)"
170
+ }
171
+ ```
172
+
173
+ ### Batch Read
174
+
175
+ Send an array as `msg.nodeIds` or `msg.payload`.
176
+
177
+ Input:
178
+
179
+ ```json
180
+ {
181
+ "nodeIds": [
182
+ "ns=1;s=Temperature",
183
+ "ns=1;s=Setpoint"
184
+ ]
185
+ }
186
+ ```
187
+
188
+ Output:
189
+
190
+ ```json
191
+ {
192
+ "payload": [
193
+ {
194
+ "nodeId": "ns=1;s=Temperature",
195
+ "payload": 23.7,
196
+ "statusCode": "Good (0x00000000)"
197
+ },
198
+ {
199
+ "nodeId": "ns=1;s=Setpoint",
200
+ "payload": 50,
201
+ "statusCode": "Good (0x00000000)"
202
+ }
203
+ ],
204
+ "nodeIds": [
205
+ "ns=1;s=Temperature",
206
+ "ns=1;s=Setpoint"
207
+ ],
208
+ "statusCodes": [
209
+ "Good (0x00000000)",
210
+ "Good (0x00000000)"
211
+ ]
212
+ }
213
+ ```
214
+
215
+ ## Writing Values
216
+
217
+ ### Single Write
218
+
219
+ Configure `Node ID` and `Data Type` on the node, or override with `msg.nodeId` and
220
+ `msg.dataType`.
221
+
222
+ Input:
223
+
224
+ ```json
225
+ {
226
+ "nodeId": "ns=1;s=Setpoint",
227
+ "dataType": "Double",
228
+ "payload": 50
229
+ }
230
+ ```
231
+
232
+ Output:
233
+
234
+ ```json
235
+ {
236
+ "nodeId": "ns=1;s=Setpoint",
237
+ "statusCode": "Good (0x00000000)"
238
+ }
239
+ ```
240
+
241
+ ### Batch Write
242
+
243
+ Use an array of write descriptors:
244
+
245
+ ```json
246
+ {
247
+ "payload": [
248
+ {
249
+ "nodeId": "ns=1;s=Setpoint",
250
+ "dataType": "Double",
251
+ "value": 50
252
+ },
253
+ {
254
+ "nodeId": "ns=1;s=Label",
255
+ "dataType": "String",
256
+ "value": "line running"
257
+ }
258
+ ]
259
+ }
260
+ ```
261
+
262
+ Output:
263
+
264
+ ```json
265
+ {
266
+ "nodeIds": [
267
+ "ns=1;s=Setpoint",
268
+ "ns=1;s=Label"
269
+ ],
270
+ "statusCodes": [
271
+ "Good (0x00000000)",
272
+ "Good (0x00000000)"
273
+ ]
274
+ }
275
+ ```
276
+
277
+ Supported data type names are the `node-opcua` `DataType` enum names, including:
278
+ `Boolean`, `SByte`, `Byte`, `Int16`, `UInt16`, `Int32`, `UInt32`, `Float`, `Double`,
279
+ `String`, and `DateTime`.
280
+
281
+ ## Browsing
282
+
283
+ `opcua-browse` browses from a configured `Node ID`, or from `msg.nodeId`.
284
+
285
+ Common starting points:
286
+
287
+ ```text
288
+ RootFolder
289
+ ObjectsFolder
290
+ ns=1;s=SomeObject
291
+ ```
292
+
293
+ Output payload is an array of references:
294
+
295
+ ```json
296
+ [
297
+ {
298
+ "nodeId": "ns=1;s=Temperature",
299
+ "browseName": "1:Temperature",
300
+ "displayName": "Temperature",
301
+ "nodeClass": 2,
302
+ "typeDefinition": "i=63"
303
+ }
304
+ ]
305
+ ```
306
+
307
+ ## Subscribing To Changes
308
+
309
+ `opcua-subscribe` automatically connects and arms its monitored item when the flow starts.
310
+ It has no input. It emits a message each time the server reports a value change.
311
+
312
+ ![Subscribe deadband configuration](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/subscribe-deadband-config.png)
313
+
314
+ Output:
315
+
316
+ ```json
317
+ {
318
+ "payload": 23.9,
319
+ "nodeId": "ns=1;s=Temperature",
320
+ "statusCode": "Good (0x00000000)",
321
+ "sourceTimestamp": "2026-06-28T12:00:00.000Z"
322
+ }
323
+ ```
324
+
325
+ Subscription settings:
326
+
327
+ | Field | Meaning |
328
+ | --- | --- |
329
+ | Sampling (ms) | How often the server samples the value |
330
+ | Publishing (ms) | How often the subscription publishes notifications |
331
+ | Queue Size | Number of changes to queue if the client cannot process them immediately |
332
+ | Trigger | Status only, status + value, or status + value + timestamp |
333
+ | Deadband | `None`, `Absolute`, or `Percent` |
334
+ | Deadband Value | Threshold for absolute or percent deadband |
335
+
336
+ All subscribe nodes that share the same endpoint use one OPC-UA subscription with separate
337
+ monitored items. This is friendlier to servers that limit subscription counts.
338
+
339
+ ## Exposing Node-RED As An OPC-UA Server
340
+
341
+ Use `opcua-server` when you want other OPC-UA clients to read or write data owned by
342
+ Node-RED.
343
+
344
+ ![Server security configuration](https://raw.githubusercontent.com/jsgorana/node-red-opcua/main/docs/assets/server-security-config.png)
345
+
346
+ Input message:
347
+
348
+ ```json
349
+ {
350
+ "topic": "Temperature",
351
+ "payload": 24.2,
352
+ "dataType": "Double"
353
+ }
354
+ ```
355
+
356
+ The server exposes that as:
357
+
358
+ ```text
359
+ ns=1;s=Temperature
360
+ ```
361
+
362
+ If an OPC-UA client writes to a served variable, the node emits:
363
+
364
+ ```json
365
+ {
366
+ "topic": "Setpoint",
367
+ "payload": 50,
368
+ "nodeId": "ns=1;s=Setpoint",
369
+ "source": "client"
370
+ }
371
+ ```
372
+
373
+ Server security options:
374
+
375
+ - Offer `None`, `Sign`, and/or `SignAndEncrypt` endpoints.
376
+ - Require username/password, allow anonymous, or support both.
377
+ - Validate client certificates in the server PKI trust store.
378
+ - Use `SignAndEncrypt` plus credentials for production-facing servers.
379
+
380
+ ## OPC-UA Security And Certificates
381
+
382
+ ### Client Certificate Trust
383
+
384
+ For secure client connections (`Sign` or `SignAndEncrypt`), server certificate validation is
385
+ enabled by default.
386
+
387
+ The client PKI store is created under:
388
+
389
+ ```text
390
+ <Node-RED userDir>/opcua-pki
391
+ ```
392
+
393
+ Important folders:
394
+
395
+ | Folder | Purpose |
396
+ | --- | --- |
397
+ | `own/certs` | Node-RED client's own application certificate |
398
+ | `trusted/certs` | Server certificates explicitly trusted by this Node-RED instance |
399
+ | `rejected` | Unknown certificates rejected during connection attempts |
400
+
401
+ If a secure connection fails with `BadCertificateUntrusted`, copy the server certificate
402
+ from `rejected` into `trusted/certs`, then reconnect.
403
+
404
+ The **Accept untrusted server cert** option is for development only. It disables the trust
405
+ decision and should not be used in production.
406
+
407
+ ### Username And Password
408
+
409
+ Credentials are stored using Node-RED credentials storage. For production systems, combine
410
+ username/password with `SignAndEncrypt`.
411
+
412
+ ### Server Certificate Trust
413
+
414
+ The `opcua-server` node stores server-side PKI material under:
415
+
416
+ ```text
417
+ <Node-RED userDir>/opcua-pki/server
418
+ ```
419
+
420
+ When client certificate validation is enabled, unknown client certificates are rejected
421
+ until trusted.
422
+
423
+ ## Docker And Network Notes
424
+
425
+ `localhost` means "inside this runtime".
426
+
427
+ Common cases:
428
+
429
+ - Node-RED and OPC-UA server on the same host: `opc.tcp://localhost:4840/...`
430
+ - Node-RED in Docker, server on host machine: use the host name/IP reachable from the
431
+ container, not `localhost`.
432
+ - Node-RED in Docker Compose: use the service name if both containers share a network.
433
+ - Remote PLC/server: use the PLC/server IP or DNS name and ensure the OPC-UA port is open.
434
+
435
+ ## Troubleshooting
436
+
437
+ ### Node status says `error` or operation times out
438
+
439
+ - Confirm the endpoint URL, port, and resource path.
440
+ - Confirm Node-RED can reach the server from its runtime environment.
441
+ - Increase `Op timeout` if the network is slow.
442
+ - Check whether the server requires security or credentials.
443
+
444
+ ### Secure connection fails with `BadCertificateUntrusted`
445
+
446
+ - Look in `<userDir>/opcua-pki/rejected`.
447
+ - Move the server certificate to `<userDir>/opcua-pki/trusted/certs`.
448
+ - Restart/reconnect the flow.
449
+ - Avoid **Accept untrusted server cert** outside development.
450
+
451
+ ### Username/password fails
452
+
453
+ - Check whether the server requires `SignAndEncrypt`.
454
+ - Confirm the username and password in the endpoint credentials.
455
+ - Confirm the server supports username/password user tokens for the selected endpoint.
456
+
457
+ ### Browse works but read/write fails
458
+
459
+ - Confirm the exact NodeId.
460
+ - Confirm the node exposes the `Value` attribute.
461
+ - For writes, confirm the server allows writing and the selected data type matches.
462
+
463
+ ### Subscribe emits nothing
464
+
465
+ - Confirm the node value actually changes.
466
+ - Check sampling/publishing intervals.
467
+ - Remove deadband while testing.
468
+ - Confirm the server permits subscriptions.
469
+
470
+ ### Node-RED does not show the nodes
471
+
472
+ - Confirm Node.js is `>=22.9.0`.
473
+ - Confirm the package is installed in the Node-RED user directory or through Palette Manager.
474
+ - Restart Node-RED after installing if needed.
475
+
476
+ ## Development
477
+
478
+ ```bash
479
+ npm install
480
+ npm run lint
481
+ npm test
482
+ ```
483
+
484
+ Run a local test server:
485
+
486
+ ```bash
487
+ node test/helpers/standalone-server.js 4841
488
+ ```
489
+
490
+ It exposes:
491
+
492
+ ```text
493
+ ns=1;s=Temperature
494
+ ns=1;s=Label
495
+ ns=1;s=Setpoint
496
+ ```
497
+
498
+ ## Project Status
499
+
500
+ `0.1.0` is the first public release. The core client/server workflows are implemented and
501
+ tested. Deferred items include OPC-UA method calls, X.509 user authentication, and richer
502
+ server-side address-space modeling.
503
+
504
+ ## License
505
+
506
+ MIT © jsgorana