Horloge Arduino mobile syncronisée ethernet

Bonjour bobino

Ton souci est d'afficher HH:MM:SS et la phase de la lune?
Comme je suis un ignare dans le domaine, comment la phase se calcule ?

Cordialement
jpbbricole

En moyenne, entre deux nouvelles lunes, il se passe 29 jours 12 heures 44 minutes et 2,9 secondes soit 29,53 jours ou plus précisément 1/((1/27,322)-(1/365,25)) jours (formule de Copernic).

Mon afficheur LCD affiche actuellement l'heure et la date du jours sur deux lignes.

J'aimerai afficher sur la 3ème ligne "l'âge de la lune" soit :

  • Une valeur entre 0 et 29 pour le jours depuis la dernière nouvelle lune (un cycle de lune complet étant d'environ 29.53 jours).
  • et également HH:MM:SS depuis le début de la nouvelle lune.

En gros il faut que je définisse dans mon code une date et heure exacte de référence antérieur à laquelle une nouvelle lune avait commencé. (jours : Heure : Min : Sec = 0 : 0 : 0 : 0)
Et en fonction de cette référence calculer l'age actuelle.
c'est plus claire?

il existe pas mal d'exemple ou de bibliothèques pour la lune. Deux exemples:


Si vous pouvez mettre un petit aimant sur l'aiguille vous pouvez vous pourriez avoir un détecteur de position. une autre option (si 180° suffisent) serait de prendre un servo

Bonjour J-M-L,

J'ai fais des essais ce weekend avec la bibliothèque CelliesProject/moonPhase (ton 1er lien).
Mais le code me renvoie un angle et une surface d'exposition pour le 1er janvier 1970.
moon = moonPhase.getPhase(); // gets the current moon phase ( 1/1/1970 at 00:00:00 UTC )
Je ne sait pas comment obtenir les infos en fonction de la date retournée par le réseau.

Pour ton 2ème exemple j'ai un peu de peine a comprendre son code, mais je vais essayer de me pencher dessus.

moonPhase.getPhase()donne la phase à l'heure actuelle mais comme ils disent dans la doc, il faut configurer l'heure système de votre ESP32 sinon vous avez la phase à l'heure 0 qui correspond au 1/1/1970 at 00:00:00 UTC.

regardez cet exemple

Je vois, je vais faire des essais avec ce code, mais je n'ai pas l'impression que cela peu me retourner l'information que je cherche a obtenir comme ce code me retournera un angle et un pourcentage d'exposition. Alors que je cherche à obtenir un age de lune (jour:Heure:minute:seconde depuis le début de la dernière nouvelle lune).

vous pourriez peut-être calculer votre jour en fonction de l'angle ?

Si vous cherchez "arduino lunar clock" il y a plein de projets associés

En bricolant un peu des bouts de code j'en arrive là.

Ça fonctionne, mais toutes les 5 min (environ je n’ai pas chronométré), le LCD me retourne la date de départ du temps unix soit 1 jan 1970 et après quelque seconde ça redevient juste.

Vous avez une idée de la provenance de cette erreur?

void AfficherHeureLocale(time_t Heure_P)
{
    char Buffer_L[50];

    char Buffer_A[50];
    
    unsigned long TempsUnix_L;
    unsigned long Unixsyncro;
    double Unixparcycle;
    unsigned long Unixsyncrosimple;
    unsigned long Agedelune;
    double Agedelunev;
    unsigned long AgedeluneH;
    double AgedeluneHv;
    unsigned long AgedeluneM;
    
    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"};
    
    lcd.setCursor(0,0);
    sprintf(Buffer_L, "      %.2d:%.2d:%.2d", hour(Heure_P), minute(Heure_P), second(Heure_P));
    lcd.print(Buffer_L);
    lcd.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));
    lcd.print(Buffer_L);
    
    lcd.setCursor(0,2);
    lcd.print("    Phase de lune:");
    TempsUnix_L = ClientNtp_G.getUnixTime();    //temps unix en seconde soit temps écoulé depuis le 1er janvier 1970 en seconde
    Unixsyncro = 1955232+TempsUnix_L+33120;           //33120=décalage + 1er janvier 1970 age de la lune = 22.63jours soit 1955232 secondes --> temps unix en sec + 1955232 seconde
    Unixparcycle = Unixsyncro/2551480.63;       //nombre de cycle de lune depuis le janvier 1970 (nombre a virgule)
    Unixsyncrosimple = Unixsyncro/2551480.63;    //nombre de cycle de lune depuis le janvier 1970 (nombre sans virgule)
    Agedelune = (Unixparcycle - Unixsyncrosimple)*29.53102583982387;   //age de la lune depuis sont dernier début de cycle (en jours et sans virgule)
    sprintf(Buffer_A, "     %.2dJ:", Agedelune);
    lcd.setCursor(0,3);
    lcd.print(Buffer_A);
    AgedeluneH = (((Unixparcycle - Unixsyncrosimple)*29.53102583982387) - Agedelune)*24;  // age de la lune - les jours il reste donc les heures (en Heure sans virgule)
    sprintf(Buffer_A, "%.2dH:", AgedeluneH);
    lcd.print(Buffer_A);
    AgedeluneHv = (((Unixparcycle - Unixsyncrosimple)*29.53102583982387) - Agedelune)*24; // age de la lune - les jours il reste donc les heures (en Heure avec virgule)
    AgedeluneM = (AgedeluneHv - AgedeluneH)*60;                                           // age de la lune - les jours - les heures il reste donc les minutes (en Minutes sans virgule)
    sprintf(Buffer_A, "%.2dM     ", AgedeluneM);
    lcd.print(Buffer_A);
 
}

