• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Делюсь опытом Вот написал классик для NTP

Сергей_Ф

Moderator
Команда форума
Ну или просто добавить в класс две настраиваемые даты перехода и оставить на усмотрение создателя экземпляра.
Именно это я и мел ввиду под словом автоматическая. Т.е. Не вручную часовой пояс менять, а вбить две даты и флажок менять/не менять.
P.S. на счёт возраста @pvvx Вы серьезно ошиблись, имхо :)
 

pvvx

Активный участник сообщества
@pvvx, "Хорошие люди не пишут на паскале" это мем из безсмертного произведения времен фидо "9600 бод и все, все, все...". Классику хорошо бы помнить;) И это как-бы намекает, что Assm VS С++, и прочие холивары решения задач разноуровневых языков имеют корни столь же древние, как и сами языки.
А я не особо понимаю эти 'холивары'. Мне всё равно какой язык, т.к. все они возникли за время моей работы с железками на которых они работают. Но точно знаю, что 'холивары' разводят те, кто не знает других языков. Вот вы уже выделяете что-то и разводите 'холивар' :)
Я вот с Arduino плохо знаком - например, не знаю как узнать в ней сколько I2C портов там имеет чип, на котором я пишу. Но после получасовых поисков в инете, задавая разные поисковые запросы, это нашел. В других языковых средах на такую задачу уходило до пары секунд - клик правой кнопкой мыши и вылезало описание объекта... :) В итоге ковыряние в окошке-амбразуре редактора Arduin-ы, не имеющей даже правильной подсветки контекста или чего другого, вызвало отторжение. Но тут на вкус и цвет... :)
Узнать, какая среда программирования лучше можно по простым критериям - чем меньше тем в инете по ней, тем она лучше. Тут как с авто - если в автомобиле много ошибок и неисправностей выявляющихся в процессе эксплуатации, тем больше кол-во форумов и прочих вопросов владельцев. На хорошей вещи обсуждают типа какого цвета лучше повесить наклейку и каким типом шрифта её написать :)
 
Последнее редактирование:

Sr.FatCat

Member
@pvvx, то что Вы сейчас пишите - и есть холивар :) Поэтому продолжать в этом духе смысла нет.

Абсолютно ясно, что лучше та среда - которую знаешь. Если бы вместо неприятного Вам "ковыряние в окошке-амбразуре редактора Arduin-ы" поставили бы Visual Micro для Visual Studio, то получили бы полный набор положительных эмоций от правильной подсветки синтаксиса, мощного языкового помошника, разветвленного инспектора объектов, огромного набора путеводителей по библиотекам, возможности просмотра кода в микроассемблере и очень приятных средств отладки


Но, как бы, каждый решает сам...
 

pvvx

Активный участник сообщества
Если бы вместо неприятного Вам "ковыряние в окошке-амбразуре редактора Arduin-ы" поставили бы Visual Micro для Visual Studio, то получили бы полный набор положительных эмоций от правильной подсветки синтаксиса, мощного языкового помошника, разветвленного инспектора объектов, огромного набора путеводителей по библиотекам, возможности просмотра кода в микроассемблере и очень приятных средств отладки
Я про то вам и сказал.
Вот только это не верно:
Абсолютно ясно, что лучше та среда - которую знаешь.
Они все имеют одинаковые структуры и если знаете их, то выйдет всё равно какая, лиш бы давала информацию. Но вы указывали, что знаний не требуется :) От этого и возник сыр-бор.
--------
ФАПЧ для системных часов по NTP не планируется?

< Источник http://www.ntp.org/ntpfaq/NTP-s-algo.htm#FIG-NTP-INIT >
 
Последнее редактирование:

pvvx

