Bonjour à tous, je suis nouveau dans le monde Arduino. Je viens de débuter avec un projet qui me permettait de réaliser ce que je cherchais, à savoir une commande horaire qui ne dérive pas dans le temps et qui montre une fiabilité à toute épreuve.
Comme suggéré à juste titre, je modifie l'exposé de mon problème, en sautant l'historique de mon parcours et en résumant la situation actuelle.
Mon cahier des charges:
- créer à chaque heure pleine (hh:00:00) l'activation d'une sortie pendant 1 minute (donc jusque hh:00:59)
- pendant cette minute, créer l'activation d'une seconde sortie pendant 1/2 seconde à partir de la 41ème seconde
Matériel utilisé: un module ESP8285 WiFi acheté ici [Horloge connectée avec Arduino - Tropratik]
Suite au problème de confinement du module dans un coffret partiellement métallique, j'ai modifié l'antenne WiFi selon ce tuto https://www.instructables.com/External-Antenna-for-ESP8266/
Tout fonctionne parfaitement et voici le code:
```cpp
// Déclaration des librairies utilisées
#include <ESP8266WiFi.h>
#include "LiquidCrystal_I2C.h"
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <Timezone.h>
// Déclaration globales
LiquidCrystal_I2C Afficheur_G(0x27, 16, 2); // Afficheur LCD1602 d'addresse 0x27 avec écran de 2 lignes de 16 caractères
WiFiUDP Udp_G; // Objet UDP permettant d'envoyer et recevoir des trames Wi-Fi selon le protocole UDP
EasyNTPClient ClientNtp_G(Udp_G, "fritz.box"); // Objet NTP synchronisé avec "fritz.box" qui a son propre serveur NTP disponible dans le réseau domestique
TimeChangeRule RegleHeureEteBelgique_G = {"RHEB", Last, Sun, Mar, 2, 120}; // Règle de passage à l'heure d'été en Belgique
TimeChangeRule RegleHeureHiverBelgique_G = {"RHHB", Last, Sun, Oct, 3, 60}; // Règle de passage à l'heure d'hiver en Belgique
Timezone ConvertirHeureBelgique_G(RegleHeureEteBelgique_G, RegleHeureHiverBelgique_G); // Objet de conversion de l'heure avec les caractéristiques de la Belgique
const int CommandeCF = 12; // définition de la broche "12" comme sortie commande coffret
const int CommandeDL = 13; // définition dela broche "13" comme sortie commande Data Logger
const int EntreeBP = 14; // définition de la broche "14" comme entrée bouton-poussoir
int etat_BP; // variable pour stocker l'état du BP
int memoire_BP = HIGH; // variable pour mémoriser l'état du BP, initialisée à 1 lorsque le BP est relaché
unsigned long temps_T0 = millis(); // variable intermédiaire pour stocker le temps Arduino pour la fonction chrono min:sec
unsigned long temps_S; // variable pour calculer la durée d'1 seconde
unsigned long chrono_BP; // variable pour mesurer une durée de 1 minute
unsigned long chrono_T0 = millis(); // variable intermédiaire pour stocker le temps Arduino pour la fonction BP
bool cond_Setup = false; // flag pour initier le chronomètre de la routine Lecture_Mesure
unsigned long TempsUnix; // variable permettant de lire la valeur du temps Unix
unsigned long TempsUnixMem = ClientNtp_G.getUnixTime(); // variable servant à mémoriser l'heure Unix précédente et initialisée au temps Unix la 1ère fois
bool TempsUnixVal = false; // flag permettant de valider la bonne réception de l'heure Unix
bool DL_Flag = false; // flag permettant de ne créer qu'une seule implusion vers le Data Logger (external trigger)
bool BL_Flag = true; // flag permettant d'éteindre le rétro-éclairage après les 60 premières secondes de mise sous tension, une seule fois
bool BP_Flag = false; // flag permettant de couper le 12V coffret uniquement après le cycle BP
int ValeurMinute;
int ValeurSeconde;
// Fonction de démarrage, s'exécute une seule fois:
void setup()
{
// Constantes de la fonction
const char* SSID_L = "xxxxxxxx"; // Nom du réseau Wi-Fi
const char* MOT_DE_PASSE_L = "xxxxxxxx"; // Mot De Passe du réseau
pinMode(CommandeCF, OUTPUT); // configuration de la broche "12" comme sortie
pinMode(CommandeDL, OUTPUT); // configuration de la broche "13" comme sortie
pinMode(EntreeBP, INPUT); // configuration de la broche "14" comme entrée
digitalWrite(CommandeCF, LOW); // initialisation de la sortie "12" à l'état repos = bas
digitalWrite(CommandeDL, LOW); // initialisation de la sortie "13" à l'état repos = bas
// Variables de la fonction
wl_status_t StatutConnexion_L; // Pour mémoriser l'état de la connexion
Afficheur_G.init(5,4); // Initialisation de l'afficheur, SDA=5, SCL=4
Afficheur_G.backlight(); // Allumage du rétroéclairage
WiFi.begin(SSID_L, MOT_DE_PASSE_L); // Fonction permettant d'initialiser le module WiFi et de lancer la connexion
StatutConnexion_L = WiFi.status(); // Lecture de l'état de la connexion et stockage dans la variable "StatutConnexion_L"
while ((StatutConnexion_L != WL_NO_SSID_AVAIL)&&(StatutConnexion_L != WL_CONNECTED)&&(StatutConnexion_L != WL_CONNECT_FAILED))
{
delay(500);
Afficheur_G.print("."); // Affichage de points pendant la tentative de connexion
StatutConnexion_L = WiFi.status(); // Lecture de l'état de la connexion et mémorisation dans la variable "StatutConnexion_L"
}
Afficheur_G.clear(); // Effacer l'écran avant l'affichage de l'heure
}
// Fonction principale du programme, s'exécute en boucle:
void loop()
{
// Variables de la fonction
time_t HeureLocale_L;
if(WiFi.status()==WL_CONNECTED)
{
// Internet disponible
HeureLocale_L = ConvertirHeureBelgique_G.toLocal(ClientNtp_G.getUnixTime());
AfficherHeureLocale(HeureLocale_L); // routine affichage heure locale
}
else
{
// Pas de connexion Internet
Afficheur_G.setCursor(0,0);
Afficheur_G.print("Erreur de ");
Afficheur_G.setCursor(0,1);
Afficheur_G.print(" Connexion");
LectureMesure(); // on laisse la possibilité de commander le coffret par BP hors connexion
}
delay(300);
if((millis() > 60000) && BL_Flag) // on teste si on vient de mettre sous tension et le temps écoulé depuis
{
Afficheur_G.noBacklight(); // on éteint l'écran
digitalWrite(CommandeCF, LOW); // et on coupe le 12V du coffret car ValeurMinute vaut 0 au démarrage
BL_Flag = false; // et on bloque la commande d'extinction pour ne plus la reproduire par la suite
}
CommandeHoraire(HeureLocale_L); // routine de commande horaire pour démarrer les mesures et l'enregistrement des valeurs par le Data Logger, même sans connection internet
}
void AfficherHeureLocale(time_t Heure_P)
{
char Buffer_L[50];
char AbreviationMois_L[12][4]={"Jan","Fev","Mar","Avr","Mai","Jun","Jul","Aou","Sep","Oct","Nov","Dec"};
char AbreviationJour_L[7][4]={"Dim","Lun","Mar","Mer","Jeu","Ven","Sam"};
Afficheur_G.setCursor(0,0);
sprintf(Buffer_L, " %.2d:%.2d:%.2d %.2d:%.2d", hour(Heure_P), minute(Heure_P), second(Heure_P), ValeurMinute, ValeurSeconde);
Afficheur_G.print(Buffer_L);
Afficheur_G.setCursor(0,1);
sprintf(Buffer_L, "%s %.2d %s %d", AbreviationJour_L[weekday(Heure_P)-1], day(Heure_P), AbreviationMois_L[month(Heure_P)-1], year(Heure_P));
Afficheur_G.print(Buffer_L);
}
void CommandeHoraire(time_t Heure_P)
{
// vérification de la validité du temps Unix reçu qui doit s'incrémenter de 1 toutes les secondes
TempsUnix = ClientNtp_G.getUnixTime(); // on charge la valeur Unix reçue par WiFi
// et on compare à la valeur précédente; seule la même valeur (même seconde en cours) ou la valeur suivante sera valide
if((TempsUnix == TempsUnixMem || TempsUnix == TempsUnixMem + 1) && TempsUnix != 0)
{
TempsUnixVal = true; // on valide le flag
}
else
{
TempsUnixVal = false; // sinon on ne valide pas le flag
}
if(TempsUnix > TempsUnixMem)
{
TempsUnixMem = ClientNtp_G.getUnixTime(); // on sauvegarde la valeur en mémoire uniquement si celle-ci est supérieure à la précédente; cela permet d'échapper à une valeur WiFi non reçue ou intempestive
}
// initialisation d'un compteur min:sec synchronisé avec le temps Unix si celui-ci est valide, sinon incrémentation automatique
if(TempsUnixVal) // vérification du temps Unix valide
{
ValeurMinute = minute(Heure_P); // synchronisation de la valeur minute dans le compteur min:sec
ValeurSeconde = second(Heure_P); // synchronisation de la valeur seconde dans le compteur min:sec
temps_T0 = millis(); // on maintient le chrono milliseconde à la valeur millis tant que le temps Unix est valide
}
else // dès que le temps Unix est perdu, on active l'incrémentation automatique
{
//temps_S = temps_T0 + 999; // calcul de la durée d'1 seconde
if(millis() > (temps_T0 + 999))
{
ValeurSeconde++; // on incrémente d'1 seconde toutes les 1000 millisecondes
temps_T0 = millis(); // on réinitialise le chrono millisecondes
}
if(ValeurSeconde > 59)
{
ValeurMinute++; // on incrémente d'1 minute toutes les 60 secondes
ValeurSeconde = 0; // on remet le compteur secondes à zéro
}
if(ValeurMinute > 59) // on remet le chrono min:sec à zéro après la valeur 59:59
{
ValeurMinute = 0;
ValeurSeconde = 0;
temps_T0 = millis();
DL_Flag = true; // on remet le flag à 1 pour le cycle heure pleine
}
}
// on surveille le moment de l'heure pleine
if(ValeurMinute == 00)
{
Afficheur_G.backlight(); // Allumage du rétroéclairage
digitalWrite(CommandeCF, HIGH); // commande de la sortie "12" qui va alimenter le 12V du coffret pendant 1 minute
if(ValeurSeconde == 01)
{
DL_Flag = true; // initialisation de l'autorisation de la commande DL à la seconde 01
}
// pendant la minute de l'heure pleine, on attend 45 secondes pour que les mesures soient stables
if(ValeurSeconde == 45 && DL_Flag)
{
// à la 45ème seconde du chrono (00:45), commande de la sortie "13" qui envoie une impulsion de 1/2 s sur l'entrée External Trigger du Data Logger
digitalWrite(CommandeDL, HIGH);
delay(500);
digitalWrite(CommandeDL, LOW);
DL_Flag = false; // remise à zéro du flag pour ne générer qu'une impulsion vers le DL
}
}
else
{
LectureMesure(); // routine qui permet d'activer la sortie 12V coffret par BP et afficher la mesure pendant 1 minute, sans enregistrer dans le Data Logger
// on coupe le 12V du coffret et le rétro-éclairage de l'écran
if(ValeurMinute == 01) // à la 1ère minute suivante, on coupe le 12V du coffret et on éteint l'écran
{
digitalWrite(CommandeCF, LOW);
Afficheur_G.noBacklight();
}
}
}
void LectureMesure()
{
// Pour lancer la mesure lorsque le BP est relaché, il faut mémoriser son état
etat_BP = digitalRead(EntreeBP); // lecture de l'état du BP
// on vérifie si le bouton est relaché après avoir été activé
if((etat_BP != memoire_BP) && (etat_BP == HIGH) && chrono_BP < 60000)
{
// setup conditionnel, commandes à n'éxécuter qu'une seule fois
if(cond_Setup == false)
{
digitalWrite(CommandeCF, HIGH); // commande du relais 12V coffret
chrono_T0 = millis(); // initialisation du temps T0
cond_Setup = true; // blocage du flag
BP_Flag = true; // autorisation de couper le 12V à la fin du cycle BP
}
// routine proprement dite
else
{
chrono_BP = (millis() - chrono_T0); // calcul du temps écoulé depuis T0
}
}
else
{
cond_Setup = false; // remise à 0 du flag
chrono_BP = 0; // remise à 0 du chrono
memoire_BP = etat_BP; // mémorisation de l'état du BP
if(BP_Flag)
{
digitalWrite(CommandeCF, LOW); // extinction du coffret après le BP
BP_Flag = false; // blocage du flag
}
}
}
Sauf que... une fois le WiFi interrompu, l'affichage "erreur de connexion" ne s'affiche qu'au bout de 12 à 13 secondes, de même mon compteur incrémente 1 sec au bout de cette même période. Il faut plus de 600 sec pour arriver à incrémenter d'1 min.
Le code permettant la lecture du temps Unix depuis le serveur NTP, la transformation en date/heure humaine, la vérification de la connexion WiFi sont recopiés tels quels du tuto fourni avec le ESP8285. Des librairies spécifiques sont incluses pour y arriver. Et je ne sais absolument pas ce qui y est traité.
Ma question est: que fait le ESP8285 lorsque la connexion WiFi est interrompue??? Visiblement il n'exécute pas le else, sauf 1 fois toutes les 12 à 13 secondes.
Dès que je rétabli le WiFi, tout refonctionne normalement, les commandes horaires suivent leur cours.
J'ai essayé de résumer, car je suis sur ce projet depuis septembre dernier, donc j'y ai passé pas mal d'heures et je n'ai pas décrit toutes les étapes.
Le module ESP8285 est monté sur un support et intégré dans un montage électronique, sur un circuit imprimé, pour effectuer les adaptations vers le monde extérieur (alimentation 5VDC, transistors et bornier entrées/sorties vers du câblage).
Encore une fois je suis novice et mon vocabulaire ne correspond peut-être pas au vôtre, veuillez m'en excuser.
D'avance je remercie celle ou celui qui pourrait m'aider.