openenergymonitor / EmonLib

Electricity monitoring library - install in Arduino IDE's libraries folder then restart the IDE
openenergymonitor.org
GNU Affero General Public License v3.0
584 stars 418 forks source link

Emonlib+Esp32+ADS1115 outputting inconsistant data #61

Open korishan opened 4 years ago

korishan commented 4 years ago

I did get it to work, by rewriting the emonlib library, but it was crontoversly to say at least. But it works perfectly, it still is measuring the current. The reason I used the ADS1115 was indeed the ESP. I used the Nodemcu board and could use the extra current sensors.

Originally posted by @SybrenV in https://github.com/openenergymonitor/EmonLib/issues/23#issuecomment-381682062

How were you able to get it working properly??

I have the hardware implemented, and under standard testing (only using an ADS1115 based sketch) the values work fine. However, when using the Emonlib w/ ADS support that Paul provided, I get invalid data.

I have changed the files to EmonLib_I2C considering that's what it's for. This way I don't get conflicts with ArduinoIDE.

#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include "EmonLib_I2C.h"                   // Include Emon Library
EnergyMonitor emon1;                   // Create an instance

Adafruit_ADS1115 ads;                  // Create an instance of the ADS1115 object

// Make a callback method for reading the pin value from the ADS instance
int ads1115PinReader(int _pin){
  return ads.readADC_SingleEnded(_pin);
}

void setup()
{  
  Serial.begin(115200);

  emon1.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
  emon1.current(3, 111.1);             // Current: input pin, calibration.
}

void loop()
{
  double Irms1 = emon1.calcIrms(250);  // Calculate Irms only

  Serial.print("E1: ");
  emon1.serialprint();
}

Unfortunately, this is the output I get:

E1: 0.00 0.00 0.00 20696.53 0.00 
E1: 0.00 0.00 0.00 16211.26 0.00 
E1: 0.00 0.00 0.00 12698.02 0.00 
E1: 0.00 0.00 0.00 9946.16 0.00 
E1: 0.00 0.00 0.00 7790.67 0.00 
E1: 0.00 0.00 0.00 6102.30 0.00 
E1: 0.00 0.00 0.00 4779.84 0.00 
E1: 0.00 0.00 0.00 3743.97 0.00 
E1: 0.00 0.00 0.00 2932.59 0.00 
E1: 0.00 0.00 0.00 2297.05 0.00 
E1: 0.00 0.00 0.00 1799.24 0.00 
E1: 0.00 0.00 0.00 1409.32 0.00 
.........
E1: 0.00 0.00 0.00 1.18 0.00 
E1: 0.00 0.00 0.00 0.93 0.00 
E1: 0.00 0.00 0.00 0.73 0.00 
E1: 0.00 0.00 0.00 0.57 0.00 
E1: 0.00 0.00 0.00 0.44 0.00 
E1: 0.00 0.00 0.00 0.35 0.00 
E1: 0.00 0.00 0.00 0.27 0.00 
E1: 0.00 0.00 0.00 0.21 0.00 
E1: 0.00 0.00 0.00 0.17 0.00 
E1: 0.00 0.00 0.00 0.13 0.00 
E1: 0.00 0.00 0.00 0.10 0.00 
E1: 0.00 0.00 0.00 0.08 0.00 
E1: 0.00 0.00 0.00 0.06 0.00 
E1: 0.00 0.00 0.00 0.05 0.00 
E1: 0.00 0.00 0.00 0.04 0.00 
E1: 0.00 0.00 0.00 0.03 0.00 
E1: 0.00 0.00 0.00 0.02 0.00 
E1: 0.00 0.00 0.00 0.02 0.00 
E1: 0.00 0.00 0.00 0.01 0.00 
E1: 0.00 0.00 0.00 0.01 0.00 
E1: 0.00 0.00 0.00 0.01 0.00 
E1: 0.00 0.00 0.00 0.01 0.00 
E1: 0.00 0.00 0.00 0.01 0.00 
E1: 0.00 0.00 0.00 0.00 0.00 

It just slowly goes cycles down to "0" and then stays there. It doesn't matter if I have a current load or not. And no, I don't have an external voltage reading of the mains line. It shouldn't matter for reading "current_only", correct? It would only be used during realpower calculations I would think.

