Node-RED

Tableau de bord TRS (OEE) Node-RED à partir de données machine MQTT

Calculez le TRS (OEE) dans Node-RED à partir de deux topics MQTT, l'état de la machine et les compteurs de pièces, puis affichez disponibilité, performance, qualité et TRS sur des jauges Dashboard 2.0 et republiez les indicateurs pour d'autres systèmes.

Tableau de bord TRS Node-RED avec quatre jauges pour la disponibilité, la performance, la qualité et l'OEE alimentées par des données machine 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

Un tableau de bord TRS Node-RED est l'un des moyens les plus rapides de mettre un véritable indicateur de production sous les yeux d'une équipe sans acheter de MES. Dans ce tutoriel, vous allez calculer la disponibilité, la performance et la qualité à partir de deux topics MQTT, l'état de la machine et les compteurs de pièces, et afficher le TRS (OEE en anglais) en direct sur des jauges Dashboard 2.0. Vous republierez aussi les indicateurs sur MQTT pour que d'autres outils puissent les utiliser, et découvrirez les cas limites qui faussent les calculs naïfs du TRS.

Le TRS en une minute

Le taux de rendement synthétique (TRS, Overall Equipment Effectiveness ou OEE en anglais) multiplie trois ratios, chacun compris entre 0 et 1 :

Facteur Formule Ce qu'il fait perdre
Disponibilité Temps de fonctionnement / temps de production planifié Pannes, changements de série, attente de matière
Performance (Temps de cycle idéal x nombre total) / temps de fonctionnement Cycles lents, micro-arrêts
Qualité Nombre de pièces bonnes / nombre total Rebuts et retouches
TRS (OEE) Disponibilité x Performance x Qualité Tout ce qui précède

L'intérêt de la formule est qu'elle demande très peu de données : quand la machine tournait, combien de pièces elle a produites et combien étaient bonnes. Cela se transpose parfaitement à MQTT. Pour approfondir les définitions, notamment les arrêts planifiés et non planifiés, voyez comment calculer le TRS.

Le modèle de données MQTT

La machine, ou une passerelle placée devant elle, publie deux topics :

Topic Payload Retenu Quand
connectmq/demo/a7f3k2/plant1/line1/press1/state RUNNING, IDLE ou DOWN Oui À chaque changement
connectmq/demo/a7f3k2/plant1/line1/press1/count {"total": 1234, "good": 1201} Non Toutes les quelques secondes

Deux choix de conception rendent l'ensemble robuste :

  • L'état est événementiel et retenu. Node-RED connaît l'état actuel dès sa connexion et cumule le temps de fonctionnement à partir des événements de changement.
  • Les compteurs sont cumulatifs, pas par pièce. Si un message est perdu, le suivant porte toujours le bon total. Node-RED calcule les écarts, et un compteur qui recule est traité comme une remise à zéro de l'automate plutôt que comme une production négative.

Le topic suit une hiérarchie de style ISA-95 (site, ligne, machine), derrière un préfixe de démo. Remplacez a7f3k2 par votre propre chaîne aléatoire, car le broker public est lisible par tous.

Simuler une machine

Ce script Python se comporte comme une presse avec un cycle idéal de 2 secondes, des arrêts occasionnels et environ 3 % de rebut. Il publie sur broker.connectmq.com, le serveur MQTT public gratuit, réservé aux tests et aux prototypes.

# pip install "paho-mqtt>=2.0"
import json
import random
import time
import uuid

import paho.mqtt.client as mqtt

BASE = "connectmq/demo/a7f3k2/plant1/line1/press1"

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=f"press-sim-{uuid.uuid4().hex[:8]}")
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()

state = None
total = 0
good = 0
next_cycle = time.time()
last_count_pub = 0.0


def set_state(new_state):
    global state
    if new_state != state:
        state = new_state
        client.publish(f"{BASE}/state", state, qos=1, retain=True)
        print("State:", state)


set_state("RUNNING")
try:
    while True:
        now = time.time()
        if state == "RUNNING":
            if random.random() < 0.004:
                set_state(random.choice(["IDLE", "DOWN"]))
            elif now >= next_cycle:
                total += 1
                if random.random() > 0.03:
                    good += 1
                # Les cycles réels sont un peu plus lents que l'idéal
                next_cycle = now + random.uniform(2.0, 2.6)
        elif random.random() < 0.02:
            set_state("RUNNING")
            next_cycle = time.time() + 2.0

        if now - last_count_pub >= 5:
            client.publish(f"{BASE}/count",
                           json.dumps({"total": total, "good": good}), qos=1)
            last_count_pub = now
        time.sleep(0.2)
except KeyboardInterrupt:
    pass
finally:
    client.loop_stop()
    client.disconnect()

Construire le flow du tableau de bord TRS Node-RED

