1613 lines
45 KiB
Plaintext
1613 lines
45 KiB
Plaintext
#ifndef EC200U_H
|
||
#define EC200U_H
|
||
|
||
#include <Arduino.h>
|
||
#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();
|
||
// -------------------- توابع پایه EC200U --------------------
|
||
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;
|
||
}
|
||
|
||
// جدول تبدیل کاراکترهای فارسی به UCS2 (بهینه شده)
|
||
inline String convertFarsiToUCS2(String text) {
|
||
String ucs2 = "";
|
||
for (int i = 0; i < text.length(); i++) {
|
||
unsigned char c = text.charAt(i);
|
||
|
||
// تشخیص کاراکترهای فارسی UTF-8 (دو بایتی)
|
||
if (c >= 0xD8 && c <= 0xDF && i + 1 < text.length()) {
|
||
unsigned char c2 = text.charAt(i + 1);
|
||
|
||
// محاسبه کد Unicode از UTF-8
|
||
uint16_t unicode = ((c - 0xD8) << 6) + (c2 - 0x80) + 0x0600;
|
||
|
||
// تبدیل به HEX
|
||
char hex[5];
|
||
sprintf(hex, "%04X", unicode);
|
||
ucs2 += hex;
|
||
i++; // یک کاراکتر اضافه مصرف شد
|
||
}
|
||
// کاراکترهای ASCII
|
||
else if (c < 0x80) {
|
||
char hex[5];
|
||
sprintf(hex, "%04X", c);
|
||
ucs2 += hex;
|
||
}
|
||
// سایر کاراکترها
|
||
else {
|
||
char hex[5];
|
||
sprintf(hex, "%04X", c);
|
||
ucs2 += hex;
|
||
}
|
||
}
|
||
return ucs2;
|
||
}
|
||
|
||
// تبدیل شماره به UCS2 (اعداد)
|
||
inline String convertNumberToUCS2(String number) {
|
||
String ucs2 = "";
|
||
for (int i = 0; i < number.length(); i++) {
|
||
char c = number.charAt(i);
|
||
if (c == '+') {
|
||
ucs2 += "002B";
|
||
} else if (c >= '0' && c <= '9') {
|
||
char hex[5];
|
||
sprintf(hex, "%04X", c);
|
||
ucs2 += hex;
|
||
}
|
||
}
|
||
return ucs2;
|
||
}
|
||
|
||
// تابع اصلی ارسال SMS فارسی
|
||
// تابع اصلاح شده برای ارسال SMS فارسی
|
||
inline bool sendSMS(String numbers, String messages) {
|
||
Serial1.println("\n📱 SENDING SMS - PDU MODE");
|
||
|
||
// تقسیم شمارهها
|
||
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;
|
||
|
||
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();
|
||
|
||
// --- روش ۱: ابتدا با GSM معمولی امتحان کن ---
|
||
sendAT("AT+CMGF=1", 2000, false); // Text mode
|
||
sendAT("AT+CSCS=\"GSM\"", 2000, false);
|
||
sendAT("AT+CSMP=17,167,0,0", 2000, false);
|
||
|
||
EC200U.print("AT+CMGS=\"");
|
||
EC200U.print(phone);
|
||
EC200U.println("\"");
|
||
|
||
delay(100);
|
||
|
||
String response = "";
|
||
unsigned long start = millis();
|
||
bool gotPrompt = false;
|
||
|
||
while (millis() - start < 5000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
if (response.indexOf(">") != -1) {
|
||
gotPrompt = true;
|
||
break;
|
||
}
|
||
}
|
||
if (gotPrompt) break;
|
||
}
|
||
|
||
if (!gotPrompt) {
|
||
Serial1.println("❌ No prompt");
|
||
allSent = false;
|
||
continue;
|
||
}
|
||
|
||
// ارسال پیام
|
||
EC200U.print(message);
|
||
EC200U.write(26);
|
||
|
||
response = "";
|
||
start = millis();
|
||
bool gotResponse = false;
|
||
bool hasError = false;
|
||
|
||
while (millis() - start < 10000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
if (response.indexOf("+CMGS:") != -1) {
|
||
gotResponse = true;
|
||
totalMessagesSent++;
|
||
break;
|
||
}
|
||
if (response.indexOf("ERROR") != -1 || response.indexOf("CMS ERROR") != -1) {
|
||
hasError = true;
|
||
break;
|
||
}
|
||
}
|
||
if (gotResponse || hasError) break;
|
||
}
|
||
|
||
if (gotResponse) {
|
||
Serial1.println("✅ Sent with GSM encoding");
|
||
continue; // موفق بود، برو به شماره بعدی
|
||
}
|
||
|
||
if (hasError) {
|
||
Serial1.println("⚠️ GSM failed, trying 8-bit encoding...");
|
||
|
||
// --- روش ۲: 8-bit encoding ---
|
||
sendAT("AT+CMGF=1", 2000, false);
|
||
sendAT("AT+CSMP=17,167,0,8", 2000, false); // 8-bit data coding
|
||
|
||
EC200U.print("AT+CMGS=\"");
|
||
EC200U.print(phone);
|
||
EC200U.println("\"");
|
||
|
||
delay(100);
|
||
|
||
response = "";
|
||
start = millis();
|
||
gotPrompt = false;
|
||
|
||
while (millis() - start < 5000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
if (response.indexOf(">") != -1) {
|
||
gotPrompt = true;
|
||
break;
|
||
}
|
||
}
|
||
if (gotPrompt) break;
|
||
}
|
||
|
||
if (!gotPrompt) {
|
||
Serial1.println("❌ No prompt for 8-bit");
|
||
allSent = false;
|
||
continue;
|
||
}
|
||
|
||
EC200U.print(message);
|
||
EC200U.write(26);
|
||
|
||
response = "";
|
||
start = millis();
|
||
gotResponse = false;
|
||
|
||
while (millis() - start < 10000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
if (response.indexOf("+CMGS:") != -1) {
|
||
gotResponse = true;
|
||
totalMessagesSent++;
|
||
break;
|
||
}
|
||
if (response.indexOf("ERROR") != -1) {
|
||
break;
|
||
}
|
||
}
|
||
if (gotResponse) break;
|
||
}
|
||
|
||
if (gotResponse) {
|
||
Serial1.println("✅ Sent with 8-bit encoding");
|
||
} else {
|
||
Serial1.println("❌ 8-bit also failed");
|
||
allSent = false;
|
||
}
|
||
}
|
||
|
||
// تاخیر بین ارسالها
|
||
if (i < phoneCount - 1) {
|
||
delay(3000);
|
||
}
|
||
}
|
||
|
||
Serial1.print("📊 Result: ");
|
||
Serial1.print(totalMessagesSent);
|
||
Serial1.print("/");
|
||
Serial1.print(phoneCount);
|
||
Serial1.println(" messages sent");
|
||
|
||
// بازگشت به تنظیمات عادی
|
||
sendAT("AT+CSMP=17,167,0,0", 2000, false);
|
||
|
||
return (totalMessagesSent > 0);
|
||
}
|
||
|
||
// -------------------- پردازش 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(); // به جای initEC200U() از این تابع استفاده شود
|
||
} 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() {
|
||
// حذف شرط config.verified - همیشه اجرا شود
|
||
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("Modem not responding, powering on...");
|
||
|
||
Serial1.println(" PWRKEY -> HIGH (MOSFET ON, PWRKEY to GND)");
|
||
digitalWrite(PWRKEY_PIN, HIGH);
|
||
delay(1500);
|
||
Serial1.println(" PWRKEY -> LOW (MOSFET OFF, PWRKEY floating)");
|
||
digitalWrite(PWRKEY_PIN, LOW);
|
||
*/
|
||
Serial1.println("Waiting for modem to boot (8s)...");
|
||
delay(8000);
|
||
|
||
if (!sendAT("AT", 5000, false)) {
|
||
Serial1.println("⚠️ First attempt failed, trying again with longer pulse...");
|
||
digitalWrite(PWRKEY_PIN, HIGH);
|
||
delay(2000);
|
||
digitalWrite(PWRKEY_PIN, LOW);
|
||
delay(10000);
|
||
|
||
if (!sendAT("AT", 5000, false)) {
|
||
Serial1.println("❌ Modem not responding after power on!");
|
||
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 جدید
|
||
|
||
// فقط اگر 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;
|
||
}
|
||
|
||
// -------------------- توابع دانلود و تماس صوتی --------------------
|
||
inline bool downloadAMRFile(String url) {
|
||
Serial1.println("\n--- Downloading AMR File ---");
|
||
Serial1.print("URL (");
|
||
Serial1.print(url.length());
|
||
Serial1.print(" chars): [");
|
||
Serial1.print(url);
|
||
Serial1.println("]");
|
||
|
||
if (url.length() < 10 || !url.startsWith("http")) {
|
||
Serial1.println("❌ Invalid URL!");
|
||
return false;
|
||
}
|
||
|
||
sendAT("AT+QFDEL=\"UFS:audio.amr\"", 2000, false);
|
||
delay(100);
|
||
|
||
int urlLen = url.length();
|
||
//Serial1.print("Setting URL with length: ");
|
||
//Serial1.println(urlLen);
|
||
|
||
String cmd = "AT+QHTTPURL=" + String(urlLen) + ",80";
|
||
//Serial1.print("Command: ");
|
||
//Serial1.println(cmd);
|
||
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;
|
||
}
|
||
if (response.indexOf("CONNECT") != -1) {
|
||
gotConnect = true;
|
||
break;
|
||
}
|
||
if (response.indexOf("ERROR") != -1) {
|
||
Serial1.println("❌ QHTTPURL error");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if (!gotConnect) {
|
||
Serial1.println("❌ No CONNECT for URL");
|
||
return false;
|
||
}
|
||
|
||
EC200U.print(url);
|
||
delay(1000);
|
||
|
||
response = "";
|
||
start = millis();
|
||
while (millis() - start < 3000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
}
|
||
if (response.indexOf("OK") != -1) break;
|
||
}
|
||
|
||
if (response.indexOf("OK") == -1) {
|
||
Serial1.println("❌ URL not accepted");
|
||
return false;
|
||
}
|
||
|
||
Serial1.println("✅ URL set successfully");
|
||
delay(200);
|
||
|
||
//Serial1.println("Step 1: Sending HTTP GET request...");
|
||
EC200U.println("AT+QHTTPGET=60");
|
||
|
||
response = "";
|
||
start = millis();
|
||
bool httpSuccess = false;
|
||
|
||
while (millis() - start < 65000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
Serial1.write(c);
|
||
}
|
||
|
||
int qhttpIdx = response.indexOf("+QHTTPGET:");
|
||
if (qhttpIdx != -1) {
|
||
String afterQhttp = response.substring(qhttpIdx);
|
||
int firstComma = afterQhttp.indexOf(',');
|
||
int secondComma = afterQhttp.indexOf(',', firstComma + 1);
|
||
|
||
if (firstComma != -1 && secondComma != -1) {
|
||
int errorCode = afterQhttp.substring(11, firstComma).toInt();
|
||
int httpCode = afterQhttp.substring(firstComma + 1, secondComma).toInt();
|
||
|
||
Serial1.print("\n Error code: ");
|
||
Serial1.print(errorCode);
|
||
Serial1.print(", HTTP code: ");
|
||
Serial1.println(httpCode);
|
||
|
||
if (errorCode == 0 && httpCode >= 200 && httpCode < 300) {
|
||
httpSuccess = true;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (response.indexOf("ERROR") != -1) {
|
||
Serial1.println("\n❌ HTTP GET failed");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if (!httpSuccess) {
|
||
Serial1.println("\n❌ HTTP GET timeout or failed");
|
||
return false;
|
||
}
|
||
|
||
Serial1.println("✅ HTTP GET successful");
|
||
|
||
delay(500);
|
||
while (EC200U.available()) EC200U.read();
|
||
|
||
Serial1.println("Step 2: Saving response to file...");
|
||
EC200U.println("AT+QHTTPREADFILE=\"UFS:audio.amr\",80");
|
||
|
||
response = "";
|
||
start = millis();
|
||
bool success = false;
|
||
|
||
while (millis() - start < 60000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
Serial1.write(c);
|
||
}
|
||
|
||
if (response.indexOf("+QHTTPREADFILE: 0") != -1) {
|
||
success = true;
|
||
break;
|
||
}
|
||
if (response.indexOf("ERROR") != -1) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (success) {
|
||
Serial1.println("\n✅ AMR file downloaded to RAM");
|
||
return true;
|
||
} else {
|
||
Serial1.println("\n❌ Failed to save AMR file");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
inline int getCallState(String clccResponse) {
|
||
int clccIdx = clccResponse.indexOf("+CLCC:");
|
||
if (clccIdx == -1) return -1;
|
||
|
||
String afterClcc = clccResponse.substring(clccIdx + 7);
|
||
int firstComma = afterClcc.indexOf(',');
|
||
if (firstComma == -1) return -1;
|
||
int secondComma = afterClcc.indexOf(',', firstComma + 1);
|
||
if (secondComma == -1) return -1;
|
||
int thirdComma = afterClcc.indexOf(',', secondComma + 1);
|
||
if (thirdComma == -1) return -1;
|
||
|
||
String statStr = afterClcc.substring(secondComma + 1, thirdComma);
|
||
statStr.trim();
|
||
return statStr.toInt();
|
||
}
|
||
inline bool makeVoiceCallWithAudio(String phoneNumber) {
|
||
isInCall = true;
|
||
Serial1.println("\n--- Making Voice Call ---");
|
||
Serial1.print("Phone: ");
|
||
Serial1.println(phoneNumber);
|
||
|
||
delay(1000);
|
||
|
||
String dialCmd = "ATD" + phoneNumber + ";";
|
||
EC200U.println(dialCmd);
|
||
|
||
String response = "";
|
||
unsigned long start = millis();
|
||
bool callAnswered = false;
|
||
|
||
while (millis() - start < 10000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
Serial1.write(c);
|
||
}
|
||
if (response.indexOf("OK") != -1) break;
|
||
if (response.indexOf("ERROR") != -1 ||
|
||
response.indexOf("NO CARRIER") != -1 ||
|
||
response.indexOf("BUSY") != -1) {
|
||
Serial1.println("❌ Call initiation failed");
|
||
isInCall = false;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
Serial1.println("📞 Call initiated, waiting for answer...");
|
||
|
||
start = millis();
|
||
while (millis() - start < 60000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
Serial1.write(c);
|
||
}
|
||
|
||
EC200U.println("AT+CLCC");
|
||
delay(500);
|
||
|
||
String clccResp = "";
|
||
unsigned long clccStart = millis();
|
||
while (millis() - clccStart < 2000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
clccResp += c;
|
||
Serial1.write(c);
|
||
}
|
||
if (clccResp.indexOf("OK") != -1) break;
|
||
}
|
||
|
||
int callState = getCallState(clccResp);
|
||
Serial1.print(" Call state: ");
|
||
Serial1.println(callState);
|
||
|
||
if (callState == 0) {
|
||
callAnswered = true;
|
||
Serial1.println("✅ Call answered!");
|
||
break;
|
||
} else if (callState == 2) {
|
||
Serial1.println(" ⏳ Dialing...");
|
||
} else if (callState == 3) {
|
||
Serial1.println(" 🔔 Ringing...");
|
||
} else if (callState == -1) {
|
||
if (clccResp.indexOf("NO CARRIER") != -1 ||
|
||
clccResp.indexOf("+CLCC:") == -1) {
|
||
Serial1.println("❌ Call ended or no answer");
|
||
break;
|
||
}
|
||
}
|
||
|
||
delay(2000);
|
||
}
|
||
|
||
if (!callAnswered) {
|
||
Serial1.println("❌ Call not answered");
|
||
sendAT("ATH", 2000, false);
|
||
isInCall = false;
|
||
return false;
|
||
}
|
||
|
||
Serial1.println("✅ Call connected, playing audio...");
|
||
|
||
// بارگذاری فایل صوتی در RAM
|
||
sendAT("AT+QPSND=0", 1000, false); // تنظیم حالت پخش
|
||
sendAT("AT+QHTTPREADFILE=\"UFS:audio.amr\"", 1000, false);
|
||
|
||
// پخش فایل صوتی
|
||
sendAT("AT+QPSND=1,\"UFS:audio.amr\"", 1000, false);
|
||
|
||
response = "";
|
||
start = millis();
|
||
bool playStarted = false;
|
||
|
||
while (millis() - start < 5000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
Serial1.write(c);
|
||
}
|
||
if (response.indexOf("OK") != -1) {
|
||
playStarted = true;
|
||
break;
|
||
}
|
||
if (response.indexOf("ERROR") != -1) {
|
||
Serial1.println("❌ Failed to play audio");
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (playStarted) {
|
||
Serial1.println("✅ Audio playing...");
|
||
|
||
bool playEnded = false;
|
||
start = millis();
|
||
|
||
while (millis() - start < 120000) {
|
||
while (EC200U.available()) {
|
||
char c = EC200U.read();
|
||
response += c;
|
||
Serial1.write(c);
|
||
}
|
||
|
||
if (response.indexOf("+QPSND: 0") != -1 ||
|
||
response.indexOf("QPSND: END") != -1) {
|
||
playEnded = true;
|
||
break;
|
||
}
|
||
|
||
if (response.indexOf("NO CARRIER") != -1) {
|
||
Serial1.println("Call ended by other party");
|
||
break;
|
||
}
|
||
|
||
delay(500);
|
||
}
|
||
|
||
if (playEnded) {
|
||
Serial1.println("✅ Audio playback completed");
|
||
}
|
||
}
|
||
|
||
delay(500);
|
||
Serial1.println("Hanging up...");
|
||
sendAT("ATH", 3000, true);
|
||
|
||
delay(2000);
|
||
|
||
Serial1.println("✅ Call ended");
|
||
isInCall = false;
|
||
return true;
|
||
}
|
||
|
||
inline void deleteAMRFile() {
|
||
Serial1.println("Deleting AMR file from RAM...");
|
||
sendAT("AT+QFDEL=\"UFS:audio.amr\"", 2000, false);
|
||
Serial1.println("✅ File deleted");
|
||
}
|
||
|
||
// -------------------- پردازش پاسخ سرور --------------------
|
||
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)");
|
||
|
||
String data = response.substring(2);
|
||
|
||
Serial1.print("Data after TY removal (");
|
||
Serial1.print(data.length());
|
||
Serial1.print(" chars): ");
|
||
Serial1.println(data);
|
||
|
||
int hashIdx = data.indexOf('#');
|
||
Serial1.print("Hash index: ");
|
||
Serial1.println(hashIdx);
|
||
|
||
if (hashIdx != -1) {
|
||
String phoneNumber = data.substring(0, hashIdx);
|
||
String audioUrl = data.substring(hashIdx + 1);
|
||
|
||
phoneNumber.trim();
|
||
audioUrl.trim();
|
||
|
||
Serial1.print("Phone length: ");
|
||
Serial1.println(phoneNumber.length());
|
||
Serial1.print("URL length: ");
|
||
Serial1.println(audioUrl.length());
|
||
|
||
Serial1.print(" Phone: ");
|
||
Serial1.println(phoneNumber);
|
||
Serial1.print(" Audio URL: ");
|
||
Serial1.println(audioUrl);
|
||
|
||
if (phoneNumber.length() >= 10 && audioUrl.length() > 0) {
|
||
if (downloadAMRFile(audioUrl)) {
|
||
if (makeVoiceCallWithAudio(phoneNumber)) {
|
||
Serial1.println("✅ Voice call completed");
|
||
lastMessage = "TY Call Done";
|
||
} else {
|
||
Serial1.println("❌ Voice call failed");
|
||
lastMessage = "TY Call Fail";
|
||
}
|
||
|
||
deleteAMRFile();
|
||
} else {
|
||
Serial1.println("❌ Failed to download audio");
|
||
lastMessage = "TY DL Fail";
|
||
}
|
||
} else {
|
||
Serial1.println("❌ Invalid phone or URL");
|
||
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(7) +
|
||
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://farsnews.ir/4512.2232f38.js';
|
||
//for test call
|
||
//url="http://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 (!calibrationComplete) {
|
||
Serial1.print(" [CALIBRATING]");
|
||
}
|
||
// Serial1.println();
|
||
// Serial1.print(" Light: ");
|
||
// Serial1.print(currentData.lightLux, 1);
|
||
// Serial1.println(" lux");
|
||
Serial1.println("--- FULL URL ---");
|
||
Serial1.println(url);
|
||
Serial1.print(" URL Length: ");
|
||
Serial1.println(url.length());
|
||
//Serial1.println("--------------------");
|
||
|
||
configureSSL();
|
||
|
||
//Serial1.println("Step 1: Setting URL...");
|
||
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
|
||
|