Automatización IoT

Integración MQTT del cargador de vehículo eléctrico: OCPP frente a MQTT y carga solar en casa

OCPP conecta los cargadores con los sistemas de gestión, mientras que MQTT los conecta con el resto de tu casa. Descubre cómo encajan ambos, qué vía de integración conviene a tu wallbox y cómo construir una carga basada en el excedente solar sobre MQTT.

Wallbox doméstico cargando un coche eléctrico con paneles solares y un diagrama de flujos de energía para la integración MQTT del cargador
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

La integración MQTT del cargador de vehículo eléctrico permite que tu wallbox forme parte del resto del sistema energético de tu hogar: cargar cuando brilla el sol, pausar cuando funcionan el horno y la bomba de calor, y mostrar su estado en el mismo panel que todo lo demás. Esta guía explica en qué se diferencian OCPP y MQTT, las tres formas prácticas de llevar un cargador a MQTT, un diseño de topics limpio y un controlador de excedente solar funcional en Python. Al terminar sabrás qué vía encaja con tu cargador y cómo construir sobre ella de forma segura.

OCPP y MQTT resuelven problemas distintos

A menudo se pregunta si un cargador debería usar OCPP o MQTT. En la práctica sirven a relaciones distintas, y una buena instalación doméstica suele usar ambos.

OCPP (Open Charge Point Protocol) es el lenguaje estándar entre un cargador y un sistema de gestión de estaciones de carga (CSMS), el back office que se ocupa de la autorización, las sesiones y la facturación. OCPP 1.6J y 2.0.1 envían mensajes JSON por un WebSocket que el cargador abre hacia el CSMS. Los mensajes incluyen BootNotification, StatusNotification, MeterValues, el inicio y fin de transacciones y SetChargingProfile para la carga inteligente. Cada cargador se conecta a un único CSMS a la vez.

MQTT es un protocolo publicación/suscripción de propósito general. Un cargador o un puente publica su estado en un broker, y cualquier número de consumidores (panel, Home Assistant, gestor energético, app móvil) se suscriben sin que el cargador sepa de ellos. Si el patrón es nuevo para ti, la explicación de qué hace un broker MQTT cubre los conceptos básicos.

Aspecto OCPP MQTT
Finalidad Del cargador al back office: sesiones, autorización, facturación, carga inteligente De cualquier dispositivo a cualquier número de consumidores
Transporte WebSocket, el cargador se conecta a un único CSMS TCP o WebSocket hacia un broker, muchos suscriptores
Esquema de mensajes Definido estrictamente en cada versión de OCPP Tú diseñas los topics y los payloads
Usuario típico Operadores de puntos de carga, flotas, carga en el trabajo Domótica, gestión energética, paneles
Control Inicio/parada remotos, perfiles de carga Lo que exponga el dispositivo o el puente
Varios consumidores No, un CSMS por conexión Sí, de forma nativa

Si gestionas cargadores públicos o en el lugar de trabajo, OCPP hacia un CSMS es el núcleo adecuado. Si quieres que un cargador doméstico coopere con paneles solares, baterías y consumos del hogar, MQTT es la capa de integración práctica, a veces alimentada por OCPP entre bastidores.

Tres formas de llevar un cargador de vehículo eléctrico a MQTT

1. MQTT nativo en el cargador. Algunos cargadores, sobre todo los modelos de hardware abierto y los pensados para entusiastas, publican su estado y aceptan comandos directamente por MQTT. Introduces el host, el puerto y las credenciales del broker en la interfaz web del cargador. Es la vía más sencilla cuando está disponible, pero los nombres de topic y los payloads varían según el fabricante.

2. Un servidor OCPP local que hace de puente a MQTT. Muchos wallbox comerciales solo hablan OCPP (además de la nube del fabricante). Apunta la URL OCPP del cargador a un servidor OCPP local, por ejemplo la integración OCPP para Home Assistant o un CSMS de código abierto, y deja que ese servidor republique el estado y los valores de medición en MQTT. Conservas la semántica estándar de OCPP y ganas MQTT para todo lo demás. El inconveniente es que las funciones de la nube del fabricante pueden dejar de funcionar mientras el cargador habla con tu servidor.

3. Un gestor energético intermedio. Los gestores energéticos de código abierto como evcc hablan con muchos cargadores a través de sus protocolos nativos y publican su propio estado en MQTT, incluidas la potencia de red, la potencia fotovoltaica y la potencia de carga de cada punto de carga, y aceptan cambios de modo a través de topics MQTT. Suele ser la vía más rápida para cargar con excedente solar, porque la lógica de control ya está construida y probada.