Il vous faut Node-RED 4.x avec Dashboard 2.0 (@flowfuse/node-red-dashboard) installé. Si vous ne l'avez pas encore utilisé, le tutoriel Dashboard 2.0 couvre l'installation et la structure en pages et groupes.

Entrées

  1. Un nœud mqtt in sur .../press1/state, sortie « a UTF-8 string ».
  2. Un nœud mqtt in sur .../press1/count, sortie « a parsed JSON object ».
  3. Un nœud inject nommé « tick » qui se répète toutes les 5 secondes, avec msg.topic défini à tick.
  4. Un ui-button intitulé « Start new shift » avec msg.topic défini à shift/reset, plus un nœud inject avec le même topic programmé aux heures de changement d'équipe (par exemple 06:00, 14:00 et 22:00).

Utilisez deux abonnements précis plutôt qu'un wildcard press1/#. Vous publierez plus tard les indicateurs sous le même chemin machine, et un wildcard réinjecterait votre propre sortie dans le calcul.

Le calcul du TRS

Reliez les quatre entrées à un seul nœud function doté de cinq sorties :

// Nœud function "OEE calculator" - réglez Outputs sur 5
const IDEAL_CYCLE_S = 2.0;         // secondes idéales par pièce pour cette machine
const now = Date.now();

function newShift() {
    return { shiftStart: now, state: "UNKNOWN", since: now, runMs: 0,
             lastTotal: null, lastGood: null, total: 0, good: 0 };
}

let s = flow.get("oee") || newShift();
const topic = String(msg.topic || "");

if (topic === "shift/reset") {
    const keepState = s.state;
    s = newShift();
    s.state = keepState;            // la machine reste dans le même état
    flow.set("oee", s);
    return null;
}

if (topic.endsWith("/state")) {
    const st = String(msg.payload).trim().toUpperCase();
    if (s.state === "RUNNING") s.runMs += now - s.since;
    s.state = st;
    s.since = now;
    flow.set("oee", s);
    return null;
}

if (topic.endsWith("/count")) {
    const total = Number(msg.payload.total);
    const good = Number(msg.payload.good);
    if (!Number.isFinite(total) || !Number.isFinite(good)) return null;
    if (s.lastTotal !== null) {
        // Un compteur qui recule signifie que l'automate l'a remis à zéro
        const dTotal = total >= s.lastTotal ? total - s.lastTotal : total;
        const dGood = good >= s.lastGood ? good - s.lastGood : good;
        s.total += dTotal;
        s.good += Math.min(dGood, dTotal);
    }
    s.lastTotal = total;
    s.lastGood = good;
    flow.set("oee", s);
    return null;
}

if (topic !== "tick") return null;

// Calculer les indicateurs de l'équipe en cours
const runMs = s.runMs + (s.state === "RUNNING" ? now - s.since : 0);
const plannedMs = now - s.shiftStart;
const availability = plannedMs > 0 ? runMs / plannedMs : 0;
const rawPerformance = runMs > 0 ? (IDEAL_CYCLE_S * 1000 * s.total) / runMs : 0;
const performance = Math.min(1, rawPerformance);
const quality = s.total > 0 ? s.good / s.total : 0;
const oee = availability * performance * quality;

if (rawPerformance > 1.05) {
    node.warn("Performance above 100%: check IDEAL_CYCLE_S");
}

const pct = v => Math.round(v * 1000) / 10;
node.status({ fill: s.state === "RUNNING" ? "green" : "red", shape: "dot",
              text: `${s.state} OEE ${pct(oee)}%` });

return [
    { payload: pct(availability) },
    { payload: pct(performance) },
    { payload: pct(quality) },
    { payload: pct(oee) },
    { topic: "connectmq/demo/a7f3k2/plant1/line1/press1/oee",
      payload: { availability: pct(availability), performance: pct(performance),
                 quality: pct(quality), oee: pct(oee), total: s.total, good: s.good,
                 state: s.state, shiftStart: new Date(s.shiftStart).toISOString() },
      retain: true }
];

Cliquez une fois sur Start new shift après le déploiement, afin que l'équipe démarre à un instant connu.

Widgets

  • Les sorties 1 à 4 vont vers quatre nœuds ui-gauge, plage de 0 à 100, unité %. Un code couleur courant pour le TRS est rouge en dessous de 60, orange de 60 à 85 et vert au-dessus de 85, mais choisissez des seuils qui reflètent votre propre situation de départ.
  • La sortie 5 va vers un nœud mqtt out dont les champs topic et retain sont laissés vides, pour qu'il utilise msg.topic et msg.retain du message. Ajoutez un nœud ui-text après un nœud change qui extrait payload.state si vous voulez aussi afficher l'état de la machine à l'écran.

Ouvrez /dashboard et regardez les chiffres se stabiliser au cours des premières minutes. En début d'équipe, un seul arrêt fait fortement varier la disponibilité ; c'est mathématiquement correct, et les opérateurs s'y habituent vite.

