@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.
@@ -0,0 +1,146 @@
1
+ [
2
+ {
3
+ "id": "cq_tab",
4
+ "type": "tab",
5
+ "label": "OPC-UA · Client Quickstart",
6
+ "disabled": false,
7
+ "info": "# OPC-UA Client Quickstart\n\nRead, write, browse and subscribe against an OPC-UA server.\n\n## Set up the Endpoint first\n1. Double-click any OPC-UA node → open the **Endpoint** config (pencil icon).\n2. **URL**: `opc.tcp://HOST:PORT[/path]`, e.g. `opc.tcp://localhost:4840`.\n - Use `localhost` only if the server runs on the **same machine** as Node-RED.\n - Otherwise use the server's **hostname or IP address**. (If Node-RED runs in a\n container/VM, `localhost` points at that container — use the server's reachable address.)\n3. **Security / Authentication** must match the server (default: None / Anonymous).\n For Sign/SignAndEncrypt, see the endpoint node's help for certificate trust.\n4. **Deploy**, then click the inject buttons and watch the **Debug** sidebar.\n\n> If the endpoint is wrong, the nodes show a red **error** status and read/write\n> time out. Fix the URL/security and redeploy.\n\nEach coloured group is one independent pattern — use what you need."
8
+ },
9
+
10
+ {
11
+ "id": "cq_help",
12
+ "type": "comment",
13
+ "z": "cq_tab",
14
+ "name": "⚠ Configure the Endpoint first — opc.tcp://HOST:PORT (HOST = localhost only if the server is on this machine, else its hostname/IP). Wrong endpoint = red 'error' on nodes.",
15
+ "info": "Open any OPC-UA node and edit its Endpoint config:\n- URL: opc.tcp://HOST:PORT[/path]\n- HOST = localhost if the server runs on the same machine as Node-RED; otherwise the server's hostname or IP\n- Security/Auth must match the server (default None/Anonymous)\nThen Deploy.",
16
+ "x": 320,
17
+ "y": 30,
18
+ "wires": []
19
+ },
20
+
21
+ {
22
+ "id": "cq_g_read",
23
+ "type": "group",
24
+ "z": "cq_tab",
25
+ "name": "READ — get a value on demand",
26
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#bdd7e7", "fill-opacity": "0.4" },
27
+ "nodes": ["cq_read_c", "cq_read_in", "cq_read", "cq_read_dbg"],
28
+ "x": 74, "y": 70, "w": 762, "h": 132
29
+ },
30
+ {
31
+ "id": "cq_read_c", "type": "comment", "z": "cq_tab", "g": "cq_g_read",
32
+ "name": "Inject → opcua-read → debug. Edit the node's Node ID (e.g. ns=1;s=Temperature).",
33
+ "x": 340, "y": 110, "wires": []
34
+ },
35
+ {
36
+ "id": "cq_read_in", "type": "inject", "z": "cq_tab", "g": "cq_g_read",
37
+ "name": "Read", "props": [{ "p": "payload" }], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date",
38
+ "x": 170, "y": 160, "wires": [["cq_read"]]
39
+ },
40
+ {
41
+ "id": "cq_read", "type": "opcua-read", "z": "cq_tab", "g": "cq_g_read",
42
+ "name": "", "endpoint": "cq_endpoint", "nodeId": "ns=1;s=Temperature",
43
+ "x": 410, "y": 160, "wires": [["cq_read_dbg"]]
44
+ },
45
+ {
46
+ "id": "cq_read_dbg", "type": "debug", "z": "cq_tab", "g": "cq_g_read",
47
+ "name": "value", "active": true, "complete": "payload", "targetType": "msg",
48
+ "x": 650, "y": 160, "wires": []
49
+ },
50
+
51
+ {
52
+ "id": "cq_g_write",
53
+ "type": "group",
54
+ "z": "cq_tab",
55
+ "name": "WRITE — send a value (msg.payload), type set on the node",
56
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#c7e9c0", "fill-opacity": "0.4" },
57
+ "nodes": ["cq_write_c", "cq_write_in", "cq_write", "cq_write_dbg"],
58
+ "x": 74, "y": 222, "w": 762, "h": 132
59
+ },
60
+ {
61
+ "id": "cq_write_c", "type": "comment", "z": "cq_tab", "g": "cq_g_write",
62
+ "name": "Inject payload 42.5 → opcua-write (Double) → debug shows the write status code.",
63
+ "x": 350, "y": 262, "wires": []
64
+ },
65
+ {
66
+ "id": "cq_write_in", "type": "inject", "z": "cq_tab", "g": "cq_g_write",
67
+ "name": "Write 42.5", "props": [{ "p": "payload" }], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "42.5", "payloadType": "num",
68
+ "x": 180, "y": 312, "wires": [["cq_write"]]
69
+ },
70
+ {
71
+ "id": "cq_write", "type": "opcua-write", "z": "cq_tab", "g": "cq_g_write",
72
+ "name": "", "endpoint": "cq_endpoint", "nodeId": "ns=1;s=Setpoint", "dataType": "Double",
73
+ "x": 410, "y": 312, "wires": [["cq_write_dbg"]]
74
+ },
75
+ {
76
+ "id": "cq_write_dbg", "type": "debug", "z": "cq_tab", "g": "cq_g_write",
77
+ "name": "status", "active": true, "complete": "statusCode", "targetType": "msg",
78
+ "x": 650, "y": 312, "wires": []
79
+ },
80
+
81
+ {
82
+ "id": "cq_g_browse",
83
+ "type": "group",
84
+ "z": "cq_tab",
85
+ "name": "BROWSE — discover the address space",
86
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#fdd0a2", "fill-opacity": "0.4" },
87
+ "nodes": ["cq_browse_c", "cq_browse_in", "cq_browse", "cq_browse_dbg"],
88
+ "x": 74, "y": 374, "w": 762, "h": 132
89
+ },
90
+ {
91
+ "id": "cq_browse_c", "type": "comment", "z": "cq_tab", "g": "cq_g_browse",
92
+ "name": "Returns an array of child references. Start at ObjectsFolder, then drill into a Node ID.",
93
+ "x": 360, "y": 414, "wires": []
94
+ },
95
+ {
96
+ "id": "cq_browse_in", "type": "inject", "z": "cq_tab", "g": "cq_g_browse",
97
+ "name": "Browse", "props": [{ "p": "payload" }], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date",
98
+ "x": 170, "y": 464, "wires": [["cq_browse"]]
99
+ },
100
+ {
101
+ "id": "cq_browse", "type": "opcua-browse", "z": "cq_tab", "g": "cq_g_browse",
102
+ "name": "", "endpoint": "cq_endpoint", "nodeId": "ObjectsFolder",
103
+ "x": 410, "y": 464, "wires": [["cq_browse_dbg"]]
104
+ },
105
+ {
106
+ "id": "cq_browse_dbg", "type": "debug", "z": "cq_tab", "g": "cq_g_browse",
107
+ "name": "references", "active": true, "complete": "payload", "targetType": "msg",
108
+ "x": 660, "y": 464, "wires": []
109
+ },
110
+
111
+ {
112
+ "id": "cq_g_sub",
113
+ "type": "group",
114
+ "z": "cq_tab",
115
+ "name": "SUBSCRIBE — stream value changes (no input needed)",
116
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#d6c9f1", "fill-opacity": "0.4" },
117
+ "nodes": ["cq_sub_c", "cq_sub", "cq_sub_dbg"],
118
+ "x": 74, "y": 526, "w": 762, "h": 132
119
+ },
120
+ {
121
+ "id": "cq_sub_c", "type": "comment", "z": "cq_tab", "g": "cq_g_sub",
122
+ "name": "Arms automatically on deploy and re-arms after a reconnect. Emits on every change.",
123
+ "x": 350, "y": 566, "wires": []
124
+ },
125
+ {
126
+ "id": "cq_sub", "type": "opcua-subscribe", "z": "cq_tab", "g": "cq_g_sub",
127
+ "name": "", "endpoint": "cq_endpoint", "nodeId": "ns=1;s=Temperature",
128
+ "samplingInterval": 1000, "publishingInterval": 1000,
129
+ "x": 200, "y": 616, "wires": [["cq_sub_dbg"]]
130
+ },
131
+ {
132
+ "id": "cq_sub_dbg", "type": "debug", "z": "cq_tab", "g": "cq_g_sub",
133
+ "name": "live value", "active": true, "complete": "payload", "targetType": "msg",
134
+ "x": 470, "y": 616, "wires": []
135
+ },
136
+
137
+ {
138
+ "id": "cq_endpoint",
139
+ "type": "opcua-endpoint",
140
+ "name": "OPC-UA Server",
141
+ "endpointUrl": "opc.tcp://localhost:4840",
142
+ "securityMode": "None",
143
+ "securityPolicy": "None",
144
+ "authType": "anonymous"
145
+ }
146
+ ]
@@ -0,0 +1,197 @@
1
+ [
2
+ {
3
+ "id": "demo_tab",
4
+ "type": "tab",
5
+ "label": "OPC-UA · Server + Client Demo",
6
+ "disabled": false,
7
+ "info": "# OPC-UA Server + Client — self-contained demo\n\nThis flow runs **both** an OPC-UA server and a client in the same Node-RED, so it\nworks the moment you **Deploy** — no external server needed.\n\n## How it works\n1. **Server** (orange): click **Simulate sensor** to push a random temperature\n into the `Temperature` variable the server exposes.\n2. **Client** (blue): reads + subscribes to that same server on\n `opc.tcp://localhost:4840/UA/NodeRED`, and can write the `Setpoint`.\n3. When the client writes `Setpoint`, the **server's output** reports it.\n\n## Try it\n- Click **Deploy**, then open the **Debug** sidebar.\n- Click **Simulate sensor** a few times — *Live temperature* (subscription) and\n *Read once* both reflect the new value.\n- Click **Write Setpoint = 50** and see the server report the client write.\n\n## Endpoint note\nThe client Endpoint here is `opc.tcp://localhost:4840/UA/NodeRED`, which works because\nthe server and client run in the **same** Node-RED. To connect to a server elsewhere,\nuse that server's **hostname or IP** instead of `localhost` (and make sure the port is\nreachable). A wrong endpoint makes the client nodes show a red **error** status."
8
+ },
9
+
10
+ {
11
+ "id": "demo_help",
12
+ "type": "comment",
13
+ "z": "demo_tab",
14
+ "name": "Self-contained: the client talks to the server on opc.tcp://localhost:4840/UA/NodeRED. Click 'Simulate sensor' to drive it. (For a remote server, use its hostname/IP.)",
15
+ "info": "Client Endpoint = opc.tcp://localhost:4840/UA/NodeRED.\nlocalhost works because server+client share this Node-RED.\nTo connect to a server elsewhere, use that server's hostname or IP.\nWrong endpoint = red 'error' on client nodes.",
16
+ "x": 360,
17
+ "y": 30,
18
+ "wires": []
19
+ },
20
+
21
+ {
22
+ "id": "demo_g_server",
23
+ "type": "group",
24
+ "z": "demo_tab",
25
+ "name": "1 · OPC-UA SERVER — exposes Node-RED data",
26
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#fdd0a2", "fill-opacity": "0.4" },
27
+ "nodes": ["demo_s_note", "demo_s_tick", "demo_s_fn", "demo_s_server", "demo_s_dbg"],
28
+ "x": 74, "y": 60, "w": 752, "h": 212
29
+ },
30
+ {
31
+ "id": "demo_s_note",
32
+ "type": "comment",
33
+ "z": "demo_tab",
34
+ "g": "demo_g_server",
35
+ "name": "Click 'Simulate sensor' to push a value into the served 'Temperature' variable",
36
+ "x": 360, "y": 100, "wires": []
37
+ },
38
+ {
39
+ "id": "demo_s_tick",
40
+ "type": "inject",
41
+ "z": "demo_tab",
42
+ "g": "demo_g_server",
43
+ "name": "Simulate sensor",
44
+ "props": [{ "p": "payload" }], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date",
45
+ "x": 180, "y": 150,
46
+ "wires": [["demo_s_fn"]]
47
+ },
48
+ {
49
+ "id": "demo_s_fn",
50
+ "type": "function",
51
+ "z": "demo_tab",
52
+ "g": "demo_g_server",
53
+ "name": "Random 20–25 °C",
54
+ "func": "msg.topic = 'Temperature';\nmsg.payload = Math.round((20 + Math.random() * 5) * 100) / 100;\nreturn msg;",
55
+ "outputs": 1,
56
+ "x": 410, "y": 150,
57
+ "wires": [["demo_s_server"]]
58
+ },
59
+ {
60
+ "id": "demo_s_server",
61
+ "type": "opcua-server",
62
+ "z": "demo_tab",
63
+ "g": "demo_g_server",
64
+ "name": "Node-RED OPC-UA Server",
65
+ "port": 4840,
66
+ "resourcePath": "/UA/NodeRED",
67
+ "serverName": "Node-RED OPC-UA Server",
68
+ "folderName": "NodeRED",
69
+ "allowAnonymous": true,
70
+ "variables": [
71
+ { "name": "Temperature", "dataType": "Double", "value": "20" },
72
+ { "name": "Setpoint", "dataType": "Double", "value": "0" }
73
+ ],
74
+ "x": 640, "y": 150,
75
+ "wires": [["demo_s_dbg"]]
76
+ },
77
+ {
78
+ "id": "demo_s_dbg",
79
+ "type": "debug",
80
+ "z": "demo_tab",
81
+ "g": "demo_g_server",
82
+ "name": "Client wrote →",
83
+ "active": true, "complete": "true", "targetType": "full",
84
+ "x": 650, "y": 220, "wires": []
85
+ },
86
+
87
+ {
88
+ "id": "demo_g_client",
89
+ "type": "group",
90
+ "z": "demo_tab",
91
+ "name": "2 · OPC-UA CLIENT — reads from the server above",
92
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#bdd7e7", "fill-opacity": "0.4" },
93
+ "nodes": ["demo_c_note", "demo_c_read_tick", "demo_c_read", "demo_c_read_dbg", "demo_c_sub", "demo_c_sub_dbg", "demo_c_write_tick", "demo_c_write", "demo_c_write_dbg"],
94
+ "x": 74, "y": 300, "w": 752, "h": 300
95
+ },
96
+ {
97
+ "id": "demo_c_note",
98
+ "type": "comment",
99
+ "z": "demo_tab",
100
+ "g": "demo_g_client",
101
+ "name": "Connects to opc.tcp://localhost:4840/UA/NodeRED (the server above)",
102
+ "x": 290, "y": 340, "wires": []
103
+ },
104
+ {
105
+ "id": "demo_c_read_tick",
106
+ "type": "inject",
107
+ "z": "demo_tab",
108
+ "g": "demo_g_client",
109
+ "name": "Read once",
110
+ "props": [{ "p": "payload" }], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date",
111
+ "x": 180, "y": 390,
112
+ "wires": [["demo_c_read"]]
113
+ },
114
+ {
115
+ "id": "demo_c_read",
116
+ "type": "opcua-read",
117
+ "z": "demo_tab",
118
+ "g": "demo_g_client",
119
+ "name": "read Temperature",
120
+ "endpoint": "demo_endpoint",
121
+ "nodeId": "ns=1;s=Temperature",
122
+ "x": 410, "y": 390,
123
+ "wires": [["demo_c_read_dbg"]]
124
+ },
125
+ {
126
+ "id": "demo_c_read_dbg",
127
+ "type": "debug",
128
+ "z": "demo_tab",
129
+ "g": "demo_g_client",
130
+ "name": "Read value",
131
+ "active": true, "complete": "payload", "targetType": "msg",
132
+ "x": 650, "y": 390, "wires": []
133
+ },
134
+ {
135
+ "id": "demo_c_sub",
136
+ "type": "opcua-subscribe",
137
+ "z": "demo_tab",
138
+ "g": "demo_g_client",
139
+ "name": "subscribe Temperature",
140
+ "endpoint": "demo_endpoint",
141
+ "nodeId": "ns=1;s=Temperature",
142
+ "samplingInterval": 1000,
143
+ "publishingInterval": 1000,
144
+ "x": 200, "y": 460,
145
+ "wires": [["demo_c_sub_dbg"]]
146
+ },
147
+ {
148
+ "id": "demo_c_sub_dbg",
149
+ "type": "debug",
150
+ "z": "demo_tab",
151
+ "g": "demo_g_client",
152
+ "name": "Live temperature",
153
+ "active": true, "complete": "payload", "targetType": "msg",
154
+ "x": 470, "y": 460, "wires": []
155
+ },
156
+ {
157
+ "id": "demo_c_write_tick",
158
+ "type": "inject",
159
+ "z": "demo_tab",
160
+ "g": "demo_g_client",
161
+ "name": "Write Setpoint = 50",
162
+ "props": [{ "p": "payload" }], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "50", "payloadType": "num",
163
+ "x": 190, "y": 540,
164
+ "wires": [["demo_c_write"]]
165
+ },
166
+ {
167
+ "id": "demo_c_write",
168
+ "type": "opcua-write",
169
+ "z": "demo_tab",
170
+ "g": "demo_g_client",
171
+ "name": "write Setpoint",
172
+ "endpoint": "demo_endpoint",
173
+ "nodeId": "ns=1;s=Setpoint",
174
+ "dataType": "Double",
175
+ "x": 410, "y": 540,
176
+ "wires": [["demo_c_write_dbg"]]
177
+ },
178
+ {
179
+ "id": "demo_c_write_dbg",
180
+ "type": "debug",
181
+ "z": "demo_tab",
182
+ "g": "demo_g_client",
183
+ "name": "Write status",
184
+ "active": true, "complete": "statusCode", "targetType": "msg",
185
+ "x": 650, "y": 540, "wires": []
186
+ },
187
+
188
+ {
189
+ "id": "demo_endpoint",
190
+ "type": "opcua-endpoint",
191
+ "name": "Local Node-RED Server",
192
+ "endpointUrl": "opc.tcp://localhost:4840/UA/NodeRED",
193
+ "securityMode": "None",
194
+ "securityPolicy": "None",
195
+ "authType": "anonymous"
196
+ }
197
+ ]
@@ -0,0 +1,83 @@
1
+ [
2
+ {
3
+ "id": "sq_tab",
4
+ "type": "tab",
5
+ "label": "OPC-UA · Server Quickstart",
6
+ "disabled": false,
7
+ "info": "# OPC-UA Server Quickstart\n\nExpose Node-RED data as an OPC-UA server that external clients (SCADA, MES,\nother Node-RED instances) can read, subscribe to, and write.\n\n## Setup\n1. The **opcua-server** node is preconfigured on port `4840`, path `/UA/NodeRED`,\n with two variables: `Temperature` and `Setpoint`.\n2. **Deploy.** The node badge shows `running :4840`.\n3. Click **Update Temperature** to push a value into the server.\n4. The right group reports values **written by clients**.\n\n## Connect a client to this server\nFrom any OPC-UA client (incl. the *Client Quickstart* example) set the endpoint to:\n```\nopc.tcp://localhost:4840/UA/NodeRED\n```\n- Use `localhost` only if the client runs on the **same machine** as this server;\n otherwise use this machine's **hostname or IP** (and ensure the port is reachable).\n- Security None / Anonymous matches the defaults here.\n- A wrong URL/port/path makes the client show a red **error** status.\n\n## Update / add variables\nSend `msg.topic = \"<name>\"`, `msg.payload = <value>`. Unknown names are created\non the fly (set `msg.dataType` to choose the type, default Double)."
8
+ },
9
+
10
+ {
11
+ "id": "sq_help",
12
+ "type": "comment",
13
+ "z": "sq_tab",
14
+ "name": "Clients connect to opc.tcp://HOST:4840/UA/NodeRED (HOST = localhost if on this machine, else this machine's hostname/IP). Wrong URL/port/path = red 'error' on the client.",
15
+ "info": "This node IS the server. Point a client's Endpoint at:\nopc.tcp://HOST:4840/UA/NodeRED\n- HOST = localhost if the client is on the same machine, otherwise this machine's hostname or IP\n- Security None / Anonymous by default",
16
+ "x": 360,
17
+ "y": 30,
18
+ "wires": []
19
+ },
20
+
21
+ {
22
+ "id": "sq_g_in",
23
+ "type": "group",
24
+ "z": "sq_tab",
25
+ "name": "FEED DATA IN — Node-RED → served variables",
26
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#c7e9c0", "fill-opacity": "0.4" },
27
+ "nodes": ["sq_in_c", "sq_tick", "sq_fn"],
28
+ "x": 74, "y": 70, "w": 472, "h": 132
29
+ },
30
+ {
31
+ "id": "sq_in_c", "type": "comment", "z": "sq_tab", "g": "sq_g_in",
32
+ "name": "Push a Temperature value the server exposes (click to send)",
33
+ "x": 270, "y": 110, "wires": []
34
+ },
35
+ {
36
+ "id": "sq_tick", "type": "inject", "z": "sq_tab", "g": "sq_g_in",
37
+ "name": "Update Temperature", "props": [{ "p": "payload" }], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date",
38
+ "x": 180, "y": 160, "wires": [["sq_fn"]]
39
+ },
40
+ {
41
+ "id": "sq_fn", "type": "function", "z": "sq_tab", "g": "sq_g_in",
42
+ "name": "Temperature 20–25", "func": "msg.topic = 'Temperature';\nmsg.payload = Math.round((20 + Math.random() * 5) * 100) / 100;\nreturn msg;",
43
+ "outputs": 1, "x": 400, "y": 160, "wires": [["sq_server"]]
44
+ },
45
+
46
+ {
47
+ "id": "sq_server",
48
+ "type": "opcua-server",
49
+ "z": "sq_tab",
50
+ "name": "Node-RED OPC-UA Server",
51
+ "port": 4840,
52
+ "resourcePath": "/UA/NodeRED",
53
+ "serverName": "Node-RED OPC-UA Server",
54
+ "folderName": "NodeRED",
55
+ "allowAnonymous": true,
56
+ "variables": [
57
+ { "name": "Temperature", "dataType": "Double", "value": "20" },
58
+ { "name": "Setpoint", "dataType": "Double", "value": "0" }
59
+ ],
60
+ "x": 400, "y": 270,
61
+ "wires": [["sq_out"]]
62
+ },
63
+
64
+ {
65
+ "id": "sq_g_out",
66
+ "type": "group",
67
+ "z": "sq_tab",
68
+ "name": "CLIENT WRITES OUT — react when a client changes a variable",
69
+ "style": { "label": true, "label-position": "nw", "color": "#3b3b3b", "fill": "#bdd7e7", "fill-opacity": "0.4" },
70
+ "nodes": ["sq_out_c", "sq_out"],
71
+ "x": 74, "y": 360, "w": 472, "h": 132
72
+ },
73
+ {
74
+ "id": "sq_out_c", "type": "comment", "z": "sq_tab", "g": "sq_g_out",
75
+ "name": "Emitted on every client write: {topic, payload, nodeId, source}",
76
+ "x": 280, "y": 400, "wires": []
77
+ },
78
+ {
79
+ "id": "sq_out", "type": "debug", "z": "sq_tab", "g": "sq_g_out",
80
+ "name": "client wrote", "active": true, "complete": "true", "targetType": "full",
81
+ "x": 250, "y": 450, "wires": []
82
+ }
83
+ ]