Un monitor de consumo eléctrico Raspberry Pi te dice exactamente cuánto consume un circuito, cuánto se está cargando una batería y cuánta energía usa un dispositivo a lo largo de un día. En este tutorial medirás tensión, corriente y potencia en continua con un INA219, las integrarás en vatios-hora y lo publicarás todo como JSON por MQTT para que un dashboard o una automatización puedan usarlo. También verás cómo los HAT con pinza CT llevan la misma idea a los circuitos de corriente alterna de la red eléctrica.
Elegir el sensor: INA219 o pinza CT
| Placa INA219 | HAT con pinza CT | |
|---|---|---|
| Mide | Tensión DC (hasta 26 V), corriente, potencia | Corriente AC a través de una pinza; algunas placas también miden tensión AC |
| Conexión | En serie con la carga, mediante una resistencia shunt | No invasiva, se abraza alrededor de un conductor |
| Uso típico | Paneles solares, baterías de 12 V, tiras LED, robots, la propia Pi | Circuitos domésticos, electrodomésticos, máquinas |
| Interfaz | I2C | Normalmente un ADC SPI o I2C en el HAT |
| Seguridad | Solo baja tensión | La pinza está aislada, pero la instalación cerca de la red eléctrica requiere a una persona cualificada |
Este tutorial construye de principio a fin la versión con INA219 porque es barata, precisa para continua de baja tensión y segura para experimentar. Si necesitas alterna, un HAT con pinza CT viene con su propia librería de Python; lee sus valores y reutiliza sin cambios la parte MQTT del script. El equivalente con ESP32 para la red eléctrica se explica en la guía del sensor de corriente SCT-013 con ESP32.
Cómo funciona el INA219
El INA219 mide la pequeña caída de tensión en una resistencia shunt de 0,1 ohmios en serie con la carga, y la tensión de bus en el lado de la carga. A partir de esos dos valores calcula internamente la corriente y la potencia. La placa estándar admite hasta 26 V en el bus y, con la calibración por defecto, unos 3,2 A. Como el shunt está en serie, toda la corriente de la carga pasa por la placa, así que mantente dentro de sus límites y usa cables lo bastante gruesos para la corriente.
Cableado
| Pin del INA219 | Conectar a |
|---|---|
| VCC | 3,3 V de la Pi (pin físico 1) |
| GND | GND de la Pi (pin físico 6) y la tierra de la fuente de la carga |
| SDA | GPIO2 (pin físico 3) |
| SCL | GPIO3 (pin físico 5) |
| VIN+ | Terminal positivo de la fuente de alimentación |
| VIN- | Entrada positiva de la carga |
La tierra del circuito medido debe compartirse con la tierra de la Pi; de lo contrario, la lectura de tensión de bus no tiene sentido. Activa I2C con sudo raspi-config nonint do_i2c 0 y confirma que el sensor aparece en la dirección 0x40 con i2cdetect -y 1.
Instalación del 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 y payload
| Topic | Contenido | Retained |
|---|---|---|
connectmq/demo/8d20f6/solar/power |
Tensión, corriente, potencia cada 5 s | No |
connectmq/demo/8d20f6/solar/energy |
Wh acumulados, cada minuto | Sí |
connectmq/demo/8d20f6/solar/status |
online / offline |
Sí |
Un mensaje de potencia tiene este aspecto:
{"voltage": 12.84, "current_ma": 412.6, "power_w": 5.3, "ts": 1792161000}
El topic de energía es retained para que un dashboard que se abra más tarde vea de inmediato el total del día.
El script del monitor de consumo eléctrico Raspberry Pi
El script toma una muestra por segundo, promedia durante el intervalo de publicación para suavizar el ruido e integra la potencia en el tiempo para obtener vatios-hora. Guarda el contador de energía en disco cada diez minutos para que un reinicio no lo ponga a cero, sin escribir en la tarjeta SD en cada muestra. Guárdalo 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()) # calibración por defecto: rango de 32 V y 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) # el renombrado atómico evita archivos a medio escribir
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 # tensión del lado de la fuente
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()
Ejecútalo con python power_monitor.py y suscríbete desde otro equipo:
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-8d20f6 \
-t 'connectmq/demo/8d20f6/solar/#' -v
Enciende y apaga la carga y observa cómo current_ma y power_w responden en menos de cinco segundos.
Calibración y precisión
La calibración por defecto cubre 32 V y 2 A con una resolución razonable. Si tu carga es pequeña, como un microcontrolador que consume decenas de miliamperios, llama a ina.set_calibration_16V_400mA() tras crear el sensor para obtener una resolución más fina. Si necesitas más de lo que admite la placa, sustituye el shunt por uno de menor valor y escribe tu propia calibración, o cambia a un sensor diseñado para corrientes más altas.
Verifica con un multímetro en serie con la carga. Los pequeños desfases son normales; un error porcentual constante suele deberse a la tolerancia del shunt, que puedes corregir con un factor de escala en software. Una corriente negativa significa que VIN+ y VIN- están intercambiados, lo que de hecho puede ser útil: un monitor de batería puede usar el signo para mostrar si se está cargando o descargando.
Casos de uso
El mismo script sirve para muchos proyectos cambiando solo el prefijo del topic y la calibración. Como los suscriptores solo ven JSON con campos de tensión, corriente, potencia y energía, puedes cambiar el sensor más adelante, o añadir un segundo INA219 en la dirección 0x41 para otro circuito, sin tocar el dashboard ni la automatización que consumen los datos.
- Sistemas solares y de baterías: sigue la producción del panel y la tensión de la batería, y publica una alerta cuando la batería baje de un nivel seguro.
- Medir tus propios proyectos con Pi o ESP32: coloca el INA219 entre la fuente y un dispositivo para ver el consumo real durante las ráfagas de Wi-Fi y el modo de reposo.
- Robots y vehículos: monitoriza la corriente de los motores para detectar bloqueos.
- Iluminación y bombas de 12 V: confirma que una carga se ha encendido de verdad, no solo que un relé ha hecho clic.
Para monitorizar toda una vivienda con pinzas CT y gráficas a largo plazo, nuestro artículo sobre el monitor de energía doméstico con MQTT muestra el lado del suscriptor, y la guía de Raspberry Pi con Grafana e InfluxDB almacena las lecturas durante meses. Con presupuestos de energía ajustados, el mismo script funciona bien en un nodo MQTT con Raspberry Pi Zero 2 W.
Del banco de pruebas a la instalación permanente
En el servidor MQTT público gratuito broker.connectmq.com cualquiera puede leer tus topics, lo cual está bien para una prueba en el banco pero revela patrones de consumo en una vivienda o un taller reales. Pasa a un broker privado con TLS antes de instalar el monitor de forma permanente. Con ConnectMQ, un broker MQTT gestionado, obtienes credenciales generadas por dispositivo; define MQTT_PORT=8883 más MQTT_USERNAME=YOUR_USERNAME, MQTT_PASSWORD=YOUR_PASSWORD y MQTT_CLIENT_ID=YOUR_CLIENT_ID en un archivo de entorno de systemd y reinicia. Después añade una regla de alerta por umbral en el portal de ConnectMQ, por ejemplo tensión inferior a 11,8 V en el topic de potencia, para recibir un aviso antes de que se dañe una batería.
Si eres nuevo en lo que hace un broker MQTT o en cómo ejecutar un script como servicio, empieza por el tutorial de MQTT con Raspberry Pi y vuelve después a este montaje.
Solución de problemas
ValueError: No I2C device at address: 0x40: revisa SDA y SCL, activa I2C y ejecutai2cdetect -y 1.- La tensión marca casi cero: VIN+ o VIN- no están conectados al circuito medido, o las tierras no son comunes.
- Las lecturas de corriente son ruidosas: promedia durante el intervalo de publicación como hace el script y mantén cortos los cables del shunt.
- El total de energía se reinicia tras un reinicio del sistema: el archivo de estado no se puede escribir o el script se detuvo antes de guardar; revisa los permisos del directorio de trabajo.
Empieza con ConnectMQ
Envía tus datos de consumo a un broker MQTT en la nube al que los dashboards y las alertas puedan llegar desde cualquier lugar. Crea tu broker gratuito de ConnectMQ con el plan Serverless, sin tarjeta de crédito, y conéctate por TLS con MQTT 3.1.1 o 5.0. El explorador de topics en vivo muestra cada lectura en cuanto llega.
Preguntas frecuentes
¿Puede un INA219 medir la potencia de la red eléctrica en alterna?
No. El INA219 es un sensor de continua para hasta 26 V. Usa un HAT con pinza CT o un medidor de energía certificado para circuitos de alterna, y deja los trabajos en la red eléctrica en manos de una persona cualificada.
¿Qué precisión tiene un monitor de consumo eléctrico Raspberry Pi con INA219?
La suficiente para la mayoría de los proyectos personales y de monitorización una vez contrastado con un multímetro. La tolerancia del shunt es la principal fuente de error y se puede corregir con un factor de escala.
¿Por qué publicar la energía como retained message?
Para que cualquier dashboard o suscriptor que se conecte más tarde reciba de inmediato el total actual en lugar de esperar hasta un minuto a la siguiente actualización.
¿Con qué frecuencia debo publicar las lecturas de potencia?
Cada pocos segundos basta para los dashboards. Muestrea más rápido en local, promedia y publica la media para mantener bajo el tráfico.



