Meça qualquer tensão AC (250VAC) com ZMPT101B e ESP8266 12E com Android App / Adafruit IO MQTT

Tempo de leitura: 9 minutes

Olá a todos e bem vindos ao canal SurtrTech, este é um projeto sobre como medir qualquer tensão AC (até 250 VAC 50/60 Hz) usando o módulo ZMPT101B, e por qualquer estou falando sobre a forma do sinal, pois medindo um O sinal de onda senoidal é bastante simples, mas quando se trata de algumas formas estranhas como a de um triac, você precisa de um módulo e código especial como você verá aqui.

Este é um exemplo da forma do sinal quando você usa um Triac, aqui vou usar um dimmer de luz baseado em Triac, e em meu tutorial anterior, quando usei o Arduino, mostrei que o código que fiz teve um desempenho muito melhor do que um multímetro barato ou multímetros não TRMS.

Este é o módulo que estou usando, é chamado ZMPT101B, mas na verdade este é o nome do transformador (grande coisa azul), ele tem um amplificador LM358.

 

ZMPT101B

Dependendo de qual placa você está usando, a tensão de saída será diferente e também o deslocamento, para o Arduino os extremos foram 0 e 5V com um deslocamento de 2,5V.

Para o ESP8266, os extremos são 0 e 3,3 V com um deslocamento de 1,65 V.

Sinal ZMPT101B ESP8266

Por isso o módulo é bom, ele pega um sinal que vai queimar sua placa e adaptá-la sem perder sua forma, o que é muito importante para uma medição TrueRMS.

Sobre o poder!

Quando testei este módulo com a placa Arduino, ele estava muito estável porque estava usando 5V, mas quando o conectei com o ESP8266 12E, notei uma queda de tensão, por isso usei uma bateria Li e um conversor para manter a alimentação estável (3,3 VCC).

Bateria Li + conversor

Eu não sei, talvez porque eu tenha uma placa antiga (2017), ESP8266 12E (NodeMcu V1.0), ou a placa não está puxando energia suficiente do cabo USB…. mas se funciona para você, é praticamente a mesma coisa para esse tipo de placa, mesmo as de 5V.

 

Primeira calibração

Aqui, queremos calibrar nosso módulo primeiro, usando o potenciômetro embutido, para ajustar a amplificação do sinal.

Potenciômetro ZMPT101B

Como expliquei antes, teoricamente, o sinal de 250 VAC (RMS) deve ser reproduzido como um sinal que vai de 0 a 3,3V e centrado em torno de 1,65 V, o que significa que podemos explorar toda a faixa de ADC que é 0 – 1023, e isso será mais preciso para calcular os valores.

Mas infelizmente não podemos fazer isso, pois o sinal pode se perder em alguns pontos, então temos que reduzir a amplificação e ao invés de explorar todos os 0 – 3,3V teremos que trabalhar com um alcance menor, por isso usar placas de 5V é melhor.

 

Ligação

Aqui na fiação eu tenho o módulo conectado à placa e também tenho minha bancada de teste, eu escolhi medir a tensão de uma lâmpada incandescente conectada com um dimmer de luz baseado em Triac, você pode medir o que quiser.

Agora é só colocar a tensão MÁXIMA (sem ultrapassar 250VAC), no meu caso tenho em torno de 230V/50Hz, pode tirar direto da tomada ou depois de um dimmer de ciclo completo.

 

Código

Agora você carrega esse código e abre o Serial Plotter do Arduino IDE

void setup() {
  Serial.begin(115200);
  pinMode(A0,INPUT);
}
void loop() {
  Serial.println(analogRead(A0));
  //delay(100);
}

 

Calibration

Depois de abrir o Serial Plotter, você verá algumas formas passando.

Isso é o que você não quer: uma forma que tem uma linha reta horizontal nos extremos …

Isto é o que você precisa ver: Algum sinal do tipo onda senoidal, então continue girando seu potenciômetro até ver algo assim, e preste atenção aqui, você está controlando a amplificação do sinal, então você precisa ter os valores máximos sem perturbar as formas.

Depois de fazer isso, lembre-se de que você não deve continuar girando, pois isso afetará todos os cálculos futuros.

 

Medição e calibração True RMS

Aqui, veremos o código importante para medir o valor TRMS, mas ele deve ser calibrado primeiro e, depois de começar a medir “corretamente” os valores, você pode fazer o que quiser com seus valores: Envie-os via MQTT, crie um pequeno aplicativo, usar com Blynk….

Primeiro você deve colocar 0 VAC como a entrada do módulo, é claro que você pode manter a mesma Ligação.

Código

/* Este código funciona com sensor de tensão CA ESP8266 12E ou Arduino e ZMPT101B até 250 VAC 50/60 Hz
* Permite a medição do valor True RMS de qualquer sinal AC, não apenas a onda senoidal
* O código usa o método Sigma "Desvio padrão" e exibe o valor a cada "período de impressão"
*/
#include <Filters.h>                            // Biblioteca a ser usada

