Node-RED

Histórico de gráficos no Node-RED: mantenha os dados MQTT após reinicializações

Os gráficos do Dashboard esquecem tudo quando o Node-RED reinicia. Este guia mostra duas formas confiáveis de manter o histórico de gráficos no Node-RED para dados MQTT: armazenamento de contexto em arquivo e uma pequena tabela SQLite, ambos reenviados ao Dashboard 2.0 na inicialização.

Gráfico de linha no Node-RED Dashboard 2.0 restaurando 24 horas de dados de temperatura via MQTT para mostrar o histórico de gráficos no Node-RED após uma reinicialização
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

O histórico de gráficos no Node-RED desaparece toda vez que o Node-RED reinicia, porque os gráficos do Dashboard mantêm seus pontos na memória. Este tutorial mostra duas formas práticas de manter esse histórico para dados MQTT: um armazenamento de contexto em arquivo para conjuntos de dados pequenos e uma tabela SQLite quando você quer consultas e retenção mais longa. Nos dois casos, você vai reenviar os dados armazenados para um gráfico do Dashboard 2.0 na inicialização, para que os operadores vejam as últimas 24 horas em vez de uma grade vazia.

Por que os gráficos do Node-RED perdem o histórico

Um node ui-chart no Dashboard 2.0 guarda os pontos que recebeu em um armazenamento de dados no lado do servidor, e é por isso que uma nova aba do navegador ainda mostra a linha existente. Esse armazenamento vive na memória do processo do Node-RED. Reinicie o Node-RED, reinicie o Raspberry Pi em que ele roda ou atualize um pacote e reinicie, e o gráfico começa do zero.

O MQTT sozinho não preenche essa lacuna. Uma retained message guarda apenas o último valor por topic, então um assinante que se reconecta recebe um ponto, não uma tendência. Um broker é um roteador de mensagens, não um banco de dados. Para entender exatamente onde fica esse limite, leia o que um broker MQTT faz. O histórico precisa ser armazenado em algum lugar que você controle, e o Node-RED é um lugar conveniente para isso.

Escolhendo como armazenar o histórico de gráficos no Node-RED

Abordagem Indicada para Retenção Instalação extra Trade-offs
Contexto em arquivo (localfilesystem) Uma a poucas séries, um ponto por minuto Horas a poucos dias Nenhuma Array inteiro regravado a cada flush; não permite consultas
SQLite (node-red-node-sqlite) Muitas séries, filtro por intervalo de tempo Semanas a meses Um node da paleta Você cuida da limpeza da tabela
Banco de séries temporais (InfluxDB) Muitos dispositivos, agregação, Grafana Meses a anos Servidor separado Mais peças móveis

O restante deste artigo implementa as duas primeiras. Para a terceira, siga o tutorial Node-RED com InfluxDB, que usa a mesma entrada MQTT e um banco de dados feito para essa tarefa.

Dados de teste a partir de um broker gratuito

Você precisa de um fluxo de leituras. Publique uma temperatura a cada poucos segundos em broker.connectmq.com, o servidor MQTT público, com um prefixo de topic único. Substitua a7f3k2 por uma string aleatória sua; tudo no servidor público pode ser lido por qualquer pessoa, então use-o só para testes.

# Publica uma temperatura aleatória a cada 5 segundos (Ctrl+C para parar)
while true; do
  T=$(awk -v r=$RANDOM 'BEGIN { printf "%.2f", 20 + (r % 800) / 100 }')
  mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-hist-a7f3k2 \
    -t connectmq/demo/a7f3k2/room1/telemetry -m "{\"temperature\": $T}"
  sleep 5
done

No Node-RED, adicione um node mqtt in em connectmq/demo/a7f3k2/room1/telemetry, com saída "a parsed JSON object", usando um node de configuração de broker com um client ID único.

Método 1: armazenamento de contexto em arquivo

Ative um armazenamento de contexto persistente

Por padrão, o contexto do Node-RED fica na memória. Edite o settings.js no diretório de usuário do Node-RED (normalmente ~/.node-red/settings.js) e defina um segundo armazenamento que grava em disco:

// ~/.node-red/settings.js (dentro de module.exports = { ... })
contextStorage: {
    default: { module: "memory" },
    file: {
        module: "localfilesystem",
        config: { flushInterval: 30 }   // segundos entre gravações em disco
    }
},

