ESP32 e Arduino

Monitor de Energia com Sensor de Corrente SCT-013 e ESP32 via MQTT

Prenda um transformador de corrente SCT-013 em um cabo da rede elétrica, meça a corrente RMS com o ADC do ESP32, estime potência e energia e publique os resultados no broker.connectmq.com para dashboards de energia.

Alicate de corrente SCT-013 em volta de um cabo ligado a um monitor de energia com ESP32, ilustrando o projeto do sensor de corrente SCT-013
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Montar um sensor de corrente SCT-013 com ESP32 é a forma não invasiva mais barata de ver quanta energia um circuito consome, porque o alicate envolve o cabo sem cortar nada. Neste tutorial, você vai montar o circuito de polarização, calcular a corrente RMS com o ADC do ESP32, estimar potência e kWh e publicar os resultados via MQTT no broker.connectmq.com para um dashboard de energia.

Segurança em primeiro lugar

O SCT-013 em si é um alicate de núcleo dividido que nunca toca nos condutores energizados, e é isso que torna este projeto acessível. O quadro onde ele é instalado é outra história. Abrir um quadro de distribuição expõe tensões letais. Se você não é qualificado, prenda o alicate apenas em um cabo já acessível, como o cabo de um único aparelho separado em seus condutores em um adaptador próprio para isso, ou peça a um eletricista para instalar o alicate. Nunca abra o alicate de um SCT-013-000 com corrente circulando sem um resistor de carga (burden) instalado, porque um transformador de corrente sem carga pode desenvolver uma tensão perigosa em seus terminais.

Escolhendo a variante certa do SCT-013

Modelo Saída Burden necessário Faixa Conversão
SCT-013-000 Corrente, 50 mA em 100 A Sim, externo Até 100 A Depende do seu resistor de burden
SCT-013-030 Tensão, 1 V RMS em 30 A Não, embutido Até 30 A 30 A por volt
SCT-013-020 Tensão, 1 V RMS em 20 A Não, embutido Até 20 A 20 A por volt
SCT-013-005 Tensão, 1 V RMS em 5 A Não, embutido Até 5 A 5 A por volt

Para uma primeira montagem, escolha uma versão com saída em tensão dimensionada para o circuito. Uma resolução maior em correntes baixas vem de escolher a menor faixa que cubra sua carga máxima: um alicate de 5 A no circuito de uma geladeira dá leituras muito melhores que um de 100 A.

Se você usar o SCT-013-000, adicione um resistor de burden na saída. Um burden de 22 Ohm mantém a tensão de pico abaixo de cerca de 1,6 V em 100 A RMS, o que se encaixa no circuito de polarização abaixo, e resulta em uma conversão de 2000 / 22, aproximadamente 90,9 A por volt.

O circuito de polarização

O alicate produz um sinal CA que oscila positiva e negativamente em torno de zero. O ADC do ESP32 só lê de 0 a cerca de 3,1 V, então o sinal precisa estar sobre um ponto médio CC.

  1. Ligue dois resistores iguais (10 kOhm cada) em série entre 3V3 e GND. A junção fica em cerca de 1,65 V.
  2. Ligue um capacitor eletrolítico de 10 uF da junção ao GND para estabilizar o ponto médio.
  3. Ligue um terminal do alicate (a ponta do plugue de 3,5 mm) à junção.
  4. Ligue o outro terminal (a luva) à entrada do ADC, GPIO 34.

Com uma saída de 1 V RMS, o sinal atinge picos de cerca de 1,41 V, então o ADC vê aproximadamente de 0,24 V a 3,06 V. Isso fica dentro da faixa da atenuação padrão. Use um pino do ADC1 (GPIO 32 a 39 em um ESP32 clássico); os pinos do ADC2 não podem ser lidos com o Wi-Fi ativo.

Medindo a corrente RMS

O código amostra o ADC o mais rápido possível durante 200 ms, o que cobre 10 ciclos completos em 50 Hz e 12 em 60 Hz. Ele calcula a média (o ponto médio CC, medido em vez de presumido) e o desvio padrão em torno dela, que é exatamente o valor RMS da componente CA. Multiplicar pelo fator de conversão do alicate dá o valor em ampères.

Medir o ponto médio a cada passagem elimina erros de tolerância dos resistores e de variação da alimentação, e analogReadMilliVolts() aplica a calibração de fábrica do ADC, o que ajuda com a conhecida não linearidade do ADC do ESP32.

O sketch do sensor de corrente SCT-013 com 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";   // use seu próprio id aleatório

const uint8_t CT_PIN          = 34;      // pino do ADC1
const float   AMPS_PER_VOLT   = 30.0f;   // SCT-013-030; 90.9 para o -000 com burden de 22 Ohm
const float   MAINS_VOLTAGE   = 230.0f;  // use 120.0 na América do Norte (ou 127.0 conforme a rede)
const float   CALIBRATION     = 1.00f;   // ajuste após comparar com um alicate amperímetro
const float   NOISE_FLOOR_A   = 0.08f;   // leituras abaixo disto são informadas como 0
const uint32_t WINDOW_MS      = 200;
const uint32_t PUBLISH_MS     = 10000;
const uint32_t SAVE_MS        = 600000;  // persiste a energia 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;          // volts RMS da parte CA
  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();

  // Amostra cerca de uma vez por segundo e integra a energia
  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);   // gravações limitadas protegem a flash
  }
}

