Cutom ota esp8266 error

I have a little problem, when uploading the OTA firmware it says successful but the ESP doesn't restart, where is the problem?

#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#else
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
#include <Update.h>
#endif

#include <WiFiUdp.h>
#include <Wire.h>
#include <MPU6050.h>
#include <ArduinoJson.h>

// Platform-specific configurations
#ifdef ESP8266
#define BOARD_TYPE "ESP8266"
#define LED_BUILTIN 2  // ESP8266 built-in LED pin
#else
#define BOARD_TYPE "ESP32"
#define LED_BUILTIN 2  // ESP32 built-in LED pin
#endif

// WiFi Manager settings
char apSSID[33] = "Gyro_Control";     // 32 characters + null terminator
char apPassword[65] = "12345678";   // 64 characters + null terminator

String routerSSID = "";
String routerPassword = "";
char expectedMAC[18] = "";  // MAC address format XX:XX:XX:XX:XX:XX

// UDP Settings
const char* serverIP = "192.168.4.1";
unsigned int serverPort = 4210;

// System variables
unsigned long lastWiFiCheckMillis = 0;
const long wifiCheckInterval = 30000;

// Add these function declarations at the top of your file
void handleUpdate(AsyncWebServerRequest *request);
void handleDoUpdate(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final);
void printProgress(size_t prg, size_t sz);

// Add these variables for update progress tracking
size_t contentLength = 0;
size_t currentLength = 0;
bool updateStarted = false;

#ifdef ESP8266
AsyncWebServer server(80);
#else
AsyncWebServer server(80);
#endif

WiFiUDP udp;
MPU6050 mpu;
int failedWiFiConnections = 0;
bool isStaConnected = false;  // Track STA connection status

// WiFi Scanning variables
unsigned long scanStartTime = 0;
unsigned long lastScanRequest = 0;
const unsigned long SCAN_COOLDOWN = 10000;       // 10 seconds cooldown between scans

volatile bool isScanning = false;
WiFiMode_t lastWiFiMode;
const unsigned long SCAN_TIMEOUT = 40000;  // 40 seconds timeout
const unsigned long MIN_SCAN_TIME = 2000;  // Minimum scan time

const unsigned long AP_MODE_TIMEOUT = 300000;  // 5 menit dalam mode AP
const unsigned long WIFI_RECONNECT_INTERVAL = 180000;  // Coba rekoneksi setiap 3 menit

unsigned long apModeStartTime = 0;
unsigned long lastReconnectAttempt = 0;

volatile bool needsWiFiRestore = false;

// Platform-specific SPIFFS mounting
bool mountSPIFFS() {
    #ifdef ESP8266
    return SPIFFS.begin();
    #else
    return SPIFFS.begin(true);  // Format SPIFFS if mount fails on ESP32
    #endif
}

void resetSettings() {
    routerSSID = "";
    routerPassword = "";
    memset(expectedMAC, 0, sizeof(expectedMAC));
    saveWiFiCredentials();

    strncpy(apSSID, "Gyro_Control", sizeof(apSSID) - 1);
    strncpy(apPassword, "12345678", sizeof(apPassword) - 1);
    apSSID[sizeof(apSSID) - 1] = '\0';
    apPassword[sizeof(apPassword) - 1] = '\0';
    saveAPSettings();

    Serial.println("All settings reset to default values");
}

void loadAPSettings() {
    if (SPIFFS.exists("/ap_settings.txt")) {
        File file = SPIFFS.open("/ap_settings.txt", "r");
        if (file) {
            String ssid = file.readStringUntil('\n');
            String password = file.readStringUntil('\n');
            ssid.trim();
            password.trim();
            strncpy(apSSID, ssid.c_str(), sizeof(apSSID) - 1);
            strncpy(apPassword, password.c_str(), sizeof(apPassword) - 1);
            apSSID[sizeof(apSSID) - 1] = '\0';
            apPassword[sizeof(apPassword) - 1] = '\0';
            Serial.println("AP settings loaded: " + String(apSSID));
            file.close();
        }
    }
}

void saveAPSettings() {
    File file = SPIFFS.open("/ap_settings.txt", "w");
    if (file) {
        file.println(apSSID);
        file.println(apPassword);
        file.close();
        Serial.println("AP settings saved");
    }
}

void loadWiFiCredentials() {
    if (SPIFFS.exists("/wifi_creds.txt")) {
        File file = SPIFFS.open("/wifi_creds.txt", "r");
        if (file) {
            routerSSID = file.readStringUntil('\n');
            routerPassword = file.readStringUntil('\n');
            String mac = file.readStringUntil('\n');
            routerSSID.trim();
            routerPassword.trim();
            mac.trim();
            if (mac.length() > 0) {
                strncpy(expectedMAC, mac.c_str(), sizeof(expectedMAC) - 1);
                expectedMAC[sizeof(expectedMAC) - 1] = '\0';
            }
            Serial.println("WiFi credentials loaded: " + routerSSID);
            file.close();
        }
    }
}

void saveWiFiCredentials() {
    File file = SPIFFS.open("/wifi_creds.txt", "w");
    if (file) {
        file.println(routerSSID);
        file.println(routerPassword);
        file.println(expectedMAC);
        file.close();
        Serial.println("WiFi credentials saved");
    }
}


