Sim800l no detection signal

What's wrong with the program that the SIM card is not detected in the SIM800L?

=== MODEM STATUS UPDATE ===
Checking modem parameters...

Current Modem Status:
- Present SIM: No
- Signal Strength: 0
- Network Mode: Unknown
- APN Status:
- Network Registered: No
========================

=== ERROR CONDITION ===
✗ SIM card not detected!
Skipping AC line status check
=====================

=== SIM STATUS CHECK ===
Previous state: Not Present
Current state: Not Present
========================
#include <ESP8266WebServer.h>
#include <LittleFS.h>
#include <ArduinoJson.h>
#include <SoftwareSerial.h>

ESP8266WebServer server(80);

#define OCTOCOUPLER_PIN 2
#define SIM800L_RX 3     
#define SIM800L_TX 4     

SoftwareSerial sim800l(SIM800L_RX, SIM800L_TX);
String indexHtml;
bool isBusy = false;

struct Config {
    String phoneNumber;
    String networkMode;  // New field for network mode
    String apn;
    String apnUsername;
    String apnPassword;
    String smsConnected;
    String smsDisconnected;
    bool smsConnectedEnabled;
    bool smsDisconnectedEnabled;
} config;

bool currentACState = false;
bool previousACState = false;
bool hasNotifiedLow = false;
bool hasNotifiedHigh = false;
bool isSimPresent = false;
bool previousSimState = false;
int signalStrength = 0;

unsigned long lastSimCheckTime = 0;
unsigned long lastModemUpdate = 0;
const unsigned long SIM_CHECK_INTERVAL = 5000;
const unsigned long MODEM_UPDATE_INTERVAL = 30000;

struct ModemStatus {
    bool simPresent;
    int signalStrength;
    String networkMode;
    String apnStatus;
    bool isRegistered;
} modemStatus;

void setupWiFi() {
    Serial.println("\n=== WIFI SETUP ===");
    Serial.println("Setting up WiFi Access Point...");
    WiFi.mode(WIFI_AP);
    
    String ssid = "ESP-Config-" + String(ESP.getChipId(), HEX);
    Serial.printf("Attempting to create AP with SSID: %s\n", ssid.c_str());
    
    if (WiFi.softAP(ssid.c_str(), "password123")) {
        Serial.println("✓ AP Created successfully");
        Serial.printf("SSID: %s\n", ssid.c_str());
        Serial.println("Password: password123");
        Serial.printf("IP Address: %s\n", WiFi.softAPIP().toString().c_str());
        Serial.printf("MAC Address: %s\n", WiFi.softAPmacAddress().c_str());
        Serial.printf("Channel: %d\n", WiFi.channel());
        Serial.printf("Current AP Connections: %d\n", WiFi.softAPgetStationNum());
    } else {
        Serial.println("✗ AP Creation failed!");
        Serial.println("Possible reasons:");
        Serial.println("- Invalid SSID length");
        Serial.println("- Insufficient memory");
        Serial.println("- Hardware initialization failure");
    }
    Serial.println("=================\n");
}

void setupWebServer() {
    Serial.println("\n=== WEB SERVER SETUP ===");
    
    if (!LittleFS.begin()) {
        Serial.println("✗ Failed to mount LittleFS");
        Serial.println("Possible reasons:");
        Serial.println("- File system not formatted");
        Serial.println("- Bad flash connection");
        Serial.println("- Incorrect partition scheme");
        return;
    }
    Serial.println("✓ LittleFS mounted successfully");
    
    Serial.println("Loading index.html from LittleFS...");
    File file = LittleFS.open("/index.html", "r");
    if (!file) {
        Serial.println("✗ Failed to open index.html");
        Serial.println("Ensure index.html is uploaded to LittleFS");
        return;
    }
    
    indexHtml = file.readString();
    file.close();
    Serial.printf("✓ Loaded index.html (size: %d bytes)\n", indexHtml.length());

    server.on("/", HTTP_GET, handleRoot);
    server.on("/config", HTTP_GET, handleGetConfig);
    server.on("/config", HTTP_POST, handleSetConfig);
    server.on("/modem-status", HTTP_GET, handleModemStatus);

    server.begin();
    Serial.println("✓ HTTP server started on port 80");
    Serial.println("========================\n");
}

