Projet station météo ESP8266 (Partie 3). Récupérer l'heure avec NTPClient et stockage SPIFFS • Domotique et objets connectés à faire soi-même

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

jc6lsscp9hmon18qeiws-5521400

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

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.

bwznaqyzhnzh725xqppf-3730863

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 
#include 
#include 

#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 
#include 
#include 
#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

Monde entier pool.ntp.org
Asie asia.pool.ntp.org
Europe europe.pool.ntp.org
Amérique du Nord north-america.pool.ntp.org
America du Sud south-america.pool.ntp.org
Oceanie oceania.pool.ntp.org

Accéder rapidement aux autres parties du projet

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

Vous êtes ici !

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 ?