Raspberry Pi Zero W Bancada
BCM2835 · ARMv6 · 512 MB · 2,4 GHz

Um computador de 10 g que faz uma coisa só, o dia inteiro.

O Zero W é fraco para desktop e ótimo como dispositivo dedicado: consome menos de 1 W, tem Wi-Fi, Bluetooth, porta de câmera e 40 pinos de GPIO. Aqui estão 48 projetos que aproveitam isso e, no fim, o guia completo de um nó MQTT que você liga em qualquer tomada, carro ou barco e ele começa a publicar sozinho.

1 GHz × 1ARM1176JZF-S
512 MBRAM compartilhada
0,5–0,8 Wconsumo típico
BLE 4.1Wi-Fi só 2,4 GHz
CSI · OTGcâmera e USB gadget

Rende bem

  • Serviços leves 24/7 (DNS, MQTT, cron)
  • Python, Go, C, scripts shell
  • Sensores, relés, câmera, rádio

Evite

  • Docker e imagens arm64
  • Chromium, Playwright, IA local
  • Node.js recente (sem build oficial ARMv6)
Guia completo

Nó MQTT móvel plug and play

Um único cartão SD que vira sensor em qualquer lugar. Você pluga os sensores, liga na energia e ele descobre sozinho o que está conectado, acha uma rede, publica no broker e aparece no Home Assistant. Sem rede, guarda tudo e envia depois.

Liga e conecta

Tenta a rede de casa, depois o hotspot do celular. Sem nenhuma, abre um portal Wi-Fi para configurar pelo telefone.

Configura no PC

Um arquivo node.toml na partição de boot, editável no Windows ou Mac com o cartão no leitor.

Detecta sensores

Varre o barramento I²C e o 1-Wire a cada 30 ciclos. Plugou um sensor novo, ele passa a publicar.

Não perde leitura

Toda medição entra numa fila SQLite. Sem conexão, ela cresce; quando volta, esvazia com QoS 1.

Aparece sozinho

Publica mensagens de descoberta do Home Assistant. Cada sensor vira uma entidade com unidade e tipo.

Avisa quando cai

Last Will retido em status: o broker marca offline se o nó sumir sem se despedir.

árvore de tópicos publicada
nodes/zero-5a3c91f2/status         online | offline            # retido, Last Will
nodes/zero-5a3c91f2/sistema        {"cpu_temp": 41.2, "wifi_rssi": -58.0, "uptime_h": 12.4, "ts": 1790000000}
nodes/zero-5a3c91f2/bme280_76      {"temperatura": 23.4, "umidade": 71.2, "pressao": 1013.2, "ts": 1790000000}
nodes/zero-5a3c91f2/ds18b20_3f1a   {"temperatura": 19.8, "ts": 1790000000}
nodes/zero-5a3c91f2/gps            {"lat": -27.14, "lon": -48.48, "vel_kmh": 0.0, "ts": 1790000000}
homeassistant/sensor/zero-5a3c91f2/bme280_76_temperatura/config   # descoberta, retido
Passo a passo

Montagem do primeiro nó

Cerca de duas horas do cartão em branco ao dado no Home Assistant. Depois disso, cada nó novo é uma cópia do cartão.

ItemFunçãoObrigatório
Pi Zero W + barra de pinos soldadaO nóSim
Cartão microSD A1, 16–32 GB, de marcaSistema e fila offlineSim
Fonte 5 V / 2,5 A ou power bankEnergia estável; subtensão causa travamentosSim
BME280 (ou SHT31) em placa breakoutTemperatura, umidade, pressãoUm sensor I²C
DS18B20 à prova d'água + resistor 4,7 kΩTemperatura de água, freezer, soloOpcional
BH1750Luminosidade em luxOpcional
GPS NEO-6M ou NEO-M8N com antenaPosição e velocidade em uso móvelOpcional
Case ventilado ou caixa IP65 com prensa-caboUso externo, barco, veículoRecomendado
01sistema

Grave o Raspberry Pi OS Lite 32-bit

No Raspberry Pi Imager, escolha o dispositivo Raspberry Pi Zero e o sistema Raspberry Pi OS Lite (32-bit). Em "Editar configurações", defina hostname zero-campo, usuário e senha, a rede Wi-Fi de casa com país BR, e ative SSH com chave pública. Sem interface gráfica o sistema sobra mais RAM e escreve menos no cartão.

