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

Решено HTTPClient отваливается случайно

arrowcircle

New member
Добрый вечер!

На nodemcu v3 и arduino IDE через PlatformIO (все последних версий) имею странную проблему.

В начале работы программы все работает замечательно, однако после какого-то количества времени начинают вылезать ошибки.

Код:
[HTTP] GET... failed, error: connection refused
Wifi status: 3
Wifi signal: -53
При этом ошибки вылезают совершенно случайно, иногда запросы восстанавливаются и продолжают проходить после ошибки. Такое может случиться как на 3 запросе, так и на 50. Подряд может не пройти 1 запрос, а может и 20. Сервер при этом точно доступен, а WiFi.status() == WL_CONNECTED.

К модулю подключен OLED-экран, на котором по таймеру (без делейев, на millis) отображаются результаты запросов в интернет.

Запросы также делаются по таймеру.

loop выглядит так (пробовал добавлять yield):

Код:
void loop() {
  if (isWifiConnected() == true) { startNtpClient(); }
  yield();
  scrapeApiHandler();
  yield();
  updateDisplayHandler();
  yield();
  loopButton();
  yield();
}
Все хендлеры разнесены по разным файлам, httpclient используется и объявлен в api_handler.
Что интересно, если объявление переменной "HTTPClient http;" перенести внутрь метода, который делает запросы, например как ниже, то модуль вообще не может достучаться до API с той же ошибкой.
Важно, сайт без https. Сначала был с https, но подключиться к нему с модуля не удалось.

Код:
void scrapeApi() {
  HTTPClient http;
  if (WiFi.status() != WL_CONNECTED) { return; }
  Serial.println("======= Scraping API");
  String url = "http://mysite.com";
  http.begin(url);
  int httpCode = http.GET();

  if (httpCode > 0) {
    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      parseServerResponse(payload);
    }
  } else {
    Serial.print("[HTTP] GET... failed, error: ");
    Serial.println(http.errorToString(httpCode).c_str());
    printWiFiDebug();
  }

  http.end();
}
Еще одно наблюдение, таких ошибок без экрана было гораздо меньше.

В проекте используются библиотеки:
  • tzapu/wifimanager#development
  • gmag11/NtpClient
  • ArduinoJson@5.13.2
  • ESP8266_SSD1306@4.0.0
В какую сторону стоит копать для улучшения стабильности работы программы?
Или это кривые китайские модули? Подскажите, пожалуйста, советом.
 

arrowcircle

New member
просто объявите ее вне функции
Пробовал, ничего не меняется. Изначально переменная объявлена вне функции. Если объявить внутри, то вообще ничего не работает.
Судя по ошибке, это сервер отбрасывает соедининие, возможно слишком часто к нему обращаетесь.
ab -n 1000 -c 10 сервер выдерживает без проблем. Это мой же сервер с апи, никакого тротлинга там нет, ответ < 10мс.

Поставил конденсаторы на питание дисплея и сам модуль. Результат такой-же.
 

CodeNameHawk

Moderator
Команда форума
нп. Перегрузите сервер, сделайте запрос, снова перезагрузите сервер - запрос.
Что у вас за запрос? Что сервер делает с данными? Что в логах сервера?

У меня подобный код работает без проблем.
Код:
HTTPClient http;
char temp[2000];   //2000, так как используется и в других местах
const uint32_t Zadierzka = 30000;//30 сек
unsigned long old_time_send_term_data_to_SQL = 0;

void Send_Term_Data_to_SQL(void)
{
      if ((millis() - old_time_send_term_data_to_SQL) > Zadierzka)// отработает, если прошло больше чем 30 сек
        {
            Serial.println();
            podgotowka_zmiennych_SQL();
            snprintf(temp, 200, "http://mojsait.co.nf/tempe1.php?Data=%04d-%02d-%02d&Time=%02d:%02d:%02d&A=%s&B=%s&C=%s&D=%s&E=%s&F=%s", rok, miesiac, dzien, hr, minut, sec, podloga_s, kotlownia_s, podworz_s, shody_s, pierwszepientro_s, boiler_s);

            old_time_send_term_data_to_SQL = millis();
            Serial.print(temp);
            Serial.println();

#ifdef DEBUG
            Serial.print("[HTTP] Begin.\n");
#endif // DEBUG
            // configure traged server and url

            http.begin(temp); //HTTP

            httpCode_term_data_to_SQL = http.GET();

            // httpCode will be negative on error
            if (httpCode_term_data_to_SQL > 0)
            {
                // HTTP header has been send and Server response header has been handled
#ifdef DEBUG
                Serial.printf("[HTTP] GET code : %d\n", httpCode_term_data_to_SQL);
#endif // DEBUG
                // file found at server
                if (httpCode_term_data_to_SQL == HTTP_CODE_OK)
                {
#ifdef DEBUG
                    Serial.println(http.getString());
#endif // DEBUG
                }
            } else
            {
#ifdef DEBUG
                Serial.printf("[HTTP] GET failed, error : %s\n", http.errorToString(httpCode_term_data_to_SQL).c_str());
#endif // DEBUG
            }

            http.end();
        }
}
 