Reinicie o Node-RED. Manter a memória como padrão e nomear o armazenamento em arquivo explicitamente faz com que apenas os dados que você escolher sejam gravados em disco, o que importa em cartões SD. Os valores são gravados a cada 30 segundos, então um corte brusco de energia pode perder até essa janela; um desligamento limpo grava tudo. O guia de contexto do Node-RED explica escopos e armazenamentos com mais detalhes.

Registre um ponto por minuto

Armazenar cada leitura bruta rapidamente gera um array grande que é regravado a cada flush. Em vez disso, calcule a média das leituras por minuto. Ligue o node mqtt in a este function node e ligue a saída dele ao gráfico:

// Function node "record history" - 1 saída
const RETENTION_MS = 24 * 60 * 60 * 1000;   // manter 24 horas
const value = Number(msg.payload.temperature);
if (Number.isNaN(value)) {
    return null;
}

const now = Date.now();
const minute = Math.floor(now / 60000);
let acc = context.get("acc") || { minute: minute, sum: 0, n: 0 };

if (acc.minute !== minute) {
    if (acc.n > 0) {
        let history = flow.get("tempHistory", "file") || [];
        history.push({
            x: acc.minute * 60000,
            y: Math.round((acc.sum / acc.n) * 100) / 100
        });
        const cutoff = now - RETENTION_MS;
        history = history.filter(p => p.x >= cutoff);
        flow.set("tempHistory", history, "file");
    }
    acc = { minute: minute, sum: 0, n: 0 };
}

acc.sum += value;
acc.n += 1;
context.set("acc", acc);

// Ponto ao vivo para o gráfico
return { topic: "Temperature", payload: { x: now, y: value } };

Com um ponto por minuto, um dia de histórico são 1.440 objetos pequenos por série, bem dentro do que um arquivo de contexto suporta com folga.

Configure o gráfico

No node ui-chart, escolha um gráfico de linha, mantenha Series como msg.topic, defina X com a chave x e Y com a chave y e limite o gráfico a 24 horas de pontos, para combinar com a sua retenção.

Reenvie o histórico na inicialização

Adicione um inject node configurado como Inject once after 1 second, sem repetição, e ligue-o a este function node e depois ao mesmo gráfico:

// Function node "replay history" - 1 saída
const history = flow.get("tempHistory", "file") || [];
node.status({ fill: "green", shape: "dot", text: history.length + " points" });

return [[
    { topic: "Temperature", payload: [] },        // limpa o gráfico primeiro
    { topic: "Temperature", payload: history }    // depois envia o array armazenado
]];

Enviar um array vazio limpa o gráfico, o que evita linhas duplicadas após um redeploy. Enviar um array de objetos {x, y} adiciona todos de uma vez. Reinicie o Node-RED e o gráfico volta com as médias do último dia e depois continua com os pontos ao vivo.

Método 2: SQLite para retenção mais longa

Quando você tem várias séries, quer uma semana ou mais, ou quer filtrar por tempo, um banco de dados é mais limpo. Instale o node-red-node-sqlite pelo gerenciador de paleta. Em algumas plataformas, ele compila um módulo nativo, então aguarde um minuto.

Crie a tabela

Adicione um inject node (inject once na inicialização) com msg.topic definido como a instrução abaixo e ligue-o a um node sqlite com o arquivo de banco de dados /home/pi/.node-red/history.db (ajuste o caminho) e o modo de consulta SQL Via msg.topic.

