gestione data/ora da ntp

Buongiorno a tutti,attualmente ho vari nodemcu installati nella mia abitazione, e su quasi tutti ho installato la funzionalità ntp, vorrei centralizzarla su un unico node e poi da questo inviare comandi centralizzati a tutti gli altri, inoltre ho trovato una libreria che gestisce l'ora legale e vorrei utilizzarla.
Il problema è che questo codice;

/*
   This sketch shows an example of sending a reading to data.sparkfun.com once per day.

   It uses the Sparkfun testing stream so the only customizing required is the WiFi SSID and password.

   The Harringay Maker Space
   License: Apache License v2
*/
#include <NTPtimeESP.h>

#define DEBUG_ON


NTPtime NTPch("ch.pool.ntp.org");   // Choose server pool as required
char *ssid      = "";               // Set you WiFi SSID
char *password  = "";               // Set you WiFi password

/*
 * The structure contains following fields:
 * struct strDateTime
{
  byte hour;
  byte minute;
  byte second;
  int year;
  byte month;
  byte day;
  byte dayofWeek;
  boolean valid;
};
 */
strDateTime dateTime;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("Booted");
  Serial.println("Connecting to Wi-Fi");

  WiFi.mode(WIFI_STA);
  WiFi.begin (ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("WiFi connected");
}

void loop() {

  // first parameter: Time zone in floating point (for India); second parameter: 1 for European summer time; 2 for US daylight saving time; 0 for no DST adjustment; (contributed by viewwer, not tested by me)
  dateTime = NTPch.getNTPtime(1.0, 1);

  // check dateTime.valid before using the returned time
  // Use "setSendInterval" or "setRecvTimeout" if required
  if(dateTime.valid){
    NTPch.printDateTime(dateTime);

    byte actualHour = dateTime.hour;
    byte actualMinute = dateTime.minute;
    byte actualsecond = dateTime.second;
    int actualyear = dateTime.year;
    byte actualMonth = dateTime.month;
    byte actualday =dateTime.day;
    byte actualdayofWeek = dateTime.dayofWeek;
  }
}

funziona, ma solo finché e collegata la wifi, appena la scollego non ho più data/ora.
Ho provato a passare i dati nel clock interno del node in questo modo ( e in molti altri)

time_t tempo_NODE;
dateTime = NTPch.getNTPtime(1.0, 1);
  // check dateTime.valid before using the returned time
  // Use "setSendInterval" or "setRecvTimeout" if required
  if(dateTime.valid){
  tempo_NODE.hour = dateTime.hour;
   tempo_NODE.minute = dateTime.minute;
   tempo_NODE.second = dateTime.second;
   tempo_NODE.year = dateTime.year;
   tempo_NODE.month = dateTime.month;
   tempo_NODE.day =dateTime.day;
   setSyncProvider(tempo_NODE);
   serial.println("aggiornamento avvenuto");

ma mi dà questo messaggio di errore compilandolo "
request for member 'minute' in 'tempo_NODE', which is of non-class type 'time_t {aka long int}'
"ma da problemi anche impostando "long" su minute

potete aiutarmi ?

Premetto che non ho ancora mai fatto sincronizzazioni con NTP, ma parlando in generale la time_t non è una struttura, è un unsigned long (Unix time) che rappresenta i secondi dal 1 Gennaio 1970!

Se a te serve un valore time_t devi convertire i campi di dateTime per ottenere una time_t.

Ma la setSyncProvider() non credo che si usi così, perché leggo come descrizione:

"The argument requested is the address of a function which returns the Unix time in time_t format, which is an unsigned long or uint32_t."

Credo tu debba fare qualche altra ricerca per poter realizzare ciò che hai in mente...

Prova a guardare i vari esempi TimeNTPxxxx della libreria Time, che immagino tu stia già usando.
Ci trovi delle funzioni getNtpTime che tornano la data in formato time_t, che puoi tranquillamente utilizzare per la setSyncProvider().

Federico

Grazie Federico66, è vero, era proprio sotto i miei occhi:)

