Gestione delle date su wemos d1 mini (esp8266)

Ciao, vorrei proporvi un problema che sto avendo nell'inizializzare la data di sistema alla data corrente, incluso fuso orario, utilizzando NTP DST incluso nel core dell'ESP8266 (sto utilizzando la versione 3.1.0). Ho sempre utilizzato l'NTP Client per gestire data e fuso orario e non ho mai riscontrato il problema che vi espongo (allego anche lo sketch e il log).
Se uso setTime (data in secondi) il valore di now() e di hour() risultano diversi: now() risulta in linea con l'ora corrente, hour() risulta indietro di un'ora.
Se uso setTime (con ora , minuti, secondi, giorno, mese, anno) il valore di now() è un'ora avanti all'ora corrente mentre il valore di hour() risulta in linea con l'ora corrente.
Come si può spiegare questo arcano. Dov'è che sbaglio e/o non ho capito come funzionano now() e hour()?
grazie per l'aiuto

data-ora-esp8266_1.1_log.txt (870 Byte)

data-ora-esp8266_1.1.ino (5,6 KB)

:warning:
Ti segnalo che, nella sezione in lingua Inglese, si può scrivere SOLO in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana ... la prossima volta potrebbe venire direttamente eliminato. Grazie.

chiedo scusa, è il mio primo post e pensavo di essere nella sezione italiana

Cortesemente, per rendere più semplice l'uso del forum, modifica il tuo primo post ed inserisci il tuo codice nel testo, tra i tag "code" e non come allegato. E possibilmente la stessa cosa anche per il log.

@gigi_56: come ti ha già detto docdoc, per facilitare il lavoro a tutti, ma specie a quelli che leggono da smatphone, codice e testi vanno, nei limiti del possibile, inseriti direttamente nel post racchiudendoli nei tag CODE (ovvero, dopo averlo inserito, seleziona la parte di codice e premi l'icona <code/> nella barra degli strumenti per contrassegnarla come codice).

Relativamente al solo "codice", prima di inserirlo, assicurati di averlo correttamente indentato nell'IDE (questo lo si fa premendo ctrlT su un PC o cmd T su un Mac, sempre all'interno del IDE).

Grazie,

Guglielmo

come disse qualcuno più famoso di me: OBBEDISCO!
scusate la mia goffaggine....

/*
  NTP TZ DST - bare minimum
  NetWork Time Protocol - Time Zone - Daylight Saving Time
  This example is a stripped down version of the NTP-TZ-DST (v2)
  And works for ESP8266 core 2.7.4 and 3.0.2
  by noiasca
  2020-09-22
*/

#ifndef STASSID
#define STASSID "xxxxxxxx"                          // set your SSID
#define STAPSK  "xxxxxxxx"                        // set your wifi password
#endif

/* Configuration of NTP */
#define MY_NTP_SERVER "europe.pool.ntp.org"
#define MY_TZ "CET-1CEST,M3.5.0/02,M10.5.0/03"

#include <ESP8266WiFi.h>            // we need wifi to get internet access
#include <TimeLib.h>
#include <time.h>                   // time() ctime()

/* Globals */
time_t dtora;
tm tmt;                              // the structure tm holds time information in a more convient way
time_t ora;

char tmnow[9] = "00:00:00";         //  "hh:mm:ss"
char dt[11]   = "00.00.0000";

