Hi
I picked up a sct013 100A current clamp and a ads1115 for a homebrew powermonitor system using a pico/arduino.
I followed the write up by https://solarduino.com/diy-ac-energy-meter/ and this forum thread: https://forum.arduino.cc/t/solved-how-ac-current-can-connect-to-ads1115/953906 but the reading I'm getting out seem to be wrong or wrong accoring to my current meter.
I am using 2.5V to power the sct013 so in theory my lowest reading should be 0V and my highest 5V. Firstly is this wrong and secondly if someone could just go through my code and point out where my calculation is whack that would be great
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
/* 0- General */
Adafruit_ADS1115 ads1115_1;
Adafruit_ADS1115 ads1115_2;
const byte PICO_I2C_SDA = 16;
const byte PICO_I2C_SCL = 17;
int timeOut = 0;
int decimalPrecision = 1; // decimal places for large values such as voltage, wattage, apparent power, and frequency shown in LED Display & Serial Monitor
// decimal places for small values such as current, power factor and accumulate energy will be decimal places x 2.
/* 1- AC Voltage Measurement */
float voltageSampleRead = 0; /* to read the value of a sample*/
float voltageLastSample = 0; /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float voltageSampleSum = 0; /* accumulation of sample readings */
float voltageSampleCount = 0; /* to count number of sample. */
float voltageMean ; /* to calculate the average value from all samples*/
float RMSVoltageMean ; /* square roof of voltageMean*/
/*1.1 Offset AC Voltage */
float voltageOffset1 = 0; // to Offset deviation and accuracy. Offset any fake current when no current operates.
// Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
// If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
float voltageOffset2 = 0; // to offset value due to calculation error from squared and square root.
/* 2- AC Current Measurement */
float mVperAmpValue = 31.25; // If using ACS712 current module : for 5A module key in 185, for 20A module key in 100, for 30A module key in 66
// If using "Hall-Effect" Current Transformer, key in value using this formula: mVperAmp = maximum voltage range (in milli volt) / current rating of CT
/* For example, a 20A Hall-Effect Current Transformer rated at 20A, 2.5V +/- 0.625V, mVperAmp will be 625 mV / 20A = 31.25mV/A */
float currentSampleRead_1 = 0; /* to read the value of a sample*/
float currentLastSample_1 = 0; /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float currentSampleSum_1 = 0; /* accumulation of sample readings */
float currentSampleCount_1 = 0; /* to count number of sample. */
float currentMean_1 ; /* to calculate the average value from all samples*/
float RMSCurrentMean_1 =0 ; /* square roof of currentMean*/
float FinalRMSCurrent_1 ; /* the final RMS current reading*/
/*2.1 Offset AC Current */
float currentOffset1_1 = 0; // to Offset deviation and accuracy. Offset any fake current when no current operates.
// Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
// If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
// 26 means add 26 to all analog value measured
float currentOffset2_1 = 0; // to offset value due to calculation error from squared and square root.
float currentSampleRead_2 = 0; /* to read the value of a sample*/
float currentLastSample_2 = 0; /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float currentSampleSum_2 = 0; /* accumulation of sample readings */
float currentSampleCount_2 = 0; /* to count number of sample. */
float currentMean_2 ; /* to calculate the average value from all samples*/
float RMSCurrentMean_2 =0 ; /* square roof of currentMean*/
float FinalRMSCurrent_2 ; /* the final RMS current reading*/
/*2.1 Offset AC Current */
float currentOffset1_2 = 0; // to Offset deviation and accuracy. Offset any fake current when no current operates.
// Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
// If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
// 26 means add 26 to all analog value measured
float currentOffset2_2 = 0; // to offset value due to calculation error from squared and square root.
float currentSampleRead_3 = 0; /* to read the value of a sample*/
float currentLastSample_3 = 0; /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float currentSampleSum_3 = 0; /* accumulation of sample readings */
float currentSampleCount_3 = 0; /* to count number of sample. */
float currentMean_3 ; /* to calculate the average value from all samples*/
float RMSCurrentMean_3 =0 ; /* square roof of currentMean*/
float FinalRMSCurrent_3 ; /* the final RMS current reading*/
/*2.1 Offset AC Current */
float currentOffset1_3 = 0; // to Offset deviation and accuracy. Offset any fake current when no current operates.
// Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
// If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
// 26 means add 26 to all analog value measured
float currentOffset2_3 = 0; // to offset value due to calculation error from squared and square root.
/* 5- frequency measurement */
unsigned long startMicros; /* start counting time for frequency (in micro seconds)*/
unsigned long currentMicros; /* current counting time for frequency (in micro seconds) */
int expectedFrequency = 46; // This is to collect number of samples. for 50Hz use 46 or below. For 60Hz use 54 or below.
float frequencySampleCount = 0; /* count the number of sample, 1 sample equivalent to 1 cycle */
float frequency = 0; /* shows the value of frequency*/
float switch01 = 9; /* use for switching function */
float vAnalogRead = 0;
float zz; /* use for calculation purpose*/
/* 5- wifi stuff */
const char* ssid = ""; /*SSID of the network being connected to*/
const char* password = ""; /*Password of the network being connected to*/
float lastReadingSent = 0; /* to count time for reading send. Reading sent every 30000 milliseconds*/
char * deviceName = "";
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
void setup() /*codes to run once */
{
/* 0- General */
Serial.begin(115200);
Wire.setSDA(PICO_I2C_SDA);
Wire.setSCL(PICO_I2C_SCL);
Wire.begin();
ads1115_1.begin(0x48);
ads1115_2.begin(0x49);
WiFi.setHostname("Power_Pico");
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
timeOut = timeOut + 1;
if(timeOut >= 30)
{
watchdog_reboot(0,0,300);
}
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
startMicros = micros();
}
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
void loop()
{
/* 1- AC Voltage Measurement */
if(millis() >= voltageLastSample + 10) /* every 1 milli second taking 1 reading */
{
voltageSampleRead = 2*(ads1115_2.readADC_SingleEnded(2)- 32768) + voltageOffset1; /* read the sample value */
voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ; /* accumulate value with older sample readings*/
voltageSampleCount = voltageSampleCount + 1; /* to move on to the next following count */
voltageLastSample = millis() ; /* to reset the time again so that next cycle can start again*/
}
if(voltageSampleCount == 100) /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
{
voltageMean = voltageSampleSum/voltageSampleCount; /* calculate average value of all sample readings taken*/
RMSVoltageMean = sqrt(voltageMean)+ voltageOffset2; /* square root of the average value*/
Serial.print(RMSVoltageMean,decimalPrecision);
Serial.print(" V ");
voltageSampleSum =0; /* to reset accumulate sample values for the next cycle */
voltageSampleCount=0; /* to reset number of sample for the next cycle */
}
/* 2- AC Current Measurement */
if(millis() >= currentLastSample_1 + 10) /* every 1 milli second taking 1 reading */
{
currentSampleRead_1 = ads1115_1.readADC_SingleEnded(0) - 32768 + currentOffset1_1; /* read the sample value */
currentSampleSum_1 = currentSampleSum_1 + sq(currentSampleRead_1) ; /* accumulate value with older sample readings*/
currentSampleCount_1 = currentSampleCount_1 + 1; /* to move on to the next following count */
currentLastSample_1 = millis(); /* to reset the time again so that next cycle can start again*/
}
if(currentSampleCount_1 == 100) /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
{
currentMean_1 = currentSampleSum_1/currentSampleCount_1; /* calculate average value of all sample readings taken*/
RMSCurrentMean_1 = sqrt(currentMean_1)+currentOffset2_1 ; /* square root of the average value*/
FinalRMSCurrent_1 = (((RMSCurrentMean_1 /1024) *5000) /mVperAmpValue); /* calculate the final RMS current*/
Serial.print("Phase 1 ");
Serial.print(FinalRMSCurrent_1,decimalPrecision*2);
Serial.println(" A ");
currentSampleSum_1 =0; /* to reset accumulate sample values for the next cycle */
currentSampleCount_1=0; /* to reset number of sample for the next cycle */
}
/* 3- AC Current Measurement */
if(millis() >= currentLastSample_2 + 10) /* every 1 milli second taking 1 reading */
{
currentSampleRead_2 = ads1115_1.readADC_SingleEnded(1) - 32768 + currentOffset1_2; /* read the sample value */
currentSampleSum_2 = currentSampleSum_2 + sq(currentSampleRead_2) ; /* accumulate value with older sample readings*/
currentSampleCount_2 = currentSampleCount_2 + 1; /* to move on to the next following count */
currentLastSample_2 = millis(); /* to reset the time again so that next cycle can start again*/
}
if(currentSampleCount_2 == 100) /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
{
currentMean_2 = currentSampleSum_2/currentSampleCount_2; /* calculate average value of all sample readings taken*/
RMSCurrentMean_2 = sqrt(currentMean_2)+currentOffset2_2 ; /* square root of the average value*/
FinalRMSCurrent_2 = (((RMSCurrentMean_2 /1024) *5000) /mVperAmpValue); /* calculate the final RMS current*/
Serial.print("Phase 2 ");
Serial.print(FinalRMSCurrent_2,decimalPrecision*2);
Serial.println(" A ");
currentSampleSum_2 =0; /* to reset accumulate sample values for the next cycle */
currentSampleCount_2=0; /* to reset number of sample for the next cycle */
}
/* 4- AC Current Measurement */
if(millis() >= currentLastSample_3 + 1) /* every 1 milli second taking 1 reading */
{
currentSampleRead_3 = ads1115_1.readADC_SingleEnded(2) - 32768 + currentOffset1_3; /* read the sample value */
currentSampleSum_3 = currentSampleSum_3 + sq(currentSampleRead_3) ; /* accumulate value with older sample readings*/
currentSampleCount_3 = currentSampleCount_3 + 1; /* to move on to the next following count */
currentLastSample_3 = millis(); /* to reset the time again so that next cycle can start again*/
}
if(currentSampleCount_3 == 1000) /* after 1000 count or 1000 milli seconds (1 second), do the calculation and display value*/
{
currentMean_3 = currentSampleSum_3/currentSampleCount_3; /* calculate average value of all sample readings taken*/
RMSCurrentMean_3 = sqrt(currentMean_3)+currentOffset2_3 ; /* square root of the average value*/
FinalRMSCurrent_3 = (((RMSCurrentMean_3 /1024) *5000) /mVperAmpValue); /* calculate the final RMS current*/
Serial.print("Phase 3 ");
Serial.print(FinalRMSCurrent_3,decimalPrecision*2);
Serial.println(" A ");
currentSampleSum_3 =0; /* to reset accumulate sample values for the next cycle */
currentSampleCount_3=0; /* to reset number of sample for the next cycle */
}
sendReading(deviceName, RMSVoltageMean, FinalRMSCurrent_1, FinalRMSCurrent_2, FinalRMSCurrent_3, lastReadingSent);
}
/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/
void sendReading(char * deviceName, float RMSVoltageMean, float FinalRMSCurrent_1, float FinalRMSCurrent_2, float FinalRMSCurrent_3, float & lastReadingSent)
{
const char* serverName = "";
if(millis() >= lastReadingSent + 60000 ) /* every 30000 milli seconds sending 1 reading */
{
if(WiFi.status()== WL_CONNECTED)
{
WiFiClient client;
HTTPClient http;
http.begin(client, serverName);
http.addHeader("Content-Type", "application/json");
String httpRequestData = "{\"deviceName\":\"" + String(deviceName) + "\",\"RMSVoltage\":" + String(RMSVoltageMean,decimalPrecision*2) +
",\"RMSCurrentP1\":" + String(FinalRMSCurrent_1,decimalPrecision*2) +
",\"RMSCurrentP2\":" + String(FinalRMSCurrent_2,decimalPrecision*2) +
",\"RMSCurrentP3\":" + String(FinalRMSCurrent_3,decimalPrecision*2) + "}";
Serial.println(httpRequestData);
int httpResponseCode = http.POST(httpRequestData);
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
Serial.println();
http.end(); /*Free Up resources*/
}
else
{
Serial.println("WiFi Disconnected");
timeOut = timeOut + 1;
if(timeOut >= 30)
{
watchdog_reboot(0,0,300);
}
}
lastReadingSent = millis() ; /* to reset the time again so that next cycle can start again*/
}
}