Skip to main content

Code mẫu sản phẩm TDM2421 kết nối MQTT tới sever dùng 4G

Dưới đây là code mẫu dùng cho Mạch phát triển 4G GPS ESP32-C3 TDM2421TDM2421, một số sản phẩm khác bạn cần tìm hiểu tập lệnh AT để chỉnh sửa cho phù hợp.

#include <HardwareSerial.h>

#define simSerial Serial0  // Sử dụng Serial0 cho module SIM
#define MCU_SIM_BAUDRATE 115200
#define MCU_SIM_TX_PIN 21
#define MCU_SIM_RX_PIN 20
#define MCU_SIM_EN_PIN 2  // Đối với module_V2
#define BUF_SIZE 256
#define PAYLOAD_SIZE 128
#define MSG_SIZE 128

char data[BUF_SIZE];
char payload[PAYLOAD_SIZE];
char msg[MSG_SIZE];
float latDecimalGlobal = 0.0;
float lonDecimalGlobal = 0.0;
bool is_publishing = false;

// Hàm chuyển đổi tọa độ sang dạng thập phân
float convertToDecimal(char *coordinate, char direction) {
    float degrees, minutes, decimal;
    char degStr[4], minStr[10];

    if (strlen(coordinate) > 9) { // Kinh độ (DDDMM.MMMM)
        strncpy(degStr, coordinate, 3);
        degStr[3] = '\0';
        strcpy(minStr, coordinate + 3);
    } else { // Vĩ độ (DDMM.MMMM)
        strncpy(degStr, coordinate, 2);
        degStr[2] = '\0';
        strcpy(minStr, coordinate + 2);
    }

    degrees = atof(degStr);
    minutes = atof(minStr);
    decimal = degrees + (minutes / 60.0);

    if (direction == 'S' || direction == 'W') {
        decimal = -decimal;
    }

    return decimal;
}

// Hàm phân tích chuỗi GPS
void parseGPSData(char *gpsData) {
    char *token;
    char latitude[12], longitude[12];
    char latDir, lonDir;
    float latDecimal, lonDecimal;

    // Kiểm tra lỗi GPS hoặc dữ liệu không hợp lệ
    if (strstr(gpsData, "+CME ERROR:") != NULL) {
        Serial.print("GPS error: ");
        Serial.println(gpsData);
        // Tạo payload mặc định
        snprintf(payload, sizeof(payload), "{\"latitude\": %.6f, \"longitude\": %.6f}", latDecimalGlobal, lonDecimalGlobal);
        Serial.print("Payload (default): ");
        Serial.println(payload);
        return;
    }

    if (strstr(gpsData, "+QGPSLOC:") == NULL) {
        Serial.println("No valid GPS data found");
        // Tạo payload mặc định
        snprintf(payload, sizeof(payload), "{\"latitude\": %.6f, \"longitude\": %.6f}", latDecimalGlobal, lonDecimalGlobal);
        Serial.print("Payload (default): ");
        Serial.println(payload);
        return;
    }

    // Bỏ qua phần đầu "+QGPSLOC: "
    token = strtok(gpsData, " ");
    token = strtok(NULL, ",");
    // Bỏ qua thời gian
    token = strtok(NULL, ",");
    // Lấy vĩ độ
    strcpy(latitude, token);
    latDir = latitude[strlen(latitude) - 1];
    latitude[strlen(latitude) - 1] = '\0';
    // Lấy kinh độ
    token = strtok(NULL, ",");
    strcpy(longitude, token);
    lonDir = longitude[strlen(longitude) - 1];
    longitude[strlen(longitude) - 1] = '\0';
    // Chuyển đổi sang thập phân
    latDecimal = convertToDecimal(latitude, latDir);
    lonDecimal = convertToDecimal(longitude, lonDir);

    // Cập nhật biến toàn cục
    latDecimalGlobal = latDecimal;
    lonDecimalGlobal = lonDecimal;

    // In kết quả
    Serial.print("Vi do: ");
    Serial.println(latDecimal, 6);
    Serial.print("Kinh do: ");
    Serial.println(lonDecimal, 6);

    // Tạo payload JSON
    snprintf(payload, sizeof(payload), "{\"latitude\": %.6f, \"longitude\": %.6f}", latDecimalGlobal, lonDecimalGlobal);
    Serial.print("Payload: ");
    Serial.println(payload);
}

