Community
OpenEnergyMonitor

Community

ESP32+ADS1115+EmonLib Code Error Invalid Conversion from int

Greetings all. It’s been awhile since I posted, 3 years already, wow.

Anyways, the powermonitor I built those years ago has been faithfully chugging along giving reports.

Now I’m updating to use an esp32 and an ads1115 (actually 4) so I can add 16 sensors. I found the ads library from i2cdevlib, and also found the minor adjustment to the emonlib to allow for ads1115 redirects by following the post by PaulWieland on github.

So added the following code to the main:

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

Because I have an array for the ads:

ADS1115 ads[] = {0x48, 0x49, 0x4A, 0x4B};

I have to loop through them. I’m using the following:

int sensor = 0;
   for (int i = 0; i < ADC_COUNT; i++)
   {
     //e_monitor[i].current(SCT1_SensorPin, SCT1_CURRENT_CAL); // Current: input pin, calibration.
     for (int j = 0; j < 4; j++)
     {
       e_monitor[sensor++].inputPinReader = ads1115PinReader(i, j);
     }
   }

Problem is, I keep getting compile errors:

current-volt_sensor_esp32:107:60: error: invalid conversion from 'int' to 'EnergyMonitor::inputPinReaderMethod {aka int (*)(int)}' [-fpermissive]
 
        e_monitor[sensor++].inputPinReader = ads1115PinReader(i, j);
                                                             ^

I’m not sure what I need to do to fix this problem.
Any help, suggestions, better way to accomplish the task?

Thanks,
Kori

Edit - formatted text. BT, Moderator

Welcome back, Kori.

That error message tells me that you are trying to convert an integer value (which ads1115PinReader(i, j) undoubtedly is, into a pointer to a function - one that takes an integer as its only argument and returns an integer. And that doesn’t make sense.

I’ve no knowledge of the ADS library, nor the version of emonLib that you appear to be using; but surely, and assuming that ads1115PinReader( ) returns one instantaneous reading of the ADC, you should be using that method inside emonLib’s calcVI(...) in much the same way that analogRead( ) is used, and then picking up the value that emonLib has calculated, as in power = ct1.realpower?

I think you need to find some documentation about that version of emonLib and if there are examples, study and understand them.

Thanks Robert.

I’ve been fiddling with this, and I’m soooo confused as to what’s going on here. I created a new sketch in Arduino IDE to ‘only’ work with this specific code issue. Cut out all the other stuff to speed up compile times.

I looked into the EmonLib I2C variant to see what the changes were, and primarily this has been added:

EmonLib.cpp:

//--------------------------------------------------------------------------------------
// Constructor. Set the pinReader to the default pin reader method
//--------------------------------------------------------------------------------------
EnergyMonitor::EnergyMonitor()
{
  this->inputPinReader = defaultInputPinReader;
}

//--------------------------------------------------------------------------------------
// By default we just call Arduino's analogRead
//--------------------------------------------------------------------------------------
int EnergyMonitor::defaultInputPinReader(int _pin)
{
  return analogRead(_pin);
}

And this is added to the EmonLib.h in the public section:

EnergyMonitor(); 

typedef int (*inputPinReaderMethod) (int _pin);
inputPinReaderMethod inputPinReader;

static int defaultInputPinReader(int _pin);

There are a few other spots in the other functions that redirect the pin to the ads reference with the use of

(this->inputPinReader)(inPinV);

instead of

analogRead(inPinV);

I think that’s everything.

So I have this:

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

// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3

#include "EmonLib_I2C.h"                   // Include Emon Library
EnergyMonitor emon1[4];                   // 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(9600);
  
  emon1[1].inputPinReader = ads1115PinReader; // Replace the default pin reader with the customized ads pin reader
  emon1[1].current(1, 111.1);             // Current: input pin, calibration.
}

I created an array on the emon to verify that wasn’t the issue. Worked as expected. Compiles clean.
But as soon as I change
emon1[1].inputPinReader = ads1115PinReader;
to
emon1[1].inputPinReader = ads1115PinReader(1);

I get the error. I don’t understand it. Also I don’t understand why the variable can be blank and it works when the function declaration has a variable in it ???

I hope this helps a little bit. I want to get this working so I can build my next version of the Power Monitor and get more detailed stats.

Thanks,
Kori

Sorry, but there’s not enough there for me to see what’s going on. I think you need to go back to the creator of that version and ask them how to use it.

I would assume considering this is a coding issue, it should be able to be diagnosed by anyone who is knowledgeable about programming in this language (unfortunately I am not). I have tried to contact Paul Wieland via his GitHub repo, but there is no option to do so. I have no idea how to contact him, and right in the documentation he refers to openenergymonitor as the community to go to for help.

My background is in basic arduino code, and college for Visual Basic. Getting into C++ or derivatives and classes is beyond my skill set. However, I am always open to learn new tasks, and I generally scour google search to find an answer. Problem is, I don’t always know the proper terminology to search for so results can be quite daunting at times.

As far as I know, all the relevant code I have included. I also included the links to the source code if more information is needed. If there is something beyond that I need to provide, please ask and I will try to provide it.

That is a very hopeful and misguided attitude. Bear in mind this isn’t a paid helpdesk, neither I nor anyone else here is under any obligation to help you, despite what the creator of the stuff you’re trying to use thinks.

Where? I can’t see any.

No, you have not. You have provided snippets, with no context, that leave me to guess what the rest looks like.

It would have been helpful to provide a link to, or a copy of, the relevant libraries in their complete form, instead of snippets.

I can’t find a name remotely like that in out list of members. In all honesty, he’s created the software so it’s his responsibility to maintain it.
We can certainly help with emonLib, but unless you can provide the “altered” version, nobody can guess what he done to it. Even then, we cannot know what was in his brain and what the intentions are.