Grazie anche a docdoc per la disponibilità :smiley:

edit- Ma perché non trovo progetti con RTC, aggiornamento periodico da NTP e magari che riesca a gestire l'ora legale ?
Li trovo slegati ma integrarli non è nelle mie possibilità purtroppo

ATTILA666999:
edit- Ma perché non trovo progetti con RTC, aggiornamento periodico da NTP e magari che riesca a gestire l'ora legale ?
Li trovo slegati ma integrarli non è nelle mie possibilità purtroppo

Non mi è ben chiaro, ma con una semplice ricerca ho trovato questo e poi questo (dettaglio funzioni), lascia stare tutto il grosso del progetto, ma se guardi bene c'è esattamente quello che cerchi (se ho capito bene).

Ogni ora, legge il tempo via NTP e aggiorna RTC se necessario.
Utilizza la funzione LegalTime(), per calcolare l'ora legale partendo dall'ora corrente.

Non ho mai affrontato questioni di questo tipo, ma mi sembra un buon punto di partenza, inoltre tutto il codice è ben commentato ed è in italiano (ceh non guasta).

Spero ti sia utile.

Federico

interessante, me lo studio :slight_smile:
Grazie & karma per te :slight_smile:

ATTILA666999:
Grazie & karma per te :slight_smile:

Grazie

PS
A proposito di karma, ma c'è modo di sapere quando sono stati dati, in modo da capire il perché sono stati dati?

non saprei, forse un mod può delucidarci :slight_smile:

ATTILA666999:
edit- Ma perché non trovo progetti con RTC, aggiornamento periodico da NTP e magari che riesca a gestire l'ora legale
Li trovo slegati ma integrarli non è nelle mie possibilità purtroppo

Perché la maggior parte dei progetti non dura più di un mese o la gente non è abbastanza pigra.
Il core ESP8266 ha già tutto

/*
ESP8266_Time_Sync_NTP

Original
https://forum.arduino.cc/index.php?topic=466867.msg3686997#msg3686997
European version using CET
https://forum.arduino.cc/index.php?topic=546753.msg3728905#msg3728905

*/

#include <sys/time.h>                   // struct timeval
#include <time.h>                       // time() ctime()       
#include <ESP8266WiFi.h>   //Part of ESP8266 Board Manager install

#define NTP0 "europe.pool.ntp.org"
#define NTP1 "ntp1.inrim.it"
/*
  ntp1.inrim.it (193.204.114.232)
  ntp2.inrim.it (193.204.114.233)
  it.pool.ntp.org

  Worldwide 	pool.ntp.org
  Asia 	asia.pool.ntp.org
  Europe 	europe.pool.ntp.org
  North America 	north-america.pool.ntp.org
  Oceania 	oceania.pool.ntp.org
  South America 	south-america.pool.ntp.org

*/

//#define TZ "EST+5EDT,M3.2.0/2,M11.1.0/2"
#define TZ "CET-1CEST,M3.5.0/2,M10.5.0/3"
//CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00
/*
  Found this reference on setting TZ: http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html

  Here are some example TZ values, including the appropriate Daylight Saving Time
  and its dates of applicability. In North American Eastern Standard Time (EST)
  and Eastern Daylight Time (EDT), the normal offset from UTC is 5 hours;
  since this is west of the prime meridian, the sign is positive.
  Summer time begins on March's second Sunday at 2:00am,
  and ends on November's first Sunday at 2:00am.
*/



// Replace with your network details
const char* ssid = "yourSSID";
const char* password = "yourPASSPHRASE";

/*
  //setting the addresses
  IPAddress staticIP(10, 0, 0, 174);
  IPAddress gateway(10, 0, 0, 1);
  IPAddress subnet(255, 255, 255, 0);
*/


int DOW, MONTH, DATE, YEAR, HOUR, MINUTE, SECOND;

