#ifndef EC200U_H #define EC200U_H #include #include "Config.h" #include "Memory.h" // -------------------- متغیرهای خارجی -------------------- extern HardwareSerial EC200U; extern DeviceConfig config; extern SensorData currentData; extern bool networkConnected; extern bool simConnected; extern bool networkRegistered; extern int signalStrength; extern String lastMessage; extern String currentAPN; extern String tempPhoneNumber; extern String tempTokenCode; extern bool awaitingSMS2; extern bool isInCall; //extern bool calibrationComplete; extern unsigned long lastUpload; // Forward declarations void initEC200U(); void updateNetworkStatus(); // -------------------- توابع کمکی جدید -------------------- bool checkAudioPlaybackStatus() { Serial1.println("Checking audio playback status..."); EC200U.println("AT+QVTSTAT?"); String response = ""; unsigned long start = millis(); while (millis() - start < 2000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); } } if (response.indexOf("+QVTSTAT: 0,0") != -1) { return true; // پخش تمام شده } else if (response.indexOf("+QVTSTAT: 0,1") != -1) { Serial1.println("Audio is playing"); return false; // در حال پخش است } else { Serial1.println("Unknown playback status"); return false; } } inline bool sendAT(String cmd, uint16_t wait = 2000, bool showResponse = false) { if (showResponse) { Serial1.print(">> "); Serial1.println(cmd); } EC200U.println(cmd); String response = ""; unsigned long start = millis(); while (millis() - start < wait) { while (EC200U.available()) { char c = EC200U.read(); response += c; if (showResponse) Serial1.write(c); } if (response.indexOf("OK") != -1) return true; if (response.indexOf("ERROR") != -1) return false; } return false; } inline String stringSendAT(String cmd, uint16_t wait = 2000, bool showResponse = false) { if (showResponse) { Serial1.print(">> "); Serial1.println(cmd); } EC200U.println(cmd); String response = ""; unsigned long start = millis(); while (millis() - start < wait) { while (EC200U.available()) { char c = EC200U.read(); response += c; if (showResponse) Serial1.write(c); } // اگر پاسخ کامل دریافت شده (دارای OK یا ERROR) خاتمه بده if (response.indexOf("OK") != -1 || response.indexOf("ERROR") != -1 || response.indexOf("NO CARRIER") != -1 || response.indexOf("CONNECT") != -1) { break; } } return response; } // void initAudioSettings() { // Serial1.println("Initializing audio settings..."); // // ریست تنظیمات صدا // sendAT("AT+CRESET", 3000, true); // delay(2000); // // تنظیمات اولیه // sendAT("AT+CLVL=5", 2000, true); // سطح صدا متوسط // sendAT("AT+CMUT=0", 2000, true); // غیرفعال کردن mute // sendAT("AT+QDAI=5", 2000, true); // تنظیم رابط صوتی // sendAT("AT+VTD=1", 2000, true); // تنظیم تون DTMF // // تنظیمات کدک صوتی // sendAT("AT+QMBNCFG=\"select\",0", 2000, true); // sendAT("AT+QCODECCFG=0,2,1", 2000, true); // AMR-NB, 12.2kbps // Serial1.println("✅ Audio settings initialized"); // } bool sendSMS(String numbers, String messages) { Serial1.println("\n📱 SENDING SMS - FINAL OPTIMIZED VERSION"); // تقسیم شماره‌ها int phoneCount = 0; String phoneNumbers[10]; String numbersCopy = numbers; numbersCopy.replace(" ", ""); int startIdx = 0; int commaIdx = numbersCopy.indexOf(','); while (commaIdx != -1 && phoneCount < 9) { phoneNumbers[phoneCount] = numbersCopy.substring(startIdx, commaIdx); phoneCount++; startIdx = commaIdx + 1; commaIdx = numbersCopy.indexOf(',', startIdx); } if (startIdx < numbersCopy.length()) { phoneNumbers[phoneCount] = numbersCopy.substring(startIdx); phoneCount++; } if (phoneCount == 0) { Serial1.println("❌ No phone numbers"); return false; } // تقسیم پیام‌ها int messageCount = 0; String messageTexts[10]; String messagesCopy = messages; startIdx = 0; int atIdx = messagesCopy.indexOf('@'); while (atIdx != -1 && messageCount < 9) { messageTexts[messageCount] = messagesCopy.substring(startIdx, atIdx); messageCount++; startIdx = atIdx + 1; atIdx = messagesCopy.indexOf('@', startIdx); } if (startIdx < messagesCopy.length()) { messageTexts[messageCount] = messagesCopy.substring(startIdx); messageCount++; } if (messageCount == 0) { Serial1.println("❌ No messages"); return false; } bool allSent = true; int totalMessagesSent = 0; // تنظیمات اولیه ماژول (یک بار انجام می‌شود) Serial1.println("📋 Initializing module..."); while (EC200U.available()) EC200U.read(); // پاکسازی بافر EC200U.println("AT+CMGF=1"); delay(50); EC200U.println("AT+CSMP=17,167,0,8"); delay(50); EC200U.println("AT+CSCS=\"UTF-8\""); delay(50); while (EC200U.available()) EC200U.read(); // پاکسازی مجدد // ارسال به همه شماره‌ها for (int i = 0; i < phoneCount; i++) { String phone = phoneNumbers[i]; if (phone.length() < 10) { Serial1.print("❌ Invalid number: "); Serial1.println(phone); allSent = false; continue; } // انتخاب پیام String message; if (messageCount == 1) { message = messageTexts[0]; } else if (i < messageCount) { message = messageTexts[i]; } else { message = messageTexts[messageCount - 1]; } if (message.length() == 0) { Serial1.print("❌ Empty message for: "); Serial1.println(phone); allSent = false; continue; } Serial1.print("📤 To: "); Serial1.print(phone); Serial1.print(" | Msg: "); if (message.length() > 30) { Serial1.print(message.substring(0, 30)); Serial1.print("..."); } else { Serial1.print(message); } Serial1.println(); // پاکسازی بافر قبل از ارسال while (EC200U.available()) EC200U.read(); // ارسال دستور CMGS EC200U.print("AT+CMGS=\""); EC200U.print(phone); EC200U.println("\""); // منتظر prompt > int timeout = 0; bool gotPrompt = false; while (timeout < 100) { if (EC200U.available() && EC200U.read() == '>') { gotPrompt = true; break; } delay(50); timeout++; } if (!gotPrompt) { Serial1.println("❌ No prompt received"); allSent = false; continue; } // ارسال متن (بدون خط جدید) for (int j = 0; j < message.length(); j++) { EC200U.write(message.charAt(j)); } // ارسال Ctrl+Z EC200U.write(26); // بررسی نتیجه timeout = 0; bool sent = false; String response = ""; while (timeout < 80) { // 8 ثانیه (80 * 100ms) while (EC200U.available()) { char c = EC200U.read(); response += c; if (response.indexOf("+CMGS:") != -1 || response.indexOf("OK") != -1) { sent = true; break; } if (response.indexOf("ERROR") != -1 || response.indexOf("CMS ERROR") != -1) { sent = false; break; } } if (sent || response.indexOf("ERROR") != -1) break; delay(100); timeout++; } if (sent || response.indexOf("ERROR") == -1) { // اگر خطایی نیامد، موفق فرض کن totalMessagesSent++; Serial1.println("✅ Sent successfully"); } else { Serial1.println("❌ Failed"); allSent = false; } if (sent) { Serial1.println("✅ Sent successfully"); } else { Serial1.println("❌ Failed"); allSent = false; } // تاخیر بین ارسال‌ها if (i < phoneCount - 1) { Serial1.println("⏳ Waiting 2 seconds..."); delay(2000); } } Serial1.print("\n📊 Result: "); Serial1.print(totalMessagesSent); Serial1.print("/"); Serial1.print(phoneCount); Serial1.println(" messages sent"); return (totalMessagesSent > 0); } // { // Serial1.println("\n📱 ارسال __ پیامک"); // Serial1.println("=============="); // // 1. تنظیم Text Mode // if (!sendAT("AT+CMGF=1")) { // Serial1.println("❌ خطا: Text Mode تنظیم نشد"); // return false; // } // // 2. تنظیم charset به UTF-8 // if (!sendAT("AT+CSCS=\"UTF-8\"")) { // Serial1.println("❌ خطا: UTF-8 پشتیبانی نمی‌شود"); // return false; // } // // 3. تنظیم پارامترهای SMS (اختیاری) // sendAT("AT+CSMP=1,167,0,8"); // // 4. ارسال دستور CMGS // String cmd = "AT+CMGS=\"" + phoneNumber + "\""; // EC200U.println(cmd); // // منتظر prompt > // delay(100); // unsigned long startTime = millis(); // bool gotPrompt = false; // while (millis() - startTime < 5000) { // while (EC200U.available()) { // if (EC200U.read() == '>') { // gotPrompt = true; // break; // } // } // if (gotPrompt) break; // } // if (!gotPrompt) { // Serial1.println("❌ خطا: Prompt دریافت نشد"); // return false; // } // // 5. ارسال متن UTF-8 // EC200U.println(message); // delay(100); // // 6. ارسال Ctrl+Z // EC200U.write(26); // // 7. دریافت پاسخ // startTime = millis(); // String response = ""; // bool success = false; // while (millis() - startTime < 15000) { // while (EC200U.available()) { // char c = EC200U.read(); // response += c; // if (response.indexOf("+CMGS:") != -1) success = true; // if (response.indexOf("+CMS ERROR") != -1) return false; // } // if (response.indexOf("OK") != -1) break; // if (response.indexOf("ERROR") != -1) break; // } // if (success) { // Serial1.println("✅ پیامک ارسال شد"); // return true; // } else { // Serial1.println("❌ ارسال ناموفق"); // return false; // } // } // -------------------- پردازش SMS -------------------- inline void extractNumbersFromSMS2(String message, String numbers[], int &count) { count = 0; String current = ""; for (int i = 0; i < message.length(); i++) { char c = message.charAt(i); if (c >= '0' && c <= '9') { current += c; } else { if (current.length() > 0) { if (count < 10) { numbers[count] = current; count++; } current = ""; } } } if (current.length() > 0 && count < 10) { numbers[count] = current; count++; } } inline void updateNetworkStatus() { if (!config.verified) { simConnected = false; networkRegistered = false; signalStrength = 0; return; } simConnected = sendAT("AT", 1000, false); EC200U.println("AT+CSQ"); String response = ""; unsigned long start = millis(); while (millis() - start < 2000) { while (EC200U.available()) { char c = EC200U.read(); response += c; } if (response.indexOf("OK") != -1 || response.indexOf("ERROR") != -1) break; } if (response.indexOf("+CSQ:") != -1) { int idx = response.indexOf("+CSQ:"); int comma = response.indexOf(',', idx); if (comma != -1) { String rssiStr = response.substring(idx + 6, comma); rssiStr.trim(); signalStrength = rssiStr.toInt(); if (signalStrength > 31) signalStrength = 0; } } EC200U.println("AT+CREG?"); response = ""; start = millis(); while (millis() - start < 2000) { while (EC200U.available()) { char c = EC200U.read(); response += c; } if (response.indexOf("OK") != -1 || response.indexOf("ERROR") != -1) break; } networkRegistered = (response.indexOf("+CREG:") != -1 && (response.indexOf(",1,") != -1 || response.indexOf(",5,") != -1)); } inline int detectSMSType(String message) { int count = 0; String current = ""; for (int i = 0; i < message.length(); i++) { char c = message.charAt(i); if (c >= '0' && c <= '9') { current += c; } else { if (current.length() > 0) { count++; current = ""; } } } if (current.length() > 0) { count++; } return (count >= 5) ? 2 : 1; } inline void connectToNetwork() { Serial1.println("\n======== NETWORK CONNECTION ========"); lastMessage = "Connecting"; if (!config.verified) { Serial1.println("❌ Cannot connect: Device not configured"); return; } currentAPN = simTypeToAPN(config.simType); Serial1.print("Setting APN: "); Serial1.println(currentAPN); String apnCmd = "AT+CGDCONT=1,\"IP\",\"" + currentAPN + "\""; sendAT(apnCmd, 2000, false); Serial1.println("Waiting for network registration..."); bool registered = false; for (int attempt = 1; attempt <= 30; attempt++) { EC200U.println("AT+CREG?"); String response = ""; unsigned long start = millis(); while (millis() - start < 2000) { while (EC200U.available()) { char c = EC200U.read(); response += c; } if (response.indexOf("OK") != -1) break; } if (response.indexOf(",1") != -1 || response.indexOf(",5") != -1) { registered = true; Serial1.print("✅ Network registered after "); Serial1.print(attempt); Serial1.println(" seconds"); break; } Serial1.print(" Attempt "); Serial1.print(attempt); Serial1.println("/30 - Searching..."); delay(1000); } if (!registered) { Serial1.println("⚠️ Network registration timeout - continuing anyway"); } Serial1.println("Deactivating old PDP context..."); sendAT("AT+QIDEACT=1", 5000, false); delay(1000); Serial1.println("Activating PDP context..."); if (sendAT("AT+QIACT=1", 30000, false)) { networkConnected = true; lastMessage = "Online"; Serial1.println("✅ Internet connection established!"); } else { Serial1.println("First attempt failed, retrying..."); delay(2000); if (sendAT("AT+QIACT=1", 30000, false)) { networkConnected = true; lastMessage = "Online"; Serial1.println("✅ Internet connection established on retry!"); } else { networkConnected = false; lastMessage = "Offline"; Serial1.println("❌ Failed to connect to internet"); } } if (networkConnected) { Serial1.println("Configuring SSL for HTTPS..."); sendAT("AT+QSSLCFG=\"sslversion\",1,4", 2000, false); sendAT("AT+QSSLCFG=\"ciphersuite\",1,0xFFFF", 2000, false); sendAT("AT+QSSLCFG=\"seclevel\",1,0", 2000, false); sendAT("AT+QHTTPCFG=\"sslctxid\",1", 2000, false); Serial1.println("✅ SSL configured for HTTPS"); } updateNetworkStatus(); Serial1.println("--- NETWORK STATUS ---"); Serial1.print(" SIM: "); Serial1.println(simConnected ? "Connected" : "Not detected"); Serial1.print(" Network: "); Serial1.println(networkRegistered ? "Registered" : "Searching"); Serial1.print(" Signal: "); Serial1.print(signalStrength); Serial1.println("/31"); Serial1.print(" Internet: "); Serial1.println(networkConnected ? "Online" : "Offline"); Serial1.println("=================================\n"); } inline void processSMS1(String message) { Serial1.println("\n======== SMS1 RECEIVED ========"); Serial1.print("Raw Message: "); Serial1.println(message); String numbers[10]; int count = 0; extractNumbersFromSMS2(message, numbers, count); String phone = ""; String token = ""; if (count >= 2) { phone = numbers[0]; token = numbers[1]; } Serial1.print("Phone: "); Serial1.println(phone); Serial1.print("Token: "); Serial1.println(token); if (phone.length() >= 10 && token.length() == 5) { tempPhoneNumber = phone; tempTokenCode = token; String verifyCode = generateVerificationCode(token); String reply = "Code: " + verifyCode; Serial1.print("Generated Verification Code: "); Serial1.println(verifyCode); Serial1.print("Sending SMS to: "); Serial1.println(phone); if (sendSMS(phone, reply)) { Serial1.println("✅ SMS1: Verification code sent successfully!"); awaitingSMS2 = true; lastMessage = "Wait SMS2"; } else { Serial1.println("❌ SMS1: Failed to send verification code"); lastMessage = "SMS1 Failed"; } } else { Serial1.println("❌ SMS1: Invalid format - phone or token missing"); Serial1.print(" Phone length: "); Serial1.print(phone.length()); Serial1.print(", Token length: "); Serial1.println(token.length()); lastMessage = "Invalid SMS1"; } Serial1.println("================================\n"); } inline void processSMS2(String message) { Serial1.println("\n======== SMS2 RECEIVED ========"); Serial1.print("Raw Message: "); Serial1.println(message); String numbers[10]; int count = 0; extractNumbersFromSMS2(message, numbers, count); Serial1.print("Numbers found: "); Serial1.println(count); for (int i = 0; i < count; i++) { Serial1.print(" ["); Serial1.print(i); Serial1.print("]: "); Serial1.println(numbers[i]); } if (count >= 5) { // 1. Device ID String deviceId = numbers[0]; Serial1.print("Original Device ID: "); Serial1.println(deviceId); if (deviceId.length() > 2) { deviceId = deviceId.substring(0, deviceId.length() - 2); } deviceId.toCharArray(config.deviceId, 16); Serial1.print("Parsed Device ID: "); Serial1.println(config.deviceId); // 2. Upload Interval if (numbers[1].length() > 1) { config.uploadInterval = numbers[1].substring(1).toInt(); } else { config.uploadInterval = numbers[1].toInt(); } Serial1.print("Upload Interval: "); Serial1.print(config.uploadInterval); Serial1.println(" min"); // 3. SMS Settings if (numbers[2].length() >= 2) { config.smsEnabled = (numbers[2].charAt(0) == '1'); config.smsInterval = numbers[2].substring(1).toInt(); } else { config.smsEnabled = false; config.smsInterval = 0; } Serial1.print("SMS Enabled: "); Serial1.println(config.smsEnabled ? "Yes" : "No"); Serial1.print("SMS Interval: "); Serial1.print(config.smsInterval); Serial1.println(" min"); // 4. SIM Type (index 4 if 6 numbers, else last) int simIndex = (count >= 6) ? 4 : (count - 1); String simValue = numbers[simIndex]; Serial1.print("SIM Value (raw): "); Serial1.println(simValue); if (simValue.length() >= 2) { String simCode = simValue.substring(simValue.length() - 2); if (simCode == "21") config.simType = SIM_HAMRAHE_AVAL; else if (simCode == "22") config.simType = SIM_IRANCELL; else if (simCode == "23") config.simType = SIM_RIGHTEL; else if (simCode == "71") config.simType = SIM_HAMRAHE_AVAL; else config.simType = SIM_UNKNOWN; } else { int simInt = simValue.toInt(); if (simInt == 21 || simInt == 71) config.simType = SIM_HAMRAHE_AVAL; else if (simInt == 22) config.simType = SIM_IRANCELL; else if (simInt == 23) config.simType = SIM_RIGHTEL; else config.simType = SIM_UNKNOWN; } Serial1.print("SIM Type: "); Serial1.println(simTypeToString(config.simType)); // 5. Phone number if (tempPhoneNumber.length() > 0) { tempPhoneNumber.toCharArray(config.serverPhoneNumber, 16); } else { strcpy(config.serverPhoneNumber, ""); } Serial1.print("Server Phone: "); Serial1.println(config.serverPhoneNumber); // 6. Save and connect config.verified = true; saveConfig(); currentAPN = simTypeToAPN(config.simType); awaitingSMS2 = false; Serial1.println("\n✅ SMS2: Configuration Complete!"); Serial1.println("--- FINAL CONFIG ---"); Serial1.print(" Device ID: "); Serial1.println(config.deviceId); Serial1.print(" SIM Type: "); Serial1.println(simTypeToString(config.simType)); Serial1.print(" APN: "); Serial1.println(currentAPN); Serial1.print(" Upload Int: "); Serial1.print(config.uploadInterval); Serial1.println(" min"); Serial1.print(" SMS Enabled: "); Serial1.println(config.smsEnabled ? "Yes" : "No"); Serial1.print(" Server Phone: "); Serial1.println(config.serverPhoneNumber); Serial1.println("--------------------"); lastMessage = "Configured"; Serial1.println("Connecting to network..."); connectToNetwork(); } else { Serial1.println("❌ SMS2: Invalid format - need at least 5 numbers"); Serial1.print(" Found only: "); Serial1.println(count); lastMessage = "Invalid SMS2"; } Serial1.println("================================\n"); } inline void checkSMS() { if (!sendAT("AT", 2000, false)) return; sendAT("AT+CMGF=1", 2000, false); delay(100); EC200U.println("AT+CMGL=\"REC UNREAD\""); String response = ""; unsigned long start = millis(); while (millis() - start < 5000) { while (EC200U.available()) { char c = EC200U.read(); response += c; } if (response.indexOf("OK") != -1) break; } if (response.indexOf("+CMGL:") != -1) { int msgIndex = response.indexOf("+CMGL:"); int comma1 = response.indexOf(',', msgIndex); int comma2 = response.indexOf(',', comma1 + 1); int quote1 = response.indexOf('\"', comma2 + 1); int quote2 = response.indexOf('\"', quote1 + 1); if (quote1 != -1 && quote2 != -1) { int msgStart = response.indexOf('\n', quote2) + 1; int msgEnd = response.indexOf('\n', msgStart); if (msgEnd == -1) msgEnd = response.length(); String message = response.substring(msgStart, msgEnd); message.trim(); Serial1.println("\n📱 SMS received"); int smsType = detectSMSType(message); if (config.verified) { Serial1.println("⚠️ Already configured - try SMS Proccess2"); lastMessage = "Already Configured - try sms process 2"; processSMS2(message); } else if (smsType == 1 && !awaitingSMS2) { processSMS1(message); } else if (smsType == 2 && awaitingSMS2) { processSMS2(message); } else if (smsType == 2 && !awaitingSMS2 && !config.verified) { // این حالت برای زمانی است که مستقیم SMS2 دریافت شود processSMS2(message); } else { Serial1.println("❌ Invalid SMS or wrong state"); lastMessage = "Invalid SMS"; } String indexStr = response.substring(msgIndex + 6, comma1); indexStr.trim(); sendAT("AT+CMGD=" + indexStr, 2000, false); } } } // -------------------- توابع مدیریت EC200U -------------------- inline void powerOffEC200U() { Serial1.println("Powering off EC200U..."); sendAT("AT+QPOWD", 3000, true); delay(3000); digitalWrite(PWRKEY_PIN, HIGH); delay(1500); digitalWrite(PWRKEY_PIN, LOW); Serial1.println("EC200U powered off"); networkConnected = false; } inline void initEC200U() { Serial1.println("\n======== MODEM INITIALIZATION ========"); lastMessage = "Modem Initializing"; Serial1.println("Checking if modem is already running..."); bool modemAlreadyOn = sendAT("AT", 2000, false); if (modemAlreadyOn) { Serial1.println("✅ Modem is already ON"); lastMessage = "Modem Ready"; } else { Serial1.println("Waiting for modem to boot (8s)..."); delay(8000); if (!sendAT("AT", 5000, false)) { Serial1.println("❌ Modem not responding!"); lastMessage = "Modem Err"; Serial1.println("=================================\n"); return; } Serial1.println("✅ Modem powered on successfully"); lastMessage = "Modem Ready"; } digitalWrite(PWRKEY_PIN, LOW); // تنظیمات اولیه sendAT("AT+CMGF=1", 2000, false); // تنظیم فرمت SMS sendAT("AT+CNMI=2,1,0,0,0", 2000, false); // اعلان SMS جدید // تنظیمات صوتی //initAudioSettings(); // فقط اگر config.verified بود به شبکه وصل شود if (config.verified) { Serial1.println("Device is configured, connecting to network..."); connectToNetwork(); } else { Serial1.println("⏳ Device not configured. Waiting for configuration SMS..."); Serial1.println("📱 Send SMS1 format: PHONENUMBER TOKENCODE"); lastMessage = "Wait SMS1"; } updateNetworkStatus(); Serial1.println("=================================\n"); } // -------------------- توابع SSL و HTTP -------------------- inline void configureSSL() { Serial1.println("Configuring SSL for HTTPS..."); sendAT("AT+QSSLCFG=\"sslversion\",1,4", 2000, false); sendAT("AT+QSSLCFG=\"ciphersuite\",1,0xFFFF", 2000, false); sendAT("AT+QSSLCFG=\"seclevel\",1,0", 2000, false); sendAT("AT+QHTTPCFG=\"sslctxid\",1", 2000, false); Serial1.println("✅ SSL configured"); } inline String readHttpResponse() { Serial1.println("Reading HTTP response body..."); while (EC200U.available()) { EC200U.read(); } EC200U.println("AT+QHTTPREAD=80"); char buffer[600]; int bufIndex = 0; unsigned long start = millis(); bool gotConnect = false; int bodyStart = -1; while (millis() - start < 30000 && bufIndex < 599) { if (EC200U.available()) { char c = EC200U.read(); buffer[bufIndex++] = c; Serial1.write(c); if (!gotConnect && bufIndex >= 7) { if (strncmp(&buffer[bufIndex-7], "CONNECT", 7) == 0) { gotConnect = true; } } } if (bufIndex >= 12) { buffer[bufIndex] = '\0'; if (strstr(buffer, "+QHTTPREAD: 0") != NULL) { delay(100); while (EC200U.available() && bufIndex < 599) { buffer[bufIndex++] = EC200U.read(); } break; } if (strstr(buffer, "ERROR") != NULL) { Serial1.println("\n❌ Error reading HTTP response"); return ""; } } } buffer[bufIndex] = '\0'; Serial1.println("\n--- Raw buffer ---"); Serial1.println(buffer); Serial1.println("--- End raw ---"); String body = ""; char* connectPtr = strstr(buffer, "CONNECT"); if (connectPtr != NULL) { char* bodyPtr = strchr(connectPtr, '\n'); if (bodyPtr != NULL) { bodyPtr++; char* endPtr = strstr(bodyPtr, "\r\nOK"); if (endPtr == NULL) endPtr = strstr(bodyPtr, "\nOK"); if (endPtr == NULL) endPtr = strstr(bodyPtr, "+QHTTPREAD"); if (endPtr != NULL) { int len = endPtr - bodyPtr; body.reserve(len + 1); for (int i = 0; i < len; i++) { if (bodyPtr[i] != '\r' && bodyPtr[i] != '\n') { body += bodyPtr[i]; } } } else { body = String(bodyPtr); } } } body.trim(); Serial1.print("\n--- Extracted Body ("); Serial1.print(body.length()); Serial1.print(" chars) ---\n["); Serial1.print(body); Serial1.println("]"); Serial1.println("--- End Body ---"); return body; } String extractNumberFromResponse(String response) { String result = ""; for (int i = 0; i < response.length(); i++) { char c = response.charAt(i); if (c >= '0' && c <= '9') { result += c; } } return result; } inline bool downloadAMRFile(String url) { Serial1.println("\n--- Downloading AMR File ---"); Serial1.print("URL: "); Serial1.println(url); // 1. بررسی اتصال if (!sendAT("AT", 2000, true)) { Serial1.println("❌ Modem not responding"); return false; } // 2. پاکسازی بافر while (EC200U.available()) EC200U.read(); // 3. تنظیم URL (روش مستقیم) Serial1.println("Setting URL..."); EC200U.println("AT+QHTTPURL"); String response = ""; unsigned long start = millis(); bool gotConnect = false; // منتظر CONNECT while (millis() - start < 5000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); if (response.indexOf("CONNECT") != -1) { gotConnect = true; break; } } if (gotConnect) break; } if (!gotConnect) { Serial1.println("❌ No CONNECT, trying alternative..."); // روش جایگزین: استفاده از طول URL String cmd = "AT+QHTTPURL=" + String(url.length()) + ",30"; EC200U.println(cmd); response = ""; start = millis(); while (millis() - start < 5000) { while (EC200U.available()) { char c = EC200U.read(); response += c; if (c == '\n') { if (response.indexOf("CONNECT") != -1) { gotConnect = true; break; } } } if (gotConnect) break; } } if (!gotConnect) { Serial1.println("❌ Could not get CONNECT prompt"); return false; } // 4. ارسال URL Serial1.println("Sending URL..."); EC200U.println(url); // 5. منتظر OK response = ""; start = millis(); bool urlAccepted = false; while (millis() - start < 5000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); if (response.indexOf("OK") != -1) { urlAccepted = true; break; } if (response.indexOf("ERROR") != -1) { Serial1.println("❌ URL rejected"); return false; } } if (urlAccepted) break; } if (!urlAccepted) { Serial1.println("❌ URL not accepted (timeout)"); return false; } Serial1.println("✅ URL set successfully"); delay(1000); // 6. ارسال GET request Serial1.println("Sending GET request..."); EC200U.println("AT+QHTTPGET"); response = ""; start = millis(); bool gotResponse = false; while (millis() - start < 30000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); if (response.indexOf("+QHTTPGET:") != -1) { gotResponse = true; // بررسی کد وضعیت int idx = response.indexOf("+QHTTPGET:"); String httpResponse = response.substring(idx); Serial1.print("HTTP Response: "); Serial1.println(httpResponse); // استخراج کد HTTP int comma1 = httpResponse.indexOf(','); int comma2 = httpResponse.indexOf(',', comma1 + 1); if (comma1 != -1 && comma2 != -1) { int httpCode = httpResponse.substring(comma1 + 1, comma2).toInt(); Serial1.print("HTTP Code: "); Serial1.println(httpCode); if (httpCode != 200) { Serial1.println("❌ HTTP error"); return false; } } break; } } if (gotResponse) break; } if (!gotResponse) { Serial1.println("❌ GET request timeout"); return false; } Serial1.println("✅ GET successful"); delay(2000); // 7. ذخیره فایل Serial1.println("Saving to file..."); EC200U.println("AT+QHTTPREADFILE=\"UFS:output.amr\""); response = ""; start = millis(); bool fileSaved = false; while (millis() - start < 60000) { while (EC200U.available()) { char c = EC200U.read(); response += c; // نمایش پیشرفت static int dots = 0; if (c == '\n') { Serial1.print("."); dots++; if (dots % 50 == 0) Serial1.println(); } if (response.indexOf("+QHTTPREADFILE: 0") != -1) { fileSaved = true; break; } } if (fileSaved) break; } if (fileSaved) { Serial1.println("\n✅ File saved successfully"); // بررسی وجود فایل Serial1.println("Verifying file..."); EC200U.println("AT+QFLST=\"UFS:output.amr\""); response = ""; start = millis(); while (millis() - start < 3000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); } if (response.indexOf("output.amr") != -1) break; } if (response.indexOf("output.amr") != -1) { Serial1.println("✅ File verified"); return true; } else { Serial1.println("⚠️ File not found in listing"); return true; // باز هم true برگردان چون ذخیره شد } } Serial1.println("\n❌ Failed to save file"); return false; } // ==================== تابع نهایی: تماس با DTMF Tones ==================== // // تابع اصلی که واقعاً باید کار کند // inline bool makeVoiceCallWithAudio(String phoneNumber) { // return false; // } // ==================== تابع اصلاح شده processServerResponse ==================== inline void processServerResponse(String response) { if (response.length() == 0) { Serial1.println("Empty response, no action needed"); return; } Serial1.println("\n======== PROCESSING SERVER RESPONSE ========"); Serial1.print("Response: "); Serial1.println(response); if (response.startsWith("tt")) { Serial1.println("Response Type: TT (Send SMS)"); String data = response.substring(2); int hashIdx = data.indexOf('#'); if (hashIdx != -1) { String phoneNumber = data.substring(0, hashIdx); String message = data.substring(hashIdx + 1); phoneNumber.trim(); message.trim(); Serial1.print(" Phone: "); Serial1.println(phoneNumber); Serial1.print(" Message: "); Serial1.println(message); if (phoneNumber.length() >= 10 && message.length() > 0) { if (sendSMS(phoneNumber, message)) { Serial1.println("✅ SMS sent successfully"); lastMessage = "TT SMS Sent"; } else { Serial1.println("❌ Failed to send SMS"); lastMessage = "TT SMS Fail"; } } else { Serial1.println("❌ Invalid phone or message"); lastMessage = "TT Invalid"; } } else { Serial1.println("❌ Invalid TT format (no #)"); lastMessage = "TT Format Err"; } } else if (response.startsWith("RST")) { NVIC_SystemReset(); } else if (response.startsWith("SHD")) { HAL_PWR_EnterSTANDBYMode(); } // else if (response.startsWith("TY")) { // Serial1.println("Response Type: TY (Voice Call with Audio/DMTF)"); // String data = response.substring(2); // int hashIdx = data.indexOf('#'); // if (hashIdx != -1) { // String phoneNumber = data.substring(0, hashIdx); // String audioUrl = data.substring(hashIdx + 1); // phoneNumber.trim(); // audioUrl.trim(); // Serial1.print(" Phone: "); // Serial1.println(phoneNumber); // Serial1.print(" Audio URL: "); // Serial1.println(audioUrl); // if (phoneNumber.length() >= 10) { // if (makeVoiceCallWithAudio(phoneNumber)) { // Serial1.println("✅ Voice call with DTMF completed"); // lastMessage = "TY Call Done (DTMF)"; // } else { // Serial1.println("❌ Voice call failed"); // lastMessage = "TY Call Fail"; // } // } else { // Serial1.println("❌ Invalid phone number"); // lastMessage = "TY Invalid"; // } // } else { // Serial1.println("❌ Invalid TY format (no #)"); // lastMessage = "TY Format Err"; // } // } else { Serial1.println("Response Type: Numeric or unknown - No action needed"); } Serial1.println("=============================================\n"); } // -------------------- ارسال داده به سرور -------------------- inline void uploadData() { Serial1.println("\n======== DATA UPLOAD ========"); if (!config.verified) { Serial1.println("❌ Upload skipped: Device not verified"); Serial1.println("==============================\n"); return; } if (!networkConnected && config.verified) { Serial1.println("⚠️ Not connected, trying to reconnect..."); connectToNetwork(); } if (!networkConnected) { Serial1.println("⚠️ Not connected, trying to reconnect..."); initEC200U(); if (!networkConnected) { Serial1.println("❌ Upload skipped: No network connection"); Serial1.println("==============================\n"); return; } } float coToSend = currentData.coPPM; String data = "deviceId=" + String(config.deviceId) + "&temperatureC=" + String(currentData.temperature, 1) + "&humidityPercent=" + String(currentData.humidity, 1) + "&gasPPM=" + String(coToSend, 0) + "&lux=" + String(currentData.lightLux, 1) + "&voltage=" + String(currentData.volage, 1) + "&power=" + String(currentData.power) + "&oldPower=" + String(currentData.oldPower) + "&batteryPercent=" + String(currentData.batteryPercent, 1) + "&batteryVoltage=" + String(currentData.batteryVoltage, 1); data.replace(" ", ""); String url = String(config.serverUrl) + "/api/Telemetry/AddData?" + data; //url = "https://ghback.nabaksoft.ir/My_StaticFiles/calltest.html"; Serial1.println("--- REQUEST INFO ---"); Serial1.print(" Server: "); Serial1.println(config.serverUrl); Serial1.print(" Device ID: "); Serial1.println(config.deviceId); Serial1.print(" Temp: "); Serial1.print(currentData.temperature, 1); Serial1.println(" C"); Serial1.print(" Hum: "); Serial1.print(currentData.humidity, 1); Serial1.println(" %"); Serial1.print(" CO (local): "); Serial1.print(currentData.coPPM, 0); Serial1.println(" ppm"); Serial1.print(" CO (to server): "); Serial1.print(coToSend, 0); Serial1.print(" ppm"); if (!MQ7sensorPreheated) { Serial1.print(" [CALIBRATING]"); } Serial1.println("--- FULL URL ---"); Serial1.println(url); Serial1.print(" URL Length: "); Serial1.println(url.length()); configureSSL(); String cmd = "AT+QHTTPURL=" + String(url.length()) + ",80"; EC200U.println(cmd); String response = ""; unsigned long start = millis(); bool gotConnect = false; while (millis() - start < 5000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); } if (response.indexOf("CONNECT") != -1) { gotConnect = true; break; } if (response.indexOf("ERROR") != -1) { Serial1.println("\n❌ Step 1 failed: QHTTPURL error"); lastMessage = "URL Err"; Serial1.println("==============================\n"); return; } } if (!gotConnect) { Serial1.println("❌ Step 1 failed: No CONNECT response"); lastMessage = "URL Err"; Serial1.println("==============================\n"); return; } Serial1.println("\n✅ Step 1: Got CONNECT, sending URL..."); EC200U.print(url); delay(1000); response = ""; start = millis(); while (millis() - start < 5000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); } if (response.indexOf("OK") != -1) break; } if (response.indexOf("OK") == -1) { Serial1.println("\n❌ Step 1 failed: URL not accepted"); lastMessage = "URL Err"; Serial1.println("==============================\n"); return; } Serial1.println("\n✅ Step 1: URL set successfully"); delay(500); Serial1.println("Step 2: Sending HTTP GET (waiting up to 60 sec)..."); EC200U.println("AT+QHTTPGET=60"); response = ""; start = millis(); bool success = false; bool gotResponse = false; while (millis() - start < 65000) { while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); } if (response.indexOf("+QHTTPGET:") != -1) { delay(1000); while (EC200U.available()) { char c = EC200U.read(); response += c; Serial1.write(c); } gotResponse = true; int idx = response.indexOf("+QHTTPGET:"); String httpResult = response.substring(idx); Serial1.print("\nHTTP Result: "); Serial1.println(httpResult); if (httpResult.indexOf(" 0,200") != -1 || httpResult.indexOf(" 0,201") != -1 || httpResult.indexOf(":0,200") != -1 || httpResult.indexOf(":0,201") != -1) { success = true; } else if (httpResult.indexOf(",200,") != -1 || httpResult.indexOf(",201,") != -1) { success = true; } break; } if (response.indexOf("ERROR") != -1) { Serial1.println("\n❌ HTTP GET command error"); break; } } if (success) { lastUpload = millis(); lastMessage = "Uploaded"; Serial1.println("\n✅ Step 2: Data uploaded successfully!"); Serial1.println("--- UPLOAD SUCCESS ---"); Serial1.print(" Time: "); Serial1.print(millis() / 1000); Serial1.println(" sec since boot"); Serial1.println("----------------------"); delay(500); String serverResponse = readHttpResponse(); if (serverResponse.length() > 0) { processServerResponse(serverResponse); } } else { lastMessage = "Upload Err"; if (gotResponse) { Serial1.println("\n❌ Step 2: Server returned error"); } else { Serial1.println("\n❌ Step 2: Timeout waiting for response"); } Serial1.println("--- FULL RESPONSE ---"); Serial1.println(response); Serial1.println("---------------------"); Serial1.println("Will retry on next interval..."); networkConnected = false; } Serial1.println("==============================\n"); } #endif // EC200U_H