Primeiro boot demora 2 a 4 minutos. Depois, acesse com ssh usuario@zero-campo.local.

02base

Ative interfaces e proteja o cartão

Liga I²C, 1-Wire e UART, manda o log para a RAM (menos escrita no SD) e ativa o watchdog de hardware, que reinicia a placa se o sistema travar.

terminal no Pi
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y i2c-tools sqlite3 python3-venv mosquitto-clients

# I2C ligado, console serial desligado, UART de hardware ligada
sudo raspi-config nonint do_i2c 0
sudo raspi-config nonint do_serial_cons 1
sudo raspi-config nonint do_serial_hw 0

# 1-Wire no GPIO4; libera a UART principal para o GPS (desativa o Bluetooth)
echo 'dtoverlay=w1-gpio,gpiopin=4' | sudo tee -a /boot/firmware/config.txt
echo 'dtoverlay=disable-bt'        | sudo tee -a /boot/firmware/config.txt
sudo systemctl disable hciuart

# log só em RAM: poupa o cartão
sudo mkdir -p /etc/systemd/journald.conf.d
printf '[Journal]\nStorage=volatile\nRuntimeMaxUse=16M\n' | sudo tee /etc/systemd/journald.conf.d/ram.conf

# watchdog de hardware: reinicia se o sistema congelar por 15 s
sudo sed -i 's/^#\?RuntimeWatchdogSec=.*/RuntimeWatchdogSec=15/' /etc/systemd/system.conf

sudo reboot
Se não for usar GPS e quiser manter o Bluetooth (por exemplo, para ler sensores BLE), pule a linha disable-bt e o hciuart.
03fiação

Ligue os sensores

Com a placa desligada. O mapa de pinos está no topo da página. Todos os sensores I²C dividem os mesmos dois fios, cada um com seu endereço.

SensorBarramentoEndereçoPinos físicos
BME280 / BMP280I²C0x76 ou 0x771 VCC · 3 SDA · 5 SCL · 6 GND
SHT31I²C0x44mesmos pinos
BH1750I²C0x23mesmos pinos
DS18B201-Wire28-xxxxxxxxxxxx1 VCC · 7 dados · 9 GND + 4,7 kΩ
GPS NEO-6MUART 9600/dev/serial02 VCC · 8 TX→RX · 10 RX←TX · 14 GND
confira o que foi detectado
i2cdetect -y 1                       # deve mostrar 76, 44, 23…
ls /sys/bus/w1/devices/              # deve listar 28-…
cat /sys/bus/w1/devices/28-*/temperature   # milésimos de °C

Para o GPS, instale o gpsd e aponte para a serial:

terminal no Pi
sudo apt install -y gpsd gpsd-clients
sudo sed -i 's|^DEVICES=.*|DEVICES="/dev/serial0"|; s|^GPSD_OPTIONS=.*|GPSD_OPTIONS="-n"|' /etc/default/gpsd
sudo systemctl enable --now gpsd
cgps -s          # aguarde o "3D FIX" com céu aberto
04broker

Escolha onde o dado chega

Em uso móvel o nó fica atrás do CGNAT da operadora do celular. Por isso ele sempre inicia a conexão para fora, e o broker precisa estar acessível na internet ou numa rede privada.

Recomendado

Mosquitto na sua VPS

Controle total, TLS com Let's Encrypt, ACL por usuário. Uma VPS pequena aguenta centenas de nós.

Sem servidor

Broker gerenciado

HiveMQ Cloud ou EMQX Serverless têm planos gratuitos. Troque só host, user e password no node.toml.

Rede privada

Tailscale

Nó e broker na mesma tailnet, porta 1883 sem expor nada na internet. Use tls = false e o IP 100.x do broker.

na VPS (Debian/Ubuntu) · troque o domínio
sudo apt install -y mosquitto mosquitto-clients certbot
sudo certbot certonly --standalone -d mqtt.seudominio.com.br

# copia o certificado para o mosquitto a cada renovação
sudo install -d -m 750 -o root -g mosquitto /etc/mosquitto/certs
sudo tee /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh >/dev/null <<'EOF'
#!/bin/sh
D=/etc/letsencrypt/live/mqtt.seudominio.com.br
install -m 640 -o root -g mosquitto $D/fullchain.pem $D/privkey.pem /etc/mosquitto/certs/
systemctl restart mosquitto
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh
sudo /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh

