xoseperez / hlw8012

HLW8012 library for Arduino and ESP8266 using the Arduino Core for ESP8266.
GNU General Public License v3.0
126 stars 48 forks source link

Multiple instances of HLW8012 class with interrupts? #25

Closed joshuaboniface closed 3 years ago

joshuaboniface commented 3 years ago

So I've been digging into this for a while now, and I'm trying to come up with a good solution but am currently stumped, and figured I'd go right to the source.

I have a project where I want to attach more than one HLW8012 board/chip to a single Arduino, then every interval return the values for all of them. In short, a PDU, more than a single smart plug. And for the sake of argument I have an Arduino with at least 4 PWM inputs (so not an Uno). So I create an array of instances of the HLW8012 class inside a simple struct like so:

struct Sensor {
    String   label;              // Sensor label/name
    HLW8012* hlw;                // Class instance of HLW8012 library
    int      sel_pin;            // Digital output pin for sel
    int      cf1_pin;            // Digital PWM-capable input pin for cf1
    int      cf_pin;             // Digital PWM-capable input pin for cf
};
const Sensor SensorDatabase[] = {
    (Sensor) { "01A", new HLW8012, 1,  2,  3 },
    (Sensor) { "01B", new HLW8012, 4,  5,  6 }
};
const int SensorCount = 2;

I then initialize them in a loop:

void setup() {
    // Initialize the HLW8012 module for each sensor entry
    for (int s = 0; s < SensorCount; s++) {
        // Initialize HLW8012 class instance
        SensorDatabase[s].hlw->begin(SensorDatabase[s].cf_pin, SensorDatabase[s].cf1_pin, SensorDatabase[s].sel_pin, HIGH, true);

        // Set the nominal value of the resistors
        SensorDatabase[s].hlw->setResistors(CURRENT_RESISTOR, VOLTAGE_RESISTOR_US, VOLTAGE_RESISTOR_DS);

        // ???????????
    }
}

The issue comes with the attachInterrupt calls, which I presume I would want to do in the ????? bit above. One fairly obvious but non-working attempt:

attachInterrupt(digitalPinToInterrupt(SensorDatabase[s].cf_pin), SensorDatabase[s].hlw->cf_interrupt, CHANGE);
attachInterrupt(digitalPinToInterrupt(SensorDatabase[s].cf1_pin), SensorDatabase[s].hlw->cf1_interrupt, CHANGE);
error: invalid use of non-static member function
attachInterrupt(digitalPinToInterrupt(SensorDatabase[s].cf_pin), SensorDatabase[s].hlw->cf_interrupt, CHANGE);

error: invalid use of non-static member function
attachInterrupt(digitalPinToInterrupt(SensorDatabase[s].cf1_pin), SensorDatabase[s].hlw->cf1_interrupt, CHANGE);

Since these have to take a pointer to a function with no arguments that returns a void, I can't find a way to do this - all of the methods seem to require these to be static functions, but doing so seems non-trivial. I've tried looking for other more general solution, but a solid number of them recommend workarounds that don't seem to go anywhere (stuff like std::bind, using various constructors there, and of course the wrapper function idea that is used in the interrupts example but is hard to scale like this).

Does anyone have any advice about this specific library, and what if anything I might need to do to it to make this work how I'd like - initialize multiple instance of the class each bound to interrupts on different pins in a semi-dynamic (array) way?

joshuaboniface commented 3 years ago

So I probably should have thought a bit more logically about my project before diving so deep into this, but the short of it is I'm probably going to be more heavily limited by the hardware than by this code. Especially since even the "best" Arduino Mega only has 15 PWM-capable pins (or 7 sensors' worth, far less than I would need for my goal), with only 6 capable of interrupts. So I'm going to close this for now and think about my options. But, I'd still be curious about any thoughts here long-term!