Веб-сервер ESP8266 недоступен через 2 минуты после сброса

У меня есть Keyes Espressif ESP8266 NodeMCU, у меня есть два светодиода, которыми я хочу управлять и которые подключены к ESP. Когда я открываю веб-страницу http://10.0.0.5/5 после загрузки скетча, она работает нормально. Если я не открою и не закрою веб-сайт до ~ 02:30 [мм: сс], сервер станет недоступным, даже если я закрою существующее соединение и открою новое соединение в новой вкладке, выдает ту же ошибку: ERR_CONNECTION_TIMED_OUT

Если я не открою веб-страницу до ~ 02:30[мм:сс], я также получу сообщение об ошибке ERR_CONNECTION_TIMED_OUT

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

ESP.getFullVersion() outputs: 
SDK:2.2.1(cfd48f3)/Core:2.5.1=20501000/lwIP:STABLE-2_1_2_RELEASE/glue:1.1-7-g82abda3/BearSSL:a143020

Вопрос:

Как сделать веб-сервер доступным постоянно?

С помощью @Juraj я попытался перейти на SDK V3, но это не помогло. Я также пробовал:

  • Все варианты lwip

Мой код:

// Загружаем библиотеку Wi-Fi
#include <ESP8266WiFi.h>

// Замените учетными данными вашей сети
const char* ssid     = "DO_231455";
const char* password = "0828842107";

// Установить номер порта веб-сервера на 80
WiFiServer server(80);

// Переменная для хранения HTTP-запроса
String header;

// Вспомогательные переменные для хранения текущего состояния вывода
String output5State = "off";
String output4State = "off";

// Назначаем выходные переменные контактам GPIO
const int output5 = 16;
const int output4 = 4;

