Compteur énergie

Bonjour à tous

Petit partage de ma réalisation compteur énergie à base d’un PZEM-004T

Le schéma

Installation à proximité du disjoncteur

Coté Jeedom

Le node envoi le courant et la puissance toutes les minutes
le voltage, energie, frequence et facteur de puissance toutes les 5 minutes
Jeedom récupère l’energie consommée à 23h59 et fait un reset sur le PZEM-004T

Le sketch correspondant :


/**
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
 * Copyright (C) 2013-2015 Sensnology AB
 * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 *******************************************************************************
 *
 * DESCRIPTION
 *
 * JLB le 08/02/2021
 * système de mesure power meter
 * PZEM-004T V3.0 et arduino pro mini 
 * 
*/

// Enable debug prints to serial monitor
//#define MY_DEBUG 

// Enable and select radio type attached
#define MY_RADIO_RF24

// Set LOW transmit power level as default, if you have an amplified NRF-module and
// power your radio separately with a good regulator you can turn up PA level.
//#define MY_RF24_PA_LEVEL RF24_PA_MIN
#define MY_RF24_PA_LEVEL RF24_PA_LOW
//#define MY_RF24_PA_LEVEL RF24_PA_HIGH
//#define MY_RF24_PA_LEVEL RF24_PA_MAX

#define MY_TRANSPORT_WAIT_READY_MS 3000  

#define child_id_voltage        0      
#define child_id_courant        1       
#define child_id_puissance      2       
#define child_id_energie        3       
#define child_id_frequence      4       
#define child_id_power_factor   5       
#define child_id_reset_energie  6

#define reset_node_id 3  

#include <SPI.h>
#include <MySensors.h>
#include <PZEM004Tv30.h>

bool debug                = false;
bool ack                  = false;          // ack de gateway
bool reset_power_energie  = false;          // pour reset du compteur énergie du PZEM004T
float voltage       = 0;
float courant       = 0;
float puissance     = 0;
float energie       = 0;
float frequence     = 0;
float power_factor  = 0;

/* Use software serial for the PZEM
PZEM004Tv30 pzem(Pin Rx arduino, Pin Tx arduino);
*/
PZEM004Tv30 pzem(4, 2); // définit les pins de comm du promini

// Initialize messages
MyMessage msg_voltage(child_id_voltage,V_VOLTAGE);                // voltage en Volts               
MyMessage msg_courant(child_id_courant,V_CURRENT);                // courant en Ampères            
MyMessage msg_puissance(child_id_puissance,V_WATT);               // énergie instantanée en Watts 
MyMessage msg_energie(child_id_energie,V_KWH);                    // énergie cumulée en KW   
MyMessage msg_frequence(child_id_frequence,V_VAR1);               // fréquence en Hertz
MyMessage msg_power_factor(child_id_power_factor,V_POWER_FACTOR); // facteur de puissance (de 0 à 1)
MyMessage msg_reset_energie(child_id_reset_energie,V_STATUS);     // pour remise à 0 du compteur energie

//--------------------------------------------------------------------  
void before()
{
}

//--------------------------------------------------------------------
void setup() {
  //Serial.begin(115200);
  //Serial.print("Reset Energy");
  //pzem.resetEnergy();
  
  // use the 1.1 V internal reference
#if defined(__AVR_ATmega2560__)
    analogReference(INTERNAL1V1);
#else
    analogReference(INTERNAL);
#endif

  // regarde si reset node id demandé
  if (!digitalRead(reset_node_id))  {     // reset node id demandé
    for (uint16_t i=0; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
        hwWriteConfig(i,0xFF);
    }
    sleep(3600000);
  }
}

//--------------------------------------------------------------------
void presentation() {
  // Send the sketch version information to the gateway and Controller
  sendSketchInfo("Compteur energie", "2.0");
  wait(500);
  present(child_id_voltage, S_MULTIMETER);
  wait(500);
  present(child_id_courant, S_MULTIMETER);
  wait(500);
  present(child_id_puissance, S_POWER);
  wait(500);
  present(child_id_energie, S_POWER);
  wait(500);
  present(child_id_frequence, S_POWER);
  wait(500);
  present(child_id_power_factor, S_POWER);
  wait(500);
  present(child_id_reset_energie, S_BINARY);
  wait(500);
}