But if I run the ADC only code, I get these values:

ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115)
AIN0    AIN1    AIN2    AIN3
770 0   771 0
773 0   771 0
770 0   767 0
773 0   1110    0   ---- Turned on load here
774 0   546 0
774 0   1147    0
775 0   450 0
770 0   818 0
773 0   947 0   ---- Turned off load here
769 0   771 0
773 0   772 0
773 0   772 0

Code:


#include <Wire.h>
#include <Adafruit_ADS1015.h>

// Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
Adafruit_ADS1015 ads;     /* Use thi for the 12-bit version */

void setup(void) 
{
  Serial.begin(115200);
  Serial.println("Hello!");

  Serial.println("Getting single-ended readings from AIN0..3");
  Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115)");
  ads.begin();
}

void loop(void) 
{
  int16_t adc0, adc1, adc2, adc3;

  adc0 = ads.readADC_SingleEnded(0);
  adc1 = ads.readADC_SingleEnded(1);
  adc2 = ads.readADC_SingleEnded(2);
  adc3 = ads.readADC_SingleEnded(3);
  Serial.print(adc0);
  Serial.print("\t");
.......
}

Thanks, Kori
sultanfikri commented 3 years ago

i hope this proble get solved

persistive commented 3 years ago

Finally i got it to work, thanks to all contributes here and on other forums. I am using a ESP32 NodeMCU board, ADS1015, SCT013-15 CT and a 0.96"oled display. I found out that the ADC1015 is much faster than the ADC1115. Serial communication is disturbing the current reading so i left that out. I calibrated the unit with an function generator and did some comparison with know loads. The overall performance is in my opinion very good.

For who is interesting hereby my code:

// In this example we will use an ADS1115 breakout board instead of the Arduino's local analog inputs // This is especially useful for nodemcu/esp8266 users who only have a single analog input

include

include

include "SSD1306Wire.h"

SSD1306Wire display(0x3c,21,22); // EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

include "EmonLib.h" // Include Emon Library

EnergyMonitor emon1; // Create an instance EnergyMonitor emon2; // Create an instance EnergyMonitor emon3; // Create an instance EnergyMonitor emon4; // Create an instance

//Adafruit_ADS1115 ads; // Create an instance of the ADS1115 object Adafruit_ADS1015 ads; / Use this for the 12-bit version / // Make a callback method for reading the pin value from the ADS instance int ads1115PinReader(int _pin){ return ads.readADC_SingleEnded(_pin); } void setup() {
display.init(); display.flipScreenVertically(); display.setFont(ArialMT_Plain_10); display.drawString(0, 0, "Welcome"); display.drawString(0, 12, "PowerMeter starting up"); display.drawString(0, 24, "Calibrated for"); display.drawString(0, 36, "230VAC and max. 15A"); display.drawString(0, 48, "One moment please..."); display.display(); delay(3000); //Serial.begin(9600); // The ADC input range (or gain) can be changed via the following // functions, but be careful never to exceed VDD +0.3V max, or to // exceed the upper and lower limits if you adjust the input range! // Setting these values incorrectly may destroy your ADC! // ADS1015 ADS1115 // ------- ------- // ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default) ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV // ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV // ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV // ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV // ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV

ads.begin();

emon1.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader emon1.current(0, 9.35); // Current: input pin1, calibration. emon2.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader emon2.current(1, 9.35); // Current: input pin2, calibration. emon3.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader emon3.current(2, 9.35); // Current: input pin3, calibration. emon4.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader emon4.current(3, 9.35); // Current: input pin4, calibration. }

