commit 0756b0b4f3ddee15afe27767952b51c12491391c Author: ldeyun Date: Tue Aug 26 09:47:03 2025 +0000 添加 main.ino diff --git a/main.ino b/main.ino new file mode 100644 index 0000000..593b6ca --- /dev/null +++ b/main.ino @@ -0,0 +1,681 @@ + +#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); +}