Raspberry Pi

Publique estatísticas do sistema do Raspberry Pi via MQTT para monitorar a saúde da frota

Um pequeno serviço Python que publica temperatura da CPU, carga, memória, uso de disco e flags de subtensão de cada Raspberry Pi via MQTT, com last will para você saber quando um Pi fica offline.

Várias placas Raspberry Pi enviando temperatura da CPU e uso de memória como estatísticas do sistema via MQTT para um broker central
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

Publicar estatísticas do Raspberry Pi via MQTT é a forma mais simples de saber, num relance, se cada Pi que você opera está saudável. Neste tutorial você vai escrever um serviço Python que informa temperatura da CPU, carga, memória, uso de disco, uptime e flags de throttling de energia em intervalos fixos, anuncia que está online com um status retained e deixa o broker marcá-lo como offline por meio de um last will. O mesmo script roda sem alterações em um Pi ou em cinquenta.

Por que monitorar Raspberry Pis via MQTT

Pis em campo falham de formas previsíveis: cartões SD enchem de logs, gabinetes retêm calor e a CPU entra em throttling, fontes baratas causam subtensão e quedas de Wi-Fi deixam um dispositivo silenciosamente inacessível. Stacks de monitoramento tradicionais consultam cada máquina, o que significa abrir portas ou rodar um agente que precisa de acesso de entrada. O MQTT inverte essa lógica. Cada Pi abre uma única conexão de saída com um broker e envia seus próprios números, então funciona atrás de NAT, em roteadores 4G e em redes que você não controla.

O broker também oferece presença de graça. Com um status online retained e um last will offline, qualquer dashboard que assine os topics vê na hora o estado atual de cada Pi, e o broker o atualiza quando um dispositivo some. Se esse mecanismo não for familiar, leia primeiro o que faz um broker MQTT.

As métricas e de onde elas vêm

Métrica Origem Por que importa
cpu_temp /sys/class/thermal/thermal_zone0/temp O throttling começa conforme a temperatura sobe
load1, load5 os.getloadavg() Carga sustentada acima do número de núcleos indica fila acumulada
cpu_pct psutil.cpu_percent() Uso de CPU de curto prazo
mem_pct psutil.virtual_memory() Vazamentos de memória em serviços de longa duração
disk_pct psutil.disk_usage("/") Um sistema de arquivos raiz cheio quebra tudo
uptime_s psutil.boot_time() Reinicializações inesperadas aparecem como zeragens
throttled vcgencmd get_throttled Flags de subtensão e de throttling térmico
wifi_rssi /proc/net/wireless Sinal fraco explica as quedas

O valor de get_throttled é um campo de bits. O bit 0 indica subtensão neste momento, o bit 2 indica throttling ativo e os bits 16 e 18 indicam que essas condições ocorreram desde o boot. Um valor diferente de zero já merece um alerta por si só, porque quase sempre aponta para um problema de fonte que acabará corrompendo o cartão SD. A documentação do Raspberry Pi lista todos os bits.

Desenho de topics para uma frota

Use uma subárvore por dispositivo, com o hostname como ID do dispositivo. Para testes no servidor MQTT público gratuito, adicione um segmento aleatório para que os dados de outras pessoas não colidam com os seus:

connectmq/demo/a9e217/fleet/<hostname>/stats     JSON, every 30 s, not retained
connectmq/demo/a9e217/fleet/<hostname>/status    "online" / "offline", retained, last will

Um cliente de monitoramento então assina connectmq/demo/a9e217/fleet/+/status e connectmq/demo/a9e217/fleet/+/stats e descobre novos Pis automaticamente quando eles publicam pela primeira vez.

Instale as dependências

Em cada Pi, crie um ambiente virtual para que o serviço não dependa dos pacotes Python do sistema:

sudo apt update && sudo apt install -y python3-venv
python3 -m venv ~/pistats-env
~/pistats-env/bin/pip install "paho-mqtt>=2.0" psutil

