Projet station météo ESP8266 (Partie 3). Récupérer l’heure avec NTPClient et stockage SPIFFS

Partager sur facebook
Partager sur twitter
Partager sur linkedin
Partager sur pinterest
Partager sur email
Partager sur telegram

Dans cette troisième partie du projet de station météo avec interface WEB, nous allons apprendre comment récupérer l’heure depuis un serveur de temps à l’aide de la librairie NTPClient. L’Arduino et l’ESP8266 ne disposent pas d’horloge temps réel. On peut ajouter une horloge temps réelle (module RTC, Real Time Clock), mais il sera beaucoup plus facile et moins chère de récupérer l’heure sur un serveur de temps (NTP) directement sur internet via la connexion WiFi . 

 

Projet actualisé le 29 juillet 2020

Dès que vous disposez d’une connexion Internet, il est très facile de récupérer la date et l’heure actuelles à partir d’un serveur externe ou d’un serveur de temps NTP. Il sera possible d’horodater les mesures, de connaître le temps écoulé entre deux événements, d’afficher l’heure actuelle sur l’interface WEB, de déclencher une action programmée…

Le schéma ci-dessous explique comment nous allons faire

esp8266 esp32 ntp server date time

 

Si vous avez besoin d’aller plus loin avec la librairie NTPClient, vous pouvez continuer en lisant cet article plus détaillé

A LIRE AUSSI :
ESP8266. Récupérer l'heure avec NTPClient, stockage SPIFFS, calculer le temps écoulé et déclencher un événement

Installer la librairie NTPClient

Ouvrez le gestionnaire de librairies de l’IDE Arduino et cherchez la librairie NTPClient de Fabrice Weinberg. C’est une librairie  puissante et simple d’utilisation.

esp8266 ntp server ntpclient library

Lors du développement d’objets connectés fonctionnant sur batterie, on peut souhaiter connaître rapidement le temps de déclenchement pour appeler éventuellement une autre fonction. La bibliothèque NTPClient peut le faire très facilement en forçant la récupération du temps en appelant la connexion UDP pour se connecter à un serveur NTP. Pour cela, il faudra inclure la bibliothèque standard WiFiUdp.h dans l’en-tête du croquis.

Ensuite, il est possible d’initialiser l’objet NTPClient avec la configuration par défaut:

  • Serveur, pool.ntp.org
  • Intervalle de mise à jour, 60 secondes
  • Décalage horaire (en secondes), aucun
NTPClient timeClient(ntpUDP);

Ou pour spécifier des paramètres. Ici, nous appliquons un décalage horaire d’une heure

NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);

Ensuite, il ne reste plus qu’à démarrer le service avec la méthode forceUpdate (). Il est idéal pour les projets fonctionnant sur batterie.

Voici un petit exemple qui récupère et affiche l’heure toutes les 10 secondes

#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

#define NB_TRYWIFI        10    // Nbr de tentatives de connexion au réseau WiFi - Number of try to connect to WiFi network

const char* ssid = "xxxx";
const char* password = "xxxx";

WiFiClient espClient;
WiFiUDP ntpUDP;

NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);

void setup() {
  Serial.begin(115200);
  Serial.println("");
  Serial.print("Startup reason:");Serial.println(ESP.getResetReason());

  WiFi.begin(ssid, password);

  Serial.println("Connecting to WiFi.");
  int _try = 0;
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print("..");
    delay(500);
    _try++;
    if ( _try >= NB_TRYWIFI ) {
        Serial.println("Impossible to connect WiFi network, go to deep sleep");
        ESP.deepSleep(10e6);
    }
  }
  Serial.println("Connected to the WiFi network");
  
  // Démarrage du client NTP - Start NTP client
  timeClient.begin();
}

void loop() {
    // Met à jour l'heure toutes les 10 secondes - update time every 10 secondes
    timeClient.update();
    Serial.println(timeClient.getFormattedTime());
}

Stockez l’heure dans la zone SPIFFS, calculez le temps écoulé depuis le premier démarrage

Dans de nombreux cas, on voudra garder une trace du temps pour d’autres utilisations :

  • Calculer le temps écoulé depuis le dernier démarrage ou la dernière réinitialisation
  • Déclenchez une action si le temps écoulé est supérieur à un point de consigne.
  • Déclenchez une action pré-programmée.