Elijas la vía que elijas, busca el mismo resultado en el broker: un árbol de topics estable que no cambie si sustituyes el cargador.

Diseño del árbol de topics MQTT del cargador

Separa el estado de los comandos, retén el estado y nunca retengas los comandos:

home/ev/charger1/state            retained  {"status":"charging","power_w":7210,"current_a":10.4,"phases":3,"session_kwh":12.8}
home/ev/charger1/status           retained  online / offline (Last Will)
home/ev/charger1/set/current_a    command   6..16
home/ev/charger1/set/enabled      command   true / false
home/energy/grid/telemetry        retained  {"net_w": -2350, ...}

Usa valores de estado al estilo OCPP (available, preparing, charging, suspended_ev, suspended_evse, finishing, faulted) aunque la fuente no sea OCPP. Se entienden bien y distinguen "el coche está lleno" (suspended_ev) de "el cargador ha pausado" (suspended_evse), algo importante para las automatizaciones.

Retener un comando como set/current_a es un error clásico: tras un corte de luz, el cargador o el puente se reconecta y reproduce un valor antiguo. Los comandos no deben retenerse; el puente publica el valor efectivo en el topic de estado retenido.

Un controlador de excedente solar en Python

El siguiente controlador se suscribe al net_w del contador de red (negativo significa exportación, tal como lo publica el tutorial del monitor de energía doméstico) y al estado del cargador, y publica una corriente de carga que sigue al excedente. Funciona con cualquier cargador o puente que acepte una consigna de corriente en un topic. Pruébalo en el servidor MQTT público gratuito con mensajes simulados antes de conectar nada real; ese servidor es solo para pruebas y prototipos, no para datos de producción.

pip install "paho-mqtt>=2.0"
import json
import time
import paho.mqtt.client as mqtt

PREFIX = "connectmq/demo/ev7k2"      # usa tu propio prefijo aleatorio durante las pruebas
GRID_TOPIC = f"{PREFIX}/energy/grid/telemetry"
STATE_TOPIC = f"{PREFIX}/ev/charger1/state"
SET_CURRENT = f"{PREFIX}/ev/charger1/set/current_a"
SET_ENABLED = f"{PREFIX}/ev/charger1/set/enabled"

VOLTAGE = 230
PHASES = 1            # pon 3 para un cargador trifásico
MIN_A, MAX_A = 6, 16  # 6 A es la corriente mínima en la señalización IEC 61851
START_MARGIN_W = 300  # exportación adicional necesaria antes de empezar
UPDATE_EVERY = 30     # segundos entre cambios de consigna
STOP_AFTER = 300      # segundos por debajo del mínimo antes de pausar

state = {"net_w": None, "charger_current_a": 0.0, "status": "unknown"}
current_set = 0
below_since = None
last_update = 0.0


def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    client.subscribe(GRID_TOPIC, qos=1)
    client.subscribe(STATE_TOPIC, qos=1)


def on_message(client, userdata, msg):
    data = json.loads(msg.payload)
    if msg.topic == GRID_TOPIC:
        state["net_w"] = data.get("net_w")
    elif msg.topic == STATE_TOPIC:
        state["charger_current_a"] = data.get("current_a", 0.0)
        state["status"] = data.get("status", "unknown")


def control(client):
    global current_set, below_since, last_update
    if state["net_w"] is None or state["status"] in ("available", "faulted", "unknown"):
        return
    if time.time() - last_update < UPDATE_EVERY:
        return
    charger_w = state["charger_current_a"] * VOLTAGE * PHASES
    surplus_w = charger_w - state["net_w"]          # lo que podríamos usar sin importar
    if current_set == 0:
        surplus_w -= START_MARGIN_W
    target = int(surplus_w // (VOLTAGE * PHASES))

    if target >= MIN_A:
        below_since = None
        target = min(target, MAX_A)
        if current_set == 0:
            client.publish(SET_ENABLED, "true", qos=1)
        if target != current_set:
            client.publish(SET_CURRENT, str(target), qos=1)
            print(f"surplus {surplus_w:.0f} W -> {target} A")
            current_set = target
    elif current_set > 0:
        below_since = below_since or time.time()
        if time.time() - below_since > STOP_AFTER:
            client.publish(SET_ENABLED, "false", qos=1)
            print("Not enough surplus, pausing")
            current_set = 0
        elif current_set != MIN_A:
            client.publish(SET_CURRENT, str(MIN_A), qos=1)
            current_set = MIN_A
    last_update = time.time()


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="ev-surplus-6619")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
while True:
    control(client)
    time.sleep(1)

