Доброго всем! Устройство на базе esp нуждается в более-менее точном времени. модуль припаивать не комильфо ведь есть же вайфай. В общем, ищу нормальную реализацию NTP клиента (асинхронную) поскольку устройство занимается пением. Я немного подпилил пример с AsyncUDP клиентом для асинхронного получения "точного" времени, но совсем не Си-гуру и мне нужно, чтобы я мог задавать адрес серевра NTP через его доменное имя, а не IP-адрес. Следующий шаг - завернуть в класс/библу и отдать нуждающимся если таковые есть (а может уже и есть решение, но не нашел). Тогда это была бы законченная реализация, дружественная к конечному пользователю девайса (настройка через web). Мой код ниже (реализацию запроса взял https://github.com/arduino-libraries/NTPClient ) Не поверю, что все кто сталкивался с синхроном по NTP не сталкивались с проблемой тупого GetLocalTime. И да, скажу заранее - опубликованный здесь код уже есть на другом форуме, и он мой, просто там не смогли/не хотели помочь. Код (C++): #include "Arduino.h" #include "WiFi.h" #include "AsyncUDP.h" #define secs70 2208988800UL #define NTP_PACKET_SIZE 48 #define UPDATE_PERIOD 10 //каждый 10 сек корректируем время unsigned long lastUpdate = 0; long gmtOffset = 3600 * 9; //9 - мой часовой пояс unsigned long offsetTime = 0; unsigned long updateT = 0; int retryUpd = 0; time_t now; //системное время на устройстве const char* ssid = "ssid"; const char* password = "pass"; AsyncUDP udp; void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); if (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("WiFi Failed"); while (1) { delay(1000); } } now = millis() / 1000; if (udp.connect(IPAddress(162, 159, 200, 123), 123)) //time.cloudflare.com......pool.ntp.org 0-й сервер (197,84,150,123)/* { Serial.println("UDP connected"); udp.onPacket([](AsyncUDPPacket packet) { unsigned long highWord = word(packet.data()[40], packet.data()[41]); unsigned long lowWord = word(packet.data()[42], packet.data()[43]); unsigned long secs1900 = highWord << 16 | lowWord; unsigned long current = secs1900 - secs70 + gmtOffset; offsetTime = (time_t)(current); Serial.println("TIME CORRECTION"); }); } } void printTime() { tm tm; localtime_r(&now, &tm); char buff[30]; strftime(buff, 256, "%Y-%m-%d %H:%M:%S", &tm); Serial.println(buff); } void update() { byte buff[NTP_PACKET_SIZE]; //48 memset(buff, 0, NTP_PACKET_SIZE); buff[0] = 0b11100011; buff[1] = 0; buff[2] = 6; buff[3] = 0xEC; buff[12] = 49; buff[13] = 0x4E; buff[14] = 49; buff[15] = 52; if (udp.connected()) udp.write(buff, NTP_PACKET_SIZE); } void loop() { now = offsetTime + (millis() - updateT) / 1000; if (millis() - lastUpdate > 1000) { Serial.print("Now: "); printTime(); lastUpdate = millis(); retryUpd++; if (retryUpd >= UPDATE_PERIOD)//~каждые 10 секунд корректировка асинхронная { updateT = millis(); update(); retryUpd = 0; } } }
Если речь про это: https://github.com/arduino-libraries/NTPClient то вот по чему: Код (C++): do { delay ( 10 ); cb = this->_udp->parsePacket(); if (timeout > 100) return false; // timeout after 1000 ms timeout++; } while (cb == 0); фриз в лупе
А как правильно выходить из цикла, если нужно либо дождаться ответа, либо прекратить запрос? Вот в вашем коде : Код (C++): if (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("WiFi Failed"); while (1) { delay(1000); } } При попытке соединения с сетью вы просто уходите в бесконечный цикл вместо того, чтобы повторить запрос. Так ваше устройство не сможет работать автономно. Допустим, выключили электричество, потом включили. Ардуино включилось сразу, а роутер через N минут. Но Ардуино уже не сможет самостоятельно к нему подключиться. Потребуется ручная перезагрузка. Тут бы вам либо WTD поставить, либо зациклить попытки соединения.
А какая проблема? Не сталкивался ни с какими проблемами, использую все стандартное: Код (C++): #include <ESP8266WiFi.h> #include <WiFiUdp.h>
Всех с прошедшим! Никого не хочу обидеть, но похоже никто не вникает в содержание вопроса. Да, я вам про асинхронный запрос, а вы мне про бесконечный цикл Речь вообще не об этом. А как Вы синхронизируете время по ntp? Прошу показать кусочек кода по отправке запроса и обработке ответа от ntp-сервака, будет забавно, если я на ровном месте нашел проблему.
как в примере к библиотеке. Асинхронностью кода не заморачивался, так как у меня для NTP отдельный контроллер, основной код на другом МК
в примерах стандартного SDK есть следующее: Код (C++): sntp_stop(); sntp_setservername(0,"ntp.time.in.ua"); sntp_setservername(1,"pool.ntp.org"); sntp_set_timezone(2); sntp_init(); и забираем время Код (C++): uint32 Time = sntp_get_current_timestamp()
в примере к библиотеке (еще вопрос какой библиотеки) показан еще один способ как задушить луп. Что касается отдельного МК под время, ну не у всех такие грандиозные проекты и теперь мне капец как интересно узнать какой контроллер вы для этого используете и в каком устройстве. От души приветствую! Я натыкался на этот код, но как его прикрутить к своей задаче ума не хватило. Погуглил сегодня еще и вроде кое-что нашел, и там реализованы колбэки. Проверить надо
Согласен, но я водитель, а не механик ). Много быстрее собрать проект из того что уже сделано чем писать самому. Что касается найденной библы - проверил, работает отлично. Синхронизация в бэкграунде, колбэк, точность 1 мс. https://github.com/gmag11/ESPNtpClient. parovoZZ, спасибо за наводку, библу нашел гугля реализацию sntp_. Остальным участникам - фэйспалм
таки зачем тогда вообще отвечать? тем более не в кассу. только по фразе - "ну перепишите цикл асинхронно - в чем проблема?" уже все понятно - гуру по количеству бесполезных реплик Посмотрите библу, может уберете лишний мк.
не уберу, меня устраивает А что до "перепишите" - ну правда смешно, там поменять-то надо пару строк - разбить получение времени на две отдельные процедуры, отправку запроса и получения ответа.
Нужно еще посмотреть на эту асинхронность. Хотел протестировать, когда и откуда вызывается обработчик, но пока не до этого, восстанавливаю систему на даче.
на примере "блинк без делэй". а может лучше на две функции? погуглите - асинхронная реализация ну так если "Не сталкивался ни с какими проблемами, использую все стандартное:" конечно упадет
Спойлер: А у меня так и сделано: Код (C++): loop() { //............................................................ //............................................................ if( (cur_ms - ms2) > 900000L) && !NTP_answer_timeout && T100_ms_timer==1 && s > 20 && WiFi_Last_State == CONNECTED ) { err_count++; // увеличим счетчик попыток NTP_Request_Send(); } if(NTP_Answer_Check()) { if( NTP_answer_timeout ) { if (NTP_Answer_Read()) { ms2 = cur_ms; err_count = 0; NTP_answer_timeout=0; } } } //............................................................ //............................................................ } В часах с NTP, я не использовал <Time.h>, только UDP, время считаю и синхронизирую сам. Использую <Ticker.h>, который дергает каждые 100мс функцию (делал и 10мс, разницы глазами не видно), из нее и обновление 4-х разрядного, 7-ми индикатора по SPI. Когда делал первые часики с NTP хотелось сделать, чтобы поставленные рядом несколько часов обновлялись бы синхронно (типа как в Apple Watch, все часы в мире ходят абсолютно синхронно). Поэтому из приходящего пакета NTP вытаскиваю не только время до секунд, но и доли секунд (44-47, байты пакета), отправляю запрос в начале секунды, учитываю время отправки пакета, время получения ответа. Если если ответ пришел c задержкой - игнорирую ответ. Если без задержек смотрю на доли секунд, рассчитываю десятые, и если время отличаются - синхронизирую. Все это в loop(), при этом часы еще измеряют температуру, влажность, отправляют их по MQTT, получают по MQTT уличную температуру, которую отображают попеременно со временем. Дома таких в разных размерах 5 штук.