void lecture_voltage()  {
  float lecture = pzem.voltage();
  if( !isnan(lecture) ){
    voltage = lecture;
  } 
}

void lecture_courant()  {
  float lecture = pzem.current();
  if( !isnan(lecture) ){
    courant = lecture;
  } 
}

void lecture_puissance()  {
  float lecture = pzem.power();
  if( !isnan(lecture) ){
    puissance = lecture;
  } 
}

void lecture_energie()  {
  float lecture = pzem.energy();
  if( !isnan(lecture) ){
    energie = lecture;
  } 
}

void lecture_frequence()  {
  float lecture = pzem.frequency();
  if( !isnan(lecture) ){
    frequence = lecture;
  } 
}

void lecture_power_factor()  {
  float lecture = pzem.pf();
  if( !isnan(lecture) ){
    power_factor = lecture;
  } 
}

//--------------------------------------------------------------------
void loop() {
  static unsigned long memo_millis_temps1 = millis();
  static unsigned long memo_millis_temps2 = millis();
  unsigned long temps1 = 60000;  
  unsigned long temps2 = 300000;
  static bool one_time = false;

  if (!one_time)  {         // une seule fois au demarrage
    one_time = true;
    lecture_courant();
    lecture_puissance();
    lecture_voltage();
    lecture_energie();
    lecture_frequence();
    lecture_power_factor(); 
    send_state (child_id_voltage, voltage);
    send_state (child_id_courant, courant);
    send_state (child_id_puissance, puissance);
    send_state (child_id_energie, energie);
    send_state (child_id_frequence, frequence);
    send_state (child_id_power_factor, power_factor);
  }
  
  // comm courant et puissance toutes les minutes
  if (millis() - memo_millis_temps1 >= temps1)   {      // toutes les 60 secondes
    memo_millis_temps1 = millis();
    lecture_courant();
    lecture_puissance();
    send_state (child_id_courant, courant);
    send_state (child_id_puissance, puissance);
    if( debug)  {
      Serial.print("Current: "); Serial.print(courant); Serial.println("A");
      Serial.print("Power: "); Serial.print(puissance); Serial.println("W");
      Serial.println();
    }
  }
  
  // comm voltage, energie, frequence et facteur de puissance toutes les 5 minutes
  if (millis() - memo_millis_temps2 >= temps2)   {      // toutes les 5 minutes
    memo_millis_temps2 = millis();
    lecture_voltage();
    lecture_energie();
    lecture_frequence();
    lecture_power_factor(); 
    send_state (child_id_voltage, voltage);
    send_state (child_id_energie, energie);
    send_state (child_id_frequence, frequence);
    send_state (child_id_power_factor, power_factor);
    if( debug)  {
      Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V");
      Serial.print("Energy: "); Serial.print(energie,3); Serial.println("kWh");
      Serial.print("Frequency: "); Serial.print(frequence, 1); Serial.println("Hz");
      Serial.print("Power Factor: "); Serial.println(power_factor);
      Serial.println();
    } 
  }
  
  // reset du compteur energie du PZEM004T
  if (reset_power_energie == true)  {       // commande reset reçu
    pzem.resetEnergy();
    reset_power_energie = false;
    if (debug)  { Serial.print("Reset Energy"); }
  }
} // fin loop

/* ======================================================================
Function:send_state
// envoi l'état à jeedom
// 3 tentatives si pas reception ack
====================================================================== */
void send_state (int child, float valeur) {
  for ( int i = 0 ; i < 3 ; i++ ) {
    send(msg_voltage.setSensor(child).set(valeur,2),true);  // avec demande ack
    if (reception_ack()) {
      break ; // sortie boucle for
    }
  }
}

/* ======================================================================
Function: reception_ack
// attend la réception
// sortie au bout de 2 secondes si pas de reception
====================================================================== */
bool reception_ack () {
  unsigned long previousMillis = 0 ;
  unsigned long interval = 2000 ;  // 2 secondes
  previousMillis = millis() ;
  ack = false ;
  while (ack==false) {
    wait(100) ;
    if (millis() - previousMillis >= interval) {  // regarde si timeout
      return false ; // sortie sur timeout
    }
  }
  if (debug == 1) {
    Serial.print("Retournement ack :"); Serial.println((millis() - previousMillis));
  }
  return true ;
}

