Node-RED

Almacenamiento de contexto en Node-RED: flow, global y persistente

El contexto de Node-RED permite que los flujos recuerden cosas entre mensajes. Esta guía explica los tres ámbitos, el almacenamiento en memoria frente a archivo, el uso de varios almacenes, el acceso asíncrono y un patrón práctico para guardar el último valor MQTT de cada dispositivo.

Diagrama de los ámbitos de contexto de Node-RED con almacenamiento node, flow y global que guarda los últimos valores MQTT
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

El contexto de Node-RED es el almacenamiento clave-valor integrado que permite a un flujo recordar valores entre mensajes, como la última temperatura que informó un sensor o un contador de las alarmas de hoy. Esta guía explica los tres ámbitos de contexto, cómo hacer que el contexto sobreviva a los reinicios, cómo usar varios almacenes a la vez y un patrón limpio para conservar el último valor MQTT de cada dispositivo.

Por qué los flujos necesitan estado

Los mensajes en Node-RED son independientes. Cuando un nodo mqtt in emite una lectura, el siguiente nodo solo conoce lo que hay dentro de ese mensaje. Muchas tareas reales necesitan más que eso:

  • Comparar un valor con el anterior para detectar un cambio o una tendencia.
  • Responder a una petición HTTP con la lectura más reciente, aunque en ese momento no esté llegando ningún mensaje MQTT.
  • Contar eventos por turno o recordar cuándo empezó una alarma.
  • Combinar valores de dos topics que llegan en momentos distintos.

MQTT ofrece por sí mismo una forma de memoria mediante los mensajes retenidos, en los que el broker guarda el último mensaje de un topic y lo entrega a los nuevos suscriptores. Es ideal para el estado compartido entre clientes, y deberías usarlo. El contexto es la herramienta complementaria para el estado que vive dentro de Node-RED. Si no tienes claro a qué lado corresponde una responsabilidad, nuestra explicación sobre qué hace un broker MQTT traza la línea.

Los tres ámbitos de contexto de Node-RED

Ámbito Visible para Uso típico Acceso en una función
Node Solo el nodo que lo definió Filtros de banda muerta, contadores dentro de una función context.get() / context.set()
Flow Todos los nodos de la misma pestaña (o dentro de la misma instancia de subflujo) Últimos valores usados por varios nodos de una pestaña flow.get() / flow.set()
Global Todos los nodos de la instancia de Node-RED Configuración compartida, tablas de consulta global.get() / global.set()

Elige el ámbito más reducido que funcione. Cualquier nodo de cualquier pestaña puede cambiar un valor del contexto global, lo que hace que los errores sean difíciles de rastrear. El contexto de nodo es privado, así que nada más puede romperlo.

No necesitas escribir código para usar el contexto. El nodo Change puede asignar, leer, mover y eliminar propiedades flow. y global., y los nodos Inject, Switch y Template pueden leerlas. La pestaña Context Data de la barra lateral del editor muestra los valores actuales de cada ámbito y te permite actualizarlos o eliminar entradas mientras depuras.

Los subflujos tienen un matiz adicional: el contexto flow dentro de un subflujo pertenece a esa instancia. Un subflujo puede acceder al contexto del flujo padre con el prefijo $parent., por ejemplo flow.get("$parent.lastTemp").

Contexto en memoria frente a contexto persistente

Por defecto todo el contexto se guarda en memoria. Es rápido, pero desaparece cuando Node-RED se reinicia, cuando se recrea el contenedor o cuando el host se reinicia. Para cualquier cosa que no puedas reconstruir fácilmente, activa el almacenamiento en archivo.

Abre settings.js (en ~/.node-red/ en una instalación estándar, o en /data/ en la imagen de Docker) y busca la sección contextStorage:

// settings.js
module.exports = {
    // ...
    contextStorage: {
        default: { module: "memory" },
        file:    { module: "localfilesystem" }
    },
    // ...
};

Reinicia Node-RED. Ahora tienes dos almacenes: default, que se queda en memoria, y file, que escribe archivos JSON en la carpeta context/ de tu directorio de usuario. Los nodos eligen el almacén explícitamente:

