Skip to Content

← All functionalities

Textile monitoring (weaving)Server (Node-RED)MQTTHTTPInfrastructure

The server side: a multi-plant Node-RED concentrator

A Node-RED MQTT concentrator is where a fleet of ESP32 PLCs becomes a system: one server per plant receiving every snapshot and event, validating it, backing it up and watching who went silent. These four function nodes — validation, file recovery endpoint, disk backup and fleet check — are the distilled server side of a real textile machine monitoring deployment running the same flow in two production plants.

Validate and deduplicate at the door

The first function node parses each incoming MQTT payload, routes malformed JSON to a dedicated discard output instead of dropping it silently, and deduplicates by the unique id_msg the firmware stamps on every message. Deduplication is essential here, because PLCs deliberately replay buffered data after every reconnection and would otherwise double-count production. Valid messages are then enriched with the plant name, a server-side timestamp and the origin topic before anything downstream — file backup, database, dashboard — ever sees them.

Everything lands on disk, twice

A backup function node appends every received message — and every discard, together with its error reason — to daily files per plant, mirroring on the server what the SD cards do on the PLC side. A separate HTTP-in endpoint, /get_data protected with basic auth, receives the daily files that PLCs upload after an outage and stores them in a per-plant recovery folder, sanitising the filename header first.

Knowing who went quiet

Telemetry that quietly stops is an alarm nobody hears, and a dead PLC looks exactly like a healthy idle one unless someone checks. The fleet-check node, fired by an inject every five minutes, compares each expected PLC's last-seen timestamp against a two-minute silence threshold and emits a status object naming the devices that have gone dark. The exact same flow serves both production plants — the only thing that changes between deployments is a single environment variable with the plant name.

A snippet from the implementation

Straight from the example as deployed on the Server (Node-RED) — copy it freely:

const PLANT = env.get("PLANT") || "plant1";      // same logic in both plants

let data;
try {
  data = (typeof msg.payload === "string") ? JSON.parse(msg.payload) : msg.payload;
} catch (e) {
  msg.error = "invalid JSON: " + e.message;
  return [null, msg];                            // output 2: discards
}

// Minimum fields sent by the firmware
if (data.id === undefined) {
  msg.error = "missing PLC id";
  return [null, msg];
}

// Deduplication by id_msg (the PLC re-sends after reconnection / SD replay)
if (data.id_msg) {
  const seen = context.get("seen") || {};
  if (seen[data.id_msg]) {
    msg.error = "duplicate: " + data.id_msg;
    return [null, msg];
  }
  seen[data.id_msg] = Date.now();
  // Purge: keep only the last hour of IDs so the map does not grow unbounded
  const oneHourAgo = Date.now() - 3600 * 1000;
  for (const k in seen) if (seen[k] < oneHourAgo) delete seen[k];
  context.set("seen", seen);
}

The full example is a complete program — wiring header, setup and main loop — ready to adapt to your application.

Frequently asked questions

Why deduplicate on the server instead of the PLC?

The PLC deliberately favours at-least-once delivery — it would rather send twice than lose data after a reconnection. The concentrator holds the recent id_msg set centrally, which is cheap in Node-RED context and impossible to do across reboots on the device.

Should each plant run its own concentrator?

Yes in this deployment — one broker plus Node-RED per plant keeps data flowing during inter-site link failures. The flows are identical; an environment variable sets the plant name, and a central system can consume both.

How does data get into a database from here?

Add a database node after the validation output — the messages are already clean, deduplicated and enriched JSON. The file backups stay as the audit trail and replay source if the database ever needs rebuilding.

Related functionalities