Mains Power/Energy Measurement with an ACS712
Posted: Fri Mar 30, 2018 6:25 am
Let me share some code from my project with you: the ACS712 is a hall effect current sensor that converts current values into voltage. Together with the ADC of the ESP8266 this can be used to build a power-meter for mains sockets.
I build this intermediate socket using an old remote switch case and an ACS712 sensor:
(Caution: Mains power here when connected, but the ACS712 has a galvanic separation of the measured current and the sensor voltage!)
The ACS712 has to be powered with 5V and its output is in the range from 0-5V (with a 0 offset of 2.5V, i.e. if there is no current, the output is 2.5V). Before feeding it into the ESP's ADC it has to be divided with two resistors (or a trim pots) to either 1:2 to 3.3V (for a modul like the Wemos that accepts 3.3V as max for the ADC) or 1:4 for a basic ESP that only accepts 1V.
If you are using WiFi (and on an ESP8266 you probably will do that), make sure to set wifi_set_sleep_type(NONE_SLEEP_T), otherwise the ADC will produce some more random noise - see this issue.
Now we are ready to measure: the sketch below will do the job for a ACS712 with max current of 5A and 230V. It computes the effective voltage by integrating over a multiple of the period and computes the current and the power consumption since the start of the sketch.
Expect a noise of about 1-2 Watts and a max range up to 2kW.
I build this intermediate socket using an old remote switch case and an ACS712 sensor:
(Caution: Mains power here when connected, but the ACS712 has a galvanic separation of the measured current and the sensor voltage!)
The ACS712 has to be powered with 5V and its output is in the range from 0-5V (with a 0 offset of 2.5V, i.e. if there is no current, the output is 2.5V). Before feeding it into the ESP's ADC it has to be divided with two resistors (or a trim pots) to either 1:2 to 3.3V (for a modul like the Wemos that accepts 3.3V as max for the ADC) or 1:4 for a basic ESP that only accepts 1V.
If you are using WiFi (and on an ESP8266 you probably will do that), make sure to set wifi_set_sleep_type(NONE_SLEEP_T), otherwise the ADC will produce some more random noise - see this issue.
Now we are ready to measure: the sketch below will do the job for a ACS712 with max current of 5A and 230V. It computes the effective voltage by integrating over a multiple of the period and computes the current and the power consumption since the start of the sketch.
Expect a noise of about 1-2 Watts and a max range up to 2kW.
Code: Select all
#include <ESP8266WiFi.h>
extern "C" {
#include "user_interface.h"
}
#define SUM_MAX 600
#define ADC_MAX 1024
int count = 0;
int adc_avr = 0;
uint16_t vals[ADC_MAX+1];
unsigned long time_m;
unsigned long time_mn;
float Ieff;
float P;
float W;
void setup() {
// initialize serial communication:
Serial.begin(115200);
//WiFi.mode(WIFI_OFF);
wifi_set_sleep_type(NONE_SLEEP_T);
Serial.println();
Serial.println();
delay(500);
time_m = millis();
}
void do_measurements(int n) {
uint16_t last_adc_read;
for (;n > 0; n--) {
count++;
if (count >= SUM_MAX) {
float U, Ueff;
float Sum_U_Square= 0.0;
count = 0;
adc_avr = adc_avr/SUM_MAX;
for (int i = 0; i < ADC_MAX+1; i++) {
if (vals[i] != 0) {
//Serial.print(i);Serial.print(": ");
//Serial.print(vals[i]);Serial.println(" ");
if (abs(i-adc_avr) > 2) {
U = ((float)(i - adc_avr))/1024 *5000;
Sum_U_Square += U*U*vals[i];
}
vals[i] = 0;
}
}
Ueff = sqrt(Sum_U_Square/SUM_MAX);
Ieff = Ueff/185.0;
P = Ieff*230;
time_mn = millis();
W += P * (time_mn - time_m)/3600000.0;
time_m = time_mn;
Serial.print(String(adc_avr)+" ");
Serial.print(String(Ueff)+"mV ");
Serial.print(String(Ieff)+"A ");
Serial.print(String(P)+"W ");
Serial.println(String(W)+"Wh");
adc_avr = 0;
}
last_adc_read = analogRead(A0);
if (last_adc_read > ADC_MAX) {
Serial.println("ADC error");
continue;
}
vals[last_adc_read]++;
adc_avr += last_adc_read;
delay(2);
}
}
void loop() {
do_measurements(50);
}