Swisscore
Published

Home Power Monitoring

Measuring 3 phases in electrical panel

AdvancedWork in progress3,857
Home Power Monitoring

Things used in this project

Hardware components

ESP8266 ESP-12E
Espressif ESP8266 ESP-12E
×1
PZEM-016
×3
74HC4052
×1

Story

Read more

Custom parts and enclosures

Solidworks assembly

Solidworks 2019 Assembly

Schematics

Schematic with Target3001! V20

Schematic V1.2

Schematic with Target3001! V20

Code

Arduino IDE code

C/C++
//
// PowerMeter
// GRA
// Créé le : 22.05.2019
// V1.0 Lecture d'une phase et envoi par MQTT sur node-red
// Param pour  ESP MQTT HW 2.0 : Generic ESP8266 module, 115200, 80MHz, 26MHz, DOUT(compatible), 512K (no SPIFFS), 40MHz, ck, Disabled, Rien, V2 lower memory, Flash, Disabled, 2, Only Sketch 

#include <PZEM004Tv30.h>
#include <PubSubClient.h>
#include "ESP8266WiFi.h"

#define Tx 5
#define Rx 4

#define AD0_PIN 12
#define AD1_PIN 13

#define LED_PIN 14
#define waitTime 60 // en seconde

// Ponthaux
const char* ssid = "yourSSID";                                   
const char* password = "YourPassword";
const char* server = "yourMQTTserverIP";

char* topicPowerMeter = "power/powerMeter";    // Topic Power meter

String swVersion = "V1.0";
String hwVersion = "V1.0";

String payload = "";
String clientName;
String msg = "";

char message_buff[1];   // initialise storage buffer (i haven't tested to this capacity.)

int sleepTimeS = 30;     //300 = 5mn, 600 = 10mn, 1800 = 30mn, 3600 = 1h
int i = 0;

unsigned long lastReconnectAttempt = 0;

void callback(char* topicPowerMeter, byte* payload, unsigned int length);

WiFiClient wifiClient;
PubSubClient client(server, 1883, callback, wifiClient);

//PZEM004T pzem(D1,D2);  // (RX,TX) connect to TX,RX of PZEM
PZEM004Tv30 pzem(Rx, Tx);  // (RX,TX) connect to TX,RX of PZEM
IPAddress ip(192,168,1,1);

///////////////////////////////////////////////////////////////
// Convert Mac adress to string
///////////////////////////////////////////////////////////////
String macToStr(const uint8_t* mac)
{
  String result;
  for (i = 0; i < 6; ++i) {
    result += String(mac[i], 16);
    if (i < 5)
      result += ':';
  }
  return result;
}
///////////////////////////////////////////////////////////////
// Connect to wifi
///////////////////////////////////////////////////////////////
void connectwifi()
{
  int cnt = 0;
  Serial.print("Connecting to ");
  Serial.print(ssid);
  
  WiFi.mode(WIFI_STA);          // 26.05.2018 Mettre en station et non AP pour ne pas être piratable
  WiFi.begin(ssid, password);
  //WiFi.config(ip, gateway, subnet);
  while (WiFi.status() != WL_CONNECTED)
  {
    digitalWrite(LED_PIN, LOW);
    delay(50);
    
    Serial.print(".");
    cnt += 1;
    digitalWrite(LED_PIN, HIGH);
    if(cnt>=500)                  //V1.7 240->500
    {
      digitalWrite(LED_PIN, LOW);
      delay(1000);
      //connectwifi();              //V1.7 supprimé ESP.deepSleep(1000); pour retenter la connexion
      cnt = 0;                    // Ajouté pour remettre à 0
      ESP.restart();
    }
  }
  
  Serial.println("WiFi connected");  
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  // Generate client name based on MAC address
  clientName += "PowerRemote-";
  uint8_t mac[6];
  WiFi.macAddress(mac);
  clientName += macToStr(mac);

  Serial.print("Connecting to ");
  Serial.print(server);
  Serial.print(" as ");
  Serial.println(clientName);

  if (client.connect((char*) clientName.c_str()))
  {
    Serial.println("Connected to MQTT broker");
    Serial.print("Topic is: ");
    Serial.println(topicPowerMeter);   
    char* topicTest = "test/test-connexion";
    if (client.publish(topicTest, "Starting..."))
    {
      Serial.println("Publish successfully sent");
      //client.subscribe(topicPowerMeter);
    }
    else
    {
      digitalWrite(LED_PIN, LOW);
      Serial.println("Publish failed");
    }
  }
  else
  {
    digitalWrite(LED_PIN, LOW);
    Serial.println("MQTT connect failed");
    Serial.println("Sleeping and try again...");
    //ESP.deepSleep(5000000);
  }
  digitalWrite(LED_PIN, HIGH);
}

///////////////////////////////////////////////////////////////
// Callback
///////////////////////////////////////////////////////////////

