Я пытаюсь создать простую демонстрацию с модулем NodeMCU:
- NodeMCU открывает AP и настраивает веб-сервер
- Клиент подключается к этой точке доступа, отправляет полезную нагрузку на веб-сервер для настройки WiFI на модуле и получает ответ, если подключение было успешным.
Это прекрасно работает при отправке правильных учетных данных WiFi. Однако ESP8266WebServer разрывает соединение с клиентом, если указан неверный пароль WiFi.
Веб-сервер в моей демоверсии может обрабатывать 3 запроса и возвращать ответ для каждого из них.
- Корень веб-сервера - просто пропингуйте его, чтобы убедиться, что он доступен.
- Статус - возвращает полезную нагрузку статуса соединения WiFi
- Сети - принимает учетные данные WiFi, настраивает WiFi и возвращает полезную нагрузку статуса
Я явно ввел 15-секундные задержки в Status и Networks, чтобы проверить, происходит ли разрыв соединения из-за тайм-аута.
Вот как я тестирую (используя Postman на клиенте):
- Загрузите скетч с установленным флагом стирания WiFi.
- Подключите клиент к точке доступа и пропингуйте корень веб-сервера, чтобы убедиться, что он работает
- Состояние вызова несколько раз. Ответ возвращается каждый раз после 15-секундной задержки
- Вызовите сети с неверными учетными данными. Я вижу в журналах, что
while
цикл в connectToWiFi()
метод работает. Вероятно, через 5-6 секунд я получаю сообщение "Не удалось получить ответ" в Почтальоне. В то же время, я вижу окончательный статус загрузки вызовов Networks в журналах через 15 секунд (как и ожидалось). Если я снова позвоню в сети с неправильными учетными данными, то через 1-2 секунды появится сообщение «Не удалось получить ответ».
- Снова вызовите статус. Теперь он также начинает давать сбой на стороне клиента, при этом успешно генерируя полезную нагрузку через 15 секунд на стороне сервера.
- Звоните в сети с правильными учетными данными сейчас. Клиент по-прежнему получает сообщение об отсутствии ответа, но код сервера работает успешно.
- После этого вызывающие конечные точки состояния или сети (с правильными учетными данными) начинают возвращать действительный ответ HTTP OK 200.
Что я заметил, так это то, что если я удаляю строку WiFi.begin(ssid.c_str(), password.c_str());
, я никогда не получаю сообщение «нет ответа». Так что, каким-то образом, ввод неправильного пароля портит ответ.
Я что-то упустил и как получить в любом случае хороший ответ? Единственный обходной путь, который я имею в виду, это просто вызвать конечную точку сети, но не ждать ответа. Затем, чтобы начать опрос конечной точки состояния, пока не будет получен желаемый ответ. Однако это решение выглядит не очень красиво.
Вот мой набросок:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "ESP8266WiFiType.h"
#include <ArduinoJson.h>
#define MESSAGE_MAX_LEN 1024
ESP8266WebServer server(80);
String ssid = "";
String password = "";
static byte mac[6];
void configureServer()
{
server.on("/", []() {
//String responseBody;
Serial.println("Running root");
StaticJsonBuffer<MESSAGE_MAX_LEN> jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
root["status"] = "OK";
String rootpayload;
root.prettyPrintTo(rootpayload);
Serial.print("rootpayload:");
Serial.println(rootpayload);
return server.send(200, "application/json", rootpayload);
});
server.on("/networks", []() {
Serial.println("Running /networks");
if (server.hasArg("ssid") && server.hasArg("pass")) {
Serial.print("got ssid:");
Serial.println(server.arg("ssid"));
Serial.print("got pass:");
Serial.println(server.arg("pass"));
ssid = server.arg("ssid");
password = server.arg("pass");
connectToWiFi();
StaticJsonBuffer<MESSAGE_MAX_LEN> jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
JsonObject &payload = jsonBuffer.createObject();
root["payload"] = payload;
bool connected_status = (WiFi.status() == WL_CONNECTED);
payload["connected"] = connected_status;
payload["localip"] = WiFi.localIP().toString();
String networkspayload;
root.prettyPrintTo(networkspayload);
Serial.println("networkspayload:");
Serial.println(networkspayload);
server.send(200, "application/json", networkspayload);
}
});
server.on("/status", []() {
String responseBody;
delay(15000);
bool connected_status = (WiFi.status() == WL_CONNECTED);
Serial.print("wifi.status = ");
Serial.println(WiFi.status());
StaticJsonBuffer<MESSAGE_MAX_LEN> jsonBuffer;
JsonObject &root = jsonBuffer.createObject();
JsonObject &payload = jsonBuffer.createObject();
payload["network_ssid"] = WiFi.SSID();
payload["connected"] = connected_status;
payload["localip"] = WiFi.localIP().toString();
JsonArray &devicespayload = jsonBuffer.createArray();
root["payload"] = payload;
String statuspayload;
root.prettyPrintTo(statuspayload);
Serial.print("statuspayload:");
Serial.println(statuspayload);
return server.send(200, "application/json", statuspayload);
});
}
void connectToWiFi()
{
Serial.println();
Serial.println("Connecting to the router...");
WiFi.begin(ssid.c_str(), password.c_str());
int t = 0;
int timeout = 15000;
while (WiFi.status() != WL_CONNECTED && t < timeout) { //Wait for the connection to the WiFi network
delay(100);
t += 100;
Serial.print(".");
}
while ( t < timeout) {
delay(100);
t += 100;
Serial.print(".");
}
}
String getMacAddress()
{
String mac = WiFi.macAddress();
mac.replace(":", "");
mac.toLowerCase();
return mac;
}
void openAP()
{
Serial.println("Opening AP...");
WiFi.mode(WIFI_AP_STA);
boolean result = WiFi.softAP("Test AP");
Serial.print("AP opened: ");
Serial.println(result);
}
// the setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);
Serial.println("Serial successfully inited.");
configureServer();
server.begin();
openAP();
WiFi.macAddress(mac);
Serial.print("MAC: ");
Serial.print(WiFi.macAddress());
Serial.println();
Serial.println("Server started");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
Serial.print("Connected to wifi: ");
Serial.println(WiFi.status() == WL_CONNECTED);
Serial.print("Local IP: ");
Serial.println(WiFi.localIP().toString());
}
// the loop function runs over and over again until power down or reset
void loop() {
server.handleClient();
}