Bug heure UTC - heure CET avec ESP32 ?

Bonjour !

Hier j'ai publié un code (fonctionnel, rassurez-vous !) dans les tutos, ici :

Mais pendant la mise au point j'ai constaté ce que j’appellerai un bug, en tout cas un truc qui m'échappe totalement.

Voici déjà le code (quasi identique) qui permet de se rendre compte du phénomène si on le lance et qu'on regarde ce que dit le moniteur série :

/* **** Routine d'extraction des couleurs Tempo du site de RTE ****

   Les 2 requêtes HTTP utilisées dans ce programme ont été créées
   par J-M-L du forum francophone Arduino (un très GROS merci !)
   ici : https://forum.arduino.cc/t/api-rte-ecowatt/1017281
   D'où la notice de copyright ci-dessous :

 ============================================
  KEEP THIS INFORMATION IF YOU USE THIS CODE

  This "API RTE" demo code for ESP 32 is placed under the MIT license
  Copyright (c) 2022 J-M-L For the Arduino Forum

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/

#include <WiFi.h>
#include <esp_sntp.h>      // Permet le contrôle de la synchro avec un serveur NTP
#include <HTTPClient.h>
#include <ArduinoJson.h>

// ******* Valeurs nécessaires à l'accès à l'API "Tempo Like Supply Contract" de RTE *******
    // ID Client et ID Secret en base 64, créées sur le site de RTE avec le bouton "Copier en base 64"
    #define identificationRTE   "YTI1YjM------------------------------------------------------------------------ZjE1LTExMmUzMDZmNDZjMg=="

    const char * idRTE = "Basic " identificationRTE;

    // Certificat racine (format PEM) de https://digital.iservices.rte-france.com
    const char* root_ca = \
    "-----BEGIN CERTIFICATE-----\n" \
    "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G\n" \
    "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp\n" \
    "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4\n" \
    "MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG\n" \
    "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" \
    "hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8\n" \
    "RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT\n" \
    "gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm\n" \
    "KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\n" \
    "QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ\n" \
    "XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw\n" \
    "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o\n" \
    "LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU\n" \
    "RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp\n" \
    "jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK\n" \
    "6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX\n" \
    "mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs\n" \
    "Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\n" \
    "WD9f\n" \
    "-----END CERTIFICATE-----\n";

bool FirstCycleDone = false;                 // Mis à "true" après la première boucle de loop()
int annee_debut, annee_fin;                  // variables nécessaires à la mise en forme du lien https vers RTE
byte mois_debut, mois_fin, jour_debut, jour_fin, decal_horaire_debut, decal_horaire_fin;
String JourJ, JourJ1 ;                       // Strings contenant les couleur du jour actuel et du lendemain


// ******** Variables pour gérer l'intervalle de lecture de l'API de RTE
long intervalle = 600000;                    //  = 15 minutes
unsigned long top_lect_API_RTE;

// ******** Valeurs en relation avec l'horloge internet et la gestion de la date et de l'heure
const char* ntpServer = "fr.pool.ntp.org";   // Adresse du serveur NTP
time_t moment;                               // utilisé pour stocker la date et l'heure au format unix
struct tm *loc;                              // Structure qui contient les informations de l'heure et de la date

void setup()
{
  Serial.begin(115200);
  delay(2000);

  connect_WiFi();
}

String errorDescription(int code, HTTPClient& http)
// Liste des codes d'erreurs spécifique à l'API RTE ou message général en clair
{
  switch (code) 
  {
    case 400: return "Erreur dans la requête";
    case 401: return "L'authentification a échouée";
    case 403: return "L’appelant n’est pas habilité à appeler la ressource";
    case 413: return "La taille de la réponse de la requête dépasse 7Mo";
    case 414: return "L’URI transmise par l’appelant dépasse 2048 caractères";
    case 429: return "Le nombre d’appel maximum dans un certain laps de temps est dépassé";
    case 509: return "L‘ensemble des requêtes des clients atteint la limite maximale";
    default: break;
  }
  return http.errorToString(code);
}

bool getRTEData()
// ****** Deux requêtes vers l'API de RTE, nécessite que le WiFi soit actif ******
{
  int HTTPcode;
  const char* access_token;
  bool requeteOK = true;
  const char* oauthURI =   "https://digital.iservices.rte-france.com/token/oauth/";

  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("WiFI non disponible. Requête impossible");
    return false;
  }
  WiFiClientSecure client;     // on passe en connexion sécurisée (par https...)
  HTTPClient http;
  client.setCACert(root_ca);   // permet la connexion sécurisée en vérifiant le certificat racine

// ************** Première des deux requêtes pour obtenit un token **************
  http.begin(client, oauthURI);

  // Headers nécessaires à la requête
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  http.addHeader("Authorization", idRTE);

  // Send HTTP POST request
  Serial.printf("***** Date et heure avant http.POST(nullptr,0) : %02d/%02d/%04d %02d:%02d:%02d *****\n", loc->tm_mday, loc->tm_mon+1, loc->tm_year+1900, loc->tm_hour, loc->tm_min, loc->tm_sec);       
  HTTPcode = http.POST(nullptr,0);
  Serial.printf("***** Date et heure après http.POST(nullptr,0) : %02d/%02d/%04d %02d:%02d:%02d *****\n", loc->tm_mday, loc->tm_mon+1, loc->tm_year+1900, loc->tm_hour, loc->tm_min, loc->tm_sec);       

  if (HTTPcode == HTTP_CODE_OK)
  {
    String oauthPayload = http.getString();
    Serial.println("------------ Contenu renvoyé par la requête 1 : ------------");
    Serial.println(oauthPayload);
    Serial.println("------------------------------------------------------------\n");
    StaticJsonDocument<192> doc;
    DeserializationError error = deserializeJson(doc, oauthPayload);
    if (error)     // cas où il y a un problème dans le contenu renvoyé par la requête
    {
      Serial.print("deserializeJson() failed: ");
      Serial.println(error.c_str());
      access_token = "";
      requeteOK = false;
    }
    else           // cas où le contenu renvoyé par la requête est valide et exploitable
    {
      access_token = doc["access_token"];
    }
  } 
  else 
  {
    Serial.print("erreur HTTP POST: ");
    Serial.println(errorDescription(HTTPcode, http));
    requeteOK = false;
  }
  http.end();
  if (!requeteOK) return false;

// ***** Deuxième des deux requêtes pour obtenir la couleur des jours, nécessitant le token *****

  // REMARQUES : l'adresse pour la requête est sous la forme :
  // https://digital.iservices.rte-france.com/open_api/tempo_like_supply_contract/v1/tempo_like_calendars?start_date=2015-06-08T00:00:00%2B02:00&end_date=2015-06-11T00:00:00%2B02:00
  // avec (dans notre cas) "start_date" la date du jour et "end_date" la date du jour + 2
  // Après les "%2B" (signe +) on a le décalage horaire par rapport au temps UTC. On doit obligatoirement avoir "02:00" en heures d'été et "01:00" en heure d'hiver
  // Les heures de début et de fin peuvent rester à "T00:00:00" pour la requête mais doivent être présentes !
  // Pour les mois et les jours, les "0" au début peuvent être omis dans le cas de nombres inférieurs à 10

  String requete = "https://digital.iservices.rte-france.com/open_api/tempo_like_supply_contract/v1/tempo_like_calendars?start_date=";
  requete += String(annee_debut)+"-"+String(mois_debut)+"-"+String(jour_debut)+"T00:00:00%2B0"+String(decal_horaire_debut)+":00&end_date="+String(annee_fin)+"-"+String(mois_fin)+"-"+String(jour_fin)+"T00:00:00%2B0"+String(decal_horaire_fin)+":00";
  // Remarque : "loc->tm_isdst" est à 0 en heure d'hiver et à 1 en heure d'été
  
  Serial.println("---------------- Adresse pour la requête 2 : ---------------");
  Serial.println(requete);
  Serial.println("------------------------------------------------------------\n");
  http.begin(client, requete);

    String signalsAutorization = "Bearer "+ String(access_token);
    
    // Headers nécessaires à la requête
    http.addHeader("Authorization", signalsAutorization.c_str());
    http.addHeader("Accept", "application/xml");
    // Mettre la ligne précédente en remarque pour avoir le résultat en json plutôt qu'en xml

    // On envoie la requête HTTP GET
    HTTPcode = http.GET();

    if (HTTPcode == HTTP_CODE_OK)
    {
      String recup = http.getString();              // "recup" est une chaîne de caractères au format xml
      Serial.println("------------ Contenu renvoyé par la requête 2 : ------------");
      Serial.println(recup);
      Serial.println("------------------------------------------------------------\n");

      // Récupération des couleurs
      int posi = recup.indexOf("<Couleur>",100);    // Recherche de la première occurence de la chaîne "<Couleur>"
                                                    // à partir du 100ème caractère de "recup"
      if (recup.length() > 200)                     // Si la couleur J+1 est connue le String "recup" fait plus de 200 caractères 
      {
        JourJ1 = (recup.substring(posi+9,posi+13)); // Récupération du substring des 4 caractères contenant couleur du lendemain
                                                    // peut être "BLEU", "BLAN" ou "ROUG"
        posi = recup.indexOf("<Couleur>",230);      // Recherche de la deuxième  occurence de la chaîne "<Couleur>"
                                                    // à partir du 230ème caractère de "recup"
        JourJ = (recup.substring(posi+9,posi+13));  // Récupération du substring des 4 caractères contenant la couleur du jour
                                                    // peut être "BLEU", "BLAN" ou "ROUG"
      }
      else                                          // cas où la couleur de J+1 n'est pas encore connue
      {
        JourJ = (recup.substring(posi+9,posi+13));  // Récupération du substring des 4 caractères contenant la couleur du jour
                                                    // peut être "BLEU", "BLAN" ou "ROUG"
        JourJ1 = "NON_DEFINI";
      }
      Serial.print("Couleur Tempo du jour : "); Serial.println(JourJ);
      Serial.print("Couleur Tempo de demain : "); Serial.println(JourJ1 + "\n");
    } 
    else
    {
      Serial.print("erreur HTTP GET: ");
      Serial.print(HTTPcode);
      Serial.print(" => ");
      Serial.println(errorDescription(HTTPcode, http));
      requeteOK = false;
    }
  http.end();
  return requeteOK;
}

void connect_WiFi()
{
  const char* ssid = "xxxxxxxxxxx";
  const char* mdp = "yyyyyyyyyy";
  const int TimeOut_connexion = 40;                 // Time-out connexion après 40 essais
  int timeOut_counter = 0;                          // Compteur de nombre d'essais de connexion au Wifi
  sntp_sync_status_t syncStatus;                    // Renvoie le statut de synchro au serveur SNTP, nécessite la librairie "esp_sntp.h"

  Serial.println("Connection au WiFi");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, mdp);

  while (WiFi.status() != WL_CONNECTED) 
    {
     delay(250);
     Serial.write('.');
     ++timeOut_counter;                             // redémarrage de l'ESP si pas de connexion pendant 10 sec
    if (timeOut_counter > TimeOut_connexion) ESP.restart();

    }
  Serial.print("\nConnecté au WiFi avec l'adresse IP ");
  Serial.println(WiFi.localIP());
  delay(1000);
  
  // Prise en compte automatique du décalage horaire et des dates de début et de fin d'heure d'été par rapport au temps UTC
  // Fonction intégrée à la librairie "time.h"
  configTzTime("CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", ntpServer);

  // Vérification de la synchronisation effective de l'heure au démarrage  
  timeOut_counter = 0;
  Serial.println("\nSynchronisation de l'heure en cours ");
   while (syncStatus != SNTP_SYNC_STATUS_COMPLETED)
   {
    syncStatus = sntp_get_sync_status();    
    delay(250); 
     Serial.write('.');
    ++timeOut_counter;                              // redémarrage de l'ESP si pas de connexion pendant 10 sec
    if (timeOut_counter > TimeOut_connexion) ESP.restart();
   }
  Serial.println("\nSynchronisation de l'heure OK !\n");
  delay(1000);
}


void loop()
{
  // ****** Accès périodique à l'API de RTE ******
  if (top_lect_API_RTE + intervalle < millis() || FirstCycleDone == false)  // condition vraie tous les "intervalle" ou au premier loop()
    {
      top_lect_API_RTE=millis();
      // Définition de la date et de l'heure de dans 2 jours
      moment = time(NULL)+172800;  // Mise de la date et heure de dans 2 jours au format unix dans la variable "moment" de type time_m
                                   // 172800 = 2 jours en secondes
      loc = localtime(&moment);    // Mise dans la structure loc des éléments de date et de l'heure de dans deux jours
      Serial.printf("Date et heure dans 2 jours : %02d/%02d/%04d %02d:%02d:%02d\n", loc->tm_mday, loc->tm_mon+1, loc->tm_year+1900, loc->tm_hour, loc->tm_min, loc->tm_sec);
      Serial.printf("Décalage par rapport à l'heure UTC de dans 2 jours : +%01d heure(s)\n", loc->tm_isdst + 1);
      // Mémorisation de la date et du décalage horaire de dans 2 jours car les données "loc->tm_xxxx" vont êtres reécrites par le prochain appel à localtime
      annee_fin = loc->tm_year+1900;
      mois_fin = loc->tm_mon+1;
      jour_fin = loc->tm_mday;
      decal_horaire_fin = loc->tm_isdst + 1;
      // Définition de la date et de l'heure actuelles
      moment = moment-172800;      // Mise de la date et de heure actuelles au format unix dans variable "moment" de type time_m
      loc = localtime(&moment);    // Mise dans la structure loc des éléments de date et de l'heure actuelles
      Serial.printf("Date et heure actuelles : %02d/%02d/%04d %02d:%02d:%02d\n", loc->tm_mday, loc->tm_mon+1, loc->tm_year+1900, loc->tm_hour, loc->tm_min, loc->tm_sec);       
      Serial.printf("Décalage par rapport à l'heure UTC : +%01d heure(s)\n", loc->tm_isdst + 1);
      Serial.println();
      // Mémorisation de la date et du décalage horaire actuel
      annee_debut = loc->tm_year+1900;
      mois_debut = loc->tm_mon+1;
      jour_debut = loc->tm_mday;
      decal_horaire_debut = loc->tm_isdst + 1;

      
      // REMARQUE : le décalage horaire et l'heure d'été sont automatiquemment pris en compte
      //            grâce à la commande "configTzTime" après la connexion au WiFi

      getRTEData();
    }
  FirstCycleDone = true; 
}

Donc que se passe-t-il ?
Pour mettre en forme la chaîne de la deuxième requête avec les bonnes dates, mes lignes ressemblaient tout d'abord à :

  String requete = "https://digital.iservices.rte-france.com/open_api/tempo_like_supply_contract/v1/tempo_like_calendars?start_date=";
  requete += String(loc->tm_year+1900)+"-"+String(loc->tm_mon+1)+"-"+String(loc->tm_mday)+"T00:00:00%2B0"+String(loc->tm_isdst)+":00&end_date="+String(annee_fin)+"-"+String(mois_fin)+"-"+String(jour_fin)+"T00:00:00%2B0"+String(decal_horaire_fin)+":00";

J'ai du créer de nouvelles variables et modifier les lignes ainsi :

  String requete = "https://digital.iservices.rte-france.com/open_api/tempo_like_supply_contract/v1/tempo_like_calendars?start_date=";
  requete += String(annee_debut)+"-"+String(mois_debut)+"-"+String(jour_debut)+"T00:00:00%2B0"+String(decal_horaire_debut)+":00&end_date="+String(annee_fin)+"-"+String(mois_fin)+"-"+String(jour_fin)+"T00:00:00%2B0"+String(decal_horaire_fin)+":00";

Que se passe-t-il ?
Eh bien je me suis rendu compte que dans les requêtes effectuées entre minuit et 1h du matin, ma date de début restait celle d'hier au lieu de celle du jour.
En recherchant un peu plus, j'ai découvert que mes infos "loc->tm_xxxx", entre le moment où elles ont été définies par loc = localtime(&moment); dans le loop() et le moment où je m'en servais pour construire la requête, perdaient leur fuseau horaire (UTC + 1 heure), c'est à dire repassaient à l'heure UTC.
Et cela se passe pile-poil au moment de la commande HTTPcode = http.POST(nullptr,0); de la première des deux requêtes.

Pour preuve, j'ai mofifié le code comme ça :

Serial.printf("***** Date et heure avant http.POST(nullptr,0) : %02d/%02d/%04d %02d:%02d:%02d *****\n", loc->tm_mday, loc->tm_mon+1, loc->tm_year+1900, loc->tm_hour, loc->tm_min, loc->tm_sec);       
HTTPcode = http.POST(nullptr,0);
Serial.printf("***** Date et heure après http.POST(nullptr,0) : %02d/%02d/%04d %02d:%02d:%02d *****\n", loc->tm_mday, loc->tm_mon+1, loc->tm_year+1900, loc->tm_hour, loc->tm_min, loc->tm_sec);

Le même Serial.printf me donne deux résultats décalés d'une heure. :open_mouth:
J'ai essaye avec deux ESP32 différents (un DOIT ESP32 DEVKIT V1 avec une puce "ESP-WROOM 32" et un autre avec une puce "ESP32-S3-WROOM-1") c'est pareil.

Loin de moi de vouloir mettre en cause le code de @J-M-L j'aimerai simplement comprendre ce qu'il se passe !
Bug au niveau de la gestion des fuseaux horaires de l'ESP, bug d'allocation de mémoire... ?

Enfin bref, si quelqu'un avait une explication, je serais reconnaissant !

Roland

mon code peut être buggy :slight_smile: ainsi que les bibliothèques

Ce serait intéressant de voir ce qu'il se passe au niveau NTP en appelant le callback pour voir si le le http.POST met le bazar ?

rajoutez en début de code une fonction callback

void ntpSync(struct timeval *tv) {
  Serial.println("NTP SYNC"); 
}

et juste avant la ligne configTzTime() dans le setup vous mettez

sntp_set_time_sync_notification_cb(ntpSync);

Merci pour la réponse rapide (c'est dimanche on a le temps...)

Alors essai fait, le message "NTP SYNC" s'affiche juste une fois, pendant la boucle
while (syncStatus != SNTP_SYNC_STATUS_COMPLETED), ce qui me semble normal...

Roland

pouvez vous coller exactement tout ce que dit le moniteur série ?

ps: l'écriture

  if (top_lect_API_RTE + intervalle < millis() || FirstCycleDone == false)  // condition vraie tous les "intervalle" ou au premier loop()

n'est pas bonne on écrit toujours en soustraction pour gérer le rollover et ce serait plutôt

  if (millis() - top_lect_API_RTE >=  intervalle || FirstCycleDone == false)  // condition vraie tous les "intervalle" ou au premier loop()

Voili voilou :

11:26:39.450 -> Connection au WiFi
11:26:39.790 -> ..
11:26:40.028 -> Connecté au WiFi avec l'adresse IP 192.168.1.154
11:26:41.046 -> 
11:26:41.046 -> Synchronisation de l'heure en cours 
11:26:41.285 -> ..NTP SYNC
11:26:41.794 -> ..
11:26:42.032 -> Synchronisation de l'heure OK !
11:26:42.032 -> 
11:26:43.028 -> Date et heure dans 2 jours : 12/12/2023 11:26:42
11:26:43.028 -> Décalage par rapport à l'heure UTC de dans 2 jours : +1 heure(s)
11:26:43.080 -> Date et heure actuelles : 10/12/2023 11:26:42
11:26:43.080 -> Décalage par rapport à l'heure UTC : +1 heure(s)
11:26:43.080 -> 
11:26:43.080 -> ***** Date et heure avant http.POST(nullptr,0) : 10/12/2023 11:26:42 *****
11:26:43.731 -> ***** Date et heure après http.POST(nullptr,0) : 10/12/2023 10:26:43 *****
11:26:43.731 -> ------------ Contenu renvoyé par la requête 1 : ------------
11:26:43.731 -> {
11:26:43.731 ->   "access_token" : "aox02BsavG9Gd2N28SuTxskGKkDRvn45hfGDFjS3ekrcVbwmZKK5dR",
11:26:43.784 ->   "token_type" : "Bearer",
11:26:43.784 ->   "expires_in" : 7200
11:26:43.784 -> }
11:26:43.784 -> ------------------------------------------------------------
11:26:43.784 -> 
11:26:43.784 -> ---------------- Adresse pour la requête 2 : ---------------
11:26:43.784 -> https://digital.iservices.rte-france.com/open_api/tempo_like_supply_contract/v1/tempo_like_calendars?start_date=2023-12-10T00:00:00%2B01:00&end_date=2023-12-12T00:00:00%2B01:00
11:26:43.784 -> ------------------------------------------------------------
11:26:43.784 -> 
11:26:43.837 -> ------------ Contenu renvoyé par la requête 2 : ------------
11:26:43.837 -> <Tempos><Tempo><DateHeureCreation>2023-12-10</DateHeureCreation><DateApplication>2023-12-11</DateApplication><Couleur>BLEU</Couleur></Tempo><Tempo><DateHeureCreation>2023-12-09</DateHeureCreation><DateApplication>2023-12-10</DateApplication><Couleur>BLEU</Couleur></Tempo></Tempos>
11:26:43.897 -> ------------------------------------------------------------
11:26:43.897 -> 
11:26:43.897 -> Couleur Tempo du jour : BLEU
11:26:43.897 -> Couleur Tempo de demain : BLEU

Roland

OK en fait le souci vient de votre dépendance aveugle :slight_smile: au pointeur fourni par la fonction localtime()

cette fonction possède elle même la structure qui vous est rendue sous forme de pointeur, mais tout appel à gmtime() ou localtime() viendra modifier cette structure et donc tout pointeur vers la structure s'en trouvera modifié.

Je pense que la couche TCP qui se charge de faire la requête POST doit faire appel à ces fonctions de temps (en UTC) pour vérifier la validité du certificat et donc ça met à jour la structure sous jacente

➜ si vous voulez que loc ne soit pas modifié par la suite déclarez une variable globale pour la struct complète et pas un pointeur

  struct tm loc;

et à la lecture

loc = *(localtime(&moment)); // on fait une copie

bien sûr il faut changer toutes les -> en . quand vous accédez au contenu de la structure

C'est effectivement un peu comme ça que je voyais le problème.
Il en est question là (site très bien fait je trouve qui m'a bien aidé, en tout cas à mon niveau de connaissance !) : KooR.fr - localtime - Langage C

Pour le reste c'est tout bon, en déclarant une variable globale pour la structure comme vous le proposez, plus de problème !

Pfff, coder c'est enrichissant et frustrant en même temps : plus j'avance plus je vois qu'il me reste beaucoup à apprendre et que j'ai encore beaucoup de lacunes, surtout avec ces histoires de pointeurs
(les * et les &) qui sont encore très abstraites pour moi...

P.S. J'ai mis le code modifié dans mon tuto, c'est un peu plus propre....

Encore une fois grand merci !

Roland

peut-être mon tuto sur la mémoire vous aidera à y voir plus clair ?

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.