ESP32 - неточность NTP после глубокого сна

Я пытаюсь создать проект выборки датчиков с использованием ESP32 (аккумулятор, солнечная панель и влияние температуры не являются частью теста прямо сейчас, чтобы уменьшить внешние эффекты, которые могут вызвать/усилить такое поведение).

На текущем этапе я только тестирую функцию sleep & процесс пробуждения.

Краткое описание: система просыпается после цикла глубокого сна, подключается к Wi-Fi, MQTT, NTP и проверяет время пробуждения (значение пробуждения хранится в переменной ׳RTC_DATA_ATTR long calc_waketime׳ из предыдущего цикла), публикуя IFTTT, уходит в глубокий сон еще на 10 мин. цикл.

Феномен, которым я хотел бы поделиться: Чем дольше глубокий сон, NTP имеет дрейф в несколько секунд, который становится длиннее (опять же - синхронизация NTP имеет дрейф, а не часы RTC).

Я знаю, что время пробуждения/RTC дрейфует во время глубокого сна (особенно в чипах ESP8266, которые пробуждения могут быть неточными с точки зрения минут - я использую ESP32). Поскольку ESP32 использует RTC, пробуждение происходит очень точно (секунды). Чтобы проснуться в точное время (18:00, 18:10, 18:20... каждый час) код подключается к Wifi& NTP и убедитесь, что время пробуждения соответствовало назначению (сравните значение эпохи, которое было сохранено в конце предыдущего цикла, и текущее время эпохи).

Но - Что меня озадачивает, так это то, почему обновленное время NTP (которое никак не связано с дрейфами RTC) смещается по мере того, как длится сон (для сравнения: когда меньше минуты - почти нет дрейфа, когда сон длится 10 минут, 3 секунды дрейфа, 20 минут до 5 секунд дрейфа ).

Пожалуйста, см. ПРИМЕЧАНИЕ(1), чтобы увидеть дрейф в 10-минутном сне.

Публикация вывода терминала: некоторые пояснения: ПРИМЕЧАНИЕ (1) отображает 3-секундный дрейф, ПРИМЕЧАНИЕ (2) расчетное время, которое было сохранено в предыдущем цикле пробуждения, ПРИМЕЧАНИЕ (3) показывает, что этот дрейф синхронизируется во время выполнения кода - 594 сек для следующего пробуждения в 18:50:00.