static tm getDateTimeByParams(long time) {
  struct tm *newtime;
  const time_t tim = time;
  newtime = localtime(&tim);
  return *newtime;
}
/**
   Input tm time format and return String with format pattern
   by Renzo Mischianti <www.mischianti.org>
*/
static String getDateTimeStringByParams(tm *newtime, char* pattern = (char *)"%d.%m.%Y %H:%M:%S") {
  char buffer[30];
  strftime(buffer, 30, pattern, newtime);
  return buffer;
}
/**
   Input time in epoch format format and return String with format pattern
   by Renzo Mischianti <www.mischianti.org>
*/
static String getTimeGMY_HMS(long time, char* pattern = (char *)"%d.%m.%Y-%H:%M:%S") {
  //    struct tm *newtime;
  tm newtime;
  newtime = getDateTimeByParams(time);
  return getDateTimeStringByParams(&newtime, pattern);
}
/*------------------------------------------------------*/
uint32_t sntp_update_delay_MS_rfc_not_less_than_15000 ()  {
  Serial.println(F("\ntime was updated! "));
  upd_DateTime();
  while ((tmt.tm_year + 1900) == 1970) {
    upd_DateTime();
  }
  //  return 12 * 60 * 60 * 1000UL; // 12 hours
  return 1 * 60 * 1000UL; // 1 minuti
}
/*------------------------------------------------------*/
void upd_DateTime() {
  Serial.println(" ");

  time(&dtora);                    // read the current time
  localtime_r(&dtora, &tmt);       // update the structure tm with the current time
  if ((tmt.tm_year + 1900) == 1970) {
    return;
  }
  printf("local:     %s", asctime(localtime(&dtora)));

  Serial.println("\n---------- setTime(local)");
  setTime(dtora);
  Serial.print("1. local           : "); Serial.println(dtora);
  Serial.print("1. now()           : "); Serial.println(now());
  Serial.print("1. getTimeGMY_HMS(now()): "); Serial.println(getTimeGMY_HMS(now()));

  sprintf(tmnow, "%02u:%02u:%02u", hour(), minute(), second());
  sprintf(dt, "%02d.%02d.%04d", day(), month(), year());
  Serial.print("1. ora-data hour()      : "); Serial.print(dt); Serial.print("-"); Serial.println(tmnow);

  Serial.println(" ");
  Serial.println("----------  setTime(tmt.tm_hour, tmt.tm_min,...... ");
  time(&dtora);                    // read the current time
  localtime_r(&dtora, &tmt);       // update the structure tm with the current time
  setTime(tmt.tm_hour, tmt.tm_min, tmt.tm_sec, tmt.tm_mday, tmt.tm_mon + 1, tmt.tm_year + 1900);

  Serial.print("2. local                : "); Serial.println(dtora);
  Serial.print("2. now()                : "); Serial.println(now());
  Serial.print("2. getTimeGMY_HMS(now()): "); Serial.println(getTimeGMY_HMS(now()));

  sprintf(tmnow, "%02u:%02u:%02u", hour(), minute(), second());
  sprintf(dt, "%02d.%02d.%04d", day(), month(), year());
  Serial.print("2. ora-data hour()      : "); Serial.print(dt); Serial.print("-"); Serial.println(tmnow);

  Serial.print("\nwday");
  Serial.print(tmt.tm_wday);         // days since Sunday 0-6
  if (tmt.tm_isdst == 1)  {          // Daylight Saving Time flag
    Serial.print(" - DST");
    Serial.println(" - Fuso orario = 2");
  } else {
    Serial.print(" - standard");
    Serial.println(" - Fuso orario = 1");
  }
}

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("\nTest NTP TZ DST ");

  configTime(MY_TZ, MY_NTP_SERVER); 

  WiFi.persistent(false);
  WiFi.mode(WIFI_OFF);
  WiFi.mode(WIFI_STA);
  WiFi.begin(STASSID, STAPSK);
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print ( "." );
  }
  Serial.println("\nWiFi connected");
  // by default, the NTP will be started after 60 secs
}

void loop() {
}

