Bonjour à tous,
Si ça peut aider…
Ci-joint schéma et codes de mon routeur qui fonctionne parfaitement depuis 1 an
Je communique avec le routeur en protocole MySensors
Je lui transmet la consommation souhaitée pour le chauffe-eau
Il me retourne le puissance consommée actuelle ainsi que le total consommé pour la journée
Schéma carte :
-Arduino pro mini pour le calculateur
-NRF 24L01+ pour la com radio
-PZEM 004T pour la mesure de puissance du chauffe-eau
-Module dimmer pour la commande
Schematic_Carte mesure puissance v1_2022-10-08.pdf (64,2 Ko)
Le sketch arduino
/**
* 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 09/12/2021
* système de gestion du chauffe eau
* PZEM-004T V3.0 pour la consommation
* arduino pro mini pour la gestion
* mysensors pour la comm vers gateway
* lecture consommation en watts
* lecture énergie consommée en kw/h
* consigne de chauffe en watts
* reset compteur énergie du pzem-004t
* envoi puissance instantanée et cumul energie suite à demande de jeeedom
*
*/
// 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_consommation 0
#define child_id_energie 1
#define child_id_consigne 2
#define child_id_reset_energie 3
#define child_id_demande 4
#include <SPI.h>
#include <MySensors.h>
#include <PZEM004Tv30.h>
#define reset_node_id 8 // entrée pour reset node id
bool debug = false;
bool ack = false; // ack de gateway
bool reset_energie = false; // pour reset du compteur énergie du PZEM004T consommation
bool demande = false; // pour demande puissance instantanée et cumul energie
float consommation = 0;
float energie = 0;
bool first_time = true;
int AC_LOAD = 3; // Output to Opto Triac pin
int dimming = 90; // Dimming level (0-128) 0 = ON, 128 = OFF
int dimtime = 0;
//PZEM004Tv30 pzem(Pin Rx arduino, Pin Tx arduino);
PZEM004Tv30 pzem(6, 5); // définit les pins de comm du promini énergie production
// Initialize messages
MyMessage msg_puissance(child_id_consommation,V_WATT); // énergie instantanée en Watts
MyMessage msg_energie(child_id_energie,V_KWH); // énergie cumulée en KW
MyMessage msg_consigne(child_id_consigne,V_PERCENTAGE); // consigne
MyMessage msg_reset_energie(child_id_reset_energie,V_STATUS); // pour remise à 0 du compteur energie
MyMessage msg_demande(child_id_demande,V_STATUS); // pour demande puissance instantanée et cumul energie
//--------------------------------------------------------------------
void before()
{
}
//--------------------------------------------------------------------
void setup() {
//Serial.begin(115200);
pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output
//attachInterrupt(0, zero_crosss_int, RISING); // Choose the zero cross interrupt # from the table above
pinMode(reset_node_id, INPUT_PULLUP);
// 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("Chauffe eau", "4.0");
wait(500);
present(child_id_consommation, S_POWER);
wait(200);
present(child_id_energie, S_POWER);
wait(200);
present(child_id_consigne, S_DIMMER);
wait(200);
present(child_id_reset_energie, S_BINARY);
wait(200);
present(child_id_demande, S_BINARY);
wait(200);
}
//--------------------------------------------------------------------
void loop() {
wait(100);
static bool one_time = false;
if (!one_time) { // une seule fois au demarrage envoi puissance instantanée et cumul energie suite à demande
dimming = 126;
one_time = true;
lecture_puissance();
send_state (child_id_consommation, consommation);
lecture_energie();
send_state (child_id_energie, energie);
wait(500);
first_time = true;
attachInterrupt(0, zero_crosss_int, RISING);
dimming = 128;
}
// envoi puissance instantanée et cumul energie suite à demande
if (demande) {
demande = false;
detachInterrupt(0);
consommation = 0;
lecture_puissance();
//Serial.print("conso: "); Serial.println(consommation);
send_state (child_id_consommation, consommation);
energie = 0;
lecture_energie();
//Serial.print("energie: "); Serial.println(energie);
send_state (child_id_energie, energie);
first_time = true;
attachInterrupt(0, zero_crosss_int, RISING);
}
// reset du compteur energie du PZEM004T consommation
if (reset_energie == true) { // commande reset reçu
detachInterrupt(0);
pzem.resetEnergy();
reset_energie = false;
if (debug) { Serial.print("Reset Energy Consommation"); }
first_time = true;
attachInterrupt(0, zero_crosss_int, RISING);
}
}
//--------------------------------------------------------------------
//the interrupt function must take no parameters and return nothing
void zero_crosss_int() //function to be fired at the zero crossing to dim the light
{
// Firing angle calculation : 1 full 50Hz wave =1/50=20ms
// Every zerocrossing thus: (50Hz)-> 10ms (1/2 Cycle)
// For 60Hz => 8.33ms (10.000/120)
// 10ms=10000us
// (10000us - 10us) / 128 = 75 (Approx) For 60Hz =>65
//int dimtime = (75*dimming); // For 60Hz =>65
if (first_time == false) {
dimtime = (77*dimming); // For 60Hz =>65
delayMicroseconds(dimtime); // Wait till firing the TRIAC
digitalWrite(AC_LOAD, HIGH); // Fire the TRIAC
delayMicroseconds(10); // triac On propogation delay
// (for 60Hz use 8.33) Some Triacs need a longer period
digitalWrite(AC_LOAD, LOW); // No longer trigger the TRIAC (the next zero crossing will swith it off) TRIAC
}
first_time = false;
}
//--------------------------------------------------------------------
void lecture_puissance() {
float lecture = pzem.power();
if( !isnan(lecture) ){
consommation = lecture;
consommation = int(consommation);
}
}
//--------------------------------------------------------------------
void lecture_energie() {
float lecture = pzem.energy();
if( !isnan(lecture) ){
energie = lecture;
}
}
/* ======================================================================
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_puissance.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 intervale = 2000 ; // 2 secondes
previousMillis = millis() ;
ack = false ;
while (ack==false) {
wait(100) ;
if (millis() - previousMillis >= intervale) { // 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_demande) { // puissance instantanée et cumul energie demandé
demande = message.getBool();
}
if (message.type == V_STATUS && message.sensor == child_id_reset_energie) { // reset power energie demandé
reset_energie = message.getBool();
}
if (message.type == V_PERCENTAGE && message.sensor==child_id_consigne) { // consigne recu de jeedom
dimming = message.getInt() ;
dimming = dimming*1.28; // transforme 0-100 en 128-0
dimming = 128-dimming;
}
}
}
Le scénario :
Jean-luc.