bool loadConfiguration() {
    if (!LittleFS.begin()) {
        Serial.println("Failed to mount LittleFS, formatting...");
        LittleFS.format();
        if (!LittleFS.begin()) {
            Serial.println("LittleFS still failed after formatting");
            return false;
        }
    }
    
    File configFile = LittleFS.open("/config.json", "r");
    if (!configFile) {
        Serial.println("Config file not found, creating default config...");
        File newFile = LittleFS.open("/config.json", "w");
        if (newFile) {
            StaticJsonDocument<512> doc;
            doc["phoneNumber"] = "";
            doc["networkMode"] = "auto";
            doc["apn"] = "internet";
            doc["apnUsername"] = "";
            doc["apnPassword"] = "";
            doc["smsConnected"] = "AC Line Connected";
            doc["smsDisconnected"] = "AC Line Disconnected";
            doc["smsConnectedEnabled"] = true;
            doc["smsDisconnectedEnabled"] = true;
            serializeJson(doc, newFile);
            newFile.close();
        }
        return false;
    }
    
    StaticJsonDocument<512> doc;
    DeserializationError error = deserializeJson(doc, configFile);
    configFile.close();
    
    if (error) {
        Serial.println("Failed to parse config file");
        return false;
    }
    
    config.phoneNumber = doc["phoneNumber"].as<String>();
    config.networkMode = doc["networkMode"].as<String>();
    config.apn = doc["apn"].as<String>();
    config.apnUsername = doc["apnUsername"].as<String>();
    config.apnPassword = doc["apnPassword"].as<String>();
    config.smsConnected = doc["smsConnected"].as<String>();
    config.smsDisconnected = doc["smsDisconnected"].as<String>();
    config.smsConnectedEnabled = doc["smsConnectedEnabled"].as<bool>();
    config.smsDisconnectedEnabled = doc["smsDisconnectedEnabled"].as<bool>();
    
    return true;
}

bool saveConfiguration() {
    StaticJsonDocument<512> doc;
    
    doc["phoneNumber"] = config.phoneNumber;
    doc["networkMode"] = config.networkMode;  // Add network mode
    doc["apn"] = config.apn;
    doc["apnUsername"] = config.apnUsername;
    doc["apnPassword"] = config.apnPassword;
    doc["smsConnected"] = config.smsConnected;
    doc["smsDisconnected"] = config.smsDisconnected;
    doc["smsConnectedEnabled"] = config.smsConnectedEnabled;
    doc["smsDisconnectedEnabled"] = config.smsDisconnectedEnabled;

    File configFile = LittleFS.open("/config.json", "w");
    if (!configFile) {
        Serial.println("Failed to open config file for writing");
        return false;
    }

    serializeJson(doc, configFile);
    configFile.close();
    return true;
}

void handleRoot() {
    Serial.println("\n=== HANDLING ROOT REQUEST ===");
    Serial.printf("Client IP: %s\n", server.client().remoteIP().toString().c_str());
    Serial.printf("User Agent: %s\n", server.header("User-Agent").c_str());
    
    server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
    server.sendHeader("Pragma", "no-cache");
    server.sendHeader("Expires", "-1");
    server.send(200, "text/html", indexHtml);
    
    Serial.println("✓ Root page served successfully");
    Serial.println("========================\n");
}

