mandulaj / PZEM-004T-v30

Arduino library for the Updated PZEM-004T v3.0 Power and Energy meter
MIT License
256 stars 108 forks source link

Reading Multiple PZEM-004t in one SoftwareSerial #19

Closed Wachenanggo closed 4 years ago

Wachenanggo commented 4 years ago

Screen Shot 2020-01-24 at 4 02 10 PM

I follow the same initialization, as you said. But it only returns the last PZEM connected.

here's my code. '#include

/ Use software serial for the PZEM Pin 11 Rx (Connects to the Tx pin on the PZEM) Pin 12 Tx (Connects to the Rx pin on the PZEM) / PZEM004Tv30 pzem1(D5, D6, 0x01); PZEM004Tv30 pzem2(D5, D6, 0x02); PZEM004Tv30 pzem3(D5, D6, 0x03); void setup() { Serial.begin(115200); }

void loop() { float voltage1 = pzem1.voltage(); if( !isnan(voltage1) ){ Serial.print("voltage1: "); Serial.print(voltage1); Serial.println("V"); } else { Serial.println("Error reading voltage"); }

float current1 = pzem1.current();
if( !isnan(current1) ){
    Serial.print("Current1: "); Serial.print(current1); Serial.println("A");
} else {
    Serial.println("Error reading current");
}

float power1 = pzem1.power();
if( !isnan(power1) ){
    Serial.print("Power: "); Serial.print(power1); Serial.println("W");
} else {
    Serial.println("Error reading power");
}

float energy1 = pzem1.energy();
if( !isnan(energy1) ){
    Serial.print("Energy1: "); Serial.print(energy1,3); Serial.println("kWh");
} else {
    Serial.println("Error reading energy");
}

float frequency1 = pzem1.frequency();
if( !isnan(frequency1) ){
    Serial.print("Frequency1: "); Serial.print(frequency1, 1); Serial.println("Hz");
} else {
    Serial.println("Error reading frequency");
}

float pf1 = pzem1.pf();
if( !isnan(pf1) ){
    Serial.print("PF1: "); Serial.println(pf1);
} else {
    Serial.println("Error reading power factor");
}

float voltage2 = pzem2.voltage(); if( !isnan(voltage2) ){ Serial.print("voltage2: "); Serial.print(voltage2); Serial.println("V"); } else { Serial.println("Error reading voltage"); }

float current2 = pzem2.current();
if( !isnan(current2) ){
    Serial.print("Current2: "); Serial.print(current2); Serial.println("A");
} else {
    Serial.println("Error reading current");
}

float power2 = pzem2.power();
if( !isnan(power2) ){
    Serial.print("Power: "); Serial.print(power2); Serial.println("W");
} else {
    Serial.println("Error reading power");
}

float energy2 = pzem2.energy();
if( !isnan(energy2) ){
    Serial.print("Energy2: "); Serial.print(energy2,3); Serial.println("kWh");
} else {
    Serial.println("Error reading energy");
}

float frequency2 = pzem2.frequency();
if( !isnan(frequency2) ){
    Serial.print("Frequency2: "); Serial.print(frequency2, 2); Serial.println("Hz");
} else {
    Serial.println("Error reading frequency");
}

float pf2 = pzem2.pf();
if( !isnan(pf2) ){
    Serial.print("PF2: "); Serial.println(pf2);
} else {
    Serial.println("Error reading power factor");
}

 float voltage3 = pzem3.voltage();
if( !isnan(voltage3) ){
    Serial.print("voltage3: "); Serial.print(voltage3); Serial.println("V");
} else {
    Serial.println("Error reading voltage");
}

float current3 = pzem3.current();
if( !isnan(current3) ){
    Serial.print("Current3: "); Serial.print(current3); Serial.println("A");
} else {
    Serial.println("Error reading current");
}

float power3 = pzem3.power();
if( !isnan(power3) ){
    Serial.print("Power: "); Serial.print(power3); Serial.println("W");
} else {
    Serial.println("Error reading power");
}

float energy3 = pzem3.energy();
if( !isnan(energy3) ){
    Serial.print("Energy3: "); Serial.print(energy3,3); Serial.println("kWh");
} else {
    Serial.println("Error reading energy");
}

float frequency3 = pzem3.frequency();
if( !isnan(frequency3) ){
    Serial.print("Frequency3: "); Serial.print(frequency3, 3); Serial.println("Hz");
} else {
    Serial.println("Error reading frequency");
}

float pf3 = pzem3.pf();
if( !isnan(pf3) ){
    Serial.print("PF3: "); Serial.println(pf3);
} else {
    Serial.println("Error reading power factor");
}

}`

sergiocntr commented 4 years ago

You did .setaddress before, as Mandulaj wrote?

mandulaj commented 4 years ago

Yeah you have to use a separate sketch in order to set the address for each individual PZEM. Then you can address them on one Serial bus.

Wachenanggo commented 4 years ago

Yeah you have to use a separate sketch in order to set the address for each individual PZEM. Then you can address them on one Serial bus.

I already use the change address sketch and set each device address one by one. But only the last one is returning a value.or do i need a delay every tx of data and rx of data?

mandulaj commented 4 years ago

Are all of them connected to the mains voltage?

Wachenanggo commented 4 years ago

They are all connected to mains 67BFC21B-195C-4777-B048-6842F5700012

Wachenanggo commented 4 years ago

I found out that you need to call PZEM004Tv30 pzem1(D5, D6, 0x01); in void loop every time you query.

sergiocntr commented 4 years ago

Wait a moment @Wachenaggo,following the necessity to reconstruct every time the object I went deep into and get this warning :

lib/PZEM-004T-v30/PZEM004Tv30.cpp: In destructor 'PZEM004Tv30::~PZEM004Tv30()': lib/PZEM-004T-v30/PZEM004Tv30.cpp:94:20: warning: deleting object of abstract class type 'Stream' which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor] delete this->_serial;

so I found https://stackoverflow.com/questions/47702776/how-to-properly-delete-pointers-when-using-abstract-classes it's needed a "virtual" destructor , thanks for your feedback.

mandulaj commented 4 years ago

@Wachenanggo could you explain what you mean with :

call PZEM004Tv30 pzem1(D5, D6, 0x01); in void loop every time you query.

Maybe send me the section of code you are talking about. You should not have to call the constructor multiple times....

I just threw together a simple sketch according to your original code and connected two of the PZEMs on one bus. They are both connected to the same AC voltage potential and don't measure current but my point is to read the data from them on one bus. And it appears to work no problem. I call the initialization functions only once at the beginning of the sketch. In the main loop, I only call the getter functions, such as pzem1.voltage():

#include <PZEM004Tv30.h>

/* You must use the pzem.setAddress() as shown in the example sketch
* in order to set up the individual addresses for each AC module
*/
PZEM004Tv30 pzem1(D5, D6, 0x01); // Only called once over here
PZEM004Tv30 pzem2(D5, D6, 0x02); 

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

void loop() {
    Serial.println("PZEM1=====================");
    float voltage = pzem1.voltage();
    if(!isnan(voltage)){
        Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V");
    } else {
        Serial.println("Error reading voltage");
    }

    float current = pzem1.current();
    if(!isnan(current)){
        Serial.print("Current: "); Serial.print(current); Serial.println("A");
    } else {
        Serial.println("Error reading current");
    }

    float power = pzem1.power();
    if(!isnan(power)){
        Serial.print("Power: "); Serial.print(power); Serial.println("W");
    } else {
        Serial.println("Error reading power");
    }

    float energy = pzem1.energy();
    if(!isnan(energy)){
        Serial.print("Energy: "); Serial.print(energy,3); Serial.println("kWh");
    } else {
        Serial.println("Error reading energy");
    }

    float frequency = pzem1.frequency();
    if(!isnan(frequency)){
        Serial.print("Frequency: "); Serial.print(frequency, 1); Serial.println("Hz");
    } else {
        Serial.println("Error reading frequency");
    }

    float pf = pzem1.pf();
    if(!isnan(pf)){
        Serial.print("PF: "); Serial.println(pf);
    } else {
        Serial.println("Error reading power factor");
    }

    Serial.println();
    Serial.println("PZEM2=====================");

    voltage = pzem2.voltage();
    if(!isnan(voltage)){
        Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V");
    } else {
        Serial.println("Error reading voltage");
    }

    current = pzem2.current();
    if(!isnan(current)){
        Serial.print("Current: "); Serial.print(current); Serial.println("A");
    } else {
        Serial.println("Error reading current");
    }

    power = pzem2.power();
    if(!isnan(power)){
        Serial.print("Power: "); Serial.print(power); Serial.println("W");
    } else {
        Serial.println("Error reading power");
    }

    energy = pzem2.energy();
    if(!isnan(energy)){
        Serial.print("Energy: "); Serial.print(energy,3); Serial.println("kWh");
    } else {
        Serial.println("Error reading energy");
    }

    frequency = pzem2.frequency();
    if(!isnan(frequency)){
        Serial.print("Frequency: "); Serial.print(frequency, 1); Serial.println("Hz");
    } else {
        Serial.println("Error reading frequency");
    }

    pf = pzem2.pf();
    if(!isnan(pf)){
        Serial.print("PF: "); Serial.println(pf);
    } else {
        Serial.println("Error reading power factor");
    }

    Serial.println();

    delay(2000);
}

Of course I initially used the setAddress sketch for each of the modules individually to give them their respective addresses.

The output is as follows:

PZEM1=====================
Voltage: 239.00V
Current: 0.00A
Power: 0.00W
Energy: 0.000kWh
Frequency: 50.0Hz
PF: 0.00

PZEM2=====================
Voltage: 239.10V
Current: 0.00A
Power: 0.00W
Energy: 0.002kWh
Frequency: 50.0Hz
PF: 0.00

You can see that for example the Cumulative Energy quantity differs for the two modules, so I am definitely reading from the two different sensors on one bus.

Here is a picture of my setup. Please excuse the wire mess, I had little time and space :smile:

Very nice mess of wires goes here...

It might not be very clear but on the white breadboard I am connecting the RX pins of both modules together to the one TX pin on the Arduino and both module's TX pins to the one Arduino RX pin... Also both modules are supplied with 5V and GND.

morganflint commented 3 years ago

Wouldnt it be a good idea if you could send the address as a parameter, instead of creating different instances for each PZEM? I mean, instead of reading PZEM with address X this way:

PZEM004Tv30 pzemX(D5, D6, 0xXX); 
....
....
power = pzemX.power();

Would be better if you could do:

PZEM004Tv30 pzem(D5, D6); 
....
....
power = pzem.power(0xXX);

This would allow, for example, to use a loop if you have to do the same thing with several PZEMs:

for (int sensor=1; sensor<4; sensor++){
 power = pzem.power(sensor);
   if(!isnan(power)){
       Serial.print("Sensor "); Serial.print(sensor); Serial.print(" Power: "); Serial.print(power); Serial.println("W");
   } else {
       Serial.print("Error reading power for sensor "); Serialprintln(sensor);
   }
}

To avoid incompatibility with "classic" mode I imagine it could be possible to make the library behave the same as now if you don't pass any parameter.

Would it be very difficult to implement?

[EDIT] I found a workaround for this using an array of PZEM004Tv30 instances and posted it here. Anyway, I still think the possibility to add PZEM's address as an argument in the function is also a good alternative...

Renaudp commented 3 years ago

Hello,

I have an issue while changing pzem address.

include

PZEM004Tv30 pzem(&Serial3); uint8_t addr=0x0001;

void setup() { Serial.begin(9800); pzem.setAddress(addr); }

void loop() { Serial.print("Current address:"); Serial.println(pzem.getAddress()); Serial.println(); delay(1000); }

When I restart de pzem, the address is back to 248.

Any idea what is wrong? Thanks,

Guudiin commented 2 years ago

How to reset pzem2 = 0x02 ?? Exemplo:

PZEM004Tv30 pzem1(D5, D6, 0x01); PZEM004Tv30 pzem2(D5, D6, 0x02);

For 0x01 = [0x01, 0x42, 0x80, 0x11]

for 0x02 = ???

help

TDHofstetter commented 7 months ago

How to reset pzem2 = 0x02 ?? Exemplo:

PZEM004Tv30 pzem1(D5, D6, 0x01); PZEM004Tv30 pzem2(D5, D6, 0x02);

For 0x01 = [0x01, 0x42, 0x80, 0x11]

for 0x02 = ???

help

Two ways. First, you could run the PZEM querying program on your PC and use it to change your PZEM's address to whatever you want. Second, you could connect your second PZEM ALONE to your Arduino and run the address changing "sketch" without any other PZEM devices attached to the Arduino. After changing its address, you can connect your other PZEMs back to the Arduino and they should have different addresses.