O publicador de estatísticas do Raspberry Pi via MQTT

Salve isto como ~/pistats.py:

#!/usr/bin/env python3
"""Publish Raspberry Pi health metrics over MQTT."""
import json
import os
import socket
import ssl
import subprocess
import time

import paho.mqtt.client as mqtt
import psutil

HOST = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")          # YOUR_USERNAME em produção
PASSWORD = os.getenv("MQTT_PASSWORD")          # YOUR_PASSWORD em produção
HOSTNAME = socket.gethostname()
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"pistats-{HOSTNAME}-a9e217")
PREFIX = os.getenv("MQTT_PREFIX", "connectmq/demo/a9e217/fleet")
INTERVAL = int(os.getenv("INTERVAL", "30"))

STATS_TOPIC = f"{PREFIX}/{HOSTNAME}/stats"
STATUS_TOPIC = f"{PREFIX}/{HOSTNAME}/status"


def cpu_temp():
    try:
        with open("/sys/class/thermal/thermal_zone0/temp") as f:
            return round(int(f.read().strip()) / 1000, 1)
    except (OSError, ValueError):
        return None


def throttled():
    try:
        out = subprocess.run(["vcgencmd", "get_throttled"],
                             capture_output=True, text=True, timeout=2).stdout
        return int(out.strip().split("=")[1], 16)
    except (OSError, IndexError, ValueError, subprocess.TimeoutExpired):
        return None


def wifi_rssi():
    try:
        with open("/proc/net/wireless") as f:
            lines = f.readlines()[2:]
        for line in lines:
            parts = line.split()
            if parts and parts[0].startswith("wlan"):
                return int(float(parts[3]))
    except (OSError, IndexError, ValueError):
        pass
    return None


def collect():
    load1, load5, _ = os.getloadavg()
    t = throttled()
    return {
        "ts": int(time.time()),
        "cpu_temp": cpu_temp(),
        "cpu_pct": psutil.cpu_percent(interval=None),
        "load1": round(load1, 2),
        "load5": round(load5, 2),
        "mem_pct": psutil.virtual_memory().percent,
        "disk_pct": psutil.disk_usage("/").percent,
        "uptime_s": int(time.time() - psutil.boot_time()),
        "throttled": t,
        "undervoltage_now": bool(t & 0x1) if t is not None else None,
        "undervoltage_seen": bool(t & 0x10000) if t is not None else None,
        "wifi_rssi": wifi_rssi(),
    }


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connect failed: {reason_code}")
        return
    print(f"Connected to {HOST}:{PORT} as {CLIENT_ID}")
    client.publish(STATUS_TOPIC, "online", qos=1, retain=True)


def on_disconnect(client, userdata, flags, reason_code, properties):
    print(f"Disconnected: {reason_code}, paho will reconnect")


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=CLIENT_ID, protocol=mqtt.MQTTv5)
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
    client.tls_set(cert_reqs=ssl.CERT_REQUIRED)
client.will_set(STATUS_TOPIC, "offline", qos=1, retain=True)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.reconnect_delay_set(min_delay=2, max_delay=60)

client.connect_async(HOST, PORT, keepalive=60)
client.loop_start()
psutil.cpu_percent(interval=None)  # inicializa o contador

try:
    while True:
        time.sleep(INTERVAL)
        if client.is_connected():
            client.publish(STATS_TOPIC, json.dumps(collect()), qos=0)
finally:
    client.publish(STATUS_TOPIC, "offline", qos=1, retain=True).wait_for_publish(3)
    client.disconnect()
    client.loop_stop()

Algumas escolhas são deliberadas: as estatísticas usam QoS 0 porque perder uma amostra de vez em quando não importa e a próxima chega logo. O status usa QoS 1 e retain porque a presença precisa estar correta. connect_async com loop_start permite que o script inicie mesmo que a rede ainda não esteja disponível no boot, e o paho continua tentando em segundo plano. Em um desligamento limpo, o bloco finally publica offline explicitamente, porque o last will só dispara em uma desconexão inesperada.