void handleGetConfig() {
    Serial.println("\n=== HANDLING CONFIG GET REQUEST ===");
    Serial.printf("Client IP: %s\n", server.client().remoteIP().toString().c_str());
    
    StaticJsonDocument<512> doc;
    doc["phoneNumber"] = config.phoneNumber;
    doc["networkMode"] = config.networkMode;  // Menambahkan networkMode
    doc["apn"] = config.apn;
    doc["apnUsername"] = config.apnUsername;
    doc["apnPassword"] = config.apnPassword;
    doc["smsConnected"] = config.smsConnected;
    doc["smsDisconnected"] = config.smsDisconnected;
    doc["smsConnectedEnabled"] = config.smsConnectedEnabled;  // Menambahkan smsConnectedEnabled
    doc["smsDisconnectedEnabled"] = config.smsDisconnectedEnabled;  // Menambahkan smsDisconnectedEnabled

    String response;
    serializeJson(doc, response);
    
    Serial.println("Current Configuration:");
    Serial.printf("Phone Number: %s\n", config.phoneNumber.c_str());
    Serial.printf("Network Mode: %s\n", config.networkMode.c_str());
    Serial.printf("APN: %s\n", config.apn.c_str());
    Serial.printf("APN Username: %s\n", config.apnUsername.c_str());
    Serial.printf("SMS Connected Message: %s\n", config.smsConnected.c_str());
    Serial.printf("SMS Connected Enabled: %s\n", config.smsConnectedEnabled ? "Yes" : "No");
    Serial.printf("SMS Disconnected Message: %s\n", config.smsDisconnected.c_str());
    Serial.printf("SMS Disconnected Enabled: %s\n", config.smsDisconnectedEnabled ? "Yes" : "No");
    
    server.send(200, "application/json", response);
    Serial.println("✓ Configuration sent successfully");
    Serial.println("========================\n");
}

void handleSetConfig() {
    Serial.println("\n=== HANDLING CONFIG POST REQUEST ===");
    Serial.printf("Client IP: %s\n", server.client().remoteIP().toString().c_str());
    
    if (!server.hasArg("plain")) {
        Serial.println("✗ No data received");
        server.send(400, "text/plain", "No data received");
        return;
    }

    String data = server.arg("plain");
    Serial.printf("Received data: %s\n", data.c_str());

    StaticJsonDocument<512> doc;
    DeserializationError error = deserializeJson(doc, data);
    
    if (error) {
        Serial.printf("✗ JSON parsing failed: %s\n", error.c_str());
        server.send(400, "text/plain", "Invalid JSON");
        return;
    }

    Serial.println("Updating configuration...");
    
    // Store old values for logging
    String oldNetworkMode = config.networkMode;
    bool oldConnectedEnabled = config.smsConnectedEnabled;
    bool oldDisconnectedEnabled = config.smsDisconnectedEnabled;
    
    config.phoneNumber = doc["phoneNumber"] | config.phoneNumber;
    config.networkMode = doc["networkMode"] | config.networkMode;
    config.apn = doc["apn"] | config.apn;
    config.apnUsername = doc["apnUsername"] | config.apnUsername;
    config.apnPassword = doc["apnPassword"] | config.apnPassword;
    config.smsConnected = doc["smsConnected"] | config.smsConnected;
    config.smsDisconnected = doc["smsDisconnected"] | config.smsDisconnected;
    config.smsConnectedEnabled = doc["smsConnectedEnabled"] | config.smsConnectedEnabled;
    config.smsDisconnectedEnabled = doc["smsDisconnectedEnabled"] | config.smsDisconnectedEnabled;

    // Log changes in network mode
    if (oldNetworkMode != config.networkMode) {
        Serial.printf("Network mode changed: %s -> %s\n", 
            oldNetworkMode.c_str(),
            config.networkMode.c_str());
            
        // Reinitialize modem if network mode changed
        if (modemStatus.simPresent) {
            Serial.println("Reinitializing modem with new network mode...");
            initializeSIM800L();
        }
    }

    if (saveConfiguration()) {
        Serial.println("✓ Configuration saved successfully");
        server.send(200, "text/plain", "Configuration saved");
    } else {
        Serial.println("✗ Failed to save configuration");
        server.send(500, "text/plain", "Failed to save configuration");
    }
    Serial.println("========================\n");
}

