ESP32 y Arduino

Monitor de energía con sensor de corriente SCT-013 y ESP32 por MQTT

Coloca un transformador de corriente SCT-013 en un cable de red, mide la corriente RMS con el ADC del ESP32, estima potencia y energía y publica los resultados en broker.connectmq.com para dashboards de energía.

Pinza de corriente SCT-013 alrededor de un cable conectada a un monitor de energía ESP32, ilustrando el proyecto de sensor de corriente sct-013 esp32
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

Un montaje con el sensor de corriente SCT-013 y un ESP32 es la forma no invasiva más barata de ver cuánta energía consume un circuito, porque la pinza rodea un cable sin cortar nada. En este tutorial construirás el circuito de polarización, calcularás la corriente RMS con el ADC del ESP32, estimarás la potencia y los kWh y publicarás los resultados por MQTT en broker.connectmq.com para un dashboard de energía.

Lo primero, la seguridad

El SCT-013 es una pinza de núcleo partido que nunca toca conductores en tensión, y eso es lo que hace accesible este proyecto. El cuadro donde se instala es otra cosa. Abrir un cuadro eléctrico o de distribución expone tensiones mortales. Si no estás cualificado, coloca la pinza solo en un cable ya accesible, como el cable de un electrodoméstico separado en sus conductores dentro de un adaptador fabricado para ello, o pide a un electricista que instale la pinza. Nunca abras la pinza de un SCT-013-000 mientras circula corriente sin una resistencia de carga montada, porque un transformador de corriente sin carga puede generar una tensión peligrosa en sus terminales.

Elegir la variante adecuada del SCT-013

Modelo Salida Resistencia de carga Rango Conversión
SCT-013-000 Corriente, 50 mA a 100 A Sí, externa Hasta 100 A Depende de tu resistencia de carga
SCT-013-030 Tensión, 1 V RMS a 30 A No, integrada Hasta 30 A 30 A por voltio
SCT-013-020 Tensión, 1 V RMS a 20 A No, integrada Hasta 20 A 20 A por voltio
SCT-013-005 Tensión, 1 V RMS a 5 A No, integrada Hasta 5 A 5 A por voltio

Para un primer montaje, elige una versión con salida de tensión dimensionada para el circuito. La mayor resolución a corrientes bajas se consigue eligiendo el rango más pequeño que cubra tu carga máxima: una pinza de 5 A en el circuito de un frigorífico da lecturas mucho mejores que una de 100 A.

Si usas el SCT-013-000, añade una resistencia de carga en su salida. Una resistencia de 22 Ohm mantiene la tensión de pico por debajo de unos 1,6 V a 100 A RMS, lo que encaja con el circuito de polarización siguiente, y da una conversión de 2000 / 22, aproximadamente 90,9 A por voltio.

El circuito de polarización

La pinza produce una señal alterna que oscila en positivo y negativo alrededor de cero. El ADC del ESP32 solo puede leer de 0 a unos 3,1 V, así que la señal debe ir montada sobre un punto medio de continua.

  1. Conecta dos resistencias iguales (de 10 kOhm cada una) en serie entre 3V3 y GND. Su unión queda a unos 1,65 V.
  2. Conecta un condensador electrolítico de 10 uF de la unión a GND para estabilizar el punto medio.
  3. Conecta un terminal de la pinza (la punta del jack de 3,5 mm) a la unión.
  4. Conecta el otro terminal (la camisa) a la entrada del ADC, GPIO 34.

Con una salida de 1 V RMS, la señal alcanza picos de unos 1,41 V, así que el ADC ve aproximadamente de 0,24 V a 3,06 V. Eso queda dentro del rango de la atenuación por defecto. Usa un pin del ADC1 (GPIO 32 a 39 en un ESP32 clásico); los pines del ADC2 no pueden leerse mientras el Wi-Fi está activo.

Medir la corriente RMS

El código muestrea el ADC lo más rápido posible durante 200 ms, lo que cubre 10 ciclos completos a 50 Hz y 12 a 60 Hz. Calcula la media (el punto medio de continua, medido en lugar de supuesto) y la desviación típica a su alrededor, que es exactamente el valor RMS de la componente alterna. Al multiplicarlo por el factor de conversión de la pinza se obtienen amperios.

Medir el punto medio en cada pasada elimina los errores por tolerancia de las resistencias y deriva de la alimentación, y analogReadMilliVolts() aplica la calibración de fábrica del ADC, lo que ayuda con la conocida falta de linealidad del ADC del ESP32.

El sketch del sensor de corriente SCT-013 con ESP32

#include <WiFi.h>
#include <PubSubClient.h>
#include <Preferences.h>
#include <math.h>

const char* WIFI_SSID     = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST     = "broker.connectmq.com";
const uint16_t MQTT_PORT  = 1883;
const char* PREFIX        = "connectmq/demo/sct3m8w";   // usa tu propio id aleatorio