Postez tout le code

Généralement le problème n’est pas où on le cherche…

Voila pour le code entier, mais l'erreur doit provenir de la fin pour l'affichage de l'age de la lune, car je n'avais pas de problèmes avant.

#include <WiFiManager.h>
#include <LiquidCrystal_I2C.h>
#include <EasyNTPClient.h>
#include <WiFiUdp.h>
#include <Timezone.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);     // Afficheur LCD1206 d'addresse 0x27 avec écran de 4 lignes de 20 caractères

WiFiManager wm;
const char* ssid = "ESP32AP";
const char* password = "devkit1234";

WiFiUDP Udp_G; // Objet UDP permettant d'envoyer et recevoir des trames Wi-Fi selon le protocole UDP
EasyNTPClient ClientNtp_G(Udp_G, "pool.ntp.org"); // Objet NTP synchronisé avec "pool.ntp.org"

TimeChangeRule RegleHeureEteFrance_G = {"RHEE", Last, Sun, Mar, 2, 120}; // Règle de passage à l'heure d'été pour la France
TimeChangeRule RegleHeureHiverFrance_G = {"RHHE", Last, Sun, Oct, 3, 60}; // Règle de passage à l'heure d'hiver pour la France
Timezone ConvertirHeureFrance_G(RegleHeureEteFrance_G, RegleHeureHiverFrance_G); // Objet de conversion d'heure avec les caractéristique de la France

void setup()
{
lcd.begin(20,4);
lcd.init();  //Initialisation de l'afficheur
lcd.backlight(); // Allumage du rétroéclairage
lcd.clear();

pinMode(LED_BUILTIN, OUTPUT); // blink
WiFi.mode(WIFI_STA);

Serial.begin(115200);
delay(1000);
Serial.println("\n");
if(!wm.autoConnect(ssid, password))
  Serial.println("Erreur de connexion.");
  
else
  Serial.println("Connexion etablie!");
  digitalWrite(LED_BUILTIN, HIGH);   // allumé LED bleu de l'esp32 (HIGH c'est le niveau du voltage)
  delay(1000);                       // délai
  digitalWrite(LED_BUILTIN, LOW);    // éteindre la LED bleu de l'esp en passant le voltage LOW
  delay(1000);
}


