Example Collection
To import and run a completed flow immediately, please see Example Flows for Import first — Node-RED is shipped as a blank canvas, so examples are imported from the documentation.
The examples below are patterns frequently created in the field. All of them work by simply dragging, connecting, and deploying nodes, similar to Hello World. The code blocks are JavaScript that can be pasted directly into the function node.
1. Threshold Alert
Goal: Send a notification to Slack if the temperature tag is 80℃ or higher.
inject (5s) ─▶ 태그값 읽기 (TAG_TEMPERATURE) ─▶ function (임계값 체크) ─▶ switch ─▶ slack out
function:
const v = parseFloat(msg.payload.value);
msg.over = (v >= 80);
msg.temp = v;
return msg;
switch: If condition msg.over is true → Pass.
The message in slack out (or email/telegram) will contain 🔥 온도 경보 ${msg.temp}℃.
To prevent chatter (80↔80.1) near the threshold, it is recommended to send an alarm only at the rising edge and send it again only after it has been cleared and rises again. Use flow.set('lastAlert', true) to remember the state and trigger only at the toggle point.
2. Summing Multiple Tags to Write to a New Tag (Calculated Value)
Goal: Update TAG_PLANT_TOTAL_QTY every 1 second by calculating TAG_LINE1_QTY + TAG_LINE2_QTY + TAG_LINE3_QTY.
inject (1s) ─▶ 태그값 읽기 ×3 (병렬) ─▶ join ─▶ function (sum) ─▶ 태그값 쓰기
join: mode manual, combine array, key msg.topic, count 3.
Attach a change node to the output of each Read Tag Value to assign msg.topic as line1/line2/line3 differently.
function:
const sum = msg.payload.reduce(
(a, p) => a + (parseFloat(p.value) || 0), 0);
return { tag_id: 'TAG_PLANT_TOTAL_QTY', payload: String(sum) };
PlantPulse has a built-in formula tag feature. Simple arithmetic is faster and more stable when processed there. Node-RED is more powerful when mixed with external APIs, MQTT, time conditions, or conditional branching.
3. CSV Logging (Minute-by-Minute)
Goal: Accumulate the values of 5 major tags into a single line of CSV on the local disk every 1 minute.
inject (1m) ─▶ 태그값 읽기 ×5 ─▶ join ─▶ function (CSV 한 줄) ─▶ file (append)
function:
const ts = new Date().toISOString();
const cols = msg.payload.map(p => (p.value || '').replace(/,/g, ''));
msg.payload = [ts, ...cols].join(',') + '\n';
msg.filename = '/data1/pp-data/node-red/log/tags-' + ts.slice(0, 10) + '.csv';
return msg;
file node: Action append to file, Add newline off.
The Node-RED userDir is /data1/pp-data/node-red. Placing the CSV under that directory ensures it is included in the gateway backup policy.
4. Real-time Publishing to External SCADA via MQTT
(Refer to MQTT for detailed settings). Quick one-line pattern:
inject (1s) ─▶ 태그값 읽기 ─▶ change (topic=plant/${tag_id}/value) ─▶ mqtt out
5. Importing Values from External REST API as Tags (Reverse Integration)
Goal: Every 5 minutes, take the outdoor temperature from an external weather API → write to virtual tag TAG_OUTDOOR_TEMP.
inject (5m) ─▶ http request (GET https://api.example.com/weather?...) ─▶ function ─▶ 태그값 쓰기
function:
return { tag_id: 'TAG_OUTDOOR_TEMP', payload: String(msg.payload.main.temp) };
This value is used like a normal tag across all PlantPulse screens, charts, and external SCADAs.
6. Daily Report Email at Start of Workday
Goal: Every morning at 7 AM, send the average, maximum, and minimum of the previous 24 hours via email.
inject (cron: 0 7 * * *) ─▶ http request (GET /ui/opcua/history?...) ─▶ function (집계) ─▶ email
function:
const points = msg.payload.points || [];
const vs = points.map(p => parseFloat(p.value)).filter(v => !isNaN(v));
const avg = vs.reduce((a,b)=>a+b,0) / vs.length;
msg.topic = '[일일 리포트] 어제의 ' + msg.payload.tag_id;
msg.payload = '평균: ' + avg.toFixed(2)
+ '\n최대: ' + Math.max(...vs)
+ '\n최소: ' + Math.min(...vs);
return msg;
7. Simultaneous Branching to Slack and DB upon Alarm
inject (1s) ─▶ 태그값 읽기 ─▶ switch (정상/비정상) ─▶┬─▶ slack out
└─▶ http request (POST /alerts)
The two nodes at the end of the abnormal branch (slack out, http request) receive the same message simultaneously.
8. Unit/Scale Conversion (4-20mA → bar)
inject (1s) ─▶ 태그값 읽기 (TAG_RAW_MA) ─▶ function (스케일) ─▶ 태그값 쓰기 (TAG_PRESSURE_BAR)
function:
const raw = parseFloat(msg.payload.value);
const ma = (raw / 32767) * 20;
const bar = Math.max(0, ((ma - 4) / (20 - 4)) * 100);
return { tag_id: 'TAG_PRESSURE_BAR', payload: bar.toFixed(2) };
9. Gateway Health Check → Telegram
Poll the EDGE system tags as seen in the OPC UA server (/ui/opcua).
inject (30s) ─▶ 태그값 읽기 (TAG_EDGE_..._OPC_CONNECTED_COUNT) ─▶ function ─▶ telegram
If the value drops to 0, all PLCs are disconnected → Immediate notification.
10. Real-time without Polling via OPC-UA Subscribe (Edge → Edge)
inject (once) ─▶ OpcUa-Item ×N ─▶ join ─▶ OpcUa-Subscribe ─▶ function (정규화) ─▶ 태그값 쓰기
Mirror only change events from another company's OPC-UA server directly to tags in our gateway — acting as a real-time gateway bridge.
Refer to the OPC-UA Node page for detailed OPC-UA node settings.
11. Transmission to Cloud via Sparkplug B
inject (5s) ─▶ 태그값 읽기 ×N ─▶ function (metrics 배열 만들기) ─▶ sparkplug device out
PlantPulse also performs Sparkplug transmission natively (고급 / 통합 파트너용 → Sparkplug B). Use direct transmission from Node-RED only when Sparkplug behavior customization is required. Refer to the Sparkplug B Node for detailed settings.
12. Creating Chart Images to Attach to Alarm Messages
By combining Node-RED's node-red-contrib-image-output + chart.js or an external QuickChart API, you can send a "Last 1 Hour Trend" graph to Slack along with the alarm — allowing operators to make an immediate judgment.
Next Steps
- Flow Troubleshooting — Common pitfalls