Активный участник сообщества
Что то не работает ваш ESP8266_NTPClass_test :(
В исправленном варианте работает на всех модулях:
Код:
WiFi start...
interface 0 is initialized
interface 1 is initialized
Initializing WIFI ...
WIFI initialized
RTL8710[Driver]: set ssid [***********]
RTL8710[Driver]: start auth to **:**:**:**:**:**
RTL8710[Driver]: auth success, start assoc
RTL8710[Driver]: association success(res=3)
RTL8710[Driver]: set pairwise key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4)
RTL8710[Driver]: set group key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4) keyid:1
Interface 0 IP address : 192.168.1.122
Connection done!
No NTP Response :-(
No NTP Response :-(
swap 2
09:46:03 10.11.2016
09:46:04 10.11.2016
09:46:05 10.11.2016
09:46:06 10.11.2016
09:46:07 10.11.2016
09:46:08 10.11.2016
09:46:09 10.11.2016
09:46:10 10.11.2016
09:46:11 10.11.2016
09:46:12 10.11.2016
09:46:13 10.11.2016
09:46:14 10.11.2016
09:46:15 10.11.2016
И в отличии от стандартных примеров занимает на несколько килобайт больше памяти.
Вывод времени и работа практически не отличаются:
Код:
WiFi start...
interface 0 is initialized
interface 1 is initialized
Initializing WIFI ...
WIFI initialized
RTL8710[Driver]: set ssid [***********]
RTL8710[Driver]: start auth to **:**:**:**:**:**
RTL8710[Driver]: auth success, start assoc
RTL8710[Driver]: association success(res=3)
RTL8710[Driver]: set pairwise key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4)
RTL8710[Driver]: set group key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4) keyid:1
Interface 0 IP address : 192.168.1.122
waiting for sync
Transmit NTP Request
10:07:00 10 11 2016
10:07:01 10 11 2016
10:07:02 10 11 2016
10:07:03 10 11 2016
10:07:04 10 11 2016
10:07:05 10 11 2016
10:07:06 10 11 2016
10:07:07 10 11 2016
10:07:08 10 11 2016
10:07:09 10 11 2016
10:07:10 10 11 2016
В ESP8266 до сих пор не работает Udp.setRecvTimeout(xx_ms)? :confused:
 

Вложения

Sr.FatCat

Member
@pvvx, спасибо за предложенный вариант оптимизации, хотя и я не со всем согласен. Не понял - почему не работало. Без необязательной части UDP NTP пакета сервера не отвечали? Все остальное вроде тоже самое. И не понял еще насчет Udp.setRecvTimeout - оно работает или нет? В Вашем варианте вроде же вставили.

И странно, что у Вас в первом примере, аж только 3-й сервер ответил. У меня на ESP-12E ни разу даже swap-а по этим серверам не было, кроме как в тесте....

Пример больше на несколько Кбайт из-за printf. В реальном проекте, целесообразность использования printf, конечно весьма спорна, но в примерах и отладке - сильно уменьшает количество кода и не отвлекает на неважные вещи. Хотя для Arduino, по-моему, оптимальным является все-таки использование прототипа:

Код:
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
Насчет ФАПЧ для системных часов по NTP, задача красивая, но по-моим проектам придумать применение пока не могу, так, что больше академическая. О! Сбагрю сыну, в качестве курсовой, если препод возражать не будет!
 
Последнее редактирование:

pvvx