// 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 est disponible
        HeureLocale_L = ConvertirHeureFrance_G.toLocal(ClientNtp_G.getUnixTime());
        AfficherHeureLocale(HeureLocale_L);
    }
    else
    {
        // Pas de connexion internet
        lcd.setCursor(0,0);
        lcd.print("Erreur de       ");
        lcd.setCursor(0,1);
        lcd.print("       Connexion");
    }
    delay(300);
}
void AfficherHeureLocale(time_t Heure_P)
{
    char Buffer_L[50];

    char Buffer_A[50];
    
    unsigned long TempsUnix_L;
    unsigned long Unixsyncro;
    double Unixparcycle;
    unsigned long Unixsyncrosimple;
    unsigned long Agedelune;
    double Agedelunev;
    unsigned long AgedeluneH;
    double AgedeluneHv;
    unsigned long AgedeluneM;
    
    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"};
    
    lcd.setCursor(0,0);
    sprintf(Buffer_L, "      %.2d:%.2d:%.2d", hour(Heure_P), minute(Heure_P), second(Heure_P));
    lcd.print(Buffer_L);
    lcd.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));
    lcd.print(Buffer_L);
    
    lcd.setCursor(0,2);
    lcd.print("    Phase de lune:");
    TempsUnix_L = ClientNtp_G.getUnixTime();    //temps unix en seconde soit temps écoulé depuis le 1er janvier 1970 en seconde
    Unixsyncro = 1955232+TempsUnix_L+33120;           //33120=décalage + 1er janvier 1970 age de la lune = 22.63jours soit 1955232 secondes --> temps unix en sec + 1955232 seconde
    Unixparcycle = Unixsyncro/2551480.63;       //nombre de cycle de lune depuis le janvier 1970 (nombre a virgule)
    Unixsyncrosimple = Unixsyncro/2551480.63;    //nombre de cycle de lune depuis le janvier 1970 (nombre sans virgule)
    Agedelune = (Unixparcycle - Unixsyncrosimple)*29.53102583982387;   //age de la lune depuis sont dernier début de cycle (en jours et sans virgule)
    sprintf(Buffer_A, "     %.2dJ:", Agedelune);
    lcd.setCursor(0,3);
    lcd.print(Buffer_A);
    AgedeluneH = (((Unixparcycle - Unixsyncrosimple)*29.53102583982387) - Agedelune)*24;  // age de la lune - les jours il reste donc les heures (en Heure sans virgule)
    sprintf(Buffer_A, "%.2dH:", AgedeluneH);
    lcd.print(Buffer_A);
    AgedeluneHv = (((Unixparcycle - Unixsyncrosimple)*29.53102583982387) - Agedelune)*24; // age de la lune - les jours il reste donc les heures (en Heure avec virgule)
    AgedeluneM = (AgedeluneHv - AgedeluneH)*60;                                           // age de la lune - les jours - les heures il reste donc les minutes (en Minutes sans virgule)
    sprintf(Buffer_A, "%.2dM     ", AgedeluneM);
    lcd.print(Buffer_A);
 
}

J'ai réussi à isoler le problème.

Quand je vire tout mon code et que je laisse uniquement la connexion wifi et la fonction pour obtenir le temps unix ça bug toujours.
Le problème viens donc soit d'un perte momentanée du réseau, soit du serveur pool.ntp.org qui me retourne une valeur de zéro de temps en temps mais je ne sais pas pourquoi par contre.

M5.lcd.print(ClientNtp_G.getUnixTime());
Serial.println(ClientNtp_G.getUnixTime());

Quand j'isole la fonction ci-dessus dans mon code, l'afficheur série me retourne ça:

03:17:59.175 -> 1626916678
03:17:59.456 -> 1626916678
03:17:59.784 -> 1626916679
03:18:00.064 -> 1626916679
03:18:00.390 -> 1626916679
03:18:00.671 -> 1626916679
03:18:00.998 -> 1626916680
03:18:01.279 -> 1626916680
03:18:01.606 -> 1626916680
03:18:01.885 -> 1626916681
03:18:02.213 -> 1626916681
03:18:02.494 -> 1626916681
03:18:09.585 -> 0
03:18:16.610 -> 0
03:18:23.389 -> 1626916701
03:18:23.667 -> 1626916701
03:18:23.992 -> 1626916701
03:18:24.319 -> 1626916701
03:18:24.602 -> 1626916702
....
03:20:20.348 -> 1626916819
03:20:20.674 -> 1626916820
03:20:20.954 -> 1626916820
03:20:21.280 -> 1626916820
03:20:21.560 -> 1626916820
03:20:21.888 -> 1626916821
03:20:22.169 -> 1626916821
03:20:22.496 -> 1626916821
03:20:22.777 -> 1626916822
03:20:23.103 -> 1626916822
03:20:23.384 -> 1626916822
03:20:30.444 -> 0
03:20:37.504 -> 0
03:20:44.559 -> 0
03:20:51.626 -> 0
03:20:52.095 -> 1626916852
03:20:52.374 -> 1626916852
03:20:52.703 -> 1626916852
03:20:52.982 -> 1626916852
03:20:53.310 -> 1626916853
03:20:53.590 -> 1626916853
03:20:53.920 -> 1626916853
03:20:54.198 -> 1626916854
03:20:54.525 -> 1626916854
03:20:54.805 -> 1626916854

Vous auriez une idée de comment corriger ce bug?
Peut-être que je devrais utiliser un RTC ds3231pour synchroniser mon heure avec le Wifi seulement 1 fois par jours par exemple?

Demander l'heure à un serveur NTP à répétition plusieurs fois par seconde peut sembler disproportionné.
En général on envoie la requête périodiquement, attendu que l'horloge interne d'un ESP8266 peut survivre en autonome quelque temps (tout dépend de la précision de son oscillateur).
Dans ce cas on lit uniquement l'heure à l'aide des fonctions standard C (time.h), par exemple :