void setup() {
  Serial.begin(115200);

  // Инициализировать выходные переменные как выходы
  pinMode(output5, OUTPUT);
  pinMode(output4, OUTPUT);
  // Установить выходы на НИЗКИЙ уровень
  digitalWrite(output5, LOW);
  digitalWrite(output4, LOW);

  Serial.print(ESP.getFullVersion());
  //WiFi.disconnect() ;
  // WiFi.persistent(false);
  //WiFi.setSleepMode(WIFI_NONE_SLEEP);
  // Подключаемся к сети Wi-Fi с SSID и паролем
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Выводим локальный IP-адрес и запускаем веб-сервер
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Слушаем входящих клиентов
  if (client) {                             // Если подключается новый клиент,
    Serial.println("New Client.");          // вывести сообщение в последовательный порт
    String currentLine = "";                // создаем строку для хранения входящих данных от клиента
    while (client.connected()) {            // цикл, пока клиент подключен
      if (client.available()) {             // если есть байты для чтения от клиента,
        char c = client.read();             // прочитать байт, затем
        Serial.write(c);                    // вывести его на серийный монитор
        header += c;
        if (c == '\n') {                    // если байт является символом новой строки
          // если текущая строка пуста, вы получили два символа новой строки подряд.
          // это конец клиентского HTTP-запроса, поэтому отправьте ответ:
          if (currentLine.length() == 0) {
            // Заголовки HTTP всегда начинаются с кода ответа (например, HTTP/1.1 200 OK)
            // и тип контента, чтобы клиент знал, что придет, затем пустая строка:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();

            // включает и выключает GPIO
            if (header.indexOf("GET /5/on") >= 0) {
              Serial.println("GPIO 5 on");
              output5State = "on";
              digitalWrite(output5, HIGH);
            } else if (header.indexOf("GET /5/off") >= 0) {
              Serial.println("GPIO 5 off");
              output5State = "off";
              digitalWrite(output5, LOW);
            } else if (header.indexOf("GET /4/on") >= 0) {
              Serial.println("GPIO 4 on");
              output4State = "on";
              digitalWrite(output4, HIGH);
            } else if (header.indexOf("GET /4/off") >= 0) {
              Serial.println("GPIO 4 off");
              output4State = "off";
              digitalWrite(output4, LOW);
            }

            // Отображение веб-страницы в формате HTML
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS для оформления кнопок включения/выключения
            // Не стесняйтесь изменять атрибуты background-color и font-size в соответствии с вашими предпочтениями
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");

            // Заголовок веб-страницы
            client.println("<body><h1>ESP8266 Web Server</h1>");

            // Отображение текущего состояния и кнопки ВКЛ/ВЫКЛ для GPIO 5
            client.println("<p>GPIO 5 - State " + output5State + "</p>");
            // Если output5State выключен, отображается кнопка ON
            if (output5State=="off") {
              client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 

            // Отображение текущего состояния и кнопки ВКЛ/ВЫКЛ для GPIO 4
            client.println("<p>GPIO 4 - State " + output4State + "</p>");
            // Если output4State выключен, отображается кнопка ON
            if (output4State=="off") {
              client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");

            // Ответ HTTP заканчивается еще одной пустой строкой
            client.println();
            // Выход из цикла while
            break;
          } else { // если вы получили новую строку, то очищаем currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // если вы получили что-то еще, кроме символа возврата каретки,
          currentLine += c;      // добавляем его в конец currentLine
        }
      }
    }
    // Очистить переменную заголовка
    header = "";
    // Закрыть соединение
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Стоит отметить (во время отладки):
Новый клиент отключается.

, 👍1

Обсуждение

если клиент возвращается с сервера, то проблема в скетче, @Juraj

Какие ресурсы вы бы посоветовали мне посмотреть, чтобы узнать, как решить эту проблему?, @Brandon Pillay

помогает ли перезапуск WiFi-маршрутизатора/точки доступа?, @Juraj

Никакого эффекта, сайт по-прежнему падает, если не запрашивается из моего браузера W8.1 Chrome в течение 2 минут после сброса или загрузки., @Brandon Pillay

он перестает работать через две минуты - даже если вы не делаете к нему никаких запросов, пока не пройдет 2 минуты? Или он останавливается после определенного количества запросов, выполнение которых занимает около 2 минут?? Дело в том, происходит ли сбой после определенного количества запросов или после определенного периода работы - независимо от рабочей нагрузки???, @GMc

Я проверил это, сбрасывая, а затем открывая и закрывая соединение в моем браузере каждую минуту - я мог делать это в течение 30 минут и продолжать делать это после этого, но если я не устанавливаю новое соединение в течение ~ 2 минут 35 секунд, время сервера вне. Как будто ESP переходит в спящий режим после отсутствия запросов., @Brandon Pillay

он печатает «Новый клиент», поэтому он не спит, @Juraj

Да, время ожидания ESP истекает, только если новый запрос не сделан. Я пытаюсь найти способ предотвратить тайм-аут веб-сервера., @Brandon Pillay

это не тайм-аут. он возвращает клиента. скетч печатает "Новый клиент", @Juraj

Это только в том случае, если я отправлю запрос на веб-сервер, а не в том случае, если он будет бездействовать. Если он остается бездействующим, время ожидания истекает., @Brandon Pillay

и следующий клиент после этого времени возвращается сервером. только не обработано в вашем скетче, @Juraj

Есть ли лучший способ решить эту проблему, чем то, как я справился с ней в своем ответе ниже?, @Brandon Pillay

Мне нужно .stop() для старого (первого) клиента!, @Brandon Pillay

вы останавливаете () клиент, @Juraj

в моем случае я добирался через http://esp8266.local/. Я заметил, что все еще могу получить доступ через ip, но mdns не удалось, я думаю, @nerkn


2 ответа


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

1

Короткий ответ: настройте статический IP-адрес!

Посмотрев на Git Issue #2371, я обнаружил, что мне нужно создать статический IP-адрес, чтобы исправить Эта проблема. Я могу сделать это, вставив WiFi.config(ip, gateway, subnet) непосредственно перед WiFi.mode(WIFI_STA) в приведенном выше коде.

  • Сначала я нашел информацию gateway & subnet мне нужно, открыв командную строку на компьютере, подключенном к точке доступа (маршрутизатору), как к ESP8266, который работает в режиме станции. Я сделал это в Windows, выполнив поиск в Command Prompt, а затем набрав ipconfig, чтобы получить следующую информацию:

Замените точки запятыми! См. эту ссылки для получения дополнительной информации о других параметрах и DNS.


  • Чтобы создать IP-адрес, вам нужно увидеть свой IP-адрес в красном квадрате на картинке выше, взятой из командной строки. Первые три октета (числа) IP-адреса вашего маршрутизатора (вероятно, 10.0.0.x, 192.168.0.x или 192.168.1.x) должен соответствовать выбранному вами статическому IP-адресу. В моем примере совпадающие числа будут 10.0.0.

  • Затем мне нужно было получить диапазон DCHP для моего маршрутизатора. Мой маршрутизатор — это маршрутизатор Netgear Wireless ADSL2+ с модемом DG834Gv5. Чтобы получить диапазон, мне нужно было получить доступ к настройкам моего маршрутизатора. Чтобы получить к нему доступ, я искал HTTP-ссылку под маршрутизатором. Для моего маршрутизатора это был http://10.0.0.2 вместе с именем пользователя и паролем, которые были admin, admin соответственно. Вот как это выглядит:

Это зависит от вашего маршрутизатора. Затем я зашел в Дополнительные настройки и увидел диапазон DHCP. Это ошибка с моей стороны, отмеченная @djsfantasi. См. его ответ относительно выбора диапазона DHCP.Новый статический IP-адрес должен находиться в пределах диапазона DHCP. Согласно одному из комментариев brendanmatkin в Git Issue #2371 последний номер моего статического IP (это ZZ в WW.XX.YY .ZZ) должен быть за пределами этого диапазона. У меня это не сработало, сработало, когда я использовал значение внутри этого диапазона, но brendanmatkin знает гораздо больше меня, я просто новичок. Возможны последствия, о которых я не знаю, поэтому я думаю, что их стоит изучить. Диапазон DHCP выглядит следующим образом:

Мой вставленный код выглядит следующим образом:

void setup(void) {
  .
  .
  .
  Serial.begin(115200);
  //WiFi.disconnect(); //Запретить подключение к Wi-Fi на основе предыдущей конфигурации
  IPAddress ip(10,0,0,15); // эти 3 строки для фиксированного IP-адреса
  IPAddress gateway(10,0,0,2); 
  IPAddress subnet(255,255,255,0);
  // WiFi.hostname ("ESP8266"); // Имя хоста DHCP (полезно для поиска устройства для статической аренды)
  WiFi.config(ip, gateway, subnet);
  //Режим станции:
  WiFi.mode(WIFI_STA); 
  .
  .
  .
}

Пожалуйста, прокомментируйте для получения дополнительной информации :)

Дополнительная информация и изменения, которые я внес в IDE:

ОС: Windows 8.1

IDE: Arduino IDE V1.9.8

Плата: Keyes ESP8266

Arduino IDE > Инструменты > Плата (в диспетчере плат): Универсальная плата ESP8266

Arduino IDE > Инструменты >lwip: мало памяти V2

Arduino IDE > Инструменты >Esp FW:"nonos.." : nonos-sdk pr-3(известные проблемы)*

Электропитание: USB COM от настольного блока питания мощностью 300 Вт. Выходной ток ~ 1,5А.

Большое спасибо @Juraj. Юрай

,

1

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

WW.XX.YY.0 и WW.XX.YY.255 зарезервированы. Маршрутизатор использует адреса .1 и .2. Остается 3-254 доступных, которые, как мы видим, являются адресами в пределах диапазона DHCP.

Вы можете назначить статический IP-адрес в диапазоне DHCP, но рискуете отключить 1 или 2 устройства. DHCP не знает, что вы использовали один из его адресов, поэтому может назначить его другому устройству. Бум! Два устройства с одинаковым адресом и оба не будут работать.

Правильный способ решить эту проблему – войти в систему маршрутизатора и изменить диапазон DHCP. Например, увеличьте нижний предел с 3 до (случайный выбор) 20. Теперь DHCP не будет беспокоить и с радостью раздаст адреса вашим устройствам. Но если вам нужен статический IP-адрес, вы определили пул от WW.XX.YY.3 до WW.XX.YY.19

,