Node-RED

Stockage de contexte Node-RED : flow, global et persistant

Le contexte Node-RED permet aux flows de mémoriser des informations entre les messages. Cet article explique les trois portées, le stockage en mémoire ou sur fichier, les magasins multiples, l'accès asynchrone et un modèle pratique pour conserver la dernière valeur MQTT de chaque appareil.

Schéma des portées du contexte Node-RED avec les stockages node, flow et global contenant les dernières valeurs MQTT
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Le contexte Node-RED est le stockage clé-valeur intégré qui permet à un flow de mémoriser des valeurs entre les messages, comme la dernière température remontée par un capteur ou le nombre d'alarmes de la journée. Cet article présente les trois portées de contexte, la façon de faire survivre le contexte aux redémarrages, l'utilisation de plusieurs magasins en même temps et un modèle propre pour conserver la dernière valeur MQTT de chaque appareil.

Pourquoi les flows ont besoin d'un état

Les messages dans Node-RED sont indépendants. Lorsqu'un nœud mqtt in émet une mesure, le nœud suivant ne connaît que le contenu de ce message. Beaucoup de tâches réelles exigent davantage :

  • Comparer une valeur à la précédente pour détecter un changement ou une tendance.
  • Répondre à une requête HTTP avec la mesure la plus récente, même si aucun message MQTT n'arrive à cet instant.
  • Compter des événements par poste, ou mémoriser le début d'une alarme.
  • Combiner des valeurs issues de deux topics qui arrivent à des moments différents.

MQTT offre lui-même une forme de mémoire grâce aux retained messages : le broker stocke le dernier message d'un topic et le transmet aux nouveaux abonnés. C'est idéal pour un état partagé entre clients, et vous devriez l'utiliser. Le contexte est l'outil complémentaire pour l'état qui vit à l'intérieur de Node-RED. Si vous ne savez pas de quel côté placer une responsabilité, notre article sur ce que fait un broker MQTT trace la frontière.

Les trois portées du contexte Node-RED

Portée Visible par Usage typique Accès dans une function
Node Uniquement le nœud qui l'a définie Filtres à bande morte, compteurs dans une function context.get() / context.set()
Flow Tous les nœuds du même onglet (ou de la même instance de subflow) Dernières valeurs utilisées par plusieurs nœuds d'un onglet flow.get() / flow.set()
Global Tous les nœuds de l'instance Node-RED Configuration partagée, tables de correspondance global.get() / global.set()

Choisissez la portée la plus étroite qui convient. Une valeur du contexte global peut être modifiée par n'importe quel nœud de n'importe quel onglet, ce qui rend les bugs difficiles à tracer. Le contexte node est privé : rien d'autre ne peut le casser.

Vous n'avez pas besoin d'écrire du code pour utiliser le contexte. Le nœud Change peut définir, lire, déplacer et supprimer des propriétés flow. et global., et les nœuds Inject, Switch et Template peuvent les lire. L'onglet Context Data de la barre latérale de l'éditeur affiche les valeurs actuelles de chaque portée et permet de rafraîchir ou de supprimer des entrées pendant le débogage.

Les subflows ont une particularité supplémentaire : le contexte flow à l'intérieur d'un subflow appartient à cette instance. Un subflow peut atteindre le contexte du flow parent avec le préfixe $parent., par exemple flow.get("$parent.lastTemp").

Contexte en mémoire ou persistant

Par défaut, tout le contexte est stocké en mémoire. C'est rapide, mais il disparaît quand Node-RED redémarre, quand le conteneur est recréé ou quand l'hôte redémarre. Pour tout ce que vous ne pouvez pas reconstruire facilement, activez le stockage sur fichier.

Ouvrez settings.js (dans ~/.node-red/ sur une installation standard, ou /data/ dans l'image Docker) et trouvez la section contextStorage :

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

Redémarrez Node-RED. Vous disposez maintenant de deux magasins : default, qui reste en mémoire, et file, qui écrit des fichiers JSON dans le dossier context/ de votre répertoire utilisateur. Les nœuds choisissent un magasin explicitement :

flow.set("lastReading", msg.payload, "file");   // persisté
flow.set("scratch", 42);                        // mémoire (magasin par défaut)
const last = flow.get("lastReading", "file");

Dans le nœud Change et les autres éditeurs, un petit sélecteur de magasin apparaît à côté des champs flow. et global. dès que vous avez plus d'un magasin.

Si vous préférez tout rendre persistant, définissez plutôt default: { module: "localfilesystem" }. Gardez en tête le fonctionnement du magasin fichier : les valeurs sont mises en cache en mémoire et écrites sur disque à intervalle régulier, toutes les 30 secondes par défaut, selon l'option flushInterval. Un plantage brutal peut faire perdre les dernières secondes de modifications. C'est acceptable pour des dernières valeurs et des compteurs, mais le contexte n'est pas une base de données. Pour les données historiques, écrivez dans une base de séries temporelles comme InfluxDB, comme le montre notre guide Node-RED InfluxDB.

Notez aussi que seules les valeurs sérialisables en JSON sont persistées de manière fiable. Les fonctions, minuteries et instances de classes ne reviendront pas intactes après un redémarrage : stockez des objets simples, des nombres et des chaînes.

Accès synchrone et asynchrone

Avec les magasins memory et localfilesystem, get et set fonctionnent de façon synchrone comme ci-dessus. Certains magasins tiers, comme les modules basés sur Redis, sont asynchrones et exigent des 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();
    });
});

Écrire le code avec des callbacks dès le départ coûte peu et permet de changer de magasin plus tard sans réécrire chaque function. Sachez qu'un get suivi d'un set n'est pas atomique. Avec des débits de messages très élevés sur un magasin asynchrone, deux messages peuvent lire la même ancienne valeur du compteur. Gardez les compteurs dans le contexte node, où un seul nœud écrit, ou regroupez les mises à jour.

