ESP8266/main.ino
2025-08-26 09:47:03 +00:00

682 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiClient.h>
#include <EEPROM.h>
#include <DNSServer.h>
#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 <PubSubClient.h>
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 = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"<title>配网页面</title>"
"<style>"
"* {box-sizing: border-box; margin: 0; padding: 0; font-family: Arial, sans-serif;}"
"body {background-color: #f5f5f5; padding: 20px; color: #333;}"
".container {max-width: 500px; margin: 0 auto; background: white; border-radius: 10px; padding: 25px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);}"
"h1 {text-align: center; margin-bottom: 30px; color: #2c3e50; font-size: 28px;}"
".btn {display: block; width: 100%; padding: 15px; margin: 12px 0; background-color: #3498db; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; transition: background-color 0.3s;}"
".btn:hover {background-color: #2980b9;}"
".btn:nth-child(odd) {background-color: #2ecc71;}"
".btn:nth-child(odd):hover {background-color: #27ae60;}"
".btn-danger {background-color: #e74c3c;}"
".btn-danger:hover {background-color: #c0392b;}"
"</style></head>"
"<body>"
"<div class=\"container\">"
"<h1>配网页面</h1>"
"<button class=\"btn\" onclick=\"location.href='/custom'\">自定义设置</button>"
"<button class=\"btn\" onclick=\"location.href='/wifi'\">WiFi设置</button>"
"<button class=\"btn\" onclick=\"location.href='/info'\">网络信息</button>"
"<button class=\"btn\" onclick=\"location.href='/reset'\">重 置</button>"
"<button class=\"btn\" onclick=\"location.href='/reboot'\">重 启</button>"
"<button class=\"btn\" onclick=\"window.close()\">退 出</button>"
"</div>"
"</body></html>";
server.send(200, "text/html", html);
}
void handleCustom() {
String html = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"<title>自定义设置</title>"
"<style>"
"* {box-sizing: border-box; margin: 0; padding: 0; font-family: Arial, sans-serif;}"
"body {background-color: #f5f5f5; padding: 20px; color: #333;}"
".container {max-width: 500px; margin: 0 auto; background: white; border-radius: 10px; padding: 25px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);}"
"h1 {text-align: center; margin-bottom: 30px; color: #2c3e50; font-size: 24px;}"
".input-group {margin-bottom: 20px;}"
".input-group label {display: block; margin-bottom: 8px; font-weight: bold; color: #555;}"
".input-group input {width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 16px;}"
".btn {display: block; width: 100%; padding: 15px; margin: 15px 0; background-color: #3498db; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; transition: background-color 0.3s;}"
".btn:hover {background-color: #2980b9;}"
".btn-back {background-color: #95a5a6;}"
".btn-back:hover {background-color: #7f8c8d;}"
"</style></head>"
"<body>"
"<div class=\"container\">"
"<h1>自定义设置</h1>"
"<form action=\"/save\">"
"<div class=\"input-group\">"
"<label>MQTT地址:</label>"
"<input type=\"text\" name=\"mqtt_server\" value=\""
+ String(config.mqttServer) + "\">"
"</div>"
"<div class=\"input-group\">"
"<label>MQTT端口:</label>"
"<input type=\"text\" name=\"mqtt_port\" value=\""
+ String(config.mqttPort) + "\">"
"</div>"
"<div class=\"input-group\">"
"<label>客户端ID:</label>"
"<input type=\"text\" name=\"client_id\" value=\""
+ String(config.clientID) + "\">"
"</div>"
"<div class=\"input-group\">"
"<label>用户名称:</label>"
"<input type=\"text\" name=\"mqtt_user\" value=\""
+ String(config.mqttUser) + "\">"
"</div>"
"<div class=\"input-group\">"
"<label>输入密码:</label>"
"<input type=\"password\" name=\"mqtt_pass\" value=\""
+ String(config.mqttPass) + "\">"
"</div>"
"<div class=\"input-group\">"
"<label>发布主题:</label>"
"<input type=\"text\" name=\"pub_topic\" value=\""
+ String(config.pubTopic) + "\">"
"</div>"
"<div class=\"input-group\">"
"<label>订阅主题:</label>"
"<input type=\"text\" name=\"sub_topic\" value=\""
+ String(config.subTopic) + "\">"
"</div>"
"<button type=\"submit\" class=\"btn\">保 存</button>"
"</form>"
"<button onclick=\"window.location.replace('/');\" class=\"btn btn-back\">返 回</button>"
"</div>"
"</body></html>";
server.send(200, "text/html", html);
}
void handleWiFi() {
String html = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"<title>WiFi设置</title>"
"<style>"
"* {box-sizing: border-box; margin: 0; padding: 0; font-family: Arial, sans-serif;}"
"body {background-color: #f5f5f5; padding: 20px; color: #333;}"
".container {max-width: 500px; margin: 0 auto; background: white; border-radius: 10px; padding: 25px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);}"
"h1 {text-align: center; margin-bottom: 20px; color: #2c3e50; font-size: 24px;}"
"#networks {margin-bottom: 20px; max-height: 300px; overflow-y: auto; border: 1px solid #eee; border-radius: 6px; padding: 10px;}"
"#networks div {padding: 12px; border-bottom: 1px solid #eee; cursor: pointer; transition: background-color 0.2s;}"
"#networks div:hover {background-color: #f9f9f9;}"
"form {margin-bottom: 20px;}"
"input {width: 100%; padding: 12px; margin-bottom: 15px; border: 1px solid #ddd; border-radius: 6px; font-size: 16px;}"
".btn {display: block; width: 100%; padding: 15px; margin: 15px 0; background-color: #3498db; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; transition: background-color 0.3s;}"
".btn:hover {background-color: #2980b9;}"
".btn-back {background-color: #95a5a6;}"
".btn-back:hover {background-color: #7f8c8d;}"
"</style>"
"<script>"
"function loadNetworks() {"
" fetch('/scan')"
" .then(r => r.json())"
" .then(data => {"
" let networksDiv = document.getElementById('networks');"
" networksDiv.innerHTML = '';"
" data.forEach(net => {"
" let div = document.createElement('div');"
" div.textContent = net;"
" div.style.cursor = 'pointer';"
" div.onclick = function() {"
" document.getElementById('ssid').value = net;"
" };"
" networksDiv.appendChild(div);"
" });"
" });"
"}"
"window.onload = loadNetworks;"
"</script></head>"
"<body>"
"<div class=\"container\">"
"<h1>WiFi设置</h1>"
"<div id=\"networks\"></div>"
"<form action=\"/connect\">"
"<input type=\"text\" id=\"ssid\" name=\"ssid\" placeholder=\"WiFi名称\">"
"<input type=\"password\" name=\"pass\" placeholder=\"WiFi密码\">"
"<button type=\"submit\" class=\"btn\">连 接</button>"
"</form>"
"<button onclick=\"window.location.href='/';\" class=\"btn btn-back\">返 回</button>"
"</div>"
"</body></html>";
server.send(200, "text/html", html);
}
void handleInfo() {
String html = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"<title>网络信息</title>"
"<style>"
"* {box-sizing: border-box; margin: 0; padding: 0; font-family: Arial, sans-serif;}"
"body {background-color: #f5f5f5; padding: 20px; color: #333;}"
".container {max-width: 500px; margin: 0 auto; background: white; border-radius: 10px; padding: 25px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);}"
"h1 {text-align: center; margin-bottom: 30px; color: #2c3e50; font-size: 24px;}"
".info {margin-bottom: 15px; padding: 15px; background-color: #f9f9f9; border-radius: 6px; font-size: 16px;}"
".info strong {color: #2c3e50;}"
".connected {color: #27ae60; font-weight: bold;}"
".disconnected {color: #c0392b; font-weight: bold;}"
".btn {display: block; width: 100%; padding: 15px; margin: 20px 0 0; background-color: #3498db; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; transition: background-color 0.3s;}"
".btn:hover {background-color: #2980b9;}"
"</style></head>"
"<body>"
"<div class=\"container\">"
"<h1>网络信息</h1>"
"<div class=\"info\"><strong>IP地址:</strong> "
+ WiFi.localIP().toString() + "</div>"
"<div class=\"info\"><strong>MAC地址:</strong> "
+ WiFi.macAddress() + "</div>"
"<div class=\"info\"><strong>工作模式:</strong> "
+ (WiFi.getMode() == WIFI_AP ? "AP" : "STA") + "</div>"
"<div class=\"info\"><strong>信号强度:</strong> "
+ String(WiFi.RSSI()) + " dBm</div>"
"<div class=\"info\"><strong>MQTT连接状态:</strong> <span class=\"" + (mqttClient.connected() ? "connected" : "disconnected") + "\">" + (mqttClient.connected() ? "已连接" : "未连接") + "</span></div>"
"<div class=\"info\"><strong>MQTT地址:</strong> "
+ String(config.mqttServer) + "</div>"
"<div class=\"info\"><strong>MQTT端口:</strong> "
+ String(config.mqttPort) + "</div>"
"<div class=\"info\"><strong>客户端ID:</strong> "
+ String(config.clientID) + "</div>"
"<div class=\"info\"><strong>发布主题:</strong> "
+ String(config.pubTopic) + "</div>"
"<div class=\"info\"><strong>订阅主题:</strong> "
+ String(config.subTopic) + "</div>"
"<button onclick=\"window.location.href='/';\" class=\"btn\">返 回</button>"
"</div>"
"</body></html>";
server.send(200, "text/html", html);
}
void handleReboot() {
String html = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<title>重启</title>"
"<style>"
"body {background:#000;color:#fff;font-size:40px;text-align:center;}"
"</style></head>"
"<body>"
"<h1>设备重启中...</h1>"
"<script>"
"setTimeout(function() {"
" window.location.href = '/';"
"}, 3000);"
"</script>"
"</body></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 = "<!DOCTYPE html><html><head><title>连接成功</title>";
html += "<meta http-equiv='refresh' content='3;url=/'>";
html += "</head><body><h1>配置保存成功MQTT连接成功</h1>";
html += "<p>设备将在 3 秒后跳转...</p></body></html>";
enableTransparentMode();
} else {
html = "<!DOCTYPE html><html><head><title>连接失败</title>";
html += "<meta http-equiv='refresh' content='5;url=/custom'>";
html += "</head><body><h1>配置保存成功但MQTT连接失败</h1>";
html += "<p>请检查MQTT配置页面将在 5 秒后跳转至配置页面...</p></body></html>";
}
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 = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<title>WiFi连接状态</title>"
"<style>"
"body {background:#000;color:#fff;font-size:40px;text-align:center;}"
" .info {margin:15px 0;font-size:40px;}"
" button {background:#0066cc;color:#fff;border:none;padding:15px 30px;margin:15px;cursor:pointer; font-size: 40px;}"
"</style></head>"
"<body>"
"<h1>WiFi连接状态</h1>";
if (WiFi.status() == WL_CONNECTED) {
html += "</head><body>"
"<h1 style=\"color:green\">连接成功</h1>"
"<p>SSID: "
+ WiFi.SSID() + "</p>"
"<p>IP地址: "
+ WiFi.localIP().toString() + "</p>"
"<button onclick=\"window.location.href='/';\">返回首页</button>";
connecting = false;
} else if (connecting && millis() - connectStartTime < 30000) {
html += "</head><body>"
"<h1>正在连接中...</h1>"
"<meta http-equiv=\"refresh\" content=\"5\">";
} else {
html += "</head><body>"
"<h1 style=\"color:red\">连接失败</h1>"
"<button onclick=\"window.location.href='/wifi';\">重新选择WiFi</button>";
connecting = false;
}
html += "</body></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 = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"<title>WiFi连接状态</title>"
"<style>"
"* {box-sizing: border-box; margin: 0; padding: 0; font-family: Arial, sans-serif;}"
"body {background-color: #f5f5f5; padding: 20px; color: #333;}"
".container {max-width: 500px; margin: 0 auto; background: white; border-radius: 10px; padding: 25px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);}"
"h1 {text-align: center; margin-bottom: 20px; font-size: 24px;}"
".connected {color: #27ae60;}"
".disconnected {color: #c0392b;}"
".info {margin: 15px 0; padding: 15px; background-color: #f9f9f9; border-radius: 6px; font-size: 16px;}"
".btn {display: block; width: 100%; padding: 15px; margin: 20px 0 0; background-color: #3498db; color: white; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; transition: background-color 0.3s;}"
".btn:hover {background-color: #2980b9;}"
"</style></head>"
"<body>"
"<div class=\"container\">";
if (WiFi.status() == WL_CONNECTED) {
html += "<h1 class=\"connected\">连接成功</h1>"
"<div class=\"info\"><strong>SSID:</strong> "
+ WiFi.SSID() + "</div>"
"<div class=\"info\"><strong>IP地址:</strong> "
+ WiFi.localIP().toString() + "</div>"
"<div class=\"info\"><strong>信号强度:</strong> "
+ String(WiFi.RSSI()) + " dBm</div>";
} else {
html += "<h1 class=\"disconnected\">未连接</h1>";
}
html += "<button onclick=\"window.location.href='/';\" class=\"btn\">返回首页</button>"
"</div>"
"</body></html>";
server.send(200, "text/html", html);
}
void handleWiFiStatus() {
String html = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<title>WiFi连接状态</title>"
"<style>"
"body {background:#000;color:#fff;font-size:40px;text-align:center;}"
" .info {margin:15px 0;font-size:40px;}"
" button {background:#0066cc;color:#fff;border:none;padding:15px 30px;margin:15px;cursor:pointer; font-size: 40px;}"
"h1 {font-size:24px;}"
"p {margin: 15px 0;}"
"</style></head>"
"<body>";
if (WiFi.status() == WL_CONNECTED) {
html += "<h1 style=\"color:green\">连接成功</h1>"
"<p>SSID: "
+ WiFi.SSID() + "</p>"
"<p>IP地址: "
+ WiFi.localIP().toString() + "</p>"
"<p>信号强度: "
+ String(WiFi.RSSI()) + " dBm</p>";
} else {
html += "<h1 style=\"color:red\">未连接</h1>";
}
html += "<button onclick=\"window.location.href='/';\">返回首页</button>"
"</body></html>";
server.send(200, "text/html", html);
}
void handleReset() {
memset(&config, 0, sizeof(config));
saveConfig();
String html = "<!DOCTYPE html><html><head>"
"<meta charset=\"UTF-8\">"
"<title>重置成功</title>"
"<style>"
"body {background:#000;color:#fff;text-align:center;}"
"</style></head>"
"<body>"
"<h1>重置成功</h1>"
"<p>WiFi配置已清除设备将重启进入AP模式</p>"
"<script>"
"setTimeout(function() {"
" window.location.href = '/reboot';"
"}, 3000);"
"</script>"
"</body></html>";
server.send(200, "text/html", html);
}