Активный участник сообщества
@pvvx, спасибо за предложенный вариант оптимизации, хотя и я не со всем согласен. Не понял - почему не работало. Без необязательной части UDP NTP пакета сервера не отвечали?
В базовом варианте никто не отвечал вообще.
Все остальное вроде тоже самое. И не понял еще насчет Udp.setRecvTimeout - оно работает или нет? В Вашем варианте вроде же вставили.
С ней и заработало. А как иначе таймаут у Udp.read() ?
И странно, что у Вас в первом примере, аж только 3-й сервер ответил. У меня на ESP-12E ни разу даже swap-а по этим серверам не было, кроме как в тесте....
Ужасные сервера. Через какое-то время работы пишет ещё "sawp 0".
Пример больше на несколько Кбайт из-за printf. В реальном проекте, целесообразность использования printf, конечно весьма спорна, но в примерах и отладке - сильно уменьшает количество кода и не отвлекает на неважные вещи. Хотя для Arduino, по-моему, оптимальным является все-таки использование прототипа:
Код:
template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }
Сравнивал без printf. Итоговый, правленный (что в прошлом посту) и пример от Ameba. Разница может быть в том, что это RTL8710 :) У них один printf в ROM, другой в RAM всегда сидят.
Насчет ФАПЧ для системных часов по NTP, задача красивая, но по-моим проектам придумать применение пока не могу, так, что больше академическая. О! Сбагрю сыну, в качестве курсовой, если препод возражать не будет!
Ну вот и подошли к описанному ранее - точность лучше, если ping меньше. Это обеспечивается не запросом сторонних серверов, а берется у DHCP. Он при соединении узнает спец.запросом IP местного сервера NTP... (Что-то из этой области)
В web-свалке -
esp8266web/lwipopts.h at master · pvvx/esp8266web · GitHub
esp8266web/sntp.c at master · pvvx/esp8266web · GitHub
esp8266web/dhcp.c at master · pvvx/esp8266web · GitHub
...
К серверам NTP обычно обращаются по имени, а не по IP. В сети, местный DNS может на них давать локальный и близкий IP...
А то вдруг ваш NTP запрашиваемый по IP уже на Марсе? Пинг будет гулять в зависимости от отражений от Луны... :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
Sr.FatCat - я всё равно что-то не понимаю. В Менеджере библиотек Arduino куча NTPClient-ов...
Все, что потыкал, работают:
Код:
CLK CPU         166666666 Hz
RAM heap        157 336 bytes
RAM free        80 316 bytes
TCM heap        64 768 bytes
interface 0 is initialized
interface 1 is initialized
Initializing WIFI ...
WIFI initialized
RTL8710[Driver]: set ssid [******]
RTL8710[Driver]: start auth to **:**:**:**:**:**
RTL8710[Driver]: auth success, start assoc
RTL8710[Driver]: association success(res=2)
RTL8710[Driver]: set pairwise key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4)
RTL8710[Driver]: set group key to hw: alg:4(WEP40-1 WEP104-5 TKIP-2 AES-4) keyid:2
Interface 0 IP address : 192.168.1.122
23:14:38
23:14:39
23:14:40
23:14:41
23:14:42
...
Смысл писать свой и при этом не использовать "системный"? Это такая игра на ESP8266, т.к. как что не возьму в Arduino, так стоит [inline]#include <ESP8266WiFi.h>[/inline] вместо [inline]#include <WiFi.h>[/inline]? ;)
 

nikolz

Well-known member
используйте SNTP из SDK.
В документации есть готовый пример (2c-esp8266_non_os_sdk_api_reference_en.pdf стр 126. )
Все работает без проблем .
 

pvvx

Активный участник сообщества
Смею предположить, что это стоит для того, чтобы скетчи под esp не компилировали для avr.
"Та я" проверяю все попадающиеся на глаза в поиске, в инете, "скечи" на Arduino для RTL8710.
Пока 95% работает, с мелкими коррекциями, а на ESP8266 значительно меньше. :( NTP клиентов попалась дюжина...
 

Sr.FatCat

Member
Sr.FatCat - я всё равно что-то не понимаю. В Менеджере библиотек Arduino куча NTPClient-ов...
Все, что потыкал, работают:
Ну я, как бы, МК чисто для фана занимаюсь, поэтому самый простой способ разобраться с NTP было реализовать самостоятельно. Плюс: я рьяный дилетант-поклонник ООП, поэтому все, что нужно и не нужно стремлюсь завернуть в классы. Ну и в силу малого опыта и несильных навыков поиска в библиотеках, кроме двух примеров, никаких клиентов не нашел. Кроме того, порой по времени меньше получается написать быстренько свое, чем найти, разобраться и отладить чужое.
Вообщем, не считаю, что время потратил зря, но конечно, сейчас буду делать по другому :) Спасибо Вам за ценные мысли и терпеливое наставление дилетанта :)