#define ZMPT101B A0                             // Entrada analógica

float testFrequency = 50;                     // teste de frequência do sinal (Hz)
float windowLength = 100/testFrequency;       // quanto tempo para calcular a média do sinal, para estatista, mudar isso pode ter um efeito drástico
                                              // Teste conforme necessário

int RawValue = 0;     
float Volts_TRMS;     // tensão real estimada em Volts

float intercept = 0;  // a ser ajustado com base no teste de calibração
float slope = 1;      

/* Como obter a interceptação e o declive? Primeiro, mantenha-os como acima, intercepte = 0 e declive = 1,
 * também abaixo continua exibindo valores calibrados e não calibrados para ajudá-lo neste processo.
 * Coloque a entrada AC como 0 Volts, carregue o código e verifique o monitor serial, normalmente você deve ter 0
 * se você vir outro valor e ele estiver estável, a interceptação será o oposto desse valor
 * Exemplo, você carrega pela primeira vez e então vê um 1,65 V estável, então a interceptação será -1,65
 * Para definir a inclinação agora, você precisa colocar a tensão em algo superior a 0 e medir isso usando seu multímetro TRMS de referência
 * carregue o novo código com a nova interceptação e verifique o valor exibido como valores calibrados
 * Slope = (Valores medidos pelo multímetro) / (Valores medidos pelo código)
 * Coloque sua nova inclinação e recarregue o código, se você tiver problemas com a calibração, tente ajustar os dois
 * ou adicione uma nova linha para calibrar ainda mais
 * Inclinação e interceptação não têm nada a ver com o cálculo do TRMS, é apenas um ajuste da linha de soluções
 */

unsigned long printPeriod = 1000; //A frequência de medição, a cada 1s, pode ser alterada
unsigned long previousMillis = 0;

RunningStatistics inputStats; //Esta classe coleta o valor para que possamos aplicar algumas funções

void setup() {
  Serial.begin(115200);    // inicie a porta serial
  Serial.println("Série iniciada");
  inputStats.setWindowSecs( windowLength );
}

void loop() {
                 
     ReadVoltage();   // A única função que estou executando, tome cuidado ao usar com este tipo de placa
                      // Não use atrasos muito longos ou loops infinitos dentro do loop
}

float ReadVoltage(){
    RawValue = analogRead(ZMPT101B);  // leia o valor analógico:
    inputStats.input(RawValue);       // logar na função de estatísticas
        
    if((unsigned long)(millis() - previousMillis) >= printPeriod) { //Calculamos e exibimos a cada 1s
      previousMillis = millis();   // tempo de atualização
      
      Volts_TRMS = inputStats.sigma()* slope + intercept;
//     Volts_TRMS = Volts_TRMS*0.979; // Calibração adicional, se necessário
      
      Serial.print("Não calibrado: ");
      Serial.print("\t");
      Serial.print(inputStats.sigma()); 
      Serial.print("\t");
      Serial.print("Calibrado: ");
      Serial.print("\t");
      Serial.println(Volts_TRMS);
    
  }
}

Este é o código que você pode usar primeiro para se familiarizar com a biblioteca, medição e calibração, não tem terceiros ou precisa estar conectado ao WiFi, tudo o que faz é medir os valores TRMS e exibi-los no o Serial Monitor e, claro, você pode recalibrar conforme necessário ao usar outras coisas.

Essas são basicamente as três partes importantes da calibração:

float windowLength = 100/testFrequency;       // quanto tempo para calcular a média do sinal, para estatista, mudar isso pode ter um efeito drástico
float intercept = 0; // a ser ajustado com base no teste de calibração 
float slope = 1;

Para o windowLength, com o Arduino usei “40/testFrequency” foi bom, mas com o ESP8266, o “100/testFrequency” deu melhores resultados, você pode tentar e ver o que mais lhe convém.

No momento, é melhor manter a interceptação e a inclinação como estão, e como você pode ver, eles não mudam o “Sigma” que é o que calculamos neste código.

Volts_TRMS = inputStats.sigma()* slope + intercept;

 

Resultado

Depois de fazer o upload do código, abra o monitor serial, não se esqueça de 0VAC como entrada.
Você verá algo assim:

Existem algumas flutuações, não é tão grande, normalmente se eu tivesse um valor estável como 1,88, a interceptação seria -1,88, então o que você precisa ver é 0 ou perto de 0. No meu caso eu mantive a interceptação como 0.

Agora coloque o valor de interceptação como você achou melhor e recarregue o código para o quadro.

Além disso, coloque a entrada CA em algum valor, por exemplo, o RMS da sua rede, meça usando o multímetro para obter o valor correto e abra novamente o monitor serial.

Esses são os valores que obtive em torno de “90,5” na calibração. (Eles são iguais porque a interceptação é 0).

Medido com o multímetro “228,6”.

Portanto, a inclinação será = 228,6/90,5