int lc = 0;
time_t tnow;
char strftime_buf[64];


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

  if (Serial.available())
  {

    Serial.println("Starting...");
    Serial.println("ESP8266_Time_Sync.ino");
  }
  // set up TimeZone in local environment
  setenv("TZ", TZ, 3);
  tzset();

  // Connecting to local WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  //WiFi.config(staticIP, gateway, subnet);
  WiFi.begin(ssid, password);
  delay(10);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(100);
  }
  configTime(0, 0, NTP0, NTP1);
  Serial.println("\n WiFi connected");
  Serial.print("MAC: ");
  Serial.println(WiFi.macAddress());
  Serial.print("Server IP:  ");
  Serial.println(WiFi.localIP());
  Serial.println("\n");
  Serial.print("wait for first valid timestamp ");

  while (time(nullptr) < 100000ul)
  {
    Serial.print(".");
    delay(10);
  }
  Serial.println(" time synced");
  // set up SoftAP
  // WiFi.softAP("DATA","*logger#");
  // WiFi.softAPConfig(local_ip, gateway, subnet);
}

void loop()
{
  getDateTime();
  Serial.println(strftime_buf);

  Serial.println("");
  Serial.print(DOW);
  Serial.println("   Day of week");

  Serial.print(HOUR);
  Serial.println("  Hours");
  Serial.print(MINUTE);
  Serial.println("  Minutes");
  Serial.print(SECOND);
  Serial.println("  Seconds");
  Serial.println("\n");
  delay(1000);
}

void getDateTime()
{
  struct tm *ti;

  tnow = time(nullptr) + 1;
  strftime(strftime_buf, sizeof(strftime_buf), "%c", localtime(&tnow));
  ti = localtime(&tnow);
  DOW = ti->tm_wday;
  YEAR = ti->tm_year + 1900;
  MONTH = ti->tm_mon + 1;
  DATE = ti->tm_mday;
  HOUR  = ti->tm_hour;
  MINUTE  = ti->tm_min;
  SECOND = ti->tm_sec;
}

Questo esempio gestisce la richiesta NTP e tiene conto dell'ora legale, quindi mette su un RTC software.

zoomx:
Questo esempio gestisce la richiesta NTP e tiene conto dell'ora legale, quindi mette su un RTC software.

Grazie, prima o poi mi servirà, quindi lo metto subito nel cassetto...

Federico

zoomx:
Il core ESP8266 ha già tutto

Grazie mille, lo provo questo WE

@zoomx
L'ho caricato e funziona benissimo non so però ogni quanto si aggiornata tramite NTP, mi sono letto il tread di riferimento (in cui la sviluppavate Tu e Techno500 ) e mi sembrava di aver capito che si aggiornava ogni 15 minuti, oppure ho capito male ed è legata unicamente alla funzione "getDataTime" ? oppure è possibile inserire una variabile con un dato tipo in secondi ad esempio ?
Altrimenti posso semplicemente controllare la funzione con un if e farla partire quando cambia l'ora ad esempio ?

Nel Thread di riferimento io avevo proposto un altro approccio perché non conoscevo questa possibilità.
Tale approccio si basava sulla richiesta del pacchetto UDP con il tempo e la sua successiva interpretazione. Poi veniva usata la libreria TimeZone per il cambio di ora. Techno500 richiamava la funzione ogni 15 minuti.

Un utente del forum ESP8266.com ha suggerito poi a Techno500 questo approccio che non fa uso di librerie.
https://www.esp8266.com/viewtopic.php?f=6&t=18642
Qui
https://www.esp8266.com/viewtopic.php?p=80329
dicono che effettua la sincronizzazione ogni ora e fa riferimento a questo esempio
Arduino/NTP-TZ-DST.ino at master · esp8266/Arduino · GitHub
presente fra gli esempi dell'ESP8266 e mi sembra anche migliore di quello postato da me.

Alla fine sono ritornato qui...

