PLC32 CONTROL

Blog

Monitorización del estado de salud de un Servidor Linux (en sistemas IOT Industriales)

En cualquier sistema de monitorización o automatización basado en arquitectura edge, solemos centrarnos en sensores, señales, lógica de control y visualización. Sin embargo, hay un elemento crítico que muchas veces se pasa por alto:

El propio servidor que soporta el sistema.

Cuando trabajamos con soluciones basadas en Linux (ya sea en dispositivos industriales, gateways IoT o sistemas embebidos), la estabilidad del sistema depende directamente de la “salud” de ese servidor.

¿Por qué es importante monitorizar el sistema?

En entornos industriales o técnicos, no siempre es posible acceder físicamente al equipo. Esto ocurre especialmente en Instalaciones remotas, cuadros técnicos cerrados, entornos sensibles como invernaderos tecnológicos o sistemas que deben funcionar 24/7 sin intervención.

En estos casos, un fallo del sistema no solo implica pérdida de datos, sino también:

Por eso, además de monitorizar el proceso, es imprescindible monitorizar el sistema.

Parámetros clave a supervisar

Una monitorización básica pero efectiva de un servidor Linux debe incluir al menos:

🔹 Temperatura de CPU

Permite detectar problemas de ventilación o sobrecarga.

🔹 Carga del sistema (Load Average)

Indica el nivel de trabajo del sistema y posibles saturaciones.

🔹 Uso de memoria RAM

Crítico para evitar bloqueos o degradación del rendimiento.

🔹 Uso de disco

Evita fallos por falta de espacio, especialmente en sistemas con registro histórico.

🔹 Uptime

Permite detectar reinicios inesperados.

🔹 Estado de servicios

Fundamental para saber si los componentes clave del sistema siguen funcionando:

(Estos son los que habitualmente utilizo yo, pero que pueden personalizarse, como veremos a continuación.)

Funcionamiento de los flujos en Node-Red

Funcionamiento de los flujos en Node-Red

1. Nodo: Cada 10s (Inject).

Dispara el flujo automáticamente cada 10 segundos.

🔹 2. Nodo: /usr/bin/vcgencmd measure_temp (Exec)

Ejecuta un comando del sistema Linux que devuelve la temperatura de la CPU. La salida típica es algo así como:

temp=39.7'C

Es importante porque detecta sobrecalentamientos siendo fundamental contar con este parámetro en sistemas embebidos.

🔹 3. Nodo: Parse Temp (Function)

Extrae el valor numérico de la temperatura ya que el exec devuelve texto, no número, es decir, transforma:

"temp=39.7'C" → 39.7
const s = (msg.payload ?? "").toString().trim();   // "temp=36.5'C"
const m = s.match(/(\d+(\.\d+)?)/);               // busca 36.5

if (!m) return null;                               // si no encuentra número, no envía nada

msg.payload = Number(m[1]);                        // 36.5 como número
return msg;

🔹 4. Nodo: /bin/cat /proc/loadavg (Exec)

Este nodo lee directamente del sistema Linux el estado de carga. El comando es directamente el ejecutado en linux como: /bin/cat /proc/loadavg.

La salida típica es:

0.09 0.12 0.10 1/215 7421

🔹 5. Nodo: Parse Load (Function)

Este nodo extrae el primer valor (Load 1m), como por ejemplo:

"0.09 0.12 0.10..." → 0.09
const s = (msg.payload ?? "").toString().trim();
if (!s) return null;

// /proc/loadavg: "0.00 0.02 0.00 2/215 7449"
const parts = s.split(/\s+/);
const load1 = Number(parts[0]);

if (Number.isNaN(load1)) return null;

msg.payload = load1;
return msg;

🔹 6. Nodo: /usr/bin/free -m (Exec)

Este nodo obtiene el estado de memoria RAM en MB. la salida típica en linux es:

Mem: 921 438 107 35 469 482

Arrojando los campos clave como total, used y available.

🔹 7. Nodo: Parse RAM % (Function)

Este nodo function calcula el porcentaje real de memoria usada, teniendo en cuenta que linux usa memoria para cache. El código es:

const s = (msg.payload ?? "").toString();
if (!s) return null;

const lines = s.split("\n");

// buscamos la línea que empieza por "Mem:"
const line = lines.find(l => l.trim().startsWith("Mem:"));
if (!line) return null;

const p = line.trim().split(/\s+/);
if (p.length < 7) return null;

const total = Number(p[1]);
const used = Number(p[2]);
const available = Number(p[6]);

if ([total, used, available].some(Number.isNaN) || total <= 0) return null;

// OPCIÓN A → % usada real según "used"
const pctUsed = Math.round((used / total) * 100);

// OPCIÓN B (más correcta en Linux)
// memoria realmente ocupada por procesos:
const pctReal = Math.round(((total - available) / total) * 100);

// usa la opción que prefieras:
msg.payload = pctReal;

return msg;

🔹 8. Nodo: /usr/bin/df -h / (Exec)

Qué hace

Este nodo obtiene el uso del disco raíz, expresándolo en %

