#include #include #include #include #include #define AP_TIMEOUT 300000 // 5分钟AP模式超时(毫秒) const byte DNS_PORT = 53; DNSServer dnsServer; ESP8266WebServer server(80); // 配置结构体 struct Config { char wifiSSID[32]; char wifiPass[64]; char mqttServer[40]; char mqttPort[6]; char clientID[24]; char mqttUser[24]; char mqttPass[24]; char subTopic[32]; char pubTopic[32]; }; Config config; bool isAPMode = false; // 函数前置声明 void handleRoot(); void handleCustom(); void handleWiFi(); void handleInfo(); void handleReset(); void handleReboot(); void handleSave(); void handleConnect(); void handleScan(); void handleCheckWiFi(); void handleWiFiStatus(); #include WiFiClient espClient; PubSubClient mqttClient(espClient); // MQTT消息回调函数 void callback(char* topic, byte* payload, unsigned int length) { Serial.write(payload, length); } unsigned long connectStartTime = 0; unsigned long lastMqttReconnectAttempt = 0; unsigned long lastMqttPing = 0; const unsigned long mqttPingInterval = 60000; // 每60秒发送一次心跳包 bool connecting = false; String pendingSSID = ""; String pendingPass = ""; bool shouldConnectWiFi = false; int wifiConnectAttempts = 0; const int maxWifiConnectAttempts = 5; // WiFi最大连接尝试次数 int mqttReconnectAttempts = 0; const int maxMqttReconnectAttempts =20; // MQTT最大重连尝试次数 void enableTransparentMode() { // 检查模块是否响应 Serial.println("AT"); if (waitForResponse("OK", 1000)) { Serial.println("AT+CWMODE=1"); if (waitForResponse("OK", 1000)) { Serial.println("AT+CIPMODE=1"); if (waitForResponse("OK", 1000)) { Serial.println("AT+CIPSEND"); waitForResponse(">", 1000); } } } } // 辅助函数,等待模块响应 bool waitForResponse(const char* response, unsigned long timeout) { unsigned long startTime = millis(); while (millis() - startTime < timeout) { if (Serial.find(response)) { return true; } } return false; } bool reconnect() { if (mqttClient.connect(config.clientID, config.mqttUser, config.mqttPass)) { mqttClient.subscribe(config.subTopic); WiFi.mode(WIFI_STA); enableTransparentMode(); } return mqttClient.connected(); } void startAPMode() { isAPMode = true; WiFi.mode(WIFI_AP); String mac = WiFi.macAddress(); mac.replace(":", ""); String apName = "znkg_" + mac.substring(mac.length() - 6); WiFi.softAP(apName.c_str(), "12345678"); // DNS重定向到配网页面 dnsServer.start(DNS_PORT, "*", WiFi.softAPIP()); startWebServer(); } void setup() { Serial.begin(9600); EEPROM.begin(sizeof(Config)); loadConfig(); // 设置MQTT回调函数 mqttClient.setCallback(callback); // 首次通电或配置为空时进入AP模式 if (strlen(config.wifiSSID) == 0 || strlen(config.mqttServer) == 0) { WiFi.mode(WIFI_AP); startAPMode(); } else { // 设置MQTT服务器 mqttClient.setServer(config.mqttServer, atoi(config.mqttPort)); // 尝试连接保存的WiFi WiFi.mode(WIFI_AP_STA); WiFi.begin(config.wifiSSID, config.wifiPass); connectStartTime = millis(); wifiConnectAttempts++; // 等待15秒连接 for (int i = 0; i < 15; i++) { if (WiFi.status() == WL_CONNECTED) { Serial.println("WiFi连接成功"); wifiConnectAttempts = 0; break; } delay(1000); } if (WiFi.status() != WL_CONNECTED) { wifiConnectAttempts++; // 递增尝试次数 Serial.printf("WiFi连接失败,当前尝试次数: %d/%d\n", wifiConnectAttempts, maxWifiConnectAttempts); if (wifiConnectAttempts >= maxWifiConnectAttempts) { Serial.println("已达到最大WiFi连接尝试次数,进入AP模式"); WiFi.mode(WIFI_AP); startAPMode(); } else { delay(5000); // 等待5秒后重试 WiFi.begin(config.wifiSSID, config.wifiPass); // 重新尝试连接 } } else { startWebServer(); } // 未连接则判断是否超过最大尝试次数 // 原代码(直接重启) // 修改后代码(递增尝试次数) } } void loop() { static unsigned long apStartTime = millis(); // 处理AP模式超时 if (isAPMode && millis() - apStartTime > AP_TIMEOUT) { ESP.restart(); } // 处理DNS请求 if (isAPMode) { dnsServer.processNextRequest(); } // 处理STC串口数据转发到MQTT if (Serial.available() > 0 && mqttClient.connected()) { String data = Serial.readStringUntil('\n'); if (data == "rest") { memset(&config, 0, sizeof(config)); saveConfig(); ESP.restart(); } mqttClient.publish(config.pubTopic, data.c_str()); } // MQTT重连机制 if (!mqttClient.connected()) { unsigned long now = millis(); if (now - lastMqttReconnectAttempt > 5000) { lastMqttReconnectAttempt = now; mqttReconnectAttempts++; if (reconnect()) { Serial.println("MQTT连接成功"); lastMqttPing = now; mqttReconnectAttempts = 0; } else { Serial.printf("MQTT重连失败,当前尝试次数: %d/%d\n", mqttReconnectAttempts, maxMqttReconnectAttempts); if (mqttReconnectAttempts >= maxMqttReconnectAttempts) { Serial.println("已达到最大MQTT重连尝试次数,设备即将自动重启"); startAPMode(); ESP.restart(); } } startWebServer(); } } else { unsigned long now = millis(); if (now - lastMqttPing > mqttPingInterval) { if (mqttClient.loop()) { lastMqttPing = now; } else { // ping失败,断开连接触发重连 mqttClient.disconnect(); } } mqttClient.loop(); } server.handleClient(); } void startWebServer() { server.on("/", handleRoot); server.on("/custom", handleCustom); server.on("/wifi", handleWiFi); server.on("/info", handleInfo); server.on("/reset", handleReset); server.on("/reboot", handleReboot); server.on("/save", handleSave); server.on("/connect", handleConnect); server.on("/scan", handleScan); server.on("/check_wifi", handleCheckWiFi); server.on("/wifi_status", handleWiFiStatus); // 添加强制门户重定向 server.on("/generate_204", handleRoot); // 安卓设备 server.on("/fwlink", handleRoot); // 微软设备 server.on("/hotspot-detect.html", handleRoot); // 苹果设备 server.on("/ncsi.txt", []() { server.send(200, "text/plain", "OK"); }); // 未知请求重定向到首页 server.onNotFound([]() { server.sendHeader("Location", "http://" + WiFi.softAPIP().toString(), true); server.send(302, "text/plain", ""); }); server.begin(); } // 网页处理函数 void handleRoot() { String html = "" "" "" "配网页面" "" "" "
" "