"Та я" проверяю все попадающиеся на глаза в поиске, в инете, "скечи" на Arduino для RTL8710.
Пока 95% работает, с мелкими коррекциями, а на ESP8266 значительно меньше. :( NTP клиентов попалась дюжина...
Значит, все-таки Arduino пользуете :) А я, наконец понял, что Вы имели ввиду, когда про многозадчаность не раз упоминали. Да, будете смеяться, но я для себя "открыл" FreeRTOS и то, что она входит в SDK 8266 :) Сижу, постепенно офигеваю от перевернувшегося мира и открывшихся возможностей.

Кстати, в профильной ветке, отличия на программном уровне RTL8710 и ESP8266 осознать не удалось - там обсуждения куда-то в дебри ушли. Но судя по тому, что Вы пишете - зря я ESP-шек натарил, с RTL-ями должно быть полегче, при использовании готовых либ из Ардуино-библиотек?
 

pvvx

Активный участник сообщества
Вообщем, не считаю, что время потратил зря, но конечно, сейчас буду делать по другому :) Спасибо Вам за ценные мысли и терпеливое наставление дилетанта :)
Я также впервой и ознакомился с Arduino с модулями RTL. Там всё ужасно, в Arduino. :)
На примеры с A+B=C стоят (с) :)
Кто-то напишет кривой sample и все повторяют. Это вообще ужасно - нежели все думать разучились и только бездумный копи-паст из первичного sample совершенно ненужных функций в начало каждого примера...
Кстати, в профильной ветке, отличия на программном уровне RTL8710 и ESP8266 осознать не удалось - там обсуждения куда-то в дебри ушли. Но судя по тому, что Вы пишете - зря я ESP-шек натарил, с RTL-ями должно быть полегче, при использовании готовых либ из Ардуино-библиотек?
Для RTL8710 Arduino сыровата. Официальной ещё нет, а появилась всего директория на git. Её взял за основу и патчу, чтобы работала :) Для этого и качал все подряд примеры...
 
Последнее редактирование:

shuraf

Member
Как можно получить числовое значение таймзоны (3 или 4) по городу (Москва)?
В сентябре задал смещение и все считалось нормально, а сейчас глянул, на час отстает.
 

krepton85

Member
А я добавил в стандартный скетч вывод даты, это было не легко, потратил пару часов, аж не верится что я это сделал.:)
Проверьте мой скетч, мне кажется что мог где то допустить ошибку.
Код:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

char ssid[] = "*******************";  //  your network SSID (name)
char pass[] = "******************";       // your network password


unsigned int localPort = 2390;      // local port to listen for UDP packets

/* Don't hardwire the IP address or we won't get the benefits of the pool.
    Lookup the IP address for the host name instead */
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServerIP; // time.nist.gov NTP server address
const char* ntpServerName = "time.nist.gov";

const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
#define GMT 3 //часовой пояс
long evTimeClock;
byte state_clock = 1;
// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;
byte weekday;// день недели
byte day;// число месяца
int year;// год
byte month;// месяц
int month_days; //дней в месяце
long count_day; //количество дней с 1970 года 1 яанваря по текущее время
long v_year; //кличество дней в году
long next_year; //количество дней с 1970 года 1 яанваря, до зовершения текущего года
int next_month; //количество дней от ночала текущего года до зовершения текущего месяца
int count_day_curent_year; //сколько прошло дней в текущем году
void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println();

  // We start by connecting to a WiFi network
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Starting UDP");
  udp.begin(localPort);
  Serial.print("Local port: ");
  Serial.println(udp.localPort());
  evTimeClock = millis();

}