const uint8_t CT_PIN          = 34;      // pin del ADC1
const float   AMPS_PER_VOLT   = 30.0f;   // SCT-013-030; 90.9 para el -000 con carga de 22 Ohm
const float   MAINS_VOLTAGE   = 230.0f;  // pon 120.0 en Norteamérica
const float   CALIBRATION     = 1.00f;   // ajústalo tras comparar con una pinza amperimétrica
const float   NOISE_FLOOR_A   = 0.08f;   // las lecturas por debajo se informan como 0
const uint32_t WINDOW_MS      = 200;
const uint32_t PUBLISH_MS     = 10000;
const uint32_t SAVE_MS        = 600000;  // guarda la energía cada 10 min

WiFiClient   net;
PubSubClient mqtt(net);
Preferences  prefs;
String clientId, tPower, tStatus;

double energyKwh = 0;
uint32_t lastSample = 0, lastPublish = 0, lastSave = 0;
float lastIrms = 0, sumIrms = 0;
uint32_t samplesInPeriod = 0;

float readIrms() {
  uint32_t n = 0;
  double sum = 0, sumSq = 0;
  uint32_t start = millis();
  while (millis() - start < WINDOW_MS) {
    double mv = analogReadMilliVolts(CT_PIN);
    sum += mv;
    sumSq += mv * mv;
    n++;
  }
  double mean = sum / n;
  double variance = sumSq / n - mean * mean;
  if (variance < 0) variance = 0;
  double vrms = sqrt(variance) / 1000.0;          // voltios RMS de la parte alterna
  float irms = vrms * AMPS_PER_VOLT * CALIBRATION;
  return irms < NOISE_FLOOR_A ? 0.0f : irms;
}

void connectWifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) delay(300);
  Serial.printf("Wi-Fi OK, IP %s\n", WiFi.localIP().toString().c_str());
}

void connectMqtt() {
  while (!mqtt.connected()) {
    if (mqtt.connect(clientId.c_str(), tStatus.c_str(), 1, true, "offline")) {
      mqtt.publish(tStatus.c_str(), "online", true);
      Serial.println("MQTT connected");
    } else {
      Serial.printf("MQTT failed, state %d\n", mqtt.state());
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);
  prefs.begin("energy", false);
  energyKwh = prefs.getDouble("kwh", 0.0);

  clientId = "esp32-sct013-" + String((uint32_t)ESP.getEfuseMac(), HEX);
  tPower   = String(PREFIX) + "/power";
  tStatus  = String(PREFIX) + "/status";

  connectWifi();
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setBufferSize(512);
  connectMqtt();
  lastSample = lastPublish = lastSave = millis();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) connectWifi();
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  // Muestrea aproximadamente una vez por segundo e integra la energía
  uint32_t now = millis();
  if (now - lastSample >= 1000) {
    float irms = readIrms();
    float dtHours = (millis() - lastSample) / 3600000.0f;
    lastSample = millis();
    energyKwh += (irms * MAINS_VOLTAGE) * dtHours / 1000.0;
    lastIrms = irms;
    sumIrms += irms;
    samplesInPeriod++;
    mqtt.loop();
  }

  if (now - lastPublish >= PUBLISH_MS && samplesInPeriod > 0) {
    lastPublish = now;
    float avgIrms = sumIrms / samplesInPeriod;
    sumIrms = 0;
    samplesInPeriod = 0;

    char payload[200];
    snprintf(payload, sizeof(payload),
             "{\"irms\":%.2f,\"irmsAvg\":%.2f,\"apparentPowerVA\":%.0f,"
             "\"energyKwh\":%.4f,\"voltageAssumed\":%.0f}",
             lastIrms, avgIrms, avgIrms * MAINS_VOLTAGE, energyKwh, MAINS_VOLTAGE);
    mqtt.publish(tPower.c_str(), payload);
    Serial.println(payload);
  }

  if (now - lastSave >= SAVE_MS) {
    lastSave = now;
    prefs.putDouble("kwh", energyKwh);   // limitar las escrituras protege la flash
  }
}

Cada ventana de medida bloquea el bucle durante 200 ms, lo que no afecta a los keep-alives de MQTT porque el sketch llama a mqtt.loop() justo después de muestrear. Si añades más pinzas, léelas una tras otra en la misma pasada, o lleva el muestreo a su propia tarea de FreeRTOS como se muestra en la guía de ESP32 FreeRTOS MQTT, para que el código de red nunca espere tras una larga serie de ventanas.

Pruebas y calibración

Suscríbete al topic:

mosquitto_sub -h broker.connectmq.com -p 1883 -i sct-view-3m8w -t "connectmq/demo/sct3m8w/#" -v