Cada janela de medição bloqueia o loop por 200 ms, o que é inofensivo para os keep-alives do MQTT, porque o sketch chama mqtt.loop() logo após amostrar. Se você adicionar mais alicates, leia-os um após o outro na mesma passagem, ou mova a amostragem para uma tarefa FreeRTOS própria, como mostra o guia ESP32 FreeRTOS MQTT, para que o código de rede nunca espere atrás de uma longa série de janelas.

Testando e calibrando

Assine o topic:

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

Sem nada ligado, irms deve ler 0. Ligue uma carga resistiva conhecida, como uma chaleira ou um aquecedor, e compare irms com um alicate amperímetro no mesmo condutor. Ajuste CALIBRATION pela razão entre as duas leituras, por exemplo 1,04 se o ESP32 ler 4 por cento a menos. Calibre perto do meio da faixa do alicate para a melhor precisão geral.

O servidor MQTT público (gratuito) pode ser lido por qualquer pessoa, e padrões de consumo de energia podem revelar quando uma casa está ocupada, então use-o apenas para testes de bancada; a página dele lista seus limites.

O que os números significam

O sketch publica a potência aparente em volt-ampères, calculada a partir da corrente medida e de uma tensão de rede presumida. Para cargas resistivas como chaleiras e aquecedores, a potência aparente fica próxima da potência real em watts. Para motores, compressores, fontes e drivers de LED, o fator de potência é menor que 1, então a potência real é menor que o valor em VA. A tensão da rede também varia ao longo do dia.

A potência real exige também a medição da tensão, normalmente por um transformador CA-CA isolado alimentando um segundo pino do ADC, além da multiplicação amostra a amostra. É um próximo passo que vale a pena, mas a versão só com corrente já basta para ver qual aparelho funciona e quando, identificar cargas em standby e comparar dias.

Checklist de precisão

  1. Prenda o alicate em volta de um único condutor. Em volta do cabo inteiro, as correntes de fase e neutro se cancelam e a leitura fica perto de zero.
  2. Escolha a menor faixa de alicate que cubra sua corrente máxima.
  3. Mantenha os fios analógicos curtos e longe de antenas Wi-Fi e fontes chaveadas.
  4. Meça o ponto médio a cada janela em vez de presumir 1,65 V.
  5. Aplique um piso de ruído para que um circuito ocioso leia 0, e não algumas centenas de miliampères.
  6. Calibre com um medidor confiável usando uma carga resistiva.

Montando um dashboard de energia

Do lado de quem recebe, um assinante transforma as mensagens em gráficos. O MQTT consumer do Telegraf pode interpretar o JSON e gravá-lo no InfluxDB para o Grafana, o Node-RED pode calcular totais diários e custos, e o Home Assistant pode tratar energyKwh como um sensor de energia com uma definição de sensor MQTT. Todos eles se conectam ao broker como clientes MQTT comuns. Em uma planta industrial, por exemplo em Campinas ou Manaus, os mesmos topics podem alimentar um gêmeo digital de energia que compara o consumo de cada circuito. Se você monitora vários circuitos ou temperaturas ao mesmo tempo, combine este nó com o projeto com várias sondas DS18B20 ou leia medidores existentes com o gateway Modbus RS485 com ESP32.

Para produção, crie um broker em app.connectmq.com, mude para WiFiClientSecure na porta 8883 com o certificado ISRG Root X1 e conecte com YOUR_CLIENT_ID, YOUR_USERNAME e YOUR_PASSWORD. As regras de alerta por limite do portal do ConnectMQ podem então avisar quando a corrente ultrapassar um limite, como um circuito se aproximando da capacidade do disjuntor.

Comece com o ConnectMQ

Dados de energia valem mais quando são coletados continuamente e mantidos privados, ainda mais quando o consumo de uma residência identificada se torna dado pessoal sob a LGPD. O ConnectMQ é um broker MQTT gerenciado com TLS, MQTT 3.1.1 e 5.0, explorador de topics ao vivo e alertas, e o plano gratuito Serverless não exige cartão de crédito. Aponte este sketch para o seu broker e veja o hub do tutorial de IoT com ESP32 para mais projetos de medição.

Perguntas frequentes

O sensor de corrente SCT-013 com ESP32 mede a potência real em watts?

Apenas com a corrente, ele estima a potência aparente em VA. A potência real exige também a medição da tensão, para que o código considere o fator de potência.

Por que minha leitura mostra corrente sem nada ligado?

Isso é ruído do ADC e interferência captada. Aplique um piso de ruído, mantenha os fios curtos e confira se o capacitor do ponto médio está instalado.

Quais pinos do ESP32 posso usar com o SCT-013?

Use pinos do ADC1 (GPIO 32 a 39 em um ESP32 clássico). Os pinos do ADC2 não funcionam com o Wi-Fi ativo.

Preciso de um resistor de burden?

Apenas para o SCT-013-000, com saída em corrente. As versões com saída em tensão, como o SCT-013-030, têm burden embutido.

Artigos relacionados

Exemplo de MQTT com ESP-IDF: Monte um Cliente esp-mqtt do Zero

Monte um projeto ESP-IDF a partir de uma pasta vazia com o componente esp-mqtt: configuração do Wi-Fi em modo station, o handler de eventos MQTT, publicação e inscrição, propriedades do MQTT 5 e TLS com o bundle de certificados.

8 min de leitura

Usando os Recursos do MQTT 5 do esp-mqtt no ESP32 com ESP-IDF

Um projeto ESP-IDF prático que ativa o MQTT 5.0 no esp-mqtt e usa user properties, expiração de mensagens, topic aliases, expiração de sessão e response topics com um broker MQTT 5 real.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.