sudo mosquitto_passwd -c /etc/mosquitto/passwd node
sudo mosquitto_passwd    /etc/mosquitto/passwd homeassistant
/etc/mosquitto/conf.d/nodes.conf
listener 1883 127.0.0.1
listener 8883
certfile /etc/mosquitto/certs/fullchain.pem
keyfile  /etc/mosquitto/certs/privkey.pem

allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
/etc/mosquitto/acl
user node
topic readwrite nodes/#
topic write homeassistant/#

user homeassistant
topic read nodes/#
topic readwrite homeassistant/#

Depois: sudo systemctl restart mosquitto e libere a porta 8883 no firewall.

05config

Crie o arquivo de configuração no cartão

Ele fica em /boot/firmware/node.toml, a partição FAT que aparece como unidade "bootfs" em qualquer computador. Assim você muda broker e redes Wi-Fi sem SSH, só com o cartão no leitor.

/boot/firmware/node.toml
[mqtt]
host = "mqtt.seudominio.com.br"
port = 8883
tls = true
user = "node"
password = "troque-esta-senha"
base = "nodes"

[node]
name = ""          # vazio: usa zero-<serial da CPU>, único por placa
interval = 60      # segundos entre leituras

[gps]
enabled = false

# redes em ordem de preferência (maior prioridade primeiro)
[[wifi]]
ssid = "Casa"
psk = "senha-da-casa"
prioridade = 30

[[wifi]]
ssid = "Hotspot-Celular"
psk = "senha-do-hotspot"
prioridade = 20
A partição FAT não tem permissões por usuário: qualquer processo no Pi lê esse arquivo. Use um usuário MQTT exclusivo para os nós, com ACL restrita a nodes/#, como no passo 4.
06agente

Instale o agente

Um único arquivo Python. Ele lê a configuração, detecta sensores, grava cada leitura na fila e esvazia a fila sempre que há conexão. O paho-mqtt cuida da reconexão.

terminal no Pi
sudo useradd -r -s /usr/sbin/nologin -G i2c,gpio node
sudo mkdir -p /opt/node-agent
sudo python3 -m venv /opt/node-agent/venv
sudo /opt/node-agent/venv/bin/pip install paho-mqtt smbus2 RPi.bme280
sudo nano /opt/node-agent/agent.py      # cole o código abaixo
/opt/node-agent/agent.py
#!/usr/bin/env python3
"""Nó MQTT móvel: detecta sensores, publica e guarda leituras offline."""
import glob, json, socket, sqlite3, time, tomllib

import paho.mqtt.client as mqtt
from smbus2 import SMBus, i2c_msg

CFG = tomllib.load(open("/boot/firmware/node.toml", "rb"))
M, N = CFG["mqtt"], CFG.get("node", {})


def cpu_serial():
    for line in open("/proc/cpuinfo"):
        if line.startswith("Serial"):
            return line.split(":")[1].strip()[-8:]
    return socket.gethostname()


NODE_ID = N.get("name") or f"zero-{cpu_serial()}"
BASE = f'{M.get("base", "nodes")}/{NODE_ID}'

DB = sqlite3.connect("/var/lib/node-agent/outbox.db", isolation_level=None)
DB.execute("PRAGMA journal_mode=WAL")
DB.execute("CREATE TABLE IF NOT EXISTS outbox (id INTEGER PRIMARY KEY, topic TEXT, payload TEXT)")

bus = SMBus(1)

# ---------- sensores ----------

def present(addr):
    try:
        bus.read_byte(addr)
        return True
    except OSError:
        return False


def read_bme280(addr):
    import bme280  # pacote RPi.bme280
    cal = bme280.load_calibration_params(bus, addr)
    d = bme280.sample(bus, addr, cal)
    # BMP280 no mesmo endereço não mede umidade; ignore esse campo se for o caso
    return {"temperatura": round(d.temperature, 2),
            "umidade": round(d.humidity, 1),
            "pressao": round(d.pressure, 1)}


def read_sht31(addr):
    bus.write_i2c_block_data(addr, 0x2C, [0x06])   # medição única, alta repetibilidade
    time.sleep(0.02)
    msg = i2c_msg.read(addr, 6)
    bus.i2c_rdwr(msg)
    d = list(msg)
    t = -45 + 175 * (d[0] << 8 | d[1]) / 65535
    h = 100 * (d[3] << 8 | d[4]) / 65535
    return {"temperatura": round(t, 2), "umidade": round(h, 1)}


def read_bh1750(addr):
    bus.write_byte(addr, 0x20)                     # uma leitura, alta resolução
    time.sleep(0.2)
    msg = i2c_msg.read(addr, 2)
    bus.i2c_rdwr(msg)
    d = list(msg)
    return {"luz": round((d[0] << 8 | d[1]) / 1.2, 1)}


I2C = {0x76: ("bme280", read_bme280), 0x77: ("bme280", read_bme280),
       0x44: ("sht31", read_sht31), 0x23: ("bh1750", read_bh1750)}


def detect():
    return [(name, addr, fn) for addr, (name, fn) in I2C.items() if present(addr)]


def read_ds18b20():
    out = {}
    for path in glob.glob("/sys/bus/w1/devices/28-*/temperature"):
        sid = path.split("/")[-2][-4:]
        try:
            out[f"ds18b20_{sid}"] = {"temperatura": int(open(path).read()) / 1000}
        except (OSError, ValueError):
            pass
    return out


def read_system():
    temp = int(open("/sys/class/thermal/thermal_zone0/temp").read()) / 1000
    rssi = None
    for line in open("/proc/net/wireless").readlines()[2:]:
        if line.strip().startswith("wlan0"):
            rssi = float(line.split()[3].rstrip("."))
    up = float(open("/proc/uptime").read().split()[0])
    return {"cpu_temp": round(temp, 1), "wifi_rssi": rssi, "uptime_h": round(up / 3600, 1)}


def read_gps():
    try:
        with socket.create_connection(("127.0.0.1", 2947), timeout=3) as s:
            s.sendall(b'?WATCH={"enable":true,"json":true}\n')
            f = s.makefile()
            for _ in range(20):
                msg = json.loads(f.readline())
                if msg.get("class") == "TPV" and msg.get("mode", 0) >= 2:
                    return {"lat": msg["lat"], "lon": msg["lon"],
                            "vel_kmh": round(msg.get("speed", 0) * 3.6, 1)}
    except (OSError, ValueError, KeyError):
        pass
    return {}

# ---------- fila offline ----------

def enqueue(topic, payload):
    DB.execute("INSERT INTO outbox (topic, payload) VALUES (?, ?)", (topic, json.dumps(payload)))
    DB.execute("DELETE FROM outbox WHERE id <= (SELECT MAX(id) - 50000 FROM outbox)")


def flush():
    rows = DB.execute("SELECT id, topic, payload FROM outbox ORDER BY id LIMIT 500").fetchall()
    for rid, topic, payload in rows:
        info = client.publish(topic, payload, qos=1)
        try:
            info.wait_for_publish(timeout=5)
        except Exception:
            return
        if not info.is_published():
            return
        DB.execute("DELETE FROM outbox WHERE id = ?", (rid,))

# ---------- Home Assistant ----------

META = {"temperatura": ("°C", "temperature"), "umidade": ("%", "humidity"),
        "pressao": ("hPa", "pressure"), "luz": ("lx", "illuminance"),
        "cpu_temp": ("°C", "temperature"), "wifi_rssi": ("dBm", "signal_strength"),
        "uptime_h": ("h", None), "vel_kmh": ("km/h", "speed")}


def announce(readings):
    dev = {"identifiers": [NODE_ID], "name": NODE_ID,
           "model": "Raspberry Pi Zero W", "manufacturer": "DIY"}
    for sensor, values in readings.items():
        for metric in values:
            unit, dclass = META.get(metric, (None, None))
            cfg = {"name": f"{sensor} {metric}",
                   "unique_id": f"{NODE_ID}_{sensor}_{metric}",
                   "state_topic": f"{BASE}/{sensor}",
                   "value_template": f"{{{{ value_json.{metric} }}}}",
                   "availability_topic": f"{BASE}/status",
                   "state_class": "measurement",
                   "device": dev}
            if unit:
                cfg["unit_of_measurement"] = unit
            if dclass:
                cfg["device_class"] = dclass
            client.publish(f"homeassistant/sensor/{NODE_ID}/{sensor}_{metric}/config",
                           json.dumps(cfg), qos=1, retain=True)

# ---------- MQTT ----------

state = {"announced": False}

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=NODE_ID)
client.username_pw_set(M["user"], M["password"])
if M.get("tls", True):
    client.tls_set()
client.will_set(f"{BASE}/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=2, max_delay=120)


def on_connect(c, userdata, flags, reason_code, properties):
    if not reason_code.is_failure:
        c.publish(f"{BASE}/status", "online", qos=1, retain=True)
        state["announced"] = False
        print("conectado ao broker", flush=True)


client.on_connect = on_connect
client.connect_async(M["host"], M.get("port", 8883), keepalive=60)
client.loop_start()

# ---------- laço principal ----------

sensors, cycle = [], 0
while True:
    if cycle % 30 == 0:
        sensors = detect()
        print("sensores I2C:", [f"{n}@{a:#x}" for n, a, _ in sensors], flush=True)
    cycle += 1

    readings = {"sistema": read_system()}
    for name, addr, fn in sensors:
        try:
            readings[f"{name}_{addr:02x}"] = fn(addr)
        except OSError as e:
            print("falha na leitura", name, e, flush=True)
    readings.update(read_ds18b20())
    if CFG.get("gps", {}).get("enabled"):
        g = read_gps()
        if g:
            readings["gps"] = g

    ts = int(time.time())
    for sensor, values in readings.items():
        enqueue(f"{BASE}/{sensor}", {**values, "ts": ts})

    if client.is_connected():
        if not state["announced"]:
            announce(readings)
            state["announced"] = True
        flush()

    time.sleep(N.get("interval", 60))
07wi-fi

Wi-Fi em qualquer lugar

Dois mecanismos. Um script lê as redes do node.toml a cada boot e cria perfis no NetworkManager com prioridade. Se nenhuma rede conhecida aparecer, o comitup abre um ponto de acesso comitup-NNN com portal em http://10.41.0.1 para você escolher a rede pelo celular.

/opt/node-agent/node-wifi.py
#!/usr/bin/env python3
"""Cria ou atualiza perfis Wi-Fi do NetworkManager a partir do node.toml."""
import subprocess, tomllib

cfg = tomllib.load(open("/boot/firmware/node.toml", "rb"))
have = subprocess.run(["nmcli", "-t", "-f", "NAME", "con", "show"],
                      capture_output=True, text=True).stdout.splitlines()

for net in cfg.get("wifi", []):
    name = f"node-{net['ssid']}"
    prio = str(net.get("prioridade", 10))
    if name in have:
        subprocess.run(["nmcli", "con", "modify", name,
                        "wifi-sec.psk", net["psk"],
                        "connection.autoconnect-priority", prio])
    else:
        subprocess.run(["nmcli", "con", "add", "type", "wifi", "ifname", "wlan0",
                        "con-name", name, "ssid", net["ssid"],
                        "wifi-sec.key-mgmt", "wpa-psk", "wifi-sec.psk", net["psk"],
                        "connection.autoconnect-priority", prio])
terminal no Pi
sudo apt install -y comitup      # portal de configuração quando não há rede
O Zero W só enxerga 2,4 GHz. No Android, configure o hotspot na banda de 2,4 GHz. No iPhone, ative "Maximizar compatibilidade" em Acesso Pessoal.
08serviço

Transforme em serviço

O systemd sobe o agente no boot, reinicia se ele cair e cria o diretório da fila com o dono certo.

/etc/systemd/system/node-wifi.service
[Unit]
Description=Sincroniza redes Wi-Fi do node.toml
After=NetworkManager.service
Wants=NetworkManager.service

[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /opt/node-agent/node-wifi.py

[Install]
WantedBy=multi-user.target
/etc/systemd/system/node-agent.service
[Unit]
Description=Agente MQTT do nó móvel
After=network-online.target node-wifi.service
Wants=network-online.target

[Service]
User=node
Group=node
SupplementaryGroups=i2c gpio
StateDirectory=node-agent
ExecStart=/opt/node-agent/venv/bin/python /opt/node-agent/agent.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
terminal no Pi
sudo systemctl daemon-reload
sudo systemctl enable --now node-wifi node-agent
journalctl -u node-agent -f      # deve mostrar "sensores I2C" e "conectado ao broker"
09teste

Confira do outro lado

em qualquer máquina
mosquitto_sub -h mqtt.seudominio.com.br -p 8883 --capath /etc/ssl/certs \
  -u homeassistant -P 'senha' -t 'nodes/#' -v
  • Queda de rede: desligue o Wi-Fi do roteador por 5 minutos. Ao voltar, as leituras atrasadas chegam em sequência, cada uma com seu ts original.
  • Last Will: tire o nó da tomada. Em até 90 s (1,5 × keepalive) o tópico status vira offline.
  • Home Assistant: com a integração MQTT apontando para o broker, o dispositivo zero-xxxxxxxx aparece em Configurações › Dispositivos, com uma entidade por medida.
  • Móvel: desligue a rede de casa e ligue o hotspot do celular. O nó troca sozinho em menos de um minuto.
10frota

Clone para vários nós

Com o primeiro nó funcionando, desligue, leia o cartão inteiro como imagem (Raspberry Pi Imager não lê; use Win32 Disk Imager, dd ou balenaEtcher em modo clone) e grave nos outros cartões. O ID vem do serial da CPU, então cada placa publica em tópicos próprios sem mudar nada.

Antes de gerar a imagem, apague as chaves SSH do host para cada cópia criar as suas no primeiro boot:

último comando antes de desligar o nó-matriz
sudo rm /etc/ssh/ssh_host_* && sudo systemctl enable regenerate_ssh_host_keys && sudo poweroff

Em cada cópia, ajuste só o node.toml se o nó for para outra rede.

Uso móvel

Energia e autonomia

A média fica perto de 0,7 W com Wi-Fi ligado e leitura a cada minuto. O GPS acrescenta cerca de 0,2 W.

FonteUso indicadoCuidado
Power bank 10.000 mAhColeta temporária, trilhas, eventosAlguns desligam com corrente baixa; prefira modelos com modo "baixa corrente"
USB 12 V do carro ou barcoRastreador veicular, telemetria náuticaA partida do motor derruba a tensão; use conversor 12→5 V de qualidade com capacitor
Painel 10 W + bateria 18650 + controladorEstação off-grid permanenteDimensione 3 dias de autonomia para semanas nubladas
HAT de UPS (PiSugar e similares)Desligamento seguro ao faltar energiaConfira compatibilidade com o Zero W e o formato do case
Calculadora de autonomia
45 h≈ 1,9 dia de operação contínua

Considera células de 3,7 V nominais. Estimativa; meça o consumo real com um medidor USB.

Aumente o intervalo

interval = 300 reduz tráfego e aquecimento. Para temperatura de água, 5 minutos basta.

Desligue o que não usa

Sem GPS e sem BLE, mantenha disable-bt. Sem monitor, o HDMI fica ocioso e consome pouco.

Verifique a fonte

vcgencmd get_throttled deve retornar 0x0. Qualquer outro valor indica subtensão no passado.

Diagnóstico

Quando algo não funciona

SintomaCausa provávelO que fazer
Não conecta no hotspot do celularHotspot em 5 GHzForce 2,4 GHz ou "Maximizar compatibilidade"
i2cdetect vazioSDA/SCL trocados, I²C desligadoConfira pinos 3 e 5; rode raspi-config nonint do_i2c 0
DS18B20 marca 85 °CValor de reset: sem pull-up ou alimentação fracaResistor de 4,7 kΩ entre dados e 3V3
Falha de TLS logo após ligarSem RTC, relógio errado até o NTP sincronizarNormal nos primeiros segundos; o paho reconecta sozinho
Travamentos aleatóriosSubtensão ou cabo micro-USB finoFonte oficial, cabo curto; confira get_throttled
GPS sem posiçãoPartida a frio ou antena cobertaCéu aberto por 5–15 min na primeira vez; acompanhe com cgps -s
Fila crescendo sem pararCredencial ou ACL recusando publicaçãoVeja journalctl -u node-agent e o log do Mosquitto

Próximas extensões

Comandos de volta

Assine nodes/<id>/cmd para acionar relés, mudar intervalo ou pedir leitura imediata.

Alertas no WhatsApp

Um fluxo no n8n com o gatilho MQTT dispara mensagem quando a temperatura do freezer passa do limite.

Trilha no mapa

Telegraf grava o tópico gps no InfluxDB e o painel Geomap do Grafana desenha o percurso.

Atualização remota

Guarde o agente num repositório e rode git pull com um timer do systemd uma vez por dia.