void callback(char* topicCallback, byte* payload, unsigned int length)
{
  /*// Here is what i have been using to handle subscriptions. I took it as a snippet from elsewhere but i cannot credit author as i dont have reference!
  int i = 0;
  
  Serial.print("Comparaison de topics : ");
  Serial.print(topicPowerMeter);
  Serial.print(" et ");
  Serial.println(topicCallback);
  if (String(topicPowerMeter) == String(topicCallback ))
    {
    Serial.println("Message arrived:  topic: " + String(topicCallback));
    Serial.println("Length: " + String(length,DEC));
   
    // create character buffer with ending null terminator (string)
    for(i=0; i<length; i++)
    {
      message_buff[i] = payload[i];
      delay(20);
    }
    message_buff[i] = '\0';
   
    String msgString = String(message_buff);
   
    Serial.println("Payload: " + msgString);

    if (String(topicPowerMeter) == String(topicCallback))   // Si bon topic, récupérer les données tension courant 
    {
      digitalWrite(LED_PIN, LOW);     // set output low
      Serial.print("Voltage : ");
      Serial.println(voltage);
    }
    else if

    else
    {
      return;
    }
  }
  else
  {
    Serial.println("Another topic, not for me");
  }*/
}
///////////////////////////////////////////////////////////////
// Reconnect to MQTT client
///////////////////////////////////////////////////////////////

boolean reconnect()
{
  Serial.println("Connection loosen, try to reconnect");
  if (client.connect("ESPClient"))
  {
    // Once connected, publish an announcement...
    client.publish("topicTest","hello world");
    // ... and resubscribe
    //client.subscribe(topicPowerMeter);
  }
  return client.connected();
}

///////////////////////////////////////////////////////////////
// Setup
///////////////////////////////////////////////////////////////
void setup()
{
  Serial.begin(115200);
  delay(100);
  Serial.println();
  Serial.println("Power Meter ");
  Serial.print(swVersion);
  Serial.print(", HW:");
  Serial.println(hwVersion);

  pinMode(AD0_PIN, OUTPUT);
  pinMode(AD1_PIN, OUTPUT);

  delay(200);

  digitalWrite(AD0_PIN,LOW);
  digitalWrite(AD1_PIN,LOW);
  
  //pzem.setAddress(ip);

    connectwifi();    // Connect wifi
  
  if (client.connected())   // Connect to broker
  {  
    if (client.publish(topicPowerMeter, (char*) payload.c_str(),true))
    {   
      Serial.println("Publish ok");
      //client.subscribe(topicPowerMeter);
      digitalWrite(LED_PIN, HIGH);
    }
    else
    {    
      digitalWrite(LED_PIN, LOW);
      Serial.println("Publish failed");
    }
  }
  else
  {
    digitalWrite(LED_PIN, LOW);
    Serial.println("Try to reconnect...");
    ESP.deepSleep(1000);
  }
  for (int i=0;i<=4;i++)
  {
    digitalWrite(LED_PIN, LOW);
    delay(200);
    digitalWrite(LED_PIN, HIGH);
    delay(200);
  }
}

///////////////////////////////////////////////////////////////
// Loop
///////////////////////////////////////////////////////////////
void loop()
{
  if (!client.connected())
  {
    long now = millis();
    if (now - lastReconnectAttempt > 50000)
    {
      lastReconnectAttempt = now;
      Serial.print("Last Reconnect Attempt : ");
      Serial.println(lastReconnectAttempt);
      // Attempt to reconnect
      if (reconnect())
      {
        Serial.println("Reconnected");
        lastReconnectAttempt = 0;
      }
    }
    Serial.println("");
  }
  client.loop();
  if (WiFi.status() != WL_CONNECTED)    // Si le Wifi n'est plus connecté, reconnecter
  {
    delay(200);
    connectwifi();
    Serial.println("");
  }

  int i = 0;
  // Envoi sur les 3 UART différents la demande d'énergée puis envoyer par wifi sur le serveur MQTT
  for(i = 0 ; i<=2 ; i++)
  {
    Serial.print("Capteur sélectionné : ");
    Serial.println(i);
    //Serial.println(i & 0b00000001);
    //Serial.println(i & 0b00000010);
    if(i == 0)
    {
      digitalWrite(AD0_PIN,LOW);
      digitalWrite(AD1_PIN,LOW);
    }
    else if(i == 1)
    {
      digitalWrite(AD0_PIN,HIGH);
      digitalWrite(AD1_PIN,LOW);
    }
    else if(i == 2)
    {
      digitalWrite(AD0_PIN,LOW);
      digitalWrite(AD1_PIN,HIGH);
    }
    else if(i == 3)
    {
      digitalWrite(AD0_PIN,HIGH);
      digitalWrite(AD1_PIN,HIGH);
    }
    
    delay(1000);

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

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

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

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

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

    float pf = pzem.pf();
    Serial.println(pf);
    if(not isnan(pf))
    {
        Serial.print("PF: "); Serial.println(pf);
    } else
    {
        Serial.println("Error reading power factor");
        //break;
    }
    
    if(isnan(voltage) || isnan(current) || isnan(power) || isnan(energy))
    {
      Serial.println("At least one 'NAN' status");
      //break;
    }
    else
    {
      i++;
      msg = "v" + String(i) + ":" + String(voltage) +"V;i" + String(i) + ":" + String(current) + "A;p" + String(i) + ":" + String(power) + "W;e" + String(i) + ":" + String(energy) +"kWh";
      Serial.print("Msg : ");
      Serial.println(msg);
      Serial.println("Publishing PZEM data...");
      client.publish(topicPowerMeter, msg.c_str(),true);
      i--;
    }
    delay(250);
  }
  digitalWrite(AD0_PIN,LOW);    // Remise à 0 de l'adresse
  digitalWrite(AD1_PIN,LOW);
  
  Serial.println("Waiting...");

  delay(waitTime*1000);

  ESP.restart();    // On restart pour se reconnecter!

}

Credits

Swisscore

Swisscore

2 projects • 2 followers

Comments