GPS Neo M8 + SIM800L + TCP

I am having a problem guys, I am making my thesis project, And one of the main function of my system project is the motorcycle Anti-Theft, and now my problem is I am using TCP connection and planning to do real-time updates with the coordinates, but I am having a few seconds delay when the data is sending over to my database. Is this because I am using an old GSM module?

UPDATE:
Sending the coordinates is much more faster now depending on the signal of SIM800L
might upgrade to A7672S for 4G connection.

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include "GSMFunctions.h"

#define RXD2 16
#define TXD2 17
HardwareSerial neogps(1);

// SIM800L Pins
#define RXD_SIM800 4
#define TXD_SIM800 5
SoftwareSerial sim800l(RXD_SIM800, TXD_SIM800);

// Ignition switch pin
#define IGNITION_SWITCH 32
bool ignitionOn = false;
bool lastIgnitionState = false;

// TCP Server (Using Ngrok)
const char* tcpServer = "52.74.74.86";  // Update with your Ngrok host
const int tcpPort = 11139;  // Update with your Ngrok assigned port

TinyGPSPlus gps;

// Variables to store the last known valid GPS coordinates
float lastLat = 0.0;
float lastLng = 0.0;


// Flag to indicate if a command is received
bool commandReceived = false;

void setup() {
  Serial.begin(115200);
  sim800l.begin(9600);  // Initialize SIM800L serial
  neogps.begin(9600, SERIAL_8N1, RXD2, TXD2);

  pinMode(IGNITION_SWITCH, INPUT_PULLUP);  // Set GPIO 32 as input (with internal pull-up)

  // Initialize SIM800L for GPRS connection
  Serial.println("πŸ”Œ Initializing SIM800L... Please wait 6 seconds");
  delay(6000);
  sendATCommand("AT", 10000);  // Test AT command
  sendATCommand("AT+CSQ", 6000); // Check signal quality
  sendATCommand("AT+CREG?", 2000);  // Check network registration
  sendATCommand("AT+CGDCONT?", 5000);  // This command can sometimes return the APN, depending on the carrier
  // GPRS Initialization
  sendATCommand("AT+CFUN=1", 3000);  // Set full functionality
  sendATCommand("AT+CGATT=1", 3000);  // Attach to GPRS network
  sendATCommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", 3000);  // Set connection type
  sendATCommand("AT+SAPBR=3,1,\"APN\",\"internet\"", 3000);  // Set APN
  sendATCommand("AT+SAPBR=1,1", 3000);  // Activate bearer
  sendATCommand("ATE0", 5000);  // Disable echo


  // Connect to TCP Server
  connectTCP();
}

void loop() {
  if (!sim800l.available()) {
    Serial.println("⚠️ TCP Disconnected! Reconnecting...");
    connectTCP();
  }

  // Read the ignition state
  ignitionOn = digitalRead(IGNITION_SWITCH) == LOW;

  // Debugging print for ignition state
  Serial.printf("πŸ”‘ Ignition State: %s\n", ignitionOn ? "ON" : "OFF");

  // Print Ignition State if it changes
  if (ignitionOn != lastIgnitionState) {
    lastIgnitionState = ignitionOn; // Update the last ignition state
    Serial.println("⚠️ Ignition State Changed!");
  }

  while (neogps.available() && !commandReceived) {
    if (gps.encode(neogps.read())) {
      if (gps.location.isValid()) {
        float lat = gps.location.lat();
        float lng = gps.location.lng();
        int speed = gps.speed.kmph();
        int satellites = gps.satellites.value();

        // Update last known valid GPS coordinates
        lastLat = lat;
        lastLng = lng;

        // Prepare data string without start_latitude and start_longitude
        String data = "lat=" + String(lat, 6) + 
                      "&lng=" + String(lng, 6) +
                      "&speed=" + String(speed) + 
                      "&satellites=" + String(satellites) +
                      "&ignition=" + (ignitionOn ? "ON" : "OFF");

        // Send data to server over TCP using SIM800L
        sendTCPData(data);
        Serial.println("πŸ“‘ Sent: " + data);

        // Check ignition state after sending data
        ignitionOn = digitalRead(IGNITION_SWITCH) == LOW;
        Serial.printf("πŸ”‘ Ignition State (mid-send): %s\n", ignitionOn ? "ON" : "OFF");
      } else {
        Serial.println("⚠️ GPS Data Invalid, Skipping...");
      }
    }
  }

  // Continuously process incoming commands
  processIncomingCommand();

  // If a command is received, process it and reset the flag
  if (commandReceived) {
    commandReceived = false;
  }
}



  String command = "";  // Store incoming command
void processIncomingCommand() {
    while (sim800l.available()) {
        char c = sim800l.read();
        if (c == '\n' || c == '\r') {  // End of command
            command.trim();
            if (command.length() > 0) {
                Serial.println("πŸ“₯ Received command: [" + command + "]");
                
                // Filter out responses that you don't care about
                if (command.startsWith("lat=")) {
                    Serial.println("⚠️ Ignoring echoed GPS data");
                }
                else if (command.indexOf("SEND OK") != -1) {
                    Serial.println("⚠️ Ignoring SEND OK confirmation");
                }
                else if (command.indexOf("Data received and processed") != -1) {
                    Serial.println("⚠️ Ignoring data confirmation");
                }
                // Process only the THEFT (or STATUS) command
                else if (command.equals("THEFT")) {  
                    Serial.println("🚨 Theft Detected!");
                    commandReceived = true;  
                    makeCallAndStop();
                    sendSMSAlert(lastLat, lastLng);
                } 
                else if (command.equals("STATUS")) {
                    Serial.println("πŸ“Š Sending status...");
                    commandReceived = true;
                } 
                else {
                    Serial.println("❓ Unknown command: [" + command + "]");
                }
            }
            command = "";  // Reset command buffer
        } else {
            command += c;
        }
    }
}


void connectTCP() {
  // Send AT command to start a TCP connection to Ngrok server
  sendATCommand("AT+CIPSTART=\"TCP\",\"" + String(tcpServer) + "\"," + String(tcpPort), 5000);
  Serial.println("βœ… Connected to TCP Server!");
}

void sendTCPData(String data) {
  // Send AT command to start sending data over TCP
  sendATCommand("AT+CIPSEND=" + String(data.length()), 500);
  sim800l.println(data);  // Send the actual data
}

void sendATCommand(String command, unsigned long timeout) {
  sim800l.println(command);
  long int time = millis();
  while (millis() - time < timeout) {
    while (sim800l.available()) {
      String response = sim800l.readString();
      Serial.print(response);  // Print SIM800L response for debugging
      if (response.indexOf("OK") != -1 || response.indexOf("CONNECT") != -1) {
        return;
      }
    }
  }
  Serial.println("❌ Command Timeout: " + command);
}
SEND OK
THEFT
πŸ“‘ Sent: lat=7.783598&lng=122.586800&speed=0&satellites=12&ignition=OFF
πŸ”‘ Ignition State (mid-send): OFF


That sounds quite reasonable.

1 Like

There's a second's delay right there.

And even if your server finished responding in less than a second, your code will still wait a full 5 seconds here.

1 Like

Is that good enough for GPS tracking via GSM?

I'll try to solve it later, right now I am having problem of the ignition State reading it is not responsing looks like the sendTCPData() is looping

It certainly would be for me. Why do you think a few seconds latency would matter?

As I'm sure you are aware, such vehicle trackers have been commercially available for a long time, and are not expensive.

1 Like

Yeah, but this is for my Thesis Project. I've been thinking about implementing the anti theft, On what basis would I use for it to trigger. Because if I use the movement of the GPS whenever the motorcycle ignition Switch is off, the coordinates keep moving even if the GPS module is stationary..

Can't say anything about why the ignition state might not be detected without seeing a schematic.

Not that I can see your code does anything different based on whether the ignition is on or off.

But a cheap vibration sensor might do the trick of detecting movement.

The commercial GPS antitheft trackers often use geofencing. For example, if the tracked device moves more than a certain distance from its parking spot, an alarm is sent.

Consider reading up on how they work.

2 Likes

I'll try that approach too. As of now I am having problem on why the command is not being recognize when the server is sending as "THEFT"

I am using TCP and that's is for my testing server.js

 if (ignition === "OFF" && distance_moved > movementThreshold && !theftAlertSent) {
                        console.log('🚨 Movement detected while ignition is off!');
                        socket.write("THEFT\n");
                        theftAlertSent = true; // Set theft alert flag
                    }
void loop() {
  if (!sim800l.available()) {
    Serial.println("⚠️ TCP Disconnected! Reconnecting...");
    connectTCP();
  }

  // Read the ignition state
  ignitionOn = digitalRead(IGNITION_SWITCH) == LOW;

  // Debugging print for ignition state
  Serial.printf("πŸ”‘ Ignition State: %s\n", ignitionOn ? "ON" : "OFF");

  // Print Ignition State if it changes
  if (ignitionOn != lastIgnitionState) {
    lastIgnitionState = ignitionOn; // Update the last ignition state
    Serial.println("⚠️ Ignition State Changed!");
  }

  while (neogps.available() && !commandReceived) {
    if (gps.encode(neogps.read())) {
      if (gps.location.isValid()) {
        float lat = gps.location.lat();
        float lng = gps.location.lng();
        int speed = gps.speed.kmph();
        int satellites = gps.satellites.value();

        // Update last known valid GPS coordinates
        lastLat = lat;
        lastLng = lng;

        // Prepare data string without start_latitude and start_longitude
        String data = "lat=" + String(lat, 6) + 
                      "&lng=" + String(lng, 6) +
                      "&speed=" + String(speed) + 
                      "&satellites=" + String(satellites) +
                      "&ignition=" + (ignitionOn ? "ON" : "OFF");

        // Send data to server over TCP using SIM800L
        sendTCPData(data);
        Serial.println("πŸ“‘ Sent: " + data);

        // Check ignition state after sending data
        ignitionOn = digitalRead(IGNITION_SWITCH) == LOW;
        Serial.printf("πŸ”‘ Ignition State (mid-send): %s\n", ignitionOn ? "ON" : "OFF");
      } else {
        Serial.println("⚠️ GPS Data Invalid, Skipping...");
      }
    }
  }

  // Continuously process incoming commands
  processIncomingCommand();

  // If a command is received, process it and reset the flag
  if (commandReceived) {
    commandReceived = false;
  }
}
 String command = "";  // Store incoming command
void processIncomingCommand() {
    while (sim800l.available()) {
        char c = sim800l.read();
        if (c == '\n' || c == '\r') {  // End of command
            command.trim();
            if (command.length() > 0) {
                Serial.println("πŸ“₯ Received command: [" + command + "]");
                
                // Filter out responses that you don't care about
                if (command.startsWith("lat=")) {
                    Serial.println("⚠️ Ignoring echoed GPS data");
                }
                else if (command.indexOf("SEND OK") != -1) {
                    Serial.println("⚠️ Ignoring SEND OK confirmation");
                }
                else if (command.indexOf("Data received and processed") != -1) {
                    Serial.println("⚠️ Ignoring data confirmation");
                }
                // Process only the THEFT (or STATUS) command
                else if (command.equals("THEFT")) {  
                    Serial.println("🚨 Theft Detected!");
                    commandReceived = true;  
                    makeCallAndStop();
                    sendSMSAlert(lastLat, lastLng);
                } 
                else if (command.equals("STATUS")) {
                    Serial.println("πŸ“Š Sending status...");
                    commandReceived = true;
                } 
                else {
                    Serial.println("❓ Unknown command: [" + command + "]");
                }
            }
            command = "";  // Reset command buffer
        } else {
            command += c;
        }
    }
}

I might also do that, but for now I am having problem with my code, the command "THEFT" is not being recognize

#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include "GSMFunctions.h"

#define RXD2 16
#define TXD2 17
HardwareSerial neogps(1);

// SIM800L Pins
#define RXD_SIM800 4
#define TXD_SIM800 5
SoftwareSerial sim800l(RXD_SIM800, TXD_SIM800);

// Ignition switch pin
#define IGNITION_SWITCH 32
bool ignitionOn = false;
bool lastIgnitionState = false;

// TCP Server (Using Ngrok)
const char* tcpServer = "52.74.74.86";  // Update with your Ngrok host
const int tcpPort = 11139;  // Update with your Ngrok assigned port

TinyGPSPlus gps;

// Variables to store the last known valid GPS coordinates
float lastLat = 0.0;
float lastLng = 0.0;


// Flag to indicate if a command is received
bool commandReceived = false;

void setup() {
  Serial.begin(115200);
  sim800l.begin(9600);  // Initialize SIM800L serial
  neogps.begin(9600, SERIAL_8N1, RXD2, TXD2);

  pinMode(IGNITION_SWITCH, INPUT_PULLUP);  // Set GPIO 32 as input (with internal pull-up)

  // Initialize SIM800L for GPRS connection
  Serial.println("πŸ”Œ Initializing SIM800L... Please wait 6 seconds");
  delay(6000);
  sendATCommand("AT", 10000);  // Test AT command
  sendATCommand("AT+CSQ", 6000); // Check signal quality
  sendATCommand("AT+CREG?", 2000);  // Check network registration
  sendATCommand("AT+CGDCONT?", 5000);  // This command can sometimes return the APN, depending on the carrier
  // GPRS Initialization
  sendATCommand("AT+CFUN=1", 3000);  // Set full functionality
  sendATCommand("AT+CGATT=1", 3000);  // Attach to GPRS network
  sendATCommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", 3000);  // Set connection type
  sendATCommand("AT+SAPBR=3,1,\"APN\",\"internet\"", 3000);  // Set APN
  sendATCommand("AT+SAPBR=1,1", 3000);  // Activate bearer
  sendATCommand("ATE0", 5000);  // Disable echo


  // Connect to TCP Server
  connectTCP();
}