Pour stocker l’heure, il est beaucoup plus facile de la sauvegarder dans un simple fichier texte dans la zone SPIFFS que de la stocker dans l’EEPROM. Pour cela, il suffit de déclarer simplement la bibliothèque fs.h au début du programme.

Ensuite, il sera très facile de calculer le temps écoulé depuis le dernier démarrage.

Collez le code suivant dans un nouveau croquis sans oublier de modifier les paramètres suivants :

  • ssid identifiant de connexion au réseau WiFi
  • password mot de passe du réseau WiFi
  • NB_TRYWIFI permet de spécifier le nombre de tentatives de connexion au réseau WiFi. Sur batterie, le mieux est de mettre le module ESP8266 ou ESP32 en veille et recommencer ultérieurement pour éviter de drainer cette dernière.
  • LOOP_DELAY permet de spécifier le temps d’attente entre deux exécution de la boucle loop. Par défaut, il est de 60 secondes. Attention, ici on force l’actualisation du temps, évitez d’envoyer trop de requêtes au serveur NTP.
  • RESET_INITIAL_NTPTIME permet de réinitialiser manuellement le temps initial à partir duquel est calculé le temps écoulé. Il suffira par exemple de modifier la méthode resetInitialTime() sur un événement, par exemple un déclencheur tel qui bouton poussoir pour l’initialiser manuellement.
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "FS.h"

#define NB_TRYWIFI        10        // Nbr de tentatives de connexion au réseau WiFi - Number of try to connect to WiFi network
#define LOOP_DELAY        30 * 1000 // Fréquence d'actualisation | update frequency
#define RESET_INITIAL_NTPTIME false // Permet de réinitialisé le temps initial | Allows to reset initial NTP time
// Paramètres WiFi | WiFi settings
const char* ssid = "****";
const char* password = "****";

WiFiClient espClient;
WiFiUDP ntpUDP;

NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);

void resetInitialTime() {
  timeClient.forceUpdate();
  _now = timeClient.getEpochTime();
  saveLastEvent();
}
int lastEvent;
int start = millis();
long int _now = 0;

bool lastEventExist() {
  File f = SPIFFS.open("/lastEvent.txt", "r");
  if (!f) {
    return false;
  }
  return true;
}

bool loadLastEvent() {
  // Recharge le dernier horodatage depuis la zone SPIFFS | Reload last date/time from SPIFFS area
  File f = SPIFFS.open("/lastEvent.txt", "r");
  if (!f) {
    Serial.println("Failed to open file, force NTP");
    return false;
  }
  lastEvent = f.readStringUntil('n').toInt();
  return true;
}

bool saveLastEvent() {
  File f = SPIFFS.open("/lastEvent.txt", "w");
  if (!f) {
    Serial.println("file open failed");
    return false;
  }
  f.println(_now);
  f.close();
  return true;
}

long int calculateTimeSpent() {
  loadLastEvent();
  timeClient.forceUpdate();
  _now = timeClient.getEpochTime();
  int timeSpent = _now - lastEvent;
  Serial.print("Time spent since last update (s): "); Serial.println(timeSpent);
  return timeSpent;
}

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

  SPIFFS.begin();

  WiFi.begin(ssid, password);

  Serial.println("Connecting to WiFi.");
  int _try = 0;
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print("..");
    delay(500);
    _try++;
    if ( _try >= NB_TRYWIFI ) {
      Serial.println("Impossible to connect WiFi network, go to deep sleep");
    }
  }
  Serial.println("Connected to the WiFi network");

  // Démarrage du client NTP - Start NTP client
  timeClient.begin();
  if ( RESET_INITIAL_NTPTIME ) {
    resetInitialTime();
  }
  if ( !lastEventExist() ) {
     Serial.println("First Boot, store NTP time on SPIFFS area");
     saveLastEvent();
  } else {
    Serial.println("NTP time already stored on SPIFFS area");
    calculateTimeSpent(); 
  }
}

void loop() {
  timeClient.update();
  calculateTimeSpent();
  delay(LOOP_DELAY);
}

Comment fonctionnent les principales méthode du code