ATTILA666999:
Li trovo slegati ma integrarli non è nelle mie possibilità purtroppo

:frowning:

Quello che ho accluso gestisce anche l'ora legale.
Sta tutto qui
#define TZ "CET-1CEST,M3.5.0/2,M10.5.0/3"
M3 sta per Marzo e M10 sta per ottobre, per il resto basta vedere la documentazione per Unix/Linux in quanto la sintassi è la stessa.

Riassumendo nel tuo codice devi aggiungere all'inizio le librerie

#include <sys/time.h>                   // struct timeval[color=#222222][/color]
#include <time.h>                       // time() ctime()

i server NTP

#define NTP0 "europe.pool.ntp.org"
#define NTP1 "ntp1.inrim.it"

La variabile d'ambiente TZ

#define TZ "CET-1CEST,M3.5.0/2,M10.5.0/3"

Poi anche queste variabili usate per trattare l'orario nel codice (ma può anche ssere fatto in altro modo)

int DOW, MONTH, DATE, YEAR, HOUR, MINUTE, SECOND;

int lc = 0;
time_t tnow;
char strftime_buf[64];

Nel setup va messo

configTime(0, 0, NTP0, NTP1);
  while (time(nullptr) < 100000ul)
  {
    Serial.print(".");
    delay(10);
  }
  Serial.println(" time synced");

Dopodiché agiungi questa funzione ma, come ho scritto prima, qui la gestione della lettura del tempo può essere fatta diversamente

void getDateTime()
{
  struct tm *ti;

  tnow = time(nullptr) + 1;
  strftime(strftime_buf, sizeof(strftime_buf), "%c", localtime(&tnow));
  ti = localtime(&tnow);
  DOW = ti->tm_wday;
  YEAR = ti->tm_year + 1900;
  MONTH = ti->tm_mon + 1;
  DATE = ti->tm_mday;
  HOUR  = ti->tm_hour;
  MINUTE  = ti->tm_min;
  SECOND = ti->tm_sec;
}

Quindi ovunque chiami getDateTime() poi ti ritrovi con le variabili popolate con l'ora corrente. Ma qui potrebbe anche essere realizzato in maniera differente.

@Zoomx,
Sei gentilissimo lo provo nel prossimo WE

P.S. Scusa il ritardo per la risposta ma non riesco a dedicare tutto il tempo che vorrei a questo splendido mondo :slight_smile:

P.p.s. Questa funzione l'avevo abbastanza compresa, la mia difficoltà era integrare una memorizzazione dell'orario dentro al node (o magari dentro un RTC 3231) altrimenti appena non ho wifi non ho più l'orario, sbaglio ? per questo pensavo di far partire la funzione un paio di volte al giorno per sincronizzarla e memorizzarla.

L'ESP8266 mantiene l'ora anche senza WiFi, l'interrogazione avviene ogni ora ma credo che se fallisce tiene l'informazione che ha.

Io uso la tecnica proprio per degli orologi, ma senza allarme o altro, uno è un cosiddetto Pong Clock (gioca una finta partita di pong e il punteggio è l'orario) e l'altro un Word Clock (ma in inglese). Il primo soprattutto, va perfettamente.
Un paio di progetti con Arduino li ho abbandonati proprio perché c'era da sistemare gli orari (e quindi mettere dei pulsanti), qui invece eventualmente mi basta resettare.

Prenditi tutto il tempo che vuoi, siamo a luglio!

perfetto, ho dovuto aggiungere solo la riga;

 setenv("TZ", TZ, 3);
 tzset();

per avere il fuso giusto, anche se pensavo che avrei dovuto aggiungerla qui, ma non ha funzionato;

tnow = time(nullptr) + 1;

Ultima cosa, ma lui si aggiorna ogni ora oppure quando faccio partire la funzione getDateTime(); o quella funzione è solo per formattare i valori ?

Grazie ancora

La seconda che hai detto, l'orologio va per i fatti suoi e si dovrebbe aggiornare da solo ogni ora.