// heure UTC
time_t	   time (time_t *_timer);

Et on la met à l'heure périodiquement à l'aide de :
int clock_settime (clockid_t clock_id, const struct timespec *tp);
La struct timespec :

// heure UTC
struct timespec {
  time_t  tv_sec;   /* Seconds */
  long    tv_nsec;  /* Nanoseconds */
};

Bien entendu les nanosecondes peuvent être nulles.

EDIT : mais il y a plus simple. Voir post suivant.

Je l'ai fait sur un projet. La requête NTP est envoyée seulement une fois par mois, ce qui est amplement suffisant pour un DS3231.

La librairie ESP32 dispose de tout ce qu'il faut pour gérer NTP et TIMEZONE. Ce n'est pas la peine d'ajouter quoi que ce soit :

#include <Arduino.h>
#include "WiFi.h"

#define MAX_SIZE 80

const char *ssid = "sssssssssssss";
const char *password = "pppppppppppppp";

const char* ntpServer = "pool.ntp.org";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay (500);
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  // timezone pour la France/Paris
  configTzTime("CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", ntpServer);
}

void loop() {
  time_t timestamp = time(NULL);
  char buffer[MAX_SIZE];
  struct tm *pTime = localtime(&timestamp);
  strftime(buffer, MAX_SIZE, "%d/%m/%Y %H:%M:%S", pTime);
  Serial.println(buffer);
  delay(10000);
}

L'heure NTP est demandée toutes les heures par défaut :
#define SNTP_UPDATE_DELAY_DEFAULT 3600000
Cette constante est dans les options (hardware/esp8266/3.0.0/tools/sdk/lwip2/include/lwip/apps/sntp_opts.h)

Bonjour hbachetti,

Je te remercie pour ton aide!
Je vais essayer d'intégrer ça à mon programme.
Par contre si j'intègre ça, je devrais revoir mes calculs pour l'age de la lune je suppose, comme ceux-ci sont fait à partir du temps unix. Mais bon chaque chose en son temps ^^.

oui, ou si on veut accéder aux champs de la structure tm directement (ici affichage toutes les 5s)

#include <WiFi.h>
const char* ssid = "xxxx";
const char* password = "xxxx";

const char* jours[] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};
const char* mois[]  = {"Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"};

void printTime(struct tm *pTime) {
  Serial.print("Le ");
  Serial.print(jours[pTime->tm_wday]); Serial.write(' ');
  Serial.print(pTime->tm_mday);  Serial.write(' ');
  Serial.print(mois[pTime->tm_mon]); Serial.write(' ');
  Serial.print(pTime->tm_year + 1900); Serial.print(", il est ");
  Serial.print(pTime->tm_hour);  Serial.print('h');
  if (pTime->tm_min < 10) Serial.write('0');
  Serial.print(pTime->tm_min);
  Serial.print(" et ");
  Serial.print(pTime->tm_sec);  Serial.println(" secondes.");
}

void gestionHorloge() {
  static uint32_t dernierEssai;
  if (millis() - dernierEssai >= 5000) {
    struct tm t;
    if (getLocalTime(&t)) printTime(&t);
    dernierEssai = millis();
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial);

  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Erreur connexion WiFi");
    while (true) yield();
  }
  configTzTime("CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", "pool.ntp.org");
}

void loop() {
  gestionHorloge();
}
  time_t timestamp = time(NULL);
  char buffer[MAX_SIZE];
  struct tm *pTime = localtime(&timestamp);

time() renvoie le temps unix ou UTC (GMT), en nombre de secondes (time_t). localtime() la transforme en heure locale, mais si tu utilises gmtime() à la place de localtime() tu auras l'heure UTC dans la même structure tm.

Bonjour bobino

Quel M5stack as-tu ?
Si c'est un ESP32 GREY, l'adresse i2c de la RTC DS3231 0x68 est déjà prise par le MPU6886.
Les CORE2 ont une RTC.
L'ESP32 Basic n'a pas de MPU6886.

Cordialement
jpbbricole

Le code posté au #75 tourne sans dérive notable sur plusieurs heures, avec la mise à jour NTP effectuée toutes les heures. Il faudrait fouiller au niveau milliseconde pour en trouver une je pense.
Mon essai tourne sur un ESP32 DevKitC. A voir avec le M5stack si la précision de l'horloge est aussi bonne. A priori il n'y a pas de raison d'en douter.
Donc, pour conclure un DS3231 me paraît totalement inutile.