loadLastEvent() permet de recharger la dernière heure NTP enregistrée dans le fichier lastEvent.txt situé dans la zone mémoire SPIFFS de l’ESP8266

La librairie fs.h met à disposition la classe SPIFFS qui permet de lire et d’enregistrer des fichiers.
La méthode open(fichier, option) permet d’ouvrir le fichier (attention, il n’est pas possible d’avoir des dossiers dans la zone SPIFFS).  L’option “r” indique qu’on souhaite un accès uniquement en lecture (read).

La méthode readStringUntil(‘n’) lit le contenu du fichier jusqu’au caractère indiqué, ici “n” qui est le caractère de contrôle du retour à la ligne.

On n’oublie pas de convertir en entier avec la méthode .toInt() ce qui nous permettra de calculer le temps écoulé avec une simple soustraction.

On ferme le fichier avec la méthode close().

File f = SPIFFS.open("/lastEvent.txt", "r"); 
lastEvent = f.readStringUntil('n').toInt();
f.close();

saveLastEvent() enregistre le temps NTP au format EPOCH Unix

Comme précédemment, on ouvre le fichier avec la méthode SPIFFS.open(). Cette fois, on indique qu’on souhaite écrire dans le fichier avec l’option “w”.

On enregistre dans un fichier comme sur le port série avec les méthode print() ou println(). La méthode println() ajoute un renvoi à la ligne, souvenez-vous, c’est le caractère “n” utilisé précédemment.

On ferme le fichier avec la méthode close().

File f = SPIFFS.open("/lastEvent.txt", "w")
f.println(_now); 
f.close();

lastEventExist() permet de vérifier si le fichier lastEvent.txt existe déjà dans la zone SPIFFS. Cette méthode retourne un booléen qui prend l’état vrai si le fichier existe et faux dans le cas contraire. Pour savoir si le fichier existe, on procède de la même façon que précédemment en ouvrant en lecture le fichier.

Il suffit ensuite de tout simplement tester l’état de l’objet f

lastEventExist() {
  File f = SPIFFS.open("/lastEvent.txt", "r"); 
  if (!f) {
    return false;
  }
  return true;
}

calculateTimeSpent() calcule le temps écoulé en secondes depuis que le fichier lastEvent.txt a été actualisé, par exemple depuis le premier démarrage

Pour calculer facilement la durée écoulée, il suffit de récupérer le temps au format Unix à l’aide de la méthode getEpochTime(). Connaissant le temps précédent lastEvent, il suffit de faire une simple soustraction pour calculer le temps écoulé

_now = timeClient.getEpochTime(); 
int timeSpent = _now - lastEvent;

Quelques serveurs de temps (NTP)

Voici une petite liste de serveurs de temps (en France et dans le monde). Il en existe des centaines, voici les principaux

ZoneServeur NTP
Monde entierpool.ntp.org
Asieasia.pool.ntp.org
Europeeurope.pool.ntp.org
Amérique du Nordnorth-america.pool.ntp.org
America du Sudsouth-america.pool.ntp.org
Oceanieoceania.pool.ntp.org

Accéder rapidement aux autres parties du projet

Voici les liens pour accéder aux autres parties du projet

A LIRE AUSSI :
Projet station météo ESP8266 (Partie 1). Stocker l'interface Web dans la zone SPIFFS (HTML, CSS, JS)
A LIRE AUSSI :
Projet station météo ESP8266 (Partie 2). Piloter le code Arduino depuis l'interface HTML

Vous êtes ici !

A LIRE AUSSI :
Projet station météo ESP8266 (Partie 3). Récupérer l'heure avec NTPClient et stockage SPIFFS
A LIRE AUSSI :
Projet station météo ESP8266 (Partie 4). ArduinoJson, charger, enregistrer des fichiers (SPIFFS)
A LIRE AUSSI :
Projet station météo ESP8266 (Partie 5). Afficher des jauges et graphiques Google Charts

Mises à jour

29/07/2020 Rétablissement de la partie consacrée au stockage dans la zone SPIFFS du temps récupéré sur un serveur NTP

 

Avez-vous aimé cet article ?
[Total: 0 Moyenne: 0]
Partager sur facebook
Partager sur twitter
Partager sur linkedin
Partager sur pinterest
Partager sur email
Partager sur telegram

