Using 2x PZEM-004T for solar monitoring

As you can see, the sketch in my previous post is not very efficient, as it needs to repeat several blocks of code with slight changes.

With a little help from my son, who suggested using an array of modbusmaster instances (we weren’t sure it was going to work, but it did!), I rewrote the code which is now shorter, with a more “elegant” approach to using several sensors, very easy to “escalate” in case more sensors are added.

I also simplified Key’s code (the base for this one, which had some remains of former experiments, vars, and libraries that weren’t needed) and also eliminated the need for “settingsPZEM.h”.

// #include <ArduinoOTA.h> //not used
#include <BlynkSimpleEsp8266.h>
#include <ModbusMaster.h>
#include <ESP8266WiFi.h>

#include <SoftwareSerial.h>   
SoftwareSerial pzem(D5,D6);   // (RX,TX) connect to TX,RX of PZEM for NodeMCU
//SoftwareSerial pzem(D7,D8); // (RX,TX) connect to TX,RX of PZEM
#include <ModbusMaster.h>

// instantiate ModbusMaster objects
ModbusMaster node[3];

BlynkTimer timer;

//WiFi data
char ssid[] = "*********";        //WiFi Credential
char pass[] = "**********";    //WiFi Password

// Server data
char server[] = "192.168.1.XXX";  //Blynk local server IP address
int port = 8080;                  //Blynk local port
#define USE_LOCAL_SERVER          //Use local Blynk Server - comment-out if use Blynk hosted cloud service

#define AUTH "******************************" //PZEM-004v3 Auth code for 192.168.1.XXX:9443 (gmail)

// #define OTA_HOSTNAME "PZEM-004v3" // Brought from settingsPZEM.h, not needed


// Vars for reading PZEM's output
float U_PR[3], I_PR[3],  P_PR[3],  E_PR[3], F_PR[3], PF_PR[3]; bool AL_PR[3]; 
uint8_t result; 
  
void setup(){
  
  // Flash LED on start
    pinMode(LED_BUILTIN, OUTPUT);
    for (int i = 0; i < 6 ; i++){
      Serial.println("LED on");
      digitalWrite(LED_BUILTIN, LOW);
      delay(200);
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.println("LED off");
      delay(200);
      }
  // End LED flash

  //Initialize serial ports and Modbus nodes
  Serial.begin(74880); Serial.println("Start serial");
  pzem.begin(9600); Serial.println("Start PZEM serial");
  node[0].begin(1, pzem);  Serial.println("Start PZEM 1"); // 1 = ID MODBUS, pzem = soft serial port previously defined
  node[1].begin(2, pzem);  Serial.println("Start PZEM 2"); // 2 = ID MODBUS 
  node[2].begin(3, pzem);  Serial.println("Start PZEM 3"); // 3 = ID MODBUS 

  //Wifi and server connect
  WiFi.mode(WIFI_STA);
  #if defined(USE_LOCAL_SERVER)
    Serial.println("Connecting to WiFi");
    WiFi.begin(ssid, pass);
    Serial.println("Connecting local Blync server");
    Blynk.config(AUTH, server, port);
  #else
    Serial.println("Connecting to WiFi and Blynk");
    Blynk.begin(AUTH, ssid, pass);
  #endif
  while (Blynk.connect() == false) {}
  Serial.println("Connected!");
  
//  ArduinoOTA.setHostname(OTA_HOSTNAME);
//  ArduinoOTA.begin();
//  timerTask1 = timer.setInterval(1000, updateBlynk);

} //end Setup

void updateBlynk() { // Write values to Blynk's virtual pins
for (int i=0; i<3; i++){
  //Write to Blynk virtual pins
  Blynk.virtualWrite(7*i,   U_PR[i]);     // Write voltage to V0, V7, V14
  Blynk.virtualWrite(7*i+1, I_PR[i]);     // Write current to V1, V8, V15
  Blynk.virtualWrite(7*i+2, P_PR[i]);     // Write active power to V2, V9, V16
  Blynk.virtualWrite(7*i+3, E_PR[i]);      // Write active energy to V3, V10, V17
  Blynk.virtualWrite(7*i+4, F_PR[i]);     // Write frequency to V4, V11, V18
  Blynk.virtualWrite(7*i+5, PF_PR[i]);    // Write power factor to V5, V12, V19
  Blynk.virtualWrite(7*i+6, AL_PR[i]); // Write alarm status to V6, V13, V20
  }
} //End updateBlynk()


void loop(){
Serial.println("Starting loop");
Blynk.run();
//ArduinoOTA.handle();

for (int i=0; i<3; i++){
  result = node[i].readInputRegisters(0x0000, 10); // leer 10 registros comenzando en el 0
  if (result == node[i].ku8MBSuccess)  {
    
    U_PR[i]      = (node[i].getResponseBuffer(0x00)/10.0f);
    I_PR[i]      = ((node[i].getResponseBuffer(0x01) + (node[i].getResponseBuffer(0x02)*65532))/1000.000f);
    P_PR[i]      = ((node[i].getResponseBuffer(0x03) + (node[i].getResponseBuffer(0x04)*65532))/10.0f);
    E_PR[i]      = ((node[i].getResponseBuffer(0x05) + (node[i].getResponseBuffer(0x06)*65532))/1000.0f);
    F_PR[i]      = (node[i].getResponseBuffer(0x07)/10.0f);
    PF_PR[i]     = (node[i].getResponseBuffer(0x08)/100.0f);
    AL_PR[i]     = (node[i].getResponseBuffer(0x09));  
   
    Serial.print("Node ");  Serial.print(i+1); Serial.println(" OK    LED on");
    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Voltage      ");  Serial.print(U_PR[i]);     Serial.println(" V");  // V
    Serial.print("Current      ");  Serial.print(I_PR[i],3);   Serial.println(" A");  // A
    Serial.print("Active power ");  Serial.print(P_PR[i]);     Serial.println(" W");  // W 
    Serial.print("Energy       ");  Serial.print(E_PR[i],3);   Serial.println(" kWh");// kWh
    Serial.print("Frequency    ");  Serial.print(F_PR[i]);     Serial.println(" Hz"); // Hz
    Serial.print("Power factor ");  Serial.print(PF_PR[i]);    Serial.println();      // FP
    Serial.print("Alarm        ");  Serial.print(AL_PR[i]);    Serial.println();      // Alarm
    delay(200);
    Serial.print("Node ");  Serial.print(i+1); Serial.println("       LED off");
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("====================================================");
    }
  else{
    U_PR[i]       = 0;
    I_PR[i]       = 0;
    P_PR[i]       = 0;
    // E_PR[i]       = 0; //If PZEM cannot be read (lost of power), last energy would be better aproximation than zero
    F_PR[i]       = 0;
    PF_PR[i]      = 0;
    AL_PR[i]      = 0;
  
    Serial.print("Node ");  Serial.print(i+1); Serial.println(" ERROR");
    Serial.println("====================================================");
    }
  delay(200);
  }

updateBlynk();

}