If you’re prepared to cooperate instead of getting up on your high horse and thinking that the world owes you a living, then I’m prepared to help you with this and in the process, help you learn. Otherwise, you need to figure it out for yourself or find another way to solve your problem.

I thought I had provided the links.



I was using this ADS library, but switched back the Arduino_ADS1105 Library and still get the same problem

PaulWieland has made the EmonLib available to be used with external ADC’s instead of relying on the MCU’s built in one.

I have also read this thread:
ADS1115 and sampling speed in hopes that it would help me figure out the problem. Which, you have participated in multiple times. So I know you are aware of this modification.

I’m not expecting someone to hand feed me the correct code. I want to understand what’s going on here as i can’t seem to find the right info. I don’t know why it works one way and not the other. It’s confusing to me.

I’m not on any high horse, nor have I acted like it in any fashion, and nor do I expect the world owes me anything. I don’t where you got that idea from because it was not in my context, words, or insinuation.
I know that you, Robert Wall, are not the only person on this forum. There are tons of others, those who work for, volunteer for, OpenEnergyMonitor, and there are plenty of those who are working on various other projects that don’t work for, volunteer for, them

Please let me know if there’s more I need to add.

I think you need to read up on C function pointers.

this->inputPinReader = defaultInputPinReader;

That is assigning a function to a function pointer. It’s not calling the function (that will happen later) so no arguments are passed.

(this->inputPinReader)(inPinV);

That is calling the function - whichever function was previously assigned to the function pointer, so that’s when you need to pass an argument.

emon1[1].inputPinReader = ads1115PinReader;

That makes sense… it’s assigning a function to a function pointer.

emon1[1].inputPinReader = ads1115PinReader(1);

That doesn’t make sense. The RHS of the assignment is actually calling the function and so returning a reading. You’re then trying to assign that reading to a function pointer. That’s what the compiler is complaining about. You can only assign functions to function pointers, not results from a function call.

Ohhhhh, ok. Thanks dBC. I didn’t know it was a function re-assignment call.

Ok, so now to try a different way to call the values.

Ok, so I’ve made some progress. While combing through the code, I realized that emon.current(pin, calibration) was going to point to the same ADC as emon.voltage(pin, calibration).
So I had to add some more function calls.

This is what I’ve come up with so far:

main.cpp:

ADS1115 adc_0(0x48);
ADS1115 adc_1(0x49);
ADS1115 adc_2(0x4A);
ADS1115 adc_3(0x4B);

EnergyMonitor emon[4];

int adc_0_CurrentPin(int _pin) {  return adc_0.readADC_SingleEnded(_pin);  }
int adc_1_CurrentPin(int _pin) {  return adc_1.readADC_SingleEnded(_pin);  }
int adc_2_CurrentPin(int _pin) {  return adc_2.readADC_SingleEnded(_pin);  }
int adc_3_CurrentPin(int _pin) {  return adc_3.readADC_SingleEnded(_pin); }

int adc_VoltPin(int _pin) {  return adc_0.readADC_SingleEnded(_pin); }


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

  if (initializeADC(adc_0)) {
	 emon[0].inputCurrentPin = adc_0_CurrentPin;
	 emon[0].current(3, 111.1);              // Current: input pin, calibration.
	 emon[1].inputCurrentPin = adc_0_CurrentPin;
	 emon[1].current(4, 111.1);              // Current: input pin, calibration.
  }
  if (initializeADC(adc_1)) {
	emon[2].inputCurrentPin = adc_1_CurrentPin;
	emon[2].current(0, 111.1);              // Current: input pin, calibration.
	emon[3].inputCurrentPin = adc_1_CurrentPin;
	emon[3].current(1, 111.1);              // Current: input pin, calibration.
	emon[4].inputCurrentPin = adc_1_CurrentPin;
	emon[4].current(2, 111.1);              // Current: input pin, calibration.
	emon[5].inputCurrentPin = adc_1_CurrentPin;
	emon[5].current(3, 111.1);              // Current: input pin, calibration.
 }
  for (int i = 0; i < 16; i++){
	emon[i].inputVoltagePin = adc_VoltPin;
	emon[i].voltage(2, 186.1, 1.7);         // Voltage: input pin, calibration, phase_shift
  }
}

emonlib.cpp:

EnergyMonitor::EnergyMonitor()
{
  this->inputCurrentPin = defaultInputCurrentPin;
  this->inputVoltagePin = defaultInputVoltagePin;
}
int EnergyMonitor::defaultInputCurrentPin(int _pin)
{
  return analogRead(_pin);
}
int EnergyMonitor::defaultInputVoltagePin(int _pin)
{
  return analogRead(_pin);
}

Changed all inputPinV references to the inputVoltagePin and inputPinI to inputCurrentPin

sampleV = (this->inputVoltagePin)(inPinV);
sampleI = (this->inputCurrentPin)(inPinI);

emonlib.h:

typedef int (*inputCurrentPinMethod) (int _pin);
inputCurrentPinMethod inputCurrentPin;    
static int defaultInputCurrentPin(int _pin);

typedef int (*inputVoltagePinMethod) (int _pin);
inputVoltagePinMethod inputVoltagePin;    
static int defaultInputVoltagePin(int _pin);

So far it compiles clean. I haven’t finished building the hardware to see if it works in real world. Hopefully someone can do a glance over the code to see if I missed something, or if I need to add some more details for clarity.
I’d like to make this all available for anyone else who would like to do something similar, so I want the code to be clean, not hacked together and barely working. So any help is appreciated.

Kori