arrowcircle

New member
нп. Перегрузите сервер, сделайте запрос, снова перезагрузите сервер - запрос.
Что у вас за запрос? Что сервер делает с данными? Что в логах сервера?
Зачем перезагружать сервер? Сервер - это кубернетес кластер, в котором есть и постоянные проверки на то, что апи живое и на все остальное.
Сам запрос - простой джейсон файл с текстовыми данными, которые отображаются на дисплей. В джейсоне от одного до 10 экранов, которые ротируются на дисплее каждые 5 секунд.

PlatformIO как раз работает поверх Visual Studio Code, но дает нормальный менеджер библиотек и инструменты командной строки.
---
Сделал счетчик на количество ошибок при запросах, переподключаю wifi после 3 неудачных запросов. После переподключения первые n запросов идут нормально.

Где еще можно поискать проблему?
 

CodeNameHawk

Moderator
Команда форума
Зачем перезагружать сервер?
При обращении к серверу открывается поток с данными, а вот закрылся ли он, не известно. Перезагрузка его точно закроет.

Что бы найти решение проблемы, выкиньте из вашей программы все, что не относится к ней.
Короткий код покажите, причем весь.
Решайте только одну проблему.
 

arrowcircle

New member
При обращении к серверу открывается поток с данными, а вот закрылся ли он, не известно. Перезагрузка его точно закроет.

Что бы найти решение проблемы, выкиньте из вашей программы все, что не относится к ней.
Короткий код покажите, причем весь.
Решайте только одну проблему.
Сервер точно не причем. В логах как реверспрокси так и самого апи пусто, запрос не доходит. Судя по дебагу, http.end() выполняется.
Попробую сделать один код http, спасибо
 

CodeNameHawk

Moderator
Команда форума
PlatformIO как раз работает поверх Visual Studio Code, но дает нормальный менеджер библиотек и инструменты командной строки.
Мне не понравилось, что они (PlatformIO) устанавливают библиотеки отдельно от ардуиноиде, возможно все поправили, давно не пробовал.
 

arrowcircle

New member
При обращении к серверу открывается поток с данными, а вот закрылся ли он, не известно. Перезагрузка его точно закроет.

Что бы найти решение проблемы, выкиньте из вашей программы все, что не относится к ней.
Короткий код покажите, причем весь.
Решайте только одну проблему.
Выкинул все лишнее, проблема остается:
api_handler.cpp
В зависимостях только
ArduinoJson@5.13.2
 

CodeNameHawk

Moderator
Команда форума
Мне не нравиться
Код:
 if (currentMillis > lastApiUpdatedAt + apiPeriod)
попробуйте так if (currentMillis > (lastApiUpdatedAt + apiPeriod))

Существует отладка :)
 

arrowcircle

New member
Мне не нравиться
попробуйте так if (currentMillis > (lastApiUpdatedAt + apiPeriod))

Существует отладка :)
Попробовал, не помогает.
Поставил такой же код на прошивке nodemcu (указал DNS google в коде). Там вылезает другая ошибка:
Код:
DNS Error code -1.
DNS failed for ...
Связи с успешными и проваленными запросами на разных прошивках нет.
 

CodeNameHawk

Moderator
Команда форума
В ардуино иде есть вывод отладочной информации о состоянии WiFi, мне помог.
Код:
  int64_t currentMillis = millis();
  if (currentMillis > lastApiUpdatedAt + apiPeriod) {
    scrapeApi();
    lastApiUpdatedAt = currentMillis;
Если scrapeApi(); будет длится около секунды, то второй запрос отправиться через сколько времени?

Долбать сервер раз в секунду, не хорошая идея.

Что пишет ваш сервер при подключении к нему?
 

arrowcircle

New member
На такой String url = "http://headers.jsontest.com/"; запрос, по идее получите http://headers.jsontest.com/index.html
Это никак не связано с тем, что глючат esp8266.

В ардуино иде есть вывод отладочной информации о состоянии WiFi, мне помог.

Если scrapeApi(); будет длится около секунды, то второй запрос отправиться через сколько времени?

Долбать сервер раз в секунду, не хорошая идея.

Что пишет ваш сервер при подключении к нему?
WiFi.status() == WL_CONNECTED.
Если будет выполняться секунду, что запрос уйдет через 9 секунд.
Долбать сервер раз в секунду не проблема для дебага.

Мой сервер выдает стандартный ответ со статусом 200 и заголовками кеширования. Время ответа - 5 мс.
 

CodeNameHawk

Moderator
Команда форума
Мой сервер выдает стандартный ответ со статусом 200 и заголовками кеширования. Время ответа - 5 мс.
Это не информативно, лог все покажет, время, кто и к чему подключился, когда и разорвалось ли связь и.т.д.
 
Сверху Снизу