Node-RED

Node-RED HTTP vers MQTT : exposer des endpoints REST qui publient sur votre broker

Les systèmes historiques, les scripts ERP et les webhooks parlent HTTP, vos équipements parlent MQTT. Ce tutoriel construit une passerelle Node-RED HTTP vers MQTT avec validation, authentification, endpoints de lecture et attente optionnelle de l'acquittement.

Passerelle Node-RED HTTP vers MQTT transformant les requêtes REST de systèmes historiques en commandes MQTT pour les équipements
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

Une passerelle Node-RED HTTP vers MQTT permet à n'importe quel système capable d'envoyer une requête web de déclencher des commandes sur des équipements MQTT, sans ajouter de bibliothèque MQTT à ce système. Dans ce tutoriel, vous allez exposer dans Node-RED un endpoint REST qui valide la requête, publie une commande sur un broker, attend éventuellement la confirmation de l'équipement et renvoie un code de statut HTTP correct.

Quand une passerelle HTTP vers MQTT a du sens

MQTT est le bon protocole entre les équipements et le broker, mais une grande partie des logiciels qui gravitent autour d'une usine ou d'un bâtiment ne connaissent que HTTP :

  • Un ERP ou un MES capable d'appeler une URL au démarrage d'un ordre de fabrication.
  • Un webhook provenant d'un produit SaaS, d'un prestataire de paiement ou d'un outil de formulaires.
  • Des scripts shell et des tâches cron qui utilisent déjà curl.
  • Des applications mobiles ou des tableaux de bord auxquels vous ne voulez pas confier des connexions MQTT de longue durée.
  • Un intégrateur tiers qui n'accepte qu'un contrat REST.

Au lieu d'apprendre MQTT à chacun de ces systèmes, vous leur fournissez une petite API HTTP bien définie. Node-RED traduit chaque requête en une publication sur le bon topic. Les équipements restent de purs clients MQTT, et le broker reste l'unique endroit par lequel transitent les messages.

Architecture du flow

HTTP client --POST /api/devices/pump1/command--> Node-RED
Node-RED --publish connectmq/demo/h7r2pq/pump1/cmd--> MQTT broker --> device
device --publish connectmq/demo/h7r2pq/pump1/ack--> MQTT broker --> Node-RED
Node-RED --HTTP 200 or 202 or 504--> HTTP client

Nous allons construire trois endpoints :

Méthode et chemin Rôle Réponse
POST /api/devices/:id/command Publier une commande et répondre immédiatement 202 Accepted
POST /api/devices/:id/command?wait=1 Publier et attendre l'acquittement de l'équipement 200 OK ou 504 Gateway Timeout
GET /api/devices/:id/state Renvoyer le dernier état connu reçu via MQTT 200 OK ou 404 Not Found

Pour la démo, nous utilisons le serveur MQTT public gratuit broker.connectmq.com avec le préfixe connectmq/demo/h7r2pq. Choisissez votre propre préfixe aléatoire et n'envoyez jamais de vraies commandes de pilotage via l'espace public : n'importe qui peut y lire et y publier. Il est réservé aux tests et aux prototypes, pas aux données de production.

Étape 1 : l'endpoint HTTP et la validation

Ajoutez un nœud http in avec la méthode POST et l'URL /api/devices/:id/command. Node-RED analyse automatiquement les corps JSON lorsque le client envoie Content-Type: application/json, et place les paramètres de chemin dans msg.req.params.

Reliez-le à un nœud function doté de deux sorties : la première part vers MQTT, la seconde renvoie directement les erreurs à un nœud http response.

const PREFIX = "connectmq/demo/h7r2pq";
const ALLOWED_DEVICES = ["pump1", "pump2", "valve3"];
const ALLOWED_ACTIONS = ["start", "stop", "setpoint"];
const API_KEY = env.get("BRIDGE_API_KEY");   // à définir dans le flow ou l'environnement

function fail(code, message) {
    msg.statusCode = code;
    msg.payload = { error: message };
    return [null, msg];
}

if (!API_KEY || msg.req.headers["x-api-key"] !== API_KEY) {
    return fail(401, "invalid or missing API key");
}

const id = msg.req.params.id;
if (!ALLOWED_DEVICES.includes(id)) return fail(404, "unknown device " + id);

const body = msg.payload;
if (typeof body !== "object" || body === null) return fail(400, "JSON body required");
if (!ALLOWED_ACTIONS.includes(body.action)) return fail(400, "action must be one of " + ALLOWED_ACTIONS.join(", "));
if (body.action === "setpoint" && typeof body.value !== "number") {
    return fail(400, "setpoint requires a numeric value");
}

const correlationId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
const command = {
    action: body.action,
    value: body.value,
    correlationId,
    issuedAt: new Date().toISOString(),
    source: "http"
};