Vous pouvez aussi lire et écrire plusieurs clés à la fois en passant des tableaux : flow.get(["a", "b"]) renvoie un tableau de valeurs.

Modèle : conserver la dernière valeur MQTT de chaque appareil

Une tâche courante du contexte Node-RED est une table « dernière valeur connue » en direct : une entrée par appareil, mise à jour à chaque message, lisible depuis n'importe où dans le flow. Publiez quelques données de test sur le serveur MQTT public gratuit de ConnectMQ (réservé aux tests, jamais aux données de production), en remplaçant c8d1 par votre propre chaîne aléatoire :

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}'

Abonnez-vous dans Node-RED avec un nœud mqtt in sur connectmq/demo/c8d1/+/+/telemetry, sortie en JSON parsé, et reliez-le à cette function :

// Function "store latest"
const parts = msg.topic.split("/");
const deviceId = parts[3] + "/" + parts[4];       // par ex. "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;

Désormais, n'importe quel nœud de l'onglet peut lire la table. Un nœud http in sur GET /latest suivi de cette function et d'un nœud http response vous donne une petite API :

// Function "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;

L'indicateur stale est le détail important. Une table de dernières valeurs qui n'expire jamais affiche sans sourciller la mesure d'un appareil mort la veille. Stockez toujours un horodatage avec la valeur.

Liste de bonnes pratiques pour le contexte Node-RED

  1. Utilisez la portée la plus étroite : node, puis flow, puis global.
  2. Activez un magasin fichier et choisissez-le explicitement pour les valeurs que vous ne pouvez pas reconstruire.
  3. Stockez des horodatages avec les valeurs pour détecter les données périmées.
  4. Évitez les objets énormes ; de grosses entrées de contexte ralentissent chaque écriture et chaque rafraîchissement de la barre latérale.
  5. Préfixez les clés globales selon leur rôle, par exemple cfg_ pour la configuration et cache_ pour les données de correspondance.
  6. Ne stockez pas de secrets dans le contexte. Les identifiants ont leur place dans les nœuds de configuration et les variables d'environnement.
  7. Utilisez les retained messages MQTT pour l'état dont d'autres clients ont besoin, et le contexte pour l'état dont seul Node-RED a besoin.
  8. Sauvegardez le dossier context/ avec vos flows. Vous faites tourner Node-RED dans des conteneurs ? Notre guide Node-RED Docker montre comment garder /data sur un volume persistant.

La documentation officielle du contexte couvre en détail l'API des magasins et les options de configuration. Pour le versant code de ces modèles, consultez notre guide du nœud function Node-RED, et pour une vue d'ensemble de la connexion des flows aux brokers, le tutoriel Node-RED MQTT.

Associez le contexte Node-RED à ConnectMQ

Le contexte conserve la mémoire propre de Node-RED ; le broker conserve celle de tous les autres. ConnectMQ est un broker MQTT managé avec retained messages, expiration de session MQTT 5 et TLS, si bien que les appareils, les tableaux de bord et Node-RED voient tous les mêmes dernières valeurs connues. Son portail ajoute un explorateur de topics en direct et des règles d'alerte à seuil pour des vérifications rapides sans construire de flow. Commencez avec l'offre Serverless gratuite sur app.connectmq.com, sans carte bancaire, et connectez Node-RED avec le nom d'utilisateur, le mot de passe et le client ID générés.

Questions fréquentes

Quelle est la différence entre le contexte flow et le contexte global dans Node-RED ?

Le contexte flow n'est partagé que par les nœuds d'un même onglet, tandis que le contexte global est partagé par tous les nœuds de l'instance Node-RED. Utilisez le contexte flow, sauf si plusieurs onglets ont réellement besoin de la même valeur.

Comment faire survivre le contexte Node-RED à un redémarrage ?

Ajoutez un magasin localfilesystem sous contextStorage dans settings.js, redémarrez Node-RED et écrivez dans ce magasin, par exemple flow.set("key", value, "file").

Où Node-RED stocke-t-il les fichiers de contexte persistant ?

Dans un dossier context du répertoire utilisateur Node-RED, généralement ~/.node-red/context ou /data/context sous Docker, organisé par portée.

Faut-il utiliser le contexte ou les retained messages MQTT pour les dernières valeurs ?

Utilisez les retained messages quand d'autres clients MQTT ont besoin de la dernière valeur, et le contexte quand seul Node-RED en a besoin, par exemple pour servir une API ou comparer des mesures. Beaucoup de flows utilisent les deux.

Articles liés

Node-RED Dashboard 2.0 avec MQTT : jauges, graphiques et commandes

Un tutoriel pratique Node-RED Dashboard 2.0 : abonnez-vous à une télémétrie MQTT en direct, affichez-la sur des jauges et un graphique en courbe, et pilotez un appareil avec un interrupteur qui publie des commandes et reflète l'état réel.

9 min de lecture

Client Node-RED OPC UA vers MQTT avec des topics ISA-95

Utilisez node-red-contrib-opcua pour vous abonner aux variables OPC UA d'un automate ou d'un serveur de simulation, associer les node IDs à des topics MQTT de style ISA-95 et publier les valeurs avec leur qualité et leur horodatage.

10 min de lecture

Historique des graphiques Node-RED : conserver les données MQTT après un redémarrage

Les graphiques du Dashboard oublient tout quand Node-RED redémarre. Ce guide présente deux méthodes fiables pour conserver l'historique des graphiques Node-RED pour les données MQTT : le stockage de contexte sur fichier et une petite table SQLite, toutes deux rejouées dans Dashboard 2.0 au démarrage.

8 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.