void loop() {
  if (!sim800l.available()) {
    Serial.println("⚠️ TCP Disconnected! Reconnecting...");
    connectTCP();
  }

  // Read the ignition state
  ignitionOn = digitalRead(IGNITION_SWITCH) == LOW;

  // Debugging print for ignition state
  Serial.printf("πŸ”‘ Ignition State: %s\n", ignitionOn ? "ON" : "OFF");

  // Print Ignition State if it changes
  if (ignitionOn != lastIgnitionState) {
    lastIgnitionState = ignitionOn; // Update the last ignition state
    Serial.println("⚠️ Ignition State Changed!");
  }

  while (neogps.available() && !commandReceived) {
    if (gps.encode(neogps.read())) {
      if (gps.location.isValid()) {
        float lat = gps.location.lat();
        float lng = gps.location.lng();
        int speed = gps.speed.kmph();
        int satellites = gps.satellites.value();

        // Update last known valid GPS coordinates
        lastLat = lat;
        lastLng = lng;

        // Prepare data string without start_latitude and start_longitude
        String data = "lat=" + String(lat, 6) + 
                      "&lng=" + String(lng, 6) +
                      "&speed=" + String(speed) + 
                      "&satellites=" + String(satellites) +
                      "&ignition=" + (ignitionOn ? "ON" : "OFF");

        // Send data to server over TCP using SIM800L
        sendTCPData(data);
        Serial.println("πŸ“‘ Sent: " + data);

        // Check ignition state after sending data
        ignitionOn = digitalRead(IGNITION_SWITCH) == LOW;
        Serial.printf("πŸ”‘ Ignition State (mid-send): %s\n", ignitionOn ? "ON" : "OFF");
      } else {
        Serial.println("⚠️ GPS Data Invalid, Skipping...");
      }
    }
  }

  // Continuously process incoming commands
  processIncomingCommand();

  // If a command is received, process it and reset the flag
  if (commandReceived) {
    commandReceived = false;
  }
}



  String command = "";  // Store incoming command
void processIncomingCommand() {
    while (sim800l.available()) {
        char c = sim800l.read();
        if (c == '\n' || c == '\r') {  // End of command
            command.trim();
            if (command.length() > 0) {
                Serial.println("πŸ“₯ Received command: [" + command + "]");
                
                // Filter out responses that you don't care about
                if (command.startsWith("lat=")) {
                    Serial.println("⚠️ Ignoring echoed GPS data");
                }
                else if (command.indexOf("SEND OK") != -1) {
                    Serial.println("⚠️ Ignoring SEND OK confirmation");
                }
                else if (command.indexOf("Data received and processed") != -1) {
                    Serial.println("⚠️ Ignoring data confirmation");
                }
                // Process only the THEFT (or STATUS) command
                else if (command.equals("THEFT")) {  
                    Serial.println("🚨 Theft Detected!");
                    commandReceived = true;  
                    makeCallAndStop();
                    sendSMSAlert(lastLat, lastLng);
                } 
                else if (command.equals("STATUS")) {
                    Serial.println("πŸ“Š Sending status...");
                    commandReceived = true;
                } 
                else {
                    Serial.println("❓ Unknown command: [" + command + "]");
                }
            }
            command = "";  // Reset command buffer
        } else {
            command += c;
        }
    }
}


void connectTCP() {
  // Send AT command to start a TCP connection to Ngrok server
  sendATCommand("AT+CIPSTART=\"TCP\",\"" + String(tcpServer) + "\"," + String(tcpPort), 5000);
  Serial.println("βœ… Connected to TCP Server!");
}

void sendTCPData(String data) {
  // Send AT command to start sending data over TCP
  sendATCommand("AT+CIPSEND=" + String(data.length()), 500);
  sim800l.println(data);  // Send the actual data
}

void sendATCommand(String command, unsigned long timeout) {
  sim800l.println(command);
  long int time = millis();
  while (millis() - time < timeout) {
    while (sim800l.available()) {
      String response = sim800l.readString();
      Serial.print(response);  // Print SIM800L response for debugging
      if (response.indexOf("OK") != -1 || response.indexOf("CONNECT") != -1) {
        return;
      }
    }
  }
  Serial.println("❌ Command Timeout: " + command);
}

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