Sin nada en marcha, irms debería marcar 0. Enciende una carga resistiva conocida, como un hervidor o un calefactor, y compara irms con una pinza amperimétrica en el mismo conductor. Ajusta CALIBRATION según la proporción entre ambas lecturas, por ejemplo 1.04 si el ESP32 marca un 4 por ciento menos. Calibra cerca de la mitad del rango de la pinza para obtener la mejor precisión global.

El área pública del broker puede leerla cualquiera, y los patrones de consumo eléctrico pueden revelar cuándo una vivienda está ocupada, así que úsala solo para pruebas de banco y prototipos, nunca para datos de producción. Sus límites figuran en la página del servidor MQTT público gratuito.

Qué significan los números

El sketch publica la potencia aparente en voltamperios, calculada a partir de la corriente medida y una tensión de red supuesta. Para cargas resistivas como hervidores y calefactores, la potencia aparente se aproxima a la potencia real en vatios. En motores, compresores, fuentes de alimentación y drivers LED, el factor de potencia es inferior a 1, así que la potencia real es menor que la cifra en VA. Además, la tensión de red varía a lo largo del día.

La potencia real requiere también medir la tensión, normalmente con un transformador CA-CA aislado que alimenta un segundo pin del ADC, además de una multiplicación muestra a muestra. Es un buen siguiente paso, pero la versión que solo mide corriente ya basta para ver qué aparato funciona y cuándo, detectar consumos en standby y comparar días.

Lista de comprobación de precisión

  1. Coloca la pinza alrededor de un solo conductor. Alrededor de un cable completo, las corrientes de fase y neutro se anulan y la lectura es casi cero.
  2. Elige el rango de pinza más pequeño que cubra tu corriente máxima.
  3. Mantén cortos los cables analógicos y lejos de las antenas Wi-Fi y de las fuentes conmutadas.
  4. Mide el punto medio en cada ventana en lugar de suponer 1,65 V.
  5. Aplica un umbral de ruido para que un circuito inactivo marque 0, no unos cientos de miliamperios.
  6. Calibra contra un medidor fiable con una carga resistiva.

Crear un dashboard de energía

En el lado receptor, un suscriptor convierte los mensajes en gráficas. El MQTT consumer de Telegraf puede analizar el JSON y escribirlo en InfluxDB para Grafana, Node-RED puede calcular totales y costes diarios, y Home Assistant puede tratar energyKwh como un sensor de energía con una definición de sensor MQTT. Todos ellos se conectan al broker como clientes MQTT normales. Si monitorizas varios circuitos o temperaturas a la vez, combina este nodo con el proyecto multisonda con DS18B20, o lee contadores existentes con la pasarela Modbus RS485 con ESP32. Si vigilas muchos circuitos de una planta o de un edificio, los mismos topics pueden alimentar un gemelo digital 3D que muestre el consumo por zona en el navegador.

Para producción, crea un broker en app.connectmq.com, cambia a WiFiClientSecure en el puerto 8883 con el certificado ISRG Root X1 y conéctate con YOUR_CLIENT_ID, YOUR_USERNAME y YOUR_PASSWORD. Las reglas de alerta por umbral del portal de ConnectMQ pueden avisarte entonces cuando la corriente supere un límite, por ejemplo cuando un circuito se acerque a la capacidad de su interruptor automático (magnetotérmico o breaker).

Empieza con ConnectMQ

Los datos de energía son más valiosos cuando se recogen de forma continua y se mantienen privados. ConnectMQ es un broker MQTT gestionado con TLS, MQTT 3.1.1 y 5.0, explorador de topics en vivo y alertas, y el plan gratuito Serverless no requiere tarjeta de crédito. Apunta este sketch a tu broker y consulta el tutorial de IoT con ESP32 para ver más proyectos de medición.

Preguntas frecuentes

¿Puede el sensor de corriente SCT-013 con ESP32 medir la potencia real en vatios?

Solo con la corriente, estima la potencia aparente en VA. La potencia real requiere también medir la tensión para que el código pueda tener en cuenta el factor de potencia.

¿Por qué mi lectura muestra corriente sin nada encendido?

Es ruido del ADC e interferencias captadas. Aplica un umbral de ruido, mantén los cables cortos y comprueba que el condensador del punto medio está montado.

¿Qué pines del ESP32 puedo usar para el SCT-013?

Usa pines del ADC1 (GPIO 32 a 39 en un ESP32 clásico). Los pines del ADC2 no funcionan mientras el Wi-Fi está activo.

¿Necesito una resistencia de carga?

Solo para el SCT-013-000 con salida de corriente. Las versiones con salida de tensión, como el SCT-013-030, llevan la resistencia de carga integrada.

Artículos relacionados

Ejemplo de ESP-IDF MQTT: crea un cliente esp-mqtt desde cero

Construye un proyecto ESP-IDF desde una carpeta vacía con el componente esp-mqtt: configuración de Wi-Fi en modo estación, el manejador de eventos MQTT, publicación y suscripción, propiedades de MQTT 5 y TLS con el bundle de certificados.

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