Ir al contenido

← Dashboard Node-RED multiestación con gauges y LEDs

Monitorización geotécnica de taludServidor (Node-RED)HTTPHMI / Dashboard

Dashboard Node-RED multiestación con gauges y LEDs — ejemplo completo

Crea un dashboard en Node-RED con gauges, widgets de texto y LEDs de estado para vigilar cuatro estaciones PLC remotas desde una pantalla. Código incluido.

Programa completo y ejecutable para el Servidor (Node-RED) (multi-station-dashboard-node-red.js): incluye cabecera de conexionado, requisitos y notas de integración.

Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales

Vista de solo lectura.

/*
 * COMPLETE EXAMPLE — Multi-station dashboard with gauges and LEDs
 *
 * Hardware:  Server (Node-RED, node-red-dashboard) on a Raspberry Pi
 * Based on:  geotechnical slope monitoring project (4 stations,
 *            ESP32 PLC 14 Ethernet + electrical cabinet)
 *
 * Flow architecture (wiring in the Node-RED editor):
 *
 *   [function "classify alert"] --> [function "prepare dashboard"]
 *         output 1 --> [ui-gauge "Station level"]  (1 per station)
 *         output 2 --> [ui-text  "Input detail"]   (several per station)
 *         output 3 --> [ui-led   "Station status"] (1 per station)
 *
 *   - The ui-gauge widgets are configured with range 0-4 and color
 *     sectors (0-1 green, 2-3 yellow, 4 red).
 *   - The ui-text widgets show a text value and the last-reading timestamp.
 *   - The ui-led widgets (node-red-contrib-ui-led) change color via msg.color.
 *   - Each widget filters by msg.topic ("station/31/gauge", etc.) using
 *     an upstream switch node or one dashboard group per station.
 *
 *   In the real project: 60 ui-text, 31 gauges and 4 LEDs spread across
 *   tabs (one per station plus an electrical-cabinet summary tab).
 */

// ======================================================================
// FUNCTION NODE "prepare dashboard"  (1 input, 3 outputs)
// Receives the already classified msg (msg.station, msg.alert, msg.inputs,
// msg.ts) and emits the messages consumed by gauge, texts and LED.
// ======================================================================
const station = msg.station;
const level   = msg.alert ?? 0;
const inputs  = msg.inputs || {};
const ts      = msg.ts || new Date().toISOString();

// --- Output 1: alert level gauge (range 0-4) --------------------------
const msgGauge = {
    topic: `station/${station}/gauge`,
    payload: level
};

// --- Output 2: one ui-text per input + summary text --------------------
// node.send() accepts arrays: every element of the inner array goes out
// the same output, so we feed several ui-text widgets at once.
const textMsgs = Object.keys(inputs).map(channel => ({
    topic: `station/${station}/text/${channel}`,
    payload: inputs[channel] ? "ACTIVE" : "idle"
}));

textMsgs.push({
    topic: `station/${station}/text/summary`,
    payload: `Level ${level} — ${ts.substring(11, 19)}`
});

// --- Output 3: station status LED ---------------------------------------
// Green = normal (0-1), yellow = attention (2-3), red = critical (4).
// If the station has not reported in >3 min, the LED blinks red.
const COLORS = ["green", "green", "yellow", "yellow", "red"];

const states = flow.get("states") || {};
const last   = states[station] ? new Date(states[station].ts).getTime() : 0;
const silent = Date.now() - last > 3 * 60 * 1000;

const msgLed = {
    topic: `station/${station}/led`,
    payload: !silent,                  // false => LED off/blinking
    color: silent ? "red" : COLORS[level]
};

node.status({
    fill: msgLed.color,
    shape: silent ? "ring" : "dot",
    text: `sta. ${station}: level ${level}${silent ? " (NO DATA)" : ""}`
});

return [msgGauge, textMsgs, msgLed];

// ======================================================================
// FUNCTION NODE "global summary"  (optional, 1 output -> header ui-text)
// Wire it in parallel: shows the worst level across the 4 stations.
// ======================================================================
/*
const states = flow.get("states") || {};
const levels = Object.values(states).map(s => s.level);
const worst = levels.length ? Math.max(...levels) : 0;

const LABELS = ["NORMAL", "NOTICE", "WARNING", "ALARM", "CRITICAL"];
msg.topic   = "slope/summary";
msg.payload = `Slope status: ${LABELS[worst]} (${levels.length}/4 stations reporting)`;
return msg;
*/
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales