Um monitor de energia com Raspberry Pi mostra exatamente quanto um circuito consome, quanto uma bateria está carregando e quanta energia um equipamento gasta ao longo do dia. Neste tutorial você vai medir tensão, corrente e potência em corrente contínua com um INA219, integrar esses valores em watt-hora e publicar tudo como JSON via MQTT para que um dashboard ou uma automação possa usar. Você também vai ver como HATs com alicate CT levam a mesma ideia para circuitos de corrente alternada da rede elétrica.
Escolhendo o sensor: INA219 ou alicate CT
| Breakout INA219 | HAT com alicate CT | |
|---|---|---|
| Mede | Tensão CC (até 26 V), corrente, potência | Corrente CA por um alicate; algumas placas também medem tensão CA |
| Conexão | Em série com a carga, por um resistor shunt | Não invasiva, o alicate abraça um condutor |
| Uso típico | Painéis solares, baterias de 12 V, fitas de LED, robôs, o próprio Pi | Circuitos residenciais, eletrodomésticos, máquinas |
| Interface | I2C | Normalmente um ADC SPI ou I2C no HAT |
| Segurança | Apenas baixa tensão | O alicate é isolado, mas a instalação perto da rede elétrica exige um profissional qualificado |
Este tutorial monta a versão com INA219 de ponta a ponta porque ela é barata, precisa para CC de baixa tensão e segura para experimentar. Se você precisa medir CA, um HAT com alicate CT vem com sua própria biblioteca Python; leia os valores dele e reutilize a parte MQTT do script sem alterações. O equivalente com ESP32 para a rede elétrica está no guia do sensor de corrente SCT-013 com ESP32.
Como o INA219 funciona
O INA219 mede a pequena queda de tensão em um resistor shunt de 0,1 ohm em série com a carga e a tensão do barramento do lado da carga. A partir desses dois valores, ele calcula internamente a corrente e a potência. O breakout padrão suporta até 26 V no barramento e, com a calibração padrão, cerca de 3,2 A. Como o shunt fica em série, toda a corrente da carga passa pelo breakout, então respeite os limites dele e use fios grossos o suficiente para a corrente.
Ligação
| Pino do INA219 | Ligar em |
|---|---|
| VCC | 3,3 V do Pi (pino físico 1) |
| GND | GND do Pi (pino físico 6) e o terra da fonte da carga |
| SDA | GPIO2 (pino físico 3) |
| SCL | GPIO3 (pino físico 5) |
| VIN+ | Terminal positivo da fonte de energia |
| VIN- | Entrada positiva da carga |
O terra do circuito medido precisa ser compartilhado com o terra do Pi; caso contrário, a leitura da tensão do barramento não faz sentido. Ative o I2C com sudo raspi-config nonint do_i2c 0 e confirme que o sensor aparece no endereço 0x40 com i2cdetect -y 1.
Instalando o software
sudo apt update
sudo apt install -y python3-venv i2c-tools
mkdir -p ~/power-monitor && cd ~/power-monitor
python3 -m venv .venv
source .venv/bin/activate
pip install "paho-mqtt>=2.0" adafruit-circuitpython-ina219
Topics e payload
| Topic | Conteúdo | Retained |
|---|---|---|
connectmq/demo/8d20f6/solar/power |
Tensão, corrente, potência a cada 5 s | Não |
connectmq/demo/8d20f6/solar/energy |
Wh acumulados, a cada minuto | Sim |
connectmq/demo/8d20f6/solar/status |
online / offline |
Sim |
Uma mensagem de potência tem esta cara:
{"voltage": 12.84, "current_ma": 412.6, "power_w": 5.3, "ts": 1792161000}
O topic de energia é retained, então um dashboard aberto mais tarde vê na hora o total do dia.
O script do monitor de energia com Raspberry Pi
O script faz uma amostragem por segundo, tira a média ao longo do intervalo de publicação para suavizar o ruído e integra a potência no tempo em watt-hora. Ele salva o contador de energia em disco a cada dez minutos, para que um reinício não o zere, sem gravar no cartão SD a cada amostra. Salve como power_monitor.py:
#!/usr/bin/env python3
"""INA219 power monitor publishing to MQTT."""
import json
import os
import time
import uuid
from pathlib import Path
import board
import paho.mqtt.client as mqtt
from adafruit_ina219 import INA219
BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"power-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("MQTT_PREFIX", "connectmq/demo/8d20f6/solar")
PUBLISH_EVERY = 5 # segundos
ENERGY_EVERY = 60 # segundos
SAVE_EVERY = 600 # segundos
STATE_FILE = Path(os.getenv("STATE_FILE", "energy_wh.txt"))
ina = INA219(board.I2C()) # calibração padrão: faixa de 32 V, 2 A
def load_energy():
try:
return float(STATE_FILE.read_text())
except (OSError, ValueError):
return 0.0
def save_energy(wh):
tmp = STATE_FILE.with_suffix(".tmp")
tmp.write_text(f"{wh:.4f}")
tmp.replace(STATE_FILE) # renomeação atômica evita arquivos gravados pela metade
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print(f"Connection refused: {reason_code}")
return
print(f"Connected as {CLIENT_ID}")
client.publish(f"{PREFIX}/status", "online", qos=1, retain=True)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=1, max_delay=60)
if USERNAME:
client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
client.tls_set()
client.connect(BROKER, PORT, keepalive=30)
client.loop_start()
energy_wh = load_energy()
samples = []
last_sample = time.monotonic()
last_publish = last_energy = last_save = last_sample
try:
while True:
time.sleep(1)
now = time.monotonic()
voltage = ina.bus_voltage + ina.shunt_voltage # tensão do lado da fonte
current_ma = ina.current
power_w = ina.power
if ina.overflow:
print("Warning: INA219 overflow, current exceeds calibrated range")
energy_wh += power_w * (now - last_sample) / 3600.0
last_sample = now
samples.append((voltage, current_ma, power_w))
if now - last_publish >= PUBLISH_EVERY:
n = len(samples)
payload = {
"voltage": round(sum(s[0] for s in samples) / n, 2),
"current_ma": round(sum(s[1] for s in samples) / n, 1),
"power_w": round(sum(s[2] for s in samples) / n, 2),
"ts": int(time.time()),
}
client.publish(f"{PREFIX}/power", json.dumps(payload), qos=0)
samples.clear()
last_publish = now
if now - last_energy >= ENERGY_EVERY:
energy = {"energy_wh": round(energy_wh, 3), "ts": int(time.time())}
client.publish(f"{PREFIX}/energy", json.dumps(energy), qos=1, retain=True)
last_energy = now
if now - last_save >= SAVE_EVERY:
save_energy(energy_wh)
last_save = now
except KeyboardInterrupt:
pass
finally:
save_energy(energy_wh)
client.publish(f"{PREFIX}/status", "offline", qos=1, retain=True).wait_for_publish(2)
client.loop_stop()
client.disconnect()
Rode com python power_monitor.py e assine a partir de outra máquina:
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-8d20f6 \
-t 'connectmq/demo/8d20f6/solar/#' -v
Ligue e desligue a carga e veja current_ma e power_w responderem em até cinco segundos.
Calibração e precisão
A calibração padrão cobre 32 V e 2 A com resolução razoável. Se a sua carga for pequena, como um microcontrolador consumindo dezenas de miliampères, chame ina.set_calibration_16V_400mA() depois de criar o sensor para obter uma resolução mais fina. Se precisar de mais do que a faixa do breakout, troque o shunt por um de valor menor e escreva sua própria calibração, ou passe para um sensor projetado para correntes maiores.
Confira com um multímetro em série com a carga. Pequenos desvios são normais; um erro percentual constante geralmente indica a tolerância do shunt, que você pode corrigir com um fator de escala no software. Corrente negativa significa que VIN+ e VIN- estão invertidos, o que pode até ser útil: um monitor de bateria pode usar o sinal para mostrar carga versus descarga.
Casos de uso
O mesmo script serve para muitos projetos, mudando apenas o prefixo de topic e a calibração. Como os assinantes só veem JSON com campos de tensão, corrente, potência e energia, você pode trocar o sensor depois, ou adicionar um segundo INA219 no endereço 0x41 para outro circuito, sem mexer no dashboard ou na automação que consome os dados.
- Sistemas solares e de baterias: acompanhe a geração dos painéis e a tensão da bateria e publique um alerta quando a bateria cair abaixo de um nível seguro, por exemplo em um sistema fotovoltaico isolado em uma fazenda.
- Medir seus próprios projetos com Pi ou ESP32: coloque o INA219 entre a fonte e um dispositivo para ver o consumo real durante picos de Wi-Fi e durante o sleep.
- Robôs e veículos: monitore a corrente do motor para detectar travamentos.
- Iluminação e bombas de 12 V: confirme que uma carga realmente ligou, e não apenas que um relé estalou.
Para monitorar uma casa inteira com alicates CT e gráficos de longo prazo, nosso artigo sobre monitor de energia residencial com MQTT mostra o lado do assinante, e o guia Raspberry Pi com Grafana e InfluxDB armazena as leituras por meses. Esses mesmos dados de energia também podem alimentar um gêmeo digital da instalação. Com orçamento de energia apertado, o mesmo script roda bem em um nó MQTT com Raspberry Pi Zero 2 W.
Da bancada à instalação permanente
No servidor MQTT público em broker.connectmq.com qualquer pessoa pode ler os seus topics, o que é aceitável para um teste de bancada, mas revela padrões de uso em uma casa ou oficina de verdade. Migre para um broker privado com TLS antes de instalar o monitor de forma permanente. Com o ConnectMQ, um broker MQTT gerenciado, você recebe credenciais geradas por dispositivo; defina MQTT_PORT=8883 mais MQTT_USERNAME=YOUR_USERNAME, MQTT_PASSWORD=YOUR_PASSWORD e MQTT_CLIENT_ID=YOUR_CLIENT_ID em um arquivo de ambiente do systemd e reinicie. Depois adicione uma regra de alerta por limite no portal ConnectMQ, por exemplo tensão abaixo de 11,8 V no topic de potência, para ser avisado antes que uma bateria seja danificada.
Se você ainda está conhecendo o que faz um broker MQTT ou como rodar um script como serviço, comece pelo tutorial MQTT com Raspberry Pi e volte a este projeto.
Solução de problemas
ValueError: No I2C device at address: 0x40: confira SDA e SCL, ative o I2C e rodei2cdetect -y 1.- A tensão aparece perto de zero: VIN+ ou VIN- não está ligado ao circuito medido, ou os terras não estão compartilhados.
- As leituras de corrente estão ruidosas: tire a média ao longo do intervalo de publicação, como o script faz, e mantenha curtos os fios do shunt.
- O total de energia zera após o reboot: o arquivo de estado não tem permissão de escrita ou o script foi encerrado antes de salvar; verifique as permissões do diretório de trabalho.
Comece com o ConnectMQ
Envie seus dados de energia para um broker MQTT na nuvem que dashboards e alertas possam acessar de qualquer lugar. Crie seu broker ConnectMQ gratuito no plano Serverless, sem cartão de crédito, e conecte via TLS com MQTT 3.1.1 ou 5.0. O explorador de topics ao vivo mostra cada leitura assim que ela chega.
Perguntas frequentes
Um INA219 consegue medir a potência da rede elétrica CA?
Não. O INA219 é um sensor de CC para até 26 V. Use um HAT com alicate CT ou um medidor de energia certificado para circuitos CA, e deixe o trabalho na rede elétrica com um profissional qualificado.
Qual a precisão de um monitor de energia com Raspberry Pi e INA219?
Precisão suficiente para a maioria dos trabalhos de hobby e monitoramento, depois de conferida com um multímetro. A tolerância do shunt é a principal fonte de erro e pode ser corrigida com um fator de escala.
Por que publicar a energia como retained message?
Para que qualquer dashboard ou assinante que se conecte mais tarde receba na hora o total atual, em vez de esperar até um minuto pela próxima atualização.
Com que frequência devo publicar as leituras de potência?
A cada poucos segundos é suficiente para dashboards. Faça a amostragem mais rápido localmente, tire a média e publique a média para manter o tráfego baixo.