Vous avez aimé ce projet ? Ne manquez plus aucun projet en vous abonnant à notre lettre d’information hebdomadaire!

Ressources utiles
quel modèle esp8266 choisir
Quel modèle d'ESP8266EX choisir en 2020 ?
guide choix esp32 development board
Quel ESP32 choisir en 2020 ?
11 Commentaires
  1. Bonjour.
    Il n’y a que quelques partie de code !
    Et la partie stockage en zone SPIFFS est inexistente. ou je n’ai su la trouver ?

    • Bonsoir Thib, oui absolument, j’ai malheureusement effacé le contenu par erreur lors d’une mise à jour. Heureusement que j’avais la version anglaise sous le coude ! J’en ai profité pour reprendre l’article et améliorer le code Arduino. Il est transféré ici dans la catégorie débuter avec l’ESP8266. Bonne soirée

  2. Bonjour,
    Merci d’essayer de m’aider en fait j’ai fait des essais avec le code exemple livré avec
    la librairie afin de comprendre le fonctionnement je joint quand meme le code:

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    // Enter a MAC address for your controller below.

    // Newer Ethernet shields have a MAC address printed on a sticker on the shield

    byte mac[] = {

    0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02

    };

    EthernetClient client;

    void setup()

    {

    Serial.begin(115200);

    if (Ethernet.begin(mac) == 0) {

    Serial.println(“Failed to configure Ethernet using DHCP”);

    // no point in carrying on, so do nothing forevermore:

    for (;;)

    ;

    }

    NTP.onNTPSyncEvent([](NTPSyncEvent_t error) {

    if (error) {

    Serial.print(“Time Sync error: “);

    if (error == noResponse)

    Serial.println(“NTP server not reachable”);

    else if (error == invalidAddress)

    Serial.println(“Invalid NTP server address”);

    }

    else {

    Serial.print(“Got NTP time: “);

    Serial.println(NTP.getTimeDateString(NTP.getLastNTPSync()));

    }

    });

    NTP.begin(“es.pool.ntp.org”, 1, true);

    NTP.setInterval(63);

    }

    void loop()

    {

    static int i = 0;

    static int last = 0;

    if ((millis() – last) > 5100) {

    //Serial.println(millis() – last);

    last = millis();

    Serial.print(i); Serial.print(” “);

    Serial.print(NTP.getTimeDateString()); Serial.print(“. “);

    Serial.print(NTP.isSummerTime() ? “Summer Time. ” : “Winter Time. “);

    Serial.print(“Uptime: “);

    Serial.print(NTP.getUptimeString()); Serial.print(” since “);

    Serial.println(NTP.getTimeDateString(NTP.getFirstSync()).c_str());

    i++;

    }

    delay(0);

    Ethernet.maintain(); // Check DHCP for renewal

    }

  3. 0 00:00:05 01/01/1970. Winter Time. Uptime: 0 days 00:00:05 since Time not set

    1 00:00:10 01/01/1970. Winter Time. Uptime: 0 days 00:00:10 since Time not set

    2 00:00:15 01/01/1970. Winter Time. Uptime: 0 days 00:00:15 since Time not set

    3 00:00:20 01/01/1970. Winter Time. Uptime: 0 days 00:00:20 since Time not set

    4 00:00:25 01/01/1970. Winter Time. Uptime: 0 days 00:00:25 since Time not set

    voici ce que j’obtient pour être plus clair
    Merci si vous avez une solution, moi je galère pour l’instant

  4. bonjour,
    j’ai essayé cette librairie mais sa ne m’affiche que la date du 01/01/1970
    puis un décompte de temps depuis que c’est en marche je ne comprend pas
    si j’ai bien compris je devrais avoir le temps reel?

  5. Nice article. Regards!

  6. Bonjour,

    Et merci pour vos très bon articles.

    D’après mes tests, il semble que le paramètre de réglage de la fréquence d’interrogation, s’exprime en secondes.
    Donc un paramètre de 60000 est équivalent à 1000 minutes.

    Cordialement.

    Laisser un commentaire

    Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

    Domotique et objets connectés à faire soi-même