Rode o script uma vez manualmente e acompanhe a saída de outra máquina:

~/pistats-env/bin/python ~/pistats.py
mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-a9e217 \
  -t 'connectmq/demo/a9e217/fleet/#' -v

Desconecte o cabo de rede do Pi e, depois de cerca de um intervalo e meio de keepalive, o broker publica offline em nome dele. É o last will do MQTT fazendo o seu trabalho.

Execute como serviço systemd

Crie um arquivo de ambiente para manter as credenciais fora do script:

sudo tee /etc/pistats.env >/dev/null <<'EOF'
MQTT_HOST=broker.connectmq.com
MQTT_PORT=1883
INTERVAL=30
EOF
sudo chmod 600 /etc/pistats.env
sudo tee /etc/systemd/system/pistats.service >/dev/null <<'EOF'
[Unit]
Description=Publish Raspberry Pi stats over MQTT
After=network-online.target
Wants=network-online.target

[Service]
User=pi
EnvironmentFile=/etc/pistats.env
ExecStart=/home/pi/pistats-env/bin/python /home/pi/pistats.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now pistats
journalctl -u pistats -f

Ajuste o usuário e os caminhos à sua conta. Para mais padrões de scripts executados no boot, veja como executar um script Python MQTT na inicialização.

Migrando a frota para um broker privado

Estatísticas do sistema revelam hostnames, uptime e detalhes de rede, então uma frota real não deve reportar a um broker público; o servidor MQTT público serve apenas para testes e protótipos. Com o ConnectMQ, um broker MQTT na nuvem e também um broker MQTT gerenciado, você cria um broker no portal e recebe as credenciais. Altere apenas o arquivo de ambiente:

MQTT_HOST=broker.connectmq.com
MQTT_PORT=8883
MQTT_USERNAME=YOUR_USERNAME
MQTT_PASSWORD=YOUR_PASSWORD
MQTT_CLIENT_ID=YOUR_CLIENT_ID
MQTT_PREFIX=site1/fleet

O ConnectMQ vincula os client IDs às credenciais emitidas, então cada Pi precisa do seu próprio conjunto gerado no portal. A porta 8883 usa TLS com um certificado Let's Encrypt em que o Pi já confia. O plano Serverless (Free) permite até 25 conexões, o que cobre uma frota considerável em casa ou no laboratório; o plano Serverless (Paid) vai muito além.

O portal do ConnectMQ também ajuda no lado do monitoramento sem software extra. O explorador de topics ao vivo mostra as estatísticas mais recentes de cada Pi, e regras de alerta por limite podem sinalizar quando um valor como cpu_temp ultrapassa um patamar, com um log de alertas para revisar depois.

Escolhendo limites de alerta que façam sentido

Coletar números é fácil; decidir quais merecem uma notificação é onde o monitoramento de frota mostra seu valor. Alertas que disparam o tempo todo acabam ignorados, então comece com uma lista curta de condições que quase sempre indicam um problema real:

  • Subtensão registrada desde o boot. Qualquer undervoltage_seen diferente de zero aponta para uma fonte fraca ou um cabo USB fino. Corrija antes que isso corrompa o cartão SD.
  • Temperatura da CPU que continua alta. Picos curtos durante atualizações são normais. Uma temperatura que fica perto do ponto de throttling por muitos minutos indica uma ventilação obstruída, um dissipador ausente ou um gabinete exposto ao sol.
  • Uso de disco acima de cerca de 90 por cento. Logs e imagens de contêiner crescem silenciosamente. Um sistema de arquivos raiz cheio quebra atualizações de pacotes, bancos de dados e às vezes o próprio boot.
  • Uptime zerando inesperadamente. Se uptime_s cai sem uma reinicialização planejada, o Pi travou ou perdeu energia, e a causa costuma ser alimentação ou calor.
  • Offline por mais de alguns intervalos. Combine o status retained com a idade da última mensagem de estatísticas para que uma breve oscilação do Wi-Fi não acione ninguém.

Carga média e memória são melhor acompanhadas como tendências do que como alertas. Uma subida lenta ao longo de dias geralmente revela um serviço com vazamento muito antes de ele causar problemas.

Usando os dados

Com os números fluindo, escolha quanta ferramenta você quer:

  1. Olhada rápida: o explorador de topics do ConnectMQ ou qualquer cliente MQTT de desktop.
  2. Painel na parede: o dashboard em modo quiosque no Raspberry Pi pode mostrar um bloco por Pi.
  3. Histórico e gráficos: Telegraf gravando no InfluxDB com Grafana por cima, como no tutorial de Raspberry Pi com Grafana e InfluxDB.

Solução de problemas

Sintoma Causa Correção
throttled é null vcgencmd ausente ou sem permissão Instale libraspberrypi-bin e adicione o usuário ao grupo video
cpu_pct sempre 0.0 na primeira amostra Contador não inicializado O script o inicializa antes do loop
O status alterna entre online e offline repetidamente Dois Pis com o mesmo client ID Dê a cada Pi um client ID único
offline nunca aparece após desconectar Aguardando o timeout do keepalive Espere cerca de 1,5 vez o keepalive
wifi_rssi é null no Ethernet Sem interface sem fio Esperado; ignore ou remova o campo

Comece a usar o ConnectMQ

Reúna a saúde de todos os Pis em um só lugar: cadastre-se em app.connectmq.com, crie um broker Serverless gratuito sem cartão de crédito e coloque as credenciais em /etc/pistats.env. Para a série completa de projetos com Pi, comece pelo tutorial de MQTT com Raspberry Pi.

Perguntas frequentes

Com que frequência um Raspberry Pi deve publicar estatísticas do sistema?

A cada 30 a 60 segundos é mais que suficiente para monitorar a saúde. Intervalos menores aumentam o tráfego sem revelar muito mais, já que temperatura e uso de disco mudam devagar.

Publicar estatísticas deixa o Raspberry Pi mais lento?

Não de forma significativa. Ler alguns arquivos e enviar uma pequena mensagem JSON a cada 30 segundos é uma carga desprezível, mesmo em um Pi Zero 2 W.

Como sei quando um Pi fica offline?

Assine o topic de status retained. O script define um last will offline, então o broker o publica automaticamente quando o Pi se desconecta de forma inesperada.

Posso adicionar a temperatura da GPU ou métricas personalizadas?

Sim, adicione campos ao dicionário de collect(). Nos modelos atuais de Pi, CPU e GPU compartilham o mesmo chip, então o valor da zona térmica já reflete ambos.

Artigos relacionados

Registro de Acessos Raspberry Pi RFID MQTT com o Leitor RC522

Ligue um leitor RFID RC522 a um Raspberry Pi, leia tags em Python, confira-as em uma lista de permissões local e publique cada tentativa de acesso como um evento MQTT que loggers, dashboards e ferramentas de alerta podem consumir.

8 min de leitura

Confiabilidade do Raspberry Pi: Rodando um Pi 24/7 como Gateway IoT

Um guia prático para manter um gateway MQTT com Raspberry Pi rodando por meses: desgaste do armazenamento, sistemas de arquivos somente leitura, alimentação, refrigeração, watchdogs de hardware e software e monitoramento remoto de saúde.

9 min de leitura

Pico W vs Pico 2 W para MQTT: Desempenho, Memória e TLS do RP2040 vs RP2350

O Pico 2 W mantém o formato e o chip Wi-Fi do Pico W, mas troca o RP2040 pelo RP2350, mais rápido. Esta comparação mostra o que isso significa para dispositivos MQTT: CPU, memória, TLS, recursos de segurança, suporte de software e qual placa comprar para cada projeto.

9 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.