void startAPMode() {
    // Use a common implementation that works on both platforms
    if (WiFi.getMode() != WIFI_AP && WiFi.getMode() != WIFI_AP_STA) {
        WiFi.mode(WIFI_AP_STA);  // Always use dual mode
        delay(100);
    }
    
    if(WiFi.softAP(apSSID, apPassword)) {
        Serial.println("AP Created Successfully");
    } else {
        Serial.println("AP Creation Failed!");
        // Try with default settings
        if(WiFi.softAP("RC_Car_AP", "12345678")) {
            Serial.println("AP Created with default settings");
            strcpy(apSSID, "RC_Car_AP");
            strcpy(apPassword, "12345678");
        }
    }
    
    delay(500);
    IPAddress myIP = WiFi.softAPIP();
    Serial.println("AP Mode active");
    Serial.print("AP IP address: ");
    Serial.println(myIP);
    
    // Print AP settings
    Serial.print("AP SSID: ");
    Serial.println(apSSID);
    Serial.print("AP Password: ");
    Serial.println(apPassword);
}

bool connectToWiFi() {
    int attempts = 0;
    const int maxAttempts = 20;

    Serial.println("Connecting to WiFi while maintaining AP...");
    WiFi.mode(WIFI_AP_STA);  // Set to dual mode
    WiFi.begin(routerSSID.c_str(), routerPassword.c_str());

    while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts) {
        delay(1000);
        Serial.print(".");
        attempts++;
    }

    if (WiFi.status() == WL_CONNECTED) {
        String actualMAC = WiFi.BSSIDstr();
        Serial.println("\nConnected to WiFi");
        Serial.print("MAC Address: ");
        Serial.println(actualMAC);
        
        if (expectedMAC[0] == '\0' || actualMAC.equals(expectedMAC)) {
            Serial.println("Connected to correct AP");
            Serial.print("STA IP Address: ");
            Serial.println(WiFi.localIP());
            Serial.print("AP IP Address: ");
            Serial.println(WiFi.softAPIP());

            // Dapatkan alamat IP gateway setelah terhubung
            #ifdef ESP8266
            serverIP = WiFi.gatewayIP().toString().c_str();
            #else
            serverIP = WiFi.gatewayIP().toString().c_str();
            #endif

            Serial.print("Gateway IP (serverIP): ");
            Serial.println(serverIP);

            isStaConnected = true;
            return true;
        } else {
            Serial.println("MAC address mismatch!");
            WiFi.disconnect(false);  // Disconnect STA but keep AP running
            isStaConnected = false;
            return false;
        }
    }
    
    Serial.println("\nFailed to connect to WiFi");
    failedWiFiConnections++;
    isStaConnected = false;
    return false;
}

void scanNetworks(AsyncWebServerRequest *request) {
    Serial.println("\n=== Starting Enhanced WiFi Scan ===");
    
    if (isScanning) {
        Serial.println("Error: Scan already in progress");
        request->send(429, "application/json", "{\"status\":\"busy\",\"message\":\"A scan is already in progress\"}");
        return;
    }

    lastWiFiMode = WiFi.getMode();
    Serial.printf("Current WiFi Mode: %d\n", lastWiFiMode);
    
    if (WiFi.status() == WL_CONNECTED) {
        Serial.println("Disconnecting from current network for scan...");
        WiFi.disconnect(false);  // false = don't erase saved credentials
        delay(100);
    }

    if (lastWiFiMode == WIFI_AP) {
        Serial.println("Switching to AP_STA mode for scanning");
        WiFi.mode(WIFI_AP_STA);
    } else if (lastWiFiMode != WIFI_STA && lastWiFiMode != WIFI_AP_STA) {
        Serial.println("Switching to STA mode for scanning");
        WiFi.mode(WIFI_STA);
    }
    delay(100);  // Allow mode change to settle


    WiFi.scanDelete();
    Serial.println("Previous scan results cleared");

    int scanResult = WiFi.scanNetworks(true, true);  // async=true, show_hidden=true
    
    if (scanResult == WIFI_SCAN_FAILED) {
        Serial.println("Failed to initiate scan!");
        restoreWiFiState();
        request->send(500, "application/json", "{\"status\":\"error\",\"message\":\"Failed to start scan\"}");
        return;
    }

    isScanning = true;
    scanStartTime = millis();
    Serial.println("Scan initiated successfully");
    request->send(200, "application/json", "{\"status\":\"scanning\",\"message\":\"Scan started\"}");
}