void handleModemStatus() {
    StaticJsonDocument<256> doc;
    doc["simPresent"] = modemStatus.simPresent;
    doc["signalStrength"] = map(modemStatus.signalStrength, 0, 31, 0, 100); // Convert signal strength to percentage
    doc["networkMode"] = modemStatus.networkMode;
    doc["isRegistered"] = modemStatus.isRegistered;

    String response;
    serializeJson(doc, response);
    server.send(200, "application/json", response);
}

bool sendATCommand(const char* command, const char* expectedResponse, unsigned long timeout) {
    sim800l.flush();  // Hapus buffer sebelum kirim command
    sim800l.println(command);
    unsigned long startTime = millis();
    String response = "";
    
    while (millis() - startTime < timeout) {
        while (sim800l.available()) {
            char c = sim800l.read();
            response += c;
        }
        if (response.indexOf(expectedResponse) >= 0) {
            Serial.println("AT Response: " + response);
            return true;
        }
    }
    Serial.println("AT Command Failed: " + String(command));
    Serial.println("Response: " + response);
    return false;
}

bool setNetworkMode(const String& mode) {
    String command;
    sendATCommand("AT+CFUN=1", "OK", 2000); // Pastikan modem aktif
    delay(2000);
    
    if (mode == "2g") {
        command = "AT+CNMP=13";  // GSM only
    } else if (mode == "3g") {
        command = "AT+CNMP=14";  // WCDMA only
    } else if (mode == "4g") {
        command = "AT+CNMP=38";  // LTE only
    } else {
        command = "AT+CNMP=2";   // Automatic
    }
    
    return sendATCommand(command.c_str(), "OK", 5000);
}

bool configureAPN() {
    sendATCommand("AT+SAPBR=0,1", "OK", 5000);
    delay(1000);
    sendATCommand(("AT+CGDCONT=1,\"IP\",\"" + config.apn + "\"").c_str(), "OK", 5000);
    delay(1000);
    sendATCommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 1000);
    delay(500);
    sendATCommand(("AT+SAPBR=3,1,\"APN\",\"" + config.apn + "\"").c_str(), "OK", 1000);
    delay(500);
    
    if (config.apnUsername.length() > 0) {
        sendATCommand(("AT+SAPBR=3,1,\"USER\",\"" + config.apnUsername + "\"").c_str(), "OK", 1000);
        delay(500);
    }
    if (config.apnPassword.length() > 0) {
        sendATCommand(("AT+SAPBR=3,1,\"PWD\",\"" + config.apnPassword + "\"").c_str(), "OK", 1000);
        delay(500);
    }
    return sendATCommand("AT+SAPBR=1,1", "OK", 10000);
}

bool waitForNetworkRegistration() {
    unsigned long startTime = millis();
    while (millis() - startTime < 60000) {
        if (checkNetworkRegistration()) {
            return true;
        }
        delay(1000);
    }
    return false;
}

bool initializeSIM800L() {
    if (isBusy) return false;
    isBusy = true;
    
    delay(1000);
    Serial.println("Initializing SIM800L...");
    
    sim800l.println("AT+CFUN=1,1");
    delay(10000);
    
    bool success = sendATCommand("AT", "OK", 3000) &&
                  sendATCommand("AT+CMGF=1", "OK", 1000) &&
                  checkSimPresent() &&
                  setNetworkMode(config.networkMode) &&  // Add network mode configuration
                  waitForNetworkRegistration() &&
                  configureAPN();
    
    if (success) {
        Serial.println("SIM800L initialized successfully!");
    }
    
    isBusy = false;
    return success;
}