msg.deviceId = id;
msg.correlationId = correlationId;
msg.wait = msg.req.query.wait === "1";
msg.topic = `${PREFIX}/${id}/cmd`;
msg.payload = JSON.stringify(command);
msg.qos = 1;
msg.retain = false;
return [msg, null];

Ne construisez jamais le topic MQTT directement à partir d'une saisie utilisateur sans la vérifier contre une liste autorisée. Sinon, une requête pour l'équipement # ou ../../other publierait sur des topics que vous n'aviez jamais l'intention d'exposer.

Étape 2 : publier et répondre

Reliez la première sortie à deux endroits :

  1. Un nœud mqtt out avec un champ topic vide, afin qu'il utilise msg.topic, connecté au nœud de configuration de votre broker.
  2. Un nœud function qui décide comment répondre à l'appelant HTTP :
if (msg.wait) {
    // Mettre la requête en attente jusqu'à l'acquittement ou l'expiration du minuteur
    const pending = flow.get("pending") || {};
    pending[msg.correlationId] = msg;
    flow.set("pending", pending);

    setTimeout(() => {
        const p = flow.get("pending") || {};
        const waiting = p[msg.correlationId];
        if (waiting) {
            delete p[msg.correlationId];
            flow.set("pending", p);
            waiting.statusCode = 504;
            waiting.payload = { error: "device did not acknowledge in time", correlationId: msg.correlationId };
            node.send(waiting);
        }
    }, 5000);
    return null;
}

msg.statusCode = 202;
msg.payload = { status: "accepted", correlationId: msg.correlationId, topic: msg.topic };
return msg;

Reliez ce nœud function et la sortie d'erreur de l'étape 1 au même nœud http response. Celui-ci utilise msg.statusCode et envoie msg.payload au format JSON.

La réponse asynchrone 202 est le bon choix par défaut. Les équipements MQTT peuvent être en veille, en cours de reconnexion ou occupés, et un client HTTP ne doit pas rester bloqué pour autant. La variante wait=1 est utile pour les outils interactifs, lorsqu'une personne clique sur un bouton et veut savoir si la pompe a réellement démarré.

Étape 3 : traiter les acquittements des équipements

L'équipement publie un acquittement qui reprend l'identifiant de corrélation, par exemple sur connectmq/demo/h7r2pq/pump1/ack :

{ "correlationId": "lrx2k9ab12cd", "result": "ok", "state": "running" }

Abonnez-vous avec un nœud mqtt in à connectmq/demo/h7r2pq/+/ack (sortie : JSON analysé) et associez-le à la requête en attente :

const ack = msg.payload;
const pending = flow.get("pending") || {};
const waiting = pending[ack.correlationId];
if (!waiting) return null;   // déjà expirée, ou requête 202

delete pending[ack.correlationId];
flow.set("pending", pending);

waiting.statusCode = ack.result === "ok" ? 200 : 409;
waiting.payload = { status: ack.result, state: ack.state, correlationId: ack.correlationId };
return waiting;

Reliez-le au même nœud http response. Comme le message en attente transporte toujours l'objet msg.res d'origine, la réponse revient au bon appelant HTTP. Les requêtes en attente vivent en mémoire, ce qui ne pose pas de problème : les connexions HTTP auxquelles elles appartiennent disparaissent elles aussi au redémarrage de Node-RED.

Si vous utilisez MQTT 5, vous pouvez définir msg.responseTopic et msg.correlationData sur la commande sortante au lieu d'intégrer l'identifiant dans le JSON. Le nœud mqtt out les transmet sous forme de propriétés MQTT 5, et les équipements qui les prennent en charge peuvent répondre sur le topic demandé. Le guide des fonctionnalités de MQTT 5 détaille le modèle requête-réponse.

Étape 4 : un endpoint de lecture pour l'état des équipements

Les équipements doivent publier leur état sous forme de retained messages sur connectmq/demo/h7r2pq/<id>/state. Abonnez-vous à connectmq/demo/h7r2pq/+/state et stockez chaque état dans le contexte du flow :

const id = msg.topic.split("/")[3];
const states = flow.get("states") || {};
states[id] = { state: msg.payload, receivedAt: new Date().toISOString() };
flow.set("states", states);
return null;

Ajoutez ensuite un nœud http in pour GET /api/devices/:id/state :

const states = flow.get("states") || {};
const s = states[msg.req.params.id];
if (!s) {
    msg.statusCode = 404;
    msg.payload = { error: "no state received for this device" };
} else {
    msg.statusCode = 200;
    msg.payload = s;
}
return msg;

Comme les messages d'état sont retenus, Node-RED reçoit la dernière valeur de chaque équipement dès sa reconnexion : l'endpoint de lecture est donc utilisable immédiatement après un redémarrage.