void getScanResults(AsyncWebServerRequest *request) {
    Serial.println("\n=== Checking Enhanced Scan Results ===");
    
    if (!isScanning) {
        Serial.println("Error: No scan in progress");
        request->send(400, "application/json", "{\"status\":\"error\",\"message\":\"No scan in progress\"}");
        return;
    }

    int scanResult = WiFi.scanComplete();
    unsigned long elapsedTime = millis() - scanStartTime;
    
    // Ensure minimum scan time
    if (elapsedTime < MIN_SCAN_TIME) {
        Serial.println("Waiting for minimum scan time...");
        request->send(202, "application/json", "{\"status\":\"scanning\",\"message\":\"Scan in progress\"}");
        return;
    }

    // Handle timeout
    if (elapsedTime > SCAN_TIMEOUT) {
        Serial.println("Scan timed out!");
        isScanning = false;
        WiFi.scanDelete();
        restoreWiFiState();
        request->send(504, "application/json", "{\"status\":\"timeout\",\"message\":\"Scan timed out\"}");
        return;
    }

    // Process results
    if (scanResult == WIFI_SCAN_FAILED) {
        Serial.println("Scan failed!");
        isScanning = false;
        restoreWiFiState();
        request->send(500, "application/json", "{\"status\":\"error\",\"message\":\"Scan failed\"}");
        return;
    }
    
    if (scanResult == WIFI_SCAN_RUNNING) {
        Serial.println("Scan still in progress...");
        request->send(202, "application/json", "{\"status\":\"scanning\",\"message\":\"Scan in progress\"}");
        return;
    }

    // Handle zero networks found
    if (scanResult == 0) {
        Serial.println("No networks found - initiating retry...");
        // Optional: Implement retry logic here
        WiFi.scanDelete();
        int retryScan = WiFi.scanNetworks(true, true);  // async=true, show_hidden=true
        if (retryScan == WIFI_SCAN_FAILED) {
            isScanning = false;
            restoreWiFiState();
            request->send(200, "application/json", "[]");  // Return empty array instead of error
            return;
        }
        request->send(202, "application/json", "{\"status\":\"scanning\",\"message\":\"Retrying scan\"}");
        return;
    }

    // Process found networks
    if (scanResult > 0) {
        Serial.printf("Found %d networks\n", scanResult);
        DynamicJsonDocument doc(4096);
        JsonArray networks = doc.to<JsonArray>();
        
        for (int i = 0; i < scanResult; i++) {
            JsonObject network = networks.createNestedObject();
            network["ssid"] = WiFi.SSID(i);
            network["bssid"] = WiFi.BSSIDstr(i);
            network["rssi"] = WiFi.RSSI(i);
            network["channel"] = WiFi.channel(i);
            network["encryption"] = WiFi.encryptionType(i);
            network["hidden"] = WiFi.SSID(i).length() == 0;
            
            Serial.printf("Network %d: SSID: %s, RSSI: %d\n", 
                i, WiFi.SSID(i).c_str(), WiFi.RSSI(i));
        }
        
        String response;
        serializeJson(doc, response);
        
        WiFi.scanDelete();
        isScanning = false;
        restoreWiFiState();
        
        request->send(200, "application/json", response);
    }
}

void restoreWiFiState() {
    Serial.println("Restoring WiFi state...");
    if (lastWiFiMode == WIFI_AP) {
        WiFi.mode(WIFI_AP);
    } else if (lastWiFiMode == WIFI_STA && routerSSID.length() > 0) {
        WiFi.mode(WIFI_STA);
        WiFi.begin(routerSSID.c_str(), routerPassword.c_str());
    }
}

// Tambahkan fungsi untuk memeriksa status WiFi
void printWiFiStatus() {
    Serial.println("\n=== WiFi Status ===");
    Serial.printf("Mode: %d\n", WiFi.getMode());
    Serial.printf("Status: %d\n", WiFi.status());
    
    if (WiFi.getMode() == WIFI_STA || WiFi.getMode() == WIFI_AP_STA) {
        Serial.printf("Connected to: %s\n", WiFi.SSID().c_str());
        Serial.printf("IP Address: %s\n", WiFi.localIP().toString().c_str());
    }
    
    if (WiFi.getMode() == WIFI_AP || WiFi.getMode() == WIFI_AP_STA) {
        Serial.printf("AP SSID: %s\n", apSSID);
        Serial.printf("AP IP: %s\n", WiFi.softAPIP().toString().c_str());
    }
}