CREATE TABLE IF NOT EXISTS readings (
  ts     INTEGER NOT NULL,
  series TEXT    NOT NULL,
  value  REAL    NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_readings ON readings (series, ts);

Se a sua versão do node executa apenas uma instrução por mensagem, envie as duas instruções em dois injects separados.

Insira cada leitura

Use um segundo node sqlite no modo Prepared Statement com este SQL:

INSERT INTO readings (ts, series, value) VALUES ($ts, $series, $value)

Alimente-o a partir de um function node que monta os parâmetros:

// Function node "to sqlite params"
const value = Number(msg.payload.temperature);
if (Number.isNaN(value)) return null;
msg.params = { $ts: Date.now(), $series: "Temperature", $value: value };
return msg;

Consulte na inicialização e limpe diariamente

Na inicialização, consulte as últimas 24 horas e envie as linhas ao gráfico. Um node sqlite no modo Via msg.topic devolve as linhas como um array em msg.payload:

// Function node "history query" - disparado por um inject once na inicialização
msg.topic = "SELECT ts AS x, value AS y FROM readings " +
            "WHERE series = 'Temperature' AND ts > " + (Date.now() - 86400000) +
            " ORDER BY ts";
return msg;

Passe o resultado por um change node que define msg.topic como Temperature e depois envie-o ao gráfico. Adicione um inject diário que execute DELETE FROM readings WHERE ts < <cutoff>, com o corte calculado da mesma forma, para que o arquivo não cresça para sempre.

Checklist antes de confiar nisso

  1. Escolha um período de retenção e aplique-o no código ou no SQL, não na esperança.
  2. Reduza a amostragem antes de armazenar se você só exibe médias.
  3. Garanta que o limite de pontos do gráfico combine com a retenção, ou pontos antigos somem antes da hora.
  4. Limpe o gráfico antes de reenviar para evitar linhas duplicadas após deploys.
  5. Faça backup do diretório de contexto ou do arquivo de banco de dados junto com o restante do seu projeto Node-RED.
  6. Fique de olho no uso de disco em cartões SD; prefira SQLite ou um banco externo para dados de alta frequência.

De onde os dados devem vir em produção

O histórico só é tão bom quanto o fluxo que o alimenta. Se o broker cai, aparecem lacunas no gráfico, e em um servidor público compartilhado qualquer pessoa pode ler ou publicar nos seus topics de demonstração. Para instalações reais, aponte o node mqtt in para um broker privado com credenciais e TLS. Com o ConnectMQ, o portal emite username, password e client ID para cada broker, e a mudança no flow se limita ao node de configuração: servidor, porta 8883, TLS ativado e as credenciais.

Um broker MQTT gerenciado também mantém os dispositivos publicando enquanto você reinicia ou atualiza o Node-RED. Combine isso com uma sessão MQTT persistente e QoS 1 na assinatura, e reinicializações curtas do Node-RED podem ser cobertas pelo broker enfileirando mensagens para a sessão, de acordo com a expiração de sessão do seu plano. Para os dashboards em si, o tutorial do Dashboard 2.0 aborda gauges, controles e layout, e o tutorial Node-RED MQTT cobre o básico do broker.

Mantenha seus dados do Node-RED fluindo com o ConnectMQ

Cadastre-se em app.connectmq.com e comece no plano Serverless gratuito, sem cartão de crédito. Crie um broker, cole as credenciais no node de configuração do Node-RED e seus gráficos passam a ser alimentados por um fluxo privado e criptografado com TLS. O explorador de topics ao vivo do ConnectMQ ajuda a confirmar que as leituras estão chegando antes de você começar a depurar o armazenamento.

Perguntas frequentes

O Node-RED Dashboard 2.0 salva os dados do gráfico automaticamente?

Ele mantém os dados do gráfico na memória para que novas abas do navegador vejam os pontos existentes, mas nada é gravado em disco. Depois de reiniciar o Node-RED, o gráfico fica vazio, a menos que você reenvie os dados armazenados.

Retained messages MQTT podem armazenar o histórico do gráfico?

Não. Uma retained message guarda apenas o valor mais recente de um topic. Ela é útil para mostrar o estado atual imediatamente, mas para uma tendência você precisa de armazenamento de contexto ou de um banco de dados.

Quanto histórico posso manter no contexto do Node-RED?

O contexto em arquivo funciona bem para poucas séries reduzidas a um ponto por minuto ao longo de um dia ou de poucos dias. Para volumes maiores, use SQLite ou um banco de séries temporais como o InfluxDB.

Como evito linhas duplicadas após um deploy?

Envie um array vazio ao gráfico antes de reenviar os pontos armazenados. Isso limpa o gráfico, de modo que o histórico seja desenhado uma única vez.

Artigos relacionados

Node-RED Dashboard 2.0 com MQTT: gauges, gráficos e controles

Um tutorial prático do Node-RED Dashboard 2.0: assine telemetria MQTT ao vivo, exiba-a em gauges e em um gráfico de linha e controle um dispositivo com um switch que publica comandos e reflete o estado real.

9 min de leitura

Cliente OPC UA no Node-RED para MQTT com topics ISA-95

Use o node-red-contrib-opcua para assinar variáveis OPC UA em um CLP ou servidor de simulação, mapear node IDs para topics MQTT no estilo ISA-95 e publicar os valores com qualidade e timestamps.

10 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.