void updateModemStatus() {
    if (isBusy) {
        Serial.println("System busy, skipping modem status update");
        return;
    }
    
    Serial.println("\n=== MODEM STATUS UPDATE ===");
    Serial.println("Checking modem parameters...");
    
    isBusy = true;
    
    // Previous states
    bool prevSimPresent = modemStatus.simPresent;
    int prevSignal = modemStatus.signalStrength;
    String prevNetwork = modemStatus.networkMode;
    bool prevRegistered = modemStatus.isRegistered;
    
    // Update states
    modemStatus.simPresent = checkSimPresent();
    modemStatus.signalStrength = getSignalStrength();
    modemStatus.networkMode = getNetworkMode();
    modemStatus.apnStatus = getAPNStatus();
    modemStatus.isRegistered = checkNetworkRegistration();
    
    // Log changes
    if (prevSimPresent != modemStatus.simPresent) {
        Serial.printf("! SIM Status changed: %s -> %s\n", 
            prevSimPresent ? "Present" : "Not Present",
            modemStatus.simPresent ? "Present" : "Not Present");
    }
    
    if (prevSignal != modemStatus.signalStrength) {
        Serial.printf("! Signal Strength changed: %d -> %d\n", 
            prevSignal, modemStatus.signalStrength);
    }
    
    if (prevNetwork != modemStatus.networkMode) {
        Serial.printf("! Network Mode changed: %s -> %s\n", 
            prevNetwork.c_str(), modemStatus.networkMode.c_str());
    }
    
    if (prevRegistered != modemStatus.isRegistered) {
        Serial.printf("! Registration Status changed: %s -> %s\n",
            prevRegistered ? "Registered" : "Not Registered",
            modemStatus.isRegistered ? "Registered" : "Not Registered");
    }
    
    // Current Status Summary
    Serial.println("\nCurrent Modem Status:");
    Serial.printf("- SIM Present: %s\n", modemStatus.simPresent ? "Yes" : "No");
    Serial.printf("- Signal Strength: %d\n", modemStatus.signalStrength);
    Serial.printf("- Network Mode: %s\n", modemStatus.networkMode.c_str());
    Serial.printf("- APN Status: %s\n", modemStatus.apnStatus.c_str());
    Serial.printf("- Network Registered: %s\n", modemStatus.isRegistered ? "Yes" : "No");
    
    isBusy = false;
    Serial.println("========================\n");
}

void checkAndHandleSimChange() {
    if (isBusy) {
        Serial.println("System busy, skipping SIM check");
        return;
    }
    
    bool currentSimState = checkSimPresent();
    Serial.printf("\n=== SIM STATUS CHECK ===\n");
    Serial.printf("Previous state: %s\n", previousSimState ? "Present" : "Not Present");
    Serial.printf("Current state: %s\n", currentSimState ? "Present" : "Not Present");
    
    if (currentSimState != previousSimState) {
        Serial.println("! SIM state changed !");
        
        if (currentSimState) {
            Serial.println("✓ SIM card inserted");
            
            if (initializeSIM800L()) {
                Serial.println("Sending system restart notification...");
                if (sendSMSNotification("System running with new SIM card")) {
                    Serial.println("✓ Restart notification sent");
                } else {
                    Serial.println("✗ Failed to send restart notification");
                }
                hasNotifiedLow = false;
                hasNotifiedHigh = false;
            }
        } else {
            Serial.println("✗ SIM card removed");
        }
        previousSimState = currentSimState;
    }
    Serial.println("========================\n");
}

bool checkSimPresent() {
    sim800l.println("AT+CSMINS?");
    String response = sim800l.readString();
    return response.indexOf("+CSMINS: 0,1") >= 0;
}

int getSignalStrength() {
    sim800l.println("AT+CSQ");
    String response = sim800l.readString();
    if (response.indexOf("+CSQ:") >= 0) {
        int start = response.indexOf(" ") + 1;
        int end = response.indexOf(",");
        return response.substring(start, end).toInt();
    }
    return 0;
}

String getNetworkMode() {
    sim800l.println("AT+COPS?");
    String response = sim800l.readString();
    if (response.indexOf("+COPS:") >= 0) {
        return response.substring(response.indexOf("\"") + 1, response.lastIndexOf("\""));
    }
    return "Unknown";
}