/dev/... 14G 5.8G 7.6G 44% /

🔹 9. Nodo: Parse Disco % (Function)

Qué hace

Extrae el porcentaje de uso del disco evitando fallos por disco lleno. El código es:

const s = (msg.payload ?? "").toString().trim();
if (!s) return null;

const lines = s.split("\n").map(l => l.trim()).filter(Boolean);

// Busca la línea cuyo "Mounted on" sea "/"
const dataLine = lines.find(l => {
  const parts = l.split(/\s+/);
  return parts[parts.length - 1] === "/";
});

if (!dataLine) return null;

const parts = dataLine.split(/\s+/);

// En df -h: ... Use% suele ser el penúltimo antes del mount,
// pero para asegurar, buscamos el campo que termine en %
const pctField = parts.find(x => x.endsWith("%"));
if (!pctField) return null;

const pct = Number(pctField.replace("%", ""));
if (Number.isNaN(pct)) return null;

msg.payload = pct;
return msg;

🔹 10. Nodo: uptime -p (Exec)

Este nodo devuelve el tiempo que lleva el sistema encendido, arrojando un dato similar a:

up 2 weeks, 6 days, 1 hour

🔹 11. Nodo: IP (Exec)

hostname -I | awk '{print $1}'

Este exec obtiene la IP local del equipo, para cualquier acceso remoto o identificación del dispositivo.

🔹 12. Nodo: systemctl is-active mosquitto (Exec)

Este nodo ejecuta el comando que se indica, para comprobar si el servicio MQTT está activo. El nodo siguiente nos dará varias posibles salidas como active, inactive o failed.

🔹 13. Nodo: function (estado servicio)

Convierte texto en estado visual:

active → 🟢 ACTIVO
inactive → 🔴 INACTIVO
const s = (msg.payload ?? "").toString().trim().toLowerCase();

// Si no hay salida (algo raro), no rompas el flow
if (!s) {
  msg.payload = "🔴 SIN RESPUESTA";
  return msg;
}

if (s === "active") {
  msg.payload = "🟢 ACTIVO";
} else {
  // inactive, failed, activating, deactivating...
  msg.payload = "🔴 " + s.toUpperCase();
}

return msg;

🔹 14. Nodo: systemctl is-active nodered

Este nodo comprueba si el motor de automatización está funcionando. (También es un nodo exec que replica un comando linux) que enlazará a otro nodo función para lanzarnos los mensajes de "activo" o "sin respuesta", tal como se observa en el siguiente código:

const s = (msg.payload ?? "").toString().trim().toLowerCase();

if (!s) {
  msg.payload = "🔴 SIN RESPUESTA";
  return msg;
}

msg.payload = (s === "active") ? "🟢 ACTIVO" : ("🔴 " + s.toUpperCase());
return msg;

🔹 15. Nodo: systemctl is-active zigbee2mqtt

Este nodo es un poco peculiar y tal vez no lo necesites. Zigbee es un protocolo inalámbrico de bajo consumo utilizado para envío de datos. En este caso se utilizó para un sensor de presencia tipo PIR, con lo cual se conectó una antena tipo USB al servidor para este propósito.

Al igual que los nodos anteriores, éste va unido a uno tipo función con el siguiente código:

const s = (msg.payload ?? "").toString().trim().toLowerCase();

if (!s) {
  msg.payload = "🔴 SIN RESPUESTA";
  return msg;
}

msg.payload = (s === "active")
  ? "🟢 ACTIVO"
  : "🔴 " + s.toUpperCase();

return msg;

🔹 16. Nodo: systemctl is-active apache2

Este flujo comprueba el servidor web. Al igual que el anterior, el servidor dispone de una pequeña página web, con lo cual dispone de apache, el cual también se supervisa.

De igual manera este nodo exec va unido a otro función con el siguiente código:

const s = (msg.payload ?? "").toString().trim().toLowerCase();

if (!s) {
  msg.payload = "🔴 SIN RESPUESTA";
  return msg;
}

msg.payload = (s === "active")
  ? "🟢 ACTIVO"
  : "🔴 " + s.toUpperCase();

return msg;

🔹 17. Nodos Dashboard (gauge y text)

Estos nodos de color azul son los que en último término vamos a "visualizar" , ajustándolos a rangos, talla, etc. y los que de alguna manera van a formar el "Scada".

🔹 18. Nodo: Custom CSS

Por último introducimos un último nodo con un lenguaje CSS para definir algunos parámetros puramente estéticos del Scada, como pueden ser el fondo de la página, títulos de grupo, texto general etc. Esto es un poco personal, y cada uno deberá ver cual es el que encaja para él o su cliente.

🔹 18. Nodo: Custom CSS

CONCLUSIÓN

En sistemas de monitorización edge, la adquisición de datos no siempre devuelve valores estructurados. Por ello, es necesario aplicar técnicas de parsing robusto que permitan extraer información fiable a partir de salidas no normalizadas.

Primera consulta sin compromiso.

Cuéntame qué equipo tienes y qué quieres controlar o medir.

Contactar Escribir por WhatsApp