Les pièges qui faussent le TRS

  1. Mauvais temps de cycle idéal. Si la performance dépasse 100 %, votre cycle idéal est trop lent. Ne vous contentez pas de plafonner la valeur : le plafond dans le code masque un problème de données.
  2. Compter les arrêts planifiés comme des temps d'arrêt. Pauses, maintenance planifiée et périodes sans commande sont généralement exclues du temps de production planifié. Ajoutez un état PLANNED_STOP et retirez ce temps de plannedMs si votre usine utilise cette définition.
  3. Perdre l'état lors des redémarrages. Le contexte du flow est en mémoire par défaut. Stockez l'objet oee dans un magasin de contexte persistant sur fichier, pour qu'un redémarrage de Node-RED en cours d'équipe ne remette pas les indicateurs à zéro.
  4. Messages dans le désordre. En QoS 1 avec un seul éditeur, MQTT préserve l'ordre par topic, mais l'état et le comptage sont des topics distincts. Calculer sur une minuterie, comme ci-dessus, rend les petits écarts temporels sans importance.
  5. Débordement des compteurs. Les compteurs d'automate 16 bits repassent à zéro après 65 535. La logique de remise à zéro traite ce débordement comme une remise à zéro, ce qui fait perdre au plus un intervalle de comptage.

Les motifs d'arrêt constituent l'étape suivante naturelle : ajoutez un code motif à l'état DOWN et cumulez les minutes par motif. Le guide sur le suivi des arrêts machine explique comment structurer ces codes.

Conserver l'historique du TRS

Les jauges n'affichent que l'équipe en cours. Pour comparer les équipes, écrivez le message d'indicateurs retenu dans une base de séries temporelles à la fin de chaque équipe, ou chaque minute. Le tutoriel Node-RED InfluxDB montre comment stocker exactement ce type de JSON avec des tags comme la ligne et la machine, puis le représenter graphiquement.

Passer à une ligne ou une usine entière

Un nœud function par machine convient pour un pilote. Pour une ligne complète, abonnez-vous avec un wildcard à un niveau comme plant1/line1/+/state, conservez un objet de contexte par machine indexé par le niveau de topic, et publiez les indicateurs de chaque machine sur son propre topic. Comme le calcul ne dépend que des topics MQTT, peu importe que les données proviennent d'une passerelle d'automate, d'un compteur ESP32 ou d'un équipement edge.

C'est aussi là que le broker compte. Une usine avec des dizaines de machines, un serveur Node-RED, un historien et peut-être un client SCADA connectés simultanément a besoin d'un broker MQTT cloud fiable avec authentification, plutôt que d'un service de test public. ConnectMQ reconnaît les topics de style ISA-95 comme plant1/line1/press1/state et regroupe les équipements selon ces niveaux dans son portail, ce qui permet de voir facilement quelles machines remontent des données. Les règles d'alerte à seuil du portail ConnectMQ peuvent aussi signaler une valeur numérique qui franchit une limite de votre choix, tandis que Node-RED reste responsable du calcul lui-même. Si vous préférez ne pas exploiter vous-même cette infrastructure, un broker MQTT managé retire le broker de votre liste de maintenance. Pour les fondamentaux du broker et de Node-RED, commencez par le tutoriel Node-RED MQTT.

Placez vos données TRS sur ConnectMQ

Inscrivez-vous sur app.connectmq.com avec l'offre gratuite Serverless, sans carte bancaire. Créez un broker, utilisez le nom d'utilisateur, le mot de passe et le client ID générés dans vos machines et dans Node-RED, et passez en TLS sur le port 8883. Votre pipeline TRS privé tournera avant le prochain changement d'équipe.

Questions fréquentes

De quelles données ai-je besoin pour calculer le TRS dans Node-RED ?

Il vous faut l'état de la machine dans le temps, un nombre total de pièces, un nombre de pièces bonnes et le temps de cycle idéal. Avec ces quatre entrées, Node-RED peut calculer la disponibilité, la performance, la qualité et le TRS.

Pourquoi les machines doivent-elles publier des compteurs cumulatifs ?

Les compteurs cumulatifs rendent le calcul tolérant aux messages perdus ou retardés, car chaque message porte le total complet. Node-RED calcule la différence et gère les remises à zéro.

À quelle fréquence le tableau de bord TRS doit-il se mettre à jour ?

Toutes les 5 à 30 secondes suffisent pour les opérateurs. Calculer sur une minuterie plutôt qu'à chaque message garde aussi le tableau de bord fluide lorsque de nombreuses machines publient en même temps.

Puis-je afficher le TRS de plusieurs machines sur une même page ?

Oui. Utilisez un abonnement avec wildcard, conservez un objet de contexte par machine et ajoutez un groupe de tableau de bord par machine, ou un tableau construit avec un nœud ui-template.

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.