GPS Data to map markers

Hi there I am using an adafruit ultimate v3 with a feather v2 esp32 and I am trying to map the latitude and longitude data that gets send over bluetooth to different map markers in an app. The difficulty i am having is splitting the data I am receiving and then setting the marker longitude and latitude markers using the data. A few things that makes this more difficult is that i have not got a set number of markers as depending on how long the user would like to log data a different number of points will be recorded.

so far i have been able to send a the data string to a "serial monitor" i have set up in the app but have not been able to get much further.

The relevant arduino code for this is as follows:
if (ESPFeather.available()) {
incoming = ESPFeather.read();
int button = floor(incoming / 10);
int value = incoming % 10;
case 2:
Serial.print("Button 2: "); Serial.println(value);
if (value == 1) {
// Read GPS data and print to Serial Monitor
File file = SPIFFS.open("/gps_data.txt", FILE_READ);
if (!file) {
ESPFeather.println("Failed to open file for reading");
return;
}
ESPFeather.println("Sending GPS data:");
while (file.available()) {
ESPFeather.write(file.read());
}
file.close();
ESPFeather.println("GPS data sent.");

    }

}

case 2 refers to button 2 on the app

The app code looks like this: (I know it is not even close but i'm not sure where to go from here any help would be greatly appreciated)

Hello George

There are other Power Users with more GPS experience than me, but yes your App Inventor code is way off - you need a lot of help.

Help us to help you:

  1. Post the whole .ino file here (as a file!)
  2. Post the AI Project file .aia here.
  3. It seems as though your App is designed to receive one 'lump' of data only - is that your requirement or do you want to stream the data at runtime, over a period of time determined by the User or until the User disconnects the stream?
  4. Is this a one-off project for your personal use or is it for many Users? (If for many Users, different versions of Android and Bluetooth have to be catered for).

I assume your button click is essentially a request for the data from the ESP32? Why "21"? (that's 3 bytes).

Here is a brief collection of Blocks that would do what you seem to want your Blocks to do - there is more to it than I show, including Android permissions, scanning for devices, error catching, automation of switching Bluetooth on and of course what to do with the received data.

Click on the image for a better view.

Perhaps either use

  • run time Markers to display all the points your arduino collects. You could use code similar to this

    using Map.CreateMarker The code plots Markers from a csv file but can be adapted to plot Markers as they are recorded from the arduino.

or

  • instead of Markers, use a LineString to display a trak of coordinates (Track list)

or

Use a single design time marker. Record coordinates to a list. Then display a single marker at a time by selecting items (individual coordinates) from a List.

What you do depends on how you want to display the GPS trak of your arduino. You can essentially display an 'unlimited' set of Markers.

for some reason i cant get it to work.
Below is the full arduino code and the blocks i am using:.

#include "BluetoothSerial.h" 
#include "SPIFFS.h"

// Initialize BluetoothSerial and class instance
BluetoothSerial ESP_BT;

// Initialize PINs: assign any pin on ESP32
int led_pin_1 = 27;
int led_pin_2 = 33;
int led_pin_3 = 13;

// Parameters for Bluetooth interface
int incoming;

void setup() {
  Serial.begin(19200);
  ESP_BT.begin("ESP32_Control"); // Name of your Bluetooth interface

  pinMode(led_pin_1, OUTPUT);
  pinMode(led_pin_2, OUTPUT);
  pinMode(led_pin_3, OUTPUT);

  // Initialize SPIFFS
  if (!SPIFFS.begin(true)) {
    Serial.println("An error has occurred while mounting SPIFFS");
    return;
  }

  // Open the file for appending (creating if necessary)
  File file = SPIFFS.open("/gps_data.csv", FILE_APPEND);
  if (!file) {
    Serial.println("Failed to open file for writing");
    return;
  }

  // Add headers if the file is empty
  if (file.size() == 0) {
    file.println("Latitude,Longitude");
  }

  // Example GPS data to write
  String gpsData = "51.498308,-0.176882\n";
  file.print(gpsData);  // Write CSV formatted GPS data
  file.close();
}

void loop() {
  // Receive Bluetooth signal
  if (ESP_BT.available()) {
    incoming = ESP_BT.read();  // Read what we receive

    // Separate button ID from button value -> button ID is 10, 20, 30, etc., value is 1 or 0
    int button = incoming / 10;
    int value = incoming % 10;

    switch (button) {
      case 1:
        Serial.print("Button 1: "); Serial.println(value);
        digitalWrite(led_pin_1, value);
        break;
      case 2: {
        File file = SPIFFS.open("/gps_data.csv", FILE_READ);
        if (!file) {
          ESP_BT.println("Failed to open file for reading");
          return;
        }

        ESP_BT.println("Sending GPS data:");
        while (file.available()) {
          ESP_BT.write(file.read());
        }
        file.close();
        break;
      }
      case 3:
        Serial.print("Button 3: "); Serial.println(value);
        digitalWrite(led_pin_3, value);
        break;
    }
  }
}

I realised i called the file the wrong name in the blocks. I changed it to the right name and it still doesnt work

Probably because you copied the example code as was shown instead of

You are trying erroneously to use the File control. You don't need that George. :cry:

What you should be doing is use part of the blocks in what you copied for the File1.GotText block. you should be using code similar to

I would be more specific but I don't have an arduino to I can't see where the latitude and longitude are coming from the BT. So I am guessing the changes I made to the code probably won't work unless LocationList contains the lat and long as a ListOfPairs.

George, in your Sketch, you are using Bluetooth Serial (ESP_BT) to send to the App right?

Do not send progress messages to the App, nor any form of labelling - just send the data (values). A Bluetooth packet carries approx 20 bytes of your data so you need to keep it "short and sweet". You also need to indicate the end of the data sent.

For example, if you are sending the location of the Eiffel Tower in Paris, France, your data would be:
String Data = "48.8584N,2.2945E\n"; where '\n' indicates the end of the data and ',' separates the two values.

If your CSV file contains multiple data sets (lines), read then send one set at a time, in a loop that has a small delay to give the App enough time to receive and process the data.

Something like this:

string data[20];

While (file.available())
{
          data = file.readStringUntil('\n');
          ESP_BT.write(data);
          delay(100);
}
        
file.close();

ok so basically the issue im having is i cant seem to use a variable to set the longitude and latitude for a marker. I can print a number e.g. 53.2938 for longitude and lets say I have set this as a global variable called loc1. When i use the set map1 longitude to loc1 which is just a variable set to 53.2938 it returns the error: The operation select list item cannot accept the arguments: , [empty-string], [1]

just not really sure why this doesnt work


this says latitude cannot accept empty argument

Doing this in a Click event assumes instant availability of an answer from Bluetooth.

Here is how it's done with a timer:

Be sure to use println() at the end of each message to send from the sending device, to signal end of message.

Only use print() in the middle of a message.

Be sure not to println() in the middle of a message, or you will break it into two short messages and mess up the item count after you split the message in AI2.

Do not rely on timing for this, which is unreliable.

In the AI2 Designer, set the Delimiter attribute of the BlueTooth Client component to 10 to recognize the End of Line character.
BlueToothClient1_Properties
Also, return data is not immediately available after sending a request,
you have to start a Clock Timer repeating and watch for its arrival in the Clock Timer event. The repeat rate of the Clock Timer should be faster than the transmission rate in the sending device, to not flood the AI2 buffers.

In your Clock Timer, you should check

  Is the BlueTooth Client still Connected?
  Is Bytes Available > 0?
     IF Bytes Available > 0 THEN
       set message var  to BT.ReceiveText(-1) 

This takes advantage of a special case in the ReceiveText block:

ReceiveText(numberOfBytes)
Receive text from the connected Bluetooth device. If numberOfBytes is less than 0, read until a delimiter byte value is received.

If you are sending multiple data values per message separated by | or comma, have your message split into a local or global variable for inspection before trying to select list items from it. Test if (length of list(split list result) >= expected list length) before doing any select list item operations, to avoid taking a long walk on a short pier. This bulletproofing is necessary in case your sending device sneaks in some commentary messages with the data values.

Some people send temperature and humidity in separate messages with distinctive prefixes like "t:" (for temperature) and "h:" (for humidity).
(That's YAML format.)

The AI2 Charts component can recognize these and graph them. See Bluetooth Client Polling Rate - #12 by ABG

To receive YAML format messages, test if the incoming message contains ':' . If true, split it at ':' into a list variable, and find the prefix in item 1 and the value in item 2.

...