di seguito il log dell'esecuzione
00:42:17.021 ->
00:42:17.021 -> Test NTP TZ DST
00:42:17.212 -> ...............
00:42:20.832 -> time was updated!
00:42:20.832 ->
00:42:20.832 -> local: Thu Mar 23 00:42:20 2023
00:42:20.878 ->
00:42:20.878 -> ---------- setTime(local)
00:42:20.878 -> 1. local : 1679528540
00:42:20.878 -> 1. now() : 1679528540
00:42:20.878 -> 1. getTimeGMY_HMS(now()): 23.03.2023-00:42:20
00:42:20.878 -> 1. ora-data hour() : 22.03.2023-23:42:20
00:42:20.878 ->
00:42:20.878 -> ---------- setTime(tmt.tm_hour, tmt.tm_min,......
00:42:20.878 -> 2. local : 1679528540
00:42:20.878 -> 2. now() : 1679532140
00:42:20.878 -> 2. getTimeGMY_HMS(now()): 23.03.2023-01:42:20
00:42:20.878 -> 2. ora-data hour() : 23.03.2023-00:42:20
00:42:20.878 ->
00:42:20.878 -> wday4 - standard - Fuso orario = 1

1 Like

Non so cosa ne penserebbe quel guerrafondaio di Garibaldi, ma secondo me lo sketch è inutilmente complesso...

Con i microcontrollori ESP (ed anche con molti altri) non sono necessarie librerie esterne per gestire la sincronizzazione con dei server NTP (ed infatti mi pare che tu la includa, ma poi in realtà non la usi mai).

Viene tutto gestito egregiamente dal core e tutto quel che serve sono le istruzioni standard C/C++ per la gestione del tempo (time.h che stai già usando).
Questo è l'approccio che uso sempre nei mei progetti che fanno uso di MCU Espressif

1 Like

premesso che "ho poche idee MA confuse" con il linguaggio C (C++) , lo sketch mi serve per comprendere meglio le relazioni tra le funzioni now() e hour() e di come inizializzare il sistema con le info provenienti dal server NTP. Quindi volutamente è ridondante. Nelle applicazioni che ho realizzato faccio ampio ricorso a definizioni di data-ora, ad esempio per accendere spegnere luci, alzare/abbassare tapparelle, inviare messaggi, etc., quindi ho necessità di avere data e ora corrente da confrontare con tali date-ora.
Finora utilizzando NTP.client non mi sono mai imbattuto nel problema citato. Ora, avendo capito che potevo semplificare il tutto, volevo utilizzare il sistema fornito dal core dell'ESP perché è decisamente la via più corretta e semplice.
Nello sketch che ho riportato uso due volte il setTime e mi sono meravigliato di vedere risultati diversi da quanto mi aspettassi e da qui la consapevolezza che forse non ho capito alcunché.

Io non uso mai questo approccio invece, ma ragiono sempre in termini di epoch time soprattutto perché è più semplice la gestione degli intervalli a cavallo della mezzanotte: basta calcolare il valore dell'epoch time corrispondente all'inizio del giorno corrente e poi fare un confronto tra interi.


struct tm tInfo; 
uint32_t epochTime; 
uint32_t startOfDay;

.....
....

uint32_t startTime = 23*3600 + 30*60;    // Start 23:30
uint32_t stopTime = 1*3600 + 45*60;      // Stop 01:45

void loop() {

  getLocalTime(&tInfo);        // Aggiorno la struct tInfo
  epochTime= mktime(&tInfo);   // Tempo attuale in formato unix time
  startOfDay = epochTime- tInfo.tm_hour*3600UL - tInfo.tm_min*60UL - tInfo.tm_sec;
....
  bool outState = (epochTime > (startOfDay + startTime)) && (epochTime <= (startOfDay + stopTime));
  digitalWrite(OUT_PIN, outState);
....

cotestatnt ti ringrazio dei preziosi suggerimenti ma la mia domanda rimane ancora senza risposta.
Puoi aiutarmi a capire come mai utilizzando il setTime nei due modi dello sketch ottengo due risultati diversi?
ciao e grazie ancora

Tu fai questo:

  time(&dtora);                              // read the current time
  localtime_r(&dtora, &tmt);       // update the structure tm with the current time

Poi con setTime() usi la prima volta la variabile dtora e la successiva la variabile tmt.

L'istruzione time() ritorna il timestamp attuale in formato unix time senza quindi tenere conto del tuo timezone. Con l'istruzione localtime_r() invece ottieni il tempo locale e quindi viene tenuto conto dell'offset di 3600 secondi di differenza che hai impostato nel setup() con l'istruzione configTime(MY_TZ, MY_NTP_SERVER);

cotestatnt ho utilizzato il tuo sketch per fare le prove ed il risultato non cambia, i valori di now() e hour() risultano diversi.
Ma hour() non è un sottoinsieme di now() ?
Scusami se ti sto facendo perdere del tempo.

#include <ESP8266WiFi.h>
#include <TimeLib.h>
#include <time.h>

// Timezone definition
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"

/*--------------------------------------------------*/
static tm getDateTimeByParams(long time) {
  struct tm *newtime;
  const time_t tim = time;
  newtime = localtime(&tim);
  return *newtime;
}
/**
   Input tm time format and return String with format pattern
   by Renzo Mischianti <www.mischianti.org>
*/
static String getDateTimeStringByParams(tm *newtime, char* pattern = (char *)"%d.%m.%Y %H:%M:%S") {
  char buffer[30];
  strftime(buffer, 30, pattern, newtime);
  return buffer;
}
/**
   Input time in epoch format format and return String with format pattern
   by Renzo Mischianti <www.mischianti.org>
*/
static String getTimeGMY_HMS(long time, char* pattern = (char *)"%d.%m.%Y-%H:%M:%S") {
  //    struct tm *newtime;
  tm newtime;
  newtime = getDateTimeByParams(time);
  return getDateTimeStringByParams(&newtime, pattern);
}

char tmnow[9] = "00:00:00";         //  "hh:mm:ss"
char dt[11]   = "00.00.0000";

void loop() {
  static uint32_t pTime;
  if (millis() - pTime > 1000) {
    pTime = millis();

    time_t ora;
    tm tInfo;    
    getLocalTime(&tInfo);        //Update tInfo struct
    
    Serial.print("\n tInfo.tm_mday      : ");  Serial.println(tInfo.tm_mday);
    Serial.print(" tInfo.tm_mon +1    : ");  Serial.println(tInfo.tm_mon+1);
    Serial.print(" tInfo.tm_year+1900 : ");  Serial.println(tInfo.tm_year+1900);
    Serial.print(" tInfo.tm_hour      : ");  Serial.println(tInfo.tm_hour);
    Serial.print(" tInfo.tm_min       : ");  Serial.println(tInfo.tm_min);
    Serial.print(" tInfo.tm_sec       : ");  Serial.println(tInfo.tm_sec);
    Serial.print(" tInfo.tm_wday      : ");  Serial.println(tInfo.tm_wday);
    Serial.print(" tInfo.tm_isdst     : ");  Serial.println(tInfo.tm_isdst);
    
    ora = mktime(&tInfo);
    setTime(tInfo.tm_hour, tInfo.tm_min, tInfo.tm_sec, tInfo.tm_mday, tInfo.tm_mon + 1, tInfo.tm_year + 1900);
  time_t ora_now;
  ora_now = now();  
  Serial.println("\n----------  setTime(tmt.tm_hour, tmt.tm_min,...... ");
  Serial.print("\n1. ora                  : "); Serial.println(ora);
  Serial.print("1. now()                : "); Serial.println(now());
  Serial.print("1. ora in chiaro        : ");Serial.print(ctime(&ora));
  Serial.print("1. now() in chiaro      : ");Serial.print(ctime(&ora_now));
  Serial.print("1. getTimeGMY_HMS(now()): "); Serial.println(getTimeGMY_HMS(now()));
  Serial.print("1. getTimeGMY_HMS(ora)  : "); Serial.println(getTimeGMY_HMS(ora));
  sprintf(tmnow, "%02u:%02u:%02u", hour(), minute(), second());
  sprintf(dt, "%02d.%02d.%04d", day(), month(), year());
  Serial.print("1. ora-data hour()      : "); Serial.print(dt); Serial.print("-"); Serial.println(tmnow);
  sprintf(tmnow, "%02u:%02u:%02u", hour(now()), minute(now()), second(now()));
  sprintf(dt, "%02d.%02d.%04d", day(now()), month(now()), year(now()));
  Serial.print("1. ora-data hour(now()) : "); Serial.print(dt); Serial.print("-"); Serial.println(tmnow);
  
  setTime(ora);
//  time_t ora_now;
  ora_now = now();  
  Serial.println("\n---------- setTime(ora) --------------------");
  Serial.print("\n2. ora                  : "); Serial.println(ora);
  Serial.print("2. now()                : "); Serial.println(now());
  Serial.print("2. ora in chiaro        : ");Serial.print(ctime(&ora));
  Serial.print("2. now() in chiaro      : ");Serial.print(ctime(&ora_now));
  Serial.print("2. getTimeGMY_HMS(now()): "); Serial.println(getTimeGMY_HMS(now()));
  Serial.print("2. getTimeGMY_HMS(ora)  : "); Serial.println(getTimeGMY_HMS(ora));
  sprintf(tmnow, "%02u:%02u:%02u", hour(), minute(), second());
  sprintf(dt, "%02d.%02d.%04d", day(), month(), year());
  Serial.print("2. ora-data hour()      : "); Serial.print(dt); Serial.print("-"); Serial.println(tmnow);
    
  sprintf(tmnow, "%02u:%02u:%02u", hour(now()), minute(now()), second(now()));
  sprintf(dt, "%02d.%02d.%04d", day(now()), month(now()), year(now()));
  Serial.print("2. ora-data hour(now()) : "); Serial.print(dt); Serial.print("-"); Serial.println(tmnow);
  }
  delay(60000); // Increase simulation performance
}

void setup() {
  Serial.begin(115200);
    
  Serial.println("Connecting to WiFi ");
  WiFi.begin("R_1_Mya_2.4", "1_Marina_0hkl");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nWiFi connected. ");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP().toString());

  // Sync time with NTP server
  configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
}

e questo è il log

16:25:22.551 -> .......
16:25:26.335 -> WiFi connected. IP address: 
16:25:26.335 -> 192.168.2.169
16:25:26.382 -> 
16:25:26.382 ->  tInfo.tm_mday      : 28
16:25:26.382 ->  tInfo.tm_mon +1    : 3
16:25:26.429 ->  tInfo.tm_year+1900 : 2023
16:25:26.429 ->  tInfo.tm_hour      : 16
16:25:26.429 ->  tInfo.tm_min       : 25
16:25:26.429 ->  tInfo.tm_sec       : 25
16:25:26.429 ->  tInfo.tm_wday      : 2
16:25:26.429 ->  tInfo.tm_isdst     : 1
16:25:26.429 -> 
16:25:26.429 -> ----------  setTime(tmt.tm_hour, tmt.tm_min,...... 
16:25:26.429 -> 
16:25:26.429 -> 1. ora                  : 1680013525
16:25:26.429 -> 1. now()                : 1680020725
16:25:26.429 -> 1. ora in chiaro        : Tue Mar 28 16:25:25 2023
16:25:26.429 -> 1. now() in chiaro      : Tue Mar 28 18:25:25 2023
16:25:26.429 -> 1. getTimeGMY_HMS(now()): 28.03.2023-18:25:25
16:25:26.429 -> 1. getTimeGMY_HMS(ora)  : 28.03.2023-16:25:25
16:25:26.429 -> 1. ora-data hour()      : 28.03.2023-16:25:25
16:25:26.476 -> 1. ora-data hour(now()) : 28.03.2023-16:25:25
16:25:26.476 -> 
16:25:26.476 -> ---------- setTime(ora) --------------------
16:25:26.476 -> 
16:25:26.476 -> 2. ora                  : 1680013525
16:25:26.476 -> 2. now()                : 1680013525
16:25:26.476 -> 2. ora in chiaro        : Tue Mar 28 16:25:25 2023
16:25:26.476 -> 2. now() in chiaro      : Tue Mar 28 16:25:25 2023
16:25:26.476 -> 2. getTimeGMY_HMS(now()): 28.03.2023-16:25:25
16:25:26.476 -> 2. getTimeGMY_HMS(ora)  : 28.03.2023-16:25:25
16:25:26.476 -> 2. ora-data hour()      : 28.03.2023-14:25:25
16:25:26.476 -> 2. ora-data hour(now()) : 28.03.2023-14:25:25

Scusate se mi intrometto, ma anche io vorrei capire meglio il problema.
Io immagino che la differenza tra "ora" e "ora_now" sia semplicemente nel fatto che la prima è UTC (la vecchia GMT), mentre la seconda è mappata nella Time Zone impostata nella setup().
Attualmente siamo CEST, che equivale a UTC+2, e da qui la differenza di 2 ore. Tant'e veroche era una sola ora nel tuo post iniziale, prima dell'inizio dell'ora legale (vedila come "controprova" di quello che sto dicendo). :wink:
O sbaglio?

  • caso 1

il primo setTime imposta il sistema con l'ora legale presa con i dettagli della struttura tm. "ora" è il time_t dell'ora locale, quindi i due dati sono uguali. In questo caso "ora" e now() sono diversi. - now() riporta un incremento di 2 ore rispetto all'ora legale. E' come se "ora" fosse l'ora GMT che va incrementata per l'ora legale. Il valore di hour() è uguale ad "ora".

  • caso 2
    il setTime imposta il sistema con l'ora legale utilizzando il valore time_t ("ora") della struttura tm. In questo caso "ora" e now() coincidono ma hour() è indietro di 2 ore.

Ma hour() prende il suo valore da now()? O no?

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