flow.set("lastReading", msg.payload, "file");   // persistente
flow.set("scratch", 42);                        // memoria (almacén predeterminado)
const last = flow.get("lastReading", "file");

En el nodo Change y otros editores aparece un pequeño selector de almacén junto a los campos flow. y global. en cuanto tienes más de un almacén.

Si prefieres que todo sea persistente, configura default: { module: "localfilesystem" }. Ten en cuenta cómo funciona el almacén en archivo: los valores se guardan en caché en memoria y se escriben en disco a intervalos, cada 30 segundos por defecto, según la opción flushInterval. Un fallo grave puede perder los cambios de los últimos segundos. Eso está bien para últimos valores y contadores, pero el contexto no es una base de datos. Para datos históricos, escribe en un almacén de series temporales como InfluxDB, como se muestra en nuestra guía de Node-RED con InfluxDB.

Ten en cuenta también que solo los valores serializables en JSON persisten de forma fiable. Las funciones, los temporizadores y las instancias de clase no volverán intactos tras un reinicio, así que guarda objetos simples, números y cadenas.

Acceso síncrono y asíncrono

Con los almacenes memory y localfilesystem, get y set funcionan de forma síncrona, como se ha mostrado. Algunos almacenes de terceros, como los módulos basados en Redis, son asíncronos y requieren callbacks:

flow.get("count", "redis", (err, count) => {
    if (err) { node.error(err, msg); return; }
    count = (count || 0) + 1;
    flow.set("count", count, "redis", (err) => {
        if (err) { node.error(err, msg); return; }
        msg.payload = count;
        node.send(msg);
        node.done();
    });
});

Escribir el código con callbacks desde el principio cuesta poco y te permite cambiar de almacén más adelante sin reescribir cada función. Ten presente que un get seguido de un set no es atómico. Con tasas de mensajes muy altas en un almacén asíncrono, dos mensajes pueden leer el mismo contador antiguo. Mantén los contadores en el contexto de nodo, donde solo un nodo los escribe, o agrupa las actualizaciones.

También puedes leer y escribir varias claves a la vez pasando arrays: flow.get(["a", "b"]) devuelve un array de valores.

Patrón: conserva el último valor MQTT de cada dispositivo

Una tarea habitual del contexto de Node-RED es una tabla en vivo de "último valor conocido": una entrada por dispositivo, actualizada con cada mensaje y legible desde cualquier punto del flujo. Publica algunos datos de prueba en el servidor MQTT público gratuito de ConnectMQ, sustituyendo c8d1 por tu propia cadena aleatoria:

mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-ctx-c8d1 \
  -t "connectmq/demo/c8d1/boiler/tank1/telemetry" -m '{"level": 71.5, "temp": 63.2}'
mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-ctx-c8d1 \
  -t "connectmq/demo/c8d1/boiler/pump2/telemetry" -m '{"rpm": 1450, "temp": 41.0}'

Suscríbete en Node-RED con un nodo mqtt in en connectmq/demo/c8d1/+/+/telemetry, con la salida configurada como JSON analizado, y conéctalo a esta función:

// Función "store latest"
const parts = msg.topic.split("/");
const deviceId = parts[3] + "/" + parts[4];       // p. ej. "boiler/tank1"

const latest = flow.get("latest", "file") || {};
latest[deviceId] = {
    values: msg.payload,
    ts: Date.now()
};
flow.set("latest", latest, "file");

node.status({ text: Object.keys(latest).length + " devices" });
return null;

Ahora cualquier nodo de la pestaña puede leer la tabla. Un nodo http in en GET /latest seguido de esta función y de un nodo http response te da una pequeña API:

// Función "serve latest"
const latest = flow.get("latest", "file") || {};
const staleMs = 5 * 60 * 1000;
const now = Date.now();

msg.payload = Object.entries(latest).map(([id, v]) => ({
    device: id,
    values: v.values,
    ageSeconds: Math.round((now - v.ts) / 1000),
    stale: now - v.ts > staleMs
}));
return msg;

