GPS tracker with web interface for downloading KLM files, possible?

My first project on an arduino was a gps tracker with a web interface for downloading KLM files.
I may have started with the wrong modules to complete this, hoping someone can answer if it is feasible, possibly help with the coding.

I have come this far.
GPS communication works and writes the klm files to the SD card, and the web server also works as an independent access point to display the html file on the SD card.

The problem is mainly after hours of trial and error that I am unable to list the klm files that are written on the SD card.

#include <HardwareSerial.h>
#include <TinyGPSPlus.h>
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"

#define RX_gps 16
#define TX_gps 17

#define CS  5
#define SCK  18
#define MISO  19
#define MOSI  23

#define trigger_pin 25
#define LED_pin 32
#define LED_position_pin 12

const char* ssid = "GPS TRACKER1";        //Write your own Wi-Fi name here
const char* password = "tracker";    //Write your own password here


AsyncWebServer server(80);         //object created on default port 80

HardwareSerial gps_serial(2);

TinyGPSPlus gps;

double last_lat = 0;
double last_lng = 0;

const int chipSelect = 5;
bool recording = false;
bool has_valid_position = false;
String recording_file = "";

int ledState = LOW;
int buttonState;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

void setup() {
  Serial.begin(115200);

  pinMode(LED_pin, OUTPUT);
  pinMode(LED_position_pin, OUTPUT);
  pinMode(trigger_pin, INPUT);
  digitalWrite(LED_pin, LOW);
  digitalWrite(LED_position_pin, LOW);

  // see if the card is present and can be initialized:
  // if (!SD.begin(chipSelect)) {
  //   Serial.println("Card failed, or not present");
  //   // don't do anything more:
  //   while (1);
  // }
  while (!SD.begin(chipSelect)) {
    
    Serial.println("Card failed, or not present");
    // Try again after waiting 5 seconds.
    delay (5000);
  }
  Serial.println("Card ready...");
    
  gps_serial.begin(115200, SERIAL_8N1, RX_gps, TX_gps);

  //wait a bit for serail to stabilize
  delay(3000);
  Serial.println("GPS ready...");
  
  //Serial.begin(115200);
  initWiFi();
  Serial.println("WiFi ready...");
  initmicroSDCard();
  Serial.println("SD card initialized...");

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SD, "/index.html", "text/html");
  });

  server.serveStatic("/", SD, "/");

  server.begin();
}

void loop() {
  int reading = digitalRead(trigger_pin);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
        if(recording) {
          //stop recording and finalize file
          finalizeFile();
          recording = false;
        } else {
          //start recording
          recording_file = getNextFileName(SD);
          startFile();
          recording = true;
        }
      }
    }
  }

  // set the LEDs:
  digitalWrite(LED_pin, ledState);
  digitalWrite(LED_position_pin, has_valid_position ? HIGH : LOW);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;

  if (Serial.available()) {
    String content = Serial.readString();
    content.trim();
    if (content.startsWith("gps:")) {
      Serial.println("Writing to GPS Module");
      sendGPSCommand(content.substring(4));
    } else if (content == "current_gps") {
      Serial.println("Current position: " + String(gps.location.lat(), 6) + ", " + String(gps.location.lng(), 6));
      Serial.println("Distance: " + String(gps.distanceBetween(gps.location.lat(), gps.location.lng(), last_lat, last_lng)));
      Serial.println("Altitude: " + String(gps.altitude.meters()));
      Serial.println("Failed Checksum: " + String(gps.failedChecksum()));
      recordGPSPosition();
    }
  } else {
    Serial.println("Serial not available.");
  }

  String gps_incomming = "";
  while (gps_serial.available() > 0) {
    char c = (char)gps_serial.read();
    gps_incomming += c;
    if (gps.encode(c)) {
      handleLocation();
    }
  }
  // if(gps_incomming != "") {
  //   Serial.println(gps_incomming);
  // }
}