void setupServerRoutes() {
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send(SPIFFS, "/index.html", "text/html");
    });
    
    server.on("/assets/css/foundation.css", HTTP_GET, [](AsyncWebServerRequest *request) {
        request->send(SPIFFS, "/assets/css/foundation.css", "text/css");
    });

    // Update route untuk scan
    server.on("/scan-wifi", HTTP_GET, scanNetworks);
    
    // Tambah route baru untuk hasil scan
    server.on("/scan-results", HTTP_GET, getScanResults);

    server.on("/setwifi", HTTP_POST, [](AsyncWebServerRequest *request) {
        String newSSID = request->hasParam("ssid", true) ? request->getParam("ssid", true)->value() : "";
        String newPassword = request->hasParam("password", true) ? request->getParam("password", true)->value() : "";
        String newMAC = request->hasParam("mac", true) ? request->getParam("mac", true)->value() : "";
        
        if (newSSID.length() > 0 && newPassword.length() >= 8) {
            routerSSID = newSSID;
            routerPassword = newPassword;
            if (newMAC.length() == 17) {
                strncpy(expectedMAC, newMAC.c_str(), sizeof(expectedMAC) - 1);
                expectedMAC[sizeof(expectedMAC) - 1] = '\0';
            }
            
            saveWiFiCredentials();
            request->send(200, "text/plain", "WiFi settings updated. Restarting...");
            delay(1000);
            ESP.restart();
        } else {
            request->send(400, "text/plain", "Invalid parameters");
        }
    });

    server.on("/setap", HTTP_POST, [](AsyncWebServerRequest *request) {
        if (request->hasParam("ssid", true) && request->hasParam("password", true)) {
            String newSSID = request->getParam("ssid", true)->value();
            String newPassword = request->getParam("password", true)->value();
            
            if (newSSID.length() > 0 && newPassword.length() >= 8) {
                strncpy(apSSID, newSSID.c_str(), sizeof(apSSID) - 1);
                strncpy(apPassword, newPassword.c_str(), sizeof(apPassword) - 1);
                apSSID[sizeof(apSSID) - 1] = '\0';
                apPassword[sizeof(apPassword) - 1] = '\0';
                
                saveAPSettings();
                request->send(200, "text/plain", "AP settings updated. Restarting...");
                delay(1000);
                ESP.restart();
            } else {
                request->send(400, "text/plain", "Invalid parameters");
            }
        } else {
            request->send(400, "text/plain", "Missing parameters");
        }
    });

    server.on("/devicestatus", HTTP_GET, [](AsyncWebServerRequest *request) {
      String ssid = WiFi.SSID();
      String ip = WiFi.localIP().toString();
      String mac = String(expectedMAC);
  
      String response = "{";
      response += "\"ssid\":\"" + (ssid.length() > 0 ? ssid : "No WiFi") + "\",";
      response += "\"ip\":\"" + (ip != "0.0.0.0" ? ip : "0.0.0.0") + "\",";
      response += "\"mac\":\"" + (mac.length() > 0 ? mac : "00:00:00:00:00:00") + "\",";
      response += "\"freeHeap\":\"" + String(ESP.getFreeHeap()) + "\"";
      response += "}";
      request->send(200, "application/json", response);
    });

    server.on("/reset", HTTP_POST, [](AsyncWebServerRequest *request) {
        resetSettings();
        request->send(200, "text/plain", "All settings reset. Restarting...");
        delay(1000);
        ESP.restart();
    });

    // Serve the HTML page
    server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
        request->send(SPIFFS, "/update.html", "text/html");
    });

    // Handle firmware upload
    server.on("/update", HTTP_POST, 
        [](AsyncWebServerRequest *request) {
            // Ketika update selesai, kirim respon
            String updateStatus = Update.hasError() ? "Update failed!" : "Update successful!";
            AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", updateStatus);
            response->addHeader("Connection", "close");
            request->send(response);
        },
        [](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
            handleDoUpdate(request, filename, index, data, len, final);
        }
    );
}

void handleDoUpdate(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
    if(!index) {
        Serial.println("Update Start");
        #ifdef ESP8266
        Update.runAsync(true);
        contentLength = request->contentLength();
        if(!Update.begin(contentLength, U_FLASH)) {
        #else
        contentLength = request->contentLength();
        if(!Update.begin(UPDATE_SIZE_UNKNOWN)) {
        #endif
            Update.printError(Serial);
        }
    }

    if(Update.write(data, len) != len) {
        Update.printError(Serial);
    }

    currentLength += len;
    printProgress(currentLength, contentLength);

    if(final) {
        if(!Update.end(true)) {
            Update.printError(Serial);
        } else {
            Serial.println("\nUpdate Success!");
        }
    }
}

void printProgress(size_t prg, size_t sz) {
    Serial.printf("Progress: %d%%\n", (prg * 100) / sz);
}

void sendUDPPacket(const char* command) {
    if (isStaConnected) {
        udp.beginPacket(serverIP, serverPort);
        udp.write((const uint8_t*)command, strlen(command));  // Convert to uint8_t* and specify length
        udp.endPacket();
    }
}

void setup() {
    Serial.begin(115200);
    Serial.println("\n=== Starting Setup ===");
    
    if (!mountSPIFFS()) {
        Serial.println("Error mounting SPIFFS");
        strcpy(apSSID, "Gyro_Control");
        strcpy(apPassword, "12345678");
    }
    Serial.println("SPIFFS mounted successfully");
    
    loadWiFiCredentials();
    loadAPSettings();

    // Set hostname dari apSSID
    #ifdef ESP8266
    WiFi.hostname(apSSID);
    #else
    WiFi.setHostname(apSSID);
    #endif
    
    // Tambahkan Serial.print untuk memverifikasi hostname
    Serial.print("Hostname: ");
    #ifdef ESP8266
    Serial.println(WiFi.hostname());
    #else
    Serial.println(WiFi.getHostname());
    #endif

    Wire.begin();
    mpu.initialize();
    
    if (mpu.testConnection()) {
        Serial.println("MPU6050 connection successful!");
    } else {
        Serial.println("MPU6050 connection failed!");
    }

    // Start AP Mode first
    startAPMode();

    // Then try to connect to WiFi if credentials exist
    if (routerSSID.length() > 0) {
        Serial.println("WiFi credentials found, attempting to connect...");
        if (!connectToWiFi()) {
            startAPMode();
            apModeStartTime = millis();  // Catat waktu mulai mode AP
        }
    }
    
    setupServerRoutes();
    server.begin();
    
    printWiFiStatus();
    
    Serial.println("System ready!");
    Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap());
}