String getAPNStatus() {
    sim800l.println("AT+CGACT?");
    return sim800l.readString();
}

bool checkNetworkRegistration() {
    sim800l.println("AT+CREG?");
    String response = sim800l.readString();
    return (response.indexOf("+CREG: 0,1") >= 0) || (response.indexOf("+CREG: 0,5") >= 0);
}

void processACLineStatus() {
    if (isBusy) {
        Serial.println("System busy, skipping AC line status check");
        return;
    }

    currentACState = digitalRead(OCTOCOUPLER_PIN);
    
    Serial.println("\n=== AC LINE STATUS ===");
    Serial.printf("Previous State: %s\n", previousACState ? "HIGH" : "LOW");
    Serial.printf("Current State: %s\n", currentACState ? "HIGH" : "LOW");
    
    // Check enabled status before sending notifications
    if (currentACState == HIGH && !hasNotifiedHigh && config.smsConnectedEnabled) {
        Serial.println("! Detected HIGH state change, sending notification...");
        if (sendSMSNotification(config.smsConnected.c_str())) {
            hasNotifiedHigh = true;
            hasNotifiedLow = false;
            Serial.println("✓ HIGH state notification sent");
        }
    }
    else if (currentACState == LOW && !hasNotifiedLow && config.smsDisconnectedEnabled) {
        Serial.println("! Detected LOW state change, sending notification...");
        if (sendSMSNotification(config.smsDisconnected.c_str())) {
            hasNotifiedLow = true;
            hasNotifiedHigh = false;
            Serial.println("✓ LOW state notification sent");
        }
    }

    previousACState = currentACState;
}

bool sendSMSNotification(const char* message) {
    Serial.println("\n=== SENDING SMS NOTIFICATION ===");
    
    if (!modemStatus.simPresent || !modemStatus.isRegistered) {
        Serial.println("✗ Cannot send SMS:");
        if (!modemStatus.simPresent) Serial.println("  - No SIM card present");
        if (!modemStatus.isRegistered) Serial.println("  - Not registered to network");
        return false;
    }
    
    Serial.printf("Sending SMS to: %s\n", config.phoneNumber.c_str());
    Serial.printf("Message: %s\n", message);
    
    sim800l.println("AT+CMGF=1");
    delay(1000);
    
    sim800l.print("AT+CMGS=\"");
    sim800l.print(config.phoneNumber);
    sim800l.println("\"");
    delay(1000);
    
    sim800l.println(message);
    delay(100);
    sim800l.write(26);
    delay(1000);
    
    // Check for "OK" response
    String response = sim800l.readString();
    bool success = response.indexOf("OK") >= 0;
    
    if (success) {
        Serial.println("✓ SMS sent successfully");
    } else {
        Serial.println("✗ Failed to send SMS");
        Serial.printf("Response: %s\n", response.c_str());
    }
    
    Serial.println("========================\n");
    return success;
}

