IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Convertir une date en une alarme RTC [Arduino ESP32]


Sujet :

Arduino

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut Convertir une date en une alarme RTC
    Bonjour à tous,

    Je souhaite ( toujours dans le même projet)
    réveiller mon ESP32 avec une date "éphémeride" créée avec NTP

    la date éphéméride est appelée "sunsetUTC" sous cette forme structurée :
    -> Coucher de soleil stocké: 2025-07-28T21:14:19+02:00
    et doit donc être incorporée via
    -> rtc.setAlarm1()

    mais je ne vois pas comment faire cela
    car une alarme est sous la forme : DateTime(y,M,d,h,m,s)
    or lorsque je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    rtc.setAlarm1(String(sunsetUTC), DS3231_A1_Minute);
    cela ne fonctionne pas ...

    une petite suggestion me serait utile ...

    merci
    pascal

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    1 545
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 1 545
    Par défaut
    Déjà ton paramètre DS3231_A1_Minute sert pour un déclenchement d'alarme quand les minutes correspondent, ça ne peut pas convenir pour ton besoin, il faut au moins que l'heure aussi corresponde
    Quel est le type de sunsetUTC, une chaine c'est différent d'un DateTime; donc
    si c'est une chaine, il va falloir en extraire les éléments pour les fournir à DateTime,
    si c'est un DateTime, il suffit de la passer tout simplement
    Si c'est une structure comme dans le post#6 de philippe86220 de ce sujet https://forum.arduino.cc/t/sunrise-e...-dst/1042678/6, tu accède au élément par sunnsetUTC->tm_hour (cf sa fontion ephemride)
    https://mikaelpatel.github.io/Arduin.../structtm.html

    https://github.com/garrysblog/DS3231...RTClib-Library

    PS: il faudra géré le décalage UTC indiqué aussi

  3. #3
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    Bonsoir umfred

    Déjà ton paramètre DS3231_A1_Minute sert pour un déclenchement d'alarme quand les minutes correspondent, ça ne peut pas convenir pour ton besoin, il faut au moins que l'heure aussi corresponde
    je pense plutôt utiliser :
    -> DS3231_A1_Date When date, hours, minutes, and seconds match (day of month)

    Quel est le type de sunsetUTC, une chaine c'est différent d'un DateTime; donc
    c'est une structure de ce type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    // Convertir une heure UTC ISO en heure locale (ex: "2025-07-26T19:58:02+00:00" → 21:58:02 pour UTC+2)
    tm parseSunsetToLocal(String sunsetUTC) {
      struct tm tm;
      int y, M, d, h, m, s;
      sscanf(sunsetUTC.c_str(), "%d-%d-%dT%d:%d:%d", &y, &M, &d, &h, &m, &s);
     
      tm.tm_year = y - 1900;
      tm.tm_mon = M - 1;
      tm.tm_mday = d;
      tm.tm_hour = h + 2;  // UTC+2 (été)
      tm.tm_min = m;
      tm.tm_sec = s;
      tm.tm_isdst = 1;
      return tm;
    }
    J'ai donc essaye de faire ceci après la mise à jour du sunsetUTC

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    struct tm sunset = parseSunsetToLocal(sunsetUTC);
    DateTime alarm1Time = DateTime(sunset.tm_year, sunset.tm_mon, sunset.tm_mday, sunset.tm_hour, sunset.tm_min, 0);
    mais çà n'a pas abouti ....

  4. #4
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    Juste pour avoir toutes les données du problèmes, c'est un ESP32 avec un DS3231 attachée en I2C, c'est ça ?

  5. #5
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    Oui , c'est cela

    le but étant simplement de collecter via NTP le "sunset" afin que je puisse déclencher une alarme si des panneaux de véranda ne sont pas fermés
    je souhaite donc :
    1) collecter la date et heur courante ainsi que l'heure du coucher du soleil chaque jour ( pour cela je me connecte au NTP toutes les heures et je regarde si la date à changer )
    2) mettre à jour quotidiennement l'alarme1 de mon RTC DS3231
    3) puis déclencher l'alarme si besoin est

    Pour l'instant , je galère car je n'arrive pas à sauvegarde le "sunset journalier dans les registres du DS3231

    EDIT : j'ajoute que le SQW du DS3231 est relié à l'entrée GPIO 33 du ESP32

  6. #6
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    je progresse mais l'architecture de mon croquis est minable

    j'ai modifié l'heure du DS3231 pour tests voici : les résultats via la console :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    15:03:23.773 -> 192.168.1.110
    15:03:23.773 ->  WiFi connecté.
    15:03:25.391 -> Le réveil n'a pas été causé par un sommeil profond : 0
    15:03:28.007 -> 🌇 Coucher de soleil stocké (UTC): 2025-07-29T21:13:07+02:00
    15:03:28.007 ->  [Alarm1: 29 21:13:07, Mode: DateL'alarme se déclenchera à l'heure spécifiée
    15:03:28.007 -> Boot number: 1
    15:03:29.486 -> 🌇 Coucher de soleil stocké (UTC): 2025-07-29T21:13:07+02:00
    15:03:29.486 -> 🕒 Heure actuelle DS3231 : 21:12:03
    15:03:29.486 -> Going to sleep now
    ---/---
    15:04:37.486 ->  WiFi connecté.
    15:04:37.486 -> Réveil causé par un signal externe utilisant RTC_IO
    15:04:39.839 -> 🌇 Coucher de soleil stocké (UTC): 2025-07-29T21:13:07+02:00
    15:04:39.839 ->  [Alarm1: 29 21:13:07, Mode: DateL'alarme se déclenchera à l'heure spécifiée
    15:04:39.839 -> Boot number: 2
    15:04:41.061 -> 🌇 Coucher de soleil stocké (UTC): 2025-07-29T21:13:07+02:00
    15:04:41.061 -> 🕒 Heure actuelle DS3231 : 21:12:02
    15:04:41.061 -> Going to sleep now
    et voici le croquis

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
     
    #include "RTClib.h"
    #include "driver/rtc_io.h"
    #include <WiFi.h>
    #include <HTTPClient.h>
    #include <ArduinoJson.h>
    #include <Preferences.h>
    #include <Wire.h>
    #include <time.h>
     
    // Définir la broche d'interruption du DS3231 (qui réveillera l'ESP32 - doit être un GPIO RTC)
    #define CLOCK_INTERRUPT_PIN   GPIO_NUM_33  // Only RTC IO are allowed
     
    // WiFi
    const char* ssid = "xxxxxxxx";
    const char* password = "xxxxxxxx";
    IPAddress ip;   // the IP address of your shield
     
    // Coordonnées
    const float latitude = 45.658952;  // 
    const float longitude = 5.27877;
     
    // ⏱ Fuseau horaire France
    const char* ntpServer = "fr.pool.ntp.org";
    const long  gmtOffset_sec = 3600;
    const int   daylightOffset_sec = 3600;
     
    // Stockage
    Preferences preferences;
     
    String getCurrentDate() {
      time_t now = time(nullptr);
      struct tm* timeinfo = localtime(&now);
      char dateStr[11];
      strftime(dateStr, sizeof(dateStr), "%d/%m/%Y", timeinfo);
      return String(dateStr);
    }
     
    // LED pour l'indication visuelle
    const int ledPin = 32;
     
    // Enregistre le nombre de fois où l'ESP32 s'est réveillé
    RTC_DATA_ATTR int bootCount = 0;
     
    // Instance pour le RTC
    RTC_DS3231 rtc;
     
    DateTime alarm1Time = DateTime(0, 0, 0, 0, 0, 0);
     
    // Convertir une heure UTC ISO en heure locale (ex: "2025-07-26T19:58:02+00:00" → 21:58:02 pour UTC+2)
    tm parseSunsetToLocal(String sunsetUTC) {
      struct tm tm;
      int y, M, d, h, m, s;
      sscanf(sunsetUTC.c_str(), "%d-%d-%dT%d:%d:%d", &y, &M, &d, &h, &m, &s);
     
      tm.tm_year = y - 1900;
      tm.tm_mon = M - 1;
      tm.tm_mday = d;
      tm.tm_hour = h + 2;  // UTC+2 (été)
      tm.tm_min = m;
      tm.tm_sec = s;
      tm.tm_isdst = 1;
      return tm;
    }
     
    void onAlarm(){
      Serial.print("Une alarme s'est produite!");
    }
     
     
    //****************************************//
    //              SETUP                      //  
    //****************************************//
    void setup() {
      Serial.begin(115200);
      pinMode (ledPin, OUTPUT);
     
      preferences.begin("sunset", false);
     
      connectWiFi();
      setupTime();
     
      //Imprime le motif de réveil de l'ESP32
      print_wakeup_reason();
     
      // Clignotement de la LED lorsque l'ESP32 se réveille
      digitalWrite(ledPin, HIGH);
      delay(1000);
      digitalWrite(ledPin, LOW);
     
      // Initialiser le RTC
      if(!rtc.begin()) {
        Serial.println("Couldn't find RTC!");
        Serial.flush();
        while (1) delay(10);
      }
     
      if(rtc.lostPower()) {
          // ceci s'ajustera à la date et à l'heure de la compilation
          rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
      }
     
      // Décommenter si vous avez besoin de définir l'heure du RTC
      //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
      rtc.adjust(DateTime(2025, 7, 29, 21, 12, 0));
     
     
      // Nous n'avons pas besoin de la broche 32K, il faut donc la désactiver.
      rtc.disable32K();
     
      // L'alarme déclenche une interruption
      pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
      attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);
     
      // Mettre l'alarme 1, 2 à false (donc l'alarme 1, 2 ne s'est pas produite jusqu'à présent)
      // si ce n'est pas fait, cela conduit facilement à des problèmes, car les deux registres ne sont pas réinitialisés au redémarrage/recompilation.
      rtc.clearAlarm(1);
      rtc.clearAlarm(2);
     
      // Arrêter les signaux oscillants sur la broche SQW, sinon setAlarm1 échouera.
      rtc.writeSqwPinMode(DS3231_OFF);
     
      // Désactiver l'alarme 2 (au cas où elle ne le serait pas déjà)
     // encore une fois, cela n'est pas fait au redémarrage, de sorte qu'une alarme précédemment réglée pourrait facilement être ignorée.
      rtc.disableAlarm(2);
     
      // Programmation d'une alarme
     
      if(!rtc.setAlarm1(alarm1Time, DS3231_A1_Date)) {  // ce mode déclenche l'alarme lorsque la date et heure correspondantes
            Serial.println("Erreur, l'alarme n'a pas été réglée!");
      }else {
          fetchAndStoreSunset();
          checkAlarms();
          Serial.println("L'alarme se déclenchera à l'heure spécifiée");
      }
     
      // Incrémente le numéro de démarrage et l'imprime à chaque redémarrage
      ++bootCount;
      Serial.println("Boot number: " + String(bootCount));
     
      // Configuration du réveil externe
      esp_sleep_enable_ext0_wakeup(CLOCK_INTERRUPT_PIN, 0);  //1 = Haut, 0 = Bas
      // Configurer le pullup/down via RTCIO pour lier les broches de réveil à un niveau inactif pendant le sommeil profond.
      // La broche SQW du RTC est active à un niveau bas.
      rtc_gpio_pulldown_dis(CLOCK_INTERRUPT_PIN);
      rtc_gpio_pullup_en(CLOCK_INTERRUPT_PIN);
     
      // Mettre à jour le coucher du soleil si besoin
      String today = getCurrentDate();
      String lastDate = preferences.getString("dernière_date", "");
      if (today != lastDate) fetchAndStoreSunset();
      preferences.end(); 
     
      DateTime now = rtc.now();
     
      // Heure actuelle du DS3231
      char buf[9];
      sprintf(buf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
      Serial.print("🕒 Heure actuelle DS3231 : ");
      Serial.println(buf);
     
      // Charger l'heure du coucher du soleil depuis la NVS
      preferences.begin("sunset", true);
      String sunsetUTC = preferences.getString("dernier_coucher du soleil", "");
      preferences.end();
     
     
      if (sunsetUTC != "") {
        struct tm sunset = parseSunsetToLocal(sunsetUTC);
     
        // Comparaison
        if (now.hour() > sunset.tm_hour ||
            (now.hour() == sunset.tm_hour && now.minute() >= sunset.tm_min)) {
            Serial.println("🌙 Il fait nuit (après le coucher du soleil)");
            // Allumer LED ou déclencher action
            digitalWrite(ledPin, HIGH);
        } else {
          Serial.println("☀️ Il fait encore jour");
          digitalWrite(ledPin, LOW);
        }
      }
     
      //S'endormir maintenant jusqu'à ce qu'une alarme se déclenche
      Serial.println("Going to sleep now");
      esp_deep_sleep_start();
    }
     
    //****************************************//
    //              LOOP                      //  
    //****************************************//
    void loop() {
      // Le code n'atteint jamais la boucle, car l'ESP32 se met en veille à la fin de l'installation.
      Serial.print("Ce document ne sera jamais imprimé!");
    }
     
    // Méthode permettant d'imprimer la raison pour laquelle l'ESP32 a été réveillé de son sommeil
    void print_wakeup_reason() {
      esp_sleep_wakeup_cause_t wakeup_reason;
      wakeup_reason = esp_sleep_get_wakeup_cause();
      switch (wakeup_reason) {
        case ESP_SLEEP_WAKEUP_EXT0:     Serial.println("Réveil causé par un signal externe utilisant RTC_IO"); break;
        case ESP_SLEEP_WAKEUP_EXT1:     Serial.println("Réveil provoqué par un signal externe utilisant RTC_CNTL"); break;
        case ESP_SLEEP_WAKEUP_TIMER:    Serial.println("Réveil provoqué par la minuterie"); break;
        case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Réveil provoqué par le pavé tactile"); break;
        case ESP_SLEEP_WAKEUP_ULP:      Serial.println("Réveil causé par le programme ULP"); break;
        default:                        Serial.printf("Le réveil n'a pas été causé par un sommeil profond : %d\n", wakeup_reason); break;
      }
    }
     
    //****************************************//
    void connectWiFi() {
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) delay(500);
      ip = WiFi.localIP();
      Serial.println(ip);
      Serial.println(" WiFi connecté.");
    }
     
    //****************************************//
    void setupTime() {
      // ⏲ Initialisation du temps NTP
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
      struct tm timeinfo;
      if (!getLocalTime(&timeinfo)) {
        Serial.println("Échec d'obtention du temps.");
        return;
      }
    }
     
    //****************************************//
    void fetchAndStoreSunset() {
      HTTPClient http;
      String url = "https://api.sunrise-sunset.org/json?lat=" + String(latitude, 6) + "&lng=" + String(longitude, 6) + "&formatted=0"+ "&tzid=Europe/Paris";
      http.begin(url);
      int httpCode = http.GET();
      if (httpCode > 0) {
        String payload = http.getString();
        DynamicJsonDocument doc(1024);
        if (!deserializeJson(doc, payload)) {
          String sunsetUTC = doc["results"]["sunset"];
          preferences.putString("dernier coucher du soleil", sunsetUTC);
          preferences.putString("dernière date", getCurrentDate());
          Serial.println("🌇 Coucher de soleil stocké (UTC): " + sunsetUTC);
     
          struct tm sunset = parseSunsetToLocal(sunsetUTC);
          //setAlarm1(DateTime(2020, 6, 25, 15, 34, 0), DS3231_A1_Hour) // exemple
          rtc.setAlarm1(DateTime(sunset.tm_year, sunset.tm_mon, sunset.tm_mday, sunset.tm_hour-2, sunset.tm_min, sunset.tm_sec),DS3231_A1_Date); 
     
        }
      }
      http.end();
    }
     
     
    //********************************************//
    void checkAlarms()
    {
        DateTime alarm1Time = rtc.getAlarm1();
        Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
        char alarm1Date[12] = "DD hh:mm:ss";
        alarm1Time.toString(alarm1Date);
        Serial.print(" [Alarm1: ");
        Serial.print(alarm1Date);
        Serial.print(", Mode: ");
        switch (alarm1mode) {
          case DS3231_A1_PerSecond: Serial.print("PerSecond"); break;
          case DS3231_A1_Second: Serial.print("Second"); break;
          case DS3231_A1_Minute: Serial.print("Minute"); break;
          case DS3231_A1_Hour: Serial.print("Hour"); break;
          case DS3231_A1_Date: Serial.print("Date"); break;
          case DS3231_A1_Day: Serial.print("Day"); break;
        }
    }

  7. #7
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    L'ESP32 est endormi le reste du temps et vous voulez le réveiller par une interruption, c'est cela ?

  8. #8
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    Puisque vous avez l'heure et le jour via NTP ainsi que la position géographique, pourquoi ne pas utiliser une formule pour calculer le coucher du soleil directement plutôt que de faire une requête à un service tiers ?

  9. #9
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    j'ai bien essayé cette librairie
    : Dusk2Dawn (par Joao Lopes)

    mais le programme se plante même avec l'exemple alors j'ai abandonné
    je ne connais pas d'autre façon de faire

  10. #10
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    Citation Envoyé par cobra38 Voir le message
    je ne connais pas d'autre façon de faire
    sur le forum Arduino, un utilisateur (Bricoleau) avait posté un bout de code avec les formules

    https://forum.arduino.cc/t/calcul-ep...-soleil/266532

    lire la discussion, elle est intéressante.

  11. #11
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    Pour l'instant je pense avoir réussi à faire tourner le programme en réel
    voici le résultat de la console :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
     
    /// LANCEMENT DU PROGRAMME  ////
    16:45:54.793 -> WiFi connecté: 192.168.1.110
    16:45:57.725 -> Le réveil n'a pas été causé par un sommeil profond : 0
    16:46:00.466 -> 🌇 Coucher de soleil local stocké : 2025-07-29T21:13:07+02:00
    16:46:00.466 -> L'alarme se déclenchera à l'heure spécifiée
    16:46:00.466 -> [ Alarme 1: 29 21:13:07, Mode: Date ]
    16:46:00.466 -> --------------------
    16:46:00.466 -> Boot number: 1
    16:46:00.466 -> --------------------
    16:46:02.022 -> 🌇 Coucher de soleil local stocké : 2025-07-29T21:13:07+02:00
    16:46:02.022 -> 🕒 Heure actuelle DS3231 : 16:45:24  <========================
    16:46:02.022 -> Going to sleep now
    /////////////////////////////////////////////////////////////////////////////////
     
    ///// REVEIL DE L'ESP32  ////////////////////////////////////////////////////
    21:13:49.446 -> WiFi connecté: 192.168.1.110
    21:13:49.446 -> Réveil causé par un signal externe utilisant RTC_IO   <======================
    21:13:51.894 -> 🌇 Coucher de soleil local stocké : 2025-07-29T21:13:07+02:00
    21:13:51.894 -> L'alarme se déclenchera à l'heure spécifiée
    21:13:51.894 -> [ Alarme 1: 29 21:13:07, Mode: Date ]
    21:13:51.894 -> --------------------
    21:13:51.894 -> Boot number: 2
    21:13:51.894 -> --------------------
    21:13:53.232 -> 🌇 Coucher de soleil local stocké : 2025-07-29T21:13:07+02:00
    21:13:53.232 -> 🕒 Heure actuelle DS3231 : 21:13:14    <===========================
    21:13:53.232 -> Going to sleep now

  12. #12
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    Citation Envoyé par Jay M Voir le message
    sur le forum Arduino, un utilisateur (Bricoleau) avait posté un bout de code avec les formules

    https://forum.arduino.cc/t/calcul-ep...-soleil/266532

    lire la discussion, elle est intéressante.
    J'ai testé ce programme et j'ai rentré mes données GPS converties en degrés
    et j'obtiens ceci :

    23:29:21.802 -> Date Lever Meridien Coucher
    23:29:21.866 -> 29/07/2025 05:02:42 12:27:37 19:51:48

    or la vraie valeur de coucher est :

    21:13:53.232 -> 🌇 Coucher de soleil local stocké : 2025-07-29T21:13:07+02:00

    la différence est que l'auteur attend des données de Longitude Ouest mais moi il s'agit de Longitude Est (?)


    EDIT pour les coordonnées Est , il faut mettre par ex -5 et non pas 5
    ce qui donne pour la journée du 30/07

    08:40:41.024 ->
    08:40:41.024 -> Date Lever Meridien Coucher
    08:40:41.024 -> 30/07/2025 04:21:35 11:45:21 19:08:22
    08:40:41.024 ->
    08:40:41.024 -> Duree moyenne de calcul d'une ephemeride = 1000 microsecondes

    Le problème maintenant reste toujours le m^me : comment mettre cette valeur dans l'alarme1 RTC .....

  13. #13
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    imaginez que vous ayez la date et l'heure julienne comme dans le code de bricoleau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      int annee = 2025;
      int mois = 7;
      int jour = 30;
      double heureJulienne = 0.25;  // exemple : 18h00 UTC le 30 juillet 2025
    si vous utilisez la bibliothèque RTCLib d'adafruit ils ont un exemple sur les alarmes.

    si vous regardez la classe pour la DS3231, ils ont différents flags pour le type de l'alarme 1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /** DS3231 Alarm modes for alarm 1 */
    enum Ds3231Alarm1Mode {
      DS3231_A1_PerSecond = 0x0F, /**< Alarm once per second */
      DS3231_A1_Second = 0x0E,    /**< Alarm when seconds match */
      DS3231_A1_Minute = 0x0C,    /**< Alarm when minutes and seconds match */
      DS3231_A1_Hour = 0x08,      /**< Alarm when hours, minutes and seconds match */
      DS3231_A1_Date = 0x00,      /**< Alarm when date (day of month), hours, minutes and seconds match */
      DS3231_A1_Day = 0x10        /**< Alarm when day (day of week), hours,
                                       minutes and seconds match */
    };
    cela contient DS3231_A1_Hour et DS3231_A1_Date qui permettent un déclenchement à une heure/minute/seconde précise (avec le jour ou pas).

    vous pourriez donc avoir une fonction (tapée ici non testée) un peu comme cela

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    void programmerAlarme(int annee, int mois, int jour, double heureJulienne) {
     
      // on calcule l'heure, minute et seconde comme dans le code de bricoleau
      // dans sa fonction afficherHeure() en modifiant éventuellement le jour
     
      int h, m, s;
     
      double d = heureJulienne + 0.5;
     
      if (d < 0.0) {
        jour -= 1;
        d += 1.0;
      } else if (d >= 1.0) {
        jour += 1;
        d -= 1.0;
      }
     
      h = d * 24.0;
      d -= (double) h / 24.0;
      m = d * 1440.0;
      d -= (double) m / 1440.0;
      s = d * 86400.0 + 0.5;
     
      // puis on fabrique un DateTime avec ces infos
      DateTime alarme(annee, mois, jour, h, m, s);
     
      // qu'on utilise pour armer l'alarme1 en mode date+heure exacte
      rtc.setAlarm1(alarme, DS3231_A1_Date);
      rtc.enableAlarm(DS3231_ALARM_1);
    }
    et dans votre code l'appeler avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
      programmerAlarme(annee, mois, jour, heureJulienne);
    à tester

  14. #14
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    Merci encore Jay M

    j'ai donc repris le programme de Bricoleau
    que j'ai fusionné avec la gestion RTC du DS3231 pour avoir l'heure et la date courante
    voici le croquis

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
     
    #include "RTClib.h"
    #include "driver/rtc_io.h"
    #include <WiFi.h>
    #include <HTTPClient.h>
    #include <ArduinoJson.h>
    #include <Preferences.h>
    #include <Wire.h>
    #include <time.h>
    #include <math.h>
     
    // Définir la broche d'interruption du DS3231 (qui réveillera l'ESP32 - doit être un GPIO RTC)
    #define CLOCK_INTERRUPT_PIN   GPIO_NUM_33  // Only RTC IO are allowed
     
    // LED pour l'indication visuelle
    const int ledPin = 32;
     
    // Enregistre le nombre de fois où l'ESP32 s'est réveillé
    RTC_DATA_ATTR int bootCount = 0;
     
    // Instance pour le RTC
    RTC_DS3231 rtc;
     
    DateTime alarm1Time = DateTime(0, 0, 0, 0, 0, 0);
     
    void onAlarm(){
      Serial.print("Une alarme s'est produite!");
    }
     
     void initialiserAffichage()
      {
        Serial.begin(115200);
      }
     
      void afficherTexte(char texte[])
      {
        Serial.print(texte);
      }
    /*
    unsigned long int millis()
      {
          return (unsigned long int) clock() * 1000 / CLOCKS_PER_SEC;
      }
    */
    //****************************************//
    //              SETUP                      //  
    //****************************************//
    void setup() {
      Serial.begin(115200);
      pinMode (ledPin, OUTPUT);
     
      char texte[80];
      initialiserAffichage();
     
      //Imprime le motif de réveil de l'ESP32
      print_wakeup_reason();
     
      // Clignotement de la LED lorsque l'ESP32 se réveille
      digitalWrite(ledPin, HIGH);
      delay(1000);
      digitalWrite(ledPin, LOW);
     
      // Initialiser le RTC
      if(!rtc.begin()) {
        Serial.println("Couldn't find RTC!");
        Serial.flush();
        while (1) delay(10);
      }
     
      if(rtc.lostPower()) {
          // ceci s'ajustera à la date et à l'heure de la compilation
          rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
      }
     
      // Décommenter si vous avez besoin de définir l'heure du RTC
      //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
      //rtc.adjust(DateTime(2025, 7, 29, 15, 16, 0));
     
     
      // Nous n'avons pas besoin de la broche 32K, il faut donc la désactiver.
      rtc.disable32K();
     
      // L'alarme déclenche une interruption
      pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP);
      attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING);
     
      // Mettre l'alarme 1, 2 à false (donc l'alarme 1, 2 ne s'est pas produite jusqu'à présent)
      // si ce n'est pas fait, cela conduit facilement à des problèmes, car les deux registres ne sont pas réinitialisés au redémarrage/recompilation.
      rtc.clearAlarm(1);
      rtc.clearAlarm(2);
     
      // Arrêter les signaux oscillants sur la broche SQW, sinon setAlarm1 échouera.
      rtc.writeSqwPinMode(DS3231_OFF);
     
      // Désactiver l'alarme 2 (au cas où elle ne le serait pas déjà)
     // encore une fois, cela n'est pas fait au redémarrage, de sorte qu'une alarme précédemment réglée pourrait facilement être ignorée.
      rtc.disableAlarm(2);
     
      // Programmation d'une alarme
      if(!rtc.setAlarm1(alarm1Time, DS3231_A1_Date)) {  // ce mode déclenche l'alarme lorsque la date et heure correspondantes
            Serial.println("Erreur, l'alarme n'a pas été réglée!");
      }else {
          // Lat : 45.6590039 & Long : 5.278757777777778  => Lat : N 45 39 32.414 & Long : E 5 16 43
          testerEphemeride(30, 07, 2025, 1, -5, 16, 43, 45, 39, 32);
          Serial.println("L'alarme se déclenchera à l'heure spécifiée");
          checkAlarms();
      }
     
      // Incrémente le numéro de démarrage et l'imprime à chaque redémarrage
      ++bootCount;
      Serial.println("--------------------");
      Serial.println("Boot number: " + String(bootCount));
      Serial.println("--------------------");
     
      // Configuration du réveil externe
      esp_sleep_enable_ext0_wakeup(CLOCK_INTERRUPT_PIN, 0);  //1 = Haut, 0 = Bas
      // Configurer le pullup/down via RTCIO pour lier les broches de réveil à un niveau inactif pendant le sommeil profond.
      // La broche SQW du RTC est active à un niveau bas.
      rtc_gpio_pulldown_dis(CLOCK_INTERRUPT_PIN);
      rtc_gpio_pullup_en(CLOCK_INTERRUPT_PIN);
     
      DateTime now = rtc.now();
     
      // Heure actuelle du DS3231
      char buf[9];
      sprintf(buf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
      Serial.print("🕒 Heure actuelle DS3231 : ");
      Serial.println(buf);
     
      //S'endormir maintenant jusqu'à ce qu'une alarme se déclenche
      Serial.println("Going to sleep now");
      esp_deep_sleep_start();
    }
     
    //****************************************//
    //              LOOP                      //  
    //****************************************//
    void loop() {
      // Le code n'atteint jamais la boucle, car l'ESP32 se met en veille à la fin de l'installation.
      Serial.print("Ce document ne sera jamais imprimé!");
    }
     
     
     
    // Méthode permettant d'imprimer la raison pour laquelle l'ESP32 a été réveillé de son sommeil
    void print_wakeup_reason() {
      esp_sleep_wakeup_cause_t wakeup_reason;
      wakeup_reason = esp_sleep_get_wakeup_cause();
      switch (wakeup_reason) {
        case ESP_SLEEP_WAKEUP_EXT0:     Serial.println("Réveil causé par un signal externe utilisant RTC_IO"); break;
        case ESP_SLEEP_WAKEUP_EXT1:     Serial.println("Réveil provoqué par un signal externe utilisant RTC_CNTL"); break;
        case ESP_SLEEP_WAKEUP_TIMER:    Serial.println("Réveil provoqué par la minuterie"); break;
        case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Réveil provoqué par le pavé tactile"); break;
        case ESP_SLEEP_WAKEUP_ULP:      Serial.println("Réveil causé par le programme ULP"); break;
        default:                        Serial.printf("Le réveil n'a pas été causé par un sommeil profond : %d\n", wakeup_reason); break;
      }
    }
     
     
    //********************************************//
    void checkAlarms()
    {
        DateTime alarm1Time = rtc.getAlarm1();
        Ds3231Alarm1Mode alarm1mode = rtc.getAlarm1Mode();
        char alarm1Date[12] = "DD hh:mm:ss";
        alarm1Time.toString(alarm1Date);
        Serial.print("[ Alarme 1: ");
        Serial.print(alarm1Date);
        Serial.print(", Mode: ");
        switch (alarm1mode) {
          case DS3231_A1_PerSecond: Serial.println("PerSecond ]"); break;
          case DS3231_A1_Second: Serial.println("Second ]"); break;
          case DS3231_A1_Minute: Serial.println("Minute ]"); break;
          case DS3231_A1_Hour: Serial.println("Hour ]"); break;
          case DS3231_A1_Date: Serial.println("Date ]"); break;
          case DS3231_A1_Day: Serial.println("Day ]"); break;
        }
        Serial.print("");
    }
     
     
    //********************************************//
    void calculerEphemeride(int jour, int mois, int annee, double longitude_ouest, double latitude_nord, double *lever, double *meridien, double *coucher)
    {
      int nbjours;
      const double radians = M_PI / 180.0;
      double d, x, sinlat, coslat;
     
      //calcul nb jours écoulés depuis le 01/01/2000
      if (annee > 2000) annee -= 2000;
      nbjours = (annee*365) + ((annee+3)>>2) + jour - 1;
      switch (mois)
      {
        case  2 : nbjours +=  31; break;
        case  3 : nbjours +=  59; break;
        case  4 : nbjours +=  90; break;
        case  5 : nbjours += 120; break;
        case  6 : nbjours += 151; break;
        case  7 : nbjours += 181; break;
        case  8 : nbjours += 212; break;
        case  9 : nbjours += 243; break;
        case 10 : nbjours += 273; break;
        case 11 : nbjours += 304; break;
        case 12 : nbjours += 334; break;
      }
      if ((mois > 2) && (annee&3 == 0)) nbjours++;
      d = nbjours;
     
      //calcul initial meridien & lever & coucher
      x = radians * latitude_nord;
      sinlat = sin(x);
      coslat = cos(x);
      calculerCentreEtVariation(longitude_ouest, sinlat, coslat, d + longitude_ouest/360.0, meridien, &x);
      *lever = *meridien - x;
      *coucher = *meridien + x;
     
      //seconde itération pour une meilleure précision de calcul du lever
      calculerCentreEtVariation(longitude_ouest, sinlat, coslat, d + *lever, lever, &x);
      *lever = *lever - x;
     
      //seconde itération pour une meilleure précision de calcul du coucher
      calculerCentreEtVariation(longitude_ouest, sinlat, coslat, d + *coucher, coucher, &x);
      *coucher = *coucher + x;
    }
     
     
     
    //********************************************//
    void afficherDate(int jour, int mois, int annee)
    {
      char texte[20];
      sprintf(texte, "%02d/%02d/%04d", jour, mois, annee);
      afficherTexte(texte);
    }
     
    //********************************************//
    void afficherCoordonnee(int degre, int minute, int seconde, char c)
    {
      char texte[20];
      if (degre < 0)
      {
        degre = -degre;
        if (c == 'W') c = 'E';
        if (c == 'N') c = 'S';
      }
      sprintf(texte,"%dd%d'%d''%c", degre, minute, seconde, c);
      afficherTexte(texte);
    }
     
    //********************************************//
    void afficherHeure(double d)
    {
      int h,m,s;
      char texte[20];
     
      d = d + 0.5;
     
      if (d < 0.0)
      {
        afficherTexte("(J-1)");
        d = d + 1.0;
      }
      else
      {
        if (d > 1.0)
        {
          afficherTexte("(J+1)");
          d = d - 1.0;
        }
        else
        {
          afficherTexte("     ");
        }
      }
     
      h = d * 24.0;
      d = d - (double) h / 24.0;
      m = d * 1440.0;
      d = d - (double) m / 1440.0;
      s = d * 86400.0 + 0.5;
     
      sprintf(texte,"%02d:%02d:%02d",h,m,s);
      afficherTexte(texte);
    }
     
    //********************************************//
    double calculerCoordonneeDecimale(int degre, int minute, int seconde)
    {
      if (degre > 0)
      {
        return (double) degre + minute / 60.0 + seconde / 3600.0;
      }
      else
      {
        return (double) degre - minute / 60.0 - seconde / 3600.0;
      }
    }
     
    //********************************************//
    void avancerDate(int *jour, int *mois, int *annee)
    {
      (*jour)++;
      if ((*jour>31)
      || ((*jour==31) && (*mois==2 || *mois==4 || *mois==6 || *mois==9 || *mois==11))
      || ((*jour==30) && (*mois==2))
      || ((*jour==29) && (*mois==2) && (((*annee)&3) != 0)))
      {
        *jour = 1;
        (*mois)++;
        if (*mois > 12)
        {
          *mois = 1;
          (*annee)++;
        }
      }
    }
     
    int nb_calculs = 0;
    unsigned long int duree_calculs = 0;
     
    //********************************************//
    void testerEphemeride(int jour, int mois, int annee, int nbjours,
                          int longitude_ouest_degres, int longitude_ouest_minutes, int longitude_ouest_secondes,
                          int latitude_nord_degres, int latitude_nord_minutes, int latitude_nord_secondes)
    {
      double longitude_ouest, latitude_nord;
      double lever, meridien, coucher;
      int i;
      unsigned long int duree;
     
      afficherTexte("\nCalcul ephemeride au lieu ");
      afficherCoordonnee(longitude_ouest_degres, longitude_ouest_minutes, longitude_ouest_secondes, 'W');
      afficherTexte(" - ");
      afficherCoordonnee(latitude_nord_degres, latitude_nord_minutes, latitude_nord_secondes, 'N');
      afficherTexte("\n\nDate            Lever         Meridien      Coucher\n");
     
      longitude_ouest = calculerCoordonneeDecimale(longitude_ouest_degres, longitude_ouest_minutes, longitude_ouest_secondes);
      latitude_nord = calculerCoordonneeDecimale(latitude_nord_degres, latitude_nord_minutes, latitude_nord_secondes);
     
      for (i=0; i<nbjours; i++)
      {
        afficherDate(jour, mois, annee);
        afficherTexte(" ");
     
        duree = millis();
        calculerEphemeride(jour, mois, annee, longitude_ouest, latitude_nord, &lever, &meridien, &coucher);
        duree = millis() - duree;
        duree_calculs += duree;
        nb_calculs++;
     
        afficherHeure(lever);
        afficherTexte(" ");
        afficherHeure(meridien);
        afficherTexte(" ");
        afficherHeure(coucher);
        afficherTexte("\n");
     
        avancerDate(&jour, &mois, &annee);
     
      /*------------------------------------*/  
      int Aannee = annee;
      int Amois = mois;
      int Ajour = jour;
      double AheureJulienne = coucher;  // exemple : 18h00 UTC le 30 juillet 2025
      programmerAlarme(Aannee, Amois, Ajour, AheureJulienne); 
     
     }  
     
     
    }
     
    void programmerAlarme(int annee, int mois, int jour, double heureJulienne) {
     
      // on calcule l'heure, minute et seconde comme dans le code de bricoleau
      // dans sa fonction afficherHeure() en modifiant éventuellement le jour
     
      int h, m, s;
     
      double d = heureJulienne + 0.5;
     
      if (d < 0.0) {
        jour -= 1;
        d += 1.0;
      } else if (d >= 1.0) {
        jour += 1;
        d -= 1.0;
      }
     
      h = d * 24.0;
      d -= (double) h / 24.0;
      m = d * 1440.0;
      d -= (double) m / 1440.0;
      s = d * 86400.0 + 0.5;
     
      // puis on fabrique un DateTime avec ces infos
      DateTime alarme(annee, mois, jour, h+2, m, s);
     
      // qu'on utilise pour armer l'alarme1 en mode date+heure exacte
      rtc.setAlarm1(alarme, DS3231_A1_Date);
      //rtc.enableAlarm(DS3231_ALARM_1);
    }
     
    void calculerCentreEtVariation(double longitude_ouest, double sinlat, double coslat, double d, double *centre, double *variation)
    {
      //constantes précalculées par le compilateur
      const double M_2PI = 2.0 * M_PI;
      const double degres = 180.0 / M_PI;
      const double radians = M_PI / 180.0;
      const double radians2 = M_PI / 90.0;
      const double m0 = 357.5291;
      const double m1 = 0.98560028;
      const double l0 = 280.4665;
      const double l1 = 0.98564736;
      const double c0 = 0.01671;
      const double c1 = degres * (2.0*c0 - c0*c0*c0/4.0);
      const double c2 = degres * c0*c0 * 5.0 / 4.0;
      const double c3 = degres * c0*c0*c0 * 13.0 / 12.0;
      const double r1 = 0.207447644182976; // = tan(23.43929 / 180.0 * M_PI / 2.0)
      const double r2 = r1*r1;
      const double d0 = 0.397777138139599; // = sin(23.43929 / 180.0 * M_PI)
      const double o0 = -0.0106463073113138; // = sin(-36.6 / 60.0 * M_PI / 180.0)
     
      double M,C,L,R,dec,omega,x;
     
      //deux ou trois petites formules de calcul
      M = radians * fmod(m0 + m1 * d, 360.0);
      C = c1*sin(M) + c2*sin(2.0*M) + c3*sin(3.0*M);
      L = fmod(l0 + l1 * d + C, 360.0);
      x = radians2 * L;
      R = -degres * atan((r2*sin(x))/(1+r2*cos(x)));
      *centre = (C + R + longitude_ouest)/360.0;
     
      dec = asin(d0*sin(radians*L));
      omega = (o0 - sin(dec)*sinlat)/(cos(dec)*coslat);
      if ((omega > -1.0) && (omega < 1.0))
        *variation = acos(omega) / M_2PI;
      else
        *variation = 0.0;
    }
    et le resultat à la console est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    15:08:20.747 -> Date                 Lever           Meridien       Coucher
    15:08:20.747 -> 30/07/2025      04:21:35      11:45:21      19:08:22
    15:08:20.747 -> L'alarme se déclenchera à l'heure spécifiée
    15:08:20.747 -> [ Alarme 1: 31 21:08:22, Mode: Date ]
    15:08:20.747 -> --------------------
    15:08:20.747 -> Boot number: 1
    15:08:20.747 -> --------------------
    15:08:20.747 -> 🕒 Heure actuelle DS3231 : 15:07:44
    15:08:20.747 -> Going to sleep now
    2 remarques :
    1) j'ai du rajouter +2h pour avoir l'heure locale
    2) j'ai une date d'alarme au 31 , alors que mon test s'effectue correctement le 30 , je n'en ai pas trouvé la raison

  15. #15
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    Citation Envoyé par cobra38 Voir le message
    1) j'ai du rajouter +2h pour avoir l'heure locale
    2) j'ai une date d'alarme au 31 , alors que mon test s'effectue correctement le 30 , je n'en ai pas trouvé la raison
    le plus simple est de conserver la RTC en heure UTC comme ça vous n'avez pas à gérer le changement d'heure ou le décalage horaire (le +2)

    pour l'histoire du jour qui change, la fonction testerEphemeride() permet de voir l'évolution sur plusieurs jours et vous appelez bien la fonction avec nbjours étant 1 (donc un seul affichage) mais vous avez mis l'enregistrement de l'alarme APRES l'appel à avancerDate() qui change le jour.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
        avancerDate(&jour, &mois, &annee);
     
      /*------------------------------------*/  
      int Aannee = annee;
      int Amois = mois;
      int Ajour = jour;
      double AheureJulienne = coucher;  // exemple : 18h00 UTC le 30 juillet 2025
      programmerAlarme(Aannee, Amois, Ajour, AheureJulienne);

    vous devriez modifier cette fonction pour enlever la boucle for, enlever le changement de date et enlever le paramètre nombre de jours ou alors juste utiliser la fonction calculerEphemeride() qui est celle qui compte.

  16. #16
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    Bien vu ...Merci !!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    15:58:37.852 -> Date            Lever         Meridien      Coucher
    15:58:37.852 -> 30/07/2025      04:21:35      11:45:21      19:08:22
    15:58:37.852 -> L'alarme se déclenchera à l'heure spécifiée
    15:58:37.852 -> [ Alarme 1: 30 19:08:22, Mode: Date ]
    15:58:37.852 -> --------------------
    15:58:37.852 -> Boot number: 1
    15:58:37.852 -> --------------------
    15:58:37.852 -> 🕒 Heure actuelle DS3231 : 13:57:59    <=== Heure UTC
    15:58:37.852 -> Going to sleep now
    Il me reste donc à réveiller l'ESP32 chaque jour à 00:01 pour afficher l'horaire du coucher de soleil , c'est çà ?

    Par ailleurs, je souhaiterais avoir quelques précisons svp
    Je dois rajouter dans ce croquis un certain nombre de tests , ( ex , T° ext etc ... ) , le croquis devient volumineux
    comment puis-je faire pour séparer les fonctions et faire par exemple un sous-programme RTC et Ephemeride si cela est possible

  17. #17
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    Citation Envoyé par cobra38 Voir le message
    Il me reste donc à réveiller l'ESP32 chaque jour à 00:01 pour afficher l'horaire du coucher de soleil , c'est çà ?
    vous pouvez profiter du réveil lors du coucher du soleil pour planifier celui du lendemain. Vous avez la DateTime du jour, vous ajouter un TimeSpan de 24h, ça vous donne le lendemain et vous calculer le coucher du soleil et l'enregistrez dans la RTC. Comme ça votre ESP ne se réveille qu'une seule fois au coucher du soleil.

    Citation Envoyé par cobra38 Voir le message
    Je dois rajouter dans ce croquis un certain nombre de tests , ( ex , T° ext etc ... ) , le croquis devient volumineux
    comment puis-je faire pour séparer les fonctions et faire par exemple un sous-programme RTC et Ephemeride si cela est possible
    Pour cela on fait de la compilation séparée et de l'édition de lien (ce que l'IDE sait gérer). Le mieux est de créer un fichier .h et un fichier .cpp contenant les calculs à mettre dans le même répertoire que votre sketch.

    Fichier ephemeride.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    #ifndef EPHEMERIDE_H
    #define EPHEMERIDE_H
     
    // Calcul éphéméride solaire (lever, coucher, passage au méridien)
    // D'après le code original de démonstration par @bricoleau (2014)
    // https://forum.arduino.cc/t/calcul-ephemeride-precis-lever-et-coucher-de-soleil/266532
     
    void calculerEphemeride(int jour, int mois, int annee,
                            double longitude_ouest, double latitude_nord,
                            double *lever, double *meridien, double *coucher);
     
    void afficherHeureJulienne(double d);
     
    #endif // EPHEMERIDE_H


    Fichier ephemeride.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
     
    // D'après le code original de démonstration par @bricoleau (2014)
    // https://forum.arduino.cc/t/calcul-ephemeride-precis-lever-et-coucher-de-soleil/266532
     
    #include "ephemeride.h"
    #include <Arduino.h>
    #include <math.h>
     
    static void calculerCentreEtVariation(double longitude_ouest, double sinlat, double coslat, double d, double *centre, double *variation)
    {
      const double M_2PI = 2.0 * M_PI;
      const double degres = 180.0 / M_PI;
      const double radians = M_PI / 180.0;
      const double radians2 = M_PI / 90.0;
      const double m0 = 357.5291;
      const double m1 = 0.98560028;
      const double l0 = 280.4665;
      const double l1 = 0.98564736;
      const double c0 = 0.01671;
      const double c1 = degres * (2.0 * c0 - c0 * c0 * c0 / 4.0);
      const double c2 = degres * c0 * c0 * 5.0 / 4.0;
      const double c3 = degres * c0 * c0 * c0 * 13.0 / 12.0;
      const double r1 = 0.207447644182976;
      const double r2 = r1 * r1;
      const double d0 = 0.397777138139599;
      const double o0 = -0.0106463073113138;
     
      double M, C, L, R, dec, omega, x;
     
      M = radians * fmod(m0 + m1 * d, 360.0);
      C = c1 * sin(M) + c2 * sin(2.0 * M) + c3 * sin(3.0 * M);
      L = fmod(l0 + l1 * d + C, 360.0);
      x = radians2 * L;
      R = -degres * atan((r2 * sin(x)) / (1 + r2 * cos(x)));
      *centre = (C + R + longitude_ouest) / 360.0;
     
      dec = asin(d0 * sin(radians * L));
      omega = (o0 - sin(dec) * sinlat) / (cos(dec) * coslat);
      if ((omega > -1.0) && (omega < 1.0))
        *variation = acos(omega) / M_2PI;
      else
        *variation = 0.0;
    }
     
    void calculerEphemeride(int jour, int mois, int annee,
                            double longitude_ouest, double latitude_nord,
                            double *lever, double *meridien, double *coucher)
    {
      int nbjours;
      const double radians = M_PI / 180.0;
      double d, x, sinlat, coslat;
     
      if (annee > 2000) annee -= 2000;
      nbjours = (annee * 365) + ((annee + 3) >> 2) + jour - 1;
      switch (mois)
      {
        case  2: nbjours +=  31; break;
        case  3: nbjours +=  59; break;
        case  4: nbjours +=  90; break;
        case  5: nbjours += 120; break;
        case  6: nbjours += 151; break;
        case  7: nbjours += 181; break;
        case  8: nbjours += 212; break;
        case  9: nbjours += 243; break;
        case 10: nbjours += 273; break;
        case 11: nbjours += 304; break;
        case 12: nbjours += 334; break;
      }
      if ((mois > 2) && ((annee & 3) == 0)) nbjours++;
      d = nbjours;
     
      x = radians * latitude_nord;
      sinlat = sin(x);
      coslat = cos(x);
     
      calculerCentreEtVariation(longitude_ouest, sinlat, coslat, d + longitude_ouest / 360.0, meridien, &x);
      *lever = *meridien - x;
      *coucher = *meridien + x;
     
      calculerCentreEtVariation(longitude_ouest, sinlat, coslat, d + *lever, lever, &x);
      *lever -= x;
     
      calculerCentreEtVariation(longitude_ouest, sinlat, coslat, d + *coucher, coucher, &x);
      *coucher += x;
    }
     
    void afficherHeureJulienne(double d)
    {
      d += 0.5;
      if (d < 0.0) d += 1.0;
      if (d > 1.0) d -= 1.0;
     
      int h = d * 24;
      d -= h / 24.0;
      int m = d * 1440;
      d -= m / 1440.0;
      int s = d * 86400 + 0.5;
     
      if (h < 10) Serial.print('0');
      Serial.print(h); Serial.print(':');
      if (m < 10) Serial.print('0');
      Serial.print(m); Serial.print(':');
      if (s < 10) Serial.print('0');
      Serial.println(s);
    }
    (si je ne me suis pas trompé dans mon nettoyage - j'ai tapé cela ici)


    ensuite vous pouvez l'utiliser par un simple include du .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    #include "ephemeride.h"
     
    void setup() {
      Serial.begin(115200);
     
      double lever, meridien, coucher;
     
      int jour = 30;
      int mois = 7;
      int annee = 2025;
     
      double latitude_nord = 45.6590039;
      double longitude_ouest = -5.278757777777778;
     
      calculerEphemeride(jour, mois, annee, longitude_ouest, latitude_nord, &lever, &meridien, &coucher);
     
      Serial.print("Lever : ");
      afficherHeureJulienne(lever);
     
      Serial.print("Meridien : ");
      afficherHeureJulienne(meridien);
     
      Serial.print("Coucher : ");
      afficherHeureJulienne(coucher);
    }
     
    void loop() {}

  18. #18
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    Pensez à bien utiliser l’alarme pour un jour et heure donné si vous prenez cette approche sinon quand l’heure du coucher s’avance dans la soirée vous allez avoir un second réveil le même jour au lieu du lendemain)

  19. #19
    Membre éprouvé
    Inscrit en
    Juillet 2004
    Messages
    982
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 982
    Par défaut
    Salut Jay M

    Pensez à bien utiliser l’alarme pour un jour et heure donné si vous prenez cette approche sinon quand l’heure du coucher s’avance dans la soirée vous allez avoir un second réveil le même jour au lieu du lendemain)

    Si l'alarme est déclenchée en mode : Date , c'est correct ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    08:55:46.214 -> Date            Lever         Meridien      Coucher
    08:55:46.214 -> 31/07/2025      04:22:44      11:45:18      19:07:06
    08:55:46.214 -> L'alarme se déclenchera à l'heure spécifiée
    08:55:46.214 -> [ Alarme 1: 31 19:07:06, Mode: Date ]    <==================
    08:55:46.214 -> --------------------
    08:55:46.214 -> Boot number: 1
    08:55:46.214 -> --------------------
    08:55:46.214 -> 🕒 Heure actuelle DS3231 : 06:55:35
    08:55:46.214 -> Going to sleep now

  20. #20
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 918
    Par défaut
    Si vous utilisez DS3231_A1_Date c’est OK

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [Firebird] Convertir une String en date
    Par laffreuxthomas dans le forum SQL
    Réponses: 1
    Dernier message: 04/05/2005, 19h42
  2. Convertir une date lunaire
    Par djeckelle dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 03/12/2004, 14h06
  3. []Comment convertir une date GMT en date vb ?
    Par Invité dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 11/08/2004, 16h01
  4. Convertir une date au format excel en datetime SQL server
    Par ALLB dans le forum MS SQL Server
    Réponses: 8
    Dernier message: 20/07/2004, 11h28
  5. Convertir une date en type string
    Par ziboux dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 29/10/2003, 10h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo