No scan wifi via web

I'm trying to make a website to scan WiFi but it always says not found, what's wrong with my code?

No WiFi credentials found, starting AP Mode
AP Created Successfully
AP Mode started
AP IP address: 192.168.4.1
AP SSID: RC_Car_AP
AP Password: 12345678

=== WiFi Status ===
Mode: 2
Status: 7
AP SSID: RC_Car_AP
AP IP: 192.168.4.1
System ready!
Free heap: 43232 bytes

=== Starting WiFi Scan ===
Current WiFi Mode: 2
Stored last WiFi mode: 2
Switching from AP to AP_STA mode
Current WiFi Mode after change: 3
Previous scan results cleared
Starting async scan...
Scan start result: -1
Scan started successfully

=== Checking Scan Results ===
Scan status: 0
Elapsed time: 739 ms
Found 0 networks
Response length: 2
Scan complete, sending results

full code

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <MPU6050.h>
#include <ArduinoJson.h>

// WiFi Manager settings
char apSSID[33] = "RC_Car_AP";     // 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;
AsyncWebServer server(80);
WiFiUDP udp;
MPU6050 mpu;
int failedWiFiConnections = 0;
bool isAPMode = false;

// WiFi Scanning variables
bool isScanning = false;
unsigned long scanStartTime = 0;
unsigned long lastScanRequest = 0;
const unsigned long SCAN_TIMEOUT = 40000;        // 40 seconds timeout for scanning
const unsigned long SCAN_COOLDOWN = 10000;       // 10 seconds cooldown between scans

volatile bool needsWiFiRestore = false;
volatile WiFiMode_t lastWiFiMode;

void resetSettings() {
    routerSSID = "";
    routerPassword = "";
    strcpy(expectedMAC, "");
    saveWiFiCredentials();

    strncpy(apSSID, "RC_Car_AP", 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() {
    WiFi.mode(WIFI_AP);
    delay(100);
    
    if(WiFi.softAP(apSSID, apPassword)) {
        Serial.println("AP Created Successfully");
    } else {
        Serial.println("AP Creation Failed!");
        // Coba dengan pengaturan default
        if(WiFi.softAP("RC_Car_AP", "12345678")) {
            Serial.println("AP Created with default settings");
            strcpy(apSSID, "RC_Car_AP");
            strcpy(apPassword, "12345678");
        }
    }
    isAPMode = true;
    
    delay(500);
    IPAddress myIP = WiFi.softAPIP();
    Serial.println("AP Mode started");
    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...");
    WiFi.mode(WIFI_STA);
    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("IP Address: ");
            Serial.println(WiFi.localIP());
            isAPMode = false;
            return true;
        } else {
            Serial.println("MAC address mismatch!");
            WiFi.disconnect();
            return false;
        }
    }
    
    Serial.println("\nFailed to connect to WiFi");
    failedWiFiConnections++;
    return false;
}