void setup() {
    Serial.begin(9600);
    Serial.println("\n\n====================================");
    Serial.println("Starting ESP8266 Configuration Portal");
    Serial.println("====================================");
    
    // System Information
    Serial.println("\n=== SYSTEM INITIALIZATION ===");
    Serial.printf("Firmware Version: 1.0.0\n");
    Serial.printf("Chip ID: %s\n", String(ESP.getChipId(), HEX).c_str());
    Serial.printf("Flash Size: %dMB\n", ESP.getFlashChipSize() / 1024 / 1024);
    Serial.printf("CPU Frequency: %dMHz\n", ESP.getCpuFreqMHz());
    Serial.printf("Free Heap: %d bytes\n", ESP.getFreeHeap());
    
    // Initialize SIM800L Serial
    Serial.println("\nInitializing SIM800L serial communication...");
    sim800l.begin(9600);
    Serial.println("✓ SIM800L serial initialized");
    
    // Initialize GPIO
    Serial.println("\nInitializing GPIO pins...");
    pinMode(OCTOCOUPLER_PIN, INPUT);
    Serial.printf("✓ Pin %d configured as INPUT for optocoupler\n", OCTOCOUPLER_PIN);
    Serial.printf("✓ Pin %d configured for SIM800L RX\n", SIM800L_RX);
    Serial.printf("✓ Pin %d configured for SIM800L TX\n", SIM800L_TX);
    
    // Initialize File System
    Serial.println("\nMounting file system...");
    if (LittleFS.begin()) {
        FSInfo fs_info;
        LittleFS.info(fs_info);
        Serial.println("✓ LittleFS mounted successfully");
        Serial.printf("Total space: %d bytes\n", fs_info.totalBytes);
        Serial.printf("Used space: %d bytes\n", fs_info.usedBytes);
    } else {
        Serial.println("✗ LittleFS mount failed!");
        Serial.println("System will continue but configuration storage will be unavailable");
    }

    loadConfiguration();

    // Setup WiFi
    setupWiFi();
    
    // Setup Web Server
    setupWebServer();
    
    // Initialize SIM Card
    Serial.println("\nChecking initial SIM card state...");
    previousSimState = checkSimPresent();
    Serial.printf("Initial SIM state: %s\n", previousSimState ? "Present" : "Not Present");
    
    if (previousSimState) {
        Serial.println("Performing initial SIM800L setup...");
        if (initializeSIM800L()) {
            Serial.println("✓ SIM800L initialized successfully");
        } else {
            Serial.println("✗ SIM800L initialization failed!");
            Serial.println("Will retry in main loop");
        }
    }
    
    // Log initial memory state
    Serial.println("\n=== SETUP COMPLETION STATUS ===");
    Serial.printf("Free Heap after setup: %d bytes\n", ESP.getFreeHeap());
    Serial.printf("Heap Fragmentation: %d%%\n", ESP.getHeapFragmentation());
    Serial.println("Setup completed!");
    Serial.println("====================================\n");
}

void loop() {
    unsigned long currentMillis = millis();
    static unsigned long lastHeapLog = 0;
    const unsigned long HEAP_LOG_INTERVAL = 300000; // Log heap every 5 minutes
    
    // Handle Web Server Clients
    server.handleClient();
    
    // Periodic System Status Logging
    if (currentMillis - lastHeapLog >= HEAP_LOG_INTERVAL) {
        Serial.println("\n=== PERIODIC SYSTEM STATUS ===");
        Serial.printf("Uptime: %lu seconds\n", currentMillis / 1000);
        Serial.printf("Free Heap: %d bytes\n", ESP.getFreeHeap());
        Serial.printf("Heap Fragmentation: %d%%\n", ESP.getHeapFragmentation());
        Serial.printf("WiFi Stations Connected: %d\n", WiFi.softAPgetStationNum());
        lastHeapLog = currentMillis;
        Serial.println("============================\n");
    }
    
    // Check SIM Card Status
    if (currentMillis - lastSimCheckTime >= SIM_CHECK_INTERVAL) {
        checkAndHandleSimChange();
        lastSimCheckTime = currentMillis;
    }
    
    // Update Modem Status
    if (currentMillis - lastModemUpdate >= MODEM_UPDATE_INTERVAL) {
        updateModemStatus();
        lastModemUpdate = currentMillis;
    }
    
    // Process AC Line Status with Error Checking
    if (!modemStatus.simPresent) {
        Serial.println("\n=== ERROR CONDITION ===");
        Serial.println("✗ SIM card tidak terdeteksi!");
        Serial.println("Skipping AC line status check");
        Serial.println("=====================\n");
        delay(1000);
        return;
    }

    if (modemStatus.signalStrength < 10) {
        Serial.println("\n=== WARNING CONDITION ===");
        Serial.printf("✗ Sinyal lemah! (Strength: %d)\n", modemStatus.signalStrength);
        Serial.println("Continuing with reduced reliability");
        Serial.println("=====================\n");
        delay(5000);
        return;
    }

    processACLineStatus();
    delay(1000);
}

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