Aplique a nova inclinação ao código, você pode descartar o “valor não calibrado”.

Esta é praticamente a tarefa difícil e mais importante de se conseguir. Depois de conseguir isso, você pode adicionar algumas funções de WiFi ou Internet conforme desejar. Eu escolhi algumas para colocar aqui como exemplo.

 

Usando com Adafruit IO MQTT

Agora que você pode medir a tensão CA, você pode enviar esses valores para um terceiro, peguei aqui o Adafruit IO MQTT como exemplo.

Depois de fazer login lá, você deve ir para Feeds e criar um novo feed (preste atenção, não é ilimitado). Eu criei um feed e o chamei de “Teste”.

Lembre-se do nome, é importante!

Então você vai para Dashboards, cria um e adiciona um novo bloco, aqui eu adicionei um Gauge.

Cada medidor precisa de um feed, então você escolhe aquele que criou antes.

E você ajusta as configurações conforme necessário.

Agora que você está pronto para começar, tudo que você precisa são algumas bibliotecas e um código adequado.

 

Bibliotecas

É melhor ir para o Gerenciador de bibliotecas do IDE do Arduino e procurar por estas abaixo; se ele solicitar que você baixe algumas outras bibliotecas porque são essenciais, deixe-as instalá-las.

Código

/* Este código funciona com o sensor de tensão CA ESP8266 12E e ZMPT101B
 * Pode medir o TRMS de qualquer tensão até 250 VAC 50 / 60Hz e enviar os valores para Adafruit MQTT
 */
#include <ESP8266WiFi.h>                         // Bibliotecas necessárias
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT_Client.h>
#include <Filters.h>

#define WLAN_SSID       "xxxxxxxx"               // Seu SSID WiFi e senha
#define WLAN_PASS       "xxxxxxxx"

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883                  

#define AIO_USERNAME    "xxxxxxxxxx"               // Seu nome de usuário e chave Adafruit IO
#define AIO_KEY         "xxxxxxxxxxxxxxxxxxxxxxxx"

#define ZMPT101B A0                          //ZMPT101B analog pin
 
int Current_Time=0, Previous_Time=0, Period=10000;  //Enviamos um valor a cada 10s, o máximo é 30 valores por minuto

float testFrequency = 50;                    // frequência do sinal de teste (Hz)
float windowLength = 100/testFrequency;      // quanto tempo para calcular a média do sinal, para estatísticas

int RawValue = 0;

float intercept = 0; // a ser ajustado com base no teste de calibração
float slope = 1;     // a ser ajustado com base no teste de calibração
float Volts_TRMS;    // tensão real estimada em Volts

WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Publish Test = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Test");        //My feed name is "Test" so pay attention to yours, remplace it at the name and "/feeds/Test"
RunningStatistics inputStats;

void setup() {
  
  Serial.begin(115200);
  delay(10);
  inputStats.setWindowSecs( windowLength );
  Serial.println();
  Serial.print("Conectando à ");
  Serial.println(WLAN_SSID);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("Wi-Fi conectado");
  Serial.println("Endereço de IP: "); 
  Serial.println(WiFi.localIP());

}

void loop() {
  
  Volts_TRMS=ReadVoltage(); // Lemos a tensão, normalmente a função retorna o valor Volts_TRMS, você pode fazer isso diretamente no Test.publish
                            // Mas esta é a sintaxe que funcionou para mim, retorne um valor para ela mesma: D
  MQTT_connect();           // Mantenha o MQTT conectado
  Current_Time=millis();

  if(Current_Time - Previous_Time >= Period){  // A cada período enviamos o valor para o prestador de serviço
  Serial.print(F("\nEnvio de valor "));         // O valor também é mostrado no monitor serial
  Serial.print(Volts_TRMS);
  Serial.print("...");
  if (! Test.publish(Volts_TRMS)) {
    Serial.println(F("Fracassado"));
  } else {
    Serial.println(F("OK!"));
  }
  Previous_Time = Current_Time;
  
  }

}

void MQTT_connect() {                  // Reconectar automaticamente ao MQTT, caso contrário, ele acionará uma reinicialização do watchdog
  int8_t ret;

  // Pare se já estiver conectado.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Conectando ao MQTT ...");

  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // conectar retornará 0 para conectado
       Serial.println(mqtt.connectErrorString(ret));
       Serial.println("Tentando novamente a conexão MQTT em 5 segundos ...");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
       retries--;
       if (retries == 0) {
         // basicamente morrer e esperar que o WDT me reinicie
         while (1);
       }
  }
  Serial.println("MQTT conectado!");
}

float ReadVoltage(){
  
      RawValue = analogRead(ZMPT101B);  // leia o valor analógico:
      inputStats.input(RawValue);  // logar na função Stats
     
      Volts_TRMS = inputStats.sigma()* slope + intercept;
     // Volts_TRMS = Volts_TRMS*0.979;

      return Volts_TRMS;
       
}

 

Todos os Códigos destes projetos e as librarys no (arquivo)