void receiv_time_clock() {

  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no packet yet");
  }
  else {
    Serial.print("packet received, length=");
    Serial.println(cb);
    // We've received a packet, read the data from it
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = " );
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = (secsSince1900 - seventyYears) + (3600 * GMT);
    // print Unix time:
    Serial.println(epoch);


    count_day = epoch / 86400L;// прошедшее количество дней с 1 яанваря 1970 года
    Serial.print("count day on Jan 1 1970: ");
    Serial.println(count_day);
    year = 1970;// старт отсчета лет
    for (int i = 0; i <= count_day; i ++) {

      if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400) == 0) { //если год високосный
        v_year = 366; // то количество дней в високосном году 366
      
      } else {
        v_year = 365;//иначе количество дней в НЕ високосном году 365
      
      }

      if (i <= v_year) {
        next_year = v_year;
      }

      if (i == next_year) {
        year++;
        if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400) == 0) { //если год високосный
        v_year = 366; // то количество дней в високосном году 366
      
      } else {
        v_year = 365;//иначе количество дней в НЕ високосном году 365
      
      }
        next_year = next_year + v_year;

      }
    }

    count_day_curent_year = (count_day - (next_year - v_year))+1; // сколько прошло дней сначала этого (текущего) года (не полных, наверное по этому +1).
   
    month = 1;
for(int m = 0; m <= count_day_curent_year; m ++){
  if(month == 1)month_days = 31;
 
  if(m <= month_days)next_month = month_days;
 
  if(m == next_month){
  month ++;
  if(v_year == 366 && month == 2)month_days = 29;
  if(v_year == 365 && month == 2)month_days = 28;
  if(month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month ==  12)month_days = 31;
  if(month == 4 || month == 6 || month == 9 || month == 11)month_days = 30;
   
  next_month = next_month + month_days;
   
  } 
}

day = count_day_curent_year - (next_month - month_days);
    Serial.print("count_day_curent_year: ");
    Serial.println(count_day_curent_year);
   
    Serial.print("Tekushchiy god visokosnay?: ");   
    if(v_year == 365)Serial.println("No");
    if(v_year == 366)Serial.println("Yes");

    Serial.print("next_year: "); //количество дней с 1970 года 1 яанваря, что бы начался новый год или закончился текущий
    Serial.println(next_year);
   
    Serial.print("next_month: ");// количество дней с начала текущего года, для того что бы начался новый месяц или закончился текущий
    Serial.println(next_month);
   
    Serial.print("year: "); //текущий год
    Serial.println(year);

    Serial.print("month: "); //текущий месяц
    Serial.println(month);

    Serial.print("day: "); //текущий день месяца
    Serial.println(day);

    weekday = (count_day - 3) % 7;
    Serial.print("weekday: "); //день недели
    Serial.println(weekday);
   
   
       
   Serial.print(day);
   Serial.print(" / ");
   Serial.print(month);
   Serial.print(" / ");
   Serial.print(year);
   Serial.print(" ---- ");
   
   
    // вывод часов минут секунд:
    Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
    Serial.print((epoch  % 86400L) / 3600); // вывод часов (86400 секунд в дне)
    Serial.print(':');
    if ( ((epoch % 3600) / 60) < 10 ) {
      // отображение нуля перед минутами, если их меньше 10
      Serial.print('0');
    }
    Serial.print((epoch  % 3600) / 60); // вывод минут (3600 секунд в одном часе)
    Serial.print(':');
    if ( (epoch % 60) < 10 ) {
      // отображение нуля перед секундами, если их меньше 10
      Serial.print('0');
    }
    Serial.println(epoch % 60); // вывод секунд
  }
}

// запрашиваем у NTP сервера время
unsigned long sendNTPpacket(IPAddress& address)
{
  Serial.println("sending NTP packet...");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  udp.beginPacket(address, 123); //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
}

void loop()
{
  if ((millis() - evTimeClock) > 1000 && state_clock == 1) {
    WiFi.hostByName(ntpServerName, timeServerIP);
    sendNTPpacket(timeServerIP); // запрашиваем у NTP сервера время
    state_clock = 2;
  }

  if ((millis() - evTimeClock) > 2000 && state_clock == 2) { //ждем секундачку пока NTP сервер ответит сколько время натикало :)
    receiv_time_clock();
    state_clock = 3;
  }

  if ((millis() - evTimeClock) > 10000 && state_clock == 3) { // через минуточку повторяем все сначало.
    evTimeClock = millis();
    state_clock = 1;
  }
}
 
Сверху Снизу