// Update fungsi scanNetworks dengan logging tambahan
void scanNetworks(AsyncWebServerRequest *request) {
    unsigned long currentMillis = millis();
    
    Serial.println("\n=== Starting WiFi Scan ===");
    Serial.printf("Current WiFi Mode: %d\n", WiFi.getMode());
    
    if (currentMillis - lastScanRequest < SCAN_COOLDOWN) {
        Serial.println("Scan rejected: Still in cooldown period");
        request->send(429, "application/json", "{\"status\":\"cooldown\",\"message\":\"Please wait before starting another scan\"}");
        return;
    }
    
    if (isScanning) {
        Serial.println("Scan rejected: Another scan is already in progress");
        request->send(429, "application/json", "{\"status\":\"busy\",\"message\":\"A scan is already in progress\"}");
        return;
    }

    // Store current WiFi mode
    lastWiFiMode = WiFi.getMode();
    Serial.printf("Stored last WiFi mode: %d\n", lastWiFiMode);
    
    // Set appropriate mode for scanning
    if (WiFi.getMode() == WIFI_AP) {
        Serial.println("Switching from AP to AP_STA mode");
        WiFi.mode(WIFI_AP_STA);
    } else if (WiFi.getMode() != WIFI_STA) {
        Serial.println("Switching to STA mode");
        WiFi.mode(WIFI_STA);
    }
    
    delay(100); // Allow mode change to settle
    Serial.printf("Current WiFi Mode after change: %d\n", WiFi.getMode());
    
    // Clear any previous scan results
    WiFi.scanDelete();
    Serial.println("Previous scan results cleared");
    
    // Start async scan
    Serial.println("Starting async scan...");
    int result = WiFi.scanNetworks(true,true);
    Serial.printf("Scan start result: %d\n", result);
    
    if (result == WIFI_SCAN_FAILED) {
        Serial.println("Failed to start scan!");
        WiFi.mode(lastWiFiMode);
        request->send(500, "application/json", "{\"status\":\"error\",\"message\":\"Failed to start scan\"}");
        return;
    }

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

// Update fungsi getScanResults dengan logging tambahan
void getScanResults(AsyncWebServerRequest *request) {
    Serial.println("\n=== Checking 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;
    
    Serial.printf("Scan status: %d\n", scanResult);
    Serial.printf("Elapsed time: %lu ms\n", elapsedTime);

    // Check for timeout
    if (elapsedTime > SCAN_TIMEOUT) {
        Serial.println("Scan timed out!");
        isScanning = false;
        WiFi.scanDelete();
        needsWiFiRestore = true;
        request->send(504, "application/json", "{\"status\":\"timeout\",\"message\":\"Scan timed out\"}");
        return;
    }
    
    // Still scanning
    if (scanResult == WIFI_SCAN_RUNNING) {
        Serial.println("Scan still in progress...");
        request->send(202, "application/json", "{\"status\":\"scanning\",\"message\":\"Scan in progress\"}");
        return;
    }
    
    // Scan failed
    if (scanResult == WIFI_SCAN_FAILED) {
        Serial.println("Scan failed!");
        isScanning = false;
        needsWiFiRestore = true;
        request->send(500, "application/json", "{\"status\":\"error\",\"message\":\"Scan failed\"}");
        return;
    }

    // Process results
    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();
            String ssid = WiFi.SSID(i);
            String bssid = WiFi.BSSIDstr(i);
            int32_t rssi = WiFi.RSSI(i);
            int32_t channel = WiFi.channel(i);
            
            network["ssid"] = ssid;
            network["bssid"] = bssid;
            network["rssi"] = rssi;
            network["channel"] = channel;
            network["encryption"] = WiFi.encryptionType(i);
            network["hidden"] = ssid.length() == 0;
            
            Serial.printf("Network %d:\n", i);
            Serial.printf("  SSID: %s\n", ssid.c_str());
            Serial.printf("  BSSID: %s\n", bssid.c_str());
            Serial.printf("  RSSI: %d\n", rssi);
            Serial.printf("  Channel: %d\n", channel);
            
            yield();
        }
        
        String response;
        serializeJson(doc, response);
        
        Serial.printf("Response length: %d\n", response.length());
        
        WiFi.scanDelete();
        isScanning = false;
        needsWiFiRestore = true;
        
        Serial.println("Scan complete, sending results");
        request->send(200, "application/json", response);
    }
}

// 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());
    }
}

// Add these helper functions for monitoring heap
void printHeapInfo(const char* message) {
    Serial.printf("%s - Free Heap: %d, Largest Free Block: %d\n",
        message,
        ESP.getFreeHeap(),
        ESP.getMaxFreeBlockSize()
    );
}

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) {
        DynamicJsonDocument doc(256);
        doc["mode"] = isAPMode ? "AP" : "Station";
        doc["ssid"] = isAPMode ? String(apSSID) : WiFi.SSID();
        doc["ip"] = isAPMode ? WiFi.softAPIP().toString() : WiFi.localIP().toString();
        doc["mac"] = WiFi.BSSIDstr();
        doc["rssi"] = isAPMode ? 0 : WiFi.RSSI();
        doc["freeHeap"] = ESP.getFreeHeap();
        
        String response;
        serializeJson(doc, 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();
    });
}