El indicador stale es el detalle importante. Una tabla de últimos valores que nunca caduca mostrará tan tranquila la lectura de un dispositivo que dejó de funcionar ayer. Guarda siempre una marca de tiempo junto al valor.

Lista de buenas prácticas del contexto en Node-RED

  1. Usa el ámbito más reducido: node, después flow y, por último, global.
  2. Activa un almacén en archivo y elígelo explícitamente para los valores que no puedas reconstruir.
  3. Guarda marcas de tiempo junto a los valores para detectar datos obsoletos.
  4. Evita objetos enormes; las entradas de contexto grandes ralentizan cada volcado a disco y cada actualización de la barra lateral.
  5. Pon prefijos a las claves globales según su propósito, por ejemplo cfg_ para configuración y cache_ para datos de consulta.
  6. No guardes secretos en el contexto. Las credenciales van en nodos de configuración y variables de entorno.
  7. Usa mensajes MQTT retenidos para el estado que necesitan otros clientes, y el contexto para el estado que solo necesita Node-RED.
  8. Haz copia de seguridad de la carpeta context/ junto con tus flujos. ¿Ejecutas Node-RED en contenedores? Nuestra guía de Node-RED en Docker muestra cómo mantener /data en un volumen persistente.

La documentación oficial del contexto cubre por completo la API de los almacenes y las opciones de configuración. Para la parte de código de estos patrones, consulta nuestra guía del nodo function de Node-RED, y para la visión general de cómo conectar flujos con brokers, el tutorial de Node-RED MQTT.

Combina el contexto de Node-RED con ConnectMQ

El contexto conserva la memoria propia de Node-RED; el broker conserva la de todos los demás. ConnectMQ es un broker MQTT gestionado con mensajes retenidos, caducidad de sesión de MQTT 5 y TLS, de modo que dispositivos, paneles y Node-RED ven los mismos últimos valores conocidos. Su portal añade un explorador de topics en directo y reglas de alerta por umbral para comprobaciones rápidas sin necesidad de crear un flujo. Empieza con el plan Serverless gratuito en app.connectmq.com, sin tarjeta de crédito, y conecta Node-RED con el usuario, la contraseña y el client ID generados.

Preguntas frecuentes

¿Cuál es la diferencia entre el contexto flow y el global en Node-RED?

El contexto flow solo lo comparten los nodos de la misma pestaña, mientras que el contexto global lo comparten todos los nodos de la instancia de Node-RED. Usa el contexto flow salvo que varias pestañas necesiten realmente el mismo valor.

¿Cómo hago que el contexto de Node-RED sobreviva a un reinicio?

Añade un almacén localfilesystem en contextStorage dentro de settings.js, reinicia Node-RED y escribe en ese almacén, por ejemplo flow.set("key", value, "file").

¿Dónde guarda Node-RED los archivos de contexto persistente?

En una carpeta context dentro del directorio de usuario de Node-RED, normalmente ~/.node-red/context o /data/context en Docker, organizada por ámbito.

¿Debo usar contexto o mensajes MQTT retenidos para los últimos valores?

Usa mensajes retenidos cuando otros clientes MQTT necesiten el último valor, y el contexto cuando solo lo necesite Node-RED, por ejemplo para servir una API o comparar lecturas. Muchos flujos usan ambos.

Artículos relacionados

Cliente OPC UA en Node-RED hacia MQTT con topics ISA-95

Usa node-red-contrib-opcua para suscribirte a variables OPC UA de un PLC o de un servidor de simulación, asignar los node IDs a topics MQTT de estilo ISA-95 y publicar los valores con calidad y marcas de tiempo.

10 min de lectura

Node-RED Dashboard 2.0 con MQTT: indicadores, gráficos y controles

Un tutorial práctico de Node-RED Dashboard 2.0: suscríbete a telemetría MQTT en directo, muéstrala en indicadores y en un gráfico de líneas, y controla un dispositivo con un interruptor que publica comandos y refleja el estado real.

9 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.