Tester avec curl

Définissez la clé d'API comme variable d'environnement pour Node-RED (BRIDGE_API_KEY=change-me), déployez, puis appelez les endpoints sur le port par défaut 1880 :

# Envoyer sans attendre
curl -i -X POST http://localhost:1880/api/devices/pump1/command \
  -H "Content-Type: application/json" -H "X-API-Key: change-me" \
  -d '{"action":"start"}'

# Attendre l'acquittement (renvoie 504 après 5 s si aucun équipement ne répond)
curl -i -X POST "http://localhost:1880/api/devices/pump1/command?wait=1" \
  -H "Content-Type: application/json" -H "X-API-Key: change-me" \
  -d '{"action":"setpoint","value":42.5}'

# Simuler l'acquittement de l'équipement (copiez le correlationId depuis le topic cmd)
mosquitto_sub -h broker.connectmq.com -p 1883 -i dev-h7r2pq -v -t "connectmq/demo/h7r2pq/pump1/cmd"
mosquitto_pub -h broker.connectmq.com -p 1883 -i ack-h7r2pq -t "connectmq/demo/h7r2pq/pump1/ack" \
  -m '{"correlationId":"PASTE_ID","result":"ok","state":"running"}'

Sécuriser une passerelle Node-RED HTTP vers MQTT

Un endpoint HTTP qui actionne des pompes constitue une surface d'attaque. Parcourez cette liste avant de l'exposer au-delà de localhost :

  1. Authentifiez chaque requête. La vérification de clé d'API ci-dessus est un minimum. Pour une authentification basique sur tous les endpoints HTTP-in, définissez httpNodeAuth dans settings.js avec un hachage bcrypt généré par node-red admin hash-pw.
  2. Terminez le TLS devant Node-RED avec un reverse proxy comme Nginx ou Caddy. N'exposez pas directement le port 1880 sur Internet.
  3. Protégez l'éditeur avec adminAuth, ou servez l'éditeur sur un chemin ou un port distinct, uniquement interne.
  4. Validez les entrées à l'aide de listes autorisées pour les équipements et les actions, et vérifiez le type des valeurs.
  5. Limitez le débit au niveau du proxy, en gardant à l'esprit que le broker applique lui aussi des limites. Le broker public autorise 10 messages par seconde et par client, et les offres de production ont leurs propres quotas.
  6. Utilisez des identifiants de broker privés via TLS sur le port 8883 pour les nœuds mqtt.

Notre article sur la sécurisation de Node-RED traite en détail de l'éditeur et des paramètres.

Passer à un broker de production

Remplacez la configuration du broker de démo par un broker ConnectMQ privé : port 8883, TLS activé, et les valeurs YOUR_USERNAME, YOUR_PASSWORD et YOUR_CLIENT_ID générées dans le portail. ConnectMQ ne propose ni webhooks ni API de publication HTTP propre, et c'est précisément pour cela que ce modèle existe : Node-RED est la couche exposée en HTTP, et le broker reste concentré sur MQTT. Avec un broker MQTT managé, le seul serveur dont vous vous occupez est l'instance Node-RED.

Faites tourner votre passerelle Node-RED sur ConnectMQ

Créez gratuitement un broker sur app.connectmq.com avec l'offre Serverless, sans carte bancaire, et connectez-y votre passerelle Node-RED via TLS. Vous pouvez suivre les commandes et les acquittements dans l'explorateur de topics en direct du portail pendant que vous testez vos endpoints avec curl. Pour les bases des nœuds MQTT, consultez le tutoriel Node-RED MQTT et, pour le sens inverse, l'envoi d'alertes à des personnes, le guide du bot Telegram avec Node-RED.

Questions fréquentes

Node-RED peut-il recevoir des webhooks et les publier sur MQTT ?

Oui. Un nœud http in accepte le webhook, un nœud function le valide et construit un topic, et un nœud mqtt out le publie. Renvoyez rapidement une réponse 2xx pour que l'émetteur du webhook ne réessaie pas.

L'endpoint HTTP doit-il attendre la réponse de l'équipement ?

Renvoyez 202 Accepted par défaut et laissez les clients consulter l'état séparément. Attendre un acquittement est utile en usage interactif, mais imposez toujours un délai d'expiration court.

Quelle QoS utiliser pour les commandes venant de HTTP ?

La QoS 1 est un bon choix par défaut pour les commandes, combinée à des actions idempotentes comme start et stop plutôt qu'une bascule (toggle), afin qu'une livraison en double ne cause aucun dommage.

ConnectMQ fournit-il une API REST de publication ?

Non. ConnectMQ est un broker MQTT doté d'endpoints MQTT, TLS et WebSocket. Utilisez Node-RED ou un petit service de votre cru pour traduire les requêtes HTTP en publications MQTT.

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.