void loop() { double Irms1 = emon1.calcIrms(1480); // Calculate Irms only int Prms1 = Irms1230; double Irms2 = emon2.calcIrms(1480); // Calculate Irms only int Prms2 = Irms2230; double Irms3 = emon3.calcIrms(1480); // Calculate Irms only int Prms3 = Irms3230; double Irms4 = emon4.calcIrms(1480); // Calculate Irms only int Prms4 = Irms4230; //Serial.print(Prms1); // Apparent power //Serial.print(" "); //Serial.println(Irms1); // Irms display.clear(); display.drawString(0, 0, "Ch1: "); display.drawString(25, 0, String(Irms1)); // Displays all current data display.drawString(55, 0, "A"); display.drawString(70, 0, String(Prms1)); // Displays all power data display.drawString(100, 0, "W");

display.drawString(0, 15, "Ch2: "); display.drawString(25, 15, String(Irms2)); // Displays all current data display.drawString(55, 15, "A"); display.drawString(70, 15, String(Prms2)); // Displays all power data display.drawString(100, 15, "W");

display.drawString(0, 30, "Ch3: "); display.drawString(25, 30, String(Irms3)); // Displays all current data display.drawString(55, 30, "A"); display.drawString(70, 30, String(Prms3)); // Displays all power data display.drawString(100, 30, "W");

display.drawString(0, 45, "Ch4: "); display.drawString(25, 45, String(Irms4)); // Displays all current data display.drawString(55, 45, "A"); display.drawString(70, 45, String(Prms4)); // Displays all power data display.drawString(100, 45, "W"); display.display(); }

thijstriemstra commented 3 years ago

thanks for sharing @persistive

How did you connect the SCT013-15 CT to the ADS1015? Any other components needed? Any chance you have a fritzing sketch?

Looks like the SCT-013 has a mini jack plug, I guess a breadboard stereo audio jack would do?

breadboard-audio-jack-18-35mm-stereo

sultanfikri commented 3 years ago

thanks @persistive But in my opinion, if we use ESP32, it is better to directly use ESP32 internal ADC instead of External ADC like ADS1115

bytheway, it's worked! NodemCU with ADS1115, but strangely it worked when I used "Adafruit_ADS1015 ads;", i don't know why ...

persistive commented 3 years ago

I use the ADS1015 because the ADCs on the ESP are not reliable. Not only are the ADCs not lineair, they also are quite sensitive for noise. Using the (cheap) ADS1015 will give a good lineair signal. Do not use the ADS1115, although the higher bandwith (16 bits) looks beter then the 12 bits of the ADC1015, the 1115 is very slow resulting in slow updates of your readings. Furthermore the 16 bits is really 15 bits because you use it in single ended mode. @Thijstiemstra: indeed i used those connectors, but i used the ones that are connecting the centerpin to ground when the CT plug is not inserted. This will avoid noise on the not used channels. Just connect the CT with the two 10k resistors and a 10uF or so capacitor to create a 1,65 volt base voltage. Take a look at https://www.instructables.com/Simple-Arduino-Home-Energy-Meter for a good example. I also added wifi for communication with my domoticz system. What i saw is that the wifi signal is disturbing the power readings. To overcome that problem i switch wifi off after sending the average value of the four channels to domoticz and turn it on at the moment i send the new values. Still have a misreading of 1 or 2 watts power peaks, but i can live with that.

thijstriemstra commented 3 years ago

Do not use the ADS1115, although the higher bandwith (16 bits) looks beter then the 12 bits of the ADC1015, the 1115 is very slow resulting in slow updates of your readings.

What arduino package do you use for reading the ADS? Could be the bottleneck as well? I have good results with https://github.com/wollewald/ADS1115_WE

persistive commented 3 years ago

I use the Adafruit_ADS1X15-master library. Using the ADS1015 is much faster in my setup. According adafruit: These two boards are very similar, differing only in resolution and speed. The ADS1115 has higher resolution and the ADS1015 has a higher sample rate.

GianRickes commented 2 years ago

Hello.. I'm trying to implement it, but I have an error.. 'class EnergyMonitor' has no member named 'inputPinReader'

I'm not finding the problem. The code:

include

include

include

EnergyMonitor emon1;
Adafruit_ADS1115 ads; // Create an instance of the ADS1115 object

int ads1115PinReader(int _pin){ return ads.readADC_SingleEnded(_pin); }

void setup(){ Serial.begin(9600); ads.begin(); emon1.inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader emon1.current(0, 23.4);
}

void loop(){ double Irms = emon1.calcIrms(1996); // Calculate Irms only

Serial.print("Current: "); Serial.print(Irms, 3); Serial.println(" A"); }

GianRickes commented 2 years ago

I believe I have a problem with EmonLib.. now I used.. https://github.com/PaulWieland/EmonLib ...and I'm still having problems.. image

Can you share Adafruit and EmonLib library?