Как работает NTPClient.h или почему сбиваются вайфай часы

Доброго времени суток.
Сделал вайфай часы на Max7219 и ESP8266 с получением времени от NTP.
Использую библиотеку GitHub - arduino-libraries/NTPClient: Connect to a NTP server
Инициализирую NTPClient timeClient(ntpUDP,“europe.pool.ntp.org”,14400,60000);
Опрос NTP раз в минуту

Раз в минуту вывожу бегущей строкой день недели и дату с годом, или температуру в доме и на улице.
Раз в 5 минут получаю и парсю температуры со своего уличного датчика на народном мониторинге
Раз в секунду с помощью SimpleTimer timer получаю время от NTP и вывожу на экран

void DisplayTime(){
//Получаем время
     timeClient.update(); 
    hh = timeClient.getHours();
    mm = timeClient.getMinutes();
    ss = timeClient.getSeconds(); 
   day = timeClient.getDay();
// Выводим время 
   matrix.drawChar(x... ит.д.

в лупе

void loop(){
    timer.run();
    timeClient.update();
    yield();
}

Всё работает отлично, если бы не периодическое отставание до 5 минут с последующим восстановление точного времени.
Один раз минуты совпали, но часы отставали на час. Вывел информацию о полученном времени раз минуту в WebSerial для контроля.

timeClient.update();
     Time = String(timeClient.getFormattedTime());
     String date_time = timeClient.getFormattedDate();
     Date = date_time.substring(0, 10); 
    
     WebSerial.print(hh);  WebSerial.print(":");  WebSerial.print(mm);
     WebSerial.print(":"); WebSerial.println(ss); 
     WebSerial.println(date_time);

Так по нему получается, что такое отстающее время я получаю от NTP.
Пробовал библиотеку GyverNTP, тоже самое. Что то я совсем ничего не понимаю. Как работает сервер NTP, может разъясните.
Полный код не вывожу, он состоит из 6 вкладок. Не знаю как вывести.

Сократить до десятка-другого строк, так, чтобы проблема сохранилась и привести.

Каждый раз поражаюсь этому. Смысл постить такие запросы? Без кода сказать определённо нельзя ничего, кроме самых наипростейших случаев.

Кстати, пока будете сокращать код, весьма вероятно, что сами и выявите проблему (заметите где она появляется и при каких условиях исчезает). Тогда и посты не понадобятся.

3 лайка

Вот вроде так и сделал

[code]
/* Часы на светодиодной матрице Max7219 и ESP12
 * 
Подключение:
     ESP 12E    -> Matrix
MOSI-GPIO13     -> DIN
CLK -GPIO14     -> Clk
     GPI12      -> CS
****************************************************************     
*/

#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>  
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Max72xxPanel.h>
#include <ArduinoJson.h>
#include <SimpleTimer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <WebSerial.h>
#include <AsyncElegantOTA.h> 
//**************************************************************
//const char* ssid     = "";     // название и пароль точки доступа
const char* ssid     = "";
const char* password = "";
const char* host     = "narodmon.ru";
const int   httpPort = 8283;
//**************************************************************
#define MAX_DIGITS             16
#define ONE_WIRE_BUS            2          // pin DS18B20
#define Pin_led                 4          // pin светодиода
#define Pin_CS                 12          // Прикрепите CS к этому контакту, DIN к MOSI и CLK к SCK 
#define t0_interval          1000          // через время (1*1000) милисекунд многократно выполнять функцию DisplayTime
#define t1_interval         60000          // через время (60*1000) милисекунд многократно выполнять функцию Scroll
#define t2_interval        300000          // через время (5*60*1000) милисекунд многократно выполнять функцию jsonGet
//**************************************************************
byte dig[MAX_DIGITS]     ={0};
byte digold[MAX_DIGITS]  ={0};
byte digtrans[MAX_DIGITS]={0};

int day,dd,hh,mm,ss;                       // день,дата,час,мин,сек
String Date = "";
String Time = "";
unsigned int timer0, timer1, timer2;

float temp0,temp1;
String Out_temp,In_temp;
bool UPDATE;                         // если включенo обновление - true

bool FLAG,WEATER;
int refresh = 0;
int wait   = 50;         // скорость бегущей строки
int spacer = 2;
int width  = 5 + spacer; // Регулируем расстояние между символами
//**************************************************************
Max72xxPanel matrix = Max72xxPanel(Pin_CS, 4, 1);  // матрица 4*1
WiFiUDP ntpUDP;
SimpleTimer timer;
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org",14400,60000); // 14400 - временной сдвиг в секундах от UTC
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds(&oneWire);
DeviceAddress ds0;
AsyncWebServer server(80);
//**************************************************************
void setup(){
// Начальная яркость матрицы от 0 до 15  
    matrix.setIntensity(0); 

// Начальные координаты матриц 8*8
    matrix.setRotation(0, 1);        // 1 матрица
    matrix.setRotation(1, 1);        // 2 матрица
    matrix.setRotation(2, 1);        // 3 матрица
    matrix.setRotation(3, 1);        // 4 матрица

// serial
    Serial.begin(115200);

// OUT 
    pinMode(Pin_led, OUTPUT);digitalWrite(Pin_led, LOW);

// DS18B20
    ds.begin();

// Достаем адрес датчикa
  if(!ds.getAddress(ds0,0)) Serial.println("Unable to find address for Device 0"); 

// Устанавливаем разрешение 12 bit
    ds.setResolution(ds0,12);
     delay(100);    

// Запускаем WIFI                              
      ConnectWiFi();

// Получаем данные из сети
    timeClient.begin();

// Запускаем таймеры
    timer0 = timer.setInterval(t0_interval, DisplayTime);
//    timer1 = timer.setInterval(t1_interval, Time_init);
    timer2 = timer.setInterval(t2_interval, jsonGet);      
}
//**************************************************************
void Scroll(){
// Получение текущего времени
    Time_init();    
// запускаем бегущую строку 
    if(FLAG){
       if(day == 0)ScrollText(utf8rus("Воскресенье "));
       if(day == 1)ScrollText(utf8rus("Понедельник "));
       if(day == 2)ScrollText(utf8rus("Вторник "));
       if(day == 3)ScrollText(utf8rus("Среда "));
       if(day == 4)ScrollText(utf8rus("Четверг "));
       if(day == 5)ScrollText(utf8rus("Пятница "));
       if(day == 6)ScrollText(utf8rus("Суббота "));
       ScrollText(utf8rus(Date));                     // дата
       ScrollText(utf8rus(Time));                     // дата
       }
    else {ScrollText(utf8rus(In_temp));               // температура в доме
          if(WEATER) ScrollText(utf8rus(Out_temp));   // температура на улице
         }
    FLAG = !FLAG;
    DisplayTime(); 
}
//**************************************************************
void loop(){
    timer.run();
    timeClient.update();
    yield();
}
//**************************************************************
// Получаем время  и день
void DisplayTime(){
     timeClient.update(); 
    hh = timeClient.getHours();
    mm = timeClient.getMinutes();
    ss = timeClient.getSeconds(); 
   day = timeClient.getDay();

// регулировка яркости
  if(hh > 7 && hh < 22)matrix.setIntensity(3);
  else                 matrix.setIntensity(1);    

// Определяем момент для бегущей строки
  if(ss == 0) Scroll();

// Выводим время на Max7219    
    matrix.fillScreen(LOW);
..............................
..............................
}
//**************************************************************
void Time_init(){
// Получение текущего времени
    timeClient.update();
     Time = String(timeClient.getFormattedTime());
     String date_time = timeClient.getFormattedDate();
     Date = date_time.substring(0, 10); 
//     Date.replace("-",".");
     Serial.println(Time);
     WebSerial.print(hh);  WebSerial.print(":");  WebSerial.print(mm);
     WebSerial.print(":"); WebSerial.println(ss); 
     WebSerial.println(date_time);
}
//**************************************************************
void jsonGet(){
// Получаем температуру из сети и в доме
}
//END***********************************************************
[/code]

Если оставить только работу с временем, то получится такой код

[code]

#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>  
//**************************************************************
//const char* ssid     = "";     // название и пароль точки доступа
const char* ssid     = "";
const char* password = "";
const char* host     = "narodmon.ru";
const int   httpPort = 8283;
//**************************************************************
#define t0_interval          1000          // через время (1*1000) милисекунд многократно выполнять функцию DisplayTime
#define t2_interval        300000          // через время (5*60*1000) милисекунд многократно выполнять функцию jsonGet
//**************************************************************
int day,dd,hh,mm,ss;                       // день,дата,час,мин,сек
String Date = "";
String Time = "";
unsigned int timer0, timer1, timer2;
//**************************************************************
WiFiUDP ntpUDP;
SimpleTimer timer;
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org",14400,60000); // 14400 - временной сдвиг в секундах от UTC
//**************************************************************
void setup(){
// Запускаем WIFI                              
      ConnectWiFi();

// Получаем данные из сети
    timeClient.begin();

// Запускаем таймеры
    timer0 = timer.setInterval(t0_interval, DisplayTime);
    timer2 = timer.setInterval(t2_interval, jsonGet);      
}
//**************************************************************
void Scroll(){
// Получение текущего времени
    Time_init();    

// запускаем бегущую строку 
    if(FLAG){  // выводим дни недели.....
       }
    else {   // температура в доме и на улице
         }
   
 FLAG = !FLAG;
    DisplayTime(); 
}
//**************************************************************
void loop(){
    timer.run();
    timeClient.update();
    yield();
}
//**************************************************************
// Получаем время  и день
void DisplayTime(){
     timeClient.update(); 
    hh = timeClient.getHours();
    mm = timeClient.getMinutes();
    ss = timeClient.getSeconds(); 
   day = timeClient.getDay();

// Определяем момент для бегущей строки
  if(ss == 0) Scroll();

// Выводим время на Max7219    
    matrix.fillScreen(LOW);
..............................
..............................
}
//**************************************************************
void Time_init(){
// Получение текущего времени
    timeClient.update();
     Time = String(timeClient.getFormattedTime());
     String date_time = timeClient.getFormattedDate();
     Date = date_time.substring(0, 10); 
// выводим в  Serial
     Serial.println(Time);
     WebSerial.print(hh);  WebSerial.print(":");  WebSerial.print(mm);
     WebSerial.print(":"); WebSerial.println(ss); 
     WebSerial.println(date_time);
}
//**************************************************************
void jsonGet(){
// Получаем температуру из сети и в доме
}
//END***********************************************************
[/code]

Проблема в нём присутствует или исчезла?

Если присутствует, то физически удалите всё лишнее (чтобы глаза не мозолило) и выложите наконец короткий и ясный код, содержащий проблему.

И кстати, вот эти библиотеки нестандартные,

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

а потому давайте ссылки на гитхаб или где Вы их там брали.

Вы поймите, цель всего этого дать желающему возможность, запустить код у себя, увидеть проблему, решить её и рассказать Вам. Вот из этого и исходите - если Вы выложили не всё, что для этого требуется, значит Вам не помогут при всём желании.

1 лайк

Меньше последнего кода, уже некуда. Там я оставил только работу со временем, и описание, того, что есть в исходном коде.

Что значит нестандартные? Самые стандартные. А ссыль на них я дал в самом первом посте.
Повторю, что использую библиотеку NTPClient
Достаточно открыть ссылку и посмотреть пример. По нему и делал. По большому счету, у меня вопрос не по коду, а по работе c NTP сервером. Почему получая от него каждую секунду время, мои часы могут убегать? Как такое может быть?

Для “стандартных” библиотек и поведение “стандартное”

Щас такое время… Я читал, что теперь столетний эталон килограмма в палате мер и весов объявлен нестандартным.
А стандартный теперь другой…

А ежесекундно бомбардировать NTP сервер - это нормально?
Он, вообще-то, служит для того, чтобы время от времени (например, раз в сутки) подкорректировать часы.

Ну вообще то это не моя блажь. Вы по ссылке пример гляньте, там опрос ежесекундно. Делаю исключительно по нему.

Да, это чужая глупость, которую вы повторяете

Ну не знаю. Я как то верю автору библиотеки, тем более она довольно популярная. Пойду на форуме esp8266ипоспрашиваю. Профильный форум, должны знать. Спасибо всем.

И напрасно.

Вы думаете, Вы один такой - который верит вместо того, чтобы самому разобраться.

Вот интересно, на сколько убегают часы за 1 сек? Может часы по лучше использовать?