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();
}
}
}
Pour ceux qui veulent réaliser, n’hésitez pas à me demmander
Jean-luc