18:39:58.032 -> 09B⸮⸮L⸮1U1V(⸮⸮⸮1m1m1F⸮Connecting to Xiaomi_D6C8 .... // ПРОСЫПАЕМСЯ
18:39:58.595 -> 192.168.3.186
18:39:59.013 -> now is: 1580575203               **// ПРИМЕЧАНИЕ (1)**
18:39:59.013 -> sleep time was: 1580574611
18:39:59.048 -> expected wake time: 1580575200   // ПРИМЕЧАНИЕ (2)
18:39:59.085 -> total time delta: 3
18:39:59.122 -> OK - WOKE UP after due time: 
18:39:59.419 -> Attempting MQTT connection...connected
18:40:04.544 -> Connecting to maker.ifttt.com
18:40:04.855 -> Request resource: /trigger/send_reading/with/key/cFLymB4JT9tlODsKLFn9TA
18:40:05.376 -> HTTP/1.1 200 OK
18:40:05.376 -> Date: Sat, 01 Feb 2020 16:40:05 GMT
18:40:05.414 -> Content-Type: text/html; charset=utf-8
18:40:05.447 -> Content-Length: 52
18:40:05.480 -> Connection: close
18:40:05.515 -> X-Top-SecreTTT: VG9vIGVhc3k/IElmIHlvdSBjYW4gcmVhZCB0aGlzLCBFbWFpbCB1cyBhdCBqb2JzK3NlY3JldEBpZnR0dC5jb20uIFdlIHdhbnQgTWFrZXJzLg==
18:40:05.619 -> Server: web_server
18:40:05.619 -> 
18:40:05.619 -> Congratulations! You've fired the send_reading event
18:40:05.689 -> closing connection
18:40:07.007 -> Last Sleep: 1580574611
18:40:07.007 -> Time left: 594                 // ПРИМЕЧАНИЕ (3)
18:40:07.041 -> Going to DeepSleep for [594] sec

Соответствующий код:

void sleepNOW(int sec2sleep = 2700)
{
  char tmsg[30];
  sprintf(tmsg, "Going to DeepSleep for [%d] sec", sec2sleep);
  Serial.println(tmsg);
  // mqtt_pubmsg(tmsg);
  Serial.flush();
  esp_sleep_enable_timer_wakeup(sec2sleep * uS_TO_S_FACTOR);
  esp_deep_sleep_start();
}
bool getTime()
{
  delay(200);
  if (getLocalTime(&timeinfo))
  {
    time(&now1);
    delay(200);
    return 1;
  }
  else
  {
    return 0;
  }
}

bool check_awake_ontime()
{
  getTime();
  if (timeinfo.tm_year >= 120) // 2020 год
  {
    if (lastsleeptime != 0)
    { // не первая загрузка
      long current_boottime = now1;
      int t_delta = now1 - calc_waketime;
      // int t_delta1 = TIME_TO_SLEEP * 60 - (t_delta + TIME_AWAKE);
      Serial.print("now is: ");
      Serial.println(now1);
      Serial.print("sleep time was: ");
      Serial.println(lastsleeptime);
      Serial.print("expected wake time: ");
      Serial.println(calc_waketime);

      Serial.print("total time delta: ");
      Serial.println(t_delta);
      if (t_delta >= 0)
      {
        Serial.println("OK - WOKE UP after due time: ");
        return 1;
      }
      else
      {
        Serial.println("FAIL- woke up before time: ");
        sleepNOW(-1 * t_delta);
        return 0;
      }
    }
    else
    {
      return 1;
    }
  }
  else
  {
    return 0;
  }
}

внутри setup()

#if USE_WIFI
  if (startWifi())
  {
    mqttConnect();
    startNTP();
#if USE_SLEEP
    check_awake_ontime();   // ОБРАЩАЙТЕСЬ ТОЛЬКО НА ЭТУ ЛИНИЮ
#endif
  }

внутри loop()

#if USE_SLEEP
  if (millis() >= TIME_AWAKE * 1000)
  {
    getTime();

    Serial.print("Last Sleep: ");
    Serial.println(lastsleeptime);

    long clockCount = TIME_TO_SLEEP * 60 - (timeinfo.tm_min * 60 + timeinfo.tm_sec) % (TIME_TO_SLEEP * 60);
    // Serial.print(timeinfo.tm_hour);
    // Serial.print(":");
    // Serial.print(timeinfo.tm_min);
    // Serial.print(":");
    // Serial.print(timeinfo.tm_sec);
    // Serial.println("");
    Serial.print("Time left: ");
    Serial.println(clockCount);

    lastsleeptime = now1;
    calc_waketime = now1 + clockCount;

    sleepNOW(clockCount);
  }

Я публикую не весь код, а только соответствующие части. Будем признательны за любую помощь,

, 👍0

Обсуждение

NTP устанавливает только RTC. и NTP не сразу, @Juraj

@Juraj вы бы порекомендовали отсрочку? так как getTime() имеет 2 задержки по 200 миллисекунд, @Guy . D

Обычно достаточно 5 секунд. Вы можете сделать трюк. сбросьте время RTC на 0, а затем вы можете проверить, установлено ли оно уже NTP, @Juraj

@Juraj, не могли бы вы объяснить, как?, @Guy . D

извините, я забыл, что нет API для установки времени RTC на esp32. https://arduinoprosto.ru/q/72010/set-the-wall-clock-time-or-change-gmt-offset-without-ntp-server/72019#72019, @Juraj


1 ответ


Лучший ответ:

0

Как прокомментировал Юрай, задержка в 2,5 [сек.] решила проблему, и обновление NTP было правильным.

,

Можно принять свой собственный ответ как решение проблемы., @VE7JRO