Программная точка доступа ESP8266: тайм-аут запроса ресурса, если на него не получен ответ в течение установленного недокументированного времени.

Я экспериментирую с чипом ESP8266 на плате Wemos D1 R2. Я пытаюсь написать код, который позволит пользователю ввести имя пользователя и пароль в HTML-форме, а затем получить ответ о том, что произошло при попытке подключения к Wi-Fi, поскольку либо они подключились, либо пароль был неправильным. После того, как я включил настройку режима точки доступа и станции на устройстве, используя:

    // Поле здесь будет глобальным, чтобы другие функции могли получить к нему доступ
    ESP8266WebServer server(80);
    server.on("/connect", handleConnect);
    server.begin();

В моей функции handleConnect я проверяю тело запроса и пытаюсь войти в систему:

    if(!server.hasArg("ssid") || !server.hasArg("password")) {
        server.send(200, "text/html", "You didn't submit a ssid and password");
        return;
    }

    auto ssid = server.arg("ssid");
    auto password = server.arg("password");

    WiFi.begin(ssid, password);

    auto status = WiFi.waitForConnectionResult();

    server.send(200, "text/html", String(status));

Когда пользователь вводит правильный пароль, функция вовремя возвращает запрос, и запрос отвечает цифрой 3 (соединение установлено успешно). Однако, если пароль неправильный, время ожидания запроса истекает. Я также попробовал несколько подходов, чтобы обойти или устранить проблему, например:

  • Использование цикла while, вызов WiFi.status(), его проверка и соответствующий ответ. Этот подход заканчивается тем же тайм-аутом запроса, если пароль неверен. Примером этого может быть:

    while(true) {
      delay(1000);
      auto status = WiFi.status();
    
      if(status == WL_CONNECTED) {
        server.send(200, "text/html", "You're connected!");
      }
    
      if(status == WL_CONNECT_FAILED) {
            server.send(200, "text/html", "You inputted the wrong password! Try again!");
      }
    }
    
  • Регистрация другого ресурса только для того, чтобы возвращать только то состояние, в котором находится Wi-Fi, и в исходной функции подключения для отправки обратно HTML с некоторым JavaScript в нем, который вызывает этот другой ресурс и принимает решение о том, какой текст отображать клиенту -side, но этот подход всегда возвращает 0 (когда Wi-Fi находится в процессе смены состояний, указанных в документации)

    server.on("/checkConnection", checkConnection);
    
    // другой код
    
    void checkConnection() {
      server.send(WiFi.status());
    }
    
    • И, наконец, я экспериментировал с использованием общедоступного поля для сохранения состояния после его завершения в основной функции, где пытались установить исходное соединение, а затем использовал функцию checkConnection для возврата этого состояния и этого ЧТО-ТО работает, однако код беспорядочный, хакерский, и должен быть лучший способ сделать это, иначе это должно быть мое решение, пока библиотеки не будут обновлены, чтобы исправить это или что-то в этом роде что:

// публичное поле для статуса

      int status = 0;

      // другой код

      void handleConnect() {

        // проверка ssid и пароля

        WiFi.begin(ssid, password);

        // используем интервал с AJAX или этим, чтобы получить состояние соединения
        server.send(200, "text/html", "Go to <a href='/checkConnection'>to check the connection</a>");

        while(true) {
          delay(1000);
          auto s = WiFi.status();
          status = s;
          if(s = WL_CONNECTED) break;
        }

      }

      void checkConnection() {
        server.send(200, "text/html", status);
      }

Сталкивался ли кто-нибудь с этой проблемой, и если да, то есть ли лучший способ ее решения, кроме использования общедоступной переменной, работать с которой просто утомительно? Спасибо.

, 👍2

Обсуждение

1. waitForConnectionResult, вероятно, не обрабатывает ошибки так, как вы хотите. 2. WL_CONNECT_FAILED означает и другие вещи (https://github.com/esp8266/Arduino/blob/a41f55c469dbf3ecfa3aa051fa95322d8d316e2e/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp#L98), так что не хотите ли вы просто искать что-нибудь рядом с «подключено»? 3. Точка доступа должна использовать тот же канал, что и STA, поэтому я не понимаю, как это может сохранять соединение http открытым, пока/если оно изменится., @dandavis

@dandavis Спасибо за ответ. Во-первых, waitForConnectResult документируется как ожидание окончательного результата работы сети, а затем возврат состояния соединения. Во-вторых, спасибо за информацию о других значениях WL_CONNECT_FAILED. Я как бы предположил, что это могло иметь какое-то другое значение, но теперь я знаю, но в данном случае мы предполагаем, что ssid правильный и неправильный только пароль. Наконец, esp8266 имеет режим Wi-Fi под названием WIFI_AP_STA, который позволяет устройству быть точкой доступа и станцией, что очень удобно, если вы хотите сделать что-то подобное, поэтому я не думаю, что это причина., @Cam

да, в WIFI_AP_STA каналы Wi-Fi должны совпадать между ними. если ваша точка доступа загрузила другой канал, чем STA, к которой вы подключаетесь, вы (на самом деле) не сможете поддерживать открытое http-соединение во время смены канала точки доступа (неожиданной/недокументированной), независимо от действительности пароля., @dandavis


2 ответа


0

Сделайте WiFi.begin вне обработчика веб-сервера. В обработчике сохраните ssid и пароль в переменных и отправьте ответ. В цикле() затем создайте WiFi.begin. Для получения результата выполните пул из браузера с помощью javascript.

Пример

,

1
WifiMulti wifiMulti;//объявляем глобальный.
wifiMulti.addAP(ssid,pass);//вместо WiFi.begin();
int i = 0;
//добавим ниже, чтобы дождаться соединения.
while (i < 20)
  {
    if (wifiMulti.run() == WL_CONNECTED)
    {
      return (20);
    }
    delay(500);
    Serial.println(WiFi.status());
    i++;
  }
,