// -----------------------------------------------------------------------------
void receive(const MyMessage &message) {
  if (message.isEcho()) {
    ack = true ;
    if (debug == 1) {Serial.println("ack recu");}
  }
  else  {
    if (message.type == V_STATUS && message.sensor == child_id_reset_energie) {     // reset power energie demandée
      reset_power_energie = message.getBool();
    }
  }
}

Tuile

Pour ceux qui veulent réaliser, n’hésitez pas à me demmander

Jean-luc

Bonjour,
Merci jean-luc pour ce partage
Juste une question
le PZEM-004T est t’il capable de fournir des puissance selon le sens du courrant ?

je pense a ceux qui font du solaire et qui injectent du courant sur le réseau !

bonne journée

Bonjour ,
Non le PZEM-004T ne permet pas de remonter le sens du courant , il reste en positif dans les 2 sens

Super question car c’est vraiment un besoin pour le producteur solaire et vraiment c’est pas simple de trouver ce truc

Non malheureusement pas le sens du courant sur le PZEM-004T

Je compte faire de la production solaire dans quelque mois et j’étudierai
un montage à base arduino pour le sens du courant.

Sinon j’ai vu sur le forum que c’était possible en mettant une diode dans la boucle courant et
donc en utilisant 2 montages PZEM-004T, mais je n’ai pas encore essayé.

J’y crois pas de trop quand on connais le principe d’un tore ce n’est qu’un transformateur a une spire …
sit tu met une diode tu n’aura qu’une demie alternance … en gros tu va diviser le courrant par 2 !

Bonjour,

J’ai pondu un code MQTT qui pourrai intéresser.

Pour ma par j’ai 3 PZEM branché sur les même pour d’un ESP
Ces PZEM sont adressés ce qui me permet des les interrogés un a un sur le meme bus.
PZEM1 = conso maison
PZEM2 = onduleur Solaire
PZEM3 = clim
Ayant fait un décodeur linky par le passé, je comptais faire une soustraction sous jeedom.
ConsoMaison - ConsoLinky = Consomation solaire
Je bute encore sur certains problèmes, nouement la différenciation sur les PZEM des heures pleines et heures creuses

Si une âme charitable veux m’aider est participer, ces sera avec plaisir.

Bonjour,
Je suis en train de finaliser un node mysensors avec 2 PZEM
J’attend mon PCB qui devrait arrivé sous quelques jours.
Il permet de connaitre énergie produite, consommée et injectée
Si ça intéresse je peux partager schéma, pcb et sketch arduino
Jean-luc

Capture1

Capture2.PNG

1 « J'aime »

Bonjour

Cette solution m’intéresse si tu veux bien partager je suis preneur.
Je souhaite apprendre cette forme de DIY

Bonjour,
Pas de problèmes, je finalise et partage dans quelques jours.
En attendant il faut te familiariser avec mysensors.
Il te faut quelques notions en électronique pour réaliser ta passerelle et tes nodes
(J’ai 50 nodes qui fonctionnent depuis quelques années)
Si tu as besoin de mes schémas et PCB, je peux partager

Jean-luc

1 « J'aime »

bonjour,

J’ai fait des plan et réalisation de passerelle mysensors.
Depuis j’ai lâché la solution Mysensors au profit de MQTT (question de goûts personnels).
Mais ma passerelle fonctionne depuis plusieurs années.
Je suis disposé a fournir plans croquis et photos a ceux qui souhaitent en réaliser.

Passerelle Mysensors TCPIP

Passerelle MySensors Arduino Wifi - 2019-07-14.PDF (32,1 Ko)

1 « J'aime »

Bonsoir, peut-être ouvrir un nouveau sujet sujet avec le tag tutoriel !

Juste pour info, il est recommandé de ne pas avoir de piste en dessous de l’antenne du wemos. Cela évite les interférences.