void sim_at_wait() {
    delay(1000); // Tăng delay để đảm bảo nhận đủ dữ liệu
    int len = 0;
    while (simSerial.available()) {
        char c = simSerial.read();
        if (len < BUF_SIZE - 1) {
            data[len++] = c;
        }
    }
    if (len > 0) {
        data[len] = '\0'; // Null-terminate chuỗi
        Serial.print("===== SIM receive: ");
        Serial.println(data);
        // Kiểm tra lỗi MQTT
        if (strstr(data, "+QMTSTAT:") != NULL) {
            Serial.print("MQTT connection error: ");
            Serial.println(data);
        }
        // Phân tích GPS nếu nhận được và không đang publish
        if (strstr(data, "+QGPSLOC:") != NULL && !is_publishing) {
            parseGPSData(data);
        } else if (strstr(data, "+CME ERROR:") != NULL) {
            parseGPSData(data); // Xử lý lỗi GPS
        }
    } else {
        Serial.println("No data received from SIM module");
    }
}

bool sim_at_cmd(String cmd) {
    Serial.print("Sending command: ");
    Serial.println(cmd);
    simSerial.println(cmd);
    sim_at_wait();
    // Kiểm tra phản hồi OK hoặc ERROR
    if (strstr(data, "OK") != NULL) {
        return true;
    } else if (strstr(data, ">") != NULL) {
        return true; // Dấu > cho biết module chờ payload
    } else if (strstr(data, "ERROR") != NULL) {
        Serial.print("Command failed: ");
        Serial.println(cmd);
        return false;
    }
    return false;
}

bool sim_at_send(char c) {
    simSerial.write(c);
    return true;
}

void get_gps_data() {
    Serial.println("Requesting GPS data...");
    sim_at_cmd("AT+QGPS?");
    for (int i = 0; i < 5; i++) { // Thử 5 lần
        Serial.print("GPS attempt ");
        Serial.println(i + 1);
        sim_at_cmd("AT+QGPSLOC=0");
        delay(5000); // Chờ 5 giây để GPS thử định vị
        if (strstr(data, "+QGPSLOC:") != NULL) {
            Serial.println("GPS data received!");
            break;
        }
    }
}

bool check_network() {
    sim_at_cmd("AT+CSQ");
    if (strstr(data, "+CSQ: 0,0") != NULL || strstr(data, "+CSQ: 99,99") != NULL) {
        Serial.println("No network signal!");
        return false;
    }
    Serial.println("Network signal OK");
    // Kiểm tra GPRS
    sim_at_cmd("AT+CGATT?");
    if (strstr(data, "+CGATT: 1") == NULL) {
        Serial.println("GPRS not attached, attempting to attach...");
        sim_at_cmd("AT+CGATT=1");
        delay(2000);
        return strstr(data, "OK") != NULL;
    }
    return true;
}