String getNextFileName(fs::FS& fs) {
  int count = 1;
  File root = fs.open("/");
  if (!root) {
    Serial.println("Failed to open directory");
    return "";
  }
  if (!root.isDirectory()) {
    Serial.println("Not a directory");
    return "";
  }

  File file = root.openNextFile();
  while (file) {
    if (!file.isDirectory()) {
      count++;
    }
    file = root.openNextFile();
  }
  char buffer [9];
  sprintf (buffer, "%04d.kml", count);
  return buffer;
}

void startFile() {
  String file_start = R"=="==(<?xml version="1.0" encoding="UTF-8"?>
  <kml xmlns="http://www.opengis.net/kml/2.2">
    <Document>
      <name>Paths</name>
      <description>Recorded path using the Nature Trail Mapper</description>
      <Style id="yellowLineGreenPoly">
        <LineStyle>
          <color>7f00ffff</color>
          <width>4</width>
        </LineStyle>
        <PolyStyle>
          <color>7f00ff00</color>
        </PolyStyle>
      </Style>
      <Placemark>
        <name>Recorded Path</name>
        <description>A line indicated a recorded path.</description>
        <styleUrl>#yellowLineGreenPoly</styleUrl>
        <LineString>
          <extrude>0</extrude>
          <tessellate>0</tessellate>
          <altitudeMode>clampToGround</altitudeMode>
          <coordinates>)=="==";
  writeToFile(recording_file, file_start, FILE_WRITE);
}

void finalizeFile() {
  String file_start = R"(</coordinates>
        </LineString>
      </Placemark>
    </Document>
  </kml>)";
  writeToFile(recording_file, file_start);
}

void writeToFile(String file_name, String data_to_write) {
  writeToFile(file_name, data_to_write, FILE_APPEND);
}

void writeToFile(String file_name, String data_to_write, char* mode) {
  File dataFile = SD.open("/" + file_name, mode);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(data_to_write);
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening file");
  }
}

void sendGPSCommand(String command) {
  command = command + "\r\n";
  char* buf = (char*)malloc(sizeof(char) * command.length() + 1);
  Serial.println(command);
  command.toCharArray(buf, command.length() + 1);
  gps_serial.write(buf);
  free(buf);
}

void recordGPSPosition() {
  if(recording) {
    writeToFile(recording_file, String(gps.location.lng(), 6) + "," + String(gps.location.lat(), 6) + "," + String(gps.altitude.meters()));
  }
}

void handleLocation() {
  if (gps.location.isValid()) {
    has_valid_position = true;
    if (last_lat == 0 || last_lng == 0) {
      //first position, set initial values
      last_lat = gps.location.lat();
      last_lng = gps.location.lng();
      Serial.println("Initial position: " + String(last_lat, 6) + ", " + String(last_lng, 6));
      recordGPSPosition();
    } else {
      //update last position if distance is greater than 1m
      if (gps.distanceBetween(gps.location.lat(), gps.location.lng(), last_lat, last_lng) > 1) {
        last_lat = gps.location.lat();
        last_lng = gps.location.lng();
        Serial.println("Updated position: " + String(last_lat, 6) + ", " + String(last_lng, 6) + ", " + String(gps.altitude.meters()));
        recordGPSPosition();
      }
    }
  } else {
    has_valid_position = false;
    Serial.println("Invalid GPS position...");
  }
}

void initmicroSDCard(){
  if(!SD.begin()){
    Serial.println("Initialization Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("SD card is not present!");
    return;
  }

  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

void initWiFi() {
  WiFi.mode(WIFI_AP);
  WiFi.begin(ssid, password);
  Serial.print("Setting AP (Access Point)…");
  WiFi.softAP(ssid, password);
   IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);
}

Welcome to the forum

Why did you start a topic in the Uncategorised category of the forum ?

Your topic has been moved to a relevant category. Please be careful in future when deciding where to start new topics

There are examples in the SD library that list files. Study them and modify as required.

have a look at firebeetle-2-esp32-e-rfid-microsd-rtc-rfid-scans-once which has an example of listing listing SD card directories

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