Simula una tarde soleada desde otro terminal y observa cómo reacciona el controlador:

mosquitto_pub -h broker.connectmq.com -p 1883 -i ev-sim-1 -t "connectmq/demo/ev7k2/ev/charger1/state" -m '{"status":"suspended_evse","current_a":0}'
mosquitto_pub -h broker.connectmq.com -p 1883 -i ev-sim-2 -t "connectmq/demo/ev7k2/energy/grid/telemetry" -m '{"net_w":-2600}'

Con 2.600 W de exportación en una sola fase a 230 V, el controlador arranca a 10 A tras restar el margen de inicio. Si tu red doméstica es de 127 V, como en México y parte de Latinoamérica, ajusta la constante de tensión del script para que el cálculo de corriente sea correcto.

Reglas de diseño para un control seguro del cargador

El hardware de carga maneja corrientes elevadas durante horas, así que sé conservador:

  1. Deja que el cargador aplique sus propios límites. Tu controlador solo solicita una consigna; el máximo configurado en el cargador y las protecciones de la instalación deben seguir siendo la autoridad final.
  2. Cambia las consignas despacio. Los cambios frecuentes de corriente y los ciclos de arranque y parada castigan los contactores y a algunos vehículos. Un intervalo de actualización de 30 segundos y un retardo de parada de 5 minutos son puntos de partida razonables.
  3. Respeta el mínimo de 6 A. Por debajo, pausa la carga en lugar de solicitar una corriente no válida.
  4. Gestiona con cuidado la conmutación de fases. Cambiar entre una y tres fases requiere que el cargador lo admita y nunca debe ocurrir mientras circula corriente.
  5. Falla de forma segura. Si el contador de red deja de informar, deja de ajustar y vuelve a un estado fijo o en pausa. Usa el estado Last Will retenido del contador para detectarlo.
  6. Nunca controles cargadores a través del servidor público. Cualquiera podría publicar en tu topic de comandos. El área pública es solo para simulaciones.

Paso a un broker privado

Cuando la simulación se comporte bien, conecta el cargador real o el puente y el controlador a un broker privado con TLS y credenciales por cliente. Un broker MQTT gestionado como ConnectMQ mantiene ese broker en línea sin un servidor que mantener y, como tu cargador, el lector del contador y el controlador solo establecen conexiones salientes, no hay que exponer nada en tu router. En el portal de ConnectMQ, crea un broker, emite credenciales para cada cliente y conéctate por el puerto 8883:

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set()
client.connect("broker.connectmq.com", 8883, keepalive=60)

Después incorpora los datos de producción de la monitorización del inversor solar y el almacenamiento de la monitorización de baterías domésticas para decidir si el excedente va primero al coche o a la batería. La guía de automatización IoT muestra cómo encajan estos flujos de energía en una instalación doméstica más amplia, y la guía del broker MQTT en la nube te ayuda a elegir dónde alojarlo.

Conecta tu cargador a ConnectMQ

ConnectMQ ofrece a tu puente del cargador, tu gestor energético y tus paneles un broker privado con TLS, acceso por WebSocket para aplicaciones de navegador y un explorador de topics en directo para verificar cada cambio de estado. Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito.

Preguntas frecuentes

¿Mi cargador doméstico debe usar OCPP o MQTT?

Usa lo que el cargador admita de forma nativa para su conexión principal y emplea MQTT como capa de integración para la domótica. Muchas instalaciones usan OCPP hacia un servidor local y republican en MQTT.

¿Puedo usar OCPP y la nube del fabricante a la vez?

Normalmente no, porque un cargador se conecta a un único backend OCPP. Apuntarlo a tu propio servidor suele sustituir al backend del fabricante, así que comprueba qué funciones perderías.

¿Cuál es la corriente de carga mínima?

La señalización por piloto de control IEC 61851 que usan los cargadores de corriente alterna tiene un mínimo de 6 A. Por debajo de ese valor, el controlador debe pausar la carga en lugar de seguir reduciendo la corriente.

¿Con qué rapidez debe reaccionar un controlador de excedente?

Cada 30 a 60 segundos es un valor por defecto sensato. Las reacciones más rápidas sobre todo persiguen nubes pasajeras y provocan conmutaciones innecesarias.

Artículos relacionados

Guía para configurar Zigbee2MQTT: del coordinador al panel

Instala Zigbee2MQTT con Docker, configura el coordinador y la conexión MQTT, empareja y renombra dispositivos, contrólalos por MQTT y consulta sus estados en un panel, probando primero en un servidor MQTT público gratuito.

8 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.