bool send_mqtt_data() {
    // Khởi tạo payload mặc định nếu rỗng
    if (strlen(payload) == 0) {
        snprintf(payload, sizeof(payload), "{\"latitude\": %.6f, \"longitude\": %.6f}", latDecimalGlobal, lonDecimalGlobal);
        Serial.print("Payload initialized: ");
        Serial.println(payload);
    }
    Serial.print("Sending MQTT data with payload: ");
    Serial.println(payload);
    is_publishing = true;

    if (!check_network()) {
        Serial.println("Network signal weak, skipping MQTT send");
        is_publishing = false;
        return false;
    }

    // Thử mở kết nối MQTT
    bool mqtt_opened = false;
    for (int i = 0; i < 3; i++) {
        if (sim_at_cmd("AT+QMTOPEN=0,\"demo.thingsboard.io\",1883")) {
            if (strstr(data, "+QMTOPEN: 0,0") != NULL) {
                Serial.println("MQTT connection opened");
                mqtt_opened = true;
                break;
            }
        }
        Serial.println("MQTT open failed, retrying...");
        delay(3000);
    }
    if (!mqtt_opened) {
        Serial.println("Failed to open MQTT connection");
        is_publishing = false;
        return false;
    }

    // Thử kết nối client
    bool mqtt_connected = false;
    for (int i = 0; i < 3; i++) {
        if (sim_at_cmd("AT+QMTCONN=0,\"clientExample\",\"StQb4lQec7VJK7BZsUl5\"")) {
            if (strstr(data, "+QMTCONN: 0,0,0") != NULL) {
                Serial.println("MQTT client connected");
                mqtt_connected = true;
                break;
            }
        }
        Serial.println("MQTT connect failed, retrying...");
        delay(3000);
    }
    if (!mqtt_connected) {
        Serial.println("Failed to connect MQTT client");
        is_publishing = false;
        return false;
    }

    // Gửi payload
    bool mqtt_published = false;
    for (int i = 0; i < 3; i++) {
        uint32_t dodai = strlen(payload);
        snprintf(msg, sizeof(msg), "AT+QMTPUBEX=0,0,0,0,\"v1/devices/me/telemetry\",%lu", dodai);
        if (sim_at_cmd(msg)) {
            delay(1000); // Tăng delay để chờ dấu >
            if (strstr(data, ">") != NULL) {
                if (sim_at_cmd(payload)) {
                    delay(1000); // Tăng delay để gửi payload
                    sim_at_cmd(""); // Gửi \r\n
                    delay(1000); // Chờ phản hồi
                    if (strstr(data, "+QMTPUBEX: 0,0,0") != NULL) {
                        Serial.println("MQTT publish successful");
                        mqtt_published = true;
                        break;
                    }
                }
            }
        }
        Serial.println("MQTT publish failed, retrying...");
        delay(3000);
    }
    if (!mqtt_published) {
        Serial.println("Failed to publish MQTT data");
    }

    // Ngắt kết nối
    sim_at_cmd("AT+QMTDISC=0");
    delay(2000);
    is_publishing = false;
    return mqtt_published;
}

void setup() {
    pinMode(MCU_SIM_EN_PIN, OUTPUT);
    digitalWrite(MCU_SIM_EN_PIN, HIGH); // Thả PWRKEY lên cao
    delay(500);
    Serial.begin(115200);
    Serial.println("\n\n\n\n-----------------------\nSystem started!!!!");
    delay(5000);

    simSerial.begin(MCU_SIM_BAUDRATE, SERIAL_8N1, MCU_SIM_RX_PIN, MCU_SIM_TX_PIN);
    Serial.println("SIM Serial initialized!");
    Serial.println("Checking AT command...");
    sim_at_cmd("AT");
    Serial.println("Getting product info...");
    sim_at_cmd("ATI");
    Serial.println("Checking signal quality...");
    sim_at_cmd("AT+CSQ");
    Serial.println("Getting IMSI...");
    sim_at_cmd("AT+CIMI");
    Serial.println("Activating GPS...");
    sim_at_cmd("AT+QGPSCFG=\"antenna\",1"); // Bật nguồn cho anten chủ động
    sim_at_cmd("AT+QGPS=1");
    delay(15000); // Chờ 15 giây để GPS khởi động
    // Khởi tạo payload mặc định
    snprintf(payload, sizeof(payload), "{\"latitude\": %.6f, \"longitude\": %.6f}", latDecimalGlobal, lonDecimalGlobal);
    Serial.print("Initial payload: ");
    Serial.println(payload);
    get_gps_data();
}

void loop() {
    if (Serial.available()) {
        char c = Serial.read();
        sim_at_send(c);
    }
    if (!is_publishing) {
        get_gps_data(); // Đọc GPS trước khi gửi MQTT
    }
    send_mqtt_data();
    delay(5000);
}