Flows Node-RED Modbus são uma das formas mais rápidas de tirar dados de medidores, inversores e CLPs que só falam Modbus e levá-los ao MQTT, onde dashboards, historiadores e ferramentas na nuvem podem usá-los. Neste tutorial você vai fazer polling de holding registers e coils com node-red-contrib-modbus, decodificar corretamente inteiros com escala e floats de 32 bits e publicar JSON limpo em um broker apenas quando os valores mudarem. Você também vai ver como tratar comandos de escrita com segurança e como testar tudo sem hardware real.
Por que fazer a ponte de Modbus para MQTT com o Node-RED
O Modbus é um protocolo de requisição/resposta de 1979: um cliente (mestre) pede a um servidor (escravo) um bloco de registradores e recebe de volta números brutos de 16 bits. Não há unidades, nomes, timestamps nem envio espontâneo. Cada consumidor que quer os dados precisa consultar o dispositivo por conta própria, e muitos dispositivos aceitam apenas poucas conexões simultâneas.
O MQTT inverte isso. Um gateway consulta o dispositivo, dá significado aos números e os publica uma única vez em um broker. Qualquer número de assinantes recebe então valores nomeados e com escala no momento em que mudam. O Node-RED é um gateway natural porque polling, decodificação, filtragem e publicação são, cada um, um node, e a lógica fica visível para a equipe de manutenção, seja em uma estação de saneamento ou em uma planta industrial. Para a visão arquitetural mais ampla, o guia de Modbus TCP para MQTT compara o Node-RED com outras opções de gateway.
Instale o node-red-contrib-modbus
Instale o pacote em Manage palette → Install ou pela linha de comando:
cd ~/.node-red
npm install node-red-contrib-modbus
# reinicie o Node-RED em seguida
Ele fornece, entre outros, estes nodes:
| Node | Função |
|---|---|
| Modbus Read | Faz polling de um bloco fixo de registradores em intervalos regulares |
| Modbus Getter | Lê sob demanda quando chega uma mensagem |
| Modbus Flex Getter | Lê o que a mensagem de entrada especificar |
| Modbus Write | Escreve coils ou registradores |
| Modbus Server | Um servidor Modbus TCP simples para testes |
| Modbus Client (config) | Conexão TCP ou serial compartilhada pelos nodes |
Entenda primeiro o mapa de registradores
Todo projeto Modbus começa pelo mapa de registradores do dispositivo. Para este tutorial, imagine um controlador de bomba com este mapa:
| Dado | Tipo | Endereço (base 0) | Notação clássica | Escala |
|---|---|---|---|---|
| Temperatura | Holding register, 16 bits com sinal | 0 | 40001 | valor / 10, °C |
| Pressão | Holding register, 16 bits sem sinal | 1 | 40002 | valor / 100, bar |
| Vazão | Holding registers, float de 32 bits, big-endian | 2-3 | 40003-40004 | nenhuma, m³/h |
| Bomba ligada | Coil | 0 | 00001 | booleano |
O erro mais comum em Node-RED Modbus é o endereço. Datasheets costumam usar a notação "40001", que começa em um e inclui um prefixo de tipo. O endereço do protocolo, que é o que você digita no Node-RED, começa em zero e não tem prefixo: 40001 vira o holding register de endereço 0. Se seus valores parecem deslocados em um registrador, é por isso.
Teste sem hardware: um servidor Modbus local
Você pode seguir o tutorial inteiro sem nenhum dispositivo rodando um servidor Modbus dentro do próprio Node-RED.
- Arraste um node Modbus Server para uma aba separada. Configure-o para escutar em
0.0.0.0, porta10502(não privilegiada, então não precisa de root). Faça o deploy. - Crie um node de configuração Modbus Client: tipo TCP, host
127.0.0.1, porta10502, unit ID1. - Adicione um inject node repetindo a cada 2 segundos, um function node que gera valores simulados de registradores e um node Modbus Write usando esse cliente com function code 16 (preset multiple registers), endereço
0, quantidade4.
A função do simulador:
// Function node "simulate pump registers" -> Modbus Write (FC16, endereço 0, quantidade 4)
const temperature = 40 + Math.random() * 5; // °C
const pressure = 3.2 + Math.random() * 0.3; // bar
const flowRate = 12 + Math.random() * 2; // m³/h
const buf = Buffer.alloc(4);
buf.writeFloatBE(flowRate, 0);
msg.payload = [
Math.round(temperature * 10), // registrador 0
Math.round(pressure * 100), // registrador 1
buf.readUInt16BE(0), // registrador 2: palavra alta do float
buf.readUInt16BE(2) // registrador 3: palavra baixa do float
];
return msg;
Adicione um segundo node de escrita para o coil: function code 5 (force single coil), endereço 0, alimentado com true a partir de um inject node. Seu controlador de bomba simulado já está funcionando.
Monte o flow de polling Node-RED Modbus
Passo 1: faça polling dos registradores
Adicione um node Modbus Read com o mesmo cliente:
- FC: 3, Read Holding Registers
- Endereço:
0, Quantidade:4 - Taxa de polling: 2 segundos
A primeira saída emite msg.payload como um array de quatro números brutos, por exemplo [423, 334, 16708, 26214]. A segunda saída traz o buffer bruto e os detalhes da resposta, o que é útil para depurar a ordem dos bytes.
Para o coil, adicione um segundo node Modbus Read com FC 1 (Read Coil Status), endereço 0, quantidade 1 e um polling mais lento, de 5 segundos.
Passo 2: decodifique os registradores brutos em valores de engenharia
// Function node "decode pump registers"
const r = msg.payload;
if (!Array.isArray(r) || r.length < 4) {
node.warn("Unexpected register block");
return null;
}
// Conversão para 16 bits com sinal da temperatura
const int16 = v => (v > 32767 ? v - 65536 : v);
// Float de 32 bits a partir de dois registradores, ordem de palavras big-endian
const buf = Buffer.alloc(4);
buf.writeUInt16BE(r[2], 0);
buf.writeUInt16BE(r[3], 2);
const flowRate = buf.readFloatBE(0);
const values = {
temperature: Math.round(int16(r[0])) / 10,
pressure: Math.round(r[1]) / 100,
flow: Math.round(flowRate * 100) / 100
};
// Guarda para combinar com a leitura do coil
flow.set("pump1_values", values);
msg.topic = "connectmq/demo/a7f3k2/plant1/utilities/pump1/telemetry";
msg.payload = {
...values,
running: flow.get("pump1_running") === true
};
return msg;
Ligue a leitura do coil a uma pequena função que guarda o estado: flow.set("pump1_running", msg.payload[0] === true); return null;. Muitos dispositivos usam floats com "palavras invertidas", em que a palavra baixa vem primeiro. Se o valor da vazão parecer absurdo, como 1.2e-38 ou -4.5e+12, troque r[2] e r[3] de lugar e tente de novo.
Passo 3: publique apenas quando algo mudar
Fazer polling a cada 2 segundos e publicar todos os resultados desperdiça banda e enche os assinantes de dados duplicados. Insira um node filter (antes chamado RBE) configurado como "block unless value changes" em msg.payload, ou use uma versão com banda morta em valores individuais se eles oscilarem. O filtro compara o objeto inteiro, e é por isso que a função de decodificação não adiciona timestamp. Depois do filtro, adicione um change node que define msg.payload.ts com um timestamp. Reportar por exceção é um padrão central do MQTT, mas ainda vale adicionar um heartbeat periódico para valores que mudam pouco, para que os assinantes consigam distinguir um dispositivo quieto de um dispositivo morto.
Passo 4: publique no MQTT
Adicione um node mqtt out com o topic vazio para que msg.topic seja usado. Para testes, configure o broker como broker.connectmq.com, porta 1883, com um client ID único, que é o servidor MQTT público. Substitua a7f3k2 por uma string sua. Depois acompanhe a saída:
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-modbus-a7f3k2 -v \
-t 'connectmq/demo/a7f3k2/plant1/#'
Você deve ver mensagens como {"temperature":42.3,"pressure":3.34,"flow":12.81,"running":true,"ts":...}. Não envie dados reais da planta para o servidor público: qualquer pessoa pode assiná-lo, e ele serve apenas para testes e protótipos.
Escrevendo no Modbus a partir do MQTT, com segurança
Ler tem baixo risco; escrever em uma bomba, não. Se você aceitar comandos via MQTT, coloque proteções no flow:
- Assine um topic de comando dedicado, como
.../pump1/cmd, nunca um wildcard. - Valide o payload em um function node contra uma lista de ações permitidas e faixas de valores.
- Associe cada ação a um registrador ou coil fixo. Nunca deixe a mensagem escolher o endereço.
- Publique o resultado em um topic
.../pump1/cmd/ackpara que o remetente saiba se a escrita aconteceu. - Use um broker privado com autenticação para qualquer topic que possa mudar o estado de um equipamento.
// Function node "validate pump command" -> Modbus Write (FC5, coil 0)
const cmd = String(msg.payload).trim().toUpperCase();
if (cmd !== "START" && cmd !== "STOP") {
node.warn("Rejected command: " + cmd);
return null;
}
msg.payload = cmd === "START";
return msg;
Modbus RTU sobre RS-485
Para dispositivos seriais, mude apenas a configuração do cliente: tipo Serial, porta como /dev/ttyUSB0, baud rate, paridade e stop bits iguais aos do dispositivo (9600 8N1 é comum) e o tipo serial RTU. Cada dispositivo no barramento tem seu próprio unit ID. Mantenha as taxas de polling conservadoras, porque um barramento RS-485 atende todos os dispositivos em sequência, e um timeout em um dispositivo atrasa os outros. O guia de Modbus RTU para MQTT aborda ligação e terminação.
Solução de problemas em flows Node-RED Modbus
| Sintoma | Causa provável | Correção |
|---|---|---|
| Erros de timeout | IP, porta ou unit ID errados; firewall | Teste antes com uma ferramenta Modbus de desktop |
| Illegal data address (exceção 2) | Endereço deslocado em um ou function code errado | Use endereços base 0; holding vs input registers |
| Valores deslocados em um registrador | Notação 40001 digitada literalmente | Subtraia o deslocamento |
| Valores de float absurdos | Ordem de palavras diferente | Troque os dois registradores |
| Números negativos aparecem como 65.000+ | Valor com sinal lido como sem sinal | Aplique a conversão int16 |
| O dispositivo para de responder sob carga | Clientes demais ou polling rápido demais | Um gateway, polling mais lento, leituras agrupadas em blocos |
Do gateway à produção
Quando os valores estão fluindo, o gateway é tão útil quanto o broker em que publica. Em um site com vários gateways Node-RED, um cliente SCADA e um historiador, todos devem compartilhar um único broker autenticado, acessível tanto pela rede da planta quanto pela rede do escritório. Um broker MQTT na nuvem é uma forma simples de conseguir isso, porque cada gateway se conecta de saída pela porta 8883 e nenhuma porta de entrada é aberta para a rede de OT. O ConnectMQ também reconhece topics no estilo ISA-95, como plant1/utilities/pump1/telemetry, e mostra os dispositivos por esses níveis no portal. Se você prefere não rodar nenhuma infraestrutura de broker, um broker MQTT gerenciado tira os patches e o monitoramento das suas mãos.
Outros protocolos industriais seguem o mesmo padrão: veja Node-RED OPC UA para MQTT para controladores modernos e Node-RED com Siemens S7 para CLPs S7. Para configurar o broker no Node-RED, o tutorial Node-RED MQTT traz o básico.
Conecte seu gateway Modbus ao ConnectMQ
Cadastre-se em app.connectmq.com no plano Serverless gratuito, sem cartão de crédito. Crie um broker, cole o username, o password e o client ID gerados no node de configuração do Node-RED, ative o TLS na porta 8883 e seus valores Modbus passam a ser publicados de forma privada e criptografada. Use o explorador de topics ao vivo do ConnectMQ para conferir cada registrador que você decodificou.
Perguntas frequentes
O node-red-contrib-modbus suporta Modbus TCP e RTU?
Sim. O node de configuração Modbus Client suporta conexões TCP e seriais, incluindo RTU por adaptadores RS-485. Os nodes de leitura e escrita funcionam da mesma forma nos dois casos.
Por que meu endereço Modbus está deslocado em um no Node-RED?
Datasheets costumam usar a numeração no estilo 40001, que começa em um, enquanto o Node-RED usa endereços de protocolo que começam em zero. O holding register 40001 é o endereço 0 no node Modbus Read.
Como leio um float de 32 bits do Modbus no Node-RED?
Leia dois registradores consecutivos, escreva-os em um buffer de 4 bytes e chame readFloatBE. Se o resultado parecer errado, troque as duas palavras de lugar, porque alguns dispositivos usam a ordem de palavras oposta.
Com que frequência o Node-RED deve fazer polling em um dispositivo Modbus?
Faça polling tão devagar quanto o seu caso de uso permitir, muitas vezes de 1 a 10 segundos para monitoramento. Agrupe registradores em blocos e publique por exceção para manter o dispositivo e o broker com carga leve.