配网页面

" "" "" "" "" "" "" "
" ""; server.send(200, "text/html", html); } void handleCustom() { String html = "" "" "" "自定义设置" "" "" "
" "

自定义设置

" "
" "
" "" "" "
" "
" "" "" "
" "
" "" "" "
" "
" "" "" "
" "
" "" "" "
" "
" "" "" "
" "
" "" "" "
" "" "
" "" "
" ""; server.send(200, "text/html", html); } void handleWiFi() { String html = "" "" "" "WiFi设置" "" "" "" "
" "

WiFi设置

" "
" "
" "" "" "" "
" "" "
" ""; server.send(200, "text/html", html); } void handleInfo() { String html = "" "" "" "网络信息" "" "" "
" "

网络信息

" "
IP地址: " + WiFi.localIP().toString() + "
" "
MAC地址: " + WiFi.macAddress() + "
" "
工作模式: " + (WiFi.getMode() == WIFI_AP ? "AP" : "STA") + "
" "
信号强度: " + String(WiFi.RSSI()) + " dBm
" "
MQTT连接状态: " + (mqttClient.connected() ? "已连接" : "未连接") + "
" "
MQTT地址: " + String(config.mqttServer) + "
" "
MQTT端口: " + String(config.mqttPort) + "
" "
客户端ID: " + String(config.clientID) + "
" "
发布主题: " + String(config.pubTopic) + "
" "
订阅主题: " + String(config.subTopic) + "
" "" "
" ""; server.send(200, "text/html", html); } void handleReboot() { String html = "" "" "重启" "" "" "