void restoreWiFiState() {
    if (needsWiFiRestore) {
        if (isAPMode) {
            WiFi.mode(WIFI_AP);
            WiFi.softAP(apSSID, apPassword);
        } else if (routerSSID.length() > 0) {
            WiFi.mode(WIFI_STA);
            WiFi.begin(routerSSID.c_str(), routerPassword.c_str());
        }
        needsWiFiRestore = false;
    }
}

void sendUDPPacket(const char* command) {
    if (!isAPMode) {
        udp.beginPacket(serverIP, serverPort);
        udp.write(command);
        udp.endPacket();
    }
}

void setup() {
    Serial.begin(115200);
    Serial.println("\n=== Starting Setup ===");
    
    if (!SPIFFS.begin()) {
        Serial.println("Error mounting SPIFFS");
        // Gunakan default values jika SPIFFS gagal
        strcpy(apSSID, "RC_Car_AP");
        strcpy(apPassword, "12345678");
    }
    Serial.println("SPIFFS mounted successfully");
    
    loadWiFiCredentials();
    loadAPSettings();

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

    // Try to connect to WiFi if credentials exist
    if (routerSSID.length() > 0) {
        Serial.println("WiFi credentials found, attempting to connect...");
        if (!connectToWiFi()) {
            Serial.println("WiFi connection failed, starting AP Mode");
            startAPMode();
        }
    } else {
        Serial.println("No WiFi credentials found, starting AP Mode");
        startAPMode();
    }
    
    setupServerRoutes();
    server.begin();
    
    printWiFiStatus();
    
    Serial.println("System ready!");
    Serial.printf("Free heap: %d bytes\n", ESP.getFreeHeap());
}

void loop() {
    unsigned long currentMillis = millis();
    
    // Restore WiFi state if needed
    if (needsWiFiRestore) {
        restoreWiFiState();
    }
    
    // Existing WiFi connection check
    if (!isAPMode && currentMillis - lastWiFiCheckMillis >= wifiCheckInterval) {
        lastWiFiCheckMillis = currentMillis;
        if (WiFi.status() != WL_CONNECTED) {
            Serial.println("WiFi disconnected. Attempting to reconnect...");
            if (!connectToWiFi()) {
                startAPMode();
            }
        }
    }
    
    // MPU6050 data handling (unchanged)
    if (!isAPMode) {
        static unsigned long lastSendTime = 0;
        const unsigned long sendInterval = 20;
        
        if (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>Device Settings</title>
    <link rel="stylesheet" href="assets/css/foundation.css">
    <style>
        .network-list {
            max-height: 200px;
            overflow-y: auto;
            border: 1px solid #cacaca;
            padding: 10px;
            margin-bottom: 1rem;
        }
        .network-item {
            padding: 5px;
            cursor: pointer;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .network-item:hover {
            background-color: #e6e6e6;
        }
        .scanning {
            text-align: center;
            padding: 10px;
            font-style: italic;
        }
        .mac-address {
            font-family: monospace;
            background: #f0f0f0;
            padding: 2px 4px;
            border-radius: 3px;
        }
    </style>
</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>Device Settings</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 class="large-12 medium-12 small-12 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>
                                            </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 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" class="mac-address"></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>

    <script>
        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;
                });
        }

        function startAutoRefresh(interval) {
            getDeviceStatus();
            setInterval(getDeviceStatus, interval);
        }

        window.onload = function() {
            startAutoRefresh(5000);
        };
    </script>
</body>
</html>

I've done the same task in my library using asynchronous mode:
the very first request will not have any results so it trigger a new request from browser.

In the meantime the ESP32 can complete the scanning without blocking the rest of code, so when the next request will arrive, webserver can serve a complete json list of SSIDs found.

1 Like

I want to make my own, does that mean I have to use asynchronous?

seems like you've written a lot of code already without being able to perform it's essential function.

Scanning of WiFi onESP32 explains how. wy don't you make that work and then worry about storing credientials, ...

I don't see the call to scan.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.