void loop() {
    unsigned long currentMillis = millis();
    
    // Status WiFi saat ini
    WiFiMode_t currentMode = WiFi.getMode();
    
    // Jika dalam mode AP, pantau waktu
    if (currentMode == WIFI_AP || currentMode == WIFI_AP_STA) {
        // Jika sudah lebih dari waktu timeout AP
        if (currentMillis - apModeStartTime > AP_MODE_TIMEOUT) {
            // Coba kembali ke mode STA
            if (routerSSID.length() > 0) {
                Serial.println("AP Mode timeout. Attempting to reconnect to WiFi...");
                WiFi.mode(WIFI_STA);
                connectToWiFi();
            }
        }
    }
    
    // Coba rekoneksi berkala jika tidak terhubung
    if (currentMillis - lastReconnectAttempt >= WIFI_RECONNECT_INTERVAL) {
        lastReconnectAttempt = currentMillis;
        
        if (WiFi.status() != WL_CONNECTED) {
            Serial.println("Periodic WiFi reconnection attempt...");
            
            // Jika kredensial tersedia, coba rekoneksi
            if (routerSSID.length() > 0) {
                // Beralih ke mode AP_STA untuk memastikan AP tetap aktif
                WiFi.mode(WIFI_AP_STA);
                connectToWiFi();
                
                // Jika koneksi gagal, kembali ke mode AP
                if (!isStaConnected) {
                    startAPMode();
                    apModeStartTime = currentMillis;  // Reset waktu mode AP
                }
            }
        }
    }
    
    // MPU6050 data handling
    static unsigned long lastSendTime = 0;
    const unsigned long sendInterval = 20;
    
    if (isStaConnected && currentMillis - lastSendTime >= sendInterval) {
        lastSendTime = currentMillis;
        int16_t ax, ay, az;
        mpu.getAcceleration(&ax, &ay, &az);
        
        char command[32];
        snprintf(command, sizeof(command), "acc,%d,%d,%d", ax, ay, az);
        sendUDPPacket(command);
    }
}
<!doctype html>
<html class="no-js" lang="en">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Gyro WiFi</title>
    <link rel="stylesheet" href="assets/css/foundation.css">