设备重启中...

" "" ""; server.send(200, "text/html", html); delay(1000); ESP.restart(); } void handleSave() { if (server.method() == HTTP_GET) { // 保存MQTT配置 strncpy(config.mqttServer, server.arg("mqtt_server").c_str(), sizeof(config.mqttServer)); strncpy(config.mqttPort, server.arg("mqtt_port").c_str(), sizeof(config.mqttPort)); strncpy(config.clientID, server.arg("client_id").c_str(), sizeof(config.clientID)); strncpy(config.mqttUser, server.arg("mqtt_user").c_str(), sizeof(config.mqttUser)); strncpy(config.mqttPass, server.arg("mqtt_pass").c_str(), sizeof(config.mqttPass)); strncpy(config.subTopic, server.arg("sub_topic").c_str(), sizeof(config.subTopic)); strncpy(config.pubTopic, server.arg("pub_topic").c_str(), sizeof(config.pubTopic)); saveConfig(); // 设置MQTT服务器 mqttClient.setServer(config.mqttServer, atoi(config.mqttPort)); // 尝试连接MQTT bool connected = mqttClient.connect(config.clientID, config.mqttUser, config.mqttPass); String html; if (connected) { html = "连接成功"; html += ""; html += "

配置保存成功,MQTT连接成功

"; html += "

设备将在 3 秒后跳转...

"; enableTransparentMode(); } else { html = "连接失败"; html += ""; html += "

配置保存成功,但MQTT连接失败

"; html += "

请检查MQTT配置,页面将在 5 秒后跳转至配置页面...

"; } server.send(200, "text/html", html); } } void handleConnect() { if (server.hasArg("ssid") && server.hasArg("pass") && !connecting) { pendingSSID = server.arg("ssid"); pendingPass = server.arg("pass"); strncpy(config.wifiSSID, pendingSSID.c_str(), sizeof(config.wifiSSID)); strncpy(config.wifiPass, pendingPass.c_str(), sizeof(config.wifiPass)); saveConfig(); connecting = true; connectStartTime = millis(); WiFi.mode(WIFI_STA); WiFi.begin(pendingSSID, pendingPass); } String html = "" "" "WiFi连接状态" "" "" "

WiFi连接状态

"; if (WiFi.status() == WL_CONNECTED) { html += "" "

连接成功

" "

SSID: " + WiFi.SSID() + "

" "

IP地址: " + WiFi.localIP().toString() + "

" ""; connecting = false; } else if (connecting && millis() - connectStartTime < 30000) { html += "" "

正在连接中...

" ""; } else { html += "" "

连接失败

" ""; connecting = false; } html += ""; server.send(200, "text/html", html); } void handleScan() { String json = "["; int n = WiFi.scanNetworks(); for (int i = 0; i < n; ++i) { if (i) json += ","; json += "\"" + WiFi.SSID(i) + "\""; } json += "]"; server.send(200, "application/json", json); } // 保存配置到EEPROM void saveConfig() { EEPROM.put(0, config); EEPROM.commit(); } // 从EEPROM加载配置 void loadConfig() { EEPROM.get(0, config); // 检查是否为首次使用 if (config.mqttPort[0] == 0) { strcpy(config.mqttPort, "1883"); } } void handleCheckWiFi() { String html = "" "" "" "WiFi连接状态" "" "" "
"; if (WiFi.status() == WL_CONNECTED) { html += "

连接成功

" "
SSID: " + WiFi.SSID() + "
" "
IP地址: " + WiFi.localIP().toString() + "
" "
信号强度: " + String(WiFi.RSSI()) + " dBm
"; } else { html += "

未连接

"; } html += "" "
" ""; server.send(200, "text/html", html); } void handleWiFiStatus() { String html = "" "" "WiFi连接状态" "" ""; if (WiFi.status() == WL_CONNECTED) { html += "

连接成功

" "

SSID: " + WiFi.SSID() + "

" "

IP地址: " + WiFi.localIP().toString() + "

" "

信号强度: " + String(WiFi.RSSI()) + " dBm

"; } else { html += "

未连接

"; } html += "" ""; server.send(200, "text/html", html); } void handleReset() { memset(&config, 0, sizeof(config)); saveConfig(); String html = "" "" "重置成功" "" "" "

重置成功

" "

WiFi配置已清除,设备将重启进入AP模式

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