node-red-contrib-omron-eip 0.2.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/LICENSE +339 -0
- package/MANUAL.md +457 -0
- package/README.md +472 -0
- package/nodes/common.js +237 -0
- package/nodes/omron-plc.html +152 -0
- package/nodes/omron-plc.js +131 -0
- package/nodes/omron-read.html +299 -0
- package/nodes/omron-read.js +135 -0
- package/nodes/omron-write.html +416 -0
- package/nodes/omron-write.js +163 -0
- package/package.json +52 -0
package/MANUAL.md
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
# Omron EtherNet/IP Nodes for Node-RED — User Manual
|
|
2
|
+
|
|
3
|
+
A complete guide to using the `node-red-contrib-omron-eip` nodes to read and write Omron
|
|
4
|
+
NX/NJ controller tags from your Node-RED flows. No programming required.
|
|
5
|
+
|
|
6
|
+
This manual assumes the nodes are already installed (see `DOCKER_INSTALL_AND_TEST.md` or the
|
|
7
|
+
README) and that you can open the Node-RED editor.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Contents
|
|
12
|
+
|
|
13
|
+
1. [Concepts: how it fits together](#1-concepts-how-it-fits-together)
|
|
14
|
+
2. [The three nodes at a glance](#2-the-three-nodes-at-a-glance)
|
|
15
|
+
3. [Setting up the PLC connection (config node)](#3-setting-up-the-plc-connection-config-node)
|
|
16
|
+
4. [The read node — every field explained](#4-the-read-node-every-field-explained)
|
|
17
|
+
5. [The write node — every field explained](#5-the-write-node-every-field-explained)
|
|
18
|
+
6. [Variable names: scalars, arrays, structures, nesting](#6-variable-names-scalars-arrays-structures-nesting)
|
|
19
|
+
7. [Message formats in and out](#7-message-formats-in-and-out)
|
|
20
|
+
8. [Triggering: messages, polling, and on-deploy](#8-triggering-messages-polling-and-on-deploy)
|
|
21
|
+
9. [Test Connection, Load and Validate Published Variables](#9-test-connection-load-and-validate-published-variables)
|
|
22
|
+
10. [Error handling](#10-error-handling)
|
|
23
|
+
11. [Common flow recipes](#11-common-flow-recipes)
|
|
24
|
+
12. [Performance & best practices](#12-performance-best-practices)
|
|
25
|
+
13. [Troubleshooting](#13-troubleshooting)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Concepts: how it fits together
|
|
30
|
+
|
|
31
|
+
Three pieces work together:
|
|
32
|
+
|
|
33
|
+
- **The controller (PLC).** Your Omron NX/NJ. It exposes *tags* (variables) over EtherNet/IP.
|
|
34
|
+
- **The connection (config node `omron-plc`).** A single shared connection to one controller.
|
|
35
|
+
You set it up once; many read/write nodes use it.
|
|
36
|
+
- **The operations (`omron read`, `omron write`).** The nodes you drag into flows to actually
|
|
37
|
+
read or write tags.
|
|
38
|
+
|
|
39
|
+
The key idea: **one connection, many operations.** You don't configure an IP on every node —
|
|
40
|
+
you create one PLC connection and point your read/write nodes at it. Behind the scenes, all
|
|
41
|
+
operations to that controller share a single, auto-reconnecting link.
|
|
42
|
+
|
|
43
|
+
A typical flow looks like:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
[ trigger ] → [ omron read ] → [ do something with the value ]
|
|
47
|
+
[ event ] → [ omron write ] → [ confirm / next step ]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
where *trigger* is anything that produces a message (an inject node, a timer, a dashboard
|
|
51
|
+
control, another flow).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 2. The three nodes at a glance
|
|
56
|
+
|
|
57
|
+
| Node | Category | What it does |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| **omron-plc** | config | Holds the controller IP + messaging mode and the shared connection. Not placed on the canvas directly — created from a read/write node's PLC field. |
|
|
60
|
+
| **omron read** | Omron | Reads one or more tags. Outputs the values. Blue, download icon. |
|
|
61
|
+
| **omron write** | Omron | Writes one or more tags. Orange, upload icon. |
|
|
62
|
+
|
|
63
|
+
Both operational nodes have **two outputs**: the **top** output carries successful results,
|
|
64
|
+
the **bottom** output carries errors.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 3. Setting up the PLC connection (config node)
|
|
69
|
+
|
|
70
|
+
You create the connection the first time you add a read or write node:
|
|
71
|
+
|
|
72
|
+
1. Drag an **omron read** (or **omron write**) node onto the canvas and double-click it.
|
|
73
|
+
2. Next to the **PLC** field, click the **pencil** icon to add a new connection.
|
|
74
|
+
3. Fill in the config node:
|
|
75
|
+
|
|
76
|
+
| Field | What it is |
|
|
77
|
+
|---|---|
|
|
78
|
+
| **Name** | A friendly label, e.g. "Line 3 NX102". Optional but recommended — it's what you'll see in the PLC dropdown. |
|
|
79
|
+
| **Address** | The controller's IP address (the EtherNet/IP port your machine/container can reach), e.g. `192.168.250.1`. |
|
|
80
|
+
| **Messaging** | **UCMM** (recommended) or **Class 3 connected**. Leave on UCMM unless you have a specific reason (see below). |
|
|
81
|
+
|
|
82
|
+
4. Click **Add** to save the connection, then **Done** on the node.
|
|
83
|
+
5. **Deploy.** The connection is created when you deploy — not before.
|
|
84
|
+
|
|
85
|
+
### UCMM vs Class 3
|
|
86
|
+
|
|
87
|
+
**Use UCMM** (the default) for virtually all setups, especially a direct PC-to-PLC link. It's
|
|
88
|
+
faster, parallelizes, and has no large-array limit.
|
|
89
|
+
|
|
90
|
+
**Class 3** only helps when traffic routes through a gateway, comms module, or backplane to
|
|
91
|
+
reach the controller. On a direct connection it's slower (it serializes requests) and can't
|
|
92
|
+
read very large arrays. If the controller rejects Class 3, the library silently falls back to
|
|
93
|
+
UCMM, so enabling it never breaks anything — it just may not help.
|
|
94
|
+
|
|
95
|
+
One config node per controller is the norm. If you have two PLCs, make two config nodes.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 4. The read node — every field explained
|
|
100
|
+
|
|
101
|
+
Open an **omron read** node. Hover the small ⓘ icons in the editor for inline reminders; here's
|
|
102
|
+
the full reference.
|
|
103
|
+
|
|
104
|
+
**Connection**
|
|
105
|
+
- **Name** — optional canvas label. If blank, the node shows the tags it reads (e.g.
|
|
106
|
+
"read: Counter, Speed").
|
|
107
|
+
- **PLC** — which connection to use. Pick an existing config or create one.
|
|
108
|
+
|
|
109
|
+
**Variables**
|
|
110
|
+
- **Variables** — the list of tags to read, one per row. Free-form symbolic names (see
|
|
111
|
+
section 6). You can read scalars, whole arrays, whole structures, members, and elements.
|
|
112
|
+
- **Connect & validate** (button) — loads the live tag list from the controller for
|
|
113
|
+
autocomplete and checks each name (✓ found / ✗ not found). Requires a deployed PLC config
|
|
114
|
+
(section 9).
|
|
115
|
+
|
|
116
|
+
**Output**
|
|
117
|
+
- **Shape** — how results are emitted:
|
|
118
|
+
- *one message: payload = { name: value }* — all tags in a single message as an object.
|
|
119
|
+
- *one message per tag (topic = name)* — a separate message per tag, with `msg.topic` set
|
|
120
|
+
to the tag name and `msg.payload` to its value.
|
|
121
|
+
- **Msg override** — the name of a message property that, if present, replaces the configured
|
|
122
|
+
variable list at runtime. Default `variables` (i.e. set `msg.variables`). Lets a flow choose
|
|
123
|
+
what to read dynamically.
|
|
124
|
+
|
|
125
|
+
**Trigger**
|
|
126
|
+
- **Repeat** — milliseconds. If > 0, the node self-polls at that interval (in addition to
|
|
127
|
+
responding to incoming messages). 0 = only read when a message arrives.
|
|
128
|
+
- **Read once shortly after deploy** — performs one read ~1.5 s after deploy/restart, to fetch
|
|
129
|
+
an initial value with no trigger.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 5. The write node — every field explained
|
|
134
|
+
|
|
135
|
+
Open an **omron write** node.
|
|
136
|
+
|
|
137
|
+
**Connection**
|
|
138
|
+
- **Name** — optional canvas label.
|
|
139
|
+
- **PLC** — which connection to use.
|
|
140
|
+
|
|
141
|
+
**Values**
|
|
142
|
+
- **Source** — where write values come from:
|
|
143
|
+
- *From incoming message* — values arrive in `msg.payload` when the node is triggered. The
|
|
144
|
+
Variables rows are **names only**.
|
|
145
|
+
- *Fixed value(s) set here* — values are configured in the node. Each Variables row gains a
|
|
146
|
+
**typed value** field (number / boolean / string / JSON). The incoming message only
|
|
147
|
+
triggers the write; its payload is ignored.
|
|
148
|
+
|
|
149
|
+
**Variables**
|
|
150
|
+
- **Variables** — the tags to write, one per row. In *Fixed* mode each row also has a value and
|
|
151
|
+
a type selector. In *From message* mode, names only.
|
|
152
|
+
- **Connect & validate** — same as the read node.
|
|
153
|
+
|
|
154
|
+
**Options**
|
|
155
|
+
- **Verified write** — after writing, the node reads the value back and confirms it matches
|
|
156
|
+
what you sent. A normal write already gets an accepted/error reply from the controller, which
|
|
157
|
+
is enough almost always; verified write additionally catches the rarer case where the
|
|
158
|
+
controller *accepts* the write but the value isn't what you intended afterward — e.g. the PLC
|
|
159
|
+
program clamps it to a limit (you send 5000, it stores 4000), or another device overwrites the
|
|
160
|
+
tag immediately. Use it for important values (setpoints, recipe parameters). It costs one
|
|
161
|
+
extra read per tag, so it's slightly slower — leave it off for normal or high-rate writes. It
|
|
162
|
+
only checks the moment right after writing; a later change to the tag can't be detected.
|
|
163
|
+
|
|
164
|
+
**Trigger**
|
|
165
|
+
- **Repeat** — milliseconds. If > 0, the node writes automatically at that interval. With
|
|
166
|
+
*Fixed* values, this can force/hold a tag with nothing wired upstream.
|
|
167
|
+
- **Write once shortly after deploy** — one write ~1.5 s after deploy/restart. With *Fixed*
|
|
168
|
+
values, sets a tag to a known state at startup.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 6. Variable names: scalars, arrays, structures, nesting
|
|
173
|
+
|
|
174
|
+
Tags are addressed by their **symbolic name** exactly as defined in the controller. The same
|
|
175
|
+
text field handles every case — there are no separate "array mode" or "struct mode" controls.
|
|
176
|
+
|
|
177
|
+
| You want | Type the name | Read result / write value |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| A scalar | `Counter` | a number/boolean/string |
|
|
180
|
+
| A whole array | `MyArray` | a JS array `[…]` |
|
|
181
|
+
| One array element | `MyArray[3]` | a single value |
|
|
182
|
+
| A whole structure | `MyStruct` | a JS object `{…}` |
|
|
183
|
+
| A structure member | `MyStruct.Speed` | a single value |
|
|
184
|
+
| Element of an array in a struct | `MyStruct.History[2]` | a single value |
|
|
185
|
+
| Member of a struct in an array | `Machine.Axes[2].Position` | a single value |
|
|
186
|
+
| Deeper nesting | `Cell.Stations[1].Tools[3].Offset` | a single value |
|
|
187
|
+
|
|
188
|
+
**Whole vs. member.** Reading or writing a whole array/structure moves all of it in one
|
|
189
|
+
operation — the fast path for bulk data (section 12 of the install/test guide). Reading or
|
|
190
|
+
writing a single member touches just that piece.
|
|
191
|
+
|
|
192
|
+
**Writing whole structures safely.** A whole-structure write overwrites *every* member. If
|
|
193
|
+
another writer might change a member at the same time, write the specific member
|
|
194
|
+
(`MyStruct.Speed`) instead to avoid a read-modify-write race.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 7. Message formats in and out
|
|
199
|
+
|
|
200
|
+
### Read output
|
|
201
|
+
|
|
202
|
+
*One message* shape (default) — `msg.payload` is an object keyed by tag name:
|
|
203
|
+
```json
|
|
204
|
+
{ "Counter": 42, "Speed": 1500 }
|
|
205
|
+
```
|
|
206
|
+
When reading a single tag, `msg.topic` is also set to that tag name.
|
|
207
|
+
|
|
208
|
+
*Per tag* shape — one message per tag:
|
|
209
|
+
```
|
|
210
|
+
msg.topic = "Counter" msg.payload = 42
|
|
211
|
+
msg.topic = "Speed" msg.payload = 1500
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
If some tags in a batch fail (e.g. one name is wrong), the good values still come through and
|
|
215
|
+
the failures appear on `msg.errors = { name: reason }`.
|
|
216
|
+
|
|
217
|
+
### Write input (when Source = From incoming message)
|
|
218
|
+
|
|
219
|
+
**One configured variable** — send the bare value:
|
|
220
|
+
```js
|
|
221
|
+
msg.payload = 1500
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Multiple configured variables** — send an object keyed by name:
|
|
225
|
+
```js
|
|
226
|
+
msg.payload = { "Setpoint": 1500, "Mode": 3, "Enable": true }
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**A whole structure or array as a value** — nest it under the variable name:
|
|
230
|
+
```js
|
|
231
|
+
msg.payload = { "Recipe": { "Speed": 100, "Steps": [1, 2, 3] } }
|
|
232
|
+
msg.payload = { "Profile": [10, 20, 30, 40] }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Write output
|
|
236
|
+
|
|
237
|
+
On success the message passes through with `msg.payload` set to the map of what was written,
|
|
238
|
+
e.g. `{ "Setpoint": 1500 }`. On failure, the error output carries `msg.error` (a readable
|
|
239
|
+
summary naming the variable and reason) and `msg.errors` (per-variable detail).
|
|
240
|
+
|
|
241
|
+
> **Data types matter.** Node-RED's inject node defaults `msg.payload` to **string**. Sending
|
|
242
|
+
> the string `"1500"` to a numeric tag fails. Set the inject (or your upstream node) to emit a
|
|
243
|
+
> **number** for numeric tags, **boolean** for BOOLs, **JSON** for arrays/objects.
|
|
244
|
+
|
|
245
|
+
### Data type reference
|
|
246
|
+
|
|
247
|
+
The value type you choose (number / boolean / string / JSON) is a **Node-RED** type, not the
|
|
248
|
+
PLC type. The library knows each tag's real Omron type and encodes your value automatically.
|
|
249
|
+
The write node also has a built-in **Data type reference** button showing this table.
|
|
250
|
+
|
|
251
|
+
| Node-RED type | Sysmac / Omron types | How to enter the value | Range / notes |
|
|
252
|
+
|---|---|---|---|
|
|
253
|
+
| **number** | SINT | integer | -128 … 127 |
|
|
254
|
+
| **number** | INT | integer | -32,768 … 32,767 |
|
|
255
|
+
| **number** | DINT | integer | -2,147,483,648 … 2,147,483,647 |
|
|
256
|
+
| **number** | LINT | integer (64-bit) | ±9.22e18 — see 64-bit note |
|
|
257
|
+
| **number** | USINT | integer | 0 … 255 |
|
|
258
|
+
| **number** | UINT | integer | 0 … 65,535 |
|
|
259
|
+
| **number** | UDINT | integer | 0 … 4,294,967,295 |
|
|
260
|
+
| **number** | ULINT | integer (64-bit) | 0 … 1.84e19 — see 64-bit note |
|
|
261
|
+
| **number** | BYTE | integer (8-bit bit string) | 0 … 255 |
|
|
262
|
+
| **number** | WORD | integer (16-bit bit string) | 0 … 65,535 |
|
|
263
|
+
| **number** | DWORD | integer (32-bit bit string) | 0 … 4,294,967,295 |
|
|
264
|
+
| **number** | LWORD | integer (64-bit bit string) | 0 … 1.84e19 — see 64-bit note |
|
|
265
|
+
| **number** | REAL | float (single) | ~7 significant digits |
|
|
266
|
+
| **number** | LREAL | float (double) | ~15 significant digits |
|
|
267
|
+
| **number** | ENUM | integer (enum value) | 0 … 4,294,967,295 |
|
|
268
|
+
| **boolean** | BOOL | true / false | |
|
|
269
|
+
| **string** | STRING | text | up to 1986 characters (this controller) |
|
|
270
|
+
| **JSON** | ARRAY (of any type) | a JSON array, e.g. `[1,2,3]` | whole-array write |
|
|
271
|
+
| **JSON** | STRUCT (UDT) | a JSON object, e.g. `{"Speed":100}` | whole-structure write |
|
|
272
|
+
| **JSON** | UNION | a JSON object/array | layout is type-specific |
|
|
273
|
+
| **number** | DATE, DATE_AND_TIME | nanoseconds since 1970 (epoch ms × 1,000,000) | reads back as a date; verified to ms precision |
|
|
274
|
+
| **number** | TIME, TIME_OF_DAY | nanoseconds (a number) | duration; verified to ms precision |
|
|
275
|
+
|
|
276
|
+
**64-bit note (LINT / ULINT / LWORD):** these can exceed JavaScript's safe integer limit
|
|
277
|
+
(~9.0e15). Values within that range work as plain numbers; beyond it, precision can be lost
|
|
278
|
+
entering them as a JS number — handle very large 64-bit values with care.
|
|
279
|
+
|
|
280
|
+
**Date and time types (DATE, DATE_AND_TIME, TIME, TIME_OF_DAY):** send a **number of
|
|
281
|
+
nanoseconds**, with the value-type set to `number`.
|
|
282
|
+
- **DATE / DATE_AND_TIME** use nanoseconds since 1970-01-01 UTC — i.e. epoch milliseconds ×
|
|
283
|
+
1,000,000. For example, `1767270896789000000` is 2026-01-01 12:34:56.789 UTC. They read back
|
|
284
|
+
as a date (an ISO timestamp in the payload).
|
|
285
|
+
- **TIME / TIME_OF_DAY** are a nanosecond duration — e.g. `5000000000` is 5 seconds.
|
|
286
|
+
- These are **verified to millisecond precision**. The full nanosecond value is a very large
|
|
287
|
+
(19-digit) integer, so digits below the millisecond can be lost when entered as a plain
|
|
288
|
+
number; values are reliable down to the millisecond. **String input is not accepted** for
|
|
289
|
+
these types — use a number.
|
|
290
|
+
|
|
291
|
+
**Out-of-range values are rejected** with a clear error (e.g. a BYTE only accepts 0–255).
|
|
292
|
+
|
|
293
|
+
### Generating example JSON
|
|
294
|
+
|
|
295
|
+
Both nodes can generate an example of their message shape so you don't have to construct it by
|
|
296
|
+
hand:
|
|
297
|
+
|
|
298
|
+
- **Read node — "Show output JSON"** (in the Output section): generates an example of the
|
|
299
|
+
`msg.payload` this node will emit, based on the variables you've added and the selected
|
|
300
|
+
output shape. In one-message mode it shows the `{ name: value }` object; in per-tag mode it
|
|
301
|
+
shows the `{ topic, payload }` form.
|
|
302
|
+
- **Write node — "Show input JSON"** (shown in *From incoming message* mode): generates an
|
|
303
|
+
example of the `msg.payload` to send this node. For a single variable it shows the bare
|
|
304
|
+
value; for multiple it shows the `{ "VarName": value, ... }` object.
|
|
305
|
+
|
|
306
|
+
Both include a **Copy** button. Press **Test Connection, Load and Validate Published
|
|
307
|
+
Variables** first and the examples use the **real types** (numbers, booleans, strings,
|
|
308
|
+
arrays, structures) pulled from the controller; otherwise they show generic `<value>`
|
|
309
|
+
placeholders with a note reminding you to validate.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 8. Triggering: messages, polling, and on-deploy
|
|
314
|
+
|
|
315
|
+
Both nodes act when triggered. There are three trigger sources, and they combine:
|
|
316
|
+
|
|
317
|
+
1. **Incoming message** — the default. Any message arriving at the node's input fires it. Wire
|
|
318
|
+
an inject, a timer, a dashboard control, or another flow into it. (For writes in *From
|
|
319
|
+
message* mode, the message also carries the value.)
|
|
320
|
+
|
|
321
|
+
2. **Repeat (self-poll)** — set Repeat to N ms and the node fires itself every N ms with no
|
|
322
|
+
upstream node. For reads, this is steady polling. For writes with *Fixed* values, this
|
|
323
|
+
forces/holds a tag.
|
|
324
|
+
|
|
325
|
+
3. **Once after deploy** — fires a single operation ~1.5 s after the flow deploys/restarts.
|
|
326
|
+
Good for fetching an initial value or setting a startup state.
|
|
327
|
+
|
|
328
|
+
You can use any combination. A read node can self-poll *and* respond to messages. A write node
|
|
329
|
+
can fire once at deploy *and* on incoming events.
|
|
330
|
+
|
|
331
|
+
> **A note on writes that fire themselves:** continuously writing the same value is occasionally
|
|
332
|
+
> what you want (a heartbeat, holding an enable bit), but usually writes should happen in
|
|
333
|
+
> response to an event. Use Repeat/after-deploy on writes deliberately.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## 9. Test Connection, Load and Validate Published Variables
|
|
338
|
+
|
|
339
|
+
Both edit panels have a button labeled **"Test Connection, Load and Validate Published
|
|
340
|
+
Variables"** under the variable list. It:
|
|
341
|
+
|
|
342
|
+
- Connects to the controller (via the deployed PLC config),
|
|
343
|
+
- Loads every variable that is marked **"Publish Only"** (or Input/Output) on the controller,
|
|
344
|
+
- Gives you **autocomplete** as you type variable names,
|
|
345
|
+
- Marks each configured name with **✓** (exists on the controller) or **✗** (not found).
|
|
346
|
+
|
|
347
|
+
**It only works after you Deploy.** The button talks to the running flow, which only knows
|
|
348
|
+
about a PLC config once it's been deployed. If you click it on a brand-new, undeployed config
|
|
349
|
+
you'll see "config node not found or not deployed yet" — just Deploy first, then click it.
|
|
350
|
+
|
|
351
|
+
The button is a convenience for catching typos before runtime. It is **not required** —
|
|
352
|
+
reads and writes work whether or not you've validated. (If validation ever reports a connection
|
|
353
|
+
error, it means the editor backend couldn't reach the PLC; check the connection the same way as
|
|
354
|
+
any read.)
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## 10. Error handling
|
|
359
|
+
|
|
360
|
+
Errors are surfaced three ways, so you can handle them however your flow prefers:
|
|
361
|
+
|
|
362
|
+
1. **Second output (error port).** The bottom output emits a message on failure, with
|
|
363
|
+
`msg.error` describing what went wrong (and `msg.errors` for per-variable detail on writes).
|
|
364
|
+
Wire it to a debug node, a notification, a retry, etc.
|
|
365
|
+
|
|
366
|
+
2. **Catch nodes.** Errors also raise through Node-RED's standard mechanism, so a **Catch** node
|
|
367
|
+
anywhere on the flow tab will receive them — useful for centralized error handling.
|
|
368
|
+
|
|
369
|
+
3. **Status badge.** The colored dot under the node shows the latest state: green (ok), blue
|
|
370
|
+
(working), yellow (connecting / partial), red (error, with a short reason).
|
|
371
|
+
|
|
372
|
+
Common errors are decoded to plain language, e.g.:
|
|
373
|
+
- *"variable not found on the controller — check the name and that it is published"* (the tag
|
|
374
|
+
doesn't exist or isn't published to the network),
|
|
375
|
+
- *"type mismatch — expected an integer Number, got string"* (you sent the wrong data type),
|
|
376
|
+
- *"reply data too large — use UCMM for large arrays"* (a large array read over Class 3).
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## 11. Common flow recipes
|
|
381
|
+
|
|
382
|
+
### Read one tag on a button press
|
|
383
|
+
```
|
|
384
|
+
[ inject (button) ] → [ omron read: Counter ] → [ debug ]
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Poll a dashboard of values every 250 ms
|
|
388
|
+
```
|
|
389
|
+
[ omron read: Speed, Position, Status · Repeat 250ms ] → [ ui_text / chart ]
|
|
390
|
+
```
|
|
391
|
+
No inject needed — the read self-polls. Put many tags in one read node; one request fetches
|
|
392
|
+
them all.
|
|
393
|
+
|
|
394
|
+
### Write a setpoint from a dashboard slider
|
|
395
|
+
```
|
|
396
|
+
[ ui_slider ] → [ change: set msg.payload to { "Setpoint": payload } ] → [ omron write (from message): Setpoint ]
|
|
397
|
+
```
|
|
398
|
+
Or, for a single variable, skip the reshaping — the slider's numeric `msg.payload` goes
|
|
399
|
+
straight into a write node configured with the one variable `Setpoint`.
|
|
400
|
+
|
|
401
|
+
### Set initial values when the flow starts
|
|
402
|
+
```
|
|
403
|
+
[ omron write (fixed): Mode=1, Enable=true · Write once after deploy ]
|
|
404
|
+
```
|
|
405
|
+
Nothing upstream needed; it fires once at deploy.
|
|
406
|
+
|
|
407
|
+
### Heartbeat / watchdog
|
|
408
|
+
```
|
|
409
|
+
[ omron write (fixed): Heartbeat=… · Repeat 1000ms ]
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Read, decide, write
|
|
413
|
+
```
|
|
414
|
+
[ inject ] → [ omron read: Level ] → [ switch: Level > 80? ] → [ omron write (fixed): Pump=false ]
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Bulk-move a recipe (whole structure)
|
|
418
|
+
```
|
|
419
|
+
[ inject (JSON: {"Recipe":{…}}) ] → [ omron write (from message): Recipe ]
|
|
420
|
+
[ inject ] → [ omron read: Recipe ] → [ debug ] // reads the whole struct back
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## 12. Performance & best practices
|
|
426
|
+
|
|
427
|
+
- **Batch reads.** Put multiple tags in one read node rather than many single-tag nodes — one
|
|
428
|
+
request fetches them all, far more efficiently.
|
|
429
|
+
- **Use whole arrays/structures for bulk data.** Reading `MyArray` in one go is dramatically
|
|
430
|
+
faster than reading `MyArray[0]`, `MyArray[1]`, … individually.
|
|
431
|
+
- **Pick a sensible poll rate.** On a direct connection an NX102 comfortably handles, for
|
|
432
|
+
example, ~50 tags every 100 ms, ~100 tags every 250 ms, ~200 tags every 500 ms. Don't poll
|
|
433
|
+
faster than you need; split fast-changing and slow-changing data onto separate read nodes
|
|
434
|
+
with different Repeat intervals.
|
|
435
|
+
- **Prefer member writes over whole-structure writes** unless you intend to set everything, to
|
|
436
|
+
avoid clobbering concurrent changes.
|
|
437
|
+
- **Match data types.** Numbers for numeric tags, booleans for BOOLs, JSON for arrays/objects.
|
|
438
|
+
- **Keep UCMM** unless you specifically route through a gateway.
|
|
439
|
+
- **One config node per PLC**, shared by all its read/write nodes.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## 13. Troubleshooting
|
|
444
|
+
|
|
445
|
+
| Symptom | Likely cause / fix |
|
|
446
|
+
|---|---|
|
|
447
|
+
| "config node not found or not deployed yet" | You used Connect & validate (or ran a flow) before deploying. **Deploy first.** |
|
|
448
|
+
| Write fails: "type mismatch …" | You sent the wrong type (commonly a string to a numeric tag). Set the inject/upstream payload type to number/boolean/JSON. |
|
|
449
|
+
| Read/write error: "variable not found" (CIP 0x05) | The tag name is wrong, or the tag isn't published to the network. In Sysmac Studio, make it a global variable with Network Publish = Publish Only, and transfer the project to the controller. |
|
|
450
|
+
| Node status stays yellow "connecting…" | The node can't reach the PLC. Verify the address, and that the machine/container running Node-RED can reach the PLC (e.g. ping it from the same host/container). |
|
|
451
|
+
| "reply data too large" on a big array | You're on Class 3; switch the config node to UCMM for large arrays. |
|
|
452
|
+
| Editor shows old node UI after an update | Hard-refresh the browser (Ctrl-Shift-R) to clear cached node HTML. |
|
|
453
|
+
| Connect & validate reports a connection error | The editor backend can't reach the PLC. Same checks as a failed read; confirm the deployed config's address is reachable. |
|
|
454
|
+
| Some tags read fine but others fail in a batch | The failures are on `msg.errors`; the good values still come through. Check the failed names. |
|
|
455
|
+
|
|
456
|
+
For protocol-level detail, performance numbers, and the underlying library, see the `omron-eip`
|
|
457
|
+
library docs (`README.md`, `EXAMPLES.md`, `PROTOCOL.md`, `NX102_PERFORMANCE.md`).
|