</head>
<body>
    <div class="grid-container">
        <div class="grid-x grid-padding-x">
            <div class="large-12 text-center cell">
                <div class="grid-x grid-padding-y">
                    <div class="large-12 cell">
                        <h3>Gyro WiFi</h3>
                    </div>
                </div>

                <div class="grid-x grid-padding-x">
                    <div class="large-12 cell">
                        <div class="grid-x grid-padding-x">
                            <div class="large-8 medium-8 center cell">
                                <div class="callout">
                                    <div class="grid-x grid-margin-x">
                                        <div class="large-6 medium-6 cell">
                                            <div class="grid-x grid-padding-x">
                                                <div class="large-12 medium-12 small-12 cell">
                                                    WiFi Settings
                                                    <div class="grid-x grid-margin-x">
                                                        <div class="large-12 medium-12 small-12 cell">
                                                            <input type="text" id="wifiSSID" placeholder="WiFi SSID">
                                                        </div>
                                                        <div class="large-12 medium-12 small-12 cell">
                                                            <input type="password" id="wifiPassword" placeholder="WiFi Password">
                                                        </div>
                                                        <div class="large-12 medium-12 small-12 cell">
                                                            <input type="text" id="macAddress" placeholder="Expected MAC Address">
                                                        </div>
                                                        <div class="large-12 medium-12 small-12 cell">
                                                            <button class="submit success button" onclick="setWiFi()">Set WiFi Credentials</button>
                                                        </div>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="large-6 medium-6 cell">
                                            Access Point Settings
                                            <div class="grid-x grid-margin-x">
                                                <div class="large-12 medium-12 small-12 cell">
                                                    <input type="text" id="apSSID" placeholder="AP SSID">
                                                </div>
                                                <div class="large-12 medium-12 small-12 cell">
                                                    <input type="password" id="apPassword" placeholder="AP Password">
                                                </div>
                                                <div class="large-12 medium-12 small-12 cell">
                                                    <button class="submit success button" onclick="setAP()">Set AP Credentials</button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>

                                    <div class="grid-x grid-padding-y">
                                        <div class="large-12 medium-12 small-12 text-center cell">
                                            <div class="callout callout-scan">
                                                <h5>Scan WiFi Networks</h5>
                                                <div id="networkList" class="network-list" style="display: none;">
                                                    <div class="scanning">Scanning for networks...</div>
                                                </div>
                                                <button id="scanButton" class="success button callout-button" onclick="startWiFiScan()">Scan WiFi Networks</button>
                                            </div>
                                        </div>
                                    </div>

                                    <div class="grid-x grid-padding-y">
                                        <div class="large-12 medium-12 small-12 cell">
                                            <div class="callout">
                                                <div class="grid-x grid-margin-x">
                                                    <div class="large-12 medium-12 small-12 cell">
                                                        <h4>Device Status</h4>
                                                        <p>WiFi Name: <span id="wifiName"></span></p>
                                                        <p>IP Address: <span id="ipAddress"></span></p>
                                                        <p>MAC Address: <span id="currentMac"></span></p>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div class="grid-x grid-padding-x">
                            <div class="large-8 medium-8 small-12 center cell">
                                <div class="grid-x grid-margin-x">
                                    <div class="large-12 medium-12 small-12 cell">
                                        <div class="callout alert">
                                            <h4>Reset All Settings</h4>
                                            <p>This will reset all settings (WiFi and AP) to their default values. The device will restart after resetting.</p>
                                            <button class="alert button" onclick="resetSettings()">Reset All Settings</button>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="grid-container">
        <div class="grid-x grid-padding-x">
            <div class="large-12 cell">
                <div class="grid-x grid-padding-y">
                    <div class="large-12 text-center cell">
                        <h3>Firmware Update</h3>
                    </div>
                </div>

                <div class="grid-x grid-padding-x">
                    <div class="large-8 medium-8 center cell">
                        <div class="callout">
                            <form id="updateForm">
                                <div class="grid-x grid-margin-x">
                                    <div class="large-12 cell">
                                        <div class="file-upload-container">
                                            <label for="firmwareFile">
                                                <span>Choose Firmware File (.bin) or Drag & Drop Here</span>
                                                <input type="file" id="firmwareFile" accept=".bin" required>
                                            </label>
                                            <div class="selected-file" id="selectedFileName"></div>
                                        </div>
                                    </div>
                                    <div class="large-12 cell">
                                        <button type="submit" class="button success upload-button" disabled>Upload Firmware</button>
                                    </div>
                                </div>
                            </form>

                            <div class="upload-progress">
                                <div class="progress-bar"></div>
                            </div>
                            <div class="upload-status"></div>

                            <!-- Placeholder for update status message -->
                            <div id="updateMessage" class="upload-status" style="display:none;"></div>
                        </div>

                        <div class="callout secondary">
                            <h5>Instructions:</h5>
                            <ol>
                                <li>Build your firmware using Arduino IDE or PlatformIO</li>
                                <li>Locate the .bin file in your build directory</li>
                                <li>Select the file using the form above or drag & drop</li>
                                <li>Click "Upload Firmware" and wait for the process to complete</li>
                                <li>The device will restart automatically after successful update</li>
                            </ol>
                            <p><strong>Warning:</strong> Do not interrupt the upload process or power off the device during update.</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // File input and button elements
        const fileInput = document.getElementById('firmwareFile');
        const uploadButton = document.querySelector('.upload-button');
        const selectedFileName = document.getElementById('selectedFileName');
        const uploadForm = document.getElementById('updateForm');
        const progressBar = document.querySelector('.progress-bar');
        const progressDiv = document.querySelector('.upload-progress');
        const statusDiv = document.querySelector('.upload-status');

        // Disable button by default
        uploadButton.disabled = true;

        // Function to show upload status
        function showStatus(message, type) {
            console.log("showStatus called with message:", message, "and type:", type);
            const updateMessageDiv = document.getElementById('updateMessage');
            updateMessageDiv.style.display = 'block';
            updateMessageDiv.textContent = message;
            updateMessageDiv.className = `upload-status ${type}`;
        }

        // Function to update progress bar
        function updateProgress(percent) {
            progressDiv.style.display = 'block';
            progressBar.style.width = `${percent}%`;
        }

        // Function to reset form
        function resetForm() {
            fileInput.value = '';
            selectedFileName.textContent = '';
            uploadButton.disabled = true;
            progressDiv.style.display = 'none';
            progressBar.style.width = '0%';
            statusDiv.style.display = 'none';
        }

        // Add reconnection logic
        async function waitForDeviceReboot() {
            showStatus('Device is rebooting, waiting for reconnection...', '');
            
            const startTime = Date.now();
            const timeout = 60000; // 60 second timeout
            
            while (Date.now() - startTime < timeout) {
                try {
                    const response = await fetch('/devicestatus', {
                        timeout: 1000
                    });
                    if (response.ok) {
                        showStatus('Device successfully rebooted!', 'success');
                        return true;
                    }
                } catch (e) {
                    console.log('Waiting for device to come back online...');
                }
                await new Promise(resolve => setTimeout(resolve, 2000)); // Check every 2 seconds
            }
            
            showStatus('Timeout waiting for device to reboot. Please refresh the page manually.', 'alert');
            return false;
        }

        // File input change handler
        fileInput.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                if (file.name.toLowerCase().endsWith('.bin')) {
                    selectedFileName.textContent = `Selected file: ${file.name}`;
                    uploadButton.disabled = false;
                } else {
                    showStatus('Please select a valid .bin file', 'alert');
                    resetForm();
                }
            } else {
                resetForm();
            }
        });

        uploadForm.addEventListener('submit', async (e) => {
            e.preventDefault();
            
            const file = fileInput.files[0];
            if (!file) {
                showStatus('Please select a firmware file', 'alert');
                return;
            }

            const formData = new FormData();
            formData.append('firmware', file);

            progressDiv.style.display = 'block';
            showStatus('Starting upload...', '');
            uploadButton.disabled = true;

            try {
                const response = await fetch('/update', {
                    method: 'POST',
                    body: formData
                });

                console.log("Response from server:", response);
                
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }

                const data = await response.text();
                console.log("Update response:", data);

                if (data.includes("Update successful")) {
                    showStatus('Firmware uploaded successfully. Device is restarting...', 'success');
                    // Wait for device to reboot
                    setTimeout(async () => {
                        await waitForDeviceReboot();
                    }, 5000); // Give device 5 seconds to start rebooting
                } else {
                    showStatus('Update failed: ' + data, 'alert');
                    uploadButton.disabled = false;
                }

            } catch (error) {
                showStatus('Error: ' + error.message, 'alert');
                console.error('Error:', error);
                uploadButton.disabled = false;
            }
        });

        // Drag and drop handlers remain the same
        const dropZone = document.querySelector('.file-upload-container label');

        ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            dropZone.addEventListener(eventName, preventDefaults, false);
        });

        function preventDefaults(e) {
            e.preventDefault();
            e.stopPropagation();
        }

        ['dragenter', 'dragover'].forEach(eventName => {
            dropZone.addEventListener(eventName, highlight, false);
        });

        ['dragleave', 'drop'].forEach(eventName => {
            dropZone.addEventListener(eventName, unhighlight, false);
        });

        function highlight(e) {
            dropZone.style.borderColor = '#2199e8';
            dropZone.style.backgroundColor = '#f0f0f0';
        }

        function unhighlight(e) {
            dropZone.style.borderColor = '#cacaca';
            dropZone.style.backgroundColor = '#f8f8f8';
        }

        dropZone.addEventListener('drop', handleDrop, false);

        function handleDrop(e) {
            const dt = e.dataTransfer;
            const file = dt.files[0];

            if (file) {
                if (file.name.toLowerCase().endsWith('.bin')) {
                    fileInput.files = dt.files;
                    selectedFileName.textContent = `Selected file: ${file.name}`;
                    uploadButton.disabled = false;
                } else {
                    showStatus('Please select a valid .bin file', 'alert');
                    resetForm();
                }
            }
        }

        function resetSettings() {
            if (confirm("Are you sure you want to reset all settings? This action cannot be undone.")) {
                fetch("/reset", { method: 'POST' })
                    .then(response => {
                        if (response.ok) {
                            alert("All settings have been reset. The device will restart.");
                        } else {
                            alert("Failed to reset settings");
                        }
                    });
            }
        }

        function validateSSID(ssid) {
            return ssid.length >= 1;
        }

        function validatePassword(password) {
            return password.length >= 8;
        }

        function validateMAC(mac) {
            return /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(mac);
        }

        function setAP() {
            const ssid = document.getElementById("apSSID").value;
            const password = document.getElementById("apPassword").value;

            if (!validateSSID(ssid)) {
                alert("AP SSID must be at least 1 character long.");
                return;
            }
            if (!validatePassword(password)) {
                alert("AP Password must be at least 8 characters long.");
                return;
            }

            const formData = new FormData();
            formData.append('ssid', ssid);
            formData.append('password', password);

            fetch("/setap", {
                method: 'POST',
                body: formData
            })
            .then(response => {
                if (response.ok) {
                    alert("AP credentials updated successfully. The device will restart.");
                } else {
                    alert("Failed to update AP credentials");
                }
            });
        }

        function setWiFi() {
            const ssid = document.getElementById("wifiSSID").value;
            const password = document.getElementById("wifiPassword").value;
            const mac = document.getElementById("macAddress").value;

            if (!validateSSID(ssid)) {
                alert("WiFi SSID must be at least 1 character long.");
                return;
            }
            if (!validatePassword(password)) {
                alert("WiFi Password must be at least 8 characters long.");
                return;
            }
            if (!validateMAC(mac)) {
                alert("Please enter a valid MAC address (format: XX:XX:XX:XX:XX:XX)");
                return;
            }

            const formData = new FormData();
            formData.append('ssid', ssid);
            formData.append('password', password);
            formData.append('mac', mac);

            fetch("/setwifi", {
                method: 'POST',
                body: formData
            })
            .then(response => {
                if (response.ok) {
                    alert("WiFi credentials updated successfully. The device will restart.");
                } else {
                    alert("Failed to update WiFi credentials");
                }
            });
        }

        function pollScanResults(countdownInterval) {
            const networkList = document.getElementById('networkList');
            const scanButton = document.getElementById('scanButton');
            const pollInterval = 500; // Poll every 500ms
            const maxScanTime = 40000; // 40 seconds timeout
            const startTime = Date.now();
            
            function poll() {
                const elapsedTime = Date.now() - startTime;
                if (elapsedTime >= maxScanTime) {
                    clearInterval(countdownInterval);
                    handleScanError('Scan timeout after 40 seconds');
                    startButtonCooldown();
                    return;
                }
                
                fetch('/scan-results')
                    .then(response => {
                        if (!response.ok) {
                            throw new Error(`HTTP error! status: ${response.status}`);
                        }
                        return response.json();
                    })
                    .then(data => {
                        if (data.status === 'scanning' && elapsedTime < maxScanTime) {
                            setTimeout(poll, pollInterval);
                            return;
                        }
                        
                        clearInterval(countdownInterval);
                        
                        if (Array.isArray(data)) {
                            displayNetworks(data);
                            startButtonCooldown();
                        } else if (data.status === 'error' || data.status === 'timeout') {
                            handleScanError(data.message);
                            startButtonCooldown();
                        } else {
                            setTimeout(poll, pollInterval);
                        }
                    })
                    .catch(error => {
                        clearInterval(countdownInterval);
                        handleScanError('Error getting scan results');
                        startButtonCooldown();
                        console.error('Error:', error);
                    });
            }
            
            setTimeout(poll, pollInterval);
        }

        function startButtonCooldown() {
            const scanButton = document.getElementById('scanButton');
            scanButton.disabled = true;
            
            let cooldown = 10; // 10 seconds cooldown
            scanButton.textContent = `Scan WiFi Networks (${cooldown}s)`;
            
            const cooldownInterval = setInterval(() => {
                cooldown--;
                if (cooldown >= 0) {
                    scanButton.textContent = `Scan WiFi Networks (${cooldown}s)`;
                } else {
                    clearInterval(cooldownInterval);
                    scanButton.disabled = false;
                    scanButton.textContent = 'Scan WiFi Networks';
                }
            }, 1000);
        }

        function startWiFiScan() {
            const networkList = document.getElementById('networkList');
            const scanButton = document.getElementById('scanButton');
            
            scanButton.disabled = true;
            networkList.style.display = 'block';
            networkList.innerHTML = '<div class="scanning">Scanning for networks... (40 seconds remaining)</div>';

            const startTime = Date.now();
            const countdownInterval = setInterval(() => {
                const elapsedTime = Date.now() - startTime;
                const remaining = Math.max(0, Math.ceil((40000 - elapsedTime) / 1000));
                
                if (remaining >= 0) {
                    networkList.innerHTML = `<div class="scanning">Scanning for networks... (${remaining} seconds remaining)</div>`;
                }
                
                if (elapsedTime >= 40000) {
                    clearInterval(countdownInterval);
                }
            }, 1000);

            fetch('/scan-wifi')
                .then(response => response.json())
                .then(data => {
                    if (data.status === 'scanning') {
                        pollScanResults(countdownInterval);
                    } else if (data.status === 'cooldown') {
                        clearInterval(countdownInterval);
                        handleCooldown(data.message);
                    } else {
                        clearInterval(countdownInterval);
                        handleScanError(data.message);
                        startButtonCooldown();
                    }
                })
                .catch(error => {
                    clearInterval(countdownInterval);
                    handleScanError('Failed to start scan');
                    startButtonCooldown();
                    console.error('Error:', error);
                });
        }

        function handleScanError(message) {
            const networkList = document.getElementById('networkList');
            networkList.innerHTML = `<div class="error">Error: ${message}</div>`;
        }

        function displayNetworks(networks) {
            const networkList = document.getElementById('networkList');
            
            if (!networks || networks.length === 0) {
                networkList.innerHTML = '<div class="no-networks">No networks found</div>';
                return;
            }

            // Sort networks by signal strength
            networks.sort((a, b) => b.rssi - a.rssi);

            networkList.innerHTML = '<div class="network-list-header">Available Networks:</div>';
            
            networks.forEach(network => {
                const networkDiv = document.createElement('div');
                networkDiv.className = 'network-item';
                
                // Signal strength indicator
                const signalStrength = Math.abs(network.rssi);
                let signalIcon = '';
                if (signalStrength > 80) signalIcon = '▂';
                else if (signalStrength > 70) signalIcon = '▂▃';
                else if (signalStrength > 60) signalIcon = '▂▃▄';
                else signalIcon = '▂▃▄▅';

                const encryptionTypes = {
                    0: 'Open',
                    1: 'WEP',
                    2: 'WPA-PSK',
                    3: 'WPA2-PSK',
                    4: 'WPA/WPA2-PSK',
                    5: 'WPA2-Enterprise'
                };

                const securityType = encryptionTypes[network.encryption] || 'Unknown';
                
                networkDiv.innerHTML = `
                    <div class="network-info">
                        <div class="network-name">
                            ${network.hidden ? '<em>Hidden Network</em>' : network.ssid}
                            <span class="signal-strength">${signalIcon}</span>
                        </div>
                        <div class="network-details">
                            <span>Ch: ${network.channel}</span>
                            <span>Signal: ${network.rssi} dBm</span>
                            <span>Security: ${securityType}</span>
                        </div>
                        <div class="network-mac">${network.bssid}</div>
                    </div>
                `;
                
                networkDiv.onclick = () => {
                    if (network.hidden) {
                        const ssid = prompt("Enter SSID for hidden network:");
                        if (ssid) {
                            selectNetwork(ssid, network.bssid);
                        }
                    } else {
                        selectNetwork(network.ssid, network.bssid);
                    }
                };
                
                networkList.appendChild(networkDiv);
            });
        }

        function selectNetwork(ssid, bssid) {
            document.getElementById('wifiSSID').value = ssid;
            document.getElementById('macAddress').value = bssid;
            document.getElementById('networkList').style.display = 'none';
        }

        function getDeviceStatus() {
            fetch("/devicestatus")
                .then(response => response.json())
                .then(status => {
                    document.getElementById("wifiName").innerText = status.ssid;
                    document.getElementById("ipAddress").innerText = status.ip;
                    document.getElementById("currentMac").innerText = status.mac;
                });
        }
    </script>
</body>
</html>